///|
fn impact_workload(
count : Int32,
shape : String,
) -> (@trace.DatasetIndex, @trace.DatasetIndex) raise {
let files = Array::makei(count, i => {
let subject = (i / 2 + 1).to_string()
"sub-" +
subject +
"/func/sub-" +
subject +
"_task-rest_run-" +
(i % 2 + 1).to_string() +
"_bold.nii"
})
let root = "{\"RT\":2.0,\"opaque\":[null,-0,9007199254740993,1e999]}"
let base = @trace.DatasetIndex::from_manifest(files, [
@trace.SidecarInput::new("bold.json", root),
@trace.SidecarInput::new("sub-1/sub-1_bold.json", "{\"RT\":3.0}"),
@trace.SidecarInput::new("T1w.json", "{\"RT\":1}"),
])
let sources = [
@trace.SidecarInput::new(
"bold.json",
if shape == "root" {
root.replace_all(old="2.0", new="4.0")
} else {
root
},
),
]
if shape != "remove" {
sources.push(
@trace.SidecarInput::new(
"sub-1/sub-1_bold.json",
if shape == "local" {
"{\"RT\":4.0}"
} else {
"{\"RT\":3.0}"
},
),
)
}
sources.push(
@trace.SidecarInput::new(
"T1w.json",
if shape == "unmatched" {
"{\"RT\":9}"
} else {
"{\"RT\":1}"
},
),
)
if shape == "add" {
sources.push(@trace.SidecarInput::new("sub-2/sub-2_bold.json", "{}"))
}
if shape == "ambiguity" {
sources.push(@trace.SidecarInput::new("task-rest_bold.json", "{}"))
}
let paths = if shape == "inventory" {
files[:files.length() - 1].to_owned() +
["sub-new/func/sub-new_task-rest_bold.nii"]
} else {
files
}
(base, @trace.DatasetIndex::from_manifest(paths, sources))
}
///|
#cfg(target="js")
fn impact_args(raw : Array[String]) -> Array[String] {
if raw.length() >= 2 {
raw[1:].to_owned()
} else {
raw
}
}
///|
#cfg(not(target="js"))
fn impact_args(raw : Array[String]) -> Array[String] {
raw
}
///|
fn impact_argument_error(message : String) -> Unit raise {
println(
Json::object({
"code": Json::string("invalid_impact_benchmark_arguments"),
"message": Json::string(message),
}).stringify(),
)
fail(message)
}
///|
fn impact_execute(
phase : String,
before : @trace.DatasetIndex,
after : @trace.DatasetIndex,
graph : @trace.DependencyGraph?,
) -> Int32 raise {
match phase {
"full" => {
let report = before.compare(after)
report.changed_count() + report.error_count()
}
"cold" => {
let report = before.dependency_graph().advance(after).report()
report.changed_count() + report.error_count()
}
"warm" => {
let report = graph.unwrap().advance(after).report()
report.changed_count() + report.error_count()
}
"graph" => before.dependency_graph().audit().entries().length()
_ => abort("validated phase")
}
}
///|
fn main raise {
let args = impact_args(@env.args())
guard args.length() == 5 else {
impact_argument_error(
"Usage: impact-benchmark full|cold|warm|graph|verify local|root|add|remove|unmatched|noop|inventory|ambiguity SCANS SAMPLES",
)
return
}
let phase = args[1]
let shape = args[2]
guard ["full", "cold", "warm", "graph", "verify"].contains(phase) &&
[
"local", "root", "add", "remove", "unmatched", "noop", "inventory", "ambiguity",
].contains(shape) else {
impact_argument_error("Unsupported phase or shape")
return
}
let count = @string.parse_int(args[3]) catch {
_ => {
impact_argument_error("SCANS must be an integer")
0
}
}
let samples = @string.parse_int(args[4]) catch {
_ => {
impact_argument_error("SAMPLES must be an integer")
0
}
}
guard count >= 4 && count <= 5000 && samples >= 3 && samples <= 31 else {
impact_argument_error("SCANS must be 4..5000; SAMPLES must be 3..31")
return
}
let (before, after) = impact_workload(count, shape)
if phase == "verify" {
let result = before.dependency_graph().advance(after)
result.verify_full()
println(result.to_json())
return
}
// Only warm holds a prepared graph. Full/cold process RSS does not include
// an untimed graph or full verification report from another phase.
let graph = if phase == "warm" {
Some(before.dependency_graph())
} else {
None
}
ignore(impact_execute(phase, before, after, graph))
let elapsed : Array[Double] = []
let mut checksum = 0L
for _ in 0.. Json::number(v))),
"median_us": Json::number(sorted[sorted.length() / 2]),
"checksum": Json::string(checksum.to_string()),
}).stringify(),
)
}