38

学校の課題として、構成ファイルを読み取ったり、API 呼び出しを使用したりせずに、L1 データ キャッシュ ラインのサイズを取得する方法を見つける必要があります。メモリアクセスの読み取り/書き込みタイミングを使用して、この情報を分析および取得することを想定しています。では、どうすればそれを行うことができますか?

割り当ての別の部分の不完全な試みで、キャッシュのレベルとサイズを見つけるために、私は持っています:

for (i = 0; i < steps; i++) {
    arr[(i * 4) & lengthMod]++;
}

2行目を変更する必要があるのではないかと考えていました(i * 4)か?キャッシュ ラインのサイズを超えたら、それを交換する必要があるかもしれませんが、それには時間がかかりますか? しかし、それはとても簡単ですか?必要なブロックが既にどこかのメモリにある可能性がありますか? stepsまたは、十分な大きさの があれば、それはまだかなり正確に機能するという事実に頼ることができますか?

アップデート

GitHubでのHeresの試み ...以下の主要部分

// repeatedly access/modify data, varying the STRIDE
for (int s = 4; s <= MAX_STRIDE/sizeof(int); s*=2) {
    start = wall_clock_time();
    for (unsigned int k = 0; k < REPS; k++) {
        data[(k * s) & lengthMod]++;
    }
    end = wall_clock_time();
    timeTaken = ((float)(end - start))/1000000000;
    printf("%d, %1.2f \n", s * sizeof(int), timeTaken);
}

問題は、タイミングの間に大きな違いがないように見えることです。ご参考までに。L1キャッシュ用なので。私は SIZE = 32 K (配列のサイズ) を持っています

4

8 に答える 8

29

BIGchar配列を割り当てます (大きすぎて L1またはL2 キャッシュに収まらないことを確認してください)。ランダムなデータで埋めます。

配列をnバイト単位で歩き始めます。それらを合計するなど、取得したバイトで何かを行います。

n1 から始まり 1000 程度まで数えて、さまざまな の値で処理できる 1 秒あたりのバイト数をベンチマークして計算します。ベンチマークが計算された合計を出力することを確認してください。これにより、コンパイラがベンチマークされたコードを最適化できなくなる可能性があります。

n== キャッシュ ライン サイズの場合、アクセスごとに新しいラインを L1 キャッシュに読み込む必要があります。そのため、ベンチマークの結果は、その時点で急激に遅くなるはずです。

配列が十分に大きい場合、最後に到達するまでに、配列の先頭にあるデータは既にキャッシュから削除されています。これは、必要なことです。したがって、インクリメントnして再度開始した後、必要なデータが既にキャッシュにあることによって結果が影響を受けることはありません。

于 2012-10-01T14:54:11.937 に答える
6

すべての作品は著作権で保護されていますが、ソースコード自由に利用できます。ドキュメントのアイデアから、キャッシュ ライン サイズを計算することは、ここで既に述べたことよりもはるかに教育されているように思えます。

キャリブレーター ツールの根底にある考え方は、パフォーマンスが発生するキャッシュ ミスの頻度のみに依存するマイクロ ベンチマークを使用することです。キャリブレータは単純な C プログラムであり、主に 100 万回のメモリ読み取りを実行する小さなループです。ストライド (つまり、後続の 2 つのメモリ アクセス間のオフセット) とメモリ領域のサイズを変更することで、キャッシュ ミス率を変化させます。

原則として、キャッシュミスの発生は配列サイズによって決まります。L1 キャッシュに収まる配列サイズでは、データがキャッシュに読み込まれると、キャッシュ ミスは発生しません。同様に、L1 キャッシュ サイズを超えても L2 に収まる配列は、L1 ミスを引き起こしますが、L2 ミスは発生しません。最後に、L2 より大きい配列は、L1 ミスと L2 ミスの両方を引き起こします。

キャッシュ ミスの頻度は、アクセス ストライドとキャッシュ ライン サイズによって異なります。ストライドがキャッシュ ライン サイズ以上の場合、反復ごとにキャッシュ ミスが発生します。ストライドがキャッシュ ライン サイズよりも小さい場合、キャッシュ ミスは (平均で) n 回の反復ごとに発生します。ここで、n はキャッシュ ライン サイズ/ストライドの比率です。

したがって、ミスのない実行時間と、反復ごとに正確に 1 つのミスがある実行時間とを比較することで、キャッシュ ミスのレイテンシを計算できます。このアプローチは、メモリ アクセスが純粋にシーケンシャルに実行される場合にのみ機能します。つまり、2 つ以上のロード命令も、メモリ アクセスと純粋な CPU 作業も重複しないようにする必要があります。これを実現するために、単純なポインター追跡メカニズムを使用します。アクセスするメモリ領域は、各ロードが次の反復で後続のロードのアドレスを返すように初期化されます。したがって、スーパースカラー CPU は、投機的実行によってメモリ アクセス レイテンシを隠す機能の恩恵を受けることはできません。

キャッシュの特性を測定するために、ストライドと配列サイズを変えて実験を数回実行します。ストライドが少なくとも 4 バイトから予想される最大キャッシュ ライン サイズの 2 倍の間で変動し、配列サイズが最小予想キャッシュ サイズの半分から最大予想キャッシュ サイズの少なくとも 10 倍まで変動することを確認します。

コンパイルするにはコメントアウトする#include "math.h"必要がありました。その後、ラップトップのキャッシュ値が正しく検出されました。生成された PostScript ファイルも表示できませんでした。

于 2012-10-11T20:00:58.663 に答える
3

この関数はアセンブラーで使用できますが、CPUID移植性はありませんが、必要なものが得られます。

Intel マイクロプロセッサの場合、キャッシュ ライン サイズは、cpuid 関数 0x1 を呼び出した後に bh に 8 を掛けることで計算できます。

AMD マイクロプロセッサの場合、cpuid 関数 0x80000005 を呼び出した後のデータ キャッシュ ライン サイズは cl であり、命令キャッシュ ライン サイズは dl です。

私はこの記事からこれを取りました

于 2012-10-11T11:40:10.293 に答える
2

現代のプロセスはハードウェアのプリフェッチを行うため、配列を直接ではなくランダムな順序でウォークスルーするプログラムを作成する必要があると思います。たとえば、値が次のセルの番号になる int の配列を作成します。私は 1 年前に同様のプログラムを行いましたhttp://pastebin.com/9mFScs9Z 英語で申し訳ありませんが、私はネイティブ スピーカーではありません。

于 2012-10-07T17:30:31.007 に答える
1

泥にはまって抜け出せない方はこちらをご覧ください。

あなたが求めていることを行う方法を説明するマニュアルとコードがあります。コードもかなり高品質です。「サブルーチンライブラリ」を見てください。

コードとマニュアルは X86 プロセッサに基づいています。

于 2012-10-02T09:32:55.303 に答える
1

memtest86 の実装方法を参照してください。何らかの方法でデータ転送速度を測定および分析します。レート変更のポイントは、L1、L2、および可能な L3 キャッシュ サイズのサイズに対応しています。

于 2012-10-01T15:04:22.943 に答える
0

ある程度のメモリを使用する操作の時間を計るには十分だと思います。次に、操作で使用されるメモリ (オペランドなど) を徐々に増やします。動作パフォーマンスが著しく低下すると、限界が見つかりました。

大量のバイトを印刷せずに読み取るだけで済みます (印刷するとパフォーマンスが大幅に低下し、ボトルネックになる可能性があります)。読み取り中、タイミングは、データが L1 に収まらなくなるまで、読み取られたバイトの量に正比例する必要があります。そうすると、パフォーマンスが低下します。

また、プログラムの開始時と時間のカウントを開始する前に、メモリを 1 回割り当てる必要があります。

于 2012-10-01T14:25:58.633 に答える