Означает ли смягчение Meltdown в сочетании с "отложенным распределением" `calloc () CoL, подразумевает снижение производительности для выделенной памяти calloc ()? - PullRequest
0 голосов
/ 05 мая 2018

Итак, calloc() работает, запрашивая у ОС некоторую виртуальную память. Операционная система работает в сговоре с MMU и ловко отвечает адресом виртуальной памяти, который фактически отображается на страницу «копирование при записи», доступную только для чтения, заполненную нулями . Когда программа пытается выполнить запись в любое место на этой странице, происходит сбой страницы (поскольку вы не можете писать на страницы только для чтения), создается копия страницы, и виртуальная память вашей программы сопоставляется с этой новой копией этих страниц. нули.

Теперь, когда Meltdown - вещь, операционные системы были исправлены, так что больше невозможно умозрительно выполнять через ядро-пользовательскую границу. Это означает, что всякий раз, когда пользовательский код вызывает код ядра, он фактически вызывает остановку конвейера. Как правило, когда конвейер останавливается в цикле, это приводит к снижению производительности, поскольку ЦП теряет время на ожидание данных, будь то из кэша или основной памяти.

Учитывая то, что я хочу знать, это:

  • Когда программа пишет на ранее недоступную страницу, которая была выделена с помощью calloc(), и происходит переназначение на новую страницу CoW, выполняет ли это код ядра?
  • Реализована ли функция копирования при записи при сбое страницы на уровне операционной системы или на уровне MMU?
  • Если я вызову calloc(), чтобы выделить 4 ГБ памяти, а затем инициализировать его произвольным значением (скажем, 0xFF вместо 0x00) в тесном цикле, будет ли мой (Intel) ЦП работать граница спекуляции каждый раз, когда он пишет на новую страницу?
  • И, наконец, если это реально, есть ли случай, когда этот эффект важен для реальной производительности?

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Да использование памяти, выделенной calloc(), приведет к снижению производительности из-за исправлений Meltdown и Spectre.

На самом деле, calloc() здесь не является особенным: malloc(), new и в целом вся выделенная память, вероятно, будет испытывать примерно одинаковое влияние на производительность. И calloc(), и malloc() в конечном итоге поддерживаются страницами, возвращаемыми ОС (хотя распределитель будет использовать их повторно после освобождения). Единственное реальное отличие состоит в том, что интеллектуальный распределитель, когда он идет по пути использования новых страниц из ОС (вместо повторного использования ранее free d выделения) в случае calloc, он может опускать обнуление, потому что страницы, предоставляемые ОС, гарантированно равны нулю. Кроме того, поведение распределителя в основном такое же, а поведение обнуления на уровне ОС одинаково (обычно нет возможности запросить у ОС ненулевые страницы).

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

Чтобы оценить влияние на тяжелый рабочий процесс malloc, я попытался выполнить некоторое тяжелое тестирование выделения и сбоя страницы в текущем ядре (4.13.0-39-generic) с мерами по уменьшению Specter и Meltdown, а также в более раннем ядре до на эти меры.

Тестовый код очень прост:

#include <stdlib.h>
#include <stdio.h>

#define SIZE        (40 * 1024 * 1024)
#define PG_SIZE     4096

int main() {
    char *mem = malloc(SIZE);
    for (volatile char *p = mem; p < mem + SIZE; p += PG_SIZE) {
        *p = 'z';
    }
    printf("pages touched: %d\npoitner value : %p\n", SIZE / PG_SIZE, mem);
}

Результаты на более новом ядре составляли около 3700 циклов на страницу, а на более старом ядре без уменьшения около 3300 циклов. Общая регрессия (предположительно) из-за смягчения последствий составила около 14%. Обратите внимание, что это на аппаратном обеспечении Skylake (i7-6700HQ), где некоторые из смягчений Specter'а несколько дешевле, а ядро ​​поддерживает PCID, что удешевляет смягчение KPTI Meltdown. Результаты могут быть хуже на другом оборудовании.

Как ни странно, результаты по новому ядру с отключенными при загрузке Spectre и Meltdown (при использовании spectre_v2=off nopti) были намного хуже , чем по умолчанию для нового или старого ядра, примерно 5050 ошибка циклов на странице, что-то вроде 35% -ной регрессии по тому же ядру с митигациями , включенными . Таким образом, что-то идет не так, с точки зрения производительности, когда смягчение отключено.

Полные результаты

Вот полный вывод perf stat для двух прогонов.

Старое ядро ​​(4.10.0-42)

pages touched: 10240
poitner value : 0x7f7d2561e010

 Performance counter stats for './pagefaults':

         12.980048      task-clock (msec)         #    0.976 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
            10,286      page-faults               #    0.792 M/sec                  
        33,662,397      cycles                    #    2.593 GHz                    
        27,230,864      instructions              #    0.81  insn per cycle         
         4,535,443      branches                  #  349.417 M/sec                  
            11,760      branch-misses             #    0.26% of all branches        

0.013293417 seconds time elapsed

Новое ядро ​​(4.13.0-39)

pages touched: 10240
poitner value : 0x7f306ad69010

 Performance counter stats for './pagefaults':

         14.789615      task-clock (msec)         #    0.966 CPUs utilized          
                 8      context-switches          #    0.541 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
            10,288      page-faults               #    0.696 M/sec                  
        38,318,595      cycles                    #    2.591 GHz                    
        28,796,523      instructions              #    0.75  insn per cycle         
         4,693,944      branches                  #  317.381 M/sec                  
            26,853      branch-misses             #    0.57% of all branches        

       0.015312764 seconds time elapsed

Новое ядро ​​(4.13.0.-39) spectre_v2 = off nopti

pages touched: 10240
poitner value : 0x7ff079ede010

 Performance counter stats for './pagefaults':

         16.690621      task-clock (msec)         #    0.982 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
            10,286      page-faults               #    0.616 M/sec                  
        51,964,080      cycles                    #    3.113 GHz                    
        28,602,441      instructions              #    0.55  insn per cycle         
         4,699,608      branches                  #  281.572 M/sec                  
            25,064      branch-misses             #    0.53% of all branches        

       0.017001581 seconds time elapsed
0 голосов
/ 06 мая 2018

Ваша предпосылка неверна. Сбои страниц никогда не были конвейерными / супер-дешевыми. Однако смягчение последствий распада (и Призрака) делает их более дорогими, наряду с системными вызовами и всеми другими переходами пользователя-> ядра.


Спекулятивное выполнение через ядро ​​/ пользовательскую границу никогда не было возможно ; Процессоры Intel не переименовывают уровень привилегий, т. Е. Переходы ядро ​​/ пользователь всегда требуют полной очистки конвейера. Я думаю, вы неправильно понимаете Meltdown: это вызвано исключительно умозрительным выполнением в пользовательском пространстве и задержкой обработки проверок привилегий при ударах TLB .

Это универсальный дизайн CPU, AFAIK. Мне неизвестны какие-либо микроархитектуры, которые переименовывают уровень привилегий или иным образом спекулируют в коде ядра, x86 или другом.

Стоимость, которую добавляет смягчение Meltdown, заключается в том, что вход в ядро ​​сбрасывает TLB. (Или на процессорах с поддержкой идентификаторов контекста процесса TLB ядро ​​может использовать идентификаторы PCID, чтобы сделать использование отдельных таблиц страниц для ядра по сравнению с пользовательским пространством гораздо более дешевым).

Точка входа в ядро ​​(в Linux) становится трамплином, который меняет таблицы страниц и переходит к real точке входа в ядро, чтобы не подвергать смещение ASLR ядра пользовательскому пространству. Но кроме этого и дополнительного mov cr3, reg при входе и выходе из ядра (установка новой таблицы страниц), ничего больше не меняется.

(Снижение спектра также сложно, и потребовало больше изменений, таких как retpolines ... и может также значительно увеличить стоимость user-> kernel-> user. IDK о стоимости ошибок страницы.)

@ BeeOnRope сообщает (см. Комментарии и его ответ для получения полной информации), что без исправлений Spectre, только примененные исправления Meltdown, но nopti опция загрузки, чтобы «отключить» его, увеличила стоимость обращения к ядру на Skylake Процессор (с syscall с поддельным RAX, возвращающим -ENOSYS сразу) увеличился с ~ 100 до ~ 300 циклов. Так что это может быть стоимость батута? И с включенной фактической изоляцией таблицы страниц она достигла ~ 700 циклов . Это без патчей для смягчения призраков вообще. (Кроме того, это точка входа x86-64 syscall, а не ошибка страницы. Хотя они, вероятно, похожи.)


Исключения ошибок страницы :

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

Related: Когда происходит прерывание, что происходит с инструкциями в конвейере?

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


Когда программа пишет на ранее недоступную страницу, которая была выделена с помощью calloc(), и происходит переназначение на новую страницу CoW, выполняет ли это код ядра?

Да, сбои страниц обрабатываются обработчиком сбоев страниц ядра. Там нет чисто аппаратной обработки для копирования при записи.

Если я вызову calloc () для выделения 4 ГБ памяти, а затем инициализирую его произвольным значением (скажем, 0xFF вместо 0x00) в узком цикле, будет ли мой (Intel) процессор попадать на границу спекуляции каждый раз пишет на новую страницу?

Да. Ядро не находит отказ для обнуленных страниц (в отличие от отображений с файловой поддержкой, когда данные горячие в кэше страниц). Таким образом, каждая новая затронутая страница вызывает сбой страницы, даже для маленьких 4k нормальных страниц. (Спасибо @BeeOnRope за точную информацию по этому вопросу.) С анонимными огромными страницами, вы будете размахивать страницей только один раз за 2 МБ (x86-64), что значительно лучше.

Если вы хотите избежать затрат на страницу, выделите mmap(MAP_POPULATE), чтобы предварительно преобразовать все страницы в таблицу страниц HW в системе Linux. Я не уверен, может ли madvise предустановить страницы для вас, например, madvise(MADV_WILLNEED) в уже сопоставленном регионе. Но madvise(MADV_HUGEPAGE) будет побуждать ядро ​​использовать анонимные огромные страницы (и, возможно, дефрагментировать физическую память, чтобы освободить смежные блоки 2M, чтобы включить это, если у вас не настроено это делать без madvise).

Похожие: Два промаха TLB на mmap / access / munmap имеет некоторые perf результаты для ядра Linux с патчами KPTI.

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