Czy uniwersalna alternatywa porównawcza dla „czasu”? [Zamknięte]


10

Dla porównania prowadzone razy skryptów między różnymi muszli, niektóre odpowiedzi SE sugerować przy użyciu bash„s wbudowane time polecenia, tak jak poniżej:

time bash -c 'foo.sh'
time dash -c 'foo.sh'

... itd. dla każdej powłoki do przetestowania. Takie odniesienia nie eliminuje czas potrzebny dla każdej muszli załadować i zainicjować sama . Załóżmy na przykład, że oba powyższe polecenia zostały zapisane na wolnym urządzeniu z prędkością odczytu wczesnej dyskietki (124KB / s) dash( plik wykonywalny ~ 150K ) ładowałby się około 7 razy szybciej niż bash( ~ 1M ) powłoka czas ładowania będzie pochylać się timenumery - czasów pre-loading tych pocisków nie ma znaczenia do pomiaru czasów pracy foo.shpod każdym skorupy po pociski zostały załadowane.

Jakie jest najlepsze przenośne i ogólne zastosowanie do uruchamiania taktowania skryptów, które można uruchomić z poziomu każdej powłoki? Tak więc powyższy kod wyglądałby mniej więcej tak:

bash -c 'general_timer_util foo.sh'
dash -c 'general_timer_util foo.sh'

Uwaga: brak wbudowanych time poleceń powłoki , ponieważ żadne nie są przenośne ani ogólne.


Jeszcze lepiej, jeśli util jest również w stanie przeprowadzić analizę porównawczą czasu potrzebnego na wewnętrzne polecenia i potoki powłoki, bez konieczności uprzedniego zawijania ich przez skrypt w skrypcie. Sztuczna składnia taka jak ta pomogłaby:

general_timer_util "while read x ; do echo x ; done < foo"

Niektóre powłoki timemogą sobie z tym poradzić. Na przykład bash -c "time while false ; do : ; done"działa. Aby zobaczyć, co działa (i nie działa) w twoim systemie, spróbuj:

tail +2 /etc/shells | 
while read s ; do 
    echo $s ; $s -c "time while false ; do : ; done" ; echo ----
done

6
Po prostu użyj /usr/bin/time?
Kusalananda

1
Nie rozumiem, w jaki sposób każde niezbudowane może „wyeliminować czas potrzebny na załadowanie i zainicjowanie się każdej powłoki” oraz wykonać samodzielny skrypt, będąc jednocześnie „przenośnym i ogólnym”.
Michael Homer

1
To nie jest odpowiedź na pytanie, to monit o wyjaśnienie, czego chcesz.
Michael Homer

1
Podjąłem moją najlepszą próbę, ale myślę, że pytanie jest wciąż nieokreślone, co dokładnie próbuje osiągnąć.
Michael Homer

2
Co rozumiesz przez „przenośny lub ogólny”? Wbudowane powłoki są tak przenośne (działają na tylu systemach) i bardziej ogólne (działają w większej liczbie przypadków, ponieważ mogą zaprogramować coś innego niż wykonanie pliku) jak polecenie zewnętrzne. Jaki problem próbujesz rozwiązać?
Gilles „SO- przestań być zły”

Odpowiedzi:


10

Należy zauważyć, że timejest to określone przez POSIX , a AFAICT jedyna opcja, o której POSIX wspomina ( -p) jest poprawnie obsługiwana przez różne powłoki:

$ bash -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ dash -c 'time -p echo'

real 0.01
user 0.00
sys 0.00
$ busybox sh -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ ksh -c 'time -p echo'       

real 0.00
user 0.00
sys 0.00

1
Problem polega na tym, że aby móc porównać czasy, wynik musi być zsynchronizowany z tą samą implementacją time. Jest to porównywalne z pozwalaniem sprinterom mierzyć swój czas na 100 m indywidualnie, zamiast robić to z jednym zegarem w tym samym czasie. To oczywiście podstępne, ale nadal ...
Kusalananda

@Kusalananda Myślałem, że problem polega na tym, że myśl OP timenie jest przenośna; wydaje się być przenośny. (Zgadzam się jednak z twoją
opinią

@muru, w moim systemie dash -c 'time -p while false ; do : ; done'zwraca „czas: nie można uruchomić, dopóki: Nie zakończono takiego pliku lub katalogu <cr> Komenda z błędami o niezerowym statusie 127” .
agc

1
@agc POSIX mówi również: „Termin„ narzędzie ”jest używany zamiast polecenia, aby podkreślić fakt, że poleceń złożonych powłoki, potoków, specjalnych wbudowanych funkcji itd. nie można używać bezpośrednio. Jednak narzędzie to zawiera aplikacje użytkownika i skrypty powłoki, a nie tylko standardowe narzędzia. ” (patrz sekcja RATIONALE)
mur


7

Używam polecenia GNU date , które obsługuje zegar wysokiej rozdzielczości:

START=$(date +%s.%N)
# do something #######################

"$@" &> /dev/null

#######################################
END=$(date +%s.%N)
DIFF=$( echo "scale=3; (${END} - ${START})*1000/1" | bc )
echo "${DIFF}"

A potem wywołuję skrypt w następujący sposób:

/usr/local/bin/timing dig +short unix.stackexchange.com
141.835

Jednostka wyjściowa jest w milisekundach.


1
Zakładając, że czas (epoka) nie zmienia się pomiędzy. Nie mogę wymyślić przypadku w praktyce, w którym spowodowałby problem, ale nadal warto o nim wspomnieć.
phk

1
Należy dodać, że wymaga to w dateszczególności GNU .
Kusalananda

@ phk proszę wyjaśnić?
Rabin

1
@Rabin Powiedzmy, że problemy Twojego klienta NTP oraz aktualizacja i zmiana zegara pomiędzy ustawieniem STARTi ENDustawieniem, to oczywiście wpłynie na twój wynik. Nie mam pojęcia, jak precyzyjnie go potrzebujesz i czy ma to znaczenie w twoim przypadku, ale tak jak powiedziałem, należy pamiętać. (Zabawna historia: znam oprogramowanie, w którym dokładnie doprowadziło do nieoczekiwanie negatywnych wyników - było używane do obliczeń przepustowości - które następnie
popsuło

1
Ponadto, czy niektórzy klienci NTP nie zwalniają i nie przyspieszają zegara, zamiast robić „skoków” w czasie systemowym? Jeśli masz takiego klienta NTP, a wczoraj wieczorem ustaliłeś pewne czasy, prawdopodobnie są one wypaczone przez klienta NTP „oczekującego” drugiego kroku. (Czy w takim przypadku zegar systemowy po prostu biegnie do 61?)
Jörg W Mittag

6

timeNarzędzie jest zwykle wbudowany w skorupkach, jak zauważyłeś, co czyni go bezużytecznym jako „neutralny” timer.

Jednak narzędzie jest zwykle dostępne również jako narzędzie zewnętrzne /usr/bin/time, które może być również wykorzystane do przeprowadzenia proponowanych eksperymentów czasowych.

$ bash -c '/usr/bin/time foo.sh'

Jak to „eliminuje czas potrzebny na załadowanie się i zainicjowanie każdej powłoki”?
Michael Homer

1
Jeśli foo.shjest wykonywalny i ma shebang, to zawsze uruchamia go z tą samą powłoką i nie liczy czasu uruchamiania tej powłoki, więc nie tego chce OP. Jeśli foo.shbrakuje jednego z nich, to w ogóle nie działa.
Kevin

@Kevin Very true. timeWydaje mi się, że wziąłem pod uwagę tylko „brak wbudowanej powłoki ”. Czas uruchamiania powłoki może wymagać pomiaru osobno.
Kusalananda

1
Nie znam żadnej powłoki, która ma timewbudowane polecenie. Jednak wiele muszle tym bashmają timesłowo kluczowe, które mogą być używane do rurociągów czasowych. Aby wyłączyć to słowo kluczowe, aby timemożna było użyć polecenia (w systemie plików), możesz zacytować go tak "time" foo.sh. Zobacz także unix.stackexchange.com/search?q=user%3A22565+time+keyword
Stéphane Chazelas

6

Oto rozwiązanie, które:

  1. wyeliminuj czas potrzebny na załadowanie się i zainicjowanie każdej powłoki

  2. można uruchamiać od wewnątrz każdej skorupy

  3. Używa

    brak wbudowanych timepoleceń powłoki , ponieważ żadne nie są przenośne ani ogólne

  4. Działa we wszystkich powłokach zgodnych z POSIX.
  5. Działa na wszystkich systemach zgodnych z POSIX i zgodnych z XSI z kompilatorem C lub tam, gdzie można wcześniej skompilować plik wykonywalny C.
  6. Używa tej samej implementacji czasowej we wszystkich powłokach.

Składa się z dwóch części: krótkiego programu C, który się kończy gettimeofday, który jest przestarzały, ale wciąż bardziej przenośny niż clock_gettimei krótkiego skryptu powłoki, który używa tego programu, aby uzyskać zegar o precyzji mikrosekundowej odczytujący obie strony pozyskiwania skryptu. Program C jest jedynym przenośnym i minimalnym narzutem sposobem uzyskania precyzji poniżej sekundy na znaczniku czasu.

Oto program C epoch.c:

#include <sys/time.h>
#include <stdio.h>
int main(int argc, char **argv) {
    struct timeval time;
    gettimeofday(&time, NULL);
    printf("%li.%06i", time.tv_sec, time.tv_usec);
}

I skrypt powłoki timer:

#!/bin/echo Run this in the shell you want to test

START=$(./epoch)
. "$1"
END=$(./epoch)
echo "$END - $START" | bc

Jest to standardowy język poleceń powłoki i bcpowinny działać jako skrypt pod dowolnym kompatybilnym z POSIX powłoki.

Możesz użyć tego jako:

$ bash timer ./test.sh
.002052
$ dash timer ./test.sh
.000895
$ zsh timer ./test.sh
.000662

Nie mierzy czasu systemowego ani użytkownika, a jedynie upływ czasu niemonotonicznego zegara ściennego. Jeśli zegar systemowy zmieni się podczas wykonywania skryptu, da to nieprawidłowe wyniki. Jeśli system jest obciążony, wynik będzie niewiarygodny. Nie sądzę, żeby coś lepszego można było przenosić między pociskami.

evalZamiast tego można użyć skryptu timera do uruchamiania poleceń poza skryptem.


Przypadkowo, tuż przed przeczytaniem tego (i ostatniej linii eval), poprawiałem skrypt w odpowiedzi Rabina , aby włączyć eval "$@", aby mógł on uruchamiać wbudowane powłoki w locie.
agc

4

Wielokrotnie poprawione rozwiązanie wykorzystujące /proc/uptimei dc/ bc/ awkw dużych częściach dzięki wprowadzeniu przez agc :

#!/bin/sh

read -r before _ < /proc/uptime

sleep 2s # do something...

read -r after _ < /proc/uptime

duration=$(dc -e "${after} ${before} - n")
# Alternative using bc:
#   duration=$(echo "${after} - ${before}" | bc)
# Alternative using awk:
#   duration=$(echo "${after} ${before}" | awk '{print $1 - $2}')

echo "It took $duration seconds."

Zakłada oczywiście, że /proc/uptimeistnieje i ma pewną formę.


3
Dzięki temu byłby przenośny między powłokami, ale nie przenośny między implementacjami Unixa, ponieważ niektórym po prostu brakuje /procsystemu plików. Jeśli to dotyczy, czy nie, nie wiem.
Kusalananda

1
Dla podkreślenia to Q sugeruje prędkość dyskietki lub gorszą. W takim przypadku narzut obciążenia awkmoże być znaczny. Może b=$(cat /proc/uptime)przed, potem a=$(cat /proc/uptime)po, a następnie przeanalizuj $ a i $ b i odejmij.
agc

@agc Dobry wkład, dzięki, dodałem odpowiednio kilka alternatywnych rozwiązań.
phk,

1
Nie myślałem o tym wcześniej, ale gdyby takie wbudowaneread były lepsze niż cat, byłoby to czystsze (i trochę szybciej): read before dummyvar < /proc/uptime ;sleep 2s;read after dummyvar < /proc/uptime; duration=$(dc -e "${after} ${before} - n");echo "It took $duration seconds."
agc
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.