Budgets de Performance
O AppCore mantém um benchmark reproduzível entre subsistemas para que correções de concorrência e persistência sejam medidas com as mesmas cargas V1.
appcore-dev cert bottlenecks
O comando em perfil release grava
builds/certification/bottlenecks.json. O relatório registra commit exato,
estado dirty, toolchain, sistema, arquitetura, p50/p95/p99, throughput, tempo
total e pico de memória residente. Ele também conta bytes solicitados ao heap
Rust, operações de alocação/desalocação, pico vivo e retenção por subsistema. O
CI Linux e Windows executa o mesmo gate e publica o artefato JSON.
RSS continua obrigatório porque os contadores Rust excluem metadata do allocator, bibliotecas nativas, memory mappings, buffers do kernel e memória de devices. Saturação dos contadores falha fechada. Cada workload fixo é limitado a 64 MiB de delta de heap vivo e 4 MiB de crescimento retido; o processo completo mantém os tetos maiores de catástrofe de RSS e heap. A primeira calibração release no Apple M1 observou pico vivo de 29.476.637 bytes e 139.611 bytes de crescimento retido no heap Rust.
Peer RPC relata intervalos de alocação separados para V1, stream V2, codecs V2 e erros tipados. Base64 JSON com scratch fixo e decode emprestado reduziram os bytes solicitados em 8,75% no workload completo, 7,20% no stream V2 e 21,36% nos codecs em runs pareados no Apple M1. Pico e heap retido não mudaram; operações de alocação subiram 5,44% e o p99 do stream 1,69%, portanto o relatório preserva esse tradeoff em vez de confundir churn com memória residente. Mover ownership dos chunks identity pelo encoder, frame e assembler reduziu os bytes solicitados no stream de 64 MiB de 1.072.617.252 para 938.399.524 (-12,51%) e as alocações em 7,39%, com +0,22% no p99 e -0,21% no RSS pico do processo. Esse checkpoint de ownership falhava acima de 960 MiB cumulativos. A atribuição por fase mostrou então 662.732.479 bytes solicitados no encode. Uma sonda de incompressibilidade fixa em stack reduziu o total do stream de 938.404.175 para 342.886.735 (-63,57%) e as alocações em 47,83%. Dois runs da sonda completa melhoraram o p99 entre 15,38% e 16,14%, mantendo gzip nas fixtures compressíveis. O gate agora é 384 MiB.
SQLite relata intervalos separados de alocação para startup, append, leitura pontual, construção das fixtures, enqueue da outbox, backup e integrity check. O enqueue de 512 records pequenos tem gates de 2 MiB solicitados no heap Rust e 250 ms p99. O scratch proporcional do BLOB incremental reduziu bytes solicitados no workload completo de 578.081.344 para 8.251.670 (-98,57%) e o delta de heap vivo de 1.083.528 para 233.600 bytes (-78,44%); o enqueue solicitou 255.676 bytes, não reteve crescimento e mediu 141.791 ns p99.
Cargas fixas
- startup manifest-first e dispatch concorrente de commands e queries;
- enqueue, leitura e ACK da outbox perto de 1, 10 e 64 MiB, mais comparação de materialização entre snapshot completo e página limitada sobre 256 mensagens;
- contenção do routing state do Gateway com 1, 100 e 1.000 tenants, mais uma prova de independência de lock entre tenants;
- 32 trocas HTTP/1.1 sequenciais por uma única conexão keep-alive aceita;
- encode, decode, integridade e replay JSON/base64 e binário/nativo do Peer RPC entre 1 KiB e 4 MiB, mais 4.096 round trips de rejeição V2 tipada;
- startup do scheduler e lotes limitados de 64 tasks vencidas.
As fixtures não contêm segredo estático. Cada execução obtém material secreto temporário da fonte aleatória do sistema operacional.
Uso dos budgets
Os limites portáveis impedem regressões em runners CI compartilhados. Eles não são promessa de performance em produção. Cada correção deve preservar V1, mostrar antes/depois, adicionar uma invariante de comportamento e apertar o budget afetado quando o resultado estiver estável.
A baseline inicial registrou concorrência máxima 1 nos handlers de commands e
queries. AC-001 remove a execução de command handler do mutex compartilhado do
host. O gate agora exige sobreposição de pelo menos quatro entre oito workers;
testes determinísticos exigem que os oito entrem juntos, preservam execução
única para uma chave idempotente igual e verificam a drenagem no shutdown.
AC-002 também remove a execução de query endpoint do mutex do host e aplica o
mesmo gate de quatro entre oito. Seu teste determinístico congela o registro e
exige sobreposição das oito chamadas de endpoint.
AC-003 substitui o mapa global público de tenants do Gateway por um diretório limitado com 32 shards e um lock por tenant. O gate mantém o write lock de um tenant enquanto exige que o lock de outro continue disponível. Como manter o mapa antigo restauraria a serialização ou duplicaria estado mutável, a correção continua bloqueada no RC até restaurar a compatibilidade 1.x e o campo antigo foi removido.
AC-004 remove o mutex global de metadata de requests pendentes. Um único mapa privado e limitado por tenant guarda channel de resposta, geração do worker, deadline e limite da resposta na mesma entrada. Testes determinísticos exigem cleanup após resposta, resposta inválida, timeout, cancelamento, shutdown, substituição e desconexão do worker; geração stale deve preservar a entrada atual.
AC-005 adiciona um cliente HTTP reutilizável com admissão por origem, conexões
ociosas e retenção de origens limitadas. Os deadlines de conexão/admissão,
leitura e escrita são independentes. Somente respostas totalmente delimitadas e
interpretadas voltam ao pool; qualquer falha ou resposta não reutilizável
descarta o socket. O gate exige as 32 trocas pela mesma conexão aceita. O
adapter V1 livre send continua one-shot com Connection: close.
AC-007 substitui reload/rewrite integral da outbox pelo journal append-only V2
explícito no 1.0.2-rc. As cargas de 1/10/64 MiB agora incluem um
pequeno enqueue incremental de tail limitado a 100 ms p99, enquanto ACK fica
limitado a 500 ms p99. A compactação atômica muda a geração; testes exigem
recovery do frame final incompleto e falha fechada para corrupção completa,
frames duplicados/reordenados e versões incompatíveis.
AC-011 adiciona índices diretos por tenant, Core ID e (cluster_id, core_id).
O gate executa 16.384 lookups entre o máximo de 1.024 workers registrados e
exige no máximo 1 ms p99, pelo menos 10.000 lookups/s e zero inconsistências.
Testes de reconnect, disconnect e prune de heartbeat exigem que geração stale
nunca remova a entrada atual.
AC-018 substitui uma thread por execução do scheduler por pool fixo e fila
limitada. O gate de 64 tasks exige que concorrência de callbacks e nomes
distintos de threads worker permaneçam dentro de max_concurrent_tasks, além
de observar ao menos um evento limitado de saturação da fila. Trabalho
excedente é adiado sem consumir tentativas de retry.
AC-020 adiciona o contrato de telemetria Gateway do 1.0.2-rc. O gate mantém
128 séries de capability, agrega oito nomes adicionais em uma série fixa de
overflow, executa 4.096 rotas instrumentadas sem worker disponível e constrói
256 snapshots. Ele exige zero rotas inflight residuais, cardinalidade e
overflow exatos, rota p99 no máximo de 1 ms e snapshot p99 no máximo de 5 ms.
A execução limpa macOS/aarch64 no commit de implementação 31c4fbe mediu
1.792 ns p99 para rota e 5.792 ns p99 para snapshot. A exportação é uma
fronteira pull explícita do deployment e nunca é chamada pelo roteamento.
AC-021 valida a matriz completa de erros tipados, decode V1 exato e 4.096 round
trips de encode/decode/validação de rejeição V2. O gate exige p99 de no máximo
1 ms e pelo menos 1.000 operações/s. A execução limpa macOS/aarch64 em
d11befe mediu p99 de 750 ns e 1.405.708 operações/s, com pico RSS total de
298.672 KiB. Artefatos CI Linux e Windows continuam sendo a autoridade de
plataforma.
AC-012 substitui a seleção aleatória por processo pelas policies estáveis
FirstAvailable, RoundRobin, LeastInflight, HealthWeighted e Affinity
stateless. O gate registra 64 workers, exige exatamente quatro seleções
round-robin por worker, verifica invariantes de health, capacity e affinity, e
executa 16.384 seleções por policy medida. Cada policy é limitada a 1 ms p99 e
deve superar 10.000 seleções/s. A execução final limpa macOS/aarch64 em
7caddc1 mediu 17.125 ns p99 para round-robin, 18.542 ns para least-inflight e
38.083 ns para affinity.
AC-013 adiciona 4.096 lookups no registry compartilhado e três rounds completos
de recovery com 1, 100 e 1.000 tenants, depois 64 requests com sucesso em cada
rota fenced local real e rota federada V2 autenticada. Lookup é limitado a 5 ms
p99 e deve superar 500/s; recovery é limitado a 5 s; rota local a 50 ms p99 e
100/s; federação a 250 ms p99 e 20/s. A execução limpa macOS/aarch64 em
7197416 mediu no máximo 667 ns p99 de lookup, 2,25 ms p99 de recovery, 0,35 ms
p99 de rota local e 0,91 ms p99 de rota federada. Testes Redis, proxy externo e
perda de owner continuam como evidências separadas; artefatos Linux e Windows
ainda são necessários.
AC-014 adiciona uma representação binária opt-in explícita para os DTOs Peer
RPC V2 existentes, preservando as fixtures JSON/base64 exatas e todas as rotas
V1. O gate exige que bytes de body binário fiquem em até 80% do JSON, que o p99
do codec binário não ultrapasse o JSON e que o buffer limitado fique em até
90% do JSON. A execução limpa macOS/aarch64 em 6f3bc38 mediu 25% menos bytes
de body, 93% menos p99 de codec e buffer 14% menor entre 64 KiB e 4 MiB; o pico
RSS total foi 306.448 KiB. Suporte binário ausente falha sem retry JSON.
Artefatos Linux e Windows ainda são necessários.
AC-015 adiciona páginas de outbox limitadas por quantidade/bytes, stats sem
payload, readiness durável de retry e receipts parciais exatos. O follower e a
CLI do Runtime não materializam mais a fila completa. A execução limpa
macOS/aarch64 em c904e83 materializou 460.684 bytes para uma página de sete
mensagens contra 30.021.820 bytes no snapshot completo de 256 mensagens, uma
redução de 98,46%. O p99 da página foi 71.458 ns contra 1.404.417 ns; o p99 de
stats foi 54.542 ns e o pico RSS total foi 244.752 KiB. O wire peer V1 permanece
inalterado; artefatos Linux e Windows ainda são necessários.
Veja o benchmark em AC-022 pública e a correção de commands em AC-001 pública. A correção de queries está em AC-002 pública. A correção do Gateway está em AC-003 pública. O ownership de requests pendentes está em AC-004 pública. O reuso de conexões HTTP está em AC-005 pública. A correção do journal da outbox está em AC-007 pública. O índice direto de workers está em AC-011 pública. O pool fixo do scheduler está em AC-018 pública. A telemetria limitada do Gateway está em AC-020 pública. A seleção limitada de workers está em AC-012 pública. A HA do Gateway está na AC-013 pública. O framing binário do Peer RPC está na AC-014 pública. A paginação limitada da outbox está na AC-015 pública. Os artefatos de plataforma restantes do erro wire tipado estão na AC-021 pública.