Welche Codierungstechniken verwenden Sie zur Optimierung von C-Programmen?
Einigen Jahren war ich auf einem panel, die interviewt Kandidaten für eine relativ senior embedded-C-Programmierer position.
Eine der standard-Fragen, die ich stellte, war über die Optimierung Techniken. Ich war ziemlich überrascht, dass einige der Bewerber nicht Antworten.
So, in den Interessen der Zusammenstellung einer Liste für die Nachwelt - welche Techniken und Konstrukte zu tun, die Sie normalerweise verwenden, wenn die Optimierung von C-Programmen?
Antworten auf die Optimierung für Geschwindigkeit und Größe akzeptiert.
InformationsquelleAutor der Frage Andrew Edgecombe | 2008-09-21
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erste Sachen zuerst - nicht optimieren zu früh. Es ist nicht ungewöhnlich, Zeit zu verbringen, die gezielt die Optimierung ein Stück code, nur um herauszufinden, dass es war nicht der Engpass, dass Sie dachte, es war. Oder, um es anders zu sagen ", Bevor Sie es schnell, damit es funktioniert"
Untersuchen, ob es irgendeine option für die Optimierung des Algorithmus vor der Optimierung des Codes. Es wird einfacher sein, zu finden, eine Verbesserung der Leistung durch optimieren eines schlechten Algorithmus, als es ist, optimieren Sie den code, nur dann, um es wegzuwerfen, wenn Sie ändern Sie den Algorithmus trotzdem.
Und arbeiten Sie heraus, warum Sie benötigen, zu optimieren, in den ersten Platz. Was wollen Sie erreichen? Wenn Sie versuchen, sagen wir, zur Verbesserung der Reaktionszeit auf ein Ereignis, wenn es eine Möglichkeit zum ändern der Reihenfolge der Ausführung zu minimieren die Zeit, die kritischen Bereiche. Zum Beispiel, wenn Sie versuchen zur Verbesserung der Reaktion auf den externen interrupt kann man tun, irgendwelche Vorbereitung in der Toten Zeit zwischen den Ereignissen?
Sobald Sie sich entschieden haben, die Sie brauchen, um zu optimieren, den code, der die bit-tun Sie optimieren? Einen profiler verwenden. Konzentrieren Sie Ihre Aufmerksamkeit (zunächst) auf die Bereiche, die am häufigsten verwendet werden.
Also, was können Sie tun, um jene Bereiche?
Meisten der oben aufgeführten Optionen können verwendet werden, als Teil der normalen Praxis ohne Nachwirkungen. Aber wenn Sie wirklich versuchen, zu Fristen die beste Leistung:
- Untersuchen Sie, wo Sie können (sicher) deaktivieren der Fehlerüberprüfung. Es ist nicht empfohlen, aber es sparen Sie einiges an Platz und Zyklen.
- Hand-Handwerk Teile des Codes in assembler. Das bedeutet natürlich, dass Ihr code ist nicht mehr tragbar, aber wo ist das nicht ein Problem, das Sie finden können Einsparungen hier. Seien Sie sich aber bewusst, dass es möglicherweise Zeit verloren, die das verschieben von Daten in und aus dem Register, die Sie zur Verfügung haben (ie. zu befriedigen, registrieren Sie Nutzung von Ihr compiler). Auch bewusst sein, dass Ihr compiler sollte machen einen ziemlich guten job auf seine eigene. (natürlich gibt es Ausnahmen)
InformationsquelleAutor der Antwort Andrew Edgecombe
Als jeder andere hat gesagt: Profil, Profil, Profil.
Als für den eigentlichen Techniken, die man, glaube ich, nicht erwähnt wurde bisher:
Hot & Cold-Daten Trennung: Bleiben im cache der CPU unglaublich wichtig. Eine Möglichkeit zu helfen, dies zu tun ist durch die Spaltung von Ihren Datenstrukturen, auf die Häufig zugegriffen wird ("hot") und auf die selten zugegriffen wird ("cold") Abschnitten.
Ein Beispiel: Angenommen, Sie haben eine Struktur für einen Kunden, der so aussieht:
Nun, nehmen wir an, Sie möchten den Zugriff auf die ID und Kontonummer eine Menge, aber nicht so viel den Namen und die Adresse. Was würden Sie tun, ist, um es geteilt in zwei:
In dieser Weise, wenn Sie die Schleife durch Ihre "Kunden" - array, jeder Eintrag ist 12 bytes, und so können Sie passen auf viele weitere Einträge in den cache. Dies kann ein großer Gewinn sein, wenn Sie es anwenden, um Situationen wie die innere Schleife von einer rendering-engine.
InformationsquelleAutor der Antwort MrZebra
Meine Lieblings-Technik ist die Verwendung einer guten profiler. Ohne ein gutes Profil, sagen Ihnen, wo der Engpass liegt, keine tricks und Techniken gehen, um Ihnen zu helfen.
InformationsquelleAutor der Antwort 1800 INFORMATION
häufigsten Techniken, die ich gestoßen sind:
(also z.B. N Vorgänge in M Zyklen statt NxM singular Operationen)
Als Allgemeine Empfehlungen, die meisten von Ihnen sind schon Klang:
InformationsquelleAutor der Antwort aku
Für low-level-Optimierung:
InformationsquelleAutor der Antwort Dark Shikari
InformationsquelleAutor der Antwort Sklivvz
Vermeiden Sie die Verwendung des heap. Verwenden obstacks oder pool-Zuweisung für identisch große Objekte. Setzen Sie kleine Dinge mit kurzer Lebensdauer auf den Stapel. alloca noch existiert.
InformationsquelleAutor der Antwort Nils Pipenbrinck
Pre-Reife-Optimierung ist die Wurzel allen übels!
😉
InformationsquelleAutor der Antwort Shimi Bandiel
Als meine-Anwendungen in der Regel brauchen nicht viel CPU-Zeit, die durch design, konzentriere ich mich auf die Größe meiner Binärdateien auf der Festplatte und im Arbeitsspeicher. Was ich mache, meist ist auf der Suche nach statisch dimensionierte arrays und ersetzt Sie mit dynamisch zugewiesenen Speicher, wo es sich lohnt, den Mehraufwand der freien ' Ing den Speicher später. Zu reduzieren die Größe der binären, Suche ich für große arrays initialisiert werden zur compile-Zeit, und setzen Sie die initializiation zur Laufzeit.
Dadurch entfernen Sie die 1024 null-bytes aus den Binärdateien .DATA-Abschnitt und stattdessen erstellen Sie den Puffer auf dem stack zur Laufzeit und füllen Sie es mit Nullen.
EDIT: achja, und ich mag, um cache-Sachen. Es ist nicht C-spezifisch, aber je nachdem, was Sie sind, Zwischenspeichern, kann es geben Ihnen einen großen Schub in der Leistung.
PS: Bitte lassen Sie uns wissen Sie, wenn Ihre Liste fertig ist, ich bin sehr neugierig. 😉
InformationsquelleAutor der Antwort jkramer
Wenn möglich, vergleichen Sie mit 0, nicht mit beliebigen zahlen, vor allem in Schleifen, weil der Vergleich mit 0 ist oft umgesetzt mit separater, schneller assembler-Befehle.
Zum Beispiel, wenn möglich, schreiben Sie
statt
InformationsquelleAutor der Antwort dmityugov
Etwas anderes, was nicht erwähnt wurde:
InformationsquelleAutor der Antwort Sklivvz
Grundlagen/Allgemeines:
einige Dinge, die haben tatsächlich geholfen:
Entscheiden Sie sich für Größe/Speicher:
Entscheiden Sie sich für Geschwindigkeit (Vorsicht):
InformationsquelleAutor der Antwort
Schwer zu fassen ...
Datenstrukturen:
Algorithmen:
Low-Pegel:
Das wichtigste von allen: Messen Sie früh, Messen oft und nie macht Annahmen, die Basis Ihres Denkens und Optimierungen auf Daten abgerufen, die von einem profiler (bitte verwenden Sie PTU).
Ein weiterer Hinweis, performance ist der Schlüssel für den Erfolg einer Anwendung und sollte berücksichtigt werden, die zur design-Zeit, und Sie sollten klare performance-Ziele.
Dies ist bei weitem nicht erschöpfend, sondern soll eine interessante Basis.
InformationsquelleAutor der Antwort Fabien Hure
Diesen Tagen, die meisten wichtigen Dinge in der Optimierung sind:
Nicht die Mühe mit Optimierungen, die Einbeziehung der kopieren-und-einfügen des Codes (wie loop unrolling), oder die Neuanordnung von loops mit der hand. Der compiler macht in der Regel einen besseren job als Sie auf, dies zu tun, aber die meisten von Ihnen sind nicht intelligent genug, um es rückgängig zu machen.
InformationsquelleAutor der Antwort alex strange
Sammeln profile der code-Ausführung erhalten Sie 50% von dem Weg dorthin. Die anderen 50% befasst sich mit der Analyse dieser Berichte.
Weiter, wenn Sie GCC oder VisualC++ verwenden, können Sie "profile guided optimization", wo der compiler nehmen info aus früheren Ausführungen und verlegen Anweisungen, um die CPU glücklicher.
InformationsquelleAutor der Antwort Frank Krueger
Inline-Funktionen! Inspiriert durch die Profilierung fans hier habe ich profiliert einer Anwendung von mir, und fand eine kleine Funktion, die einige bitshifting auf den MP3-frames. Es macht etwa 90% aller Funktionsaufrufe in meinem applcation, also machte ich es inline-und voila - das Programm benutzt jetzt die Hälfte der CPU-Zeit vorher.
InformationsquelleAutor der Antwort jkramer
Auf den meisten embedded-system i gearbeitet, es wurde kein profiling-tools, so ist es schön zu sagen, verwendet profiler aber nicht sehr praktisch.
Erste Regel in der speed-Optimierung ist - finden Sie Ihre kritischen Pfad.
In der Regel finden Sie, dass dieser Pfad nicht so lang und nicht so Komplex. Es ist schwer zu sagen, in generischer Art und Weise, wie Sie diese optimieren, es hängt davon ab, was machst du und was steht in Ihrer macht, das zu tun. Zum Beispiel, Sie wollen in der Regel vermeiden, memcpy, die auf den kritischen Pfad, also immer müssen Sie die Verwendung von DMA oder optimieren, aber was ist, wenn man hw nicht DMA ? überprüfen Sie, ob memcpy Umsetzung ist die beste, wenn nicht das schreiben.
Verwenden Sie keine dynamische Zuordnung an alle in der embedded-aber wenn Sie aus irgendeinem Grund tun Sie es nicht im kritischen Pfad.
Organisieren Sie Ihre thread-Prioritäten richtig, was richtig ist echte Frage, und es ist klar spezifisches system.
Wir verwenden sehr einfache tools zum analysieren der Flasche-Hals, einfaches makro, speichern der Zeit-Stempel und index. Paar (2-3) wird in 90% der Fälle finden, wo Sie Ihre Zeit verbringen.
Und der Letzte ist code-review sehr wichtig. In den meisten Fällen vermeiden wir performance-problem beim code-review sehr effektiven Art und Weise 🙂
InformationsquelleAutor der Antwort Ilya
Zusätzlich, sollten Sie Leistung Messen.
InformationsquelleAutor der Antwort bk1e
Manchmal müssen Sie entscheiden, ob Sie mehr Platz oder mehr Geschwindigkeit, die Sie nach sich ziehen wird fast gegenüber Optimierungen. Zum Beispiel, um das meiste aus Ihnen Raum, Sie pack Strukturen z.B. #pragma pack(1) und verwenden Sie bit-Felder in den Strukturen. Für mehr Geschwindigkeit, die Sie packen zu richten, wobei die Prozessoren bevorzugt und vermeiden bitfields.
Ein weiterer trick ist die Auswahl des richtigen re-sizing algorithmen für die wachsende arrays via realloc, oder noch besser schreiben Sie Ihre eigenen heap-manager, basierend auf Ihren speziellen Anwendungsfall. Gehen Sie nicht davon, die eine, die kommt mit dem compiler ist die bestmögliche Lösung für jede Anwendung.
InformationsquelleAutor der Antwort Shane MacLaughlin
Wenn jemand nicht über eine Antwort auf diese Frage, es könnte sein, Sie wissen nicht viel.
Könnte es auch sein, dass Sie einiges wissen. Ich kenne eine Menge (IMHO :-), und wenn ich diese Frage gestellt, wäre ich Frage Sie zurück: Warum denkst du, dass das wichtig?
Das problem ist, jede a-priori-Vorstellungen über Leistung, wenn Sie nicht informiert sind, die von einer bestimmten situation, sind nur Vermutungen per definition.
Ich denke, es ist wichtig zu wissen, Codierungsverfahren für die Leistung, aber ich denke, es ist wichtiger zu wissen,Sie nicht zu verwendenbis die Diagnose zeigt, dass es ein problem gibt und was es ist.
Nun werde ich mich im Widerspruch und sagen, wenn Sie das tun, werden Sie lernen zu erkennen, wie der design-Ansätze, die zu Schwierigkeiten führen, so dass Sie Sie vermeiden können, und ein Anfänger, das klingt wie eine vorzeitige Optimierung.
Geben Sie ein konkretes Beispiel, dies ist eine C-Anwendung, die optimiert wurde.
InformationsquelleAutor der Antwort Mike Dunlavey
Große Listen. Ich will nur hinzufügen, einen Tipp, den ich nicht sah, in die oben genannten Listen, die in einigen Fällen kann Ausbeute große Optimierung für minimalen Kosten.
bypass linker
wenn Sie haben eine Anwendung gliedert sich in zwei Dateien, sagen main.c und lib.c, in vielen Fällen können Sie einfach fügen Sie eine
\#include "lib.c"
in Ihrem Haupt.c, die vollständig bypass linker und ermöglichen viel effizienter die Optimierung für den compiler.Der gleiche Effekt kann erreicht werden, Optimierung der Abhängigkeiten zwischen den Dateien, aber die Kosten für die änderungen ist in der Regel höher.
InformationsquelleAutor der Antwort kriss
Google manchmal ist, den besten Algorithmus-Optimierung-tool. Wenn ich ein Komplexes problem, ein bisschen auf der Suche zeigt einige Jungs mit PhDs gefunden haben, die eine Zuordnung zwischen diesem und ein bekanntes problem und haben auch schon die meiste Arbeit getan.
InformationsquelleAutor der Antwort peufeu
Ich würde empfehlen, die Optimierung der Nutzung effizienter algorithmen, und es nicht wie ein nachträglicher Einfall, aber code es so von Anfang an. Lassen Sie den compiler arbeiten Sie heraus, die details über die kleinen Dinge, die, wie Sie weiß mehr über den Ziel-Prozessor, als Sie tun.
Zum einen, ich selten verwenden, loops zu suchen, die Dinge, die ich hinzufügen von Elementen zu einer hashtable und dann verwenden der hashtable-lookup die Ergebnisse.
Zum Beispiel, Sie haben einen string zu suchen und dann 50 möglichen Werte. Also anstatt das zu tun, 50 strcmps, fügen Sie alle 50 Zeichenketten zu einer hashtable und geben Sie jedem eine eindeutige Nummer ( Sie müssen nur einmal gemacht werden ). Dann Suche die Ziel-string in hashtable und haben einen großen Schaltschrank mit allen 50 Fällen ( oder Funktionen, Zeiger ).
Wenn man sich Dinge, die mit gemeinsamen sets von input ( wie die css-Regeln ), nutze ich schnell code zu verfolgen, die nur möglich solitions und iteriere dachte, diese um eine übereinstimmung zu finden. Einmal habe ich ein Spiel Speichere ich die Ergebnisse in eine Hash-Tabelle ( als cache ) und dann mit dem cache-Ergebnisse, wenn ich den gleichen input später eingestellt.
Meine wichtigsten Werkzeuge für die schneller-code:
hashtable - für die schnelle Suche und für die Zwischenspeicherung der Ergebnisse
qsort - es ist die einzige Art, die ich verwenden
bsp - für das nachschlagen von Dingen, basierend auf Bereich ( map-rendering etc )
InformationsquelleAutor der Antwort KPexEA