____cacheline_aligned_in_smp для структуры в Linux

Почему в Linux многие структуры используют макрос ____cacheline_aligned_in_smp? Помогает ли это в повышении производительности при доступе к структуре. Если да, то как?

3 ответа

Решение

Каждая строка кэша в любом кэше (dcache или icache) имеет 64-байтовую (в x86) архитектуру. Выравнивание кэша требуется, чтобы избежать ложного расслоения строк кэша. Если строки кэша разделены между глобальными переменными (происходит больше в ядре) Если одна из глобальных переменных была изменена одним из процессоров в его кэше, то она помечает эту строку кэша как грязную. В оставшейся строке CPU cahce она становится устаревшей. Которые должны быть сброшены и извлечены из памяти. Это может привести к пропускам строк кэша. Что требует больше тактов процессора. Это снижает производительность системы. Помните, что это для переменных golabl. Большинство структурирующих данных ядра используют это, чтобы избежать пропусков строк кэша.

____cacheline_aligned инструктирует компилятор создавать экземпляр структуры или переменной по адресу, соответствующему началу строки кэша L1, для конкретной архитектуры, т. е. чтобы она была выровнена по строке кэша L1. ____cacheline_aligned_in_smp аналогично, но на самом деле строка кэша L1 выравнивается только тогда, когда ядро ​​скомпилировано в конфигурации SMP (то есть с опцией CONFIG_SMP). Они определены в файле include/linux/cache.h

Эти определения полезны для переменных (и структур данных), которые не выделяются динамически через некоторый распределитель, но являются глобальными переменными, выделенными компилятором (аналогичный эффект может быть достигнут динамическими распределителями памяти, которые могут выделять память при определенном выравнивании).

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

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

struct my_data {
   long int a;
   int b;
} ____cacheline_aligned_in_smp cpu_data[ NR_CPUS ];

Для определения такого типа от компилятора (в конфигурации ядра SMP) потребуется, чтобы структура каждого процессора начиналась с границы строки кэша. Компилятор неявно выделяет дополнительное пространство после структуры каждого процессора, так что структура следующего процессора также начинается с границы строки кэша.

Альтернативой является заполнение структуры данных размером фиктивных неиспользуемых байтов в строке кэша:

struct my_data {
   long int a;
   int b;
   char dummy[L1_CACHE_BYTES];
} cpu_data[ NR_CPUS ];

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

Linux управляет кэшем ЦП очень похоже на TLB. Кэш-память ЦП, как и кэш-память TLB, использует тот факт, что программы, как правило, демонстрируют локальность ссылок. Чтобы избежать необходимости извлекать данные из основной памяти для каждой ссылки, центральный процессор вместо этого будет кэшировать очень небольшие объемы данных в кэше центрального процессора. Часто существуют два уровня, называемые кэшами ЦП уровня 1 и уровня 2. Кэши ЦП уровня 2 больше, но медленнее, чем кэш-память L1, но Linux заботится только о кешах уровня 1 или L1.

Кэши ЦП организованы в строки. Каждая строка обычно довольно мала, обычно 32 байта, и каждая строка выравнивается по размеру границы. Другими словами, строка в 32 байта будет выровнена по 32-байтовому адресу. В Linux размер строки L1_CACHE_BYTES который определяется каждой архитектурой.

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

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

  • Часто используемые поля структуры находятся в начале структуры, чтобы увеличить вероятность того, что для обращения к общим полям требуется только одна строка;
  • Несвязанные элементы в структуре должны пытаться разделять по крайней мере размер кеша, чтобы избежать ложного разделения между процессорами;
  • Объекты в общих кэшах, таких как кэш mm_struct, выровнены по кэшу ЦП L1, чтобы избежать ложного совместного использования.

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

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

Больше информации здесь

Другие вопросы по тегам