Revert "[Support][JSON] Use std::unordered_map for object storage" (#193549)
Reverts llvm/llvm-project#171230 to look at failures.
This commit is contained in:
@@ -155,7 +155,7 @@ static void insertComment(Object &Description, json::Value &Comment,
|
|||||||
Description[Key] = std::move(CommentsArray);
|
Description[Key] = std::move(CommentsArray);
|
||||||
Description["Has" + Key.str()] = true;
|
Description["Has" + Key.str()] = true;
|
||||||
} else {
|
} else {
|
||||||
DescriptionIt->second.getAsArray()->push_back(Comment);
|
DescriptionIt->getSecond().getAsArray()->push_back(Comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include "clang/Basic/SourceLocation.h"
|
#include "clang/Basic/SourceLocation.h"
|
||||||
#include "clang/Basic/Version.h"
|
#include "clang/Basic/Version.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
|
|||||||
return MaximumValue;
|
return MaximumValue;
|
||||||
auto KV = Mapping.find(Key.normalize());
|
auto KV = Mapping.find(Key.normalize());
|
||||||
if (KV != Mapping.end())
|
if (KV != Mapping.end())
|
||||||
return KV->second;
|
return KV->getSecond();
|
||||||
// If no exact entry found, try just the major key version. Only do so when
|
// 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
|
// a minor version number is present, to avoid recursing indefinitely into
|
||||||
// the major-only check.
|
// the major-only check.
|
||||||
@@ -43,10 +43,10 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
|
|||||||
VersionTuple MinValue = Min;
|
VersionTuple MinValue = Min;
|
||||||
llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
|
llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
|
||||||
for (const auto &KV : Obj) {
|
for (const auto &KV : Obj) {
|
||||||
if (auto Val = KV.second.getAsString()) {
|
if (auto Val = KV.getSecond().getAsString()) {
|
||||||
llvm::VersionTuple KeyVersion;
|
llvm::VersionTuple KeyVersion;
|
||||||
llvm::VersionTuple ValueVersion;
|
llvm::VersionTuple ValueVersion;
|
||||||
if (KeyVersion.tryParse(KV.first) || ValueVersion.tryParse(*Val))
|
if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
Mapping[KeyVersion.normalize()] = ValueVersion;
|
Mapping[KeyVersion.normalize()] = ValueVersion;
|
||||||
if (KeyVersion < Min)
|
if (KeyVersion < Min)
|
||||||
@@ -119,7 +119,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
|
|||||||
|
|
||||||
for (auto SupportedTargetPair : *SupportedTargets) {
|
for (auto SupportedTargetPair : *SupportedTargets) {
|
||||||
llvm::json::Object *SupportedTarget =
|
llvm::json::Object *SupportedTarget =
|
||||||
SupportedTargetPair.second.getAsObject();
|
SupportedTargetPair.getSecond().getAsObject();
|
||||||
auto Vendor = SupportedTarget->getString("LLVMTargetTripleVendor");
|
auto Vendor = SupportedTarget->getString("LLVMTargetTripleVendor");
|
||||||
auto OS = SupportedTarget->getString("LLVMTargetTripleSys");
|
auto OS = SupportedTarget->getString("LLVMTargetTripleSys");
|
||||||
if (!Vendor || !OS)
|
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 key is either the Xcode platform, or a variant. The platform must be
|
||||||
// the first entry in the returned PlatformInfoStorageType.
|
// the first entry in the returned PlatformInfoStorageType.
|
||||||
StringRef PlatformOrVariant = SupportedTargetPair.first;
|
StringRef PlatformOrVariant = SupportedTargetPair.getFirst();
|
||||||
|
|
||||||
StringRef EffectivePlatformPrefix;
|
StringRef EffectivePlatformPrefix;
|
||||||
// Ignore iosmac value if it exists.
|
// Ignore iosmac value if it exists.
|
||||||
@@ -202,12 +202,12 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
|
|||||||
// FIXME: Generalize this out beyond iOS-deriving targets.
|
// FIXME: Generalize this out beyond iOS-deriving targets.
|
||||||
// Look for ios_<targetos> version mapping for targets that derive from ios.
|
// Look for ios_<targetos> version mapping for targets that derive from ios.
|
||||||
for (const auto &KV : *VM) {
|
for (const auto &KV : *VM) {
|
||||||
auto Pair = StringRef(KV.first).split("_");
|
auto Pair = StringRef(KV.getFirst()).split("_");
|
||||||
if (Pair.first.compare_insensitive("ios") == 0) {
|
if (Pair.first.compare_insensitive("ios") == 0) {
|
||||||
llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
|
llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
|
||||||
if (TT.getOS() != llvm::Triple::UnknownOS) {
|
if (TT.getOS() != llvm::Triple::UnknownOS) {
|
||||||
auto Mapping = RelatedTargetVersionMapping::parseJSON(
|
auto Mapping = RelatedTargetVersionMapping::parseJSON(
|
||||||
*KV.second.getAsObject(), *MaximumDeploymentVersion);
|
*KV.getSecond().getAsObject(), *MaximumDeploymentVersion);
|
||||||
if (Mapping)
|
if (Mapping)
|
||||||
VersionMappings[OSEnvPair(llvm::Triple::IOS,
|
VersionMappings[OSEnvPair(llvm::Triple::IOS,
|
||||||
llvm::Triple::UnknownEnvironment,
|
llvm::Triple::UnknownEnvironment,
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
|
|||||||
return llvm::opt::InputArgList();
|
return llvm::opt::InputArgList();
|
||||||
|
|
||||||
for (const auto &KV : *Root) {
|
for (const auto &KV : *Root) {
|
||||||
const Array *ArgList = KV.second.getAsArray();
|
const Array *ArgList = KV.getSecond().getAsArray();
|
||||||
std::string Label = "-X" + KV.first.str();
|
std::string Label = "-X" + KV.getFirst().str();
|
||||||
if (!ArgList)
|
if (!ArgList)
|
||||||
return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
|
return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
|
||||||
for (auto Arg : *ArgList) {
|
for (auto Arg : *ArgList) {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ TEST_F(SarifDocumentWriterTest, canCreateEmptyDocument) {
|
|||||||
const llvm::json::Object &EmptyDoc = Writer.createDocument();
|
const llvm::json::Object &EmptyDoc = Writer.createDocument();
|
||||||
std::vector<StringRef> Keys(EmptyDoc.size());
|
std::vector<StringRef> Keys(EmptyDoc.size());
|
||||||
std::transform(EmptyDoc.begin(), EmptyDoc.end(), Keys.begin(),
|
std::transform(EmptyDoc.begin(), EmptyDoc.end(), Keys.begin(),
|
||||||
[](auto Item) { return Item.first; });
|
[](auto Item) { return Item.getFirst(); });
|
||||||
|
|
||||||
// THEN:
|
// THEN:
|
||||||
ASSERT_THAT(Keys, testing::UnorderedElementsAre("$schema", "version"));
|
ASSERT_THAT(Keys, testing::UnorderedElementsAre("$schema", "version"));
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
#include "lldb/Target/DynamicLoader.h"
|
#include "lldb/Target/DynamicLoader.h"
|
||||||
#include "lldb/lldb-forward.h"
|
#include "lldb/lldb-forward.h"
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
|
|
||||||
namespace lldb_private {
|
namespace lldb_private {
|
||||||
|
|
||||||
class DynamicLoaderWindowsDYLD : public DynamicLoader {
|
class DynamicLoaderWindowsDYLD : public DynamicLoader {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#define liblldb_IntelPTPerThreadTraceCollection_H_
|
#define liblldb_IntelPTPerThreadTraceCollection_H_
|
||||||
|
|
||||||
#include "IntelPTSingleBufferTrace.h"
|
#include "IntelPTSingleBufferTrace.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace lldb_private {
|
namespace lldb_private {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ add_benchmark(MustacheBench Mustache.cpp PARTIAL_SOURCES_INTENDED)
|
|||||||
add_benchmark(SpecialCaseListBM SpecialCaseListBM.cpp PARTIAL_SOURCES_INTENDED)
|
add_benchmark(SpecialCaseListBM SpecialCaseListBM.cpp PARTIAL_SOURCES_INTENDED)
|
||||||
add_benchmark(DWARFVerifierBM DWARFVerifierBM.cpp PARTIAL_SOURCES_INTENDED)
|
add_benchmark(DWARFVerifierBM DWARFVerifierBM.cpp PARTIAL_SOURCES_INTENDED)
|
||||||
add_benchmark(PointerUnionBM PointerUnionBM.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)
|
add_benchmark(RuntimeLibcallsBench RuntimeLibcalls.cpp PARTIAL_SOURCES_INTENDED)
|
||||||
|
|
||||||
|
|||||||
@@ -1,299 +0,0 @@
|
|||||||
//===- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// \file
|
|
||||||
// Benchmarks for LLVM's JSON parser.
|
|
||||||
// Runs parsing, tree iteration, and object key lookup with generated inputs.
|
|
||||||
// Measures time performance and memory consumption.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#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
|
|
||||||
//
|
|
||||||
// These are global overrides so the benchmark might be over-counting memory
|
|
||||||
// allocations and usage. The data is still useful for comparisons with this
|
|
||||||
// benchmark itself.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
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();
|
|
||||||
@@ -46,17 +46,16 @@
|
|||||||
#ifndef LLVM_SUPPORT_JSON_H
|
#ifndef LLVM_SUPPORT_JSON_H
|
||||||
#define LLVM_SUPPORT_JSON_H
|
#define LLVM_SUPPORT_JSON_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/AlignOf.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/Error.h"
|
#include "llvm/Support/Error.h"
|
||||||
#include "llvm/Support/FormatVariadic.h"
|
#include "llvm/Support/FormatVariadic.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace json {
|
namespace json {
|
||||||
@@ -95,14 +94,9 @@ class Value;
|
|||||||
template <typename T> Value toJSON(const std::optional<T> &Opt);
|
template <typename T> Value toJSON(const std::optional<T> &Opt);
|
||||||
|
|
||||||
/// An Object is a JSON object, which maps strings to heterogenous JSON values.
|
/// An Object is a JSON object, which maps strings to heterogenous JSON values.
|
||||||
/// ObjectKey is a maybe-owned string.
|
/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string.
|
||||||
class Object {
|
class Object {
|
||||||
struct ObjectKeyHash {
|
using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
|
||||||
template <typename T> size_t operator()(const T &Key) const {
|
|
||||||
return hash_value(Key);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using Storage = std::unordered_map<ObjectKey, Value, ObjectKeyHash>;
|
|
||||||
Storage M;
|
Storage M;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -139,11 +133,8 @@ public:
|
|||||||
bool erase(StringRef K);
|
bool erase(StringRef K);
|
||||||
void erase(iterator I) { M.erase(I); }
|
void erase(iterator I) { M.erase(I); }
|
||||||
|
|
||||||
// TODO: Implement heterogeneous lookup using StringRef directly. We need to
|
iterator find(StringRef K) { return M.find_as(K); }
|
||||||
// make ObjectKey transparent with transparent hash and key equality check.
|
const_iterator find(StringRef K) const { return M.find_as(K); }
|
||||||
// This is supported for unordered containers in C++20.
|
|
||||||
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.
|
// operator[] acts as if Value was default-constructible as null.
|
||||||
LLVM_ABI Value &operator[](const ObjectKey &K);
|
LLVM_ABI Value &operator[](const ObjectKey &K);
|
||||||
LLVM_ABI Value &operator[](ObjectKey &&K);
|
LLVM_ABI Value &operator[](ObjectKey &&K);
|
||||||
@@ -655,7 +646,7 @@ inline Object::Object(std::initializer_list<KV> Properties) {
|
|||||||
for (const auto &P : Properties) {
|
for (const auto &P : Properties) {
|
||||||
auto R = try_emplace(P.K, nullptr);
|
auto R = try_emplace(P.K, nullptr);
|
||||||
if (R.second)
|
if (R.second)
|
||||||
R.first->second.moveFrom(std::move(P.V));
|
R.first->getSecond().moveFrom(std::move(P.V));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline std::pair<Object::iterator, bool> Object::insert(KV E) {
|
inline std::pair<Object::iterator, bool> Object::insert(KV E) {
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ namespace llvm {
|
|||||||
namespace json {
|
namespace json {
|
||||||
|
|
||||||
Value &Object::operator[](const ObjectKey &K) {
|
Value &Object::operator[](const ObjectKey &K) {
|
||||||
return try_emplace(K, nullptr).first->second;
|
return try_emplace(K, nullptr).first->getSecond();
|
||||||
}
|
}
|
||||||
Value &Object::operator[](ObjectKey &&K) {
|
Value &Object::operator[](ObjectKey &&K) {
|
||||||
return try_emplace(std::move(K), nullptr).first->second;
|
return try_emplace(std::move(K), nullptr).first->getSecond();
|
||||||
}
|
}
|
||||||
Value *Object::get(StringRef K) {
|
Value *Object::get(StringRef K) {
|
||||||
auto I = find(K);
|
auto I = find(K);
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
#include "Views/InstructionView.h"
|
#include "Views/InstructionView.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/MC/MCInst.h"
|
#include "llvm/MC/MCInst.h"
|
||||||
#include "llvm/MC/MCInstPrinter.h"
|
#include "llvm/MC/MCInstPrinter.h"
|
||||||
|
|||||||
Reference in New Issue
Block a user