Я немного прочел оптимизацию промахов в кеше и познакомился с этой функцией stdlib. Он выполняет какое-то выравнивание памяти для оптимизации, но может ли кто-нибудь1 помочь мне объяснить, что на самом деле делает эта функция?
Основная цель функции - выделить буфер, выровненный по размеру страницы. Это редко делается для производительности - обычно потому, что требуется буфер, подходящий для драйвера устройства / прямого аппаратного доступа.
Львиная доля производительности по сравнению с проблемами выравнивания памяти уже решена самими компиляторами. Например. все базовые типы - char, short, int, long - уже расположены в памяти (или внутри структуры) на их естественном выравнивании : адрес переменной (или поля структуры) делится на размер переменная. Для этого используется padding . (Например, в char a; int b;
после a
, будет добавлено sizeof(char)-sizeof(int)
байт, чтобы убедиться, что адрес b
выровнен по sizeof(b)
.)
Я не понимаю, что они понимают под "границей" ... Это блок памяти, разбитый на меньший кусок с размером выравнивания?
Устройства H / W (особенно не-PCI) часто видят память как блоки по N байтов и могут одновременно обращаться только к N байтам. Граница в контексте означает начало блока, как в «границе блока».
Теперь, неохотно, я упоминаю влияние выравнивания на производительность. Помните, преждевременная оптимизация - это корень всего зла. Трюки в высокой степени зависят от платформы и CPU, поэтому обычно не должны использоваться:
Выравнивание размера страницы желательно в некоторых случаях, когда вы хотите улучшить локальность ваших данных. Процессоры для преобразования виртуальных адресов в физические места ОЗУ поддерживают кэши. Меньше обращений к коду страниц, меньше нагрузки на процессор. (Большинство ОС уже пытаются оптимизировать разметку страниц приложений, чтобы минимизировать накладные расходы на виртуальный и физический перевод адресов.) Если вы знаете, что ваша очень часто используемая структура соответствует одной странице, то может быть целесообразно поместить ее на страницу выровненное хранилище, чтобы гарантировать, что оно будет содержаться в пределах одной страницы. malloc () не обеспечивает гарантированное и может поместить структуру так, чтобы она начиналась на одной странице и заканчивалась на другой - пересекала границу страницы - занимая две записи в TLB вместо желаемой отдельной записи. ( Как найти размер страницы .)
Строка кэша выравнивание. Хотя приложение может адресовать память в байтах, фактически ЦП может обращаться к физической ОЗУ только к блокам, обычно называемым «строкой кэша». Это наименьшая адресуемая единица физического ОЗУ. Используя выравнивание строки кэша в структуре, мы стремимся минимизировать отпечаток кеша и потери кода в кеше. Размер строки кэша DRAM / DDR составляет 16 байтов. Он может быть больше (32 или 64 байта), если контроллер памяти платформы имеет более широкую шину данных и параллельно обращается к нескольким модулям памяти. Та же логика (что и для выравнивания страниц) применима и здесь: если вы положите, например, Поля структуры, к которым часто обращаются как к группе, выровненные по размеру строки кеша, позволяют существенно сократить объем кеша данных. Простейшим примером будет std::map< struct aaa *, void * >
. Если struct aaa
содержит много полей, для минимизации площади кэша все поля, используемые для сравнения (ключевые поля), помещаются в начало структуры. Если ключевые поля распределены по структуре, сравнение в худшем случае коснется строки кэша для каждого ключевого поля. Если ключевые поля сгруппированы в начале структуры, сравнение, скорее всего, затронет гораздо меньше строк кэша. Меньше потребностей в строках кеша, больше кеша остается для остальной части приложения. Размер строки кэша, как правило, недоступен для приложений, хотя его можно узнать по , используя различные приемы .
Я почистил много мелких деталей, чтобы сделать их относительно короткими. Если вы хотите узнать больше об этом, то рекомендуется прочитать руководство по некоторым процессорам. Например. У Intel довольно неплохие руководства разработчика .