Handbuch zur dynamischen Ablaufverfolgung in Solaris

Beispiele

Das folgende Beispielskript zeigt bei der Ausgabe jeder E/A einschlägige Informationen an:

#pragma D option quiet

BEGIN
{
	printf("%10s %58s %2s\n", "DEVICE", "FILE", "RW");
}

io:::start
{
	printf("%10s %58s %2s\n", args[1]->dev_statname,
	    args[2]->fi_pathname, args[0]->b_flags & B_READ ? "R" : "W");
}

Bei einem Kaltstart von Acrobat Reader auf einem x86-Laptop erhalten wir eine Ausgabe der Art:


# dtrace -s ./iosnoop.d
    DEVICE                                                       FILE RW
     cmdk0                                 /opt/Acrobat4/bin/acroread  R
     cmdk0                                 /opt/Acrobat4/bin/acroread  R
     cmdk0                                                  <unknown>  R
     cmdk0                           /opt/Acrobat4/Reader/AcroVersion  R
     cmdk0                                                  <unknown>  R
     cmdk0                                                  <unknown>  R
     cmdk0                                                     <none>  R
     cmdk0                                                  <unknown>  R
     cmdk0                                                     <none>  R
     cmdk0                 /usr/lib/locale/iso_8859_1/iso_8859_1.so.3  R
     cmdk0                 /usr/lib/locale/iso_8859_1/iso_8859_1.so.3  R
     cmdk0                 /usr/lib/locale/iso_8859_1/iso_8859_1.so.3  R
     cmdk0                                                     <none>  R
     cmdk0                                                  <unknown>  R
     cmdk0                                                  <unknown>  R
     cmdk0                                                  <unknown>  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0                                                     <none>  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0                                                  <unknown>  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0                                                     <none>  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0   /opt/Acrobat4/Reader/intelsolaris/lib/libreadcore.so.4.0  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0             /opt/Acrobat4/Reader/intelsolaris/bin/acroread  R
     cmdk0                                                  <unknown>  R
     cmdk0        /opt/Acrobat4/Reader/intelsolaris/lib/libAGM.so.3.0  R
     cmdk0                                                     <none>  R
     cmdk0        /opt/Acrobat4/Reader/intelsolaris/lib/libAGM.so.3.0  R
     cmdk0        /opt/Acrobat4/Reader/intelsolaris/lib/libAGM.so.3.0  R
       ...

Die <none>-Einträge in der Ausgabe deuten darauf hin, dass sich die E/A auf keine der Daten in einer bestimmten Datei bezieht: Diese E/A-Operationen beziehen sich auf Metadaten in der einen oder anderen Form. Die <unknown>-Einträge in der Ausgabe bedeuten, dass der Pfadname der Datei unbekannt ist. Diese Situation ergibt sich relativ selten.

Das Beispielskript ließe sich durch einen assoziativen Vektor zum Erfassen der Dauer jeder E/A ein wenig verfeinern. Dies zeigt das nächste Beispiel:

#pragma D option quiet

BEGIN
{
	printf("%10s %58s %2s %7s\n", "DEVICE", "FILE", "RW", "MS");
}

io:::start
{
	start[args[0]->b_edev, args[0]->b_blkno] = timestamp;
}

io:::done
/start[args[0]->b_edev, args[0]->b_blkno]/
{
	this->elapsed = timestamp - start[args[0]->b_edev, args[0]->b_blkno];
	printf("%10s %58s %2s %3d.%03d\n", args[1]->dev_statname,
	    args[2]->fi_pathname, args[0]->b_flags & B_READ ? "R" : "W",
	    this->elapsed / 10000000, (this->elapsed / 1000) % 1000);
	start[args[0]->b_edev, args[0]->b_blkno] = 0;
}

Das nächste Beispiel zeigt die Ausgabe des obigen Beispielskripts beim Hot-Plugging eines USB-Speichergeräts in ein ansonsten im Ruhezustand befindliches x86-Laptop-System:


# dtrace -s ./iotime.d
    DEVICE                                                 FILE RW      MS
     cmdk0                                 /kernel/drv/scsa2usb  R  24.781
     cmdk0                                 /kernel/drv/scsa2usb  R  25.208
     cmdk0                                    /var/adm/messages  W  25.981
     cmdk0                                 /kernel/drv/scsa2usb  R   5.448
     cmdk0                                               <none>  W   4.172
     cmdk0                                 /kernel/drv/scsa2usb  R   2.620
     cmdk0                                    /var/adm/messages  W   0.252
     cmdk0                                            <unknown>  R   3.213
     cmdk0                                               <none>  W   3.011
     cmdk0                                            <unknown>  R   2.197
     cmdk0                                    /var/adm/messages  W   2.680
     cmdk0                                               <none>  W   0.436
     cmdk0                                    /var/adm/messages  W   0.542
     cmdk0                                               <none>  W   0.339
     cmdk0                                    /var/adm/messages  W   0.414
     cmdk0                                               <none>  W   0.344
     cmdk0                                    /var/adm/messages  W   0.361
     cmdk0                                               <none>  W   0.315
     cmdk0                                    /var/adm/messages  W   0.421
     cmdk0                                               <none>  W   0.349
     cmdk0                                               <none>  R   1.524
     cmdk0                                            <unknown>  R   3.648
     cmdk0                                 /usr/lib/librcm.so.1  R   2.553
     cmdk0                                 /usr/lib/librcm.so.1  R   1.332
     cmdk0                                 /usr/lib/librcm.so.1  R   0.222
     cmdk0                                 /usr/lib/librcm.so.1  R   0.228
     cmdk0                                 /usr/lib/librcm.so.1  R   0.927
     cmdk0                                               <none>  R   1.189
       ...
     cmdk0                            /usr/lib/devfsadm/linkmod  R   1.110
     cmdk0         /usr/lib/devfsadm/linkmod/SUNW_audio_link.so  R   1.763
     cmdk0         /usr/lib/devfsadm/linkmod/SUNW_audio_link.so  R   0.161
     cmdk0           /usr/lib/devfsadm/linkmod/SUNW_cfg_link.so  R   0.819
     cmdk0           /usr/lib/devfsadm/linkmod/SUNW_cfg_link.so  R   0.168
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_disk_link.so  R   0.886
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_disk_link.so  R   0.185
     cmdk0        /usr/lib/devfsadm/linkmod/SUNW_fssnap_link.so  R   0.778
     cmdk0        /usr/lib/devfsadm/linkmod/SUNW_fssnap_link.so  R   0.166
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_lofi_link.so  R   1.634
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_lofi_link.so  R   0.163
     cmdk0            /usr/lib/devfsadm/linkmod/SUNW_md_link.so  R   0.477
     cmdk0            /usr/lib/devfsadm/linkmod/SUNW_md_link.so  R   0.161
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_misc_link.so  R   0.198
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_misc_link.so  R   0.168
     cmdk0          /usr/lib/devfsadm/linkmod/SUNW_misc_link.so  R   0.247
     cmdk0     /usr/lib/devfsadm/linkmod/SUNW_misc_link_i386.so  R   1.735
       ... 

Diese Ausgabe lässt verschiedene Folgerungen über die Mechanik des Systems zu. Beachten Sie erstens, die lange Durchführungsdauer der ersten E/A-Operationen, die je 25 Millisekunden betrug. Diese Dauer kann darauf zurückzuführen sein, dass das Gerät cmdk0 dem Power-Management auf dem Laptop unterzogen wurde. Zweitens fällt die E/A durch das Laden des Treibers scsa2usb(7D) für die Behandlung des USB-Massenspeichergeräts auf. Drittens sind die Schreibzugriffe auf /var/adm/messages bei Meldung des Geräts zu beachten. Beachten Sie abschließend die Leszugriffe der Geräte-Link-Generatoren (die auf link.so endenden Dateien), die sich wahrscheinlich auf das neue Gerät beziehen.

Der Provider io ermöglicht eine tief greifende Interpretation der Ausgabe von iostat(1M). Nehmen wir an, es werde eine iostat-Ausgabe wie in folgendem Beispiel beobachtet:


extended device statistics
device       r/s    w/s   kr/s   kw/s wait actv  svc_t  %w  %b
cmdk0        8.0    0.0  399.8    0.0  0.0  0.0    0.8   0   1
sd0          0.0    0.0    0.0    0.0  0.0  0.0    0.0   0   0
sd2          0.0  109.0    0.0  435.9  0.0  1.0    8.9   0  97
nfs1         0.0    0.0    0.0    0.0  0.0  0.0    0.0   0   0
nfs2         0.0    0.0    0.0    0.0  0.0  0.0    0.0   0   0

Mit dem Skript iotime.d können wir diese E/A-Operationen, wie das nächste Beispiel zeigt, im Moment ihres Auftretens anzeigen:


    DEVICE                                               FILE RW      MS
       sd2                                  /mnt/archives.tar  W   0.856
       sd2                                  /mnt/archives.tar  W   0.729
       sd2                                  /mnt/archives.tar  W   0.890
       sd2                                  /mnt/archives.tar  W   0.759
       sd2                                  /mnt/archives.tar  W   0.884
       sd2                                  /mnt/archives.tar  W   0.746
       sd2                                  /mnt/archives.tar  W   0.891
       sd2                                  /mnt/archives.tar  W   0.760
       sd2                                  /mnt/archives.tar  W   0.889
     cmdk0                      /export/archives/archives.tar  R   0.827
       sd2                                  /mnt/archives.tar  W   0.537
       sd2                                  /mnt/archives.tar  W   0.887
       sd2                                  /mnt/archives.tar  W   0.763
       sd2                                  /mnt/archives.tar  W   0.878
       sd2                                  /mnt/archives.tar  W   0.751
       sd2                                  /mnt/archives.tar  W   0.884
       sd2                                  /mnt/archives.tar  W   0.760
       sd2                                  /mnt/archives.tar  W   3.994
       sd2                                  /mnt/archives.tar  W   0.653
       sd2                                  /mnt/archives.tar  W   0.896
       sd2                                  /mnt/archives.tar  W   0.975
       sd2                                  /mnt/archives.tar  W   1.405
       sd2                                  /mnt/archives.tar  W   0.724
       sd2                                  /mnt/archives.tar  W   1.841
     cmdk0                      /export/archives/archives.tar  R   0.549
       sd2                                  /mnt/archives.tar  W   0.543
       sd2                                  /mnt/archives.tar  W   0.863
       sd2                                  /mnt/archives.tar  W   0.734
       sd2                                  /mnt/archives.tar  W   0.859
       sd2                                  /mnt/archives.tar  W   0.754
       sd2                                  /mnt/archives.tar  W   0.914
       sd2                                  /mnt/archives.tar  W   0.751
       sd2                                  /mnt/archives.tar  W   0.902
       sd2                                  /mnt/archives.tar  W   0.735
       sd2                                  /mnt/archives.tar  W   0.908
       sd2                                  /mnt/archives.tar  W   0.753

Diese Ausgabe lässt die Vermutung zu, dass die Datei archives.tar von cmdk0 eingelesen (in /export/archives) und auf das Gerät sd2 (in /mnt) geschrieben wird. Das Vorhandensein von zwei Dateien mit dem Namen archives.tar, auf die separat, aber gleichzeitig zugegriffen wird, wirkt unwahrscheinlich. Um dem weiter auf den Grund zu gehen, können Sie, wie das nächste Beispiel zeigt, Gerät, Anwendung, Prozess-ID und übertragene Byte aggregieren:

#pragma D option quiet

io:::start
{
	@[args[1]->dev_statname, execname, pid] = sum(args[0]->b_bcount);
}

END
{
	printf("%10s %20s %10s %15s\n", "DEVICE", "APP", "PID", "BYTES");
	printa("%10s %20s %10d %15@d\n", @);
}

Wenn Sie dieses Skript einige Sekunden lang ausführen, erhalten Sie eine Ausgabe wie in folgendem Beispiel:


# dtrace -s ./whoio.d
^C
    DEVICE                  APP        PID           BYTES
     cmdk0                   cp        790         1515520
       sd2                   cp        790         1527808

Die Ausgabe zeigt, dass es sich bei dieser Aktivität tatsächlich um das Kopieren der Datei archives.tar von einem Gerät auf ein anderes handelt. Daraus folgt jedoch eine weitere nahe liegende Frage: Ist eines der Geräte schneller als das andere? Welches Gerät beschränkt den Kopiervorgang? Um diese Fragen zu beantworten, müssen wir anstelle der pro Sekunde übertragenen Byte den effektiven Datendurchsatz jedes Geräts in Erfahrung bringen. Dabei hilft uns das nächste Beispielskript:

#pragma D option quiet

io:::start
{
	start[args[0]->b_edev, args[0]->b_blkno] = timestamp;
}

io:::done
/start[args[0]->b_edev, args[0]->b_blkno]/
{
	/*
	 * We want to get an idea of our throughput to this device in KB/sec.
	 * What we have, however, is nanoseconds and bytes.  That is we want
	 * to calculate:
	 *
	 *                        bytes / 1024
	 *                  ------------------------
	 *                  nanoseconds / 1000000000
	 *
	 * But we can't calculate this using integer arithmetic without losing
	 * precision (the denomenator, for one, is between 0 and 1 for nearly
	 * all I/Os).  So we restate the fraction, and cancel:
	 *
	 *     bytes      1000000000         bytes        976562
	 *   --------- * -------------  =  --------- * -------------
	 *      1024      nanoseconds          1        nanoseconds
	 *
	 * This is easy to calculate using integer arithmetic; this is what
	 * we do below.
	 */
	this->elapsed = timestamp - start[args[0]->b_edev, args[0]->b_blkno];
	@[args[1]->dev_statname, args[1]->dev_pathname] =
	    quantize((args[0]->b_bcount * 976562) / this->elapsed);
	start[args[0]->b_edev, args[0]->b_blkno] = 0;
}

END
{
	printa("  %s (%s)\n%@d\n", @);
}

Wenn Sie das Beispielskript einige Sekunden lang ausführen, erhalten Sie die folgende Ausgabe:


  sd2 (/devices/pci@0,0/pci1179,1@1d/storage@2/disk@0,0:r)

           value  ------------- Distribution ------------- count
              32 |                                         0
              64 |                                         3
             128 |                                         1
             256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  2257
             512 |                                         1
            1024 |                                         0

  cmdk0 (/devices/pci@0,0/pci-ide@1f,1/ide@0/cmdk@0,0:a)

           value  ------------- Distribution ------------- count
             128 |                                         0
             256 |                                         1
             512 |                                         0
            1024 |                                         2
            2048 |                                         0
            4096 |                                         2
            8192 |@@@@@@@@@@@@@@@@@@                       172
           16384 |@@@@@                                    52
           32768 |@@@@@@@@@@@                              108
           65536 |@@@                                      34
          131072 |                                         0        

Die Ausgabe zeigt, dass sd2 eindeutig das beschränkende Gerät ist. Der Durchsatz von sd2 liegt zwischen 256K/s und 512K/s, während cmdk0 eine E/A-Leistung von 8 MB/s bis zu über 64 MB/s bietet. Das Skript gibt sowohl den Namen, wie er in iostat angezeigt wird, als auch den vollständigen Pfadnamen des Geräts aus. Wenn Sie mehr über das Gerät herausfinden möchten, könnten Sie wie folgt den Gerätepfad zu prtconf angeben:


# prtconf -v /devices/pci@0,0/pci1179,1@1d/storage@2/disk@0,0
disk, instance #2 (driver name: sd)
    Driver properties:
        name='lba-access-ok' type=boolean dev=(29,128)
        name='removable-media' type=boolean dev=none
        name='pm-components' type=string items=3 dev=none
            value='NAME=spindle-motor' + '0=off' + '1=on'
        name='pm-hardware-state' type=string items=1 dev=none
            value='needs-suspend-resume'
        name='ddi-failfast-supported' type=boolean dev=none
        name='ddi-kernel-ioctl' type=boolean dev=none
    Hardware properties:
        name='inquiry-revision-id' type=string items=1
            value='1.04'
        name='inquiry-product-id' type=string items=1
            value='STORAGE DEVICE'
        name='inquiry-vendor-id' type=string items=1
            value='Generic'
        name='inquiry-device-type' type=int items=1
            value=00000000
        name='usb' type=boolean
        name='compatible' type=string items=1
            value='sd'
        name='lun' type=int items=1
            value=00000000
        name='target' type=int items=1
            value=00000000

Die hervorgehobenen Bezeichnungen deuten darauf hin, dass es sich um einen austauschbaren USB-Datenträger handelt.

In den Beispielen dieses Abschnitts wurden alle E/A-Anforderungen untersucht. Möglicherweise interessiert Sie aber nur eine bestimmte Anforderungsart. Das folgende Beispiel protokolliert die Verzeichnisse, in denen Schreibzugriffe stattfinden, sowie die Anwendungen, die diese Schreibzugriffe durchführen.

#pragma D option quiet

io:::start
/args[0]->b_flags & B_WRITE/
{
	@[execname, args[2]->fi_dirname] = count();
}

END
{
	printf("%20s %51s %5s\n", "WHO", "WHERE", "COUNT");
	printa("%20s %51s %5@d\n", @);
}

Wenn Sie dieses Beispielskript eine Weile auf einem belegten Desktop ausführen, erhalten Sie, wie die nächste Beispielausgabe zeigt, einige interessante Ergebnisse:


# dtrace -s ./whowrite.d
^C
              WHO                                             WHERE COUNT
               su                                          /var/adm     1
          fsflush                                              /etc     1
          fsflush                                                 /     1
          fsflush                                          /var/log     1
          fsflush                                  /export/bmc/lisa     1
              esd   /export/bmc/.phoenix/default/78cxczuy.slt/Cache     1
          fsflush                              /export/bmc/.phoenix     1
              esd         /export/bmc/.phoenix/default/78cxczuy.slt     1
               vi                                          /var/tmp     2
               vi                                              /etc     2
              cat                                            <none>     2
             bash                                                 /     2
               vi                                            <none>     3
            xterm                                          /var/adm     3
          fsflush                                       /export/bmc     7
  MozillaFirebird                                            <none>     8
              vim                                       /export/bmc     9
  MozillaFirebird                                       /export/bmc    10
          fsflush                                          /var/adm    11
         devfsadm                                              /dev    14
              ksh                                            <none>    71
              ksh                                       /export/bmc    71
          fsflush         /export/bmc/.phoenix/default/78cxczuy.slt   119
  MozillaFirebird         /export/bmc/.phoenix/default/78cxczuy.slt   119
          fsflush                                            <none>   211
  MozillaFirebird   /export/bmc/.phoenix/default/78cxczuy.slt/Cache   591
          fsflush   /export/bmc/.phoenix/default/78cxczuy.slt/Cache   666
            sched                                            <none>  2385

Wie aus der Ausgabe hervorgeht, beziehen sich nahezu alle Schreibvorgänge auf den Cache für Mozilla Firebird. Die mit <none> gekennzeichneten Schreibzugriffe gehen wahrscheinlich auf das UFS-Protokoll zurück und wurden ihrerseits durch andere Schreibvorgänge im Dateisystem ausgelöst. Ausführliche Informationen zur Protokollierung finden Sie unter ufs(7FS) Dieses Beispiel demonstriert, wie mithilfe des Providers io Probleme auf wesentlich höheren Softwareebenen entdeckt werden können. In diesem Fall hat das Skript ein Konfigurationsproblem aufgespürt: Der Webbrowser würde sehr viel weniger E/A verursachen (sehr wahrscheinlich sogar überhaupt keine), wenn sich sein Cache in einem Verzeichnis in einem tmpfs(7FS)-Dateisystem befände.

In den bisherigen Beispielen kamen nur die Prüfpunkte start und done zum Einsatz. Mithilfe der Prüfpunkte wait-start und wait-done können wir der Frage auf den Grund gehen, weshalb und wie lange Anwendungen in Erwartung von E/A blockieren. Im folgenden Beispielskript werden sowohl io- als auch sched-Prüfpunkte (siehe Kapitel 26Der Provider sched) verwendet und die CPU-Zeit im Vergleich zur E/A-Wartezeit für die StarOffice-Software abgeleitet:

#pragma D option quiet

sched:::on-cpu
/execname == "soffice.bin"/
{
	self->on = vtimestamp;
}

sched:::off-cpu
/self->on/
{
	@time["<on cpu>"] = sum(vtimestamp - self->on);
	self->on = 0;
}

io:::wait-start
/execname == "soffice.bin"/
{
	self->wait = timestamp;
}

io:::wait-done
/self->wait/
{
	@io[args[2]->fi_name] = sum(timestamp - self->wait);
	@time["<I/O wait>"] = sum(timestamp - self->wait);
	self->wait = 0;
}

END
{
	printf("Time breakdown (milliseconds):\n");
	normalize(@time, 1000000);
	printa("  %-50s %15@d\n", @time);

	printf("\nI/O wait breakdown (milliseconds):\n");
	normalize(@io, 1000000);
	printa("  %-50s %15@d\n", @io);
}

Wenn Sie das Beispielskript während eines Kaltstarts von StarOffice ausführen, erhalten Sie folgende Ausgabe:


Time breakdown (milliseconds):
  <on cpu>                                                      3634
  <I/O wait>                                                   13114

I/O wait breakdown (milliseconds):
  soffice.tmp                                                      0
  Office                                                           0
  unorc                                                            0
  sbasic.cfg                                                       0
  en                                                               0
  smath.cfg                                                        0
  toolboxlayout.xml                                                0
  sdraw.cfg                                                        0
  swriter.cfg                                                      0
  Linguistic.dat                                                   0
  scalc.cfg                                                        0
  Views.dat                                                        0
  Store.dat                                                        0
  META-INF                                                         0
  Common.xml.tmp                                                   0
  afm                                                              0
  libsimreg.so                                                     1
  xiiimp.so.2                                                      3
  outline                                                          4
  Inet.dat                                                         6
  fontmetric                                                       6
  ...
  libucb1.so                                                      44
  libj641si_g.so                                                  46
  libX11.so.4                                                     46
  liblng641si.so                                                  48
  swriter.db                                                      53
  libwrp641si.so                                                  53
  liblocaledata_ascii.so                                          56
  libi18npool641si.so                                             65
  libdbtools2.so                                                  69
  ofa64101.res                                                    74
  libxcr641si.so                                                  82
  libucpchelp1.so                                                 83
  libsot641si.so                                                  86
  libcppuhelper3C52.so                                            98
  libfwl641si.so                                                 100
  libsb641si.so                                                  104
  libcomphelp2.so                                                105
  libxo641si.so                                                  106
  libucpfile1.so                                                 110
  libcppu.so.3                                                   111
  sw64101.res                                                    114
  libdb-3.2.so                                                   119
  libtk641si.so                                                  126
  libdtransX11641si.so                                           127
  libgo641si.so                                                  132
  libfwe641si.so                                                 150
  libi18n641si.so                                                152
  libfwi641si.so                                                 154
  libso641si.so                                                  173
  libpsp641si.so                                                 186
  libtl641si.so                                                  189
  <unknown>                                                      189
  libucbhelper1C52.so                                            195
  libutl641si.so                                                 213
  libofa641si.so                                                 216
  libfwk641si.so                                                 229
  libsvl641si.so                                                 261
  libcfgmgr2.so                                                  368
  libsvt641si.so                                                 373
  libvcl641si.so                                                 741
  libsvx641si.so                                                 885
  libsfx641si.so                                                 993
  <none>                                                        1096
  libsw641si.so                                                 1365
  applicat.rdb                                                  1580

Wie diese Ausgabe zeigt, wird die meiste Wartezeit beim StarOffice-Kaltstart vom Warten auf E/A-Operationen verursacht (13,1 s Wartezeit auf E/A im Vergleich zu 3,6 s Wartezeit auf CPU-Operationen). Führen wir das Skript bei einem Warmstart von StarOffice aus, wird deutlich, dass die E/A-Zeit durch Seiten-Caching eliminiert wurde:


Time breakdown (milliseconds):
  <I/O wait>                                                       0
  <on cpu>                                                      2860

I/O wait breakdown (milliseconds):
  temp                                                             0
  soffice.tmp                                                      0
  <unknown>                                                        0
  Office                                                           0

In der Kaltstart-Ausgabe sehen wir für die Datei applicat.rdb mehr E/A-Wartezeit als für jede andere Datei. Es ist anzunehmen, dass zahlreiche E/A-Zugriffe auf die Datei stattgefunden haben. Um diese weiter zu untersuchen, bedienen wir uns des folgenden D-Skripts:

io:::start
/execname == "soffice.bin" && args[2]->fi_name == "applicat.rdb"/
{
	@ = lquantize(args[2]->fi_offset != -1 ?
	    args[2]->fi_offset / (1000 * 1024) : -1, 0, 1000);
}

In diesem Skript wird das Feld fi_offset der Struktur fileinfo_t verwendet, das uns Aufschluss über die Dateibereiche geben soll, auf die zugegriffen wird. Dabei gilt eine Granularität von einem Megabyte. Wenn Sie dieses Skript während eines Kaltstarts von StarOffice ausführen, erhalten Sie eine Ausgabe wie diese:


# dtrace -s ./applicat.d
dtrace: script './applicat.d' matched 4 probes
^C


           value  ------------- Distribution ------------  count
             < 0 |                                         0
               0 |@@@                                      28
               1 |@@                                       17
               2 |@@@@                                     35
               3 |@@@@@@@@@                                72
               4 |@@@@@@@@@@                               78
               5 |@@@@@@@@                                 65
               6 |                                         0

Die Ausgabe sagt uns, dass nur auf die ersten sechs Megabyte der Datei zugegriffen wird, da die Datei möglicherweise sechs Megabyte groß ist. Außerdem deutet die Ausgabe darauf hin, dass nicht auf die gesamte Datei zugegriffen wird. Wollten wir nun die Kaltstartzeit für StarOffice verkürzen, wäre es hilfreich, das Zugriffsmuster der Datei zu verstehen. Wenn die benötigten Bereiche möglicherweise großteilig zusammenhängen, ließe sich die StarOffice-Kaltstartzeit beispielsweise mit einem Scout-Thread verbessern, der vor der Anwendung ausgeführt wird und die E/A-Zugriffe auf die Datei einleitet, noch bevor sie benötigt werden. (Dieser Ansatz ist dann besonders direkt, wenn der Zugriff auf die Datei über mmap(2) erfolgt.) Für die ca. 1,6 Sekunden Kaltstartzeit, die sich durch diese Strategie einsparen ließen, lohnt sich die zusätzliche Komplexität und Wartungslast in der Anwendung jedoch nicht. Auf jeden Fall ermöglichen die mit dem Provider io erhobenen Angaben ein genaues Verständnis der Vorteile, die durch einen solchen Aufwand zusätzlich erzielt werden könnten.