Java Profiling è il processo di monitoraggio di vari parametri a livello di JVM come l’esecuzione dei metodi, l’esecuzione dei thread, la creazione di oggetti e la garbage collection.Un thread dump è un’istantanea dello stato di tutti i thread che fanno parte del processo specifico.
In linux dando il comando ‘jps’ (JVM process status tool) è possibile ottenere le HotSpot Java Virtual Machines (JVM) strumentate sul sistema di destinazione con il loro ID di processo corrispondente.
Figura 1- JVM e i loro pid.
Il comando ‘jps -l’ restituisce il nome completo del pacchetto per la classe principale dell’applicazione o il nome completo del percorso del file JAR dell’applicazione.
Dopo di che possiamo usare il comando ‘jstack’ per catturare i thread dump. lo strumento jstack viene fornito nella cartella JDK_HOME/bin. Ecco il comando che dovete eseguire per catturare i thread dump:jstack <pid>. Qui pid è l’ID del processo dell’applicazione, il cui thread dump dovrebbe essere catturato. Quindi ‘jstack 13626’ nella mia console produrrà il seguente log di thread dump come mostrato in figura.
Strumenti di profilazione incorporati e loro implementazione
In aggiunta a questi ci sono vari strumenti incorporati per fare il profiling della JVM come Java VisualVM,Honest Profiler, Async Profiler e Java Mission Controller
Prima di andare in profondità di questi profilatori dovremmo conoscere il concetto di ‘Safe point’. La JVM si occupa internamente di molte cose per noi, come la Garbage Collection e la compilazione JIT. Quindi la JVM ha anche bisogno del suo tempo per risolvere alcune cose per se stessa, al di fuori dell’applicazione. Alcune delle cose che la JVM può fare potrebbero coinvolgere un safepoint (incluso il GC). Durante un safepoint, tutti i thread che eseguono codice Java sono sospesi per permettere alla JVM di fare il suo lavoro. L’applicazione si ferma per il tempo in cui la JVM va in un safepoint.Quindi alcuni profiler soffrono di questi problemi di safepoint dove danno un callback ai thread specificati, quei thread dovrebbero essere in un safepoint per rispondere a quel callback.Quindi influisce sulle prestazioni.
D’altra parte alcuni profiler usano una chiamata API interna openJDK AsyncGetCallTrace (ASGT) per facilitare la raccolta non safepoint delle tracce dello stack. AsyncGetCallTrace NON è l’API ufficiale della JVM.Per usare ASGT prima di tutto create un agente JVMTI .La Java Virtual Machine Tool Interface (JVMTI) fornisce un’interfaccia di programmazione che permette a voi, sviluppatori di software, di creare agenti software che possono monitorare e controllare le vostre applicazioni in linguaggio di programmazione Java.Poi impostate un gestore di segnale che innesca il segnale alla frequenza di campionamento desiderata.Quel segnale sarà diretto alla JVM in esecuzione e uno dei loro thread in esecuzione sarà interrotto e richiamato al nostro gestore di segnale.Assicuratevi che il thread interrotto sia in esecuzione nel vostro gestore di segnale e chiamate l’AGCT .Honest profiler usa questo ASGT per fare profiling .
The Honest profiler has two parts to it. Un agente JVMTI C++ che scrive un file contenente tutte le informazioni di profilazione sull’applicazione a cui l’agente jvmti è stato attaccato.La seconda parte, è un’applicazione Java che rende un profilo basato su questo log che è stato precedentemente generato.
Il metodo ASGT sarà simile a questo. AsyncGetCallTrace(ASGCT_CallTrace *trace,jint depth,void* ucontext).Dovremmo passare un puntatore alla traccia di chiamata ASGT a questo metodo.
Il problema con questo approccio è che si ottengono dati leggermente diversi da un tipico stack trace Java. Il profiler deve elaborarlo e mapparlo sulle linee del codice sorgente per essere utile.
Async profiler è un profiler di campionamento a basso overhead che opera attaccando un agente Java nativo a un processo JVM in esecuzione e raccogliendo i campioni di tracce di stack utilizzando API specifiche di HotSpot. Async-profiler funziona solo su GNU/Linux e MacOS, e sul primo utilizza anche perf_events per scavare nel codice nativo. L’approccio generale consiste nel ricevere gli stack di chiamata generati da perf_events e abbinarli agli stack di chiamata generati da AsyncGetCallTrace, al fine di produrre un profilo accurato sia di Java che del codice nativo. Utilizza l’API perf_events per configurare il campionamento della CPU in un buffer di memoria e chiede un segnale da inviare quando si verifica un campione. Il gestore del segnale chiama quindi AGCT, e fonde insieme i due stack: lo stack Java, catturato da AGCT, e lo stack nativo + kernel, catturato da perf_events. Per i thread non Java, viene mantenuto solo lo stack perf_events.
Java Mission Controller(JMC) fornisce un rapporto dettagliato di ciascuno dei thread specifici in ogni JVM e la loro percentuale di consumo della CPU in modo efficiente.Java Mission Control funziona interagendo con un agente JMX nella JVM che ha un server MBean che si integra con la strumentazione VM e app costruita in esecuzione nella JVM. Questo è un vantaggio chiave in quanto abbassa davvero il costo di overhead dello strumento, in quanto utilizza ganci preesistenti. Oracle dichiara che questo è normalmente ben al di sotto dell’1% di overhead.Non c’è niente che tu debba installare o collegare alla tua VM esistente per farlo funzionare. Con Flight recorder, ci sono un paio di flag da abilitare, ma niente da installare. Avviate un terminale e andate nella vostra directory JDK bin e digitate semplicemente jmc.JMC mostrerà una GUI contenente le vostre JVM in esecuzione.Selezionate il processo JVM che dovete profilare e iniziate la registrazione specificando il limite di tempo.
Un’altra alternativa popolare è usare Linux perf, che non supporta direttamente Java ma ha un ottimo supporto per profilare il codice nativo, e non ha problemi a guardare anche gli stack del kernel. Per il supporto JVM abbiamo bisogno di una mappa perf che mappi gli indirizzi compilati da JIT ai nomi delle funzioni (come corollario, solo i frame compilati sono supportati; i frame dell’interprete sono invisibili)
E uno switch JIT -XX:+PreserveFramePointer che faccia in modo che perf possa camminare sullo stack Java. Quando si usa questo tipo di approccio, si finisce per perdere i frame dell’interprete, non si può fare il profilo di una vecchia JVM che non ha il flag PreserveFramePointer, ci possono essere alcune voci stantie nella vostra perfmap perché il JIT può ricompilare il codice, e dato che il JIT butta via un po’ di codice, alcune funzionalità possono essere implementate in modo improprio.
In aggiunta a questi, la Java 2 Platform Standard Edition (J2SE) ha sempre fornito un semplice strumento di profiling a riga di comando chiamato HPROF per il profiling di heap e cpu. HPROF è uno strumento incorporato nel JDK per il profiling della CPU e dell’utilizzo dell’heap all’interno di una JVM. HPROF è in realtà una libreria agente nativa della JVM che viene caricata dinamicamente attraverso un’opzione della riga di comando, all’avvio della JVM, e diventa parte del processo della JVM. Fornendo le opzioni di HPROF all’avvio, gli utenti possono richiedere a HPROF vari tipi di funzioni di profilazione dell’heap e/o della CPU. I dati generati possono essere in formato testuale o binario, e possono essere utilizzati per rintracciare e isolare problemi di prestazioni che coinvolgono l’uso della memoria e codice inefficiente. Il file in formato binario da HPROF può essere usato con strumenti come HAT per sfogliare gli oggetti allocati nell’heap.
Conclusione
Osserviamo che il profiling onesto e il profiling Async hanno superato l’anomalia del ‘Suffering from safepoints’ con una chiamata API interna di openJDK AsyncGetCallTrace.Possono eseguire la profilazione con molto meno overhead rispetto agli strumenti di profilazione standard, ma non possono fornire una profilazione dettagliata dei thread che sono specifici dei processi JVM separatamente, possono solo emettere un file di log/interfaccia GUI dell’intero dump dei thread come un mucchio.D’altra parte Java Mission Control può profilare i thread che sono specifici per ogni processo separatamente dove è possibile monitorare i thread caldi con il loro utilizzo della CPU.Quindi JMC è l’opzione migliore per monitorare i parametri JVM con molta granularità.
Riferimenti.
Java Virtual Machine Process Status Tool Oracle Documentation.
https://docs.oracle.com/javase/7/docs/technotes/tools/share/jps.html
Creare un agente di debug e profilazione con JVMTI
http://www.oracle.com/technetwork/articles/java/jvmti-136367.html
I pro e i contro dei profilatori AsyncGetCallTrace
http://psy-lob-saw.blogspot.com/2016/06/the-pros-and-cons-of-agct.html
Un profilatore JVM di campionamento senza il bias del campione safepoint-Honest Profiler
https://github.com/jvm-profiling-tools/honest-profiler
Profiler di campionamento della CPU e HEAP per Java con AsyncGetCallTrace + perf_events
https://github.com/jvm-profiling-tools/async-profiler