微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何计算进程ID包括所有将来的子线程的已执行指令数 perf:

如何解决如何计算进程ID包括所有将来的子线程的已执行指令数 perf:

有时,我问了以下问题"How to count number of executed instructions of a process id including child processes",@ M-Iduoad友好地提供了一个pgrep解决方案,以捕获所有子PID并将其与-p一起用于性能统计效果很好!

但是,我遇到的一个问题是多线程应用程序以及何时生成新线程。由于我不是算命先生(太糟糕了!),我不知道tid的新生成的线程,因此无法将它们添加perf stat的-p或-t参数。

作为示例,假设我有一个多线程的nodejs服务器(部署为Kubernetes之上的容器),并带有以下pstree

root@node2:/home/m# pstree -p 4037791
node(4037791)─┬─sh(4037824)───node(4037825)─┬─{node}(4037826)
              │                             ├─{node}(4037827)
              │                             ├─{node}(4037828)
              │                             ├─{node}(4037829)
              │                             ├─{node}(4037830)
              │                             └─{node}(4037831)
              ├─{node}(4037805)
              ├─{node}(4037806)
              ├─{node}(4037807)
              ├─{node}(4037808)
              ├─{node}(4037809)
              ├─{node}(4037810)
              ├─{node}(4037811)
              ├─{node}(4037812)
              ├─{node}(4037813)
              └─{node}(4037814) 

当然,我可以使用以下perf stat命令来监视其线程:

perf stat --per-thread -e instructions,cycles,task-clock,cpu-clock,cpu-migrations,context-switches,cache-misses,duration_time -p $(pgrep --ns 4037791 | paste -s -d ",")

它与单线程nodejs应用程序一起正常工作。但是,在多线程服务的情况下,一旦收到请求,pstree输出将如下所示:

root@node2:/home/m# pstree -p 4037791
node(4037791)─┬─sh(4037824)───node(4037825)─┬─{node}(4037826)
              │                             ├─{node}(4037827)
              │                             ├─{node}(4037828)
              │                             ├─{node}(4037829)
              │                             ├─{node}(4037830)
              │                             ├─{node}(4037831)
              │                             ├─{node}(1047898)
              │                             ├─{node}(1047899)
              │                             ├─{node}(1047900)
              │                             ├─{node}(1047901)
              │                             ├─{node}(1047902)
              │                             ├─{node}(1047903)
              │                             ├─{node}(1047904)
              │                             ├─{node}(1047905)
              │                             ├─{node}(1047906)
              │                             ├─{node}(1047907)
              │                             ├─{node}(1047908)
              │                             ├─{node}(1047909)
              │                             ├─{node}(1047910)
              │                             ├─{node}(1047911)
              │                             ├─{node}(1047913)
              │                             ├─{node}(1047914)
              │                             ├─{node}(1047919)
              │                             ├─{node}(1047920)
              │                             ├─{node}(1047921)
              │                             └─{node}(1047922)
              ├─{node}(4037805)
              ├─{node}(4037806)
              ├─{node}(4037807)
              ├─{node}(4037808)
              ├─{node}(4037809)
              ├─{node}(4037810)
              ├─{node}(4037811)
              ├─{node}(4037812)
              ├─{node}(4037813)
              └─{node}(4037814)

因此,我之前的perf stat命令不会捕获新生成的线程的统计信息。我的意思是,它可能会捕获累积的指令,但绝对不会以“每线程”格式显示

有什么方法可以在性能统计中使用--per-thread并捕获多线程应用程序中新产生的线程的状态?似乎只能与-p-t一起使用,以遵循perf启动时已经存在的固定线程集,而不会遵循新的线程。


一个类似的question here for perf record,但我正在使用perf stat。另外,这似乎并没有按线程分开记录的概要文件,所以它等效于perf stat node ...,除非有一种处理记录的数据的方法,以便事后将其按线程分开?


如果还有其他可行的方法,则不需要

perf

任何其他可能帮助我动态计算给定PID的每个线程(包括生成的线程)的“指令,周期,任务时钟,cpu时钟,cpu迁移,上下文切换,缓存丢失”的潜在解决方案是可接受,无论使用perf还是其他任何方法

解决方法

perf record -sperf report -T的组合应该可以为您提供所需的信息。

为了演示,请使用以下具有良好定义的指令数的线程作为示例代码:

#include <cstdint>
#include <thread>

void work(int64_t count) {
    for (int64_t i = 0; i < count; i++);
}

int main() {
    std::thread first(work,100000000ll);
    std::thread second(work,400000000ll);
    std::thread third(work,800000000ll);
    first.join();
    second.join();
    third.join();
}

(无需优化即可编译!)

现在,使用perf record作为前缀命令。它将遵循所有产生的进程和线程。

$ perf record -s -e instructions -c 1000000000 ./a.out
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.003 MB perf.data (5 samples) ]

要很好地显示统计信息:

$ perf report -T
[... snip ...]
#    PID     TID  instructions:u
  270682  270683       500003888
  270682  270684      2000001866
  270682  270685      4000002177

perf record的参数有些棘手。 -s用准确的数字写单独的记录-它们不依赖于指令样本(每1000000000条指令生成)。但是,perf report甚至找不到-T时也会失败,因为它找不到单个样本。因此,您需要设置至少触发一次的指令样本计数-c(或频率)。任何示例都可以,每个线程都不需要示例。

或者,您可以查看perf.data中的原始记录。然后,您实际上可以告诉perf record不要收集任何个样本。

$ perf record -s -e instructions -n ./a.out             
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.003 MB perf.data ]

但是您需要过滤掉相关记录,并且可能需要汇总其他记录。

$ perf script -D | grep PERF_RECORD_READ | grep -v " 0$"
# Annotation by me                              PID    TID 
213962455637481 0x760 [0x40]: PERF_RECORD_READ: 270887 270888 instructions:u 500003881
213963194850657 0x890 [0x40]: PERF_RECORD_READ: 270887 270889 instructions:u 2000001874
213964190418415 0x9c0 [0x40]: PERF_RECORD_READ: 270887 270890 instructions:u 4000002175

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。