记录线程事件

Posted

技术标签:

【中文标题】记录线程事件【英文标题】:Record thread events 【发布时间】:2012-04-22 12:10:29 【问题描述】:

假设我需要定期查看一个线程的状态,并在整个程序执行过程中记录它的状态。我不知道如何开始思考这个问题。任何指针(双关语?)?我在 Linux 上,使用 gccphreadsC 并且可以访问所有常用的 Linux 工具。基本上,我想我问的是如何为线程构建一个简单的分析器,它会告诉我在程序执行期间线程处于某种或其他状态的时间。

我希望能够像 Threadscope 那样创建图表。 X 轴是时间,Y 轴是核心/线程数,“颜色”是状态:绿色表示正在运行,橙色表示垃圾收集,依此类推。这现在更有意义了吗?

【问题讨论】:

提示:您将如何在单线程应用程序中执行此操作? @goldilocks:我想printf 像疯了一样去控制台,但除非我在每个线程上将fprintf 放到一个单独的文件中,否则这是行不通的。我想我是从外面做的。 如果您担心报告被交错,那么“从外部”这样做会如何改变任何事情?此外,您可能会发现交错报告更具启发性。顺便说一句:printf/stdout 被缓冲。如果你想要实时控制台输出,你应该使用 fprintf(stderr)。 @goldilocks:问题是,我不想为我编写的每个程序都这样做,我想要一个通用的解决方案......虽然我知道在这里,无论我做什么,它可能不会便携。我只需要了解如何去做。 【参考方案1】:

对于 Linux 特定的解决方案,您可能想分别查看 /proc/<pid>/stat/proc/<pid>/task/<tid>/stat 的进程和线程统计信息。查看proc(5) 手册页,了解那里所有字段的完整描述(在线http://man7.org/linux/man-pages/man5/proc.5.html - 搜索/proc/[pid]/stat)。具体来说,至少 cutimestime 字段是您感兴趣的。这些是单调递增的时间,因此您需要记住先前测量的值,以便能够生成在给定时间片内进程/线程中花费的时间,以便为您的图表生成数据。 (这就是top(1) 的工作原理。)

但是,对于分析器来说,区分不同的状态会使问题变得更加复杂。分析器如何区分被分析的程序处于哪个状态?在我看来,被分析的程序线程需要以某种方式向分析器发出信号。您需要为这种状态共享提供某种量身定制的解决方案(除非您可以在不同的线程中运行不同的状态并以这种方式进行区分,我对此表示怀疑)。

如果状态转换在单个位置完成(例如,在您的示例中 enter GCleave GC),那么一种方法如下:

    被监控的线程将通过使用POSIX函数clock_gettime()获取特殊状态的开始和结束时间 - 使用clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp)可以获得进程时间,使用clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)可以获得线程时间(两者都是单调递增的) , 再次)。 线程可以通过某种 IPC 将这些时间传递给探查器程序。 如果分析器应用程序知道进入和离开状态的线程时间,那么因为它知道测量切片变化时的线程时间值,它可以确定在一个报告的状态中花费了多少线程时间报告时间片(当然这里我们需要调整一个状态的开始时间以等于下一个报告时间片的开始)。 整个进程在特定状态上花费的时间可以通过对该状态的线程时间求和来计算。

注意,通过/proc/<pid>/stat/proc/<pid>/task/<tid>/stat,测量精度不是很好(时钟滴答,通常以10ms为单位),但我不知道从进程/线程外部获取计时信息的其他方式。函数clock_gettime() 给出了非常准确的时间(名义上为纳秒精度,但请注意,至少在某些 MIPS 和 ARM 系统中,精度与/proc 下的stat 文件一样糟糕,因为不存在对Linux 内核中的这些字段)。您还需要进行一些实验以确保这两个计时源确实会给出相同的结果(通过从同一线程读取两个值)。你当然可以在线程中使用这些/proc/.../stat 文件,但是除非你在一个状态中花费大量时间,否则准确性不是很好。

【讨论】:

【参考方案2】:

嗯,与由 haskell 编译器生成并由 Threadscope 处理的分析信息的直接匹配是,使用 C 和 GCC,gprof 实用程序(它是 GNU binutils 的一部分)。

要让它与 pthread 一起正常工作,您需要每个线程触发一些计时器初始化函数。这可以在不使用此 pthreads 包装库修改代码的情况下完成:http://sam.zoy.org/writings/programming/gprof.html。我最近没有处理过这个问题,可能是有些东西发生了变化,不再需要包装器了......

至于解释分析结果的 GUI,有 kprof (http://kprof.sourceforge.net)。不幸的是,AFAIK 它不会生成线程持续时间图,因为您必须使用 gprof 生成的文本信息来处理您自己的解决方案。

如果您对使用 GCC 提供的“标准”解决方案不挑剔,您可能想试试这个:http://code.google.com/p/gperftools/?redir=1(没有亲自尝试,但听到了很好的意见)。

祝你好运!

【讨论】:

【参考方案3】:

看看Intel VTune Amplifier XE(以前的……英特尔线程分析器)看看它是否能满足您的需求。 该工具和其他英特尔 Linux 开发工具可通过 free for non-commercial use 获得。

在视频Using the Timeline in Intel VTune Amplifier XE 显示多线程应用程序的时间线中,主持人在 9:20 提到 “...使用框架 API,您可以在代码中以编程方式标记某些事件或阶段。这些标记将出现在时间轴上。”

【讨论】:

谢谢。试过了。每两分钟挂一次,GUI 很糟糕,命令行以千字节计!无论如何,谢谢。【参考方案4】:

我认为构建一个简单的分析器会相当困难构建一个简单的分析器只是因为您必须考虑许多不同的因素,并且系统分析是一项固有的复杂任务,当您这样做时更是如此分析多线程应用程序。我能想到的最好的建议是看看已经存在的东西,例如OProfile。

OProfile 的一个优点是它是开源的,所以source code is available。但除此之外,我怀疑询问如何构建分析应用程序可能超出了某人可以在 SO 问题中回答的范围,这可能就是为什么这个问题没有得到很多回应的原因。希望看一些示例可以帮助您入门,然后如果您有更集中的问题,您可能会得到一些更详细的答复。

【讨论】:

以上是关于记录线程事件的主要内容,如果未能解决你的问题,请参考以下文章

Qt自己定义事件实现及子线程向主线程传送事件消息

同步异步和Event loop事件循环

事件循环

RunLoop主要处理以下6类事件

[jS 事件循环理解] 主线程 宏任务 微任务 - 执行顺序优先级理解

mysql 主从配置记录