Android: Wie viel Overhead wird generiert, wenn eine leere Methode ausgeführt wird?

7

Ich habe eine Klasse erstellt, um meine Debug-Ausgaben zu verarbeiten, so dass ich nicht alle meine Log-Ausgaben vor der Veröffentlichung entfernen muss.

%Vor%

Nachdem ich eine andere Frage gelesen habe, habe ich gelernt, dass der Inhalt der if-Anweisung nicht kompiliert wird, wenn die Konstante Release.DEBUG falsch ist.

Was ich wissen möchte ist, wie viel Overhead generiert wird, wenn diese leere Methode ausgeführt wird? (Sobald die if-Klausel entfernt wurde, ist in der Methode kein Code mehr vorhanden.) Wird es Auswirkungen auf meine Anwendung haben? Offensichtlich ist die Leistung ein großes Problem beim Schreiben für Mobiltelefone = P

Danke

Gary

    
gsteinert 03.12.2010, 13:12
quelle

5 Antworten

14

Messungen am Nexus S mit Android 2.3.2:

%Vor%

Kontrolle:

%Vor%

Ich habe die Messungen mehrmals wiederholt. Es wurden keine signifikanten Abweichungen gefunden. Sie können sehen, dass die Kosten pro Anruf je nach Arbeitslast stark variieren können (möglicherweise aufgrund von JIT-Kompilierungen). aber 3 Schlussfolgerungen können gezogen werden:

  1. dalvik / java saugt bei der Optimierung des toten Codes auf

  2. statische Funktionsaufrufe können viel besser als nicht statische optimiert werden (nicht statische Funktionen sind virtuell und müssen in einer virtuellen Tabelle nachgeschlagen werden)

  3. die Kosten auf nexus s ist nicht größer als 70ns / Anruf (das ist ~ 70 CPU-Zyklen) und ist vergleichbar mit den Kosten einer für die Schleife leeren Iteration (d. h. eine Inkrement- und eine Bedingungsprüfung für eine lokale Variable)

Beachten Sie, dass in Ihrem Fall das String-Argument immer ausgewertet wird. Wenn Sie eine Kettenverkettung durchführen, müssen Sie Zwischenstrings erstellen. Dies wird sehr kostspielig sein und eine Menge von GC beinhalten. Zum Beispiel Ausführen einer Funktion:

%Vor%

wird mit Argumenten wie

aufgerufen %Vor%

10 ^ 4 Iterationen von 100 solcher Aufrufe dauert 10s. Das ist 10 us / Anruf, d. H. ~ 1000 mal langsamer als nur ein leerer Anruf. Es produziert auch eine große Menge an GC-Aktivität. Der einzige Weg, dies zu vermeiden, besteht darin, die Funktion manuell zu inline zu schreiben, d. H. & Gt; & gt; wenn & lt; & lt; Anweisung anstelle des Debugfunktionsaufrufs. Es ist hässlich, aber der einzige Weg, es zum Laufen zu bringen.

    
misiu_mp 15.02.2011, 21:55
quelle
2

Wenn Sie dies nicht aus einer tief verschachtelten Schleife heraus aufrufen, würde ich mir darüber keine Sorgen machen.

    
Dan Breslau 03.12.2010 13:16
quelle
2

Ein guter Compiler entfernt die gesamte leere Methode, sodass überhaupt kein Overhead entsteht. Ich bin mir nicht sicher, ob der Dalvik-Compiler das schon tut, aber ich vermute, dass es wahrscheinlich ist, zumindest seit dem Eintreffen des Just-in-Time-Compilers mit Froyo.

Siehe auch: Inline-Erweiterung

    
user494085 03.12.2010 13:21
quelle
2

Im Hinblick auf die Leistung wird der Overhead beim Erzeugen der Nachrichten, die in die Debug-Funktion gelangen, viel ernster sein, da wahrscheinlich Speicherzuweisungen gemacht werden, zB

%Vor%

Was auch immer noch durch die Nachricht geschieht, ist in Binned. Leider benötigen Sie wirklich das "if (Release.DEBUG)" um die Aufrufe dieser Funktion und nicht innerhalb der Funktion selbst, wenn Ihr Ziel Leistung ist, und Sie werden dies in einer Menge Android-Code sehen.

    
aronp 03.12.2010 17:35
quelle
1

Dies ist eine interessante Frage und ich mag @misiu_mp Analyse, also dachte ich, ich würde es mit einem Test 2016 auf einem Nexus 7 mit Android 6.0.1 aktualisieren. Hier ist der Testcode:

%Vor%

Die sleep() wurde hinzugefügt, um das Überlaufen des Log.d -Puffers zu verhindern.

Ich habe viele Male damit herumgespielt und die Ergebnisse waren ziemlich konsistent mit @misiu_mp:

%Vor%

Der statische Methodenaufruf war immer etwas schneller als der nicht statische Methodenaufruf, aber es scheint, dass a) die Lücke seit Android 2.3.2 deutlich geschlossen wurde und b) es noch immer Kosten für Aufrufe an eine leere Methode gibt , statisch oder nicht.

Ein Blick auf ein Histogramm von Zeiten offenbart jedoch etwas Interessantes. Die Mehrheit der Anrufe, egal ob statisch oder nicht, dauert zwischen 30 und 40 ns, und wenn man sich genau die Daten anschaut, sind sie praktisch alle 30 ns genau.

Wenn Sie den gleichen Code mit leeren Schleifen ausführen (die Methodenaufrufe kommentieren), wird eine Durchschnittsgeschwindigkeit von 8 ns erzeugt, jedoch sind 3/4 der gemessenen Zeiten 0 ns, während der Rest genau 30 ns beträgt.

Ich bin nicht sicher, wie ich diese Daten berücksichtigen soll, aber ich bin mir nicht sicher, ob die Schlussfolgerungen von @ misiu_m immer noch gelten. Der Unterschied zwischen leeren statischen und nicht-statischen Methoden ist vernachlässigbar und das Überwiegen von Messungen ist genau 30ns. Es scheint jedoch, dass es noch einige Kosten gibt, die nicht Null sind, um leere Methoden auszuführen.

    
Mark Cramer 06.04.2016 01:12
quelle

Tags und Links