doe is a lightweight CLI for applying design of experiments methodology to software engineering.
The UX balances the needs of fast-paced experimentation with enough scientific rigor to make results easy to analyze and reproduce.
$ go install github.com/felixge/doe@latestProjects are directories containing one or more studies. Here is a study of different compression algorithms:
$ cd ./example/compression
$ ls
compression.study.yaml run.bash sample.pb sample.png sample.txt setup.bashThe heart is the compression.study.yaml file which defines a shared protocol and named presets with combinations of factors and settings:
setup: ./setup.bash
run: ./run.bash {algorithm} {effort} {file}
factors:
file: [sample.txt]
algorithm: [gzip, zstd]
effort: [default]
presets:
smoke: {}
full:
factors:
file: [sample.pb, sample.png, sample.txt]
effort: [min, default, max]
replicates: 6The full preset inherits the shared protocol and factors, overriding file and effort while keeping both algorithms.
It uses a setup.bash script to install dependencies and to emit a JSON object describing the environment:
$ ./setup.bash
{"os":"Darwin","arch":"arm64"}The run.bash script is invoked replicates times for each design point (unique combination of factors and settings) and emits a JSON object on the last line of stdout containing the outputs of the run:
$ ./run.bash zstd default sample.pb
{"level":3,"wall_seconds":0.00039,"cpu_seconds":0.00036,"peak_rss_bytes":2588672,"input_size_bytes":26400,"output_size_bytes":24243}Run an experiment by passing the study file and a preset name to doe experiment. The command prints the experiment ID on success. Use -c to remove previous results before running again.
$ doe experiment -f compression.study.yaml -p full
<experiment ID on stdout>doe saves one JSON object per run to results/runs.jsonl. You can analyze this data any way you like, e.g. using DuckDB's read_json function:
$ duckdb -c "SELECT algorithm, file, level, effort, round(avg(input_size_bytes/output_size_bytes), 2) as ratio, round(avg(input_size_bytes/cpu_seconds/1024/1024), 2) AS throughput, count(1) FROM read_json('./results/runs.jsonl') GROUP BY ALL ORDER BY ALL;"
โโโโโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโโโโ
โ algorithm โ file โ level โ effort โ ratio โ throughput โ count(1) โ
โ varchar โ varchar โ int64 โ varchar โ double โ double โ int64 โ
โโโโโโโโโโโโโผโโโโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโผโโโโโโโโโผโโโโโโโโโโโโโผโโโโโโโโโโโค
โ gzip โ sample.pb โ 1 โ min โ 1.08 โ 70.94 โ 6 โ
โ gzip โ sample.pb โ 6 โ default โ 1.09 โ 39.41 โ 6 โ
โ gzip โ sample.pb โ 9 โ max โ 1.08 โ 23.65 โ 6 โ
โ gzip โ sample.png โ 1 โ min โ 1.0 โ 83.0 โ 6 โ
โ gzip โ sample.png โ 6 โ default โ 1.0 โ 46.11 โ 6 โ
โ gzip โ sample.png โ 9 โ max โ 1.0 โ 27.67 โ 6 โ
โ gzip โ sample.txt โ 1 โ min โ 10.12 โ 69.33 โ 6 โ
โ gzip โ sample.txt โ 6 โ default โ 10.76 โ 38.52 โ 6 โ
โ gzip โ sample.txt โ 9 โ max โ 11.04 โ 23.11 โ 6 โ
โ zstd โ sample.pb โ 1 โ min โ 1.09 โ 70.94 โ 6 โ
โ zstd โ sample.pb โ 3 โ default โ 1.09 โ 39.41 โ 6 โ
โ zstd โ sample.pb โ 22 โ max โ 1.11 โ 8.87 โ 6 โ
โ zstd โ sample.png โ 1 โ min โ 1.0 โ 83.0 โ 6 โ
โ zstd โ sample.png โ 3 โ default โ 1.0 โ 46.11 โ 6 โ
โ zstd โ sample.png โ 22 โ max โ 1.0 โ 10.38 โ 6 โ
โ zstd โ sample.txt โ 1 โ min โ 15.61 โ 69.33 โ 6 โ
โ zstd โ sample.txt โ 3 โ default โ 15.64 โ 38.52 โ 6 โ
โ zstd โ sample.txt โ 22 โ max โ 16.73 โ 8.67 โ 6 โ
โโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโดโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโ| term | description |
|---|---|
| experiment | A single doe experiment invocation. |
| factor | A factor that influences the outcome of the experiment. |
| setting | A value for a factor. |
| matrix | A mapping of factor:settings where settings can either be a single setting or a sequence of values that is used to form a cartesian product with the other factor=settings pairs in the matrix. |
| input | A factor=setting pair passed to a run. |
| design point | A combination of factor=setting pairs passed to a run. |
| response | A name of a measured outcome of the experiment. |
| measurement | A value for a response. |
| output | A response=measurement pair. |
| outcome | The outputs of a run. |
| run | A design point carried out to produce measurements. |
