1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include <malloc/malloc.h> // macOS malloc_size
#include <atomic>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <map>
#include <new>
#include <string>
#include <vector>
// Global allocation tracker
static std::atomic<int64_t> g_allocated{0};
void* operator new(std::size_t size)
{
void* p = std::malloc(size);
if (!p) throw std::bad_alloc();
g_allocated += static_cast<int64_t>(malloc_size(p));
return p;
}
void operator delete(void* p) noexcept
{
if (p) {
g_allocated -= static_cast<int64_t>(malloc_size(p));
std::free(p);
}
}
void operator delete(void* p, std::size_t) noexcept
{
if (p) {
g_allocated -= static_cast<int64_t>(malloc_size(p));
std::free(p);
}
}
#include "glaze/containers/ordered_map.hpp"
#include "glaze/containers/ordered_small_map.hpp"
std::vector<std::string> generate_keys(size_t n)
{
std::vector<std::string> base = {
"id", "name", "email", "age", "active", "role", "created", "updated", "type",
"status", "title", "body", "url", "path", "method", "headers", "params", "query",
"page", "limit", "offset", "total", "count", "data", "error", "message", "code",
"timestamp", "version", "format", "encoding", "length", "width", "height", "color", "font",
"size", "weight", "opacity", "visible", "enabled", "locked", "readonly", "required", "optional",
"default", "min", "max", "pattern", "prefix", "suffix", "separator", "locale", "timezone",
"currency", "country", "region", "city", "street", "zip"};
std::vector<std::string> keys;
keys.reserve(n);
for (size_t i = 0; i < n; ++i) {
if (i < base.size()) {
keys.push_back(base[i]);
}
else {
keys.push_back("field_" + std::to_string(i));
}
}
return keys;
}
int main()
{
std::cout << "sizeof(std::string) = " << sizeof(std::string) << "\n";
std::cout << "sizeof(glz::ordered_small_map<int>) = " << sizeof(glz::ordered_small_map<int>) << "\n";
std::cout << "sizeof(glz::ordered_map<std::string, int>) = " << sizeof(glz::ordered_map<std::string, int>) << "\n";
std::cout << "sizeof(std::map<std::string, int>) = " << sizeof(std::map<std::string, int>) << "\n";
std::cout << "\n";
// Pre-generate keys outside measurement
std::vector<std::vector<std::string>> all_keys;
for (size_t n : {8, 16, 32, 64, 128, 256}) {
all_keys.push_back(generate_keys(n));
}
std::cout
<< " n | small_map bytes | small/entry | ordered_map bytes | ordered/entry | std::map bytes | std/entry | "
"ordered/small | std/small\n";
std::cout << "-----|-----------------|-------------|-------------------|---------------|----------------|-----------"
"|---------------"
"|----------\n";
size_t idx = 0;
for (size_t n : {8, 16, 32, 64, 128, 256}) {
const auto& keys = all_keys[idx++];
// Measure glz::ordered_small_map
int64_t before = g_allocated.load();
auto* small_map = new glz::ordered_small_map<int>();
for (size_t i = 0; i < n; ++i) {
(*small_map)[keys[i]] = static_cast<int>(i);
}
// Force index build for maps > threshold
small_map->find("__nonexistent__");
int64_t small_map_bytes = g_allocated.load() - before;
delete small_map;
// Measure glz::ordered_map
before = g_allocated.load();
auto* ordered_map = new glz::ordered_map<std::string, int>();
for (size_t i = 0; i < n; ++i) {
(*ordered_map)[keys[i]] = static_cast<int>(i);
}
int64_t ordered_map_bytes = g_allocated.load() - before;
delete ordered_map;
// Measure std::map
before = g_allocated.load();
auto* std_map = new std::map<std::string, int>();
for (size_t i = 0; i < n; ++i) {
(*std_map)[keys[i]] = static_cast<int>(i);
}
int64_t std_map_bytes = g_allocated.load() - before;
delete std_map;
double small_per = static_cast<double>(small_map_bytes) / n;
double ordered_per = static_cast<double>(ordered_map_bytes) / n;
double std_per = static_cast<double>(std_map_bytes) / n;
double ordered_ratio = static_cast<double>(ordered_map_bytes) / small_map_bytes;
double std_ratio = static_cast<double>(std_map_bytes) / small_map_bytes;
printf("%4zu | %15lld | %11.1f | %17lld | %13.1f | %14lld | %9.1f | %13.2fx | %8.2fx\n", n, small_map_bytes,
small_per, ordered_map_bytes, ordered_per, std_map_bytes, std_per, ordered_ratio, std_ratio);
}
return 0;
}
|