Mam program C, który ma być uruchamiany równolegle na kilku procesorach. Muszę być w stanie zarejestrować czas wykonania (który może wynosić od 1 sekundy do kilku minut). Szukałem odpowiedzi, ale wszystkie wydają się sugerować użycie clock()
funkcji, która następnie polega na obliczeniu liczby zegarów, które program wziął podzielonej przez Clocks_per_second
wartość.
Nie jestem pewien, jak Clocks_per_second
obliczana jest wartość?
W Javie po prostu bierzę czas w milisekundach przed i po wykonaniu.
Czy w C jest coś podobnego? Spojrzałem, ale nie mogę znaleźć sposobu na uzyskanie czegoś lepszego niż drugie rozwiązanie.
Wiem też, że profiler byłby opcją, ale sam zamierzam zaimplementować licznik czasu.
Dzięki
c
benchmarking
zrozumiałem
źródło
źródło
Odpowiedzi:
CLOCKS_PER_SEC
jest stałą, która jest zadeklarowana w<time.h>
. Aby uzyskać czas procesora wykorzystywany przez zadanie w aplikacji C, użyj:Zauważ, że to zwraca czas jako typ zmiennoprzecinkowy. Może to być dokładniejsze niż sekunda (np. Mierzysz 4,52 sekundy). Precyzja zależy od architektury; na nowoczesnych systemach można łatwo uzyskać 10 ms lub mniej, ale na starszych komputerach z systemem Windows (z okresu Win98) było to bliżej 60 ms.
clock()
jest standardem C; działa „wszędzie”. Istnieją funkcje specyficzne dla systemu, na przykładgetrusage()
w systemach uniksowych.Java
System.currentTimeMillis()
nie mierzy tego samego. Jest to „zegar ścienny”: może pomóc ci zmierzyć, ile czasu zajęło wykonanie programu, ale nie mówi ci, ile czasu procesora zostało wykorzystane. W systemach wielozadaniowych (tj. Wszystkich) mogą się one znacznie różnić.źródło
clock()
zwraca czas w jakiejś wewnętrznej skali zwanej „zegarami” iCLOCKS_PER_SEC
jest liczbą zegarów na sekundę, więc podzielenie przezCLOCKS_PER_SEC
daje czas w sekundach. W powyższym kodzie wartość to a,double
dzięki czemu można ją dowolnie skalować.CLOCKS_PER_SEC
malong int
wartość1000000
, która daje czas w mikrosekundach, gdy nie jest podzielony; nie cykle zegara procesora. Dlatego nie musi uwzględniać częstotliwości dynamicznej, ponieważ zegar jest tutaj w mikrosekundach (może cykle zegara dla procesora 1 MHz?) Zrobiłem krótki program C drukujący tę wartość i było to 1000000 na moim laptopie i7-2640M, z częstotliwością dynamiczną pozwalającą od 800 MHz do 2,8 GHz, nawet przy użyciu Turbo Boost, aby osiągnąć nawet 3,5 GHz.Jeśli używasz powłoki Unix do uruchamiania, możesz użyć polecenia time.
robić
przyjęcie a.out jako pliku wykonywalnego da ci czas potrzebny na uruchomienie tego
źródło
perf stat ./a.out
aby uzyskać liczniki wydajności HW dla braków pamięci podręcznej i nieprzewidywalne oddziały oraz IPC.W zwykłej wanilii C:
źródło
Funkcjonalnie chcesz to:
Zauważ, że mierzy to w mikrosekundach, a nie tylko sekundach.
źródło
gettimeofday
jest przestarzały i nie jest zalecany do nowego kodu. Zamiast tego jego strona podręcznika POSIX zaleca clock_gettime , co pozwala zapytać oCLOCK_MONOTONIC
to, czy zmiany w zegarze systemowym nie mają na to wpływu, dlatego lepiej jest to interwał. (Zobacz odpowiedź JohnSll ). Na przykład we współczesnych systemach Linux gettimeofday jest zasadniczo opakowaniem dla clock_gettime, który zamienia nanosekundy na mikrosekundy.Większość prostych programów ma czas obliczeń w milisekundach. Przypuszczam, że przyda ci się to.
Jeśli chcesz obliczyć środowisko wykonawcze całego programu i korzystasz z systemu uniksowego, uruchom swój program za pomocą polecenia time, takiego jak ten
time ./a.out
źródło
Wiele odpowiedzi sugerowało,
clock()
a następnieCLOCKS_PER_SEC
pochodziło odtime.h
. To prawdopodobnie zły pomysł, ponieważ tak/bits/time.h
mówi mój plik:CLOCKS_PER_SEC
Można go więc zdefiniować jako 1000000, w zależności od opcji używanych do kompilacji, a zatem nie wydaje się to dobrym rozwiązaniem.źródło
CLOCK_PER_SEC==1000000
, ale jednocześnie używają precyzji 1 µs do implementacji clock (); nawiasem mówiąc, ma fajną właściwość, aby zmniejszyć problemy z udostępnianiem. Jeśli chcesz zmierzyć potencjalnie bardzo szybkich zdarzeń, powiedzmy poniżej 1 ms, to należy najpierw martwić o dokładności (lub rozdzielczości) funkcji zegara (), która jest koniecznie grubsze niż 1μs POSIX, ale jest również często znacznie grubsze; typowym rozwiązaniem jest wielokrotne uruchomienie testu; zadane pytanie jednak nie wymagało tego.clock()
, jeśli podzielisz tę wartość z sobą,CLOCK_PER_SEC
masz gwarancję, że uzyskasz czas w sekundach zajmowanych przez procesor. Pomiar rzeczywistej prędkości zegara jest obowiązkiemclock()
funkcji, a nie twojej.Odpowiedź Thomasa Pornina jako makra:
Użyj tego w ten sposób:
Wynik:
źródło
Musisz wziąć pod uwagę ten pomiar czasu potrzebnego do uruchomienia programu zależy w dużej mierze od obciążenia, jakie maszyna ma w danym momencie.
Wiedząc, że sposób uzyskania aktualnego czasu w C można osiągnąć na różne sposoby, łatwiejszym jest:
Mam nadzieję, że to pomoże.
Pozdrowienia!
źródło
(Brak tutaj wszystkich odpowiedzi, jeśli administrator systemu zmieni czas systemowy lub strefa czasowa różni się czasem zimowym i zimowym. Dlatego ...)
W przypadku korzystania z Linuksa:
clock_gettime(CLOCK_MONOTONIC_RAW, &time_variable);
Nie ma to wpływu, jeśli administrator systemu zmieni czas lub mieszkasz w kraju o czasie zimowym innym niż czas letni itp.man clock_gettime
stwierdza:źródło
(end.tv_nsec - begin.tv_nsec) / 1000000000.0
wynik w0
zawsze?double
dosłownych wyzwala int lublong
dodouble
konwersji przed podziałem. Oczywiście możesz po prostu trzymać się liczby całkowitej i wydrukowaćtv_sec
część, a następnie część ułamkową o wartości zerowej%ld.%09ld
, ale konwersja do liczby podwójnej jest łatwa, a 53 bity precyzji zwykle wystarczają na czasy testów.timespec_subtract
podobnej dotimeval_subtract
sugerowanej w instrukcji glibc : gnu.org/software/libc/manual/html_node/Elapsed-Time.html )ANSI C określa tylko funkcje czasu drugiej precyzji. Jednak jeśli pracujesz w środowisku POSIX, możesz użyć gettimeofday () która zapewnia rozdzielczość mikrosekund czasu od czasu epoki UNIX.
Na marginesie, nie zalecałbym używania clock (), ponieważ jest on źle zaimplementowany w wielu (jeśli nie wszystkich?) Systemach i nie jest dokładny, poza tym, że odnosi się to tylko do tego, ile czasu twój program spędził na procesorze i nie całkowity czas trwania programu, który według twojego pytania jest tym, co zakładam, że chciałbyś zmierzyć.
źródło
Każde rozwiązanie nie działa w moim systemie.
Mogę się użyć
źródło
time_t
wartościami jako podwójną. Ponieważtime_t
wartości są dokładne z dokładnością do jednej sekundy, ma on ograniczoną wartość w drukowaniu czasu potrzebnego do działania krótko działających programów, chociaż może być przydatny w przypadku programów działających przez długi czas.clock_t
sdifftime
wydaje się działać dla mnie z dokładnością do jednej setnej sekundy. To jest na Linuksie x86. Nie mogę też odjąćstop
istart
pracować.difftime()
clock() / CLOCKS_PER_SEC
, ponieważ oczekuje sekund.źródło
Odkryłem, że zwykły clock (), wszyscy tutaj polecają, z jakiegoś powodu bardzo różni się od uruchomienia do uruchomienia, nawet w przypadku kodu statycznego bez żadnych skutków ubocznych, takich jak rysowanie na ekranie lub czytanie plików. Może tak być, ponieważ procesor zmienia tryby zużycia energii, system operacyjny daje różne priorytety itp.
Tak więc jedynym sposobem, aby niezawodnie uzyskać ten sam wynik za każdym razem przy użyciu clock (), jest uruchomienie mierzonego kodu w pętli wiele razy (przez kilka minut), przy zachowaniu środków ostrożności, aby uniemożliwić kompilatorowi jego optymalizację: nowoczesne kompilatory mogą wstępnie obliczyć kod bez efektów ubocznych działających w pętli i wyjmij ją z pętli, np. używając losowego wejścia dla każdej iteracji.
Po zebraniu wystarczającej liczby próbek do tablicy, sortuje się tę tablicę i przyjmuje środkowy element, zwany medianą. Mediana jest lepsza niż średnia, ponieważ odrzuca ekstremalne odchylenia, jak na przykład antywirus zajmujący cały procesor lub system operacyjny przeprowadzający jakąś aktualizację.
Oto proste narzędzie do pomiaru wydajności wykonania kodu C / C ++, uśredniające wartości zbliżone do mediany: https://github.com/saniv/gauge
Nadal szukam bardziej niezawodnego i szybszego sposobu pomiaru kodu. Prawdopodobnie można by spróbować uruchomić kod w kontrolowanych warunkach na czystym metalu bez żadnego systemu operacyjnego, ale to da nierealistyczny wynik, ponieważ w rzeczywistości system operacyjny się angażuje.
x86 ma te liczniki wydajności sprzętu, w tym rzeczywistą liczbę wykonanych instrukcji, ale dostęp do nich jest trudny bez pomocy systemu operacyjnego, trudny do interpretacji i ma swoje własne problemy ( http://archive.gamedev.net/archive/reference/articles /article213.html ). Mimo to mogą być pomocne w badaniu charakteru szyjki butelki (dostęp do danych lub faktyczne obliczenia tych danych).
źródło
performance
) lub kilkadziesiąt milisekund. en.wikipedia.org/wiki/Dynamic_frequency_scaling . I tak, mediana wyników jest zwykle dobrym wyborem; high-end zwykle ma pewne kolce od interferencji.main
który pobiera argument i zwraca wynik, i nie używaj optymalizacji czasu łącza. Następnie kompilator nie może wstawić go do programu wywołującego. Działa tylko, jeśli funkcja zawiera już jakąś pętlę, w przeciwnym razie narzut wywołania / ret jest zbyt wysoki.Niektórym może się przydać inny rodzaj danych wejściowych: dano mi tę metodę pomiaru czasu w ramach uniwersyteckiego kursu programowania GPGPU z NVidia CUDA ( opis kursu ). Łączy metody widoczne we wcześniejszych postach i po prostu publikuję, ponieważ wymagania nadają mu wiarygodność:
Przypuszczam, że możesz pomnożyć przez np.,
1.0 / 1000.0
Aby uzyskać jednostkę miary, która odpowiada twoim potrzebom.źródło
clock_gettime
Zamiast tego zaleca się stronęCLOCK_MONOTONIC
podręcznika POSIX , która pozwala zapytać o to, czy zmiany w zegarze systemowym nie mają na to wpływu, dlatego jest lepszy jako interwał. Na przykład w nowoczesnych systemach Linuxgettimeofday
jest zasadniczo opakowaniem,clock_gettime
które zamienia nanosekundy na mikrosekundy. (Zobacz odpowiedź JohnSll).timeval_subtract
.Porównanie czasu wykonania sortowania bąbelkowego i sortowania selekcyjnego Mam program, który porównuje czas wykonania sortowania bąbelkowego i sortowania selekcyjnego. Aby ustalić czas wykonania bloku kodu, oblicz czas przed i za blokiem według
Przykładowy kod:
źródło