Article
· Nov 11 10m de lecture

Analyse des performances d'exécution IRIS ^PERFMON à l'aide du SDK natif Java

Documentation technique — Système de surveillance Quarkus IRIS

1. Le but et la portée

Ce module assure l'intégration entre les applications Java basées sur Quarkus et les capacités natives de surveillance des performances d'InterSystems IRIS.
Il permet aux développeurs d'annoter les méthodes avec @PerfmonReport, ce qui déclenche automatiquement les routines ^PERFMON d'IRIS lors de l'exécution des méthodes, et génère des rapports de performances sans intervention manuelle.


2. Composants du système

2.1 Annotation: @PerfmonReport

  • Définie comme un CDI InterceptorBinding.
  • Peut être appliquée à des méthodes ou à des classes.
  • Indique au framework d'encapsuler l'exécution de la méthode avec la logique de surveillance IRIS.

2.2 Intercepteur: PerfmonReportInterceptor

  • Interception des appels vers les méthodes annotées.
  • Flux d'exécution:

    1. Enregistrement de l'événement de début (LOG.infof("INIT: …"))
    2. Appel à monitorSystem.startPerfmon()
    3. Poursuite avec context.proceed()
    4. Dans le bloc finally:
    • Appel à monitorSystem.generateReportPerfmon(...)
    • Appel à monitorSystem.stopPerfmon()
    • Enregistrement de l'événement de fin avec le temps d'exécution
  • Ansi, la surveillance est toujours terminée, même si une exception est levée.

2.3 Bean DAO: MonitorSystem

  • Un bean CDI annoté avec @ApplicationScoped.
  • Contient une seule instance d'IRIS initialisée au démarrage.
  • Configuration injectée via @ConfigProperty (URL JDBC, utilisateur, mot de passe).
  • Utilization de DriverManager.getConnection(...) pour obtenir un lien IRISConnection brut.
  • Contient les méthodes suivantes:

    • startPerfmon()
    • generateReportPerfmon(String reportName)
    • stopPerfmon()
  • Chaque méthode appelle les méthodes ObjectScript appropriées dans iris.src.dc.AdapterPerfmonProc via iris.classMethodVoid(...).

2.4 Adaptateur ObjectScript: iris.src.dc.AdapterPerfmonProc

  • Définition des routines qui encapsulent la logique ^PERFMON logic:

    Class iris.src.dc.AdapterPerfmonProc Extends %RegisteredObject
    {
        ClassMethod start() As %Status
        {
            Set namespace = $NAMESPACE
            zn "%SYS"
            set status = $$Stop^PERFMON()
            set status = $$Start^PERFMON()
            zn namespace
            return status
        }
    
        ClassMethod generateReport(nameReport As %String = "report.txt") As %Status
        {
            Set namespace = $NAMESPACE
            zn "%SYS"
            Set tempDirectory = ##class(%SYS.System).TempDirectory()
            set status = $$Report^PERFMON("R","R","P", tempDirectory_"/"_nameReport)
            zn namespace
    
            return status
        }
    
        ClassMethod stop() As %Status
        {
            Set namespace = $NAMESPACE
            zn "%SYS"
            Set status = $$Stop^PERFMON()
            zn namespace
    
            return status
        }
    }
    
  • Il fonctionne dans l'espace de noms %SYS pour accéder aux routines ^PERFMON puis revient à l'espace de noms d'origine.


3. Flux d'exécution

  1. Une requête entre dans l'application Quarkus.
  2. L'intercepteur CDI détecte l'annotation @PerfmonReport et intercepte l'appel de méthode.
  3. monitorSystem.startPerfmon() est invoqué, ce qui déclenche la surveillance ^PERFMON d'IRIS.
  4. La méthode métier s'exécute de manière normale (accès aux données, transformations, logique, etc.).
  5. Une fois que la méthode renvoie ou génère une exception, l'intercepteur s'assure des éléments suivants:
    • monitorSystem.generateReportPerfmon(...) est appelé pour créer un rapport de performances .txt.
    • monitorSystem.stopPerfmon() est exécuté pour arrêter la session de surveillance.
    • Le temps d'exécution total côté Java est consigné à l'aide de Logger.infof(...).
  6. Le fichier de rapport généré est stocké dans le répertoire temporaire IRIS, typiquement le répertoire: /usr/irissys/mgr/Temp/

    • Le fichier est nommé selon le modèle suivant:
      <ClassName><MethodName><timestamp>.txt

4. Défis techniques et leurs solutions

Défis Solution
ClassCastException lors de l'utilisation de connexions JDBC mises en pool Utilisation de DriverManager.getConnection(...) pour obtenir une connexion native IRISConnection au lieu d'une connexion mise en pool ConnectionWrapper.
Surcharge due à l'ouverture répétée de connexions Maintien d'une instance IRIS unique dans un bean @ApplicationScoped, initialisée via @PostConstruct.
Assurance du fait que ^PERFMON est toujours arrêté, même en cas d'exception Utilisationu bloc d try-finally dans l'intercepteur pour appeler stopPerfmon() et generateReportPerfmon().
Portabilité de la configuration Injection des paramètres de connexion (jdbc.url, username, password) avec @ConfigProperty et application.properties.
Gestion des sessions de surveillance simultanées Évitez d'annoter les points de terminaison à haute simultanéité. Les versions futures pourraient implémenter l'isolation au niveau de la session.

5. Cas d'utilisation et avantages

  • Possibilité de visualisation en temps réel de l'activité d'exécution IRIS à partir du code Java.
  • Simplification de l'analyse des performances et de l'optimisation des requêtes pour les développeurs.
  • Utile pour le benchmarking, le profilage et les tests de régression du système.
  • Peut-être utilisé comme suivi d'audit des performances léger pour les opérations critiques.

6. Exemple pratique d'utilisation

Le code source complet et la configuration de déploiement sont disponibles aux adresses suivantes:


6.1 Aperçu

L'application exécute un serveur Quarkus connecté à une instance InterSystems IRIS configurée avec l'espace de noms FHIRSERVER.
La couche ORM est implémentée à l'aide de Hibernate ORM avec PanacheRepository, ce qui permet un mappage direct entre les entités Java et les classes de base de données IRIS.

Au démarrage de l'application (via docker-compose up), les éléments suivants s'affichent:
- Le conteneur IRIS, qui héberge le modèle de données FHIR et les routines ObjectScript (y compris AdapterPerfmonProc);
- Le conteneur Quarkus, qui expose les points de terminaison REST et se connecte à IRIS via le pilote JDBC natif.


6.2 Point de terminaison REST

Une ressource REST expose un point de terminaison simple pour récupérer les informations du patient:

@Path("/patient")
public class PatientResource {

    @Inject
    PatientService patientService;

    @GET
    @Path("/info")
    @Produces(MediaType.APPLICATION_JSON)
    public PatientInfoDTO searchPatientInfo(@QueryParam("key") String key) {
        return patientService.patientGetInfo(key);
    }
}

Ce point de terminaison accepte un paramètre de requête (clé) qui identifie la ressource patient dans le référentiel de données FHIR.


### 6.3 Couche de service avec @PerfmonReport

La classe PatientService contient la logique métier permettant de récupérer et de composer les informations sur les patients.
Cette classe est annotée avec @PerfmonReport, ce qui signifie que chaque requête adressée à /patient/info déclenche la surveillance des performances IRIS:

@ApplicationScoped
public class PatientService {

    @Inject
    PatientRepository patientRepository;

    @PerfmonReport
    public PatientInfoDTO patientGetInfo(String patientKey) {

        Optional<Patient> patientOpt = patientRepository.find("key", patientKey).firstResultOptional();
        Patient patient = patientOpt.orElseThrow(() -> new IllegalArgumentException("Patient not found"));

        PatientInfoDTO dto = new PatientInfoDTO();
        dto.setKey(patient.key);
        dto.setName(patient.name);
        dto.setAddress(patient.address);
        dto.setBirthDate(patient.birthDate != null ? patient.birthDate.toString() : null);
        dto.setGender(patient.gender);
        dto.setMedications(patientRepository.findMedicationTextByPatient(patientKey));
        dto.setConditions(patientRepository.findConditionsByPatient(patientKey));
        dto.setAllergies(patientRepository.findAllergyByPatient(patientKey));

        return dto;
    }
}

6.4 Flux d'exécution

Une requête est envoyée à l'adresse suivante: GET /patient/info?key=Patient/4

Quarkus achemine la requête vers PatientResource.searchPatientInfo().

L'intercepteur CDI détecte l'annotation @PerfmonReport dans PatientService.patientGetInfo().

Avant d'exécuter la logique de service:

  • L'intercepteur invoque MonitorSystem.startPerfmon(), qui appelle la classe IRIS iris.src.dc.AdapterPerfmonProc.start().

  • La méthode exécute la logique métier en interrogeant les données des patients à l'aide des mappages Hibernate PanacheRepository.

Lorsque la méthode est terminée:

  • MonitorSystem.generateReportPerfmon() est appelé pour créer un rapport de performances.

  • MonitorSystem.stopPerfmon() arrête le moniteur de performances IRIS.

Un rapport .txt est généré dans: usr/irissys/mgr/Temp/

Exemple de nom de fichier: PatientService_patientGetInfo_20251005_161906.txt

6.5 Résultat

Le rapport généré contient des statistiques détaillées sur l'exécution d'IRIS, par exemple:

                         Routine Activity by Routine

Started: 10/11/2025 05:07:30PM                    Collected: 10/11/2025 05:07:31PM

Routine Name                        RtnLines  % Lines   RtnLoads  RtnFetch  Line/Load Directory
----------------------------------- --------- --------- --------- --------- --------- ---------
Other                                     0.0       0.0       0.0       0.0         0
PERFMON                                  44.0       0.0       0.0       0.0         0 /usr/irissys/mgr/
%occLibrary                         3415047.0      34.1   48278.0       0.0      70.7 /usr/irissys/mgr/irislib/
iris.src.dc.AdapterPerfmonProc.1          7.0       0.0       2.0       0.0       3.5 /usr/irissys/mgr/FHIRSERVER/
%occName                            5079994.0      50.7       0.0       0.0         0 /usr/irissys/mgr/irislib/
%apiDDL2                            1078497.0      10.8   63358.0       0.0      17.0 /usr/irissys/mgr/irislib/
%SQL.FeatureGetter.1                 446710.0       4.5   66939.0       0.0       6.7 /usr/irissys/mgr/irislib/
%SYS.WorkQueueMgr                       365.0       0.0       1.0       0.0     365.0 /usr/irissys/mgr/
%CSP.Daemon.1                            16.0       0.0       1.0       0.0      16.0 /usr/irissys/mgr/irislib/
%SYS.TokenAuth.1                         14.0       0.0       5.0       0.0       2.8 /usr/irissys/mgr/
%Library.PosixTime.1                      2.0       0.0       0.0       0.0         0 /usr/irissys/mgr/irislib/
%SYS.sqlcq.uEXTg3QR7a7I7Osf9e8Bz...      52.0       0.0       1.0       0.0      52.0 /usr/irissys/mgr/
%SYS.SQLSRV                              16.0       0.0       0.0       0.0         0 /usr/irissys/mgr/
%apiOBJ                                 756.0       0.0       0.0       0.0         0 /usr/irissys/mgr/irislib/
FT.Collector.1                            0.0       0.0       0.0       0.0         0 /usr/irissys/mgr/
SYS.Monitor.FeatureTrackerSensor.1        0.0       0.0       0.0       0.0         0 /usr/irissys/mgr/
%SYS.Monitor.Control.1                    0.0       0.0       0.0       0.0         0 /usr/irissys/mgr/
%SYS.DBSRV.1                            252.0       0.0       4.0       0.0      63.0 /usr/irissys/mgr/
%sqlcq.FHIRSERVER.cls12.1                19.0       0.0       0.0       0.0         0 /usr/irissys/mgr/irislocaldata/
%sqlcq.FHIRSERVER.cls13.1                74.0       0.0       0.0       0.0         0 /usr/irissys/mgr/irislocaldata/
%sqlcq.FHIRSERVER.cls14.1                74.0       0.0       0.0       0.0         0 /usr/irissys/mgr/irislocaldata/
%sqlcq.FHIRSERVER.cls15.1                52.0       0.0       0.0       0.0         0 /usr/irissys/mgr/irislocaldata/
%SYS.System.1                             1.0       0.0       0.0       0.0         0 /usr/irissys/mgr/

Ces données fournissent des visions précises des routines exécutées au sein d'IRIS pendant cet appel REST, notamment la compilation SQL, l'exécution et l'accès aux données FHIR.

Vision précise: Les routines %sqlcq.FHIRSERVER.* capturent toutes les requêtes de cache SQL exécutées par Quarkus au sein de la méthode. La surveillance de ces routines permet aux développeurs d'analyser l'exécution des requêtes, de comprendre le comportement du code et d'identifier les goulots d'étranglement de performance potentiels. Ils constituent donc un outil puissant pour le développement et le débogage des opérations liées à FHIR.

image

6.6 Récapitulatif

Cet exemple explique comment un service Quarkus standard peut exploiter les outils de surveillance natifs IRIS de manière transparente à l'aide de l'annotation @PerfmonReport.
Il combine:

  • Intercepteurs CDI (Quarkus)

  • Hibernate PanacheRepositories (ORM)

  • Routines ObjectScript natives IRIS (^PERFMON)

Il en résulte un mécanisme de profilage des performances entièrement automatisé et reproductible qui peut être appliqué à n'importe quelle méthode de service dans l'application.

Discussion (0)2
Connectez-vous ou inscrivez-vous pour continuer