Skip to content

Commit

Permalink
chore: Add notes about performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Stranger6667 committed Apr 15, 2020
1 parent aa1bcf3 commit 1157cc1
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 36 deletions.
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# jsonschema

Yet another JSON Schema validator implementation. It compiles schema into a validation tree to have validation as fast as possible.
A JSON Schema validator implementation. It compiles schema into a validation tree to have validation as fast as possible.

```toml
# Cargo.toml
jsonschema = "0.2"
```

To validate documents against some schema and get validation errors (if any):

Expand Down Expand Up @@ -43,9 +48,37 @@ use serde_json::json;
fn main() {
let schema = json!({"maxLength": 5});
let instance = json!("foo");
let compiled = JSONSchema::compile(&schema, None); // Draft is detected automatically with fallback to Draft7
// Draft is detected automatically with fallback to Draft7
let compiled = JSONSchema::compile(&schema, None);
assert!(compiled.is_valid(&instance));
}
```

Fully supported drafts (with optional test cases included):
- Draft 7
- Draft 6

## Performance

There is a comparison with other JSON Schema validators written in Rust - `jsonschema_valid` and `valico`.

Test machine i8700K (12 cores), 32GB RAM.

Performance of `jsonschema::JSONSchema.is_valid`. Ratios are given against compiled jsonschema:

- Big valid input (`canada_schema.json` and `canada.json`)
- Small valid input (`small_schema.json` and `small_valid.json`)
- Small invalid input (`small_schema.json` and `small_invalid.json`)

| Case | jsonschema_valid | valico | jsonschema (not compiled) | jsonschema (compiled) |
| ------------- | ---------------------- | ----------------------- | ------------------------- | --------------------- |
| Big valid | 56.746 ms (**x187.2**) | 149.49 ms (**x493.17**) | 317.14 us (**x1.04**) | 303.12 us |
| Small valid | 2.23 us (**x14.92**) | 3.87 us (**x25.9**) | 3.76 us (**x25.17**) | 149.38 ns |
| Small invalid | 515.22 ns (**x85.58**) | 4.08 us (**x677.74**) | 3.63 us (**x602.99**) | 6.02 ns |

As you can see the compiled version is faster, especially for large inputs. However, not-compiled version is slower
on smaller inputs than `jsonschema_valid`.

You can find benchmark code in `benches/jsonschema.rs`

**NOTE**. This library is in early development.
101 changes: 69 additions & 32 deletions benches/jsonschema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,22 @@ fn canada_benchmark(c: &mut Criterion) {
c.bench_function("canada bench", |b| b.iter(|| validator.is_valid(&data)));
}

fn canada_benchmark_not_compiled(c: &mut Criterion) {
let schema = black_box(read_json("benches/canada_schema.json"));
let data = black_box(read_json("benches/canada.json"));
c.bench_function("canada bench not compiled", |b| {
b.iter(|| {
let validator = JSONSchema::compile(&schema, None).unwrap();
validator.is_valid(&data)
})
});
}

fn canada_benchmark_jsonschema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/canada_schema.json"));
let data = black_box(read_json("benches/canada.json"));
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap();
c.bench_function("canada bench alternative", |b| {
c.bench_function("canada bench jsonschema_valid", |b| {
b.iter(|| jsonschema_valid::validate(&cfg, &data))
});
}
Expand All @@ -58,7 +69,7 @@ fn canada_benchmark_valico(c: &mut Criterion) {
let data = black_box(read_json("benches/canada.json"));
let mut scope = json_schema::Scope::new();
let schema = scope.compile_and_return(schema.clone(), false).unwrap();
c.bench_function("canada bench alternative", |b| {
c.bench_function("canada bench valico", |b| {
b.iter(|| schema.validate(&data).is_valid())
});
}
Expand All @@ -70,67 +81,90 @@ fn canada_compile_benchmark(c: &mut Criterion) {
});
}

fn fastjsonschema_compile(c: &mut Criterion) {
let schema = read_json("benches/fast_schema.json");
c.bench_function("fastjsonschema compile", |b| {
fn small_schema_compile(c: &mut Criterion) {
let schema = read_json("benches/small_schema.json");
c.bench_function("small_schema compile", |b| {
b.iter(|| JSONSchema::compile(&schema, None).unwrap())
});
}
fn fastjsonschema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/fast_schema.json"));
fn small_schema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let validator = JSONSchema::compile(&schema, None).unwrap();
let data =
black_box(json!([9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]));
c.bench_function("fastjsonschema valid", |b| {
c.bench_function("small_schema valid", |b| {
b.iter(|| validator.is_valid(&data))
});
}
fn fastjsonschema_valid_jsonschema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/fast_schema.json"));
fn small_schema_valid_not_compiled(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let data =
black_box(json!([9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]));
c.bench_function("small_schema valid not compiled", |b| {
b.iter(|| {
let validator = JSONSchema::compile(&schema, None).unwrap();
validator.is_valid(&data)
})
});
}
fn small_schema_valid_jsonschema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap();
let data =
black_box(json!([9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]));
c.bench_function("fastjsonschema valid jsonschema_valid", |b| {
c.bench_function("small_schema valid jsonschema_valid", |b| {
b.iter(|| jsonschema_valid::validate(&cfg, &data))
});
}
fn fastjsonschema_valid_valico(c: &mut Criterion) {
let schema = black_box(read_json("benches/fast_schema.json"));
fn small_schema_valid_valico(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let mut scope = json_schema::Scope::new();
let schema = scope.compile_and_return(schema.clone(), false).unwrap();
let data =
black_box(json!([9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]));
c.bench_function("fastjsonschema valid valico", |b| {
c.bench_function("small_schema valid valico", |b| {
b.iter(|| schema.validate(&data).is_valid())
});
}

fn fastjsonschema_invalid(c: &mut Criterion) {
let schema = black_box(read_json("benches/fast_schema.json"));
fn small_schema_invalid(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let validator = JSONSchema::compile(&schema, None).unwrap();
let data =
black_box(json!([10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]));
c.bench_function("fastjsonschema invalid", |b| {
c.bench_function("small_schema invalid", |b| {
b.iter(|| validator.is_valid(&data))
});
}

fn fastjsonschema_invalid_jsonschema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/fast_schema.json"));
fn small_schema_invalid_not_compiled(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let data =
black_box(json!([10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]));
c.bench_function("small_schema invalid not compiled", |b| {
b.iter(|| {
let validator = JSONSchema::compile(&schema, None).unwrap();
validator.is_valid(&data)
})
});
}

fn small_schema_invalid_jsonschema_valid(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap();
let data =
black_box(json!([10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]));
c.bench_function("fastjsonschema invalid jsonschema_valid", |b| {
c.bench_function("small_schema invalid jsonschema_valid", |b| {
b.iter(|| jsonschema_valid::validate(&cfg, &data))
});
}
fn fastjsonschema_invalid_valico(c: &mut Criterion) {
let schema = black_box(read_json("benches/fast_schema.json"));
fn small_schema_invalid_valico(c: &mut Criterion) {
let schema = black_box(read_json("benches/small_schema.json"));
let mut scope = json_schema::Scope::new();
let schema = scope.compile_and_return(schema.clone(), false).unwrap();
let data =
black_box(json!([10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]));
c.bench_function("fastjsonschema invalid valico", |b| {
c.bench_function("small_schema invalid valico", |b| {
b.iter(|| schema.validate(&data).is_valid())
});
}
Expand Down Expand Up @@ -324,16 +358,19 @@ bench_compile!(c_aproperties6, "compile additional properties 6", {"properties":
criterion_group!(
benches,
canada_benchmark,
canada_benchmark_jsonschema_valid,
canada_benchmark_valico,
canada_benchmark_not_compiled,
// canada_benchmark_jsonschema_valid,
// canada_benchmark_valico,
// canada_compile_benchmark,
// fastjsonschema_compile,
// fastjsonschema_valid,
// fastjsonschema_valid_jsonschema_valid,
// fastjsonschema_valid_valico,
// fastjsonschema_invalid,
// fastjsonschema_invalid_jsonschema_valid,
// fastjsonschema_invalid_valico,
// small_schema_compile,
small_schema_valid,
small_schema_valid_not_compiled,
// small_schema_valid_jsonschema_valid,
// small_schema_valid_valico,
small_schema_invalid,
small_schema_invalid_not_compiled,
// small_schema_invalid_jsonschema_valid,
// small_schema_invalid_valico,
// type_string_valid,
// type_string_invalid,
// false_schema,
Expand Down
1 change: 1 addition & 0 deletions benches/small_invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]
2 changes: 1 addition & 1 deletion benches/fast_schema.json → benches/small_schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": [
{
Expand Down
1 change: 1 addition & 0 deletions benches/small_valid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]

0 comments on commit 1157cc1

Please sign in to comment.