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

Современные процессоры x86 имеют возможность поддерживать более крупные размеры страниц, чем предыдущие 4K (т.е. 2MB или 4MB), и есть ОС (Linux, Windows) для доступа к этой функции.

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

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

Ответ 1

Я попытался выработать какой-то код, который бы максимизировал избиение TLB с помощью 4k страниц, чтобы изучить возможности, которые можно получить на больших страницах. Ниже приведен пример в 2,6 раза быстрее (чем 4K страниц), когда 2MByte-страницы предоставляются libhugetlbfs malloc (Intel i7, 64-разрядный 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, когда доступ предсказуем (я полагаю, я мог бы отключить предварительную выборку, чтобы выяснить, правда ли это).

Ответ 2

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

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

Например, в системе AMD Opteron Family 10h Revision D ( "Стамбул" ) отчеты cpuid:

  • L1 DTLB: 4kB страницы: 48 записей; 2 МБ страниц: 48 записей; 1 ГБ страниц: 48 записей
  • L2 TLB: 4kB страницы: 512 записей; 2 МБ страниц: 128 записей; 1 ГБ страниц: 16 записей

Пока в системе Intel Xeon 56xx ( "Westmere" ), cpuid сообщает:

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

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

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

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

В каждом случае последняя поездка в память - это получение запрошенных данных, в то время как другие поездки необходимы для получения различных частей информации о переводе страницы. Лучшее описание, которое я видел, приведен в Разделе 5.3 "AMD64 Architecture Programmers Manual Volume 2: System Programming" (публикация 24593) http://support.amd.com/us/Embedded_TechDocs/24593.pdf

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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