L1 Cache Missのコストとは?
質問
編集 : 参考までに(もし誰かがこの問題に出くわしたら)、Igor Ostrovskyが書いた 偉大な投稿 を書きました。この記事では、いくつかの異なる問題について議論し、数値の例を示しています。 編集を終了する
いくつかのテストを行いました
<long story goes here>
を実行し、パフォーマンスの違いはメモリ キャッシュ ミスに起因するのかどうか疑問に思っています。 次のコードは、この問題を実証し、重要なタイミング部分まで煮詰めたものです。 次のコードには、ランダムな順序でメモリを訪問し、次にアドレスの昇順で訪問するループがいくつかあります。
XP マシン (VS2005: cl /O2 でコンパイル) と Linux ボックス (gcc -Os) でこれを実行しました。 どちらも同じような時間を生成しました。 これらの時間はミリ秒単位です。 私は、すべてのループが実行されており、最適化されていないと考えています (そうでなければ、「即座に」実行されるでしょう)。
*** 20000ノードでのテスト 総順序付け時間: 888.822899 総ランダム時間: 2155.846268
これらの数値は意味があるのでしょうか? この差は主に L1 キャッシュのミスによるものなのでしょうか、それとも何か他の要因があるのでしょうか? 20,000^2 回のメモリ アクセスがあり、そのすべてがキャッシュ ミスだった場合、ミスあたり約 3.2 ナノ秒になります。 テストしたXP(P4)マシンは3.2GHzで、L1キャッシュが32KB、L2が512KBと思われる(ただしわからない)。 20,000エントリ(80KB)なので、L2ミスはそれほど多くないと推測されます。 ということは、これは
(3.2*10^9 cycles/second) * 3.2*10^-9 seconds/miss) = 10.1 cycles/miss
. 私には高いように思えます。そうでないのかもしれないし、私の計算が悪いのかもしれません。 VTuneでキャッシュミスを計測してみたけど、BSODになっちゃった。 そして今、私はライセンスサーバーに接続させることができません (grrr)。
typedef struct stItem
{
long lData;
//char acPad[20];
} LIST_NODE;
#if defined( WIN32 )
void StartTimer( LONGLONG *pt1 )
{
QueryPerformanceCounter( (LARGE_INTEGER*)pt1 );
}
void StopTimer( LONGLONG t1, double *pdMS )
{
LONGLONG t2, llFreq;
QueryPerformanceCounter( (LARGE_INTEGER*)&t2 );
QueryPerformanceFrequency( (LARGE_INTEGER*)&llFreq );
*pdMS = ((double)( t2 - t1 ) / (double)llFreq) * 1000.0;
}
#else
// doesn't need 64-bit integer in this case
void StartTimer( LONGLONG *pt1 )
{
// Just use clock(), this test doesn't need higher resolution
*pt1 = clock();
}
void StopTimer( LONGLONG t1, double *pdMS )
{
LONGLONG t2 = clock();
*pdMS = (double)( t2 - t1 ) / ( CLOCKS_PER_SEC / 1000 );
}
#endif
long longrand()
{
#if defined( WIN32 )
// Stupid cheesy way to make sure it is not just a 16-bit rand value
return ( rand() << 16 ) | rand();
#else
return rand();
#endif
}
// get random value in the given range
int randint( int m, int n )
{
int ret = longrand() % ( n - m + 1 );
return ret + m;
}
// I think I got this out of Programming Pearls (Bentley).
void ShuffleArray
(
long *plShuffle, // (O) return array of "randomly" ordered integers
long lNumItems // (I) length of array
)
{
long i;
long j;
long t;
for ( i = 0; i < lNumItems; i++ )
plShuffle[i] = i;
for ( i = 0; i < lNumItems; i++ )
{
j = randint( i, lNumItems - 1 );
t = plShuffle[i];
plShuffle[i] = plShuffle[j];
plShuffle[j] = t;
}
}
int main( int argc, char* argv[] )
{
long *plDataValues;
LIST_NODE *pstNodes;
long lNumItems = 20000;
long i, j;
LONGLONG t1; // for timing
double dms;
if ( argc > 1 && atoi(argv[1]) > 0 )
lNumItems = atoi( argv[1] );
printf( "\n\n*** Testing %u nodes\n", lNumItems );
srand( (unsigned int)time( 0 ));
// allocate the nodes as one single chunk of memory
pstNodes = (LIST_NODE*)malloc( lNumItems * sizeof( LIST_NODE ));
assert( pstNodes != NULL );
// Create an array that gives the access order for the nodes
plDataValues = (long*)malloc( lNumItems * sizeof( long ));
assert( plDataValues != NULL );
// Access the data in order
for ( i = 0; i < lNumItems; i++ )
plDataValues[i] = i;
StartTimer( &t1 );
// Loop through and access the memory a bunch of times
for ( j = 0; j < lNumItems; j++ )
{
for ( i = 0; i < lNumItems; i++ )
{
pstNodes[plDataValues[i]].lData = i * j;
}
}
StopTimer( t1, &dms );
printf( "Total Ordered Time: %f\n", dms );
// now access the array positions in a "random" order
ShuffleArray( plDataValues, lNumItems );
StartTimer( &t1 );
for ( j = 0; j < lNumItems; j++ )
{
for ( i = 0; i < lNumItems; i++ )
{
pstNodes[plDataValues[i]].lData = i * j;
}
}
StopTimer( t1, &dms );
printf( "Total Random Time: %f\n", dms );
}
どのように解決するのですか?
この数字が意味を持つかどうかについての答えは出せませんが (私はキャッシュ レイテンシに詳しくはありませんが、L1 キャッシュ ミスが約 10 サイクルという記録は正しいようです)、次のようなことを提案することができます。 キャッシュグラインド を提供して、2 つのテスト間のキャッシュ パフォーマンスの違いを実際に確認するのに役立ちます。
CachegrindはValgrindツール(いつも素敵なmemcheckを動かすフレームワーク)であり、キャッシュとブランチのヒット/ミスをプロファイル化するものです。これは、プログラムで実際に得ているキャッシュ ヒット/ミスの数のアイデアを提供します。
関連
-
[解決済み] ソケットアクセプト - "開かれているファイルが多すぎる"
-
[解決済み] mallocの結果はキャストするのですか?
-
[解決済み] C言語では「?」演算子は何をするのですか?
-
[解決済み] C++でextern "C "を使用した場合の効果は?
-
[解決済み] C言語のコードで「:-!」とは何ですか?
-
[解決済み] ウェブサイト制作のためのChromeキャッシュの無効化
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み] キャッシュフレンドリーコードとは何ですか?
-
[解決済み] Cache-Control: max-age=0とno-cacheの違いは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
警告:代入がキャストなしで整数からポインタを作成する場合の修正方法に関する警告
-
エラー: 宣言されていない識別子 'bool' の使用と C コンパイラでの問題点
-
[解決済み] Valgrind が初期化されていないバイトについて警告する
-
[解決済み] ⑭と⑯は何のためにあるのですか?
-
[解決済み] Linux Socket write() によるBad File Descriptor C
-
[解決済み] CコードでEOFを表現する?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] なぜ16進数には0xがつくのですか?
-
[解決済み] フリーは、どのように無料化を知っているのですか?
-
[解決済み] C言語で "unsigned long "をprintfする方法は?