現在時刻の取得
プログラムを実行する上で、現在時刻を取得する処理が実行されることは少なくありません。意識的に実行していなくても、ロギング、乱数のシード生成、UUID の生成といった様々な用途で現在時刻が用いられていることがあります。
現在時刻の取得のオーバーヘッドを意識することは少ないかもしれませんが、Netfix 社の事例で CPU 使用率が 30% も改善したという事例が紹介されているぐらいですし、アプリケーションによっては実際にオーバーヘッドになる事例もありましたので、チューニングしておく価値があると思います。
TSC clocksource と Xen clocksource
ざっくりとした説明としては、それぞれ以下のような性質を持つ時刻の取得源です:
- TSC clocksource : ユーザーランドで特定の CPU レジスタから時刻を読み取る。Linux Kernel や Xen hypervisor の呼び出しを伴わないので速い
- Xen clocksource (Amazon Linux デフォルト): Kernel 経由で Xen の hypervisor から時刻を取得する。Kernel や hypervisor への切替を伴うので遅い。
詳細については記事末尾の参考記事などを参照ください。
なお、過去には TSC の利用は時刻がズレるため危険でしたが、2015 年時点ですでに TSC の利用は問題ない とされており、今では公式にも推奨されています。PV インスタンスで cat /proc/cpuinfo | grep constant_tsc
などとすることでも TSC サポートが見て取れますし、利用することには問題ないのではないのでしょうか。
clocksource=TSC に切り替える Ansible 例
clocksource は Linux の起動時のパラメタによって変更することができます。
OS 起動設定を変える方法を(筆者が)よく忘れがちなので、初代 Amazon Linux と Amazon Linux 2 での Ansible の例を下記に記しておきます:
Amazon Linux
初代 Amazon Linux は grub 1 なので、grub.conf の kernel
行に直接 clocksource=tsc
オプションを足します:
- name: Change kernel parameter
replace:
dest: /boot/grub/grub.conf
regexp: '^(kernel (?!.*clocksource=).*)$'
replace: '\1 clocksource=tsc'
Amazon Linux 2
Amazon Linux 2 は grub 2 なので grub.conf は grub2-mkconfig
で生成するのが正しいです。追加の設定は /etc/default/grub
(中身はシェルスクリプト) に記述します:
- name: Change kernel parameter
lineinfile:
dest: /etc/default/grub
state: present
regexp: "^GRUB_CMDLINE_LINUX="
line: "GRUB_CMDLINE_LINUX=\"clocksource=tsc\""
# 他にもオプションを渡したい場合は上記に追加するか、 GRUB_CMDLINE_LINUX=$GRUB_CMDLINE_LINUX clocksource=tsc などとする
register: grub_cmdline_linux
- name: update grub config
command: /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg
when: grub_cmdline_linux|changed
OS 稼働中に変更
一時的に動作を確認したい場合、OS 動作中に設定することもできます:
echo tsc > /sys/devices/system/clocksource/*/current_clocksource
clocksource の確認
以下のようにすることで確認できます:
$ cat /sys/devices/system/clocksource/*/current_clocksource
tsc
なお、利用可能な clocksource の一覧も確認できます:
$ cat /sys/devices/system/clocksource/*/available_clocksource
xen tsc hpet acpi_pm