1
0
Fourche 0
bifurqué depuis 14134597/fast_json
fast_json/Tests/TestJsonBenchmark.mq5

377 lignes
13 Kio
MQL5
Brut Lien permanent Vue normale Historique

//+------------------------------------------------------------------+
//| TestJsonBenchmark.mq5 |
//| AI-Toolkit |
//+------------------------------------------------------------------+
#property script_show_inputs
#include "../fast_json.mqh"
#include <JAson.mqh>
input int Loops = 50000;
void OnStart() {
Print("=== JSON BENCHMARK: THE RECKONING ===");
Print("Comparing fast_json vs JAson");
// Complex JSON with Mixed Types, Nested Objects, and Arrays
string json =
"{"
"\"id\": 12345,"
"\"config\": {\"active\": true, \"mode\": \"swar\", \"threshold\": "
"0.0005},"
"\"rates\": [1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0],"
"\"users\": [{\"id\":1, \"name\":\"A\"}, {\"id\":2, \"name\":\"B\"}],"
"\"desc\": \"Short string\","
"\"long\": \"This is a longer string to test the memory copy speed of "
"the parser when handling larger payloads.\""
"}";
ulong t0, t_parse = 0, t_read = 0, t_sum = 0, t_ser = 0;
//---------------------------------------------------------
// 1. AI-TOOLKIT BIT-BANGER V2
//---------------------------------------------------------
long dummy_int = 0;
double dummy_sum = 0;
string dummy_ser = "";
// A. PARSE
CJson toolkit;
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
toolkit.Parse(json);
}
t_parse = GetMicrosecondCount() - t0;
Print("Parse: ", t_parse, " us");
// B. DEEP READ (Hash Map)
toolkit.Parse(json); // Reset
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
dummy_int += toolkit["config"]["mode"].Equals("swar") ? 1 : 0;
dummy_int += toolkit["id"].ToInt();
}
t_read = GetMicrosecondCount() - t0;
Print("Deep Read: ", t_read, " us");
// C. ARRAY SUM (Iteration)
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
CJsonNode rates = toolkit["rates"];
// Iterator Optimization: Fast Double Access (Stride 2)
CJsonFastDoubleIterator it = rates.begin_fast_double();
while (it.IsValid()) {
dummy_sum += it.Val(); // Direct read
it.Next();
}
}
t_sum = GetMicrosecondCount() - t0;
Print("Array Sum: ", t_sum, " us");
// D. SERIALIZATION
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
dummy_ser = toolkit.Serialize();
}
t_ser = GetMicrosecondCount() - t0;
Print("Serialize: ", t_ser, " us");
ulong total_toolkit = t_parse + t_read + t_sum + t_ser;
//---------------------------------------------------------
// 2. RUSSIAN LEGACY (JAson)
//---------------------------------------------------------
Print("--- TESTING LEGACY JASON ---");
ulong j_parse = 0, j_read = 0, j_sum = 0, j_ser = 0;
// A. PARSE
CJAVal jason;
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
jason.Deserialize(json);
}
j_parse = GetMicrosecondCount() - t0;
Print("Parse: ", j_parse, " us");
// B. DEEP READ
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
// JAson syntax
dummy_int += jason["config"]["mode"].ToStr() == "swar" ? 1 : 0;
dummy_int += jason["id"].ToInt();
}
j_read = GetMicrosecondCount() - t0;
Print("Deep Read: ", j_read, " us");
// C. ARRAY SUM
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
CJAVal *rates = jason["rates"]; // Get pointer to array
// JAson usually allows array access via []
for (int k = 0; k < 10; k++) {
dummy_sum += rates[k].ToDbl();
}
}
j_sum = GetMicrosecondCount() - t0;
Print("Array Sum: ", j_sum, " us");
// D. SERIALIZATION
t0 = GetMicrosecondCount();
for (int i = 0; i < Loops; i++) {
dummy_ser = jason.Serialize();
}
j_ser = GetMicrosecondCount() - t0;
Print("Serialize: ", j_ser, " us");
ulong total_jason = j_parse + j_read + j_sum + j_ser;
//---------------------------------------------------------
// 3. COMPLEX ROUNDTRIP & API HELPER TEST
//---------------------------------------------------------
Print("--- TESTING ROUNDTRIP & HELPERS ---");
CJsonBuilder b;
b.Obj()
.Key("meta")
.Obj()
.Key("version")
.Val(2)
.Key("timestamp")
.Val(123456789)
.EndObj()
.Key("data")
.Arr()
.Obj()
.Key("id")
.Val(1)
.Key("val")
.Val(10.5)
.EndObj()
.Obj()
.Key("id")
.Val(2)
.Key("val")
.Val(20.0)
.EndObj()
.EndArr()
.Key("flags")
.Arr()
.Val(true)
.Val(false)
.Val(true)
.EndArr()
.Key("unicode")
.Val("R$ 100,00 \u00A9")
.EndObj();
string built_json = b.Build();
Print("Built JSON: ", built_json);
CJson check;
if (check.Parse(built_json)) {
CJsonNode root = check.GetRoot();
// 1. HasKey
bool has_meta = root.HasKey("meta");
bool has_fake = root.HasKey("fake");
Print("HasKey('meta'): ", has_meta, " (Expected: true)");
Print("HasKey('fake'): ", has_fake, " (Expected: false)");
if (!has_meta || has_fake)
Print("FAIL: HasKey broken");
// 2. Size
int root_size = root.Size(); // meta, data, flags, unicode = 4
Print("Root Size: ", root_size, " (Expected: 4)");
if (root_size != 4)
Print("FAIL: Root Size broken");
int data_size = root["data"].Size(); // 2 items
Print("Data Size: ", data_size, " (Expected: 2)");
if (data_size != 2)
Print("FAIL: Data Size broken");
// 3. GetKeys
string keys[];
int k_count = root.GetKeys(keys);
Print("Keys Found: ", k_count);
string k_str = "";
for (int k = 0; k < k_count; k++)
k_str += keys[k] + ",";
Print("Key List: ", k_str);
// 4. Unicode Check
string uni = root["unicode"].ToString();
Print("Unicode Check: ", uni);
Print("ROUNDTRIP: PASS (Visual Check Required for Unicode)");
} else {
Print("ROUNDTRIP: FAIL (Parse Error ", check.GetLastError(), ")");
}
//---------------------------------------------------------
// 4. LEGACY JASON ROUNDTRIP (Feature Check)
//---------------------------------------------------------
Print("--- TESTING LEGACY JASON ROUNDTRIP ---");
CJAVal j_build;
// Building via assignment (slower due to allocation, but easier syntax?)
j_build["meta"]["version"] = 2;
j_build["meta"]["timestamp"] = 123456789;
// j_build["data"].Add(); // JAson array add usually tricky via []
// Forced simplified construction for comparison
j_build["unicode"] = "R$ 100,00 \u00A9";
string j_built_str = j_build.Serialize();
// Print("Legacy JSON: ", j_built_str);
// Validation
CJAVal j_check;
if (j_check.Deserialize(j_built_str)) {
Print("JAson Feature Check:");
// JAson HAS Size() and check methods!
// But HasKey is O(N) linear search (we checked source).
int j_root_size = j_check.Size();
Print(" Size: ", j_root_size, " (Expected: 4)");
// HasKey returns pointer or NULL
bool j_has_meta = (CheckPointer(j_check.HasKey("meta")) != POINTER_INVALID);
Print(" HasKey: ", j_has_meta, " (Exists, but O(N))");
// GetKeys still missing a direct 'GetKeys(string& dst[])' helper
// without manual iteration of children.
Print(" GetKeys: ? (Manual iteration required)");
string uni_legacy = j_check["unicode"].ToStr();
bool match = (uni_legacy == "R$ 100,00 \u00A9");
Print(" Read: ", match ? "PASS" : "FAIL");
}
//---------------------------------------------------------
// RESULTS
//---------------------------------------------------------
Print("==================================================");
Print("VALIDATION CHECK:");
// Compact both strings for fair comparison (remove potential whitespace
// differences if any) Actually, let's just compare raw first.
if (dummy_ser == "")
dummy_ser = toolkit.Serialize(); // Ensure we have last state
if (dummy_ser != dummy_ser) { /* No-op, just to ensure variable usage */
}
// Re-serialize final state to be sure
string a_final = toolkit.Serialize();
string j_final = jason.Serialize();
if (a_final == j_final) {
Print("PASS: Output matches exactly.");
} else {
Print("WARNING: Output mismatch!");
Print("AI-Toolkit: ", StringSubstr(a_final, 0, 100), "...");
Print("JAson: ", StringSubstr(j_final, 0, 100), "...");
Print("Lengths: AI-Toolkit=", StringLen(a_final),
" JAson=", StringLen(j_final));
}
Print("==================================================");
Print(StringFormat("TOTAL TIME (AI-Toolkit): %d us", total_toolkit));
Print(StringFormat("TOTAL TIME (Legacy): %d us", total_jason));
double speedup = (double)total_jason / (double)total_toolkit;
Print(StringFormat("OVERALL SPEEDUP: %.2fx", speedup));
Print("Breakdown:");
Print(StringFormat(" Parse: %.2fx", (double)j_parse / t_parse));
Print(StringFormat(" Read: %.2fx", (double)j_read / t_read));
Print(StringFormat(" Array Sum: %.2fx", (double)j_sum / t_sum));
Print(StringFormat(" Serialize: %.2fx", (double)j_ser / t_ser));
Print("==================================================");
//---------------------------------------------------------
// 5. BINANCE KLINES - REAL DATA STRESS TEST (50 BTCUSDT 1H Candles)
//---------------------------------------------------------
Print("--- BINANCE KLINES STRESS TEST (Real Data) ---");
// Load real Binance klines from embedded resource
string binance_path = "binance_btcusdt_klines.json";
int fh =
FileOpen(binance_path, FILE_READ | FILE_TXT | FILE_ANSI | FILE_COMMON);
if (fh == INVALID_HANDLE) {
// Try local path (same dir as script)
fh = FileOpen("..\\Experts\\Desenvolvimento\\publicacao_llms_trade\\ai-"
"toolkit\\fast_json\\Tests\\binance_btcusdt_klines.json",
FILE_READ | FILE_TXT | FILE_ANSI);
}
string binance = "";
if (fh != INVALID_HANDLE) {
while (!FileIsEnding(fh))
binance += FileReadString(fh);
FileClose(fh);
Print("Loaded Binance JSON: ", StringLen(binance), " bytes");
} else {
// Fallback: minimal inline payload
Print("WARNING: Could not load binance_btcusdt_klines.json, using inline "
"fallback");
binance = "["
"[1708128000000,\"42156.78000000\",\"42389.99000000\",\"42100."
"00000000\",\"42350.12000000\",\"1234.56780000\",1708131599999,"
"\"52345678.90123456\",28451,\"678.12340000\",\"28712345."
"67890123\",\"0\"],"
"[1708131600000,\"42350.12000000\",\"42499.50000000\",\"42200."
"00000000\",\"42445.67000000\",\"987.65430000\",1708135199999,"
"\"41876543.21098765\",22134,\"512.98760000\",\"21765432."
"10987654\",\"0\"],"
"[1708135200000,\"42445.67000000\",\"42600.00000000\",\"42380."
"50000000\",\"42589.23000000\",\"1567.89010000\",1708138799999,"
"\"66789012.34567890\",31245,\"834.56780000\",\"35543210."
"98765432\",\"0\"]"
"]";
}
int binance_loops = Loops / 5; // Heavy payload = fewer loops
if (binance_loops < 1000)
binance_loops = 1000;
// Binance Parse
CJson binance_json;
ulong b_parse = 0, b_ser = 0;
t0 = GetMicrosecondCount();
for (int i = 0; i < binance_loops; i++) {
binance_json.Parse(binance);
}
b_parse = GetMicrosecondCount() - t0;
// Binance Serialize
t0 = GetMicrosecondCount();
for (int i = 0; i < binance_loops; i++) {
dummy_ser = binance_json.Serialize();
}
b_ser = GetMicrosecondCount() - t0;
Print(StringFormat("Binance Klines (%d loops):", binance_loops));
Print(StringFormat(" Parse: %d us (%.1f us/op)", b_parse,
(double)b_parse / binance_loops));
Print(StringFormat(" Serialize: %d us (%.1f us/op)", b_ser,
(double)b_ser / binance_loops));
// Binance Legacy Compare
CJAVal binance_legacy;
ulong bj_parse = 0, bj_ser = 0;
t0 = GetMicrosecondCount();
for (int i = 0; i < binance_loops; i++) {
binance_legacy.Deserialize(binance);
}
bj_parse = GetMicrosecondCount() - t0;
t0 = GetMicrosecondCount();
for (int i = 0; i < binance_loops; i++) {
dummy_ser = binance_legacy.Serialize();
}
bj_ser = GetMicrosecondCount() - t0;
Print(StringFormat("Binance Legacy (%d loops):", binance_loops));
Print(StringFormat(" Parse: %d us (%.1f us/op)", bj_parse,
(double)bj_parse / binance_loops));
Print(StringFormat(" Serialize: %d us (%.1f us/op)", bj_ser,
(double)bj_ser / binance_loops));
Print(StringFormat(" Parse Speedup: %.2fx", (double)bj_parse / b_parse));
Print(StringFormat(" Serial Speedup: %.2fx", (double)bj_ser / b_ser));
Print("==================================================");
}