Evrensel bash olmayan 'zaman' kıyaslama alternatifi? [kapalı]


10

Farklı kabuklar arasındaki komut çalıştırmak kez karşılaştırarak, bazı SE cevaplar kullanarak önermek bashs' dahili time , komuta şöyle:

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

... vs , her kabuğun test etmesi için. Bu tür ölçütler, her kabuğun kendini yüklemesi ve başlatması için geçen süreyi ortadan kaldırmaz . Örneğin, yukarıdaki komutların her ikisinin de erken bir disketin okuma hızına sahip yavaş bir cihazda depolandığını varsayalım (124KB / s), dash( ~ 150K yürütülebilir) kabuktan yaklaşık 7 kat daha hızlı yüklenecektir bash( ~ 1M ) yükleme süresi timesayıları çarpıtır - bu mermilerin ön yükleme süreleri , mermiler yüklendikten sonrafoo.sh her merminin altında çalışma sürelerinin ölçülmesi ile ilgisizdir .

Çalıştırılabilir komut zamanlama çalıştırmak için en iyi taşınabilir ve genel util nedir dahilinde her kabuk? Yukarıdaki kod şöyle görünecektir:

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

Not: hiçbiri taşınabilir veya genel olmadığı için kabuk yerleşik time komutları yoktur .


Daha da iyisi, util bir kabuğun dahili komutları ve boru hatları tarafından harcanan zamanı, kullanıcı önce bir komut dosyasına sarmak zorunda kalmadan kıyaslayabiliyorsa. Bunun gibi yapay sözdizimi yardımcı olacaktır:

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

Bazı mermiler timebunu başarabilir. Örneğin bash -c "time while false ; do : ; done"işler. Sisteminizde neyin işe yarayıp neyin işe yaramadığını görmek için şunu deneyin:

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

6
Sadece kullan /usr/bin/time?
Kusalananda

1
Herhangi bir yerleşik olmayan her ikisi de nasıl "her kabuk kendini yüklemek ve başlatmak için harcanan zaman ortadan kaldırmak" ve "taşınabilir ve genel" olurken bağımsız bir komut dosyası yürütmek nasıl anlayamıyorum .
Michael Homer

1
Bu soruya bir cevap değil, ne istediğinizi açıklığa kavuşturmanız için bir bilgi istemi.
Michael Homer

1
En iyi girişimimi yayınladım, ancak bence soru aslında tam olarak neyi başarmaya çalıştığı hakkında yeterince belirsiz.
Michael Homer

2
“Taşınabilir veya genel” ile ne demek istiyorsun? Kabuk yerleşikler, harici komut kadar taşınabilir (birçok sistemde çalışır) ve daha geneldir (bir dosyanın yürütülmesinden başka bir şey zamanlayabileceği için daha fazla durumda çalışır). Ne problemi çözmeye çalışıyorsun?
Gilles 'SO- kötü olmayı bırak

Yanıtlar:


10

timePOSIX tarafından belirtildiğini ve POSIX'in bahsettiği tek seçeneğin ( -p) çeşitli kabuklar tarafından doğru bir şekilde desteklendiğini AFAICT ile not etmelisiniz :

$ 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
Sorun, zamanlamaları karşılaştırabilmek için sonucun aynı uygulamayla zamanlanması gerektiğidir time. Sprinterlerin kendi zamanlarını aynı anda bir saatle yapmak yerine 100 m'de ölçmelerine izin vermek karşılaştırılabilir. Bu açıkça nitpicking, ama yine de ...
Kusalananda

@Kusalananda Problem OP düşüncesinin timetaşınabilir olmadığıydı; taşınabilir gibi görünüyor. (Yine de karşılaştırılabilirlik konusuna katılıyorum)
muru

@muru, benim sistemim üzerinde dash -c 'time -p while false ; do : ; done'döner "Böyle bir dosya ya da dizin <cr> Komut sıfır olmayan durum 127 ile çıkıldı zaman: süre koşamam" hatalar.
agc

1
@agc POSIX ayrıca şunları söylüyor: "Komut yerine komut terimi, kabuk bileşimi komutlarının, boru hatlarının, özel yerleşiklerin vb. doğrudan kullanılamayacağını vurgulamak için kullanılır. Ancak, yardımcı program kullanıcı uygulama programlarını ve kabuk komut dosyaları, sadece standart araçlar değil. " (RATIONALE bölümüne bakın)
muru


7

Yüksek çözünürlüklü bir zamanlayıcıyı destekleyen GNU date komutunu kullanıyorum :

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

"$@" &> /dev/null

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

Ve sonra senaryoyu şöyle çağırıyorum:

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

Çıkış birimi milisaniye cinsindendir.


1
Zamanın (dönem zamanı) kabul edilmesi, arada değişmez. Uygulamada bir soruna neden olacak ama yine de bahsetmeye değer bir durum düşünemiyorum.
phk

1
Bunun dateözellikle GNU gerektirdiğini eklemelisiniz .
Kusalananda

@phk lütfen açıkla?
Rabin

1
@Rabin Diyelim ki NTP istemciniz sorunları düzeltir ve saatinizi nerede STARTve ENDayarlanmış arasında günceller ve değiştirirse , sonuç açıkça bu durumdan etkilenir. Ne kadar kesin bir şekilde ihtiyacınız olduğuna ve sizin durumunuzda önemli olup olmadığına dair hiçbir fikrim yok ama dediğim gibi akılda tutulması gereken bir şey. (Eğlence hikayesi: Tam olarak beklenmedik bir şekilde olumsuz sonuçlara yol açan bir yazılım biliyorum - hesaplamaları gerçekleştirmek için kullanıldı - ve sonra birkaç şey kırdı.)
phk

1
Ayrıca, bazı NTP istemcileri sistem zamanında "sıçramalar" yapmak yerine yavaşlamıyor ve saati hızlandırmıyor mu? Böyle bir NTP istemciniz varsa ve dün akşam biraz zamanlama yaptıysanız, muhtemelen NTP istemcisi tarafından artık saniye beklemektedir. (Veya bu durumda sistem saati sadece 61'e çalışır mı?)
Jörg W Mittag

6

Yardımcı timeprogram genellikle fark ettiğiniz gibi kabuğun içine yerleştirilmiştir, bu da onu "nötr" bir zamanlayıcı olarak işe yaramaz hale getirir.

Bununla birlikte, yardımcı program, genellikle /usr/bin/timeönerdiğiniz zamanlama deneylerini gerçekleştirmek için kullanılabilecek harici bir yardımcı program olarak da kullanılabilir .

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

Bu "her merminin kendini yüklemesi ve başlatması için harcanan zamanı nasıl ortadan kaldırır"?
Michael Homer

1
Eğer foo.shçalıştırılabilir ve bir shebang vardır, o zaman bu her zaman aynı kabuk üzerinden çalışır ve bu OP istemeyiz bu yüzden, o kabuğun başlangıç zamanı sayar yapar. Eğer foo.shbunlardan bir tane eksik, o zaman bu hiç çalışmaz.
Kevin

@Kevin Çok doğru. Sadece "hiçbir kabuk yerleşik time" gözüküyor gibi görünüyor. Kabuk başlangıç ​​zamanının ayrı olarak ölçülmesi gerekebilir.
Kusalananda

1
timeYerleşik bir komutu olan herhangi bir kabuk bilmiyorum . Bununla birlikte, birçok mermi , boru hatlarını zamanlamak için kullanılabilecek bashbir timeanahtar kelimeye sahiptir. timeKomutun (dosya sisteminde) kullanılmasını sağlamak için bu anahtar kelimeyi devre dışı bırakmak için anahtar kelimeyi alıntılayabilirsiniz "time" foo.sh. Ayrıca bkz. Unix.stackexchange.com/search?q=user%3A22565+time+keyword
Stéphane Chazelas

6

İşte bir çözüm:

  1. her merminin kendini yüklemesi ve başlatması için geçen süreyi [s] ortadan kaldırır

  2. her kabuğun içinden çalıştırılabilir

  3. Kullanımları

    hiçbir kabuk yerleşik timekomut içermez , çünkü hiçbiri taşınabilir veya genel değildir

  4. POSIX uyumlu tüm mermilerde çalışır.
  5. C derleyicili veya önceden bir C yürütülebilir dosyası derleyebileceğiniz tüm POSIX uyumlu ve XSI uyumlu sistemlerde çalışır .
  6. Tüm kabuklarda aynı zamanlama uygulamasını kullanır.

İki bölüm vardır: tamamlanan gettimeofday, ancak daha taşınabilir olan kısa bir C programı clock_gettimeve bir komut dosyasını kaynaklamanın her iki tarafını okuyan mikrosaniye hassasiyetli bir saat almak için bu programı kullanan kısa bir kabuk komut dosyası. C programı, zaman damgasında bir saniyenin altında bir hassasiyet elde etmenin tek taşınabilir ve minimum tepegöz yoludur.

İşte C programı 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);
}

Ve kabuk betiği timer:

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

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

Bu standart kabuk komut dilidir ve bcherhangi bir POSIX uyumlu kabuk altında komut dosyası olarak çalışmalıdır.

Bunu şu şekilde kullanabilirsiniz:

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

Sistem veya kullanıcı süresini ölçmez, sadece monoton olmayan duvar saati geçen süreyi ölçer. Komut dosyası yürütülürken sistem saati değişirse, bu yanlış sonuçlar verir. Sistem yük altındaysa, sonuç güvenilir olmayacaktır. Daha iyi bir şeyin kabuklar arasında taşınabilir olabileceğini düşünmüyorum.

Değiştirilmiş bir zamanlayıcı komut dosyası, evalkomut dosyalarının dışındaki komutları çalıştırmak için kullanılabilir .


Tesadüfen, bunu okumadan hemen önce, (ve son satır eval), senaryoyu Rabin'in cevabına dahil etmek için ince ayar yapıyordum eval "$@", böylece kabuk yapılarını anında çalıştırabilirdi .
agc

4

Agc tarafından sağlanan giriş sayesinde büyük parçalarda /proc/uptimeve dc/ bc/ kullanarak birçok kez revize edilmiş çözüm :awk

#!/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."

Açıkça /proc/uptimevar olduğunu ve belli bir formu olduğunu varsayar .


3
Bu, onu kabuklar arasında taşınabilir hale getirir, ancak bazılarının /procdosya sisteminden yoksun olması nedeniyle Unix uygulamaları arasında taşınabilir değildir . Bu bir endişe olsun ya da olmasın, bilmiyorum.
Kusalananda

1
Vurgulamak için bu Q disket hızlarını veya daha kötüsünü önerir. Bu durumda yükleme yükü awkönemli olabilir. Belki b=$(cat /proc/uptime)önce, sonra a=$(cat /proc/uptime)sonra sonra ayrıştırmak $ a ve $ b ve çıkarma.
agc

@agc İyi girdi, teşekkürler, buna göre bazı alternatif çözümler ekledim.
phk

1
Daha önce düşünmedim, ama gibi yerleşiklerread daha iyi catolsaydı, bu daha temiz (ve biraz daha hızlı) olurdu:read before dummyvar < /proc/uptime ;sleep 2s;read after dummyvar < /proc/uptime; duration=$(dc -e "${after} ${before} - n");echo "It took $duration seconds."
agc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.