JsonParserByLeo/Test/Ben/README.md
180 lines
8.5 KiB
Markdown
Nique_372
2026-08-28 08:28:39 -05:00
# Benchmark
Nique_372
2026-08-28 17:39:28 -05:00
This benchmark was built by me as part of testing my library and the MQL5 JSON-parsing ecosystem in general, run on my personal development machine.
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:39:28 -05:00
## Reproduction
### MQL5 code
Before anything else, delete the current `.log` file.
1. For each test/library, do the following:
- Run `UtilHeader` with the library name.
- Run the test several times in **Parse** mode.
- Recompile the test in **Access** mode.
- Run it several times again.
- Repeat for the next test.
2. Once all tests are done, run the `UtilFinish` script. It parses the `.log` file (with timestamps) and saves the Parse results into the `.db` file. Access results are saved automatically as they run.
### Code in other languages
Requirements:
- VSCode (optional)
- Python 3.11+
- Rust
- C++ (Visual Studio, or GCC — instructions below assume Visual Studio; with GCC you would need to adapt the `CMakeLists.txt` and the `.h`/`.cpp` files under `DLL` and `BenOther/`)
- The `JsonParserByLeo` repo cloned with all its dependencies (assumed already done at this point)
1. **C++**: this was built with Visual Studio 2026 (used for the `simdjson` test as an example). Open the `BenOther/C++` folder as a project, then `Ctrl+S` to let the CMake cache build. After that, compiling produces a `Test.exe` under `out/build/...`.
2. **Rust**: VSCode was used with the rust-analyzer extension; opening the project pulls dependencies automatically. Then, via CLI:
```bash
cargo build --release
```
Run the resulting executable from `target/`. This can all be done purely via CLI too — the above is just the workflow used here; if you know Rust better, feel free to do it differently. Rust knowledge here is basic — just enough to run `sonic-rs`, `serde_json`, etc. The benchmark was the only use case.
3. **Python**: simplest of all — just have Python installed. VSCode's Run button was used here. A standalone `.exe` can also be generated if preferred.
Nique_372
2026-08-28 08:28:39 -05:00
## Performance
Nique_372
2026-08-28 17:39:28 -05:00
### Parsing
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:39:28 -05:00
Benchmark: `twitter.json` (616.7 KB), 1000 iterations. Values below are total time across all 1000 iterations, sorted fastest to slowest.
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:44:15 -05:00
> **Note on the benchmark below:** `JsonParserByLeo` (SIMD) is not validating the input as strictly as `simdjson` does — notably,
it does not perform full UTF-8 validation during the structural scan, and it's a single flat `switch`-based pipeline with no public error-recovery API surface, unlike `simdjson::dom::parser`.
The timings below reflect the work each parser actually does, not a strict apples-to-apples "same guarantees" comparison — read it as "same ballpark, different tradeoffs," not "beats simdjson at its own game."
Nique_372
2026-08-28 08:28:39 -05:00
| Parser | Language | Time (ms, total / 1000 iter) |
|--------|----------|-------------------------------|
Nique_372
2026-09-18 14:11:09 -05:00
| **JsonParserByLeo** (with SIMD, via DLL) | MQL5 / C++ DLL | **336-337** |
Nique_372
2026-08-28 08:28:39 -05:00
| **simdjson::dom::parser** (reused parser) | C++ | **380-384** |
Nique_372
2026-08-28 17:39:28 -05:00
| **sonic-rs** (typed struct) | Rust | **460-461** |
| **simdjson.Parser** (reused parser) | Python | **475** |
Nique_372
2026-10-03 11:47:17 -05:00
| **JsonParserByLeo** (single array copy) | MQL5 | **589-591** |
Nique_372
2026-08-28 17:39:28 -05:00
| serde_json (typed struct) | Rust | 788-796 |
Nique_372
2026-08-28 18:23:31 -05:00
| YamlParserByLeo, single array copy | MQL5 | 899-900 |
Nique_372
2026-08-28 17:39:28 -05:00
| simd-json (typed struct) | Rust | 915-972 |
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 1063.04 |
Nique_372
2026-08-28 18:20:11 -05:00
| FastJson v3.7, single array copy | MQL5 | 1213.43 |
Nique_372
2026-08-28 17:39:28 -05:00
| GLM 5.2 (Max, deep thinking), generated code (fast JSON lib), single array copy, 14+ iterations with feedback | MQL5 | 1249.76 |
Nique_372
2026-08-28 08:28:39 -05:00
| orjson | Python | 1863 |
Nique_372
2026-08-28 17:39:28 -05:00
| ryml (pure parse time) | C++ | 2846.55 |
Nique_372
2026-08-28 08:28:39 -05:00
| simdjson.Parser + as_dict | Python | 4309 |
Nique_372
2026-08-28 17:39:28 -05:00
| ToyJson3, single string copy, tokenization only | MQL5 | 4418.49 |
Nique_372
2026-08-28 08:28:39 -05:00
| simdjson.loads | Python | 4955 |
| ujson | Python | 5322 |
| json (stdlib) | Python | 5860 |
Nique_372
2026-08-28 17:39:28 -05:00
| MQL5-JsonLib (ding9736), single string copy, tape parsing only (no DOM built) | MQL5 | 17547.38 |
| JAson, single array copy | MQL5 | 21118.68 |
| CJsonNode (MQL5 Articles reference implementation), single array copy | MQL5 | 86409.04 |
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:39:28 -05:00
### Access benchmarks
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:39:28 -05:00
All access benchmarks use `test.json`, 1000 iterations, and report total time across all iterations in microseconds. Lower is better. Results are sorted fastest to slowest within each table.
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:39:28 -05:00
#### Access — Wide object (100 keys)
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-10-03 17:00:34 -05:00
Repeated key lookups across a flat object with 100 keys (random).
Nique_372
2026-08-28 08:28:39 -05:00
| Parser | Language | Time (microseconds, total / 1000 iter) |
|--------|----------|-------------------------------|
Nique_372
2026-10-03 17:00:34 -05:00
| **JsonParserByLeo** | MQL5 | **115** |
| YamlParserByLeo | MQL5 | 142 (falta revisar) |
| MQL5-JsonLib | MQL5 | 235 |
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 308 |
| ToyJson3 | MQL5 | 333 |
| FastJson v3.7 | MQL5 | 385 |
| JAson | MQL5 | 460 |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 523 |
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 8826 |
Nique_372
2026-08-28 17:39:28 -05:00
#### Access — Large array (10K integer elements)
Sequential/indexed access across a 10,000-element integer array.
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-08-28 17:39:28 -05:00
| Parser | Language | Time (microseconds, total / 1000 iter) |
|--------|----------|-------------------------------|
Nique_372
2026-10-03 17:00:34 -05:00
| **JsonParserByLeo** | MQL5 | **104** |
Nique_372
2026-08-28 17:39:28 -05:00
| YamlParserByLeo | MQL5 | 115 |
Nique_372
2026-10-03 17:00:34 -05:00
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 254 |
| JAson | MQL5 | 267 |
| ToyJson3 | MQL5 | 373 |
| MQL5-JsonLib | MQL5 | 384 |
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 9758 |
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 15550 |
| FastJson v3.7 | MQL5 | 16414 |
Nique_372
2026-08-28 17:39:28 -05:00
#### Access — Deep access
Access through deeply nested object/array paths.
| Parser | Language | Time (microseconds, total / 1000 iter) |
|--------|----------|-------------------------------|
Nique_372
2026-10-03 17:00:34 -05:00
| **ToyJson3** | MQL5 | **117** |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 227 |
| JAson | MQL5 | 387 |
| JsonParserByLeo | MQL5 | 573 |
| YamlParserByLeo | MQL5 | 755 (falta revisar) |
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 912 |
| MQL5-JsonLib | MQL5 | 982 |
| FastJson v3.7 | MQL5 | 2236 |
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 2522 |
Nique_372
2026-08-28 17:39:28 -05:00
#### Access — Mixed trading-data access pattern
A mixed read pattern modeled on typical trading-data access (combination of key lookups, array indexing, and nested paths).
Nique_372
2026-08-28 17:46:08 -05:00
| Parser | Language | Time (microseconds, total 500 iterations) |
Nique_372
2026-08-28 17:39:28 -05:00
|--------|----------|-------------------------------|
Nique_372
2026-10-03 17:00:34 -05:00
| JAson | MQL5 | 543 |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 658 |
| ToyJson3 | MQL5 | 928 |
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 930 |
Nique_372
2026-08-28 17:39:28 -05:00
| MQL5-JsonLib | MQL5 | 984 |
Nique_372
2026-10-03 17:00:34 -05:00
| YamlParserByLeo | MQL5 | 2258 (falta revisar) |
| JsonParserByLeo | MQL5 | 2297 |
| FastJson v3.7 | MQL5 | 2754 |
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 5894 |
Nique_372
2026-08-28 08:28:39 -05:00
Nique_372
2026-10-03 17:00:34 -05:00
#### Serialization
Serialization of (test.json) using the files from the previous tests
| Parser | Language | Time (ms, total / 1000 iter) |
|--------|----------|-------------------------------|
| FastJson v3.7 | MQL5 | 555 |
| JsonParserByLeo (DOM mode - with pointers, etc..) | MQL5 | 750 |
| JAson | MQL5 | 194068.9 |
| MQL5-JsonLib | MQL5 | 4503261.352 |
Nique_372
2026-08-28 08:28:39 -05:00
## Machine
Nique_372
2026-08-28 17:39:28 -05:00
Nique_372
2026-08-28 08:28:39 -05:00
- OS Name: Microsoft Windows 10 Pro
- Version: 10.0.19045 Build 19045
- OS Manufacturer: Microsoft Corporation
- System Manufacturer: LENOVO
- System Model: 81DE
- System Type: x64-based PC
- System SKU: LENOVO_MT_81DE_BU_idea_FM_ideapad 330-15IKB
- Processor: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz, 1800 MHz, 4 Cores, 8 Logical Processors
- RAM Type (Form Factor): SODIMM
- RAM Speed: 2133 MHz
- Installed Physical Memory (RAM): 8.00 GB
- Total Physical Memory: 7.91 GB
- Available Physical Memory: 2.87 GB
- Total Virtual Memory: 15.2 GB
- Available Virtual Memory: 9.13 GB
- Page File Space: 7.25 GB
- Storage: 13 GB Intel MEMPEI1J016GAL SSD, 224 GB HP SSD S650 240GB SSD
- Graphics Card: AMD Radeon(TM) 530 (2 GB), Intel(R) UHD Graphics 620 (128 MB)
## Performance notes
Nique_372
2026-08-28 17:39:28 -05:00
- MQL5 runs: MetaTrader 5 x64, build 5836-6070.
- Python/C++/Rust runs: same machine (Python 3.10.9).
- C++ compiled with optimizations (`/O2` in MSVC).
- Rust compiled with maximum optimization (`target=native`, LTO, `opt-level=3`, etc.).
## Auditing the results
The complete `.db` file and the raw `.log` file used to produce it are included in the repository releases, for anyone who wants to independently audit or reproduce these numbers.