502 Stimmen

Wann ist Assembler schneller als C?

Einer der angegebenen Gründe für Assembler-Kenntnisse ist, dass man damit gelegentlich Code schreiben kann, der leistungsfähiger ist als der Code in einer höheren Sprache, insbesondere C. Ich habe aber auch schon oft gehört, dass, obwohl das nicht ganz falsch ist, die Fälle, in denen Assembler helfen kann eigentlich zur Generierung von leistungsfähigerem Code verwendet werden können, sind extrem selten und erfordern Expertenwissen und Erfahrung mit Assembler.

Diese Frage geht noch nicht einmal auf die Tatsache ein, dass Assembler-Anweisungen maschinenspezifisch und nicht portierbar sind, oder auf andere Aspekte von Assembler. Es gibt viele gute Gründe, Assembler zu kennen, abgesehen von diesem, natürlich, aber dies soll eine spezifische Frage sein, die nach Beispielen und Daten fragt, nicht ein ausgedehnter Diskurs über Assembler gegenüber höheren Sprachen.

Kann jemand etwas über spezifische Beispiele in welchen Fällen Assembler schneller ist als gut geschriebener C-Code mit einem modernen Compiler, und können Sie diese Behauptung mit Profilergebnissen belegen? Ich bin mir ziemlich sicher, dass es diese Fälle gibt, aber ich möchte wirklich genau wissen, wie esoterisch diese Fälle sind, da dies ein Punkt zu sein scheint, über den man streiten kann.

0 Stimmen

Und nun wäre eine weitere Frage angebracht: Wann ist die Tatsache, dass Assembler schneller ist als C, tatsächlich von Bedeutung?

20 Stimmen

Eigentlich ist es recht trivial, kompilierten Code zu verbessern. Jeder, der über solide Kenntnisse in Assembler und C verfügt, kann dies erkennen, indem er den erzeugten Code untersucht. Eine einfache Möglichkeit ist die erste Leistungsklippe, von der man herunterfällt, wenn man in der kompilierten Version keine freien Register mehr hat. Im Durchschnitt wird der Compiler bei einem großen Projekt weitaus besser abschneiden als ein Mensch, aber es ist nicht schwer, bei einem Projekt von angemessener Größe Leistungsprobleme im kompilierten Code zu finden.

19 Stimmen

Die kurze Antwort lautet eigentlich: Assembler ist siempre Der Grund dafür ist, dass man Assembler ohne C haben kann, aber man kann C nicht ohne Assembler haben (in der binären Form, die wir früher "Maschinencode" nannten). Das heißt, die lange Antwort ist: C-Compiler sind ziemlich gut darin, zu optimieren und über Dinge "nachzudenken", an die man normalerweise nicht denkt, also hängt es wirklich von Ihren Fähigkeiten ab, aber normalerweise können Sie den C-Compiler immer schlagen; es ist immer noch nur eine Software, die nicht denken und Ideen bekommen kann. Sie können auch portablen Assembler schreiben, wenn Sie Makros verwenden und geduldig sind.

4voto

Eine der Möglichkeiten der CP/M-86-Version von PolyPascal (dem Geschwisterprogramm von Turbo Pascal) war es, die "use-bios-to-output-characters-to-the-screen"-Einrichtung durch eine Maschinensprachroutine zu ersetzen, die im Wesentlichen die x- und y-Zeichen und die Zeichenkette erhält, die dort eingefügt werden soll.

Dadurch konnte der Bildschirm viel, viel schneller aktualisiert werden als zuvor!

In der Binärdatei war Platz für Maschinencode (einige hundert Bytes), und es gab auch noch andere Dinge, so dass es wichtig war, so viel wie möglich herauszuholen.

Da der Bildschirm 80x25 groß war, passten beide Koordinaten jeweils in ein Byte, also in ein Zwei-Byte-Wort. Dies ermöglichte es, die erforderlichen Berechnungen in weniger Bytes durchzuführen, da eine einzige Addition beide Werte gleichzeitig bearbeiten konnte.

Meines Wissens gibt es keinen C-Compiler, der mehrere Werte in einem Register zusammenführen, mit SIMD-Befehlen bearbeiten und später wieder aufteilen kann (und ich glaube nicht, dass die Maschinenbefehle ohnehin kürzer sind).

4voto

Arun Aravind Punkte 1058

Die Frage ist ein wenig irreführend. Die Antwort findet sich in Ihrem Beitrag selbst. Es ist immer möglich, eine Assemblerlösung für ein bestimmtes Problem zu schreiben, die schneller ist als die von einem Compiler erzeugte. Die Sache ist die, dass man ein Experte in Assembler sein muss, um die Einschränkungen eines Compilers zu überwinden. Ein erfahrener Assembler-Programmierer kann Programme in jeder HLL schreiben, die schneller sind als die eines unerfahrenen Programmierers. Die Wahrheit ist, dass man immer Assemblerprogramme schreiben kann, die schneller ausgeführt werden als die von einem Compiler erzeugten Programme.

4voto

tiredcoder Punkte 11

Longpoke, es gibt nur eine Einschränkung: Zeit. Wenn Sie nicht die Ressourcen haben, um jede einzelne Änderung am Code zu optimieren und Ihre Zeit mit der Zuweisung von Registern, der Optimierung von wenigen Überläufen und so weiter zu verbringen, wird der Compiler jedes Mal gewinnen. Man nimmt seine Änderungen am Code vor, kompiliert neu und misst. Wenn nötig, wiederholen Sie das.

Außerdem kann man auf der höheren Ebene viel tun. Außerdem kann die Inspektion der resultierenden Baugruppe den Eindruck erwecken, dass der Code Mist ist, aber in der Praxis wird er schneller laufen, als Sie denken, dass er schneller ist. Beispiel:

int y = data[i]; // hier einige Dinge tun.. call_function(y, ...);

Der Compiler liest die Daten, schiebt sie auf den Stack (spill) und liest später vom Stack und gibt sie als Argument weiter. Klingt beschissen? Es könnte tatsächlich ein sehr effektiver Latenzausgleich sein und zu einer schnelleren Laufzeit führen.

// optimierte Version call_function(data[i], ...); // doch nicht so optimiert..

Die Idee bei der optimierten Version war, dass wir den Registerdruck reduziert haben und ein Überlaufen vermeiden. Aber in Wahrheit war die "beschissene" Version schneller!

Wenn man sich den Assemblercode ansieht und nur die Anweisungen betrachtet und daraus schließt: mehr Anweisungen, langsamer, wäre das eine Fehleinschätzung.

Dabei gilt es zu beachten: Viele Montageexperten piense en sie wissen viel, aber sehr wenig. Die Regeln ändern sich auch von einer Architektur zur nächsten. So gibt es zum Beispiel keinen x86-Code, der immer der schnellste ist. Heutzutage ist es besser, sich an Faustregeln zu halten:

  • der Speicher ist langsam
  • Der Cache ist schnell
  • versuchen, den Cache besser zu nutzen
  • Wie oft werden Sie fehlschlagen? Haben Sie eine Strategie zum Ausgleich von Latenzzeiten?
  • Sie können 10-100 ALU/FPU/SSE-Befehle für einen einzigen Cache-Miss ausführen
  • Anwendungsarchitektur ist wichtig..
  • aber es hilft nicht, wenn das Problem nicht in der Architektur liegt

Außerdem ist es reines Wunschdenken, wenn man sich zu sehr darauf verlässt, dass ein Compiler schlecht durchdachten C/C++-Code auf magische Weise in "theoretisch optimalen" Code verwandelt. Sie müssen den Compiler und die Toolkette, die Sie verwenden, kennen, wenn Sie sich für "Leistung" auf dieser niedrigen Ebene interessieren.

Compiler in C/C++ sind im Allgemeinen nicht sehr gut darin, Unterausdrücke neu zu ordnen, weil die Funktionen zum Beispiel Seiteneffekte haben. Funktionale Sprachen haben diesen Nachteil nicht, aber sie passen nicht so gut in das aktuelle Ökosystem. Es gibt Compiler-Optionen, die eine Lockerung der Präzisionsregeln ermöglichen, so dass die Reihenfolge der Operationen durch den Compiler/Linker/Codegenerator geändert werden kann.

Dieses Thema ist eine kleine Sackgasse; für die meisten ist es nicht relevant, und die anderen wissen ohnehin schon, was sie tun.

Es läuft alles auf Folgendes hinaus: "Zu verstehen, was man tut", ist etwas anderes als zu wissen, was man tut.

4voto

old_timer Punkte 65318

Gcc ist ein weit verbreiteter Compiler geworden. Seine Optimierungen sind im Allgemeinen nicht so gut. Weitaus besser als der durchschnittliche Programmierer, der Assembler schreibt, aber für echte Leistung nicht so gut. Es gibt Compiler, deren Code einfach unglaublich gut ist. Als allgemeine Antwort kann man also sagen, dass es viele Stellen gibt, an denen man in die Ausgabe des Compilers gehen und den Assembler optimieren kann, um die Leistung zu verbessern, und/oder die Routine einfach von Grund auf neu schreiben kann.

9 Stimmen

Der GCC führt äußerst intelligente "plattformunabhängige" Optimierungen durch. Allerdings ist er nicht so gut darin, bestimmte Befehlssätze voll auszunutzen. Für einen so portablen Compiler macht er seine Sache sehr gut.

2 Stimmen

Zugestimmt. Die Portabilität, die Sprachen, die reinkommen, und die Ziele, die rausgehen, sind erstaunlich. Diese Portabilität kann und wird sich als Hindernis erweisen, wenn man in einer Sprache oder einem Ziel wirklich gut ist. Ein Mensch hat also die Möglichkeit, bei einer bestimmten Optimierung für ein bestimmtes Ziel besser abzuschneiden.

0 Stimmen

+1: GCC ist sicherlich nicht konkurrenzfähig bei der Generierung von schnellem Code, aber ich bin mir nicht sicher, dass das daran liegt, dass er portabel ist. LLVM ist portabel und ich habe gesehen, dass es Code 4x schneller als GCCs generiert.

4voto

Beep beep Punkte 18441

Mit dem richtigen Programmierer können Assembler-Programme immer schneller gemacht werden als ihre C-Pendants (zumindest geringfügig). Es wäre schwierig, ein C-Programm zu erstellen, bei dem man nicht mindestens eine Anweisung aus dem Assembler herausnehmen könnte.

0 Stimmen

Dies wäre ein wenig korrekter: "Es wäre schwierig, eine nicht trivial C-Programm wo ..." Alternativ könnten Sie auch sagen: "Es wäre schwierig, ein eine reale Welt finden C-Programm, in dem ..." Der Punkt ist, dass es triviale Schleifen gibt, für die Compiler eine optimale Ausgabe erzeugen. Trotzdem, gute Antwort.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X