Как профилировать медленный запуск скрипта оболочки bash?


моя оболочка bash занимает до 3-4 секунд, чтобы начать, а если я начну с --norc Он сразу бежит.

Я начал "профайлинг" /etc/bash.bashrc и ~/.bashrc вручную вставлять return заявления и ищет улучшения скорости, но это не количественный процесс, и это не эффективно.

как я могу профилировать свои сценарии bash и посмотреть, какие команды занимают больше всего времени для запуска?

6 96

6 ответов:

если у вас есть GNU date (или другая версия, которая может выводить наносекунды), сделайте это в начале /etc/bash.bashrc (или там, где вы хотите начать трассировку в любом скрипте Bash):

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

добавить

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

в конце ~/.bashrc (или в конце раздела любого сценария Bash, который вы хотите остановить).

вы должны получить трассировки в /tmp/bashstart.PID.log это показывает секунды.наносекундная метка времени каждой выполненной команды. Отличие от один раз к следующему - это количество времени, которое занял промежуточный шаг.

как вы сужаете вещи вниз, вы можете двигаться set -x позже set +x ранее (или скобка несколько разделов, представляющих интерес выборочно).

профилирования Баш (4 ответов)

Редактировать: Март 2016 добавить script метод

читать это и потому что профилирования это важный шаг, я сделал некоторые тесты и исследования по всему этому вопросу SO и уже опубликовал ответы.

есть 4+ Ответ:

  • первый основан на идее @DennisWilliamson, но с гораздо меньшим ресурсом потребление
  • второй был мой собственный (до этого;)
  • третий основан на ответе @fgm, но более точном.
  • последнее использование script,scriptreplay и файл времени.

  • наконец, небольшое сравнение выступлений в конце.

используя set -x и date но с ограниченным вилки

взять из идеи @ DennisWilliamson, но при следующем синтаксисе будет только одна начальная вилка для 3 команд:

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

делать это будет работать date только один раз. Существует быстрая демонстрация / тест, чтобы показать, как это работает:

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

сценарий:

#!/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>&-

запустив этот скрипт, вы создадите 2 файла:/tmp/sample-XXXX.log и /tmp/sample-XXXX.tim (где XXXX-идентификатор процесса запущенного скрипта).

вы можете представить их с помощью paste:

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

или вы даже можете вычислить разница времени:

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

или по двум столбцам:

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

May render:

 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

используя trap debug и /proc/timer_list on последние ядра GNU/Linux,безвилки.

под GNU / Linuxпоследние ядра, вы можете найти /proc файл с именем timer_list:

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

где текущее время-это сумма 5461935212966259 + 1383718821564493249, но в наносекундах.

так для вычисление времени, нет необходимости знать смещение.

для такого рода работ я написал elap.Баш (В2), которые будут получены с помощью следующего синтаксиса:

source elap.bash-v2

или

. elap.bash-v2 init

(полный синтаксис см. В комментариях)

так что вы могли бы просто добавить эту строку в верхней части вашего скрипта:

. elap.bash-v2 trap2

маленький пример:

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

сделать рендер на моем ведущий:

 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

используя trap2 вместо trap в качестве аргумента команды источник:

#!/bin/bash

. elap.bash-v2 trap2
...

будет отображаться две колонки последняя команда и общей сумме:

 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

используя strace

да strace может сделать работу:

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

но там можно было бы сделать много вещей!

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

используя более ограниченную команду:

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

свалка будет легче журнал:

  4519  36695 374453 sample-script-strace.log

в зависимости от того, что вы ищете, вы можете быть более строгими:

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

читать их будет немного сложнее:

{
    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) ---

оригинал bash script - это не так легко следовать в этом...

используя script,scriptreplay и файл времени

в рамках BSD Utils,scriptscriptreplay) - это очень старый инструмент, который можно использовать для профилирования Баш, с очень маленьким следом ноги.

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
"'

будет:

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

и создать два файла:

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

File script.log содержат все следы и script.tim - это файл времени:

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

вы можете увидеть общее время выполнения с первой и последней строками файла журнала и / или суммируя время в файле синхронизации:

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

в файле синхронизации второе значение-это количество следующих байтов в соответствующем файл журнала. Это позволит вам способность воспроизведение файл журнала дополнительно с Ан ускорение-фактор:

scriptreplay script.{tim,log}

или

scriptreplay script.{tim,log} 5

или

 scriptreplay script.{tim,log} .2

отображение времени и команд бок о бок тоже немного сложнее:

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

тесты и заключение

чтобы сделать тесты, я скачал второй пример Баш комплекса Привет, мир, этот сценарий занимает около 0,72 секунды, чтобы завершить на моем хосте.

я добавил в верхней части сценария один из:

  • by elap.bash функции

    #!/bin/bash
    
    source elap.bash-v2 trap2
    
    eval "BUNCHS=(" $(perl <<EOF | gunzip
    ...
    
  • by set -x и PS4

    #!/bin/bash
    
    PS4='+ $(date "+%s.%N")1 '
    exec 3>&2 2>/tmp/bashstart.$$.log
    set -x
    
    eval "BUNCHS=(" $(perl <<EOF | gunzip
    ...
    
  • by set -x и начальная вилка для длинной команды exec

    #!/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
    
  • by scriptset +x)

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

времени

и сравнить время выполнения (на моем хосте):

  • прямые 0.72 сек
  • elap.Баш 13.18 сек
  • set + date@PS4 54.61 сек
  • установить + 1 вилка 1.45 сек
  • сценарий и файл времени 2.19 сек
  • strace 4.47 сек

выходы

  • by elap.bash функции

         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))
    
  • by set -x и PS4

    ++ 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 -x и начальная вилка для длинной команды exec (и мое второе paste пример скрипта)

     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=
    
  • by 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)         = ?
    
  • by 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
    

вывод

хорошо! Если мой чисто Баш быстрее разветвление на сегодняшний день по каждой команде, Мой чистый bash подразумевает некоторые операции по каждой команде.

способ выделения независимого процесса для регистрации и хранения явно более эффективным.

strace это интересный способ, более подробный, но трудно читать.

script С scriptreplay и фактор ускорения тоже очень хорош, а не такая же точность, как это основано на обмене консолями вместо процесса исполнение, но очень легкое и эффективное (не та же цель, не то же использование).

наконец, я думаю, что более эффективным, в удобочитаемости и производительности является set + 1 fork, первый из этого ответа, но в порядке, в зависимости от конкретного случая, я использую когда-нибудь strace и/или screen тоже.

это часто помогает отслеживать системные вызовы

strace -c -f ./script.sh

из руководства:

- C подсчитайте время, вызовы и ошибки для каждого системного вызова и сообщите сводку о выходе из программы.

-Ф отслеживать дочерние процессы ...

Это не совсем то, что вы хотите, и что линейно-ориентированный профилировщик покажет вам, но обычно это помогает найти горячие точки.

вы можете посмотреть с DEBUG состояние. Существует способ установить команды, которые будут выполняться вместе с вашими командами. См. примечания к ответу.

этой post by Алан Харгривз описывает метод профилирования сценария оболочки Bourne с помощью поставщика DTrace. Насколько я знаю, это работает с Solaris и OpenSolaris (см.: /bin/sh DTrace Provider).

Итак, учитывая следующий сценарий dtrace (sh_flowtime.d в GH на основе оригинал):

#!/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));
}

вы можете отслеживать поток функций, включая Дельта-время.

образец вывод:

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

затем с помощью sort -nrk7 команда, вы можете сортировать выходные данные, чтобы показать наиболее потребляющие вызовы.

Я не знаю о каких-либо зондах провайдера, доступных для других оболочек, поэтому сделайте некоторые исследования (поиск GitHub?) или если вы хотите инвестировать некоторое время, вы можете написать такое на основе существующего ш например: (см.: как активировать SH DTrace провайдера?).

время, xtrace, bash-x,set -x и set+x (http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html) остается ортодоксальным способом отладки скрипта.

тем не менее, чтобы расширить наш горизонт, можно проверить некоторые системы для отладки и профилирования, доступные для обычных программ Linux [вот один из списков], например, это должно привести к полезному на основе отчет специально для отладки памяти или sysprof для профилирования всей системы:

для sysprof:

С помощью sysprof вы можете профилировать все приложения, запущенные на вашем компьютере, включая многопоточное или многопроцессорное приложение...

а после выбрать ветку подпроцессов, которые вам покажутся интересными.


Для Valgrind:
С еще одним тренажерным залом, кажется, можно сделать видимого для Valgrind некоторые программы, которые обычно мы устанавливаем из двоичного файла (например OpenOffice).

Это можно прочитать из часто задаваемые вопросы из Valgrind это Valgrind будет профиль дочерние процессы при явном запросе.

... Даже если по умолчанию он профилирует только трассировку процесса верхнего уровня, и так, если ваша программа запускается shell-скрипт, Perl скрипт, или что-то аналогично, Valgrind будет отслеживать оболочку, или интерпретатор Perl, или эквивалент...

Он будет делать с этой включенной опцией

 --trace-children=yes 

Дополнительные Ссылки: