libthx 0.3.1__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {libthx-0.3.1 → libthx-0.4.0}/PKG-INFO +1 -1
- {libthx-0.3.1 → libthx-0.4.0}/libthx.egg-info/PKG-INFO +1 -1
- {libthx-0.3.1 → libthx-0.4.0}/libthx.egg-info/SOURCES.txt +2 -0
- {libthx-0.3.1 → libthx-0.4.0}/pyproject.toml +1 -1
- libthx-0.4.0/tests/test_cleanup.py +145 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_bootstrap.py +32 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_store.py +7 -4
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/app.py +3 -1
- libthx-0.4.0/theseus/cli/cleanup.py +58 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/bootstrap.sh +15 -1
- {libthx-0.3.1 → libthx-0.4.0}/theseus/store.py +35 -2
- {libthx-0.3.1 → libthx-0.4.0}/LICENSE +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/README.md +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/libthx.egg-info/dependency_links.txt +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/libthx.egg-info/entry_points.txt +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/libthx.egg-info/requires.txt +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/libthx.egg-info/top_level.txt +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/setup.cfg +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_addition_dataset.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_analysis.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_bundle.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_checkpoint.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_browser.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_configure.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_execute.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_import.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_logs.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_run.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_cli_verbosity.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_combobulator.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_comet_logging.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_contrastive_roundtrip.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_data.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_datasets.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_eval_padding.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_bootstrap_generate.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_dispatch.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_provider_utils.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_run.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_solve.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_execute_volcano.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_flywheel_determinism.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_flywheel_reads.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_gpu_availability.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_hardware_discovery.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_hardware_dispatch.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_inference.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_job.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_kv_cache.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_lora.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_mfu.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_model_flops.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_module_debug.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_optimizers.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_optional_dependencies.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_profiler.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_quick.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_registries.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_rollout_chat_tokenization.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_rollout_eos.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_scalar_metadata.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_schedules.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_sharding.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_stack_e2e.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_store_delta.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_trainer_lifecycle.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/tests/test_unembedding_dtype.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/analysis/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/analysis/attention.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/analysis/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/analysis/plots.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/analysis/trace.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/axis.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/chip.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/dag.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/hardware.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/job.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/base/topology.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/checkpoint.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/configurator/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/configurator/fields.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/configurator/steps.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/configure.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/actions.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/age.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/cache.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/chart.js +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/chart.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/data.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/driver.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/fields.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/keyboard.js +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/location.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/log_data.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/log_list.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/log_view.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/navigation.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/plot.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/plot_controls.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/plot_math.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/plotly_options.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/run.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/state.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/status.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/terminal.css +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/timeline.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/tree.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/tree_row.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/view.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/views.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/interface/walk.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/jobs.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/run.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/submit.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/cli/ui.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/config.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/addition.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/alpaca.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/bbq.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/ccaligned.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/cfq.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/clutrr.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/dataset.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/fever.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/fineweb.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/fineweb_edu.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/flan.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/harmfulqa.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/longbench.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/longhealth.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/mmlu.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/mnli.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/mtob.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/openr1_math.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/pes2o.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/pg19.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/pile.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/pile_detoxify.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/pile_injected.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/qqp.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/siqa.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/squad.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/sst2.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/datasets/winogrande.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/tokenize.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/data/tokenizer.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/addition.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/alpaca.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/arc_challenge.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/arithmetic.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/bbh.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/bbq.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/blimp.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/ccaligned.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/cfq.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/clutrr.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/fever.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/gsm8k.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/hellaswag.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/longbench.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/longhealth.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/math.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/mmlu.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/mnli.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/mtob.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/perplexity_evals.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/pes2o.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/pg19.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/pg19_lengthgen.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/pile.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/pile_injected.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/qqp.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/siqa.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/squad.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/sst2.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/tinystories.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/evaluation/datasets/winogrande.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/bootstrap.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/bundle.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/combobulator.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/config.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/dispatch.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/slurm/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/slurm/availability.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/slurm/provider.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/ssh.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/utils.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/volcano/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/volcano/config.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/volcano/manifest.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/provider/volcano/transport.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/run/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/run/__main__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/run/lineage.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/run/run.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/execute/solve.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/benchmark.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/data/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/data/blockwise.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/data/streaming.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/forking/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/forking/pretrain.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/models/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/models/gpt.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/models/gpt_neox.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/models/llama.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/models/qwen.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/experiments/models/qwen_3_5.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/inference/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/inference/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/job.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/activations/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/activations/swiglu.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/attention/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/attention/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/attention/forking.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/attention/gated_delta.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/attention/grouped.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/attention/rope.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/axes.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/block.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/forking.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/gpt_neox.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/llama.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/qwen.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/block/qwen_3_5.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/debug.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/layers/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/layers/layernorm.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/layers/mlp.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/layers/mrope.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/layers/rmsnorm.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/layers/rope.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/masks.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/gpt_neox.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/llama.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/marin.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/qwen.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/qwen_3_5.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/contrib/qwen_3_5_moe.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/models/thoughtbubbles.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/module.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/moe/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/moe/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/moe/shared.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/model/utils.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/quick.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/registry.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/backbone.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/contrastive.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/contrastive.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/dataset.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/io.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/padded.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/pmd.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/strategy.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/flywheel/stream.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/grpo.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/kl_divergence.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/lora.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/optimizers/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/optimizers/adamw.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/optimizers/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/optimizers/muon.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/ppo.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/profiler.html +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/profiler.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/schedules/__init__.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/schedules/base.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/schedules/cosine_rewarm.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/schedules/wsd.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/schedules/wsds.py +0 -0
- {libthx-0.3.1 → libthx-0.4.0}/theseus/training/utils.py +0 -0
|
@@ -12,6 +12,7 @@ tests/test_analysis.py
|
|
|
12
12
|
tests/test_base.py
|
|
13
13
|
tests/test_bundle.py
|
|
14
14
|
tests/test_checkpoint.py
|
|
15
|
+
tests/test_cleanup.py
|
|
15
16
|
tests/test_cli.py
|
|
16
17
|
tests/test_cli_browser.py
|
|
17
18
|
tests/test_cli_configure.py
|
|
@@ -81,6 +82,7 @@ theseus/base/job.py
|
|
|
81
82
|
theseus/base/topology.py
|
|
82
83
|
theseus/cli/__init__.py
|
|
83
84
|
theseus/cli/app.py
|
|
85
|
+
theseus/cli/cleanup.py
|
|
84
86
|
theseus/cli/configure.py
|
|
85
87
|
theseus/cli/jobs.py
|
|
86
88
|
theseus/cli/run.py
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Value-table maintenance preserves committed rows and reader snapshots."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import importlib
|
|
5
|
+
import shutil
|
|
6
|
+
from time import time
|
|
7
|
+
from unittest.mock import Mock
|
|
8
|
+
|
|
9
|
+
import pyarrow as pa
|
|
10
|
+
import pytest
|
|
11
|
+
from deltalake import DeltaTable, write_deltalake
|
|
12
|
+
from deltalake.exceptions import CommitFailedError
|
|
13
|
+
from deltalake.table import TableOptimizer
|
|
14
|
+
from typer.testing import CliRunner
|
|
15
|
+
|
|
16
|
+
from theseus.cli.app import app
|
|
17
|
+
from theseus.store import ObjectStore
|
|
18
|
+
import theseus.store as store_module
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def seed(values):
|
|
22
|
+
for value in range(3):
|
|
23
|
+
write_deltalake(values, pa.table({"value": [value]}), mode="append")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.parametrize("expire", [False, True])
|
|
27
|
+
def test_cleanup_compacts_and_vacuums_with_selected_retention(tmp_path, monkeypatch, expire):
|
|
28
|
+
values = tmp_path / "objects" / "values"
|
|
29
|
+
seed(values)
|
|
30
|
+
snapshot = DeltaTable(values)
|
|
31
|
+
old_files = snapshot.file_uris()
|
|
32
|
+
expired = values / "orphan.parquet"
|
|
33
|
+
shutil.copyfile(old_files[0], expired)
|
|
34
|
+
old_time = time() - 8 * 24 * 3600
|
|
35
|
+
os.utime(expired, (old_time, old_time))
|
|
36
|
+
recent = values / "recent-orphan.parquet"
|
|
37
|
+
shutil.copyfile(old_files[0], recent)
|
|
38
|
+
cleanup_module = importlib.import_module("theseus.cli.cleanup")
|
|
39
|
+
delay = Mock()
|
|
40
|
+
monkeypatch.setattr(cleanup_module, "sleep", delay)
|
|
41
|
+
|
|
42
|
+
result = CliRunner().invoke(app, ["cleanup", str(tmp_path), *(["--expire"] if expire else [])])
|
|
43
|
+
|
|
44
|
+
assert result.exit_code == 0, result.output
|
|
45
|
+
assert "Value table cleanup" in result.output
|
|
46
|
+
assert "CLEANUP | compacting" in result.output
|
|
47
|
+
assert "CLEANUP | vacuuming" in result.output
|
|
48
|
+
assert not expired.exists()
|
|
49
|
+
assert recent.exists() is not expire
|
|
50
|
+
assert len(DeltaTable(values).file_uris()) == 1
|
|
51
|
+
if expire:
|
|
52
|
+
delay.assert_called_once_with(10)
|
|
53
|
+
assert "ALL ACTIVE WRITERS WILL CRASH IN 10 SECONDS, C-c ONCE TO CANCEL" in result.output
|
|
54
|
+
assert all(not os.path.exists(path) for path in old_files)
|
|
55
|
+
else:
|
|
56
|
+
delay.assert_not_called()
|
|
57
|
+
# Default retention preserves readers bound before compaction.
|
|
58
|
+
assert sorted(snapshot.to_pyarrow_table()["value"].to_pylist()) == [0, 1, 2]
|
|
59
|
+
assert sorted(DeltaTable(values).to_pyarrow_table()["value"].to_pylist()) == [0, 1, 2]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_cleanup_expire_can_be_cancelled_before_mutation(tmp_path, monkeypatch):
|
|
63
|
+
cleanup_module = importlib.import_module("theseus.cli.cleanup")
|
|
64
|
+
delay = Mock(side_effect=KeyboardInterrupt)
|
|
65
|
+
compact = Mock()
|
|
66
|
+
vacuum = Mock()
|
|
67
|
+
monkeypatch.setattr(cleanup_module, "sleep", delay)
|
|
68
|
+
monkeypatch.setattr(ObjectStore, "compact", compact)
|
|
69
|
+
monkeypatch.setattr(DeltaTable, "vacuum", vacuum)
|
|
70
|
+
|
|
71
|
+
result = CliRunner().invoke(app, ["cleanup", str(tmp_path), "--expire"])
|
|
72
|
+
|
|
73
|
+
assert result.exit_code != 0
|
|
74
|
+
assert "ALL ACTIVE WRITERS WILL CRASH IN 10 SECONDS, C-c ONCE TO CANCEL" in result.output
|
|
75
|
+
delay.assert_called_once_with(10)
|
|
76
|
+
compact.assert_not_called()
|
|
77
|
+
vacuum.assert_not_called()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_cleanup_missing_table_is_noop(tmp_path):
|
|
81
|
+
result = CliRunner().invoke(app, ["cleanup", str(tmp_path)])
|
|
82
|
+
assert result.exit_code == 0, result.output
|
|
83
|
+
assert "no Delta value table" in result.output
|
|
84
|
+
assert not (tmp_path / "objects").exists()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@pytest.mark.parametrize("schema_change", [False, True])
|
|
88
|
+
def test_compaction_preserves_concurrent_append_and_retries_schema_change(
|
|
89
|
+
tmp_path, monkeypatch, schema_change,
|
|
90
|
+
):
|
|
91
|
+
values = tmp_path / "objects" / "values"
|
|
92
|
+
seed(values)
|
|
93
|
+
original = TableOptimizer.compact
|
|
94
|
+
calls = 0
|
|
95
|
+
|
|
96
|
+
def racing_compact(optimizer):
|
|
97
|
+
nonlocal calls
|
|
98
|
+
calls += 1
|
|
99
|
+
if calls == 1:
|
|
100
|
+
data = {"value": [3]}
|
|
101
|
+
if schema_change:
|
|
102
|
+
data["new_column"] = [4]
|
|
103
|
+
write_deltalake(values, pa.table(data), mode="append", schema_mode="merge")
|
|
104
|
+
return original(optimizer)
|
|
105
|
+
|
|
106
|
+
monkeypatch.setattr(TableOptimizer, "compact", racing_compact)
|
|
107
|
+
monkeypatch.setattr(store_module, "_DELTA_IO_RETRY_SECONDS", 0)
|
|
108
|
+
ObjectStore.compact(tmp_path)
|
|
109
|
+
|
|
110
|
+
assert calls == (2 if schema_change else 1)
|
|
111
|
+
rows = DeltaTable(values).to_pyarrow_table()
|
|
112
|
+
assert sorted(rows["value"].to_pylist()) == [0, 1, 2, 3]
|
|
113
|
+
if schema_change:
|
|
114
|
+
assert rows.filter(pa.compute.equal(rows["value"], 3))["new_column"].to_pylist() == [4]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_close_logs_compaction_failure_after_flushing(tmp_path, monkeypatch):
|
|
118
|
+
from theseus.base import Node
|
|
119
|
+
|
|
120
|
+
store = ObjectStore.local(tmp_path)
|
|
121
|
+
store.value(Node(name="test"), {"value": 1})
|
|
122
|
+
warning = Mock()
|
|
123
|
+
monkeypatch.setattr(store_module.logger, "warning", warning)
|
|
124
|
+
monkeypatch.setattr(
|
|
125
|
+
ObjectStore, "compact", Mock(side_effect=CommitFailedError("conflict")),
|
|
126
|
+
)
|
|
127
|
+
store.close()
|
|
128
|
+
warning.assert_called_once()
|
|
129
|
+
assert store.query().select() == [{"value": 1}]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_cleanup_stops_before_vacuum_after_repeated_conflicts(tmp_path, monkeypatch):
|
|
133
|
+
seed(tmp_path / "objects" / "values")
|
|
134
|
+
compact = Mock(side_effect=CommitFailedError("concurrent schema change"))
|
|
135
|
+
vacuum = Mock()
|
|
136
|
+
monkeypatch.setattr(TableOptimizer, "compact", compact)
|
|
137
|
+
monkeypatch.setattr(DeltaTable, "vacuum", vacuum)
|
|
138
|
+
monkeypatch.setattr(store_module, "_DELTA_IO_RETRY_SECONDS", 0)
|
|
139
|
+
|
|
140
|
+
result = CliRunner().invoke(app, ["cleanup", str(tmp_path)])
|
|
141
|
+
|
|
142
|
+
assert result.exit_code == 1
|
|
143
|
+
assert "concurrent schema change" in result.output
|
|
144
|
+
assert compact.call_count == store_module._DELTA_IO_ATTEMPTS
|
|
145
|
+
vacuum.assert_not_called()
|
|
@@ -603,6 +603,38 @@ def test_bootstrap_autobatch_isolates_probes_and_overrides_real_run(
|
|
|
603
603
|
assert "probing training.per_device_batch_size=512" in contents
|
|
604
604
|
|
|
605
605
|
|
|
606
|
+
def test_bootstrap_autobatch_waits_for_delayed_log_writer(
|
|
607
|
+
render_bootstrap: Callable[[int], tuple[Path, Path, Path, Path]],
|
|
608
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
609
|
+
tmp_path: Path,
|
|
610
|
+
) -> None:
|
|
611
|
+
import shlex
|
|
612
|
+
|
|
613
|
+
script, dispatch, calls, logs = render_bootstrap(-1)
|
|
614
|
+
monkeypatch.setenv("THESEUS_DISPATCH_PROBE_COOLDOWN_SECONDS", "0")
|
|
615
|
+
real_tee = shutil.which("tee")
|
|
616
|
+
assert real_tee is not None
|
|
617
|
+
delayed_tee = tmp_path / "bin" / "tee"
|
|
618
|
+
delayed_tee.write_text(
|
|
619
|
+
'#!/usr/bin/env bash\n'
|
|
620
|
+
'if [[ "$1" == */autobatch-*.log ]]; then sleep 2; fi\n'
|
|
621
|
+
f'exec {shlex.quote(real_tee)} "$@"\n'
|
|
622
|
+
)
|
|
623
|
+
delayed_tee.chmod(0o755)
|
|
624
|
+
|
|
625
|
+
result = subprocess.run(
|
|
626
|
+
["bash", script, dispatch], text=True, capture_output=True, timeout=30,
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
assert result.returncode == 0, result.stdout + result.stderr
|
|
630
|
+
output = result.stdout + result.stderr
|
|
631
|
+
assert "No such file or directory" not in output
|
|
632
|
+
run_calls = [line for line in calls.read_text().splitlines() if line.startswith("run")]
|
|
633
|
+
assert len(run_calls) == 3
|
|
634
|
+
assert "dispatch.json training.per_device_batch_size=512" in run_calls[-1]
|
|
635
|
+
assert "RESOURCE_EXHAUSTED" in (logs / "project-group-name-abc123.0.log").read_text()
|
|
636
|
+
|
|
637
|
+
|
|
606
638
|
def test_bootstrap_autobatch_skips_clamped_duplicate_candidates(
|
|
607
639
|
render_bootstrap: Callable[[int], tuple[Path, Path, Path, Path]],
|
|
608
640
|
monkeypatch: pytest.MonkeyPatch,
|
|
@@ -203,7 +203,7 @@ def test_value_batch_flush_and_lifecycle(
|
|
|
203
203
|
assert store.thread is not None and store.thread is not first_thread
|
|
204
204
|
store.value(node, {"restarted": 1})
|
|
205
205
|
store.close()
|
|
206
|
-
assert len(DeltaTable(store.values()).file_uris()) ==
|
|
206
|
+
assert len(DeltaTable(store.values()).file_uris()) == 1
|
|
207
207
|
assert store.query().node(node).select() == [{"loss": 2.0, "restarted": 1}]
|
|
208
208
|
|
|
209
209
|
|
|
@@ -222,7 +222,7 @@ def test_value_time_flush(
|
|
|
222
222
|
assert store.query().node(node).select() == [{"value": 1}]
|
|
223
223
|
|
|
224
224
|
|
|
225
|
-
def
|
|
225
|
+
def test_close_compacts_without_vacuuming_committed_parts(
|
|
226
226
|
hardware: HardwareResult, monkeypatch: pytest.MonkeyPatch
|
|
227
227
|
) -> None:
|
|
228
228
|
monkeypatch.setattr(store_module, "_VALUE_BATCH_SIZE", 1)
|
|
@@ -235,8 +235,11 @@ def test_close_does_not_rewrite_or_remove_committed_parts(
|
|
|
235
235
|
before = {part: part.read_bytes() for part in parts}
|
|
236
236
|
version = DeltaTable(store.values()).version()
|
|
237
237
|
store.close()
|
|
238
|
+
compacted = DeltaTable(store.values())
|
|
239
|
+
assert len(compacted.file_uris()) == 1
|
|
240
|
+
assert compacted.version() > version
|
|
238
241
|
store.close()
|
|
239
|
-
assert DeltaTable(store.values()).version() == version
|
|
242
|
+
assert DeltaTable(store.values()).version() == compacted.version()
|
|
240
243
|
assert {part: part.read_bytes() for part in parts} == before
|
|
241
244
|
assert store.query().all() == [
|
|
242
245
|
Node(name="train", nonce="abcdef", seq=0),
|
|
@@ -304,7 +307,7 @@ def test_parallel_processes_publish_without_collisions(
|
|
|
304
307
|
|
|
305
308
|
second.close()
|
|
306
309
|
parts = DeltaTable(first.values()).file_uris()
|
|
307
|
-
assert len(parts) ==
|
|
310
|
+
assert len(parts) == 1
|
|
308
311
|
assert {row["_x_prc_idx"] for row in read_rows(first)} == {0, 1}
|
|
309
312
|
|
|
310
313
|
process_index = 0
|
|
@@ -14,6 +14,7 @@ from theseus.cli.configure import configure
|
|
|
14
14
|
from theseus.cli.submit import submit
|
|
15
15
|
from theseus.cli.run import run
|
|
16
16
|
from theseus.cli.jobs import jobs
|
|
17
|
+
from theseus.cli.cleanup import cleanup
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
app = typer.Typer(name="theseus", no_args_is_help=True)
|
|
@@ -22,6 +23,7 @@ app.command()(configure)
|
|
|
22
23
|
app.command()(submit)
|
|
23
24
|
app.command()(run)
|
|
24
25
|
app.command()(jobs)
|
|
26
|
+
app.command()(cleanup)
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
@app.callback()
|
|
@@ -42,7 +44,7 @@ def main(
|
|
|
42
44
|
"""Run and inspect Theseus workloads."""
|
|
43
45
|
logger.remove()
|
|
44
46
|
logger.add(
|
|
45
|
-
|
|
47
|
+
sys.stderr,
|
|
46
48
|
level="DEBUG" if verbose else "INFO",
|
|
47
49
|
format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <level>{message}</level>",
|
|
48
50
|
backtrace=False,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Compact and vacuum a Theseus root's Delta value table."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from time import sleep
|
|
5
|
+
|
|
6
|
+
from deltalake import DeltaTable
|
|
7
|
+
from loguru import logger
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from theseus.store import ObjectStore
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def cleanup(
|
|
16
|
+
root: Path = typer.Argument(..., exists=True, file_okay=False),
|
|
17
|
+
expire: bool = typer.Option(
|
|
18
|
+
False,
|
|
19
|
+
"--expire",
|
|
20
|
+
help="Immediately delete obsolete files. Can break active readers and writers; waits 10 seconds before starting.",
|
|
21
|
+
),
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Compact ROOT/objects/values and vacuum; --expire bypasses retention."""
|
|
24
|
+
values = root / "objects" / "values"
|
|
25
|
+
if expire:
|
|
26
|
+
logger.warning(
|
|
27
|
+
"ALL ACTIVE WRITERS WILL CRASH IN 10 SECONDS, C-c ONCE TO CANCEL"
|
|
28
|
+
)
|
|
29
|
+
logger.info(
|
|
30
|
+
"--expire deletes obsolete and uncommitted files without retention; "
|
|
31
|
+
"active readers and writers may fail."
|
|
32
|
+
)
|
|
33
|
+
sleep(10)
|
|
34
|
+
try:
|
|
35
|
+
logger.info("CLEANUP | compacting {}", values)
|
|
36
|
+
metrics = ObjectStore.compact(root)
|
|
37
|
+
if metrics is None:
|
|
38
|
+
logger.info("CLEANUP | no Delta value table at {}", values)
|
|
39
|
+
return
|
|
40
|
+
logger.info(
|
|
41
|
+
"CLEANUP | vacuuming {} with {}",
|
|
42
|
+
values,
|
|
43
|
+
"zero retention" if expire else "table retention",
|
|
44
|
+
)
|
|
45
|
+
removed = DeltaTable(values).vacuum(
|
|
46
|
+
dry_run=False,
|
|
47
|
+
full=True,
|
|
48
|
+
retention_hours=0 if expire else None,
|
|
49
|
+
enforce_retention_duration=not expire,
|
|
50
|
+
)
|
|
51
|
+
summary = Table("Statistic", "Files", title="Value table cleanup")
|
|
52
|
+
summary.add_row("Compacted inputs", str(metrics["numFilesRemoved"]))
|
|
53
|
+
summary.add_row("Compacted outputs", str(metrics["numFilesAdded"]))
|
|
54
|
+
summary.add_row("Expired files deleted", str(len(removed)))
|
|
55
|
+
Console().print(summary)
|
|
56
|
+
except Exception as error:
|
|
57
|
+
logger.error("CLEANUP | {}", error)
|
|
58
|
+
raise typer.Exit(1) from error
|
|
@@ -552,6 +552,13 @@ if grep -Eq \
|
|
|
552
552
|
"${NONCE}-${probe_id}-autobatch-${candidate}"
|
|
553
553
|
|
|
554
554
|
echo "[bootstrap] probing training.per_device_batch_size=$candidate"
|
|
555
|
+
# Create the buffer before polling, and keep the writer PID so a
|
|
556
|
+
# fast-failing probe cannot be classified before its output drains.
|
|
557
|
+
: > "$probe_log"
|
|
558
|
+
probe_pipe="$BOOTSTRAP_STAGING/autobatch-${candidate}.fifo"
|
|
559
|
+
mkfifo "$probe_pipe"
|
|
560
|
+
tee "$probe_log" < "$probe_pipe" &
|
|
561
|
+
probe_log_sink_pid=$!
|
|
555
562
|
set +e
|
|
556
563
|
# The probe tee keeps a classification buffer; its stdout still
|
|
557
564
|
# flows through the outer tee into the durable cluster log.
|
|
@@ -560,7 +567,7 @@ if grep -Eq \
|
|
|
560
567
|
uv run --no-sync python -m theseus.execute.run "$probe_spec" \
|
|
561
568
|
"training.per_device_batch_size=$candidate" \
|
|
562
569
|
"${probe_overrides[@]}" \
|
|
563
|
-
>
|
|
570
|
+
> "$probe_pipe" 2>&1 &
|
|
564
571
|
MAIN_CHILD_PID=$!
|
|
565
572
|
probe_completed=0
|
|
566
573
|
while kill -0 "$MAIN_CHILD_PID" 2>/dev/null; do
|
|
@@ -574,8 +581,15 @@ if grep -Eq \
|
|
|
574
581
|
wait "$MAIN_CHILD_PID"
|
|
575
582
|
probe_exit_code=$?
|
|
576
583
|
MAIN_CHILD_PID=""
|
|
584
|
+
wait "$probe_log_sink_pid"
|
|
585
|
+
probe_log_exit_code=$?
|
|
577
586
|
set -e
|
|
587
|
+
rm -f "$probe_pipe"
|
|
578
588
|
|
|
589
|
+
if [[ "$probe_log_exit_code" -ne 0 ]]; then
|
|
590
|
+
echo "[bootstrap] ERROR: autobatch log sink failed with exit $probe_log_exit_code"
|
|
591
|
+
exit "$probe_log_exit_code"
|
|
592
|
+
fi
|
|
579
593
|
if [[ "$probe_exit_code" -eq 0 || "$probe_completed" -eq 1 ]]; then
|
|
580
594
|
batch_size_override="training.per_device_batch_size=$candidate"
|
|
581
595
|
break
|
|
@@ -25,6 +25,7 @@ from typing import (
|
|
|
25
25
|
Mapping,
|
|
26
26
|
Self,
|
|
27
27
|
Sequence,
|
|
28
|
+
TypeVar,
|
|
28
29
|
cast,
|
|
29
30
|
overload,
|
|
30
31
|
)
|
|
@@ -37,6 +38,7 @@ import pyarrow as pa
|
|
|
37
38
|
from deltalake import DeltaTable, write_deltalake
|
|
38
39
|
from deltalake.exceptions import CommitFailedError, TableNotFoundError
|
|
39
40
|
from flax import serialization
|
|
41
|
+
from loguru import logger
|
|
40
42
|
|
|
41
43
|
from theseus.base import JobSpec, Node, PyTree
|
|
42
44
|
from theseus.base.hardware import HardwareResult, local as local_hardware
|
|
@@ -46,6 +48,7 @@ _VALUE_BATCH_SIZE = 4096
|
|
|
46
48
|
_VALUE_FLUSH_SECONDS = 30.0
|
|
47
49
|
_DELTA_IO_ATTEMPTS = 3
|
|
48
50
|
_DELTA_IO_RETRY_SECONDS = 0.25
|
|
51
|
+
_IOResult = TypeVar("_IOResult")
|
|
49
52
|
_chdb_query = cast(Callable[..., pa.Table], chdb.query)
|
|
50
53
|
_METADATA_TYPES: dict[str, pa.DataType] = {
|
|
51
54
|
"_x_blob": pa.string(),
|
|
@@ -153,7 +156,7 @@ class ObjectReader:
|
|
|
153
156
|
)
|
|
154
157
|
|
|
155
158
|
@staticmethod
|
|
156
|
-
def _retry_io(operation: Callable[[],
|
|
159
|
+
def _retry_io(operation: Callable[[], _IOResult]) -> _IOResult:
|
|
157
160
|
for attempt in range(_DELTA_IO_ATTEMPTS):
|
|
158
161
|
try:
|
|
159
162
|
return operation()
|
|
@@ -248,10 +251,34 @@ class ObjectStore(ObjectReader):
|
|
|
248
251
|
"""
|
|
249
252
|
return cls(local_hardware(str(root_dir), "-"))
|
|
250
253
|
|
|
254
|
+
@classmethod
|
|
255
|
+
def compact(cls, root_dir: str | Path) -> dict[str, Any] | None:
|
|
256
|
+
"""Compact ROOT/objects/values without starting a writer or vacuuming.
|
|
257
|
+
|
|
258
|
+
Reload the table after concurrent commit conflicts. An absent table
|
|
259
|
+
is a no-op; obsolete files remain available to existing readers.
|
|
260
|
+
"""
|
|
261
|
+
values = Path(root_dir) / "objects" / "values"
|
|
262
|
+
for attempt in range(_DELTA_IO_ATTEMPTS):
|
|
263
|
+
try:
|
|
264
|
+
return cast(
|
|
265
|
+
dict[str, Any],
|
|
266
|
+
cls._retry_io(lambda: DeltaTable(values).optimize.compact()),
|
|
267
|
+
)
|
|
268
|
+
except TableNotFoundError:
|
|
269
|
+
return None
|
|
270
|
+
except CommitFailedError:
|
|
271
|
+
if attempt + 1 == _DELTA_IO_ATTEMPTS:
|
|
272
|
+
raise
|
|
273
|
+
sleep(_DELTA_IO_RETRY_SECONDS * 2**attempt)
|
|
274
|
+
raise AssertionError("unreachable")
|
|
275
|
+
|
|
251
276
|
def close(self) -> None:
|
|
252
|
-
"""Commit queued values
|
|
277
|
+
"""Commit queued values, stop the writer, and compact the value table.
|
|
253
278
|
|
|
254
279
|
A successfully closed store may be restarted with :meth:`start`.
|
|
280
|
+
Compaction failures are logged without failing committed writes.
|
|
281
|
+
Closing never vacuums files needed by existing readers.
|
|
255
282
|
|
|
256
283
|
Raises:
|
|
257
284
|
RuntimeError: If the background writer failed while producing a
|
|
@@ -265,6 +292,12 @@ class ObjectStore(ObjectReader):
|
|
|
265
292
|
self.thread = None
|
|
266
293
|
|
|
267
294
|
self._raise_writer_error()
|
|
295
|
+
try:
|
|
296
|
+
self.compact(self.root().parent)
|
|
297
|
+
except Exception as error:
|
|
298
|
+
logger.warning(
|
|
299
|
+
"STORE | value compaction failed for {}: {}", self.values(), error
|
|
300
|
+
)
|
|
268
301
|
|
|
269
302
|
#### public writes ####
|
|
270
303
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|