From d509b4bb425e06b666a908bff6e0c48e1fb3ecc3 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Wed, 15 May 2024 12:04:00 +0200 Subject: [PATCH] build: Add boon to benchmarks Signed-off-by: Dmitry Dygalo --- jsonschema/Cargo.toml | 8 ++- jsonschema/benches/boon.rs | 128 +++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 jsonschema/benches/boon.rs diff --git a/jsonschema/Cargo.toml b/jsonschema/Cargo.toml index e00af10c..eb51366d 100644 --- a/jsonschema/Cargo.toml +++ b/jsonschema/Cargo.toml @@ -68,11 +68,12 @@ getrandom = { version = "0.2", features = ["js"] } [dev-dependencies] bench_helpers = { path = "../bench_helpers" } +boon = "0.5" codspeed-criterion-compat = "2.6.0" criterion = { version = "0.5.1", features = [], default-features = false } json_schema_test_suite = { version = "0.3.0", path = "../jsonschema-test-suite" } jsonschema-valid = "0.5" -lazy_static = "1.4" # Needed for json schema test suite +lazy_static = "1.4" # Needed for json schema test suite mockito = "0.31" paste = "1.0" test-case = "3" @@ -93,6 +94,11 @@ name = "valico" harness = false name = "jsonschema_valid" +# Benchmarks for `boon` +[[bench]] +harness = false +name = "boon" + [profile.release] codegen-units = 1 lto = "fat" diff --git a/jsonschema/benches/boon.rs b/jsonschema/benches/boon.rs new file mode 100644 index 00000000..f5472344 --- /dev/null +++ b/jsonschema/benches/boon.rs @@ -0,0 +1,128 @@ +use bench_helpers::{ + bench_citm, bench_fast, bench_geojson, bench_keywords, bench_openapi, bench_swagger, +}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use jsonschema::JSONSchema; +use serde_json::Value; + +macro_rules! boon_bench { + ($c:tt, $name:expr, $schema:ident, $instance:ident) => {{ + let mut schemas = boon::Schemas::new(); + let mut compiler = boon::Compiler::new(); + compiler.add_resource("schema.json", $schema).unwrap(); + let id = compiler.compile("schema.json", &mut schemas).unwrap(); + assert!(schemas.validate(&$instance, id).is_ok(), "Invalid instance"); + $c.bench_function(&format!("{} boon/validate", $name), |b| { + b.iter(|| { + let _ = schemas.validate(&$instance, id).is_ok(); + }); + }); + }}; +} + +fn large_schemas(c: &mut Criterion) { + // Open API JSON Schema + // Only `jsonschema` works correctly - other libraries do not recognize `zuora` as valid + bench_openapi(&mut |name, schema, instance| boon_bench!(c, name, schema, instance)); + // Swagger JSON Schema + bench_swagger(&mut |name, schema, instance| boon_bench!(c, name, schema, instance)); + // Canada borders in GeoJSON + bench_geojson(&mut |name, schema, instance| boon_bench!(c, name, schema, instance)); + // CITM catalog + bench_citm(&mut |name, schema, instance| boon_bench!(c, name, schema, instance)); +} + +fn fast_schema(c: &mut Criterion) { + bench_fast(&mut |name, schema, valid, invalid| { + let mut schemas = boon::Schemas::new(); + let mut compiler = boon::Compiler::new(); + compiler.add_resource("schema.json", schema).unwrap(); + let id = compiler.compile("schema.json", &mut schemas).unwrap(); + assert!(schemas.validate(&valid, id).is_ok(), "Invalid instance"); + assert!(schemas.validate(&invalid, id).is_err(), "Invalid instance"); + c.bench_function(&format!("{} boon/is_valid/valid", name), |b| { + b.iter(|| { + let _ = schemas.validate(&valid, id).is_ok(); + }); + }); + c.bench_function(&format!("{} boon/is_valid/invalid", name), |b| { + b.iter(|| { + let _ = schemas.validate(&invalid, id).is_ok(); + }); + }); + }); +} + +fn keywords(c: &mut Criterion) { + bench_keywords( + c, + &|_: &str| false, + &|schema: &Value, instance: &Value| { + let compiled = JSONSchema::compile(schema).expect("Valid schema"); + compiled.is_valid(instance) + }, + &mut |c: &mut Criterion, name: &str, schema: &Value| { + c.bench_with_input( + BenchmarkId::new(name, "jsonschema_rs/compile"), + schema, + |b, schema| { + b.iter(|| { + JSONSchema::compile(schema).expect("Valid schema"); + }) + }, + ); + }, + validate_valid, + validate_invalid, + ) +} + +fn validate_valid(c: &mut Criterion, name: &str, schema: &Value, instance: &Value) { + let compiled = JSONSchema::compile(schema).expect("Valid schema"); + c.bench_with_input( + BenchmarkId::new(name, "jsonschema_rs/is_valid/valid"), + instance, + |b, instance| { + b.iter(|| { + let _ = compiled.is_valid(instance); + }) + }, + ); + c.bench_with_input( + BenchmarkId::new(name, "jsonschema_rs/validate/valid"), + instance, + |b, instance| { + b.iter(|| { + compiled.validate(instance).ok(); + }) + }, + ); +} + +fn validate_invalid(c: &mut Criterion, name: &str, schema: &Value, instance: &Value) { + let compiled = JSONSchema::compile(schema).expect("Valid schema"); + c.bench_with_input( + BenchmarkId::new(name, "jsonschema_rs/is_valid/invalid"), + instance, + |b, instance| { + b.iter(|| { + let _ = compiled.is_valid(instance); + }) + }, + ); + c.bench_with_input( + BenchmarkId::new(name, "jsonschema_rs/validate/invalid"), + instance, + |b, instance| { + b.iter(|| { + let _: Vec<_> = compiled + .validate(instance) + .expect_err("There should be errors") + .collect(); + }) + }, + ); +} + +criterion_group!(arbitrary, large_schemas, fast_schema); +criterion_main!(arbitrary);