Muss ich über kompilierten Maschinencode nachdenken, wenn ich meinen Code schreibe?

20

Zum Beispiel habe ich folgenden Code:

auto z = [](int x) -> int {
    if (x > 0) {
        switch (x) {
            case 2: return 5;
            case 3: return 6;
            default: return 1;
            }
        }
    return 0;
    };

Und später rufe ich das mehrmals an. In ASM-Code sehe ich externe Anrufe mit Lambda .... etwas ... Es wird nicht mehr einfach zu lesen und ich denke, es kann auch zu Leistung führen. Vielleicht gewinne ich bei der Metaprogrammierung, aber verliere ich bei der Fehlerbehebung und der Leistung? Sollte ich auf moderne Sprachfunktionen, Makros und andere Aspekte der Metaprogrammierung verzichten, um die Leistung zu verbessern und das Debuggen zu vereinfachen?

cnd
quelle
1
Abhängig von der Version des Compilers und seiner mitgelieferten Standardbibliothek kann Lambda tatsächlich ineffizient implementiert werden. Siehe diese Frage auf Stackoverflow. Die Verantwortung für Verbesserungen sollte jedoch beim Hersteller des Compilers liegen.
Rwong
15
Sie sollten keinen Assembler-Code debuggen müssen, es sei denn, Sie befinden sich in einem kritischen Leistungspfad. Auch "sauberer Code"! = "Gute Leistungen".
BЈовић
Korrigieren Sie bitte Ihre Einrückung. Ich habe versucht, es zu tun, aber es scheint, dass Sie nicht nur Leerzeichen bearbeiten können.
Christoffer Hammarström
3
@ Heather: Sie scheinen den Ratliff-Stil zu verwenden , den ich noch nie gesehen habe und der schwer zu lesen ist. Es ist sicherlich eines der weniger bekannten. Mein Eindruck war, dass Sie nicht richtig eingerückt waren. Vergiss nicht, wenn du es lesbar findest, stimme ich einfach nicht zu.
Christoffer Hammarström
1
Das ifist im Beispielcode völlig redundant, und während der Compiler wahrscheinlich feststellen wird, dass es keinen Grund gibt, eine schlechte Verzweigungsvorhersage zu versuchen.
dmckee

Antworten:

59

Muss ich über kompilierten Maschinencode nachdenken, wenn ich meinen Code schreibe?

Nein , nicht, wenn Sie Ihren Code zum ersten Mal schreiben und keine echten, messbaren Leistungsprobleme haben. Für die meisten Aufgaben ist dies der Standardfall. Zu frühes Nachdenken über Optimierung wird als "vorzeitige Optimierung" bezeichnet, und es gibt gute Gründe, warum D. Knuth dies als "die Wurzel allen Übels" bezeichnet hat .

Ja , wenn Sie einen echten, nachweisbaren Leistungsengpass messen und dieses spezifische Lambda-Konstrukt als Grundursache identifizieren. In diesem Fall ist es möglicherweise eine gute Idee, sich an Joel Spolskys "Gesetz der undichten Abstraktionen" zu erinnern und darüber nachzudenken, was auf ASM-Ebene passieren könnte. Aber Vorsicht, Sie werden erstaunt sein, wie gering die Leistungssteigerung sein wird, wenn Sie ein Lambda-Konstrukt durch ein "nicht so modernes" Sprachkonstrukt ersetzen (zumindest, wenn Sie einen anständigen C ++ - Compiler verwenden).

Doc Brown
quelle
2
+1 Prägnant, genau und einfach zu befolgen, danke, dass wir Sie hier in der Nähe haben.
Jimmy Hoffa
Einverstanden, sehr klare Antwort.
CND
8

Die Wahl zwischen Lambda und Funktorklasse ist ein Kompromiss.

Der Gewinn von Lambda ist größtenteils syntaktisch, indem die Menge an Boilerplate minimiert wird und konzeptionell relevanter Code innerhalb der Funktion, die ihn verwenden wird (sofort oder später), inline geschrieben werden kann.

In Bezug auf die Leistung ist dies nicht schlechter als eine Funktorklasse , die eine C ++ - Struktur oder -Klasse ist, die eine einzelne "Methode" enthält. Tatsächlich behandeln Compiler Lambda nicht anders als eine vom Compiler generierte Funktorklasse hinter den Kulissen.

// define the functor method somewhere
struct some_computer_generated_gibberish_0123456789
{
    int operator() (int x) const
    {
        if (x == 2) return 5;
        if (x == 3) return 6;
        return 0;
    }
};

// make a call
some_computer_generated_gibberish_0123456789 an_instance_of_0123456789;
int outputValue = an_instance_of_0123456789(inputValue);

In Ihrem Codebeispiel unterscheidet es sich in Bezug auf die Leistung nicht von einem Funktionsaufruf, da diese Funktionsklasse zufällig keinen Status hat (weil sie eine leere Erfassungsklausel enthält) und daher keine Zuordnung, keinen Konstruktor oder Zerstörung erfordert.

int some_computer_generated_gibberish_0123456789_method_more_gibberish(int x)
{
    if (...) return ...;
    return ...;
}

Das Debuggen von nicht-trivialem C ++ - Code mit einem Disassembler war schon immer eine schwierige Aufgabe. Dies gilt mit oder ohne Lambda. Dies wird durch die ausgeklügelte Codeoptimierung durch den C ++ - Compiler verursacht, die zu einer Neuordnung, Verschachtelung und Beseitigung von totem Code führte.

Der Name-Mangling-Aspekt ist etwas unangenehm und die Debugger-Unterstützung für Lambda steckt noch in den Kinderschuhen . Es kann nur gehofft werden, dass sich die Debugger-Unterstützung mit der Zeit verbessern wird.

Derzeit ist die beste Methode zum Debuggen von Lambda-Code die Verwendung eines Debuggers, der das Festlegen von Haltepunkten auf Quellcodeebene unterstützt, dh durch Angabe des Namens der Quelldatei und der Zeilennummer.

rwong
quelle
3

Um die Antwort von @DocBrown zu ergänzen, denken Sie daran, dass heutzutage CPUs billig, Arbeitskräfte jedoch teuer sind.

Bei den Gesamtkosten eines Programms ist Hardware im Vergleich zu den Wartungskosten, die bei weitem den teuersten Teil eines typischen Projekts ausmachen (sogar mehr als dessen Entwicklung), in der Regel unbedeutend.

Daher muss Ihr Code die Wartung vor allem optimieren , es sei denn, die Leistung ist kritisch (und selbst dann muss die Wartung berücksichtigt werden).

Paddy Landau
quelle
Nur teilweise wahr. Wenn Ihr Code O (n ^ 2) (quadratisch) ausführt und Sie etwas Besseres als O (log (n)) (logarithmisch) sagen können, wird die Leistung der Hardware durch das Ändern des Codes niemals wesentlich gesteigert. In dem auf dem Originalplakat angegebenen Fall ist dies sehr unwahrscheinlich.
Gnash117
@ gnash117 - Ja, Sie haben Recht, wenn der Code mehrmals ausgeführt werden soll. Vielen Dank für diesen Hinweis. In solchen Fällen bleibt der Code durch eine eindeutige Dokumentation wartbar, während gleichzeitig die Leistung verbessert wird.
Paddy Landau
"Arbeit ist teuer" - Richtig. Die Zeit Ihres Kunden ist sehr wichtig und oft teuer.
Cerad