shell - shell 脚本在执行期间执行的 fork 次数

标签 shell fork

有没有办法计算 shell 脚本在执行时执行的 fork 数量?我一直在考虑使用 getrusage(2) 编写 C 包装器并分析

的各个字段
 struct rusage {
         struct timeval ru_utime; /* user time used */
         struct timeval ru_stime; /* system time used */
         long ru_maxrss;          /* max resident set size */
         long ru_ixrss;           /* integral shared text memory size */
         long ru_idrss;           /* integral unshared data size */
         long ru_isrss;           /* integral unshared stack size */
         long ru_minflt;          /* page reclaims */
         long ru_majflt;          /* page faults */
         long ru_nswap;           /* swaps */
         long ru_inblock;         /* block input operations */
         long ru_oublock;         /* block output operations */
         long ru_msgsnd;          /* messages sent */
         long ru_msgrcv;          /* messages received */
         long ru_nsignals;        /* signals received */
         long ru_nvcsw;           /* voluntary context switches */
         long ru_nivcsw;          /* involuntary context switches */
 };

但是这里没有提供 fork 的数量。下一个想法是追踪 shell 和 child 并寻找 fork 。有没有更简单、开销更少的方法?是否有一些带有非标准选项/变量/机制的 shell 可以显示 fork 数量?

最佳答案

有几个选项:

  • 最好的多平台方法可能是 strace或其等效项( trussktrace )或 dtrace 。见下文。这还允许您附加到正在运行的进程。
  • 一种可行但稍微棘手的多平台方法是使用您自己的 fork/execve 版本创建动态库等等,记录调用,然后调用真正的 C 库函数。搜索 LD_PRELOAD得到一些想法。但这不适用于静态链接的二进制文件。
  • 在 Linux 和 Solaris 上,您可以设置环境变量 LD_DEBUG=files ,并且动态链接器将在加载可执行文件和库时发出各种诊断信息,对于这样一个简单的步骤应该很有启发。在 Linux 上,每个新进程都应输出部分或大部分“initialize”、“init”和“fini”条目以及 PID。但这不适用于静态链接的二进制文件。
  • 如果您使用的是 Linux 或 *BSD 或 Solaris,并且具有 root 访问权限,并且进程记帐可用,您可以运行命令,然后检查 lastcomm 的输出或dump-acct 。这可能需要启动记帐(如果尚未运行)。这可能无法提供您在某些平台上所需的详细信息。它可以在 RH/CentOS 6 上轻松完成,并提供所需的所有详细信息。其他系统也有流程核算。
  • 如果您使用的是 Linux 并有 auditd支持您可以使用autrace myscript.sh记录系统调用。 ( auditd 应为此运行,以便内核数据记录到审核文件中)
  • 为了完整性:您可以使用调试器,但这是我能想到的最乏味的方法;-)

在 Linux 上,您可以通过以下方式跟踪执行情况(适度的性能损失):

strace -f -o /tmp/myscript.trace -e trace=process ./myscript.sh

然后检查.trace文件。参数-e trace=process过滤器仅显示与进程相关的系统调用。

在 Solaris 上,您可以使用以下命令进行跟踪:

truss -f -o /tmp/myscript.trace \
  -u libc:fork,execl,execv,execle,execve,execlp,execvp ./myscript.sh

Solaris truss允许您跟踪用户态库和内核系统调用。您还可以使用dtrace ,请参阅此处了解一些想法:http://www.brendangregg.com/DTrace/lostcpu.html

其他平台的变量类似于 LD_DEBUGLD_VERBOSE ,请参阅链接器文档(例如 man ld.so )。

在上述情况下,您应该了解程序(通常)调用的是 C 库函数,例如fork() ,内核的请求至少取决于操作系统,并且可能会导致 vfork系统调用 , execveclone .

关于shell - shell 脚本在执行期间执行的 fork 次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14820869/

相关文章:

linux - 程序快速将数据转储到标准输出。寻找在不被淹没的情况下编写命令的方法

linux - 需要 shell/perl 脚本来屏蔽 Linux 上日志文件中的敏感信息,如名字、出生日期、ssn 等

c - 管道和 fork() - 如何通过 C 中的管道编写 int 数组?

c - 在C中使用printf()和fork()复制输出

在函数中调用 vfork(),对结果感到困惑

linux - bash 脚本杀死竞争条件

python - 如何在单独的进程中运行 shell 并获得自动完成? (Python)

windows - 测试批处理文件中参数是否为空的正确方法是什么?

c - Linux-C : reading from pipe returns first buffer written to it

c - 如何确保父进程先于子进程执行scanf()?