Files
core/test/rust/performance/job/measure.rs
T
2026-11-03 03:32:07 +00:00

268 lines
8.2 KiB
Rust

// 入队计时含具体编码和外层提交;执行计时含真实生成分派、任务作用域、解码、业务写入和确认。
// 单阶段对照把 claim 放在计时外;完整循环另计入入队、claim、执行和确认。
struct JobInput {
name: String,
amount: i64,
key: String,
}
fn inputs(count: usize) -> Vec<JobInput> {
(0..count)
.map(|index| JobInput {
name: format!("job-{index:04} 中文\""),
amount: index as i64 % 997,
key: format!("key-{index:04}"),
})
.collect()
}
async fn submit(
generated: bool,
input: &JobInput,
scope: &Scope<'_>,
registry: &Arc<Registry>,
) -> String {
let mut database = DbContext::new(registry.clone());
let owner = database.enter();
let execution = Execution::System { tenant: None };
let id = if generated {
GENERATED_SUBMIT(
&input.name,
input.amount,
&input.key,
scope,
&mut database,
&execution,
)
.await
.unwrap()
} else {
rust_submit(
&input.name,
input.amount,
&input.key,
scope,
&mut database,
&execution,
)
.await
.unwrap()
};
database.finish(scope, owner, true).await.unwrap();
id.into_text()
}
async fn execute(
generated: bool,
claim: Arc<Claim>,
scope: &Scope<'_>,
registry: &Arc<Registry>,
) -> Result<(), JobFailure> {
let registry = registry.clone();
let timeout = claim.policy.timeout_ms;
let outcome = if generated {
scope
.spawn(move |child| job_execute(JOB_BINDING, None, claim, child, registry))
.unwrap()
.timeout(timeout)
.await
.unwrap()
} else {
scope
.spawn(move |child| rust_execute(JOB_BINDING, claim, child, registry))
.unwrap()
.timeout(timeout)
.await
.unwrap()
};
match outcome {
dever_runtime::task::Timed::Ready(value) => value,
_ => panic!("benchmark handler timed out"),
}
}
async fn claims(scope: &Scope<'_>, registry: &Arc<Registry>, count: usize) -> Vec<Arc<Claim>> {
let mut database = DbContext::new(registry.clone());
let executor = database.on(JOB_BINDING, scope).await.unwrap();
let mut claims = Vec::with_capacity(count);
for _ in 0..count {
let claim = job::claim(
executor,
scope,
dever_runtime::database::now().unwrap(),
60000,
)
.await
.unwrap()
.unwrap();
assert_eq!(claim.schema, SCHEMA);
assert_eq!(claim.target, TARGET);
assert_eq!(claim.attempt, 1);
claims.push(Arc::new(claim));
}
assert!(
job::claim(
executor,
scope,
dever_runtime::database::now().unwrap(),
60000
)
.await
.unwrap()
.is_none()
);
claims
}
fn measure_jobs(
runtime: &Runtime,
registry: &Arc<Registry>,
generated: bool,
handler: bool,
inputs: Vec<JobInput>,
) -> (u128, u64) {
runtime
.run(async |scope| {
clear(scope, registry).await;
let claims = if handler {
for input in &inputs {
black_box(submit(false, input, scope, registry).await);
}
claims(scope, registry, inputs.len()).await
} else {
Vec::new()
};
let mut checksum = 0u64;
let start = Instant::now();
if handler {
for claim in claims {
execute(generated, black_box(claim), scope, registry)
.await
.unwrap();
checksum += black_box(1);
}
} else {
for input in &inputs {
let id = black_box(submit(generated, black_box(input), scope, registry).await);
checksum += id.len() as u64 + input.name.len() as u64 + input.amount as u64;
}
}
let elapsed = start.elapsed().as_nanos();
check_rows(scope, registry, &inputs, handler).await;
(elapsed, checksum)
})
.unwrap()
}
fn main() {
let (directory, path) = directory("jobs", r#""runtime":{"mode":"worker"}"#);
let runtime = runtime();
let registry = runtime
.run(async |scope| database_registry(&path, scope).await)
.unwrap()
.unwrap();
check_jobs(&runtime, &registry);
header();
for (name, handler) in [("job_enqueue_commit", false), ("job_handler_commit", true)] {
samples(name, |generated, count| {
measure_jobs(&runtime, &registry, generated, handler, inputs(count))
});
}
samples("job_enqueue_large_payload_commit", |generated, count| {
let mut inputs = inputs(count.div_ceil(64));
for input in &mut inputs {
input.name.push_str(&"a".repeat(64 * 1024));
}
measure_jobs(&runtime, &registry, generated, false, inputs)
});
samples("job_submit_claim_complete", |generated, count| {
// 完整循环的每个样本包含 250 项实际任务;初始化及独立 SQL 核验不计时。
measure_cycle(&runtime, &registry, generated, count.div_ceil(8), false)
});
samples("job_backlog_claim_complete", |generated, count| {
measure_cycle(&runtime, &registry, generated, count.div_ceil(8), true)
});
samples("job_enqueue_duplicate_commit", |generated, count| {
measure_duplicate(&runtime, &registry, generated, inputs(count))
});
drop(registry);
drop(runtime);
drop(directory);
}
fn measure_duplicate(
runtime: &Runtime,
registry: &Arc<Registry>,
generated: bool,
inputs: Vec<JobInput>,
) -> (u128, u64) {
runtime
.run(async |scope| {
clear(scope, registry).await;
let mut expected = Vec::with_capacity(inputs.len());
for input in &inputs {
expected.push(submit(false, input, scope, registry).await);
}
let mut actual = Vec::with_capacity(inputs.len());
let mut checksum = 0u64;
let start = Instant::now();
for input in &inputs {
let id = submit(generated, black_box(input), scope, registry).await;
checksum += black_box(id.len() as u64);
actual.push(id);
}
let elapsed = start.elapsed().as_nanos();
assert_eq!(actual, expected);
check_rows(scope, registry, &inputs, false).await;
(elapsed, checksum)
})
.unwrap()
}
fn measure_cycle(
runtime: &Runtime,
registry: &Arc<Registry>,
generated: bool,
count: usize,
backlog: bool,
) -> (u128, u64) {
let inputs = inputs(count);
runtime
.run(async |scope| {
clear(scope, registry).await;
if backlog {
for input in &inputs {
submit(generated, input, scope, registry).await;
}
}
let start = Instant::now();
let mut checksum = 0u64;
for input in &inputs {
if !backlog {
submit(generated, black_box(input), scope, registry).await;
}
let claim = {
let mut database = DbContext::new(registry.clone());
let executor = database.on(JOB_BINDING, scope).await.unwrap();
job::claim(
executor,
scope,
dever_runtime::database::now().unwrap(),
60000,
)
.await
.unwrap()
.unwrap()
};
execute(generated, Arc::new(claim), scope, registry)
.await
.unwrap();
checksum += black_box(1);
}
let elapsed = start.elapsed().as_nanos();
check_rows(scope, registry, &inputs, true).await;
(elapsed, checksum)
})
.unwrap()
}