Performance shell脚本的性能分析工具
我正在尝试加速一组调用子shell并执行各种操作的脚本。我想知道是否有任何工具可用于计算shell脚本及其嵌套shell的执行时间,并报告脚本的哪些部分最昂贵 例如,如果我有如下脚本Performance shell脚本的性能分析工具,performance,bash,Performance,Bash,我正在尝试加速一组调用子shell并执行各种操作的脚本。我想知道是否有任何工具可用于计算shell脚本及其嵌套shell的执行时间,并报告脚本的哪些部分最昂贵 例如,如果我有如下脚本 #!/bin/bash echo "hello" echo $(date) echo "goodbye" 我想知道这三行每行花了多长时间时间只会给我脚本的总时间bash-x很有趣,但不包括时间戳或其他计时信息。我不知道有任何shell分析工具 历史上,人们只是用Perl、Python、Ruby甚至C重写速度太慢
#!/bin/bash
echo "hello"
echo $(date)
echo "goodbye"
我想知道这三行每行花了多长时间<代码>时间只会给我脚本的总时间
bash-x很有趣,但不包括时间戳或其他计时信息。我不知道有任何shell分析工具
历史上,人们只是用Perl、Python、Ruby甚至C重写速度太慢的shell脚本
一个不那么激烈的想法是使用比bash更快的shell。和适用于所有Unix风格的系统,通常更小、更快。听起来您希望为每个回声计时。如果echo是你所做的全部,那么这很容易
alias echo='time echo'
如果您正在运行其他命令,这显然是不够的。您可以通过管道将在-x
下运行的输出传输到接收到的每一行的时间戳。例如,来自djb的tai64n
。
举个基本的例子
sh -x slow.sh 2>&1 | tai64n | tai64nlocal
这将stdout和stderr混为一谈,但它确实为所有内容都提供了一个时间戳。
然后,您必须分析输出以找到昂贵的行,并将其与源关联起来
您也可能会发现使用strace
很有帮助。比如说,
strace -f -ttt -T -o /tmp/analysis.txt slow.sh
这将生成一个非常详细的报告,在/tmp/analysis.txt
中包含大量的计时信息,但是在每个系统调用级别,这可能太详细了。您可以设置PS4
以显示时间和行号。这样做不需要安装任何实用程序,也不需要将stderr重定向到stdout
对于此脚本:
#!/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
输出如下所示:
+ 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
这假设GNU日期,但您可以将输出规范更改为您喜欢的任何内容或与您使用的日期版本匹配的任何内容
注意:如果您有一个现有的脚本,希望在不修改它的情况下执行此操作,则可以执行以下操作:
PS4='+ $(date "+%s.%N ($LINENO) ")' bash -x scriptname
在即将到来的bash5中,您将能够保存forkingdate
(但是您得到的是微秒而不是纳秒):
更新
请参阅中的启用\u探查器/禁用\u探查器
这就是我现在用的。我还没有在所有版本的BASH上进行测试&特别是,如果您安装了ts
实用程序,它可以以较低的开销工作得很好
古老的
我喜欢的方法如下。原因是它也支持OSX(它没有高精度的日期)&即使没有安装bc也可以运行
#!/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
PROFILE_HIGH_PRECISION=y
else
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="$(_profiler_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"
}
抄袭自:
由于我至少两次来到这里,我实施了一个解决方案:
它运行脚本,透明地对所有打印的行进行计时,并在最后打印屏幕上最长的前10行列表:
~/s/shellprof (master|✔) $ ./shellprof ./testcase.sh
quick
slow
quick
Timings for printed lines:
1.01s: slow
0.00s: <<<PROGRAM START>>>
0.00s: quick
0.00s: quick
~/s/shellprof (master|✔) $
~/s/shellprof(主程序)|✔) $ ./shellprof./testcase.sh
快的
缓慢的
快的
打印行的计时:
1.01s:慢
0.00s:
0.00s:快速
0.00s:快速
~/s/shellprof(硕士)|✔) $
这里有一个简单的方法,几乎可以在所有Unix上使用,不需要特殊的软件:
- 启用外壳跟踪,例如使用
set-x
- 通过记录器对脚本的输出进行管道传输:
这将把输出写入syslog,syslog会自动为每条消息添加一个时间戳
journalctl -o short-monotonic _COMM=logger
许多传统的syslog守护进程也提供高精度的时间戳(对于shell脚本,毫秒应该足够了)
下面是一个脚本示例,我刚刚以这种方式分析了该脚本:
[1940949.100362] bremer root[16404]: + zcat /boot/symvers-5.3.18-57-default.gz
[1940949.111138] bremer root[16404]: + '[' -e /var/tmp/weak-modules2.OmYvUn/symvers-5.3.18-57-default ']'
[1940949.111315] bremer root[16404]: + args=(-E $tmpdir/symvers-$krel)
[1940949.111484] bremer root[16404]: ++ /usr/sbin/depmod -b / -ae -E /var/tmp/weak-modules2.OmYvUn/symvers-5.3.18-57-default 5.3.18-57>
[1940952.455272] bremer root[16404]: + output=
[1940952.455738] bremer root[16404]: + status=0
您可以看到“depmod”命令占用了很多时间。您可以为每个命令设置时间,如time echo“hello”
@ajreal,这是一个有效的答案,你为什么不发布它?但是你怎么知道它很慢,或者如果你不能分析,那么更快的shell会提高性能,所以不知道瓶颈在哪里?这也是一个很好的答案!我更喜欢第一个,因为我不需要找到任何其他包,但这很好,你不需要修改您正在评测的脚本。谢谢!我用它来查找脚本中最慢的一行:Bash builtintime
将为您执行此操作。请注意,在安装了bc
的msys
下,此脚本增加了大约300毫秒的开销(大约150毫秒调用which&&date | grep
,150毫秒调用echo | bc | sed
)。在WSL下,开销下降到大约5毫秒。这一差异是通过在同一个命令上调用time
来衡量的。@Pauseduntilfurthernotice。您对如何实际应用这一点有什么建议吗?关键是启用它,以便您可以看到每个命令执行多长时间后出现减速。AFAIKtime
将要求您手动注释每个步骤。@Johann,这是正确的。msys/cygwin的bash性能很差,因为在Windows上使用win32 API生成可执行文件的开销比在Linux上大得多。在WSL上,您的性能会下降到合理的水平,因为WSL直接使用NT内核,而不是坐在Win3上2所以它绕过了这个开销。注意#!/bin/bash-x
顶部的-x
很重要我爱你,你愿意嫁给我吗?为了胜利,再次堆叠溢出!
journalctl -o short-monotonic _COMM=logger
[1940949.100362] bremer root[16404]: + zcat /boot/symvers-5.3.18-57-default.gz
[1940949.111138] bremer root[16404]: + '[' -e /var/tmp/weak-modules2.OmYvUn/symvers-5.3.18-57-default ']'
[1940949.111315] bremer root[16404]: + args=(-E $tmpdir/symvers-$krel)
[1940949.111484] bremer root[16404]: ++ /usr/sbin/depmod -b / -ae -E /var/tmp/weak-modules2.OmYvUn/symvers-5.3.18-57-default 5.3.18-57>
[1940952.455272] bremer root[16404]: + output=
[1940952.455738] bremer root[16404]: + status=0