[PERF] Async Background Work Lanes for Assets and FS
This commit is contained in:
parent
bd147938a0
commit
8f37d971cd
@ -1,4 +1,4 @@
|
|||||||
{"type":"meta","next_id":{"DSC":43,"AGD":44,"DEC":34,"PLN":123,"LSN":50,"CLSN":1}}
|
{"type":"meta","next_id":{"DSC":43,"AGD":44,"DEC":35,"PLN":129,"LSN":50,"CLSN":1}}
|
||||||
{"type":"discussion","id":"DSC-0039","status":"abandoned","ticket":"render-pipeline-family-and-future-3d","title":"Render Pipeline Family and Future 3D","created_at":"2026-06-04","updated_at":"2026-06-04","tags":["gfx","renderer","runtime","architecture","pipeline"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-render-pipeline-family-and-future-3d.md","status":"abandoned","created_at":"2026-06-04","updated_at":"2026-06-04","_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."}
|
{"type":"discussion","id":"DSC-0039","status":"abandoned","ticket":"render-pipeline-family-and-future-3d","title":"Render Pipeline Family and Future 3D","created_at":"2026-06-04","updated_at":"2026-06-04","tags":["gfx","renderer","runtime","architecture","pipeline"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-render-pipeline-family-and-future-3d.md","status":"abandoned","created_at":"2026-06-04","updated_at":"2026-06-04","_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."}
|
||||||
{"type":"discussion","id":"DSC-0040","status":"done","ticket":"vm-render-parallel-execution-boundary","title":"VM and Render Parallel Execution Boundary","created_at":"2026-06-04","updated_at":"2026-06-06","tags":["runtime","renderer","vm","concurrency","architecture","perf"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0048","file":"discussion/lessons/DSC-0040-vm-render-parallel-execution-boundary/LSN-0048-render-workers-need-a-closed-packet-contract.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-06"}]}
|
{"type":"discussion","id":"DSC-0040","status":"done","ticket":"vm-render-parallel-execution-boundary","title":"VM and Render Parallel Execution Boundary","created_at":"2026-06-04","updated_at":"2026-06-06","tags":["runtime","renderer","vm","concurrency","architecture","perf"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0048","file":"discussion/lessons/DSC-0040-vm-render-parallel-execution-boundary/LSN-0048-render-workers-need-a-closed-packet-contract.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-06"}]}
|
||||||
{"type":"discussion","id":"DSC-0041","status":"open","ticket":"foreground-stack-game-pause-shell-vm-backed","title":"Foreground Stack, Game Pause, and VM-Backed Shell Coexistence","created_at":"2026-06-05","updated_at":"2026-06-05","tags":["runtime","os","lifecycle","shell","game","vm","foreground","architecture"],"agendas":[{"id":"AGD-0041","file":"AGD-0041-foreground-stack-game-pause-shell-vm-backed.md","status":"open","created_at":"2026-06-05","updated_at":"2026-06-05"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0041","status":"open","ticket":"foreground-stack-game-pause-shell-vm-backed","title":"Foreground Stack, Game Pause, and VM-Backed Shell Coexistence","created_at":"2026-06-05","updated_at":"2026-06-05","tags":["runtime","os","lifecycle","shell","game","vm","foreground","architecture"],"agendas":[{"id":"AGD-0041","file":"AGD-0041-foreground-stack-game-pause-shell-vm-backed.md","status":"open","created_at":"2026-06-05","updated_at":"2026-06-05"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
@ -18,9 +18,9 @@
|
|||||||
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"vm-owned-random-service","title":"Agenda - VM-Owned Random Service","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0005","file":"AGD-0005-vm-owned-random-service.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"vm-owned-random-service","title":"Agenda - VM-Owned Random Service","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0005","file":"AGD-0005-vm-owned-random-service.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0007","status":"open","ticket":"app-home-filesystem-surface-and-semantics","title":"Agenda - App Home Filesystem Surface and Semantics","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0006","file":"AGD-0006-app-home-filesystem-surface-and-semantics.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0007","status":"open","ticket":"app-home-filesystem-surface-and-semantics","title":"Agenda - App Home Filesystem Surface and Semantics","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0006","file":"AGD-0006-app-home-filesystem-surface-and-semantics.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"perf-runtime-telemetry-hot-path","title":"Agenda - [PERF] Runtime Telemetry Hot Path","created_at":"2026-03-27","updated_at":"2026-06-04","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0026","file":"discussion/lessons/DSC-0008-perf-runtime-telemetry-hot-path/LSN-0026-push-based-telemetry-model.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"perf-runtime-telemetry-hot-path","title":"Agenda - [PERF] Runtime Telemetry Hot Path","created_at":"2026-03-27","updated_at":"2026-06-04","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0026","file":"discussion/lessons/DSC-0008-perf-runtime-telemetry-hot-path/LSN-0026-push-based-telemetry-model.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||||
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"perf-async-background-work-lanes-for-assets-and-fs","title":"Agenda - [PERF] Async Background Work Lanes for Assets and FS","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0008","file":"AGD-0008-perf-async-background-work-lanes-for-assets-and-fs.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0009","status":"in_progress","ticket":"perf-async-background-work-lanes-for-assets-and-fs","title":"Agenda - [PERF] Async Background Work Lanes for Assets and FS","created_at":"2026-03-27","updated_at":"2026-06-28","tags":["perf","asset","fs","async","scheduler","runtime"],"agendas":[{"id":"AGD-0008","file":"AGD-0008-perf-async-background-work-lanes-for-assets-and-fs.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-06-28"}],"decisions":[{"id":"DEC-0034","file":"DEC-0034-async-work-lane-and-asset-backlog-contract.md","status":"accepted","created_at":"2026-06-28","updated_at":"2026-06-28","ref_agenda":"AGD-0008"}],"plans":[{"id":"PLN-0123","file":"PLN-0123-async-work-lane-specification-propagation.md","status":"open","created_at":"2026-06-28","updated_at":"2026-06-28","ref_decisions":["DEC-0034"]},{"id":"PLN-0124","file":"PLN-0124-async-work-lane-runtime-infrastructure.md","status":"open","created_at":"2026-06-28","updated_at":"2026-06-28","ref_decisions":["DEC-0034"]},{"id":"PLN-0125","file":"PLN-0125-asset-backlog-and-stable-slot-handles.md","status":"open","created_at":"2026-06-28","updated_at":"2026-06-28","ref_decisions":["DEC-0034"]},{"id":"PLN-0126","file":"PLN-0126-asset-backlog-public-api-and-status-surface.md","status":"open","created_at":"2026-06-28","updated_at":"2026-06-28","ref_decisions":["DEC-0034"]},{"id":"PLN-0127","file":"PLN-0127-async-lane-memcard-and-fs-integration-boundaries.md","status":"open","created_at":"2026-06-28","updated_at":"2026-06-28","ref_decisions":["DEC-0034"]},{"id":"PLN-0128","file":"PLN-0128-async-asset-pipeline-contract-tests-and-telemetry.md","status":"open","created_at":"2026-06-28","updated_at":"2026-06-28","ref_decisions":["DEC-0034"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0010","status":"done","ticket":"perf-host-desktop-frame-pacing-and-presentation","title":"Agenda - [PERF] Host Desktop Frame Pacing and Presentation","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0036","file":"discussion/lessons/DSC-0010-perf-host-desktop-frame-pacing-and-presentation/LSN-0036-frame-publication-and-host-invalidation-must-be-separate.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20"}]}
|
{"type":"discussion","id":"DSC-0010","status":"done","ticket":"perf-host-desktop-frame-pacing-and-presentation","title":"Agenda - [PERF] Host Desktop Frame Pacing and Presentation","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0036","file":"discussion/lessons/DSC-0010-perf-host-desktop-frame-pacing-and-presentation/LSN-0036-frame-publication-and-host-invalidation-must-be-separate.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20"}]}
|
||||||
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"perf-gfx-render-pipeline-and-dirty-regions","title":"Agenda - [PERF] GFX Render Pipeline and Dirty Regions","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0010","file":"AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0011","status":"abandoned","ticket":"perf-gfx-render-pipeline-and-dirty-regions","title":"Agenda - [PERF] GFX Render Pipeline and Dirty Regions","created_at":"2026-03-27","updated_at":"2026-06-28","tags":[],"agendas":[{"id":"AGD-0010","file":"AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md","status":"abandoned","created_at":"2026-03-27","updated_at":"2026-06-28","_override_reason":"User explicitly chose to remove this agenda because it no longer applies to the current render scenario; future optimizations can be discussed when needed."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to abandon this discussion because it no longer applies to the current render scenario; future optimizations can be discussed when needed."}
|
||||||
{"type":"discussion","id":"DSC-0012","status":"done","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-04-19","tags":["perf","runtime","syscall","telemetry","debug","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0034","file":"discussion/lessons/DSC-0012-perf-runtime-introspection-syscalls/LSN-0034-host-owned-debug-boundaries.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19"}]}
|
{"type":"discussion","id":"DSC-0012","status":"done","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-04-19","tags":["perf","runtime","syscall","telemetry","debug","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0034","file":"discussion/lessons/DSC-0012-perf-runtime-introspection-syscalls/LSN-0034-host-owned-debug-boundaries.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19"}]}
|
||||||
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"discussion/lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"discussion/lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||||
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"generic-memory-bank-slot-contract","title":"Agenda - Generic Memory Bank Slot Contract","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["runtime","asset","memory-bank","slots","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0029","file":"discussion/lessons/DSC-0024-generic-memory-bank-slot-contract/LSN-0029-slot-first-bank-telemetry-belongs-in-asset-manager.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"generic-memory-bank-slot-contract","title":"Agenda - Generic Memory Bank Slot Contract","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["runtime","asset","memory-bank","slots","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0029","file":"discussion/lessons/DSC-0024-generic-memory-bank-slot-contract/LSN-0029-slot-first-bank-telemetry-belongs-in-asset-manager.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||||
|
|||||||
@ -2,84 +2,556 @@
|
|||||||
id: AGD-0008
|
id: AGD-0008
|
||||||
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
title: Agenda - [PERF] Async Background Work Lanes for Assets and FS
|
title: Agenda - [PERF] Async Background Work Lanes for Assets and FS
|
||||||
status: open
|
status: accepted
|
||||||
created: 2026-03-27
|
created: 2026-03-27
|
||||||
resolved:
|
resolved: 2026-06-28
|
||||||
decision:
|
decision: DEC-0034
|
||||||
tags: []
|
tags: [perf, asset, fs, async, scheduler, runtime]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Agenda - [PERF] Async Background Work Lanes for Assets and FS
|
# Agenda - [PERF] Async Background Work Lanes for Assets and FS
|
||||||
|
|
||||||
|
## Contexto
|
||||||
|
|
||||||
|
Depois das decisoes de render worker, a concorrencia de render saiu do escopo
|
||||||
|
desta agenda. O problema restante e a lane de trabalho assincrono para IO,
|
||||||
|
decode e persistencia.
|
||||||
|
|
||||||
|
O modelo de execucao que queremos discutir agora assume uma terceira core/lane
|
||||||
|
dedicada a trabalhos assincronos de runtime:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Core/lane 1: VM, firmware, SystemOS e frame logico
|
||||||
|
Core/lane 2: render worker / rasterizacao assincrona
|
||||||
|
Core/lane 3: async work lane para asset IO/decode e possivelmente FS
|
||||||
|
```
|
||||||
|
|
||||||
|
Essa terceira lane nao deve virar um pool grande e solto. A intencao e ter uma
|
||||||
|
fila previsivel, com capacidade limitada, telemetria e regras de saturacao.
|
||||||
|
|
||||||
|
Para assets, a necessidade e concreta: `asset.load()` ainda cria uma thread do
|
||||||
|
SO por requisicao. Para FS, a motivacao provavel era evitar que operacoes de
|
||||||
|
leitura/escrita/listagem/delete, hoje chamadas de forma sincrona pelo dispatch,
|
||||||
|
roubem tempo do frame quando o backend real envolver IO. Precisamos verificar
|
||||||
|
se FS deve usar a mesma lane agora ou apenas reservar compatibilidade.
|
||||||
|
|
||||||
## Problema
|
## Problema
|
||||||
|
|
||||||
`asset.load()` hoje cria uma thread do SO por requisicao. Ao mesmo tempo, `fs` ainda nao tem uma politica clara para sync assincrono barato em hardware simples.
|
`asset.load()` hoje dispara `thread::spawn` por requisicao de asset nao
|
||||||
|
residente. Isso escala mal, cria jitter e deixa o runtime sem uma politica
|
||||||
|
unica de backpressure.
|
||||||
|
|
||||||
O projeto precisa de paralelismo para IO/decode/sync, mas o target inclui handheld DIY e hardware barato, onde um pool grande ou explosao de threads pode piorar a latencia em vez de melhorar.
|
O dominio `fs` tambem tem operacoes potencialmente bloqueantes (`read`,
|
||||||
|
`write`, `list_dir`, `delete`, memcard commit/read/write) e a tabela de
|
||||||
|
syscalls ja as marca como nao deterministicas/custosas. Ainda assim, a
|
||||||
|
implementacao atual executa essas chamadas diretamente no caminho de dispatch.
|
||||||
|
|
||||||
## Dor
|
Sem um contrato explicito, cada dominio pode inventar sua propria concorrencia:
|
||||||
|
asset criando threads, FS bloqueando o frame, e memcard herdando comportamento
|
||||||
|
acidental do backend.
|
||||||
|
|
||||||
|
## Pontos Criticos
|
||||||
|
|
||||||
- `thread::spawn` por request escala mal e cria jitter.
|
- `thread::spawn` por request escala mal e cria jitter.
|
||||||
- assets e `fs` competem por IO sem uma politica unica de fila/prioridade.
|
- A terceira core/lane deve ser um recurso de plataforma controlado, nao uma
|
||||||
- sem lane dedicada, operacoes de background tendem a vazar custo para o main loop.
|
permissao geral para criar threads.
|
||||||
- sem disciplina, o host desktop vira referencia errada para hardware fraco.
|
- Asset loading precisa de um pool/fila limitada para multiplos loads
|
||||||
|
pendentes.
|
||||||
|
- FS pode justificar a mesma lane quando envolver IO real, mas nao devemos
|
||||||
|
assinar uma API assincrona ampla sem entender a semantica de retorno.
|
||||||
|
- Commit/install em bancos residentes pode ter restricoes de determinismo e
|
||||||
|
ownership; decode pode ser assincrono, mas publicacao/instalacao talvez tenha
|
||||||
|
que cruzar de volta para a lane principal.
|
||||||
|
- A estrategia precisa funcionar em hardware alvo com poucos cores e tambem no
|
||||||
|
host desktop sem transformar desktop em referencia de custo errada.
|
||||||
|
- Render worker ja tem seu proprio contrato e nao deve compartilhar essa lane.
|
||||||
|
|
||||||
## Hotspots Atuais
|
## Hotspots Atuais
|
||||||
|
|
||||||
- [asset.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-drivers/src/asset.rs#L353)
|
- [asset.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-drivers/src/asset.rs#L438) - `AssetManager::load`.
|
||||||
- [tick.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs#L53)
|
- [asset.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-drivers/src/asset.rs#L507) - `thread::spawn` por load.
|
||||||
- [runner.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/host/prometeu-host-desktop-winit/src/runner.rs#L315)
|
- [fs.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-hal/src/syscalls/domains/fs.rs#L4) - `fs` e `mem` marcados como superficies custosas/nao deterministicas.
|
||||||
|
- [dispatch.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs#L549) - chamadas `fs.*` executam no dispatch.
|
||||||
|
- [virtual_fs.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/services/fs/virtual_fs.rs#L69) - VFS normaliza path e chama backend diretamente.
|
||||||
|
|
||||||
## Alvo da Discussao
|
## Alvo da Discussao
|
||||||
|
|
||||||
Fechar um modelo de execucao assincrona para `asset` e `fs` que seja previsivel em hardware simples.
|
Fechar um modelo de terceira core/lane para trabalho assincrono de runtime,
|
||||||
|
comecando por asset loading e avaliando se FS deve entrar na mesma lane no v1.
|
||||||
|
|
||||||
|
O alvo nao e criar multitarefa geral, callbacks para guest, ou um scheduler
|
||||||
|
paralelo da VM. A lane deve executar trabalho de IO/decode/sync e publicar
|
||||||
|
resultados observaveis por status/polling em pontos previsiveis.
|
||||||
|
|
||||||
## O Que Precisa Ser Definido
|
## O Que Precisa Ser Definido
|
||||||
|
|
||||||
1. Topologia de workers.
|
1. Topologia da terceira lane.
|
||||||
Escolher entre:
|
Definir:
|
||||||
- uma thread dedicada para `asset` e outra para `fs`;
|
- uma async work lane dedicada, separada da VM e do render worker;
|
||||||
- um worker unico multiplexando filas;
|
- se a lane e uma thread fixa no host e uma core dedicada no hardware alvo;
|
||||||
- um pool minimo e fixo;
|
- fallback quando nao houver core fisico dedicado;
|
||||||
- proibicao explicita de `spawn` por request.
|
- proibicao explicita de `thread::spawn` por request no caminho normal.
|
||||||
|
|
||||||
2. Separacao por dominio.
|
2. Pool/fila de asset loading.
|
||||||
Decidir se `asset` e `fs` compartilham scheduler/fila ou se cada dominio tem lane propria.
|
Definir:
|
||||||
|
- backlog de pedidos sem limite operacional fixo;
|
||||||
|
- exatamente um job ativo por vez na lane;
|
||||||
|
- o "pool" significa backlog e estados de job, nao multiplos workers reais;
|
||||||
|
- politica de substituicao/cancelamento para pedidos que miram o mesmo
|
||||||
|
bank/slot;
|
||||||
|
- status para pending/backlog, ativo, progresso, cancelamento, erro de
|
||||||
|
decode e sucesso.
|
||||||
|
|
||||||
3. Politica de prioridade.
|
3. Fases do asset load.
|
||||||
|
Separar:
|
||||||
|
- request e alocacao de handle;
|
||||||
|
- leitura de bytes;
|
||||||
|
- decode/materializacao;
|
||||||
|
- staging de resultado;
|
||||||
|
- install/commit em banco residente.
|
||||||
|
|
||||||
|
Ponto a fechar: quais fases rodam na terceira lane e quais voltam para a
|
||||||
|
lane principal por determinismo/ownership.
|
||||||
|
|
||||||
|
4. Inclusao de FS na mesma lane.
|
||||||
|
Verificar se `fs` deve usar a terceira lane no v1 para:
|
||||||
|
- leituras grandes;
|
||||||
|
- escritas;
|
||||||
|
- listagem;
|
||||||
|
- delete;
|
||||||
|
- memcard commit/read/write.
|
||||||
|
|
||||||
|
Ponto a fechar: FS sync publico continua bloqueante/status-first, vira
|
||||||
|
request/poll, ou ganha apenas uma implementacao interna que drena trabalho em
|
||||||
|
pontos de frame.
|
||||||
|
|
||||||
|
5. Separacao por dominio.
|
||||||
|
Decidir se `asset` e `fs` compartilham uma fila com classes de prioridade ou
|
||||||
|
se a terceira lane contem subfilas dedicadas.
|
||||||
|
|
||||||
|
6. Politica de prioridade.
|
||||||
Definir:
|
Definir:
|
||||||
- prioridade de loads visuais vs audio;
|
- prioridade de loads visuais vs audio;
|
||||||
- prioridade de sync de save/config;
|
- prioridade de save/config;
|
||||||
- limite de trabalho por frame para install/commit.
|
- prioridade de memcard commit;
|
||||||
|
- starvation prevention;
|
||||||
|
- limite de trabalho de instalacao/publicacao por frame.
|
||||||
|
|
||||||
4. Modelo de retorno.
|
7. Modelo de retorno e telemetria.
|
||||||
Fechar como o guest observa backlog, cancelamento e saturacao:
|
Fechar como guest/runtime observa:
|
||||||
- status imediato de fila cheia;
|
- `pending`;
|
||||||
- status de pending;
|
- `loading`;
|
||||||
- metrica de backlog;
|
- `ready`;
|
||||||
- politica de cancelamento.
|
- `canceled`;
|
||||||
|
- `backend_unavailable`;
|
||||||
|
- backlog;
|
||||||
|
- posicao de um asset no backlog;
|
||||||
|
- progresso percentual do asset ativo;
|
||||||
|
- drops/retries quando aplicavel.
|
||||||
|
|
||||||
5. Orçamento para hardware barato.
|
8. Orcamento para hardware barato.
|
||||||
Definir quantas threads o runtime pode assumir como baseline.
|
Definir o baseline:
|
||||||
|
- VM principal;
|
||||||
|
- render worker;
|
||||||
|
- terceira async work lane;
|
||||||
|
- limites de memoria para jobs pendentes e buffers temporarios.
|
||||||
|
|
||||||
## Open Questions de Arquitetura
|
## Opcoes
|
||||||
|
|
||||||
1. O v1 precisa de lanes separadas para `asset` e `fs` ou basta uma fila central com classes de prioridade?
|
### Opcao A - Terceira lane unica com subfilas e pool limitado de assets
|
||||||
2. Decode de asset fica no mesmo worker do IO ou em fase distinta?
|
|
||||||
3. Commit/install no device continua no main thread por determinismo?
|
- **Abordagem:** criar uma async work lane dedicada. Assets usam um pool/fila
|
||||||
|
de jobs nessa lane; FS tambem pode submeter jobs na mesma lane, com
|
||||||
|
prioridade menor ou classe separada.
|
||||||
|
- **Pro:** modelo simples de budget; evita explosao de threads; encaixa no alvo
|
||||||
|
de terceira core; permite compartilhar backpressure e telemetria.
|
||||||
|
- **Contra:** assets e FS podem competir por IO; precisa politica clara para
|
||||||
|
evitar que save/config fique atras de loads longos.
|
||||||
|
- **Manutenibilidade:** boa se a lane tiver tipos de job e estados explicitos.
|
||||||
|
|
||||||
|
### Opcao B - Lane de assets agora, FS apenas reservado
|
||||||
|
|
||||||
|
- **Abordagem:** fechar v1 somente para asset loading, removendo `spawn` por
|
||||||
|
request. FS continua sincrono por enquanto, mas o contrato da lane reserva
|
||||||
|
compatibilidade para FS no futuro.
|
||||||
|
- **Pro:** menor escopo; resolve a dor concreta de assets rapidamente; evita
|
||||||
|
alterar semantica de FS antes da agenda de app home filesystem.
|
||||||
|
- **Contra:** nao resolve stalls reais de FS/memcard; pode exigir refatorar a
|
||||||
|
lane depois para aceitar FS.
|
||||||
|
- **Manutenibilidade:** boa no curto prazo, com risco de segunda migracao.
|
||||||
|
|
||||||
|
### Opcao C - Lanes separadas para asset e FS
|
||||||
|
|
||||||
|
- **Abordagem:** criar uma lane/pool para assets e outra para FS.
|
||||||
|
- **Pro:** isolamento forte; FS/save nao compete diretamente com loads de
|
||||||
|
textura/audio/cena.
|
||||||
|
- **Contra:** consome mais threads/cores; contraria a premissa de terceira core
|
||||||
|
unica; pior para hardware simples.
|
||||||
|
- **Manutenibilidade:** media; isolamento ajuda, mas a topologia fica pesada.
|
||||||
|
|
||||||
|
### Opcao D - Pool global pequeno sem nocao de terceira lane
|
||||||
|
|
||||||
|
- **Abordagem:** trocar `spawn` por request por um pool global fixo.
|
||||||
|
- **Pro:** simples de implementar em host desktop.
|
||||||
|
- **Contra:** perde a arquitetura de lanes por core; pode mascarar custo em
|
||||||
|
desktop; fica menos claro como mapear para hardware alvo.
|
||||||
|
- **Manutenibilidade:** baixa para o modelo de console se virar dependencia
|
||||||
|
acidental de scheduler do SO.
|
||||||
|
|
||||||
|
## Sugestao / Recomendacao
|
||||||
|
|
||||||
|
Recomendo seguir com a Opcao A como direcao de arquitetura, mas fechar a
|
||||||
|
decisao em duas camadas:
|
||||||
|
|
||||||
|
1. Contrato obrigatorio agora:
|
||||||
|
- terceira async work lane como recurso runtime;
|
||||||
|
- assets deixam de usar `thread::spawn` por requisicao;
|
||||||
|
- asset loading passa por backlog consultavel/reordenavel;
|
||||||
|
- status, progresso e telemetria de backlog ficam explicitos.
|
||||||
|
|
||||||
|
2. Contrato condicionado para FS:
|
||||||
|
- FS deve ser analisado como consumidor legitimo da mesma lane porque suas
|
||||||
|
operacoes podem envolver IO real e ja sao custosas/nao deterministicas;
|
||||||
|
- a decisao precisa escolher entre incluir FS no v1 ou reservar a lane para
|
||||||
|
FS sem mudar ainda a superficie publica;
|
||||||
|
- memcard precisa ser considerado junto com FS, porque usa a mesma
|
||||||
|
capacidade e backend de persistencia.
|
||||||
|
|
||||||
|
O ponto importante: a terceira core/lane deve ser a unidade de concorrencia.
|
||||||
|
O pool de assets deve existir dentro desse modelo, nao como criacao livre de
|
||||||
|
threads por load.
|
||||||
|
|
||||||
|
## Respostas Consolidadas Ate Aqui
|
||||||
|
|
||||||
|
1. O pool de assets deve ser uma lane serial.
|
||||||
|
- Ha exatamente um job ativo na async work lane.
|
||||||
|
- O pool representa backlog, estados e controle de ordem, nao multiplos
|
||||||
|
workers executando em paralelo.
|
||||||
|
|
||||||
|
2. O backlog de pedidos deve ser semanticamente ilimitado.
|
||||||
|
- Nao existe `queue_full` como status normal do dominio.
|
||||||
|
- Como cada pedido mira um `bank_type/slot` e pedidos novos para o mesmo
|
||||||
|
alvo substituem os anteriores, o backlog efetivo fica limitado pela soma
|
||||||
|
dos slots dos bancos.
|
||||||
|
- O contrato nao precisa expor limite de fila, mas a implementacao deve
|
||||||
|
garantir que metadados de handles cancelados/superseded nao crescam sem
|
||||||
|
coleta.
|
||||||
|
|
||||||
|
3. Asset loading precisa expor consulta e reordenacao do backlog.
|
||||||
|
- Deve existir API publica/runtime para consultar onde um asset esta no
|
||||||
|
backlog.
|
||||||
|
- Deve existir capacidade de adiantar ou atrasar um pedido de asset na fila.
|
||||||
|
- O asset ativo deve expor progresso percentual.
|
||||||
|
- Requests novos para o mesmo `bank_type/slot` devem cancelar pedidos
|
||||||
|
anteriores pendentes para aquele alvo, evitando carregar asset que ja foi
|
||||||
|
substituido antes de executar.
|
||||||
|
- Se o alvo ja estiver carregado com o mesmo `asset_id`, o novo request nao
|
||||||
|
entra no backlog; ele retorna imediatamente pronto com handle disponivel.
|
||||||
|
- Se um novo request substituir o alvo atualmente ativo, a lane deve cancelar
|
||||||
|
em ponto cooperativo quando possivel; se o trabalho nao puder ser
|
||||||
|
interrompido, o resultado antigo deve ser descartado ao final por geracao
|
||||||
|
superseded.
|
||||||
|
- `superseded` significa que um request foi substituido por outro request
|
||||||
|
mais novo para o mesmo `bank_type/slot`. Nao e erro e nao e cancelamento
|
||||||
|
manual; e obsolescencia operacional do pedido antigo.
|
||||||
|
- Handles representam o slot do bank como alvo estavel. Dentro do estado do
|
||||||
|
handle deve existir uma secao de request/backlog para aquele slot,
|
||||||
|
informando se ha pedido pendente/ativo, qual asset foi solicitado,
|
||||||
|
progresso, posicao e geracao.
|
||||||
|
- Handles devem ser capazes de consultar o estado do alvo `bank_type/slot`
|
||||||
|
a qualquer momento. Se nao houver asset valido carregado e tambem nao
|
||||||
|
houver request pendente para aquele alvo, a consulta deve retornar estado
|
||||||
|
explicito de vazio/invalido, nao falhar por ausencia de request ativo.
|
||||||
|
|
||||||
|
4. Decode/materializacao fria rodam na terceira lane.
|
||||||
|
- Leitura e decode de asset podem acontecer fora da lane principal.
|
||||||
|
- O resultado deve voltar como material pronto/staged.
|
||||||
|
|
||||||
|
5. Install/commit em bancos residentes continua na lane principal.
|
||||||
|
- A async lane prepara trabalho.
|
||||||
|
- A lane principal publica/instala em pontos previsiveis por ownership,
|
||||||
|
determinismo e integracao com bancos/render/audio.
|
||||||
|
|
||||||
|
6. FS e memcard entram como consumidores possiveis da mesma lane, mas precisam
|
||||||
|
ser melhor amarrados com a agenda de app home filesystem.
|
||||||
|
- A `DSC-0007` / `AGD-0006` deve ser ajustada para estabelecer melhor a
|
||||||
|
superficie publica e o modelo async/sync de FS.
|
||||||
|
- Esta agenda deve afirmar a existencia da lane para trabalhos async de IO
|
||||||
|
desse tipo e permitir que FS a consuma.
|
||||||
|
- Questoes de API publica de FS, request/poll e semantica de app home devem
|
||||||
|
ficar a cargo da agenda 6.
|
||||||
|
- FS, memcard e assets nao devem operar sobrepostos quando isso gerar
|
||||||
|
concorrencia real de backend; se houver competicao, a fila unica resolve a
|
||||||
|
ordem.
|
||||||
|
|
||||||
|
7. Prioridade quando houver competicao:
|
||||||
|
- memcard commit/write;
|
||||||
|
- FS write/config;
|
||||||
|
- asset visual/audio load;
|
||||||
|
- list/read nao critico.
|
||||||
|
|
||||||
|
8. Status-first continua valendo.
|
||||||
|
- `backend_unavailable`, `canceled`, erro de decode e estados de job sao
|
||||||
|
status operacionais.
|
||||||
|
- Cancelamento por superseding de pedido no mesmo bank/slot e resultado
|
||||||
|
operacional normal, nao fault.
|
||||||
|
- Nao ha `queue_full` no contrato esperado.
|
||||||
|
- Trap permanece para violacao estrutural, como argumento invalido,
|
||||||
|
capability ausente ou handle estruturalmente invalido.
|
||||||
|
|
||||||
|
9. Telemetria minima:
|
||||||
|
- backlog atual;
|
||||||
|
- posicao por asset;
|
||||||
|
- progresso percentual do asset ativo;
|
||||||
|
- jobs submetidos, concluidos, falhos e cancelados;
|
||||||
|
- tempo por job;
|
||||||
|
- percentis por asset enquanto estiver carregando na lane.
|
||||||
|
|
||||||
|
10. Escopo da agenda.
|
||||||
|
- O foco desta agenda e a lane, assets e memcard/game persistence.
|
||||||
|
- FS entra como consumidor permitido da lane de IO, mas as decisoes de API
|
||||||
|
publica de FS pertencem a `AGD-0006`.
|
||||||
|
|
||||||
|
11. API de backlog.
|
||||||
|
- A API inicial sugerida cobre os casos esperados.
|
||||||
|
- `asset.backlog_promote(handle)` deve ser mantido como atalho oficial para
|
||||||
|
`asset.backlog_move(handle, 1)`.
|
||||||
|
- `asset.backlog_demote(handle)` deve ser mantido como atalho oficial para
|
||||||
|
mover o pedido para o fim dos pendentes.
|
||||||
|
- Os atalhos nao criam semantica nova; apenas evitam que o caller calcule
|
||||||
|
posicoes comuns.
|
||||||
|
- O handle deve permitir consulta estavel do slot do bank mesmo quando nao ha
|
||||||
|
asset valido carregado.
|
||||||
|
- O estado do handle deve separar:
|
||||||
|
- estado do slot/residencia atual;
|
||||||
|
- estado do request/backlog atual para aquele slot.
|
||||||
|
- Operacoes que mudam estado, como commit/cancel/reorder, atuam sobre a
|
||||||
|
secao de request/backlog do handle e precisam validar geracao/request atual
|
||||||
|
para nao agir sobre um pedido substituido.
|
||||||
|
|
||||||
|
12. Cancelamento por substituicao.
|
||||||
|
- Quando um request novo chega para o mesmo `bank_type/slot`, o request
|
||||||
|
anterior e marcado imediatamente como `superseded`.
|
||||||
|
- Se o request anterior ainda estiver no backlog, ele sai da fila.
|
||||||
|
- Se o request anterior estiver ativo, a lane tenta cancelar
|
||||||
|
cooperativamente quando a fase atual permitir.
|
||||||
|
- Se a fase ativa nao puder ser interrompida com baixo custo, ela termina e
|
||||||
|
o resultado e descartado ao final porque a geracao do alvo ja mudou.
|
||||||
|
- Como o handle pertence ao slot do bank, ele continua consultavel; sua
|
||||||
|
secao de request deve indicar que a geracao anterior foi `superseded` ou
|
||||||
|
que nao ha request ativo para aquele alvo.
|
||||||
|
|
||||||
|
13. Fases de progresso.
|
||||||
|
- `read/decode/stage` e suficiente como modelo minimo para `GLYPH`, `SOUND`
|
||||||
|
e `SCENE`.
|
||||||
|
- Subfases futuras podem detalhar progresso dentro de `decode` sem mudar o
|
||||||
|
contrato geral.
|
||||||
|
|
||||||
|
14. Percentis.
|
||||||
|
- Percentis devem existir por `bank_type` como telemetria principal.
|
||||||
|
- Percentis por `asset_id` tambem sao uteis, mas podem usar janela pequena
|
||||||
|
ou agregador leve.
|
||||||
|
- Percentis sao atualizados no fechamento do job, nao durante o hot path.
|
||||||
|
|
||||||
|
15. Ajuste esperado na agenda de FS.
|
||||||
|
- `AGD-0006` deve registrar que existe uma async IO lane compartilhavel por
|
||||||
|
FS/memcard/assets.
|
||||||
|
- Esta agenda so decide que FS pode consumir a lane.
|
||||||
|
- A API publica de FS, incluindo request/poll ou sync aparente, pertence a
|
||||||
|
`AGD-0006`.
|
||||||
|
|
||||||
|
## API Inicial Sugerida Para Assets
|
||||||
|
|
||||||
|
Esta agenda ainda nao fecha nomes finais de ABI, mas a direcao inicial sugerida
|
||||||
|
e manter `asset.load/status/commit/cancel` e adicionar uma superficie pequena
|
||||||
|
para backlog:
|
||||||
|
|
||||||
|
1. `asset.backlog_info() -> (status, pending_count, active_handle, active_asset_id, active_bank_type, active_slot, active_progress)`
|
||||||
|
- Consulta o estado geral da lane de assets.
|
||||||
|
- `active_progress` usa escala inteira, preferencialmente `0..10000` para
|
||||||
|
permitir duas casas decimais sem float.
|
||||||
|
|
||||||
|
2. `asset.backlog_position(handle) -> (status, state, position, progress)`
|
||||||
|
- Consulta um pedido especifico.
|
||||||
|
- `position = 0` significa job ativo.
|
||||||
|
- `position > 0` significa posicao no backlog.
|
||||||
|
- `position = -1` pode representar nao enfileirado/pronto/cancelado,
|
||||||
|
dependendo do `state`.
|
||||||
|
|
||||||
|
3. `asset.backlog_move(handle, new_position) -> status`
|
||||||
|
- Move um pedido pendente para uma posicao absoluta.
|
||||||
|
- `new_position = 1` significa primeiro pendente depois do ativo.
|
||||||
|
- Nao interrompe diretamente o job ativo; substituicao do mesmo
|
||||||
|
`bank_type/slot` usa a regra de superseding.
|
||||||
|
|
||||||
|
4. `asset.backlog_promote(handle) -> status`
|
||||||
|
- Atalho para mover o pedido para a frente do backlog pendente.
|
||||||
|
|
||||||
|
5. `asset.backlog_demote(handle) -> status`
|
||||||
|
- Atalho para mover o pedido para o fim do backlog pendente.
|
||||||
|
|
||||||
|
6. `asset.target_status(bank_type, slot) -> (status, asset_id, handle, state, position, progress)`
|
||||||
|
- Consulta por alvo operacional, que e o que realmente controla superseding.
|
||||||
|
- Ajuda quando o caller quer saber "o que esta programado para este slot".
|
||||||
|
|
||||||
|
Estados sugeridos para `state`:
|
||||||
|
|
||||||
|
- `empty`;
|
||||||
|
- `invalid`;
|
||||||
|
- `queued`;
|
||||||
|
- `active`;
|
||||||
|
- `ready`;
|
||||||
|
- `committed`;
|
||||||
|
- `canceled`;
|
||||||
|
- `superseded`;
|
||||||
|
- `error`;
|
||||||
|
- `backend_unavailable`.
|
||||||
|
|
||||||
|
Regra de design: APIs de backlog sao operacionais e status-first. Reordenar um
|
||||||
|
handle inexistente, ja concluido ou ja superseded retorna status operacional
|
||||||
|
apropriado quando o handle e conhecido; violações estruturais continuam Trap.
|
||||||
|
|
||||||
|
Handles sao observaveis e representam slots de banks. Um handle conhecido pode
|
||||||
|
ser consultado mesmo quando o slot alvo nao contem asset valido carregado; nesse
|
||||||
|
caso a consulta deve retornar estado como `empty` ou `invalid`.
|
||||||
|
|
||||||
|
O estado do handle deve conter pelo menos duas partes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
slot_state:
|
||||||
|
loaded_asset_id
|
||||||
|
resident_state
|
||||||
|
|
||||||
|
request_state:
|
||||||
|
requested_asset_id
|
||||||
|
generation
|
||||||
|
queued/active/ready/canceled/superseded/error
|
||||||
|
backlog_position
|
||||||
|
progress
|
||||||
|
```
|
||||||
|
|
||||||
|
Mutacoes seguem regras mais estritas e devem falhar operacionalmente quando a
|
||||||
|
secao de request/backlog do handle nao representa a geracao atual.
|
||||||
|
|
||||||
|
## Progresso e Percentis
|
||||||
|
|
||||||
|
### Progresso percentual
|
||||||
|
|
||||||
|
Sugestao:
|
||||||
|
|
||||||
|
- usar progresso em base inteira `0..10000`;
|
||||||
|
- quando o tamanho total de bytes for conhecido, calcular progresso por fases
|
||||||
|
ponderadas;
|
||||||
|
- quando o decode nao for linear ou nao houver tamanho confiavel, expor
|
||||||
|
progresso por fase com marcos conservadores.
|
||||||
|
|
||||||
|
Modelo inicial de fases:
|
||||||
|
|
||||||
|
```text
|
||||||
|
queued -> 0
|
||||||
|
read -> 0..4000
|
||||||
|
decode -> 4000..9000
|
||||||
|
stage -> 9000..10000
|
||||||
|
ready -> 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
Se uma fase nao consegue reportar progresso interno, ela deve manter o ultimo
|
||||||
|
marco e saltar para o proximo marco ao concluir. Isso evita progresso falso
|
||||||
|
sem perder visibilidade de fase.
|
||||||
|
|
||||||
|
### Percentis por asset
|
||||||
|
|
||||||
|
Sugestao:
|
||||||
|
|
||||||
|
- registrar duracoes por asset no fim de cada job, nao por tick/frame;
|
||||||
|
- manter agregadores pequenos por `asset_id` e por `bank_type`;
|
||||||
|
- calcular percentis a partir de janela/ring buffer pequeno ou histograma
|
||||||
|
barato por bucket de duracao;
|
||||||
|
- nunca atualizar percentis no loop quente de decode por item/pixel;
|
||||||
|
- o job ativo pode expor tempo decorrido e fase atual; percentis sao atualizados
|
||||||
|
apenas no fechamento do job.
|
||||||
|
|
||||||
|
## Perguntas em Aberto
|
||||||
|
|
||||||
|
- [x] A agenda esta madura para virar decisao normativa ou ainda falta algum
|
||||||
|
caso de asset/memcard/lane?
|
||||||
|
- [x] A estrutura minima de `slot_state` e `request_state` no handle esta
|
||||||
|
completa ou falta algum campo para commit/cancel/reorder seguro?
|
||||||
|
|
||||||
|
## Resolucao
|
||||||
|
|
||||||
|
A agenda esta madura para decisao normativa.
|
||||||
|
|
||||||
|
A decisao deve formalizar:
|
||||||
|
|
||||||
|
- a terceira async work lane serial;
|
||||||
|
- um job ativo por vez;
|
||||||
|
- backlog efetivamente limitado pela unicidade de `bank_type/slot`;
|
||||||
|
- handles como observadores estaveis de slots de bank;
|
||||||
|
- `slot_state` e `request_state` dentro do handle;
|
||||||
|
- cancelamento/superseding por novo request para o mesmo alvo;
|
||||||
|
- load pronto imediato quando o asset ja esta residente no alvo;
|
||||||
|
- decode/materializacao na lane async;
|
||||||
|
- commit/install na lane principal;
|
||||||
|
- memcard como consumidor prioritario da mesma lane;
|
||||||
|
- FS como consumidor permitido, deixando API publica de FS para `AGD-0006`;
|
||||||
|
- progresso por fases e percentis atualizados no fechamento do job.
|
||||||
|
|
||||||
## Dependencias
|
## Dependencias
|
||||||
|
|
||||||
- `../specs/09-events-and-concurrency.md`
|
- `docs/specs/runtime/09-events-and-concurrency.md`
|
||||||
- `../specs/15-asset-management.md`
|
- `docs/specs/runtime/15-asset-management.md`
|
||||||
- `../specs/16a-syscall-policies.md`
|
- `docs/specs/runtime/16a-syscall-policies.md`
|
||||||
- `014-app-home-filesystem-surface-and-semantics.md`
|
- `discussion/workflow/agendas/AGD-0006-app-home-filesystem-surface-and-semantics.md`
|
||||||
|
|
||||||
## Criterio de Saida Desta Agenda
|
## Criterio para Encerrar
|
||||||
|
|
||||||
Pode virar PR quando houver decisao escrita sobre:
|
Pode virar PR quando houver decisao escrita sobre:
|
||||||
|
|
||||||
- numero e tipo de workers aceitos no baseline;
|
- existencia e papel da terceira async work lane;
|
||||||
- fila/prioridade de `asset` e `fs`;
|
- relacao dessa lane com a terceira core no hardware alvo e fallback no host;
|
||||||
- proibicao ou aceitacao limitada de `thread::spawn` por request;
|
- desenho do backlog serial de asset loading;
|
||||||
- modelo de status/telemetria para backlog e saturacao.
|
- regra de cancelamento/substituicao para requests no mesmo bank/slot;
|
||||||
|
- proibicao de `thread::spawn` por load no caminho normal;
|
||||||
|
- fases de asset load que rodam na lane vs lane principal;
|
||||||
|
- inclusao condicionada de FS/memcard nessa mesma lane;
|
||||||
|
- API de consulta e reordenacao do backlog de assets;
|
||||||
|
- comportamento de request imediato quando o asset ja esta residente no alvo;
|
||||||
|
- regra de bounded backlog por unicidade de `bank_type/slot`;
|
||||||
|
- politica de prioridade entre asset, FS e memcard;
|
||||||
|
- status e telemetria para backlog, progresso, percentis, cancelamento e falha.
|
||||||
|
|
||||||
|
## Discussao
|
||||||
|
|
||||||
|
- 2026-06-28: Agenda atualizada para remover render worker do escopo, assumir
|
||||||
|
uma terceira core/lane para trabalhos assincronos, exigir pool/fila limitada
|
||||||
|
para asset loading e reavaliar o papel de FS/memcard como consumidores da
|
||||||
|
mesma lane.
|
||||||
|
- 2026-06-28: Discussao consolidou que a async work lane deve ser serial, com
|
||||||
|
um job ativo, backlog semanticamente ilimitado, consulta/reordenacao publica
|
||||||
|
de backlog de assets, progresso percentual do asset ativo, decode na lane
|
||||||
|
async, install/commit na lane principal, e FS/memcard como consumidores a
|
||||||
|
alinhar com a agenda de app home filesystem.
|
||||||
|
- 2026-06-28: Acrescentada regra de asset pipe: requests para o mesmo bank/slot
|
||||||
|
devem cancelar pedidos anteriores pendentes para aquele alvo, tratando o
|
||||||
|
pedido mais novo como substituto operacional.
|
||||||
|
- 2026-06-28: Discussao refinou que o alvo canonico e `bank_type/slot`; um
|
||||||
|
asset ja residente deve retornar handle pronto sem entrar no backlog; o
|
||||||
|
backlog efetivo e limitado pela soma dos slots dos bancos; FS fica como
|
||||||
|
consumidor permitido da lane, enquanto API publica de FS permanece na agenda
|
||||||
|
6; progresso deve usar fases conservadoras e percentis devem ser atualizados
|
||||||
|
no fechamento do job, nao no hot path.
|
||||||
|
- 2026-06-28: Open questions restantes foram consolidadas: API de backlog
|
||||||
|
aceita com `promote/demote` como atalhos; superseding marca requests
|
||||||
|
substituidos por outro request para o mesmo `bank_type/slot`; cancelamento do
|
||||||
|
ativo e cooperativo quando barato e descarte por geracao quando nao for;
|
||||||
|
`read/decode/stage` cobre GLYPH/SOUND/SCENE; percentis ficam por `bank_type`
|
||||||
|
e por `asset_id`; API publica de FS permanece em `AGD-0006`.
|
||||||
|
- 2026-06-28: Adicionada a expectativa de que handles possam consultar o alvo
|
||||||
|
`bank_type/slot` a qualquer momento, inclusive quando nao houver asset valido
|
||||||
|
carregado; mutacoes devem continuar protegidas por request/geracao para evitar
|
||||||
|
commit/cancel acidental de pedidos substituidos.
|
||||||
|
- 2026-06-28: Refinado o modelo de handle: o handle pertence ao slot do bank e
|
||||||
|
contem uma secao de estado de request/backlog para aquele slot. Consulta e
|
||||||
|
residencia ficam estaveis por alvo; mutacoes atuam sobre a geracao atual do
|
||||||
|
request dentro do handle.
|
||||||
|
|||||||
@ -1,409 +0,0 @@
|
|||||||
---
|
|
||||||
id: AGD-0010
|
|
||||||
ticket: perf-gfx-render-pipeline-and-dirty-regions
|
|
||||||
title: Agenda - [PERF] GFX Render Pipeline and Dirty Regions
|
|
||||||
status: open
|
|
||||||
created: 2026-03-27
|
|
||||||
resolved:
|
|
||||||
decision:
|
|
||||||
tags: []
|
|
||||||
---
|
|
||||||
|
|
||||||
# Agenda - [PERF] GFX Render Pipeline and Dirty Regions
|
|
||||||
|
|
||||||
## Problema
|
|
||||||
|
|
||||||
O renderer `gfx` recompõe a cena inteira a cada frame logico, mesmo quando a mudanca visual e pequena.
|
|
||||||
|
|
||||||
Hoje `render_all()` reconstrói buckets de sprites, escaneia os 512 sprites, redesenha layers e aplica dois passes fullscreen de fade sem politica de invalidacao.
|
|
||||||
|
|
||||||
Ao mesmo tempo, a arquitetura atual ja opera como um framebuffer destrutivo em memoria: draws escrevem diretamente no buffer de trabalho e operacoes posteriores sobrescrevem o que estiver por baixo. A discussao nao e migrar para um modelo tipo GPU, scene graph ou retained rendering.
|
|
||||||
|
|
||||||
Existe ainda um driver de produto importante: o objetivo continua sendo viabilizar hardware handheld proprio com limitacoes reais de orcamento e com economia de memoria o mais agressiva possivel. Isso significa que ganhos de CPU nao podem ser avaliados isoladamente; custo de RAM adicional, buffers extras e estruturas auxiliares entram diretamente no criterio de aceitacao.
|
|
||||||
|
|
||||||
## Dor
|
|
||||||
|
|
||||||
- custo visual basico cresce demais para hardware simples.
|
|
||||||
- pequenos updates pagam preco de full redraw.
|
|
||||||
- fade, HUD e world composition ficam sempre no caminho critico.
|
|
||||||
|
|
||||||
## Hotspots Atuais
|
|
||||||
|
|
||||||
- [gfx.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-drivers/src/gfx.rs#L563)
|
|
||||||
- [gfx.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-drivers/src/gfx.rs#L671)
|
|
||||||
|
|
||||||
## Alvo da Discussao
|
|
||||||
|
|
||||||
Definir ate onde o v1 pode sofisticar o modelo de desenho destrutivo em memoria para reduzir custo e manter previsibilidade, sem migrar para um renderer de estilo GPU.
|
|
||||||
|
|
||||||
## O Que Precisa Ser Definido
|
|
||||||
|
|
||||||
1. Perfil real de custo.
|
|
||||||
Medir separadamente:
|
|
||||||
- rebuild de buckets;
|
|
||||||
- rasterizacao de layers;
|
|
||||||
- rasterizacao de sprites;
|
|
||||||
- fades fullscreen;
|
|
||||||
- conversao/copia no host;
|
|
||||||
- apresentacao no host.
|
|
||||||
|
|
||||||
2. Granularidade minima de invalidacao compativel com framebuffer destrutivo.
|
|
||||||
Escolher entre:
|
|
||||||
- dirty flag por frame inteiro;
|
|
||||||
- dirty flags por subsistema (`world`, `hud`, `fade`, `sprites`);
|
|
||||||
- dirty regions restritas e derivadas de primitivas/sprites;
|
|
||||||
- combinacao minima viavel.
|
|
||||||
|
|
||||||
3. Buckets e traversal de sprites.
|
|
||||||
Decidir se os buckets continuam sendo reconstruidos por frame ou se viram estrutura incremental.
|
|
||||||
|
|
||||||
4. Fades.
|
|
||||||
Definir se fade neutro precisa bypass total e se fade parcial pode operar por regiao/camada.
|
|
||||||
|
|
||||||
5. Cache de composicao.
|
|
||||||
Delimitar se layers estaticas/HUD podem manter cache intermediario.
|
|
||||||
|
|
||||||
6. Primitivas e contrato operacional.
|
|
||||||
Definir quais draws devem continuar sendo vistos como escrita destrutiva direta no framebuffer e onde valem aceleracoes internas sem mudar a semantica observavel.
|
|
||||||
|
|
||||||
7. Meta de custo.
|
|
||||||
Fechar qual teto de pixels/trabalho por frame e aceitavel no baseline.
|
|
||||||
|
|
||||||
8. Orcamento de memoria.
|
|
||||||
Definir quais otimizacoes aceitam memoria adicional e quais precisam caber no modelo mais economico possivel para handheld barato.
|
|
||||||
|
|
||||||
## Open Questions de Arquitetura
|
|
||||||
|
|
||||||
1. Quais partes do custo atual estao no `render_all()` e quais partes estao na conversao/apresentacao do host?
|
|
||||||
2. Qual o maior ganho de curto prazo dentro do modelo atual: buckets, fades, HUD, primitivas ou host copy/convert?
|
|
||||||
3. Dirty regions restritas quebram alguma expectativa de determinismo visivel ou sao apenas um detalhe interno de implementacao?
|
|
||||||
4. O HUD deve continuar no mesmo pipeline da world scene?
|
|
||||||
5. Quais primitivas merecem tratamento especial para reduzir overdraw sem mudar a semantica de sobrescrita?
|
|
||||||
6. Qual o teto aceitavel de memoria extra para caches, buffers separados ou estruturas auxiliares no handheld alvo?
|
|
||||||
|
|
||||||
## Problemas de Medio e Grande Porte Identificados
|
|
||||||
|
|
||||||
### 1. Composicao completa do framebuffer a cada frame logico
|
|
||||||
|
|
||||||
`render_all()` recompõe o `back` inteiro por software, mesmo quando a mudanca visual e pequena.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- custo cresce com a quantidade de pixels tocados, nao apenas com a quantidade de estado alterado;
|
|
||||||
- layers, sprites e fades disputam o mesmo budget de CPU;
|
|
||||||
- o modelo atual favorece previsibilidade sem ainda ter atalhos internos suficientes.
|
|
||||||
|
|
||||||
### 2. Rasterizacao pixel a pixel de tilemaps
|
|
||||||
|
|
||||||
Cada layer visivel percorre tiles e, para cada tile nao vazio, resolve indices e escreve pixel a pixel no framebuffer.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- o custo real esta mais na escrita de pixels do que na manutencao do `TileMap`;
|
|
||||||
- scroll e barato como estado, mas caro na hora de compor a imagem se tudo for repintado;
|
|
||||||
- layers estaticas continuam pagando custo de rasterizacao em toda recomposicao.
|
|
||||||
|
|
||||||
### 3. Rasterizacao pixel a pixel de sprites e escolha por bucket full scan
|
|
||||||
|
|
||||||
Os 512 sprites sao varridos para reconstruir buckets e os sprites ativos sao desenhados pixel a pixel.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- quando poucos sprites mudam, ainda existe custo fixo de rebuild dos buckets;
|
|
||||||
- overdraw entre sprites e layers pode explodir o numero de writes no `back`;
|
|
||||||
- a escolha de sprites ativos/prioridade ainda e simples demais para cenarios com alta ocupacao.
|
|
||||||
|
|
||||||
### 4. Fades fullscreen com custo proporcional ao frame inteiro
|
|
||||||
|
|
||||||
`scene fade` e `hud fade` percorrem o framebuffer inteiro quando ativos.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- custo grande e previsivel, mas potencialmente desproporcional;
|
|
||||||
- fade neutro ja pode ser bypass, mas fade parcial ainda custa uma passada completa;
|
|
||||||
- dois passes fullscreen no mesmo frame podem virar gargalo antes de layers ou sprites.
|
|
||||||
|
|
||||||
### 5. HUD no mesmo caminho critico da composicao principal
|
|
||||||
|
|
||||||
O HUD e redesenhado como tilemap depois da world scene e antes do `hud fade`.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- HUD estatico continua gerando trabalho por frame;
|
|
||||||
- mistura responsabilidades de world/UI no mesmo budget de composicao;
|
|
||||||
- dificulta isolar ganho de cache ou dirtying so para interface.
|
|
||||||
|
|
||||||
### 6. Conversao obrigatoria de RGB565 para RGBA8 no host
|
|
||||||
|
|
||||||
No `RedrawRequested`, o host percorre todo o `front_buffer` e converte para o frame do `pixels`.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- ha custo de leitura do framebuffer inteiro e escrita de um segundo buffer inteiro;
|
|
||||||
- esse custo existe mesmo quando o host esta apenas apresentando o mesmo quadro logico;
|
|
||||||
- pode competir com o custo do renderer sem estar visivel na discussao do `gfx`.
|
|
||||||
|
|
||||||
### 7. Pipeline serializado no host desktop
|
|
||||||
|
|
||||||
`tick`, `render_all()`, conversao de formato e apresentacao ocorrem no mesmo fluxo operacional.
|
|
||||||
|
|
||||||
Impacto:
|
|
||||||
|
|
||||||
- o frame time final acumula custo de runtime, composicao, copy/convert e present;
|
|
||||||
- falta desacoplamento para esconder latencia entre producao e apresentacao;
|
|
||||||
- dificulta atribuir gargalo sem instrumentacao por etapa.
|
|
||||||
|
|
||||||
## Estudo Inicial de Possiveis Optimizacoes
|
|
||||||
|
|
||||||
### A. Dirty flags por subsistema em vez de dirty rect generico
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- flags independentes para `world`, `sprites`, `hud`, `scene_fade`, `hud_fade`, `host_present`.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- preserva a semantica de framebuffer destrutivo;
|
|
||||||
- reduz recomposicao desnecessaria quando so um subsistema mudou;
|
|
||||||
- e muito mais simples de validar do que dirty regions arbitrarias.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- exige definir dependencias claras entre world, sprites, HUD e fades;
|
|
||||||
- pode induzir falsos positivos conservadores, o que e aceitavel no v1.
|
|
||||||
|
|
||||||
### B. Rebuild incremental ou condicional dos buckets de sprite
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- so reconstruir buckets quando algum `GfxSetSprite` mudar atividade, prioridade, banco ou tile;
|
|
||||||
- opcionalmente manter contadores/sinais de mutacao da OAM.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- elimina custo fixo por frame quando OAM permanece estavel;
|
|
||||||
- combina com a ideia de sprites como estado, nao como draw list efemera.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- precisa invalidacao correta para evitar bucket desatualizado;
|
|
||||||
- ganho pode ser pequeno se o custo dominante estiver no draw dos sprites, nao no rebuild.
|
|
||||||
|
|
||||||
### C. Separar world e HUD em buffers logicos distintos
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- manter um buffer da world scene e um buffer do HUD, compondo no final apenas quando necessario.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- HUD estatico deixa de participar da recomposicao da world;
|
|
||||||
- permite cache e fade especificos para cada dominio;
|
|
||||||
- se alinha bem com a separacao conceitual entre cena e interface.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- aumenta uso de memoria e pontos de sincronizacao;
|
|
||||||
- precisa manter semantica clara de sobrescrita entre mundo e HUD.
|
|
||||||
- pode ser inviavel no perfil de handheld barato se exigir buffers adicionais permanentes.
|
|
||||||
|
|
||||||
### D. Cache de layer estatica ou composicao parcial da world
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- layers que nao mudam podem manter imagem intermediaria pronta;
|
|
||||||
- scroll, tile updates ou troca de bank invalidam o cache correspondente.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- reduz rasterizacao repetida de cenario estavel;
|
|
||||||
- aproxima o ganho de hardware tile-based sem abandonar software raster.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- cache amplo demais vira complexidade estrutural;
|
|
||||||
- se scroll muda constantemente, o ganho cai bastante.
|
|
||||||
- pode consumir memoria demais para um hardware com orcamento agressivo.
|
|
||||||
|
|
||||||
### E. Otimizacao de fades
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- bypass total para fade neutro;
|
|
||||||
- opcionalmente aplicar fade apenas sobre buffers relevantes;
|
|
||||||
- estudar LUTs ou blend mais barato por pixel.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- ataca um custo fullscreen claramente delimitado;
|
|
||||||
- baixo risco conceitual.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- fade parcial por regiao pode complicar demais o contrato;
|
|
||||||
- LUT ajuda aritmetica, mas nao elimina custo de varrer memoria.
|
|
||||||
|
|
||||||
### F. Melhorias em primitivas e spans de memoria
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- acelerar `fill_rect`, linhas horizontais/verticais, clears e possiveis blits contiguos;
|
|
||||||
- explorar caminhos de row spans contiguos em vez de loops mais genericos.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- melhora direta do modelo de desenho destrutivo;
|
|
||||||
- baixo risco arquitetural;
|
|
||||||
- cria fundacao para outros atalhos internos.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- ganho localizado se o workload dominante vier de tile/sprite compositing;
|
|
||||||
- precisa medir por primitive class.
|
|
||||||
|
|
||||||
### G. Reduzir custo de copy/convert no host
|
|
||||||
|
|
||||||
Ideia:
|
|
||||||
|
|
||||||
- medir separadamente `draw_rgb565_to_rgba8` e `pixels.render()`;
|
|
||||||
- estudar formato mais proximo do host ou conversao mais barata;
|
|
||||||
- evitar redraw host quando nao houver novo front relevante.
|
|
||||||
|
|
||||||
Vantagens:
|
|
||||||
|
|
||||||
- ataca custo fora do `gfx` que ainda entra no frame time total;
|
|
||||||
- pode render ganho imediato no desktop host.
|
|
||||||
|
|
||||||
Riscos:
|
|
||||||
|
|
||||||
- parte do custo depende da stack `pixels/wgpu`, nao apenas do runtime;
|
|
||||||
- alguns ganhos podem ser especificos do host desktop e nao do contrato do console.
|
|
||||||
|
|
||||||
## Restricao de Plataforma
|
|
||||||
|
|
||||||
Qualquer recomendacao desta agenda deve ser filtrada por um criterio adicional:
|
|
||||||
|
|
||||||
- priorizar solucoes que melhorem custo sem multiplicar buffers;
|
|
||||||
- tratar memoria extra como recurso escasso de primeira classe;
|
|
||||||
- preferir flags, metadados pequenos e estruturas incrementais a caches grandes;
|
|
||||||
- evitar solucoes cuja performance dependa de assumir um host desktop mais forte do que o handheld alvo.
|
|
||||||
|
|
||||||
Direcao atual da discussao:
|
|
||||||
|
|
||||||
- nesta etapa, buffers extras devem ficar fora;
|
|
||||||
- o foco deve ser otimizar ao maximo o pipeline existente;
|
|
||||||
- cache intermediario ou novos buffers so entram em estudo depois que as otimizacoes de baixo custo de memoria forem medidas e esgotadas.
|
|
||||||
|
|
||||||
## Sugestao / Recomendacao Atual
|
|
||||||
|
|
||||||
Priorizar o estudo em camadas, nesta ordem:
|
|
||||||
|
|
||||||
1. instrumentar o pipeline por etapa;
|
|
||||||
2. validar dirty flags por subsistema como mecanismo minimo de invalidacao;
|
|
||||||
3. testar rebuild condicional de buckets e bypass/isolamento de fades;
|
|
||||||
4. otimizar primitivas e caminhos contiguos de escrita no framebuffer atual;
|
|
||||||
5. estudar separacao world/HUD e cache de layer apenas se os dados justificarem e o teto de memoria permitir;
|
|
||||||
5. tratar copy/convert do host como frente paralela de otimizacao, nao como substituto da analise do `gfx`.
|
|
||||||
|
|
||||||
## Achados Consolidados Ate Aqui
|
|
||||||
|
|
||||||
1. O contrato base continua sendo framebuffer destrutivo em memoria.
|
|
||||||
Draws escrevem diretamente no buffer de trabalho e operacoes posteriores sobrescrevem o que estiver por baixo. A agenda nao aponta para migracao a um renderer tipo GPU, retained mode ou compositor sofisticado.
|
|
||||||
|
|
||||||
2. O `present()` atual nao parece ser o problema principal.
|
|
||||||
No `gfx`, `present()` faz swap de buffers, nao copia completa de pixels.
|
|
||||||
|
|
||||||
3. O custo suspeito esta na recomposicao e na apresentacao, nao na manutencao do estado logico.
|
|
||||||
Escritas de `TileMap`, scroll e `GfxSetSprite` sao pequenas e pontuais; o custo potencialmente dominante esta em rasterizar pixels, aplicar fades fullscreen e converter o framebuffer para o host.
|
|
||||||
|
|
||||||
4. Os maiores suspeitos atuais de custo sao:
|
|
||||||
- rasterizacao de layers;
|
|
||||||
- rasterizacao de sprites;
|
|
||||||
- fades fullscreen;
|
|
||||||
- conversao `RGB565 -> RGBA8` no host;
|
|
||||||
- `pixels.render()` / apresentacao no host.
|
|
||||||
|
|
||||||
5. O pipeline atual deve ser otimizado antes de considerar buffers extras.
|
|
||||||
A direcao aceita da discussao e esgotar primeiro flags pequenas, bypasses, melhorias de primitive paths e ajustes incrementais no pipeline existente.
|
|
||||||
|
|
||||||
6. Restricao de plataforma pesa tanto quanto CPU.
|
|
||||||
Como o alvo e um handheld proprio com limitacoes de orcamento e memoria, solucoes que consumam RAM adicional significativa devem ficar fora desta fase.
|
|
||||||
|
|
||||||
7. A instrumentacao minima desejada para retomar o estudo ficou definida.
|
|
||||||
Quando houver workload representativo, queremos medir ao menos:
|
|
||||||
- `render_all_total_us`
|
|
||||||
- `bucket_rebuild_us`
|
|
||||||
- `layer_raster_us`
|
|
||||||
- `sprite_raster_us`
|
|
||||||
- `scene_fade_us`
|
|
||||||
- `hud_raster_us`
|
|
||||||
- `hud_fade_us`
|
|
||||||
- `host_convert_us`
|
|
||||||
- `host_present_us`
|
|
||||||
|
|
||||||
8. A retencao de metricas deve ser barata e orientada a analise posterior.
|
|
||||||
A preferencia atual e por acumuladores e ring buffer pequeno de snapshots, sem logging pesado por frame no hot path.
|
|
||||||
|
|
||||||
9. Ring buffer no `TileMap` nao e prioridade nesta fase.
|
|
||||||
O custo suspeito nao esta na manutencao da grade logica do mapa, e sim na composicao da janela visivel no framebuffer. Mudar a estrutura do mapa so faria sentido se o gargalo principal estivesse em streaming/atualizacao estrutural do cenario, o que nao e a hipotese atual.
|
|
||||||
|
|
||||||
10. A direcao de otimizacao mais promissora e padronizar copias massivas para o framebuffer atual.
|
|
||||||
Em vez de atacar apenas tilemaps com loops pixel a pixel, a discussao passa a favorecer um padrao geral de blit/copia massiva com:
|
|
||||||
- calculo previo de offsets e spans;
|
|
||||||
- fast paths para casos contiguos;
|
|
||||||
- trabalho por linha/chunk em vez de trabalho atomizado por pixel quando possivel;
|
|
||||||
- reaproveitamento dessa infraestrutura para tilemaps, sprites e outras operacoes de desenho destrutivo.
|
|
||||||
|
|
||||||
11. Migrar o `back` para `RGBA8888` nao e direcao aceita neste momento.
|
|
||||||
Isso aumentaria custo de memoria e largura de banda no alvo handheld, alem de deslocar a otimizacao para o host desktop. O contrato interno continua preferencialmente em `RGB565`, mesmo considerando fades e uma futura pipeline de lights.
|
|
||||||
|
|
||||||
## Nova Direcao Tecnica Em Estudo
|
|
||||||
|
|
||||||
Quando esta agenda for reaberta, a linha principal de investigacao deve considerar:
|
|
||||||
|
|
||||||
- manter o `TileMap` simples como estado logico;
|
|
||||||
- assumir que a janela visivel provavelmente continuara sendo recomposta na maior parte dos frames;
|
|
||||||
- concentrar a otimizacao em como essa recomposicao escreve no `back`;
|
|
||||||
- desenhar uma infraestrutura compartilhada de copias massivas/blits para o framebuffer atual;
|
|
||||||
- usar essa infraestrutura nao apenas para tilemaps, mas como base comum para raster de sprites e outros caminhos de desenho.
|
|
||||||
|
|
||||||
Pergunta orientadora da reabertura:
|
|
||||||
|
|
||||||
- como transformar o renderer de um pipeline de writes atomizados por pixel em um pipeline com fast paths de spans/chunks, sem perder a semantica de framebuffer destrutivo e sem pagar memoria extra relevante?
|
|
||||||
|
|
||||||
## Status de Standby
|
|
||||||
|
|
||||||
Esta agenda deve ficar em espera ate existir um game ou workload real que exercite de forma representativa:
|
|
||||||
|
|
||||||
- tilemaps com scroll e composicao de world;
|
|
||||||
- sprites em quantidade suficiente para testar buckets e overdraw;
|
|
||||||
- HUD ativo;
|
|
||||||
- fades;
|
|
||||||
- apresentacao completa no host.
|
|
||||||
|
|
||||||
Antes disso, qualquer conclusao sobre gargalo ou prioridade de otimizacao tende a ser prematura.
|
|
||||||
|
|
||||||
## Proximo Gatilho Para Reabrir
|
|
||||||
|
|
||||||
Reabrir esta agenda quando houver:
|
|
||||||
|
|
||||||
- um game jogavel ou cena de teste que percorra o pipeline completo;
|
|
||||||
- dados de workload mais proximos do uso real;
|
|
||||||
- necessidade concreta de justificar uma rodada de instrumentacao e profiling.
|
|
||||||
|
|
||||||
## Dependencias
|
|
||||||
|
|
||||||
- `../specs/04-gfx-peripheral.md`
|
|
||||||
- `../specs/11-portability-and-cross-platform-execution.md`
|
|
||||||
|
|
||||||
## Criterio de Saida Desta Agenda
|
|
||||||
|
|
||||||
Pode virar PR quando houver decisao escrita sobre:
|
|
||||||
|
|
||||||
- filosofia explicita de framebuffer destrutivo como contrato base;
|
|
||||||
- plano de instrumentacao para localizar o custo dominante do pipeline;
|
|
||||||
- nivel minimo de invalidacao no v1;
|
|
||||||
- politica de rebuild de buckets de sprites;
|
|
||||||
- bypass/cache de fade e HUD;
|
|
||||||
- politica para otimizar primitivas sem mudar a semantica observavel;
|
|
||||||
- meta de custo para o render pipeline.
|
|
||||||
@ -0,0 +1,336 @@
|
|||||||
|
---
|
||||||
|
id: DEC-0034
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Async Work Lane and Asset Backlog Contract
|
||||||
|
status: accepted
|
||||||
|
created: 2026-06-28
|
||||||
|
accepted: 2026-06-28
|
||||||
|
ref_agenda: AGD-0008
|
||||||
|
plans: [PLN-0123, PLN-0124, PLN-0125, PLN-0126, PLN-0127, PLN-0128]
|
||||||
|
tags: [perf, asset, fs, async, scheduler, runtime]
|
||||||
|
---
|
||||||
|
|
||||||
|
# DEC-0034 - Async Work Lane and Asset Backlog Contract
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted.
|
||||||
|
|
||||||
|
## Contexto
|
||||||
|
|
||||||
|
`asset.load()` currently creates an OS thread per non-resident asset request.
|
||||||
|
That behavior does not match the target runtime model: the machine should have
|
||||||
|
explicit execution lanes, bounded ownership, observable backpressure, and no
|
||||||
|
uncontrolled thread creation from guest-visible operations.
|
||||||
|
|
||||||
|
Render worker concurrency is already handled by separate render decisions. This
|
||||||
|
decision covers the third runtime lane for asynchronous IO/decode/persistence
|
||||||
|
work:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Lane 1: VM, firmware, SystemOS, logical frame
|
||||||
|
Lane 2: render worker / asynchronous rasterization
|
||||||
|
Lane 3: async work lane for asset IO/decode and game persistence work
|
||||||
|
```
|
||||||
|
|
||||||
|
The concrete first consumer is asset loading. Game persistence through memcard
|
||||||
|
may also consume this lane. FS is allowed to consume this lane, but public FS API
|
||||||
|
shape belongs to the app-home filesystem agenda.
|
||||||
|
|
||||||
|
## Decisao
|
||||||
|
|
||||||
|
Prometeu MUST introduce a third async work lane as the runtime-owned execution
|
||||||
|
place for asset IO/decode work and compatible persistence IO work.
|
||||||
|
|
||||||
|
The async work lane MUST be serial: it has exactly one active job at a time.
|
||||||
|
The runtime MUST NOT create one OS thread per `asset.load` request in the normal
|
||||||
|
path.
|
||||||
|
|
||||||
|
Asset loading MUST use a backlog keyed by target `bank_type/slot`. A target can
|
||||||
|
have at most one current request. A newer request for the same `bank_type/slot`
|
||||||
|
MUST supersede the previous request for that target.
|
||||||
|
|
||||||
|
Asset handles MUST represent stable bank slots, not transient worker threads.
|
||||||
|
A handle MUST remain queryable even when the slot has no valid loaded asset and
|
||||||
|
even when there is no active request for that slot. The handle state MUST
|
||||||
|
separate resident slot state from request/backlog state.
|
||||||
|
|
||||||
|
Asset IO/read and decode/materialization MUST run on the async work lane.
|
||||||
|
Asset install/commit into resident banks MUST happen on the main runtime lane at
|
||||||
|
predictable ownership points.
|
||||||
|
|
||||||
|
Memcard work MAY consume the same async work lane and has higher priority than
|
||||||
|
ordinary asset loads when contention exists. FS MAY consume the same lane for
|
||||||
|
IO-style work, but this decision does not define the public FS API.
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
A serial lane maps cleanly to the intended third-core mental model and avoids a
|
||||||
|
desktop-biased generic thread pool. It gives the runtime one place to observe
|
||||||
|
IO/decode backlog, progress, priority, cancellation, and telemetry.
|
||||||
|
|
||||||
|
Keying requests by `bank_type/slot` makes the backlog naturally bounded by the
|
||||||
|
sum of bank slots. There is no need for a guest-visible `queue_full` state:
|
||||||
|
there cannot be unbounded distinct pending targets if each target has at most
|
||||||
|
one current request.
|
||||||
|
|
||||||
|
Keeping commit/install on the main lane preserves deterministic publication
|
||||||
|
semantics and avoids letting the async lane mutate resident graphics/audio/scene
|
||||||
|
state while the VM, render handoff, or frame boundary is observing it.
|
||||||
|
|
||||||
|
Separating `slot_state` and `request_state` inside the handle avoids ambiguity:
|
||||||
|
callers can inspect the slot at any time, while mutating operations still remain
|
||||||
|
protected by request generation.
|
||||||
|
|
||||||
|
## Invariantes / Contrato
|
||||||
|
|
||||||
|
### Async Work Lane
|
||||||
|
|
||||||
|
- The async work lane MUST be runtime-owned.
|
||||||
|
- The async work lane MUST be separate from the render worker.
|
||||||
|
- The async work lane MUST execute at most one active job at a time.
|
||||||
|
- The runtime MUST NOT use `thread::spawn` per asset request in the normal
|
||||||
|
asset loading path.
|
||||||
|
- The host may implement the lane as a fixed worker thread. Hardware targets may
|
||||||
|
map it to a dedicated core when available.
|
||||||
|
- If a physical third core is unavailable, the implementation MUST preserve the
|
||||||
|
same logical lane contract.
|
||||||
|
|
||||||
|
### Asset Backlog
|
||||||
|
|
||||||
|
- Asset requests MUST target a concrete `bank_type/slot`.
|
||||||
|
- The backlog is ordered and serial.
|
||||||
|
- Each `bank_type/slot` MUST have at most one current request.
|
||||||
|
- A newer request for the same `bank_type/slot` MUST supersede any earlier
|
||||||
|
pending request for that target.
|
||||||
|
- If the target already contains the requested `asset_id` as a valid resident
|
||||||
|
asset, `asset.load` MUST return a handle in ready state without adding a job
|
||||||
|
to the backlog.
|
||||||
|
- The effective backlog size is bounded by the sum of targetable bank slots,
|
||||||
|
even though the contract does not expose a fixed queue limit.
|
||||||
|
- Implementations MUST collect stale metadata for canceled or superseded
|
||||||
|
requests so the handle/request history does not grow without bound.
|
||||||
|
|
||||||
|
### Handles
|
||||||
|
|
||||||
|
An asset handle MUST represent a stable bank slot target. The handle state MUST
|
||||||
|
include at least:
|
||||||
|
|
||||||
|
```text
|
||||||
|
handle:
|
||||||
|
bank_type
|
||||||
|
slot
|
||||||
|
|
||||||
|
slot_state:
|
||||||
|
loaded_asset_id
|
||||||
|
resident_state
|
||||||
|
slot_generation
|
||||||
|
|
||||||
|
request_state:
|
||||||
|
requested_asset_id
|
||||||
|
request_generation
|
||||||
|
state
|
||||||
|
backlog_position
|
||||||
|
progress
|
||||||
|
```
|
||||||
|
|
||||||
|
The handle MUST be queryable when:
|
||||||
|
|
||||||
|
- the slot is empty;
|
||||||
|
- the slot contains a valid resident asset;
|
||||||
|
- a request is queued;
|
||||||
|
- a request is active;
|
||||||
|
- a request is ready for commit;
|
||||||
|
- a request has been canceled;
|
||||||
|
- a request has been superseded;
|
||||||
|
- a request ended in error.
|
||||||
|
|
||||||
|
Mutating operations such as commit, cancel, promote, demote, or move MUST act on
|
||||||
|
the current request generation. They MUST NOT accidentally mutate a newer
|
||||||
|
request through an older handle view.
|
||||||
|
|
||||||
|
### Superseding
|
||||||
|
|
||||||
|
`superseded` means a request was replaced by a newer request for the same
|
||||||
|
`bank_type/slot`.
|
||||||
|
|
||||||
|
- Superseding is an operational state, not a fault.
|
||||||
|
- If the old request is queued, it MUST be removed from the backlog.
|
||||||
|
- If the old request is active, the lane SHOULD cancel cooperatively when the
|
||||||
|
current phase supports cheap cancellation.
|
||||||
|
- If active work cannot be interrupted cheaply, it MAY finish, but its result
|
||||||
|
MUST be discarded when its generation no longer matches the target's current
|
||||||
|
request generation.
|
||||||
|
|
||||||
|
### Asset Backlog API Direction
|
||||||
|
|
||||||
|
The existing asset operations remain the base surface:
|
||||||
|
|
||||||
|
```text
|
||||||
|
asset.load(asset_id, slot) -> (status, handle)
|
||||||
|
asset.status(handle) -> status
|
||||||
|
asset.commit(handle) -> status
|
||||||
|
asset.cancel(handle) -> status
|
||||||
|
```
|
||||||
|
|
||||||
|
The asset backlog surface SHOULD add a small status-first API:
|
||||||
|
|
||||||
|
```text
|
||||||
|
asset.backlog_info()
|
||||||
|
-> (status, pending_count, active_handle, active_asset_id,
|
||||||
|
active_bank_type, active_slot, active_progress)
|
||||||
|
|
||||||
|
asset.backlog_position(handle)
|
||||||
|
-> (status, state, position, progress)
|
||||||
|
|
||||||
|
asset.backlog_move(handle, new_position)
|
||||||
|
-> status
|
||||||
|
|
||||||
|
asset.backlog_promote(handle)
|
||||||
|
-> status
|
||||||
|
|
||||||
|
asset.backlog_demote(handle)
|
||||||
|
-> status
|
||||||
|
|
||||||
|
asset.target_status(bank_type, slot)
|
||||||
|
-> (status, asset_id, handle, state, position, progress)
|
||||||
|
```
|
||||||
|
|
||||||
|
`asset.backlog_promote(handle)` is an official shortcut for moving a queued
|
||||||
|
request to position `1`, the first pending position after the active job.
|
||||||
|
|
||||||
|
`asset.backlog_demote(handle)` is an official shortcut for moving a queued
|
||||||
|
request to the end of the pending backlog.
|
||||||
|
|
||||||
|
The final ABI names and exact return shapes may be refined during planning, but
|
||||||
|
the implementation MUST preserve the capabilities above.
|
||||||
|
|
||||||
|
### Progress
|
||||||
|
|
||||||
|
Progress MUST be represented without floating point. The recommended scale is
|
||||||
|
`0..10000`.
|
||||||
|
|
||||||
|
The initial phase model is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
queued -> 0
|
||||||
|
read -> 0..4000
|
||||||
|
decode -> 4000..9000
|
||||||
|
stage -> 9000..10000
|
||||||
|
ready -> 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
If a phase cannot report internal progress, it MUST keep the previous progress
|
||||||
|
mark and advance at phase completion. Implementations MUST NOT invent false
|
||||||
|
precision for non-linear decode phases.
|
||||||
|
|
||||||
|
### Telemetry
|
||||||
|
|
||||||
|
Telemetry MUST be cheap and must not add hot-path per-item decode cost.
|
||||||
|
|
||||||
|
Minimum telemetry:
|
||||||
|
|
||||||
|
- current backlog depth;
|
||||||
|
- target/request position;
|
||||||
|
- active job progress;
|
||||||
|
- jobs submitted;
|
||||||
|
- jobs completed;
|
||||||
|
- jobs failed;
|
||||||
|
- jobs canceled;
|
||||||
|
- jobs superseded;
|
||||||
|
- job duration;
|
||||||
|
- percentiles by `bank_type`;
|
||||||
|
- lightweight percentiles or small-window samples by `asset_id`.
|
||||||
|
|
||||||
|
Percentiles MUST be updated when a job closes, not inside the inner decode loop.
|
||||||
|
|
||||||
|
### Priority
|
||||||
|
|
||||||
|
When async lane consumers contend, the initial priority order is:
|
||||||
|
|
||||||
|
1. memcard commit/write;
|
||||||
|
2. FS write/config work;
|
||||||
|
3. asset visual/audio/scene load;
|
||||||
|
4. non-critical list/read work.
|
||||||
|
|
||||||
|
This priority order is a lane arbitration rule. It does not define public FS
|
||||||
|
syscall semantics.
|
||||||
|
|
||||||
|
### FS Boundary
|
||||||
|
|
||||||
|
FS MAY consume the async work lane for IO-style work.
|
||||||
|
|
||||||
|
This decision MUST NOT define the public FS API, app-home FS semantics, or
|
||||||
|
whether FS is exposed as request/poll or sync-appearing operations. Those
|
||||||
|
questions belong to `AGD-0006`.
|
||||||
|
|
||||||
|
`AGD-0006` MUST be updated or interpreted with the existence of this async IO
|
||||||
|
lane in mind.
|
||||||
|
|
||||||
|
## Impactos
|
||||||
|
|
||||||
|
### Spec
|
||||||
|
|
||||||
|
- `docs/specs/runtime/15-asset-management.md` must absorb the async lane,
|
||||||
|
backlog, handle, superseding, progress, and telemetry contract.
|
||||||
|
- `docs/specs/runtime/16-host-abi-and-syscalls.md` must absorb any final public
|
||||||
|
asset backlog syscall names and return shapes.
|
||||||
|
- `docs/specs/runtime/16a-syscall-policies.md` may need status catalog updates
|
||||||
|
for superseded/canceled/backend unavailable states if not already covered by
|
||||||
|
asset domain status.
|
||||||
|
- `docs/specs/runtime/09-events-and-concurrency.md` should mention the async
|
||||||
|
work lane as an implementation-side lane that does not introduce guest
|
||||||
|
callbacks.
|
||||||
|
- `AGD-0006` / future FS spec work must account for FS as a possible consumer of
|
||||||
|
the async IO lane.
|
||||||
|
|
||||||
|
### Runtime
|
||||||
|
|
||||||
|
- Asset loading must stop spawning a thread per request.
|
||||||
|
- AssetManager needs a serial backlog keyed by `bank_type/slot`.
|
||||||
|
- Asset handles need stable slot identity plus separated `slot_state` and
|
||||||
|
`request_state`.
|
||||||
|
- Commit/install remains a main-lane operation.
|
||||||
|
- Superseding and generation checks become required correctness mechanisms.
|
||||||
|
|
||||||
|
### Host
|
||||||
|
|
||||||
|
- Desktop host may implement the async work lane with one fixed worker thread.
|
||||||
|
- Host presentation/render worker remains separate and unaffected.
|
||||||
|
|
||||||
|
### Firmware
|
||||||
|
|
||||||
|
- No direct firmware behavior is required for asset backlog mechanics.
|
||||||
|
- Firmware flows that rely on preload or memcard may later use lane telemetry or
|
||||||
|
priority policy if needed.
|
||||||
|
|
||||||
|
### Tooling
|
||||||
|
|
||||||
|
- Test tools may need support for inspecting backlog state and forcing request
|
||||||
|
ordering.
|
||||||
|
- Asset fixtures should cover queued, active, ready, canceled, superseded, and
|
||||||
|
already-resident paths.
|
||||||
|
|
||||||
|
## Referencias
|
||||||
|
|
||||||
|
- `AGD-0008` - Async Background Work Lanes for Assets and FS.
|
||||||
|
- `docs/specs/runtime/15-asset-management.md`
|
||||||
|
- `docs/specs/runtime/16-host-abi-and-syscalls.md`
|
||||||
|
- `docs/specs/runtime/16a-syscall-policies.md`
|
||||||
|
- `docs/specs/runtime/09-events-and-concurrency.md`
|
||||||
|
- `docs/specs/runtime/08-save-memory-and-memcard.md`
|
||||||
|
- `AGD-0006` - App Home Filesystem Surface and Semantics.
|
||||||
|
|
||||||
|
## Propagacao Necessaria
|
||||||
|
|
||||||
|
1. Update asset management specs with the lane/backlog/handle contract.
|
||||||
|
2. Update syscall specs if backlog APIs become public ABI.
|
||||||
|
3. Update FS agenda/spec work to acknowledge the async IO lane without deciding
|
||||||
|
FS public API in this decision.
|
||||||
|
4. Plan implementation of a serial async work lane and asset backlog.
|
||||||
|
5. Plan tests for superseding, stable slot handles, immediate-ready resident
|
||||||
|
assets, progress, telemetry, and main-lane commit.
|
||||||
|
|
||||||
|
## Revision Log
|
||||||
|
|
||||||
|
- 2026-06-28: Initial draft from `AGD-0008`.
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0123
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Async Work Lane Specification Propagation
|
||||||
|
status: open
|
||||||
|
created: 2026-06-28
|
||||||
|
completed:
|
||||||
|
ref_decisions: [DEC-0034]
|
||||||
|
tags: [perf, asset, fs, async, scheduler, runtime, spec]
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLN-0123 - Async Work Lane Specification Propagation
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0034` establishes a third serial async work lane, asset backlog semantics,
|
||||||
|
stable bank-slot handles, superseding, progress, telemetry, and FS/memcard lane
|
||||||
|
boundaries. The canonical specs must be updated before code work relies on the
|
||||||
|
new contract.
|
||||||
|
|
||||||
|
## Decisions de Origem
|
||||||
|
|
||||||
|
- `DEC-0034` - Async Work Lane and Asset Backlog Contract.
|
||||||
|
|
||||||
|
## Alvo
|
||||||
|
|
||||||
|
Publish the accepted async work lane and asset backlog contract in the canonical
|
||||||
|
runtime specs.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Update asset management spec.
|
||||||
|
- Update syscall ABI spec if public backlog APIs are named there.
|
||||||
|
- Update syscall policy/status language for operational asset states.
|
||||||
|
- Update events/concurrency spec with the async work lane as an implementation
|
||||||
|
lane that does not introduce guest callbacks.
|
||||||
|
- Add a cross-reference from FS/app-home agenda or notes to the async IO lane.
|
||||||
|
|
||||||
|
Fora de Escopo:
|
||||||
|
|
||||||
|
- Implementing runtime code.
|
||||||
|
- Finalizing public FS API semantics.
|
||||||
|
- Changing render worker contracts.
|
||||||
|
|
||||||
|
## Plano de Execucao
|
||||||
|
|
||||||
|
### Step 1 - Update Asset Management
|
||||||
|
|
||||||
|
**What:** Add the third async lane, backlog, handle, superseding, progress, and
|
||||||
|
telemetry contract.
|
||||||
|
|
||||||
|
**How:** Extend `docs/specs/runtime/15-asset-management.md` around the existing
|
||||||
|
`asset.load/status/commit/cancel` section. Preserve the existing
|
||||||
|
`asset.load(asset_id, slot)` identity contract.
|
||||||
|
|
||||||
|
**Files:** `docs/specs/runtime/15-asset-management.md`.
|
||||||
|
|
||||||
|
### Step 2 - Update Host ABI
|
||||||
|
|
||||||
|
**What:** Add the backlog API direction if the ABI spec is the canonical place
|
||||||
|
for syscall shapes.
|
||||||
|
|
||||||
|
**How:** Extend the asset surface section with the planned backlog operations,
|
||||||
|
marking exact numeric ids as implementation-plan work if ids are not assigned
|
||||||
|
yet.
|
||||||
|
|
||||||
|
**Files:** `docs/specs/runtime/16-host-abi-and-syscalls.md`.
|
||||||
|
|
||||||
|
### Step 3 - Update Syscall Policies
|
||||||
|
|
||||||
|
**What:** Clarify that `superseded`, `canceled`, `backend_unavailable`, and
|
||||||
|
decode failures are operational statuses, not faults.
|
||||||
|
|
||||||
|
**How:** Add asset-domain examples under status-first policy.
|
||||||
|
|
||||||
|
**Files:** `docs/specs/runtime/16a-syscall-policies.md`.
|
||||||
|
|
||||||
|
### Step 4 - Update Events and Concurrency
|
||||||
|
|
||||||
|
**What:** Document that the async work lane is an implementation lane.
|
||||||
|
|
||||||
|
**How:** Add a section next to render worker concurrency stating that asset/IO
|
||||||
|
lane work does not introduce guest callbacks or hidden guest execution.
|
||||||
|
|
||||||
|
**Files:** `docs/specs/runtime/09-events-and-concurrency.md`.
|
||||||
|
|
||||||
|
### Step 5 - Cross-Reference FS Work
|
||||||
|
|
||||||
|
**What:** Record that FS may consume the async IO lane, while public FS API
|
||||||
|
semantics remain owned by the app-home filesystem discussion.
|
||||||
|
|
||||||
|
**How:** Add a note in `AGD-0006` or its future decision input, without deciding
|
||||||
|
FS request/poll shape in this plan.
|
||||||
|
|
||||||
|
**Files:** `discussion/workflow/agendas/AGD-0006-app-home-filesystem-surface-and-semantics.md`.
|
||||||
|
|
||||||
|
## Criterios de Aceite
|
||||||
|
|
||||||
|
- [ ] Specs state that the async work lane is serial and separate from render.
|
||||||
|
- [ ] Asset spec states backlog keying by `bank_type/slot`.
|
||||||
|
- [ ] Asset spec states stable slot handles with `slot_state` and `request_state`.
|
||||||
|
- [ ] Asset spec states superseding behavior.
|
||||||
|
- [ ] Asset spec states main-lane commit/install.
|
||||||
|
- [ ] FS is cross-referenced as a permitted lane consumer without public API decisions.
|
||||||
|
|
||||||
|
## Tests / Validacao
|
||||||
|
|
||||||
|
- Run `discussion validate`.
|
||||||
|
- Review spec links for broken relative paths.
|
||||||
|
- No cargo tests are required for this documentation-only plan.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Public ABI names may be refined later; the spec must avoid assigning ids too
|
||||||
|
early if implementation work has not reserved them.
|
||||||
|
- FS scope can leak into this work; keep FS public API decisions in `AGD-0006`.
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0124
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Async Work Lane Runtime Infrastructure
|
||||||
|
status: open
|
||||||
|
created: 2026-06-28
|
||||||
|
completed:
|
||||||
|
ref_decisions: [DEC-0034]
|
||||||
|
tags: [perf, asset, fs, async, scheduler, runtime]
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLN-0124 - Async Work Lane Runtime Infrastructure
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0034` requires one runtime-owned async work lane, separate from VM/main
|
||||||
|
execution and separate from render worker execution. This plan introduces the
|
||||||
|
lane infrastructure before migrating asset loading.
|
||||||
|
|
||||||
|
## Decisions de Origem
|
||||||
|
|
||||||
|
- `DEC-0034` - Async Work Lane and Asset Backlog Contract.
|
||||||
|
|
||||||
|
## Alvo
|
||||||
|
|
||||||
|
Create a serial async work lane primitive that can execute one active job at a
|
||||||
|
time, expose observable state, and support deterministic shutdown.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Runtime-owned async work lane type.
|
||||||
|
- Single active job execution.
|
||||||
|
- Ordered pending job storage.
|
||||||
|
- Cooperative cancellation hook.
|
||||||
|
- Shutdown and join behavior.
|
||||||
|
- Basic lane telemetry.
|
||||||
|
|
||||||
|
Fora de Escopo:
|
||||||
|
|
||||||
|
- Public asset backlog syscalls.
|
||||||
|
- Asset handle model migration.
|
||||||
|
- FS public API.
|
||||||
|
- Render worker changes.
|
||||||
|
|
||||||
|
## Plano de Execucao
|
||||||
|
|
||||||
|
### Step 1 - Locate Runtime Service Boundary
|
||||||
|
|
||||||
|
**What:** Choose the crate/module boundary for the async lane.
|
||||||
|
|
||||||
|
**How:** Place generic lane infrastructure near VM runtime services, not inside
|
||||||
|
desktop host code and not inside render worker modules.
|
||||||
|
|
||||||
|
**Files:** likely `crates/console/prometeu-system/src/services/` or
|
||||||
|
`crates/console/prometeu-system/src/services/vm_runtime/`.
|
||||||
|
|
||||||
|
### Step 2 - Define Job and Lane Types
|
||||||
|
|
||||||
|
**What:** Add a lane type with pending queue, active job metadata, generation,
|
||||||
|
state, progress, and cancellation flag.
|
||||||
|
|
||||||
|
**How:** Use typed job enums or traits that do not require guest callbacks.
|
||||||
|
Start with internal asset job support but keep the lane generic enough for
|
||||||
|
memcard/FS later.
|
||||||
|
|
||||||
|
**Files:** new module under `prometeu-system` service layer.
|
||||||
|
|
||||||
|
### Step 3 - Implement Serial Worker
|
||||||
|
|
||||||
|
**What:** Implement one worker loop that takes one pending job and runs it to
|
||||||
|
completion or cooperative cancellation.
|
||||||
|
|
||||||
|
**How:** Use a fixed worker thread on host builds. Preserve a logical-lane API
|
||||||
|
so future hardware can map it to a dedicated core.
|
||||||
|
|
||||||
|
**Files:** async lane module; lifecycle wiring in VM runtime service setup.
|
||||||
|
|
||||||
|
### Step 4 - Implement Shutdown
|
||||||
|
|
||||||
|
**What:** Add explicit stop/shutdown behavior.
|
||||||
|
|
||||||
|
**How:** Wake the lane, stop accepting new jobs, report pending jobs as canceled
|
||||||
|
or shutdown-discarded, and join the worker with bounded behavior.
|
||||||
|
|
||||||
|
**Files:** async lane module and VM runtime lifecycle modules.
|
||||||
|
|
||||||
|
### Step 5 - Expose Internal Telemetry
|
||||||
|
|
||||||
|
**What:** Add counters for pending depth, active job, submitted, completed,
|
||||||
|
failed, canceled, and superseded.
|
||||||
|
|
||||||
|
**How:** Use cheap atomics or lane-owned state snapshots. Do not update
|
||||||
|
expensive percentile data inside inner decode loops.
|
||||||
|
|
||||||
|
**Files:** async lane module; telemetry structs where runtime telemetry lives.
|
||||||
|
|
||||||
|
## Criterios de Aceite
|
||||||
|
|
||||||
|
- [ ] Lane has one active job maximum.
|
||||||
|
- [ ] Lane is separate from render worker code.
|
||||||
|
- [ ] Lane can be started and stopped deterministically.
|
||||||
|
- [ ] Pending jobs are observable.
|
||||||
|
- [ ] Cooperative cancellation can be signaled.
|
||||||
|
- [ ] No guest callback path is introduced.
|
||||||
|
|
||||||
|
## Tests / Validacao
|
||||||
|
|
||||||
|
- Unit tests for enqueue, single active execution, ordering, cancellation signal,
|
||||||
|
and shutdown.
|
||||||
|
- Concurrency tests must synchronize on real state transitions, not sleeps.
|
||||||
|
- Run targeted `cargo test` for the owning crate.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Accidentally creating a generic pool instead of a serial lane.
|
||||||
|
- Coupling the lane to desktop host thread details.
|
||||||
|
- Reusing render worker handoff semantics where ordered backlog is required.
|
||||||
@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0125
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Asset Backlog and Stable Slot Handles
|
||||||
|
status: open
|
||||||
|
created: 2026-06-28
|
||||||
|
completed:
|
||||||
|
ref_decisions: [DEC-0034]
|
||||||
|
tags: [perf, asset, async, runtime]
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLN-0125 - Asset Backlog and Stable Slot Handles
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0034` changes asset loading from request-owned thread spawning to a serial
|
||||||
|
backlog keyed by `bank_type/slot`. Handles become stable bank-slot observers
|
||||||
|
with separate resident slot state and request state.
|
||||||
|
|
||||||
|
## Decisions de Origem
|
||||||
|
|
||||||
|
- `DEC-0034` - Async Work Lane and Asset Backlog Contract.
|
||||||
|
|
||||||
|
## Alvo
|
||||||
|
|
||||||
|
Refactor `AssetManager` so asset requests are tracked by target bank slot,
|
||||||
|
deduplicated/superseded by target, and observable through stable handles.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Stable handle structure with `bank_type`, `slot`, `slot_state`, and
|
||||||
|
`request_state`.
|
||||||
|
- Backlog keyed by `bank_type/slot`.
|
||||||
|
- Already-resident fast path.
|
||||||
|
- Superseding for queued and active requests.
|
||||||
|
- Main-lane commit/install boundary.
|
||||||
|
|
||||||
|
Fora de Escopo:
|
||||||
|
|
||||||
|
- Public backlog syscall wiring.
|
||||||
|
- Percentile telemetry.
|
||||||
|
- FS public API.
|
||||||
|
|
||||||
|
## Plano de Execucao
|
||||||
|
|
||||||
|
### Step 1 - Model Slot Handles
|
||||||
|
|
||||||
|
**What:** Replace transient load-operation assumptions with stable bank-slot
|
||||||
|
handle state.
|
||||||
|
|
||||||
|
**How:** Introduce structures equivalent to:
|
||||||
|
|
||||||
|
```text
|
||||||
|
handle: bank_type, slot
|
||||||
|
slot_state: loaded_asset_id, resident_state, slot_generation
|
||||||
|
request_state: requested_asset_id, request_generation, state, position, progress
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-drivers/src/asset.rs` and HAL asset types if
|
||||||
|
public type definitions belong there.
|
||||||
|
|
||||||
|
### Step 2 - Key Backlog by Target
|
||||||
|
|
||||||
|
**What:** Ensure at most one current request per `bank_type/slot`.
|
||||||
|
|
||||||
|
**How:** Add a target index from `(bank_type, slot)` to current request
|
||||||
|
generation/handle state. Enqueue only when the target does not already have the
|
||||||
|
same resident asset and no newer request supersedes it.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-drivers/src/asset.rs`.
|
||||||
|
|
||||||
|
### Step 3 - Implement Already-Resident Fast Path
|
||||||
|
|
||||||
|
**What:** Return a ready handle immediately when the requested asset already
|
||||||
|
resides in the target slot.
|
||||||
|
|
||||||
|
**How:** Compare requested `asset_id` with the target `slot_state.loaded_asset_id`
|
||||||
|
and resident validity before creating a queued job.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-drivers/src/asset.rs`.
|
||||||
|
|
||||||
|
### Step 4 - Implement Superseding
|
||||||
|
|
||||||
|
**What:** New request for the same target supersedes previous queued or active
|
||||||
|
request.
|
||||||
|
|
||||||
|
**How:** Remove queued older request immediately. For active work, update target
|
||||||
|
generation so the old result is discarded if it cannot stop cooperatively.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-drivers/src/asset.rs`; async lane module
|
||||||
|
from `PLN-0124`.
|
||||||
|
|
||||||
|
### Step 5 - Preserve Main-Lane Commit
|
||||||
|
|
||||||
|
**What:** Keep install/commit into resident banks on the main runtime lane.
|
||||||
|
|
||||||
|
**How:** Async lane produces staged materialized result. `asset.commit(handle)`
|
||||||
|
installs only when the request generation is current and ready.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-drivers/src/asset.rs`; VM runtime dispatch if
|
||||||
|
commit behavior changes.
|
||||||
|
|
||||||
|
## Criterios de Aceite
|
||||||
|
|
||||||
|
- [ ] No asset load spawns an OS thread per request.
|
||||||
|
- [ ] At most one request exists per `bank_type/slot`.
|
||||||
|
- [ ] Same-target newer request supersedes older queued request.
|
||||||
|
- [ ] Same-target newer request prevents active stale result from installing.
|
||||||
|
- [ ] Already-resident target returns ready handle without backlog entry.
|
||||||
|
- [ ] Handles remain queryable for empty, queued, active, ready, committed,
|
||||||
|
canceled, superseded, and error states.
|
||||||
|
|
||||||
|
## Tests / Validacao
|
||||||
|
|
||||||
|
- Unit tests for handle state transitions.
|
||||||
|
- Unit tests for target-keyed superseding.
|
||||||
|
- Unit tests for already-resident fast path.
|
||||||
|
- Integration test for stale active result discard.
|
||||||
|
- Existing asset load/commit tests must continue passing.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Confusing handle identity with request generation.
|
||||||
|
- Installing a stale async result after superseding.
|
||||||
|
- Losing compatibility with existing `asset.status/commit/cancel` behavior.
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0126
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Asset Backlog Public API and Status Surface
|
||||||
|
status: open
|
||||||
|
created: 2026-06-28
|
||||||
|
completed:
|
||||||
|
ref_decisions: [DEC-0034]
|
||||||
|
tags: [perf, asset, async, syscall, runtime]
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLN-0126 - Asset Backlog Public API and Status Surface
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0034` keeps `asset.load/status/commit/cancel` and adds a small status-first
|
||||||
|
backlog inspection and ordering surface. This plan wires that surface through
|
||||||
|
HAL syscall metadata and runtime dispatch.
|
||||||
|
|
||||||
|
## Decisions de Origem
|
||||||
|
|
||||||
|
- `DEC-0034` - Async Work Lane and Asset Backlog Contract.
|
||||||
|
|
||||||
|
## Alvo
|
||||||
|
|
||||||
|
Expose asset backlog inspection and reordering while preserving status-first
|
||||||
|
semantics and existing asset load identity.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Syscall registry additions for backlog APIs.
|
||||||
|
- Runtime dispatch handlers.
|
||||||
|
- Status enum additions or normalization.
|
||||||
|
- ABI/spec alignment with `PLN-0123`.
|
||||||
|
|
||||||
|
Fora de Escopo:
|
||||||
|
|
||||||
|
- Async lane internals.
|
||||||
|
- Asset decode refactor.
|
||||||
|
- FS API.
|
||||||
|
|
||||||
|
## Plano de Execucao
|
||||||
|
|
||||||
|
### Step 1 - Finalize Syscall Shapes
|
||||||
|
|
||||||
|
**What:** Choose final names, arity, and return slots for backlog operations.
|
||||||
|
|
||||||
|
**How:** Start from `DEC-0034`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
asset.backlog_info()
|
||||||
|
asset.backlog_position(handle)
|
||||||
|
asset.backlog_move(handle, new_position)
|
||||||
|
asset.backlog_promote(handle)
|
||||||
|
asset.backlog_demote(handle)
|
||||||
|
asset.target_status(bank_type, slot)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-hal/src/syscalls/domains/asset.rs`,
|
||||||
|
`docs/specs/runtime/16-host-abi-and-syscalls.md`.
|
||||||
|
|
||||||
|
### Step 2 - Add Status Values
|
||||||
|
|
||||||
|
**What:** Represent `empty`, `invalid`, `queued`, `active`, `ready`,
|
||||||
|
`committed`, `canceled`, `superseded`, `error`, and `backend_unavailable`.
|
||||||
|
|
||||||
|
**How:** Extend or map existing `LoadStatus` and `AssetOpStatus` without
|
||||||
|
turning operational states into traps.
|
||||||
|
|
||||||
|
**Files:** HAL asset status types and `crates/console/prometeu-drivers/src/asset.rs`.
|
||||||
|
|
||||||
|
### Step 3 - Add Dispatch
|
||||||
|
|
||||||
|
**What:** Wire new syscalls through VM runtime dispatch.
|
||||||
|
|
||||||
|
**How:** Add match arms near existing `AssetLoad`, `AssetStatus`,
|
||||||
|
`AssetCommit`, and `AssetCancel` arms. Return status-first values.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs`.
|
||||||
|
|
||||||
|
### Step 4 - Implement API Methods
|
||||||
|
|
||||||
|
**What:** Add AssetManager methods backing each public operation.
|
||||||
|
|
||||||
|
**How:** Methods must read stable handle/target state and reorder only queued
|
||||||
|
requests. `promote` and `demote` are shortcuts over move semantics.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-drivers/src/asset.rs`.
|
||||||
|
|
||||||
|
### Step 5 - Validate ABI Metadata
|
||||||
|
|
||||||
|
**What:** Ensure registry ids, args, returns, capability, cost, and
|
||||||
|
non-deterministic flags are correct.
|
||||||
|
|
||||||
|
**How:** Update syscall metadata tests and any declared PBS/runtime syscall
|
||||||
|
tables.
|
||||||
|
|
||||||
|
**Files:** `crates/console/prometeu-hal/src/syscalls/tests.rs` and related
|
||||||
|
registry files.
|
||||||
|
|
||||||
|
## Criterios de Aceite
|
||||||
|
|
||||||
|
- [ ] Public backlog operations are registered with stable metadata.
|
||||||
|
- [ ] All backlog operations are status-first.
|
||||||
|
- [ ] `promote` is equivalent to moving to first pending position.
|
||||||
|
- [ ] `demote` moves to the end of pending backlog.
|
||||||
|
- [ ] Reordering a non-queued request returns operational status.
|
||||||
|
- [ ] Structural ABI misuse remains Trap.
|
||||||
|
|
||||||
|
## Tests / Validacao
|
||||||
|
|
||||||
|
- HAL syscall metadata tests.
|
||||||
|
- VM runtime dispatch tests for each new syscall.
|
||||||
|
- AssetManager unit tests for move/promote/demote.
|
||||||
|
- Tests for `target_status` on empty, queued, active, ready, and superseded
|
||||||
|
targets.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Adding too many public ABI details before spec propagation is accepted.
|
||||||
|
- Returning payload values that are ambiguous when status is not success.
|
||||||
|
- Treating known but non-mutable states as traps instead of statuses.
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0127
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Async Lane Memcard and FS Integration Boundaries
|
||||||
|
status: open
|
||||||
|
created: 2026-06-28
|
||||||
|
completed:
|
||||||
|
ref_decisions: [DEC-0034]
|
||||||
|
tags: [perf, fs, memcard, async, runtime]
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLN-0127 - Async Lane Memcard and FS Integration Boundaries
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0034` allows memcard and FS work to consume the async IO lane but keeps
|
||||||
|
public FS API semantics out of scope. This plan establishes integration
|
||||||
|
boundaries without deciding app-home FS API shape.
|
||||||
|
|
||||||
|
## Decisions de Origem
|
||||||
|
|
||||||
|
- `DEC-0034` - Async Work Lane and Asset Backlog Contract.
|
||||||
|
|
||||||
|
## Alvo
|
||||||
|
|
||||||
|
Define and implement safe internal boundaries for memcard and FS use of the
|
||||||
|
async work lane, preserving lane priority and keeping FS public API decisions in
|
||||||
|
`AGD-0006`.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Memcard as a priority lane consumer candidate.
|
||||||
|
- FS as a permitted internal lane consumer.
|
||||||
|
- Priority ordering in the lane.
|
||||||
|
- Updates to `AGD-0006` to acknowledge the lane.
|
||||||
|
|
||||||
|
Fora de Escopo:
|
||||||
|
|
||||||
|
- Public FS request/poll design.
|
||||||
|
- App-home path/status contract.
|
||||||
|
- Full memcard async conversion if it requires public ABI changes.
|
||||||
|
|
||||||
|
## Plano de Execucao
|
||||||
|
|
||||||
|
### Step 1 - Update FS Agenda
|
||||||
|
|
||||||
|
**What:** Record that an async IO lane exists and may be used by FS.
|
||||||
|
|
||||||
|
**How:** Add a concise section to `AGD-0006` stating that FS public API remains
|
||||||
|
owned by that agenda, but implementation may use the async lane from `DEC-0034`.
|
||||||
|
|
||||||
|
**Files:** `discussion/workflow/agendas/AGD-0006-app-home-filesystem-surface-and-semantics.md`.
|
||||||
|
|
||||||
|
### Step 2 - Identify Memcard Operations
|
||||||
|
|
||||||
|
**What:** List memcard operations that can benefit from async IO.
|
||||||
|
|
||||||
|
**How:** Inspect `crates/console/prometeu-system/src/services/memcard.rs` and
|
||||||
|
VM runtime dispatch for `mem.*` operations. Classify read, write, commit, and
|
||||||
|
clear behavior.
|
||||||
|
|
||||||
|
**Files:** memcard service and VM runtime dispatch modules.
|
||||||
|
|
||||||
|
### Step 3 - Define Lane Priority
|
||||||
|
|
||||||
|
**What:** Encode the initial priority order from `DEC-0034`.
|
||||||
|
|
||||||
|
**How:** Add priority classes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
memcard commit/write
|
||||||
|
FS write/config
|
||||||
|
asset load
|
||||||
|
non-critical list/read
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files:** async lane module from `PLN-0124`.
|
||||||
|
|
||||||
|
### Step 4 - Add Internal Consumer Hooks
|
||||||
|
|
||||||
|
**What:** Provide internal APIs for memcard/FS to submit lane jobs later.
|
||||||
|
|
||||||
|
**How:** Add types/interfaces without changing public FS syscall behavior.
|
||||||
|
No public FS request/poll operations are introduced here.
|
||||||
|
|
||||||
|
**Files:** async lane module; FS/memcard service modules as needed.
|
||||||
|
|
||||||
|
### Step 5 - Preserve Current Public Behavior
|
||||||
|
|
||||||
|
**What:** Ensure existing memcard and FS syscalls keep their current observable
|
||||||
|
surface unless a later plan explicitly changes it.
|
||||||
|
|
||||||
|
**How:** Do not alter return shapes in this plan. Add tests proving existing
|
||||||
|
status-first behavior remains intact.
|
||||||
|
|
||||||
|
**Files:** VM runtime FS/memcard tests.
|
||||||
|
|
||||||
|
## Criterios de Aceite
|
||||||
|
|
||||||
|
- [ ] `AGD-0006` acknowledges the async IO lane and keeps FS public API in its
|
||||||
|
own scope.
|
||||||
|
- [ ] Async lane supports priority classes required by `DEC-0034`.
|
||||||
|
- [ ] Memcard and FS can be represented as internal lane consumers.
|
||||||
|
- [ ] Existing public memcard/FS syscall shapes are unchanged.
|
||||||
|
- [ ] No FS public request/poll API is introduced by this plan.
|
||||||
|
|
||||||
|
## Tests / Validacao
|
||||||
|
|
||||||
|
- Existing FS/memcard tests continue passing.
|
||||||
|
- Unit tests for lane priority ordering.
|
||||||
|
- Tests proving asset jobs do not overlap with higher-priority memcard jobs
|
||||||
|
once both are submitted through the lane.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Accidentally deciding FS public API in the wrong discussion.
|
||||||
|
- Making memcard async in a way that changes status-first behavior.
|
||||||
|
- Starving asset loads if priority rules do not include fairness.
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0128
|
||||||
|
ticket: perf-async-background-work-lanes-for-assets-and-fs
|
||||||
|
title: Async Asset Pipeline Contract Tests and Telemetry
|
||||||
|
status: open
|
||||||
|
created: 2026-06-28
|
||||||
|
completed:
|
||||||
|
ref_decisions: [DEC-0034]
|
||||||
|
tags: [perf, asset, async, telemetry, tests, runtime]
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLN-0128 - Async Asset Pipeline Contract Tests and Telemetry
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0034` requires observable progress, backlog state, superseding, and cheap
|
||||||
|
telemetry. This plan adds the validation and telemetry evidence needed to prove
|
||||||
|
the new async asset pipeline is correct.
|
||||||
|
|
||||||
|
## Decisions de Origem
|
||||||
|
|
||||||
|
- `DEC-0034` - Async Work Lane and Asset Backlog Contract.
|
||||||
|
|
||||||
|
## Alvo
|
||||||
|
|
||||||
|
Provide contract tests and telemetry for the async asset lane so future
|
||||||
|
implementations can be changed without regressing lane semantics.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Contract tests for lane and asset backlog behavior.
|
||||||
|
- Progress reporting tests.
|
||||||
|
- Superseding and stale result discard tests.
|
||||||
|
- Telemetry counters and percentile updates.
|
||||||
|
- No-sleep deterministic test helpers where needed.
|
||||||
|
|
||||||
|
Fora de Escopo:
|
||||||
|
|
||||||
|
- Implementing public API wiring if `PLN-0126` has not run.
|
||||||
|
- Full benchmarking infrastructure.
|
||||||
|
- Host UI display of telemetry.
|
||||||
|
|
||||||
|
## Plano de Execucao
|
||||||
|
|
||||||
|
### Step 1 - Build Deterministic Test Hooks
|
||||||
|
|
||||||
|
**What:** Add test hooks for blocking a lane job at read/decode/stage.
|
||||||
|
|
||||||
|
**How:** Use channels/barriers or explicit fake job steps. Do not rely on
|
||||||
|
`thread::sleep` for correctness.
|
||||||
|
|
||||||
|
**Files:** async lane tests; asset test support modules.
|
||||||
|
|
||||||
|
### Step 2 - Test Backlog Ordering
|
||||||
|
|
||||||
|
**What:** Prove queued jobs run serially and in backlog order.
|
||||||
|
|
||||||
|
**How:** Submit multiple target slots and assert active job, pending positions,
|
||||||
|
promote, demote, and move behavior.
|
||||||
|
|
||||||
|
**Files:** asset manager tests and lane tests.
|
||||||
|
|
||||||
|
### Step 3 - Test Superseding
|
||||||
|
|
||||||
|
**What:** Prove newer request for the same `bank_type/slot` supersedes older
|
||||||
|
requests.
|
||||||
|
|
||||||
|
**How:** Cover queued superseding and active superseding. For active work, prove
|
||||||
|
stale completion cannot install.
|
||||||
|
|
||||||
|
**Files:** asset manager tests.
|
||||||
|
|
||||||
|
### Step 4 - Test Stable Handle Observability
|
||||||
|
|
||||||
|
**What:** Prove handles are queryable for empty, queued, active, ready,
|
||||||
|
committed, canceled, superseded, and error states.
|
||||||
|
|
||||||
|
**How:** Use `target_status` and handle status APIs to inspect both `slot_state`
|
||||||
|
and `request_state`.
|
||||||
|
|
||||||
|
**Files:** asset manager tests; VM dispatch tests if public API is available.
|
||||||
|
|
||||||
|
### Step 5 - Test Progress
|
||||||
|
|
||||||
|
**What:** Prove progress uses `0..10000` and phase boundaries.
|
||||||
|
|
||||||
|
**How:** Fake read/decode/stage phases with known completion points. Validate
|
||||||
|
non-linear phases do not report false internal progress.
|
||||||
|
|
||||||
|
**Files:** asset manager tests; telemetry tests.
|
||||||
|
|
||||||
|
### Step 6 - Add Telemetry
|
||||||
|
|
||||||
|
**What:** Add counters and percentile aggregation.
|
||||||
|
|
||||||
|
**How:** Update submitted/completed/failed/canceled/superseded counters when job
|
||||||
|
state closes. Update percentiles by `bank_type` and lightweight `asset_id`
|
||||||
|
window only at job completion.
|
||||||
|
|
||||||
|
**Files:** asset manager telemetry, async lane telemetry, existing runtime
|
||||||
|
telemetry types if shared.
|
||||||
|
|
||||||
|
## Criterios de Aceite
|
||||||
|
|
||||||
|
- [ ] Tests prove one active job at a time.
|
||||||
|
- [ ] Tests prove backlog order and reordering.
|
||||||
|
- [ ] Tests prove queued and active superseding.
|
||||||
|
- [ ] Tests prove stale active results are discarded.
|
||||||
|
- [ ] Tests prove handles remain queryable across all required states.
|
||||||
|
- [ ] Tests prove progress phase behavior.
|
||||||
|
- [ ] Telemetry is updated at job closure, not inside inner decode loops.
|
||||||
|
|
||||||
|
## Tests / Validacao
|
||||||
|
|
||||||
|
- Run targeted cargo tests for asset manager, async lane, and VM runtime
|
||||||
|
dispatch.
|
||||||
|
- Run existing asset-bank tests to prove current behavior remains compatible.
|
||||||
|
- Run `discussion validate` after plan state changes.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Tests that depend on sleeps will be flaky.
|
||||||
|
- Telemetry may become too expensive if updated inside decode loops.
|
||||||
|
- Public API tests must wait for `PLN-0126` if syscall wiring is not present.
|
||||||
Loading…
x
Reference in New Issue
Block a user