24

我有一些在 Linux 上使用 PThreads 的线程代码,我怀疑这些代码正遭受过多的锁争用。我可以使用哪些工具来衡量这一点?

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

4

5 回答 5

15

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

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

于 2010-07-14T12:00:43.160 回答
5

在使用 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 脚本来测量在 FUTEX_WAIT 中花费的时间的示例,该示例来自这篇DTrace 文章中的一个简单测试程序。

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

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

于 2009-08-09T01:12:22.630 回答
4

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

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

如果您可以在 Valgrind 下产生问题(它会影响代码运行时速度)并且有足够的内存来运行 Valgrind,那就太好了。

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

http://ltt.polymtl.ca/

干杯,吉拉德

于 2009-08-09T12:01:23.503 回答
4

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

于 2010-07-14T03:44:17.670 回答
1

在没有 DTrace 的情况下,您最好的选择可能是SystemTap。这是一篇正面的文章。

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

于 2009-08-08T19:42:44.263 回答