I ' Я провожу исследование для моего университета, связанное с алгоритмом реконструкции изображений для использования в медицине.
Я застрял в чем-то на 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. Как я и думал, Папи подтверждают, что производительность снижается из-за большего количества промахов, особенно для произвольного доступа к вектору b (огромного размера).
Читая информацию в Интернете, я знаю только два варианта повышения производительности: улучшить локальность данных или уменьшить загрязнение данных.
Чтобы сделать первое улучшение, я попытаюсь изменить код, чтобы он учитывал кэш, как это было предложено Ульрихом Дреппером в Что каждый программист должен знать о памяти (www.akkadia.org /drepper/cpumemory.pdf) A.1 Умножение матриц.
Я считаю, что блокирование SpMV (разреженное умножение матрицы на вектор) улучшит производительность.
С другой стороны, каждый раз, когда программа пыталась получить доступ к b, у нас было так называемое загрязнение кеша .
Есть ли способ загрузить значение из вектора b с помощью инструкции SIMD без использования кеша?
Кроме того, можно использовать такую функцию, как void _mm_stream_ps (float * p, __m128 a) для хранения ОДНО значение с плавающей запятой в векторе b, не загрязняя кеш?
Я могу ' t используйте _mm_stream_ps, потому что всегда храните 4 числа с плавающей запятой, но доступ к вектору b явно случайный.
Я надеюсь, что моя дилемма будет ясна.
Дополнительная информация: v - значение столбца в хранилище разреженной матрицы с Формат CRS. Я понимаю, что можно было бы выполнить другую оптимизацию, если бы я попытался изменить формат CRS на другой, однако, как я уже говорил, я провел несколько тестов в течение месяцев и знаю, что снижение производительности связано с произвольным доступом к вектору b. от 400.000.000 промахов L1D Я могу перейти к 100 ~ промахам, если не сохраняю в векторе b.
Спасибо.