通过其子进程分析一个进程并在之后杀死该子进程

Posted

技术标签:

【中文标题】通过其子进程分析一个进程并在之后杀死该子进程【英文标题】:Profile a process via its child and kill the child afterwards 【发布时间】:2018-06-08 08:47:16 【问题描述】:

我正在尝试找出一种方法来通过其子进程在 C 进程中进行概要分析,然后父进程会杀死其子进程以停止概要分析。我正在使用 perf 来分析我的应用程序。 perf 将在被杀死时将其结果输出到文件中。在 bash 脚本中看起来像这样:

./run &
perf stat -o perf.data -p <pid_run> &
kill -9 <pid_perf>

到目前为止我做了什么:

 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>

 static pid_t perf_id;

 void start() 
   char *filename="test_data";
   char ppid_str[24];

   pid_t pid = fork();
   if (pid == 0)

      pid_t ppid = getppid();
      sprintf(ppid_str, "%d",ppid);
      char *args[] = "/usr/bin/perf", "stat","-p",ppid_str,"-o", filename, NULL;
      execvp(args[0], args);
   
   else 

      perf_id = pid
   


void stop() 
  kill(perf_id,SIGKILL);

我在获取 perf 的输出时遇到问题。 这是一个可以运行父进程的代码示例:

int main() 
    start();
    int a = 0;
    a+=1;
    stop();
    // ... // There are other instructions after the stop
    return 0;
 

运行此代码时,我没有从 perf 获得任何输出。我必须杀死父进程才能获得输出。

如果我在杀死子进程之前调用睡眠,那么程序将输出一个空文件。

编辑:

stat 参数是我命令中的一个示例,我也想使用 record 参数 正如祖蓝所说,如果我使用SIGINT而不是SIGKILL,我会得到一个输出,但只有主进程休眠1秒才能得到一个。

【问题讨论】:

您应该使用您的代码获得的结果来编辑您的问题。不过,这似乎是一个合理的问题,不明白为什么它被否决了 感谢@Mean-Street,会这样做的! 您可以通过确保代码是正确的minimal reproducible example 来进一步改进您的问题(提示:添加#includes 并检查语法错误)。 【参考方案1】:

您应该发送 SIGINT 而不是 SIGKILL 以允许 perf 干净地关闭并生成有效的输出文件。 perf 子进程和主进程之间的同步仍然不完美 - 因此,如果主进程不像您的示例那样花费大量时间,则很可能根本没有生成任何输出文件。这也会影响所收集数据的准确性。使用perf 作为子进程而不是相反的设置,您无法真正改进它。

【讨论】:

感谢@Zulan。输出中的 SIGINT 和 SIGKILL 之间存在差异。但在这两种方式中,我都需要让父进程休眠以获得输出。此外,当我查看有效输出时,指标也不正确。您是否想到了另一种分析我的主要流程的方法? 正如我所说,您的主进程必须在startstop 之间花费一些时间,这样perf 才能正确初始化。通常你在perf script ./example 以相反的方式运行你的程序作为一个孩子——这在时间方面更容易得到正确的结果。你有理由不这样做吗? 我正在尝试仅分析部分代码。但在我的例子中你是对的,它是整个程序,所以它相当于另一种方式。 startstop 之后的usleep(1000) 对于perf 的实用解决方案来说并不是最糟糕的想法。【参考方案2】:

问题在于 perf 将自身附加到进程,然后等待进程终止以打印计数器。尝试添加例如

-I msec 

执行选项,如 -I 1000 以每 1 秒打印一次计数器。 将您的 args 更改为 execvp 到

char *args[] = "/usr/bin/perf", "stat", "-p",ppid_str,"-o", filename, "-I", "1000", NULL;

和你的公司进入类似的循环

while (a < 10) 
    a += 1;
    sleep(1);

虽然在这种方法中文件未正确关闭(),但仍会产生结果。 我会创建一个小的二进制文件,它会在超时的情况下执行 perf,然后优雅地关闭文件并从子进程中运行它。

【讨论】:

感谢@ramrunner,它在您的示例中有效。 -I 的问题在于它取决于命令 stat。我可以使用记录。另外,如果间隔太小,我不想在我的程序中增加那么多开销。如果它太长,我将有一个空输出。 当然,我不同意你的观点,或者说这是从你的流程中获取指标的正确方法,我只是想回答为什么你没有得到任何输出的问题;) .祝你的分析顺利。

以上是关于通过其子进程分析一个进程并在之后杀死该子进程的主要内容,如果未能解决你的问题,请参考以下文章

创建一个不是创建进程子进程的新进程

golang 热重启

如何在Go代码超时时杀死进程及其子进程?

Linux学习-进程管理

杀死父进程后将标准输入传递给子进程

关于wait 和 exit