2012-03-28 5 views
10

Quando sono giù per spremere l'ultimo pezzo di prestazioni da un kernel, di solito trovo che la sostituzione del operatori logici (&& e ||) con operatori bit per bit (& e |) rende il kernel di un po 'più veloce . Ciò è stato osservato osservando il riepilogo del tempo del kernel in CUDA Visual Profiler.CUDA: Perché gli operatori bit a bit sono talvolta più veloci degli operatori logici?

Quindi, perché gli operatori bit a bit più veloci rispetto agli operatori logici in CUDA? Devo ammettere che sono non sempre più veloce, ma molte volte lo sono. Mi chiedo quale magia possa dare questa accelerazione.

Disclaimer: Sono consapevole del fatto che gli operatori logici di cortocircuiti e operatori bit a bit no. Sono ben consapevole di come questi operatori possano essere utilizzati impropriamente con conseguente codice errato. Uso questa sostituzione con cura solo quando la logica risultante rimane la stessa, c'è un aumento di velocità e l'aumento ottenuto mi importa :-)

+0

Grazie per l'ottimo consiglio di ottimizzazione! –

+0

Roger: Felice di aiutare! Sono stato sorpreso anche quando ho scoperto questo :-) –

risposta

11

Gli operatori logici generano spesso rami, in particolare quando è necessario osservare le regole della valutazione di cortocircuito. Per le CPU normali ciò può significare una errata interpretazione dei rami e per CUDA può significare divergenza di ordito. Le operazioni bit a bit non richiedono la valutazione del cortocircuito, quindi il flusso del codice è lineare (cioè senza ramo).

+1

Inoltre, per l'operatore logico, un risultato diverso da zero deve essere impostato su 1. –

+1

@Roger: true, ma spesso questo può essere ottimizzato, ad es. se l'espressione viene utilizzata come parte di un condizionale, il risultato deve essere impostato su 1 solo se è assegnato a una variabile. –

1

Le operazioni bit a bit possono essere eseguite nei registri a livello hardware. Le operazioni di registrazione sono le più veloci, questo è particolarmente vero quando i dati possono essere inseriti nel registro. Le operazioni logiche implicano una valutazione dell'espressione che potrebbe non essere associata al registro. Tipicamente &, |, ^, >> ... sono alcune delle operazioni più veloci e ampiamente utilizzate nella logica ad alte prestazioni.

6

A & & B:

if (!A) { 
    return 0; 
} 
if (!B) { 
    return 0; 
} 
return 1; 

A & B:

return A & B; 

Queste sono le semantiche considerando che la valutazione A e B può avere effetti collaterali (che può essere funzioni che alterano lo stato del sistema quando valutato).

Ci sono molti modi in cui il compilatore può ottimizzare il caso A && B, a seconda dei tipi di A e B e del contesto.