Schreiben von DSP-Algorithmen direkt in C oder Assembly? [geschlossen]

18

Ich arbeite an einem DSP-Projekt (IIR-Filterung) auf einem digitalen Signalprozessor von Analog Devices (BF706) mit der mitgelieferten Compiler-Suite CrossCore Studio. Es enthält einige Beispiele für einfache DSP-Funktionen wie FIR- und IIR-Filter und Bibliotheksfunktionen. Das Prozessorhandbuch beschreibt die Montageanleitung und kommentiert C nicht.

Meine Frage ergibt sich aus dieser bestimmten Anwendung, aber ich dachte, es gibt eine bewährte Methode, die DSP-Entwickler befolgen. Also werde ich es allgemein einrahmen:

Anhand der mit diesem DSP gelieferten Beispiele habe ich festgestellt, dass ich, wenn ich die für DSP-Anwendungen konzipierten Schaltungen verwenden möchte, Assembler programmieren muss, um diese Anweisungen direkt auszuführen (wie Multiplizieren und Addieren usw.). Meine Frage ist, ob Ich programmiere nur in C, würde der Compiler (der ebenfalls von der DSP-Chip-Firma stammt) es nicht für diesen DSP optimieren und seine Fähigkeiten nutzen? Oder muss ich wirklich DSP-Routinen direkt in Assembler schreiben?

doubleE
quelle
17
Ich habe viele Jahre damit verbracht, Assembler für den ADSP-21xx (und später Assembler und C für die Blackfin) zu schreiben. Sie legen nicht offen, was Sie verwenden, daher ist jede Antwort eher eine Vermutung und eine Meinung als irgendetwas anderes. Aber die DSP-Prozessoren von AD sind verdammt gute Sachen, und es fällt C-Compilern sehr schwer, die Pipe sozusagen richtig auszufüllen. Ich habe zwei Jahrzehnte Erfahrung in diesem Bereich (einschließlich einiger sehr bescheidener Erfahrungen beim Schreiben eines C-Compilers) und bis zu dem Zeitpunkt, als ich vor einigen Jahren aufgehört habe, Code zu schreiben, konnten die C-Compiler der Handcodierung nicht nahe kommen. Aber was Sie tun, hängt von Ihren Zielen ab.
Jonk
1
@jonk Ich hoffe, Sie werden eine Antwort auf diese Frage schreiben - ich habe immer nur ein Hardcore-DSP-Blackfin-Projekt gemacht, aber ich habe gute Erinnerungen an einige der Performance-Hacks, die es brauchte :)
pericynthion
6
@pericynthion Nein, ich kann mir nicht vorstellen, eine Antwort darauf zu schreiben, es sei denn, das OP spricht viel mehr über den jeweiligen DSP und die Projektziele. Ansonsten wären es vage, ungeleitete Meinungen, die sehr richtig oder sehr falsch sein könnten, je nachdem, was das OP dann darüber schrieb. Also warte ich einfach.
Jonk
1
Wenn Sie möchten, dass es am schnellsten läuft, optimieren Sie es manuell in der Montage. Das ist ein Kompromiss zwischen Zeit und Geld. Wenn Sie wissen, wie man gutes C schreibt, können Sie den größten Teil des Weges dorthin zurücklegen.
Voltage Spike
2
Ich bin nicht sicher über DSP aber für die meisten Mikroprozessoren Sie können verwenden Spezifika , die zwischen dem Schreiben Assembler und C - Code auf halbem Weg ist.
Maciej Piechotka

Antworten:

20

Es ist immer besser, Ihren Algorithmus in einer höheren Sprache zu implementieren (wobei C mit Assembly verglichen wird), auch wenn Sie am Ende alles in Assembly implementieren möchten.

  • Möglicherweise müssen Sie nicht einmal zusammengebaut werden . Wenn der von Ihrem Compiler generierte Code Ihre Entwurfsziele erfüllt, ist Ihre Aufgabe erledigt.

  • Andernfalls werden Sie Ihre Assembly-Codierung nicht von Grund auf neu starten . Lassen Sie den Compiler den ersten Code für Sie generieren und verwenden Sie diesen als Basis für Ihre optimierte Assembly-Version.

  • Wenn Sie später Ihren optimierten Assembly-Code testen müssen, ist die C-Version für Sie von Vorteil. Anstatt die korrekte Ausgabe für Ihre Testeingabedaten manuell zu berechnen, können Sie diese Eingabedaten einfach in Ihre nicht optimierte C-Implementierung einspeisen und dann überprüfen, ob die Assembly nach den von Ihnen vorgenommenen Optimierungen genau dieselbe Ausgabe erzeugt.

Wenn ein neuer Entwickler nach einigen Jahren Änderungen an Ihrem Algorithmus vornehmen muss und nur ein hochoptimierter Assembler-Code zur Verfügung steht, besteht eine hohe Wahrscheinlichkeit, dass er von vorne anfangen muss.

Dmitry Grigoryev
quelle
23

Wenn die Compiler-Autoren einige Anstrengungen unternehmen, um es für dieses Ziel zu optimieren, wird zumindest ein Teil der speziellen DSP-Anweisungen / -Architektur verwendet. Aber für ultimative Leistung wird es nie so gut sein wie eine handgestimmte Montage. Es könnte jedoch gut genug sein - hängt von Ihrer Anwendung ab.

Andere Alternativen umfassen:

  1. Schreiben Sie den größten Teil Ihres Programms in C und nur den kritischsten numerischen Teil in Assembly.
  2. Schreiben Sie das Programm in C und verwenden Sie die vom Hersteller oder von Drittanbietern bereitgestellten Bibliotheken. Wenn Sie allgemeine DSP-Aufgaben wie FFTs, FIR / IIR-Filter usw. ausführen, hat wahrscheinlich bereits jemand den handabgestimmten Maschinencode dafür geschrieben Sie können das verwenden (möglicherweise müssen Sie dafür bezahlen) und es mit Ihrer Anwendung verknüpfen.
pericynthion
quelle
Normalerweise liefern die DSP-Anbieter den Quellcode für die allgemeinen Funktionen. Wenn ihr Code "gut genug" ist, können Sie ihn direkt eingeben. Wenn er nicht ganz richtig ist, müssen Sie ihn optimieren. Ich musste vor einigen Jahren eine FFT-Schicht erstellen, um eine echte FFT nur mit Frequenz zu erhalten. Es gibt einen Trick, mit dem Sie eine echte 2N-Punkt-FFT als eine komplexe N-Punkt-FFT ausführen können. Anschließend müssen Sie den komplexen Ausgang endgültig übergehen, um die tatsächlichen Frequenzdaten wiederherzustellen. Analog Devices hatte diesen speziellen Fall nicht in ihrem Beispielcode.
John R. Strohm
21

Vorzeitige Optimierung ist die Wurzel allen Übels. - Donald Knuth

Wenn Sie feststellen, dass Sie nicht genügend Leistung aus Ihrem Code herausholen, profilieren Sie zuerst Ihr Programm, finden Sie die Engpässe, analysieren Sie Ihre Leistungsanforderungen und führen Sie erst dann Optimierungen durch. Das Schreiben von Assembly-Code ist das letzte Mittel.

Meine Frage ist, wenn ich nur in C programmiere, würde der Compiler (der ebenfalls von der DSP-Chip-Firma stammt) es nicht für diesen DSP optimieren und seine Fähigkeiten nutzen?

Ja, C-Compiler kann einiges an Optimierung leisten. Dies hängt jedoch von der Qualität des Compilers ab. Häufig kann ein Mensch schneller Assembler-Code schreiben als der kompilierte C-Code. Das ist mit großen Kosten menschlichen Schmerzes und Leidens verbunden.

Oder muss ich wirklich DSP-Routinen direkt in Assembler schreiben?

Schreiben Sie zuerst in C, dann in profile, und entscheiden Sie dann, ob Sie in assembly schreiben müssen. Hoffentlich brauchen Sie die Montage nicht.

Nick Alexeev
quelle
20
In der allgemeinen Programmierung ist dies sicherlich ein guter Rat, aber DSP ist ein wenig anders - wenn das OP einen DSP wirklich effizient nutzen möchte, muss wahrscheinlich irgendwo auf der Strecke ein handgeschriebener Code vorhanden sein. Tatsächlich möchten Sie bei DSP-Projekten manchmal sogar mit dem Schreiben dieses numerischen Kernels beginnen, um zu überprüfen, ob der Prozessor für die jeweilige Aufgabe geeignet ist.
Pericynthion
11
Ihre abschließende Aussage ist ein guter allgemeiner Rat. Es ist jedoch etwas blass, wenn man die spezifischen Details der AD DSP-ALUs betrachtet. Ich nehme nicht an, dass Sie sie jemals untersucht haben.
jonk
18

Ihr DSP wird mit einem Maximum an dauerhaften MACs beworben, vorausgesetzt, alle Pipes sind gefüllt. Dies ist offensichtlich eine Obergrenze für das, was erreicht werden kann. Sie wissen aus Ihrer Analyse, wie viele MACs Ihre Filter und andere Verarbeitungen benötigen. Streben Sie an, dass der erste mindestens zweimal der zweite ist, da Sie sonst den DSP-Core nicht maximal laufen lassen können. So wie Sie nicht versuchen würden, ein FPGA mit mehr als 70% Ressourcen zu füllen (PAR wird darüber hinaus sehr langsam), könnte die Entwicklung sehr langsam werden, wenn Sie versuchen, die letzten theoretischen MACs aus einem DSP herauszupressen.

Sie werden Ihre gesamte Anwendung in C codieren. Es ist unpraktisch, alle zusätzlichen erforderlichen Informationen in Assembler, Testinjektion und -sichtbarkeit, Haushaltsführung usw. zu schreiben. Schreiben Sie eine C-Version des Testfilters. Schreiben Sie eine Assembler-Version desselben Filters, um sicherzustellen, dass Sie tatsächlich Assembler für dieses Biest schreiben können.

Jetzt mach ein paar Timings. Verwenden Sie ein vom Lieferanten zugelassenes RTOS. Vergleichen Sie die Laufzeit Ihres Test Assembler-Moduls mit einer C-Version. Wenn sie innerhalb einiger Prozent liegen, fahren Sie fort. Wenn es dreifach ist, lesen Sie die Dokumentation, befragen Sie den Anbieter und finden Sie heraus, warum der Compiler es nicht optimiert. Möglicherweise müssen Sie lernen, die C-Variante zu schreiben, um die richtigen Compiler-Flags zu setzen, und Sie können schneller herausfinden, wie der Compiler ordnungsgemäß betrieben wird, als alles in Assembler neu zu schreiben.

Sie haben dies alles getan, bevor Sie sich auf einen DSP, eine Toolkette festgelegt haben.

Sobald Sie eine Toolchain haben, mit der Sie arbeiten können, einen Compiler, der sich dem Maximum annähert, einen DSP mit einigem zeitlichen Spielraum, können Sie sich darauf verlassen, dass nur noch wenige Teile Ihrer Codesuite eingefügt werden müssen Assembler, um den Job zu beenden.

Neil_UK
quelle
7

Obwohl ich diese Frage bereits beantwortet habe, werde ich eine weitere Antwort hinzufügen, um einen anderen Standpunkt zu veranschaulichen:

Schreiben Sie in C, lesen Sie in der Montage!

Anstatt also in Assembler zu schreiben, schreiben Sie die Logik in C und achten dabei darauf, dass die Assembler-Ausgabe des C-Codes optimal ist. Sie können häufig bestimmte Tricks im C-Code ausführen, um die Assembler-Ausgabe zu beeinflussen. Verwenden Sie statische Inline-Funktionen, wenn dies sinnvoll ist. Wenn Sie spezielle Anweisungen verwenden müssen, die der DSP unterstützt, erstellen Sie eine statische Inline-Funktionsabstraktion der speziellen Anweisung, und rufen Sie die spezielle Anweisung mithilfe der Abstraktion auf.

Obwohl ich sagen muss, dass ich noch nie DSPs programmiert habe, hat dieser Ansatz, den C-Code unter sorgfältiger Beobachtung der kompilierten Assembly zu schreiben, bei x86-Computern sehr gut funktioniert. So gut, dass ich noch nie etwas in der Montage schreiben musste, um die bestmögliche Leistung zu erzielen. Anstatt den Assembly-Code zu optimieren, werde ich den C-Code so ändern, dass die Assembly optimal ist.

Dies hängt natürlich davon ab, ob gute C-Compiler verfügbar sind. Für x86 sind solche Compiler verfügbar (häufig müssen Sie eine höhere Optimierungsstufe als die Standardeinstellung angeben). Bei DSPs weiß ich ehrlich gesagt nicht, ob die Compiler so gut sind.

Der Vorteil dieses Ansatzes besteht darin, dass Sie über eine einzige tragbare Codebasis verfügen, die für eine optimale Zusammenstellung für einen bestimmten DSP optimiert ist. Dies funktioniert jedoch auch, wenn der DSP in einen anderen geändert wird. Natürlich müssen Sie möglicherweise den C-Code leicht anpassen, um die bestmögliche Leistung auf dem neuen DSP zu erzielen.

juhist
quelle
Ich habe eine Frage dazu: Ich arbeite an STM32F4 Cortex-M4-Prozessoren und verwende die CMSIS / Cube-Bibliotheken. Ich benutze auch das -O3-Flag des Compilers, weil es sich als effizient erwiesen hat, als alles, was ich produzieren konnte. Das Problem ist, dass die kompilierte Assembly für eine ordnungsgemäße Analyse immer viel zu chaotisch ist. Kompilieren Sie immer ohne Compileroptimierung? Oder schaffen Sie es, den Versammlungsabend zu verstehen, wenn es überall ist?
Florent
2
@FlorentEcochard: Wenn der Assembler des Compilers von einem Programmierer nicht verstanden werden kann, ist er wahrscheinlich besser als der Assembler, den dieser Programmierer schreiben kann. Als direkte Antwort auf Ihre Frage: Verwenden Sie maximale Optimierung und manuelle Analyse des Assemblers, schwierige Teile könnten lehrreich sein.
Pasaba por aqui
4

Im Allgemeinen ist es nicht erforderlich, Assembler-Quellen zu schreiben, wenn:

  • Sie optimieren C in den kritischen Bereichen: eine gute Verwendung des Schlüsselworts "register", Inline-Funktionen, ...
  • könnte einige Funktionen des C-Programms sein, die asm- Blöcke verwenden

Das bedeutet, dass Sie den vom C-Compiler generierten Assembler (für die kritischen Teile) manuell überprüfen und die Quelle ändern, bis ein ausreichender Grad an Optimierung erreicht ist.

pasaba por aqui
quelle
Nahezu alle modernen Compiler ignorieren das Schlüsselwort "register", unabhängig von der Plattform. Es ist sehr unwahrscheinlich, dass die Verwendung zu besserem Code führt.
Kef Schecter
@KefSchecter: Sie berücksichtigen nicht nur den Registerhinweis, sondern können heutzutage sogar das zu verwendende Register auswählen: gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/…
pasaba por aqui
1
@KefSchecter: Mit Ausnahme von Compilern für eingebettete Geräte, bei denen es sich um ein sehr wichtiges Schlüsselwort handelt, wenn Sie auf Bare Metal programmieren.
vsz
@pasabaporaqui: Ich habe diese Syntax vergessen. Wenn Sie jedoch keinen Registernamen angeben, das heißt, wenn Sie ihn nach ISO-Standard verwenden, wird er von GCC wahrscheinlich ignoriert.
Kef Schecter
3

Ich würde hier sagen, dass es bei FIR / IIR-Filtern viel wichtiger ist, welchen Algorithmus Sie verwenden (den Trivialalgorithmus gegenüber der schnellen Fouriertransformation (FFT)) als welche Sprache Sie verwenden (C gegenüber der Assemblierung).

Würde ich FFT in Assembler schreiben? Wahrscheinlich nicht.

Würde ich selbst FFT schreiben? Die Antwort darauf ist wahrscheinlich auch nicht, da FFT bereits viele Male implementiert wurde. Möglicherweise finden Sie eine Bibliothek, in der FFT bereits implementiert ist. In Anbetracht dessen, dass C eine portable Sprache ist, während dies bei Assemblern nicht der Fall ist, werden Sie mit größerer Wahrscheinlichkeit vorhandene Bibliotheken finden, die bereits in C implementiert sind.

Wenn Sie die höchstmögliche Leistung wünschen, können Sie natürlich einen FFT-Algorithmus von Hand so einstellen, dass er in Assemblersprache so schnell wie möglich funktioniert. Aber ich glaube nicht wirklich, dass es Sinn macht, dies zu tun, außer unter sehr außergewöhnlichen Umständen.

juhist
quelle
2

Meiner Ansicht nach ist FWIW, dass der Assembler immer Ihr Freund ist, wenn Sie maximale Geschwindigkeit / Effizienz / Durchsatz / was auch immer wollen, solange Sie kompetent sind. Ein Compiler ist dumm; es "weiß" nur, was der Autor gedacht hat, um es zu programmieren, und der Autor kannte Ihre Anwendung überhaupt nicht.

Ich muss zugeben, ich habe Assembler seit Anfang der 80er Jahre geliebt. 8-Bit-Mikros (die modernen MCUs in vielerlei Hinsicht überhaupt nicht unähnlich sind), bei denen das Erlernen von "Maschinencode" eine Grundvoraussetzung war, um eine nützliche Leistung daraus zu ziehen, aber ich denke, ihre Rolle bleibt wie die Art und Weise zu Programm für maximale Effizienz. Außerdem ist es sehr lohnenswert, da Sie alle Arten von Optimierungsverknüpfungen verwenden können, an die ein Compiler nicht denken kann, weil ein Compiler überhaupt nicht denken kann.

C ist okay, denke ich. Wenn Sie jedoch genau wissen, was Ihre Maschine auf Hardwareebene tun soll, gehen Sie zu Assembler.

Ian Bland
quelle