instruction-bench (car 6)
あれ解説書いてなかったっけ…昔書いた気がするんだけど。
https://github.com/tanakamura/instruction-bench
命令毎のスループット、レイテンシを計測する。
AVX512f まで対応してます。
まあ他にもツールはあるのだけど、exe一個になってると楽かなと思って作った(という文章を昔に書いたはずだ)。
Linux なら make するだけでよい。Windows はもう長いこと試していないのでわからない。
Linux なら、rdtsc ではなく、perf_event インターフェースを使ってCPU_CLK_UNHALTED を取ってるので、省電力機能の影響受けないで計測できる。(ので、VMではないLinuxで計測するのをお勧めする)
その他、過去のバージョンで気になってた箇所 (例えば http://d.hatena.ne.jp/w_o/20130602#1370161374 で書いてるmulx2のレイテンシを埋められないとか) はほぼ解消してて、今はbench.cppに入っている命令で残課題は無いはず。
命令を追加したいときは、
GEN(Xmm, "xorps", (g->xorps(dst, src)), false, OT_FP32);
のように、GEN マクロに入れたい命令をつっこむとよい。
最初のXmmは使うレジスタの種類。pmovmskb のように、複数種類を取る命令は…どうしよう…特に考えてない。
次の文字列は結果表示用なのでなんでもいい。
次に命令を書く。これは中身はXbyakなので、Xbyakの書式にあわせて書く。
dst, src レジスタは、スループット計測する時は、別のレジスタが割り当てられる。レイテンシ計測する時は同じレジスタが割り当てられる。
次のfalseはアレなのでfalseで良いです。そのうち消します。(昔はxorpsで依存を切る場合はtrueにしてたけど、KNLでxorpsが重いので使わないようにした)
OT_FP32 はレジスタ消去時にxorps,xorpd,pxorを使うとかの変化がある。あんまり影響ないので気にしなくていいです。
メモリアクセスのように、レイテンシ計測用に依存を作るコードを入れたい場合は、GEN_latency を使う。
GEN_latency(Xmm, "loadps", (g->movaps(dst, g->ptr[g->rdx])), // スループット (g->movaps(dst, g->ptr[g->rdx + g->rdi])); (g->movq(g->rdi, dst)); , // レイテンシ false, OT_INT);
rdxレジスタは、2MBアラインされてるゼロ初期化されたメモリを指すので、メモリを使いたい場合はこれを使う。
rdiレジスタは一時レジスタとして空いてるので好きなように使っていい。上のだと、依存を作るのに使っている。(rdx の指すメモリはゼロ初期化されているので、rdi は必ずゼロになる。ポインタを変えないで、ロード命令の間に依存を作っている)
いくつか結果を取ってるので観賞用に
https://github.com/tanakamura/instruction-bench/blob/master/hsw.log Haswell
https://github.com/tanakamura/instruction-bench/blob/master/bdw.log Broadwell
https://github.com/tanakamura/instruction-bench/blob/master/skl.log Skylake
https://github.com/tanakamura/instruction-bench/blob/master/knl.log Knights Landing
https://github.com/tanakamura/instruction-bench/blob/master/glm.log Goldmont