Il package res

Per chi desidera vedere subito la definizione delle classi, è disponibile la guida generata da javadoc.

La classe res.ProcessMonitor

Un oggetto di tipo ProcessMonitor non è altro che un monitor di processi. Per poter funzionare il codice Java deve caricare una DLL appropriata (ad esempio ps.dll in Windows, o libps.so nei sistemi UNIX). Se tale DLL non viene trovata, ad esempio perchè è stata posizionata in un percorso non corretto, verrà lanciata un'eccezione di avvertimento.
Una volta creato, il monitor è pronto a raccogliere informazioni su processi, thread e traffico di rete. Il meccanismo utilizzato è quello del polling, cioè le misurazioni vanno effettuate a intervalli regolari, passando l'intervallo di campionamento come parametro. Ad esempio le istruzioni:

  ProcessMonitor mon;
  NetworkInfo info;
  mon=new ProcessMonitor();
  for(;;)
    {
    info=mon.getNetworkInfo(5000);
    System.out.println("in: "+info.tcp_seg_in+" out: "+info.tcp_seg_out);
    }
permettono di raccogliere statistiche sulla rete ogni 5 secondi. Analogamente le istruzioni:
  ProcessMonitor mon;
  ProcessInfo[] array;
  mon=new ProcessMonitor();
  array=mon.getNetworkInfo(7000);
  for(i=0;i < array.length;i++)
    System.out.println("Process: "+array[i].name+" cpu%: "+array[i].cpu);
mostrano per tutti i processi il consumo di cpu, in percentuale, negli ultimi 7 secondi.

Capito il meccanismo, la cosa interessante è osservare quali misure siano disponibili e quale sia la loro semantica.
Per quanto riguarda la rete, le misure sono disponibili solo in forma aggregata (non è cioè possibile ottenere delle statistiche "per-processo"). La tabella mostra il contatore di interesse e il campo dell'oggetto NetworkInfo ove è disponibile.

misuracampo di NetworkInfo
Numero di pacchetti IP trasmessiint ip_pack_out
Numero totale di pacchetti IP ricevutiint ip_pack_in
Numero di pacchetti IP errati ricevutiint ip_pack_err
Numero di connessioni TCP attiveint tcp_conn
Numero di segmenti TCP trasmessiint tcp_seg_out
Numero di segmenti TCP ricevutiint tcp_seg_in
Numero di pacchetti UDP trasmessiint udp_pack_out
Numero totale di pacchetti UDP ricevutiint udp_pack_in
Numero di pacchetti UDP errati ricevutiint udp_pack_err

Per quanto riguarda i processi, le informazioni sono restituite mediante un array di oggetti ProcessInfo, ognuno riferito ad un ben preciso processo di sistema, identificato univocamente dal PID (Process IDentifier), e meglio riconosciuto dal suo nome. La tabella mostra il contatore di interesse e il campo dell'oggetto ProcessInfo ove è disponibile.

misuracampo di ProcessInfo
il PIDint pid
il nome (generalmente equivale alla riga di comandoString name
Il tempo di CPU, cumulativo, consumato dal processo dal suo inizio ad ora, in millisecondilong time
Il tempo di CPU, in percentuale, consumato dal processo nell'intervallo di misurazione. Il 100% è riferito alla somma dei tempi di tutti i processifloat cpu
La memoria fisica allocata per questo processo (detta anche working set), in byteslong phys_mem
La memoria virtuale (o image o spazio di indirizzamento), in byteslong virt_mem
Un array i cui elementi contengono informazioni sui thread componentiThreadInfo[] thread

L'i-esimo elemento dell'array thread sarà strutturato, a sua volta, come segue:

misuracampo di ThreadInfo
il TIDint tid
Il tempo di CPU, cumulativo, consumato dal thread dal suo inizio ad ora, in millisecondilong time
Il tempo di CPU, in percentuale, consumato dal thread nell'intervallo di misurazione. Il 100% è riferito alla somma dei tempi di tutti i processifloat cpu

Queste non sono le uniche caratteristiche della classe ProcessMonitor. Per una trattazione più esaustiva si rimanda alla guida generata da javadoc.

La classe res.JvmMonitor

Un oggetto di tipo JvmMonitor è un monitor di thread Java. Per essere correttamente inizializzato, deve essere caricata la DLL appropriata già in fase di startup. Per fare ciò bisogna utilizzare il comando

java -Xrunjvmmonitor NomeClasse
quando si lancia l'applicazione. Se non si utilizza l'opzione -Xrunjvmmonitor la DLL viene caricata comunque in un secondo tempo, ma non si possono più eseguire alcune operazioni che consentono la corretta inizializzazione del monitor, cosicchè alcuni contatori possono rimanere a zero.

Il funzionamento del monitor è continuativo, nel senso che esso tiene aggiornato il suo database interno con lo stato della JVM man mano che viene interpretato il bytecode. La lettura dei dati può essere fatta in qualsiasi momento, e rispecchia la situazione attuale. Ad esempio le seguenti istruzioni:

  JvmMonitor mon;
  ThreadStat[] stat;
  mon=new JvmMonitor();
  stat=mon.getThreadStat();
  for(i=0;i < stat.length;i++)
    System.out.println("Thread: "+stat[i].thread.getName()+" #classes: "+stat[i].num_obj);
fotografano lo stato attuale della JVM fornendo, per ciascun thread attivo, il numero di classi da esso caricate.

A questo punto è interessante conoscere quali misure si possono ottenere dal monitor. La tabella mostra il contatore di interesse e il campo dell'oggetto ThreadStat ove è disponibile.

misuracampo di ThreadStat
Il riferimento all'oggetto java.lang.Thread, che identifica il thread Java.Thread thread
Il numero di classi caricate, dalla creazione del threadint class_num
Il numero di oggetti creati, dalla creazione del thread. Togliere da questo valore gli oggetti rilasciati dal Garbage Collector si è rivelato troppo oneroso e fonte di instabilitàint obj_num
La memoria occupata dagli oggetti. Questo valore è poco significativo, perchè non tiene conto della memoria rilasciata dal Garbage Collectorint obj_size
Il numero di metodi chiamati, dalla creazione del threadint meth_num
Il numero di letture da file, dalla creazione del thread. Una lettura riguarda un numero imprecisato di bytesint file_in
Il numero di scritture su file, dalla creazione del thread. Una scrittura riguarda un numero imprecisato di bytesint file_out
Il numero di letture da socket TCP, dalla creazione del thread. Una lettura riguarda da 1 a 1024 bytesint tcp_in
Il numero di scritture su socket TCP, dalla creazione del thread. Una scrittura riguarda da 1 a 1024 bytesint tcp_out
Il numero di pacchetti UDP ricevuti, dalla creazione del thread. La dimensione del pacchetto è sconosciutaint udp_in
Il numero di pacchetti UDP inviati, dalla creazione del thread. La dimensione del pacchetto è sconosciutaint udp_out
Il numero di attese su sezioni di codice synchronized, dalla creazione del threadint monitor_num
Il tempo di CPU consumato dal thread, dalla sua creazione, in millisecondi. Attualmente questo dato è disponibile solo sotto Windows NT, mentre negli altri casi viene restituito il valore zerolong time
Il tempo di CPU, in percentuale, consumato dal thread, relativo alla precedente chiamata alla funzione getThreadStat. Il 100% è riferito alla somma dei tempi di tutti i thread Java monitorati. Attualmente questo dato è disponibile solo sotto Windows NT, mentre negli altri casi viene restituito il valore zerofloat cpu

Bisogna ricordare che i precedenti contatori devono essere considerati con la giusta semantica.
Ad esempio bisogna ricordare che gli oggetti sono creati da un thread, ma possono benissimo essere passati ad altri thread; un oggetto non ha infatti un thread proprietario, ed è quindi sbagliato stabilire che un thread possa usare solo gli oggetti da lui stesso creati; molto spesso è infatti vero il contrario. Quindi è inesatto dire che il thread X usa 75K di memoria per i suoi oggetti, a meno di forti ipotesi sul tipo di applicazione. I contatori sugli oggetti sono stati teatro di forti dubbi in fase di sviluppo del monitor; la scelta attuale è prevalsa più che altro per semplificazoioni implementative.
Allo stesso modo non è detto che le operazioni I/O vengano dal thread che ci si aspetta. Ad esempio, se si sta lavorando con l'interfaccia grafica, si noterà che quasi tutte le operazioni di I/O sono eseguite dal thread AWT-Event-Queue, perchè è effettivamente a questo che tali operazioni sono delegate. La parola d'ordine è dunque ATTENZIONE: meglio fare delle prove per assicurarsi che i valori restituiti dal monitor siano quelli attesi.

Queste non sono le uniche caratteristiche della classe JvmMonitor. Per una trattazione più esaustiva si rimanda alla guida generata da javadoc.

Esempi

Il seguente è un'esempio di applicazione che utilizza la classe res.ProcessMonitor per monitorare i processi di Windows NT. L'idea è solo quella di presentare, sfruttando l'"effetto" dell'interfaccia grafica, le potenzialità del pacchetto.