В процес съм на кодиране на проста функция за навиване в C++, започвайки от най-елементарната навивка с "плъзгащ се прозорец" с обикновени продукти (без FFT неща засега), до SEE, AVX и евентуално OpenCL. Все пак срещнах проблем със SSE. Моят код изглежда така:
for (x = 0; x < SIZEX - KSIZEX + 1; ++x)
{
for (y = 0; y < SIZEY - KSIZEY + 1; ++y)
{
tmp = 0.0f;
float fDPtmp = 0.0f;
float *Kp = &K[0];
for (xi = 0; xi < KSIZEX; ++xi, Kp=Kp+4)
{
float *Cp = &C[(x+xi)*SIZEY + y];
__m128 *KpSSE = reinterpret_cast<__m128*>(&K);
__m128 *CpSSE = reinterpret_cast<__m128*>(&C[(x + xi)*SIZEY + y]);
__m128 DPtmp = _mm_dp_ps(*KpSSE, *CpSSE, 0xFF);
_mm_store_ss(&fDPtmp, DPtmp);
tmp += fDPtmp;
}
R[k] = tmp;
++k;
}
}
Необходимите матрици се инициализират по този начин (размерът на тези се счита за добър, защото по-простите реализации работят добре):
__declspec(align(16)) float *C = ReadMatrix("E:\\Code\\conv\\C.bin");
__declspec(align(16)) float *K = ReadMatrix("E:\\Code\\conv\\K.bin");
__declspec(align(16)) float *R = new float[CSIZEX*CSIZEY];
Кодът се срива при y=1, така че смятам, че може да има грешка в начина, по който боравя с указателите. Интересното е, че ако заменя reinterpret_casts с _mm_set_ps, т.е.
__m128 KpSSE = _mm_set_ps(Kp[0], Kp[1], Kp[2], Kp[3]);
__m128 CpSSE = _mm_set_ps(Cp[0], Cp[1], Cp[2], Cp[3]);
__m128 DPtmp = _mm_dp_ps(KpSSE, CpSSE, 0xFF);
_mm_store_ss(&fDPtmp, DPtmp);
всичко работи добре, макар и по-бавно, за което обвинявам всички операции за копиране.
Може ли някой да ме насочи какво точно правя грешно тук?
Благодаря ти много
потупване
Актуализация: Добре, както посочи Пол, проблемът е в ReadMatrix (или друго решение би било да се използва _mm_loadu_ps). Що се отнася до ReadMatrix(), изглежда така:
__declspec(align(16)) float* ReadMatrix(string path)
{
streampos size;
ifstream file(path, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
__declspec(align(16)) float *C = new float[size];
file.seekg(0, ios::beg);
file.read(reinterpret_cast<char*>(&C[0]), size);
file.close();
return C;
}
else cout << "Unable to open file" << endl;
}
Не върши работа. Има ли някакъв друг начин да направите това елегантно, вместо да бъдете принудени да четете файла част по част и да изпълнявате memcpy, което предполагам, че трябва да работи?!
Актуализация:
Все още не изглежда да иска да работи след това
__declspec(align(16)) float* ReadMatrix(string path)
{
streampos size;
ifstream file(path, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
__declspec(align(16)) float *C = static_cast<__declspec(align(16)) float*>(_aligned_malloc(size * sizeof(*C), 16));
file.seekg(0, ios::beg);
file.read(reinterpret_cast<char*>(&C[0]), size);
file.close();
return C;
}
else cout << "Unable to open file" << endl;
}
Добавих static_cast там, тъй като изглеждаше необходимо да се компилира кодът на Paul (т.е. _aligned_malloc връща празен указател). Приближавам се просто да прочета парчета от файла с fread и да ги memcpy в подреден масив. :/ Пак се улавям, че искам съвет. Благодаря много на всички.
потупване
PS: Кодът без SSE работи добре с тези структури от данни. _mm_loadu_ps е по-бавен от използването на не-SSE код.
__m128
. това няма смисъл, защото__m128
карта към някой от регистрите XMM[0-7]. - person UmNyobe   schedule 24.01.2014reinterpret_cast<__m128*>
е грешен, трябва да използвате_mm_loadu_ps
. - person user541686   schedule 24.01.2014