2009-10-09 1 views
2

Я хочу сохранить память, преобразовывая существующий 32-разрядный счетчик в 16-разрядный счетчик. Этот счетчик атомарно увеличивается/уменьшается. Если я это сделаю:Могу ли я атомарно увеличивать 16-разрядный счетчик на x86/x86_64?

  1. Какие инструкции я использую для atomic_inc (uint16_t x) на x86/x86_64?
  2. Является ли это надежным в многопроцессорных машинах x86/x86_64?
  3. Есть ли штраф за исполнение, заплаченный за любую из этих архитектур за это?
  4. Если да для (3), какова ожидаемая штрафная ставка исполнения?

Спасибо за ваши комментарии!

+4

Если у вас много счетчиков (и это много, как в мегабайтах), то, похоже, очень много усилий, чтобы сэкономить 2 байта. Что такое * актуальная * проблема, которую вы пытаетесь решить здесь? –

+1

Да, у меня есть * много * этих счетчиков в мегабайтах. Каждый такой счетчик представляет ожидающие операции в соответствующем блоке памяти. Когда счетчик опускается до нуля, я должен запустить еще одну операцию. – Sudhanshu

+0

Возможный дубликат [Может num ++ быть атомарным для 'int num'?] (Https: // stackoverflow.com/questions/39393850/can-num-be-atomic-for-int-num) –

ответ

4

Вот один, который использует GCC расширения сборки, в качестве альтернативы Delphi ответ Стива:

uint16_t atomic_inc(uint16_t volatile* ptr) 
{ 
    uint16_t value(1); 
    __asm__("lock xadd %w0, %w1" : "+r" (value) : "m" (*ptr)); 
    return ++value; 
} 

Изменение 1 с -1, а ++ с -- для декремента.

+0

Спасибо, но я действительно говорю о AMD64/Pentiums здесь. :) – Sudhanshu

+0

Это круто. Я все еще даю вам альтернативу C, если вы не хотите кодировать Delphi. :-) –

+0

(Ну, измените инициализаторы от 'uint_t value (1)' до 'uint_t value = 1' для C (мои привычки C++ доходят до меня), но да. :-P) –

3

Вот функция Delphi, которая работает:

function LockedInc(var Target :WORD) :WORD; 
asm 
     mov  ecx, eax 
     mov  ax, 1 
    Lock xadd [ecx], ax 
     Inc  eax 
end; 

Я думаю, вы могли бы преобразовать его в каком бы языке вы требуете.

+0

Чтобы уточнить для пользователей, не являющихся пользователями Delphi/BASM, я бы добавил, что в этой (32-разрядной) подпрограмме указатель на Target будет передан в в EAX и что возвращаемое значение функции будет в AX. – PhiS

+0

Вы намеренно оставляете высокую половину возвращаемого значения = высокую половину указателя ввода, или это ошибка? Вам может понадобиться 'mov ecx, 1' (а не только CX) /' lock xadd [eax], cx'/'lea eax, [ecx + 1]'. (У этого есть [частичный регистрационный стоп на старых Intel-процессорах (Nehalem и ранее)] (https://stackoverflow.com/questions/41573502/why-doesnt-gcc-use-partial-registers) после чтения 'ecx' после пишите 'cx'. Используйте отдельные инструкции movzx + inc, чтобы избежать необходимости при необходимости.) –

-1

Чтобы ответить на другие три вопроса:

  1. Не нашел способ сделать нумерованный список, начиная с 2
  2. Да, это надежно в многопроцессорной среде
  3. Да, есть штраф за исполнение
  4. Префикс «блокировка» блокирует шины не только для процессора, но и для любого внешнего оборудования, которое может хотеть получить доступ к шине через DMA (массовое хранение, графика ...). Таким образом, он медленный, обычно ~ 100 тактов, но он может быть более дорогостоящим. Но если у вас есть «мегабайты» счетчиков, скорее всего, вы столкнетесь с промахом кэш-памяти, и в этом случае вам придется ждать около 100 часов в любом случае (время доступа к памяти), в случае пропусков страницы несколько сто, поэтому накладные расходы от блокировки могут не иметь значения.
+0

Спасибо за ваш ответ. Это ближе всего к тому, что я искал после ответа Криса. – Sudhanshu

+3

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

+1

Downvoted, потому что нет штрафа за производительность или, может быть, тривиального даже для одного атомного счетчика. При большом массиве атомных счетчиков размер 16-разрядных операндов должен быть большой победой. Операции с байтами и словами поддерживаются изначально аппаратным обеспечением кэша x86, поэтому я не ожидаю никаких проблем, если слова выравниваются по 16 бит. 'lock inc word [mem]' должно иметь в основном идентичную производительность для 'lock inc dword [mem]' (игнорировать промахи кэша). –

0

Самый простой способ выполнить атомное увеличение следующим образом (это встроенный ASM):

asm 
    lock inc dword ptr Counter; 
end; 

, где J представляет собой целое число. Это будет напрямую увеличивать счетчик в памяти.

Я проверил это с грубой силой, и он работает на 100%.

+0

OP хочет 16-битный счетчик, но да, это будет работать с 'word' вместо' dword'. BTW, единственный способ, которым вы могли бы сказать что-то «работает на 100%» на основе тестирования грубой силы (без проверки руководства), - это проверить его на каждом текущем * и будущем процессоре x86. Все, где префикс 'lock' не является ошибкой, на 100% гарантированно атомным (я думаю, по крайней мере, для инструкций, где префикс' lock' документирован для применения). Но, например, 'movdqa [eax], xmm0' является атомарным для некоторых процессоров, но не для других, поэтому тестирование на Core2 не будет выявлять проблемы на некоторых многопроцессорных Opteron. –

Смежные вопросы