#avx #avx2 #visual-c -2013
#avx #avx2 #visual-c -2013
Вопрос:
Я пытаюсь получить более быстрый двоичный файл для определенного программного обеспечения, включив /arch:AVX2, поскольку я запускаю его на процессорах, которые должны поддерживать этот набор команд (i7 4770 и i7 4800MQ).
Однако это приводит к сбою исполняемого файла с сообщением «xxx.exe перестал работать», как если бы я запускал его на оборудовании, отличном от AVX2.
Я знаю, что AVX2 правильно поддерживается в моей системе, запустив y-cruncher, который обнаруживает аппаратное обеспечение AVX2 и запускает соответствующий исполняемый файл.
Та же проблема возникает, если я укажу /arch:AVX .
Код выполняется нормально при сборке без опции /arch . Другие используемые параметры сборки:
/Ox /Ob2 /Oi /Oy /GT /GL /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /openmp /Gd /TP /GL /GF /Ot /Qfast_transcendentals
Само ПО себе программное обеспечение не использует специфических встроенных функций AVX2, поскольку оно предназначено для работы на более широком наборе платформ. Я просто пытаюсь повысить производительность на своих платформах, не изменяя код (чего я даже не смог бы сделать, поскольку это сложная часть программного обеспечения, и я вообще не эксперт-программист).
Мой вопрос: почему этот параметр должен привести к сбою программы на компьютере с поддержкой AVX2? Я что-то упускаю, что мешает корректной работе /arch:AVX2, например, несовместимости с другими флагами? (Я проверил документы MS и не нашел никакой «перекрестной зависимости», связанной с AVX2).
Редактировать: я добавляю здесь еще немного информации о коде, как предложил Регис Порталез. Вот фрагмент кода, вызывающий проблему. VS debugger останавливается перед последней строкой, указывающей на нарушение доступа:
void Film::ComputeGroupScale(u_int i)
{
const Color white(space.ToXYZ(RGB(1.f)));
if (groups[i].temperature > 0.f) {
Color colorTemp(SPD(groups[i].temperature));
colorTemp /= colorTemp.Y();
groups[i].convert = Adapter(white,
space.ToXYZ(groups[i].rgbScale)) *
Adapter(white, colorTemp);
} else {
groups[i].convert = Adapter(white,
space.ToXYZ(groups[i].rgbScale));
}
groups[i].convert *= groups[i].globalScale;
}
Ниже приведен код сборки для последней строки:
}
groups[i].convert *= groups[i].globalScale;
00007FFB28E43B2A vbroadcastss ymm2,dword ptr [rax rbx 40h]
00007FFB28E43B31 mov rax,qword ptr [rdi 1B8h]
00007FFB28E43B38 vmulps ymm0,ymm2,ymmword ptr [rax rbx 54h]
00007FFB28E43B3E vmovups ymmword ptr [rax rbx 54h],ymm0
00007FFB28E43B44 vmulss xmm0,xmm2,dword ptr [rax rbx 74h]
00007FFB28E43B4A vmovss dword ptr [rax rbx 74h],xmm0
00007FFB28E43B50 vzeroupper
}
Отладчик указывает, что нарушение доступа происходит в vbroadcastss. Содержимое регистра выглядит следующим образом и показывает, что есть попытка прочитать местоположение 0:
RAX = 000000003F800000 RBX = 0000000000000000 RCX = 000007FEDC1143A8 RDX = 000000000021B6E8
RSI = 0000000007709710 RDI = 0000000002D165E0 R8 = 000000000021B6B0 R9 = 0000000004D25190
R10 = 00000000003B0274 R11 = 000000000021B428 R12 = 0000000000000001 R13 = 0000000000000000
R14 = 0000000000000000 R15 = 0000000002288480 RIP = 000007FEDBDC2C0A RSP = 000000000021B690
RBP = 000000000021B790 EFL = 00010340
0x000000003f800040 = 00000000
Для сравнения, когда /arch:AVX2 не используется, это сборка:
groups[i].convert *= groups[i].globalScale;
000007FEDCA019E8 movups xmm0,xmmword ptr [rax rbx 54h]
000007FEDCA019ED shufps xmm2,xmm2,0
000007FEDCA019F1 mulps xmm0,xmm2
000007FEDCA019F4 movups xmmword ptr [rax rbx 54h],xmm0
000007FEDCA019F9 movups xmm0,xmmword ptr [rax rbx 64h]
000007FEDCA019FE mulps xmm0,xmm2
000007FEDCA01A01 movups xmmword ptr [rax rbx 64h],xmm0
000007FEDCA01A06 mulss xmm2,dword ptr [rax rbx 74h]
000007FEDCA01A0C movss dword ptr [rax rbx 74h],xmm2
}
Объект groups, участвующий в нарушении доступа, определяется как:
std::vector<Group> groups;
class Group {
public:
Group(const string amp;n) : samples(0.f), name(n),
globalScale(1.f), temperature(0.f),
rgbScale(1.f), convert(Color(1.f), Color(1.f)),
enable(true) { }
~Group() {
for(vector<Buffer *>::iterator buffer = buffers.begin(); buffer != buffers.end(); buffer)
delete *buffer;
}
void CreateBuffers(const vector<BufferConfig> amp;configs, u_int x, u_int y);
Buffer *getBuffer(u_int index) const {
return buffers[index];
}
double samples;
vector<Buffer *> buffers;
string name;
float globalScale, temperature;
RGB rgbScale;
Adapter convert;
bool enable;
};
Я надеюсь, что эта информация позволит провести дополнительный анализ…
Комментарии:
1. Трудно сказать с таким уровнем детализации. Обычно я не сталкиваюсь с какой-либо конкретной проблемой с AVX2. Правильно ли работает ваша программа без поддержки AVX? В чем причина сбоя? Вы запускали отладчик?
2. Да, программа работает корректно без поддержки AVX. При добавлении /arch:AVX2 (или AVX ) к перечисленным выше параметрам происходит сбой. Причиной сбоя является нарушение доступа, и я определил строку кода, в которой это происходит с помощью отладчика (это доступ к члену объекта, но доступ к другим членам того же объекта в непосредственно предшествующих строках разрешен). Однако я не могу определить основную причину. Я думал отключить параметры оптимизации по одному и посмотреть, какие эффекты он имеет, но пока не было времени…
3. Не могли бы вы опубликовать здесь какую-то часть кода? Нравится структура, к которой обращаются. И сгенерированная сборка?
4. Я обновил текст исходным кодом и сгенерированной сборкой, как с /arch:AVX2 , так и без.
5. Какая инструкция asm на самом деле неисправна? И какие значения находятся в регистрах, задействованных в режиме адресации? Ваш отладчик должен быть в состоянии показать вам. Можете ли вы подтвердить, что это определенно не ошибка незаконных инструкций? Ваш процессор (i7 4xxx) поддерживает AVX2 (и это только AVX1), но виртуальная машина может быть проблемой, если вы работаете внутри виртуальной машины. Ни одна из задействованных инструкций AVX не имеет каких-либо требований к выравниванию, так что это не так. Возможно, ошибка компилятора или, возможно, оптимизация выявляет неопределенное поведение в исходном коде.