IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

OpenJDK envisage des traces de pile asynchrones pour Java,
Elles permettent d'inclure des informations sur les trames de pile Java et natives

Le , par Bruno

112PARTAGES

4  0 
Une proposition visant à promouvoir les traces de pile asynchrones dans Java prospére dans le processus d'amélioration de Java de l'OpenJDK. Appelé Asynchronous Stack Trace VM API, le projet consisterait à définir une API AsyncGetStackTrace pour collecter les traces de pile de manière asynchrone et inclure des données sur les trames de pile Java et natives.

Selon la proposition, les performances ne seraient pas affectées lorsque l'API n'est pas utilisée et les besoins en mémoire ne seraient pas sensiblement augmentés par rapport à l'API AsyncGetCallTrace existante. La nouvelle API ne serait pas recommandée pour une utilisation en production, car elle pourrait faire planter la JVM. Les plans prévoient de minimiser les risques d'un tel incident par le biais de tests et de vérifications approfondies.


Actuellement, AsyncGetCallTrace est utilisé par la plupart des profileurs disponibles, tant open source que commerciaux, y compris async-profiler. Mais il présente deux inconvénients majeurs.

  • il s'agit d'une API interne, non exportée dans un quelconque en-tête ;
  • elle ne renvoie que des informations sur les cadres Java, à savoir leurs indices de méthode et de bytecode.


Ces problèmes rendent plus difficile l'implémentation de profileurs et d'outils connexes. Bien que des informations supplémentaires puissent être extraites de la VM HotSpot par le biais d'un code complexe, via un code complexe, mais d'autres informations utiles sont dissimulées et impossibles à obtenir :

  • Si une trame Java compilée est inlined (actuellement, on ne peut l'obtenir que pour les trames compilées les plus hautes) ;
  • Le niveau de compilation d'une trame Java (c'est-à-dire, compilée par C1 ou C2) ;
  • Des informations sur les trames C/C++ qui ne sont pas au sommet de la pile.

Ces données peuvent être utiles lors du profilage et du réglage d'une VM pour une application donnée, ainsi que pour le profilage de code utilisant fortement JNI.

L'API AsyncGetStackTrace serait calquée sur l'API AsyncGetCallTrace. La nouvelle API n'a pas encore été proposée pour une version spécifique de Java standard. La prochaine version de Java est le kit de développement Java (JDK) 20, qui est attendu en mars 2023. Java dispose d'un processus officiel permettant d'intégrer des changements dans la plateforme qui a réussi à rester réactive face à l'évolution des circonstances tout en atteignant un haut degré de stabilité.

Description

L'équipe encharge de Java propose une nouvelle API AsyncGetStackTrace, modelée sur l'API AsyncGetCallTrace :

Code Java : Sélectionner tout
1
2
void AsyncGetStackTrace(CallTrace *trace, jint depth, void* ucontext, 
                        uint32_t options);


Cette API peut être appelée par les profileurs pour obtenir la trace de la pile pour le thread en cours d'execution. L'appel de cette API à partir d'un gestionnaire de signaux est sûr, et la nouvelle implémentation sera au moins aussi stable que AsyncGetCallTrace ou le code de suivi de pile de la JFR. La VM remplit les informations sur les trames et le nombre de trames. L'appelant de l'API doit allouer le tableau CallTrace avec suffisamment de mémoire pour la profondeur de pile demandée.

Paramètres

  • trace - tampon pour les données structurées à remplir par la VM ;
  • depth - profondeur maximale de la trace de la pile d'appels ;
  • ucontext - optionnel ucontext_t du thread actuel lorsqu'il a été interrompu ;
  • options - bit défini pour les options

Actuellement, seul le bit le plus bas des options est pris en compte : Il active (1) ou désactive (0) l'inclusion des trames C/C++. Tous les autres bits sont considérés comme étant à 0.

Code : Sélectionner tout
1
2
3
4
5
typedef struct { 
  jint num_frames;                // number of frames in this trace 
  CallFrame *frames;              // frames 
  void* frame_info;               // more information on frames 
} CallTrace;

La structure de la trace est rempli par la VM. Son champ num_frames contient le nombre réel d'images dans le tableau des images ou un code d'erreur. Le champ frame_info de cette structure peut être utilisé ultérieurement pour stocker plus d'informations, mais il est actuellement NULL. Les codes d'erreur sont un sous-ensemble des codes d'erreur pour AsyncGetCallTrace, avec l'ajout de THREAD_NOT_JAVA lié à l'appel de cette procédure pour des threads non-Java :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
enum Error { 
  NO_JAVA_FRAME         =   0, 
  NO_CLASS_LOAD         =  -1,  
  GC_ACTIVE             =  -2,     
  UNKNOWN_NOT_JAVA      =  -3, 
  NOT_WALKABLE_NOT_JAVA =  -4, 
  UNKNOWN_JAVA          =  -5, 
  UNKNOWN_STATE         =  -7, 
  THREAD_EXIT           =  -8, 
  DEOPT                 =  -9, 
  THREAD_NOT_JAVA       = -10 
};

Chaque CallFrame est l'élément d'une union, puisque les informations stockées pour les frames Java et non-Java diffèrent :

Code : Sélectionner tout
1
2
3
4
5
typedef union { 
  FrameTypeId type;     // to distinguish between JavaFrame and NonJavaFrame  
  JavaFrame java_frame; 
  NonJavaFrame non_java_frame; 
} CallFrame;
On peut distinguer plusieurs types de frames :

Code : Sélectionner tout
1
2
3
4
5
6
7
enum FrameTypeId : uint8_t { 
  FRAME_JAVA         = 1, // JIT compiled and interpreted 
  FRAME_JAVA_INLINED = 2, // inlined JIT compiled 
  FRAME_NATIVE       = 3, // native wrapper to call C methods from Java 
  FRAME_STUB         = 4, // VM generated stubs 
  FRAME_CPP          = 5  // C/C++/... frames 
};

Les deux premiers types sont destinés aux frames Java, pour lesquels nous stockons les informations suivantes dans une structure de type JavaFrame :...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !