Domanda

Ricordo di aver letto da qualche parte che realmente ottimizzare e accelerare certa sezione del codice, i programmatori di scrivere che la sezione in linguaggio Assembly. Le mie domande sono -

  1. E 'questa pratica ancora fatto? e come si fa a fare questo?
  2. non sta scrivendo in linguaggio Assembler un po 'troppo ingombrante e arcaica?
  3. Quando si compila il codice C (con o senza -O3 bandiera), il compilatore fa qualche ottimizzazione del codice e collega tutte le librerie e converte il codice in un file oggetto binario. Così, quando si corre il programma è già nella sua forma più elementare cioè binario. Così come fa indurre aiuto 'Assembly Language'?

Sto cercando di capire questo concetto e qualsiasi aiuto o link è molto apprezzato.

UPDATE: punto 3 Riformulare come richiesto dal dbemerlin- Perché si potrebbe essere in grado di scrivere codice assembly più efficace il compilatore genera, ma a meno che non sei un esperto assemblatore il codice verrà eseguito propably più lento perché spesso il compilatore ottimizza il codice meglio di molti esseri umani possono.

È stato utile?

Soluzione

L'unica volta che è utile per ripristinare il linguaggio assembly è quando

  • le istruzioni CPU non hanno equivalenti funzionali in C ++ (per esempio istruzioni singola istruzione-multiple-dati, BCD o operazioni aritmetiche decimali)

    o

  • per qualche inspiegabile ragione - l'ottimizzatore non riesce a utilizzare le migliori istruzioni della CPU

... E ...

  • l'uso di tali istruzioni della CPU avrebbe dato un po 'significativo e utile incremento delle prestazioni in codice collo di bottiglia.

Semplicemente usando in linea di montaggio per fare un'operazione che può essere facilmente espressa in C ++ - come l'aggiunta di due valori o la ricerca in una stringa - è attivamente controproducente, perché:

  • il compilatore sa come farlo altrettanto bene
    • per verificare questo aspetto in uscita assemblaggio (ad esempio gcc -S) o disassemblare il codice macchina
  • si sta artificialmente limitando le sue scelte per quanto riguarda l'allocazione registro, istruzioni della CPU, ecc, quindi potrebbe richiedere più tempo per preparare i registri della CPU con i valori necessari per eseguire la vostra istruzione hardcoded, quindi più tempo per tornare ad un'allocazione ottimale per il futuro Istruzioni
    • optimisers compilatore possono scegliere tra istruzioni equivalente prestazioni specificano diversi registri per minimizzare copia fra loro, e possono scegliere registri in modo tale che un singolo core può elaborare più istruzioni durante un ciclo, mentre costringendo everythingt attraverso appositi registri avrebbe puntate essa
      • In tutta onestà, GCC ha modo di esprimere le esigenze di specifici tipi di registri senza limitare la CPU per un registro esatto, consentendo comunque tali ottimizzazioni, ma è l'unica linea di montaggio che abbia mai visto che risolve questo
  • se un nuovo modello di CPU viene fuori il prossimo anno con un'altra istruzione che è 1000% più veloce per la stessa operazione logica, allora il produttore del compilatore è più probabile che aggiornare il proprio compilatore da usare che l'istruzione, e di conseguenza il vostro programma di beneficio una volta ricompilato, quello che sei (o chiunque sta mantenendo il software allora è)
  • il compilatore selezionerà un approccio ottimale per l'architettura bersaglio sua ha parlato di: se si hardcode un'unica soluzione allora dovrà essere un minimo comune denominatore o #ifdef-ed per le piattaforme
  • assemblaggio lingua non è più portabile C ++, sia attraverso le CPU e attraverso compilatori, e anche se apparentemente porta un'istruzione, è possibile fare un errore ri registri che sono sicuri da clobber, argomento che passa le convenzioni ecc.
  • altri programmatori possono non conoscono o stare bene con il gruppo

Una prospettiva che penso di vale la pena tenere a mente è che, quando è stato introdotto C doveva conquistare un sacco di programmatori Hardcore in linguaggio assembly che si sono dedicati oltre il codice macchina generato. Macchine avevano meno potenza di CPU e RAM di allora e si può scommettere le persone si sono dedicati oltre la cosa più piccola. Ottimizzatori sono diventati molto sofisticati e hanno continuato a migliorare, mentre le lingue di assemblaggio dei processori come i 86 sono diventati sempre più complicato, come hanno fatto tcondutture esecuzione erede, cache e altri fattori coinvolti nel loro prestazioni. Non si può semplicemente aggiungere i valori da una tabella di cicli-per-istruzione di più. scrittori del compilatore spendono tempo a considerare tutti questi fattori sottili (specialmente quelli che lavorano per i produttori di CPU, ma che alza la pressione su altri compilatori troppo). Ora è impraticabile per i programmatori di assemblaggio a media - su qualsiasi applicazione non banale - significativamente migliore efficienza del codice rispetto a quello generato da una buona ottimizzazione del compilatore, e sono estremamente probabile che fare di peggio. Quindi, l'uso di assemblaggio dovrebbe essere limitato a volte fa davvero la differenza misurabile e utile, degno i costi di accoppiamento e di manutenzione.

Altri suggerimenti

Prima di tutto, è necessario il profilo del programma. Poi di ottimizzare i percorsi più utilizzati nel codice C o C ++. A meno vantaggi sono evidenti non riscrivere in assembler . L'utilizzo di questo rende il codice più difficile da mantenere e molto meno portatile -. Non ne vale la pena se non in situazioni molto rare

(1) Sì, il modo più semplice per provare questo è quello di utilizzare in linea di montaggio, questo è il compilatore dipendente, ma di solito simile a questa:

__asm
{
    mov eax, ebx
}

(2) Questo è molto soggettiva

(3) Perché si potrebbe essere in grado di scrivere codice assembly più efficace il compilatore genera.

Si consiglia di leggere il classico Zen of Code Optimization libro e il follow-Zen of Graphics Programming da Michael Abrash .

Sommariamente nel primo libro ha spiegato come utilizzare il montaggio programmazione spinto ai limiti. Nel follow-up, ha spiegato che i programmatori dovrebbero piuttosto usare qualche linguaggio di alto livello come il C e solo cercare di ottimizzare i punti molto specifici utilizzando il montaggio, se necessario a tutti.

Una motivazione di questo cambiamento di mente era che ha visto che i programmi altamente ottimizzata per una generazione di processori potrebbe diventare (un po ') lenta nella prossima generazione dello stesso processore familly rispetto al codice compilato da un linguaggio ad alto livello (forse compilatore utilizzando nuove istruzioni per esempio, o le prestazioni e il comportamento di quelle esistenti che cambiano da un processore generazione all'altra).

Un altro motivo è che i compilatori sono abbastanza buoni e ottimizzare in modo aggressivo nowaday, di solito c'è molto di più prestazioni da guadagnare lavorando su algoritmi che la conversione di codice C al montaggio. Anche per GPU (processori schede grafiche) la programmazione si può farlo con C utilizzando CUDA o OpenCL.

Ci sono ancora alcuni (rari) casi in cui si deve / devono usare assemblaggio, di solito per ottenere il controllo molto fine sull'hardware. Ma anche in codice del kernel del sistema operativo è di solito molto piccole parti e non più di tanto il codice.

Non c'è molto pochi motivi per utilizzare linguaggio assembly in questi giorni, anche costrutti di basso livello, come SSE e il più vecchio MMX sono dotati di intrinseci sia GCC e MSVC (ICC scommessa anche io ma non ho mai usato).

Onestamente, ottimizzatori di questi tempi sono così follemente aggressivo che la maggior parte delle persone non potevano corrispondere nemmeno la metà del loro codice di scrittura prestazioni in assemblea. È possibile modificare la quantità di dati è ordinata in memoria (per località) o dire al compilatore di più il codice (attraverso #pragma), ma in realtà la scrittura di codice assembly ... dubitate si otterrà nulla in più da esso.

@VJo, nota che l'uso intrinseci in alto livello di codice C avrebbe permesso di fare le stesse ottimizzazioni, senza l'utilizzo di una singola istruzione di montaggio.

E per quel che vale, ci sono state discussioni circa il prossimo Microsoft C ++, e come faranno cadere in linea di montaggio da esso. Che la dice lunga circa la necessità di esso.

Dipende. Si è (ancora) stato fatto in alcune situazioni, ma per la maggior parte, ma non vale la pena. CPU moderne sono follemente complessa, ed è altrettanto complesso per scrivere codice assembly efficiente per loro. Così la maggior parte del tempo, l'assemblea si scrive a mano finirà più lento di quello che il compilatore in grado di generare per voi.

Supponendo un compilatore decente rilasciato entro l'ultimo paio di anni, di solito è possibile ottimizzare il vostro codice C / C ++ per ottenere lo stesso beneficio delle prestazioni, come se si stesse usando il montaggio.

Un sacco di persone nei commenti e le risposte qui si parla dei "N volte SpeedUp" hanno guadagnato la riscrittura qualcosa in assemblea, ma che di per sé non significa troppo. Ho un 13 volte Speedup da riscrivere una funzione C valutazione dinamica dei fluidi equazioni in C , applicando molte delle stesse ottimizzazioni come si farebbe se si dovesse scrivere in assemblea, conoscendo l'hardware, e profilando. Alla fine, ha ottenuto abbastanza vicino alla teorico massimo delle prestazioni della CPU che ci sarebbe stato alcun punto in riscriverlo in assemblea. Di solito, non è la lingua che è il fattore limitante, ma il codice vero che hai scritto. Finché non si sta usando le istruzioni "speciali" che il compilatore ha difficoltà con, è difficile da battere il codice ben scritto C ++.

Assemblea non è magicamente più veloce. Ci vuole solo il compilatore fuori dal giro. Questo è spesso una brutta cosa, a meno che non si davvero sa cosa si sta facendo, dal momento che le esegue compilatore un sacco di ottimizzazioni che sono veramente molto doloroso da fare manualmente. Ma in rari casi, il compilatore non capisce il codice, e non è in grado di generare il montaggio efficiente per esso, e poi , potrebbe essere utile scrivere un po 'di montaggio da soli. Altro che sviluppo di driver o simili (in cui è necessario manipolare direttamente l'hardware), l'unico posto dove posso pensare a dove la scrittura di assemblaggio può essere la pena è che se sei bloccato con un compilatore che non può generare codice SSE efficiente da intrinseci (come MSVC). Anche lì, sarei ancora iniziare utilizzando intrinseci in C ++, e il profilo e cercare di modificarlo il più possibile, ma perché il compilatore semplicemente non è molto bravo in questo, potrebbe alla fine essere la pena di riscrivere il codice in assemblea.

Non penso si è specificato il processore. risposte diverse a seconda del processore e l'ambiente. La risposta generale è sì, è ancora fatto, non è certamente arcaica. La ragione generale è i compilatori, a volte fanno un buon lavoro di ottimizzazione in generale, ma non molto bene per obiettivi specifici. Alcuni sono veramente bravo a un obiettivo e non così bene in altri. La maggior parte del tempo è abbastanza buono, la maggior parte del tempo che si desidera codice C portabile e assembler non non portabile. Ma si trovano ancora che le librerie C saranno ancora mano ottimizzare memcpy e altre routine che il compilatore semplicemente non può capire che c'è un modo molto veloce per la sua attuazione. In parte perché questo caso angolo non vale la pena spendere tempo di fare del optimize compilatore per, semplicemente risolverlo in assembler e il sistema di generazione ha un sacco di se questo obiettivo quindi utilizzare C se che l'uso di destinazione C se che ASM uso di destinazione, se questo bersaglio uso asm. Così si verifica ancora, e mi sostengono devono continuare per sempre in alcune zone.

X86 è è proprio bestia con un sacco di storia, siamo ad un punto in cui davvero non si può in un pratico modo di scrittura un blob di assembler che è sempre più veloce, è possibile routine sicuramente ottimizzare per uno specifico processore su una macchina specifica in un giorno specifico, e fuori di eseguire il compilatore. Tranne per alcuni casi specifici è generalmente inutile. Educational ma nel complesso non vale il tempo. Si noti inoltre il processore non è più il collo di bottiglia, quindi un sciatta compilatore C generico è abbastanza buono, trovare le prestazioni altrove.

Altre piattaforme che significa spesso incorporato, braccio, MIPS, avr, MSP430, pic, ecc Si può o non può eseguire un sistema operativo, si può o non può essere in esecuzione con una cache o altre cose che il vostro desktop ha. Così i punti deboli del compilatore mostreranno. Si noti inoltre che i linguaggi di programmazione continuano ad evolversi dai processori anziché verso di loro. Anche nel caso di C considerata forse per essere un linguaggio di basso livello, si pretende molto corrisponde al set di istruzioni. Ci saranno sempre momenti in cui è possibile produrre segmenti di assembler che superano il compilatore. Non necessariamente il segmento che è il collo di bottiglia, ma in tutto l'intero programma spesso è possibile apportare miglioramenti qua e là. Hai ancora a controllare il valore di fare quello. In un ambiente integrato che può e deve fare la differenza tra successo e fallimento di un prodotto. Se il vostro prodotto ha 25 $ per unità investito in più assetati di potere, a bordo immobiliare, processori di velocità superiore in modo da non dovete usare assembler, ma il vostro concorrente spende $ 10 o meno per unità ed è disposto a mescolare asm con C usare memorie più piccole, utilizzare meno energia, parti economiche, ecc ben finché il NRE viene recuperato quindi la soluzione miscelata con ASM nel lungo periodo.

La vera incorporato è un mercato specializzato con tecnici specializzati. Un altro mercato embedded, Roku Linux embedded, TiVo, ecc telefoni embedded, ecc tutti bisogno di avere sistemi operativi portatili per sopravvivere perché è necessario sviluppatori di terze parti. Così la piattaforma deve essere più simile a un desktop di un sistema embedded. Sepolto nella libreria C come detto o il sistema operativo ci possono essere alcune ottimizzazioni assembler, ma, come con il desktop che si desidera cercare di gettare più hardware in modo che il software può essere portatile, invece di ottimizzare mano. E la tua linea di prodotti o il sistema operativo embedded fallirà se è necessario assembler per il successo di terze parti.

La preoccupazione più grande che ho è che questa conoscenza si sta perdendo ad un ritmo allarmante. Perché nessuno ispeziona l'assemblatore, perché nessuno scrive in assembler, ecc Nessuno sta notando che i compilatori non sono stati in miglioramento quando si tratta di codice in produzione. Gli sviluppatori pensare spesso devono acquistare più hardware, invece di rendersi conto che da una conoscendo il compilatore o come programmare meglio possono migliorare la loro eseguonoance da 5 a diverse centinaia per cento con lo stesso compilatore, a volte con lo stesso codice sorgente. 5-10% di solito con lo stesso codice sorgente e compilatore. gcc 4 non sempre produce codice migliore di gcc 3, continuo sia in giro perché a volte gcc3 fa meglio. compilatori specifici di destinazione possono (non sempre fare) cerchi intorno gcc correre, si può vedere qualche miglioramento al cento per cento a volte con lo stesso codice sorgente del compilatore diverso. Da dove viene tutto questo? La gente che ancora si preoccupano di guardare e / o l'uso assembler. Alcune di queste persone lavorano sulle backend del compilatore. Il front-end e mezzo sono divertenti ed educative certamente, ma il backend è dove si effettua o qualità pausa e le prestazioni del programma risultante. Anche se assembler mai scrivere, ma solo osservare l'output del compilatore di tanto in tanto (gcc -O2 -s myprog.c) vi farà un programmatore migliore di alto livello e manterrà alcune di queste conoscenze. Se nessuno è disposto a conoscere e assembler scrittura quindi, per definizione, abbiamo rinunciato per iscritto e il mantenimento di compilatori per linguaggi di alto livello e software in generale, cesserà di esistere.

capire che con gcc per esempio l'output del compilatore è assembly che viene passato ad un assemblatore che lo trasforma in codice oggetto. Il compilatore C normalmente non produce i binari. Gli oggetti quando combinato nel binario finale, sono fatte dal linker, un altro programma richiamato dal compilatore e non parte del compilatore. Il compilatore trasforma C o C ++ o ADA o qualsiasi altra cosa in assembler quindi gli strumenti assemblatore e linker prendono il resto del modo. recompilers dinamici, come TCC per esempio, devono essere in grado di generare file binari al volo in qualche modo, ma vedo che come non fa eccezione alla regola. LLVM ha la sua soluzione runtime così mostrando come abbastanza visibilmente l'alto livello di codice interno per il codice di destinazione per percorso binario se lo si utilizza come un cross compiler.

Ma torniamo al punto, si è fatto, più spesso di quanto si pensi. Per lo più ha a che fare con la lingua non confrontando direttamente al set di istruzioni, e poi il compilatore non sempre produce abbastanza veloce codice. Se è possibile ottenere decine di volte diciamo miglioramento sulle funzioni pesantemente usati come malloc o memcpy. O si desidera avere un lettore video HD sul telefono senza il supporto hardware, bilanciare i pro ei contro di assembler. mercati veramente incorporati usano ancora assemblatore un bel po ', a volte è tutto C, ma a volte il software è completamente codificato in assembler. Per x86 desktop, il processore non è il collo di bottiglia. I processori sono microprogramma. Anche se si fanno bella assemblatore cercando in superficie è solito correre veramente veloce su processori x86 tutte le famiglie, sciatta, buon codice è troppo è più probabile per eseguire circa lo stesso su tutta la linea.

mi raccomando assembler apprendimento per ISA non-x86, come il braccio, il pollice / thumb2, MIPS, MSP430, avr. Obiettivi che hanno compilatori, in particolare quelli con supporto gcc o llvm compilatore. Impara l'assemblatore, imparare a capire l'output del compilatore C, e dimostrare che si può fare meglio in realtà la modifica che la produzione e testarlo. Questa conoscenza contribuirà a rendere il vostro codice di alto livello di desktop molto meglio senza assemblatore, più veloce e affidabile.

Date un'occhiata qui , dove il ragazzo ha migliorato le prestazioni 6 volte usando codice assembly. Quindi, la risposta è:. È ancora stato fatto, ma il compilatore sta facendo buon lavoro

Il mio lavoro, ho usato il montaggio sul bersaglio incorporato (microcontrollore) per l'accesso a basso livello.

Ma per un software per PC, non credo sia molto utile.

Ho un esempio di ottimizzazione di montaggio che ho fatto, ma ancora una volta è su un obiettivo incorporato. È possibile vedere alcuni esempi di assemblaggio di programmazione per PC troppo, e crea programmi davvero piccoli e veloci, ma di solito non vale la pena (cercare "assemblea per le finestre", è possibile trovare alcuni programmi molto piccoli e graziosi).

Il mio esempio è stato quando stavo scrivendo un controller di stampa, e non vi era una funzione che avrebbe dovuto essere chiamata ogni 50 microsecondi. Riguarda rimescolamento dei bit, più o meno. Utilizzando C Sono stato in grado di farlo in circa 35microseconds, e con il montaggio ho fatto in circa 8 microsecondi. Si tratta di una procedura molto specifica, ma ancora, qualcosa di reale e necessario.

Su alcuni dispositivi embedded (telefoni e PDA), è utile perché i compilatori non sono terribilmente maturi, e possono generare il codice estremamente lento e persino errato. Personalmente ho dovuto lavorare in giro, o il codice assembly scrittura alla correzione, l'uscita buggy di diversi compilatori diversi per piattaforme embedded basati su ARM.

  1. "E 'questa pratica ancora fatto?" -> E 'fatto in elaborazione di immagini, l'elaborazione del segnale, AI (es moltiplicazione di matrici efficiente.), E altri. Sono pronto a scommettere la trasformazione del gesto di scorrimento sul mio macbook trackpad è anche parzialmente assembly di codice, perché è immediato. -> E 'anche fatto in applicazioni C # (si veda https://blogs.msdn.microsoft.com/winsdk/2015/02/09/c-and-fastcall-how-to-make -them-lavoro-insieme-senza-CCLI-shellcode / )

  2. "non sta scrivendo in linguaggio Assembler un po 'troppo ingombrante e arcaica?" -.> Si tratta di uno strumento come un martello o un cacciavite e alcune attività richiedono un cacciavite orologiaio

    1. "Quando si compila il codice C (con o senza -O3 bandiera), il compilatore fa qualche ottimizzazione del codice ... Così come non indurre aiuto 'Assembly Language'?" -> Mi piace quello che @jalf detto, che la scrittura di codice C in un modo si scrive assemblea già portare a codice efficiente. Tuttavia, per fare questo è necessario pensare a come si dovrebbe scrivere il codice in linguaggio assembly, così ad esempio. comprendere tutti i luoghi in cui i dati vengono copiati (e sentire il dolore ogni volta che non è necessario). Con linguaggio assembly si può essere sicuri che le istruzioni vengono generati. Anche se il codice C è efficiente non v'è alcuna garanzia che la risultante di assemblaggio sarà efficace ad ogni compilatore. (Vedi https://lucasmeijer.com/posts/cpp_unity/ ) -> Con linguaggio assembly, quando si distribuisce un file binario, è possibile verificare per la CPU e rendere rami diversi a seconda della CPU caratteristiche come ottimizzati per per AVX o solo per SSE, ma è solo necessario distribuire un binario. Con intrinseci questo è possibile anche in C ++ o .NET core 3. (vedi https://devblogs.microsoft.com/dotnet/using-net-hardware-intrinsics-api-to-accelerate-machine-learning-scenarios/ )
  1. Sì. Uso sia in linea di montaggio o moduli di oggetto assemblaggio collegamento. Quale metodo si dovrebbe usare dipende da quanto il codice assembly è necessario scrivere. Di solito è ok per utilizzare in linea di montaggio per un paio di linee e passare a moduli di oggetto separati volta se è più di una funzione.
  2. Sicuramente, ma a volte è necessario. L'esempio importante qui sarebbe in corso la programmazione di un sistema operativo.
  3. La maggior parte dei compilatori oggi ottimizzare il codice scritto in un linguaggio ad alto livello molto meglio di quanto chiunque potesse mai scrivere codice assembly. La gente per lo più lo usano per scrivere il codice che altrimenti sarebbe impossibile scrivere in un linguaggio di alto livello come la C. Se qualcuno l'usa per niente altro mezzo che è o meglio l'ottimizzazione di un compilatore moderno (dubito che) o semplicemente stupido , per esempio egli non sa cosa bandiere o la funzione di compilazione attributi per l'uso.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top