我有一些在Linux上使用PThreads的线程代码,我怀疑它正遭受过多的锁争用。有哪些工具可供我测量?
Solaris有DTrace和plockstat。 Linux上有类似的东西吗? (我知道最近Linux的DTrace端口,但它似乎尚未准备好迎接黄金时段。)
答案 0 :(得分:14)
mutrace是工具: http://0pointer.de/blog/projects/mutrace.html
易于构建,安装和使用。
答案 1 :(得分:5)
在没有太多运气的情况下,尽管没有plockstat提供商,但我决定尝试使用DTrace Linux port取得一些成功。以下DTrace脚本不是plockstat的替代品,但它设法向我展示了我所追求的一些信息。
#!/usr/sbin/dtrace -s
/* Usage: ./futex.d '"execname"' */
long total;
END
{
printf("total time spent on futex(): %ldms\n", total);
}
/* arg1 == 0 means FUTEX_WAIT */
syscall::futex:entry
/execname == $1 && arg1 == 0/
{
self->start = timestamp;
}
syscall::futex:return
/self->start/
{
this->elapsed = (timestamp - self->start) / 1000000;
@[execname] = quantize(this->elapsed);
total += this->elapsed;
self->start = 0;
}
以下是使用上述DTrace脚本测量FUTEX_WAIT中从DTrace article开始的简单测试程序所花费的时间的示例。
$ ./futex.d '"mutex-test"'
dtrace: script './futex.d' matched 3 probes
^C
CPU ID FUNCTION:NAME
1 2 :END total time spent on futex(): 11200ms
mutex-test
value ------------- Distribution ------------- count
128 | 0
256 |@@@@@@@@@@@@@@@@@@@@ 1
512 | 0
1024 | 0
2048 | 0
4096 | 0
8192 |@@@@@@@@@@@@@@@@@@@@ 1
16384 | 0
绝对不是很好,但至少它是一个起点。
答案 2 :(得分:4)
valgrind最新版本有一个锁争用和锁定验证工具:
http://valgrind.org/docs/manual/drd-manual.html
如果您可以在Valgrind下生成问题(它影响代码运行时速度)并且有足够的内存来运行Valgrind,那么这很棒。
对于其他用途,建议使用更硬核的Linux Trace Toolkit NG:
干杯, 吉拉德
答案 3 :(得分:4)
最新版本的systemtap附带了很多example scripts。特别值得一提的是,它可以作为帮助您完成任务的良好起点:
#! /usr/bin/env stap
global thread_thislock
global thread_blocktime
global FUTEX_WAIT = 0
global lock_waits
global process_names
probe syscall.futex {
if (op != FUTEX_WAIT) next
t = tid ()
process_names[pid()] = execname()
thread_thislock[t] = $uaddr
thread_blocktime[t] = gettimeofday_us()
}
probe syscall.futex.return {
t = tid()
ts = thread_blocktime[t]
if (ts) {
elapsed = gettimeofday_us() - ts
lock_waits[pid(), thread_thislock[t]] <<< elapsed
delete thread_blocktime[t]
delete thread_thislock[t]
}
}
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]))
}
我之前尝试使用MySQL进程诊断类似的东西,并使用上述脚本观察类似于以下内容的输出:
mysqld[3991] lock 0x000000000a1589e0 contended 45 times, 3 avg us
mysqld[3991] lock 0x000000004ad289d0 contended 1 times, 3 avg us
虽然上面的脚本收集了有关系统上运行的所有进程的信息,但将其修改为仅适用于某个进程或可执行文件非常容易。例如,我们可以更改脚本以获取进程ID参数,并在输入futex调用时修改探测,如下所示:
probe begin {
process_id = strtol(@1, 10)
}
probe syscall.futex {
if (pid() == process_id && op == FUTEX_WAIT) {
t = tid ()
process_names[process_id] = execname()
thread_thislock[t] = $uaddr
thread_blocktime[t] = gettimeofday_us()
}
}
显然,您可以修改脚本以适应您想要做的事情。我建议您查看SystemTap的各种示例脚本。它们可能是最好的起点。
答案 4 :(得分:1)
在没有DTrace的情况下,最好的选择可能是SystemTap。这是一个积极的写作。