È saggio affidarsi alle ottimizzazioni?

7

Devo scrivere il mio codice per chiarire cosa sto facendo e fare affidamento sull'ottimizzatore per ripulire l'efficienza del mio codice, o dovrei essere ossessionato dall'ottenere un'ultima goccia di energia dal mio codice?

E quanta velocità / dimensioni sto perdendo scegliendo un'opzione rispetto all'altra?

    
posta DarthRubik 07.05.2016 - 00:46
fonte

5 risposte

4

Ci sono 2 tipi di ottimizzazioni molto diversi.

Il primo sono le micro-ottimizzazioni. Sono cose come (ad esempio) cambiando x = (y * 4 + z) / 2 in x = y + y + z / 2 o x = y % 8 in x = y & 7 . I compilatori sono molto bravi con le micro-ottimizzazioni, quindi non preoccuparti.

Il secondo è l'ottimizzazione algoritmica. Cose come sostituire "array di strutture" con "struttura di array" per rendere il codice più adatto per SIMD, o usare più thread invece di uno per trarre vantaggio da più CPU, o garantire che una lista rimanga ordinata mentre viene creata e modificata per evitare la necessità di ordinarlo dopo, o usando una matrice invece di una lista collegata per sbarazzarsi di "inseguitore puntatore imprevedibile (per le CPU)". Queste sono cose con cui i compilatori fanno fatica. Sono anche cose che possono causare grandi quantità di sforzi se si tenta di adattarli al codice esistente; ed è molto meglio considerare queste cose durante la fase di progettazione prima che venga implementato qualsiasi codice.

    
risposta data 14.05.2016 - 16:52
fonte
17

Entrambi: -)

Seriamente, l'ottimizzazione prematura può essere un problema - potresti finire per spendere centinaia di ore per ottimizzare una routine che è solo eseguire una volta / settimana. Inoltre, il codice completamente ottimizzato è spesso più difficile da leggere e eseguire il debug.

Considera che puoi passare un paio di giorni a processare 10.000 record al minuto. È facile da leggere, facile da mantenere, facile da testare.

Oppure puoi passare una settimana a spingere fino a 50.000 record al minuto. Tuttavia, se un bug ti porta un'altra settimana a trovarlo e risolverlo, non hai davvero guadagnato nulla: tutto il tempo risparmiato dal "codice veloce" è molto "extra di debug".

Detto questo (puoi vedere che sono strongmente a favore di scrivi codice chiaro ), dovresti comunque avere un'idea di cosa stai chiedendo al compilatore di fare. I loop nidificati profondamente verranno eseguiti lentamente e le operazioni extra all'interno del ciclo interno verranno eseguite molto più spesso di quanto ci si potrebbe aspettare.

Scrivi codice chiaro fino a quando non riscontri un problema di rendimento, quindi misura e verifica il codice finché non sai esattamente quale bit devi ottimizzare.

Assicurati di misurare e testare di nuovo dopo aver apportato le modifiche all'ottimizzazione in modo da sapere che hanno funzionato, ma non sempre.

    
risposta data 07.05.2016 - 01:20
fonte
3

Penso che tu abbia una comprensione errata dell'ottimizzazione, quindi ecco alcuni fatti al riguardo:

Innanzitutto, l'ottimizzazione è completamente irrilevante per il 99% del tuo codice! Questo è il fatto più importante sull'ottimizzazione: la maggior parte di qualsiasi codice viene eseguita in modo così raro che praticamente non esiste payoff per ottimizzarlo.

Pertanto, l'abilità più importante di cui hai bisogno per ottimizzare il tuo codice è determinare dove ottimizzare. La maggior parte delle persone usa profiler per questo.

Tuttavia, le ottimizzazioni più importanti sono generalmente a livello di algoritmo . Cioè, se la tua struttura di codice di base è pessima, puoi micro-ottimizzare tutto ciò che vuoi, non funzionerà mai bene, mentre un'implementazione del tutto schifosa usando una struttura più vantaggiosa la sovraperforma in qualsiasi momento. E dipende interamente da te come programmatore, trovare le strutture di codice migliori e usarle a tuo vantaggio. Il tuo compilatore non può farlo, perché semplicemente non può vedere l'immagine grande.

Nella mia esperienza, le cose che devi osservare a livello algoritmico sono principalmente:

  • Dove si verificano le copie?

    Questo è stato un errore comune nel codice C ++ fino a quando la costruzione del movimento è arrivata. Tuttavia, è meglio non dover copiare / spostare i dati tutto il tempo. Soprattutto, è necessario evitare di incorrere in costi di copia quadratica, come di solito quando si concatenano stringhe in un ciclo.

  • Dove utilizzo costose operazioni come gli accessi al disco / le comunicazioni di rete?

    È possibile eseguire molti calcoli mentre il sistema recupera un singolo blocco di dati da un disco rotante. Pertanto, quando si hanno operazioni con costi elevati, questi sono quelli che devono essere ottimizzati. Il tuo compilatore non ti aiuterà un po 'con quello. Altre operazioni da cercare: blocchi, chiamate di sistema e allocazioni di memoria.

  • Posso rappresentare i miei dati in modo tale che tutte le domande che devo porre sui dati possano essere risolte in modo banale, a basso costo?

    Questa è la cosa più difficile, efficace e divertente da fare. Quando lo fai seriamente, scoprirai che puoi ottenere la complessità di molti problemi fino a una complessità lineare o addirittura costante di tempo.

Quindi, per rispondere alla tua domanda più direttamente:

Should I write my code to be clear what I am doing and rely on the optimizer to clean up my code efficiency, or should I be obsessive about getting every last ounce of power out of my code?

Il 99% del codice irrilevante delle prestazioni non dovrebbe assolutamente vedere micro-ottimizzazione. È del tutto controproducente.

And how much speed/size am I losing on by choosing one option over the other?

Nessuna nel 99% del tuo codice. È l'ultimo percento che conta. La mia esperienza è che le micro-ottimizzazioni producono facilmente un aumento della velocità di 2x o più. Ma come ho detto, la potenza delle micro-ottimizzazioni è limitata: che cosa è un miglioramento 2x quando puoi migliorare la complessità del tuo algoritmo da O(N^2) a O(1) ? (Tuttavia, ci sono casi in cui dovresti usare l'algoritmo O(N^2) perché le dimensioni dei tuoi problemi sono troppo piccole!)

TL, DR: Non pensare nemmeno alla micro-ottimizzazione prima di aver fatto un'analisi approfondita!

    
risposta data 13.05.2016 - 20:42
fonte
2

Perché è così importante per te? Qualcuno si lamenta che qualcosa non è abbastanza veloce? Hai tempo limitato per fare le cose. A meno che la velocità sia davvero preoccupante, la tua priorità dovrebbe essere la correttezza e le caratteristiche.

Ma "dovrei affidarmi all'ottimizzatore per ripulire l'efficienza del mio codice" mi sembra molto brutto. Un ottimizzatore eseguirà micro optimisations che ti salva dall'orribile compito di eseguire personalmente le micro ottimizzazioni. Non fa magia. Dovresti sapere quali sono i tuoi strumenti e le tue librerie, quanto sono efficienti. Utilizzare lo strumento più efficiente per il lavoro, non fare il lavoro non necessario. La maggior parte delle volte questo richiede solo conoscenza e non uno sforzo reale.

La tua domanda ci offre la possibilità di scegliere tra due alternative malsane. La cosa giusta è imparare la tua attività, sapere cosa stai facendo e fare le cose in modo naturalmente efficiente. Il più delle volte sarà abbastanza efficiente, e quando non lo è, hai una buona base per iniziare, e il tempo per migliorarlo perché non lo hai sprecato altrove. Scrivere codice spazzatura e affidarsi all'ottimizzatore per ripulire è sbagliato. Essere "ossessivo nell'uscire l'ultima goccia di potere" è ugualmente male.

    
risposta data 07.05.2016 - 15:21
fonte
0

Altre risposte sono buone. Posso solo aggiungere che

  • Ci sono accelerazioni che il compilatore può fare, quindi non dovresti preoccuparti di loro, come riordinare le istruzioni o registri di giocoleria per salvare i recuperi di memoria.

  • Esistono accelerazioni che solo tu puoi fare; il compilatore non può farli, come l'I / O invisibile che non hai mai sospettato, o troppa gestione della memoria.

Quindi quello che faccio sono due fasi:

  • Innanzitutto, su una build di debug , ottieni gli speedup che solo io posso fare, < em> come qui . Lo faccio su una build di debug perché è essenzialmente un processo di debug, ed è molto difficile eseguire il debug di una build ottimizzata.

  • In secondo luogo, dopo aver eseguito tutte le accelerazioni possibili, attiva l'ottimizzatore del compilatore e lascia che faccia la sua magia.

Questo sembra abbastanza semplice, ma ci crediate o no, molte persone pensano che dovreste solo profilare i programmi ottimizzati per il compilatore. Questo è sciocco perché confonde i tuoi obiettivi: trovare aumenti di velocità e misurare quanto velocemente non è.

    
risposta data 13.05.2016 - 19:54
fonte

Leggi altre domande sui tag