2012-12-11 9 views
5

Wenn Sie eine Anwendung schreiben, die sehr Latenz empfindlich, was die Grenzen, innerhalb C++ Funktionen Einbettung Assembler sind (und mit der C++ Funktion ruft normalerweise), etwa so:Einbettung von Assembler in C++ akzeptabel?

inline __int64 GetCpuClocks() 
{ 

    // Counter 
    struct { int32 low, high; } counter; 

    // Use RDTSC instruction to get clocks count 
    __asm push EAX 
    __asm push EDX 
    __asm __emit 0fh __asm __emit 031h // RDTSC 
    __asm mov counter.low, EAX 
    __asm mov counter.high, EDX 
    __asm pop EDX 
    __asm pop EAX 

    // Return result 
    return *(__int64 *)(&counter); 

} 

(Die obige Funktion kam aus ein weiterer SO Post, den ich sah)

Können Sie assembler-inline Funktionen wie eine Black Box behandeln? Könnten Sie leicht ein Ergebnis aus Berechnungen in Assembler abrufen? Gibt es Gefahren, dass Sie nicht wissen, welche Variablen derzeit in Registern usw. sind? Führt es zu mehr Problemen als zur Lösung oder ist es für bestimmte kleine Aufgaben akzeptabel?

(Nehmen Sie Ihre Architektur festgelegt werden soll, und bekannt)

EDIT ich dies nur gefunden, das ist, was ich anspielend auf:

http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C

EDIT2 Dieses mehr richtet sich in Richtung Linux und x86 - es ist nur eine allgemeine C++/Assembler Frage (oder so dachte ich).

+1

Fragen Sie speziell zu Visual C++? Ich nehme an, dass andere Compiler andere Einschränkungen haben können. –

+0

@ Robᵩ Nein, wenn überhaupt, zielte ich auf Linux, ICC und G ++. Ich habe gerade die erste Assembler-Funktion genommen, die ich gesehen habe. – user997112

+1

Dies könnte etwas OT sein, aber wenn ein Sprung und eine Rückgabe keine zu hohen Strafen nach sich ziehen, sollten Sie den Assembler in reinem Assembler (in einer separaten Kompiliereinheit) schreiben, um Ihren Code portabler zu halten. Durch das Vermeiden von Inlining können Sie manchmal die Latenz durch eine effizientere Cache-Nutzung verbessern. Dies ist jedoch auf Embedded-Plattformen wichtiger. – psyill

Antwort

1

Wenn die betreffende ASM irgendwelche Register drückt, die sie oben verwendet, dann werden sie unten angezeigt. Ich denke, Sie können sich keine Sorgen machen. In Ihrem Beispiel sind dies die Anweisungen __asm push EAX und __asm pop EAX.

Die wirkliche Antwort, ich nehme an, ist, dass Sie genug darüber wissen müssen, was der Asm tut, um sicher zu sein, dass Sie es als eine Blackbox behandeln können. :)

+0

Stellen Sie also grundsätzlich sicher, dass der Staat, in dem Sie beginnen, der Staat ist, in dem Sie enden? Was, wenn Sie eine Rechnung vom Assembler zurückgeben möchten, wie würden Sie das tun? – user997112

+0

Yup, stellen Sie sicher, dass Sie nicht mit dem Staat zu tun haben. Die Rückgabe des Wertes hängt vom Compiler ab, denke ich. – Almo

3

ich auf der Teilfrage beantworten möchte:

Gibt es mehr Probleme verursacht als zu lösen, oder ist es akzeptabel, für bestimmte kleine Aufgaben?

Sicherlich! Mit Inline-Assembler nehmen Sie die Fähigkeit des Compilers, den Code zu optimieren. Es kann keine partielle Ausdruckssteuerung oder irgendeine andere ausgefallene Optimierung durchführen. Es ist wirklich sehr, sehr schwierig, Code zu erzeugen, der besser ist als der, den der Compiler mit -O3 ausgibt. Und als Bonus wird der Code mit der nächsten Compiler-Version noch besser (vorausgesetzt, dass der nächste Compiler-Release es nicht bricht;)).

Compiler meist einen breiteren Bereich als menschliche Gehirne jemals könnte (oder sollte, um die Gesundheit zu gewährleisten), in der Lage, die richtige Funktion an der richtigen Stelle zu inline, um eine teilweise Ausdruck ersetzen, die Code effizienter macht. Dinge, die du nie in ASM machen würdest, weil dein Code unlesbar wird.

Als anekdotische Referenz möchte ich this post von Linus Torvalds, in Bezug auf die Git-Implementierung von SHA1, die die Hand-optimierte SHA1 in libcrypt übertrifft.

In der Tat, ich denke, die einzige vernünftige Verwendung von Inline - Assembler heutzutage ist das Aufrufen von Prozessoranweisungen, die sonst nicht verfügbar sind (die, die Sie zitiert, ist unter Linux zum Beispiel clock_gettime, zumindest wenn Sie nur nach einem sind Hochauflösender Zeitzähler) oder wenn Sie Dinge tun müssen, bei denen Sie den Compiler tricksen müssen (zB bei der Implementierung von Fremdfunktionsschnittstellen).


Auf dem Schnipsel und was andere sagten. Gerade bei solchen Funktionen bekommen Sie eine Leistungseinbuße. In Inline-Asm müssen Sie sehr vorsichtig sein, dass die Register in dem Zustand gehalten werden, den der Compiler annimmt (push/pop, wie oben). Wenn Sie den Code jedoch normal schreiben, kann der Compiler genau die Variablen berücksichtigen, für die er in Registern Sinn macht, und diejenigen, die nicht auf den Stack passen.

Vertraue deinem Compiler. Es ist schlau. Meistens. Investieren Sie die Zeit, die Sie sparen, indem Sie keinen Inline-Assembler verwenden, um über intelligente, schnelle Algorithmen nachzudenken und die entsprechenden Compiler-Switches zu lernen (z. B. um SSE-Optimierungen usw. zu ermöglichen).

+0

Sicherlich könnte man aber argumentieren, dass ein Compiler nicht in jeder Hinsicht erstaunlich sein kann. Um die Vielzahl von Fällen zu kompensieren, die es bewältigen kann, gibt es wahrscheinlich viele Bereiche, in denen ein Programmierer für eine kleine spezifische Aufgabe weniger asm-Anweisungen schreiben könnte? – user997112

+0

@ user997112 Welche Fälle haben Sie im Sinn? Wenn Sie an alles denken, was mit Zahlen zu tun hat, werden Sie wahrscheinlich nicht in der Lage sein, es zu reduzieren. Beachten Sie auch, dass ich die Referenz getauscht habe, meine ursprüngliche enthielt tatsächlich Inline-ASM. –

+0

Ich habe nichts im Sinn, aber es wäre sicherlich nützlich, wenn es möglich wäre herauszufinden, ob es Bereiche gibt, in denen Compiler schlecht sind. – user997112