$ time foo
real 0m0.003s
user 0m0.000s
sys 0m0.004s
$
Co oznaczają „rzeczywisty”, „użytkownik” i „sys” w wyniku czasu?
Który z nich ma znaczenie podczas testowania mojej aplikacji?
unix
time
benchmarking
rayryeng
źródło
źródło
time
, zrób to, co zajmie co najmniej sekundę.time
jest to słowo kluczowe bash. Więc wpisywanieman time
się nie daje stronie man bashtime
, a to daje na stronie man/usr/bin/time
. To mnie potknęło.Odpowiedzi:
Statystyki czasu rzeczywistego, użytkownika i Sys
Jedna z tych rzeczy nie jest taka jak druga. Rzeczywisty odnosi się do rzeczywistego czasu, który upłynął; Użytkownik i Sys odnoszą się do czasu procesora wykorzystywanego tylko przez proces.
Rzeczywisty jest czas naścienny - czas od początku do końca połączenia. Jest to cały czas, który upłynął, w tym przedziały czasowe używane przez inne procesy oraz czas, jaki proces spędza zablokowany (na przykład, jeśli czeka na zakończenie operacji we / wy).
Użytkownik to ilość czasu procesora spędzona na kodzie trybu użytkownika (poza jądrem) w procesie. Jest to tylko rzeczywisty czas pracy procesora wykorzystywany do wykonania procesu. Inne procesy i czas zablokowany przez proces nie liczą się do tej liczby.
Sys to ilość czasu procesora spędzonego w jądrze w procesie. Oznacza to wykonywanie czasu procesora spędzonego na wywołaniach systemowych w jądrze, w przeciwieństwie do kodu biblioteki, który wciąż działa w przestrzeni użytkownika. Podobnie jak „użytkownik”, proces ten zajmuje tylko czas procesora. Poniżej znajduje się krótki opis trybu jądra (znanego również jako tryb „superwizora”) i mechanizmu wywołania systemowego.
User+Sys
pokaże, ile rzeczywistego czasu procesora wykorzystał proces. Zauważ, że dotyczy to wszystkich procesorów, więc jeśli proces ma wiele wątków (a ten proces działa na komputerze z więcej niż jednym procesorem), może potencjalnie przekroczyć zgłaszany czas zegara ściennegoReal
(co zwykle ma miejsce). Zauważ, że w danych wyjściowych liczby te obejmująUser
iSys
czas wszystkich procesów potomnych (i ich potomków), a także kiedy mogły zostać zebrane, np. Przezwait(2)
lubwaitpid(2)
, chociaż wywołania systemowe leżące u podstaw zwracają statystyki dla procesu i jego potomków osobno.Pochodzenie statystyk zgłoszonych przez
time (1)
Statystyki zgłaszane przez
time
są gromadzone z różnych wywołań systemowych. „Użytkownik” i „Sys” pochodzą odwait (2)
( POSIX ) lubtimes (2)
( POSIX ), w zależności od konkretnego systemu. „Rzeczywisty” jest obliczany na podstawie czasu rozpoczęcia i zakończenia zebranego zgettimeofday (2)
połączenia. W zależności od wersji systemu mogą być gromadzone różne inne statystyki, takie jak liczba przełączników kontekstutime
.Na maszynie wieloprocesorowej proces wielowątkowy lub proces rozwidlania dzieci może mieć mniejszy czas niż całkowity czas procesora - ponieważ różne wątki lub procesy mogą przebiegać równolegle. Ponadto raportowane statystyki czasowe pochodzą z różnych źródeł, więc czasy zarejestrowane dla bardzo krótkotrwałych zadań mogą być obarczone błędami zaokrąglenia, jak pokazuje przykład z oryginalnego plakatu.
Krótki podkład w trybie jądra vs. użytkownika
W systemie Unix lub dowolnym systemie operacyjnym z chronioną pamięcią tryb „Kernel” lub „Supervisor” odnosi się do trybu uprzywilejowanego , w którym może działać procesor. Niektóre działania uprzywilejowane, które mogą mieć wpływ na bezpieczeństwo lub stabilność, można wykonać tylko wtedy, gdy procesor działa w trybie ten tryb; te działania nie są dostępne dla kodu aplikacji. Przykładem takiej akcji może być manipulacja MMU w celu uzyskania dostępu do przestrzeni adresowej innego procesu. Normalnie kod trybu użytkownika nie może tego zrobić (z uzasadnionego powodu), chociaż może zażądać pamięci współdzielonej z jądra, co mogłobybyć czytane lub pisane przez więcej niż jeden proces. W takim przypadku pamięć współdzielona jest jawnie wymagana od jądra za pośrednictwem bezpiecznego mechanizmu i oba procesy muszą jawnie się z nim połączyć, aby z niego skorzystać.
Tryb uprzywilejowany jest zwykle nazywany trybem „jądra”, ponieważ jądro jest wykonywane przez procesor działający w tym trybie. Aby przejść do trybu jądra, musisz wydać konkretną instrukcję (często nazywaną pułapką ), która przełącza procesor do pracy w trybie jądra i uruchamia kod z określonej lokalizacji przechowywanej w tabeli skoków. Ze względów bezpieczeństwa nie można przejść do trybu jądra i wykonać dowolny kod - pułapkami zarządza się za pomocą tabeli adresów, których nie można zapisać, chyba że procesor pracuje w trybie nadzorcy. Trapujesz z wyraźnym numerem pułapki, a adres znajduje się w tabeli skoków; jądro ma skończoną liczbę kontrolowanych punktów wejścia.
Wywołania „systemowe” w bibliotece C (szczególnie te opisane w Rozdziale 2 stron podręcznika) mają komponent trybu użytkownika, który tak naprawdę wywołujesz z programu C. Za kulisami mogą wydawać jedno lub więcej wywołań systemowych do jądra w celu wykonania określonych usług, takich jak We / Wy, ale nadal mają kod działający w trybie użytkownika. Jest również całkiem możliwe bezpośrednie uruchomienie pułapki na tryb jądra z dowolnego kodu przestrzeni użytkownika, jeśli zajdzie taka potrzeba, chociaż może być konieczne napisanie fragmentu języka asemblera, aby poprawnie skonfigurować rejestry dla wywołania.
Więcej informacji o „sys”
Są rzeczy, których twój kod nie może zrobić z trybu użytkownika - takie jak przydzielanie pamięci lub uzyskiwanie dostępu do sprzętu (HDD, sieć itp.). Są pod nadzorem jądra i tylko on może to zrobić. Niektóre operacje, takie jak
malloc
lubfread
/,fwrite
będą wywoływać te funkcje jądra, a następnie będą liczone jako czas „sys”. Niestety nie jest to takie proste, że „każde połączenie do malloc będzie liczone w czasie„ sys ”. Wywołanie tomalloc
wykona własne przetwarzanie (wciąż liczone w czasie „użytkownika”), a następnie gdzieś po drodze może wywołać funkcję w jądrze (liczone w czasie „sys”). Po powrocie z wywołania jądra będzie więcej czasu w „user”, a potemmalloc
wróci do twojego kodu. Co do tego, kiedy nastąpi zmiana i ile jest wydane w trybie jądra ... nie można powiedzieć. To zależy od implementacji biblioteki. Również inne pozornie niewinne funkcje mogą również korzystaćmalloc
w tle i tym podobne, które znów będą miały trochę czasu w „sys”.źródło
Aby rozwinąć przyjętą odpowiedź , chciałem tylko podać inny powód, dla którego
real
≠user
+sys
.Należy pamiętać, że
real
reprezentuje rzeczywisty upływ czasu, podczasuser
isys
wartości reprezentują czas realizacji CPU. W rezultacie w systemie wielordzeniowym czasuser
i / lubsys
czas (a także ich suma) mogą faktycznie przekraczać czas rzeczywisty. Na przykład w aplikacji Java, którą uruchamiam dla klasy, otrzymuję ten zestaw wartości:źródło
real
przekroczeniuuser
isys
sumie? Obciążenie systemu operacyjnego, takie jak przełączanie kontekstu wątku może być?• rzeczywisty : Rzeczywisty czas spędzony na uruchomieniu procesu od początku do końca, tak jakby był mierzony przez człowieka ze stoperem
• użytkownik : Łączny czas spędzony przez wszystkie procesory podczas obliczeń
• sys : Łączny czas spędzony przez wszystkie procesory podczas zadań związanych z systemem, takich jak przydzielanie pamięci.
źródło
sys
czas procesora spędzany na wywołaniach systemowych (i obsłudze błędów stron?)real
jest często określany jako „zegar ścienny”.Minimalne uruchamialne przykłady POSIX C.
Żeby było bardziej konkretnie, chcę zilustrować kilka ekstremalnych przypadków
time
z minimalnymi programami testowymi C.Wszystkie programy można kompilować i uruchamiać za pomocą:
i zostały przetestowane w Ubuntu 18.10, GCC 8.2.0, glibc 2.28, jądro Linux 4.18, laptop ThinkPad P51, procesor Intel Core i7-7820HQ (4 rdzenie / 8 wątków), 2x RAM Samsung M471A2K43BB1-CRC (2x 16GiB).
sen
Non-zajęty sen nie liczyć na jeden
user
lubsys
tylkoreal
.Na przykład program, który śpi przez sekundę:
GitHub w górę .
wyprowadza coś takiego:
To samo dotyczy programów zablokowanych przy IO, które stają się dostępne.
Na przykład następujący program czeka na wprowadzenie znaku przez użytkownika i naciśnięcie enter:
GitHub w górę .
A jeśli zaczekasz około jednej sekundy, wyświetli się tak jak w przykładzie uśpienia, na przykład:
Z tego powodu
time
może pomóc ci rozróżnić programy związane z procesorem i operacjami we / wy : Co oznaczają pojęcia „związane z procesorem” i „związane z operacjami we / wy”?Wiele wątków
Poniższy przykład wykonuje
niters
iteracje bezużytecznych prac związanych wyłącznie z procesorem wnthreads
wątkach:GitHub w górę + kod fabuły .
Następnie wykreślamy ścianę, użytkownika i system jako funkcję liczby wątków dla stałej iteracji 10 ^ 10 na moim 8 procesorze hyperthread:
Wykres danych .
Z wykresu widzimy, że:
w przypadku aplikacji jednordzeniowych intensywnie wykorzystujących procesor, ściana i użytkownik są mniej więcej takie same
dla 2 rdzeni użytkownik ma około 2x ściany, co oznacza, że czas użytkownika jest liczony we wszystkich wątkach.
użytkownik w zasadzie podwoił się, a ściana pozostała bez zmian.
kontynuuje to do 8 wątków, co odpowiada mojej liczbie hiperwątków na moim komputerze.
Po 8 ściana zaczyna się również zwiększać, ponieważ nie mamy żadnych dodatkowych procesorów, aby włożyć więcej pracy w danym czasie!
Stosunki plateau w tym punkcie.
Zauważ, że ten wykres jest tylko tak przejrzysty i prosty, ponieważ praca jest ściśle związana z procesorem: gdyby była związana z pamięcią, osiągnęlibyśmy spadek wydajności znacznie wcześniej z mniejszą liczbą rdzeni, ponieważ dostęp do pamięci byłby wąskim gardłem, jak pokazano w What oznaczają terminy „związany z procesorem” i „związany z I / O”?
Sys ciężka praca z
sendfile
Najcięższym obciążeniem systemowym, jakie mogłem wymyślić, było użycie narzędzia
sendfile
, które wykonuje operację kopiowania plików w przestrzeni jądra: Kopiuj plik w rozsądny, bezpieczny i wydajny sposóbWięc wyobrażałem sobie, że to jądro
memcpy
będzie wymagało dużej mocy obliczeniowej procesora.Najpierw inicjuję duży losowy plik 10GiB za pomocą:
Następnie uruchom kod:
GitHub w górę .
co daje w zasadzie głównie czas systemowy zgodnie z oczekiwaniami:
Byłem również ciekawy, czy
time
rozróżniam systemy różnych procesów, więc spróbowałem:Rezultatem było:
Czas sys jest mniej więcej taki sam dla obu jak dla pojedynczego procesu, ale czas ściany jest dłuższy, ponieważ procesy rywalizują o dostęp do odczytu dysku.
Wygląda więc na to, że faktycznie bierze pod uwagę proces, który rozpoczął dane działanie jądra.
Kod źródłowy Bash
Kiedy robisz to tylko
time <cmd>
na Ubuntu, użyj słowa kluczowego Bash, jak widać z:które wyjścia:
Dlatego grepujemy źródło w kodzie źródłowym Bash 4.19 dla ciągu wyjściowego:
co prowadzi nas do funkcji execute_cmd.c
time_command
, która wykorzystuje:gettimeofday()
igetrusage()
jeśli oba są dostępnetimes()
Inaczejwszystkie to wywołania systemowe Linux i funkcje POSIX .
Kod źródłowy GNU Coreutils
Jeśli nazwiemy to:
następnie wykorzystuje implementację GNU Coreutils.
Ten jest nieco bardziej złożony, ale wydaje się, że odpowiednim źródłem jest resuse.c i robi:
wait3
wywołanie BSD inne niż POSIX, jeśli jest dostępnetimes
igettimeofday
inaczejźródło
Real pokazuje całkowity czas realizacji procesu; podczas gdy użytkownik pokazuje czas wykonania instrukcji zdefiniowanych przez użytkownika, a Sys czas wykonywania wywołań systemowych!
Czas rzeczywisty obejmuje również czas oczekiwania (czas oczekiwania na we / wy itp.)
źródło