2015-05-03 6 views
7

Test bit için kullanılan bir makro (Linux versiyonu 2.6.2) bulunmaktadır olarak:farkı parametre olarak derleme zaman sabit veya değişken geçen Linux çekirdek kod

static inline int constant_test_bit(int nr, const volatile unsigned long *addr ) 
{  
     return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0; 
} 


static __inline__ int variable_test_bit(int nr, const volatile unsigned long *addr) 
{  
     int oldbit; 

     __asm__ __volatile__(
       "btl %2,%1\n\tsbbl %0,%0" 
       :"=r" (oldbit) 
       :"m" (ADDR),"Ir" (nr)); 
     return oldbit; 
} 

Ben __builtin_constant_p değişken sabit veya bilinmeyen derleme süresi olup olmadığını tespit etmek için kullandığını anlıyoruz. Sorum şu: Bu argüman bir derleme zamanı sabiti olduğunda ya da değilken, bu iki işlev arasında herhangi bir performans farkı var mı? Neden C versiyonunu kullanıyor ve kurulmadığı zaman montaj sürümünü kullanıyorsunuz?

GÜNCELLEME: aşağıdaki ana işlevi performansını test etmek için kullanılır:

sabit, çağrı constant_test_bit:

int main(void) { 
     unsigned long i, j = 21; 
     unsigned long cnt = 0; 
     srand(111) 
     //j = rand() % 31; 
     for (i = 1; i < (1 << 30); i++) { 
       j = (j + 1) % 28; 
       if (constant_test_bit(j, &i)) 
         cnt++; 
     } 
     if (__builtin_constant_p(j)) 
       printf("j is a compile time constant\n"); 
     return 0; 
} 

Bu doğru cümle j bir çıkışlarının ...

Diğer durumlar için j'a "rasgele" bir numara atar ve işlev adını ly. Bu hat karşılıksız olduğunda çıktı boş olacak ve bu bekleniyor.

sabit constant_test_bit:

$ time ./a.out 

j is compile time constant 

real 0m0.454s 
user 0m0.450s 
sys  0m0.000s 

sabit variable_test_bit (aşağıdaki aynı time ./a.out, atın):

j is compile time constant 

real 0m0.885s 
user 0m0.883s 
sys  0m0.000s 
burada derlemek ve gcc test.c -O1 kullanımı

sonucudur

değişken, sabit_test_bit:

real 0m0.485s 
user 0m0.477s 
sys  0m0.007s 

değişken, variable_test_bit:

real 0m3.471s 
user 0m3.467s 
sys  0m0.000s 

ben her sürümü birkaç kez çalışır var ve yukarıdaki sonuçlar bunlardan tipik değerlerdir. constant_test_bit işlevinin her zaman variable_test_bit işlevinden daha hızlı olduğu görülüyor, parametrenin bir derleme zamanı sabiti olup olmadığı farketmez ... Son iki sonuç için (j sabit değilken) değişkenin sürümü sabitden bile önemli ölçüde daha yavaştır bir. Burada bir şey eksik miyim?Biz iyileştirici aşağıdaki sürekli ifade davayı optimize edebiliyor bkz

// Non constant expression test case 
int func1(unsigned long i, unsigned long j) 
{ 
    int x = constant_test_bit(j, &i) ; 
    return x ; 
} 

// constant expression test case 
int func2(unsigned long i) 
{ 
    int x = constant_test_bit(21, &i) ; 
    return x ; 
} 

:

+0

Olabilir, ancak öğrenmenin tek yolu ölçmektir. – deviantfan

+0

Açıkçası, birisi mükemmel bir fark yarattığını düşünüyordu ya da 2 versiyon olmayacaktı. Ayrıntılar için, göz önünde bulundurulacak 4 vakanız vardır (her iki fonksiyona da bir sabit/sabit olmayan). Her durumda ne olduğunu düşünüyorsunuz? Oluşturulan meclise baktın mı? –

+0

@deviantfan Performans sonuçlarını ekledim. –

cevap

5

aşağıdaki iki test fonksiyonları -O3 bayrağıyla gcc derlenmektedir, bir experiment using of constant_test_bit yapabiliriz godbolt kullanma

sabit olmayan ekspresyon durumda biter ise
shrq $21, %rax 
andl $1, %eax 

aşağıdaki gibi:

sarl $5, %eax 
andl $31, %ecx 
cltq 
leaq -8(%rsp,%rax,8), %rax 
movq (%rax), %rax 
shrq %cl, %rax 
andl $1, %eax 

Yani iyileştirici sabit ifade vaka için çok daha iyi kod üretmek mümkün ve biz constant_test_bit için sabit olmayan vaka el kıyasla oldukça kötü olduğunu görüyoruz variable_test_bit yılında montaj devirdi ve uygulayıcısı sabit ifadesini inanmalı olabilir çoğu durum için

btl %edi,8(%rsp) 
sbbl %esi,%esi 

: constant_test_bit için durum daha iyi olmak biter.

Test çantanızın neden farklı bir sonuç verdiğini düşündüğünüze göre, test durumunuz kusurludur. Tüm sorunları çözemedim. Hatta ile

movq (%rax), %rdi 

: Ama biz bir sabit olmayan bir ifadeyle constant_test_bit kullanılarak this case bakarsak biz optimize edici görebilirsiniz halkanın içinde constant_test_bit ilgili çalışmaları görünüm dışında tüm çalışmaları taşımak ve azaltmak yapabiliyor Daha eski bir gcc sürümü, ancak bu durum, test_bit'un kullanıldığı durumlarda ilgili olmayabilir. Bu tür bir optimizasyonun mümkün olmayacağı daha özel durumlar olabilir.

+0

Ancak, parametre sabit olmadığında değişken versiyonunu neden kullanıyorsunuz? Gcc tarafından üretilen sabit versiyonun montajı, bu durumda değişken versiyondan daha iyi görünüyor. –

+0

@XiangyuZhu cevabımı güncelledi, testinizin bazı sorunları var, onları tümüyle kızdırmak zor ama bu seçimin ilk sebebi ilk yanıtımda ortaya koyduğum nedenlerden kaynaklandı. Ilgili vakaları kullanarak kıyaslama yaptıklarını ve varsayımın gerçekten uygun fakat bilmesi zor olduğundan emin olmasını umardım. –

+0

Evet, belki de kodumun test etmek için kullandığı yol, "özel" yani gcc'nin "variable_test_bit" değerinden daha fazla optimize edebilmesini sağlıyor. Son çekirdek koduna baktım ve benzer kodun hala orada olduğunu öğrendim, bu yüzden bunun için iyi bir neden olması gerekir (farklı işlev sürümlerini kullanarak). Ancak şimdilik yalnız bırakmaya karar verdim. Cevabınız için teşekkürler. –

İlgili konular