Я провожу исследование для своего университета, связанное с алгоритмом реконструкции изображений для медицинского использования.
Я застрял в чем-то до 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, не загрязняя кэш?
Я не могу использовать _mm_stream_ps, потому что всегда храню 4 числа с плавающей запятой, но доступ к вектору b явно случайный.
Я надеюсь быть ясным в моей дилемме.
Дополнительная информация: v — это значение столбца хранилища разреженных матриц в формате CRS. Я понимаю, что можно было бы сделать другую оптимизацию, если бы я попытался изменить формат CRS на другой, однако, как я уже говорил ранее, я провел несколько тестов в течение нескольких месяцев и знаю, что снижение производительности связано со случайным доступом к вектору b. от 400 000 000 промахов L1D я могу перейти к 100 ~ промахам, если я не сохраняю в векторе b.
Спасибо.