UPDATE
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;
}
пс .: Я почти уверен, что ваш цикл не ограничен памятью. Хотя не могу быть уверен ... если "узлы", которые вы нам не показываете, действительно большие, это все равно может быть.
Оригинальный ответ:
Нет простого I_will_access_this_frequently_so_make_it_fast(void* ptr, size_t len)
-видного решения.
Вы можете сделать кое-что, хотя.
Убедитесь, что компилятор может «видеть» реализацию каждой функции, вызываемой внутри критических циклов. Что необходимо для того, чтобы компилятор мог «видеть» реализацию, зависит от компилятора. Однако есть один способ убедиться в этом: определить все соответствующие функции в одной и той же единице перевода перед циклом и объявить их как inline
.
Это также означает, что вы должны не каким-либо образом вызывать "внешние" функции в этих критических циклах. Под «внешними» функциями я подразумеваю такие вещи, как системные вызовы, материал библиотеки времени выполнения или материал, реализованный в DLL / SO. Также не вызывайте виртуальные функции и не используйте указатели на функции. И, конечно же, не выделяйте и не освобождайте память (внутри критических циклов).
Убедитесь, что вы используете оптимальный алгоритм. Линейная оптимизация является спорной, если сложность алгоритма выше, чем необходимо.
Используйте наименьшие возможные типы. Например. не используйте int
, если signed char
сделает работу. Это то, что я обычно не рекомендую, но при обработке большого объема памяти это может значительно увеличить производительность. Особенно в очень плотных петлях.
Если вы просто копируете или заполняете память, используйте memcpy
или memset
. Отключить внутреннюю версию этих двух функций, если порции больше, чем примерно от 50 до 100 байтов.
Убедитесь, что вы получаете доступ к данным в режиме кэширования. Оптимальным является «потоковая передача» - то есть доступ к памяти с восходящими или нисходящими адресами. Вы можете «прыгать» вперед на несколько байтов за раз, но не прыгайте слишком далеко. Худшее - это произвольный доступ к большому блоку памяти. Например. если вам нужно работать с двумерной матрицей (например, растровым изображением), где p [0] - p [1] - это шаг «вправо» (x + 1), убедитесь, что внутренний цикл увеличивает x, а внешний увеличивает у. Если вы сделаете это с другой стороны, производительность будет намного хуже.
Если ваши указатели не содержат псевдонимов, вы можете указать компилятору (как это будет зависеть от компилятора). Если вы не знаете, что означает отсутствие псевдонима, я рекомендую поискать в сети и документации вашего компилятора, так как объяснение выходит за рамки.
При необходимости используйте внутренние инструкции SIMD.
Используйте явные инструкции предварительной выборки, если вы знаете, какие ячейки памяти понадобятся в ближайшем будущем.