2016-04-14 1 views
3

Ich arbeite an einer Funktion, die von einem relativ heißen Codepfad in unserer vorhandenen Codebasis aufgerufen wird. Das erste, was die Funktion tut, ist Aufruf erlang:get_stacktrace/0 in einem Try-Catch-Block so können wir die stacktrace erhalten:Alternativen zu erlang: get_stacktrace/0 um Informationen über den Aufrufer einer Funktion zu erhalten?

the_function() -> 
    [_|Trace] = try error(x) of 
    _ -> error(impossible) 
    catch 
    error:x -> erlang:get_stacktrace() 
    end, 
    ... 

Wir die stacktrace halten, so dass wir Informationen über den Aufrufer der Funktion haben. Ich habe gelesen, dass erlang:get_stacktrace/0 ist nicht immer eine billige Funktion zu rufen (http://erlang.org/pipermail/erlang-questions/2013-November/075928.html). Da dies auf einem Hot-Code-Pfad ist, möchte ich es durch etwas einfacheres ersetzen. Gibt es eine andere Möglichkeit, Informationen über die aufrufende Funktion, wie Modul- und Funktionsname, Leitungsnummer usw. zu erhalten, ohne get_stacktrace anrufen zu müssen?

+3

Die Frage geht davon aus, dass Informationen über den Aufrufer unbedingt erforderlich sind. Warum brauchen Sie es? Brauchen Sie es immer oder nur, wenn Fehler auftreten? Was versuchst du wirklich zu erreichen? Haben Sie in Betracht gezogen, dass Anrufer die erforderlichen Informationen einfach als Argument übergeben müssen? –

+0

@SteveVinoski Ich arbeite mit einer vorhandenen Codebasis, und ja, Informationen über den Anrufer ist eine Voraussetzung. Ich könnte den Code aktualisieren, damit die erforderlichen Anruferinformationen als weiteres Argument übergeben werden können. Dazu müssten mehrere aufrufende Funktionen aktualisiert werden, was ich gerne vermeiden würde. Ich habe erlang gehört: process_info/2 kann mir die gleichen Informationen geben und möglicherweise billiger zu nennen als get_stacktrace. Irgendwelche Gedanken dazu? – Stratus3D

+1

Wenn es so heiß ist, wie es scheint, würde ich empfehlen, es so weit wie möglich zu straffen, auch wenn es bedeutet, dass der Aufrufer zusätzliche Arbeit leisten muss, um es aufzurufen. Ich weiß nicht, ob es besser ist, 'process_info/2' zu nennen; Sie müssen das sicher messen. –

Antwort

1

Wenn Sie wissen müssen, von wo Sie angerufen werden, ist get_stactrace möglicherweise nicht genug, weil der Anrufer möglicherweise aus dem Stapel optimiert worden ist.

Stattdessen würde ich so etwas wie dies berücksichtigen:

the_function(Normal, Args, {Module, Line}) -> 
    try something(Normal, Args) 
    catch error:x -> print_error(Module, Line). 

-define(?the_function(Normal, Args), the_function(Normal, Args, {?MODULE, ?LINE})). 

Jetzt können Sie alle Ihre Anrufe the_function in ?the_function zu ändern, und das dritte Argument wird für Sie zum Zeitpunkt der Kompilierung hinzugefügt.

Sie könnten eine ausgefeiltere Version von diesem mit einer Parse-Transformation machen.

+0

Ich habe eine Ablaufverfolgung durchgeführt, um zu überprüfen, ob der Aufrufer tatsächlich Teil des StackTrace ist. Es sieht so aus, als ob in allen Fällen die aufrufende Funktion im Stacktrace vorhanden ist. Die Verwendung eines Makros würde die Änderung der aufrufenden Funktionen vereinfachen, aber es ist immer noch eine Änderung, die ich zögere. Momentan sieht es so aus, als ob process_info ausreichen könnte, und es ist ein bisschen schneller, nach meinen Tests. – Stratus3D