# 05 — Cenário de execução
O benchmark roda inteiro na Oracle Cloud Infrastructure (OCI). A máquina local serve só para editar o código, versionar e disparar as execuções.
## Visão geral
```mermaid
flowchart LR
HF[Hugging Face Hub
e repositórios-fonte] -->|aquisição com SHA-256| ART[(Object Storage
artefatos)]
ART --> BUILD[Jobs de build
ambientes por candidato]
BUILD --> ART
GENAI[OCI Generative AI] --> DATA[Pipeline de dados
VM de trabalho]
DATA --> ENT[(Object Storage
partições congeladas)]
ART --> CPU[Jobs de medição CPU
sub-rede privada]
ART --> GPU[Jobs de medição GPU
A10]
ENT --> CPU
ENT --> GPU
CPU --> RES[(Object Storage
resultados)]
GPU --> RES
RES --> REP[reports/ no repositório]
```
| Etapa | Onde roda | O que produz |
|-------|-----------|--------------|
| Aquisição de artefatos | Fora da rede dos jobs (`env/acquire.py`) | Pesos, tokenizadores, código-fonte e runtimes nas revisões fixadas, no bucket `dmb-artefatos`, com SHA-256 em `env/artifacts-manifest.json` |
| Ambientes dos candidatos | Jobs de build do OCI Data Science, com acesso à internet (`infra/ds/build_env.sh`) | Um ambiente Python por candidato (versões de `env/requirements/`), publicado em `dmb-artefatos/envs//` com manifesto de versões |
| Dados sintéticos | VM de trabalho, chamando o OCI Generative AI (`datagen/`) | Partições congeladas em `data/splits/` e em `dmb-entrada` / `dmb-logs-imutaveis` |
| Medições em CPU | Jobs do OCI Data Science em **us-chicago-1**, `VM.Standard.E4.Flex` com 8 OCPU e 64 GB, em sub-rede privada sem saída para a internet | Predições e resumos em `dmb-resultados` |
| Medições em GPU | Jobs do OCI Data Science em **sa-saopaulo-1**, `VM.GPU.A10.1`, um por vez | Predições e resumos em `dmb-resultados-gru` |
| Análise e relatórios | VM de trabalho ou notebook do Data Science | `reports/` no repositório |
## Isolamento durante as medições
Toda inferência roda **sem acesso a fontes externas**:
- **Artefatos verificados.** O job baixa do bucket só o que está no manifesto e confere o SHA-256 de cada arquivo e do ambiente do candidato.
- **Bloqueio no processo** (`dmb/offline.py`). Variáveis offline do Hugging Face e bloqueio de conexões fora do loopback. Um autoteste a cada execução (`process_guard`) prova que o bloqueio está ativo.
- **Bloqueio na rede (CPU).** A sub-rede privada só alcança os serviços OCI pela Service Gateway. O gate de egresso de `harness/job.py` confirma que nenhum host público responde.
- **GPU.** Os jobs usam a rede gerenciada do serviço. O isolamento vem do bloqueio no processo e do autoteste (`DMB_ISOLATION=app`). Pesos e ambientes ficam em `dmb-artefatos-gru`, uma réplica server-side do bucket principal (`infra/oci/replicate.py`).
## Fluxo de uma execução
1. `infra/ds/jobs.py` (CPU) ou `infra/ds/gpu_queue.py` (GPU) empacota o repositório num zip, sem `.secrets/` e sem `models/`, e cria o job.
2. `harness/job.py` (processo pai, Python base do serviço): gate de egresso, download e verificação dos pesos e do ambiente.
3. O processo filho, no ambiente do candidato, roda `harness.sanity` ou `harness.evaluate` com o bloqueio de rede ativo.
4. O processo pai envia predições, resumos e logs para o bucket de resultados.
5. `infra/ds/collect.py` traz os resumos para `reports//`, com uma tabela comparativa.
## Runtimes por candidato
| Candidato | Runtime |
|-----------|---------|
| Laya, GLiNER | PyTorch 2.10 (wheels `cu128`), transformers 4.57 |
| SemIf | PyTorch 2.10 (wheels `cu128`), transformers 5.17 (exigência do SemIf) |
| Rizzo Flow | llama.cpp b11081 (commit fixado pelo Rizzo). CPU: binário oficial. GPU: o mesmo commit compilado para a imagem dos jobs (`infra/ds/build_llama_cuda.sh`, CUDA 12.8) |
## Comandos principais
```bash
# medição em CPU (sub-rede privada)
PYTHONPATH=infra/oci .venv/bin/python infra/ds/jobs.py run --name --entrypoint infra/ds/run_job.sh \
--private --ocpus 8 --memory 64 --env DMB_CANDIDATE= DMB_MODE=evaluate DMB_SPLIT=dev [--wait]
# medição em GPU (fila em sa-saopaulo-1)
PYTHONPATH=infra/oci:infra/ds .venv/bin/python infra/ds/gpu_queue.py evaluate laya gliner semif rizzo_flow \
--env DMB_SPLIT=dev
# resultados para o repositório
PYTHONPATH=infra/oci .venv/bin/python infra/ds/collect.py --split dev --dest reports/
# pipeline de dados (na VM de trabalho, a partir da máquina local)
infra/vm/remote.sh run 'python -m datagen.generate --out /data/runs/datagen-v1' # depois prepare, annotate, build
```
## Ciclo de vida dos recursos
Os recursos da OCI existem só durante o ciclo de medição. `infra/oci/provision.py` cria o compartment, as políticas, a rede, os buckets e o projeto do Data Science; `env/acquire.py` e `infra/ds/build_env.sh` publicam artefatos e ambientes; `infra/oci/teardown.py` remove tudo ao final. O ciclo `d1-v1` foi encerrado com o deprovisionamento completo: o registro permanente está neste repositório, e os dados brutos e os logs de execução ficam numa cópia local fora do Git (`data/raw/`, `runs/`).
## Configuração local sensível
Ficam fora do Git, em `.secrets/`: credenciais OCI e do GitHub, chaves SSH, o catálogo de recursos com OCIDs e `oci-settings.json` (compartimento pai e CIDR autorizado para SSH). O teste `tests/test_sensitive.py` falha se OCIDs, chaves, IPs públicos ou valores de `.secrets/` aparecerem em arquivos versionados.