Skip to content

Commit 23f2ae4

Browse files
authored
Create unit-ordered_map-performance.cpp
Test performance and memory usage of ordered_json (will not report memory usage unless posix or MacOS). Signed-off-by: Andrea Cocito <[email protected]>
1 parent 60ed5ed commit 23f2ae4

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include <catch2/catch.hpp>
2+
#include "json.hpp"
3+
4+
#include <chrono>
5+
#include <random>
6+
#include <iostream>
7+
#include <vector>
8+
#include <string>
9+
#include <numeric>
10+
#include <algorithm>
11+
12+
#if defined(__unix__) || defined(__APPLE__)
13+
#include <sys/resource.h>
14+
#include <unistd.h>
15+
static std::size_t get_memory_usage_kb()
16+
{
17+
struct rusage usage{};
18+
if (getrusage(RUSAGE_SELF, &usage) == 0)
19+
{
20+
#if defined(__APPLE__)
21+
// macOS returns bytes in ru_maxrss
22+
return static_cast<std::size_t>(usage.ru_maxrss / 1024);
23+
#else
24+
// Linux/BSD return KB
25+
return static_cast<std::size_t>(usage.ru_maxrss);
26+
#endif
27+
}
28+
return 0;
29+
}
30+
#else
31+
static std::size_t get_memory_usage_kb()
32+
{
33+
return 0; // unavailable on this platform
34+
}
35+
#endif
36+
37+
// generate random hex string of fixed length
38+
static std::string random_hex(std::mt19937& rng, std::size_t length = 32)
39+
{
40+
static const char* digits = "0123456789abcdef";
41+
std::uniform_int_distribution<int> dist(0, 15);
42+
43+
std::string s;
44+
s.resize(length);
45+
for (std::size_t i = 0; i < length; ++i)
46+
{
47+
s[i] = digits[dist(rng)];
48+
}
49+
return s;
50+
}
51+
52+
TEST_CASE("macro benchmark: ordered_json with 1,000,000 random hex pairs")
53+
{
54+
using json = nlohmann::ordered_json;
55+
56+
constexpr std::size_t N = 1'000'000;
57+
58+
std::mt19937 rng(12345); // deterministic seed
59+
60+
std::vector<std::string> keys;
61+
keys.reserve(N);
62+
63+
std::vector<std::string> values;
64+
values.reserve(N);
65+
66+
// generate keys and values
67+
for (std::size_t i = 0; i < N; ++i)
68+
{
69+
keys.push_back(random_hex(rng));
70+
values.push_back(random_hex(rng));
71+
}
72+
73+
std::cout << "[ordered_map benchmark] Memory usage after generating arrays: "
74+
<< get_memory_usage_kb() << " KB" << std::endl;
75+
76+
json j;
77+
78+
// time to create
79+
auto start_create = std::chrono::steady_clock::now();
80+
for (std::size_t i = 0; i < N; ++i)
81+
{
82+
j[keys[i]] = values[i];
83+
}
84+
auto end_create = std::chrono::steady_clock::now();
85+
auto create_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_create - start_create).count();
86+
87+
std::cout << "[ordered_map benchmark] Created " << N << " random hex entries in "
88+
<< create_ms << " ms" << std::endl;
89+
std::cout << "Memory usage after create: " << get_memory_usage_kb() << " KB" << std::endl;
90+
91+
// random access order
92+
std::vector<std::size_t> indices(N);
93+
std::iota(indices.begin(), indices.end(), 0);
94+
std::shuffle(indices.begin(), indices.end(), rng);
95+
96+
volatile std::size_t checksum = 0; // prevent optimizing away
97+
auto start_read = std::chrono::steady_clock::now();
98+
for (auto idx : indices)
99+
{
100+
const auto& v = j.at(keys[idx]);
101+
checksum += v.size();
102+
}
103+
auto end_read = std::chrono::steady_clock::now();
104+
auto read_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_read - start_read).count();
105+
106+
std::cout << "[ordered_map benchmark] Random read of " << N << " entries in "
107+
<< read_ms << " ms" << std::endl;
108+
std::cout << "Memory usage after read: " << get_memory_usage_kb() << " KB" << std::endl;
109+
std::cout << "Checksum: " << checksum << std::endl;
110+
}
111+

0 commit comments

Comments
 (0)