最近趣味や講義などで高性能計算に触れています。コンピューターの性能を最大限引き出して計算をさせるためにはキャッシュをうまく使うことが非常に重要です。例えば行列積の計算ではデータアクセスの順序を変えるとキャッシュヒット率が向上し、計算が数倍早くなります。また、キャッシュブロッキングという方法を用いるとさらに計算が早くなります。
こういったキャッシュを最大限利用した計算をするためにはキャッシュの大きさ、キャッシュラインの大きさなどを事前に知っておくことが必要です。ここではそれらを調べる方法を紹介します。
/sys/devices/system/cpu/cpu*/cache/index*
/sys/devices/system/cpu/cpu*/cache/index*
を見るとキャッシュの情報を見ることができます。ここで*
にはCPU番号とL1, L2, L3キャッシュのどれかを表す数字が入ります。
例えばCPU0のL1キャッシュの情報は/sys/devices/system/cpu/cpu0/cache/index1
に格納されています(私の環境ではindex0
も存在したのですが、中身はindex1
に入っているものと同一でした)。
ls
をしてみると以下のようなファイルがあります。
❯ ls /sys/devices/system/cpu/cpu0/cache/index1
coherency_line_size level physical_line_partition shared_cpu_map type ways_of_associativity
id number_of_sets shared_cpu_list size uevent
それぞれのファイルがキャッシュの情報を表す数値や文字列を格納しています。Linux Kernel Documentationを見ると以下のように対応しているようです。
Name | Description |
---|---|
coherency_line_size |
キャッシュラインの大きさ[B] |
level |
L1, L2, L3, L4, ...キャッシュのどれか |
number_of_sets |
Set Associative Cacheにおけるsetの数 |
physical_line_partition |
number of physical cache line per cache tag(?) |
shared_cpu_map |
キャッシュが共有されているCPUのリストを表すマスク |
shared_cpu_list |
キャッシュが共有されているCPUのリスト |
size |
キャッシュサイズ[KB] |
type |
キャッシュの種類 |
ways_of_associativity |
Set Associative Cacheにおけるwayの数 |
write_policy |
キャッシュへの書き込み方法の種類(自分の環境では存在しませんでした) |
例えばCPU0のL1キャッシュのキャッシュラインの大きさを調べるには以下のようにします。
❯ cat /sys/devices/system/cpu/cpu0/cache/index1/coherency_line_size
64
表にある通り、Set数や何Wayあるかといった情報も調べることができます。この方法がこのページで紹介しているものだと最も詳しくキャッシュの情報を調べることができます。
getconf
getconf
を利用するとキャッシュの大きさ, キャッシュラインの大きさ, wayの数などの情報を表示することができます。
❯ getconf -a | grep CACHE
LEVEL1_ICACHE_SIZE 32768
LEVEL1_ICACHE_ASSOC 8
LEVEL1_ICACHE_LINESIZE 64
LEVEL1_DCACHE_SIZE 32768
LEVEL1_DCACHE_ASSOC 8
LEVEL1_DCACHE_LINESIZE 64
LEVEL2_CACHE_SIZE 524288
LEVEL2_CACHE_ASSOC 8
LEVEL2_CACHE_LINESIZE 64
LEVEL3_CACHE_SIZE 33554432
LEVEL3_CACHE_ASSOC 0
LEVEL3_CACHE_LINESIZE 64
LEVEL4_CACHE_SIZE 0
LEVEL4_CACHE_ASSOC 0
LEVEL4_CACHE_LINESIZE 0
LEVEL1_ICACHE
はL1命令キャッシュ, LEVEL1_DCACHE
はL1データキャッシュ, LEVEL2_CACHE
はL2キャッシュに対応します。残りも同様です。
それぞれSIZE
, ASSOC
, LINESIZE
でキャッシュの大きさ、wayの数、キャッシュラインの大きさを表しています。サイズの大きさの単位はByteです。
この例だとL1データキャッシュは32KBの大きさを持ち、キャッシュラインの大きさは64Byte, way数は8であることが分かります。
ここでLEVEL3_CACHE_SIZE
は32MBとなっていますが、この値は上で見た/sys
を調べる方法や、後ほど紹介するlscpu
による方法の2倍になっていることが分かりました。バグなのか分かりませんがこの値を利用する際は注意したほうが良さそうです。
lscpu
lscpu
を利用するとキャッシュの大きさを調べることができます。
❯ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 48 bits physical, 48 bits virtual
CPU(s): 16
On-line CPU(s) list: 0-15
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 1
Vendor ID: AuthenticAMD
CPU family: 23
Model: 113
Model name: AMD Ryzen 7 3700X 8-Core Processor
Stepping: 0
CPU MHz: 3600.014
BogoMIPS: 7200.02
Hypervisor vendor: Microsoft
Virtualization type: full
L1d cache: 256 KiB
L1i cache: 256 KiB
L2 cache: 4 MiB
L3 cache: 16 MiB
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2: Mitigation; Full AMD retpoline, IBPB conditional, STIBP conditional, RSB filling
Vulnerability Srbds: Not affected
Vulnerability Tsx async abort: Not affected
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr
sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apici
d pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hype
rvisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext ss
bd ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_n
i xsaveopt xsavec xgetbv1 xsaves clzero xsaveerptr virt_ssbd arat umip rdpid
L1d cache
からL3 cache
までの部分にキャッシュの大きさが表示されています。L1が2つあるのはそれぞれ命令用キャッシュとデータ用キャッシュです。ここで表示されているキャッシュの大きさは各CPUコアごとの大きさではなく、全体の大きさであることに注意します。
キャッシュの大きさを調べるだけならこの方法が最も簡単だと思います。