вартість атомної експлуатації


90

Яка вартість атомної операції (будь-яке порівняння та обмін або атомне додавання / зменшення)? Скільки циклів він споживає? Це призупинить інші процесори на SMP або NUMA, або заблокує доступ до пам'яті? Чи буде він змивати буфер переупорядкування в непрацюючому ЦП?

Які наслідки матимуть на кеш-пам’яті?

Мене цікавлять сучасні, популярні процесори: x86, x86_64, PowerPC, SPARC, Itanium.


@Jason S, Any. Різниця між cas та атомними inc / dec незначна.
osgx

2
Атомні операції на x86 стають повільнішими, оскільки більше суперечок розміщується на адресі пам'яті. Я вважаю, що загалом вони на порядок повільніше, ніж незаблокована операція, але явно це буде змінюватися залежно від операції, суперечок та використовуваних бар'єрів пам'яті.
Стівен Натт,

хммм. пише, здається, атомний на x86. 'Розуміння ядра Linux' -> spin_unlock
osgx

32-бітна запис є атомною в Java, тобто є портативною атомною (але не має семантики бар'єру пам'яті, тому цього часто недостатньо для покажчиків). Додавання 1 зазвичай не є атомним, якщо ви не додасте префікс LOCK. Щодо ядра Linux, не потрібно дивитись на spin_unlock. Див. У поточних випусках arch / x86 / include / asm / atomic_32.h (раніше це було include / asm-i386 / atomic.h).
Blaisorblade

@Blaisorblade, JAva тут немає. Яка вартість заблокованих операцій?
osgx

Відповіді:


59

Я шукав фактичні дані за минулі дні і нічого не знайшов. Однак я провів деякі дослідження, які порівнюють вартість атомних операцій з витратами на пропуск кешу.

Вартість префікса x86 LOCK (включаючи lock cmpxchgатомний CAS) перед PentiumPro (як описано в документі) - це доступ до пам'яті (наприклад, пропуск кешу), + зупинка операцій з пам'яттю іншими процесорами, + будь-яка суперечка з іншими процесорами. намагається заблокувати автобус. Однак, оскільки PentiumPro для звичайної кеш-пам’яті Writeback (вся пам’ять, з якою працює програма, якщо ви не спілкуєтеся безпосередньо з обладнанням), замість блокування всіх операцій з пам’яттю блокується лише відповідний рядок кешу (на основі посилання у відповіді @ osgx ) .

тобто ядро ​​затримує відповідь на запити MESI-спільного доступу та RFO на лінію до закінчення частини фактичної lockоперації редагування. Це називається "блокуванням кешу" і впливає лише на один рядок кешу. Інші ядра можуть одночасно завантажувати / зберігати або навіть обробляти інші лінії.


Насправді, справа CAS може бути більш складною, як пояснюється на цій сторінці , без термінів, зате проникливий опис надійного інженера. (Принаймні для звичайного випадку використання, коли ви виконуєте чисте навантаження до фактичного CAS.)

Перш ніж вдаватися до занадто детальних деталей, я скажу, що заблокована операція коштує одного пропуску кеш-пам’яті + можливої ​​суперечки з іншим процесором на тій самій кеш-лінії, тоді як CAS + попереднє завантаження (що майже завжди потрібно, за винятком мьютексів, де ви завжди CAS 0 та 1) можуть коштувати двох помилок кешу.

Він пояснює, що навантаження + CAS в одному місці може насправді коштувати двох помилок кешу, як Load-Linked / Store-Conditional (див. Там останнє). Його пояснення спирається на знання протоколу когерентності кешу MESI . Він використовує 4 стани для кешеліну: M (одифікований), E (ексклюзивний), S (зайнятий), I (недійсний) (і тому він називається MESI), що пояснюється нижче, де це потрібно. Пояснюваний сценарій такий:

  • Функція LOAD випромінює кеш-пам’ять - відповідна лінія зберігання завантажується з пам'яті у загальному стані (тобто іншим процесорам все ще дозволяється зберігати цю кеш-лінію в пам’яті; в цьому стані зміни не допускаються). Якщо місцезнаходження знаходиться в пам'яті, ця помилка кешу пропускається. Можлива вартість: 1 промах кешу.(пропускається, якщо кеш-лінія знаходиться у загальному, ексклюзивному чи модифікованому стані, тобто дані знаходяться в кеші L1 цього процесора).
  • програма обчислює нові значення для зберігання,
  • і він запускає атомну інструкцію CAS.
    • Він повинен уникати одночасних модифікацій, тому він повинен видалити копії кеш-лінії з кешу інших центральних процесорів, щоб перемістити кеш-лінію в ексклюзивний стан. Можлива вартість: 1 промах кешу. Це не потрібно, якщо воно вже є виключно у власності, тобто в ексклюзивному або модифікованому стані. В обох штатах жоден інший центральний процесор не містить кеш-лінії, але в ексклюзивному стані він ще не змінений (поки).
    • Після цього спілкування змінна змінюється в локальному кеші нашого центрального процесора, після чого вона стає загальновизнаною для всіх інших процесорів (оскільки їх кеші є когерентними з нашими). Зрештою він буде записаний в основну пам’ять за звичайними алгоритмами.
    • Інші процесори, які намагаються прочитати або змінити цю змінну, спочатку повинні отримати цю кеш-лінію в загальному або ексклюзивному режимі, а для цього зв’яжуться з цим процесором та отримають оновлену версію кеш-лінії. Натомість операція LOCKED може коштувати лише пропуску кешу (оскільки кеш-лінія буде запитуватися безпосередньо в ексклюзивному стані).

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


чому зміна стану на інших процесорах коштує як 1 пропуск кешу?
osgx

1
Оскільки це зв’язок поза центральним процесором, а отже, повільніший, ніж доступ до кешу. Хоча пропуск кешу все одно повинен передаватися від інших процесорів. Насправді, може бути так, що розмова з іншим центральним процесором є швидшою, ніж розмова з пам'яттю, якщо на найновіших процесорах Xeon використовується пряме взаємозв’язок, наприклад AMD Hypertransport (з часів величезної давності), або Intel QuickPath Interconnect від Intel. на основі Негалема. В іншому випадку зв'язок з іншими процесорами відбувається на тій самій FSB, що і для пам'яті. Шукайте HyperTransport та Front Side Bus у Вікіпедії для отримання додаткової інформації.
Blaisorblade

Нічого собі, ніколи не думав, що його так дорого - пропуск кешу може тривати кілька тисяч циклів.
Lothar

2
Справді? Цифра, якою я звик: сто циклів пропусків кеш-пам’яті та тисячі циклів перемикачів контексту / привілеїв (включаючи системні виклики).
Blaisorblade

1
Пропуск кешу - це не кілька тисяч циклів! Це близько 100 нс, що зазвичай становить 300-350 циклів процесора ....
user997112

37

Я зробив деяке профілювання з наступним налаштуванням: Тестову машину (AMD Athlon64 x2 3800+) було завантажено, переведено в довгий режим (переривання відключено), а інструкція, що цікавила, виконувалась у циклі, 100 ітерацій розгорнуто та 1000 циклів циклу. Тіло циклу було вирівняно до 16 байт. Час вимірювали за допомогою інструкції rdtsc до і після циклу. Крім того, був виконаний фіктивний цикл без будь-якої інструкції (який вимірював 2 цикли за ітерацію циклу та 14 циклів для решти), а результат був вилучений з результату часу профілювання інструкцій.

Виміряно наступні інструкції:

  • " lock cmpxchg [rsp - 8], rdx" (як із порівнянням, так і з невідповідністю),
  • " lock xadd [rsp - 8], rdx",
  • " lock bts qword ptr [rsp - 8], 1"

У всіх випадках виміряний час становив близько 310 циклів, похибка становила приблизно +/- 8 циклів

Це значення для повторного виконання в одній і тій же (кешованій) пам'яті. З додатковим пропуском кешу час стає значно вищим. Також це було зроблено лише з одним із 2 активних ядер, тому кеш належав виключно у власності, і не потрібно було синхронізації кешу.

Щоб оцінити вартість заблокованої інструкції щодо пропуску кешу, я додав wbinvldінструкцію перед заблокованою інструкцією і помістив wbinvldплюс і add [rsp - 8], raxв цикл порівняння. В обох випадках вартість склала близько 80 000 циклів за пару інструкцій! У випадку блокування bts різниця в часі становила близько 180 циклів за інструкцію.

Зауважте, що це взаємна пропускна здатність, але оскільки заблоковані операції є серіалізаційними, то, мабуть, немає різниці в затримці.

Висновок: заблокована операція важка, але пропуск кешу може бути набагато важчим. Також: заблокована операція не спричиняє помилок кешу. Це може спричинити трафік синхронізації кешу лише тоді, коли кеш-лінія не належить виключно.

Для завантаження машини я використав x64 версію FreeLdr із проекту ReactOS. Ось вихідний код asm:

#define LOOP_COUNT 1000
#define UNROLLED_COUNT 100

PUBLIC ProfileDummy
ProfileDummy:

    cli

    // Get current TSC value into r8
    rdtsc
    mov r8, rdx
    shl r8, 32
    or r8, rax

    mov rcx, LOOP_COUNT
    jmp looper1

.align 16
looper1:

REPEAT UNROLLED_COUNT
    // nothing, or add something to compare against
ENDR

    dec rcx
    jnz looper1

    // Put new TSC minus old TSC into rax
    rdtsc
    shl rdx, 32
    or rax, rdx
    sub rax, r8

    ret

PUBLIC ProfileFunction
ProfileFunction:

    cli

    rdtsc
    mov r8, rdx
    shl r8, 32
    or r8, rax
    mov rcx, LOOP_COUNT

    jmp looper2

.align 16
looper2:

REPEAT UNROLLED_COUNT
    // Put here the code you want to profile
    // make sure it doesn't mess up non-volatiles or r8
    lock bts qword ptr [rsp - 8], 1
ENDR

    dec rcx
    jnz looper2

    rdtsc
    shl rdx, 32
    or rax, rdx
    sub rax, r8

    ret

Дякую! Чи можете ви опублікувати свій тестовий код або протестувати Core2 / Core i3 / i5 / i7 самостійно? Чи всі ядра були ініціалізовані у вашому тестовому налаштуванні?
osgx

Я додав вихідний код. Ініціалізовано лише одне ядро. Хотілося б побачити результати від інших машин.
Тимо

CLFLUSH повинен бути набагато легшим способом очищення рядка кешу, ніж WBINVD усього кешу. WBINVD також очистить кеш інструкцій, що призведе до додаткових помилок кешу.
Пітер Кордес,

Можливо, цікаво протестувати випадок гарячої лінії кешу в Shared state. Ви можете зробити це, якщо інший потік прочитає його з чистим навантаженням.
Пітер Кордес,

4

На SMP на основі шини атомний префікс LOCKстверджує (вмикає) сигнал дротової шини LOCK#. Він забороняє використовувати інші шини / пристрої на шині.

PPRO & P2 книга http://books.google.com/books?id=3gDmyIYvFH4C&pg=PA245&dq=lock+instruction+pentium&lr=&ei=_E61S5ehLI78zQSzrqwI&cd=1#v=onepage&q=lock%20instruction%20pentium&f=false сторінки 244-246

Заблоковані інструкції - це серіалізація, синхронізація операцій .... / про Невпорядкований / заблокований RMW / read-modify-write = atomic сам / інструкція гарантує, що процесор виконуватиме всі інструкції до заблокованої інструкції до її виконання. / про ще не змиті записи / він змушує всі розміщені записи в процесорі переноситись у зовнішню пам’ять перед виконанням наступної інструкції.

/ про SMP / семафор знаходиться в кеші в штаті S ... видає транзакцію зчитування та анулювання на 0 байт дати (це вбивство / спільних копій рядка кешу в сусідніх центральних процесорах /)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.