[clang] [clang-tools-extra] [llvm] [Support][JSON] Use `std::unordered_map` for object storage (PR #171230)
Zixu Wang via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 13 18:48:14 PDT 2026
https://github.com/zixu-w updated https://github.com/llvm/llvm-project/pull/171230
>From 94b70f40903baeea9b0d0d3e570e73f0b17d7274 Mon Sep 17 00:00:00 2001
From: Zixu Wang <zixu_wang at apple.com>
Date: Mon, 8 Dec 2025 15:21:23 -0800
Subject: [PATCH 1/3] [Support][JSON] Use `std::unordered_map` for object
storage
`llvm::DenseMap` is not suitable for the key-value `Storage` inside
`llvm::json::Object`. Use `std::unordered_map` instead to optimize
memory usage.
`llvm::DenseMap` is optimized for mapping small keys and values
(pointers), and it pre-allocates 64 buckets by default.
`llvm::json::ObjectKey` is 24 bytes in size, and `llvm::json::Value` is
40 bytes. Currently, the JSON parser allocates 4KB of memory for each
JSON object. In practice, most JSON objects contain only a handful of
fields, and likely to have lists of many small objects. This is a
significant waste of memory.
---
clang-tools-extra/clang-doc/JSONGenerator.cpp | 2 +-
clang/lib/Basic/DarwinSDKInfo.cpp | 14 +++++++-------
clang/tools/clang-installapi/Options.cpp | 4 ++--
clang/unittests/Basic/SarifTest.cpp | 2 +-
llvm/include/llvm/Support/JSON.h | 15 ++++++++++-----
llvm/lib/Support/JSON.cpp | 4 ++--
6 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index e895d641a6000..d4d12083197d5 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -155,7 +155,7 @@ static void insertComment(Object &Description, json::Value &Comment,
Description[Key] = std::move(CommentsArray);
Description["Has" + Key.str()] = true;
} else {
- DescriptionIt->getSecond().getAsArray()->push_back(Comment);
+ DescriptionIt->second.getAsArray()->push_back(Comment);
}
}
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index f7d02ef97f5a4..39d08387f8d1a 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -25,7 +25,7 @@ std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
return MaximumValue;
auto KV = Mapping.find(Key.normalize());
if (KV != Mapping.end())
- return KV->getSecond();
+ return KV->second;
// If no exact entry found, try just the major key version. Only do so when
// a minor version number is present, to avoid recursing indefinitely into
// the major-only check.
@@ -43,10 +43,10 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
VersionTuple MinValue = Min;
llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
for (const auto &KV : Obj) {
- if (auto Val = KV.getSecond().getAsString()) {
+ if (auto Val = KV.second.getAsString()) {
llvm::VersionTuple KeyVersion;
llvm::VersionTuple ValueVersion;
- if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
+ if (KeyVersion.tryParse(KV.first) || ValueVersion.tryParse(*Val))
return std::nullopt;
Mapping[KeyVersion.normalize()] = ValueVersion;
if (KeyVersion < Min)
@@ -119,7 +119,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
for (auto SupportedTargetPair : *SupportedTargets) {
llvm::json::Object *SupportedTarget =
- SupportedTargetPair.getSecond().getAsObject();
+ SupportedTargetPair.second.getAsObject();
auto Vendor = SupportedTarget->getString("LLVMTargetTripleVendor");
auto OS = SupportedTarget->getString("LLVMTargetTripleSys");
if (!Vendor || !OS)
@@ -136,7 +136,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
// The key is either the Xcode platform, or a variant. The platform must be
// the first entry in the returned PlatformInfoStorageType.
- StringRef PlatformOrVariant = SupportedTargetPair.getFirst();
+ StringRef PlatformOrVariant = SupportedTargetPair.first;
StringRef EffectivePlatformPrefix;
// Ignore iosmac value if it exists.
@@ -202,12 +202,12 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
// FIXME: Generalize this out beyond iOS-deriving targets.
// Look for ios_<targetos> version mapping for targets that derive from ios.
for (const auto &KV : *VM) {
- auto Pair = StringRef(KV.getFirst()).split("_");
+ auto Pair = StringRef(KV.first).split("_");
if (Pair.first.compare_insensitive("ios") == 0) {
llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
if (TT.getOS() != llvm::Triple::UnknownOS) {
auto Mapping = RelatedTargetVersionMapping::parseJSON(
- *KV.getSecond().getAsObject(), *MaximumDeploymentVersion);
+ *KV.second.getAsObject(), *MaximumDeploymentVersion);
if (Mapping)
VersionMappings[OSEnvPair(llvm::Triple::IOS,
llvm::Triple::UnknownEnvironment,
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index f484d6f33ad8f..1151f65af4dce 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -84,8 +84,8 @@ getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
return llvm::opt::InputArgList();
for (const auto &KV : *Root) {
- const Array *ArgList = KV.getSecond().getAsArray();
- std::string Label = "-X" + KV.getFirst().str();
+ const Array *ArgList = KV.second.getAsArray();
+ std::string Label = "-X" + KV.first.str();
if (!ArgList)
return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
for (auto Arg : *ArgList) {
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index 42e85085d646e..cfae48a96c2a8 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -83,7 +83,7 @@ TEST_F(SarifDocumentWriterTest, canCreateEmptyDocument) {
const llvm::json::Object &EmptyDoc = Writer.createDocument();
std::vector<StringRef> Keys(EmptyDoc.size());
std::transform(EmptyDoc.begin(), EmptyDoc.end(), Keys.begin(),
- [](auto Item) { return Item.getFirst(); });
+ [](auto Item) { return Item.first; });
// THEN:
ASSERT_THAT(Keys, testing::UnorderedElementsAre("$schema", "version"));
diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h
index 27862eb7ab6bb..7b7a7b29aca40 100644
--- a/llvm/include/llvm/Support/JSON.h
+++ b/llvm/include/llvm/Support/JSON.h
@@ -47,6 +47,7 @@
#define LLVM_SUPPORT_JSON_H
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -93,10 +94,14 @@ class ObjectKey;
class Value;
template <typename T> Value toJSON(const std::optional<T> &Opt);
+struct ObjectKeyHash {
+ size_t operator()(const StringRef &K) const { return hash_value(K); }
+};
+
/// An Object is a JSON object, which maps strings to heterogenous JSON values.
-/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string.
+/// ObjectKey is a maybe-owned string.
class Object {
- using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
+ using Storage = std::unordered_map<ObjectKey, Value, ObjectKeyHash>;
Storage M;
public:
@@ -133,8 +138,8 @@ class Object {
bool erase(StringRef K);
void erase(iterator I) { M.erase(I); }
- iterator find(StringRef K) { return M.find_as(K); }
- const_iterator find(StringRef K) const { return M.find_as(K); }
+ iterator find(const ObjectKey &K) { return M.find(K); }
+ const_iterator find(const ObjectKey &K) const { return M.find(K); }
// operator[] acts as if Value was default-constructible as null.
LLVM_ABI Value &operator[](const ObjectKey &K);
LLVM_ABI Value &operator[](ObjectKey &&K);
@@ -646,7 +651,7 @@ inline Object::Object(std::initializer_list<KV> Properties) {
for (const auto &P : Properties) {
auto R = try_emplace(P.K, nullptr);
if (R.second)
- R.first->getSecond().moveFrom(std::move(P.V));
+ R.first->second.moveFrom(std::move(P.V));
}
}
inline std::pair<Object::iterator, bool> Object::insert(KV E) {
diff --git a/llvm/lib/Support/JSON.cpp b/llvm/lib/Support/JSON.cpp
index 23c2542d75810..3124e6f0b8da8 100644
--- a/llvm/lib/Support/JSON.cpp
+++ b/llvm/lib/Support/JSON.cpp
@@ -22,10 +22,10 @@ namespace llvm {
namespace json {
Value &Object::operator[](const ObjectKey &K) {
- return try_emplace(K, nullptr).first->getSecond();
+ return try_emplace(K, nullptr).first->second;
}
Value &Object::operator[](ObjectKey &&K) {
- return try_emplace(std::move(K), nullptr).first->getSecond();
+ return try_emplace(std::move(K), nullptr).first->second;
}
Value *Object::get(StringRef K) {
auto I = find(K);
>From 065f4bc0a67f62f5398088bfa4c9e8d876d3e0f5 Mon Sep 17 00:00:00 2001
From: Zixu Wang <zixu_wang at apple.com>
Date: Mon, 13 Apr 2026 17:24:05 -0700
Subject: [PATCH 2/3] [NFC] Update header includes for JSON.h
Remove unused DenseMap.h and Hashing.h includes from JSON.h after
replacing `DenseMap` with `std::unordered_map`.
Include missing AlignOf.h transitively included by DenseMap.h
Add missing DenseMap.h includes transitively brought in by JSON.h
---
clang/include/clang/Basic/Sarif.h | 1 +
llvm/include/llvm/Support/JSON.h | 4 ++--
llvm/tools/llvm-mca/Views/InstructionInfoView.h | 1 +
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/Sarif.h b/clang/include/clang/Basic/Sarif.h
index 7651d2ac7a768..a9099271ccc0c 100644
--- a/clang/include/clang/Basic/Sarif.h
+++ b/clang/include/clang/Basic/Sarif.h
@@ -34,6 +34,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Version.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h
index 7b7a7b29aca40..d48cf3585a85d 100644
--- a/llvm/include/llvm/Support/JSON.h
+++ b/llvm/include/llvm/Support/JSON.h
@@ -46,17 +46,17 @@
#ifndef LLVM_SUPPORT_JSON_H
#define LLVM_SUPPORT_JSON_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <cmath>
#include <map>
+#include <unordered_map>
namespace llvm {
namespace json {
diff --git a/llvm/tools/llvm-mca/Views/InstructionInfoView.h b/llvm/tools/llvm-mca/Views/InstructionInfoView.h
index 34c6fec46a6d5..a54d21528b72e 100644
--- a/llvm/tools/llvm-mca/Views/InstructionInfoView.h
+++ b/llvm/tools/llvm-mca/Views/InstructionInfoView.h
@@ -36,6 +36,7 @@
#include "Views/InstructionView.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
>From 725ca51139d059d3485b3f85f8ee3002b414ef31 Mon Sep 17 00:00:00 2001
From: Zixu Wang <zixu_wang at apple.com>
Date: Mon, 13 Apr 2026 17:40:40 -0700
Subject: [PATCH 3/3] Add JSON parser benchmarks
Add benchmarks for LLVM's JSON parser.
Generates test JSON inputs with different sizes, and measures:
- Parsing speed
- Parsing memory consumption
- Accessing speed (iterating over parsed object, fetching values with
sequential/randomized keys)
Assisted-by: Claude Code (claude-opus-4-6)
---
llvm/benchmarks/CMakeLists.txt | 1 +
llvm/benchmarks/JSONParserBM.cpp | 288 +++++++++++++++++++++++++++++++
2 files changed, 289 insertions(+)
create mode 100644 llvm/benchmarks/JSONParserBM.cpp
diff --git a/llvm/benchmarks/CMakeLists.txt b/llvm/benchmarks/CMakeLists.txt
index 69ebeaa78344b..bdd1ce40d2cb2 100644
--- a/llvm/benchmarks/CMakeLists.txt
+++ b/llvm/benchmarks/CMakeLists.txt
@@ -15,6 +15,7 @@ add_benchmark(MustacheBench Mustache.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(SpecialCaseListBM SpecialCaseListBM.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(DWARFVerifierBM DWARFVerifierBM.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(PointerUnionBM PointerUnionBM.cpp PARTIAL_SOURCES_INTENDED)
+add_benchmark(JSONParserBM JSONParserBM.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(RuntimeLibcallsBench RuntimeLibcalls.cpp PARTIAL_SOURCES_INTENDED)
diff --git a/llvm/benchmarks/JSONParserBM.cpp b/llvm/benchmarks/JSONParserBM.cpp
new file mode 100644
index 0000000000000..3454d70f8c28e
--- /dev/null
+++ b/llvm/benchmarks/JSONParserBM.cpp
@@ -0,0 +1,288 @@
+//===- JSONParserBM.cpp - JSON parser benchmarks --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "benchmark/benchmark.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/JSON.h"
+#include <algorithm>
+#include <atomic>
+#include <random>
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Memory tracking via global operator new
+//===----------------------------------------------------------------------===//
+
+static std::atomic_size_t TotalAllocatedBytes{0};
+static std::atomic_size_t NumAllocs{0};
+static bool TrackMemory = false;
+
+// Single-object new/delete.
+void *operator new(std::size_t Size) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new(std::size_t Size, std::align_val_t) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new(std::size_t Size, const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new(std::size_t Size, std::align_val_t,
+ const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void operator delete(void *Ptr) noexcept { std::free(Ptr); }
+void operator delete(void *Ptr, std::align_val_t) noexcept { std::free(Ptr); }
+void operator delete(void *Ptr, std::size_t) noexcept { std::free(Ptr); }
+void operator delete(void *Ptr, std::size_t, std::align_val_t) noexcept {
+ std::free(Ptr);
+}
+
+// Array new/delete.
+void *operator new[](std::size_t Size) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new[](std::size_t Size, std::align_val_t) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new[](std::size_t Size, const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new[](std::size_t Size, std::align_val_t,
+ const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void operator delete[](void *Ptr) noexcept { std::free(Ptr); }
+void operator delete[](void *Ptr, std::align_val_t) noexcept { std::free(Ptr); }
+void operator delete[](void *Ptr, std::size_t) noexcept { std::free(Ptr); }
+void operator delete[](void *Ptr, std::size_t, std::align_val_t) noexcept {
+ std::free(Ptr);
+}
+
+//===----------------------------------------------------------------------===//
+// Test data generation
+//===----------------------------------------------------------------------===//
+
+/// Generate a JSON string with \p N entries in an array. Each entry is a nested
+/// structure with objects and arrays to exercise parsing, iteration, and lookup
+/// at multiple depths.
+///
+/// Structure:
+/// {"items": [
+/// {
+/// "name": "item_I",
+/// "value": I,
+/// "tags": [
+/// {"label": "tag_0", "priority": 0},
+/// ...
+/// ],
+/// "details": {
+/// "description": "description text for item I",
+/// "active": true/false,
+/// "nested": { "x": I, "y": I*100 }
+/// }
+/// },
+/// ...
+/// ]}
+static std::string generateJSON(int N) {
+ std::string S;
+ raw_string_ostream OS(S);
+ OS << "{\"items\": [\n";
+ for (int I = 0; I < N; ++I) {
+ if (I > 0)
+ OS << ",\n";
+ OS << " {\n"
+ << " \"name\": \"item_" << I << "\",\n"
+ << " \"value\": " << I << ",\n"
+ << " \"tags\": [\n"
+ << " {\"label\": \"tag_0\", \"priority\": 0},\n"
+ << " {\"label\": \"tag_1\", \"priority\": 1},\n"
+ << " {\"label\": \"tag_2\", \"priority\": 2}\n"
+ << " ],\n"
+ << " \"details\": {\n"
+ << " \"description\": \"description text for item " << I << "\",\n"
+ << " \"active\": " << (I % 2 == 0 ? "true" : "false") << ",\n"
+ << " \"nested\": {\"x\": " << I << ", \"y\": " << I * 100 << "}\n"
+ << " }\n"
+ << " }";
+ }
+ OS << "\n]}";
+ return S;
+}
+
+//===----------------------------------------------------------------------===//
+// Tree traversal helpers
+//===----------------------------------------------------------------------===//
+
+/// Walk the JSON value tree, visiting every node. Returns the number of
+/// nodes visited.
+static size_t walkTree(const json::Value &V) {
+ size_t Count = 1;
+ if (const auto *Obj = V.getAsObject()) {
+ for (const auto &KV : *Obj)
+ Count += walkTree(KV.second);
+ } else if (const auto *Arr = V.getAsArray()) {
+ for (const auto &Elem : *Arr)
+ Count += walkTree(Elem);
+ }
+ return Count;
+}
+
+/// An Object paired with its own keys, for lookup benchmarks.
+struct ObjectWithKeys {
+ const json::Object *Obj;
+ SmallVector<std::string> Keys;
+};
+
+/// Collect every Object in the tree together with its own keys.
+static void collectObjectsWithKeys(const json::Value &V,
+ SmallVectorImpl<ObjectWithKeys> &Result) {
+ if (const auto *Obj = V.getAsObject()) {
+ ObjectWithKeys Entry;
+ Entry.Obj = Obj;
+ for (const auto &KV : *Obj) {
+ Entry.Keys.push_back(std::string(StringRef(KV.first)));
+ collectObjectsWithKeys(KV.second, Result);
+ }
+ Result.push_back(std::move(Entry));
+ } else if (const auto *Arr = V.getAsArray()) {
+ for (const auto &Elem : *Arr)
+ collectObjectsWithKeys(Elem, Result);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Benchmarks
+//===----------------------------------------------------------------------===//
+
+/// Benchmark json::parse(). Reports parse throughput and memory allocated.
+static void BM_JSONParse(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+
+ // Measure memory for a single parse before the timed loop.
+ TotalAllocatedBytes = 0;
+ NumAllocs = 0;
+ TrackMemory = true;
+ {
+ auto V = json::parse(JSON);
+ benchmark::DoNotOptimize(V);
+ }
+ TrackMemory = false;
+
+ State.counters["AllocBytes"] = TotalAllocatedBytes.load();
+ State.counters["Allocs"] = NumAllocs.load();
+
+ for (auto _ : State) {
+ auto V = json::parse(JSON);
+ benchmark::DoNotOptimize(V);
+ }
+ State.counters["ParseByteRate"] = benchmark::Counter(
+ State.iterations() * JSON.size(), benchmark::Counter::kIsRate,
+ benchmark::Counter::kIs1024);
+}
+BENCHMARK(BM_JSONParse)->Arg(10)->Arg(1000)->Arg(100000);
+
+/// Benchmark recursive tree iteration over a parsed JSON value.
+static void BM_JSONIterate(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+ json::Value Root = cantFail(json::parse(JSON));
+ size_t NodeCount = 0;
+ for (auto _ : State) {
+ NodeCount = walkTree(Root);
+ benchmark::DoNotOptimize(NodeCount);
+ }
+ State.SetItemsProcessed(State.iterations() * NodeCount);
+}
+BENCHMARK(BM_JSONIterate)->Arg(10)->Arg(1000)->Arg(100000);
+
+/// Benchmark Object::get() with each object's own keys in insertion order.
+static void BM_JSONLookupSequential(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+ json::Value Root = cantFail(json::parse(JSON));
+ SmallVector<ObjectWithKeys> ObjKeys;
+ collectObjectsWithKeys(Root, ObjKeys);
+
+ size_t TotalLookups = 0;
+ for (const auto &OK : ObjKeys)
+ TotalLookups += OK.Keys.size();
+
+ for (auto _ : State) {
+ for (const auto &OK : ObjKeys)
+ for (const auto &K : OK.Keys)
+ benchmark::DoNotOptimize(OK.Obj->get(K));
+ }
+ State.SetItemsProcessed(State.iterations() * TotalLookups);
+}
+BENCHMARK(BM_JSONLookupSequential)->Arg(10)->Arg(1000)->Arg(100000);
+
+/// Benchmark Object::get() with each object's own keys in random order.
+static void BM_JSONLookupRandom(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+ json::Value Root = cantFail(json::parse(JSON));
+ SmallVector<ObjectWithKeys> ObjKeys;
+ collectObjectsWithKeys(Root, ObjKeys);
+
+ std::mt19937 RNG(42);
+ size_t TotalLookups = 0;
+ for (auto &OK : ObjKeys) {
+ TotalLookups += OK.Keys.size();
+ std::shuffle(OK.Keys.begin(), OK.Keys.end(), RNG);
+ }
+
+ for (auto _ : State) {
+ for (const auto &OK : ObjKeys)
+ for (const auto &K : OK.Keys)
+ benchmark::DoNotOptimize(OK.Obj->get(K));
+ }
+ State.SetItemsProcessed(State.iterations() * TotalLookups);
+}
+BENCHMARK(BM_JSONLookupRandom)->Arg(10)->Arg(1000)->Arg(100000);
+
+BENCHMARK_MAIN();
More information about the cfe-commits
mailing list