Гугл показал, что эта проблема носит массовый характер (раз, два, три, четыре), а AMD никак не реагирует. Пользователь форумов AMD tapek путем дебаггинга выяснил, что проблема заключается в использовании новыми версиями драйверов инструкции popcnt из набора SSE4.2.
Загрузив одну из проблемных библиотек (amdxc32.dll) в Hiew, поиском по опкоду инструкции popcnt — F3 0F B8 обнаруживаем, что она вызывается аж целых три раза! Это значит, что она не сильно там нужна и можно придумать ей замену. Эта инструкция возвращает первому аргументу количество единичных бит второго аргумента.
Для замены popcnt возьмем алгоритм Брайана Кернигана (Brian Kernigan/Kernighan).
На С++ он выглядит так:
int kernigan(int value){
int count = 0;
while(value != 0){
value &= (value-1);
count++;
}
return count;
}
На асме так:
push ebx
push ecx
xor eax,eax
mov ebx, value
kernigan_start:
cmp ebx, 0
jz kernigan_end
add eax, 1
mov ecx, ebx
sub ebx, 1
and ebx, ecx
jmp kernigan_start
kernigan_end:
pop ecx
pop ebx
retn
Ищем в конце секции кода незанятое место, забитое нулями. Там мы и будем писать наш код:
Находим в библиотеке вызов команды popcnt:
И заменяем его на переход на наш код:
В ранее найденном месте пишем наш код и возвращаем управление туда, откуда взяли
После чего повторяем вышеописанное с оставшимися вызовами команды popcnt как в этой библиотеке, так и в amdxc64.dll, подменяем ими оригиналы и получаем снова работающий DirectX12 без SSE4.2.
P.S. линк на модифицированные мною библиотеки для драйверов 16.9.1 от 13 сентября.
Комментарии (35)
VioletGiraffe
24.09.2016 08:14+1Проц без SSE4.2 — это уже довольно-таки древность. Слабо понимаю, зачем такой машине поддержка ДХ12.
Zifix
24.09.2016 08:58+4Если поставить например копеечный E5450 в материнку на 775 и купить видеокарту среднего уровня — вполне себе жизнеспособный вариант получается.
DuMOHsmol
24.09.2016 11:58+6А ещё есть AMD Phenom II, в разогнанном виде они до сих пор неплохи.
VioletGiraffe
24.09.2016 13:36-7«неплохи» = «приложения запускаются и даже как-то работают»?
strapony
24.09.2016 14:17+2Неплохи = невооружённым глазом разницы с i5 на соседнем ПК в повседневном использовании не видно.
На домашнем сервере, где тоже phenom II был, но на шесть ядер, разницу при переходе на Xeon заметил только в диспетчере задач — загрузка процессора упала с ~25-30% до 5-10% при полудюжине запущенных hyper-v машин.
VioletGiraffe
24.09.2016 14:20Если не загружен — тогда, конечно, не будет заметно. А я, например, её везде вижу. Начиная с игр и заканчивая временем компиляции проекта и временем обработки изображений в программе, над которой я работаю. Разница Core i7 с 8-ядерным Будьдозером — более 2 раз, так-то. И это старый Sandy Bridge.
DuMOHsmol
24.09.2016 15:30+2А что не так с играми? Doom играется, Deus Ex играется, оба упираются в мою видеокарту (GTX660), а не процессор. Понятно, что i7 будет намного лучше, но списывать со счетов камни без SSE 4.2 всё же ещё не стоит. Тем более, что DX12 вроде как раз и должен снижать нагрузку на процессор.
VioletGiraffe
24.09.2016 15:36-1А в играх просадки ФПС намного меньше с современными процессорами. Посмотрите, например, http://wccftech.com/intel-skylake-6700k-6600k-amd-fx-8370/
Zifix
24.09.2016 15:47+3Позвольте, но далеко не каждый может себе позволить купить топовый i7 и R9 Fury Triple Dissipation.
Что им теперь, в игры не играть? Запускать что-то, требующее выше 10 DirectX даже не мечтать?
Покупают ведь люди и новые компьютеры с Core i3, и вполне себе радуются жизни, хотя они может быть тоже раза в два слабее «старого i7».VioletGiraffe
24.09.2016 15:53-1Просадки до 15 ФПС чувствительны безо всяких Fury. А часто и до 25 ФПС (правильнее было бы, наверное, считать время задержки, если это фриз, а не переводить в ФПС). А если у компа средний ФПС такой, то он, пардон, совсем не игровой. На старой технике можно играть с пониженными настройками, но это совсем не то удовольствие. И не всегда помогает — одна из недавних игр на моей предыдущей карточке АМД 6950 была неиграбельна даже на минимальных и с внутренним масштабированием разрешения 50% (то есть 0.5 от экранного).
sumanai
24.09.2016 16:44+4но это совсем не то удовольствие
Как люди раньше без графона играли…VioletGiraffe
24.09.2016 16:46-2Как люди раньше деревянными игрушками играли? А ещё раньше только и делали, что еду искали, не до игр было.
andrey_aksamentov
26.09.2016 08:06Вам смешно, а я еще помню время когда у меня half life 1 тормозил… В те времена 25 фпс считалось вполне игровым режимом.
После обновления компа, еще некоторое время выставлял в драйвере принудительное ограничение в 25 кадров, было непривычно когда их больше 30…
Я почти на 90% уверен что комфортно можно и сейчас играть на 25кадрах, если не будет фризов и лагов, и это ограничение будет искусственным.VioletGiraffe
26.09.2016 08:09В принципе, да, хотя ещё зависит от движка. Для плавности на 25 лучше добавить немного motion blur, это здорово помогает.
dadyjo
26.09.2016 18:21-1У меня i3 3.8 ГГц производительности хватает, многопоточность для игр улучшает графику но fps проседает, это даже в примечании к настройке «Использовать несколько ядер» в игре написано.
Mpa3b_ru21
24.09.2016 13:45dxdiag вылетает с ошибкой. но успевает показать, что DirectX ? 12.
Bazanra
24.09.2016 13:45С какой ошибкой?
Mpa3b_ru21
24.09.2016 18:36Имя сбойного приложения: dxdiag.exe, версия: 10.0.14393.0, метка времени: 0x57899b4a
Имя сбойного модуля: amdxc64.dll, версия: 21.19.134.1, метка времени: 0x57d02449
Код исключения: 0xc0000005
Смещение ошибки: 0x0000000000035a0e
Идентификатор сбойного процесса: 0x1e80
Время запуска сбойного приложения: 0x01d216792db489b7
Путь сбойного приложения: C:\WINDOWS\system32\dxdiag.exe
Путь сбойного модуля: C:\WINDOWS\system32\amdxc64.dll
Идентификатор отчета: f3e4b1e0-edb0-4f0b-8246-4a0f881523f9
Полное имя сбойного пакета:
Код приложения, связанного со сбойным пакетом:Bazanra
24.09.2016 19:00Здесь что-то не так. Драйвер 16.9.1 от 13 сентября использует amdxc64.dll из DriverStore, а не из system32.
Godless
24.09.2016 15:16+2используйте сдвиги с переходом через cf и сложение с нулем и cf. ускорится все немного.
BigW
24.09.2016 16:37+6А почему jmp, а не call и ret? Тогда можно адреса возврата не высчитывать, а просто заменить инструкцию и выровнять код… Я так понимаю вы алгоритм Кернигана 3 раза вставили?
Bazanra
24.09.2016 19:13С call и ret мой промах, возьму на заметку.
Алгоритм вставлял 6 раз — по 3 раза в x32 и x64 библиотеки. Как написать одну общую функцию (пока) не придумал — вызов popcnt занимает 9 байт, а на передачу только второго аргумента в стек уйдет 7 байт.BigW
25.09.2016 13:26а, ясно. каждый раз разный аргумент, который [edi][edx]*4[00000010… Тогда, да… проще jmp…
Deamhan
24.09.2016 19:21+3Насчёт SSE4.2: всё не совсем так. POPCNT содержится и в SSE4A, а этот набор был уже в первом Phenom (2007 год, пруф: https://en.wikipedia.org/wiki/SSE4). Так что владельцам phenom/phenom II не о чем париться. Скорее всего амд включили не SSE4.2, а SSE4A.
Ivan_83
25.09.2016 02:20Как то так было бы быстрее:
/* Returns: Population Count (Ones Count) = log2 = popcount. */
static inline size_t
u32_digit_bits(uint32_t digit) {
register size_t n;
register uint32_t reg = digit;
if (0 == reg)
return (reg);
reg -= ((reg >> 1) & 0x55555555);
reg = (((reg >> 2) & 0x33333333) + (reg & 0x33333333));
reg = (((reg >> 4) + reg) & 0x0f0f0f0f);
reg += (reg >> 8);
reg += (reg >> 16);
n = (reg & 0x0000003f);
return (n);
}
Ещё пачка вариантов тут: https://habrahabr.ru/post/276957/
То что вызывается оно всего 3 раза не значит что это происходит редко, может это самые нагруженные циклы.
Я согласен что так делать очень не хорошо, могли бы сделать через cpuid детект и вызов соответствующей ветки кода на лету, как делают все приличные люди.
У себя дома систему и все приложения вот только сейчас, при апгрейде до фрибсд11 пересобрал с sse 4.1 и то сомневаюсь, ибо теперь переткнуть винт/сколонировать и запустить систему на более простых системах не получится (есть дома такие), а вот профита не так чтобы заметно. Какие то оптимизированные вещи может и стали работать в 2-3 раза быстрее, но на общем фоне не заметно совсем.
2 VioletGiraffe
2 Deamhan
У меня дома только один проц имеет поддержку SSE 4.2 и в нём же есть AVX — и тот самый бюджетный под ам1 сокет :)
Но это ещё не самое страшное, ибо у меня штуки 3 относительно приличных проца в которых SSE4 вообще нет — имя им DualCore под 775 сокет, а SSE 4.1 в коредуо е8400/8500.
И меня не напрягает ни разу на них работать, вполне достаточно.Bazanra
25.09.2016 02:55+1При выборе алгоритма я рассмотрел еще больше вариантов (их тесты тут), и выбрал Кернигановский по той причине, что он очень прост и в ассемблерном коде занимает меньше всего места, а, значит вероятность допустить ошибку меньше.
PsyHaSTe
26.09.2016 17:26Всегда можно написать на С и скомпилировать. GCC в алгоритме любой сложности не ошибется. Лишь бы влезть в сегмент.
theg4sh
25.09.2016 20:26Bazanra и правильно сделал что пропатчил.
У них явно что-то не так либо с разработкой, либо с тестированием. Год назад фиксил их драйвер для старенькой видяхи HD7770 под Linux (появились мелкие изменения в api ядра) и смотрю ситуация вообще не изменилась. Фикс был отправлен, но до выпуска официального патча прошло еще полгода.splav_asv
25.09.2016 20:44Под Linux у них генеральное направление сменилось на AMDGPU и код прямо в ядре, обновляется соответственно отлично. А вот сил на перевод драйвера на работу с открытым модулем ядра видать ушло очень много и на старое железо слегка забили.
theg4sh
25.09.2016 22:28splav_asv, спасибо, в курсе. Драйвер amdgpu, имхо, хорошо себя показал. Только неприятный отпечаток все равно остался, да и в силу обстоятельств железку уже обновил.
«Забивательство» AMD (да и других больших кампаний) на устаревшие девайсы, скорее всего, идет со стороны биснеса от вопроса «как стимулировать оборот?» и тут уже ничего не поделать, остается только поддержка сообществом.
lolipop
Вот это подход!
0xcffaedfe
Это не подход, это
костыльвременная мера.Ибо мало того что следующий апдейт заставить патчить либо искать пропатченные либы фиг знает с какой встроенной заразой, так еще в один прекрасный момент amd может пересобрать дрова с поддержкой остальных инструкций из набора.