Performans izleme için tsc'yi kullanmaya çalıştığımızı ve talimatların yeniden sıralanmasını önlemek istediğimizi varsayalım.rdtscp, rdtsc: memory ve cpuid/rdtsc arasındaki fark nedir?
1:rdtscp
bir Serileştirme çağrıdır
Bu
bizim seçeneklerdir. Rdtscp'ye çağrı etrafında yeniden sıralamayı engeller.__asm__ __volatile__("rdtscp; " // serializing read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc variable
:
: "%rcx", "%rdx"); // rcx and rdx are clobbered
Ancak rdtscp
yeni işlemci üzerinde kullanılabilir. Bu durumda rdtsc
kullanmamız gerekiyor. Ancak rdtsc
seri hale getirilmiyor, dolayısıyla tek başına kullanmak CPU'nun yeniden sıralanmasını engelleyemez.
2:
yüzden yeniden sıralama önlemek için bu iki seçenekten birini kullanabilirsiniz Bu da cpuid
ve rdtsc
için bir çağrıdır. cpuid
seri hale getirme çağrısıdır.
volatile int dont_remove __attribute__((unused)); // volatile to stop optimizing
unsigned tmp;
__cpuid(0, tmp, tmp, tmp, tmp); // cpuid is a serialising call
dont_remove = tmp; // prevent optimizing out cpuid
__asm__ __volatile__("rdtsc; " // read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc
:
: "%rcx", "%rdx"); // rcx and rdx are clobbered
3: Bu yeniden sıralama önler clobber listesinde memory
ile rdtsc
çağrısı olduğunu
__asm__ __volatile__("rdtsc; " // read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc
:
: "%rcx", "%rdx", "memory"); // rcx and rdx are clobbered
// memory to prevent reordering
aşağıdaki gibi 3 seçenek için My anlayış:
Yapımı __volatile__
numaralı çağrı, eniyileyicinin asm'ı kaldırmasını veya asm'ın sonuçlarına (veya girdilerin değiştirilmesine) gerek duyabilecek herhangi bir yönerge üzerinde hareket etmesini engeller. Ancak ilgisiz operasyonlara göre hareket edebilir. Yani __volatile__
yeterli değil.
Derleyici belleğinin yakalandığını söyle: : "memory")
. "memory"
clobber, GCC'nin, bellek içeriği ile ilgili olarak asm'da aynı kalan tüm varsayımları yapamayacağı anlamına gelir ve bu nedenle, etrafında yeniden sıralama yapmayacaktır.
Yani benim sorular şunlardır:
- 1:
__volatile__
ve"memory"
doğru benim anlayış var mı? - 2: İkinci iki çağrı da aynı şeyi yapıyor mu?
- 3:
"memory"
'u kullanmak, başka bir serileştirme komutunu kullanmaktan çok daha basit görünüyor. Neden 3. seçenekte 3. seçeneği kullanan kimse var? bir yorumda belirtildiği gibi
Sen sen kullanarak önlemek, hangi 'volatile' ve' memory' ve (aka sipariş execution_ ait _out) işlemcisi tarafından çalıştırılan komutların yeniden sıralama kullanarak önleyebilirsiniz derleyici tarafından oluşturulan talimatların yeniden sıralama şaşırtmak gibi görünüyor ' cpuid'. – hirschhornsalz
@hirschhornsalz ama "bellekteki" hafızaya alma işlemi, işlemcinin talimatları yeniden sıralamasını engelliyor mu? Bellek hafıza çiti gibi davranmıyor mu? –
ya da belki de clobber listesindeki 'hafıza 'sadece gcc'ye gönderilir ve sonuçta ortaya çıkan makine kodu bunu işlemciye göstermez mi? –