[c#] Jak zmierzyc czas wykonania fragmentu kodu

0

Jak w c# można zmierzyć ile czasu wykonywał się dany fragment kodu ? Bo w języku C to się robiło tak:

clock_t start, stop;

//kod

stop=clock();
printf("\nCzas wykonywania tego fragmentu kodu: %lf\n", (double)(stop-start)/CLOCKS_PER_SEC);

A jak to zrobić w c# ?

0

Jesli chcesz sie bawic w profesjonalna optymalizacje to przyda Ci sie profiler np ants'a.
Jednak jesli chcesz sie bawic w kod bardziej inwazyjny to System.Diagnostic.Trace jest klasa dla Ciebie.
W przypadku, gdy to jest aplikacja asp.net to ona ma juz wbudowanego trace'a i wystarczy go wlaczyc :)

0

wasiu - ale czas_ownik pyta jak zmierzyć czas pracy kawałka kodu, a nie czarować :)

int start, stop;
start = Environment.TickCount & Int32.MaxValue;
//jakaś pętla czy inne operacje
stop = Environment.TickCount & Int32.MaxValue;
Console.WriteLine("Czas pracy: " + (stop - start));
0

@somekind: co to za amatorka? przecież Environment.TickCount ma rozdzielczość 500ms, co Ty chcesz tym mierzyć?
DateTime.Ticks (rozdzielczość 100ns) albo klasa Stopwatch z System.Diagnostics (rozdzielczość ~jak taktowanie procesora).

0

Czyli bardziej dokładny czas wykonania to:

DateTime startTime = DateTime.Now;

//np. jakies sortowanie

DateTime stopTime = DateTime.Now;
TimeSpan roznica = stopTime - startTime;
Console.WriteLine("Czas pracy:" + roznica.TotalMilliseconds);

??

0

tak, z dokładnością do ms. jak wykonać pomiar 10000 bardziej dokładny masz w moim wcześniejszym poście.

0
ŁF napisał(a)

@somekind: co to za amatorka? przecież Environment.TickCount ma rozdzielczość 500ms, co Ty chcesz tym mierzyć?

MSDN twierdzi, że 1ms...
Przykład zaś wzięty żywcem z "Core C# i .NET", jakoś specjalnie nie zastanawiałem się nad jego dokładnością - nie była mi potrzebna nigdy. Ale jasne, że DateTime.Ticks jest dokładniejsze.

  • kurczę, racja - http:*msdn.microsoft.com/en-us/library/system.environment.tickcount(VS.80).aspx - "The resolution of the TickCount property cannot be less than 500 milliseconds.", nieuważnie przeczytałem. ale Ty przeczytaj uważnie; jeśli gwarantowany interwał to 500ms, to na 500 razy mniejszy trafić to jak strzał w ciemno i z zawiązanymi oczami z łuku do pestki - Ł
0

Z drugiej strony nad mniejszymi przedzialami czasu nawet nie ma sensu sie zajmowac :) Z reguly jak sie cos optymalizuje to dlatego ze trwa to czas liczony w sekundach... wiec czas liczony w milisekundach w zupelnosci wystarcza :P

0

Witam,

Jeśli potrzeba dokładniejszej rozdzielczości to pozostaje jedynie wykorzystanie windowsowych API: QueryPerformanceFrequency() i QueryPerformanceCounter(). Poniżej kod asemblera - akurat wczoraj pisałem kod dla klienta w asm więc wklejam:

        ;; -------------------------------------------------- ;; Rozpoczecie pomiaru czasu trwania algorytmu sortujacego
            lea     ebx, liFrequency
            INVOKE  QueryPerformanceFrequency, ebx ;; Funkcja zwracająca częstotliwość zegara wysokiej rozdzielczości.

            lea     esi, liPerformanceCountA
            INVOKE  QueryPerformanceCounter, esi      ;; Funkcja zwracająca aktualną wartość licznika wysokiej rozdzielczości.

           ;; jakies operacje...

       ;; --------------------------------------------------- ;;  Pomiar czasu trwania algorytmu sortujacego (z wykorzystaniem FPU)
            lea     edi, liPerformanceCountB
            INVOKE  QueryPerformanceCounter, edi


            finit
            push    1000000                                                       ;; Pomiar w mikrosekundach (10^-6)
            fild    DWORD PTR [esp]

            fild    (LARGE_INTEGER PTR [ebx]).QuadPart
            fild    (LARGE_INTEGER PTR [esi]).QuadPart
            fild    (LARGE_INTEGER PTR [edi]).QuadPart
            fsub    st(0), st(1)
            fdiv    st(0), st(2)
            fmul    st(0), st(3)

            fistp   DWORD PTR [esp]
            pop     [dwTimeA]

Niestety, tylko taki kod mogę wstawić na chwilę obecną. Może pomoże.

0
coresoftlab napisał(a)

Jeśli potrzeba dokładniejszej rozdzielczości to pozostaje jedynie wykorzystanie windowsowych API: QueryPerformanceFrequency() i QueryPerformanceCounter().

Ślepy tak jak ja kilka postów wyżej? Stopwatch, 100ns (nanosekunda to mniej niż milisekunda :P).

0

Proszę zauważyć, że ja piszę o funkcjach pomiaru czasu zegara wysokiej rozdzielczości, z którego również korzysta sam system operacyjny (chociażby warstwa HAL). Nie ma dokładniejszego pomiaru jak poprzez funkcję QueryPerformanceCounter(). Poza tym mój przykład wyznacz czas w mikrosekundach (nie w mili jak sugerujesz), ale tylko dlatego, że była taka potrzeba (stąd dzielenie wyniku przez wartość 1000000). Tą funkcją można mierzyć czas w pikosekundach.

0

Z ciekawości zbadałem klasę System.Diagnostics.Stopwatch i okazało się, że ona również korzysta z WinAPI o której wspomniałem:

Inicjalizacja zegara wysokiej rozdzielczości:

  static Stopwatch()
    {
        if (!Microsoft.Win32.SafeNativeMethods.QueryPerformanceFrequency(out Frequency))
        {
            IsHighResolution = false;
            Frequency = 0x989680L;
            tickFrequency = 1.0;
        }
        else
        {
            IsHighResolution = true;
            tickFrequency = 10000000.0;
            tickFrequency /= (double) Frequency;
        }
    }

Oraz pobranie znacznika czasu:

    public static long GetTimestamp()
    {
        if (IsHighResolution)
        {
            long num = 0L;
            Microsoft.Win32.SafeNativeMethods.QueryPerformanceCounter(out num);
            return num;
        }
        return DateTime.UtcNow.Ticks;
    }

Pozostawiam bez komentarza :D

0
coresoftlab napisał(a)

Tą funkcją można mierzyć czas w pikosekundach.

Ale jak to jest możliwe?...

0
coresoftlab napisał(a)

Nie ma dokładniejszego pomiaru jak poprzez funkcję QueryPerformanceCounter().

nie wnikając w bebechy, które wkleiłeś, takich funkcji jest kilka. inna sprawa, że wszystkie wewnątrz odwołują się do PerformanceCountera.

coresoftlab napisał(a)

Poza tym mój przykład wyznacz czas w mikrosekundach (nie w mili jak sugerujesz), ale tylko dlatego, że była taka potrzeba (stąd dzielenie wyniku przez wartość 1000000).

racja, po raz kolejny byłem nieuważny, miałem napisać mikrosekunda... ale nie o to chodzi - Stopwatch ma identyczną rozdzielczość jak PerformanceTimer i do tego jest natywną klasą .NET, więc Twoje rozwiązanie nie wnosi nic nowego.

coresoftlab napisał(a)

Tą funkcją można mierzyć czas w pikosekundach.

tu już trochę odleciałeś, to że wynik sobie pomnożysz przez 1000 to nie znaczy, że będzie dokładniejszy.
żebyś mógł mierzyć w ps, to QueryPerformanceFrequency musiałoby zwrócić więcej niż 109. nie wiem co tam u siebie masz, i7 chłodzone ciekłym azotem czy co - u mnie rozdzielczość to okolice 3579545, czyli nawet nie 107, to wychodzą setki nanosekund. a u Ciebie?

0

Ale jak to jest możliwe?...

To nie jest możliwe, zwyczajna ułańska fantazja ;-). Oczywiście dokładność funkcji QueryPerformanceCounter() zależy od sprzętu i są to najczęściej mikro bądź nanosekundy. Dla mojego sprzętu funkcja QueryPerformanceFrequency() zwraca częstotliwość = 25000000, więc uzyskana rozdzielczość to 1/25000000 (jakoś tak)

// co daje 40ns. wciąż brakuje dwóch rzędów wielkości ;P - Ł

0

Stopwatch ma identyczną rozdzielczość jak PerformanceTimer i do tego jest natywną klasą .NET, więc Twoje rozwiązanie nie wnosi nic nowego.

Zgadza się, ale ja dowiedziałem się o tym dopiero, gdy zajrzałem w kod frameworka i klasę Stopwatch (o czym napisałem). Do tej pory używałem QueryPerformanceCounter() jako jedyny słuszny sposób pomiaru czasu wysokiej rozdzielczości. Podsumowując, najrozsądniejszym rozwiązaniem dla platformy .NET jest użycie klasy Stopwatch i temat zamknięty.

Już wiem dlaczego wcześniej nie używaliśmy w pracy klasy Stopwatch. Otóż oprogramowanie mobilne, które piszemy dla klienta obsługuje Framework 1.1, a Stopwatch jest obecny dopiero w .NET Compact Framework Supported in: 3.5

0
coresoftlab napisał(a)

Ale jak to jest możliwe?...

To nie jest możliwe, zwyczajna ułańska fantazja ;-).

A już Ci zazdrościłem terahercowego procesora ;)

0

System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();

        <KOD>

        watch.Stop();
        Console.WriteLine("czas wykonania w ms: " + watch.ElapsedMilliseconds);
        Console.WriteLine("czas w taktach procka: " + watch.ElapsedTicks);

1 użytkowników online, w tym zalogowanych: 0, gości: 1