pthread_self() 中的 Pthread id 与 dtrace 脚本中的数据不匹配

Posted

技术标签:

【中文标题】pthread_self() 中的 Pthread id 与 dtrace 脚本中的数据不匹配【英文标题】:Pthread id from pthread_self() doesn't match data from dtrace script 【发布时间】:2009-08-26 05:48:43 【问题描述】:

我正在使用来自 here 的 dtrace 脚本来尝试查找 java 程序的线程何时发生上下文切换。

我正在尝试将从脚本收集的数据与从正在运行的程序收集的跟踪数据进行匹配(例如方法进入/退出)。我使用一个简短的 JNI 方法获取正在运行的线程的 pthread id,该方法只返回 pthread_self() 的值。

我遇到的问题是我通过调用 pthread_self() 获得的线程 ID 与我在 dtrace 脚本中获得的任何线程 ID 完全不同。我想知道这是否是因为我错误地调用了 pthread_self() 因为它返回了一个指针,但是很难找到有关 pthread_t 在 mac osx 上实际是什么的信息。

【问题讨论】:

显然您的回答说明了为什么您无法匹配 tidpthread_self(),但我相信下面的解决方案可以解决您试图解决的问题。你能看看吗?谢谢! 【参考方案1】:

所以我会回答我自己的问题,dtrace 中的 curthread 和 tid 变量是内核线程结构的指针值,要获取这些值以将 dtrace 与用户空间线程数据进行比较,我必须创建一个内核扩展来获取用户空间中线程的这些内部值。

一般来说这是一个坏主意,因为它是不可移植的,如果内核被更改,很容易崩溃,并且可能存在安全风险。不幸的是,我还没有找到另一种方法来实现我想要的。

【讨论】:

+1 用于寻找解决方案......如果你能发布它会更好:)【参考方案2】:

来自/usr/include/pthread.h

typedef __darwin_pthread_t pthread_t;

然后来自/usr/include/sys/_types.h:

struct _opaque_pthread_t 
  long __sig;
  struct __darwin_pthread_handler_rec* __cleanup_stack;
  char __opaque[__PTHREAD_SIZE__];
;
typedef struct _opaque_pthread_t* __darwin_pthread_t;

源代码是你的朋友:)

【讨论】:

【参考方案3】:

使用处理用户空间代码的pid 提供程序来做一些更优雅的事情怎么样?

# dtrace -n 'pid$target::pthread_self:return printf("%p", arg1)' -c 'java'
dtrace: description 'pid$target::pthread_self:return ' matched 1 probe
dtrace: pid 87631 has exited
CPU     ID                    FUNCTION:NAME
  0  90705              pthread_self:return 1053a7000
  0  90705              pthread_self:return 1054ad000
  2  90705              pthread_self:return 7fff7b479180
  2  90705              pthread_self:return 7fff7b479180
  2  90705              pthread_self:return 7fff7b479180
  2  90705              pthread_self:return 7fff7b479180
  2  90705              pthread_self:return 7fff7b479180
  4  90705              pthread_self:return 10542a000
  4  90705              pthread_self:return 10542a000

嘘!

arg1 指探针中的返回值,在本例中为指针。如果您需要它指向的内容,请使用copyin(arg1, size_of_struct) 并将结果转换为您认为的任何内容(请参阅@Nikolai 的帖子,不要忘记您可以在DTrace 脚本中使用#include,只要您记得@987654327 @ 命令行上的选项)。 pid$target 提供程序名称扩展为pid1234,其中1234 是使用-c 选项执行的命令的进程ID - 在本例中为java

有关更多信息,请查看Brendan Gregg's blog(这是 dtrace 信息的一个很好的通用来源)。

【讨论】:

请注意,您可以将此探针与您之前使用的内核内探针交错以跟踪上下文切换 - 只需使用线程本地存储 (self->variable = ...) 来存储 pthread_self() 结果和引用稍后当上下文切换发生时。【参考方案4】:

在 linux 上,我发现识别进程上下文切换的最可靠方法是通过以下命令:

pidstat -hluwrt  | grep "processname"

“tid”列 (#3) 与“gettid()”相同,因此允许开发人员直接关联哪个线程正在使用 CPU 和上下文切换。我建议在为程序生成线程时吐出 gettid() 值:printf("%lul",gettid()).

在进程命令行之前的最后 2 列是每秒的“cswtch/s”(自愿)和“nvcswtch/s”(非自愿)上下文切换计数。

当“cswtch/s”很高(1000 秒)时,您的进程会过度循环通过“唤醒”和“睡眠”。您可能需要考虑某种缓冲区来提供线程,从而允许更长的唤醒和睡眠时间。例如:当缓冲区未满时,线程休眠时间更长。当缓冲区变满时,线程处于唤醒状态,直到缓冲区变空。

当“nvswtch/s”很高(1000 秒)时,这表明您的系统负载过重并且各个线程正在争用 CPU 时间。您可能想调查服务器负载、服务器上活动进程和线程的数量:“top”或“htop”是您的朋友。

我发现以下脚本对调试/优化进程线程很有用(每 20 秒输出一次):

stdbuf -oL pidstat -hluwrt  20 | stdbuf -oL grep -e "processname" -e "^#"

gettid 的文档:(doc here) pidstat 文档:(doc here) stdbuf 文档:(doc here)

【讨论】:

以上是关于pthread_self() 中的 Pthread id 与 dtrace 脚本中的数据不匹配的主要内容,如果未能解决你的问题,请参考以下文章

pthread_self() 贵吗?

linux下多线程之pthread_detach(pthread_self())

pthread_self返回不同的值

线程的创建,pthread_create,pthread_self,pthread_once

linux C语言 pthread_t pthread_self()函数(获取调用线程的ID) pthread_equal() 线程id(thread ID)

linux C语言 pthread_t pthread_self()函数(获取调用线程的ID) pthread_equal() 线程id(thread ID)