如何衡量互斥的争夺?

我有一些使用Linux上的PThreads的线程代码,我怀疑是过度的锁争夺。 我有什么工具可以衡量这一点?

Solaris有DTrace和plockstat。 Linux上有类似的东西吗? (我知道最近用于Linux的DTrace端口,但它似乎还没有准备好黄金时间。)

mutrace是工具:http://0pointer.de/blog/projects/mutrace.html

它易于构建,安装和使用。

valgrind最新版本有一个锁争用和锁定验证工具:

http://valgrind.org/docs/manual/drd-manual.html

如果你能在Valgrind下产生这个问题(它影响代码运行时速度)并且有足够的内存来运行Valgrind,那么这是非常好的。

对于其他用途,推荐使用更加硬核的Linux Trace Toolkit NG:

http://ltt.polymtl.ca/

干杯,吉拉德

最新版本的systemtap附带大量示例脚本 。 其中一个特别的地方似乎是将服务器作为帮助你完成任务的一个很好的起点:

#! /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的各种示例脚本。 他们可能是最好的起点。

在SystemTap没有多少运气之后,我决定尝试使用DTrace Linux端口 ,尽管缺少一个plockstat提供程序。 下面的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脚本来测量DTUT 文章中简单测试程序在FUTEX_WAIT中花费的时间的示例。

 $ ./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 

绝对不是很好,但至少这是一个起点。

在没有DTrace的情况下,您最好的选择可能是SystemTap 。 这是一个积极的写作。

http://davidcarterca.wordpress.com/2009/05/27/systemtap/