Nel codice del kernel esiste una macro utilizzato per bit di prova (Linux versione 2.6.2): differenza tra il rendimento funzione quando passa parametro tempo di compilazione costante o variabile
#define test_bit(nr, addr) \
(__builtin_constant_p((nr)) \
? constant_test_bit((nr), (addr)) \
: variable_test_bit((nr), (addr)))
cui sono definiti constant_test_bit
e variable_test_bit
come:
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;
}
capisco che __builtin_constant_p
è utilizzato per rilevare se una variabile è tempo di compilazione costante o sconosciuta. La mia domanda è: c'è qualche differenza di prestazioni tra queste due funzioni quando l'argomento è una costante di tempo di compilazione o no? Perché usare la versione C quando è e utilizzare la versione di assemblaggio quando non lo è?
UPDATE: La seguente funzione principale è utilizzata per testare le prestazioni:
costante, chiamata 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;
}
Questa emette correttamente la frase j è un ...
Per le altre situazioni basta decommentare la linea che assegna un numero "casuale" a j
e modificare il nome della funzione in base LY. Quando questa riga non è commentata, l'output sarà vuoto e ciò è previsto.
uso gcc test.c -O1
compilare, e qui è il risultato:
costante, constant_test_bit:
$ time ./a.out
j is compile time constant
real 0m0.454s
user 0m0.450s
sys 0m0.000s
costante, variable_test_bit (omettere time ./a.out
, uguale per i seguenti):
j is compile time constant
real 0m0.885s
user 0m0.883s
sys 0m0.000s
variabile, constant_test_bit:
real 0m0.485s
user 0m0.477s
sys 0m0.007s
variabile, variable_test_bit:
real 0m3.471s
user 0m3.467s
sys 0m0.000s
ho ogni versione viene eseguito più volte, ed i risultati di cui sopra sono i valori tipici di loro. Sembra che la funzione constant_test_bit
sia sempre più veloce della funzione variable_test_bit
, indipendentemente dal fatto che il parametro sia una costante di tempo di compilazione o meno ... Per gli ultimi due risultati (quando j
non è costante) la versione variabile è anche drammaticamente più lenta della costante uno. Mi manca qualcosa qui?
Potrebbe essere, ma l'unico modo per scoprirlo è misurare. – deviantfan
Ovviamente qualcuno ha pensato che potesse fare la differenza in perf, o non ci sarebbero state 2 versioni. Per i dettagli, hai 4 casi da considerare (passando una costante/non costante a una delle due funzioni). Cosa pensi che accada in ogni caso? Hai guardato l'assemblaggio generato? –
@deviantfan Ho aggiunto i risultati delle prestazioni. –