如何在strace中调试futex争用问题?

15

我正在调试一个多线程的Linux进程,其中某个线程似乎在几秒钟内没有运行。查看strace输出发现它在等待futex,例如:
1673109 14:36:28.600329 futex(0x44b8d20, FUTEX_WAIT_PRIVATE,
1673109 14:36:33.221850 <... futex resumed> ) = 0 <4.621514>

如何找出这个futex(0x44b8d20)在用户空间中对应的是什么锁定构造,即如何将其映射到内部使用futex的锁定构造。

1个回答

13
我会使用一个简单的SystemTap脚本,这样可以帮助您快速找到争用的futex锁的地址。当我说地址时,我指的是futex()系统调用的第一个参数。
  1. 您可以在这里下载一个简单的SystemTap脚本,用于查找争用的用户空间锁:
    https://sourceware.org/systemtap/examples/process/futexes.stp

如果您的系统上已安装SystemTap,
只需启动此SystemTap脚本:stap futexes.stp

2. 捕获与之前一样的strace输出。 3. 如果你通过简单地按下Ctrl-C来结束系统tap脚本的执行,你将得到争用的futexes的输出。 4. 最后,在你的strace输出中,搜索futex调用,其中第二个参数(操作类型)是FUTEX_WAIT。 例如:futex(0x7f58a31999d0, FUTEX_WAIT, 4508, NULL) = 0 5. 然后你可以在system tap脚本输出中搜索第一个参数。 类似于:ome[4489] lock 0x7f58a31999d0 contended 1 times, 7807 avg us
如果你看一下这个system tap脚本,它会很好地为你打印进程名称和进程/线程ID。 这使得查找你要找的内容变得容易。
然而,需要注意的是执行systemtap脚本实际上会在整个系统范围内挂钩一个系统调用。

如果链接不可用,请参考以下脚本:

#! /usr/bin/env stap

# This script tries to identify contended user-space locks by hooking
# into the futex system call.

global FUTEX_WAIT = 0 /*, FUTEX_WAKE = 1 */
global FUTEX_PRIVATE_FLAG = 128 /* linux 2.6.22+ */
global FUTEX_CLOCK_REALTIME = 256 /* linux 2.6.29+ */

global lock_waits # long-lived stats on (tid,lock) blockage elapsed time
global process_names # long-lived pid-to-execname mapping

global entry_times%, uaddrs%

probe syscall.futex {
  if ((op & ~(FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME)) != FUTEX_WAIT) next
  entry_times[tid()] = gettimeofday_us()
  uaddrs[tid()] = futex_uaddr
}

probe syscall.futex.return {
  if (!(entry_times[tid()])) next
  elapsed = gettimeofday_us() - entry_times[tid()]
  lock_waits[pid(), uaddrs[tid()]] <<< elapsed
  delete entry_times[tid()]
  delete uaddrs[tid()]
  if (!(pid() in process_names))
    process_names[pid()] = execname()
}

probe end {
  foreach ([pid+, lock] in lock_waits) 
    printf ("%s[%d] lock %p contended %d times, %d avg us\n",
            process_names[pid], pid, lock, @count(lock_waits[pid,lock]),
            @avg(lock_waits[pid,lock]))
}

这真的很聪明,但不幸的是我正在使用OS X。感谢您的帖子,我现在已经开始研究使用Ruby探针的DTrace了。这绝对是一条我之前从未考虑过的途径。 - Reck
太好了!不幸的是,我在Ubuntu LTS 14.04.05上编写sudo ./futexes.stp时遇到了问题。 语义错误:解析探测点时:'syscall'标识符在./futexes.stp:15:7处 源:probe >syscall.futex {语义错误:无匹配项第2遍:分析失败。[man error :: pass2] 类似错误消息的数量被抑制:1。 使用-v重新运行以查看它们。 - ThorSummoner
1
@ThorSummoner 你需要使用 systemtap 工具运行 futexes.stp 脚本。在 Ubuntu 上可以使用 apt-get install systemtap 安装,然后以 root 用户身份执行 stap futexes.stp 命令。更多信息请参见:https://sourceware.org/systemtap/SystemTap_Beginners_Guide/using-systemtap.html - dpoggi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接