2015-03-27 10 views
12

Stavamo lavorando su nostro progetto lettore audio su Mac e ho notato che il consumo di energia era così alto (circa 7x quella di Google Chrome facendo lo stesso carico di lavoro.)perché una variabile condizionale fissa il nostro consumo di energia?

ho usato strumento di profiling di energia di Xcode, uno dei problemi era abbiamo avuto troppa CPU in testa.

Secondo Xcode:

Ogni volta che la CPU si sveglia dal minimo, c'è una penalità energetica sostenuti. Se le scie sono alte e l'utilizzo della CPU per scia è basso, è necessario considerare il lavoro di batching.

Abbiamo ridotto il problema a una chiamata di funzione usleep.

Nel nostro codice, il decodificatore audio è un produttore che produce dati audio e li inserisce nel consumatore - il lettore audio. Il nostro lettore audio è basato su OpenAL, che ha un buffer per i dati audio.

Poiché il lettore audio può essere più lento del produttore, controlliamo sempre la disponibilità del buffer prima di fornire nuovi dati audio al lettore audio. Se nessun buffer è disponibile, ci addormentiamo per un po 'e riproviamo. Così il codice è simile:

void playAudioBuffer(Data *data) 
{ 
    while(no buffer is available) 
    { 
     usleep() 
    } 
    process data. 
} 

Sapendo che usleep è un problema, la prima cosa che abbiamo fatto è stato semplicemente rimuovendo usleep(). (Poiché OpenAL non sembra fornire callback o in altro modo, il polling sembra essere l'unica opzione.) Abbiamo ridotto l'utilizzo di energia della metà dopo averlo fatto.

Poi, ieri, abbiamo provato

for(int i =0; i<attempts; ++i) 
{ 
    std::unique_lock<std::mutex> lk(m); 
    cv.wait_for(lk, 3, []{ 
          available = checkBufferAvailable(); 
          return available; 
         }) 

    if (available) 
    { 
     process buf; 
    } 
} 

Questo è un esperimento che abbiamo provato per caso. Non ha senso per noi, poiché logicamente esegue la stessa attesa. E l'uso della variabile condizionale non è corretto, perché la variabile "disponibile" è accessibile solo da un thread. Ma in realtà ha ridotto il nostro consumo di energia del 90%, l'utilizzo della CPU del thread è diminuito molto. Ora siamo migliori di chrome. Ma come la variabile condizionale viene implementata in modo diverso dal seguente codice? Perché ci salva energia?

mutex lock; 
while(condition is false) 
{ 
    mutex unlock; 
    usleep(); 
    mutex lock; 
} 
... 
mutex unlock 
... 

(Usiamo il monitor del Mac attività (numero di energia) e uno strumento di utilizzo di profilazione della CPU per misurare il consumo di energia.)

+5

Forse il cv gira invece di dormire in alcuni casi? E forse fa uno spin lock "lento" o "low power" ... in qualche modo? (btw, 3 quali unità di tempo? Stiamo parlando di 'std :: condition_variable' qui? Come funziona 3?) Oh, non stai postando codice reale, stai trascrivendo manualmente e hai introdotto un numero sconosciuto di errori e omissioni. Per favore non farlo: per favore pubblica un codice che riproduca effettivamente la cosa che ti interessa. Ciò potrebbe comportare la semplificazione del codice esistente: se hai capito cosa ha causato la tua cosa interessante, non ti staresti chiedendo qui! – Yakk

+2

Oppure potresti semplicemente aspettare più a lungo con una condizione in confronto a noi addormentati? – Lol4t0

+0

in entrambi i casi aspettiamo 3 millisecondi e riproviamo. abbiamo provato ad esempio 4 millisecondi e notato singhiozzo –

risposta

1

Posso sbagliarmi, ma per quanto ho capito quando si utilizza variabile condizionale per attuare l'attesa per il reddito dei dati del buffer. La cosa principale che fa è mettere il thread, che rende questa variabile di condizione, in sleep fino a quando un segnale ad esso associato non riattiva questo thread. Questo è il motivo per cui si ottiene meno risveglio e si utilizzano le risorse in modo più efficiente.

qui ci sono link a lavorare con fili in Linux, dove ho letto su di esso:

Può essere questo vi darà una certa comprensione perché e come succede

Ancora una volta non sono del tutto sicuro di avere perfettamente ragione, ma mi sembra una giusta direzione.

Ci scusiamo per il mio inglese puro.

+0

Nel caso dell'OP, niente riattiva mai il thread - dorme sempre fino al timeout. – Arkadiy

0

Se si desidera ridurre il consumo di energia il più possibile su un Mac o iOS, è possibile utilizzare almeno un dispatch_semaphore_t per attendere esattamente fino a quando il buffer è pieno o passare qualche blocco al codice di riempimento del buffer.