PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Optimierungsfrage zum java Compiler/JVM


Senior Sanchez
2005-11-24, 11:52:34
Hi,

Mal ne Frage, die gerade aufgekommen ist (der Kontext ist jetzt nicht so wichtig).

Was macht der Compiler bzw. die VM aus so einem Konstrukt?

zahl[a >> 3] += b?

wird das zu zahl[a >> 3] = zahl[a >> 3] + b?

Weil dann könnte man das a >> 3 in ne tmp Variable speichern und somit Rechenaufwand sparen, oder?

Trap
2005-11-24, 12:17:29
Ob der Compiler es macht kannst du nachgucken mit http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javap.html

Wie man der JVM auf die Finger gucken kann weiß ich allerdings nicht.

Coda
2005-11-24, 14:10:39
Weil dann könnte man das a >> 3 in ne tmp Variable speichern und somit Rechenaufwand sparen, oder?Woa Leute, hört auf an solchen Stellen zu "optimieren". Die Compiler heute sind lang nicht mehr so hirntot wie ihr glaubt und machen sowas selber.

Lesbaren Code schreiben und nen Profiler benützen damit man auch an notwendigen Stellen wirklich was optimieren kann.

Senior Sanchez
2005-11-24, 14:23:59
Woa Leute, hört auf an solchen Stellen zu "optimieren". Die Compiler heute sind lang nicht mehr so hirntot wie ihr glaubt und machen sowas selber.

Lesbaren Code schreiben und nen Profiler benützen damit man auch an notwendigen Stellen wirklich was optimieren kann.

Es geht aber um Millisekunden ;) Und es ist doch nicht so, dass ich das generell so mache, es ist einfach ne art proof-of-concept, was möglich ist.

Ich habs btw mal dissassembliert ;)


public class Test {

public static void main(String[] args) {

int[] a= new int[] {0, 1, 2, 3, 4};
int b=2;

System.out.println("");

a[8 >> 3] += b;
System.out.println("");

a[8 >> 3] = a[8 >> 3] + b;

System.out.println(a);

}

}

Is einfach mal nen Testcode und dazu die Ausgabe des Dissassemblers:

Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: iconst_5
1: newarray int
3: dup
4: iconst_0
5: iconst_0
6: iastore
7: dup
8: iconst_1
9: iconst_1
10: iastore
11: dup
12: iconst_2
13: iconst_2
14: iastore
15: dup
16: iconst_3
17: iconst_3
18: iastore
19: dup
20: iconst_4
21: iconst_4
22: iastore
23: astore_1
24: iconst_2
25: istore_2
26: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
29: ldc #3; //String
31: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: aload_1
35: iconst_1
36: dup2
37: iaload
38: iload_2
39: iadd
40: iastore
41: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
44: ldc #3; //String
46: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
49: aload_1
50: iconst_1
51: aload_1
52: iconst_1
53: iaload
54: iload_2
55: iadd
56: iastore
57: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
60: aload_1
61: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
64: return

}



Die System.out.printlns sind zur besseren orientierung. Was auffällt: Bei Variante 1 (a[8 >> 3] += b) kommt das hier:
34: aload_1
35: iconst_1
36: dup2
37: iaload
38: iload_2
39: iadd
40: iastore

und bei der anderen das hier:
49: aload_1
50: iconst_1
51: aload_1
52: iconst_1
53: iaload
54: iload_2
55: iadd
56: iastore

Der einzige unterschied ist das bei Variante 1 dup2 aufgerufen wird, währenddessen bei der anderen aload_1 und iconst_1 aufgerufen wird. Die Variante hat sozusagen zwei Array-Zugriffe aber was bedeutet das dup2?

zeckensack
2005-11-24, 14:33:07
<...>
Der einzige unterschied ist das bei Variante 1 dup2 aufgerufen wird, währenddessen bei der anderen aload_1 und iconst_1 aufgerufen wird. Die Variante hat sozusagen zwei Array-Zugriffe aber was bedeutet das dup2?Egal.
Dein Experiment ist sowieso für die Katz weil 8>>3 eine Konstante ist.
Mach's nochmal mit Variable>>3, und dann können wir drüber reden.
Ich tendiere aber auch sehr zu Coda's Meinung. Das ist CSE für blöde, kein moderner Compiler wird daran scheitern, zumal deine Ausgansfrage ...zahl[a >> 3] += b?

wird das zu zahl[a >> 3] = zahl[a >> 3] + b?... mit einem klaren Nein beantwortet werden muss, und somit sogar diese "CSE für blöde" flachfällt.

*CSE: common subexpression elimination (http://en.wikipedia.org/wiki/Common_subexpression_evaluation)

Senior Sanchez
2005-11-24, 14:39:32
Egal.
Dein Experiment ist sowieso für die Katz weil 8>>3 eine Konstante ist.
Mach's nochmal mit Variable>>3, und dann können wir drüber reden.
Ich tendiere aber auch sehr zu Coda's Meinung. Das ist CSE für blöde, kein moderner Compiler wird daran scheitern, zumal deine Ausgansfrage ...... mit einem klaren Nein beantwortet werden muss, und somit sogar diese "CSE für blöde" flachfällt.

*CSE: common subexpression elimination (http://en.wikipedia.org/wiki/Common_subexpression_evaluation)

So besser?


public class Test {

public static void main(String[] args) {

int[] a= new int[] {0, 1, 2, 3, 4};
int b=2;
int c=8;

System.out.println("");

a[c >> 3] += b;
System.out.println("");

a[c >> 3] = a[c >> 3] + b;

System.out.println(a);

}

}



Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: iconst_5
1: newarray int
3: dup
4: iconst_0
5: iconst_0
6: iastore
7: dup
8: iconst_1
9: iconst_1
10: iastore
11: dup
12: iconst_2
13: iconst_2
14: iastore
15: dup
16: iconst_3
17: iconst_3
18: iastore
19: dup
20: iconst_4
21: iconst_4
22: iastore
23: astore_1
24: iconst_2
25: istore_2
26: bipush 8
28: istore_3
29: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
32: ldc #3; //String
34: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
37: aload_1
38: iload_3
39: iconst_3
40: ishr
41: dup2
42: iaload
43: iload_2
44: iadd
45: iastore
46: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
49: ldc #3; //String
51: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
54: aload_1
55: iload_3
56: iconst_3
57: ishr
58: aload_1
59: iload_3
60: iconst_3
61: ishr
62: iaload
63: iload_2
64: iadd
65: iastore
66: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
69: aload_1
70: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
73: return

}



Ich weiß, kommt jetzt bestimmt nen nein, aber ich poste es trotzdem.
Ich weiß, dass das nicht viel bringt bzw. im Rahmen der messungenauigkeit liegt, aber mich interessierts trotzdem *g*

Trap
2005-11-24, 14:46:32
Die JVM ist eine Stackmaschine und dup dupliziert den obersten Wert auf dem Stack. dup2 macht das gleiche nur auch für longs und doubles richtig.

zeckensack
2005-11-24, 14:47:21
OMFG yaaaaaa!
*hysterischlacht*
Deine JVM ist ja voll behindert! :ugly:

Weißt du was? Speicher dir eine Referenz auf das Element in dem Container, und arbeite damit. Das ist dann wohl doch schneller.

Und den Jungs von Sun sollte man das eigentlich auch mal zeigen. Das könnte glatt ein Bug sein (lvalue vs rvalue oder sowas).

Senior Sanchez
2005-11-24, 15:02:37
OMFG yaaaaaa!
*hysterischlacht*
Deine JVM ist ja voll behindert! :ugly:

Weißt du was? Speicher dir eine Referenz auf das Element in dem Container, und arbeite damit. Das ist dann wohl doch schneller.

Und den Jungs von Sun sollte man das eigentlich auch mal zeigen. Das könnte glatt ein Bug sein (lvalue vs rvalue oder sowas).

Siehste, durch meine nachforschung wegen solcher coolen Geschichten hätteste das jetzt nicht gewusst :ucatch:

ethrandil
2005-11-24, 19:13:51
Die JVM führt ja den Bytecode nicht direkt aus, sondern wandelt ihn in Maschinencode um. Dabei wird nach Bedarf (Hotspot) weiter optimiert.

Ob es da dann noch Geschwindigkeitsunterschiede gibt kannst du nur messen. [Oder Demirug fragen - der hats mal geschafft sich den generierten Assemblercode anzugucken. Durch nen Absturz ;)]

- Eth

Senior Sanchez
2005-11-24, 23:38:59
Die JVM führt ja den Bytecode nicht direkt aus, sondern wandelt ihn in Maschinencode um. Dabei wird nach Bedarf (Hotspot) weiter optimiert.

Ob es da dann noch Geschwindigkeitsunterschiede gibt kannst du nur messen. [Oder Demirug fragen - der hats mal geschafft sich den generierten Assemblercode anzugucken. Durch nen Absturz ;)]

- Eth

Naja, das weiß ich ja schon ;)

Aber es bringt nix, höchstens ganz minimale Unterschiede im Rahmen der Messungenauigkeit.

HajottV
2005-11-25, 11:13:43
Oder Demirug fragen - der hats mal geschafft sich den generierten Assemblercode anzugucken. Durch nen Absturz ;)

Das hab ich auch mal geschafft - durch einen Stacküberlauf. Hab's leider nie wieder reproduzieren können. Das Ganze war ziemlich erhellend - insbesondere in Hinblick auf die Qualität der JIT-Assemblercodes (die grottig ist).

Gruß

Jörg