Danilo Poccia - Tecnologia et al.

giovedì mar 02, 2006

DTrace in Solaris 10 OS

DTrace è un framework per il tracciamento dinamico delle attività svolte dal sistema operativo Solaris 10. Il framework è composto da tre componenti principali:

  • una serie di sonde (probe) introdotte nel kernel di Solaris 10 OS, che possono essere o meno attivate, descritte in dtrace(7D);

  • una libreria di interfacciamento per accedere dallo spazio utente alle funzionalità del framework, libdtrace(3LIB);

  • alcuni comandi utente che permettono di accedere in modo completo alle informazioni che sono rilevate, su richiesta, dalle sonde, tra cui il comando, omonimo del framework, dtrace(1M).

     

Alcuni comandi di monitoraggio (ad es. lockstat, plockstat, intrstat) già presenti in versioni precedenti del sistema operativo Solaris sono stati re-implementati nella 10 tramite il framework DTrace.

Per vedere un esempio delle sonde è possibile lanciare il comando seguente e vedere le prime schermate:

# dtrace -l|more

Ogni sonda è individuata con un nome composto con la sintassi seguente: "provider:module:function:name".

Per avere una idea della numerosità delle sonde è possibile lanciare il comando:

# dtrace -l|wc -l

e sottrarre uno per la riga di intestazione. Quest'ultimo comando ritorna un numero superiore a 40.000 sul mio portatile con Solaris 10 1/06 x86 (32bit). Tale valore dipende dai moduli kernel (che implementano DTrace) caricati sul sistema.

Per testare le potenzialità di DTrace è possibile realizzare degli script in un apposito linguaggio denominato D Programming Language. Tale linguaggio ha una sintassi simile a quella dell'awk e non è quindi un linguaggio puramente procedurale, ma del tipo "pattern action", dove il pattern è un modo per selezionare alcune sonde e/o alcuni risultati particolari delle sonde, mentre con l'action si identificano le attività necessarie per elaborare le informazioni reperite.

Ad esempio un modo per registrarsi sulle sonde che monitorano le system call è possibile utilizzare il comando:

# dtrace -n 'syscall:::entry { trace(execname)}'|more

dove tra apici singoli è indicato il pattern ("syscall:::entry") e tra le parentesi graffe l'azione corrispondente ("trace(execname)"). Il pattern, che rispecchia la sintassi già indicata "provider:module:function:name", non specificando il module e la function, si registra su tutte le sonde che hanno provider="syscall" e name="entry". L'action indicata aggiunge, alle colonne standard dell'output del comando dtrace(1), il nome dell'eseguibile che ha effettuato la system call.

Lo stesso risultato si può ottenere utilizzando il seguente script (syscall.d):

 

#!/usr/sbin/dtrace -s
syscall:::entry
{
trace(execname);
}

 

Per raggruppare i risultati della sonda che monitora le system call per nome dell'eseguibile che le ha effettuate e funzione, lo script è il seguente (syscall2.d):

#!/usr/sbin/dtrace -s
syscall:::entry
{
@numCalls[execname,probefunc] = count();
}

Andando invece a verificare le system call in scrittura, il seguente script (writes.d) raggruppa le chiamate per nome dell'eseguibile:

#!/usr/sbin/dtrace -s
syscall::write:entry
{
@numWrites[execname] = count();
}

Nel caso delle scritture è però importante monitorare, oltre il numero di accessi, la dimensione del blocco utilizzato. Difatti molti problemi di performance sono poi legati proprio a questo aspetto. Le linee guida generali (che vanno di volta in volta contestualizzate all'architettura implementata) indicano che:

  • per letture/scritture sequenziali la dimensione del blocco dovrebbe essere "grande" (ad es. 32KB o superiori);

  • per letture/scritture random (ad es. via indice) la dimensione del blocco dovrebbe essere la più "piccola" che contiene la variazione richiesta con un unico accesso.

Il seguente script (writes2.d) restituisce per ogni eseguibile la dimensione media del blocco utilizzato nelle scritture via system call:

 

#!/usr/sbin/dtrace -s
syscall::write:entry
{
@avgSize[execname] = avg(arg2);
}

Con una semplice variazione (sostituendo la funzione avg con quantize) è possibile avere per ciascun eseguibile la distribuzione (su base potenze di 2) della dimensione del blocco utilizzato nelle scritture via system call (writes3.d):

 

#!/usr/sbin/dtrace -s
syscall::write:entry
{
@quantizeSize[execname] = quantize(arg2);
}

Per restringere l'analisi ad un solo eseguibile, è sufficiente aggiungere un predicato di ricerca tra doppi "/" (slash) nel pattern (writes4.d):

#!/usr/sbin/dtrace -s
syscall::write:entry
/execname == "soffice.bin"/
{
@quantizeSize[execname] = quantize(arg2);
}

Nel seguente esempio, in cui sono tracciate tutte le attività di I/O (iotrace.d), l'output standard del DTrace è disabilitato. Il pattern "BEGIN" è utilizzato per attivare la corrispondente action una volta all'inizio dell'esecuzione dello script, in questo caso per stampare una riga di intestazione:

#!/usr/sbin/dtrace -qs
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");
}

Per approfondire la sintassi e le funzionalità del framework è consigliabile consultare la Solaris Dynamic Tracing Guide.

Si possono utilizzare (e visionare) ulteriori script (più complessi dei precedenti) scaricando l'ultima versione del DTraceToolkit dal sito della comunità OpenSolaris.

Per ulteriori informazioni:

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed





    follow me on Twitter

    Calendar

    Feeds

    Search

    Blogroll

    Navigation

    Referrers

    Recent Entries