The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Копии переменных для каждого процессора

Копии переменных для каждого процессора

Предыдущая  Содержание  Следующая V*D*V

Per-CPU variables (По-Процессорные переменные) являются интересной особенностью ядра версии 2.6. Когда вы создаёте по-процессорную переменную, каждый процессор в системе получает собственную копию этой переменной. Желание сделать это может показаться странным, но оно имеет свои преимущества. Доступ к по-процессорным переменным не требует (почти) блокирования, потому что каждый процессор работает со своей собственной копией. По-процессорные переменные могут также оставаться в своих процессорных кэшах, что приводит к существенно более высокой производительности для часто обновляемых параметров.

 

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

 

Декларация по-процессорных переменных может быть найдена в <linux/percpu.h>. Чтобы создать по-процессорную переменную во время компиляции, используйте этот макрос:

 

DEFINE_PER_CPU(type, name);

 

Если переменная (которая будет называться name) является массивом, включается информация о типе массива. Таким образом, по-процессорный массив из трёх чисел был бы создан так:

 

DEFINE_PER_CPU(int[3], my_percpu_array);

 

По-процессорными переменными можно манипулировать почти без явного блокирования. Помните, что ядро версии 2.6 является вытесняющим; это бы не следует делать в середине критической секции, которая модифицирует по-процессорную переменную. Также будет не хорошо, если ваш процесс будет перемещён в другой процессор в середине доступа к по-процессорной переменной. По этой причине вы должны явно использовать макрос get_cpu_var для непосредственного доступа к данной переменной текущего процессора и вызвать put_cpu_var по окончании. Вызов get_cpu_var возвращает величину для прямого доступа к текущей процессорной версии переменной и отключает вытеснение. Поскольку возвращается сама переменная, она может быть напрямую использоваться для присваивания или управления. Например, один счётчик в сетевом коде увеличивается этими двумя командами:

 

get_cpu_var(sockets_in_use)++;

put_cpu_var(sockets_in_use);

 

Вы можете получить доступ другой процессорной копии переменной с помощью:

 

per_cpu(variable, int cpu_id);

 

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

 

Динамическое создание по-процессорной переменной также возможно. Эти переменные могут быть созданы так:

 

void *alloc_percpu(type);

void *__alloc_percpu(size_t size, size_t align);

 

В большинстве случаев alloc_percpu делает свою работу, вы можете вызвать __alloc_percpu в случаях, когда требуется особое выравнивание. В любом случае, по-процессорная переменная может быть возвращена системе с помощью free_percpu. Доступ к динамически созданной по-процессорной переменной осуществляется через per_cpu_ptr:

 

per_cpu_ptr(void *per_cpu_var, int cpu_id);

 

Этот макрос возвращает указатель на версию per_cpu_var, соответствующей данному cpu_id. Если вы просто читаете другую процессорную версию переменной, вы можете разыменовать указатель и что-то сделать с ней. Однако, если вы манипулируете текущей процессорной версией, то вероятно, сначала надо убедиться, что вы не можете быть передвинуты из этого процессора. Если весь доступ к по-процессорной переменной происходит с удержанием спин-блокировки, всё хорошо. Однако, обычно для блокировки вытеснения при работе с переменной вам необходимо использовать get_cpu. Таким образом, код, использующий динамические по-процессорные переменные, как правило, выглядит следующим образом:

 

int cpu;

 

cpu = get_cpu( )

ptr = per_cpu_ptr(per_cpu_var, cpu);

/* работаем с ptr */

put_cpu( );

 

При использовании по-процессорных переменных во время компиляции, макросы get_cpu_var и put_cpu_var заботятся об этих деталях. Динамические по-процессорные переменные требуют более явной защиты.

 

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

 

EXPORT_PER_CPU_SYMBOL(per_cpu_var);

EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);

 

Для доступа к таким переменным внутри модуля, объявите её так:

 

DECLARE_PER_CPU(type, name);

 

Использование DECLARE_PER_CPU (вместо DEFINE_PER_CPU) сообщает компилятору, что создаётся внешняя ссылка.

 

Если вы хотите использовать по-процессорные переменные для создания простого целочисленного счётчика, взгляните на заготовленную реализацию в <linux/percpu_counter.h>. Наконец, отметим, что некоторые архитектуры имеют ограниченный объём адресного пространства, доступного для по-процессорных переменных. Если вы создаёте по-процессорные переменные, вы должны попытаться сохранить их число небольшим.

Предыдущая  Содержание  Следующая