Unerklärlicher Speedup

fkerber

Mitglied
Hi!

Ich habe ein Problem, dass es mir schwer macht, eine Optimierung durchzuführen. Ich versuche, es mal zu umreißen:
Es geht um die Programmierung einer MainMemory-Storage-Database - konkret um Queries an diese. Man hat also solche Sachen wie eine Selektion einer Projektion eines Kreuzproduktes von 2 Tabellen.
Jede dieser Dinger ist eine eigene Klasse und man hat dann ein Objekt davon, das eine Handle-Methode hat, die dann die eigentliche Aktion ausführt. Ein Aufruf sieht dann z.B. so aus

Java:
		// Inputs
		Input S = new Input("S");
		Input N = new Input("N");
		Input R = new Input("R");

		// Joins
		Join S_join_N = new Join(S, N, "s_id", "n_id");
		Join S_join_N_join_R = new Join(S_join_N, R, "n_rid",
				"r_rid");

		// Select
		PredicateTreeNode predicate = new LeafPredicateTreeNode("r_name",
				ComparisonOperator.EQ, new String("TEST"));
		Selection sel = new Selection(S_join_N_join_R, predicate);

		// Project
		Projection proj = new Projection(sel, new String[] { "s_name" });

		// Execute Query
		query(proj);

Jetzt kann man solche Queries optimieren, wenn man die Reihenfolge der Ausführung ändert (also z.B. die Projektion vor der Selektion macht (etwas angepasst dann, aber nur vom System her)).

Nicht alle Umschreibungen, die möglich sind, sind auch sinnvoll - daher sollte man messen, welche Ausführung wie lange braucht - und genau da ist das Problem.
Selbst wenn ich 3x hintereinander die selbe Query (also ohne Umschreibungen) ausführe, sind die Zeiten nicht annähernd gleich (z.B. 107ms, 6ms, 6ms oder auch mal 40ms, 68ms, 12ms).
Dabei führe ich die Queries direkt hintereinander aus, also sollte die Rechnerauslastung in etwa gleich sein. In aller Regel ist es so, dass die 2. und 3. Query schneller sind als die erste....

Das macht eine Optimierung sehr schwer.

Hat vllt. jemand eine Idee, warum die selbe Sachen um fast Faktor 20 schneller werden, wenn ich sie 2x hintereinander ausführe?
Kann man da irgendetwas dagegen machen?

Grüße,
fkerber
 

MrWhite

Bekanntes Mitglied
Die JVM hat doch einen Hotspot Compiler, der Code bei der ersten Ausführung in nativen und optimierten Bytecode übersetzt, wenn sie merkt, dass der Code öfters gebraucht wird.

Ausserdem vermute ich, dass der Speicher bereits alloziert worden ist und wieder verwendet wird oder das die JVM intern cached.

Du könntest bei den Startup-Parametern der JVM gucken, ob du diese beiden Dinge irgendwie unterbinden kannst.

Such mal hier z.B. Java HotSpot VM Options

oder

Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine
 

fkerber

Mitglied
Hi!

Von welchem Server sprichst du?
Das DBMS ist komplett selbst geschrieben und kein absichtlicher Cache eingebaut.

Edit:
Alles klar ;)
@MrWhite:
Vielen Dank - ich werde danach schauen.

Grüße, fkerber
 
T

tuxedo

Gast
Wie läuft denn die Kommunikation mit dem Server?

Wenn Object*Streams eingesetzt werden dann wird da ganz massiv gecached was das serialisieren von Objekten angeht.

- Alex
 

MrWhite

Bekanntes Mitglied
Ich vermute, es gibt da noch keinen Server, die Engine wird direkt getestet. Das muss in erster Linie der JIT-Compiler der JVM sein.
 

ice-breaker

Top Contributor
wird denn auf die Festplatte zugegriffen?
Das Betriebssystem kann die gelesenen Daten und mehr (read-ahead) cachen, damit du in Zukunft weniger/keine IO-Zugriffe auf die Festplatte brauchst.

Edit: Ups, memory-only-db :eek: hmm, vllt wirklich die VM-Optimierungen
 

FArt

Top Contributor
Der Laufzeitcompiler optimiert erst nach vielen (oft sehr vielen) Durchläufen z.B. durch Inlining u.Ä.

Microbenchmarks sind oft mir Vorsicht zu genießen. Da wirken sich viele Parameter aus, z.B. die Instanziierung von Objekten ein später einsetzender GC usw. Ich würde sagen, die Zahlen sind in der Form einfach nicht aussagekräftig genug um irgendwelche Rückschlüsse zu ziehen, abhängig von der suboptimalen Herangehensweise.
 

MrWhite

Bekanntes Mitglied
Der Laufzeitcompiler optimiert erst nach vielen (oft sehr vielen) Durchläufen z.B. durch Inlining u.Ä.

Mag sein, dass der JIT erst spät das optimieren anfängt, aber eine Übersetzung in nativen Bytecode findet recht rasch statt und das hat die größten Auswirkungen auf die Performance.

Microbenchmarks sind oft mir Vorsicht zu genießen. Da wirken sich viele Parameter aus, z.B. die Instanziierung von Objekten ein später einsetzender GC usw. Ich würde sagen, die Zahlen sind in der Form einfach nicht aussagekräftig genug um irgendwelche Rückschlüsse zu ziehen, abhängig von der suboptimalen Herangehensweise.

Du hast vollkommen recht, 3 Durchläufe sind etwas wenig für einen Performance-Test.
 

fkerber

Mitglied
Gibt es denn andere Möglichkeiten, wie man so etwas besser testen kann?
Auch mehr als 3 Testläufe bringen leider nichts, weil dann einfach im Mittel bei allen Ausfürhungen 5 oder 6ms rauskommen - egal ob optimiert oder nicht.
Und zumindest in der Theorie gibt es massive Unterschiede...
 

ThreadPool

Bekanntes Mitglied
Gibt es denn andere Möglichkeiten, wie man so etwas besser testen kann?
Auch mehr als 3 Testläufe bringen leider nichts, weil dann einfach im Mittel bei allen Ausfürhungen 5 oder 6ms rauskommen - egal ob optimiert oder nicht.
Und zumindest in der Theorie gibt es massive Unterschiede...

Was sind denn bei dir "mehr als 3 Testläufe"? 5-6? Wie ist die Verteilung der Ergebnisse, sollte vielleicht eine andere Maßzahl als das arithmetische Mittel verwendet werden, der Median z.B.? Verwendest du überhaupt realistische Testdaten? Letzteres ist wichtig, wenn Algorithmus A theoretisch besser ist als Algorithmus B gilt das ja oft erst ab einer bestimmten Größenordnung der zu verarbeitenden Daten.
 

fkerber

Mitglied
Ich habe die Zeiten bisher einfach mit System.getCurrentTimeMillis davor und danach und davon die Differenz dann.

Kann ich deiner Aussage entnehmen, dass das nicht sinnvoll ist?
 
S

SlaterB

Gast
wenn irgendwas 6ms dauert, muss man es eben 1000x hintereinander machen, dann sind es 6000,
wenn beide schwankend 5-6 sec dauern, dann gibt es offensichtlich keine messbaren Unterschiede
 
M

maki

Gast
Ich habe die Zeiten bisher einfach mit System.getCurrentTimeMillis davor und danach und davon die Differenz dann.

Kann ich deiner Aussage entnehmen, dass das nicht sinnvoll ist?
Das ist absolut nicht sinnvoll imho, nimm einen Profiler wie VisualVM (integriert in NetBeans), Eclipse TPTP, oder oder oder... aber bitte nciht versuchen das selber zu machen wenn es wichtig ist.
 

FArt

Top Contributor
Gibt es denn andere Möglichkeiten, wie man so etwas besser testen kann?
Auch mehr als 3 Testläufe bringen leider nichts, weil dann einfach im Mittel bei allen Ausfürhungen 5 oder 6ms rauskommen - egal ob optimiert oder nicht.
Und zumindest in der Theorie gibt es massive Unterschiede...
Ein Messwert (ob klein oder groß) sagt für sich nichts aus.
Lassen wir mal theoretische Probleme außer Acht, die sind eben nur theoretisch.

Was soll gemessen werden? Welche nicht-funktionale Anforderung steckt dahinter?
Ein Durchschnittswert? Ein Maximum? Der erste Zugriff? Für eine Anfrage? Für konkurrierende Zugriffe? Mehrere Zugriffe auf geteilte Daten oder auf separate Daten? ...?
Je nach Fragestellung muss ich die Art und Weise des Performancetests aufbauen, z.B. evtl. das System "vorwärmen" usw, danach die Zahlen den Anforderungen entsprechend interpretieren.
 

fkerber

Mitglied
Hi!

Also es soll gemessen werden, ob eine Query schneller ist als eine andere. Als Beispiel kann eine zusätzliche Projektion eingeführt werden - das heißt dann auf der einen Seite, dass es nach dieser weniger Daten gibt, die von den anderen "Operatoren" betrachtet werden müssen - auf der anderen Seite bedeutet die zusätzliche Projektion ja mehr Arbeit.
Daher müsste man wissen, ob diese Optimierung wirklich eine ist, oder ob es mehr eine Verschlimmbesserung ist ;)

Von der theoretischen Seite her, sollte jeder Ausführung einer gleichen Query gleich lange dauern - klar, dass das in der Praxis nicht genau so sein kann - aber eine Schwankung um Faktor 20 macht die Messung leider unbrauchbar - auch der Mittelwert alleine bringt leider nichts, wie sich gezeigt hat...

Hoffe, das beantwortet deine Frage.

Grüße, Frederic
 

Ähnliche Java Themen

Neue Themen


Oben