use criterion::{criterion_group, criterion_main, Criterion};
use prost_types::field_descriptor_proto::{Label, Type};
use prost_types::{DescriptorProto, FieldDescriptorProto, FileDescriptorProto, FileDescriptorSet};
fn make_field(name: &str, number: i32, r#type: Type, label: Label) -> FieldDescriptorProto {
FieldDescriptorProto {
name: Some(name.to_string()),
number: Some(number),
label: Some(label as i32),
r#type: Some(r#type as i32),
..Default::default()
}
}
fn make_message(name: &str) -> DescriptorProto {
DescriptorProto {
name: Some(name.to_string()),
field: vec![
make_field("id", 1, Type::Int64, Label::Optional),
make_field("name", 2, Type::String, Label::Optional),
make_field("value", 3, Type::Double, Label::Optional),
make_field("enabled", 4, Type::Bool, Label::Optional),
make_field("tags", 5, Type::String, Label::Repeated),
make_field("count", 6, Type::Uint32, Label::Optional),
make_field("data", 7, Type::Bytes, Label::Optional),
],
..Default::default()
}
}
fn build_flat_fds(n: usize) -> FileDescriptorSet {
let messages: Vec<DescriptorProto> = (0..n)
.map(|i| make_message(&format!("Message{i}")))
.collect();
let file = FileDescriptorProto {
name: Some("bench.proto".to_string()),
package: Some("bench".to_string()),
message_type: messages,
..Default::default()
};
FileDescriptorSet { file: vec![file] }
}
fn build_namespaced_fds(n: usize, pkg_count: usize) -> FileDescriptorSet {
let mut pkg_messages: Vec<Vec<DescriptorProto>> = (0..pkg_count).map(|_| vec![]).collect();
for i in 0..n {
pkg_messages[i % pkg_count].push(make_message(&format!("Msg{i}")));
}
let files: Vec<FileDescriptorProto> = (0..pkg_count)
.map(|p| FileDescriptorProto {
name: Some(format!("pkg{p}.proto")),
package: Some(format!("bench.pkg{p}")),
message_type: pkg_messages[p].clone(),
..Default::default()
})
.collect();
FileDescriptorSet { file: files }
}
fn bench_generate_flat(c: &mut Criterion) {
let mut group = c.benchmark_group("generate_flat");
let fds_small = build_flat_fds(10);
let fds_medium = build_flat_fds(50);
let fds_large = build_flat_fds(100);
let opts = oxiproto_codegen::CodegenOptions::default();
group.bench_function("10_messages", |b| {
b.iter(|| {
let result =
oxiproto_codegen::generate_with_options(std::hint::black_box(&fds_small), &opts);
std::hint::black_box(result.unwrap().len())
})
});
group.bench_function("50_messages", |b| {
b.iter(|| {
let result =
oxiproto_codegen::generate_with_options(std::hint::black_box(&fds_medium), &opts);
std::hint::black_box(result.unwrap().len())
})
});
group.bench_function("100_messages", |b| {
b.iter(|| {
let result =
oxiproto_codegen::generate_with_options(std::hint::black_box(&fds_large), &opts);
std::hint::black_box(result.unwrap().len())
})
});
group.finish();
}
fn bench_generate_oxi_impl(c: &mut Criterion) {
let fds = build_flat_fds(20);
let opts = oxiproto_codegen::CodegenOptions {
emit_oxi_message_impl: true,
..Default::default()
};
c.bench_function("generate_oxi_impl_20", |b| {
b.iter(|| {
let result = oxiproto_codegen::generate_with_options(std::hint::black_box(&fds), &opts);
std::hint::black_box(result.unwrap().len())
})
});
}
fn bench_generate_json(c: &mut Criterion) {
let fds = build_flat_fds(20);
let opts = oxiproto_codegen::CodegenOptions {
emit_json: true,
..Default::default()
};
c.bench_function("generate_json_20", |b| {
b.iter(|| {
let result = oxiproto_codegen::generate_with_options(std::hint::black_box(&fds), &opts);
std::hint::black_box(result.unwrap().len())
})
});
}
#[cfg(feature = "format")]
fn bench_generate_formatted(c: &mut Criterion) {
let fds = build_flat_fds(20);
let opts = oxiproto_codegen::CodegenOptions {
format_output: true,
..Default::default()
};
c.bench_function("generate_formatted_20", |b| {
b.iter(|| {
let result = oxiproto_codegen::generate_with_options(std::hint::black_box(&fds), &opts);
std::hint::black_box(result.unwrap().len())
})
});
}
fn bench_generate_module_tree(c: &mut Criterion) {
let fds = build_namespaced_fds(20, 4);
let opts = oxiproto_codegen::CodegenOptions {
package_namespacing: true,
..Default::default()
};
c.bench_function("generate_module_tree_20x4pkg", |b| {
b.iter(|| {
let result = oxiproto_codegen::generate_module(std::hint::black_box(&fds), &opts);
std::hint::black_box(result.unwrap().render().len())
})
});
}
fn bench_streaming_vs_string(c: &mut Criterion) {
let fds = build_flat_fds(50);
let opts = oxiproto_codegen::CodegenOptions::default();
let mut group = c.benchmark_group("streaming_vs_string_50");
group.bench_function("generate_to_string", |b| {
b.iter(|| {
let result = oxiproto_codegen::generate_with_options(std::hint::black_box(&fds), &opts);
std::hint::black_box(result.unwrap().len())
})
});
group.bench_function("generate_to_writer_vec", |b| {
b.iter(|| {
let mut buf: Vec<u8> = Vec::with_capacity(64 * 1024);
oxiproto_codegen::generate_to_writer(std::hint::black_box(&fds), &opts, &mut buf)
.unwrap();
std::hint::black_box(buf.len())
})
});
group.finish();
}
#[cfg(feature = "format")]
criterion_group!(
benches,
bench_generate_flat,
bench_generate_oxi_impl,
bench_generate_json,
bench_generate_formatted,
bench_generate_module_tree,
bench_streaming_vs_string,
);
#[cfg(not(feature = "format"))]
criterion_group!(
benches,
bench_generate_flat,
bench_generate_oxi_impl,
bench_generate_json,
bench_generate_module_tree,
bench_streaming_vs_string,
);
criterion_main!(benches);