JsonParserByLeo/Test/Ben/README.md

179 lines
8.4 KiB
Markdown
Raw Permalink Normal View History

2026-08-28 08:28:39 -05:00
# Benchmark
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.
2026-08-28 08:28:39 -05:00
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.
2026-08-28 08:28:39 -05:00
## Performance
2026-08-28 17:39:28 -05:00
### Parsing
2026-08-28 08:28:39 -05:00
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.
2026-08-28 08:28:39 -05:00
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."
2026-08-28 08:28:39 -05:00
| Parser | Language | Time (ms, total / 1000 iter) |
|--------|----------|-------------------------------|
2026-08-28 18:20:11 -05:00
| **JsonParserByLeo** (with SIMD, via DLL) | MQL5 / C++ DLL | **356-361** |
2026-08-28 08:28:39 -05:00
| **simdjson::dom::parser** (reused parser) | C++ | **380-384** |
2026-08-28 17:39:28 -05:00
| **sonic-rs** (typed struct) | Rust | **460-461** |
| **simdjson.Parser** (reused parser) | Python | **475** |
| **JsonParserByLeo** ASM (single array copy, JSONASM file, ~458 KB) | MQL5 | **637.97** |
| **JsonParserByLeo** (single array copy) | MQL5 | **647.49** |
| serde_json (typed struct) | Rust | 788-796 |
2026-08-28 18:23:31 -05:00
| YamlParserByLeo, single array copy | MQL5 | 899-900 |
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 |
2026-08-28 18:20:11 -05:00
| FastJson v3.7, single array copy | MQL5 | 1213.43 |
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 |
2026-08-28 08:28:39 -05:00
| orjson | Python | 1863 |
2026-08-28 17:39:28 -05:00
| ryml (pure parse time) | C++ | 2846.55 |
2026-08-28 08:28:39 -05:00
| simdjson.Parser + as_dict | Python | 4309 |
2026-08-28 17:39:28 -05:00
| ToyJson3, single string copy, tokenization only | MQL5 | 4418.49 |
2026-08-28 08:28:39 -05:00
| simdjson.loads | Python | 4955 |
| ujson | Python | 5322 |
| json (stdlib) | Python | 5860 |
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 |
2026-08-28 08:28:39 -05:00
2026-08-28 17:39:28 -05:00
### Access benchmarks
2026-08-28 08:28:39 -05:00
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.
2026-08-28 08:28:39 -05:00
2026-08-28 17:39:28 -05:00
#### Access — Wide object (100 keys)
2026-08-28 08:28:39 -05:00
2026-08-28 17:39:28 -05:00
Repeated key lookups across a flat object with 100 keys.
2026-08-28 08:28:39 -05:00
| Parser | Language | Time (microseconds, total / 1000 iter) |
|--------|----------|-------------------------------|
2026-08-28 17:39:28 -05:00
| **JsonParserByLeo** | MQL5 | **135** |
| JsonParserByLeo-ASM | MQL5 | 140 |
| YamlParserByLeo | MQL5 | 142 |
| JsonParserByLeo-DLL | MQL5 | 149 |
| MQL5-JsonLib | MQL5 | 227 |
2026-08-28 18:20:11 -05:00
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 301 |
2026-08-28 17:39:28 -05:00
| ToyJson3 | MQL5 | 325 |
2026-08-28 18:20:11 -05:00
| FastJson v3.7 | MQL5 | 372 |
2026-08-28 17:39:28 -05:00
| JAson | MQL5 | 453 |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 522 |
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 8880 |
#### Access — Large array (10K integer elements)
Sequential/indexed access across a 10,000-element integer array.
2026-08-28 08:28:39 -05:00
2026-08-28 17:39:28 -05:00
| Parser | Language | Time (microseconds, total / 1000 iter) |
|--------|----------|-------------------------------|
| **JsonParserByLeo** | MQL5 | **101** |
| JsonParserByLeo-ASM | MQL5 | 102 |
| JsonParserByLeo-DLL | MQL5 | 112 |
| YamlParserByLeo | MQL5 | 115 |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 238 |
| JAson | MQL5 | 283 |
| ToyJson3 | MQL5 | 371 |
| MQL5-JsonLib | MQL5 | 442 |
2026-08-28 18:20:11 -05:00
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 9738 |
2026-08-28 17:39:28 -05:00
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 15477 |
2026-08-28 18:20:11 -05:00
| FastJson v3.7 | MQL5 | 17896 |
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) |
|--------|----------|-------------------------------|
| **ToyJson3** | MQL5 | **116** |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 230 |
| JAson | MQL5 | 380 |
| JsonParserByLeo | MQL5 | 657 |
| JsonParserByLeo-ASM | MQL5 | 685 |
| JsonParserByLeo-DLL | MQL5 | 750 |
| YamlParserByLeo | MQL5 | 755 |
2026-08-28 18:20:11 -05:00
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 898 |
2026-08-28 17:39:28 -05:00
| MQL5-JsonLib | MQL5 | 1022 |
2026-08-28 18:20:11 -05:00
| FastJson v3.7 | MQL5 | 2257 |
2026-08-28 17:39:28 -05:00
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 2554 |
#### 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).
2026-08-28 17:46:08 -05:00
| Parser | Language | Time (microseconds, total 500 iterations) |
2026-08-28 17:39:28 -05:00
|--------|----------|-------------------------------|
2026-08-28 18:20:11 -05:00
| Claude Fable 5 (Effort=Max), generated code (fast JSON lib), single array copy, 3+ iterations with feedback | MQL5 | 352 |
2026-08-28 17:39:28 -05:00
| JAson | MQL5 | 432 |
| CJsonNode (MQL5 Articles reference implementation) | MQL5 | 577 |
| ToyJson3 | MQL5 | 765 |
| MQL5-JsonLib | MQL5 | 984 |
| JsonParserByLeo | MQL5 | 1782 |
| JsonParserByLeo-ASM | MQL5 | 1887 |
| JsonParserByLeo-DLL | MQL5 | 2006 |
2026-08-28 18:20:11 -05:00
| FastJson v3.7 | MQL5 | 2057 |
2026-08-28 17:39:28 -05:00
| YamlParserByLeo | MQL5 | 2258 |
| GLM 5.2 (Max, deep thinking), generated code | MQL5 | 4274 |
2026-08-28 08:28:39 -05:00
## Machine
2026-08-28 17:39:28 -05:00
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
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.