Как измерить конкуренцию за мьютекс? - PullRequest
23 голосов
/ 08 августа 2009

У меня есть некоторый многопоточный код, использующий PThreads в Linux, который, я подозреваю, страдает от чрезмерной конкуренции за блокировку. Какие инструменты доступны для меня, чтобы измерить это?

Солярис имеет DTrace и plockstat. Есть ли что-то похожее на Linux? (Я знаю о недавнем порте DTrace для Linux, но он еще не готов к прайм-тайму.)

Ответы [ 5 ]

14 голосов
/ 14 июля 2010

Mutrace - это инструмент: http://0pointer.de/blog/projects/mutrace.html

Его легко создавать, устанавливать и использовать.

5 голосов
/ 09 августа 2009

После неудачи с 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        

Определенно, не очень, но, по крайней мере, это отправная точка.

4 голосов
/ 14 июля 2010

Последняя версия 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

Хотя вышеприведенный скрипт собирает информацию обо всех процессах, запущенных в системе, его было бы довольно легко изменить, чтобы он работал только с определенным процессом или исполняемым файлом. Например, мы могли бы изменить скрипт, чтобы он принимал аргумент идентификатора процесса, и изменить зонд при входе в вызов 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 голосов
/ 09 августа 2009

В последних версиях Valgrind есть блокировка конкуренции и инструменты проверки блокировки:

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

Прекрасно, если вы можете создать проблему в Valgrind (это влияет на скорость выполнения кода) и иметь достаточно памяти для запуска Valgrind.

Для других целей рекомендуется более жесткая версия Linux Trace Toolkit NG:

http://ltt.polymtl.ca/

Cheers, Гилад

1 голос
/ 08 августа 2009

В отсутствие DTrace, ваша лучшая ставка, вероятно, SystemTap . Вот положительный отзыв.

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

...