Artigo
· 9 hr atrás 10min de leitura

Analisando a Performance em Tempo de Execução do IRIS ^PERFMON [JAVA Native SDK]

Documentação Técnica — Quarkus IRIS Monitor System

1. Objetivo e Escopo

Este módulo permite a integração entre aplicações Java baseadas em Quarkus e as capacidades nativas de monitoramento de performance do InterSystems IRIS.
Ele possibilita que o desenvolvedor anote métodos com @PerfmonReport, acionando automaticamente as rotinas ^PERFMON do IRIS durante a execução do método e gerando relatórios de performance sem intervenção manual.


2. Componentes do Sistema

2.1 Anotação: @PerfmonReport

  • Definida como InterceptorBinding do CDI.
  • Pode ser aplicada a métodos ou classes.
  • Instrui o framework a envolver a execução do método com a lógica de monitoramento do IRIS.

2.2 Interceptor: PerfmonReportInterceptor

  • Intercepta chamadas a métodos anotados.
  • Fluxo de execução:

    1. Registrar evento de início (LOG.infof("INIT: …"))
    2. Chamar monitorSystem.startPerfmon()
    3. Prosseguir com context.proceed()
    4. No bloco finally:
    • Chamar monitorSystem.generateReportPerfmon(...)
    • Chamar monitorSystem.stopPerfmon()
    • Registrar evento de fim com tempo de execução
  • Garante que o monitoramento sempre será encerrado, mesmo se ocorrer uma exceção.

2.3 Bean DAO: MonitorSystem

  • Bean CDI anotado com @ApplicationScoped.
  • Mantém uma única instância de IRIS inicializada na inicialização.
  • Configuração injetada via @ConfigProperty (URL JDBC, usuário, senha).
  • Utiliza DriverManager.getConnection(...) para obter uma IRISConnection nativa.
  • Contém os métodos:

    • startPerfmon()
    • generateReportPerfmon(String reportName)
    • stopPerfmon()
  • Cada método chama as correspondentes rotinas ObjectScript em iris.src.dc.AdapterPerfmonProc via iris.classMethodVoid(...).

2.4 Adapter ObjectScript: iris.src.dc.AdapterPerfmonProc

  • Define as rotinas que encapsulam a lógica do ^PERFMON:

    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
        }
    }
    

    Opera no namespace %SYS para acessar as rotinas ^PERFMON e, em seguida, retorna para o namespace original.

  • Opera no namespace %SYS para acessar as rotinas ^PERFMON, retornando ao namespace original.


3. Fluxo de Execução

  1. Uma requisição entra na aplicação Quarkus.
  2. O interceptor CDI detecta a anotação @PerfmonReport e intercepta a chamada do método.
  3. monitorSystem.startPerfmon() é invocado, acionando o monitoramento ^PERFMON do IRIS.
  4. O método de negócio é executado normalmente (acesso a dados, transformações, lógica, etc.).
  5. Após o método retornar ou lançar uma exceção, o interceptor garante que:
    • monitorSystem.generateReportPerfmon(...) seja chamado para criar um relatório de performance .txt.
    • monitorSystem.stopPerfmon() seja executado para encerrar a sessão de monitoramento.
    • O tempo total de execução do lado Java seja registrado usando Logger.infof(...).
  6. O arquivo de relatório gerado é armazenado no diretório temporário do IRIS, normalmente: /usr/irissys/mgr/Temp/

    • O nome do arquivo segue o padrão:
      <ClassName><MethodName><timestamp>.txt

4. Desafios Técnicos e Soluções

Desafio Solução
ClassCastException ao usar conexões JDBC pooladas Use DriverManager.getConnection(...) para obter uma IRISConnection nativa, em vez do ConnectionWrapper poolado.
Sobrecarga por abrir conexões repetidamente Mantenha uma única instância de IRIS dentro de um bean @ApplicationScoped, inicializada via @PostConstruct.
Garantir que ^PERFMON seja sempre encerrado, mesmo em exceções Use try-finally no interceptor para chamar stopPerfmon() e generateReportPerfmon().
Portabilidade de configuração Injete as configurações de conexão (jdbc.url, username, password) usando @ConfigProperty e application.properties.
Gerenciamento de sessões de monitoramento concorrentes Evite anotar endpoints com alta concorrência. Versões futuras podem implementar isolamento por sessão.

5. Casos de Uso e Benefícios

  • Permite visibilidade em tempo real da atividade do IRIS a partir do código Java.
  • Simplifica a análise de performance e otimização de consultas para desenvolvedores.
  • Útil para benchmarking, profiling e testes de regressão do sistema.
  • Pode servir como um registro leve de auditoria de performance para operações críticas.

6. Exemplo Prático de Uso

O código-fonte completo e o setup de deployment estão disponíveis em:


6.1 Visão Geral

A aplicação roda um servidor Quarkus conectado a uma instância InterSystems IRIS configurada com o namespace FHIRSERVER.
A camada ORM é implementada usando Hibernate ORM com PanacheRepository, permitindo mapeamento direto entre entidades Java e classes do banco IRIS.

Quando a aplicação é iniciada (via docker-compose up), são iniciados:
- O container IRIS, hospedando o modelo de dados FHIR e rotinas ObjectScript (incluindo AdapterPerfmonProc);
- O container Quarkus, expondo endpoints REST e conectando-se ao IRIS via driver JDBC nativo.


6.2 Endpoint REST

Um recurso REST expõe um endpoint simples para recuperar informações de pacientes:

@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);
    }
}

Este endpoint aceita um parâmetro de consulta (key) que identifica o recurso do paciente dentro do repositório de dados FHIR.


6.3 Camada de Serviço com @PerfmonReport

A classe PatientService contém a lógica de negócio para recuperar e compor informações do paciente.
Ela é anotada com @PerfmonReport, o que significa que cada requisição para /patient/info aciona o monitoramento de performance do 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 Fluxo de Execução

Uma requisição é feita para: GET /patient/info?key=Patient/4

O Quarkus encaminha a requisição para PatientResource.searchPatientInfo().

O interceptor CDI detecta a anotação @PerfmonReport em PatientService.patientGetInfo().

Antes de executar a lógica de serviço:

  • O interceptor invoca MonitorSystem.startPerfmon(), que chama a classe IRIS iris.src.dc.AdapterPerfmonProc.start().

  • O método executa a lógica de negócio, consultando dados do paciente usando os mapeamentos Hibernate PanacheRepository.

Após a conclusão do método:

  • MonitorSystem.generateReportPerfmon() é chamado para criar o relatório de performance.

  • MonitorSystem.stopPerfmon() interrompe o monitoramento de performance do IRIS.

Um relatório .txt é gerado em: usr/irissys/mgr/Temp/

Exemplo de nome de arquivo: PatientService_patientGetInfo_20251005_161906.txt

6.5 Resultado

O relatório gerado contém estatísticas detalhadas de execução do IRIS, por exemplo:

                         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/

Esses dados fornecem uma visão precisa sobre quais rotinas foram executadas internamente pelo IRIS durante aquela chamada REST — incluindo compilação de SQL, execução e acesso a dados FHIR.

Observação: As rotinas %sqlcq.FHIRSERVER.* registram todas as consultas SQL cache executadas pelo Quarkus dentro do método. Monitorar essas rotinas permite aos desenvolvedores analisar a execução das queries, compreender o comportamento do código e identificar possíveis gargalos de performance. Isso as torna uma ferramenta poderosa para desenvolvimento e depuração de operações relacionadas ao FHIR.

image

6.6 Resumo

Este exemplo demonstra como um serviço padrão Quarkus pode utilizar de forma transparente as ferramentas nativas de monitoramento do IRIS usando a anotação @PerfmonReport.
Ele combina:

  • Interceptadores CDI (Quarkus)
  • Hibernate PanacheRepositories (ORM)
  • Rotinas ObjectScript nativas do IRIS (^PERFMON)

O resultado é um mecanismo de profiling de performance totalmente automatizado e reproduzível, que pode ser aplicado a qualquer método de serviço na aplicação.

Discussão (0)1
Entre ou crie uma conta para continuar