2017-11-16 3 views
1

Angenommen, wir haben eine Fortran-Funktion (zum Beispiel ein mathematisches Optimierungsalgorithmus), die als Eingabe verwendet, eine andere Fortran-Funktion:Effizienzverlust aufgrund der Verwendung von Funktionszeiger anstelle von if-Block

myOptimizer(func) 

Jetzt je nach Nach Wahl des Benutzers könnte die Eingabefunktion aus einer Liste mehrerer verschiedener Funktionen bestehen. Diese Auswahlliste kann über einen if-Block realisiert werden:

if (userChoice=='func1') then 
    myOptimizer(func1) 
elseif (userChoice=='func2') then 
    myOptimizer(func2) 
elseif (userChoice=='func3') then 
    myOptimizer(func3) 
end if 

Alternativ könnte ich auch Funktionszeiger definieren, und schreibe dies als,

if (userChoice=='func1') then 
    func => func1 
elseif (userChoice=='func2') then 
    func => func2 
elseif (userChoice=='func3') then 
    func => func3 
end if 
myOptimizer(func) 

Basierend auf meinen Tests mit Intel Fortran Compiler 2017 Mit O2-Flag ist die zweite Implementierung um mehrere Faktoren langsamer (4-5 mal langsamer als die if-Block-Implementierung). Aus der Perspektive der Softwareentwicklung würde ich den zweiten Ansatz bevorzugen, da er zu einem viel prägnanteren und saubereren Code führt, zumindest in meinem Problem, wo ein fester Arbeitsablauf mit verschiedenen möglichen Eingabefunktionen für den Arbeitsablauf vorhanden ist. Die Leistung spielt jedoch auch in dem Problem eine Rolle.

Ist dieser Leistungsverlust bei indirekten Funktionsaufrufen in allen Fortran-Codes zu erwarten? oder ist es ein Compiler-abhängiges Problem? Gibt es eine Lösung für indirekte Funktionsaufrufe ohne Leistungsverlust? Wie wäre es mit anderen Sprachen wie C/C++?

+2

Können Sie ein vollständiges Beispiel vorbereiten ([mcve])? Es könnte wichtig sein, ob die Schnittstellen explizit sind, was die Merkmale sind und so weiter. – francescalus

Antwort

1

Dies ist eine reine Vermutung, basierend auf, wie Compiler im Allgemeinen arbeiten und was die 4-5x perf Unterschiede erklären könnte.

In der ersten Version, vielleicht der Compiler myOptimizer() in jede Aufrufort mit func1, func2 und func3 in den Optimierer inlined ist inlining, so dass, wenn es läuft gibt es keine geschieht tatsächlichen Funktionszeiger oder Funktionsaufruf.

Ein indirekter Funktionsaufruf ist nicht viel teurer als ein normaler Funktionsaufruf auf moderner x86-Hardware. Es ist der Mangel an Inlining, der wirklich schmerzt, besonders für FP-Code. Das Verschütten/Neuladen aller Gleitkommaregister um einen Funktionsaufruf ist teuer, insbesondere wenn die Funktion ziemlich klein ist.

. Was Ihnen wahrscheinlich wehtut ist, dass Ihre zweite Version den Compiler davon überzeugt, die Indirektion nicht aufzuheben. Dies gilt auch für C/C++. Wenn Sie Ihren Compiler zum Erstellen von Fast Asm führen, bedeutet das wahrscheinlich, dass Sie ihn auf die erste Art schreiben müssen, es sei denn, es gibt eine profilgesteuerte Optimierungsoption, die den Compiler erkennen lässt, dass dies ein Hotspot ist und es sich lohnt härter mit der Quelle geschrieben den 2. Weg. (Leider benutze ich Fortran nicht, und ich weiß, nur ein paar der Optionen für Intel C/C++ Compiler aus der Betrachtung seines asm Ausgang gegen gcc und Klirren auf http://gcc.godbolt.org/)


Um zu sehen, ob meine Hypothese ist richtig, überprüfen Sie die vom Compiler erzeugte ASM. Wenn die erste Version einen Funktionszeiger nicht tatsächlich an eine eigenständige Definition von übergibt, aber die zweite Version, ist das wahrscheinlich alles, was es zu tun hat.

Weitere Informationen zum Compiler-Ausgang finden Sie unter How to remove "noise" from GCC/clang assembly output?. Matt Godbolts CppCon2017 Talk: “What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid” ist ein gutes Intro zum Lesen der Compiler-Ausgabe und warum Sie wollen.

+2

Sie können das direkt auf der gleichen Seite von godbolt überprüfen, indem Sie '-x f95' oder' -x fortran' verwenden (ich bin mir nicht sicher, aber ich denke erstere). Ich habe GIMPLE immer dramatisch einfacher zu lesen als Assembly gefunden, aber ich bin mir nicht sicher, ob Inlining da ist. –

+0

@VladimirF: Danke für die '-x f95' Spitze. ICC/ifort verwendet GIMPLE jedoch nicht; es ist eine der internen Darstellungen von gcc. Ich bin nie dazu gekommen, GIMPLE zu lernen. das Lesen von x86 asm ist notwendig, um zu überprüfen, ob der Compiler wirklich einen guten Job gemacht hat (für andere Dinge als Inlining), und zu wissen, x86 asm und was effizient ist, können Sie herausfinden, in welche Richtung den Compiler in der Hand halten. –

+0

Richtig, die Fahnen sind Nicht wirklich brauchbar für Intel. –

Verwandte Themen