Почему этот спекполин не работает на озере Кабы? - PullRequest
4 голосов
/ 05 апреля 2019

Я пытаюсь создать спецполин (ср. Генри Вонг) на моем озере Кабе 7600U , я использую CentOS 7.

Полный репозиторий для тестирования доступен на GitHub .

Моя версия specpoline следующая ( cfr. Spec.asm ):

specpoline:
        ;Long dependancy chain
        fld1
        TIMES 4 f2xm1
        fcos
        TIMES 4 f2xm1
        fcos
        TIMES 4 f2xm1

        %ifdef ARCH_STORE
            mov DWORD [buffer], 241     ;Store in the first line
        %endif

        add rsp, 8
        ret

Эта версия отличается от версии Генри Вонга тем, что поток перенаправлен на архитектурный путь. В то время как оригинальная версия использовала фиксированный адрес, я передаю цель в стек.
Таким образом, add rsp, 8 удалит исходный адрес возврата и будет использовать искусственный адрес.

В первой части функции я создаю длинную цепочку зависимостей с задержкой, используя некоторые старые инструкции FPU, затем независимую цепочку, которая пытается обмануть предиктор стека возврата процессора.


Описание кода

Спецполина вставляется в контекст профилирования с помощью FLUSH + RELOAD 1 , этот же файл сборки также содержит:

buffer

Непрерывный буфер, охватывающий 256 отдельных строк кэша, каждая из которых разделена GAP-1 строками, всего 256*64*GAP байтов.

GAP используется для предотвращения аппаратной предварительной выборки.

Далее следует графическое изображение (каждый указатель идет сразу за другим).

F+R buffer

timings

Массив из 256 DWORD, каждая запись содержит время в циклах ядра , необходимое для доступа к соответствующей строке в буфере F + R.

flush

Небольшая функция для прикосновения к каждой странице (с хранилищем, просто чтобы быть уверенным, что COW на нашей стороне) буфера F + R и освобождает обозначенные строки.

profile`

Стандартная функция профиля, которая использует лунку lfence+rdtsc+lence для профилирования нагрузки из каждой строки в буфере F + R и сохранения результата в массиве timings.

leak

Это функция, которая выполняет реальную работу, вызывает specpoline, помещающий хранилище в умозрительный путь, и функцию profile в архитектурном пути.

;Flush the F+R lines
        call flush

        ;Unaligned stack, don't mind
        lea rax, [.profile]
        push rax
        call specpoline

        ;O.O 0
        ; o o o SPECULATIVE PATH
        ;0.0 O

        %ifdef SPEC_STORE
            mov DWORD [buffer], 241        ;Just a number
        %endif

        ud2                             ;Stop speculation

   .profile:
        ;Ll Ll
        ;  !  !  ARCHITECTURAL PATH
        ;Ll Ll

        ;Fill the timings array
        call profile

Небольшая программа на C используется для «начальной загрузки» тестового жгута.

Выполнение тестов

Код использует препроцессоры, условно помещающие хранилище в архитектурный путь (фактически в сам спекулят), если определено ARCH_STORE, и условно помещают хранилище в умозрительный путь, если определено SPEC_STORE.

Оба хранилища обращаются к первой строке буфера F + R.

Запуск make run_spec и make run_arch соберет spec.asm с соответствующим символом, скомпилирует тест и запустит его.

Тест показывает время для каждой строки буфера F + R.

Хранить в архитектурном тракте

 38    230    258    250    212    355    230    223    214    212    220    216    206    212    212    234
213    222    216    212    212    210   1279    222    226    301    258    217    208    212    208    212
208    208    208    216    210    212    214    213    211    213    254    216    210    224    211    209
258    212    214    224    220    227    222    224    208    212    212    210    210    224    213    213
207    212    254    224    209    326    225    216    216    224    214    210    208    222    213    236
234    208    210    222    228    223    208    210    220    212    258    223    210    218    210    218
210    218    212    214    208    209    209    225    206    208    206   1385    207    226    220    208
224    212    228    213    209    226    226    210    226    212    228    222    226    214    230    212
230    211    226    218    228    212    234    223    228    216    228    212    224    225    228    226
228    242    268    226    226    229    224    226    224    212    299    216    228    211    226    212
230    216    228    224    228    216    228    218    228    218    227    226    230    222    230    225
228    226    224    218    225    252    238    220    229   1298    228    216    228    208    230    225
226    224    226    210    238    209    234    224    226    255    230    226    230    206    227    209
226    224    228    226    223    246    234    226    227    228    230    216    228    211    238    216
228    222    226    227    226    240    236    225    226    212    226    226    226    223    228    224
228    224    229    214    224    226    224    218    229    238    234    226    225    240    236    210

Хранить в умозрительном тракте

298    216    212    205    205   1286    206    206    208    251    204    206    206    208    208    208
206    206    230    204    206    208    208    208    210    206    202    208    206    204    256    208
206    208    203    206    206    206    206    206    208    209    209    256    202    204    206    210
252    208    216    206    204    206    252    232    218    208    210    206    206    206    212    206
206    206    206    242    207    209    246    206    206    208    210    208    204    208    206    204
204    204    206    210    206    208    208    232    230    208    204    210   1287    204    238    207
207    211    205    282    202    206    212    208    206    206    204    206    206    210    232    209
205    207    207    211    205    207    209    205    205    211    250    206    208    210    278    242
206    208    204    206    208    204    208    210    206    206    206    206    206    208    204    210
206    206    208    242    206    208    206    208    208    210    210    210    202    232    205    207
209    207    211    209    207    209    212    206    232    208    210    244    204    208    255    208
204    210    206    206    206   1383    209    209    205    209    205    246    206    210    208    208
206    206    204    204    208    246    206    206    204    234    207    244    206    206    208    206
208    206    206    206    206    212    204    208    208    202    208    208    208    208    206    208
250    208    214    206    206    206    206    208    203    279    230    206    206    210    242    209
209    205    211    213    207    207    209    207    207    211    205    203    207    209    209    207

Я поместил магазин в архитектурный путь для проверки функции таймингов, похоже, она работает.

Однако я не могу получить тот же результат с магазином в спекулятивном пути.

Почему ЦП не спекулятивно выполняет хранилище?


1 Признаюсь, я никогда не тратил время на различие всех методов профилирования кэша. Я надеюсь, что использовал правильное имя. Под FLUSH + RELOAD я подразумеваю процесс удаления набора строк, умозрительно выполняющего некоторый код и затем записывающего время доступа к каждой из удаленных строк.

1 Ответ

3 голосов
/ 06 апреля 2019

Ваша "длинная цепочка деп" - это много мопов из тех микрокодированных инструкций x87.fcos - это 53-105 моп в SKL с пропускной способностью 50-130 циклов.Таким образом, это примерно 1 цикл на задержку, и планировщик / станция резервирования (RS) "только" имеет 97 записей в SKL / KBL.Кроме того, может возникнуть проблема с получением более поздних инструкций в бэкэнде вышедшего из строя, потому что микрокод берет на себя внешний интерфейс и нуждается в каком-то механизме, чтобы решить, какие мопы выпустить дальше, возможно, в зависимости от результата некоторых вычислений.(Количество мопов, как известно, зависит от данных.)

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

    xorps  xmm0,xmm0                   ; avoid subnormals that might trigger FP assists
    times 40 sqrtsd xmm0, xmm0

    ; then make the store of the new ret addr dependent on that chain
    movd   ebx, xmm0
    ; and  ebx, 0            ; not needed, sqrt(0) = 0.0 = integer bit pattern 0
    mov [rsp+rbx], rax
    ret

Начиная с Nehalem, процессоры Intel имеют быстрое восстановление при промахах ветвления с помощью буфера порядка ветвления, который снимает состояние OoO (включая RAT и, вероятно, RS) Что именно происходит, когда процессор Skylake неправильно прогнозируетветка? . Таким образом, они могут в точности восстановиться до ошибочного прогноза, не дожидаясь, пока ошибочный прогноз станет состоянием выхода на пенсию.

mov [rsp], rax может выполняться сразу после его входа в RS или, по крайней мере, без зависимостив цепочке sqrt dep.Как только переадресация магазина может выдать значение, uop ret может выполнить и проверить прогноз, а также обнаружить неверный прогноз, пока цепочка sqrt dep все еще работает.(ret - это 1 микроплавленый бит для портов загрузки + порт 6, где находится исполняемый модуль ветвления.)

Соединение цепочки депо sqrtsd с сохранением нового обратного адреса предотвращаетret с раннего выполнения . Выполнение a ret моп в порту выполнения = проверка прогноза и обнаружение ошибочного прогноза, если таковой имеется.

(Контраст с Meltdown, где «неправильный» путь продолжается досбойная нагрузка достигает выхода на пенсию, и вы хотите выполнить ее как можно скорее (только не удаляясь). Но вы обычно хотите поставить целую атаку Meltdown в тень чего-то другого, например TSX или specpoline, в этом случаевам нужно что-то вроде этого и иметь полное падение в тени этой цепи депо . Тогда для Meltdown не понадобится собственная sqrtsd цепочка деп.)


(vsqrtpd ymm по-прежнему 1 моп на SKL, с худшей пропускной способностью, чем xmm, но с той же задержкой . Поэтому используйте sqrtsd, потому что это такая же длина и, вероятно, более энергоэффективная.)

Наилучшая задержка составляет 15 циклов против наихудшего значения 16 для SKL / KBL (https://agner.org/optimize),, поэтому вряд ли имеет значение, с какого ввода вы начинаете.


Я изначально использовал sqrtpd с сиМилар результаты.Однако я не инициализировал регистр XMM, используемый как вход (и выход), думая, что это не имеет значения.Я проверил снова, но на этот раз я инициализировал регистр с двумя двойными значениями 1e200, и я получаю неустойчивый результат.Иногда строка выбирается спекулятивно, иногда это не так.

Если XMM0 содержит субнормальное значение (например, битовая комбинация представляет собой небольшое целое число), sqrtpd принимает помощь микрокода.(fp_assist.any счетчик перфорации).Даже если результат нормальный, но вход ненормальный.Я проверил оба случая на SKL с помощью этого цикла:

  pcmpeqd   xmm0,xmm0
  psrlq     xmm0, 61        ; or 31 for a subnormal input whose sqrt is normalized
  addpd     xmm0,xmm0       ; avoid domain-crossing vec-int -> vec-fp weirdness

  mov   ecx, 10000000
.loop:
    sqrtpd  xmm1, xmm0
    dec    ecx
    jnz   .loop

 mov eax,1
 int 0x80   ; sys_exit

perf stat -etask-clock,context-switches,cpu-migrations,page-faults,cycles,branches,instructions,uops_issued.any,uops_executed.thread,fp_assist.any показывает 1 ассистент на итерацию для ненормальных входных данных, с выданными 951M моп (и ~ 160 циклов на итерацию).Таким образом, мы можем заключить, что вспомогательный микрокод для sqrtpd в этом случае занимает ~ 95 моп и имеет пропускную способность ~ 160 циклов, когда это происходит спина к спине.

против.Всего выдано 20 млн. Моп для ввода = NaN (все единицы), с 4,5 циклами на итерацию.(Цикл работает 10M sqrtpd мопс и 10 Мб с макросом dec / jcc моп.)

...