atomik operasyon maliyeti


92

Atomik işlemin maliyeti nedir (karşılaştırma ve değiştirme veya atomik ekleme / azaltma işlemlerinden herhangi biri)? Ne kadar döngü tüketiyor? SMP veya NUMA'daki diğer işlemcileri duraklatacak mı yoksa bellek erişimlerini engelleyecek mi? Sıra dışı CPU'da yeniden sıralama tamponunu temizleyecek mi?

Önbellekte ne gibi etkiler olacak?

Modern, popüler CPU'larla ilgileniyorum: x86, x86_64, PowerPC, SPARC, Itanium.


@Jason S, Herhangi biri. Cas ve atomic inc / dec arasındaki fark önemsizdir.
osgx

2
Bir x86 üzerindeki atomik işlemler, bellek adresine daha fazla çekişme yerleştirildikçe yavaşlar. Genel olarak, kilitli olmayan işlemden daha yavaş olduklarına inanıyorum, ancak bu, kullanılan işlem, çekişme ve bellek engellerine bağlı olarak değişecektir.
Stephen Nutt

hmmm. yazıyor x86'da atomik görünüyor. 'Linux Çekirdeğini Anlamak' -> spin_unlock
osgx

Java'da 32 bitlik bir yazma atomiktir, yani taşınabilir biçimde atomiktir (ancak bellek engeli anlambilimine sahip değildir, bu nedenle bu genellikle işaretçiler için yeterli değildir). LOCK önekini eklemediğiniz sürece 1 eklemek normalde atomik değildir. Linux çekirdeği hakkında spin_unlock'a bakmaya gerek yok. Bakın, mevcut yayınlarda arch / x86 / include / asm / atomic_32.h (önceden / asm-i386 / atomic.h olarak kullanılırdı).
Blaisorblade

@Blaisorblade, JAva burada değil. KİLİTLİ işlemlerin maliyeti nedir?
osgx

Yanıtlar:


60

Geçen günler için gerçek verileri aradım ve hiçbir şey bulamadım. Bununla birlikte, atomik operasyonların maliyetini önbellek kaçırma maliyetleriyle karşılaştıran bazı araştırmalar yaptım.

X86 LOCK önekinin ( lock cmpxchgatomik CAS dahil ) PentiumPro'dan önceki maliyeti (belgede açıklandığı gibi), bir bellek erişimi (bir önbellek kaçırma gibi), + diğer işlemcilerin bellek işlemlerini durdurma + diğer işlemcilerle herhangi bir ihtilaftır. otobüsü KİLİTLEMEK. Bununla birlikte, PentiumPro, normal Writeback önbelleğe alınabilir bellek için (doğrudan donanımla konuşmadığınız sürece bir uygulamanın kullandığı tüm bellek), tüm bellek işlemlerini engellemek yerine, yalnızca ilgili önbellek hattı engellenir ( @ osgx'in cevabındaki bağlantıya göre ) .

yani çekirdek, fiili lockişlemin mağaza kısmına kadar hat için MESI paylaşımını ve RFO taleplerini yanıtlamayı geciktirir . Buna "önbellek kilidi" denir ve yalnızca o önbellek satırını etkiler. Diğer çekirdekler aynı anda diğer hatları yükleyebilir / depolayabilir veya hatta CASing yapabilir.


Aslında, CAS vakası, bu sayfada açıklandığı gibi , zamanlama olmadan, ancak güvenilir bir mühendis tarafından kapsamlı bir açıklama ile daha karmaşık olabilir . (En azından gerçek CAS'tan önce saf bir yükleme yaptığınız normal kullanım durumu için.)

Çok fazla ayrıntıya girmeden önce, KİLİTLİ bir işlemin bir önbellek eksikliğine + aynı önbellekteki diğer işlemciyle olası çekişmeye mal olduğunu söyleyeceğim; CAS 0 ve 1) iki önbellek eksikliğine mal olabilir.

Tek bir konumdaki bir yükleme + CAS'ın aslında Yük Bağlantılı / Koşullu Depolama gibi iki önbellek eksikliğine mal olabileceğini açıklıyor (ikincisi için oraya bakın). Onun açıklaması, MESI önbellek tutarlılık protokolü bilgisine dayanmaktadır . Bir önbellek çizgisi için 4 durum kullanır: M (odified), E (xclusive), S (hared), I (nvalid) (ve bu nedenle MESI olarak adlandırılır), aşağıda gerektiği yerde açıklanmıştır. Açıklanan senaryo şudur:

  • LOAD, bir önbellekte eksikliğe neden olur - ilgili önbellek, Paylaşılan durumda bellekten yüklenir (yani, diğer işlemcilerin bu önbelleği bellekte tutmasına hala izin verilir; bu durumda hiçbir değişikliğe izin verilmez). Konum hafızadaysa, bu önbellek kaçırılır. Muhtemel maliyet: 1 önbellek eksik. (önbellek Paylaşımlı, Özel veya Değiştirilmiş durumdaysa atlanır, yani veriler bu CPU'nun L1 önbelleğindeyse).
  • program depolanacak yeni değerleri hesaplar,
  • ve atomik bir CAS komutu çalıştırır.
    • Eşzamanlı değişiklikten kaçınması gerekir, bu nedenle önbelleği Özel duruma taşımak için diğer CPU'ların önbelleğinden önbellek kopyalarını kaldırması gerekir. Muhtemel maliyet: 1 önbellek eksik. Zaten münhasır olarak sahip olunan, yani Münhasır veya Değiştirilmiş durumda buna gerek yoktur. Her iki durumda da, başka hiçbir CPU önbelleği tutmaz, ancak Özel durumda (henüz) değiştirilmemiştir.
    • Bu iletişimden sonra, değişken CPU'mızın yerel önbelleğinde değiştirilir ve bu noktada diğer tüm CPU'lar tarafından genel olarak görülebilir (çünkü önbellekleri bizimkilerle uyumludur). Sonunda, olağan algoritmalara göre ana belleğe yazılacaktır.
    • Bu değişkeni okumaya veya değiştirmeye çalışan diğer işlemciler, önce bu önbelleği Paylaşılan veya Özel kipte almak zorunda kalacak ve bunu yapmak için bu işlemciyle iletişim kuracak ve önbelleğin güncellenmiş sürümünü alacak. Bunun yerine KİLİTLİ bir işlem, yalnızca bir önbellek kaybına mal olabilir (çünkü önbellek doğrudan Özel durumda istenecektir).

Her durumda, bir önbellek talebi, verileri zaten değiştiren diğer işlemciler tarafından durdurulabilir.


Neden 1 önbellek eksikken diğer cpus maliyetlerinde durum değişiyor?
osgx

1
Çünkü CPU dışındaki iletişimdir ve bu nedenle önbelleğe erişmekten daha yavaştır. Bir önbellek kaçırma yine de diğer CPU'lardan geçmek zorunda iken. Aslında, en son Xeon işlemcilerde AMD Hypertransport (çok eskiden beri) veya Intel'den Intel QuickPath Interconnect gibi doğrudan bir ara bağlantı kullanılıyorsa, başka bir CPU ile konuşmak bellekle konuşmaktan daha hızlı olabilir. Nehalem'e dayalı. Aksi takdirde, diğer CPU'larla iletişim, bellek için olanla aynı FSB üzerinde gerçekleşir. Daha fazla bilgi için Wikipedia'da HyperTransport ve Front Side Bus'ı arayın.
Blaisorblade

Vay canına, onun bu kadar pahalı olduğunu hiç düşünmemiştim - bir önbellek kaçırma birkaç bin döngü olabilir.
Lothar

2
Gerçekten mi? Alışık olduğum rakamlar: önbellek kayıpları için yüz döngü ve bağlam / ayrıcalık anahtarları için binlerce döngü (sistem çağrıları dahil).
Blaisorblade

1
Önbellek kaçırma birkaç bin döngü değildir! Yaklaşık 100ns, tipik olarak 300-350 CPU döngüsüdür ....
user997112

37

Aşağıdaki kurulumla bazı profilleme yaptım: Test makinesi (AMD Athlon64 x2 3800+) başlatıldı, uzun moda geçirildi (kesintiler devre dışı bırakıldı) ve ilgilenilen talimat bir döngüde yürütüldü, 100 iterasyon açıldı ve 1.000 döngü döngüsü. Döngü gövdesi 16 bayta hizalandı. Zaman, döngüden önce ve sonra bir rdtsc talimatı ile ölçüldü. Ek olarak, herhangi bir talimat içermeyen bir kukla döngü yürütüldü (döngü yinelemesi başına 2 döngü ve geri kalanı için 14 döngü ölçüldü) ve sonuç, komut profili oluşturma süresinin sonucundan çıkarıldı.

Aşağıdaki talimatlar ölçüldü:

  • " lock cmpxchg [rsp - 8], rdx" (hem karşılaştırmalı hem de uyumsuz),
  • " lock xadd [rsp - 8], rdx",
  • " lock bts qword ptr [rsp - 8], 1"

Her durumda ölçülen süre yaklaşık 310 döngüdür, hata yaklaşık +/- 8 döngüdür

Bu, aynı (önbelleğe alınmış) bellekte tekrarlanan yürütme değeridir. Ek bir önbellek kaçırıldığında, süreler önemli ölçüde daha yüksektir. Ayrıca bu, 2 çekirdekten yalnızca biri etkinken yapıldı, bu nedenle önbellek özel olarak sahiplendi ve önbellek senkronizasyonuna gerek yoktu.

Kaçırılan bir önbellekte kilitli talimatın maliyetini değerlendirmek için wbinvld, kilitli talimatın önüne bir talimat ekledim vewbinvld artı add [rsp - 8], raxa'yı karşılaştırma döngüsüne . Her iki durumda da maliyet, komut çifti başına yaklaşık 80.000 döngüdür! Bts kilitlenmesi durumunda, zaman farkı komut başına yaklaşık 180 döngüdür.

Bunun karşılıklı çıktı olduğunu unutmayın, ancak kilitli işlemler serileştirme işlemleri olduğundan, gecikmeden büyük olasılıkla bir fark yoktur.

Sonuç: Kilitli bir işlem ağırdır, ancak bir önbellek kaçırma çok daha ağır olabilir. Ayrıca: kilitli bir işlem önbellek kayıplarına neden olmaz. Yalnızca bir önbellek özelliğine sahip olmadığında önbellek senkronizasyon trafiğine neden olabilir.

Makineyi başlatmak için ReactOS projesinden bir x64 FreeLdr sürümü kullandım. İşte asm kaynak kodu:

#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

Teşekkürler! Test kodunuzu yayınlayabilir veya Core2 / Core i3 / i5 / i7'yi kendiniz test edebilir misiniz? Test kurulumunuzda tüm çekirdekler başlatıldı mı?
osgx

Kaynak kodunu ekledim. Yalnızca bir çekirdek başlatıldı. Diğer makinelerin sonuçlarını görmek isterim.
Timo

CLFLUSH, bir önbellek hattını tüm önbelleğin WBINVD'sinden çok daha hafif bir şekilde temizlemelidir. WBINVD , talimat önbelleklerini de temizleyerek fazladan önbellek eksikliğine yol açar.
Peter Cordes

Paylaşılan durumda önbellek hattının ısınması durumunu test etmek ilginç olabilir. Bunu, başka bir iş parçacığının saf bir yükle okumasını sağlayarak gerçekleştirebilirsiniz.
Peter Cordes

4

Veri yolu tabanlı SMP'de, atomik önek LOCKbir veri yolu kablosu sinyali verir (açar)LOCK# . Veri yolundaki diğer cpus / aygıtları kullanmak için yasaklayacaktır.

Ppro & P2 kitap 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 sayfalar 24

Kilitli talimatlar serileştirme, senkronizasyon işlemleri ... / Sıra dışı / kilitli RMW / okuma-değiştirme-yazma = atomik kendisi / talimat, işlemcinin, çalıştırmadan önce kilitli talimattan önce tüm talimatları yürütmesini sağlar. / henüz yıkanmamış yazmalar hakkında / sonraki talimatı çalıştırmadan önce işlemci içindeki tüm yazılan yazıları harici belleğe boşaltmaya zorlar.

/ SMP hakkında / semafor, S durumunda önbellekte ... 0 baytlık tarih için bir okuma ve geçersiz kılma işlemi yayınlıyor (bu, bitişik CPU'larda önbellek satırının paylaşılan kopyalarının kesilmesidir /)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.