Scrivere algoritmi DSP direttamente in C o assembly? [chiuso]


18

Sto lavorando a un progetto DSP (filtro IIR) su un processore di segnale digitale Analog Devices (BF706) con la suite di compilatori che lo accompagna, CrossCore Studio. Ha alcuni esempi di semplici cose DSP come filtri FIR e IIR e funzioni di libreria per esso. Il manuale del processore descrive il set di istruzioni di assemblaggio e non commenta C.

La mia domanda nasce da questa particolare applicazione, ma ho pensato che ci fosse una buona pratica seguita dagli sviluppatori DSP. Quindi lo inquadrerò in modo generale:

Quello che ho capito dagli esempi forniti con questo DSP è che se voglio usare i circuiti progettati per le applicazioni DSP, devo programmare in assembly per eseguire direttamente quelle istruzioni (come moltiplicare e aggiungere, ecc.) La mia domanda è se Ho appena programmato in C, il compilatore (che proviene anche dalla società di chip DSP) non lo ottimizzerebbe per quel DSP e ne userebbe le capacità? O devo davvero scrivere le routine DSP direttamente nell'assembly?


17
Ho trascorso molti anni a scrivere assembly per ADSP-21xx (e assembly e C per Blackfin, in seguito). Non sveli ciò che stai usando, quindi qualsiasi risposta sarà più un'ipotesi e un'opinione che altro. Ma i processori DSP di AD sono dannatamente validi ed è molto difficile per gli scrittori di compilatori C riempire correttamente la pipe, per così dire. Ho due decenni di esperienza in questo settore (inclusa un'esperienza molto modesta nella scrittura di un compilatore C) e fino a quando ho smesso di scrivere codice (alcuni anni fa) i compilatori C non potevano avvicinarsi alla codifica manuale. Ma ciò che fai dipende dai tuoi obiettivi.
Jon

1
@jonk spero che tu abbia intenzione di scrivere una risposta a questo - ho sempre e solo fatto un progetto DSP Blackfin hardcore, ma ho bei ricordi di alcuni degli hack di performance di cui aveva bisogno :)
pericynthion

6
@pericynthion No, non posso immaginare di scrivere una risposta a meno che l'OP non parli MOLTO di più sul particolare DSP e sugli obiettivi del progetto. Altrimenti, sarebbero opinioni vaghe e non guidate che potrebbero essere molto giuste o molto sbagliate a seconda di ciò che l'OP ha quindi scritto al riguardo. Quindi aspetterò.
Jon

1
Se vuoi che funzioni il più velocemente, lo ottimizzi a mano nell'assemblaggio. Questo è un compromesso tempo \ denaro. Se sai come scrivere una buona C puoi ottenere la maggior parte del percorso lì.
Picco di tensione

2
Non sono sicuro di DSP, ma per la maggior parte dei microprocessori è possibile utilizzare i valori intrinseci che si trovano a metà strada tra la scrittura dell'assemblatore e il codice C.
Maciej Piechotka,

Risposte:


20

È sempre meglio avere il tuo algoritmo implementato in un linguaggio di livello superiore (che C viene confrontato con assembly), anche se alla fine prevedi di implementare tutto in assembly.

  • è probabile che non avrai nemmeno bisogno del montaggio . Se il codice generato dal compilatore soddisfa i tuoi obiettivi di progettazione, il tuo lavoro è fatto.

  • in caso contrario, non inizierai la codifica dell'assieme da zero . Consenti al compilatore di generare il codice iniziale per te e utilizzalo come base per la versione dell'assembly ottimizzata.

  • più tardi, quando dovrai testare il tuo codice assembly ottimizzato , sarai felice di avere la versione C. Invece di calcolare manualmente l'output corretto per i dati di input del test, è possibile semplicemente inviare tali dati di input all'implementazione C non ottimizzata, quindi verificare che l'assemblaggio produca esattamente lo stesso output dopo le ottimizzazioni apportate.

Se, dopo qualche anno, un nuovo sviluppatore dovrà apportare modifiche all'algoritmo e tutto ciò che ha a portata di mano è un codice assembly altamente ottimizzato, è molto probabile che dovranno ricominciare da capo.


23

Se gli autori del compilatore si sforzano di ottimizzarlo per quella destinazione, farà almeno un uso delle speciali istruzioni / architettura DSP. Ma per le massime prestazioni non sarà mai buono come un assemblaggio sintonizzato a mano. Potrebbe essere abbastanza buono, però - dipende dalla tua applicazione.

Altre alternative includono:

  1. Scrivi la maggior parte del tuo programma in C, e solo la parte numerica più critica nell'assemblaggio.
  2. Scrivi il programma in C e usa le librerie fornite dal produttore o da terze parti - se stai eseguendo attività DSP comuni come FFT, filtri FIR / IIR ecc. Qualcuno probabilmente ha già scritto il codice macchina sintonizzato a mano per farlo, quindi puoi utilizzarlo (potresti doverlo pagare) e collegarlo alla tua applicazione.

Di solito, i fornitori di DSP forniranno il codice sorgente per le funzioni comuni. Se il loro codice è "abbastanza buono", puoi inserirlo direttamente. Se non è del tutto corretto, devi modificarlo. Ho dovuto fare uno strato FFT alcuni anni fa, per ottenere un vero FFT solo in frequenza. C'è un trucco che ti consente di fare una FFT reale a 2 punti N come FFT complessa a punti N, ma poi devi fare un passaggio finale sull'uscita complessa per recuperare i dati di frequenza reali. Analog Devices non aveva quel caso particolare nel loro codice di esempio.
John R. Strohm,

21

L'ottimizzazione prematura è la radice di tutti i mali. - Donald Knuth

Quando scopri che non ottieni abbastanza prestazioni dal tuo codice, prima profila il tuo programma, trova i colli di bottiglia, analizza i tuoi requisiti di prestazione e solo allora inizia a fare ottimizzazioni. La scrittura del codice assembly è l'ultima risorsa.

La mia domanda è se programmassi semplicemente in C, il compilatore (che proviene anche dalla società di chip DSP) non lo ottimizzerebbe per quel DSP e userebbe le sue capacità?

Sì, il compilatore C può fare una buona dose di ottimizzazione. Ma questo dipende dalla qualità del compilatore. Spesso un essere umano può scrivere un codice assembly più veloce del codice C compilato. A scapito del dolore e della sofferenza umana, cioè.

O devo davvero scrivere le routine DSP direttamente nell'assembly?

Scrivi prima in C, poi nel profilo, quindi decidi se devi scrivere nell'assembly. Eventualmente, non avresti bisogno dell'assemblea.


20
Nella programmazione generale questo è certamente un buon consiglio, ma DSP è un po 'diverso: se l'OP vuole davvero fare un uso efficiente di un DSP, probabilmente ci sarà bisogno di un codice scritto a mano da qualche parte lungo la linea. E in effetti con i progetti DSP a volte vuoi persino iniziare scrivendo quel core kernel numerico, per convalidare che il processore sarà adatto per l'attività da svolgere.
pericynthion

11
La tua dichiarazione conclusiva è un buon consiglio generale. Ma è un po 'pallido se si considerano i dettagli specifici degli ALU AD DSP. Immagino non li abbia mai esaminati.
Jon

18

Il tuo DSP verrà pubblicizzato con un MAC massimo sostenuto, supponendo che tutte le pipe siano riempite. Questo è ovviamente un limite massimo a ciò che può essere raggiunto. Sai quanti MAC impiegheranno i tuoi filtri e altre elaborazioni, dalla tua analisi. Cerca di avere il primo almeno il doppio del secondo, poiché non sarai in grado di mantenere il core DSP al massimo. Proprio come non si proverebbe a riempire un FPGA superiore al 70% delle risorse (PAR diventa molto più lento di quello), lo sviluppo potrebbe rallentare cercando di spremere gli ultimi MAC teorici da un DSP.

Codificherai la tua intera applicazione in C. Non è pratico scrivere tutte le cose extra, necessarie in assemblatore, iniezione di prova e visibilità, pulizie ecc. Scrivi una versione C del filtro di prova. Scrivi una versione dell'assemblatore dello stesso filtro, per verificare che puoi effettivamente scrivere l'assemblatore per questa bestia.

Ora fai dei tempi. Utilizzare un RTOS approvato dal fornitore. Confronta il tempo di esecuzione del modulo assemblatore di test con una versione C. Se sono entro qualche percento, vai avanti. Se è triplo, leggi la documentazione, fai una domanda al fornitore e scopri perché il compilatore non la sta sintonizzando. Potrebbe essere necessario imparare a scrivere il suo sapore di C tanto quanto impostare i flag corretti del compilatore, sarà più veloce scoprire come guidare correttamente il compilatore che riscrivere tutto in assembler.

Hai fatto tutto questo prima di impegnarti in un DSP, in una catena di strumenti.

Una volta che hai una toolchain con cui puoi lavorare, un compilatore che puoi sintonizzare per avvicinarti ragionevolmente al massimo, un DSP con un po 'di margine di tempo residuo, quindi puoi essere ragionevolmente sicuro che dovranno essere inserite in pochissime parti della tua suite di codici assemblatore per finire il lavoro.


7

Anche se ho già risposto a questa domanda, aggiungerò un'altra risposta per illustrare un diverso punto di vista:

Scrivi in ​​C, leggi in assemblea!

Quindi, invece di scrivere in assembly, scriverai la logica in C, assicurandoti che l'output dell'assemblatore del codice C sia ottimale. Spesso è possibile eseguire alcuni trucchi sul codice C per influire sull'output dell'assemblatore. Utilizzare le funzioni statiche incorporate quando ha senso. Se è necessario utilizzare alcune istruzioni speciali supportate dal DSP, eseguire un'astrazione in funzione statica in linea dell'istruzione speciale e chiamare l'istruzione speciale utilizzando l'astrazione.

Anche se devo dire che non ho mai programmato DSP, questo approccio di scrittura del codice C mentre osservando attentamente l'assemblaggio compilato ha funzionato molto bene su macchine x86. Così bene, infatti, che non ho mai dovuto scrivere nulla in assemblea per ottenere le migliori prestazioni possibili. Invece di ottimizzare il codice dell'assembly, modificherò il codice C in modo tale che l'assemblaggio sia ottimale.

Naturalmente, questo dipende dalla disponibilità di buoni compilatori C. Per x86 tali compilatori sono disponibili (spesso è necessario specificare un livello di ottimizzazione superiore a quello predefinito). Per i DSP, francamente non so se i compilatori siano altrettanto buoni.

Il vantaggio di questo approccio è che hai una singola base di codice portatile, ottimizzata per ottenere un assemblaggio ottimale per un determinato DSP, ma funziona anche se il DSP viene cambiato in qualcos'altro. Naturalmente potrebbe essere necessario modificare leggermente il codice C per ottenere le migliori prestazioni possibili sul nuovo DSP.


Ho una domanda al riguardo: lavoro sui processori Cortex-M4 STM32F4 e utilizzo le librerie CMSIS / Cube. Uso anche il flag -O3 del compilatore, perché si è rivelato efficace per tutto ciò che potevo produrre. Il problema è che l'assemblaggio compilato è sempre troppo caotico per un'analisi corretta. Compilate sempre senza ottimizzazione del compilatore? O riesci a comprendere la vigilia dell'assemblea, se è ovunque?
Florent,

2
@FlorentEcochard: se l'assemblatore del compilatore non può essere compreso da un programmatore, probabilmente è meglio dell'assemblatore che questo programmatore può scrivere. Come risposta diretta alla tua domanda: utilizzare la massima ottimizzazione e analisi manuale dell'assemblatore, le parti difficili potrebbero essere educative.
pasaba por aqui,

4

In generale, non è necessario scrivere fonti assembler se:

  • ottimizzi C nelle sezioni critiche: un buon uso della parola chiave "registra", funzioni incorporate, ...
  • potrebbero essere alcune funzioni del programma C usando i blocchi asm

Ciò significa rivedere manualmente l'assemblatore generato dal compilatore C (per le parti critiche) e modificare l'origine fino a un livello sufficiente di ottimizzazione.


Praticamente tutti i compilatori moderni ignorano la parola chiave "register", indipendentemente dalla piattaforma. È molto improbabile che utilizzarlo porti a un codice migliore.
Kef Schecter,

@KefSchecter: non solo tengono conto del suggerimento del registro, oggigiorno consentono anche di selezionare il registro da utilizzare: gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/…
pasaba por aqui

1
@KefSchecter: ad eccezione dei compilatori scritti per dispositivi incorporati, dove è una parola chiave molto importante se stai programmando su bare metal.
vsz

@pasabaporaqui: mi sono dimenticato di quel po 'di sintassi. Ma se non specifichi un nome di registro - in altre parole, se lo usi in modo standard ISO - Scommetto che GCC lo ignorerà.
Kef Schecter,

3

Vorrei dire qui che se si eseguono filtri FIR / IIR, è molto più importante quale algoritmo si utilizza (l'algoritmo banale contro la trasformata di Fourier veloce (FFT)) rispetto al linguaggio che si utilizza (C contro assembly).

Scriverei FFT in assemblea? Probabilmente no.

Scriverei FFT da solo? Anche la risposta a questa domanda probabilmente non lo è, poiché FFT è già stata implementata molte volte. Quindi è probabile che troverai una libreria che ha già implementato FFT. Considerando che C è un linguaggio portatile, mentre assembly no, sarà molto più probabile trovare librerie esistenti già implementate in C.

Se vuoi le prestazioni più estreme possibili, puoi ovviamente mettere a punto un algoritmo FFT per lavorare il più rapidamente possibile nel linguaggio assembly. Ma non credo davvero che abbia senso farlo se non in circostanze eccezionali.


2

La mia opinione personale FWIW è che ogni volta che vuoi la massima velocità / efficienza / produttività / qualunque cosa, l'assemblatore è tuo amico, purché tu sia competente. Un compilatore è stupido; "conosce" solo ciò che il suo autore pensava di programmare in esso, e il suo autore non conosceva affatto la tua applicazione.

Devo ammettere che ho amato l'assemblatore sin dai primi anni '80 a 8 bit micro (non molto diverso dai moderni MCU per molti aspetti) in cui l'apprendimento del "codice macchina" era un prerequisito per ottenere prestazioni utili da essi, ma penso che il suo ruolo rimanga come il modo di programma per la massima efficienza. Inoltre, è molto gratificante in quanto puoi inserire tutti i tipi di scorciatoie di ottimizzazione che un compilatore non penserà, perché un compilatore non può pensare affatto.

C va bene immagino. Ma se sai davvero cosa vuoi che la tua macchina faccia a livello hardware, vai assembler.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.