我的bash shell最多需要3-4秒才能启动,而如果我将其启动,--norc
它将立即运行。
我开始进行“概要分析”,/etc/bash.bashrc
并~/.bashrc
通过手动插入return
语句并寻求提高速度来进行,但是这不是一个定量过程,并且效率不高。
我如何配置我的bash脚本并查看哪些命令花费最多的时间来启动?
time bash -c 'exit'
和time bash -i -c 'exit'
和可以玩--norc
和--noprofile
。
我的bash shell最多需要3-4秒才能启动,而如果我将其启动,--norc
它将立即运行。
我开始进行“概要分析”,/etc/bash.bashrc
并~/.bashrc
通过手动插入return
语句并寻求提高速度来进行,但是这不是一个定量过程,并且效率不高。
我如何配置我的bash脚本并查看哪些命令花费最多的时间来启动?
time bash -c 'exit'
和time bash -i -c 'exit'
和可以玩--norc
和--noprofile
。
Answers:
如果您有GNU date
(或其他可以输出纳秒的版本),请在/etc/bash.bashrc
(或任何要在任何Bash脚本中开始跟踪的位置)的开头执行此操作:
PS4='+ $(date "+%s.%N")\011 '
exec 3>&2 2>/tmp/bashstart.$$.log
set -x
加
set +x
exec 2>&3 3>&-
在~/.bashrc
(您希望停止跟踪的任何Bash脚本的末尾)。该\011
是一个八进制制表符。
您应该获得一个跟踪日志,/tmp/bashstart.PID.log
其中显示了已执行的每个命令的seconds.nanoseconds时间戳。一次到下一次的差是干预步骤所花费的时间。
当您缩小范围时,您可以set -x
稍后移动set +x
(或更早)(或有选择地将几个感兴趣的部分放在括号中)。
尽管它的粒度不如GNU date
的纳秒级,但Bash 5包含一个以毫秒为单位给出时间的变量。使用它可以避免为每一行生成外部可执行文件,并且可以在Mac或其他没有GNU的地方使用date
-当然,只要有Bash 5。更改以下设置PS4
:
PS4='+ $EPOCHREALTIME\011 '
如@pawamoy所指出的,BASH_XTRACEFD
如果您具有Bash 4.1或更高版本,则可以用来将跟踪的输出发送到单独的文件描述符。从这个答案:
#!/bin/bash
exec 5> command.txt
BASH_XTRACEFD="5"
echo -n "hello "
set -x
echo -n world
set +x
echo "!"
这将导致跟踪输出转到文件command.txt
离开stdout
并stdout
正常输出(或单独重定向)。
exec
应该使fd2恢复正常,因此您应该会得到提示。
\D{...}
in PS4
可以扩展完全任意时间格式的字符串,而不会date
以子进程启动的性能开销。
date
理解%N
并且Bash 4.2 strftime(3)
在GNU系统上不(因为没有)-因此具有限制。关于性能与分辨率的观点是一个很好的观点,用户应该明智地做出选择,同时要记住,只有在调试期间(并且仅set -x
在生效时),性能下降才是暂时的。
编辑:2016年3月添加script
方法
阅读这篇文章,因为概要分析是重要的一步,因此我对整个SO问题进行了一些测试和研究,并且已经发布了答案。
有4个以上的答案:
最后使用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是正在运行的脚本的进程ID)。
您可以使用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
可能呈现:
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
在最新的 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.bash(V2),该文件由以下语法提供:
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
,scriptreplay
并定时文件作为BSD Utils的一部分,script
(和scriptreplay
)是一个非常古老的工具,可用于分析bash,而且占用空间很小。
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
文件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
为了进行测试,我已经在bash complex hello world下载了第二个示例,该脚本大约需要0.72秒才能在主机上完成。
我在以下脚本之一的顶部添加:
按elap.bash
功能
#!/bin/bash
source elap.bash-v2 trap2
eval "BUNCHS=(" $(perl <<EOF | gunzip
...
由set -x
和PS4
#!/bin/bash
PS4='+ $(date "+%s.%N")\011 '
exec 3>&2 2>/tmp/bashstart.$$.log
set -x
eval "BUNCHS=(" $(perl <<EOF | gunzip
...
通过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
通过script
(和set +x
)
script -t helloworld.log 2>helloworld.tim -c '
bash -x complex_helloworld-2.sh' >/dev/null
并比较执行时间(在我的主机上):
按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))
由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=
通过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=
通过 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) = ?
通过 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比每个命令的最新版本要快,那么我的bash意味着对每个命令进行一些操作。
专门用于记录和存储独立过程的方法显然更有效。
strace
是一种有趣的方式,虽然更详细,但是却很难阅读。
script
,带有 scriptreplay
和加速因子也非常好,与基于控制台交换而不是基于流程执行的精度不同,但非常轻便且高效(目标不同,用法不同)。
最终,我认为更有效,在可读性和表现是set + 1 fork
,首先这个答案,但在精致,视具体情况,我用一段时间strace
和/或script
过。
exec {BASH_XTRACEFD}>
,而不是exec 3>&2 2>
将填充日志文件只跟踪日志输出,而不是其他stderr输出。
script.sh
,我bash -c "exec {BASH_XTRACEFD}> >(tee trace.log | sed -u 's/^.*$//' | date -f - +%s.%N > timing.log); set -x; . script.sh
无需修改就可以获取和分析数据script.sh
。当不需要亚秒精度时,我喜欢bash -c "exec {BASH_XTRACEFD}>trace.log; set -x; PS4='+\t'; . script.sh
用第二个精度并且不分叉地标记每个跟踪行的时间戳(低开销)。
您可以看看trap
带有DEBUG条件的命令。有一种方法可以设置要与您的命令一起执行的命令。请参阅答案注释。
help trap
:“如果SIGNAL_SPEC是DEBUG,则在每个简单命令之前执行ARG。” 在Bash 3.2中,它表示“之后”。这是一个错字。从Bash 2.05b开始,它已经运行过。参考:“该文档详细介绍了此版本bash-2.05b-alpha1和先前版本bash-2.05a-release之间的更改。...3. Bash的新功能... w。DEBUG陷阱现已发布运行之前简单的命令,((...))命令,[[...]]有条件的命令,并为((?))的循环“。在每个版本中进行测试都可以确认之前。
时间,xtrace,bash -x set -x
和set+x
(http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html)仍然是调试脚本的常规方法。
为了扩大我们的视野,可以对某些系统进行检查,以进行常规Linux程序可用的调试和性能分析(此处为列表之一),例如,它应该基于valgrind产生有用的结果,尤其是调试内存或sysprof进行概要分析整个系统:
对于sysprof:
使用sysprof,您可以分析计算机上正在运行的所有应用程序,包括多线程或多进程的应用程序...
然后选择您感兴趣的子流程分支。
对于Valgrind:
随着更多的体育馆,似乎有可能使Valgrind 看到一些我们通常从二进制文件安装的程序(例如OpenOffice)。
如果明确提出要求,可以从valgrind的FAQ中读取该文件,该 Valgrind
文件将描述子进程。
...即使默认情况下,它的配置文件仅跟踪顶层进程,因此,如果您的程序是由Shell脚本,Perl脚本或类似的东西启动的,则Valgrind将跟踪外壳或Perl解释器或等效的东西。 ..
启用此选项将完成此操作
--trace-children=yes
其他参考:
艾伦·哈格里夫斯(Alan Hargreaves)的这篇文章介绍了使用DTrace提供程序对Bourne shell脚本进行性能分析的方法。据我所知,这适用于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示例编写这样的代码:(请参阅:如何激活sh DTrace Provider?)。