Я нахожусь в процессе кодирования простой функции свертки в C++, начиная с самой основной «скользящей оконной» свертки с регулярными произведениями (на данный момент нет материала FFT), до SEE , AVX и, возможно, OpenCL. Однако я столкнулся с проблемой SSE. Мой код выглядит следующим образом:SSE: reinterpret_cast <__m128*> вместо _mm_load_ps
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;
}
}
Необходимые матрицы инициализируются, как это (размер тех, является considerd хорошо, потому что более простые реализации работают нормально):
__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];
Код аварий при у = 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);
все это работает просто отлично, хотя медленнее, что я обвиняю все операции копирования.
Может кто-нибудь, пожалуйста, указать мне, что именно я делаю неправильно здесь?
Большое спасибо
Pat
Update: Хорошо, так как указал Павла проблема заключается в 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, который, как я полагаю, должен работать ?!
Update:
Тем не менее, кажется, не хотят работать после того, как
размер__declspec(align(16)) float* ReadMatrix(string path)
{ streampos;
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 там, так как это казалось необходимым, чтобы получить код Павла компилировать (т.е. _aligned_malloc возвращает указатель недействительным). Я приближаюсь к просто читать фрагменты файла с fread и memcpy их в alligned массив. :/И снова я нахожусь со своим советом. Спасибо вам большое.
Pat
PS: Non-SSE код прекрасно работает с этими структурами данных. _mm_loadu_ps медленнее, чем использование кода, отличного от SSE.
У вас не может быть указателя на '__m128'. это не имеет смысла, потому что '__m128' отображается в любом из регистров XMM [0-7]. – UmNyobe
'reinterpret_cast <__m128*>' неправильно, вы должны использовать '_mm_loadu_ps'. – Mehrdad
@UmNyobe: нет, код в порядке, и будет работать нормально, если данные будут правильно выровнены. –