Was ist eine Standardmethode zum Profilieren von Scala-Methodenaufrufen?
Was ich brauche, sind Hooks um eine Methode, mit der ich Timer starten und stoppen kann.
In Java verwende ich die Aspektprogrammierung, AspektJ, um die zu profilierenden Methoden zu definieren und Bytecode einzufügen, um dasselbe zu erreichen.
Gibt es in Scala einen natürlicheren Weg, auf dem ich eine Reihe von Funktionen definieren kann, die vor und nach einer Funktion aufgerufen werden sollen, ohne dabei statische Eingaben zu verlieren?
Antworten:
Möchten Sie dies tun, ohne den Code zu ändern, für den Sie das Timing messen möchten? Wenn es Ihnen nichts ausmacht, den Code zu ändern, können Sie Folgendes tun:
quelle
t1
innerhalb einerfinally
Klauseldef time[R](label: String)(block: => R): R = {
println
Zusätzlich zu Jespers Antwort können Sie Methodenaufrufe automatisch in die REPL einschließen:
Nun - lassen Sie uns etwas darin einwickeln
OK - wir müssen im Power-Modus sein
Weg wickeln
Ich habe keine Ahnung, warum das 5 Mal gedruckt wurde
Update ab 2.12.2:
quelle
:wrap
Feature wurde entfernt aus dem REPL: - \Es gibt drei Benchmarking-Bibliotheken für Scala , die Sie nutzen können.
Da sich die URLs auf der verlinkten Website wahrscheinlich ändern, füge ich den entsprechenden Inhalt unten ein.
SPerformance - Framework für Leistungstests, das darauf abzielt, Leistungstests automatisch zu vergleichen und in Simple Build Tool zu arbeiten.
Scala-Benchmarking-Vorlage - SBT-Vorlagenprojekt zum Erstellen von Scala (Mikro-) Benchmarks basierend auf Caliper.
Metriken - Erfassen von Metriken auf JVM- und Anwendungsebene. Sie wissen also, was los ist
quelle
Das was ich benutze:
quelle
testing.Benchmark
könnte nützlich sein.quelle
Ich nahm die Lösung von Jesper und fügte ihr bei mehreren Durchläufen desselben Codes eine Aggregation hinzu
Angenommen, Sie möchten zwei Funktionen zeitlich festlegen,
counter_new
undcounter_old
Folgendes wird verwendet:Hoffentlich ist das hilfreich
quelle
Ich verwende eine Technik, die sich leicht in Codeblöcken bewegen lässt. Der springende Punkt ist, dass genau dieselbe Zeile den Timer startet und beendet - es ist also wirklich ein einfaches Kopieren und Einfügen. Die andere schöne Sache ist, dass Sie definieren können, was das Timing für Sie als Zeichenfolge bedeutet, alle in derselben Zeile.
Anwendungsbeispiel:
Der Code:
Vorteile:
Nachteile:
quelle
Timelog.timer("timer name/description")
?ScalaMeter ist eine nette Bibliothek, um Benchmarking in Scala durchzuführen
Unten ist ein einfaches Beispiel
Wenn Sie das obige Code-Snippet im Scala-Arbeitsblatt ausführen, erhalten Sie die Laufzeit in Millisekunden
quelle
Ich mag die Einfachheit von @ wricks Antwort, wollte aber auch:
Der Profiler verarbeitet Schleifen (aus Gründen der Konsistenz und Bequemlichkeit).
genaueres Timing (mit nanoTime)
Zeit pro Iteration (nicht die Gesamtzeit aller Iterationen)
Geben Sie einfach ns / iteration zurück - kein Tupel
Dies wird hier erreicht:
Für noch mehr Genauigkeit ermöglicht eine einfache Änderung eine JVM-Hotspot-Aufwärmschleife (nicht zeitgesteuert) zum Timing kleiner Snippets:
quelle
Der empfohlene Ansatz für das Benchmarking von Scala-Code ist sbt-jmh
Dieser Ansatz wird von vielen großen Scala-Projekten verfolgt, zum Beispiel von
Ein einfacher Wrapper-Timer basierend auf
System.nanoTime
ist keine zuverlässige Methode zum Benchmarking:Darüber hinaus können Überlegungen wie JIT-Aufwärmphase , Speicherbereinigung , systemweite Ereignisse usw. zu Unvorhersehbarkeit bei Messungen führen:
Basierend auf Travis Browns Antwort finden Sie hier ein Beispiel für die Einrichtung eines JMH-Benchmarks für Scala
project/plugins.sbt
build.sbt
Hinzufügen
src/main/scala/bench/VectorAppendVsListPreppendAndReverse.scala
Die Ergebnisse sind
Dies scheint darauf hinzudeuten, dass das Voranstellen an a
List
und das anschließende Umkehren am Ende um eine Größenordnung schneller ist als das Anhängen an aVector
.quelle
Während auf den Schultern von Riesen stehen ...
Eine solide Bibliothek von Drittanbietern wäre idealer, aber wenn Sie eine schnelle und auf Standardbibliotheken basierende Bibliothek benötigen, bietet die folgende Variante:
.
Erwähnenswert ist auch, dass Sie die
Duration.toCoarsest
Methode verwenden können, um in die größtmögliche Zeiteinheit zu konvertieren, obwohl ich nicht sicher bin, wie freundlich dies mit einem geringen Zeitunterschied zwischen den Läufen ist, zquelle
Sie können verwenden
System.currentTimeMillis
:Verwendung:
nanoTime wird es Ihnen zeigen
ns
, daher ist es schwer zu sehen. Daher schlage ich vor, dass Sie stattdessen currentTimeMillis verwenden können.quelle