Frage

Ich habe eine Klasse erstellt, um meine Debug-Ausgaben zu behandeln, so dass ich nicht alle vor der Veröffentlichung meiner Logausgaben abzustreifen aus.

public class Debug {
    public static void debug( String module, String message) {
        if( Release.DEBUG )
            Log.d(module, message);
    }
}

Nach einer anderen Frage zu lesen, ich habe gelernt, dass der Inhalt des if-Anweisung nicht kompiliert, wenn die Konstante Release.DEBUG falsch ist.

Was ich wissen möchte, ist, wie viel Aufwand wird durch das Ausführen dieses leere Methode erzeugt? (Wenn die if-Klausel dort entfernt wird, ist kein Code in der Methode links) Wird es Auswirkungen auf meine Anwendung haben? Offensichtlich Leistung ist ein großes Problem, wenn für Mobiltelefone zu schreiben = P

Danke

Gary

War es hilfreich?

Lösung

Die Messungen erfolgen auf dem Nexus S mit Android 2.3.2:

10^6 iterations of 1000 calls to an empty static void function: 21s  <==> 21ns/call
10^6 iterations of 1000 calls to an empty non-static void function: 65s  <==> 65ns/call

10^6 iterations of 500 calls to an empty static void function: 3.5s  <==> 7ns/call
10^6 iterations of 500 calls to an empty non-static void function: 28s  <==> 56ns/call

10^6 iterations of 100 calls to an empty static void function: 2.4s  <==> 24ns/call
10^6 iterations of 100 calls to an empty non-static void function: 2.9s  <==> 29ns/call

Kontrolle:

10^6 iterations of an empty loop: 41ms <==> 41ns/iteration
10^7 iterations of an empty loop: 560ms <==> 56ns/iteration
10^9 iterations of an empty loop: 9300ms <==> 9.3ns/iteration

Ich habe die Messungen wiederholt mehrmals. Keine signifikanten Abweichungen gefunden. Sie können sehen, dass die pro-Call-Kosten stark je nach Arbeitsbelastung variieren können (möglicherweise aufgrund JIT Compilierung), aber 3 Schlussfolgerungen gezogen werden:

  1. Dalvik / java saugt bei totem Code zu optimieren

  2. statische Funktion Anrufe können viel besser als nicht-statisch optimiert werden (Nicht-statische Funktionen sind virtuelle und Notwendigkeit in einer virtuellen Tabelle nachgeschlagen werden)

  3. die Kosten auf nexus s nicht größer als 70 ns / Anruf (das ist ~ 70 CPU-Zyklen) und ist vergleichbar mit den Kosten für einen leeren für Schleifeniteration (d.h. ein Inkrement und einer Bedingungsprüfung auf einer lokalen Variablen)

Beachten Sie, dass die String-Argument in Ihrem Fall wird immer ausgewertet werden. Wenn Sie String-Verkettung tun, beinhalten diese Zwischen Saiten zu schaffen. Dies wird sehr teuer sein und eine Menge gc einzubeziehen. Zum Beispiel die Ausführung einer Funktion:

void empty(String string){
}

genannt mit Argumenten wie

empty("Hello " + 42 + " this is a string " + count );

10 ^ 4 Wiederholungen von 100 solche Anrufe dauert 10s. Das heißt 10us / Anruf, das heißt bis 1000-mal langsamer als nur einen leeren Anruf. Es produziert auch riesige Menge an GC-Aktivität. Der einzige Weg, dies zu vermeiden, ist die manuelle Inline-Funktion, das heißt verwenden, um die >> wenn << Anweisung anstelle des Debug-Funktion aufrufen. Es ist hässlich, aber der einzige Weg, es funktioniert.

Andere Tipps

Wenn Sie diese anrufen aus einer tief verschachtelten Schleife, würde ich nicht darum kümmern.

Ein guter Compiler entfernt die gesamte leere Methode, sich im Handoverhead führt. Ich bin mir nicht sicher, ob der Dalvik Compiler bereits dies tut, aber ich vermute, es ist wahrscheinlich, zumindest seit der Ankunft der Just-in-Time-Compiler mit Froyo.

Siehe auch: Inline Expansion

Im Hinblick auf die Leistung der Aufwand, die Nachrichten zu erzeugen, die in die Debug-Funktion übergeben bekommen werden viel ernster sein, da seine wahrscheinlich, dass sie tun Speicherzuordnungen zB

Debug.debug(mymodule, "My error message" + myerrorcode);

, die auch noch durch die Nachricht auftreten wird binned. Leider müssen Sie wirklich die „if (Release.DEBUG)“ um die Anrufe auf diese Funktion nicht innerhalb der Funktion selbst, wenn Ihr Ziel ist die Leistung, und Sie werden diese in vielen Android-Code sehen.

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

public void runSpeedTest() {
    long startTime;
    long[] times = new long[100000];
    long[] staticTimes = new long[100000];
    for (int i = 0; i < times.length; i++) {
        startTime = System.nanoTime();
        for (int j = 0; j < 1000; j++) {
            emptyMethod();
        }
        times[i] = (System.nanoTime() - startTime) / 1000;
        startTime = System.nanoTime();
        for (int j = 0; j < 1000; j++) {
            emptyStaticMethod();
        }
        staticTimes[i] = (System.nanoTime() - startTime) / 1000;
    }
    int timesSum = 0;
    for (int i = 0; i < times.length; i++) { timesSum += times[i]; Log.d("status", "time," + times[i]); sleep(); }
    int timesStaticSum = 0;
    for (int i = 0; i < times.length; i++) { timesStaticSum += staticTimes[i]; Log.d("status", "statictime," + staticTimes[i]); sleep(); }
    sleep();
    Log.d("status", "final speed = " + (timesSum / times.length));
    Log.d("status", "final static speed = " + (timesStaticSum / times.length));
}

private void sleep() {
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void emptyMethod() { }
private static void emptyStaticMethod() { }

Die sleep() wurde hinzugefügt, um den Log.d Puffer zu verhindern, überfüllt.

spielte ich oft mit ihm um, und die Ergebnisse waren ziemlich konsistent mit @misiu_mp:

10^5 iterations of 1000 calls to an empty static void function: 29ns/call
10^5 iterations of 1000 calls to an empty non-static void function: 34ns/call

Die statische Methode Aufruf war immer etwas schneller als die nicht-statische Methode aufrufen, aber es scheint, dass a) die Lücke seit Android deutlich geschlossen 2.3.2 und b) es gibt noch eine Kosten Anrufe an eine leere Methode zur Herstellung von , statisch oder nicht.

Mit Blick auf ein Histogramm der Zeiten zeigt etwas Interessantes, aber. Die Mehrheit des Anrufs, ob statisch oder nicht, zwischen 30-40ns nehmen und eng mit Blick auf den Daten, die sie sind so gut wie alle 30 ns genau.

Ausführen des gleichen Code mit leeren Schleifen (Kommentierung der Verfahrensaufrufe) erzeugt eine Durchschnittsgeschwindigkeit von 8 ns, jedoch etwa 3/4 der gemessenen Zeiten sind 0ns während der Rest sind genau 30ns.

Ich bin mir nicht sicher, wie man Konto für diese Daten, aber ich bin nicht sicher, dass @ misiu_mp Schlussfolgerungen noch halten. Der Unterschied zwischen leeren statischen und nicht-statischen Methoden vernachlässigbar ist, und das Übergewicht der Messungen ist genau 30ns. That being said, so scheint es, dass es noch einige Nicht-Null-Kosten leere Methoden ausgeführt werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top