Bir bash kabuğu betiğinin profili nasıl yavaş açılır?


124

Bash kabuğumun başlaması 3-4 saniye sürerken, başlatırsam --norchemen çalışır.

"Profil oluşturmaya" başladım /etc/bash.bashrcve ~/.bashrcmanuel olarak returnifadeler ekleyerek ve hız iyileştirmeleri arayarak başladım , ancak bu nicel bir süreç değil ve verimli değil.

Bash komut dosyalarımın profilini nasıl çıkarabilirim ve hangi komutların başlatılmasının en çok zaman aldığını nasıl görebilirim?


3
Komut dosyalarının profilini çıkardım ve çoğu zaman bash_completion kurulumu sırasında harcandı.
Andrea Spadaccini

1
Oldukça büyük olduğu için bu şaşırtıcı değil. Değişikliklerinizi güncellemelerde vb.
Sürdürme

2
Sen karşılaştırabilirsiniz: time bash -c 'exit've time bash -i -c 'exit've ile oynayabilir --norcve --noprofile.
F. Hauri

Bu yanıta da bakın (sorumluluk reddi: benimdir). Tam olarak istediğiniz şey değil, ama kesinlikle ilgili: unix.stackexchange.com/a/555510/384864
Johan Walles

Yanıtlar:


128

GNU'nuz date(veya nanosaniye çıktı verebilen başka bir sürümünüz) varsa, bunu başlangıcında /etc/bash.bashrc(veya herhangi bir Bash betiğinde izlemeye başlamak istediğiniz yerde) yapın:

PS4='+ $(date "+%s.%N")\011 '
exec 3>&2 2>/tmp/bashstart.$$.log
set -x

Ekle

set +x
exec 2>&3 3>&-

sonunda ~/.bashrc(veya izlemenin durdurulmasını istediğiniz herhangi bir Bash betiğinin bölümünün sonunda). \011Bir sekizlik sekme karakteridir.

Bir izleme oturumu açmalısınız /tmp/bashstart.PID.logYürütülen her komutun saniye.nanosaniye zaman damgasını gösteren . Bir zamandan diğerine fark, araya giren adımın attığı süredir.

İşleri daraltırken, set -xdaha sonra ve set +xdaha erken hareket edebilirsiniz (veya ilgilendiğiniz birkaç bölümü seçime bağlı olarak parantez içine alabilirsiniz).

GNU'nun datenanosaniye kadar ince taneli olmasa da Bash 5, zamanı mikrosaniye cinsinden veren bir değişken içerir. Bunu kullanmak sizi her satır için harici bir yürütülebilir dosya oluşturmaktan kurtarır ve Mac'lerde veya GNU'su olmayan başka yerlerde çalışır date- elbette Bash 5'e sahip olduğunuz sürece. Ayarını değiştirin PS4:

PS4='+ $EPOCHREALTIME\011 '

@Pawamoy tarafından belirtildiği gibi, BASH_XTRACEFDBash 4.1 veya sonraki bir sürümüne sahipseniz, izleme çıktısını ayrı bir dosya tanımlayıcısına göndermek için kullanabilirsiniz . Gönderen bu cevap :

#!/bin/bash

exec 5> command.txt
BASH_XTRACEFD="5"

echo -n "hello "

set -x
echo -n world
set +x

echo "!"

Bu, izleme çıktısının command.txtayrılan dosyaya gitmesine stdoutve stdoutnormal olarak çıktısının alınmasına (veya ayrı olarak yeniden yönlendirilmesine) neden olur.


Kabuk isteminin görünmez olması ve komutlarımın geri yansımaması normal mi? Ancak, izlemeyi aldım, böylece analize başlayabilirim .. çok teşekkürler!
Andrea Spadaccini

1
@AndreaSpadaccini: Final execfd2'yi normale döndürmeli, böylece istemi geri almalısınız.
sonraki duyuruya kadar duraklatıldı.

7
... aslında, bash 4.2 ile, tek iyi yapabilirim - kullanarak \D{...}içinde PS4tamamen keyfi zaman biçimi dizeleri başlatılması performans yükü olmadan genişletilebilir olanak verir datealt süreç olarak.
Charles Duffy

3
@CharlesDuffy: Bunların ikisi de gerçekten harika. Ancak GNU dateanlar %Nve Bash 4.2, strftime(3)GNU sisteminde anlamaz (çünkü anlamaz ) - sınırlarla çok keyfi. Performansa karşı çözünürlük hakkındaki görüşleriniz iyidir ve bir kullanıcı seçimi akıllıca yapmalıdır; performans vuruşunun yalnızca hata ayıklama sırasında (ve yalnızca etkin olduğunda set -x) geçici olduğunu unutmayın .
sonraki duyuruya kadar duraklatıldı.

1
Bash 4 ile hata ayıklama çıktısını varsayılan olandan (2 veya stderr) başka bir dosya tanımlayıcısına yeniden yönlendirmek için BASH_XTRACEFD değişkeni de kullanılabilir. Çıktıyı (profilleme verilerini) analiz etme zamanı geldiğinde, artık stderr ve set -x çıktısını çözmek zorunda olmadığından (çok sayıda uç durum) çok yardımcı olur.
pawamoy

107

profil oluşturma (4 cevap)

Düzenleme: Mart 2016 ekleme scriptyöntemi

Bunu okumak ve profil oluşturma önemli bir adım olduğu için, tüm bu SO sorusu hakkında biraz test ve araştırma yaptım ve yanıtları zaten gönderdim.

4+ cevap var:

  • İlki @ DennisWilliamson'ın fikrine dayanıyor, ancak çok daha az kaynak tüketimi ile
  • İkincisi benim (bundan önce;)
  • Üçüncüsü @fgm cevabına dayanır, ancak daha doğrudur.
  • Geçen kullanım script, scriptreplayve zamanlama dosyası .

  • Son olarak, sonunda performansların küçük bir karşılaştırması.

Kullanılması set -xve dateancak sınırlı olan çatal

@ DennisWilliamson'ın fikrinden alın, ancak aşağıdaki sözdizimi ile, 3 komuta yalnızca bir başlangıç ​​çatallanma olacaktır:

exec 3>&2 2> >(tee /tmp/sample-time.$$.log |
                 sed -u 's/^.*$/now/' |
                 date -f - +%s.%N >/tmp/sample-time.$$.tim)
set -x

Bunu yapmak dateyalnızca bir kez çalışacaktır . Nasıl çalıştığını göstermek için hızlı bir demo / test var:

for i in {1..4};do echo now;sleep .05;done| date -f - +%N

Örnek komut dosyası:

#!/bin/bash

exec 3>&2 2> >( tee /tmp/sample-$$.log |
                  sed -u 's/^.*$/now/' |
                  date -f - +%s.%N >/tmp/sample-$$.tim)
set -x

for ((i=3;i--;));do sleep .1;done

for ((i=2;i--;))
do
    tar -cf /tmp/test.tar -C / bin
    gzip /tmp/test.tar
    rm /tmp/test.tar.gz
done

set +x
exec 2>&3 3>&-

Bu komut dosyasını çalıştırarak 2 dosya oluşturursunuz: /tmp/sample-XXXX.logve /tmp/sample-XXXX.tim(burada XXXX, çalışan komut dosyasının işlem kimliğidir).

Bunları kullanarak sunabilirsiniz paste:

paste tmp/sample-XXXX.{tim,log}

Veya fark zamanını bile hesaplayabilirsiniz:

paste <(
    while read tim ;do
        crt=000000000$((${tim//.}-10#0$last))
        printf "%12.9f\n" ${crt:0:${#crt}-9}.${crt:${#crt}-9}
        last=${tim//.}
      done < sample-time.24804.tim
  ) sample-time.24804.log 

 1388487534.391309713        + (( i=3 ))
 0.000080807        + (( i-- ))
 0.000008312        + sleep .1
 0.101304843        + (( 1 ))
 0.000032616        + (( i-- ))
 0.000007124        + sleep .1
 0.101251684        + (( 1 ))
 0.000033036        + (( i-- ))
 0.000007054        + sleep .1
 0.104013813        + (( 1 ))
 0.000026959        + (( i-- ))
 0.000006915        + (( i=2 ))
 0.000006635        + (( i-- ))
 0.000006844        + tar -cf /tmp/test.tar -C / bin
 0.022655107        + gzip /tmp/test.tar
 0.637042668        + rm /tmp/test.tar.gz
 0.000823649        + (( 1 ))
 0.000011314        + (( i-- ))
 0.000006915        + tar -cf /tmp/test.tar -C / bin
 0.016084482        + gzip /tmp/test.tar
 0.627798263        + rm /tmp/test.tar.gz
 0.001294946        + (( 1 ))
 0.000023187        + (( i-- ))
 0.000006845        + set +x

veya iki sütun üzerinde:

paste <(
    while read tim ;do
        [ -z "$last" ] && last=${tim//.} && first=${tim//.}
        crt=000000000$((${tim//.}-10#0$last))
        ctot=000000000$((${tim//.}-10#0$first))
        printf "%12.9f %12.9f\n" ${crt:0:${#crt}-9}.${crt:${#crt}-9} \
                                 ${ctot:0:${#ctot}-9}.${ctot:${#ctot}-9}
        last=${tim//.}
      done < sample-time.24804.tim
  ) sample-time.24804.log

Oluşturabilir:

 0.000000000  0.000000000   + (( i=3 ))
 0.000080807  0.000080807   + (( i-- ))
 0.000008312  0.000089119   + sleep .1
 0.101304843  0.101393962   + (( 1 ))
 0.000032616  0.101426578   + (( i-- ))
 0.000007124  0.101433702   + sleep .1
 0.101251684  0.202685386   + (( 1 ))
 0.000033036  0.202718422   + (( i-- ))
 0.000007054  0.202725476   + sleep .1
 0.104013813  0.306739289   + (( 1 ))
 0.000026959  0.306766248   + (( i-- ))
 0.000006915  0.306773163   + (( i=2 ))
 0.000006635  0.306779798   + (( i-- ))
 0.000006844  0.306786642   + tar -cf /tmp/test.tar -C / bin
 0.022655107  0.329441749   + gzip /tmp/test.tar
 0.637042668  0.966484417   + rm /tmp/test.tar.gz
 0.000823649  0.967308066   + (( 1 ))
 0.000011314  0.967319380   + (( i-- ))
 0.000006915  0.967326295   + tar -cf /tmp/test.tar -C / bin
 0.016084482  0.983410777   + gzip /tmp/test.tar
 0.627798263  1.611209040   + rm /tmp/test.tar.gz
 0.001294946  1.612503986   + (( 1 ))
 0.000023187  1.612527173   + (( i-- ))
 0.000006845  1.612534018   + set +x

Kullanılması trap debugve /proc/timer_listüzerinde son , GNU / Linux çekirdekleri olmadan çatal .

GNU / Linux'un en son çekirdeklerinin altında şu adda bir /procdosya bulabilirsiniz timer_list:

grep 'now at\|offset' /proc/timer_list
now at 5461935212966259 nsecs
  .offset:     0 nsecs
  .offset:     1383718821564493249 nsecs
  .offset:     0 nsecs

Şu anki zamanın toplamı olduğu yerde 5461935212966259 + 1383718821564493249, ancak nanosaniye cinsinden .

Dolayısıyla geçen zamanı hesaplamak için ofseti bilmeye gerek yoktur.

Bu tür işler için, aşağıdaki sözdiziminden elde edilen elap.bash (V2) yazdım :

source elap.bash-v2

veya

. elap.bash-v2 init

(Tam sözdizimi için yorumlara bakın)

Böylece bu satırı komut dosyanızın en üstüne ekleyebilirsiniz:

. elap.bash-v2 trap2

Küçük örnek:

#!/bin/bash

. elap.bash-v2 trap

for ((i=3;i--;));do sleep .1;done

elapCalc2
elapShowTotal \\e[1mfirst total\\e[0m

for ((i=2;i--;))
do
    tar -cf /tmp/test.tar -C / bin
    gzip /tmp/test.tar
    rm /tmp/test.tar.gz
done

trap -- debug
elapTotal \\e[1mtotal time\\e[0m

Ana makinemde render yap:

 0.000947481 Starting
 0.000796900 ((i=3))
 0.000696956 ((i--))
 0.101969242 sleep .1
 0.000812478 ((1))
 0.000755067 ((i--))
 0.103693305 sleep .1
 0.000730482 ((1))
 0.000660360 ((i--))
 0.103565001 sleep .1
 0.000719516 ((1))
 0.000671325 ((i--))
 0.000754856 elapCalc2
 0.316018113 first total
 0.000754787 elapShowTotal \e[1mfirst total\e[0m
 0.000711275 ((i=2))
 0.000683408 ((i--))
 0.075673816 tar -cf /tmp/test.tar -C / bin
 0.596389329 gzip /tmp/test.tar
 0.006565188 rm /tmp/test.tar.gz
 0.000830217 ((1))
 0.000759466 ((i--))
 0.024783966 tar -cf /tmp/test.tar -C / bin
 0.604119903 gzip /tmp/test.tar
 0.005172940 rm /tmp/test.tar.gz
 0.000952299 ((1))
 0.000827421 ((i--))
 1.635788924 total time
 1.636657204 EXIT

Kaynak komutuna argüman trap2yerine kullanmak trap:

#!/bin/bash

. elap.bash-v2 trap2
...

Son komut ve toplam iki sütun oluşturacaktır :

 0.000894541      0.000894541 Starting
 0.001306122      0.002200663 ((i=3))
 0.001929397      0.004130060 ((i--))
 0.103035812      0.107165872 sleep .1
 0.000875613      0.108041485 ((1))
 0.000813872      0.108855357 ((i--))
 0.104954517      0.213809874 sleep .1
 0.000900617      0.214710491 ((1))
 0.000842159      0.215552650 ((i--))
 0.104846890      0.320399540 sleep .1
 0.000899082      0.321298622 ((1))
 0.000811708      0.322110330 ((i--))
 0.000879455      0.322989785 elapCalc2
 0.322989785 first total
 0.000906692      0.323896477 elapShowTotal \e[1mfirst total\e[0m
 0.000820089      0.324716566 ((i=2))
 0.000773782      0.325490348 ((i--))
 0.024752613      0.350242961 tar -cf /tmp/test.tar -C / bin
 0.596199363      0.946442324 gzip /tmp/test.tar
 0.003007128      0.949449452 rm /tmp/test.tar.gz
 0.000791452      0.950240904 ((1))
 0.000779371      0.951020275 ((i--))
 0.030519702      0.981539977 tar -cf /tmp/test.tar -C / bin
 0.584155405      1.565695382 gzip /tmp/test.tar
 0.003058674      1.568754056 rm /tmp/test.tar.gz
 0.000955093      1.569709149 ((1))
 0.000919964      1.570629113 ((i--))
 1.571516599 total time
 0.001723708      1.572352821 EXIT

kullanma strace

Evet, straceişi yapabilirdi:

strace -q -f -s 10 -ttt sample-script 2>sample-script-strace.log

Ama çok şey yapabilir!

wc sample-script-strace.log
    6925  57637 586518 sample-script-strace.log

Daha kısıtlı komut kullanma:

strace -f -s 10 -ttt -eopen,access,read,write ./sample-script 2>sample-script-strace.log

Daha hafif kütüğü dökecek:

  4519  36695 374453 sample-script-strace.log

Ne aradığınıza bağlı olarak daha kısıtlayıcı olabilirsiniz:

 strace -f -s 10 -ttt -eaccess,open ./sample-script 2>&1 | wc
  189    1451   13682

Onları okumak biraz daha zor olacak:

{
    read -a first
    first=${first//.}
    last=$first
    while read tim line;do
        crt=000000000$((${tim//.}-last))
        ctot=000000000$((${tim//.}-first))
        printf "%9.6f %9.6f %s\n" ${crt:0:${#crt}-6}.${crt:${#crt}-6} \
            ${ctot:0:${#ctot}-6}.${ctot:${#ctot}-6} "$line"
        last=${tim//.}
      done
  } < <(
    sed </tmp/sample-script.strace -e '
        s/^ *//;
        s/^\[[^]]*\] *//;
        /^[0-9]\{4\}/!d
  ')

 0.000110  0.000110 open("/lib/x86_64-linux-gnu/libtinfo.so.5", O_RDONLY) = 4
 0.000132  0.000242 open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY) = 4
 0.000121  0.000363 open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 4
 0.000462  0.000825 open("/dev/tty", O_RDWR|O_NONBLOCK) = 4
 0.000147  0.000972 open("/usr/lib/locale/locale-archive", O_RDONLY) = 4
 ...
 0.000793  1.551331 open("/etc/ld.so.cache", O_RDONLY) = 4
 0.000127  1.551458 open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 4
 0.000545  1.552003 open("/usr/lib/locale/locale-archive", O_RDONLY) = 4
 0.000439  1.552442 --- SIGCHLD (Child exited) @ 0 (0) ---

Orijinal bash betiğini bunda takip etmek o kadar kolay değil ...

Kullanılması script, scriptreplayve dosyayı zamanlama

BSD Utils'in bir parçası olarak , script(ve scriptreplay) çok küçük bir ayak izi ile bash'ı profillemek için kullanılabilen çok eski bir araçtır.

script -t script.log 2>script.tim -c 'bash -x -c "
    for ((i=3;i--;));do sleep .1;done

    for ((i=2;i--;)) ;do
        tar -cf /tmp/test.tar -C / bin
        gzip /tmp/test.tar
        rm /tmp/test.tar.gz
    done
"'

Üretecek:

Script started on Fri Mar 25 08:29:37 2016
+ (( i=3 ))
+ (( i-- ))
+ sleep .1
+ (( 1 ))
+ (( i-- ))
+ sleep .1
+ (( 1 ))
+ (( i-- ))
+ sleep .1
+ (( 1 ))
+ (( i-- ))
+ (( i=2 ))
+ (( i-- ))
+ tar -cf /tmp/test.tar -C / bin
+ gzip /tmp/test.tar
+ rm /tmp/test.tar.gz
+ (( 1 ))
+ (( i-- ))
+ tar -cf /tmp/test.tar -C / bin
+ gzip /tmp/test.tar
+ rm /tmp/test.tar.gz
+ (( 1 ))
+ (( i-- ))
Script done on Fri Mar 25 08:29:39 2016

ve iki dosya oluşturun:

ls -l script.*
-rw-r--r-- 1 user user 450 Mar 25 08:29 script.log
-rw-r--r-- 1 user user 177 Mar 25 08:29 script.tim

Dosya script.logtüm izlerini içeren ve script.timbir zamanlama dosyası :

head -n 4 script.*
==> script.log <==
Script started on Fri Mar 25 08:29:37 2016
+ (( i=3 ))
+ (( i-- ))
+ sleep .1

==> script.tim <==
0.435331 11
0.000033 2
0.000024 11
0.000010 2

Günlük dosyasının ilk ve son satırlarıyla ve / veya zamanlama dosyasında zamanları özetleyerek toplam süre yürütmeyi görebilirsiniz:

head -n1 script.log ;tail -n1 script.log 
Script started on Fri Mar 25 08:29:37 2016
Script done on Fri Mar 25 08:29:39 2016

sed < script.tim  's/ .*$//;H;${x;s/\n/+/g;s/^\+//;p};d' | bc -l
2.249755

Zamanlama dosyasında ikinci değer, karşılık gelen günlük dosyasındaki sonraki baytların sayısıdır. Bu, günlük dosyasını isteğe bağlı olarak bir hızlandırma faktörü ile yeniden oynatma becerisine izin verir :

scriptreplay script.{tim,log}

veya

scriptreplay script.{tim,log} 5

veya

 scriptreplay script.{tim,log} .2

Zamanları ve komutları yan yana göstermek de biraz daha karmaşıktır:

exec 4<script.log
read -u 4 line
echo $line ;while read tim char;do
    read -u 4 -N $char -r -s line
    echo $tim $line
  done < script.tim &&
while read -u 4 line;do
    echo $line
done;exec 4<&-
Script started on Fri Mar 25 08:28:51 2016
0.558012 + (( i=3 ))
0.000053 
0.000176 + (( i-- ))
0.000015 
0.000059 + sleep .1
0.000015 
 + sleep .1) + (( 1 ))
 + sleep .1) + (( 1 ))
 + tar -cf /tmp/test.tar -C / bin
0.035024 + gzip /tmp/test.tar
0.793846 + rm /tmp/test.tar.gz
 + tar -cf /tmp/test.tar -C / bin
0.024971 + gzip /tmp/test.tar
0.729062 + rm /tmp/test.tar.gz
 + (( i-- )) + (( 1 ))
Script done on Fri Mar 25 08:28:53 2016

Testler ve sonuç

Test yapmak için , bash karmaşık merhaba dünyasında ikinci örnek indirdim , bu komut dosyasının sunucumda tamamlanması yaklaşık 0,72 saniye sürüyor.

Senaryonun üstüne şunlardan birini ekledim:

  • tarafından elap.bashfonksiyonuna

    #!/bin/bash
    
    source elap.bash-v2 trap2
    
    eval "BUNCHS=(" $(perl <<EOF | gunzip
    ...
  • tarafından set -xvePS4

    #!/bin/bash
    
    PS4='+ $(date "+%s.%N")\011 '
    exec 3>&2 2>/tmp/bashstart.$$.log
    set -x
    
    eval "BUNCHS=(" $(perl <<EOF | gunzip
    ...
  • ile set -xve ilk çataldan uzun exec komutuna

    #!/bin/bash
    
    exec 3>&2 2> >(tee /tmp/sample-time.$$.log |
                     sed -u 's/^.*$/now/' |
                     date -f - +%s.%N >/tmp/sample-time.$$.tim)
    set -x
    
    eval "BUNCHS=(" $(perl <<EOF | gunzip
  • script(ve set +x) tarafından

    script -t helloworld.log 2>helloworld.tim -c '
        bash -x complex_helloworld-2.sh' >/dev/null 

Zamanlar

Ve yürütme sürelerini karşılaştırın (sunucumda):

  • Doğrudan 0,72 sn
  • elap.bash 13.18 saniye
  • set + tarih @ PS4 54.61 sn
  • set + 1 çatal 1,45 sn
  • komut dosyası ve zamanlama dosyası 2.19 sn
  • adım 4.47 saniye

çıktılar

  • tarafından elap.bashfonksiyonuna

         0.000950277      0.000950277 Starting
         0.007618964      0.008569241 eval "BUNCHS=(" $(perl <<EOF | gunzi
         0.005259953      0.013829194 BUNCHS=("2411 1115 -13 15 33 -3 15 1
         0.010945070      0.024774264 MKey="V922/G/,2:"
         0.001050990      0.025825254 export RotString=""
         0.004724348      0.030549602 initRotString
         0.001322184      0.031871786 for bunch in "${BUNCHS[@]}"
         0.000768893      0.032640679 out=""
         0.001008242      0.033648921 bunchArray=($bunch)
         0.000741095      0.034390016 ((k=0))
  • tarafından set -xvePS4

    ++ 1388598366.536099290  perl
    ++ 1388598366.536169132  gunzip
    + 1388598366.552794757   eval 'BUNCHS=(' '"2411' 1115 -13 15 33 -3 15 1
    ++ 1388598366.555001983  BUNCHS=("2411 1115 -13 15 33 -3 15 13111 -6 1
    + 1388598366.557551018   MKey=V922/G/,2:
    + 1388598366.558316839   export RotString=
    + 1388598366.559083848   RotString=
    + 1388598366.560165147   initRotString
    + 1388598366.560942633   local _i _char
    + 1388598366.561706988   RotString=
  • by set -xve ilk fork to long exec komutu (ve ikinci pasteörnek betiğim)

     0.000000000  0.000000000    ++ perl
     0.008141159  0.008141159    ++ gunzip
     0.000007822  0.008148981    + eval 'BUNCHS=(' '"2411' 1115 -13 15 33 -3 
     0.000006216  0.008155197    ++ BUNCHS=("2411 1115 -13 15 33 -3 15 13111 
     0.000006216  0.008161413    + MKey=V922/G/,2:
     0.000006076  0.008167489    + export RotString=
     0.000006007  0.008173496    + RotString=
     0.000006006  0.008179502    + initRotString
     0.000005937  0.008185439    + local _i _char
     0.000006006  0.008191445    + RotString=
  • tarafından strace

     0.000213  0.000213 brk(0)                = 0x17b6000
     0.000044  0.000257 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
     0.000047  0.000304 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf1c0dc000
     0.000040  0.000344 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
     0.000040  0.000384 open("/etc/ld.so.cache", O_RDONLY) = 4
     ...
     0.000024  4.425049 close(10)             = 0
     0.000042  4.425091 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
     0.000028  4.425119 read(255, "", 4409)   = 0
     0.000058  4.425177 exit_group(0)         = ?
  • tarafından script

    Le script a débuté sur ven 25 mar 2016 09:18:35 CET
    0.667160 ++ gunzip
    0.000025 
    0.000948 ++ perl
    0.000011 
    0.005338 + eval 'BUNCHS=(' '"2411' 1115 -13 15 33 -3 15 13111 -6 1 111 4
    0.000044 1223 15 3311 121121 17 3311 121121 1223 3311 121121 17 3311 121
    0.000175 ++ BUNCHS=("2411 1115 -13 15 33 -3 15 13111 -6 15 1114 15 12211
    0.000029 1 1321 12211 412 21211 33 21211 -2 15 2311 11121 232 121111 122
    0.000023 4 3311 121121 12221 3311 121121 12221 3311 121121 1313 -6 15 33

Sonuç

İyi! Benim ise saf bash gibi batacak her komutun güncel çatallama , benim saf bash her komutun bazı işlemleri gerektirir.

Günlük tutma ve depolama için bağımsız bir süreç tahsis etmenin yolu açıkça daha verimlidir.

strace ilginç bir yol, daha ayrıntılı, ancak okuması zor.

script, ile scriptreplayve hızlanma faktörü de çok güzel, aynı hassasiyet, işlem yürütme yerine konsol değişimine dayanıyor, ancak çok hafif ve verimli (aynı amaç değil, aynı kullanım değil).

Son olarak, okunabilirlik ve performans açısından daha verimli olduğunu düşünüyorum set + 1 fork, Bu cevabın ilki, ama iyi, özel duruma bağlı olarak, bazen straceve / veya ben de kullanıyorum script.



2
Times bölüm çatallar (komut aslında tamamen hakim birçok türde) burnunuzu bir şey olduğunu oldukça bilgilendirici ve sürücüler ev sahipliği yapmaktadır. İyi bir (uzun süredir çekilmişse) bir cevap için +1. Belki de gelecekte ayrı cevaplar göndermeyi düşünmelisiniz
sehe

1
Çok teşekkürler @sehe! Bir bulacaksınız tam hazır çalıştırmak orada bash kaynak dosyası: ELAP-bash-v3 (whith şeffaf kullanımına izin gibi bazı özellik STDIN ve STDERR )
F. Hauri

1
Bash'ın son sürümlerinde (> = 4.1), exec {BASH_XTRACEFD}>bunun yerine exec 3>&2 2>günlük dosyasını yalnızca izleme günlüğü çıktısıyla dolduracak ve diğer stderr çıktılarıyla doldurmayacaksınız.
ws_e_c421

1
Tek bir tarih işlem yöntemini yürütmek çok zekice ve benim tercihim saniyenin altında hassasiyet. Çünkü profilleme verilerini değiştirmeden script.shyapabilir bash -c "exec {BASH_XTRACEFD}> >(tee trace.log | sed -u 's/^.*$//' | date -f - +%s.%N > timing.log); set -x; . script.shve alabilirim script.sh. Saniyenin altında hassasiyet gerekmediğinde, bash -c "exec {BASH_XTRACEFD}>trace.log; set -x; PS4='+\t'; . script.shher izleme satırını hangi zamanın ikinci hassasiyetle ve bugüne kadar çatallama olmadan (düşük genel gider) damgaladığını seviyorum .
ws_e_c421

17

Genellikle sistem çağrılarının izlenmesine yardımcı olur

strace -c -f ./script.sh

Kılavuzdan:

-c Her sistem çağrısı için zamanı, çağrıları ve hataları sayın ve programdan çıkıldığında bir özet rapor edin.

-f Alt işlemleri izle ...

Bu tam olarak istediğiniz şey ve hat odaklı bir profil oluşturucunun size göstereceği şey değildir, ancak genellikle sıcak noktaları bulmaya yardımcı olur.


5

DEBUG koşulu trapile komuta göz atabilirsiniz . Komutlarınızla birlikte yürütülecek bir komut (lar) belirlemenin bir yolu vardır. Cevabın notlarına bakın.


@Dennis Williamson: Bir süredir kullanmadım, ancak sistemimdeki yardım "Eğer bir SIGNAL_SPEC DEBUG ise, ARG her basit komuttan sonra çalıştırılır."

Bash 4.0.33'ten help trap: "SIGNAL_SPEC, DEBUG ise, ARG her basit komuttan önce çalıştırılır." Bash 3.2'de "sonra" yazmaktadır. Bu bir yazım hatası. Bash 2.05b'den itibaren, daha önce çalıştırılmıştır. Referans : "Bu belge, bu sürüm, bash-2.05b-alpha1 ve önceki sürüm olan bash-2.05a-release arasındaki değişikliklerin ayrıntılarını verir. ... 3. Bash'deki Yeni Özellikler ... w. DEBUG tuzağı artık çalıştırmak önce basit komutlar, ((...)) komutları, [[...]] koşullu komutları ve için ((...)) döngüler." Her sürümde yapılan testler, daha önce olduğunu doğrular .
sonraki duyuruya kadar duraklatıldı.

@Dennis Williamson: Tamam, o zaman benim sahip olduğum versiyon bu. Cevabı düzelttim :)

0

Time, xtrace, bash -x set -xve set+x( http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html ) bir komut dosyasında hata ayıklamanın geleneksel yolu olmaya devam etmektedir.

Ufkumuzu genişletmeyi asla söylemeden, her zamanki Linux programları için mevcut olan hata ayıklama ve profilleme için bazı sistemlere bir kontrol vermek mümkündür [burada listelerden biri] , örneğin, valgrind'e dayalı olarak özellikle hata ayıklamak için veya sysprof profil için yararlı bir sonuç vermelidir tüm sistem:

Sysprof için:

Sysprof ile, çok iş parçacıklı veya çok işlemcili bir uygulama dahil olmak üzere, makinenizde çalışan tüm uygulamaların profilini çıkarabilirsiniz ...

Ve sonra ilginç bulduğunuz alt işlemlerin dalını seçin.


Valgrind için:
Biraz daha spor salonuyla, genellikle ikiliden yüklediğimiz bazı programları (örneğin OpenOffice ) Valgrind'e görünür kılmak mümkün görünüyor .

Bu okuma mümkündür valgrind ait SSSValgrind profil olacak çocuk süreçlerini explicitely istenirse.

... Varsayılan olarak profiller yalnızca üst düzey süreci izler ve bu nedenle , programınız bir kabuk betiği , Perl betiği veya benzer bir şeyle başlatılırsa , Valgrind kabuğu veya Perl yorumlayıcısı veya eşdeğerini izler. ..

Bu seçenek etkinleştirildiğinde yapacak

 --trace-children=yes 

Ek Referanslar:


1
Olumsuz oy veren değil, ancak bu ipuçlarının çoğu havalı olsa da, burada gerçekten alakalı değil. Uygun bir soru sormak ve kendi kendine cevap vermek burada daha hoş karşılanır - Google, ilgili görgü kuralları için "stackoverflow self Answers".
Blaisorblade

0

Alan Hargreaves tarafından yazılan bu gönderi , DTrace sağlayıcısını kullanarak Bourne kabuğu betiğini profilleme yöntemini açıklıyor. Bildiğim kadarıyla bu Solaris ve OpenSolaris ile çalışıyor (bakınız: / bin / sh DTrace Provider ).

Aşağıdaki dtrace betiği verildiğinde ( orijinalish_flowtime.d temel alan GH'de ):

#!/usr/sbin/dtrace -Zs
#pragma D option quiet
#pragma D option switchrate=10

dtrace:::BEGIN
{
        depth = 0;
        printf("%s %-20s  %-22s   %s %s\n", "C", "TIME", "FILE", "DELTA(us)", "NAME");
}

sh*:::function-entry
{
        depth++;
        printf("%d %-20Y  %-22s %*s-> %s\n", cpu, walltimestamp,
            basename(copyinstr(arg0)), depth*2, "", copyinstr(arg1));
}

sh*:::function-return
{
        printf("%d %-20Y  %-22s %*s<- %s\n", cpu, walltimestamp,
            basename(copyinstr(arg0)), depth*2, "", copyinstr(arg1));
        depth--;
}

sh*:::builtin-entry
{
        printf("%d %-20Y  %-22s %*s   > %s\n", cpu, walltimestamp,
            basename(copyinstr(arg0)), depth*2, "", copyinstr(arg1));
}

sh*:::command-entry
{
        printf("%d %-20Y  %-22s %*s   | %s\n", cpu, walltimestamp,
            basename(copyinstr(arg0)), depth*2, "", copyinstr(arg1));
}

delta süreleri dahil işlev akışını izleyebilirsiniz.

Örnek çıktı:

# ./sh_flowtime.d
C TIME                  FILE                 DELTA(us)  -- NAME
0 2007 Aug 10 18:52:51  func_abc.sh                  0   -> func_a
0 2007 Aug 10 18:52:51  func_abc.sh                 54      > echo
0 2007 Aug 10 18:52:52  func_abc.sh            1022880      | sleep
0 2007 Aug 10 18:52:52  func_abc.sh                 34     -> func_b
0 2007 Aug 10 18:52:52  func_abc.sh                 44        > echo
0 2007 Aug 10 18:52:53  func_abc.sh            1029963        | sleep
0 2007 Aug 10 18:52:53  func_abc.sh                 44       -> func_c
0 2007 Aug 10 18:52:53  func_abc.sh                 43          > echo
0 2007 Aug 10 18:52:54  func_abc.sh            1029863          | sleep
0 2007 Aug 10 18:52:54  func_abc.sh                 33       <- func_c
0 2007 Aug 10 18:52:54  func_abc.sh                 14     <- func_b
0 2007 Aug 10 18:52:54  func_abc.sh                  7   <- func_a

Ardından sort -nrk7komutu kullanarak , en çok tüketen çağrıları göstermek için çıktıyı sıralayabilirsiniz.

Diğer mermiler için mevcut olan herhangi bir sağlayıcı sondasının farkında değilim, bu yüzden biraz araştırma yapın (GitHub araması?) Veya biraz zaman ayırmak isterseniz, mevcut sh örneğine göre böyle yazabilirsiniz : (bkz: sh nasıl etkinleştirilir DTrace Sağlayıcısı? ).

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.