From 4d25f1d905047d9909f998f41f94446ad98ec62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva=20de=20Jesus?= Date: Mon, 12 Aug 2024 03:31:32 -0300 Subject: [PATCH] Create parse micro-bench for JsonNode and fix other JsonNode bench namespace --- .../System.Text.Json/Node/NodeParse.cs | 161 ++++++++++++++++++ .../System.Text.Json/Node/ParseThenWrite.cs | 130 +++++++------- 2 files changed, 227 insertions(+), 64 deletions(-) create mode 100644 src/benchmarks/micro/libraries/System.Text.Json/Node/NodeParse.cs diff --git a/src/benchmarks/micro/libraries/System.Text.Json/Node/NodeParse.cs b/src/benchmarks/micro/libraries/System.Text.Json/Node/NodeParse.cs new file mode 100644 index 00000000000..11cb6ef835f --- /dev/null +++ b/src/benchmarks/micro/libraries/System.Text.Json/Node/NodeParse.cs @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; +using System.Text.Json.Document.Tests; +using System.Text.Json.Tests; + +namespace System.Text.Json.Nodes.Tests; + +[BenchmarkCategory(Categories.Libraries, Categories.JSON)] +public class Perf_NodeParse +{ + public enum TestCaseType + { + HelloWorld, + BasicJson, + Json400B, + Json400KB + } + + [ParamsAllValues] + public TestCaseType TestCase; + + [Params(true, false)] + public bool IsDataIndented; + + [Params(false, true)] + public bool TestRandomAccess; + + private byte[] _dataUtf8; + + [GlobalSetup] + public void Setup() + { + string jsonString = JsonStrings.ResourceManager.GetString(TestCase.ToString()); + + // Remove all formatting/indentation + if (!IsDataIndented) + { + _dataUtf8 = DocumentHelpers.RemoveFormatting(jsonString); + } + else + { + _dataUtf8 = Encoding.UTF8.GetBytes(jsonString); + } + } + + [Benchmark] + [MemoryRandomization] + public void Parse() + { + JsonNode node = JsonNode.Parse(_dataUtf8); + if (TestRandomAccess) + { + if (TestCase == TestCaseType.HelloWorld) + { + ReadHelloWorld(node); + } + else if (TestCase == TestCaseType.Json400B) + { + ReadJson400B(node); + } + else if (TestCase == TestCaseType.BasicJson) + { + ReadJsonBasic(node); + } + else if (TestCase == TestCaseType.Json400KB) + { + ReadJson400KB(node); + } + } + } + + private static string ReadHelloWorld(JsonNode node) + { + string message = node["message"].GetValue(); + return message; + } + + private static void ReadJson400B(JsonNode node) + { + JsonArray nodeArr = node.AsArray(); + for (int i = 0; i < nodeArr.Count; i++) + { + nodeArr[i]["_id"].GetValue(); + nodeArr[i]["index"].GetValue(); + nodeArr[i]["isActive"].GetValue(); + nodeArr[i]["balance"].GetValue (); + nodeArr[i]["picture"].GetValue(); + nodeArr[i]["age"].GetValue(); + nodeArr[i]["email"].GetValue(); + nodeArr[i]["phone"].GetValue(); + nodeArr[i]["address"].GetValue(); + nodeArr[i]["registered"].GetValue(); + nodeArr[i]["latitude"].GetValue(); + nodeArr[i]["longitude"].GetValue(); + } + } + + private static void ReadJsonBasic(JsonNode node) + { + node["age"].GetValue(); + node["first"].GetValue(); + node["last"].GetValue(); + + JsonArray phoneNumbers = node["phoneNumbers"].AsArray(); + for (int i = 0; i < phoneNumbers.Count; i++) + { + phoneNumbers[i].GetValue(); + } + + JsonNode address = node["address"]; + address["street"].GetValue(); + address["city"].GetValue(); + address["zip"].GetValue(); + } + + private static void ReadJson400KB(JsonNode node) + { + JsonArray nodeArr = node.AsArray(); + for (int i = 0; i < nodeArr.Count; i++) + { + nodeArr[i]["_id"].GetValue(); + nodeArr[i]["index"].GetValue(); + nodeArr[i]["guid"].GetValue(); + nodeArr[i]["isActive"].GetValue(); + nodeArr[i]["balance"].GetValue(); + nodeArr[i]["picture"].GetValue(); + nodeArr[i]["age"].GetValue(); + nodeArr[i]["eyeColor"].GetValue(); + nodeArr[i]["name"].GetValue(); + nodeArr[i]["gender"].GetValue(); + nodeArr[i]["company"].GetValue(); + nodeArr[i]["email"].GetValue(); + nodeArr[i]["phone"].GetValue(); + nodeArr[i]["address"].GetValue(); + nodeArr[i]["about"].GetValue(); + nodeArr[i]["registered"].GetValue(); + nodeArr[i]["latitude"].GetValue(); + nodeArr[i]["longitude"].GetValue(); + + JsonArray tagsObject = nodeArr[i]["tags"].AsArray(); + for (int j = 0; j < tagsObject.Count; j++) + { + tagsObject[j].GetValue(); + } + + JsonArray friendsObject = node[i]["friends"].AsArray(); + for (int j = 0; j < friendsObject.Count; j++) + { + friendsObject[j]["id"].GetValue(); + friendsObject[j]["name"].GetValue(); + } + + node[i]["greeting"].GetValue(); + node[i]["favoriteFruit"].GetValue(); + } + } +} diff --git a/src/benchmarks/micro/libraries/System.Text.Json/Node/ParseThenWrite.cs b/src/benchmarks/micro/libraries/System.Text.Json/Node/ParseThenWrite.cs index 7bfd80f49f6..9eacbd96afa 100644 --- a/src/benchmarks/micro/libraries/System.Text.Json/Node/ParseThenWrite.cs +++ b/src/benchmarks/micro/libraries/System.Text.Json/Node/ParseThenWrite.cs @@ -1,89 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using BenchmarkDotNet.Attributes; using MicroBenchmarks; using System.Buffers; using System.Collections.Generic; using System.Text.Json.Document.Tests; -using System.Text.Json.Nodes; using System.Text.Json.Tests; -namespace System.Text.Json.Node.Tests +namespace System.Text.Json.Nodes.Tests; + +[BenchmarkCategory(Categories.Libraries, Categories.JSON)] +public class Perf_ParseThenWrite { - [BenchmarkCategory(Categories.Libraries, Categories.JSON)] - public class Perf_ParseThenWrite + public enum TestCaseType { - public enum TestCaseType - { - HelloWorld, - DeepTree, - BroadTree, - LotsOfNumbers, - LotsOfStrings, - Json400B, - Json4KB, - Json400KB - } - - private byte[] _dataUtf8; - private Utf8JsonWriter _writer; + HelloWorld, + DeepTree, + BroadTree, + LotsOfNumbers, + LotsOfStrings, + Json400B, + Json4KB, + Json400KB + } - [ParamsAllValues] - public TestCaseType TestCase; + private byte[] _dataUtf8; + private Utf8JsonWriter _writer; - [Params(true, false)] - public bool IsDataIndented; + [ParamsAllValues] + public TestCaseType TestCase; - [GlobalSetup] - public void Setup() - { - string jsonString = JsonStrings.ResourceManager.GetString(TestCase.ToString()); + [Params(true, false)] + public bool IsDataIndented; - if (!IsDataIndented) - { - _dataUtf8 = DocumentHelpers.RemoveFormatting(jsonString); - } - else - { - _dataUtf8 = Encoding.UTF8.GetBytes(jsonString); - } + [GlobalSetup] + public void Setup() + { + string jsonString = JsonStrings.ResourceManager.GetString(TestCase.ToString()); - var abw = new ArrayBufferWriter(); - _writer = new Utf8JsonWriter(abw, new JsonWriterOptions { Indented = IsDataIndented }); + if (!IsDataIndented) + { + _dataUtf8 = DocumentHelpers.RemoveFormatting(jsonString); } - - [GlobalCleanup] - public void CleanUp() + else { - _writer.Dispose(); + _dataUtf8 = Encoding.UTF8.GetBytes(jsonString); } - [Benchmark] - [MemoryRandomization] - public void ParseThenWrite() - { - _writer.Reset(); + var abw = new ArrayBufferWriter(); + _writer = new Utf8JsonWriter(abw, new JsonWriterOptions { Indented = IsDataIndented }); + } + + [GlobalCleanup] + public void CleanUp() + { + _writer.Dispose(); + } - JsonNode jsonNode = JsonNode.Parse(_dataUtf8); - WalkNode(jsonNode); - jsonNode.WriteTo(_writer); + [Benchmark] + [MemoryRandomization] + public void ParseThenWrite() + { + _writer.Reset(); + JsonNode jsonNode = JsonNode.Parse(_dataUtf8); + WalkNode(jsonNode); + jsonNode.WriteTo(_writer); - static void WalkNode(JsonNode node) - { - // Forces conversion of lazy JsonElement representation of document into - // a materialized JsonNode tree so that we measure writing performance - // of the latter representation. - switch (node) - { - case JsonObject obj: - foreach (KeyValuePair kvp in obj) - WalkNode(kvp.Value); - break; - case JsonArray arr: - foreach (JsonNode elem in arr) - WalkNode(elem); - break; - } + static void WalkNode(JsonNode node) + { + // Forces conversion of lazy JsonElement representation of document into + // a materialized JsonNode tree so that we measure writing performance + // of the latter representation. + + switch (node) + { + case JsonObject obj: + foreach (KeyValuePair kvp in obj) + WalkNode(kvp.Value); + break; + case JsonArray arr: + foreach (JsonNode elem in arr) + WalkNode(elem); + break; } } }