Ich schreibe eine (einfache!) Lineare Algebra-Bibliothek. Bei der Implementierung von matrix multiplication eine VisualVM Leistung Probe wird mir zu sagen, dass der Algorithmus 85% seiner Zeit („self Zeit“, speziell) in dem folgende Verfahren verbringt, wenn große Matrizen multiplizieren (5k x 120k):Warum ist diese Methode ein Hot Spot?
public double next() {
double result;
if(hasNext())
result = vis[i++].next();
else
throw new IllegalStateException("No next value");
return result;
}
Ohne zu sehr ins Detail zu gehen (sorry, ich kann nicht mehr Code teilen), ist diese Methode die next()
Methode eines "Iterators" für die Matrix. (Sie können sich die Klasse vorstellen, in der diese Methode als Zeileniterator aus einzelnen Spalteniteratoren lebt, die in vis
gespeichert sind.) Es überrascht mich nicht, dass diese Methode viel aufgerufen wird, da sie ein Iterator ist, aber ich bin überrascht, dass das Programm eine Menge Zeit in diese Methode verbringt. Diese Methode macht nicht viel, also warum verbringt sie ihre Zeit hier?
Hier sind die spezifischen Fragen Ich frage:
- Gibt es eine „Gotcha“ von VisualVM Ich schlage? Könnte das JIT zum Beispiel VisualVM in irgendeiner Weise verwirren, was dazu führt, dass VisualVM die Zeit der falschen Methode zuordnet?
- Warum sollte das Programm hier seine Zeit verbringen? Die Methode macht einfach nicht viel. Insbesondere glaube ich nicht, dass Cache-Effekte dieses Problem erklären, da das Array
vis
viel kleiner ist als die Daten der Matrizen, die multipliziert werden.
Im Fall ist es sinnvoll, hier ist ein jad Demontage des Verfahrens ich oben eingefügt: für Ihre Hilfe Jungs
public double next()
{
double result;
if(hasNext())
//* 0 0:aload_0
//* 1 1:invokevirtual #88 <Method boolean hasNext()>
//* 2 4:ifeq 32
result = vis[i++].next();
// 3 7:aload_0
// 4 8:getfield #42 <Field VectorIterator[] vis>
// 5 11:aload_0
// 6 12:dup
// 7 13:getfield #28 <Field int i>
// 8 16:dup_x1
// 9 17:iconst_1
// 10 18:iadd
// 11 19:putfield #28 <Field int i>
// 12 22:aaload
// 13 23:invokeinterface #72 <Method double VectorIterator.next()>
// 14 28:dstore_1
else
//* 15 29:goto 42
throw new IllegalStateException("No next value");
// 16 32:new #89 <Class IllegalStateException>
// 17 35:dup
// 18 36:ldc1 #91 <String "No next value">
// 19 38:invokespecial #93 <Method void IllegalStateException(String)>
// 20 41:athrow
return result;
// 21 42:dload_1
// 22 43:dreturn
}
Vielen Dank im Voraus!
Ich denke, es hängt wirklich von den hasNext() und next() Aufrufen ab, da wir die zugrunde liegenden Objekte nicht kennen, kann ich nicht annehmen, sie sind O (1) und die Methode sollte ziemlich schnell sein, dass hasNext() sein könnte Um die Sonne gehen 1000x für alles, was wir wissen – RuntimeError
@RuntimeError, "selbst Zeit" * sollte * nur Zeit in der Methode selbst enthalten, so dass die 'hasNext()' und die Sub-'next()' Anrufe * haben sollte nichts mit der Zeit zu tun, die dieser Methode zugeschrieben wird, soweit ich weiß. (Bitte korrigieren Sie mich, wenn Sie anders wissen!) – sigpwned
Ist 'next' selbst (rekursiv)? Das wäre ein guter Grund, warum es Zeit braucht, wenn die Rekursion tief ist ... – assylias