use apache_avro::writer::datum::GenericDatumWriter;
use apache_avro::{
schema::Schema,
types::{Record, Value},
};
use criterion::{Criterion, criterion_group, criterion_main};
use std::time::Duration;
const RAW_SMALL_SCHEMA: &str = r#"
{
"namespace": "test",
"type": "record",
"name": "Test",
"fields": [
{
"type": {
"type": "string"
},
"name": "field"
}
]
}
"#;
const RAW_BIG_SCHEMA: &str = r#"
{
"namespace": "my.example",
"type": "record",
"name": "userInfo",
"fields": [
{
"default": "NONE",
"type": "string",
"name": "username"
},
{
"default": -1,
"type": "int",
"name": "age"
},
{
"default": "NONE",
"type": "string",
"name": "phone"
},
{
"default": "NONE",
"type": "string",
"name": "housenum"
},
{
"default": {},
"type": {
"fields": [
{
"default": "NONE",
"type": "string",
"name": "street"
},
{
"default": "NONE",
"type": "string",
"name": "city"
},
{
"default": "NONE",
"type": "string",
"name": "state_prov"
},
{
"default": "NONE",
"type": "string",
"name": "country"
},
{
"default": "NONE",
"type": "string",
"name": "zip"
}
],
"type": "record",
"name": "mailing_address"
},
"name": "address"
}
]
}
"#;
const RAW_ADDRESS_SCHEMA: &str = r#"
{
"fields": [
{
"default": "NONE",
"type": "string",
"name": "street"
},
{
"default": "NONE",
"type": "string",
"name": "city"
},
{
"default": "NONE",
"type": "string",
"name": "state_prov"
},
{
"default": "NONE",
"type": "string",
"name": "country"
},
{
"default": "NONE",
"type": "string",
"name": "zip"
}
],
"type": "record",
"name": "mailing_address"
}
"#;
fn make_small_record() -> Result<(Schema, Value), Box<dyn std::error::Error>> {
let small_schema = Schema::parse_str(RAW_SMALL_SCHEMA)?;
let small_record = {
let mut small_record = Record::new(&small_schema).unwrap();
small_record.put("field", "foo");
small_record.into()
};
Ok((small_schema, small_record))
}
fn make_big_record() -> Result<(Schema, Value), Box<dyn std::error::Error>> {
let big_schema = Schema::parse_str(RAW_BIG_SCHEMA)?;
let address_schema = Schema::parse_str(RAW_ADDRESS_SCHEMA)?;
let mut address = Record::new(&address_schema).unwrap();
address.put("street", "street");
address.put("city", "city");
address.put("state_prov", "state_prov");
address.put("country", "country");
address.put("zip", "zip");
let big_record = {
let mut big_record = Record::new(&big_schema).unwrap();
big_record.put("username", "username");
big_record.put("age", 10i32);
big_record.put("phone", "000000000");
big_record.put("housenum", "0000");
big_record.put("address", address);
big_record.into()
};
Ok((big_schema, big_record))
}
fn bench_small_schema_write_record(c: &mut Criterion) {
let (schema, record) = make_small_record().unwrap();
c.bench_function("small record", |b| {
b.iter(|| {
GenericDatumWriter::builder(&schema)
.build()
.unwrap()
.write_value_to_vec(record.clone())
});
});
}
fn bench_big_schema_write_record(c: &mut Criterion) {
let (schema, record) = make_big_record().unwrap();
c.bench_function("big record", |b| {
b.iter(|| {
GenericDatumWriter::builder(&schema)
.build()
.unwrap()
.write_value_to_vec(record.clone())
});
});
}
fn bench_small_schema_write_record_reuse_datum_writer(c: &mut Criterion) {
let (schema, record) = make_small_record().unwrap();
let writer = GenericDatumWriter::builder(&schema).build().unwrap();
c.bench_function("small record (reused writer)", |b| {
b.iter(|| writer.write_value_ref(&mut Vec::new(), &record));
});
}
fn bench_big_schema_write_record_reuse_datum_writer(c: &mut Criterion) {
let (schema, record) = make_big_record().unwrap();
let writer = GenericDatumWriter::builder(&schema).build().unwrap();
c.bench_function("big record (reused writer)", |b| {
b.iter(|| writer.write_value_ref(&mut Vec::new(), &record));
});
}
fn bench_small_schema_write_record_no_validation(c: &mut Criterion) {
let (schema, record) = make_small_record().unwrap();
let writer = GenericDatumWriter::builder(&schema)
.validate(false)
.build()
.unwrap();
c.bench_function("small record (no validation)", |b| {
b.iter(|| writer.write_value_ref(&mut Vec::new(), &record));
});
}
fn bench_big_schema_write_record_no_validation(c: &mut Criterion) {
let (schema, record) = make_big_record().unwrap();
let writer = GenericDatumWriter::builder(&schema)
.validate(false)
.build()
.unwrap();
c.bench_function("big record (no validation)", |b| {
b.iter(|| writer.write_value_ref(&mut Vec::new(), &record));
});
}
criterion_group!(
name = benches;
config = Criterion::default().sample_size(200).measurement_time(Duration::from_secs(10));
targets =
bench_small_schema_write_record,
bench_big_schema_write_record,
bench_small_schema_write_record_reuse_datum_writer,
bench_big_schema_write_record_reuse_datum_writer,
bench_small_schema_write_record_no_validation,
bench_big_schema_write_record_no_validation,
);
criterion_main!(benches);