2014-09-16 5 views
8

Ich habe kürzlich angefangen, über Benchmarks zu lesen und sie für Android (in Java) zu schreiben. Mir sind solche Probleme wie Warmups, Garbage Collector und Compiler-Optimierungen bekannt, aber ich weiß nicht, ob das Problem, auf das ich stoße, von einem dieser Probleme verursacht werden könnte.Warum verursacht das Hinzufügen lokaler Variablen eine Verzögerung der Methode?

In meiner Benchmark-App erstelle ich ein Array von 10.000 Float-Variablen und initialisiere es mit zufälligen Werten. Wenn Benchmark-Code ausgeführt wird:

private void runMinorBenchmarkFloat (float[] array) { 
     float sum = 0; 
     long startTime; 
     long endTime; 

     /* Fast warm-up */ 
     startTime = System.nanoTime(); 
     for(int i=0; i<SMALL_LOOP_ITERATION_COUNT; i++) 
      for(int j=0; j<TAB_SIZE; j++) 
       sum += array[j]; 
     endTime = System.nanoTime() - startTime; 
     postMessage("Warm-up for FLOAT finished in: " + endTime/1000000 + "ms.\n"); 

     /* Main benchmark loop */ 
     startTime = System.nanoTime(); 
     for(int i=0; i<BIG_LOOP_ITERATION_COUNT; i++) 
     { 
      sum = 0; 
      for(int j=0; j<TAB_SIZE; j++) 
       sum += array[j]; 
     } 
     endTime = System.nanoTime() - startTime; 
     postMessage("Benchmark for FLOAT finished in: " + endTime/1000000 + "ms.\n"); 
     postMessage("Final value: " + sum + "\n\n"); 
    } 

auf meinem Handy bekomme ich ca. 2 Sekunden für Warm-up und 20 Sekunden für die „echte“ Schleife.

Nun, wenn ich hinzufügen, zwei weitere Variablen vom Typ float (sum2 und SUM3 - nie in der Methode verwendet wird):

private void runMinorBenchmarkFloat (float[] array) { 
     float sum = 0, sum2 = 0, sum3 = 0; // <------- the only code change here!!! 
     long startTime; 
     long endTime; 

     /* Fast warm-up */ 
     startTime = System.nanoTime(); 
     for(int i=0; i<SMALL_LOOP_ITERATION_COUNT; i++) 
      for(int j=0; j<TAB_SIZE; j++) 
       sum += array[j]; 
     endTime = System.nanoTime() - startTime; 
     postMessage("Warm-up for FLOAT finished in: " + endTime/1000000 + "ms.\n"); 

     /* Main benchmark loop */ 
     startTime = System.nanoTime(); 
     for(int i=0; i<BIG_LOOP_ITERATION_COUNT; i++) 
     { 
      sum = 0; 
      for(int j=0; j<TAB_SIZE; j++) 
       sum += array[j]; 
     } 
     endTime = System.nanoTime() - startTime; 
     postMessage("Benchmark for FLOAT finished in: " + endTime/1000000 + "ms.\n"); 
     postMessage("Final value: " + sum + "\n\n"); 
    } 

Ausführungszeit von 2 Sekunden springt für Warm-up auf 5 Sekunden und 20 Sekunden für echte Schleife bis 50 Sekunden.

Die Konstanten:

SMALL_LOOP_ITERATION_COUNT = 100,000 
BIG_LOOP_ITERATION_COUNT = 1,000,000 

Glauben Sie, dass diese Differenz durch Ausrichtungsprobleme verursacht werden könnten (nur lose Idee)?

Vielen Dank im Voraus für alle Antworten.

EDIT:

Es scheint, wie diese Fehler auf jedem Gerät nicht angezeigt. Ich kann es auf dem Samsung Galaxy S5 reproduzieren. Das Hauptziel des Programms war, wenig Benchmark zu machen. Ich habe vier fast-die gleichen Funktionen (runMinorBenchmark____ wo _ war entweder: int, kurz, float, double), die nur in der Variable 'sum' Typ unterschieden. In der Hauptbewertungsfunktion habe ich diese Funktionen aufgerufen. Da der erwähnte Fehler aufgetreten ist, habe ich mich entschlossen, diese Funktion in eine große zusammenzufassen. Jetzt ... Beim Testlauf habe ich solche Zeiten: 1. 37640ms. (für int) 2. 46728ms. (kurz) 3. 60589ms. (für Schwimmer) 4. 34467ms. (für Doppel)

Ich weiß, dass kurze soll wegen Typ Gießen langsamer sein. Ich dachte auch, dass Float langsamer sein sollte, wenn man es zu verdoppeln versucht (vielleicht gibt FPU den Casting-Befehl jedes Mal doppelt (?)). Aber wenn ich den Variablentyp für sumFloat von float auf double ändere, ist die Zeit für float identisch mit double time. Ich habe auch diese "Benchmark" auf einem anderen Gerät, das nicht von diesem seltsamen Verhalten zu leiden schien und die Zeiten für jeden Test waren fast gleich: ~ 45000ms. (wirklich keine sichtbaren Unterschiede).

Dalvik VM Fehler (?)

+1

Nein. Das Hinzufügen von zwei "unbenutzten" Feldern hat keinen Einfluss auf die tatsächliche Laufzeit der Schleife. Etwas anderes muss falsch sein. – TheLostMind

+0

Ich stimme @TheLostMind zu. Das Hinzufügen von zwei Float-Variablen sollte die Ausführungszeit nicht wesentlich verlängern. Wie Sie sehen können, kann die CPU 10.000 Floats sehr schnell verarbeiten, also gibt es keinen Grund, warum es nicht in der Lage sein sollte, diese beiden schnell zu verarbeiten. – erad

+0

Danke für die Antworten. Ich stimme euch beiden zu, aber das ist es, was wirklich passiert. Haben Sie Ideen, wo Sie weiter suchen können? – Waszker

Antwort

2

Ich weigere mich zu glauben, dass die Ursache Ihrer Probleme ist. Sicher, der Compiler schmeißt die ungenutzten Variablen einfach weg? Sind Sie sicher, dass sich das Eingabearray nicht ändert oder Ihre Konstanten oder ?

Wenn Sie immer noch sicher sind, beweisen sie durch so etwas wie dieses ausgeführt und Einfügen der Ausgabe hier:

public void proveIt() { 
    float[] inputArray = new float[10000]; 
    for (int i = 0; i < 10000; i++) { 
     inputArray[i] = 1; 
    } 

    postMessage("Without declaration:"); 
    runMinorBenchmarkFloatA(inputArray); 

    postMessage("With declaration:"); 
    runMinorBenchmarkFloatB(inputArray); 

    postMessage("And again just to make sure..."); 

    postMessage("Without declaration:"); 
    runMinorBenchmarkFloatA(inputArray); 

    postMessage("With declaration:"); 
    runMinorBenchmarkFloatB(inputArray); 
} 

long TAB_SIZE = 10000; 
long SMALL_LOOP_ITERATION_COUNT = 100000; 
long BIG_LOOP_ITERATION_COUNT = 1000000; 

private void runMinorBenchmarkFloatA(float[] array) { 
    float sum = 0; 
    long startTime; 
    long endTime; 

    /* Fast warm-up */ 
    startTime = System.nanoTime(); 
    for (int i = 0; i < SMALL_LOOP_ITERATION_COUNT; i++) 
     for (int j = 0; j < TAB_SIZE; j++) 
      sum += array[j]; 
    endTime = System.nanoTime() - startTime; 
    postMessage("Warm-up for FLOAT finished in: " + endTime 
      /1000000 + "ms.\n"); 

    /* Main benchmark loop */ 
    startTime = System.nanoTime(); 
    for (int i = 0; i < BIG_LOOP_ITERATION_COUNT; i++) { 
     sum = 0; 
     for (int j = 0; j < TAB_SIZE; j++) 
      sum += array[j]; 
    } 
    endTime = System.nanoTime() - startTime; 
    postMessage("Benchmark for FLOAT finished in: " + endTime 
      /1000000 + "ms.\n"); 
    postMessage("Final value: " + sum + "\n\n"); 
} 

private void runMinorBenchmarkFloatB(float[] array) { 
    float sum = 0, sum2 = 0, sum3 = 0; 
    long startTime; 
    long endTime; 

    /* Fast warm-up */ 
    startTime = System.nanoTime(); 
    for (int i = 0; i < SMALL_LOOP_ITERATION_COUNT; i++) 
     for (int j = 0; j < TAB_SIZE; j++) 
      sum += array[j]; 
    endTime = System.nanoTime() - startTime; 
    postMessage("Warm-up for FLOAT finished in: " + endTime 
      /1000000 + "ms.\n"); 

    /* Main benchmark loop */ 
    startTime = System.nanoTime(); 
    for (int i = 0; i < BIG_LOOP_ITERATION_COUNT; i++) { 
     sum = 0; 
     for (int j = 0; j < TAB_SIZE; j++) 
      sum += array[j]; 
    } 
    endTime = System.nanoTime() - startTime; 
    postMessage("Benchmark for FLOAT finished in: " + endTime 
      /1000000 + "ms.\n"); 
    postMessage("Final value: " + sum + "\n\n"); 
} 
+0

Ok, ich habe es auf zwei verschiedenen Geräten gemacht und hier sind die Ergebnisse: Erstes Gerät, auf dem die vorherigen Probleme aufgetreten sind (Samsung Galaxy S5): 1. 21170ms. 2. 55626ms. 3. 20640 ms. 4. 55522 ms. Aber auf dem zweiten Gerät (Samsung Note): 1. 32194ms. 2. 34008 ms. 3. 32171 ms. 4. 34359 ms. – Waszker

0

Nun, wenn ich zwei weitere Schwimmer Variablen (sum2 und SUM3 hinzufügen - nie innerhalb des Hauses das Verfahren):

float sum = 0, sum2 = 0, sum3 = 0; // <------- the only code change here!!! 

Aber sum2 und sum3 innerhalb des Verfahrens verwendet. Sie werden auf Null initialisiert. Das kostet Zeit.

Wenn sie nicht initialisiert wurden, wäre der generierte Byte-Code identisch mit und ohne sie, abgesehen von der Größe des zugewiesenen Stack-Frames, was das Timing nicht beeinflusst.

+1

Ich denke, es könnte nicht so große Verzögerungen verursachen, oder? – Waszker

Verwandte Themen