Soru Kabuk betikleri için performans profili oluşturma araçları


Subshells'ı çağıran ve her türlü şeyi yapan bir dizi komut dosyasını hızlandırmaya çalışıyorum. Bir kabuk senaryosunun ve iç içe geçmiş kabukların uygulanmasını zamanlamak için herhangi bir araç mevcut olup olmadığını ve senaryonun hangi bölümlerinin en pahalı olduğunu bildirip bildirmediğini merak ettim.

Örneğin, aşağıdaki gibi bir komut dosyası varsa.

#!/bin/bash

echo "hello"
echo $(date)
echo "goodbye"

Her üç çizginin ne kadar sürdüğünü bilmek isterim. time sadece senaryo için bana sadece zaman verecektir. bash -x ilginçtir, ancak zaman damgalarını veya diğer zamanlama bilgilerini içermez.


25
2017-12-02 14:28


Menşei


komut denir time - ajreal
komutun her birine zaman ayırabilirsin, time echo "hello" - ajreal
@ajreal, bu geçerli bir cevap, neden onu yayınlamıyorsun? - Fred Foo


Cevaplar:


Sen ayarlayabilirsiniz PS4 zamanı ve satır numarasını göstermek için Bunu yapmak, herhangi bir yardımcı programın yüklenmesini gerektirmez ve stderr'i stdout'a yönlendirmeden çalışır.

Bu komut dosyası için:

#!/bin/bash -x
# Note the -x flag above, it is required for this to work
PS4='+ $(date "+%s.%N ($LINENO) ")'
for i in {0..2}
do
    echo $i
done
sleep 1
echo done

Çıktı gibi görünüyor:

+ PS4='+ $(date "+%s.%N ($LINENO) ")'
+ 1291311776.108610290 (3) for i in '{0..2}'
+ 1291311776.120680354 (5) echo 0
0
+ 1291311776.133917546 (3) for i in '{0..2}'
+ 1291311776.146386339 (5) echo 1
1
+ 1291311776.158646585 (3) for i in '{0..2}'
+ 1291311776.171003138 (5) echo 2
2
+ 1291311776.183450114 (7) sleep 1
+ 1291311777.203053652 (8) echo done
done

Bu, GNU tarihini varsayar, ancak çıktı belirtimini istediğiniz herhangi bir şeye veya kullandığınız tarihin sürümüyle eşleşecek şekilde değiştirebilirsiniz.

Not: Bunu değiştirmeksizin bunu yapmak istediğiniz mevcut bir komut dosyanız varsa, bunu yapabilirsiniz:

PS4='+ $(date "+%s.%N ($LINENO) ")' bash -x scriptname

Yaklaşan Bash 5'de, forking kaydetme mümkün olacak date (ancak nanosaniye yerine mikro saniye alırsınız):

PS4='+ $EPOCHREALTIME ($LINENO) '

44
2017-12-02 17:43



Not -x tepede #!/bin/bash -x önemli - Babken Vardanyan


Altında çalışan çıktıyı pipetleyebilirsin. -x her satırın alındığı zaman zaman damgası olan bir şeye. Örneğin, tai64n djb'den Daemon araçları. Temel bir örnekte,

sh -x slow.sh 2>&1 | tai64n | tai64nlocal

Bu stdout ve stderr'i birleştirir ancak her zaman bir zaman damgası verir. Daha sonra, pahalı hatları bulmak için çıktıyı analiz etmeniz ve bunu kaynağınızla ilişkilendirmeniz gerekir.

Bunu kullanarak da bulabilirsiniz strace faydalı. Örneğin,

strace -f -ttt -T -o /tmp/analysis.txt slow.sh

Bu, çok sayıda zamanlama bilgisiyle çok ayrıntılı bir rapor oluşturacaktır. /tmp/analysis.txtAncak, çok detaylı olabilecek, sistem başına bir çağrı düzeyinde.


10
2017-12-02 16:34



Ayrıca iyi bir cevap! İlkini tercih ediyorum çünkü herhangi bir ek paket bulmam gerekmiyor, ancak bu, profil oluşturduğunuz senaryonu değiştirmek zorunda kalmamanız güzel. Teşekkürler! - bradtgmurray
teşekkürler, gerçekten yararlı! - Y.Huang
Bunu senaryodaki en yavaş satırı bulmak için kullandım: github.com/brycepg/notebooks/blob/master/... - Bryce Guinta


Her ekoyu zamanlamak istiyor gibisin. Echo, tüm yaptığınız şey bu kadar kolaysa

alias echo='time echo'

Başka bir komut çalıştırıyorsanız, bu yeterli olmayacaktır.


1
2017-12-02 15:54





Tercih edilen yaklaşımım aşağıda. Bunun nedeni, OSX'i de desteklemesidir (yüksek hassasiyetli olmayan tarihler) ve bc yüklü olmasa bile çalışır.

#!/bin/bash

_profiler_check_precision() {
    if [ -z "$PROFILE_HIGH_PRECISION" ]; then
        #debug "Precision of timer is unknown"
        if which bc > /dev/null 2>&1 && date '+%s.%N' | grep -vq '\.N$'; then
            export PROFILE_HIGH_PRECISION=y
        else
            export PROFILE_HIGH_PRECISION=n
        fi
    fi
}


_profiler_ts() {
    _profiler_check_precision

    if [ "y" = "$PROFILE_HIGH_PRECISION" ]; then
        date '+%s.%N'
    else
        date '+%s'
    fi
}

profile_mark() {
    _PROF_START="$(_profiler_ts)"
}

profile_elapsed() {
    _profiler_check_precision

    local NOW="$(_profile_ts)"
    local ELAPSED=

    if [ "y" = "$PROFILE_HIGH_PRECISION" ]; then
        ELAPSED="$(echo "scale=10; $NOW - $_PROF_START" | bc | sed 's/\(\.[0-9]\{0,3\}\)[0-9]*$/\1/')"
    else
        ELAPSED=$((NOW - _PROF_START))
    fi

    echo "$ELAPSED"
}

do_something() {
    local _PROF_START
    profile_mark()
    sleep 10
    echo "Took $(profile_elapsed()) seconds"
}

1
2018-06-13 21:08



Bash yerleşik time Bunu senin için yapacak. - Dennis Williamson


Herhangi bir kabuk profilleme aracından haberdar değilim.

Tarihsel olarak Perl, Python, Ruby ve hatta C'deki çok yavaş kabuk betiklerini yeniden yazıyor.

Daha az sert bir fikir, bash'tan daha hızlı bir kabuk kullanmaktır. tire ve kül Tüm Unix tarzı sistemler için kullanılabilir ve genellikle oldukça küçük ve daha hızlıdır.


-3
2017-12-02 14:36



Ancak, profilin bulamaması ve bu yüzden darboğazın nerede olduğunu bilmemeniz halinde daha yavaş ya da daha hızlı bir kabuğun performansı nasıl artıracağını nereden biliyorsunuz? - Sorpigal