2021年最新CPU(Intel 第12世代 Core i9 12900K)でFreeBSDを使ってみる

# はじめに

2021年11月にIntelの新CPU 第12世代Coreシリーズが発売されました。しかし、毎度最新CPUが発表されるたびに話題になるのはWindowsばかり。あってもせいぜいLinuxの情報くらい...
FreeBSDの情報なんて微塵もありませんw (まあ、ユーザー数考えれば当然ですが...)

そう、自分で人柱になるしかないのです。
というわけで、買いました。

ちょうどNASに使っていたマシンが丸4年を超え、5年目に突入しようとしているところでしたので、新しくPCを組み直しました。

# Intel 第12世代 Coreシリーズの特徴 － そもそも、何がすごいの？

まず、Core i9 12900KやCore i7 12700Kのスペックを見てください。
あれ？と思いませんでしたか。

>Core i9 12900K
 CPU Specifications
    Total Cores 16
    # of Performance-cores 8
    # of Efficient-cores 8
    Total Threads 24

https://ark.intel.com/content/www/us/en/ark/products/134599/intel-core-i912900k-processor-30m-cache-up-to-5-20-ghz.html

コア数が16なのに、総スレッド数が24??

>Core i7 12700K
 CPU Specifications
    Total Cores 12
    # of Performance-cores 8
    # of Efficient-cores 4
    Total Threads 20

https://ark.intel.com/content/www/us/en/ark/products/134594/intel-core-i712700k-processor-25m-cache-up-to-5-00-ghz.html

コア数が12なのに、総スレッド数が20??

これまでの、CoreシリーズではHyper Threadingに対応していれば、
総スレッド数は単純にコア数の2倍になっていました。
第12世代Coreシリーズでは、その図式が成り立たなくなっています。
よく見ると、# of Performance-cores, # of Efficient-coresとコア数の内訳が書いてあります。そう、第12世代Coreシリーズは種類の異なる2種類のコアが1つのCPUの中に含まれているのです。(ヘテロジニアス・マルチコアと言われるやつです)

つまり、高いパフォーマンスのPerformance-core, 高い電力効率を持つEfficient-coreを1つのCPUにまとめたことで、総合性能を高めたCPUという訳です。
PerformanceコアはHyper Threadingに対応し、Efficientコアは対応してないコアになるため、コア数を単純に倍にした数がスレッド数にはならないということになってます。

しかし、性能の異なるコアが混在することプロセススケジューラが適切にプロセス割り当てできるのか？という疑問がわきます。これまでのプロセススケジューラは基本的にどのコアも同じものだという前提で作られています(のはずです...)。また、第12世代CoreにはThread DirectorというOSのプロセススケジューラと協調して最適なプロセス割り当てを実現する機能があるようなのですが、現状これに対応しているのはWindows 11のみです。

さて、FreeBSDで性能がどこまで発揮できるのでしょうか...という訳で早速見てみたいと思います。

# スペック

今回組んだPCの主なパーツは以下の通りです。
- CPU: Intel Core i9 12900K
- GPU: CPU内蔵GPUを使用
- M/B: ASRock Z690 PG RIPTIDE
- MEM: ADATA XPG GAMMIX D20 DDR4-3200 64GB
- Storage1: WD RED Plus HDD 8TB x 5
- Storage2: CFD CSSD-M2M1TPG4VNZ (NVMe SSD 1TB)
- NIC: Intel X540-T2 (10GbE)

ちなみにCPUの冷却系は空冷です。
性能的には簡易水冷などを使う方が良いと思いますが、古いケースを使用しているので、ラジエーターを設置するスペースがないため、空冷式にしてます。

とりあえず、ケースにHDD以外のパーツを一通り取り付けたところ...ケーブルがごちゃごちゃしてますが...
![IMG_1564.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373056/3d206b7c-3965-c112-6616-000f4a66885e.jpeg)


# Install

13.0-RELEASEをインストールしました。
オンボードのAHCI/NVMeコントローラデバイスはともに問題なく認識して普通にインストールできました。

5個のHDDでraidz2を組み、SSDはzfsのL2ARCとintent log用、そしてOSのswap用として使用
という構成にしています。

# デバイス周りの認識状況
## CPU関連
### CPU topology
FreeBSDのスケジューラSCHED_ULEはコア、スレッドとCPUキャッシュがどのような構成になっているかを検知して適切なスケジューリングが行えるような仕組みになっています。
その構成(トポロジ)をsysctlのkern.sched.topology_specで確認することができます。

<details><summary>sysctl kern.sched.topology_specの実行結果</summary><div>

```
# sysctl kern.sched.topology_spec

kern.sched.topology_spec: <groups>
 <group level="1" cache-level="3">
  <cpu count="24" mask="ffffff,0,0,0">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23</cpu>
  <children>
   <group level="2" cache-level="2">
    <cpu count="2" mask="3,0,0,0">0, 1</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="c,0,0,0">2, 3</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="30,0,0,0">4, 5</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="c0,0,0,0">6, 7</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="300,0,0,0">8, 9</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="c00,0,0,0">10, 11</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="3000,0,0,0">12, 13</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="2" mask="c000,0,0,0">14, 15</cpu>
    <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
   </group>
   <group level="2" cache-level="2">
    <cpu count="4" mask="f0000,0,0,0">16, 17, 18, 19</cpu>
   </group>
   <group level="2" cache-level="2">
    <cpu count="4" mask="f00000,0,0,0">20, 21, 22, 23</cpu>
   </group>
  </children>
 </group>
</groups>
```
</div>
</details>

0～15までがP-Core(Hyper-Threading含む), 16～23がE-Coreの様です。
インテル社の公開している以下のホワイトペーパーにあるトポロジの図(以下の資料のFigure 1)と比較しても正しく認識されていることが分かります。

https://www.intel.com/content/www/us/en/developer/articles/guide/alder-lake-developer-guide.html

### coretemp / cpufreq

coretempをロードすると、
<pre>coretemp0: Tj(target) value 115 does not seem right.</pre>
というメッセージが表示されます。どうもCPUIDで返ってくるTjunction(この温度を超えるとサーマルスロットリングが発生するという閾値)が115になっているようです。現在のFreeBSDのcoretempドライバは、Tjunctionの値が110を超えていると何かおかしいよ？と見なして無視してデフォルト値を入れるような処理になっています。
これによって、Tjmaxは100に設定されてしまい、温度表示がおかしくなります。

<pre>#sysctl -a | grep temper
...
dev.cpu.0.temperature: 17.0C
</pre>

明らかに室温より低い...
quick hackですが、以下の様に修正して、+15℃した表示になるようにすると、実態に近いような気がします。(ちゃんと温度を計ったわけではないので、本当に正しいのか不明ですが。)

```
# git diff
diff --git a/sys/dev/coretemp/coretemp.c b/sys/dev/coretemp/coretemp.c
index bdc71b284ac..fc53f19e6c9 100644
--- a/sys/dev/coretemp/coretemp.c
+++ b/sys/dev/coretemp/coretemp.c
@@ -257,7 +257,7 @@ coretemp_attach(device_t dev)
                         * these values whenever the MSR is available for
                         * read, regardless the CPU model.
                         */
-                       if (tjtarget >= 70 && tjtarget <= 110)
+                       if (tjtarget >= 70 && tjtarget <= 115)
                                sc->sc_tjmax = tjtarget;
                        else
                                device_printf(dev, "Tj(target) value %d "
```


cpufreqの方はドライバとしてhwpstateがロードされています。
<pre>
hwpstate_intel0: <Intel Speed Shift> on cpu0
hwpstate_intel1: <Intel Speed Shift> on cpu1
...(論理CPU分続く)
</pre>

以下を見る限り、負荷によって値が変わるので、正しく認識しているように見えます。

<details><summary>sysctl dev.cpu.*.freqの結果</summary><div>
<pre>\# sysctl -a | grep -E  'dev\.cpu\.[0-9]+\.freq:'
dev.cpu.23.freq: 3882
dev.cpu.22.freq: 3882
dev.cpu.21.freq: 3882
dev.cpu.20.freq: 3184
dev.cpu.19.freq: 2435
dev.cpu.18.freq: 1969
dev.cpu.17.freq: 1651
dev.cpu.16.freq: 1351
dev.cpu.15.freq: 1472
dev.cpu.14.freq: 1252
dev.cpu.13.freq: 2986
dev.cpu.12.freq: 994
dev.cpu.11.freq: 895
dev.cpu.10.freq: 1102
dev.cpu.9.freq: 1093
dev.cpu.8.freq: 895
dev.cpu.7.freq: 758
dev.cpu.6.freq: 609
dev.cpu.5.freq: 497
dev.cpu.4.freq: 497
dev.cpu.3.freq: 873
dev.cpu.2.freq: 497
dev.cpu.1.freq: 497
dev.cpu.0.freq: 497</pre></div></details>

## VGAドライバ/X Window System
portsにあるdrm-devel-kmodを試してみましたが、現状は対応してないように見えます。
ロードしても認識しませんでした。Xは試しませんでしたが、普通にVESAドライバで動くと思います。

## オンボードデバイス関連

以下のデバイスは、13.0-RELEASEでは認識せず、13.0-STABLEにしたら認識しました。

<pre>ig4iic0: &lt;Intel Alder Lake-S I2C Controller-0&gt; at device 21.0 on pci0
ig4iic0: Using MSI
iicbus0: &lt;Philips I2C bus (ACPI-hinted)&gt; on ig4iic0
ichsmb0: &lt;Intel Alder Lake SMBus controller&gt; port 0xefa0-0xefbf mem 0x6002118000-0x60021180ff at device 31.4 on pci0
smbus0: &lt;System Management Bus&gt; on ichsmb0
smb0: &lt;SMBus generic I/O&gt; on smbus0
</pre>

smb認識したので、xmbmonや、bsdhwmonなどのハードウェアモニタ系のソフトを使ってみましたが、残念ながらファンの回転数やマザーボード上の温度センサーには対応していないようです。
共通のAPIじゃないんですかね...あまり詳しくないのですが。

また、このマザーボードのオンボードNICである、Killer E3000はドライバがなく認識しませんでした。Realtekのドライバre(4)では対応していないようです。
<pre>none4@pci0:3:0:0:       class=0x020000 rev=0x06 hdr=0x00 vendor=0x10ec device=0x3000 subvendor=0x1849 subdevice=0x3000
    vendor     = 'Realtek Semiconductor Co., Ltd.'
    device     = 'Killer E3000 2.5GbE Controller'
    class      = network
    subclass   = ethernet
</pre>

代わりにIntelの10GbE X540-T2を載せています。

# ベンチマーク
## make buildworld / make buildkernel

CPUの総合性能を計るには、ファイルI/Oがたくさんあり、計算量もそれなりにあるシステムのコンパイルをやらせてみるのがよいでしょうということで、FreeBSDをビルドしてみます。

make -j24 buildworld && make -j24 buildkernel
を実行して13.0-STABLEのソースをビルドしてみました。
timeコマンドで時間を測定したところ以下の様になっています。

<pre>--------------------------------------------------------------
>>> Kernel build for GENERIC completed on Tue Dec 14 00:35:55 JST 2021
--------------------------------------------------------------
>>> Kernel(s)  GENERIC built in 88 seconds, ncpu: 24, make -j24
--------------------------------------------------------------
makebuild  19937.49s user 877.80s system 2104% cpu 16:28.98 total
</pre>

make buildworldの部分は流れてしまっていますが、buildkernelは88秒、
make buildworld+buildkernelの合計で、16分28秒です。

参考ですが、Intel Core i7 7700K では1時間7分ほどかかりました。

## stream bench

こちらはメモリのバンド幅を測定するベンチマークstreamの結果です。
http://www.cs.virginia.edu/stream/

-fopenmp　オプションを付けてマルチスレッド対応でコンパイルしてます。

<pre>% ./stream_omp
-------------------------------------------------------------
STREAM version $Revision: 5.10 $
-------------------------------------------------------------
This system uses 8 bytes per array element.
-------------------------------------------------------------
Array size = 10000000 (elements), Offset = 0 (elements)
Memory per array = 76.3 MiB (= 0.1 GiB).
Total memory required = 228.9 MiB (= 0.2 GiB).
Each kernel will be executed 10 times.
 The *best* time for each kernel (excluding the first iteration)
 will be used to compute the reported bandwidth.
-------------------------------------------------------------
Number of Threads requested = 24
Number of Threads counted = 24
-------------------------------------------------------------
Your clock granularity/precision appears to be 1 microseconds.
Each test below will take on the order of 3463 microseconds.
   (= 3463 clock ticks)
Increase the size of the arrays if this shows that
you are not getting at least 20 clock ticks per test.
-------------------------------------------------------------
WARNING -- The above is only a rough guideline.
For best results, please be sure you know the
precision of your system timer.
-------------------------------------------------------------
Function    Best Rate MB/s  Avg time     Min time     Max time
Copy:           35866.0     0.004468     0.004461     0.004476
Scale:          34744.4     0.004614     0.004605     0.004642
Add:            35279.6     0.006812     0.006803     0.006822
Triad:          36172.1     0.006666     0.006635     0.006793
-------------------------------------------------------------
Solution Validates: avg error less than 1.000000e-13 on all three arrays
-------------------------------------------------------------
</pre>

こちらも、参考までに7700Kでの測定結果を付けておきます。

<pre>-------------------------------------------------------------
Function    Best Rate MB/s  Avg time     Min time     Max time
Copy:           26551.5     0.006084     0.006026     0.006197
Scale:          19177.8     0.008413     0.008343     0.008538
Add:            21420.9     0.011242     0.011204     0.011267
Triad:          21472.5     0.011210     0.011177     0.011232
-------------------------------------------------------------
</pre>

こちらもスピードアップしています。

DDR5でも試してみたかったのですが、割高な上にそもそも品薄で買えなかったので、今回はDDR4対応マザーを買ってしまいました。ということで、それはまた次の機会に。どなたか買った人がいたら是非結果を教えて頂きたいです。

# まとめ

第12世代Core、Z690という新しいCPU,チップセットですが、FreeBSD 13.0-RELEASEのインストールは特に問題なくCPUも全てのコアを認識しました。また、性能的にも私が持っていた過去機種(第7世代Coreシリーズ)と比べると大きくアップです。
また、負荷をかけても安定しており、これから利用していく上でも特に不安はありません。

性能をフルに発揮できているかどうかは他のOSと比較できていないので分かりませんが、過去機種との比較では十分なパワーアップであり、個人的には満足いくものでした。

長くなったため色々説明端折ったところもあるので、不明な点があれば、お気軽にコメントどうぞ。