При каких обстоятельствах большие страницы могут ускорить работу?


Современные процессоры x86 имеют возможность поддерживать более крупных размеров, чем наследие 4К (т. е. 2 Мб или 4 МБ), и есть средства OS (для Linux, окна), чтобы получить доступ к этой функциональности.

Ссылка Microsoft выше гласит, что большие страницы "увеличивают эффективность буфера трансляции, что может увеличить производительность для часто используемой памяти". Что не очень полезно при прогнозировании того, улучшат ли большие страницы ту или иную ситуацию. Меня интересуют конкретные, предпочтительно количественные примеры того, как перемещение некоторой логики программы (или целого приложения) для использования огромных страниц привело к некоторому улучшению производительности. У кого-нибудь есть истории успеха ?

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

5 18

5 ответов:

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

Чтобы сделать вещи более сложными, количество записей TLB для страниц 4kB часто больше, чем количество записей для страниц 2MB, но это сильно зависит от процессора. Есть также большое разнообразие в том, сколько записей "большой страницы" доступно в TLB уровня 2.

Например, в системе AMD Opteron семейства 10h Revision D ("Istanbul") cpuid сообщает:

  • L1 DTLB: 4KB страниц: 48 записей; 2MB страниц: 48 записей; 1GB страниц: 48 записей
  • L2 TLB: 4KB страниц: 512 записей; 2MB страниц: 128 записей; 1GB страниц: 16 записей

Находясь в системе Intel Xeon 56xx ("Westmere"), cpuid сообщает:

  • L1 DTLB: 4kB страниц: 64 записи; 2 МБ страниц: 32 записи
  • L2 TLB: 4KB страниц: 512 записей; 2MB страниц: нет

Оба могут сопоставить 2 МБ (512*4кб), используя небольшие страницы, прежде чем страдать пропусками TLB уровня 2, в то время как система Westmere может сопоставить 64 МБ, используя свои 32 записи TLB 2 МБ, а система AMD может сопоставить 352 МБ, используя 176 записей TLB 2 МБ в своих L1 и L2 TLBs. Любая система получит значительное ускорение, используя большие страницы для произвольного доступа по диапазонам памяти, которые намного больше 2 МБ и меньше, чем 64 МБ. Система AMD должна продолжать демонстрировать хорошую производительность, используя большие страницы для гораздо больших диапазонов памяти.

Во всех этих случаях вы пытаетесь избежать наихудшего сценария (Примечание 1) прохождения всех четырех уровней иерархической трансляции адресов x86_64.
Если ни один из механизмов кэширования преобразования адресов (примечание 2) не работает, требуется:

  • 5 переходов в память для загрузки данных, отображенных на странице размером 4 КБ,
  • 4 поездки в память для загрузки данных, отображенных на Страница 2 МБ, и
  • 3 перехода в память для загрузки данных, отображенных на странице объемом 1 ГБ.

В каждом случае последнее обращение к памяти выполняется для получения запрошенных данных, в то время как другие обращения требуются для получения различных частей информации о переводе страницы. Лучшее описание, которое я видел, находится в разделе 5.3 руководства AMD "amd64 Architecture Programmer's Manual Volume 2: System Programming" (публикация 24593) http://support.amd.com/us/Embedded_TechDocs/24593.pdf

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

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

Я попытался придумать какой-нибудь код, который максимизировал бы трепку TLB с 4K страницами, чтобы изучить возможные выгоды от больших страниц. Материал ниже работает в 2,6 раза быстрее (чем 4K страниц), когда 2mbyte страницы предоставляются malloc libhugetlbfs (Intel i7, 64bit Debian Lenny); надеюсь, очевидно, что scoped_timer и random0n делают.

  volatile char force_result;

  const size_t mb=512;
  const size_t stride=4096;
  std::vector<char> src(mb<<20,0xff);
  std::vector<size_t> idx;
  for (size_t i=0;i<src.size();i+=stride) idx.push_back(i);
  random0n r0n(/*seed=*/23);
  std::random_shuffle(idx.begin(),idx.end(),r0n);

  {
    scoped_timer t
      ("TLB thrash random",mb/static_cast<float>(stride),"MegaAccess");
    char hash=0;
    for (size_t i=0;i<idx.size();++i) 
      hash=(hash^src[idx[i]]);
    force_result=hash;
  }

Более простая версия "прямой линии" с всего лишь hash=hash^src[i] получила только 16% от больших страниц, но (дикие предположения) фантазии Intel аппаратная предварительная выборка может помочь в случае 4K, когда доступы предсказуемы (я полагаю, что я мог бы отключить предварительную выборку, чтобы проверить, верно ли это).

Я видел улучшения в некоторых сценариях HPC / Grid-в частности, в физических пакетах с очень, очень большими моделями на машинах с большим количеством оперативной памяти. Кроме того, процесс запуска модели был единственным активным на машине. Я подозреваю, хотя и не измерял, что некоторые функции БД (например, массовый импорт) также выиграют.

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

Это становится эзотерическим, но огромные страницы TLB существенно влияют на архитектуру Intel Xeon Phi (MIC) при передаче памяти DMA (от хоста к Phi через PCIe). по этой ссылке, корпорация Intel описывается, как включить огромные страницы. Я обнаружил, что увеличение размеров передачи DMA за пределами 8 МБ при нормальном размере страницы TLB (4K) начало снижать производительность, примерно с 3 ГБ/С до менее 1 ГБ/с, как только размер передачи достиг 512 МБ.

После включения огромных страниц TLB (2 Мб), скорость передачи данных продолжал увеличиваться до более чем 5 Гбит / с для передачи DMA 512 МБ.

Я получаю ~ 5% ускорение на серверах с большим объемом памяти (>=64 ГБ), выполняющих большие процессы. например, для 16-гигабайтного процесса java это 4M X 4kB страниц, но только 4K x 4MB страниц.