CPUをRyzenに変えたらPPS同期のntpdのoffsetが急増した

# 現象
タイトルの通り、CPUをRyzenに変えたらPPS同期のntpdのoffsetが急増した。
しかも、数usから20ms以上に急増。
jitterも数usecから数百usecに。単位が違いすぎる。
何故。

#環境
## Ryzen移行前
- CPU: J3455
- OS: ArchLinux
    - `linux`カーネル
    - `intel_idle.max_cstate=1`でC Stateを制限済み[^1]
- 時刻源: GPS18x LVC[^2]
- ntpd: 4.2.8.p15
    - [`timepps.h`](https://github.com/redlab-i/pps-tools/blob/master/timepps.h)を設置してコンパイル済み
    - `ntpd -N`でhighest priority化済み[^1]
- ntpd Reference Clock Driver: [Type 20](http://doc.ntp.org/current-stable/drivers/driver20.html)
    - PPS使用

[^1]: 過去に書いた[こちらの記事](https://qiita.com/air-gh/items/28c5e1f8f678a0b24a8f)参照
[^2]: [こちら](https://qiita.com/air-gh/items/28c5e1f8f678a0b24a8f)によると、ファームウェアVer 4.40が2019年10月に出ていたりして、まだ現役

## Ryzen移行後
- CPU: Ryzen 5 PRO 3400GE
    - 流行りのM75q-1
- OS: ArchLiux
    - `linux-zen`カーネル
- 時刻源: GPS18x LVC[^2]
    - 移行前と同じ
- ntpd: 4.2.8.p15
    - 移行前と同じく、[`timepps.h`](https://github.com/redlab-i/pps-tools/blob/master/timepps.h)を設置してコンパイル済み
- ntpd Reference Clock Driver: [Type 20](http://doc.ntp.org/current-stable/drivers/driver20.html)
    - 移行前と同じく、PPS使用

# 実験
## `ntpd -N`でhighest priority化
結果は、あまり?変わらず。

## `fudge`の`time1`でPPSのoffsetを調整
[本家](http://doc.ntp.org/current-stable/drivers/driver20.html)によると、

> Specifies the PPS time offset calibration factor, in seconds and fraction, with default 0.0

とのこと。
結果は、`time 1`をいくら修正しても、offsetの値は変わらない。

ただ、実験の過程で、色々調べたところ、みなさん[^3]他のNTPサーバーでPPSのoffsetを較正していることが分かった。
実際、Type 20のoffsetが20msであっても、`time 1`を調整したら、他のNTPサーバーのoffsetは0に近づいた。
今まではPPSの精度を信じていたが、例えそうであっても、PPSがntpdに到着してカーネルの時刻に反映されるまでの遅延は、システム毎に異なる可能性を考慮すべきかも。

[^3]: [こちら](http://k-hiura.cocolog-nifty.com/blog/2017/11/gpsgpsppsntp-7b.html)や[こちら](https://kana.me/entry/ntpd-pps-discipline)

## C Stateの制限
とはいえ、`time 1`では、jitterは減らせなかった。
過去に書いた[こちらの記事](https://qiita.com/air-gh/items/28c5e1f8f678a0b24a8f)と同じことを、Ryzenでやるには、どうすれば。

### CPU idle driver
[本家](https://www.kernel.org/doc/html/latest/admin-guide/pm/cpuidle.html)によると、CPU idle driverには、`intel_idle`と`acpi_idle`の2種類があるらしい。
まずは、Ryzen移行後のM75q-1で、どちらが使われているか、見てみよう。

```shell-session
$ cat /sys/devices/system/cpu/cpuidle/current_driver
acpi_idle
```

ほーそうですか。そして、先ほどの[本家](https://www.kernel.org/doc/html/latest/admin-guide/pm/cpuidle.html)によると、

> (前略) there are parameters affecting individual CPUIdle drivers that can be passed to them via the kernel command line. Specifically, the intel_idle.max_cstate=<n> and processor.max_cstate=<n> parameters (中略) causes the intel_idle and acpi_idle drivers, respectively, to discard all of the idle states deeper than idle state <n>.

とある。`acpi_idle`には`processor.max_cstate=<n>`ということか。

### grubにカーネルパラメーターを設定
```:/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet processor.max_cstate=1"
```

```shell-session
sudo grub-mkconfig -o /boot/grub/grub.cfg
```

そして再起動。

# 結果
```shell-session
$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
oGPS_NMEA(0)     .GPS.            0 l   15   16  377    0.000   -0.001   0.001
```

![ntp_kernel_pll_off-day.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104225/7aa60098-8c63-c104-2dcd-2a93f9f018ad.png)

こうでなくっちゃ!

# 宿題

- 消費電力やCPU温度の変化は一体…
- Kernel discipline([Type 22](http://doc.ntp.org/current-stable/drivers/driver22.html))
- Stratum 1はRaspberry Piで作る時代でしょう
- PTPによる配布
    - M75q-1で動く`r8169`はPTP対応…してないか…
    - そもそもPTP対応スイッチ持ってなかった…