Écrire des algorithmes DSP directement en C ou en assembleur? [fermé]


18

Je travaille sur un projet DSP (filtrage IIR) sur un processeur de signal numérique Analog Devices (BF706) avec la suite de compilateurs qui l'accompagne, CrossCore Studio. Il a quelques exemples de trucs DSP simples comme les filtres FIR et IIR et les fonctions de bibliothèque pour cela. Le manuel du processeur décrit le jeu d'instructions d'assemblage et ne commente pas C.

Ma question découle de cette application particulière, mais je pensais que les développeurs DSP suivaient une bonne pratique. Je vais donc l'encadrer de manière générale:

Ce que j'ai réalisé avec les exemples fournis avec ce DSP, c'est que si je veux utiliser les circuits conçus pour les applications DSP, je dois programmer en assembleur pour exécuter directement ces instructions (comme multiplier et ajouter, etc.) Ma question est de savoir si Je viens de programmer en C, le compilateur (qui vient également de la société de puces DSP) ne l'optimiserait-il pas pour ce DSP et n'utiliserait-il pas ses capacités? Ou dois-je vraiment écrire des routines DSP directement dans l'assemblage?


17
J'ai passé de nombreuses années à écrire l'assemblage pour l'ADSP-21xx (et l'assemblage et le C pour le Blackfin, plus tard.) Vous ne divulguez pas ce que vous utilisez, donc toute réponse sera plus une supposition et une opinion qu'autre chose. Mais les processeurs DSP d'AD sont sacrément bons et il est très difficile pour les rédacteurs du compilateur C de remplir correctement le tuyau, pour ainsi dire. J'ai deux décennies d'expérience dans ce domaine (y compris une expérience très modeste dans l'écriture d'un compilateur C) et jusqu'à ce que j'arrête d'écrire du code (il y a quelques années), les compilateurs C ne pouvaient pas s'approcher du codage manuel. Mais ce que vous faites dépend de vos objectifs.
jonk

1
@jonk espère que vous allez écrire une réponse à celui-ci - je n'ai jamais fait qu'un seul projet DSP Blackfin hardcore, mais j'ai de bons souvenirs de certains des hacks de performance dont il avait besoin :)
pericynthion

6
@pericynthion Non, je ne peux pas imaginer y répondre à moins que le PO ne parle beaucoup plus du DSP particulier et des objectifs du projet. Sinon, il s'agirait d'opinions vagues et non guidées qui pourraient être très bonnes ou très mauvaises selon ce que le PO a ensuite écrit à ce sujet. Je vais donc attendre.
jonk

1
Si vous souhaitez qu'il fonctionne le plus rapidement possible, optimisez-le à la main lors de l'assemblage. C'est un compromis temps / argent. Si vous savez écrire du bon C, vous pouvez y arriver presque tout le temps.
Voltage Spike

2
Je ne suis pas sûr de DSP mais pour la plupart des microprocesseurs, vous pouvez utiliser des intrinsèques qui sont à mi-chemin entre l'écriture d'assembleur et le code C.
Maciej Piechotka

Réponses:


20

Il est toujours préférable d'avoir votre algorithme implémenté dans un langage de niveau supérieur (que C est comparé à l'assembly), même si vous prévoyez de tout implémenter dans l'assembly à la fin.

  • les chances sont, vous n'aurez même pas besoin d'assemblage . Si le code généré par votre compilateur atteint vos objectifs de conception, votre travail est terminé.

  • sinon, vous ne commencerez pas votre codage d'assemblage à partir de zéro . Laissez le compilateur générer le code initial pour vous et utilisez-le comme base pour votre version d'assembly optimisée.

  • plus tard, lorsque vous aurez besoin de tester votre code d'assemblage optimisé , vous serez heureux d'avoir la version C. Au lieu de calculer manuellement la sortie correcte pour vos données d'entrée de test, vous pouvez simplement alimenter ces données d'entrée vers votre implémentation C non optimisée, puis vérifier que l'assembly produit exactement la même sortie après les optimisations que vous avez faites.

Si, après quelques années, un nouveau développeur doit apporter des modifications à votre algorithme et qu'il ne dispose que d'un code d'assemblage hautement optimisé, il y a de fortes chances qu'il devra recommencer à zéro.


23

Si les rédacteurs du compilateur s'efforcent de l'optimiser pour cette cible, ils utiliseront au moins une partie des instructions / architecture DSP spéciales. Mais pour des performances ultimes, il ne sera jamais aussi bon qu'un assemblage réglé à la main. Cela peut être suffisant, mais cela dépend de votre application.

D'autres alternatives incluent:

  1. Écrivez la majorité de votre programme en C, et juste la partie numérique la plus critique de l'assemblage.
  2. Écrivez le programme en C et utilisez les bibliothèques fournies par le fabricant ou des tiers - si vous effectuez des tâches DSP courantes telles que des FFT, des filtres FIR / IIR, etc., quelqu'un a probablement déjà écrit le code machine réglé manuellement pour le faire, donc vous pouvez l'utiliser (vous devrez peut-être payer pour cela) et le lier à votre application.

Habituellement, les fournisseurs de DSP fourniront le code source pour les fonctions communes. Si leur code est "assez bon", vous pouvez le déposer directement. S'il n'est pas tout à fait correct, vous devez le modifier. J'ai dû faire une couche FFT il y a quelques années, pour obtenir une vraie FFT en fréquence uniquement. Il existe une astuce qui vous permet de faire une FFT réelle à 2N points en tant que FFT complexe à N points, mais vous devez ensuite effectuer un dernier passage sur la sortie complexe pour récupérer les données de fréquence réelle. Analog Devices n'avait pas ce cas particulier dans son exemple de code.
John R. Strohm

21

L'optimisation prématurée est la racine de tout Mal. - Donald Knuth

Lorsque vous constatez que vous n'obtenez pas suffisamment de performances de votre code, profilez d'abord votre programme, trouvez les goulots d'étranglement, analysez vos exigences de performances, puis commencez à faire des optimisations. L'écriture du code d'assemblage est le dernier recours.

Ma question est de savoir si je programme simplement en C, le compilateur (qui vient également de la société de puces DSP) ne l'optimiserait-il pas pour ce DSP et n'utiliserait-il pas ses capacités?

Oui, le compilateur C peut faire une bonne quantité d'optimisation. Mais cela dépend de la qualité du compilateur. Souvent, un humain peut écrire du code d'assemblage plus rapide que le code C compilé. Au détriment de la douleur et de la souffrance humaines, bien sûr.

Ou dois-je vraiment écrire des routines DSP directement dans l'assemblage?

Écrivez d'abord en C, puis le profil, puis décidez si vous devez écrire dans l'assemblage. J'espère que vous n'auriez pas besoin de l'assemblage.


20
Dans la programmation générale, c'est certainement un bon conseil, mais le DSP est un peu différent - si l'OP veut vraiment faire un usage efficace d'un DSP, il devra probablement y avoir du code manuscrit quelque part le long de la ligne. Et en fait, avec les projets DSP, vous voulez même parfois commencer par écrire ce noyau numérique de base, pour valider que le processeur sera adapté à la tâche à accomplir.
pericynthion

11
Votre conclusion est un bon conseil général. Mais c'est un peu pâle quand on considère les détails spécifiques des ALU AD DSP. Je suppose que vous ne les avez jamais examinés.
jonk

18

Votre DSP sera annoncé avec un maximum de MAC soutenus, en supposant que tous les canaux sont remplis. C'est évidemment une limite supérieure à ce qui peut être réalisé. Vous savez combien de MAC vos filtres et autres traitements prendront, d'après votre analyse. Essayez d'avoir le premier au moins deux fois le second, car vous ne pourrez pas faire fonctionner le noyau DSP au maximum. Tout comme vous n'essaieriez pas de remplir un FPGA au-dessus de 70% des ressources (le PAR devient très lent au-dessus de cela), le développement pourrait devenir très lent en essayant d'extraire les derniers MAC théoriques d'un DSP.

Vous coderez l'intégralité de votre application en C. Il n'est pas pratique d'écrire tous les éléments supplémentaires nécessaires dans l'assembleur, l'injection de test et la visibilité, le nettoyage, etc. Écrivez une version C du filtre de test. Écrivez une version assembleur du même filtre, pour vérifier que vous pouvez bien écrire un assembleur pour cette bête.

Maintenant, faites quelques synchronisations. Utilisez un RTOS approuvé par le fournisseur. Comparez le temps d'exécution de votre module assembleur de test à une version C. S'ils sont à quelques pour cent, passez à autre chose. Si c'est triple, lisez la documentation, interrogez le fournisseur et découvrez pourquoi le compilateur ne le règle pas. Vous devrez peut-être apprendre à écrire sa saveur de C autant qu'à définir les bons drapeaux du compilateur, il sera plus rapide de savoir comment piloter le compilateur correctement que de tout réécrire dans l'assembleur.

Vous avez fait tout cela avant de vous engager dans un DSP, dans une chaîne d'outils.

Une fois que vous avez une chaîne d'outils avec laquelle vous pouvez travailler, un compilateur que vous pouvez régler pour vous rapprocher raisonnablement du maximum, un DSP avec un peu de marge de manœuvre, alors vous pouvez être raisonnablement sûr que très peu de parties de votre suite de code devront être insérées dans assembleur pour terminer le travail.


7

Même si j'ai déjà répondu à cette question, j'ajouterai une autre réponse pour illustrer un point de vue différent:

Ecrivez en C, lisez en assemblée!

Ainsi, au lieu d'écrire en assembleur, vous écrirez la logique en C, en vous assurant soigneusement que la sortie de l'assembleur du code C est optimale. Vous pouvez souvent effectuer certaines astuces sur le code C pour affecter la sortie de l'assembleur. Utilisez des fonctions statiques en ligne lorsque cela est logique. Si vous devez utiliser certaines instructions spéciales prises en charge par le DSP, effectuez une abstraction statique de la fonction en ligne de l'instruction spéciale et appelez l'instruction spéciale à l'aide de l'abstraction.

Bien que je doive dire que je n'ai jamais programmé de DSP, cette approche d'écriture du code C tout en observant attentivement l'assemblage compilé a extrêmement bien fonctionné pour moi sur les machines x86. Tellement bien, en fait, que je n'ai jamais eu à écrire quoi que ce soit en assembleur pour obtenir les meilleures performances possibles. Je vais au lieu d'optimiser le code assembleur modifier le code C de telle manière que l'assemblage soit optimal.

Bien sûr, cela dépend de la disponibilité de bons compilateurs C. Pour x86, de tels compilateurs sont disponibles (vous devez souvent spécifier un niveau d'optimisation supérieur à celui par défaut). Pour les DSP, je ne sais franchement pas si les compilateurs sont aussi bons.

L'avantage de cette approche est que vous disposez d'une base de code portable unique, optimisée pour aboutir à un assemblage optimal pour un DSP donné, mais cela fonctionne également si le DSP est changé pour quelque chose d'autre. Bien sûr, vous devrez peut-être ajuster légèrement le code C pour obtenir les meilleures performances possibles sur le nouveau DSP.


J'ai une question à ce sujet: je travaille sur les processeurs STM32F4 Cortex-M4 et j'utilise les bibliothèques CMSIS / Cube. J'utilise également l'indicateur -O3 du compilateur, car il s'est avéré plus efficace que tout ce que je pouvais produire. Le problème est que l'assembly compilé est toujours beaucoup trop chaotique pour une analyse correcte. Compilez-vous toujours sans optimisation du compilateur? Ou parvenez-vous à sous-estimer la veille du montage, si elle est partout?
Florent

2
@FlorentEcochard: Si l'assembleur du compilateur ne peut pas être compris par un programmeur, c'est probablement mieux que l'assembleur que ce programmeur peut écrire. Comme réponse directe à votre question: utilisez une optimisation maximale et une analyse manuelle de l'assembleur, les pièces difficiles peuvent être pédagogiques.
pasaba por aqui

4

En général, il n'est pas nécessaire d'écrire des sources assembleur si:

  • vous optimisez C dans les sections critiques: une bonne utilisation du mot-clé "register", des fonctions en ligne, ...
  • pourrait être certaines fonctions du programme C en utilisant des blocs asm

Cela signifie revoir manuellement l'assembleur généré par le compilateur C (pour les parties critiques) et modifier la source jusqu'à un niveau d'optimisation suffisant.


Presque tous les compilateurs modernes ignorent le mot-clé "register", quelle que soit la plate-forme. Il est très peu probable que son utilisation entraîne un meilleur code.
Kef Schecter

@KefSchecter: non seulement ils prennent en compte l'indication du registre, mais ils permettent même aujourd'hui de sélectionner le registre à utiliser: gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/…
pasaba por aqui

1
@KefSchecter: sauf pour les compilateurs écrits pour les appareils embarqués, où c'est un mot-clé très important si vous programmez sur du métal nu.
vsz

@pasabaporaqui: J'ai oublié ce bit de syntaxe. Mais si vous ne spécifiez pas de nom de registre - en d'autres termes, si vous l'utilisez de la manière standard ISO - je parie que GCC l'ignorera.
Kef Schecter

3

Je dirais ici que si vous faites des filtres FIR / IIR, il est beaucoup plus important quel algorithme vous utilisez (l'algorithme trivial contre la transformée de Fourier rapide (FFT)) que le langage que vous utilisez (C contre l'assemblage).

Dois-je écrire la FFT dans l'assemblage? Probablement pas.

Est-ce que j'écrirais moi-même la FFT? La réponse à cela n'est probablement pas non plus, car la FFT a déjà été implémentée à plusieurs reprises. Il y a donc de fortes chances que vous trouviez une bibliothèque qui a déjà implémenté FFT. Étant donné que C est un langage portable alors que l'assembly ne l'est pas, vous serez beaucoup plus susceptible de trouver des bibliothèques existantes déjà implémentées en C.

Si vous voulez les performances les plus extrêmes possibles, vous pouvez évidemment régler manuellement un algorithme FFT pour qu'il fonctionne le plus rapidement possible en langage assembleur. Mais je ne crois pas vraiment que cela ait du sens, sauf dans des circonstances très exceptionnelles.


2

Mon propre point de vue FWIW est que chaque fois que vous voulez une vitesse / efficacité / débit / quoi que ce soit maximum, l'assembleur est votre ami, tant que vous êtes compétent. Un compilateur est stupide; il "sait" seulement ce que son auteur pensait y programmer, et son auteur ne connaissait pas du tout votre application.

Je dois admettre que j'aime l'assembleur depuis le début des années 80, les micros 8 bits (pas du tout différents des MCU modernes à bien des égards) où l'apprentissage du "code machine" était une condition préalable pour en tirer des performances utiles, mais je pense que son rôle reste comme le moyen de programme pour une efficacité maximale. De plus, c'est très gratifiant car vous pouvez ajouter toutes sortes de raccourcis d'optimisation auxquels un compilateur ne pense pas, car un compilateur ne peut pas penser du tout.

C va bien je suppose. Mais si vous savez vraiment ce que vous voulez que votre machine fasse au niveau matériel, allez assembleur.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.