Cosa programmano i micro-ottimizzatori per oggi? [chiuso]

12

Tornando ai "buoni vecchi giorni", quando avremmo copiato shareware su floppy per amici, abbiamo usato anche un bel po 'di assembly. C'era una pratica comune di "micro-ottimizzazione", in cui si guardava e fissava le linee di assemblaggio finché non si riusciva a trovare un modo per esprimerlo in un numero inferiore di istruzioni. C'era persino un detto, che era matematicamente impossibile, che " Puoi sempre rimuovere un'altra istruzione. " Dato che modificare le prestazioni di runtime con piccoli fattori costanti non è un grosso problema per (la maggior parte) programmazione oggi , i programmatori trasferiscono questi sforzi di micro-ottimizzazione altrove?

In altre parole, È possibile adottare una best practice in uno stato estremo in cui non si aggiunge più nulla di valore? e invece si perde tempo?

Ad esempio: i programmatori sprecano tempo per generalizzare metodi privati che vengono chiamati solo da una posizione? Il tempo sprecato riduce i dati del test case? I programmatori (ancora) sono eccessivamente preoccupati di ridurre le linee di codice?

Ci sono due grandi esempi di ciò che sto cercando qui sotto: (1) Trascorrere del tempo a trovare i nomi delle variabili giuste, anche rinominando tutto; e (2) Rimozione della duplicazione di codice anche minore e tenue.

Si noti che questo è diverso dalla domanda " Per cosa ottimizzi? ", perché sto chiedendo che cosa gli altri programmatori sembrano massimizzare, con lo stigma di queste ottimizzazioni" micro ", e quindi non un uso produttivo del tempo.

    
posta Macneil 28.11.2010 - 00:56
fonte

12 risposte

22

Formattazione codice

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.
    
risposta data 28.11.2010 - 15:22
fonte
20

Di solito scrivevo molto assembler nel corso della giornata. Non è solo che i compilatori sono migliorati, è che la maggior parte dell'hardware ora ha un sacco di logica dedicata all'esecuzione di codice del codice. La vera micro-issue è la pianificazione, la maggior parte delle istruzioni del computer impiegano più clock di macchina per produrre un risultato e un carico di memoria che perde la cache può richiedere diverse centinaia! Quindi l'idea era di programmare altre istruzioni per fare qualcosa di utile, invece di aspettare un risultato. E le macchine moderne possono emettere diverse istruzioni per periodo di clock. Una volta che abbiamo iniziato a eseguire l'esecuzione fuori ordine HW, ho scoperto che provare a ottenere grandi prestazioni con la codifica manuale è diventato un gioco di mug. Per prima cosa, l'HW out-of-order non avrebbe eseguito le istruzioni nel tuo ordine accuratamente predisposto, la nuova architettura HW ha ridotto la penalità di una programmazione software inoptimale, sufficiente a far sì che il compilatore fosse in genere in una percentuale inferiore delle prestazioni. Inoltre ho scoperto che i compilatori ora stavano implementando trucchi noti, ma di complessità, come lo srotolamento, il caricamento dal basso, il pipelining del software, ecc. La linea di fondo, devi lavorare davvero molto, saltare alcuni di questi trucchi e il compilatore ti batte. Usali tutti e il numero di istruzioni per assemblatore che ti servono aumenta di più volte!

Probabilmente, ancora più importante, la maggior parte dei problemi di prestazioni non riguardano i tassi di emissione delle istruzioni, ma il recupero dei dati nella CPU. Come accennato in precedenza, la latenza della memoria è ora centinaia di cicli e la CPU può eseguire diverse istruzioni per periodo di clock, quindi a meno che il programma - e specialmente le strutture dati siano progettate in modo tale che il tasso di hit della cache sia eccessivamente alto, la microtuning a livello di istruzioni non avrà alcun risultato. Proprio come i militari dicono che i dilettanti parlano tattiche, i professionisti parlano di logistica. La programmazione delle prestazioni è ora più del 90% della logistica (dati in movimento). E questo è difficile da quantificare, poiché la gestione moderna della memoria ha in genere più livelli di cache e le pagine di memoria virtuale sono gestite da un'unità hardware chiamata TLB. Anche l'allineamento di basso livello degli indirizzi diventa importante, come dati effettivi i trasferimenti, non sono in unità di byte o anche lunghi a 64 bit, ma sono disponibili in unità delle linee della cache. Quindi la maggior parte delle macchine moderne ha un hardware che cerca di prevedere quale linea della cache manchi di cui si potrebbe aver bisogno nel prossimo futuro e rilasciare prefetches automatici per portarli nella cache. Quindi la realtà è che con le moderne CPU i modelli di prestazioni sono così complessi da risultare quasi incomprensibili. Anche i simulatori hardware dettagliati non possono mai eguagliare la logica esatta dei chip, così esatta la sintonizzazione è semplicemente impossibile più.

C'è ancora un posto per alcuni codici mano. Librerie matematiche (come la funzione exp), così come le più importanti operazioni di algebra lineare (come la moltiplicazione della matrice) sono ancora in genere codificate a mano da esperti che lavorano per il fornitore di hardware (ad esempio Intel o AMD o IBM), ma probabilmente servono solo un paio di programmatori di assemblatori di prima qualità per mega-computer corp.

    
risposta data 28.11.2010 - 05:47
fonte
10

A volte spendo (sprecando?) tempo scegliendo un buon nome per una variabile o un metodo in modo che non sia solo descrittivo ma abbia anche un buon stile linguistico.

Va un po 'oltre quando cerco di mettere l'intero lavoro (un programma) nello stesso stile linguistico. A volte la mia opinione cambia e rivedo il libro. :)

No, ci vuole molto tempo. È piuttosto raro. Ma mi piace mantenere la buona grammatica nei miei programmi.

    
risposta data 28.11.2010 - 01:05
fonte
10

La complessità del tempo. Trascorro troppo tempo ad ottimizzare le cose per le prestazioni del caso peggiore su una scala che è di ordini di grandezza maggiore di qualsiasi cosa io conosca che il programma realizzerà realisticamente.

Sono troppo ossessivo per lasciar andare il "ma potrebbe far crescere quel grosso" osso, anche quando altre decisioni di progettazione impediscono che avvenga realisticamente.

Tuttavia, a mia difesa, l'irrealistico dovrebbe diventare realtà .. l'ottimizzazione non è più "micro". Nota, non ho detto impossibile , ma non realistico .

Naturalmente, i requisiti hanno la precedenza.

    
risposta data 28.11.2010 - 07:21
fonte
8

Penso di aver sprecato settimane di tempo a trafficare con i gestori di eccezioni Java.

Questo è un sacco di lavoro per il codice che fallisce due o tre volte all'anno. Questo dovrebbe essere un avvertimento o un'informazione? Errore o fatale? È davvero fatale che il processo venga riproposto in cinque minuti? È davvero un avvertimento se tutto è ancora in stato predefinito?

Un sacco di osservazione dell'ombelico e discussione sulla natura di un errore di I / O. Se non riesci a leggere un file sulla rete, si tratta di un errore di file o di una rete? E così via.

A un certo punto ho sostituito tutte le stringhe concat con String.format in modo che l'errore di file annuale non comporti oggetti extra nell'heap. Quello era uno spreco.

    
risposta data 28.11.2010 - 06:42
fonte
7

Suppongo di preoccuparmi troppo delle LOC. Non tanto le LOC stesse, ma piuttosto il numero di affermazioni e ancora più il numero di dichiarazioni duplicate. Sono allergico al codice duplicato. In generale, adoro il refactoring, ma suppongo che circa il 50% di ciò che faccio non renda il codice molto più bello.

    
risposta data 28.11.2010 - 01:12
fonte
5

Leggere un file riga per riga invece di leggere l'intera riga in una stringa ed elaborare la stringa in una sola ripresa.

Certo, fa la differenza nella velocità di esecuzione, ma raramente vale le righe di codice aggiuntive. Rende il codice molto meno gestibile e aumenta la dimensione del codice.

Sì, probabilmente questo non ha senso se il file è grande 3 GB ma la maggior parte dei file non è così grande (almeno non quelli con cui sto lavorando; -)).

    
risposta data 28.11.2010 - 22:22
fonte
3

Quando stavo scrivendo il linguaggio dell'assemblaggio aveva senso fare il pasticcio su byte e cicli, ma era tanto tempo fa ei compilatori hanno fatto molta strada da allora. Non proverei a eseguire manualmente l'ottimizzazione di uno ora.

Allo stesso modo, quando sono passato a scrivere in C è stato piuttosto facile fare un lavoro migliore rispetto ai compilatori C, ma ogni anno Borland o Microsoft o qualcuno rilasciavano un nuovo e migliorato che ha dato il calcio a quello precedente per la stanza . Ho iniziato a prestare attenzione al codice di assemblaggio effettivo che il compilatore stava emettendo e, se non scriveva codice bello e stretto, a srotolare loop, spostare variabili al di fuori dei loop, ecc.

Ora sto scrivendo in lingue molto più alte come Perl, Python e Ruby. Io uso alcuni trucchi del compilatore in primo piano, come lo srotolamento del loop se ha senso, spostare le variabili statiche al di fuori dei loop, ecc., Ma non mi preoccupo più di tanto perché le CPU sono un po 'più veloci ora. Se un'app sembra trascinarsi inaspettatamente, userò un profiler e vedrò cosa riesco a trovare, e poi se qualcosa può essere migliorato inizierò il benchmarking in vari modi a cui posso pensare di fare qualcosa più velocemente, e poi vedere come scala.

In generale cerco di essere intelligente su come scrivo codice, sulla base di anni di esperienza.

    
risposta data 28.11.2010 - 01:32
fonte
3

Una micro-ottimizzazione: migliorare le prestazioni single-threaded di cose che sono parallelizzabili o che possono essere semplicemente migliorate con il nuovo hardware.

Se qualcosa è lento su un computer di 10 anni fa, una soluzione più economica è probabilmente quella di acquistare un computer più nuovo e più veloce, piuttosto che sprecare tempo per ottimizzare il programmatore. Un grande focus delle ottimizzazioni prese in considerazione, però, dovrebbe essere trovare un modo per utilizzare gli 8 core che puoi ottenere oggi, o il 64 sarai in grado di ottenere in un paio di anni, invece di tormentarti di minutia come il costo extra della spazzatura raccolta.

    
risposta data 28.11.2010 - 03:14
fonte
2

La micro-ottimizzazione in termini di prestazioni di runtime non è quasi un problema chiuso anche oggi (anche se potrebbe essere meno comune). Occasionalmente devo spiegare alla gente che il sovraccarico di allocare un oggetto extra ogni richiesta o aggiungere una chiamata di funzione extra è trascurabile.

A parte ciò, vedo anche i programmatori che ottimizzano il codice per semplicità (incluso me stesso). Devo ancora lavorare da qualche parte che non ho dovuto spiegare la differenza tra semplicità e semplicità.

    
risposta data 28.11.2010 - 03:35
fonte
2

Sono tutto per il principio non-ottimizzare-se non-veramente-necessario. E io sono tutto per il primo principio del profilo. E in linea di principio, ottimizzerò solo qualcosa che farà la differenza necessaria.

Questo è in linea di principio. Ma il principio è un bugiardo.

Ho l'abitudine di occuparmi delle funzioni nelle librerie usate frequentemente che penso saranno usate molto nei loop interni. E poi, quando noti qualcosa in un'altra funzione, non è così spesso usato ...

Oh - e poi c'è la logica "Sto scrivendo - ovviamente è una libreria importante".

Oh - e BTW. Non ho mai utilizzato un profiler per guidare l'ottimizzazione. Non ho accesso a uno commerciale, e mai abbastanza costruito la motivazione per capire gprof.

Fondamentalmente, sono un ipocrita. Questi principi si applicano ad altre persone, ma ho troppa paura di qualcuno che dice "ma perché l'hai scritto in modo lento e schifoso?" quindi non potrò mai veramente applicarli correttamente a me stesso.

Non sono così cattivo come lo capisco qui, però. E sono completamente immune dall'auto-inganno, quindi sai che ho ragione su questo!

Modifica

Dovrei aggiungere - uno dei miei principali stupidi hang-up è il sovraccarico di chiamata. Non dappertutto, naturalmente, ma in quei casi di I-think-it-be-used-a-lot-in-inner-loop (dove non ho prove oggettive di un problema). Ho scritto un brutto codice offsetof per evitare di fare chiamate al metodo virtuale più di una volta. Il risultato potrebbe anche essere più lento, dal momento che probabilmente non è uno stile di codifica che gli ottimizzatori sono progettati per gestire bene - ma è cleverer ; -)

    
risposta data 28.11.2010 - 11:46
fonte
1

Nei vecchi tempi in cui i computer avevano tempi di clock misurati in microsecondi, memoria misurata in kilobyte e primitivi compilatori, la micro-ottimizzazione aveva un senso.

La velocità e le dimensioni dei computer di generazione corrente e la qualità dei compilatori di generazione corrente fanno sì che la micro-ottimizzazione di solito sia una perdita totale di tempo. Le eccezioni tendono ad essere quando devi assolutamente ottenere il massimo delle prestazioni da un codice computazionalmente intensivo ... o stai scrivendo per un sistema embedded con risorse estremamente limitate.

but I'm looking for what programmers do to waste time, not to optimize runtime performance.

Mi vengono in mente Twitter e Facebook: -)

    
risposta data 28.11.2010 - 03:01
fonte

Leggi altre domande sui tag