Preços

Visão geral da arquitetura

Arquivos-fonte

Esta página foi gerada com base nos seguintes arquivos-fonte:

O microprofile é uma biblioteca de profiling embutível para CPU e GPU, projetada para oferecer análise de desempenho em tempo real com baixa sobrecarga. O sistema permite instrumentar código através de regiões hierárquicas, contadores e visualização integrada via interface in-game ou servidor web embutido [README.md:1-22].

A arquitetura do projeto é baseada em um modelo header-only, onde toda a funcionalidade principal está contida em um único arquivo de cabeçalho (microprofile.h). Esta decisão de design facilita a integração em projetos existentes, exigindo apenas a definição de MICROPROFILE_IMPL em um arquivo de implementação para gerar o código necessário.

O sistema opera através de macros de instrumentação que capturam timestamps de CPU e GPU, armazenando esses dados em buffers circulares para análise posterior. A visualização pode ser feita através de três modalidades: interface in-game renderizada via callbacks fornecidos pela aplicação, servidor web embutido que gera HTML dinamicamente, ou exportação para arquivo HTML estático [README.md:10-19].

Visão Geral da Arquitetura

O microprofile adota uma arquitetura modular com separação clara entre instrumentação, coleta de dados, backends de GPU e sistemas de visualização. O diagrama abaixo ilustra os principais componentes e suas interações:

正在加载图表渲染器...

Pontos-chave da arquitetura:

  1. Instrumentação via Macros: O ponto de entrada principal são os macros como MICROPROFILE_SCOPE e MICROPROFILE_SCOPEGPU, que capturam automaticamente o início e fim de escopos de código através do padrão RAII [microprofile.h:39-52].

  2. Unificação CPU/GPU: O sistema trata timers de CPU e GPU de forma unificada através das mesmas macros, com detecção automática do tipo de grupo. Isso simplifica a instrumentação e permite análise correlacionada de ambos os domínios [README.md:43-44].

  3. Backends GPU Dinâmicos: Suporte para múltiplos backends gráficos pode ser compilado simultaneamente, com inicialização dinâmica em runtime. Isso permite que o mesmo binário suporte diferentes APIs gráficas dependendo do ambiente de execução [README.md:46-47].

  4. Buffers por Thread: Cada thread mantém seus próprios buffers de dados de profiling, evitando contenção de locks durante a captura de timestamps. O sistema suporta múltiplas threads com nomes customizados via MicroProfileOnThreadCreate [microprofile.h:30].

  5. Visualização Múltipla: Os dados coletados podem ser visualizados em tempo real via interface in-game ou servidor web, ou exportados para análise offline em HTML [README.md:17].

Módulo de Instrumentação

O módulo de instrumentação é responsável por fornecer a API de macros que desenvolvedores usam para marcar regiões de código. Este módulo implementa o padrão RAII (Resource Acquisition Is Initialization) para garantir captura automática de timestamps de entrada e saída.

Responsabilidades e Limites

O módulo de instrumentação faz:

  • Define macros para declaração e definição de timers estáticos (MICROPROFILE_DECLARE, MICROPROFILE_DEFINE)
  • Fornece macros de escopo para uso em blocos de código (MICROPROFILE_SCOPE, MICROPROFILE_SCOPEI)
  • Suporta timers GPU através de macros dedicados (MICROPROFILE_SCOPEGPU, MICROPROFILE_SCOPEGPUI)
  • Permite adicionar metadados e labels dinâmicos via MICROPROFILE_META e MICROPROFILE_LABEL

O módulo não faz:

  • Gerenciamento de memória dos buffers (delegado ao módulo de buffers)
  • Renderização direta de dados (delegado aos callbacks da aplicação)
  • Sincronização de threads (cada thread tem seus próprios dados)

APIs de Entrada Principais

As macros de instrumentação são divididas em categorias baseadas no tipo de uso:

MacroCategoriaPropósito
MICROPROFILE_DECLAREDeclaraçãoDeclara um timer estático para uso em múltiplos arquivos
MICROPROFILE_DEFINEDefiniçãoDefine um timer estático com grupo, nome e cor
MICROPROFILE_SCOPEEscopo CPUCaptura timing de um escopo usando timer pré-definido
MICROPROFILE_SCOPEIEscopo CPUCaptura timing com nome inline (sem declaração prévia)
MICROPROFILE_SCOPEGPUEscopo GPUCaptura timing GPU usando timer pré-definido
MICROPROFILE_SCOPEGPUIEscopo GPUCaptura timing GPU com nome inline
MICROPROFILE_METAMetadadosAdiciona contador ou valor associado ao escopo atual
MICROPROFILE_LABELLabelsAdiciona string descritiva ao escopo atual
MICROPROFILE_LABELFLabelsAdiciona string formatada (printf-style) ao escopo

[microprofile.h:39-52]

Padrão de Uso Típico

O uso padrão segue um fluxo de declaração (opcional) e instrumentação de escopo:

cpp
1// Declaração global (opcional, para ordenação consistente)
2MICROPROFILE_DEFINE(g_ProfileFisk, "Fisk", "Skalle", nSomeColorRgb);
3
4// Em outro arquivo que usa o timer
5MICROPROFILE_DECLARE(g_ProfileFisk);
6
7void foo() {
8    MICROPROFILE_SCOPE(g_ProfileFisk);
9    // Código a ser medido
10}
11
12// Alternativa inline (sem declaração prévia)
13void bar() {
14    MICROPROFILE_SCOPEI("GroupName", "TimerName", nColorRgb);
15    // Código a ser medido
16}

[microprofile.h:60-70]

Estruturas de Dados Internas

Cada timer definido cria uma entrada em uma tabela global de metadados contendo:

  • Hash do nome para identificação rápida
  • Índice do grupo ao qual pertence
  • Cor para visualização (pode ser -1 para seleção automática baseada em hash)
  • Ponteiros para estatísticas acumuladas

O escopo RAII gerado pelos macros mantém um ponteiro para o timer ativo e captura o timestamp de entrada no construtor e saída no destrutor. Para timers GPU, o construtor também insere um comando de timestamp na fila de comandos gráficos.

Tratamento de Erros e Condições de Borda

O módulo de instrumentação implementa várias proteções contra condições de erro:

  1. Limite de Timers: O sistema define um número máximo de timers únicos. Tentativas de criar timers além desse limite são ignoradas silenciosamente para evitar overflow de buffers.

  2. Recursão: Timers recursivos são tratados corretamente, com cada nível de recursão contribuindo para as estatísticas do mesmo timer.

  3. Thread Safety: Cada thread mantém sua própria pilha de escopos ativos, eliminando a necessidade de sincronização durante a instrumentação.

  4. Inicialização Lazy: Buffers grandes são alocados sob demanda quando grupos são efetivamente capturados, reduzindo overhead de memória quando o profiler está inativo [README.md:49].

Sistema de Timers CPU e GPU

O sistema de timers é responsável pela captura, armazenamento e sincronização de timestamps de CPU e GPU. Este módulo abstrai as diferenças entre as diversas APIs de timing disponíveis em diferentes plataformas.

Responsabilidades

O sistema de timers faz:

  • Captura timestamps de alta resolução para CPU usando QueryPerformanceCounter (Windows) ou clock_gettime (POSIX)
  • Gerencia queries de timestamp GPU através de callbacks específicos de backend
  • Sincroniza timestamps CPU/GPU para visualização correlacionada
  • Converte ticks para unidades de tempo consistentes

O sistema não faz:

  • Renderização de gráficos de timeline
  • Gerenciamento do ciclo de vida de objetos GPU
  • Processamento de comandos de entrada do usuário

APIs de Timestamp

O sistema define três callbacks que devem ser implementados para suporte a GPU timing:

cpp
1uint32_t MicroProfileGpuInsertTimer(void* pContext);
2uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey);
3uint64_t MicroProfileTicksPerSecondGpu();

[microprofile.h:81-83]

Estas funções permitem que o microprofile:

  1. Insira um comando de timestamp na fila GPU (retornando uma chave para recuperação posterior)
  2. Recupere o valor do timestamp quando a GPU completar a execução
  3. Converta ticks GPU para segundos para exibição consistente

Fluxo de Captura de Timestamps

正在加载图表渲染器...

Explicação do fluxo:

  1. Entrada de Escopo: Quando o código entra em um escopo instrumentado, o construtor do objeto RAII captura imediatamente o timestamp CPU e insere uma query de timestamp na fila GPU [microprofile.h:81].

  2. Execução do Escopo: O código dentro do escopo executa normalmente enquanto as queries GPU permanecem pendentes.

  3. Saída de Escopo: O destrutor captura o timestamp final e insere uma segunda query GPU, então armazena todos os dados no buffer de frame.

  4. Resolução Assíncrona: Os timestamps GPU são resolvidos assincronamente quando a GPU completa a execução. O sistema faz polling dos resultados em frames subsequentes.

  5. Sincronização: Uma vez que ambos os timestamps estão disponíveis, o sistema calcula a correlação entre clocks CPU e GPU para exibição precisa na timeline.

Backends GPU Suportados

O sistema suporta múltiplos backends gráficos através de implementações condicionais:

BackendMacro de AtivaçãoFunção de InicializaçãoNotas
OpenGLMICROPROFILE_GPU_TIMERS_GLMicroProfileGpuInitGL()Requer contexto OpenGL ativo
D3D11MICROPROFILE_GPU_TIMERS_D3D11MicroProfileGpuInitD3D11(Device)Single-threaded por padrão
D3D12MICROPROFILE_GPU_TIMERS_D3D12MicroProfileGpuInitD3D12(Device, Queue)Suporta modo multi-threaded
VulkanMICROPROFILE_GPU_TIMERS_VKMicroProfileGpuInitVK(Device, PhysicalDevice, Queue)Similar ao D3D12

[microprofile.h:87-114]

Tratamento de Casos Especiais

Modo Multi-threaded (D3D12/Vulkan):

Para APIs modernas que suportam gravação de comandos em múltiplas threads, o sistema fornece um protocolo específico:

cpp
1#define MICROPROFILE_GPU_TIMERS_MULTITHREADED 1
2
3// Na thread de gravação:
4MicroProfileGpuBegin(CommandList);
5// ... gravar comandos com markers ...
6work = MicroProfileGpuEnd();
7
8// Na thread de submissão:
9MicroProfileGpuSubmit(work);  // Mesma ordem que ExecuteCommandLists

[microprofile.h:102-105]

Limitação Conhecida: GPU timestamps só podem ser inseridos de uma única thread por contexto, conforme documentado em [microprofile.h:113].

Sistema de Visualização e Interface

O sistema de visualização é responsável por transformar os dados de profiling brutos em representações visuais compreensíveis. O microprofile suporta três modos de visualização distintos, cada um com suas características específicas.

Modalidades de Visualização

ModoDescriçãoRequisitos
In-Game UIInterface renderizada sobre a aplicaçãoCallbacks de renderização implementados
Servidor WebInterface HTML servida via HTTP embutidoThread dedicada para servidor
Exportação HTMLArquivo estático para análise offlineNenhum requisito em runtime

[README.md:17]

Callbacks de Renderização Obrigatórios

Para a interface in-game, a aplicação deve implementar três callbacks de renderização:

cpp
1void MicroProfileDrawText(int nX, int nY, uint32_t nColor, 
2                          const char* pText, uint32_t nNumCharacters);
3void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, 
4                         uint32_t nColor, MicroProfileBoxType);
5void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, 
6                            uint32_t nColor);

[microprofile.h:77-79]

Estes callbacks permitem que o microprofile desenhe sua interface usando qualquer backend de renderização suportado pela aplicação (OpenGL, DirectX, Vulkan, ou até software rendering).

Ciclo de Atualização da Interface

O sistema de visualização opera em um ciclo por-frame coordenado por três funções principais:

  1. MicroProfileFlip(): Chamada uma vez por frame para finalizar a captura do frame atual e preparar o próximo. Esta função gerencia a rotação dos buffers circulares e dispara a geração de dados para o servidor web se ativo [microprofile.h:34].

  2. MicroProfileDraw(): Chamada uma vez por frame para renderizar a interface in-game. Esta função usa os callbacks de renderização para desenhar a UI sobre a aplicação [microprofile.h:35].

  3. MicroProfileToggleDisplayMode(): Alterna entre os modos de exibição (oculto, barras de frame, interface completa). Deve ser vinculado a uma tecla pelo desenvolvedor [microprofile.h:36].

Modos de Exibição

A interface in-game suporta múltiplos modos de exibição:

  • Modo Completo: Exibe toda a interface com timelines, contadores e controles
  • Modo Frame Bar: Exibe apenas a barra de frames para detecção de spikes sem obstruir gameplay [README.md:39-40]
  • Modo Oculto: Profiling continua ativo mas a interface não é renderizada

Sistema de Contadores

Além de timers, o sistema suporta contadores para rastrear valores que mudam ao longo do tempo:

cpp
1// Exemplo de uso de contador
2MICROPROFILE_COUNTER_ADD("Memory", "Allocations", 1);
3MICROPROFILE_COUNTER_SET("Network", "BytesReceived", totalBytes);

Contadores podem ser grafados em tempo real junto com timers, permitindo correlacionar métricas de desempenho com valores de estado da aplicação [README.md:15-16].

Integração e Dependências

A integração do microprofile em um projeto requer configuração de build, implementação de callbacks obrigatórios e inicialização dos sistemas apropriados.

Funções de Callback Obrigatórias

Além dos callbacks de renderização, o sistema requer implementação de funções de threading:

cpp
1const char* MicroProfileGetThreadName();  // Retorna nome da thread atual

[microprofile.h:85]

Esta função é usada para exibir nomes de threads significativos na visualização detalhada, facilitando a identificação de gargalos em aplicações multi-threaded.

Fluxo de Inicialização

正在加载图表渲染器...

Etapas do fluxo:

  1. Configuração de Build: O arquivo de implementação deve definir MICROPROFILE_IMPL antes de incluir microprofile.h para gerar as definições de todas as funções [microprofile.h:89].

  2. Inicialização de Thread: Cada thread que usa profiling deve chamar MicroProfileOnThreadCreate() no início de sua execução [microprofile.h:30].

  3. Inicialização GPU (Opcional): Se usar GPU profiling, inicializar o backend apropriado (MicroProfileGpuInitGL(), MicroProfileGpuInitD3D11(), etc.) [microprofile.h:91].

  4. Loop Principal: Integrar MicroProfileFlip() e MicroProfileDraw() no loop principal da aplicação [microprofile.h:34-35].

  5. Controles de Entrada: Vincular MicroProfileToggleDisplayMode() e MicroProfileTogglePause() a teclas ou controles de UI [microprofile.h:36-37].

Dependências de Plataforma

O microprofile é projetado para ser altamente portátil, com suporte conhecido para:

  • Windows XP e superiores
  • Linux
  • macOS (OSX)
  • iOS
  • Android
  • Xbox One

[README.md:22-23]

A portabilidade é alcançada através de abstrações condicionais de plataforma para:

  • Timers de alta resolução
  • Primitivas de sincronização (mutexes, condition variables)
  • Threads e TLS (Thread-Local Storage)
  • Sockets para servidor web

Configuração de Backends GPU

A tabela abaixo resume as opções de configuração para cada backend GPU:

BackendDefines NecessáriosInicializaçãoContexto Multi-thread
OpenGLMICROPROFILE_GPU_TIMERS_GL 1MicroProfileGpuInitGL()Não suportado
D3D11MICROPROFILE_GPU_TIMERS_D3D11 1MicroProfileGpuInitD3D11(Device)Não suportado
D3D12MICROPROFILE_GPU_TIMERS_D3D12 1MicroProfileGpuInitD3D12(Device, Queue)MICROPROFILE_GPU_TIMERS_MULTITHREADED 1
VulkanMICROPROFILE_GPU_TIMERS_VK 1MicroProfileGpuInitVK(Device, PhysicalDevice, Queue)MICROPROFILE_GPU_TIMERS_MULTITHREADED 1

[microprofile.h:87-114]

Decisões de Design e Trade-offs

O microprofile faz várias escolhas de design arquiteturais que refletem suas prioridades de baixa sobrecarga e facilidade de integração.

1. Header-Only Library

Decisão: Toda a funcionalidade é implementada em um único arquivo de cabeçalho.

Vantagens:

  • Integração trivial (apenas incluir o header)
  • Sem dependências de bibliotecas externas
  • Build simplificado

Desvantagens:

  • Tempo de compilação aumentado quando MICROPROFILE_IMPL é definido
  • Código fonte exposto ao projeto integrador

Justificativa: A simplicidade de integração foi priorizada sobre tempo de compilação, já que o profiler é tipicamente usado durante desenvolvimento e não em builds de produção.

2. Unificação de APIs CPU/GPU

Decisão: Macros únicos (MicroProfileEnter/MicroProfileLeave) detectam automaticamente se o grupo é CPU ou GPU.

Vantagens:

  • API mais simples para desenvolvedores
  • Menos macros para aprender
  • Código de instrumentação mais limpo

Desvantagens:

  • Overhead mínimo de verificação de tipo em runtime
  • Menos controle explícito sobre comportamento

Justificativa: A detecção automática reduz erros de uso e simplifica a instrumentação de código misto CPU/GPU [README.md:43].

3. Buffers Circulares por Thread

Decisão: Cada thread mantém seus próprios buffers de dados de profiling.

Vantagens:

  • Elimina contenção de locks durante captura
  • Escalabilidade em sistemas multi-core
  • Baixa sobrecarga por medição

Desvantagens:

  • Uso de memória proporcional ao número de threads
  • Agregação requer processamento de múltiplos buffers

Justificativa: A contenção de locks seria inaceitável para um profiler de desempenho, tornando esta escolha obrigatória.

4. Alocação Lazy de Buffers

Decisão: Buffers grandes são alocados apenas quando grupos são efetivamente capturados.

Vantagens:

  • Reduz overhead de memória quando profiler está inativo
  • Permite compilar em builds de produção sem penalidade

Desvantagens:

  • Possível stutter na primeira captura de cada grupo
  • Complexidade adicional no gerenciamento de memória

Justificativa: Permite que o profiler seja incluído em builds de produção sem impacto significativo em memória [README.md:49].

5. Servidor Web em Thread Dedicada

Decisão: O servidor web embutido roda em sua própria thread.

Vantagens:

  • Não bloqueia o thread principal da aplicação
  • Performance melhorada na geração de HTML
  • Responsividade da UI web mantida

Desvantagens:

  • Complexidade de sincronização entre threads
  • Requer suporte a threading na plataforma

Justificativa: A geração de HTML pode ser custosa; executá-la em thread separada mantém a aplicação principal responsiva [README.md:47].

6. Seleção Dinâmica de Backend GPU

Decisão: Múltiplos backends GPU podem ser compilados e um é selecionado em runtime.

Vantagens:

  • Mesmo binário funciona em diferentes configurações de hardware
  • Flexibilidade para aplicações multi-plataforma
  • Teste simplificado de múltiplos backends

Desvantagens:

  • Tamanho do binário aumentado
  • Código morto se apenas um backend é usado

Justificativa: Aplicações gráficas frequentemente suportam múltiplas APIs; permitir seleção dinâmica simplifica o código da aplicação [README.md:46].

7. Cores Automáticas Baseadas em Hash

Decisão: Valor de cor -1 gera cor automaticamente baseada no hash do nome.

Vantagens:

  • Menos trabalho para desenvolvedores
  • Cores consistentes entre execuções
  • Visualização automaticamente diversificada

Desvantagens:

  • Menos controle sobre estética
  • Possíveis colisões de cor

Justificativa: A conveniência supera a perda de controle fino sobre cores [README.md:42].

8. Limitação de Timestamps GPU a Uma Thread

Decisão: GPU timestamps só podem ser inseridos de uma thread por contexto.

Vantagens:

  • Simplifica implementação
  • Evita complexidade de sincronização GPU
  • Compatível com modelos de uso comuns

Desvantagens:

  • Limita profiling GPU em engines multi-threaded
  • Requer design cuidadoso em alguns casos

Justificativa: A maioria das APIs gráficas tem restrições similares; a limitação é aceitável dado o benefício em simplicidade [microprofile.h:113].

Tabela de Seleção de Tecnologias

TecnologiaUsoJustificativaAlternativas Consideradas
Header-onlyDistribuiçãoIntegração trivial, sem dependênciasBiblioteca estática, dinâmica
Macros C++InstrumentaçãoZero-overhead quando desabilitado, RAII automáticoFunções inline, templates
Buffers circularesArmazenamentoUso de memória limitado, sem alocações em runtimeVetores dinâmicos, mapas
TLS (Thread-Local Storage)Dados por threadElimina contenção, escalávelMutexes, lock-free queues
Callbacks de renderizaçãoVisualização in-gameFlexibilidade de backend, sem dependências gráficasRenderização embutida (OpenGL/DX)
Servidor HTTP embutidoVisualização webSem dependências externas, funciona em qualquer navegadorWebSocket, bibliotecas externas
Query objects GPUTiming GPUPrecisão de nanosegundos, suportado por todas APIsEstimativas baseadas em CPU
Hash de nomesIdentificação de timersComparação rápida, IDs estáveisStrings, enums
Alocação lazyGerenciamento de memóriaOverhead zero quando inativoAlocação antecipada
Cores por hashVisualizaçãoConveniência, consistênciaPaletas manuais

Relações de Dependência entre Módulos

O diagrama abaixo ilustra as dependências entre os principais módulos do sistema:

正在加载图表渲染器...

Análise de dependências:

  1. Macros → Timer Manager: Os macros de instrumentação dependem do gerenciador de timers para obter e registrar timestamps.

  2. Timer Manager → CPU/GPU Timers: O gerenciador abstrai as diferenças entre plataformas e backends, delegando a captura real para implementações específicas.

  3. Timer Manager → Buffers: Dados de timing são armazenados em buffers circulares para análise posterior.

  4. Buffers → Sistemas de Saída: Todos os sistemas de visualização consomem dados dos mesmos buffers, garantindo consistência.

  5. Thread Management → Buffers/Web: O sistema de threads gerencia buffers por thread e a thread dedicada do servidor web.

  6. UI → Render Callbacks: A interface in-game é independente de backend gráfico, delegando renderização para callbacks implementados pela aplicação.

Configuração e Fluxo de Inicialização Detalhado

A configuração do microprofile envolve várias etapas que devem ser realizadas na ordem correta para garantir funcionamento adequado.

Etapa 1: Configuração de Build

No arquivo de implementação (tipicamente microprofile.cpp):

cpp
1#define MICROPROFILE_IMPL
2#include "microprofile.h"
3
4// Opcional: habilitar backends GPU
5#define MICROPROFILE_GPU_TIMERS_GL 1
6// ou
7#define MICROPROFILE_GPU_TIMERS_D3D11 1
8// etc.

A ordem é crítica: MICROPROFILE_IMPL deve ser definido antes de incluir o header para gerar as definições de funções [microprofile.h:89].

Etapa 2: Implementação de Callbacks

A aplicação deve implementar os callbacks obrigatórios:

cpp
1// Renderização (necessários para UI in-game)
2void MicroProfileDrawText(int nX, int nY, uint32_t nColor, 
3                          const char* pText, uint32_t nNumCharacters) {
4    // Usar sistema de texto da aplicação
5}
6
7void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, 
8                         uint32_t nColor, MicroProfileBoxType type) {
9    // Usar sistema de renderização 2D da aplicação
10}
11
12void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, 
13                            uint32_t nColor) {
14    // Desenhar linhas 2D
15}
16
17// Threading
18const char* MicroProfileGetThreadName() {
19    // Retornar nome significativo para a thread atual
20    return "MainThread";
21}

[microprofile.h:75-86]

Etapa 3: Inicialização em Runtime

A inicialização deve ocorrer no início da aplicação, antes de qualquer código instrumentado:

cpp
1void InitializeProfiler() {
2    // Inicializar thread principal
3    MicroProfileOnThreadCreate("MainThread");
4    
5    // Inicializar backend GPU (se aplicável)
6    #if MICROPROFILE_GPU_TIMERS_GL
7        MicroProfileGpuInitGL();
8    #elif MICROPROFILE_GPU_TIMERS_D3D11
9        MicroProfileGpuInitD3D11(g_pD3D11Device);
10    #elif MICROPROFILE_GPU_TIMERS_D3D12
11        MicroProfileGpuInitD3D12(g_pD3D12Device, g_pCommandQueue);
12    #elif MICROPROFILE_GPU_TIMERS_VK
13        MicroProfileGpuInitVK(g_pVkDevice, g_pVkPhysicalDevice, g_pVkQueue);
14    #endif
15}

[microprofile.h:91-109]

Etapa 4: Integração no Loop Principal

O loop principal deve integrar as funções de atualização:

cpp
1void MainLoop() {
2    while (running) {
3        // Início do frame
4        BeginFrame();
5        
6        // Processar entrada
7        if (KeyPressed(KEY_F1)) {
8            MicroProfileToggleDisplayMode();
9        }
10        if (KeyPressed(KEY_F2)) {
11            MicroProfileTogglePause();
12        }
13        
14        // Atualizar lógica (código instrumentado)
15        Update();
16        
17        // Renderizar (código instrumentado)
18        Render();
19        
20        // Finalizar frame de profiling
21        MicroProfileFlip();
22        
23        // Renderizar UI do profiler (sobre a aplicação)
24        MicroProfileDraw();
25        
26        // Apresentar frame
27        Present();
28    }
29}

[microprofile.h:34-37]

Configuração para Modo Multi-threaded GPU

Para D3D12 ou Vulkan com gravação multi-threaded:

cpp
1// Configuração
2#define MICROPROFILE_GPU_TIMERS_MULTITHREADED 1
3
4// Thread de gravação
5void RecordCommandList(VkCommandBuffer cmd) {
6    MicroProfileGpuBegin(cmd);
7    
8    // Gravar comandos com markers de profiling
9    MICROPROFILE_SCOPEGPU("RenderPass", "Geometry", -1);
10    // ... comandos ...
11    
12    MicroProfileGpuEnd();
13}
14
15// Thread de submissão
16void SubmitCommandLists() {
17    // Coletar work de todas as threads
18    for (auto& work : pendingWork) {
19        MicroProfileGpuSubmit(work);
20    }
21    
22    // Submeter à GPU
23    vkQueueSubmit(...);
24}

[microprofile.h:102-105]

Verificação de Integração Correta

Para verificar se a integração está funcionando:

  1. UI In-Game: Pressionar a tecla vinculada a MicroProfileToggleDisplayMode() ou clicar no canto superior esquerdo da tela [microprofile.h:72].

  2. Servidor Web: Acessar http://localhost:1337 (porta padrão) em um navegador.

  3. Exportação HTML: Chamar MicroProfileDumpHtmlToFile() para gerar arquivo estático.

Se nenhum dado aparecer, verificar:

  • Callbacks de renderização estão implementados corretamente
  • MicroProfileFlip() está sendo chamado todo frame
  • Código está instrumentado com macros
  • Thread principal foi registrada com MicroProfileOnThreadCreate()