Оптимизированная процедура равенства сборки - PullRequest
0 голосов
/ 28 мая 2011

Я пытаюсь написать (очень) короткую процедуру сборки, которая проверяет равенство двух слов и возвращает логическое значение (1 = true, 0 = false).До сих пор я придумал три метода, один из которых использует LAHF, который, очевидно, не поддерживается некоторыми процессорами x86_64, так что, к сожалению, один из них исключен.

Первая версия:

    mov eax, [esp + 8]
    cmp b, [esp + 4]
    mov eax, 1
    jnz jpt 
    mov eax, 0
jpt:    ret

и второй версии:

    mov eax, [ebp + 8]
    cmp b, [ebp + 4]
    pushf       ; Get lowest word of the flags register
    pop ax      
    and eax, 0x0040 ; Extract the zero flag
    shr eax, 6  ; eax is now true(1) if arg1 == arg2    
    ret

В первой версии есть дополнительная инструкция ветвления, но во второй версии есть дополнительная команда push и дополнительная команда pop.Какой из них вы ожидаете быть самым быстрым и почему?Зависит ли это от того, будет ли ветвление принято / предсказано или нет?

Ответы [ 2 ]

2 голосов
/ 28 мая 2011

Обе версии плохие.Произвольная ветвь занимает много времени, потому что ее невозможно предсказать, а lahf - просто нет, нет из-за частичной записи в регистр.Но, конечно же, написание теста на равенство в ассемблере в любом случае является полной ерундой, потому что служебная нагрузка функции будет кратна эквивалентным встроенным инструкциям, поэтому здесь я иду:

mov eax, [ebp + 8]
cmp eax, [ebp + 4]
setz al                ;set al to 1 if equal
movzx eax,al         ;convert to dword
ret
0 голосов
/ 28 мая 2011

Я уже нашел эти узкие места в приложениях, которые мне нужно было оптимизировать, и они являются верным признаком того, что вы врезались в стену и не можете оптимизировать дальше.

Наилучшим вариантом действий будетвыбрать другой алгоритм или макет данных, который соответствует платформе и шаблонам доступа лучше, чем тот, который у вас есть в настоящее время.Это, пожалуй, самая важная вещь, которую вы можете сделать.

Однако из-за крайних сроков или других ограничений, которые иногда невозможны, вам придется проявить изобретательность, а это, вероятно, потребует тестирования.несколько элементов одновременно с использованием операций SIMD (например, используйте встроенную функцию _mm_cmpeq_epi32 для сравнения 4 элементов).Если вы собираетесь выполнить ответвление, вы можете сравнить 16 элементов, поразрядно или по маскам, и выполнить переход по ним (затем выбрать правильные данные внутри ветви).

Это в первую очередь выгодно на платформах, где ветки очень дороги, а на IA-32/64 это не так (например, ветки дешевы).

Также следует помнить, что из-зана платформы Intel Out-of-order Execution (OOE), чтобы затем использовать;вполне может быть так, что используемый вами профилировщик сообщает об остановке в более или менее случайном месте, потому что так получается, что процессору нужно ждать, пока данные будут считаны из кеша или ОЗУ.

Если вы оказались в такой ситуации, убедитесь, что вы оптимизировали свой алгоритм, чтобы сделать его более удобным для кэша (например, выясните, сколько элементов помещается в строку кэша, уменьшите размер структур данных и т. Д.).)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...