Я провожу исследование для моего университета, связанное с алгоритмом реконструкции изображения для медицинского использования.
Я застрял в чем-то до 3 недель, мне нужно улучшить производительность следующего кода:
for (lor=lor0[mypid]; lor <= lor1[mypid]; lor++)
{
LOR_X = P.symmLOR[lor].x;
LOR_Y = P.symmLOR[lor].y;
LOR_XY = P.symmLOR[lor].xy;
lor_z = P.symmLOR[lor].z;
LOR_Z_X = P.symmLOR[lor_z].x;
LOR_Z_Y = P.symmLOR[lor_z].y;
LOR_Z_XY = P.symmLOR[lor_z].xy;
s0 = P.a2r[lor];
s1 = P.a2r[lor+1];
for (s=s0; s < s1; s++)
{
pixel = P.a2b[s];
v = P.a2p[s];
b[lor] += v * x[pixel];
p = P.symm_Xpixel[pixel];
b[LOR_X] += v * x[p];
p = P.symm_Ypixel[pixel];
b[LOR_Y] += v * x[p];
p = P.symm_XYpixel[pixel];
b[LOR_XY] += v * x[p];
// do Z symmetry.
pixel_z = P.symm_Zpixel[pixel];
b[lor_z] += v * x[pixel_z];
p = P.symm_Xpixel[pixel_z];
b[LOR_Z_X] += v * x[p];
p = P.symm_Ypixel[pixel_z];
b[LOR_Z_Y] += v * x[p];
p = P.symm_XYpixel[pixel_z];
b[LOR_Z_XY] += v * x[p];
}
}
для тех, кто хочет знать, в коде реализована функция пересылки MLEM , и все переменные FLOAT .
После нескольких тестов я заметил, что большая задержка была в этой части кода. (Вы знаете, правило 90 - 10).
Позже я использовал Papi (http://cl.cs.utk.edu/papi/) для измерения пропусков L1D-кэша. Как я и думал, Papi подтверждает, что производительность снижается из-за большого количества пропусков, особенно для произвольного доступа к вектору b (огромного размера).
Чтение информации в Интернете. Мне известны только два варианта повышения производительности: улучшение локальности данных или уменьшение загрязнения данных.
Чтобы сделать первое улучшение, я попытаюсь изменить код для поддержки кэширования, как это было предложено Ульрихом Дреппером на Что должен знать каждый программист о памяти (www.akkadia.org /drepper/cpumemory.pdf) A.1 Умножение матриц.
Я считаю, что блокирование SpMV (разреженного умножения матрицы на вектор) улучшит производительность.
С другой стороны, каждый раз, когда программа пыталась получить доступ к вектору b, мы имели то, что известно как загрязнение кэша .
Есть ли способ загрузить значение из вектора b с помощью SIMD-инструкции без использования кэша?
Также можно использовать функцию типа void _mm_stream_ps (float * p, __m128 a) для хранения ОДНОГО значения с плавающей запятой в векторе b без загрязнения кэша?
Я не могу использовать _mm_stream_ps, потому что всегда храню 4 числа с плавающей запятой, но доступ к вектору b явно случайный.
Я бы хотел быть ясным в моей дилемме.
Дополнительная информация: v - это значение столбца хранилища Sparse Matrix в формате CRS. Я понимаю, что можно было бы провести другую оптимизацию, если бы я попытался изменить формат CRS на другой, однако, как я уже говорил, я провел несколько тестов в течение нескольких месяцев, и я знаю, что снижение производительности связано со случайным доступом к вектору b. из 400.000.000 L1D Пропуски Я могу перейти к 100 ~ Пропуски, когда не сохраняю в векторе b.
Спасибо.