Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Aug 27, 2024
0 parents commit 206d88b
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[Makefile]
indent_style = tab

[*.mk]
indent_style = tab

[*.uk]
indent_style = tab
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Benchmark

on:
push:
branches:
- main
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make
- run: cat dist/report.csv
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/dist
/node_modules
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.DEFAULT_GOAL := all
SCHEMAS = $(notdir $(wildcard schemas/*))
IMPLEMENTATIONS = $(notdir $(wildcard implementations/*))

node_modules: package.json package-lock.json ; npm ci
.PHONY: clean
clean: ; rm -rf dist node_modules
dist: ; mkdir $@
dist/results: | dist ; mkdir $@
dist/temp: | dist ; mkdir $@
define PREPARE_IMPLEMENTATION
dist/results/$1: | dist/results ; mkdir $$@
dist/temp/$1: | dist/temp ; mkdir $$@
ALL_TARGETS += $$(addprefix dist/results/$1/,$(SCHEMAS))
endef
$(foreach implementation,$(IMPLEMENTATIONS),$(eval $(call PREPARE_IMPLEMENTATION,$(implementation))))
dist/report.csv: report.sh $(ALL_TARGETS) | dist ; ./$< $(ALL_TARGETS) > $@
.PHONY: all
all: dist/report.csv ; cat $<

# JSON Toolkit

dist/results/jsontoolkit/%: \
implementations/jsontoolkit/CMakeLists.txt \
implementations/jsontoolkit/main.cc \
schemas/%/schema.json \
schemas/%/instance.json \
| dist/results/jsontoolkit dist/temp/jsontoolkit
[ -d $(word 2,$|)/repo ] && git -C $(word 2,$|)/repo pull || git clone https://github.com/sourcemeta/jsontoolkit $(word 2,$|)/repo
cmake -S $(dir $<) -B $(word 2,$|)/build -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_SHARED_LIBS:BOOL=OFF
cmake --build $(word 2,$|)/build --config Release --parallel 4
$(word 2,$|)/build/jsontoolkit_benchmark $(dir $(word 3,$^)) > $@

# AJV

dist/results/ajv/%: \
implementations/ajv/main.js \
schemas/%/schema.json \
schemas/%/instance.json \
node_modules \
| dist/results/ajv
node $< $(word 2,$^) $(word 3,$^) > $@
46 changes: 46 additions & 0 deletions implementations/ajv/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const Ajv = require('ajv');
const draft4schema = require('ajv/lib/refs/json-schema-draft-04.json');
const fs = require('fs');
const { performance } = require('perf_hooks');

function readJSONFile(filePath) {
try {
const fileContent = fs.readFileSync(filePath, 'utf8');
return JSON.parse(fileContent);
} catch (error) {
process.exit(1);
}
}

function validateSchema(schemaPath, instancePath) {
const schema = readJSONFile(schemaPath);
const instance = readJSONFile(instancePath);

const ajv = new Ajv({
schemaId: 'id',
meta: false,
validateSchema: false
});

ajv.addMetaSchema(draft4schema);
const validate = ajv.compile(schema);

const startTime = performance.now();
if (!validate(instance)) {
process.exit(1);
}

const endTime = performance.now();

const durationNs = (endTime - startTime) * 1e6;
console.log(durationNs.toFixed(0));
}

if (process.argv.length !== 4) {
process.exit(1);
}

const schemaPath = process.argv[2];
const instancePath = process.argv[3];

validateSchema(schemaPath, instancePath);
9 changes: 9 additions & 0 deletions implementations/jsontoolkit/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.16)
project(jsontoolkit_benchmark)
include(../../dist/temp/jsontoolkit/repo/vendor/noa/cmake/noa.cmake)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
add_subdirectory(../../dist/temp/jsontoolkit/repo jsontoolkit)
add_executable(jsontoolkit_benchmark main.cc)
noa_add_default_options(PRIVATE jsontoolkit_benchmark)
target_link_libraries(jsontoolkit_benchmark PRIVATE sourcemeta::jsontoolkit::json)
target_link_libraries(jsontoolkit_benchmark PRIVATE sourcemeta::jsontoolkit::jsonschema)
36 changes: 36 additions & 0 deletions implementations/jsontoolkit/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <sourcemeta/jsontoolkit/json.h>
#include <sourcemeta/jsontoolkit/jsonschema.h>

#include <chrono>
#include <iostream>
#include <filesystem>

int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <schema>\n";
return EXIT_FAILURE;
}

const std::filesystem::path example{argv[1]};
const auto schema{sourcemeta::jsontoolkit::from_file(example / "schema.json")};
const auto instance{sourcemeta::jsontoolkit::from_file(example / "instance.json")};

const auto schema_template{sourcemeta::jsontoolkit::compile(
schema, sourcemeta::jsontoolkit::default_schema_walker,
sourcemeta::jsontoolkit::official_resolver,
sourcemeta::jsontoolkit::default_schema_compiler)};

const auto timestamp_start{std::chrono::high_resolution_clock::now()};
const auto result{sourcemeta::jsontoolkit::evaluate(
schema_template, instance)};
const auto timestamp_end{std::chrono::high_resolution_clock::now()};
if (!result) {
return EXIT_FAILURE;
}

const auto duration{
std::chrono::duration_cast<std::chrono::nanoseconds>(timestamp_end - timestamp_start)};
std::cout << duration.count() << "\n";

return EXIT_SUCCESS;
}
67 changes: 67 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "jsonschema-benchmark",
"version": "1.0.0",
"author": "Juan Cruz Viotti <[email protected]>",
"dependencies": {
"ajv": "^6.12.6"
}
}
20 changes: 20 additions & 0 deletions report.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh

set -o errexit
set -o nounset

if [ $# -lt 1 ]
then
echo "Usage: $0 <results...>" 1>&2
exit 1
fi

echo "implementation,name,nanoseconds"

for argument in "$@"
do
IMPLEMENTATION="$(basename "$(dirname "$argument")")"
EXAMPLE="$(basename "$argument")"
NANOSECONDS="$(tr -d '\n\r' < "$argument")"
echo "$IMPLEMENTATION,$EXAMPLE,$NANOSECONDS"
done
46 changes: 46 additions & 0 deletions schemas/example/instance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"storeName": "TechGadgets Online",
"lastUpdated": "2024-08-27T14:30:00Z",
"categories": ["Electronics", "Accessories", "Smart Home"],
"products": [
{
"id": "PRD-EL-000001",
"name": "SuperSound Wireless Headphones",
"description": "High-quality wireless headphones with noise-cancelling technology.",
"price": 129.99,
"category": "Electronics",
"tags": ["audio", "wireless", "headphones"],
"inStock": true,
"rating": {
"average": 4.7,
"count": 253
}
},
{
"id": "PRD-AC-000015",
"name": "DuraPro Phone Case",
"description": "Rugged phone case for ultimate protection.",
"price": 24.95,
"category": "Accessories",
"tags": ["phone", "protection"],
"inStock": true,
"rating": {
"average": 4.2,
"count": 187
}
},
{
"id": "PRD-SH-000008",
"name": "SmartHome Hub",
"description": "Central control unit for your smart home devices.",
"price": 79.99,
"category": "Smart Home",
"tags": ["iot", "control", "automation"],
"inStock": false,
"rating": {
"average": 4.5,
"count": 42
}
}
]
}
Loading

0 comments on commit 206d88b

Please sign in to comment.