Как я могу оптимизировать большое количество операций копирования и доступа в моем числовом солвере?

Я работаю над небольшим кусочком кода, который итеративно переносит плотность от одного временного шага к другому, пока не будет достигнуто время назначения

Код, над которым я работаю, имеет следующую форму:

  1. инициализировать
  2. пинг-понг между двумя буферами сейчас и далее

    1. вычислить новый уровень уточнения для следующего
    2. для каждого значения вектора now некоторое количество добавляется к следующему.

Мой вопрос: есть ли общий шаблон, как ускорить такой кусок кода?

Дополнительный вопрос: могу ли я реализовать это лучше / лучше, используя алгоритмы stl?


std::vector<double> ping;
std::vector<double> pong;
ping.reserve(1000000);
pong.reserve(1000000);std::vector* now= &ping;
std::vector* next = &pong;

Initialize(now);  // Fill first timestep
for(size_t t = 0; t < 1000; t++)  // timesteps
{
size_t M = now->size();
size_t N = calcNewRefinement(t, now);
next->resize(N);
for(size_t i = 0; i < N; i++) // all elements
{
for(size_t j = 0; j < now->size(); j++)
{
if (j > 0 && j < N)
(*next)[i] += ExpensiveFunction((*now)[j-1], (*now)[j], (*now)[j+1], (*next)[i])
else if (j == 0)
(*next)[i] += ExpensiveFunction2((*now)[j], (*now)[j+1], (*next)[i])
else if (j == M-1)
(*next)[i] += ExpensiveFunction3((*now)[j-1], (*now)[j], (*next)[i])
}
}
vector<double> *intermediate = now;
now = next;
next = intermediate;
}

1

Решение

Общий совет по оптимизации должен сделать профилирование первый. Я предполагаю, что вы уже сделали это и обнаружили, что ваши «операции копирования и доступа» (как описано в вопросе) должны быть оптимизированы.

В этом случае позвольте мне отметить, что имя ExpensiveFunction вводит в заблуждение, потому что это не может быть дорогостоящим, когда несколько операций копирования и доступа так важны в вашем коде.

«Общая схема» для оптимизации: посмотрите на свой внутренний цикл, и попробуйте удалить ненужные операции.

В вашем случае у вас есть следующее:

  • for (...; j < now->size(); ...) — попробуйте заменить now->size() от M — есть хороший шанс, что ваш компилятор уже сделал это, но вы никогда не знаете …
  • if (j > 0 && < j < N) — вы можете полностью удалить эти проверки, если разделите свой цикл на 3 части (первая итерация; средние итерации; последняя итерация)
  • now[j-1], now[j], now[j+1] — некоторые реализации c ++ настаивают на проверке границ массива для каждого доступа (это не требуется для c ++); если у вас так, попробуйте отключить проверку или замените std::vector от std::array или (если это не помогает) массивом в стиле C
  • next[i] = ... — как указано выше
  • Вместо этого вы можете попробовать оптимизировать код в ваших дорогих функциях …
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]