Являются ли спин-блокировки хорошим выбором для распределителя памяти? - PullRequest
8 голосов
/ 16 декабря 2009

Я несколько раз предлагал сопровождающим во время выполнения языка программирования D, чтобы распределитель памяти / сборщик мусора использовал спин-блокировки вместо обычных критических разделов ОС. Это действительно не завоевало популярность. Вот причины, по которым я думаю, что спинлоки будут лучше:

  1. По крайней мере, в синтетических тестах, которые я сделал, это в несколько раз быстрее, чем в критических разделах ОС, когда есть конфликт за блокировку памяти / GC. Изменить: опытным путем, использование спин-блокировки даже не было измеримых накладных расходов в одноядерной среде, вероятно, потому что блокировки должны быть в течение такого короткого периода времени в распределителе памяти.
  2. Распределение памяти и подобные операции обычно занимают небольшую долю временного интервала и даже небольшую долю времени, которое занимает переключение контекста, что делает глупым переключение контекста в случае конфликта.
  3. Сборка мусора в рассматриваемой реализации все равно останавливает мир. Во время коллекции вращений не будет.

Есть ли веские причины не использовать спин-блокировки в реализации распределителя памяти / сборщика мусора?

Ответы [ 6 ]

3 голосов
/ 16 декабря 2009
  1. Очевидно, что наихудшее поведение спин-блокировки ужасное (планировщик ОС видит только 30 потоков, связанных с процессором, поэтому он пытается дать им некоторое время процессора; 29 из них вращаются как безумные, а поток держит замок спит), поэтому вам следует избегать их, если можете. Многие люди умнее меня утверждают, что из-за этого у спинлок есть нет вариантов использования в пользовательском пространстве.

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

  3. Распределитель часто может практически устранить конфликт блокировки, используя блокировку только для выделения страниц потокам. Каждый поток отвечает за разбиение своих страниц. В итоге вы получаете блокировку только один раз при каждом выделении N, и вы можете настроить N так, как вам нравится.

Я считаю 2 и 3 сильными аргументами, которые не могут быть эффективно опровергнуты синтетическими тестами. Вам нужно будет показать, что производительность реальной программы страдает.

2 голосов
/ 16 декабря 2009

Есть ли веские причины не использовать спин-блокировки в реализации распределителя памяти / сборщика мусора?

Когда некоторые потоки привязаны к вычислениям (привязаны к ЦП), а другие потоки привязаны к распределителю памяти, использование спин-блокировок занимает циклы ЦП, которые в противном случае могли бы использоваться либо привязанными к вычислениям потоками, и / или использованными потоками, которые принадлежат к другим процессам.

2 голосов
/ 16 декабря 2009

В любом случае в Windows объекты критических секций уже имеют возможность сделать это (http://msdn.microsoft.com/en-us/library/ms682530.aspx):

Поток использует функцию InitializeCriticalSectionAndSpinCount или SetCriticalSectionSpinCount, чтобы указать счетчик вращений для объекта критической секции. Спиннинг означает, что когда поток пытается получить критическую секцию, которая заблокирована, поток входит в цикл, проверяет, снята ли блокировка, и если блокировка не снята, поток переходит в спящий режим. В однопроцессорных системах счетчик оборотов игнорируется, а счетчик оборотов в критической секции устанавливается на 0 (ноль). В многопроцессорных системах, если критическая секция недоступна, вызывающий поток вращает время dwSpinCount перед выполнением операции ожидания на семафоре, который связан с критической секцией. Если критическая секция освобождается во время операции вращения, вызывающий поток избегает операции ожидания.

Надеюсь, другие платформы последуют их примеру, если они этого еще не сделали.

2 голосов
/ 16 декабря 2009

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

0 голосов
/ 12 июня 2010

Одна из ошибок в сборщике мусора компилятора Glasgow Haskell настолько раздражает, что у него есть имя " последнее замедление ядра ". Это является прямым следствием их неуместного использования спин-блокировок в их ГХ и усугубляется в Linux из-за его планировщика, но на самом деле эффект может наблюдаться, когда другие программы конкурируют за процессорное время.

Эффект очевиден на втором графике здесь и видно, что он влияет не только на последнее ядро ​​ здесь , где программа на Haskell видит снижение производительности за пределами только 5 ядер.

0 голосов
/ 10 января 2010

Не уверен, если я согласен, поскольку выделение памяти МОЖЕТ занимать очень много времени (единственный способ, если вы предварительно не распределяете всю память, а затем повторно ее выделяете) .. Вам действительно нужно попробовать те же распределения и освобождения с несколькими размеры кучи гигабайт с миллионами записей, при этом многие приложения попадают в критическую секцию выделения (приложения для заметок, а не потоки), а также с очисткой / заменой диска из-за недостатка памяти. Вы также можете получить проблемы с заменой диска при распределении, и выполнение спин-блокировки в ожидании запроса диска, безусловно, не подходит.

И, как упомянул CyberShadow для однопоточного процессора, вы в конечном итоге перейдете к обычной блокировке с накладными расходами. Теперь язык может работать на многих встроенных CPUS, которые являются однопоточными.

Также, если вам удастся обойтись блокированным обменом, это лучше (так как он без блокировки, хотя все еще останавливает процессор и повышает LOCK # для многоядерной памяти), но большинство блокировок все равно используют это (но нужно делать больше). Однако структура кучи обычно означает, что блокированного обмена недостаточно, и в итоге вы создаете критическую секцию. Обратите внимание, что в (Поколение) питомнике Mark Sweep с GC можно выполнять распределения в виде взаимосвязанного сравнения и добавления указателя. Я делаю это для Cosmos C # OS GC, и это делает для распределения скорости стека.

...