7

問題があります.... while ループで配列にデータを書き込んでいます。そしてポイントは、私がそれを本当に頻繁にやっているということです。この書き込みがコードのボトルネックになっているようです。したがって、メモリへの書き込みが原因であると推測されます。この配列はそれほど大きくありません (300 要素程度)。問題は、キャッシュに保存し、while ループが終了した後にのみメモリに更新するという方法で実行できるかどうかです。

[編集 - アレックスが追加した回答からコピー]

double* array1  = new double[1000000]; // this array has elements  
unsigned long* array2  = unsigned long[300];
double varX,t,sum=0;
int iter=0,i=0;
while(i<=max_steps)
{
   varX+=difX;
   nm0 =  int(varX);
   if(nm1!=nm0)
   {
        array2[iter] = nm0;  // if you comment this string application works more then 2 times faster :)
        nm1=nm0;
        t = array1[nm0]; // if you comment this string , there is almost no change in time 
        ++iter;
   }
   sum+=t;
   ++i;
}

まず、回答をくださった皆様に感謝いたします。確かに、コードを配置しないのは少しばかげていました。だから私は今それをすることにしました。

double* array1  = new double[1000000]; // this array has elements  
unsigned long* array2  = unsigned long[300];
double varX,t,sum=0;
int iter=0,i=0;
while(i<=max_steps)
{
   varX+=difX;
   nm0 =  int(varX);
   if(nm1!=nm0)
   {
        array2[iter] = nm0;  // if you comment this string application works more then 2 times faster :)
        nm1=nm0;
        t = array1[nm0]; // if you comment this string , there is almost no change in time 
        ++iter;
   }
   sum+=t;
   ++i;
}

それだけでした。どなたかアイデアいただけると助かります。重ねてお礼申し上げます。

敬具 アレックス

4

12 に答える 12

12

意図的ではありません。とりわけ、キャッシュの大きさがわからないため、何が収まるかわかりません。さらに、アプリがキャッシュの一部をロックオフすることを許可された場合、OS への影響がシステム全体のパフォーマンスに壊滅的な影響を与える可能性があります。これは、「やるべきではないので、やることはできません。これまでに」という私のリストに真っ向から当てはまります。

できることは、参照の局所性を改善することです。要素に複数回アクセスしないようにループを調整し、メモリ内で順番にアクセスするようにしてください。

あなたのアプリケーションに関する手がかりがなければ、より具体的なアドバイスを与えることはできないと思います.

于 2009-10-06T14:22:41.737 に答える
8

CPU は通常、きめの細かいキャッシュ制御を提供しません。削除するものを選択したり、キャッシュに固定したりすることはできません。一部の CPU ではいくつかのキャッシュ操作があります。何ができるかについてのちょっとした情報: 新しい x86{-64} CPU での興味深いキャッシュ関連の手順を次に示します (このようなことを行うと、移植性が低下しますが、興味があるかもしれません)。

ソフトウェア データ プリフェクト

非テンポラル命令は prefetchnta で、データを 2 番目のレベルのキャッシュにフェッチし、キャッシュの汚染を最小限に抑えます。

一時的な指示は次のとおりです。

* prefetcht0 – fetches the data into all cache levels, that is, to the

Pentium® 4 プロセッサの二次キャッシュ。

* prefetcht1 – Identical to prefetcht0

* prefetcht2 – Identical to prefetcht0

さらに、メモリ内のデータにアクセスするための一連の命令がありますが、データをキャッシュに挿入しないようプロセッサに明示的に指示します。これらは非テンポラル命令と呼ばれます。その一例を次に示します: MOVNTI

残りが常にキャッシュに残ることを期待して、キャッシュに入れたくないすべてのデータに対して非一時的な命令を使用できます。キャッシュに関しては注意すべき微妙な動作があるため、これが実際にパフォーマンスを向上させるかどうかはわかりません。また、それを行うのは比較的苦痛であるように思えます。

于 2009-10-06T14:48:33.930 に答える
4

問題があります.... while ループで配列にデータを書き込んでいます。そしてポイントは、私がそれを本当に頻繁にやっているということです。この書き込みがコードのボトルネックになっているようです。したがって、メモリへの書き込みが原因であると推測されます。この配列はそれほど大きくありません (300 要素程度)。問題は、キャッシュに保存し、while ループが終了した後にのみメモリに更新するという方法で実行できるかどうかです。

その必要はありません。キャッシュからプッシュされる可能性がある唯一の理由は、他のデータをキャッシュに入れることがより緊急であると見なされた場合です。

これとは別に、300 個の要素の配列は問題なくキャッシュに収まるはずです (要素のサイズが狂っていないと仮定すると)。そのため、ほとんどの場合、データは既にキャッシュにあります。

いずれにせよ、最も効果的な解決策は、おそらくコードを微調整することです。配列への書き込み/読み取りを常に行うのではなく、(メモリ アドレスが重要ではないことをコンパイラに示すために) 多数の一時変数を使用します。ループの開始時にロードが 1 回実行されるようにコードを並べ替え、依存関係の連鎖を可能な限り分割します。

ループを手動で展開すると、これらのことをより柔軟に実現できます。

最後に、キャッシュの動作について推測するのではなく、使用する必要がある 2 つの明白なツールを示します。

  • プロファイラー、および利用可能な場合はキャッシュグラインド。優れたプロファイラーはキャッシュ ミスに関する多くの統計情報を提供し、cachegrind も多くの情報を提供します。
  • ここ StackOverflow にいます。ループ コードを投稿して、そのパフォーマンスをどのように改善できるかを尋ねると、多くの人が楽しい挑戦になると確信しています。

しかし、他の人が述べたように、パフォーマンスを扱うときは推測しないでください。直感や直感ではなく、確かなデータと測定値が必要です。

于 2009-10-06T17:25:07.457 に答える
3

コードが配列への書き込みの間にまったく異なることをしない限り、配列のほとんどはおそらくキャッシュに保持されます。

残念ながら、キャッシュを念頭に置いてアルゴリズムを書き直す以外に、キャッシュの内容に影響を与えるためにできることは何もありません。メモリへの書き込みの間にできるだけ少ないメモリを使用するようにしてください。多くの変数を使用せず、他の多くの関数を呼び出さず、配列の同じ領域に連続して書き込むようにしてください。

于 2009-10-06T14:23:13.550 に答える
2

この場合、array2非常に「ホット」になり、その理由だけでキャッシュに残ります。秘訣はarray1、キャッシュに入れないようにすることです (!)。一度しか読んでいないので、キャッシュしても意味がありません。そのためのSSE命令はMOVNTPD、組み込みですvoid_mm_stream_pd(double *destination, __m128i source)

于 2009-10-07T12:29:54.163 に答える
2

少なくとも高レベルのマルチタスク オペレーティング システムでは、これが可能であるとは思えません。プロセスがプリエンプトされず、CPU が失われないことを保証することはできません。プロセスがキャッシュを所有すると、他のプロセスはそれを使用できなくなり、実行が非常に遅くなり、事態が非常に複雑になります。1 つのアプリケーションが他のすべてのアプリケーションをロックアウトしたという理由だけで、最新の数 GHz プロセッサをキャッシュなしで実行したくはありません。

于 2009-10-06T14:21:33.503 に答える
1

できたとしても、それは悪い考えです。

最近のデスクトップ コンピューターは、マルチコア CPU を使用しています。Intel のチップはデスクトップ マシンで最も一般的なチップですが、Core プロセッサと Core 2 プロセッサはオンダイ キャッシュを共有していません。

つまり、オンダイ 8MB L3 キャッシュを共有する Core 2 i7 チップがリリースされるまで、キャッシュを共有しませんでした。

したがって、これを入力しているコンピューターのキャッシュでデータをロックできたとしても、このプロセスが同じコアでスケジュールされることを保証することさえできないため、キャッシュ ロックはまったく役に立たない可能性があります。

于 2009-10-06T14:32:56.510 に答える
1

書き込みが遅い場合は、他の CPU コアが同じメモリ領域に同時に書き込みを行っていないことを確認してください。

于 2009-10-06T14:33:38.520 に答える
1

パフォーマンスの問題が発生した場合は、何も仮定せず、最初に測定してください。たとえば、書き込みをコメントアウトして、パフォーマンスが異なるかどうかを確認します。

構造体の配列に書き込む場合は、構造体ポインターを使用して構造体のアドレスをキャッシュし、アクセスするたびに配列の乗算を行わないようにします。最大限に最適化するために、配列インデクサー変数にネイティブの語長を使用していることを確認してください。

于 2009-10-06T15:19:41.827 に答える
1

CoreBoot (以前の LinuxBIOS) の初期のブート フェーズでは、まだ RAM にアクセスできないため (BIOS コードについて話しているため、RAM はまだ初期化されていません)、Cache-as-RAM (つまり、実際の RAM に支えられていなくても、プロセッサーのキャッシュを RAM として使用します。

于 2011-02-01T18:12:39.113 に答える
1

他の人が言っているように、これを直接制御することはできませんが、コードを変更すると、間接的にキャッシュが改善される可能性があります。Linux で実行していて、プログラムの実行時に CPU キャッシュで何が起こっているかを詳しく知りたい場合は、 Valgrindスイートの一部である Cachegrind ツールを使用できます。これはプロセッサのシミュレーションなので、完全に現実的ではありませんが、他の方法では得られない情報を提供します。

于 2009-10-06T15:31:13.317 に答える
1

メモリの行をキャッシュにプリフェッチするために、何らかのアセンブリ コード、または 1 人が指摘したようにアセンブリ組み込み関数を使用することは可能かもしれませんが、それをいじるには多くの時間がかかります。

試しに、すべてのデータを (コンパイラが最適化して削除しないように) 読み込んでから、書き込みを実行してみてください。それが役立つかどうかを確認してください。

于 2009-10-06T14:36:06.300 に答える