Knigts Landing とクロックダウンする石 part 2 (車 10)
昨日のまとめ
- KNL はサイクル当たり2個の命令を実行できると資料にはある
- 実際には1.69しか出ない
KNLのproduct briefによると、
http://www.intel.com/content/www/us/en/processors/xeon/xeon-phi-processor-product-brief.html
Frequency listed is nominal (non-AVX) TDP frequency. (略) For high-AVX instruction frequency, subtract 200 MHz
とあって、AVX負荷が高いと、1.3GHz から 200MHz 下がると書いてある。
今は、IPC=1.69 で、 1.69/2.0 = 0.845 ,クロックは 1.1/1.3 = 8.46 なので、200MHz 下がってるとすると計算は合う気がする。
が、これはおそらく現象を正しく表現していないように感じる。と、いうのは、今のLinuxでは、perf stat すると、実際に稼動したクロック数と、実時間から、プログラムが実際に動いたクロック数が取れるようになっているが、これで見てもクロックが下がっているようには見えない。
例えば、
#include <unistd.h> #include <signal.h> #include <stdlib.h> #define INSN() \ __asm__ __volatile__("vfmadd231ps %zmm0, %zmm0, %zmm0\n\t" \ "vfmadd231ps %zmm1, %zmm1, %zmm1\n\t" \ "vfmadd231ps %zmm2, %zmm2, %zmm2\n\t" \ "vfmadd231ps %zmm3, %zmm3, %zmm3\n\t" \ "vfmadd231ps %zmm4, %zmm4, %zmm4\n\t" \ "vfmadd231ps %zmm5, %zmm5, %zmm5\n\t" \ "vfmadd231ps %zmm6, %zmm6, %zmm6\n\t" \ "vfmadd231ps %zmm7, %zmm7, %zmm7\n\t" \ "vfmadd231ps %zmm8, %zmm8, %zmm8\n\t" \ "vfmadd231ps %zmm9, %zmm9, %zmm9\n\t" \ "vfmadd231ps %zmm10, %zmm10, %zmm10\n\t" \ "vfmadd231ps %zmm11, %zmm11, %zmm11\n\t"); int main() { signal(SIGALRM, exit); alarm(1); while(1) { INSN(); INSN(); INSN(); INSN(); INSN(); INSN(); INSN(); } }
こういうコードで perf stat とると、
$ perf stat ./a.out Performance counter stats for './a.out': 1001.998233 task-clock (msec) # 0.999 CPUs utilized 2 context-switches # 0.002 K/sec 0 cpu-migrations # 0.000 K/sec 117 page-faults # 0.117 K/sec 1,288,186,518 cycles # 1.286 GHz (50.06%) <not supported> stalled-cycles-frontend <not supported> stalled-cycles-backend 2,200,109,120 instructions # 1.71 insns per cycle (75.06%) 26,858,635 branches # 26.805 M/sec (75.02%) 51,857 branch-misses # 0.19% of all branches (74.96%) 1.002828425 seconds time elapsed
1.286 GHz とか出ている。
これは、CPU_CLK_UNHALTED の値から計算して出しているはず。CPU_CLK_UNHALTEDは、省電力機能によるクロック変動にあわせて変動するので、もしAVX-512に負荷をかけてクロックが下がるならば、これも下がって欲しいところだ。CPU_CLK_UNHALTEDが固定値だとしたら、rdtscとほぼ変わらないので、存在意義があやしくなる。
また、前世代のKNCでは、コア当たり最低2スレッド立てないとフル性能出ないという問題があったので、それと似た問題があるかもと思って試すものの、
#include <unistd.h> #include <signal.h> #include <stdlib.h> #include <omp.h> #define INSN() \ __asm__ __volatile__("vfmadd231ps %zmm0, %zmm0, %zmm0\n\t" \ "vfmadd231ps %zmm1, %zmm1, %zmm1\n\t" \ "vfmadd231ps %zmm2, %zmm2, %zmm2\n\t" \ "vfmadd231ps %zmm3, %zmm3, %zmm3\n\t" \ "vfmadd231ps %zmm4, %zmm4, %zmm4\n\t" \ "vfmadd231ps %zmm5, %zmm5, %zmm5\n\t" \ "vfmadd231ps %zmm6, %zmm6, %zmm6\n\t" \ "vfmadd231ps %zmm7, %zmm7, %zmm7\n\t" \ "vfmadd231ps %zmm8, %zmm8, %zmm8\n\t" \ "vfmadd231ps %zmm9, %zmm9, %zmm9\n\t" \ "vfmadd231ps %zmm10, %zmm10, %zmm10\n\t" \ "vfmadd231ps %zmm11, %zmm11, %zmm11\n\t"); int main() { signal(SIGALRM, exit); alarm(1); omp_set_num_threads(2); #pragma omp parallel for for (int i=0; i<2; i++) { while(1) { INSN(); INSN(); INSN(); INSN(); INSN(); INSN(); INSN(); } } }
$ numactl -C 0,64 perf stat ./a.out # 手元だと0と64が同じコアなので。 Performance counter stats for './a.out': 2003.569207 task-clock (msec) # 1.996 CPUs utilized 2 context-switches # 0.001 K/sec 1 cpu-migrations # 0.000 K/sec 190 page-faults # 0.095 K/sec 2,561,111,631 cycles # 1.278 GHz (50.04%) <not supported> stalled-cycles-frontend <not supported> stalled-cycles-backend 2,201,434,021 instructions # 0.86 insns per cycle (75.01%) 27,798,335 branches # 13.874 M/sec (75.02%) 171,238 branch-misses # 0.62% of all branches (74.99%) 1.003819386 seconds time elapsed
2スレッドで、IPC=0.86、 コア当たりは、1.72 しか出ていない。
なんかめんどくなってきたので結論を書くと、二個目のFPUだけクロックが落ちて動いているように見える。
Agner先生が Knights Landing のレイテンシ/スループット出してるけど、
http://agner.org/optimize/instruction_tables.pdf
FP0 でしか実行できないvplzcntd とかは、
#define INSN() \ __asm__ __volatile__("punpcklbw %xmm0, %xmm0\n\t" \ "punpcklbw %xmm1, %xmm1\n\t" \ "punpcklbw %xmm2, %xmm2\n\t" \ "punpcklbw %xmm3, %xmm3\n\t"); \
IPC 1.0 出る。
FP1 でしか実行できないkortestw … あれkortestw は asm で実行したらIPC 1.0 出るんだが…よくわからん…もういいや…(完)