Какой самый быстрый способ инициализации вновь выделенной памяти в C ++? - PullRequest
0 голосов
/ 09 февраля 2019

Я пытаюсь выделить и использовать 100 МБ данных (size_t s = 100 * 1024 * 1024) и измерил различными способами в C ++:

Необработанное выделение без init:

// < 0.01 ms
auto p = new char[s]; 

C ++ ноль-init:

// 20 ms
auto p = new char[s](); 

Ручной ноль-init:

// 20 ms
auto p = new char[s];
for (auto i = 0; i < s; ++i) 
    p[i] = 0;

Это не ограничение моей памяти, о чем свидетельствует повторная запись памяти:

// 3 ms
std::memset(p, 0xFF, s);

Я также пробовал std::malloc и std::calloc, но они показывают то же самое поведение.calloc возвращает память с нулевой инициализацией, но если я потом сделаю memset, это все равно займет 20 мс.

Насколько я понимаю, неинициализированная память быстро выделяется, потому что она на самом деле не касаетсяобъем памяти.Только когда я получаю к нему доступ, страницы выделяются для моей программы.3 мс для установки 100 МБ соответствуют ~ 35 ГБ / с, что нормально.Кажется, что 20 мс являются издержками при возникновении ошибок страницы.

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

// 6-10 ms
auto p = new char[s];
#pragma omp parallel for
for (auto i = 0; i < s; ++i) 
    p[i] = 0;

Мой вопрос: есть ли способ не только распределить память, но и сразу же распределить все страницы, чтобы при обращении к ней не возникало дальнейших сбоев страниц?

Я хотел бы по возможности избегать использования огромных страниц.

(Измерение с std::chrono::high_resolution_clock)

Это было сделано на моей настольной системе (5 ГГц i9, 3600 МГц DDR4)., Linux Mint 19, ядро ​​4.15.0-45-generic) с Clang 7 (-O2 -march=native), хотя, глядя на сборку, проблема не в компиляторе.

EDIT: Это упрощенный пример,в моем реальном приложении мне нужно инициализировать его значением, отличным от 0, но это не меняет времени вообще.

...