È sempre sbagliato ottimizzare prima della profilazione? [duplicare]

22

Vedo il mantra di "profilazione prima dell'ottimizzazione" ripetuto ancora e ancora qui, su SO e altrove. Sebbene utilizzi certamente strumenti di profilazione, sono solo occasionalmente sorpreso dai risultati. Sembra che, il più delle volte, il profiler stia semplicemente dando le stesse informazioni che potresti ragionevolmente dedurre conoscendo il probabile percorso di esecuzione del tuo programma, comprendendo come funziona la tua architettura e avendo una buona idea di quali tecniche di ottimizzazione il compilatore può impiegare per te.

Per questo motivo, di solito trovo che quando sto sviluppando, vedo aree del codice che posso percepire come dei colli di bottiglia (spesso quando scrivo il codice penso a me stesso "hey, questo sta andando essere una parte critica del codice, e deve essere veloce, ma userò prima un'implementazione più lenta per dimostrare il concetto, quindi ottimizzarlo in seguito ") e procedo con l'ottimizzazione di queste aree prima di preoccuparmi di fare molto profiling.

Questa è davvero una pessima pratica o è solo il risultato naturale di acquisire esperienza nell'ottimizzazione?

    
posta Cercerilla 31.03.2011 - 16:40
fonte

11 risposte

33

Penso che la regola d'oro qui sia "Tutto con moderazione".

Se sei abbastanza sicuro che un pezzo di codice si dimostrerà un collo di bottiglia, non è una pratica orribile fare qualche ottimizzazione iniziale. Per lo meno, è una buona idea prendere provvedimenti per assicurarsi che sarà più facile refactoring più tardi.

Quello che vuoi evitare è esagerare sacrificando tempo e leggibilità nel nome delle micro-ottimizzazioni prima che tu abbia visto i dati reali per giustificare tale sforzo.

    
risposta data 31.03.2011 - 16:44
fonte
12

Il confine tra "ottimizzazione" e "design sensibile" è a volte abbastanza buono, ma altre volte piuttosto ovvio. Per esempio, non hai bisogno di un profiler per essere sicuro che se stai ordinando alcuni milioni di elementi, vale la pena usare un algoritmo O (N log N) piuttosto che un O (N 2 ) algoritmo. IMO, che semplicemente rientra nella ragionevolezza ragionevole, non nell'ottimizzazione però.

Ci sono anche alcune cose che potresti fare, semplicemente perché potrebbero fornire un vantaggio, e il costo è minimo inesistente. Per usare l'esempio di @ unholysampler, scrivere ++i invece di i++ potrebbe avere un costo minimo se si è abituati a digitarlo come post-incremento, ma (al massimo) è temporaneo e banale. Non passerei certo tempo a riscrivere il codice di lavoro per il possibile salvataggio di un nanosecondo, a meno che il profiler non abbia dimostrato che veramente abbiamo avuto bisogno di quel tempo, e ho avuto una ragionevole possibilità di salvarlo. Allo stesso tempo, quando sto digitando un nuovo codice, lavorerei abitualmente usando il modulo che probabilmente è migliore, perché una volta che lo fai abitualmente è gratis. Spesso non guadagna nulla e anche quando fa la differenza spesso non sarà abbastanza grande da notare o preoccuparsi - ma è ancora gratuito, quindi non c'è motivo non per farlo .

Casi come quelli sono abbastanza ovvi, e nella mia mente cadrebbe davvero sotto un design sensibile piuttosto che ciò che penserei sia davvero un'ottimizzazione. La maggior parte degli altri casi di "ottimizzazione senza rappresentazione" sarebbe tuttavia molto più difficile da giustificare. Se hai intenzione di dedicare tempo o sforzi significativi all'ottimizzazione, dovresti avere qualcosa di molto più solido di un "istinto" per giustificarlo.

Dovrei aggiungere quella parte del motivo per cui dico che ritengo che il codice di profilazione sia estremamente utile, anche quando il tuo obiettivo non è l'ottimizzazione. Un profiler fornisce una panoramica di alto livello di un pezzo di codice che può essere estremamente utile anche quando non ti interessa affatto l'ottimizzazione. Ad esempio, se vedi 10 volte il numero di chiamate per allocare una risorsa in modo da liberare quel tipo di risorsa, è un buon indizio che ci sia un vero problema, anche se il codice sembra funzionare correttamente. Quando ci si apprende, un sacco di codice ha un sacco di cose che dovrebbero combaciare (non necessariamente 1: 1, ma in un modo o nell'altro) e un profiler può mostrare discrepanze come quella molto più rapidamente della maggior parte degli altri strumenti.

    
risposta data 31.03.2011 - 17:44
fonte
12

Il punto di profilazione prima di ottimizzare è che hai bisogno di una linea di base per determinare quanto miglioramento l'ottimizzazione ti ha dato. Le informazioni "sorprendenti" che ottengo dal mio profiler saranno lungo queste linee:

  • Sapevo che il metodo era chiamato molto, ma non mi ero reso conto che si chiamava così tanto.
  • Il conflitto tra thread monitor non rallenta mai le cose dove mi aspetto.
  • Sto generando che molte istanze di XYZ? Dovrebbe essere solo circa n ...

Detto questo, molte volte il profiler conferma semplicemente i miei sospetti. Un buon metodo scientifico comporta dosi salutari di monitoraggio e sperimentazione. È un po 'difficile, ma cerco di capire più problemi sistemici con il profiler. Potrei fare il cambiamento ovvio e ottenere un miglioramento del 5%, o se mi fossi avvicinato diversamente al problema avrei potuto ottenere un miglioramento del 25%. (La maggior parte delle ottimizzazioni non produce un così grande miglioramento, ma a volte lo fanno.) Naturalmente, non saprei quanto la mia ottimizzazione abbia migliorato le prestazioni senza una misurazione di base.

    
risposta data 31.03.2011 - 16:57
fonte
8

"Sento che saranno dei colli di bottiglia" (sic)

Il problema con questa affermazione è errore dell'osservatore. Solo perché pensi che possa essere cattivo non significa che sia male. Il profiler fornirà prove empiriche e ti impedirà di passare il tempo in un'area che potrebbe non apportare miglioramenti. Ecco perché dovresti iniziare con il profiler prima di ottimizzarlo. Lascia che il programma e il profiler PROVE siano prima una sezione lenta.

    
risposta data 31.03.2011 - 16:50
fonte
5

Esistono noti killer delle prestazioni e noti best practice che li evitano. Non penso che sia necessario il profilo per determinare che un cursore sia più lento in SQL Server di un'operazione basata su set. Se si inizia a saperlo, si scriverà codice che si comporta meglio dall'inizio senza la necessità di profilare le due opzioni ogni volta che si scrive codice.

Se stai adattando il codice esistente, è meglio non solo profilare il profilo in modo da essere sicuro che il codice che conosci sia inefficiente in generale funzioni male, ma può anche mostrare problemi che non sapevi di avere. Ricordo di aver profilato una cosa in cui sospettavo che il proc memorizzato potesse essere ottimizzato (poteva) e ho scoperto che veniva chiamato centinaia di volte dall'applicazione quando era necessario chiamarlo solo una volta.

Inoltre, hai il vantaggio di essere in grado di dimostrare che hai effettivamente migliorato le prestazioni quando esegui il profilo. Personalmente, salvo questi dati prima e dopo li uso nei miei resoconti di valutazione delle prestazioni e nel discutere i miei risultati durante la ricerca di un lavoro. È bello avere figure reali per mostrare quanto sei bravo a sintonizzarti.

    
risposta data 31.03.2011 - 17:26
fonte
2

La ragione per cui la gente dice che è perché non saprai cosa ha bisogno di per essere ottimizzato prima che il tuo profilo sia finito, così potresti finire per perdere un sacco di tempo senza benefici.

Tuttavia, se qualcosa ti viene fuori come una cattiva idea (ad esempio, il tuo collega sceglie di ricorrere alla ricorsione profonda invece di un semplice ciclo iterativo) puoi correggerlo. Ma dovresti concentrarti su come procedere, non sul guardare il vecchio codice. C'è uno stadio nel processo in cui è appropriato.

    
risposta data 31.03.2011 - 16:49
fonte
1

Penso che tutti cerchino di scrivere un buon codice fin dall'inizio. Suona come quello che stai facendo.

Quello che penso dovrebbe essere fatto all'inizio è semplicemente mantenere il design semplice, specialmente la struttura dei dati. Spesso le persone iniziano assumendo che hanno bisogno di una struttura dati più sofisticata, dati ridondanti e tecniche di notifica dettagliate perché sono preoccupate per le prestazioni. Nella mia esperienza, quelle cose causano il problema che dovrebbero evitare.

Nonostante una buona pratica di codifica e un buon design, i problemi di prestazioni si insinuano e devi rimuoverli periodicamente. Queste sono quasi mai cose che avresti potuto indovinare, e la maggior parte dei profiler non sono molto bravi a trovarli. Inoltre, il livello di ottimizzazione del compilatore ha raramente qualche effetto su di loro, perché per lo più non sono stretti cicli di calcolo. Per lo più si presentano come chiamate di funzioni dall'aspetto innocente (o addirittura invisibili) che, se catturate istantaneamente lo stack, sono nel mezzo di esso e consumano molto più tempo dell'orologio a muro di quanto avreste mai immaginato, come mostrato da spesso appaiono lì.

Ecco il mio esempio preferito

    
risposta data 31.03.2011 - 17:43
fonte
1

Ci sono due tipi di ottimizzazione che possono essere eseguiti (relativamente) in modo sicuro prima della profilazione.

  1. Ottimizzazione algoritmica: scelta di un algoritmo con una complessità media (o peggiore) migliore. Questo può anche (dovrebbe?) Essere fatto prima di iniziare la codifica. Dovrai comunque verificare che l'algoritmo selezionato sia quello corretto dato il tuo vero set di dati, ma è una buona idea iniziare con un algoritmo che dovrebbe migliorare, non è vero?

  2. Ottimizzazione della struttura dei dati: disporre correttamente i dati o utilizzare una struttura dati con una località migliore può aumentare le prestazioni, ma avrà un impatto sugli algoritmi che possono essere utilizzati, quindi è più facile farlo un'ottimizzazione prima della codifica (e quindi non puoi usare un profiler se non c'è codice). Ad esempio, quando si programma un videogioco, generalmente è meglio usare struct-of-array (SoA) invece di array of struct (AoS) per memorizzare i dati in quanto beneficeranno della località dei dati, della coerenza della cache, ...

risposta data 01.04.2011 - 11:01
fonte
0

Sì, è sbagliato ottimizzare prima della profilazione MA

Una buona programmazione, una programmazione che renda il codice più semplice e più diretto non richiede la profilazione. Una buona programmazione come lo spostamento di inizializzazioni non necessarie da loop non ha più bisogno di giustificazione del fatto che si sta migliorando la qualità del codice.

IMHO le uniche volte che devi profilare è quando cerchi specificamente di migliorare le prestazioni. Per mostrare il miglioramento devi prima eseguire la linea di base e poi mostrare il delta.

Ogni volta che aggiungi complessità sotto l'aspetto di ottimizzazione senza mostrare la prova che si trattava di un collo di bottiglia e il codice migliora le prestazioni; sta solo facendo cattive programmazioni.

    
risposta data 31.03.2011 - 18:41
fonte
0

La distinzione critica è tra:

  1. Il codice ottimizzato è tanto semplice quanto più semplice di quello non ottimizzato.

  2. Il codice ottimizzato è più complesso (e quindi più soggetto a errori e più difficile da modificare in futuro) rispetto al codice non ottimizzato.

Nel primo caso, andare avanti. Nel secondo caso è necessario valutare l'investimento in termini di tempo di sviluppo (incluso il costo opportunità per non utilizzare lo stesso tempo per correggere bug o fornire funzionalità) e il futuro costo maggiore di manutenzione per una soluzione più complessa. Devi pesare questo costo contro i miglioramenti osservabili alle prestazioni. Come interpreterai questo giudizio se non hai idea di quale sia il costo della prestazione? Una funzione potrebbe essere ovviamente inefficiente, ma se richiede solo pochi millisecondi, l'ottimizzazione delle prestazioni 1000x non fornirà alcun valore. Per non parlare del costo opportunità di non lavorare su un'ottimizzazione in cui conta davvero.

In secondo luogo, la tua intuizione sulle prestazioni potrebbe essere sbagliata e non saprai mai se "ottimizzi" prima di misurare. Ad esempio, molti sviluppatori tendono a pensare che un algoritmo O (log n) sia più veloce di un O (n). Ma tu non lo sai. L'algoritmo O (n) potrebbe essere più veloce fintanto che n è al di sotto di qualche soglia. Qual è la soglia? Probabilmente non lo sai. E cosa c'è in realtà nel tuo particolare programma? Solitamente è sopra o sotto questa soglia? Come lo scoprirete?

Che cosa succede se l'intuizione è sbagliata e l'ottimizzazione rende effettivamente il programma più lento? Se profilati prima e dopo, ti rendi conto del tuo errore e riattivi le modifiche. Nel peggiore dei casi hai perso tempo. Se non fai il profilo non sei il più saggio e hai causato danni a lungo termine al programma.

La decisione davvero difficile è quando puoi percorrere strade diverse nell'architettura. La comunicazione di rete dovrebbe essere JSON su HTTP (semplice) o buffer di protocollo su TCP (performante)? Il problema qui è che devi decidere in anticipo, prima ancora di poter misurare le prestazioni, se non vuoi sprecare lavoro cambiando protocollo più tardi. In questo caso non puoi iniziare con la versione semplice e poi ottimizzarla più tardi quando si rivela essere un problema. Ma non dovresti semplicemente scegliere la versione più performante di default. Dovrai fare alcune ipotesi e proiezioni elaborate.

Prendo atto che affermi che il profiling "tutte le volte che non lo sono" dà lo stesso risultato dell'intuizione in base alla tua comprensione del programma. Prendo questo per dire che hai una percentuale di successo del 50% nel predire il modo migliore per allocare le risorse per l'ottimizzazione. Dato il costo a breve e lungo termine dell'ottimizzazione erroneamente applicata, non è davvero una buona percentuale su cui fare affidamento.

    
risposta data 27.09.2015 - 11:16
fonte
-1

C'è la legge 90/10 che afferma che il 90% del tempo viene speso nel 10% del codice e solo il 10% del tempo viene speso nel 90% del codice. Un programmatore non può sempre prevedere quale 10% del codice causerà il massimo impatto se ottimizzato in modo tale fino a quando non si utilizza un profiler per capirlo, ogni ottimizzazione che si fa è prematura. È meglio capire dove si trova il problema prima di tentare di risolverlo, no?

    
risposta data 01.04.2011 - 08:20
fonte

Leggi altre domande sui tag