Оптимизация производительности сборки x86-64 - выравнивание и прогноз ветвления

В настоящее время я пишу высокооптимизированные версии некоторых строковых функций стандартной библиотеки C99, таких какstrlen(), memset()и т. д. с использованием сборки x86-64 с инструкциями SSE-2.

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

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

Таким образом, я предполагаю, что есть некоторые проблемы с выравниванием кода и / или с ветвями, которые были ошибочно предсказаны.

Я знаю, что даже при одинаковой архитектуре (x86-64) разные процессоры имеют разные алгоритмы прогнозирования ветвлений.

Но есть ли какие-то общие советы при разработке для высокой производительности на x86-64, о выравнивании кода и предсказании ветвлений?

В частности, о выравнивании, я должен гарантировать, что все метки, используемые инструкциями перехода, выровнены по DWORD?

_func:
    ; ... Some code ...
    test rax, rax
    jz   .label
    ; ... Some code ...
    ret
    .label:
        ; ... Some code ...
        ret

В предыдущем коде я должен использовать директиву выравнивания перед.label:, любить:

align 4
.label:

Если да, достаточно ли выравнивания по DWORD при использовании SSE-2?

А что касается предсказания ветвлений, существует ли «предпочтительный» способ организации меток, используемых инструкциями перехода, для того, чтобы помочь ЦП, или современные ЦП достаточно умны, чтобы определить это во время выполнения путем подсчета количества раз, которое берется ветвь?

РЕДАКТИРОВАТЬ

Хорошо, вот конкретный пример - вот началоstrlen() с SSE-2:

_strlen64_sse2:
    mov         rsi,    rdi
    and         rdi,    -16
    pxor        xmm0,   xmm0
    pcmpeqb     xmm0,   [ rdi ]
    pmovmskb    rdx,    xmm0
    ; ...

Выполнение его 10 000 000 раз с 1000-символьной строкой дает около 0,48 секунды, что нормально.
Но он не проверяет наличие ввода строки NULL. Очевидно, я добавлю простую проверку:

_strlen64_sse2:
    test       rdi,    rdi
    jz          .null
    ; ...

Тот же тест, теперь он запускается за 0,59 секунды. Но если я выровняю код после этой проверки:

_strlen64_sse2:
    test       rdi,    rdi
    jz          .null
    align      8
    ; ...

Оригинальные спектакли вернулись. Я использовал 8 для выравнивания, так как 4 ничего не меняет.
Может кто-нибудь объяснить это и дать несколько советов о том, когда выравнивать или не выравнивать фрагменты кода?

РЕДАКТИРОВАТЬ 2

Конечно, это не так просто, как выравнивание каждой цели ветки. Если я это сделаю, выступления, как правило, будут ухудшаться, если не считать каких-либо конкретных случаев, подобных описанным выше.

Ответы на вопрос(4)

Ваш ответ на вопрос