2009-10-25 15 views
14

Poszukuję sposobu na przetestowanie wywołań metod w języku C#.Wywołania metody analizy porównawczej w języku C#

Zakodowałem strukturę danych dla zadań uniwersyteckich i właśnie wymyśliłem sposób na zoptymalizowanie, ale w taki sposób, aby dodać trochę narzut we wszystkich sytuacjach, jednocześnie zamieniając zaproszenie O (n) na O (1) w niektórych.

Teraz chcę uruchomić obie wersje z danymi testowymi, aby sprawdzić, czy warto wdrożyć optymalizację. Wiem, że w Ruby można zawinąć kod w bloku Benchmark i zlecić mu czas potrzebny do wykonania bloku w konsoli - czy coś takiego jest dostępne dla C#?

Odpowiedz

3

Można użyć wbudowanego Stopwatch class do "Zapewnienia zestawu metod i właściwości, które można wykorzystać do dokładnego pomiaru upływu czasu." jeśli szukasz ręcznego sposobu na zrobienie tego. Nie jestem pewien, ale zautomatyzowany.

+0

Dzięki, tego właśnie potrzebowałem. –

+1

Wysłuchanie słów "właśnie tego, czego potrzebowałem" przypomina mi Mario. – contactmatt

+0

stoper nie jest najlepszym sposobem na porównanie. Korzysta z rejestrów procesora, więc twój własny kod nie może z niego korzystać. Możesz porównywać kod ze Stoperem i bez niego, a różnica jest do 3 razy większa niż – Evgeniy

2

Brzmi jak chcesz profiler. Zdecydowanie polecam samemu, ponieważ jest to najlepszy darmowy, jaki próbowałem. Zaletą tej metody w porównaniu z prostym stoperem jest to, że zapewnia on również podział wydajności w stosunku do niektórych metod/bloków.

+2

+1 dla miłego darmowego profilera! – TrueWill

5

Wygrałem większość z następujących metod Jon Skeet dla benchmarkingu:

private static void Benchmark(Action act, int interval) 
{ 
    GC.Collect(); 
    Stopwatch sw = Stopwatch.StartNew(); 
    for (int i = 0; i < interval; i++) 
    { 
     act.Invoke(); 
    } 
    sw.Stop(); 
    Console.WriteLine(sw.ElapsedMilliseconds); 
} 
+0

Dodanie lokalnego GC.Collect() może spowodować problemy z globalną alokacją pamięci, które mają wpływ na wydajność, jednak powoduje to, że lokalne pomiary są bardziej dokładne. –

0

Profilers dają najlepsze standardy ponieważ zdiagnozować cały swój kod, jednak oni go spowolnić dużo. Profiliści służą do znajdowania wąskich gardeł.

Aby zoptymalizować algorytm, gdy wiesz, gdzie występują wąskie gardła, użyj słownika nazwa -> stoper, aby śledzić sekcje krytyczne pod względem wydajności podczas wykonywania.

22

Stolen (i zmodyfikowana) z odpowiedzią Jurij za:

private static void Benchmark(Action act, int iterations) 
{ 
    GC.Collect(); 
    act.Invoke(); // run once outside of loop to avoid initialization costs 
    Stopwatch sw = Stopwatch.StartNew(); 
    for (int i = 0; i < iterations; i++) 
    { 
     act.Invoke(); 
    } 
    sw.Stop(); 
    Console.WriteLine((sw.ElapsedMilliseconds/iterations).ToString()); 
} 

Często dana metoda ma zainicjować pewne rzeczy i nie zawsze chcą to te koszty inicjalizacji ogólny punkt odniesienia. Ponadto należy podzielić całkowity czas wykonania przez liczbę iteracji, aby oszacowanie było mniej więcej niezależne od liczby iteracji.

+0

Fajnie, szukałem tylko szybkiej metody testowania C#. –

+7

I znalazłeś odpowiedź na podstawie jednej z twoich odpowiedzi? StackOverflow był już wystarczająco długi, że zdarzyło mi się to kilka razy: za mną odpowiada na pytanie, które zadaje mi obecnie. – MusiGenesis

+0

Przykład: 'Benchmark (() => {/ * twój kod * /}, 100);' – 2Toad

6

Oto kilka rzeczy, które znalazłem dzięki próbom i błędom.

  1. Odrzuć pierwszą partię (tysięcy) iteracji. Najprawdopodobniej zostaną dotknięci przez JITter.
  2. Przeprowadzenie testu porównawczego na oddzielnym obiekcie Thread może dać lepsze i stabilniejsze wyniki. Nie wiem dlaczego.
  3. Z jakiegoś powodu widziałem ludzi używających Thread.Sleep przed wykonaniem testu porównawczego. To tylko pogorszy sprawę. Nie wiem dlaczego. Prawdopodobnie ze względu na JITter.
  4. Nigdy nie uruchamiaj testu porównawczego z włączonym debugowaniem. Kod najprawdopodobniej będzie działał wolniej o rząd wielkości.
  5. Skompiluj aplikację z włączonymi wszystkimi optymalizacjami. Niektórym kodom może drastycznie wpłynąć optymalizacja, podczas gdy inny kod nie będzie, więc kompilacja bez optymalizacji wpłynie na wiarygodność twojego testu porównawczego.
  6. Podczas kompilacji z włączonymi optymalizacjami czasami trzeba w jakiś sposób ocenić wynik testu porównawczego (np. Wydrukować wartość itp.). W przeciwnym razie kompilator może "wymyślić" niektóre obliczenia są bezużyteczne i po prostu ich nie wykona.
  7. Wywołanie delegatów może mieć zauważalny narzut podczas wykonywania niektórych testów porównawczych. Lepiej jest umieścić więcej niż jedną iterację wewnątrz delegata, tak aby narzut miał niewielki wpływ na wynik benchmarku.
  8. Profiler może mieć własny narzut. Są dobrzy w informowaniu, które części kodu są wąskimi gardłami, ale nie są dobre w porównywaniu dwóch rzeczy w sposób niezawodny.
  9. Ogólnie rzecz biorąc, wymyślne rozwiązania porównawcze mogą mieć zauważalny narzut. Na przykład, jeśli chcesz porównać wiele obiektów za pomocą jednego interfejsu, może być kuszące zawijanie każdego obiektu w klasie. Należy jednak pamiętać, że konstruktor klasy ma również narzut, który należy wziąć pod uwagę. Lepiej trzymać wszystko tak proste i bezpośrednie, jak to tylko możliwe.
Powiązane problemy