Tracing/USDT: различия между версиями

Материал из ALT Linux Wiki
(добавление статьи)
 
(tclsh prompt)
 
(не показано 10 промежуточных версий этого же участника)
Строка 1: Строка 1:
= Userland Statically Defined Tracing =
= Userland Statically Defined Tracing =


Некоторый софт позволяет добавлять ''статические точки трассировки'' (трейспоинты) для удобства его отладки, улучшая т.н. ''observability'' системы. Например, такая поддержка есть у многих интерпретаторов скриптовых языков, MySQL, gRPC.  
Некоторый софт позволяет добавлять ''статические точки трассировки'' (трейспоинты) для удобства его отладки в сложных местах где трудно сделать другие виды трассировки, улучшая т.н. ''observability'' системы.


== Сборка пакета с поддержкой ==
Например, такая поддержка есть у некоторых языков (java, perl, php, python, ruby, tcl, nodejs, dotnet), приложений (mariadb, postgresql, couchdb, systemd-udev, sssd, ceph), библиотек (grpc, glibc, glib, zlib). У нас эти пакеты пока собраны без такой поддержки и требуют её включения.
 
Исторически эти трейспоинты восходят к Solaris ''Dtrace'', а в Линукс впервые попали через ''SystemTap''. Нужно отметить, что данная реализация USDT использует ''только'' хедер <code>sys/sdt.h</code> предоставляемый SystemTap, но не использует прочий SystemTap функционал или инфраструктуру.
 
== Сборка пакета с поддержкой usdt ==
Маинтайнеру зачастую достаточно сделать два изменения spec'а: 1) добавить
Маинтайнеру зачастую достаточно сделать два изменения spec'а: 1) добавить
   BuildRequires: systemtap-sdt-devel
   BuildRequires: systemtap-sdt-devel
который приносит Си хедер <code><sys/sdt.h></code>, и 2) добавить соответствующую опцию <code>configure</code>, например (её название может отличаться):
который приносит необходимый Си хедер, и 2) добавить соответствующую опцию <code>configure</code>, например (её название может отличаться):
   %configure --enable-dtrace
   %configure --enable-dtrace
Другие варианты: <code>--with-dtrace</code>, <code>--enable-systemtap</code>, <code>--with-systemtap</code>.


В результате — в коде в точке трассировке добавляется один <code>nop</code> не влияющий на производительность при отключенной трассировке, а в ELF бинарник в секцию <code>.note.stapsdt</code> записывается описание каждого трейспоинта и его аргументов. Проверить их наличие можно командой <code>eu-readelf --notes=.note.stapsdt ''путь-к-бинарнику''</code>. Пример для трейспоинта с именем ''example:test'' (имеющем один аргумент) и находящимся в бинарнике ''./example'':
В результате — в коде в точке трассировке добавляется один <code>nop</code> не влияющий на производительность при отключенной трассировке, а в ELF бинарник в секцию <code>.note.stapsdt</code> записывается описание каждого трейспоинта и его аргументов. Проверить их наличие можно командой <code>eu-readelf --notes=.note.stapsdt ''путь-к-бинарнику''</code>. Пример для трейспоинта с именем ''example:test'' (имеющим один аргумент) и находящимся в бинарнике ''./example'':


   $ eu-readelf --notes=.note.stapsdt ./example
   $ eu-readelf --notes=.note.stapsdt ./example
Строка 18: Строка 23:
       PC: 0x1153, Base: 0x2004, Semaphore: 0
       PC: 0x1153, Base: 0x2004, Semaphore: 0
       Provider: example, Name: test, Args: '8@%rax'
       Provider: example, Name: test, Args: '8@%rax'
== Использование ==
Есть три варианта использования этих трейспоинтов -- через eBPF, perf_event и ftrace -- все они потребуют рутовых привилегий и трассировка (по умолчанию) происходит для всей системы вцелом (или для указанного процесса).
=== Использование через ''eBPF'' ===
==== bcc-tools ====
В пакете <code>bcc-tools</code> предоставляются следующие утилиты:
* <code>tplist</code> покажет список трейспоинтов:
  # tplist -l /usr/lib64/libtcl8.6.so | grep entry
  /usr/lib64/libtcl8.6.so tcl:cmd__entry
  /usr/lib64/libtcl8.6.so tcl:proc__entry
* <code>bcc trace</code> трассировщик. Пример использования:
  шелл-А# bcc trace 'u:/usr/lib64/libtcl8.6.so:cmd__entry "%s", arg1'
  PID    TID    COMM            FUNC            -
  шелл-Б$ tclsh
  tclsh% puts test
  шелл-А:
  23036  23036  tclsh          cmd__entry      b'puts'
==== bpftrace ====
В пакете <code>bpftrace</code> одноименная утилита ([https://github.com/iovisor/bpftrace/blob/master/docs/reference%20guide.md документация на англ.]). Пример использования:
  шелл-А# bpftrace -e 'usdt:/usr/lib64/libtcl8.6.so:cmd__entry { printf("%s\n", str(arg0)); }'
  Attaching 1 probe...
  шелл-Б$ tclsh
  tclsh% puts test
  шелл-А:
  puts
=== Использование через интерфейс ''perf_event'' ===
==== perf ====
В пакете <code>perf</code> одноименная утилита, пример:
  # perf buildid-cache --add /usr/lib64/libtcl8.6.so
  # perf list | grep sdt_ | grep proc__entry
    sdt_tcl:proc__entry                                [SDT event]
  # perf probe sdt_tcl:proc__entry
  Added new events:
    sdt_tcl:proc__entry  (on %proc__entry in /usr/lib64/libtcl8.6.so)
  # perf record -e sdt_tcl:proc__entry -a -- tclsh
  tclsh% echo 'hello world'
  'hello world'
  tclsh% ^D
  # perf script | head -1
          tclsh 22814 [015] 686801.201230: sdt_tcl:proc__entry: (7f9950fdf04e) arg1=94274876797648 arg2=0 arg3=94274876480632
=== Использование через интерфейс ''ftrace'' ===
==== trace-cmd ====
В пакете <code>trace-cmd</code> одноименная утилита. NB: Сначала необходимо зарегистрировать probe в ядре так же как для <code>perf</code> и только потом использовать.
  # perf buildid-cache --add /usr/lib64/libtcl8.6.so
  # perf probe sdt_tcl:proc__entry
  # trace-cmd list -e sdt
  sdt_tcl:proc__entry
  # trace-cmd record -e sdt_tcl:proc__entry -- tclsh
  tclsh% puts test
  test
  tclsh% ^D
  # trace-cmd report
          tclsh-23269 [013] 689825.345553: proc__entry:          (7f72e1b8f04e) arg1=93884043869840 arg2=0 arg3=93884043553912
== Доп. материалы ==
* https://leezhenghui.github.io/linux/2019/03/05/exploring-usdt-on-linux.html Exploring USDT Probes on Linux
* https://lwn.net/Articles/753601/ Using user-space tracepoints with BPF [2018]
* https://www.brendangregg.com/blog/2016-10-12/linux-bcc-nodejs-usdt.html Linux bcc/BPF Node.js USDT Tracing
* https://www.brendangregg.com/blog/2015-07-03/hacking-linux-usdt-ftrace.html Hacking Linux USDT with Ftrace
* https://www.brendangregg.com/perf.html#StaticUserTracing §6.5. Static User Tracing
* https://www.sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps Adding User Space Probing to an Application

Текущая версия от 02:30, 15 октября 2022

Userland Statically Defined Tracing

Некоторый софт позволяет добавлять статические точки трассировки (трейспоинты) для удобства его отладки в сложных местах где трудно сделать другие виды трассировки, улучшая т.н. observability системы.

Например, такая поддержка есть у некоторых языков (java, perl, php, python, ruby, tcl, nodejs, dotnet), приложений (mariadb, postgresql, couchdb, systemd-udev, sssd, ceph), библиотек (grpc, glibc, glib, zlib). У нас эти пакеты пока собраны без такой поддержки и требуют её включения.

Исторически эти трейспоинты восходят к Solaris Dtrace, а в Линукс впервые попали через SystemTap. Нужно отметить, что данная реализация USDT использует только хедер sys/sdt.h предоставляемый SystemTap, но не использует прочий SystemTap функционал или инфраструктуру.

Сборка пакета с поддержкой usdt

Маинтайнеру зачастую достаточно сделать два изменения spec'а: 1) добавить

 BuildRequires: systemtap-sdt-devel

который приносит необходимый Си хедер, и 2) добавить соответствующую опцию configure, например (её название может отличаться):

 %configure --enable-dtrace

Другие варианты: --with-dtrace, --enable-systemtap, --with-systemtap.

В результате — в коде в точке трассировке добавляется один nop не влияющий на производительность при отключенной трассировке, а в ELF бинарник в секцию .note.stapsdt записывается описание каждого трейспоинта и его аргументов. Проверить их наличие можно командой eu-readelf --notes=.note.stapsdt путь-к-бинарнику. Пример для трейспоинта с именем example:test (имеющим один аргумент) и находящимся в бинарнике ./example:

 $ eu-readelf --notes=.note.stapsdt ./example
 
 Note section [30] '.note.stapsdt' of 68 bytes at offset 0x3174:
   Owner          Data size  Type
   stapsdt               45  Version: 3
     PC: 0x1153, Base: 0x2004, Semaphore: 0
     Provider: example, Name: test, Args: '8@%rax'

Использование

Есть три варианта использования этих трейспоинтов -- через eBPF, perf_event и ftrace -- все они потребуют рутовых привилегий и трассировка (по умолчанию) происходит для всей системы вцелом (или для указанного процесса).

Использование через eBPF

bcc-tools

В пакете bcc-tools предоставляются следующие утилиты:

  • tplist покажет список трейспоинтов:
 # tplist -l /usr/lib64/libtcl8.6.so | grep entry
 /usr/lib64/libtcl8.6.so tcl:cmd__entry
 /usr/lib64/libtcl8.6.so tcl:proc__entry
  • bcc trace трассировщик. Пример использования:
 шелл-А# bcc trace 'u:/usr/lib64/libtcl8.6.so:cmd__entry "%s", arg1' 
 PID     TID     COMM            FUNC             -
 шелл-Б$ tclsh
  tclsh% puts test
 шелл-А:
 23036   23036   tclsh           cmd__entry       b'puts'

bpftrace

В пакете bpftrace одноименная утилита (документация на англ.). Пример использования:

 шелл-А# bpftrace -e 'usdt:/usr/lib64/libtcl8.6.so:cmd__entry { printf("%s\n", str(arg0)); }'
 Attaching 1 probe...
 шелл-Б$ tclsh
  tclsh% puts test
 шелл-А:
 puts

Использование через интерфейс perf_event

perf

В пакете perf одноименная утилита, пример:

 # perf buildid-cache --add /usr/lib64/libtcl8.6.so
 # perf list | grep sdt_ | grep proc__entry
   sdt_tcl:proc__entry                                [SDT event]
 # perf probe sdt_tcl:proc__entry
 Added new events:
   sdt_tcl:proc__entry  (on %proc__entry in /usr/lib64/libtcl8.6.so)
 # perf record -e sdt_tcl:proc__entry -a -- tclsh
 tclsh% echo 'hello world'
 'hello world'
 tclsh% ^D
 # perf script | head -1
          tclsh 22814 [015] 686801.201230: sdt_tcl:proc__entry: (7f9950fdf04e) arg1=94274876797648 arg2=0 arg3=94274876480632

Использование через интерфейс ftrace

trace-cmd

В пакете trace-cmd одноименная утилита. NB: Сначала необходимо зарегистрировать probe в ядре так же как для perf и только потом использовать.

 # perf buildid-cache --add /usr/lib64/libtcl8.6.so
 # perf probe sdt_tcl:proc__entry
 # trace-cmd list -e sdt
 sdt_tcl:proc__entry
 # trace-cmd record -e sdt_tcl:proc__entry -- tclsh
 tclsh% puts test
 test
 tclsh% ^D
 # trace-cmd report
          tclsh-23269 [013] 689825.345553: proc__entry:          (7f72e1b8f04e) arg1=93884043869840 arg2=0 arg3=93884043553912

Доп. материалы