Jaki jest standardowy sposób profilowania wywołań metod Scala?
To, czego potrzebuję, to haczyki wokół metody, za pomocą których mogę uruchamiać i zatrzymywać Timery.
W Javie używam programowania aspektowego, aspektuJ, do definiowania metod, które mają być profilowane i wstrzykiwania kodu bajtowego, aby osiągnąć to samo.
Czy istnieje bardziej naturalny sposób w Scali, w którym mogę zdefiniować kilka funkcji, które mają być wywoływane przed i po funkcji bez utraty statycznego wpisywania w procesie?
Odpowiedzi:
Czy chcesz to zrobić bez zmiany kodu, dla którego chcesz mierzyć czasy? Jeśli nie masz nic przeciwko zmianie kodu, możesz zrobić coś takiego:
źródło
t1
w ramachfinally
klauzulidef time[R](label: String)(block: => R): R = {
println
Oprócz odpowiedzi Jespera możesz automatycznie zawijać wywołania metod w REPL:
Teraz - zawińmy w to wszystko
OK - musimy być w trybie zasilania
Zawiń
Nie mam pojęcia, dlaczego te wydrukowane rzeczy wyszły 5 razy
Aktualizacja od 2.12.2:
źródło
:wrap
funkcja została usunięta z REPL: - \Istnieją trzy biblioteki testów porównawczych dla Scala , z których możesz skorzystać.
Ponieważ adresy URL w połączonej witrynie prawdopodobnie się zmienią, wklejam poniżej odpowiednią zawartość.
SPerformance - platforma do testowania wydajności, której celem jest automagiczne porównywanie testów wydajnościowych i praca w ramach narzędzia Simple Build Tool.
scala-benchmarking-template - projekt szablonu SBT do tworzenia (mikro) benchmarków Scala w oparciu o Caliper.
Metryki - przechwytywanie wskaźników JVM i poziomu aplikacji. Więc wiesz, co się dzieje
źródło
Tego używam:
źródło
testing.Benchmark
może się przydać.źródło
Wziąłem rozwiązanie od Jespera i dodałem do niego trochę agregacji podczas wielokrotnych uruchomień tego samego kodu
Załóżmy, że chcemy czasie dwie funkcje
counter_new
icounter_old
dodaje jest użycie:Mam nadzieję, że jest to pomocne
źródło
Używam techniki, którą łatwo poruszać się po blokach kodu. Sedno polega na tym, że ta sama dokładna linia zaczyna i kończy licznik czasu - więc jest to naprawdę proste kopiowanie i wklejanie. Inną fajną rzeczą jest to, że możesz zdefiniować, co oznacza dla ciebie timing jako ciąg, wszystko w tej samej linii.
Przykładowe użycie:
Kod:
Plusy:
Cons:
źródło
Timelog.timer("timer name/description")
?ScalaMeter to fajna biblioteka do wykonywania testów porównawczych w Scali
Poniżej znajduje się prosty przykład
Jeśli wykonasz powyższy fragment kodu w arkuszu Scala, uzyskasz czas działania w milisekundach
źródło
Podoba mi się prostota odpowiedzi @ wrick, ale chciałem też:
profiler obsługuje zapętlenie (dla spójności i wygody)
dokładniejszy czas (przy użyciu nanoTime)
czas na iterację (nie całkowity czas wszystkich iteracji)
po prostu zwróć ns / iterację - nie krotkę
Osiąga się to tutaj:
Aby uzyskać jeszcze większą dokładność, prosta modyfikacja umożliwia pętlę rozgrzewki JVM Hotspot (nieokreśloną w czasie) do synchronizowania małych fragmentów:
źródło
Zalecane podejście do testów porównawczych kodu Scala to sbt-jmh
To podejście jest stosowane w wielu dużych projektach Scala, na przykład
Timer prosty wrapper na podstawie
System.nanoTime
to nie jest wiarygodną metodą z benchmarkingu:Ponadto kwestie takie jak rozgrzewka JIT , zbieranie śmieci, zdarzenia w całym systemie itp. Mogą wprowadzać nieprzewidywalność do pomiarów:
W oparciu o odpowiedź Travisa Browna, oto przykład konfiguracji JMH dla Scali
project/plugins.sbt
build.sbt
Dodać do
src/main/scala/bench/VectorAppendVsListPreppendAndReverse.scala
Wyniki są
co wydaje się wskazywać na poprzedzanie a,
List
a następnie odwrócenie go na końcu, jest o rząd wielkości szybsze niż ciągłe dołączanie do aVector
.źródło
Stojąc na ramionach gigantów ...
Solidna biblioteka innej firmy byłaby bardziej idealna, ale jeśli potrzebujesz czegoś szybkiego i opartego na bibliotece standardowej, następujący wariant zapewnia:
.
Warto również zauważyć, że możesz użyć
Duration.toCoarsest
metody konwersji na największą możliwą jednostkę czasu, chociaż nie jestem pewien, jak przyjazna jest to przy niewielkiej różnicy czasu między przebiegami, np.źródło
Możesz użyć
System.currentTimeMillis
:Stosowanie:
nanoTime pokaże
ns
, więc trudno będzie to zobaczyć. Sugeruję więc, aby zamiast tego użyć currentTimeMillis.źródło