Skip to content

Latest commit

 

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

instance-gen

Geração e transformação de instâncias para o problema de escalonamento de workflows híbridos (VM + FX/serverless). Uma instância descreve um DAG de tarefas, artefatos de dados, máquinas virtuais disponíveis, perfis de execução serverless e faixas de custo de bucket.

O repositório tem duas frentes sobre o mesmo formato de instância:

contexto o que produz código dados docs
sintético instâncias geradas por modelo, com topologia controlada src/synthetic/ data/instances/synthetic/ tabela abaixo
denethor instâncias derivadas de execuções reais do workflow DENETHOR na AWS — medidas e preditas src/denethor/ data/instances/denethor/, data/denethor_study/ tabela abaixo
compartilhado o formato .txt e o que vale para qualquer instância src/shared/ — formato_instancia.md

src/synthetic/ e src/denethor/ não se enxergam: o que os dois precisam mora em src/shared/. tests/test_package_boundaries.py trava essa direção.

Como rodar

Há uma única forma de invocar qualquer script deste repositório: como módulo, a partir de src/.

cd src
python3 -m synthetic.cli.generate_instances_user --tier easy   # gerar sintéticas
python3 -m denethor.cli.run_study --all                        # pipeline denethor
python3 -m shared.cli.instances_validation ../data/...         # validar qualquer uma

python3 src/<pacote>/cli/<script>.py não funciona: src/ não está no sys.path e o import do próprio pacote falha com ModuleNotFoundError. A única exceção é denethor/cli/run_study.py, que faz um sys.path.insert — e mesmo esse deve ser chamado como módulo, para não haver duas convenções.

Os caminhos de dados passados na linha de comando são relativos ao diretório corrente, que nessa forma é src/ — daí o ../data/... dos exemplos. O gerador do modo user é a exceção: ancora entrada e saída na raiz do repositório via shared/repo.py, então não recebe caminho nenhum.

Pendência conhecida. synthetic.cli.generate_instances_random e synthetic.cli.generate_instances_mermaid ainda resolvem data/… a partir do diretório corrente com caminho fixo, em vez de repo.ROOT. Rodados de src/ eles procuram src/data/… e falham (FileNotFoundError). Migrá-los para shared.repo é o conserto; até lá, os exemplos deste README para esses dois scripts descrevem a chamada pretendida, não uma que funcione hoje.

O formato completo das instâncias está documentado em docs/formato_instancia.md.


A — Instâncias sintéticas

Geração de instâncias

Modo user — topologia definida manualmente

Gera instâncias a partir dos workflows descritos em data/instances/defs/instance_def_<tier>.txt. Existem dois arquivos de definição: easy e ultrahard. medium e hard não são gerados: são derivados da easy (próxima seção).

cd src

# Todos os workflows do tier (padrão: easy)
python3 -m synthetic.cli.generate_instances_user --tier easy
python3 -m synthetic.cli.generate_instances_user --tier ultrahard

# Ou apenas alguns IDs
python3 -m synthetic.cli.generate_instances_user --tier ultrahard --fx Synthetic_124 Synthetic_168

Cada tier grava em data/instances/synthetic/user/<tier>/. As demais opções são --skip-edge-cases, --output-dir e --seed.

Não regerar a easy. A easy do disco teve o painel de VM trocado pelo painel real do DENETHOR (commit 6b8f05d); o gerador ainda escreve o catálogo sintético (DEFAULT_VMS), então regerá-la devolveria o painel antigo. É pendência conhecida.

Tiers derivados — medium e hard

medium e hard são a easy com outro painel de VM (e, no hard, todos os tempos × 5). DAG, tempos de tarefa, artefatos e perfis FX são os da easy, byte a byte; a única variável entre os tiers é o painel — escolha × capacidade — e a escala. O perfil de cada um é declarado em data/instances/defs/perfil_<tier>.txt (tipos do catálogo AWS, com réplica, e o fator de tempo), e a derivação é determinística:

cd src
python3 -m synthetic.cli.derive_tier --tier medium     # 10 VMs, 7 tipos, tempos da easy
python3 -m synthetic.cli.derive_tier --tier hard       # 50 VMs (medium × 5), tempos × 5
python3 -m shared.cli.instances_effective_catalog ../data/instances/synthetic/user/{easy,medium,hard}

O desenho, as medições que o sustentam e as baterias do Stratus estão em docs/sintetico_tiers.md. As versões anteriores dos dois tiers (geradas por definição própria) ficaram em medium/v1/ e hard/v1/.

Modo random — topologia aleatória

Gera uma instância com DAG criado aleatoriamente a cada execução.

cd src && python3 -m synthetic.cli.generate_instances_random

Os arquivos são salvos em data/instances/synthetic/random/ com nome sequencial automático. Vale a pendência de caminho descrita em Como rodar.


Parâmetros

Os campos abaixo valem no bloco DEFAULTS: de um arquivo de definição e, por workflow, como sobrescrita:

Campo Descrição
NUM_VMS Número de VMs incluídas na instância (10 no catálogo; acima disso ele é estendido pela mesma reta — ver docs/sintetico_catalogo_vm.md, seção 2.3)
NUM_CONFIGS Número de configurações FX por tarefa (o teto depende do piso do FX_SLOWDOWN: 3 com piso 3.0, 9 com piso 8.0, 24 com piso 20.0 — ver a seção de testes)
NUM_BUCKET_RANGES Número de faixas de preço do bucket
USE_INTEGER_TIME Usa tempos inteiros (facilita leitura e depuração)
FX_SLOWDOWN Faixa min,max de lentidão do FX em relação à VM de referência
CPU_TIME Faixa min,max do tempo de CPU sorteado por tarefa
READ_TIME Faixa min,max do tempo de leitura por dado
WRITE_TIME Faixa min,max do tempo de escrita por dado

As VMs são escolhidas de forma determinística: um tier com mais VMs recebe as mesmas do tier menor mais as seguintes do catálogo, para que os tiers só difiram na quantidade de recursos. O catálogo é ancorado nos preços on-demand da família t3 em sa-east-1 e estendido linearmente (custo/s = 5.167e-6 / cpu_slowdown), o que deixa o custo por unidade de trabalho de CPU igual em todas as VMs — o trade-off tempo × custo vem do I/O e da ociosidade, cobrados na tarifa da VM. A tabela completa, a análise de dominância e a conferência contra o preço real (incluindo duas ressalvas de fidelidade) estão em docs/sintetico_catalogo_vm.md.

O gerador do modo user ainda expõe TASK_ID_OFFSET / DATA_ID_OFFSET para renomear IDs ao escrever o arquivo final.

Após gerar cada arquivo, ambos os geradores recalculam automaticamente os limites max_running_time (TM) e max_financial_cost (CM) no cabeçalho da instância.


Definindo topologias (modo user)

Cada arquivo começa com um bloco DEFAULTS: que vale para todos os seus workflows, seguido dos blocos de workflow. O trecho abaixo é o do instance_def_easy.txt:

DEFAULTS:
NUM_VMS: 5
NUM_CONFIGS: 3
NUM_BUCKET_RANGES: 3
USE_INTEGER_TIME: true
FX_SLOWDOWN: 3.0,10.0
CPU_TIME: 1,8
READ_TIME: 1,6
WRITE_TIME: 1,3

EDGE_CASES:
VM_TASKS_ONLY: Synthetic_007, Synthetic_022, Synthetic_032, Synthetic_060
VM_HIGH_COST: Synthetic_011
TM_EXCLUDES_OPTIMAL: Synthetic_022=60.0

--------------------------------

WORKFLOW_ID: Synthetic_016
TASKS: 6
DATA: 10
PATTERN: Map, Split, Merge (Cascading Diamonds)
CPU_TIME: 1,5
READ_TIME: 1,3
WRITE_TIME: 1,3
COMMENT: ...
---
t0: d0 -> d1,d2
t1: d1 -> d3

As linhas após --- seguem o padrão task_id: [inputs] -> [outputs]. As dependências do DAG são implícitas: uma tarefa só pode executar quando todos os seus dados de entrada estiverem disponíveis.

Casos de borda (EDGE_CASES:)

Bloco opcional, no mesmo nível do DEFAULTS:. Cada campo lista WORKFLOW_IDs que ganham, além da instância normal, uma instância extra com uma transformação de caso de borda aplicada por cima — gerada automaticamente pelo gerador do modo user, sem edição manual do .txt gerado:

Campo Sufixo do arquivo Transformação
VM_TASKS_ONLY _vm_tasks_only task_type forçado para 0 (só-VM) em toda tarefa, mesmos recursos do workflow no tier
VM_HIGH_COST _vm_high_cost cost_per_second de toda VM somado a 9999, CM recalculado
TM_EXCLUDES_OPTIMAL _tm_excludes_optimal max_running_time fixado no valor declarado (ID=segundos), ou reduzido à metade do calculado se nenhum for dado

A variante é cópia da base com a transformação por cima, e não uma nova geração: o que ela pode diferir da base é exatamente o mecanismo sob teste, e nada mais. tests/test_edge_case_variants.py guarda essa propriedade.

TM explícito no TM_EXCLUDES_OPTIMAL

Só este campo aceita um valor por workflow, na forma ID=segundos:

TM_EXCLUDES_OPTIMAL: Synthetic_022=60.0    # TM medido na mão
TM_EXCLUDES_OPTIMAL: Synthetic_022         # sem valor: usa a razão automática

O valor explícito existe porque saber qual TM de fato exclui a solução ótima exige rodar a heurística na instância e decidir na mão — a razão automática não sabe onde o ótimo está. Declarar no arquivo de definição torna esse ajuste manual reproduzível: regerar o tier passa a reproduzir o valor em vez de sobrescrevê-lo. Um valor não numérico, vazio ou não-positivo é erro (InvalidEdgeCaseValueError), assim como usar =valor nos outros dois campos, que o ignorariam em silêncio. Se o TM declarado não for menor que o calculado, o gerador emite um aviso — o arquivo continua válido, mas a variante não excluiria nada.

Sem valor explícito, a razão automática é um limite conservador seguro: update_file_bounds grava TM_final = TM_listsched × (1 + margem) — o teto do escalonamento mais barato. Como TM_final / (1 + margem) = TM_listsched, qualquer razão abaixo de 1 / (1 + margem) (0.8 com a margem atual de 0.25) deixa o TM abaixo de TM_listsched para qualquer instância, sem precisar calcular o ótimo real — daí a razão fixa de 0.5 (TM_EXCLUDES_OPTIMAL_RATIO, em src/synthetic/edge_cases.py).

Um WORKFLOW_ID referenciado em EDGE_CASES que não existe no arquivo é erro (load_definition levanta UnknownEdgeCaseWorkflowError; validate_file reporta o código E3).

Precedência de configuração

campo no bloco do workflow  >  bloco DEFAULTS do arquivo

Qualquer campo do DEFAULTS pode ser repetido dentro de um workflow para valer só para ele — é o que Synthetic_016 faz com CPU_TIME e o que as topologias pesadas do ultrahard (Synthetic_124, Synthetic_168, Synthetic_264) fazem para esticar o horizonte.

Não existe um terceiro nível: o gerador não tem constantes de configuração. Um campo que não apareça nem no DEFAULTS nem no bloco do workflow faz load_definition levantar MissingSettingError apontando o campo e o workflow, e validate_file reportar o código F14. A configuração é sempre o que está escrito no arquivo de definição.


Diagramas mermaid dos DAGs

cd src

# do arquivo de definição do tier
python3 -m synthetic.cli.generate_instances_mermaid --tier ultrahard Synthetic_042 Synthetic_060

# de uma família de instâncias já gerada
python3 -m synthetic.cli.generate_instances_mermaid --family ultrahard --all

Vale a pendência de caminho descrita em Como rodar.

Escreve um .mermaid por workflow em data/instances/diagrams/mermaid/, com os dados como círculos e as tarefas como retângulos, nos mesmos ids do arquivo de instância (t_100+, d_900+).

Opção Efeito
--tier <easy|medium|ultrahard> lê o DAG de data/instances/defs/instance_def_<tier>.txt
--family <nome> lê o DAG dos arquivos de instância da família já gerada (as opções válidas estão em INSTANCE_FAMILIES, no próprio script)
--all todos os workflows da fonte, em vez dos IDs passados
--no-labels exporta só a forma do DAG: nós sem rótulo, fundo branco, sem título nem moldura. Sai em data/instances/diagrams/mermaid_plain/ com sufixo _plain
--out-subdir <nome> subpasta dentro do diretório de saída

Os dois modos de leitura produzem o mesmo DAG; --family usa só os arquivos base, já que as variantes de caso de borda não mudam a topologia, e cruza PATTERN/COMMENT com o instance_def do tier de origem. A origem fica registrada numa linha %% SOURCE no topo de cada arquivo.

Regerar um diagrama que já existe preserva os style/linkStyle ajustados à mão, desde que o conjunto de nós não tenha mudado; se mudou, o arquivo antigo fica como .bak ao lado.


B — Instâncias derivadas do DENETHOR

Instâncias construídas a partir de execuções reais do workflow DENETHOR na AWS (Lambda para FX, EC2 para a VM de referência). Cadeia completa, da linha de log bruta ao arquivo validado: docs/denethor_geracao_instancias.md.

Onde elas moram

As famílias denethor são organizadas pelo front de seleção dos n arquivos de entrada — a única coisa que muda entre as campanhas. Contagens conferidas no disco em 2026-08-27:

data/instances/                        o produto — tudo que é instância
  denethor/                            achatada como no Stratus: front no nome da pasta
    runs/                          42   as 33 reais (11 cada run1/run2/run3) + as 9 da
                                       extensão E11 (só run1: 5 run4 medidas + 4 preditas) —
                                       sufixo _r1/_r2/_r3 no nome; + CARIMBO_CONGELADO.md,
                                       _readme.md, file_mapping*.txt e os manifestos CSV
    runs_x100/                    20   escala ×100 coerente (só o front run1, sem sufixo)
    runs_x1000/                   20   escala ×1000 coerente (idem)
    first-n_bug/                   5   as I060–I100 originais, com o bug de proveniência
                                       (+ os 5 .sql que as geraram; só registro, não usar)
    denethor_original_tm_cm_sequencial/
                                  33   as 33 reais originais, com o carimbo TM/CM sequencial
  synthetic/user/                      as sintéticas (ver a parte A) — sete pastas
    easy/                         21   (+ Synthetic_easy.zip e v1/, com os 17 arquivos da campanha anterior)
    medium/                       21   derivada da easy: 10 VMs do catálogo AWS (+ v1/, a gerada, com o seu instance_def)
    hard/                         21   derivada da easy: 50 VMs, tempos × 5 (+ v1/, a derivada à mão da ultrahard)
    ultrahard/                    31
    scale022/                      8
    scale022_v2/                   8
    _scalehard_v1/                23   aposentada; ver o README da própria pasta
  cplex/                               NÃO são instâncias: são saídas do solver (ver cplex/README.md)
    easy/                         56   55 saídas da campanha easy + o zip de resultados parciais
    model_validation/              6   as 6 instâncias como foram ao solver…
      output/                     18   …e as saídas correspondentes (6 × α ∈ {0,05; 0,50; 0,95})
  defs/                            4   instance_def_{easy,ultrahard}.txt (topologias) e perfil_{medium,hard}.txt (painéis)
  diagrams/                            mermaid/ (14), mermaid_plain/{easy,scale_hard} e um .jpeg avulso

data/denethor_study/                   o estudo do trace real; cada pasta leva o nome
  measured/                            da camada que a produz. measured/ é a exceção:
    ec2_benchmarks/               13   é a medição que ENTRA, não sai de camada nenhuma
    local_runs/                          (benchmarks de download na EC2 e a rodada local)
    MANIFEST.csv                       procedência e sha256 do que foi copiado para cá
  observed/                        8   saída de E1–E5 (observation)
  predicted/                       21  saída de E6–E9 (prediction), + models/ e selected_files/

data/aws_study/                        preços e velocidade da AWS
  catalog/                         2   specs e preços reais de sa-east-1 (12 VMs, 48 configs FX)
  fx_vm_speed/                     3   razão task_time_cpu(FX)/vm_cpu_time

A natureza da instância está no basename: as preditas levam o sufixo _predicted, porque é o basename que identifica a instância nos CSVs de resultado e nos nomes dos schedules. As medidas não levam sufixo.

O pipeline de predição (E1–E12)

cd src
python3 -m denethor.cli.run_study --all        # E1–E7, para no gate de validação
python3 -m denethor.cli.run_study --etapa 9    # re-ancora a IR na execução local
python3 -m denethor.cli.run_study --etapa 10   # extrai as fontes do repo denethor
python3 -m denethor.generation.db_ids          # IDs do banco (vw_task) para as I060–I100
python3 -m denethor.generation.generate_denethor --all      # E11 — constrói as instâncias
python3 -m denethor.tools.validate_instance_files ../data/instances/denethor/runs/I002_T7_C5_D18_VM5_r1.txt

run_study aceita --etapa de 1 a 12; generate_denethor aceita --targets (só I125–I201, a partir da IR), --regen (só I060–I100, da run4) ou --all, mais --out.

denethor/generation/ é a ponta da cadeia — lê o export do Postgres e escreve os .txt. O resto de denethor/ é infraestrutura compartilhada com E1–E9.

Fora do pipeline, sob demanda: denethor.tools.format_instance normaliza a largura decimal das colunas de tempo (10 casas) e de custo (14, a convenção do SQL) das seções de tarefas, dados e matriz — sem tocar em TM/CM, painel de VM ou bucket. Idempotente e sem efeito no carimbo; tem --check para verificar sem escrever. Ver §5.4 de docs/denethor_geracao_instancias.md.

A E9 é que produz a IR definitiva: ela re-ancora na execução local medida e chama a E8 com as âncoras. O --extrapolar roda a E8 sozinha, no modo "modelo puro", sem as âncoras — variante diferente, TM bem menor.

O dump do Postgres é lido direto de denethor/database/backup_29-06-2025/ — o repo denethor precisa estar montado (os caminhos externos ficam todos em src/denethor/paths.py). data/denethor_study/measured/ guarda só o que não existe lá: hoje, os 13 relatórios de benchmark de download da EC2 e a rodada local de Python, com procedência e sha256 no MANIFEST.csv ao lado.

Famílias escaladas

As reais ficam no regime sub-segundo, onde ceil(cpu × slowdown) = 1 em todas as VMs e a escolha VM × FX passa a ser decidida pelo arredondamento. A extensão linear tira as tarefas desse piso — é uma transformação genérica, aplicável a qualquer instância:

cd src && python3 -m shared.cli.extend_instance --fator 100
cd src && python3 -m shared.cli.instances_cm_tm_updates --strategy resource_aware \
    --margin 0.25 --instances-dir ../data/instances/denethor/runs_x100
cd src && python3 -m denethor.tools.format_instance ../data/instances/denethor/runs_x100

Regra da escala coerente: todos os campos de tempo escalam pelo mesmo fator, a duração exclui o cold start (o Lambda fatura duração decorrida) e o custo é recalculado pela tarifa, nunca multiplicado — o termo fixo por invocação não escala. Travada por tests/test_extend_instance.py; detalhes na seção 5.1 de denethor_geracao_instancias.md.


Ferramentas comuns

Valem para qualquer instância, sintética ou real.

Recalcular limites TM/CM em instâncias existentes

cd src
python3 -m shared.cli.instances_cm_tm_updates --instances-dir ../data/instances/synthetic/user/easy
python3 -m shared.cli.instances_cm_tm_updates --instances-dir ../data/instances/synthetic/user/ultrahard \
    --patterns "Synthetic_124*.txt"

--strategy escolhe entre resource_aware (padrão) e pessimistic; --margin sobrescreve a folga padrão da estratégia (0.25 e 0.0, respectivamente).


Validar instâncias

cd src && python3 -m shared.cli.instances_validation ../data/instances/denethor/runs

Conferir o regime de carimbo TM/CM

cd src && python3 -m shared.cli.verifica_carimbos ../data/instances/denethor/runs --esperado-congeladas 2

O regime das reais é misto por design: das 42 instâncias dessa pasta (reunificação de 2026-08-31 de first-n/, rand-1/ e rand-2/, com o front no sufixo _r1/_r2/_r3 do nome — ver data/instances/denethor/runs/_readme.md), 40 batem com resource_aware(0.25) e 2 estão congeladas no carimbo de 2026-08-07 — as únicas com solução ótima do CPLEX. Sem este script, "40 batem e 2 não" parece bug. Ver data/instances/denethor/runs/CARIMBO_CONGELADO.md.


Documentação

Compartilhado — o formato e suas réguas

Documento Conteúdo
docs/formato_instancia.md Especificação completa das 6 seções do arquivo .txt
docs/formato_modelo.txt Exemplo comentado do arquivo, seção a seção
docs/formato_tm_cm.md Cálculo dos limites TM/CM
docs/formato_tm_cm_v2_testes.md CM v2 por dominância: o que motivou, o critério e as baterias que o testaram — experimento, não adotado
docs/sintetico_catalogo_vm.md Catálogo de VMs: tabela adotada, análise de dominância e conferência contra os preços reais da AWS
docs/aws_catalogo.md Preços e specs reais da AWS em sa-east-1 (EC2 + Lambda), em dólar: as 5 VMs e as 5 configs do DENETHOR marcadas, mais 7 VMs de workflow científico e a escada de 48 memórias de Lambda

Sintético

Documento Conteúdo
docs/sintetico_tiers.md Os tiers vigentes: medium e hard derivados da easy por perfil declarado — o painel, a escala de tempo, o catálogo efetivo medido e as baterias do Stratus
docs/sintetico_analise_topologias.md Inventário dos workflows, linhagens entre instâncias e desafios para a fase construtiva
docs/sintetico_fx_vm_calibracao.md Relação cpu_time FX × VM: gerador vs instâncias reais do DENETHOR
docs/sintetico_escada_tiers_aposentada.md Proposta de escada ×1/×4/×16 entre tiers — aposentada em 2026-08-27, nunca implementada; a direção é o catálogo AWS (docs/aws_catalogo.md)

DENETHOR

Documento Conteúdo
docs/denethor_geracao_instancias.md Cadeia completa dos logs às instâncias: fontes, o bug da run4, o construtor, a organização por front e a regra da escala
docs/aws_fx_vm_speed.md Medição independente de task_time_cpu(FX)/vm_cpu_time sobre os 1.254 itens de trabalho reais, confrontada com a literatura acadêmica — inclui o piso de overhead de 103 ms, o excesso de ~4,2× sobre o modelo de cota de CPU e a replicação pela run4 (I060–I100)
docs/denethor_estudo_escalabilidade.md Relatório numérico do estudo — auto-gerado por src/denethor/prediction/report.py, não editar
docs/denethor_estudo_escalabilidade_retomada.md Estado e decisões do estudo ao longo do tempo
docs/denethor_bateria_stratus_2026-08-18.md Registro das rodadas da heurística (Stratus) sobre as instâncias novas

Testes

Os testes usam pytest e rodam a partir da raiz do repositório — pytest.ini já põe src e tests no pythonpath:

pip install -r requirements-dev.txt
pytest

A suíte valida os arquivos data/instances/defs/instance_def_*.txt antes de qualquer geração. A lista de tiers não é fixa: tests/conftest.py a descobre por glob, então um instance_def novo entra na suíte sem editar nada (hoje são dois: easy e ultrahard; medium e hard são derivados e testados sobre os arquivos, em test_derive_tier.py).

Arquivo Cobertura
tests/test_workflow_definitions.py Um caso por workflow de cada tier, mais as relações entre tiers
tests/test_workflow_def_validation_rules.py Blocos propositalmente quebrados, garantindo que cada regra realmente falha
tests/test_edge_case_variants.py Uma variante de caso de borda só difere da sua base naquilo que ela testa: DAG, vm_cpu_time, dados, perfis FX e faixas de bucket saem byte a byte idênticos
tests/test_fx_speed_rules.py Coerência de velocidade FX × VM nos parâmetros do gerador
tests/test_instance_validation.py task_time_cpu nunca zerado: validador (V4.11) + guarda no gerador
tests/test_scale_instance.py scale_instance.py só acrescenta recursos: preservação do workflow, configs novas não dominadas, catálogo estendido monotônico
tests/test_derive_tier.py medium e hard são a easy com outro painel: perfis declarados, Seções 2/3/5/6 idênticas (ou × 5), TM escala exatamente com o fator, derivação reproduzível byte a byte
tests/test_package_boundaries.py Direção das dependências entre shared/, synthetic/ e denethor/; nenhuma biblioteca importa de um cli/; a raiz do repo tem um dono só (shared/repo.py)
tests/test_extend_instance.py Regra da escala coerente: I/O e cold start escalam, o cold start fica fora da duração faturada, o custo é recalculado pela tarifa
tests/test_denethor_pipeline.py Pipeline denethor E1–E7, contra os dados reais do estudo
tests/test_denethor_generation.py O construtor de instâncias (E11) e a extração de fontes (E10), também contra os dados reais

As regras de definição ficam em src/synthetic/workflow_def_validation.py e cobrem:

  • Campos — TASKS, DATA, PATTERN e COMMENT obrigatórios; os campos de configuração (CPU_TIME, READ_TIME, WRITE_TIME, FX_SLOWDOWN, NUM_VMS, NUM_CONFIGS, NUM_BUCKET_RANGES, USE_INTEGER_TIME) valem tanto no DEFAULTS quanto por workflow, e precisam existir em pelo menos um dos dois níveis (F14); campos desconhecidos ou repetidos são erro; COMMENT precisa ser o último campo do cabeçalho (o loader absorve como comentário qualquer linha após ele) e estar em inglês — a regra checa ASCII e também procura palavras em português, já que um texto sem acentuação passaria pela checagem de ASCII.
  • Nome — WORKFLOW_ID no padrão <Prefixo>_<NNN>, com NNN = TASKS + DATA e único dentro de cada arquivo (o mesmo ID aparece em mais de um tier de propósito).
  • Tarefas — ids t0..tN-1 sequenciais e sem repetição, cada tarefa com ao menos uma entrada e uma saída, sem dados repetidos e sem ler e escrever o mesmo dado.
  • Dados — ids d0..dM-1 contíguos, cada dado produzido por no máximo uma tarefa.
  • Grafo — todas as dependências satisfeitas, ausência de ciclos e linhas de tarefa em ordem topológica.
  • Consistência — TASKS e DATA declarados iguais ao que o DAG realmente descreve.
  • Entre tiers — ultrahard contém todo o easy com os DAGs intactos e acrescenta topologias maiores; não pode existir instance_def_medium/_hard, que reabririam a geração independente que o desenho derivado aposentou.

As regras de velocidade FX × VM ficam em src/synthetic/fx_speed_rules.py. O gerador assume que a FX é sempre mais lenta que a VM mais lenta, mas o speedup por config é cumulativo: no pior sorteio ele chega a 1 + (NUM_CONFIGS - 1) × 0.8, e o piso do FX_SLOWDOWN precisa ficar acima disso. Daí o teto de configs por piso — 3 com piso 3.0, 9 com piso 8.0, 24 com piso 20.0. As duas definições atuais estão dentro do invariante, cada uma pagando pelas próprias configs (razão de pior caso entre a melhor config e a VM mais lenta); medium e hard herdam as 3 configs da easy:

tier configs piso do FX_SLOWDOWN pior speedup acumulado razão FX/VM no pior caso
easy (e os derivados medium, hard) 3 3.0 2.6 1.15
ultrahard 10 20.0 8.2 2.44

Os defeitos conhecidos estão marcados como xfail(strict=True) — o teste vira falha assim que forem corrigidos, sinalizando a remoção do marcador.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages