---
title: "Como medir desperdício de computação em pipelines e serviços"
description: "Combine duração, CPU, memória, cache e frequência de execução para achar otimizações com impacto real em CI/CD e serviços — sem chasing de média enganosa."
date: "2026-09-24"
tags: ["devops", "ci-cd", "finops", "observabilidade", "performance", "cache", "sre", "otimizacao"]
url: "https://abjr.dev/noticias/medir-desperdicio-computacao-pipelines-servicos"
---

Um pipeline de 12 minutos que roda em 200 PRs por dia e um serviço que fica o dia inteiro a 8% de CPU. Qual desperdiça mais computação? A resposta intuitiva (“o serviço ocioso”) costuma estar errada. Desperdício não é CPU baixa. É **recurso × tempo × frequência**, distorcido por cache miss, runner errado, retry e overprovisioning.

Eu vejo times otimizarem a média de CPU de um pod e ignorarem o workflow que come metade da fatura de Actions. Ou o contrário: cortarem minutos de CI e deixarem um `m5.2xlarge` acordado 24h para um job noturno de uma hora. O método abaixo existe para achar alavancas com impacto real — sem chasing de métrica isolada.

## Uma fórmula útil (de propósito grosseira)

Para **pipelines e jobs batch**:

**impacto ≈ duração_efetiva × custo_do_runner × frequência × fator_de_desperdício**

Onde `fator_de_desperdício` sobe com cache miss, flake/retry, fila que gera re-trigger, e trabalho que não precisava rodar (path filter ausente, schedule zumbi).

Para **serviços sempre ligados**, troque frequência por *uptime com demanda real* e separe duas contas:

- **Waste (lixo):** recurso que não entrega valor — idle genuíno, disco órfão, artifact que ninguém baixa.
- **Overprovisioning:** workload vivo, só que oversized — candidato a rightsizing com guarda de SLO, não a “desligar e torcer”.

A FinOps Foundation trata redução de waste como prioridade recorrente; o erro clássico é usar só “CPU abaixo de 5%” e matar um batch noturno que parece idle 23 horas por dia. Sinal de aplicação (tráfego, conexões, erros, fila) separa quieto-mas-vivo de morto-de-verdade.

## Cinco eixos que precisam andar juntos

### 1. Duração (e a cauda)

Olhe p50, p90 e p95 — não só a média. A razão **p90 / p50** conta a história da variância. Em guias de CostOps para CI, algo na faixa 1,3–1,5× é comum; acima de ~2,5× quase sempre há loteria: cache frio, fila de runner, hardware heterogêneo, flake.

Duração de wall-clock ≠ minutos faturáveis. Fila (tempo até o runner pegar o job) irrita o desenvolvedor e empurra re-runs; a fatura começa quando o job de fato roda. Ainda assim, fila instável é desperdício de *atenção* e, indiretamente, de compute via retries.

### 2. CPU

CPU alta com duração alta: talvez paralelismo ou máquina maior ajude — **se** o speedup pagar o multiplicador de preço. Um runner 4× mais caro precisa terminar bem mais que 4× mais rápido para reduzir custo; Analytics de GitHub Actions / Depot deixam esse trade-off explícito.

CPU baixa com duração alta: o job está esperando rede, lock, teste serial, ou `sleep` disfarçado de “build”. Mais core não resolve. Cache, I/O e critical path resolvem.

Em serviços, média de CPU é a métrica mais mentirosa do rightsizing. Picos curtos (ingest matinal, checkout) somem na média e voltam como incidente depois do downsize. Prefira percentis no *pico de demanda*, não a média da semana.

### 3. Memória

Use **pico / working set**, não a média. Workload JVM ou Node “com CPU folgada” pode estar no limite de heap; downsize de instância corta RAM e o GC come o que você achou que economizou. Em nuvem, memória muitas vezes **não** entra no métricas default (CloudWatch sem agent, por exemplo) — sem ela, Compute Optimizer e qualquer planilha mentem.

Em CI, OOM mata o job, gera retry e infla minutos. Ferramentas que expõem CPU/memória por agente ou por task (Nx Cloud resource usage, runners com telemetria) transformam “o build às vezes morre” em “este projeto estoura RAM quando o paralelismo passa de N”.

### 4. Cache

Cache hit rate é o multiplicador escondido da duração. O mesmo workflow: 6 minutos com cache quente, 25 com frio. Se a chave inclui SHA do commit, ou se branches nunca compartilham restore-keys estáveis baseadas em lockfile, **cada PR paga install completo**. A variância explode; o p50 fica otimista; a fatura segue o p90.

Boas práticas chatas e eficazes: chave estável (hash de lockfile), restore-keys de fallback, imagem base enxuta, menos “um container gigante para todos os jobs”. GitLab documenta o mesmo eixo: dependências, tamanho de imagem e storage de artifact são parte da eficiência do pipeline, não acessórios.

### 5. Frequência

Um job medíocre que roda a cada push em monorepo sem path filters pode custar mais que um job lento e raro. Cancele runs superados (`concurrency` / cancel-in-progress). Evite matrix que multiplica acidente. Trate flake como custo de compute, não só como irritação: cada retry é `duração × runner` de novo.

Em serviços, “frequência” vira horário de carga e escala. Autoscaling mal calibrado (min replicas altas “por segurança”) é overprovisioning com nome elegante.

## Waste versus overprovisioning

| Tipo | O que é | Sinal típico | Ação |
| --- | --- | --- | --- |
| Waste | Zero valor | Sem tráfego, sem conexões, job morto, artifact eterno | Remover, expirar, desligar com checagem de schedule |
| Overprovisioning | Valor real, capacidade sobrando | Tráfego existe; CPU/memória/rede com folga no *pico* | Rightsizing / right-typing com guarda de SLO |
| Subprovisioning | Capacidade faltando | Latência, erro, OOM, fila | Subir recurso ou repartir carga — otimizar custo depois |

Os *four golden signals* do SRE (latência, erros, tráfego, saturação) são o filtro para não chamar de waste o que é só horário off-peak. Idle criteria de cloud (ex.: pico de CPU muito baixo **e** rede quase nula por lookback) ajudam no lixo óbvio; batch e APIs com spike pedem contexto de aplicação.

## Método em quatro passos

1. **Rankear por custo total no período** (minutos faturáveis × preço do runner; ou $/serviço). Não por “job mais lento”. O lento e raro pode ser teatro; o mediano e frequente paga as contas.
2. **Abrir o top 3.** Por job: steps, CPU/memória, cache hit, fila. Por serviço: percentis no pico, memória, rede, latência e erros.
3. **Cruzar os cinco eixos** com a mini-matriz abaixo. Escolher **uma** hipótese dominante.
4. **Uma mudança por vez**, medir uma semana representativa (duração, taxa de falha, minutos/$, p95 de latência). Sem big-bang de “otimizamos o CI”.

## Sintoma → causa provável → alavanca

| Sintoma | Causa provável | Alavanca |
| --- | --- | --- |
| Duração alta, CPU baixa | Espera de rede, lock, etapa serial | Cache de deps, parallelize o critical path, menos download |
| Duração alta, CPU saturada | Compute bound de verdade | Runner maior *só se* o speedup passa do multiplicador de preço; ou algoritmo/artifact |
| p90/p50 alto | Loteria de cache, fila, flake | Lockfile keys, restore-keys, timeout, menos re-run |
| CPU baixa, memória alta | Memory-bound | Right-type (mais RAM), não só menos vCPU |
| Minutos altos, job “ok” | Frequência | Path filters, concurrency cancel, menos matrix |
| Serviço “8% CPU” 24h | Média mentirosa ou idle real | Olhar pico + tráfego; idle genuíno → consolidar; vivo → rightsizing no pico |
| OOM intermitente no CI | Paralelismo × working set | Limitar paralelismo do monorepo; subir RAM do runner com conta explícita |

## Checklist: pipelines

- [ ] Workflows ordenados por **minutos totais** no mês, não só por duração média.
- [ ] p50/p90 (e razão) por job crítico; cauda investigada.
- [ ] Cache com chave de lockfile + fallback; hit rate acompanhado depois de mudanças.
- [ ] Path filters / rules para não buildar o monorepo inteiro a cada doc typo.
- [ ] Cancel de runs superados; timeout para job zumbi.
- [ ] Runner size justificado com antes/depois de wall-clock **e** custo.
- [ ] Artifacts com `expire_in` / retenção; registry sem imagem órfã eterna.
- [ ] Flake rate entra no ranking de custo (retry × duração).

## Checklist: serviços

- [ ] Separar candidatos a **waste** (sem tráfego/conexões no lookback) de **rightsizing**.
- [ ] Memória coletada de fato; sizing pelo working set no pico + headroom (faixa típica 10–30% conforme risco).
- [ ] CPU/memória/rede/latência juntos — rightsizing em uma dimensão só gera rollback.
- [ ] Batch e cron avaliados no horário do job, não na média diária.
- [ ] Mudança canário + SLO / error budget como freio; uma família de instância por vez.
- [ ] Autoscaling com mínimo honesto; “min=10 por medo” é linha na fatura.

## O que otimizar primeiro

Ordene alavancas por **impacto estimado × esforço**. Na maioria dos repositórios que eu vejo, cache estável e cortar frequência inútil batem runner maior. Em serviços, idle óbvio e right-type memory-bound batem “reduzir 10% CPU média”.

Desperdício de computação se mede com produto de eixos, não com um gráfico verde. Duração, CPU, memória, cache e frequência — juntos — dizem onde o próximo PR de otimização paga a si mesmo.

Se você só pudesse instrumentar uma coisa amanhã no CI, seria minutos totais por workflow ou hit rate de cache? E no serviço: memória no pico, ou tráfego junto da CPU?

## Referências

- [GitLab: Pipeline efficiency](https://docs.gitlab.com/ci/pipelines/pipeline_efficiency/) — duração, sizing de runner, cache, imagens e storage.
- [Depot: monitorar performance e custo de GitHub Actions](https://depot.dev/resources/guides/how-can-i-monitor-github-actions-performance-and-cost-across-my-organization) — minutos, CPU/memória, trade-off de runner maior.
- [CostOps: estabilizar variância de runtime de CI](https://costops.dev/guides/stabilize-ci-runtime) — p90/p50, cache lottery, fila.
- [Nx Cloud: resource usage](https://nx.dev/docs/features/ci-features/resource-usage) — CPU/memória por agente e OOM.
- [AWS Compute Optimizer e rightsizing](https://aws.amazon.com/blogs/compute/optimize-ec2-costs-with-aws-compute-optimizer-right-sizing/) — over/under/idle; memória via agent; headroom.
- [Sedai: cloud waste](https://sedai.io/blog/cloud-waste) — waste vs overprovisioning; idle ≠ batch quieto; golden signals.
- [Sedai: rightsizing playbook](https://sedai.io/blog/cloud-rightsizing-playbook) — dimensionar no pico (p95/p99), não na média.
- [Google SRE Book: Four Golden Signals](https://sre.google/sre-book/monitoring-distributed-systems/) — latency, traffic, errors, saturation.
- [ci-snitch](https://github.com/vertti/ci-snitch) — ranking de workflows por compute, volatilidade e hotspots de custo.
