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

时间:2009-08-26 05:48:43

标签: java macos pthreads dtrace

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

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

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

4 个答案:

答案 0 :(得分:3)

所以我将回答我自己的问题,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;

源代码是你的朋友:)

答案 2 :(得分:1)

使用处理userland代码的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记住命令行上的-C选项。 pid$target提供程序名称扩展为pid1234,其中1234是使用-c选项执行的命令的进程ID - 在本例中为java。< / p>

有关详细信息,请查看Brendan Gregg's blog(这是dtrace信息的一般来源)。

答案 3 :(得分:0)

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

pidstat -hluwrt  | grep "processname"

&#39;&#39;列(#3)与&#39; gettid()&#39;相同,因此允许开发人员直接关联哪个线程正在使用CPU和上下文切换。我建议当程序产生一个线程来吐出gettid()值时: printf(&#34;%lul&#34;,gettid())

在流程命令行之前的最后两列是&#39; cswtch / s&#39; (自愿)和&nbsp; nvcswtch / s&#39; (非自愿的)上下文切换计数,每秒。

当&cswtch / s&#39;很高(1000&#39; s)你的过程是循环通过'唤醒'#39;和'睡觉&#39;过度。您可能需要考虑某种缓冲来提供线程,从而允许更长时间的唤醒和睡觉时间。例如:当缓冲区未满时,线程会长时间保持睡眠状态。当缓冲区变满时,线程将处于唤醒状态,直到缓冲区变空为止。

当'nvswtch / s&#39;很高(1000&#39; s),这是系统负载很重的一个症状,而且各个线程争用CPU时间。您可能想要调查服务器负载,活动进程的数量和服务器上的线程:&#39; top&#39;或者&#39; htop&#39;是你的朋友。

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

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

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