アップデート
vector< set<uint> > vec(node_vec.size());
for(uint i = 0; i < node_vec.size(); i++)
for(uint j = i+1; j < node_vec.size(); j++)
// some computation, basic math, store the result in variable x
if( x > threshold ) {
vec[i].insert(j);
vec[j].insert(i);
}
条件が真になる頻度がわからないため、それでもあまり表示されませんx > threshold
。x > threshold
が非常に頻繁に当てはまる場合は、挿入するstd::set
たびに動的メモリ割り当てを実行する必要があるため、ボトルネックになる可能性がありuint
ます。
また、「何らかの計算」が実際に何を意味するのか/実行するのか/であるのかはわかりません。それが多くのことをする場合、またはそれがボトルネックになる可能性がある間違った方法で行う場合。
また、結果にアクセスする方法がわかりません。
とにかく、勘で:
vector<pair<int, int> > vec1;
vector<pair<int, int> > vec2;
for (uint i = 0; i < node_vec.size(); i++)
{
for (uint j = i+1; j < node_vec.size(); j++)
{
// some computation, basic math, store the result in variable x
if (x > threshold)
{
vec1.push_back(make_pair(i, j));
vec2.push_back(make_pair(j, i));
}
}
}
その形式で結果を使用できる場合は、これで完了です。それ以外の場合は、後処理を行うことができます。std::set
もう一度(明らかに)コピーしないでください。に固執してみてくださいstd::vector<POD>
。たとえば、次のようにベクトルにインデックスを作成できます。
// ...
vector<int> index1 = build_index(node_vec.size(), vec1);
vector<int> index2 = build_index(node_vec.size(), vec2);
// ...
}
vector<int> build_index(size_t count, vector<pair<int, int> > const& vec)
{
vector<int> index(count, -1);
size_t i = vec.size();
do
{
i--;
assert(vec[i].first >= 0);
assert(vec[i].first < count);
index[vec[i].first] = i;
}
while (i != 0);
return index;
}
ps.:あなたのループはメモリに縛られていないとほぼ確信しています。確かではありません...あなたが私たちに見せていない「ノード」が本当に大きい場合、それはまだ大きいかもしれません。
元の答え:
簡単なI_will_access_this_frequently_so_make_it_fast(void* ptr, size_t len)
解決策はありません。
しかし、あなたはいくつかのことをすることができます。
コンパイラがクリティカルループ内で呼び出されるすべての関数の実装を「認識」できることを確認してください。コンパイラーが実装を「見る」ことができるために必要なものは、コンパイラーによって異なります。ただし、確実にする方法が1つあります。ループの前に、関連するすべての関数を同じ変換単位で定義し、それらをとして宣言しますinline
。
これは、これらの重要なループで「外部」関数を呼び出さないようにする必要があることも意味します。また、「外部」関数とは、システムコール、ランタイムライブラリ、DLL/SOに実装されたものなどを意味します。また、仮想関数を呼び出さないでください。また、関数ポインターを使用しないでください。そしてもちろん、(クリティカルループ内で)メモリを割り当てたり解放したりしないでください。
最適なアルゴリズムを使用していることを確認してください。アルゴリズムの複雑さが必要以上に高い場合、線形最適化は重要ではありません。
可能な限り最小のタイプを使用してください。たとえば、仕事をするint
場合は使用しないでください。signed char
これは通常はお勧めしませんが、大量のメモリを処理する場合は、パフォーマンスが大幅に向上する可能性があります。特に非常にタイトなループで。
メモリをコピーまたはいっぱいにするだけの場合は、またはを使用しmemcpy
ますmemset
。チャンクが約50〜100バイトより大きい場合は、これら2つの関数の組み込みバージョンを無効にします。
キャッシュに適した方法でデータにアクセスするようにしてください。最適なのは「ストリーミング」です。つまり、昇順または降順のアドレスでメモリにアクセスします。一度に数バイト先に「ジャンプ」することはできますが、ジャンプしすぎないでください。最悪の事態は、メモリの大きなブロックへのランダムアクセスです。たとえば、p[0]からp[1]が「右へ」(x + 1)のステップである2次元マトリックス(ビットマップイメージなど)で作業する必要がある場合は、内側のループがxと外側の増分y。逆にすると、パフォーマンスが大幅に低下します。
ポインターにエイリアスがない場合は、コンパイラーに指示できます(これがどのように行われるかはコンパイラーによって異なります)。エイリアスフリーの意味がわからない場合は、説明が範囲を超えているため、ネットとコンパイラのドキュメントを検索することをお勧めします。
必要に応じて、組み込みのSIMD命令を使用します。
近い将来必要になるメモリ位置がわかっている場合は、明示的なプリフェッチ命令を使用してください。