私は3つのメモリブロックを持っています。
char block_a[1600]; // Initialized with random chars
unsigned short block_b[1600]; // Initialized with random shorts 0 - 1599 with no duplication
char block_c[1600]; // Initialized with 0
これに対して次のコピー操作を実行しています
for ( int i = 0; i < 1600; i++ ) {
memcpy(block_c[i], block_a[block_b[i]], sizeof(block_a[0]); // Point # 1
}
今、ポイント 1 で行っている上記の操作の NS で CPU サイクル + 時間を測定しようとしています。
測定環境1) プラットフォーム: インテル x86-64。コア i7
2) Linux カーネル 3.8
0) 完全な制御と正確なデータを取得できるように、実装はカーネル モジュールとして行われます。
1) シリアル化に使用する CPUID + MOV 命令のオーバーヘッドを測定しました。
2) プリエンプション + 割り込みを無効にして、CPU の排他的アクセスを取得する
3) CPUID を呼び出して、パイプラインがこの時点までの順不同の命令をクリアしていることを確認する
4) RDTSC を呼び出して、TSC の初期値を取得し、この値を保存する
5) 実行される上で述べた測定したい操作
6) RDTSCP を呼び出して TSC の終了値を取得し、この値を保存した
7) 再度 CPUID を呼び出して、2 つの RDTSC 呼び出し内に順不同で何も入っていないことを確認した
8) 開始 TSC 値から終了 TSC 値を引いて、この操作を実行するのにかかる CPU サイクルを取得します。
9) 2 つの MOVE 命令によってかかるオーバーヘッド サイクルを減算して、最終 CPU サイクルを取得します。
....
....
preempt_disable(); /* Disable preemption to avoid scheduling */
raw_local_irq_save(flags); /* Disable the hard interrupts */
/* CPU is ours now */
__asm__ volatile (
"CPUID\n\t"
"RDTSC\n\t"
"MOV %%EDX, %0\n\t"
"MOV %%EAX, %1\n\t": "=r" (cycles_high_start), "=r" (cycles_low_start)::
"%rax", "%rbx", "%rcx", "%rdx"
);
/*
Measuring Point Start
*/
memcpy(&shuffled_byte_array[idx], &random_byte_array[random_byte_seed[idx]], sizeof(random_byte_array[0]));
/*
* Measuring Point End
*/
__asm__ volatile (
"RDTSCP\n\t"
"MOV %%EDX, %0\n\t"
"MOV %%EAX, %1\n\t"
"CPUID\n\t": "=r" (cycles_high_end), "=r" (cycles_low_end)::
"%rax", "%rbx", "%rcx", "%rdx"
);
/* Release CPU */
raw_local_irq_restore(flags);
preempt_enable();
start = ( ((uint64_t)cycles_high_start << 32) | cycles_low_start);
end = ( ((uint64_t)cycles_high_end << 32) | cycles_low_end);
if ( (end-start) >= overhead_cycles ) {
total = ( (end-start) - overhead_cycles);
} else {
// We will consdider last total
}
質問
私が取得している CPU サイクルの測定値は現実的ではないようです。いくつかのサンプルの結果が与えられています
Cycles Time(NS)
0006 0005
0006 0005
0006 0005
0006 0005
0006 0005
0011 0009
0006 0005
0006 0005
0006 0005
0006 0005
0006 0005
0011 0009
0011 0009
0000 0000
0011 0009
0006 0005
0006 0005
0006 0005
0011 0009
0006 0005
0000 0000
0011 0009
0011 0009
0006 0005
0006 0005
0006 0005
0006 0005
0006 0005
0011 0009
0006 0005
0011 0009
0011 0009
0011 0009
0011 0009
0006 0005
0006 0005
0006 0005
0006 0005
0011 0009
0011 0009
0011 0009
モジュールを再度ロードすると、結果が得られます。
Cycles Time(NS)
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0006 0005
0006 0005
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0011 0009
0011 0009
0011 0009
0011 0009
0011 0009
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0000 0000
0017 0014
0011 0009
0011 0009
0000 0000
0000 0000
0000 0000
0011 0009
0000 0000
0000 0000
0011 0009
0011 0009
0011 0009
0000 0000
0022 0018
0006 0005
0011 0009
0006 0005
0006 0005
0104 0086
0104 0086
0011 0009
0011 0009
0011 0009
0006 0005
0006 0005
0017 0014
0017 0014
0022 0018
0022 0018
0022 0018
0017 0014
0011 0009
0022 0018
0011 0009
0006 0005
0011 0009
0006 0005
0006 0005
0006 0005
0011 0009
0011 0009
0011 0009
0011 0009
0011 0009
0006 0005
0006 0005
0011 0009
0006 0005
0022 0018
0011 0009
0028 0023
0006 0005
0006 0005
0022 0018
0006 0005
0022 0018
0006 0005
0011 0009
0006 0005
0011 0009
0006 0005
0000 0000
0006 0005
0017 0014
0011 0009
0022 0018
0000 0000
0011 0009
0006 0005
0011 0009
0022 0018
0006 0005
0022 0018
0011 0009
0022 0018
0022 0018
0011 0009
0006 0005
0011 0009
0011 0009
0006 0005
0011 0009
0126 0105
0006 0005
0022 0018
0000 0000
0022 0018
0006 0005
0017 0014
0011 0009
0022 0018
0011 0009
0006 0005
0006 0005
0011 0009
上記のリストでは、CPU サイクルが 0 であるコピー操作が多数あることがわかります。多くの場合、3 サイクル未満です。
memcpy 操作で CPU サイクルが 0 または非常に少ない理由は何だと思いますか? 一般的に memcpy が使用する CPU サイクルの量。
アップデート以下の変更を試してみた結果が得られ
まし
た
。コードはすでにシングル コアでのみ実行されていますが、念のため)、結果に
影響はありませんCPU が最大周波数で動作するようにします。