Kapitel 24. DTrace

This translation may be out of date. To help with the translations please access the FreeBSD translations instance.

24.1. Überblick

DTrace, auch bekannt als Dynamic Tracing, wurde von Sun™ als ein Werkzeug zur Analyse von Performance-Problemen in Produktiv- und Entwicklungssystemen entwickelt. Zusätzlich zur Diagnose von Performance-Problemen kann DTrace auch verwendet werden, um bei der Untersuchung und Behebung von unerwartetem Verhalten im FreeBSD-Kernel und den Anwenderprogrammen zu helfen.

DTrace ist ein bemerkenswertes Werkzeug zur Profilerstellung, mit einer beeindruckenden Palette von Eigenschaften zur Diagnose von Systemereignissen. Es kann auch dazu verwendet werden, bestehende Skripte ablaufen zu lassen, um einen Nutzen aus deren Möglichkeiten zu ziehen. Nutzer können mittels der Programmiersprache D von DTrace ihre eigenen Hilfsmittel schreiben, was es ermöglicht, die eigenen Profile nach Ihren Bedürfnissen anzupassen.

Die DTrace-Implementierung in FreeBSD bietet experimentelle Unterstützung für DTrace im Userland. Userland DTrace erlaubt es Anwendern, function boundary tracing für Anwendungsprogramme über den pid-Provider hinweg vorzunehmen und um statische Sonden in Anwendungsprogramme für die spätere Aufzeichnung einzufügen. Manche Ports, wie beispielsweise databases/postgresql12-server und lang/php74 besitzen eine DTrace-Option, um statische Sonden zu aktivieren.

Eine offizielle Anleitung für DTrace wird vom Illumos Projekt im DTrace Guide bereitgestellt.

Nachdem Sie dieses Kapitel gelesen haben, werden Sie Folgendes wissen:

  • Was DTrace ist und welche Funktionen es zur Verfügung stellt.

  • Unterschiede zwischen der Solaris™ DTrace Implementierung und derjenigen, die FreeBSD bereitstellt.

  • Wie man DTrace auf FreeBSD aktiviert und verwendet.

Bevor Sie dieses Kapitel lesen, sollten Sie:

Diese Funktion ist als experimentell anzusehen. Manche Einstellungen enthalten möglicherweise nicht alle Funktionalitäten, andere Teile könnten gar nicht laufen. Mit der Zeit, wenn diese Funktion als für den Produktivbetrieb geeignet erscheint, wird auch diese Dokumentation geändert, um diesem Umstand gerecht zu werden.

24.2. Unterschiede in der Implementierung

Obwohl DTrace in FreeBSD sehr ähnlich zu dem in Solaris™ ist, existieren doch Unterschiede. Der Hauptunterschied besteht darin, dass in FreeBSD DTrace als eine Menge von Kernelmodulen implementiert ist und DTrace nicht verwendet werden kann, bis diese Module geladen wurden. Um alle nötigen Module zu laden, geben Sie ein:

# kldload dtraceall

Beginnend mit FreeBSD 10.0-RELEASE werden die Module automatisch geladen, sobald dtrace aufgerufen wird.

FreeBSD verwendet die Kerneloption DDB_CTF, um die Unterstützung im Kernel für das Laden von CTF-Daten aus Kernelmodulen und dem Kernel selbst zu ermöglichen. CTF ist das Compact C Type Format von Solaris™, welches eine reduzierte Form von Debug-Informationen kapselt, ähnlich zu DWARF und den antiken Stabs. Diese CTF-Daten werden dem Binärcode von den ctfconvert und ctfmerge Befehlen den Werkzeugen zum Bauen des Systems hinzugefügt. Das ctfconvert-Dienstprogramm parst die vom Compiler erstellten DWARFELF Debug-Abschnitte und ctfmerge vereint CTFELF-Abschnitte aus Objekten, entweder in ausführbare Dateien oder Shared-Libraries.

Einige Provider in FreeBSD unterscheiden sich von der Solaris™-Implementierung. Am deutlichsten wird das beim dtmalloc-Provider, welcher das Aufzeichnen von malloc() nach Typen im FreeBSD-Kernel ermöglicht. Manche der Provider in Solaris™ wie cpc und mib sind in FreeBSD nicht vorhanden. Diese können in zukünftigen FreeBSD-Versionen auftauchen. Weiterhin sind manche der Provider in beiden Betriebssystemen nicht zueinander kompatibel, in dem Sinne daß deren Sonden unterschiedliche Argumenttypen aufweisen. Dadurch können D-Skripte, die unter Solaris™ geschrieben wurden, evtl. unter FreeBSD funktionieren oder auch nicht, umgekehrt ist das genauso.

In FreeBSD darf DTrace wegen unterschiedlicher Sicherheitskonzepte nur von root verwendet werden. Solaris™ besitzt ein paar Audit-Funktionen auf den unteren Ebenen, die noch nicht in FreeBSD implementiert sind. Deshalb kann nur root auf /dev/dtrace/dtrace zugreifen.

Zum Schluss muss noch erwähnt werden, dass die DTrace-Software unter die CDDL Lizenz fällt. Die Common Development and Distribution License wird von FreeBSD mitgeliefert, sehen Sie sich dazu /usr/src/cddl/contrib/opensolaris/OPENSOLARIS.LICENSE an, oder lesen Sie die Online-Version unter http://opensource.org/licenses/CDDL-1.0. Während der FreeBSD-Kernel mit den DTrace-Optionen immer noch BSD-lizenziert ist, tritt die CDDL in Kraft, wenn Module in Binärform vertrieben werden oder die Binärdateien geladen werden.

24.3. Die DTrace Unterstützung aktivieren

In FreeBSD 9.2 und 10.0 ist die Unterstützung von DTrace im GENERIC-Kernel bereits eingebaut. Nutzer von früheren Versionen sollten die folgenden Zeilen in eine eigene Kernelkonfigurationsdatei einfügen und den Kernel mittels der Anleitung in Konfiguration des FreeBSD-Kernels neu übersetzen:

options         KDTRACE_HOOKS
options         DDB_CTF
makeoptions         DEBUG=-g
makeoptions         WITH_CTF=1

Besitzer der AMD64-Architektur werden wahrscheinlich noch die folgende Zeile zur Kernelkonfigurationsdatei hinzufügen:

options         KDTRACE_FRAME

Diese Option liefert die Unterstützung für die FBT-Eigenschaft. DTrace wird auch ohne diese Option funktionieren; jedoch wird dann Function Boundary Tracing nur eingeschränkt unterstützt.

Sobald FreeBSD in den neuen Kernel gebootet oder die DTrace-Kernelmodule mittels kldload dtraceall geladen wurden, benötigt das System Unterstützung für die Korn-Shell, da DTrace mehrere Dienstprogramme enthält, die in ksh implementiert sind. Vergewissern Sie sich, dass das Paket oder der Port shells/ksh93 installiert ist. Es ist auch möglich, diese Werkzeuge unter shells/pdksh oder shells/mksh laufen zu lassen.

Zum Schluss sollten Sie noch den aktuellen DTrace-Werkzeugsatz beschaffen. Die DTrace-Werkzeugsammlung enthält gebrauchsfertige Skripte, um Systeminformationen zu sammeln. Es gibt Skripte zum Überprüfen von offenen Dateien, Speicher- und CPU-Gebrauch und noch viel mehr. FreeBSD 10 installiert ein paar dieser Skripte in /usr/shared/dtrace. Für andere FreeBSD-Versionen oder um die volle DTrace-Werkzeugsammlung zu installieren, verwenden Sie den sysutils/dtrace-toolkit Port oder das Paket.

Die Skripte in /usr/shared/dtrace wurden speziell für FreeBSD portiert. Nicht alle Skripte in der DTrace-Werkzeugsammlung werden in FreeBSD unverändert funktionieren und manche Skript benötigen einigen Aufwand, damit diese auf FreeBSD funktionieren.

Der DTrace-Werkzeugsatz beinhaltet viele Skripte in der speziellen Sprache von DTrace. Diese Sprache wird die D-Sprache genannt und ist sehr ähnlich zu C++. Eine detaillierte Beschreibung dieser Sprache würde den Rahmen dieses Dokuments sprengen. Im Illumos Dynamic Tracing Guide wird diese Sprache ausführlich beschrieben.

24.4. DTrace verwenden

DTrace-Skripte bestehen aus einer Liste von einer oder mehreren Sonden oder Instrumentationspunkten, an denen jede Sonde mit einer Aktion verknüpft ist. Jedesmal, wenn die Bedingung für eine Sonde zutrifft, wird die verknüpfte Aktion ausgeführt. Beispielsweise könnte eine Aktion ausgeführt werden, wenn eine Datei geöffnet, ein Prozess gestartet oder eine Codezeile ausgeführt wird. Die Aktion könnte die Protokollierung von Informationen sein oder die Änderung von Kontextvariablen. Das Lesen und Schreiben von Kontextvariablen erlaubt es den Sonden, Informationen auszutauschen und kooperativ die Korrelation bestimmter Ereignisse zu analysieren.

Um alle Sonden anzuzeigen, kann der Administrator nun den folgenden Befehl eingeben:

# dtrace -l | more

Jede Sonde besitzt eine ID, einen PROVIDER (dtrace oder fbt), ein MODULE und einen FUNCTION NAME. Lesen Sie dtrace(1) für weitere Informationen zu diesem Kommando.

Die Beispiele in diesem Abschnitt geben einen Überblick, wie man zwei dieser voll funktionsfähigen Skripte aus der DTrace-Werkzeugsammlung verwendet: die Skripte hotkernel und procsystime.

Das hotkernel Skript wurde entworfen, um zu identifizieren, welche Funktion die meiste Kernelzeit beansprucht. Es wird es Ausgaben ähnlich der Folgenden produzieren:

# cd /usr/local/share/dtrace-toolkit
# ./hotkernel
Sampling... Hit Ctrl-C to end.

Verwenden Sie wie angegeben die Tastenkombination Ctrl+C drücken, um den Prozess zu stoppen. Nach dem Abbruch wird das Skript eine Liste von Kernelfunktionen und Zeitmessungen ausgeben, aufsteigend sortiert nach den Zeiten:

kernel`_thread_lock_flags                                   2   0.0%
0xc1097063                                                  2   0.0%
kernel`sched_userret                                        2   0.0%
kernel`kern_select                                          2   0.0%
kernel`generic_copyin                                       3   0.0%
kernel`_mtx_assert                                          3   0.0%
kernel`vm_fault                                             3   0.0%
kernel`sopoll_generic                                       3   0.0%
kernel`fixup_filename                                       4   0.0%
kernel`_isitmyx                                             4   0.0%
kernel`find_instance                                        4   0.0%
kernel`_mtx_unlock_flags                                    5   0.0%
kernel`syscall                                              5   0.0%
kernel`DELAY                                                5   0.0%
0xc108a253                                                  6   0.0%
kernel`witness_lock                                         7   0.0%
kernel`read_aux_data_no_wait                                7   0.0%
kernel`Xint0x80_syscall                                     7   0.0%
kernel`witness_checkorder                                   7   0.0%
kernel`sse2_pagezero                                        8   0.0%
kernel`strncmp                                              9   0.0%
kernel`spinlock_exit                                       10   0.0%
kernel`_mtx_lock_flags                                     11   0.0%
kernel`witness_unlock                                      15   0.0%
kernel`sched_idletd                                       137   0.3%
0xc10981a5                                              42139  99.3%

Dieses Skript funktioniert auch mit Kernelmodulen. Um diese Eigenschaft zu verwenden, starten Sie das Skript mit -m:

# ./hotkernel -m
Sampling... Hit Ctrl-C to end.
^C
MODULE                                                  COUNT   PCNT
0xc107882e                                                  1   0.0%
0xc10e6aa4                                                  1   0.0%
0xc1076983                                                  1   0.0%
0xc109708a                                                  1   0.0%
0xc1075a5d                                                  1   0.0%
0xc1077325                                                  1   0.0%
0xc108a245                                                  1   0.0%
0xc107730d                                                  1   0.0%
0xc1097063                                                  2   0.0%
0xc108a253                                                 73   0.0%
kernel                                                    874   0.4%
0xc10981a5                                             213781  99.6%

Das procsystime Skript fängt die Systemaufruf-Zeiten für eine gegebene Prozess-ID (PID) oder einen Prozessnamen ab und gibt diese aus. Im folgenden Beispiel wurde eine neue Instanz von /bin/csh erzeugt. Dann wurde procsystime ausgeführt und verbleibt so, während ein paar Befehle in die andere Instanz von csh eingegeben werden. Dies sind die Ergebnisse dieses Versuchs:

# ./procsystime -n csh
Tracing... Hit Ctrl-C to end...
^C

Elapsed Times for processes csh,

         SYSCALL          TIME (ns)
          getpid               6131
       sigreturn               8121
           close              19127
           fcntl              19959
             dup              26955
         setpgid              28070
            stat              31899
       setitimer              40938
           wait4              62717
       sigaction              67372
     sigprocmask             119091
    gettimeofday             183710
           write             263242
          execve             492547
           ioctl             770073
           vfork            3258923
      sigsuspend            6985124
            read         3988049784

Wie aus der Ausgabe ersichtlich ist, verbraucht der read()-Systemaufruf die meiste Zeit in Nanosekunden, während der Systemaufruf getpid() hingegen am schnellsten läuft.


Last modified on: 11. Dezember 2021 by Sergio Carlavilla Delgado