web-dev-qa-db-ja.com

LinuxのCPUキャッシュをCプログラムからフラッシュする方法は?

私は自分の記憶をフラッシュする必要があるCプログラムを書いています。 CPUキャッシュをフラッシュするUNIXシステムコマンドがあるかどうか知りたいのですが。

これは私のプロジェクトの要件であり、ロジックにかかる時間を計算する必要があります。

cacheflush(char *s, int a, int b)関数について読みましたが、それが適切かどうか、およびパラメーターに何を渡すかについてはわかりません。

9
Rose BEck
  1. メモリキャッシュではなく、「CPUキャッシュ」を意味していると思います

  2. 上記のリンクは良いです:「CPUを介して大量のデータを書き込む」という提案はnotWindows固有です

  3. 同じテーマの別のバリエーションは次のとおりです。

  4. LinuxとCPUキャッシュに関する記事は次のとおりです。

注意:

この(非常に、非常に低い)レベルでは、 "Linux"!= "Unix"

9
paulsm4

ユーザーモード(カーネルモードではない)プログラムを作成していて、それがシングルスレッドの場合、そもそもキャッシュをフラッシュする必要はありません。ユーザーモードプログラムは、それが存在することさえ忘れることができます。プログラムの実行を高速化するためだけにあり、OSはプロセッサのMMUを介してプログラムを管理します。

ユーザーモードアプリケーションから実際にキャッシュをフラッシュしたいと思う理由は2つだけです。

  1. アプリは対称型マルチプロセッサシステムで実行することを目的としているか、外部ハードウェアとのデータトランザクションがあります)
  2. ある種のパフォーマンステストのためにキャッシュをテストしているだけです(この場合、おそらくドライバーとして、カーネルモードで動作するようにテストを作成する必要があります)。

いずれにせよ、Linuxを使用していると仮定すると...

#include <asm/cachectl.h>

int cacheflush(char *addr, int nbytes, int cache);

これは、書き込んだばかりのメモリブロックがあり、それがキャッシュからメインメモリにフラッシュされていることを確認する必要があることを前提としています。ブロックはaddrで始まり、長さはnバイトで、2つのキャッシュのいずれか(または両方)にあります。

   ICACHE Flush the instruction cache.
   DCACHE Write back to memory and invalidate the affected valid cache lines.
   BCACHE Same as (ICACHE|DCACHE).

データを「メモリ」(つまりキャッシュ)に書き込む場合、通常はデータであり、命令ではないため、通常はDCACHEをフラッシュするだけで済みます。

奇妙なテスト上の理由で「すべてのキャッシュ」をフラッシュしたい場合は、CPUのキャッシュよりも大きいことがわかっている大きなブロックをmalloc()して(シュート、8倍の大きさにしてください!)、古いガベージを書き込むことができます。その中に、そのブロック全体をフラッシュするだけです。

参照: C++でキャッシュ操作を実行する方法?

4
phonetagger

これは、Intelがキャッシュのフラッシュを提案する方法です。

mem_flush(const void *p, unsigned int allocation_size){
    const size_t cache_line = 64;
    const char *cp = (const char *)p;
    size_t i = 0;

    if (p == NULL || allocation_size <= 0)
            return;

    for (i = 0; i < allocation_size; i += cache_line) {
            asm volatile("clflush (%0)\n\t"
                         : 
                         : "r"(&cp[i])
                         : "memory");
    }

    asm volatile("sfence\n\t"
                 :
                 :
                 : "memory");
}
2
user7940320

OK、最初の答えでごめんなさい。後で質問の下のフォローアップコメントを読んだので、INSTRUCTION CACHEをフラッシュしてプログラム(またはその一部)をキャッシュから起動し、パフォーマンスをテストするときにもテストする必要があることに気付きました。メインメモリから命令キャッシュへの初期ロード時間。また、データとコードの両方が新しいロードになるように、コードが使用するデータをメインメモリにフラッシュする必要がありますか?

何よりもまず、メインメモリ自体もキャッシュの形式であり、ハードディスク(ディスク上のプログラムまたはディスク上のスワップスペース)が最も低く、プログラムの指示が来る可能性のある最も遅い場所であることを述べておきます。から。とは言うものの、ルーチンを初めて実行するときに、すでに実行されている他のコードの近くにあるためにディスクからメインメモリにまだロードされていない場合は、最初にそのCPU命令をロードする必要がありますディスクから。これには、メインメモリからキャッシュにロードするよりも1桁以上時間がかかります。次に、メインメモリにロードされると、キャッシュからCPUの命令フェッチャーにロードするよりも、メインメモリからキャッシュにロードするのに1桁長い時間がかかります。したがって、コードのコールドスタートのパフォーマンスをテストする場合は、コールドスタートの意味を決定する必要があります。ディスクからコードを引き出すか、メインメモリからコードを引き出すかです。命令/データをメインメモリから「フラッシュ」してスペースをスワップするコマンドを知らないので、メインメモリにフラッシュすることは(私が知っている)できる限りのことですが、覚えておいてください命令キャッシュをフラッシュしたとしても、テスト結果は最初の実行(ディスクからプルしている可能性がある場合)と後続の実行で異なる可能性があることに注意してください。

では、命令キャッシュをフラッシュして、独自のコードがメインメモリに確実にフラッシュされるようにするにはどうすればよいでしょうか。

これを行う必要がある場合(私の意見では非常に奇妙なことです)、おそらくメモリ内の関数の長さとおおよその配置を見つけることから始めます。 Linuxを使用しているので、コマンド「objdump -d {myprogram}> myprogram.dump.txt」を発行し、エディターでmyprogram.dump.txtを開いて、フラッシュする関数を検索します。 16進計算機を使用して、開始アドレスから終了アドレスを減算することにより、それらの長さを計算します。それぞれのサイズを書き留めておきます。後で、コードにcacheflush()呼び出しを追加して、フラッシュする各関数のアドレスを「addr」、見つけた長さを「nbytes」として指定し、ICACHEを指定します。安全のために、コードにいくつかの調整を加えてnバイトを調整するのを忘れた場合に備えて、おそらく少しファッジしてサイズに約10%を追加します。フラッシュしたい関数ごとに、このようにcacheflush()を呼び出します。次に、データもフラッシュする必要がある場合、グローバル/静的データを使用している場合は、それらもフラッシュできます(DCACHE)が、スタックまたはヒープデータの場合、フラッシュするために実行できる(または実行すべき)現実的なことは何もありません。キャッシュからそれ。そうしようとすると、通常の実行では決してまたは非常にまれにしか存在しない状態が作成されるため、愚かな演習になります。 Linuxを使用していると仮定すると...

#include <asm/cachectl.h>

int cacheflush(char *addr, int nbytes, int cache);

...where cache is one of:
   ICACHE Flush the instruction cache.
   DCACHE Write back to memory and invalidate the affected valid cache lines.
   BCACHE Same as (ICACHE|DCACHE).

ところで、これはクラスの宿題ですか?

2
phonetagger