Обнаруживает ли блок SSE FP 0.0 операндов?

По моим предыдущим вопрос Моя идея состояла в том, чтобы оптимизировать алгоритм, удалив вычисления, когда коэффициенты m_a, m_b равны 1,0 или 0,0. Теперь я попытался оптимизировать алгоритм и получил некоторые любопытные результаты, которые я не могу объяснить.

Первый анализатор работает на 100 тыс. Образцов. Значения параметров читаются из файла (!):

b0 = 1,0; b1 = -1,480838022915731; b2 = 1,0.

a0 = 1,0 a1 = -1,784147570544337 a2 = 0,854309980957510

Медленный

Второй анализатор запускает те же 100 тыс. Образцов. Значения параметров читаются из файла (!):

b0 = 1,0; b1 = -1,480838022915731; b2 = 1,0.

a0 = 1,0 a1 = -1,784147570544337 a2 = 0,0 <— Только а2 отличается!

Быстро

На рисунках цифры слева (серый фон) представляют необходимые циклы ЦП. Как хорошо видно, второй прогон с параметром a2 = 0.0 намного быстрее.

Я проверил разницу между кодом отладки и выпуска. Выпуск кода быстрее (как и ожидалось). Код отладки и выпуска имеет одинаковое странное поведение при изменении параметра a2.

Затем я проверил код ASM. Я заметил, что используются инструкции SSE. Это верно, потому что я скомпилировал с / arch: SSE2. Поэтому я отключил SSE. Полученный код больше не использует SSE, и производительность больше НЕ зависит от значения параметра a2 (как и ожидалось)

Поэтому я пришел к выводу, что это своего рода выигрыш в производительности, когда используется SSE, и движок SSE обнаруживает, что a2 равно 0.0, и поэтому исключает устаревшие умножение и вычитание. Я никогда не слышал об этом и пытался найти информацию, но безуспешно.

Так есть ли у кого-нибудь объяснение моих результатов работы?

Для полноты, это соответствующий код ASM для версии выпуска:

00F43EC0  mov         edx,dword ptr [ebx]
00F43EC2  movss       xmm0,dword ptr [eax+edi*4]
00F43EC7  cmp         edx,dword ptr [ebx+4]
00F43ECA  je          $LN419+193h (0F43F9Dh)
00F43ED0  mov         esi,dword ptr [ebx+4]
00F43ED3  lea         eax,[edx+68h]
00F43ED6  lea         ecx,[eax-68h]
00F43ED9  cvtps2pd    xmm0,xmm0
00F43EDC  cmp         ecx,esi
00F43EDE  je          $LN419+180h (0F43F8Ah)
00F43EE4  movss       xmm1,dword ptr [eax+4]
00F43EE9  mov         ecx,dword ptr [eax]
00F43EEB  mov         edx,dword ptr [eax-24h]
00F43EEE  movss       xmm3,dword ptr [edx+4]
00F43EF3  cvtps2pd    xmm1,xmm1
00F43EF6  mulsd       xmm1,xmm0
00F43EFA  movss       xmm0,dword ptr [ecx]
00F43EFE  cvtps2pd    xmm4,xmm0
00F43F01  cvtps2pd    xmm3,xmm3
00F43F04  mulsd       xmm3,xmm4
00F43F08  xorps       xmm2,xmm2
00F43F0B  cvtpd2ps    xmm2,xmm1
00F43F0F  movss       xmm1,dword ptr [ecx+4]
00F43F14  cvtps2pd    xmm4,xmm1
00F43F17  cvtps2pd    xmm2,xmm2
00F43F1A  subsd       xmm2,xmm3
00F43F1E  movss       xmm3,dword ptr [edx+8]
00F43F23  mov         edx,dword ptr [eax-48h]
00F43F26  cvtps2pd    xmm3,xmm3
00F43F29  mulsd       xmm3,xmm4
00F43F2D  subsd       xmm2,xmm3
00F43F31  movss       xmm3,dword ptr [edx+4]
00F43F36  cvtps2pd    xmm4,xmm0
00F43F39  cvtps2pd    xmm3,xmm3
00F43F3C  mulsd       xmm3,xmm4
00F43F40  movss       xmm4,dword ptr [edx]
00F43F44  cvtps2pd    xmm4,xmm4
00F43F47  cvtpd2ps    xmm2,xmm2
00F43F4B  xorps       xmm5,xmm5
00F43F4E  cvtss2sd    xmm5,xmm2
00F43F52  mulsd       xmm4,xmm5
00F43F56  addsd       xmm3,xmm4
00F43F5A  movss       xmm4,dword ptr [edx+8]
00F43F5F  cvtps2pd    xmm1,xmm1
00F43F62  movss       dword ptr [ecx+4],xmm0
00F43F67  mov         edx,dword ptr [eax]
00F43F69  cvtps2pd    xmm4,xmm4
00F43F6C  mulsd       xmm4,xmm1
00F43F70  addsd       xmm3,xmm4
00F43F74  xorps       xmm1,xmm1
00F43F77  cvtpd2ps    xmm1,xmm3
00F43F7B  movss       dword ptr [edx],xmm2
00F43F7F  movaps      xmm0,xmm1
00F43F82  add         eax,70h
00F43F85  jmp         $LN419+0CCh (0F43ED6h)
00F43F8A  movss       xmm1,dword ptr [ebx+10h]
00F43F8F  cvtps2pd    xmm1,xmm1
00F43F92  mulsd       xmm1,xmm0
00F43F96  xorps       xmm0,xmm0
00F43F99  cvtpd2ps    xmm0,xmm1
00F43F9D  mov         eax,dword ptr [ebp-4Ch]
00F43FA0  movss       dword ptr [eax+edi*4],xmm0
00F43FA5  mov         ecx,dword ptr [ebp-38h]
00F43FA8  mov         eax,dword ptr [ebp-3Ch]
00F43FAB  sub         ecx,eax
00F43FAD  inc         edi
00F43FAE  sar         ecx,2
00F43FB1  cmp         edi,ecx
00F43FB3  jb          $LN419+0B6h (0F43EC0h)

Изменить: Заменить код отладки ASM на код выпуска.

3

Решение

На SSE нет ранних выходов для умножения FP. Это полностью конвейерная операция с коротким временем ожидания, поэтому добавление ранних выходов усложнит удаление инструкций, обеспечивая при этом нулевой выигрыш в производительности. Единственные инструкции, которые обычно имеют зависящие от данных характеристики исполнения на современных процессорах, — это деление и квадратный корень (игнорирование субнормалей, которые влияют на более широкий набор инструкций). Это подробно задокументировано как Intel, так и AMD, а также независимо от Agner Fog.

Так почему вы видите изменение в производительности? Наиболее вероятным объяснением является то, что вы сталкиваетесь с остановками из-за ненормальных входных данных или результатов; это очень часто встречается с фильтрами и задержками DSP, такими как у вас. Не видя ваш код и входные данные, невозможно быть уверенным, что это именно то, что происходит, но это, безусловно, наиболее вероятное объяснение. Если это так, вы можете устранить проблему, установив биты DAZ и FTZ в MXCSR.

Документация Intel:
http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf (обратитесь к таблицам задержки в приложении, обратите внимание, что есть фиксированное значение для mulss а также mulsd.)

Задержки инструкций 16 драм (электронная таблица Excel):
http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/AMD64_16h_InstrLatency_1.1.xlsx

Таблицы задержки инструкций Agner Fog для Intel и AMD:
http://www.agner.org/optimize/instruction_tables.pdf

7

Другие решения

Это было бы нормальное поведение, если Модуль умножения FP HW будет выполнять ранние операции. Ты можешь видеть Вот больше деталей. Это означает, что когда HW обнаруживает значение 0.0, оно не пропускает его через весь конвейер.

Однако вы используете SSE mulsd инструкция. В своем посте Стивен Кэнон указал, что в реализациях Intel и AMD задержка для mulsd инструкция исправлена. Это указывает на то, что нет никаких ранних функций, связанных с SSE.

Также Стивен Кэнон указал, что проблемы с производительностью возникают при использовании ненормальных чисел. В этом сообщение Вы можете прочитать больше о том, что вызывает это.

Однако все ваши коэффициенты являются частыми значениями, которые не кажутся ненормальными. Так что проблема может быть где-то еще. Все инструкции ASM в вашем коде задокументированы с фиксированными задержками, но огромная разница в циклах указывает на то, что что-то происходит.

Ваш вывод профилирования показывает, что все ваши задержки изменились, даже если коэффициент 0,0 появляется только в нескольких умножениях. Правильно ли рассчитан результат? Все остальные переменные постоянны между прогонами?

4