prometeu-runtime/discussion/workflow/agendas/AGD-0013-perf-vm-allocation-and-copy-pressure.md

6.9 KiB

id ticket title status created resolved decision tags
AGD-0013 perf-vm-allocation-and-copy-pressure Agenda - [PERF] VM Allocation and Copy Pressure accepted 2026-03-27 2026-04-20 DEC-0018

Agenda - [PERF] VM Allocation and Copy Pressure

Problema

O core da VM ainda aloca e clona demais em alguns caminhos relevantes, especialmente quando strings entram no fluxo.

Hoje ADD com string usa format!/to_string(), GET_GLOBAL clona valores e varios caminhos de erro montam strings dinamicas.

Dor

  • churn de heap reduz o teto de throughput da VM.
  • carts que abusam de string e estado global pagam custo cedo demais.
  • hardware barato sente alocacao repetitiva de forma desproporcional.

Hotspots Atuais

Alvo da Discussao

Definir o nivel de disciplina de alocacao/copia exigido do core da VM no baseline do console.

O Que Precisa Ser Definido

  1. Prioridade dos casos. Fechar quais caminhos sao realmente hot:

    • opcodes de string;
    • acesso a globals;
    • faults;
    • logs.
  2. Estrategia de ownership. Decidir onde vale introduzir:

    • borrow temporario;
    • small-string strategy;
    • copy-on-write;
    • intern/cache de strings.
  3. Meta de alocacao. Definir se o projeto quer:

    • zero alloc no frame loop feliz;
    • alloc rara e explicita;
    • apenas reducao oportunista.
  4. Instrumentacao. Decidir como medir alocacao sem transformar a VM em microbenchmark artificial.

Open Questions de Arquitetura

  1. Strings sao citizen de primeira classe no fantasy console ou recurso conveniente mas caro?
  2. Vale endurecer a linguagem/ABI para reduzir alocacao implicitamente?
  3. Caminhos de fault precisam ser maximizados para desempenho ou apenas os caminhos felizes?

Sugestoes para Fechar as Open Questions

  1. Strings devem ser tratadas como recurso suportado, mas caro por definicao no baseline. A VM hoje modela Value::String(String) como valor inline clonavel e o opcode ADD concatena via format!, entao o custo de copia ja faz parte do comportamento real do runtime. A sugestao nao e prometer "string cheap" na semantica base, e sim preservar string como capacidade legitima da linguagem enquanto o baseline otimiza os caminhos quentes que nao dependem de formatacao dinamica. Strings hardcoded podem ser materializadas uma vez na constant pool durante build/load; strings dinamicas podem ser materializadas em storage dinamico durante runtime. Em ambos os casos, a primeira materializacao e aceitavel. O que esta fora da meta e recopiar payload de string repetidamente no caminho quente depois dessa primeira materializacao.

  2. Vale endurecer o contrato operacional, mas nao a expressividade publica da linguagem neste primeiro passo. A recomendacao e evitar uma mudanca ampla de ABI agora. Em vez disso:

    • o caminho feliz do frame loop deve evitar alocacao implicita quando opera sobre numeros, handles e valores ja materializados;
    • strings dinamicas devem continuar permitidas, mas tratadas como custo explicito de runtime;
    • globals devem privilegiar handles e valores baratos no caminho quente, sem introduzir nova semantica publica para GET_GLOBAL;
    • qualquer estrategia mais invasiva, como intern global, copy-on-write ou heap-string canonica, deve nascer como decisao posterior se a telemetria provar necessidade.
  3. Fault paths nao precisam ser maximizados como se fossem caminho quente. A recomendacao e exigir que traps e faults permanencam corretos, deterministas e legiveis para tooling host-owned, mas sem contaminar o caminho feliz com formatacao defensiva ou montagem rica de strings em toda instrucao. O investimento principal deve ir para opcode dispatch, acesso a globals e operacoes repetidas por frame; faults podem aceitar custo maior desde que esse custo seja pago so na excecao.

Sugestao / Recomendacao

Fechar esta agenda com a seguinte linha:

  • baseline alvo: "happy path com alloc rara e explicita", nao "zero alloc absoluto";
  • prioridade imediata: reduzir copia/alocacao em GET_GLOBAL e nas operacoes de string mais frequentes do loop;
  • strings constantes: custo de materializacao pago uma vez no carregamento/constant pool e depois preferencialmente referenciadas;
  • strings dinamicas: custo inicial de criacao aceito em runtime, mas sem clones implicitos repetidos apos a primeira materializacao;
  • GET_GLOBAL: nenhuma nova semantica publica; a reducao de copia deve vir de representacao interna e ownership dos tipos caros;
  • ownership baseline: manter valores triviais por copia e mover payloads caros para representacoes por handle quando houver prova de pressao suficiente para justificar a complexidade;
  • faults/logs: preservar clareza e determinismo, aceitando custo fora do caminho feliz;
  • meta interna de engenharia: perseguir zero alloc no caminho feliz numerico e nos acessos quentes ja materializados, sem publicar isso como metrica de certificacao;
  • instrumentacao canonica: medir heap_used_bytes, frequencia de GC e contagem de logs/faults no fim do frame, mantendo contadores de alocacao como metrica interna de engenharia, sem transformar o dispatch em microbenchmark intrusivo.

Perguntas em Aberto

  • Nenhuma no nivel arquitetural atual. A agenda pode ser encerrada quando esta direcao for promovida para decisao normativa.

Dependencias

  • docs/specs/runtime/02a-vm-values-and-calling-convention.md
  • docs/specs/runtime/03-memory-stack-heap-and-allocation.md
  • docs/specs/runtime/10-debug-inspection-and-profiling.md

Criterio de Saida Desta Agenda

Pode virar PR quando houver decisao escrita sobre:

  • caminho quente prioritario para desengordurar;
  • meta minima de alocacao/copia da VM;
  • estrategia de ownership para strings/values;
  • instrumentacao canonica para medir regressao.

Resolucao Proposta

  • Strings continuam parte legitima da linguagem, mas sao tratadas como recurso potencialmente caro no baseline.
  • Strings hardcoded podem pagar custo de materializacao uma vez no carregamento/constant pool.
  • Strings dinamicas podem pagar custo inicial de criacao em runtime.
  • A arquitetura deve evitar recopia de payload apos a primeira materializacao sempre que o caminho quente puder operar por referencia, handle ou ownership interno mais barato.
  • GET_GLOBAL nao ganha nova semantica publica; qualquer reducao de copia deve vir de mudancas internas de representacao e processo.
  • Zero alloc no caminho feliz e meta interna de engenharia do runtime, nao criterio publicado de certificacao.
  • Faults e logs permanecem corretos e legiveis, mas nao dirigem a otimizacao principal.