Solaris DTrace: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 1: Строка 1:
 
=DTrace=
 
=DTrace=
 
(дополненный текст отсюда: http://experience.openquality.ru/dtrace-use-cases/)
 
(дополненный текст отсюда: http://experience.openquality.ru/dtrace-use-cases/)
  +
Подробная дока:<BR>http://wikis.sun.com/display/DTrace/Documentation
   
 
Технология DTrace и подходящие инструменты для ее использования появились в 2005 году, но, несмотря на это, DTrace еще малоизвестна в широких кругах разработчиков и сисадминов. Это тем более удивительно, что за пять с половиной лет, прошедших с выхода системы Solaris 10, в которой она впервые появилась, так и не было придумано более совершенной технологии наблюдения за операционной системой и приложениями.
 
Технология DTrace и подходящие инструменты для ее использования появились в 2005 году, но, несмотря на это, DTrace еще малоизвестна в широких кругах разработчиков и сисадминов. Это тем более удивительно, что за пять с половиной лет, прошедших с выхода системы Solaris 10, в которой она впервые появилась, так и не было придумано более совершенной технологии наблюдения за операционной системой и приложениями.

Версия 11:50, 29 марта 2011

DTrace

(дополненный текст отсюда: http://experience.openquality.ru/dtrace-use-cases/) Подробная дока:
http://wikis.sun.com/display/DTrace/Documentation

Технология DTrace и подходящие инструменты для ее использования появились в 2005 году, но, несмотря на это, DTrace еще малоизвестна в широких кругах разработчиков и сисадминов. Это тем более удивительно, что за пять с половиной лет, прошедших с выхода системы Solaris 10, в которой она впервые появилась, так и не было придумано более совершенной технологии наблюдения за операционной системой и приложениями.

DTrace была разработана в компании Sun Microsystems, и открытый код всех ее компонентов был опубликован в том же 2005 году. С тех пор DTrace была перенесена в Mac OS X, QNX и FreeBSD, и появилась также во всех дистрибутивах, унаследовавших код ядра Solaris: Belenix, Korona, Nexenta, OpenIndiana и Milax. Разумеется, в Solaris технология DTrace тоже осталась и даже развилась – датчиков стало больше. В настоящее время DTrace доступна в самой свежей версии Solaris 11 Express, равно как и в Solaris 10.

По сравнению с другими средствами сбора информации о системе и отладки приложений, DTrace обладает рядом уникальных свойств:

  1. накапливает информацию о системе, работающей под максимальной нагрузкой – с низкими накладными расходами на сбор информации;
  2. собирает любую информацию из любых уголков системы, позволяя наблюдать как за работой приложений, так и за работой самого ядра системы;
  3. может показать, какие аргументы передаются от одной функции к другой, независимо от того, доступен ли исходный код функций;
  4. собирает информацию о том, как долго исполняются вызываемые функции, какой процент времени занимает исполнение каждой из них, сколько раз каждая из них была вызвана;
  5. фильтрует информацию любым заданным образом – например, позволяет ограничить область наблюдения одним приложением, одним потоком команд, или определенной областью (скажем, измерять время выполнения только конкретного системного вызова, а об остальном не заботиться);
  6. может реагировать на определенные события (ввод-вывод, вызов заданных функций, завершение программы, запуск нового потока и пр.);
  7. имеет как средства низкоуровнего наблюдения (можно изучать ход работы драйвера устройства), так и средства высокоуровневые, например, позволяет отслеживать определенные события при исполнении скриптов на PHP или вызов методов в приложении, написанном на Java;
  8. позволяет выполнять трассировку вызовов, с одновременным отслеживанием любых параметров – времени выполнения, переданных аргументов и пр.


Основным компонентом DTrace является модуль ядра, обеспечивающий функционирование подсистемы DTrace, а основным инструментом – приложение dtrace, которое воспринимает скрипты, написанные на языке D, созданном специально для работы с DTrace. В этой заметке мы не будем вдаваться в детали реализации DTrace; тем, кто в них заинтересован, я могу посоветовать найти их описание в Google, а также в главах 27 и 28 второго издания книги «Операционная система Solaris», написанной мной в соавторстве с Евгением Ильиным в 2009 году. Кроме того, наблюдение, профилирование и трассировка работы приложений с помощью DTrace подробно рассмотрены в одной из лекций по курсу «Системное администрирование ОС Solaris 10».
Cкрипт, выдающий количество функций, написать легко. В качестве затравки рассмотрим несколько вариантов, а затем перейдем к синтаксису скриптов. Например, вот такой скрипт выдает количество вызовов любых функций при работе программы ls (вначале на экран будет выдан результат ее работы, а потом – список функций с количеством вызовов для каждой в порядке возрастания):

pfexec dtrace -n 'pid$target:::entry {@funсtions[probefunc]=count();}' -c ls

А вот таким скриптом можно посчитать количество функций, вызванных конкретным процессом с PID=2355; для получения результата надо прервать выполнение скрипта с помощью Ctrl-C:

pfexec dtrace -n 'pid2355:::entry {@funсtions[probefunc]=count();}'

А вот так можно посчитать количество системных вызовов в том же процессе:

pfexec dtrace -n 'syscall:::entry /pid==2355/ {@funсtions[probefunc]=count();}'

Итак, в скриптах на языке D всегда используется следующий синтаксис:

провайдер:модуль:функция:датчик /условие/ { действия }
Провайдер – это модуль ядра или модуль приложения, обеспечивающий регистрацию своих датчиков DTrace в системе. Например, провайдер syscall регистрирует датчики, расположенные в системных вызовах, провайдер mysql – датчики, встроенные в сервер MySQL.
Модуль – это название модуля или библиотеки, например, libc.
Функция – имя функции, датчик в которой нам интересен, например, fopen.
Датчик – название датчика (во многих случаях датчик называется entry или return).
Условие задает ситуацию, когда следует выполнить действие при срабатывании датчика. Например, надо выполнить его только тогда, когда датчик сработал в приложении top. Тогда условие выглядит так:

 /execname == top/

Действия – это то, что обеспечивает сбор информации и вывод ее на экран. Из примеров ниже будет ясно, какими они бывают.
Простой пример того, как я использую DTrace в повседневной жизни: после переноса пользовательских настроек с одного компьютера на другой система на не захотела работать с принтером, как раньше. Было ясно, что какой-то из файлов настроек отчего-то не скопирован. Но какой именно? Их же сотни… Банальные /etc/printers и /etc/lp/* были проверены и разгадки не дали. Тогда пришлось задействовать DTrace. Простой скрипт дает возможность заглянуть в недра программы lpstat (наиболее безвредная программа из тех, что работает с принтером) и посмотреть, какие файлы она пытается открыть:

lpstat -s
scheduler is running
system default printer: eaqvap21
aqvap21: unknown printer
aqvap21: unknown printer

Чтобы запустить программу и подсунуть ее PID скрипту на DTrace надо использовать ключ -c :

dtrace -n 'pid$target::fopen:entry {printf("%s",copyinstr(arg0));}' -c "lpstat -s"

dtrace: description 'pid$target::fopen:entry ' matched 1 probe
scheduler is running
system default printer: eaqvap21
aqvap21: unknown printer
aqvap21: unknown printer
dtrace: pid 11156 has exited
CPU     ID                    FUNCTION:NAME
 0  59882                      fopen:entry /etc/default/init
 0  59882                      fopen:entry /etc/lp/ppd/eaqvap21.ppd
 0  59882                      fopen:entry /export/home/filip/.printers
 0  59882                      fopen:entry /export/home/filip/.printers
 0  59882                      fopen:entry /export/home/filip/.printers
 0  59882                      fopen:entry /etc/printers.conf
 0  59882                      fopen:entry /export/home/filip/.printers
 0  59882                      fopen:entry /etc/printers.conf
 1  59882                      fopen:entry /etc/nsswitch.conf
 1  59882                      fopen:entry /export/home/filip/.printers
 1  59882                      fopen:entry /export/home/filip/.printers
 1  59882                      fopen:entry /etc/printers.conf

Вот и все: я забыл, что надо почистить файл .printers в домашнем каталоге:

rm /export/home/filip/.printers

Замечание: подсовывать PID программы скрипту надо потому, что провайдер pid требует указания PID изучаемого с помощью DTrace процесса, а знакомый нам всем вызов fopen как раз относится к этому провайдеру DTrace.
Вообще, сбор информации о том, какие файлы открываются в системе, часто дает разгадку сисадмину. Поэтому иногда я использую и такую модификацию скрипта:

pfexec dtrace -n 'syscall::open*:entry {printf("%s\n",copyinstr(arg0));}'

Этот скрипт валит в кучу данные от всех системных вызовов, имена которых начинаются на open, что неудобно, но зато его легче всего вспомнить и проще всего применить к уже запущенным приложениям, а полученной информации может хватить для анализа.

Наконец, для тех, кто отлаживает веб-приложения, может пригодиться скрипт, который вылавливает SQL-операторы из сервера БД перед тем, как сервер их запустит. Это позволяет выяснить, какие именно операторы исполняются; такая информация поможет, если кажется, что скрипт, работающий с БД, все делает верно, а база данных возвращает неожиданный результат: может оказаться, что либо SQL-выражение формируется неверно, либо соединние происходит не с той базой данных, что надо, либо какой-то параметр передается СУБД без должного оформления (например, без кавычек или с лишними кавычками).

Вот этот скрипт: (не работает)

#!/usr/sbin/dtrace -s
#pragma D option quiet
dtrace:::BEGIN
{
  printf("%-20s %-20s %-40s %-9s\n", "Who", "Database", "Query", "Time(ms)");
}
mysql*:::query-start
{
  self->query = copyinstr(arg0);
  self->connid = arg1;
  self->db    = copyinstr(arg2);
  self->who   = strjoin(copyinstr(arg3),strjoin("@",copyinstr(arg4)));
  self->querystart = timestamp;
}
 
mysql*:::query-done
{
  printf("%-20s %-20s %-40s %-9d\n",self->who,self->db,self->query,
         (timestamp - self->querystart) / 1000000);
}

Запустив его, можно наблюдать картину работы сервера (осторожно! там может быть очень много информации, если сервер сильно нагружен запросами!):

$ pfexec ./mysql.d
Who                  Database             Query                                    Time(ms)
root@localhost       data                 SELECT DATABASE()                        0
root@localhost       test                 show tables                              0
root@localhost       test                 SELECT DATABASE()                        0
root@localhost       mysql                select * from users                      0
root@localhost       mysql                select * from host                       0

C помощью измерения времени между срабатываниями датчиков query-start и query-done вычисляется время исполнения SQL-оператора, и DTrace позволяет строить графики распределения времени исполнения по операторам. Так можно найти те обращения к базе данных, которые отнимают много времени при выполнении конкретных приложений. Большое преимущество DTrace в том, что все эти измерения можно производить в условиях реальной нагрузки на сервер, так как накладные расходы на работу самого DTrace минимальны и не будут мешать работе сервера.
Замечание: время выполнения запросов меньше 1 ms, а в скрипте выполняется целочисленное деление, поэтому результат получается 0. Можно считать в микросекундах, а не в миллисекундах, тогда будет какое-то небольшое значение.
Из приведенных примеров видно, что датчики DTrace расставлены в системе и приложениях Solaris повсюду. Изучить, какие аргументы, связанные с датчиками, можно использовать так, как показано выше, можно в документации по системе (man) и в документации по конкретным приложениям (например, по серверу MySQL на сайте mysql.com).

Значительно больше примеров скриптов для dtrace можно найти в следующих источниках:

Примеры

# dtrace_oneliners.txt - DTrace one liners. Handy commands.
#
# 25-Apr-2005, ver 0.70   (first release)
#
# Standard Disclaimer: This is freeware, use at your own risk.
#
# 25-Apr-2005  Brendan Gregg   Created this.


#
#  Contents
#

DTrace One Liners,

# New processes with arguments,
dtrace -n 'proc:::exec-success { trace(curpsinfo->pr_psargs); }'
 
# Files opened by process,
dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'
 
# Syscall count by program,
dtrace -n 'syscall:::entry { @num[execname] = count(); }'
 
# Syscall count by syscall,
dtrace -n 'syscall:::entry { @num[probefunc] = count(); }'
 
# Syscall count by process,
dtrace -n 'syscall:::entry { @num[pid,execname] = count(); }'
 
# Read bytes by process,
dtrace -n 'sysinfo:::readch { @bytes[execname] = sum(arg0); }'
 
# Write bytes by process,
dtrace -n 'sysinfo:::writech { @bytes[execname] = sum(arg0); }'
 
# Read size distribution by process,
dtrace -n 'sysinfo:::readch { @dist[execname] = quantize(arg0); }'
 
# Write size distribution by process,
dtrace -n 'sysinfo:::writech { @dist[execname] = quantize(arg0); }'
 
# Disk size by process,
dtrace -n 'io:::start { printf("%d %s %d",pid,execname,args[0]->b_bcount); }'
 
# Pages paged in by process,
dtrace -n 'vminfo:::pgpgin { @pg[execname] = sum(arg0); }'
 
# Minor faults by process,
dtrace -n 'vminfo:::as_fault { @mem[execname] = sum(arg0); }'
 
# Interrupts by CPU,
dtrace -n 'sdt:::interrupt-start { @num[cpu] = count(); }'


DTrace Longer One Liners,

# New processes with arguments and time,
dtrace -qn 'syscall::exec*:return { printf("%Y %s\n",walltimestamp,curpsinfo->pr_psargs); }'
 
# Successful signal details,
dtrace -n 'proc:::signal-send /pid/ { printf("%s -%d %d",execname,args[2],args[1]->pr_pid); }'



#
#  Examples
#

### New processes with arguments,
  
# dtrace -n 'proc:::exec-success { trace(curpsinfo->pr_psargs); }'
dtrace: description 'proc:::exec-success ' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0   3297         exec_common:exec-success   man ls
  0   3297         exec_common:exec-success   sh -c cd /usr/share/man; tbl /usr/share/man/man1/ls.1 |neqn /usr/share/lib/pub/
  0   3297         exec_common:exec-success   tbl /usr/share/man/man1/ls.1
  0   3297         exec_common:exec-success   neqn /usr/share/lib/pub/eqnchar -
  0   3297         exec_common:exec-success   nroff -u0 -Tlp -man -
  0   3297         exec_common:exec-success   col -x
  0   3297         exec_common:exec-success   sh -c trap '' 1 15; /usr/bin/mv -f /tmp/mpzIaOZF /usr/share/man/cat1/ls.1 2> /d
  0   3297         exec_common:exec-success   /usr/bin/mv -f /tmp/mpzIaOZF /usr/share/man/cat1/ls.1
  0   3297         exec_common:exec-success   sh -c more -s /tmp/mpzIaOZF
  0   3297         exec_common:exec-success   more -s /tmp/mpzIaOZF


### Files opened by process,
 
# dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'
dtrace: description 'syscall::open*:entry ' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0     14                       open:entry gnome-netstatus- /dev/kstat
  0     14                       open:entry man /var/ld/ld.config
  0     14                       open:entry man /lib/libc.so.1
  0     14                       open:entry man /usr/share/man/man.cf
  0     14                       open:entry man /usr/share/man/windex
  0     14                       open:entry man /usr/share/man/man1/ls.1
  0     14                       open:entry man /usr/share/man/man1/ls.1
  0     14                       open:entry man /tmp/mpqea4RF
  0     14                       open:entry sh /var/ld/ld.config
  0     14                       open:entry sh /lib/libc.so.1
  0     14                       open:entry neqn /var/ld/ld.config
  0     14                       open:entry neqn /lib/libc.so.1
  0     14                       open:entry neqn /usr/share/lib/pub/eqnchar
  0     14                       open:entry tbl /var/ld/ld.config
  0     14                       open:entry tbl /lib/libc.so.1
  0     14                       open:entry tbl /usr/share/man/man1/ls.1
  0     14                       open:entry nroff /var/ld/ld.config
[...]


### Syscall count by program,
 
# dtrace -n 'syscall:::entry { @num[execname] = count(); }'
dtrace: description 'syscall:::entry ' matched 228 probes
^C
  snmpd                                                             1
  utmpd                                                             2
  inetd                                                             2
  nscd                                                              7
  svc.startd                                                       11
  sendmail                                                         31
  poold                                                           133
  dtrace                                                         1720


### Syscall count by syscall,
 
# dtrace -n 'syscall:::entry { @num[probefunc] = count(); }'
dtrace: description 'syscall:::entry ' matched 228 probes
^C
  fstat                                                             1
  setcontext                                                        1
  lwp_park                                                          1
  schedctl                                                          1
  mmap                                                              1
  sigaction                                                         2
  pset                                                              2
  lwp_sigmask                                                       2
  gtime                                                             3
  sysconfig                                                         3
  write                                                             4
  brk                                                               6
  pollsys                                                           7
  p_online                                                        558
  ioctl                                                           579


### Syscall count by process,
 
# dtrace -n 'syscall:::entry { @num[pid,execname] = count(); }'
dtrace: description 'syscall:::entry ' matched 228 probes
^C
     1109  svc.startd                                                        1
     4588  svc.startd                                                        2
        7  svc.startd                                                        2
     3950  svc.startd                                                        2
     1626  nscd                                                              2
      870  svc.startd                                                        2
       82  nscd                                                              6
     5011  sendmail                                                         10
     6010  poold                                                            74
     8707  dtrace                                                         1720


### Read bytes by process,
  
# dtrace -n 'sysinfo:::readch { @bytes[execname] = sum(arg0); }'
dtrace: description 'sysinfo:::readch ' matched 4 probes
^C
 
  mozilla-bin                                                      16
  gnome-smproxy                                                    64
  metacity                                                         64
  dsdm                                                             64
  wnck-applet                                                      64
  xscreensaver                                                     96
  gnome-terminal                                                  900
  ttymon                                                         5952
  Xorg                                                          17544
 

### Write bytes by process,
 
# dtrace -n 'sysinfo:::writech { @bytes[execname] = sum(arg0); }'
dtrace: description 'sysinfo:::writech ' matched 4 probes
^C

  dtrace                                                            1
  gnome-settings-d                                                  8
  xscreensaver                                                      8
  gnome-panel                                                       8
  nautilus                                                          8
  date                                                             29
  wnck-applet                                                     120
  bash                                                            210
  mozilla-bin                                                    1497
  ls                                                             1947
  metacity                                                       3172
  Xorg                                                           7424
  gnome-terminal                                                51955


### Read size distribution by process,
 
# dtrace -n 'sysinfo:::readch { @dist[execname] = quantize(arg0); }'
dtrace: description 'sysinfo:::readch ' matched 4 probes
^C
[...]
  gnome-terminal
           value  ------------- Distribution ------------- count
              16 |                                         0
              32 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   15
              64 |@@@                                      1
             128 |                                         0
 
  Xorg
           value  ------------- Distribution ------------- count
              -1 |                                         0
               0 |@@@@@@@@@@@@@@@@@@@                      26
               1 |                                         0
               2 |                                         0
               4 |                                         0
               8 |@@@@                                     6
              16 |@                                        2
              32 |@                                        2
              64 |                                         0
             128 |@@@@@@@@                                 11
             256 |@@@                                      4
             512 |                                         0


### Write size distribution by process,
 
# dtrace -n 'sysinfo:::writech { @dist[execname] = quantize(arg0); }'
dtrace: description 'sysinfo:::writech ' matched 4 probes
^C
[...]
  Xorg
           value  ------------- Distribution ------------- count
              16 |                                         0
              32 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@       169
              64 |@@@                                      16
             128 |@@                                       10
             256 |                                         0
 
  gnome-terminal
           value  ------------- Distribution ------------- count
               0 |                                         0
               1 |@@                                       6
               2 |                                         0
               4 |                                         0
               8 |                                         1
              16 |@                                        2
              32 |@@@                                      7
              64 |                                         0
             128 |@@@@@@@@@@@@@@@@@@@@@@@                  63
             256 |@@@@                                     10
             512 |                                         1
            1024 |@@@@@                                    13
            2048 |@                                        2
            4096 |@@@                                      7


### Disk size by process,
  
# dtrace -n 'io:::start { printf("%d %s %d",pid,execname,args[0]->b_bcount); }'
  0   3271              bdev_strategy:start 16459 tar 1024
  0   3271              bdev_strategy:start 16459 tar 1024
  0   3271              bdev_strategy:start 16459 tar 2048
  0   3271              bdev_strategy:start 16459 tar 1024
  0   3271              bdev_strategy:start 16459 tar 1024
  0   3271              bdev_strategy:start 16459 tar 1024
  0   3271              bdev_strategy:start 16459 tar 8192
  0   3271              bdev_strategy:start 16459 tar 8192
  0   3271              bdev_strategy:start 16459 tar 16384
  0   3271              bdev_strategy:start 16459 tar 2048
  0   3271              bdev_strategy:start 16459 tar 1024
  0   3271              bdev_strategy:start 16459 tar 1024


### Pages paged in by process,
 
# dtrace -n 'vminfo:::pgpgin { @pg[execname] = sum(arg0); }'
dtrace: description 'vminfo:::pgpgin ' matched 1 probe
^C
 
  ttymon                                                            1
  bash                                                              1
  mozilla-bin                                                      36
  tar                                                            6661


### Minor faults by process,
  
# dtrace -n 'vminfo:::as_fault { @mem[execname] = sum(arg0); }'
dtrace: description 'vminfo:::as_fault ' matched 1 probe
^C
 
  mozilla-bin                                                      18
  dtrace                                                           57
  find                                                             64
  bash                                                            150
  tar                                                             501


### Interrupts by CPU,
 
# dtrace -n 'sdt:::interrupt-start { @num[cpu] = count(); }'
dtrace: description 'sdt:::interrupt-start ' matched 1 probe
^C
 
      513                2
      515                4
        3               39
        2               39


### New processes with arguments and time,
 
# dtrace -qn 'syscall::exec*:return { printf("%Y %s\n",walltimestamp,curpsinfo->pr_psargs); }'
2005 Apr 25 19:15:09 man ls
2005 Apr 25 19:15:09 sh -c cd /usr/share/man; tbl /usr/share/man/man1/ls.1 |...
2005 Apr 25 19:15:09 neqn /usr/share/lib/pub/eqnchar -
2005 Apr 25 19:15:09 tbl /usr/share/man/man1/ls.1
2005 Apr 25 19:15:09 nroff -u0 -Tlp -man -
2005 Apr 25 19:15:09 col -x
2005 Apr 25 19:15:10 sh -c trap '' 1 15; /usr/bin/mv -f /tmp/mpRZaqTF /usr/s...
2005 Apr 25 19:15:10 /usr/bin/mv -f /tmp/mpRZaqTF /usr/share/man/cat1/ls.1
2005 Apr 25 19:15:10 sh -c more -s /tmp/mpRZaqTF
2005 Apr 25 19:15:10 more -s /tmp/mpRZaqTF
[...]


### Successful signal details,
  
# dtrace -n 'proc:::signal-send /pid/ { printf("%s -%d %d",execname,args[2],args[1]->pr_pid); }'
dtrace: description 'proc:::signal-send ' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0   3303            sigtoproc:signal-send bash -15 16442
  0   3303            sigtoproc:signal-send bash -9 16443
^C