Skip to content

Commit 5ac14a3

Browse files
committed
feat(example): add memory benchmark example
1 parent 1bd8ef7 commit 5ac14a3

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../google_benchmark_cmake/memory_bench.hpp

examples/google_benchmark_cmake/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "fibonacci_bench.hpp"
66
#include "fixture_bench.hpp"
7+
#include "memory_bench.hpp"
78
#include "multithread_bench.hpp"
89
#include "pause_timing_bench.hpp"
910
#include "sleep_bench.hpp"
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#pragma once
2+
3+
#include <benchmark/benchmark.h>
4+
5+
#include <string>
6+
#include <vector>
7+
8+
// Run-length encoding: compress consecutive repeated characters
9+
// Example: "aaabbbccc" -> "3a3b3c"
10+
// NOTE: Intentionally inefficient - no pre-allocation to show multiple
11+
// allocations
12+
static std::string rle_encode(const std::string& input) {
13+
if (input.empty()) return "";
14+
15+
std::string result; // No reserve - will trigger multiple reallocations
16+
17+
char current = input[0];
18+
size_t count = 1;
19+
20+
for (size_t i = 1; i < input.size(); ++i) {
21+
if (input[i] == current) {
22+
count++;
23+
} else {
24+
// Create intermediate strings for each run
25+
std::string count_str = std::to_string(count);
26+
std::string run_encoded = count_str + current;
27+
result += run_encoded; // Concatenation causes reallocations
28+
current = input[i];
29+
count = 1;
30+
}
31+
}
32+
33+
// Final run
34+
std::string count_str = std::to_string(count);
35+
std::string final_run = count_str + current;
36+
result += final_run;
37+
38+
return result;
39+
}
40+
41+
// Run-length decoding: decompress RLE encoded string
42+
// Example: "3a3b3c" -> "aaabbbccc"
43+
static std::string rle_decode(const std::string& input) {
44+
std::string result;
45+
size_t i = 0;
46+
47+
while (i < input.size()) {
48+
// Parse the count
49+
size_t count = 0;
50+
while (i < input.size() && std::isdigit(input[i])) {
51+
count = count * 10 + (input[i] - '0');
52+
i++;
53+
}
54+
55+
// Get the character
56+
if (i < input.size()) {
57+
char ch = input[i];
58+
result.append(count, ch);
59+
i++;
60+
}
61+
}
62+
63+
return result;
64+
}
65+
66+
// Generate a string with patterns for RLE
67+
static std::string generate_rle_input(size_t size, size_t run_length) {
68+
std::string result;
69+
result.reserve(size);
70+
71+
const std::string chars = "abcdefghijklmnopqrstuvwxyz";
72+
size_t char_idx = 0;
73+
74+
while (result.size() < size) {
75+
size_t count = std::min(run_length, size - result.size());
76+
result.append(count, chars[char_idx % chars.size()]);
77+
char_idx++;
78+
}
79+
80+
return result;
81+
}
82+
83+
// Benchmark: RLE encoding with small runs (high compression)
84+
static void BM_RLE_Encode_SmallRuns(benchmark::State& state) {
85+
const size_t input_size = state.range(0);
86+
std::string input = generate_rle_input(input_size, 3);
87+
88+
for (auto _ : state) {
89+
std::string encoded = rle_encode(input);
90+
benchmark::DoNotOptimize(encoded);
91+
benchmark::ClobberMemory();
92+
}
93+
94+
state.SetBytesProcessed(state.iterations() * input_size);
95+
}
96+
BENCHMARK(BM_RLE_Encode_SmallRuns)
97+
->Arg(100)
98+
->Arg(1000)
99+
->Arg(10000)
100+
->Arg(100000);
101+
102+
// Benchmark: RLE encoding with large runs (low compression)
103+
static void BM_RLE_Encode_LargeRuns(benchmark::State& state) {
104+
const size_t input_size = state.range(0);
105+
std::string input = generate_rle_input(input_size, 100);
106+
107+
for (auto _ : state) {
108+
std::string encoded = rle_encode(input);
109+
benchmark::DoNotOptimize(encoded);
110+
benchmark::ClobberMemory();
111+
}
112+
113+
state.SetBytesProcessed(state.iterations() * input_size);
114+
}
115+
BENCHMARK(BM_RLE_Encode_LargeRuns)
116+
->Arg(100)
117+
->Arg(1000)
118+
->Arg(10000)
119+
->Arg(100000);
120+
121+
// Benchmark: RLE decoding
122+
static void BM_RLE_Decode(benchmark::State& state) {
123+
const size_t input_size = state.range(0);
124+
std::string input = generate_rle_input(input_size, 10);
125+
std::string encoded = rle_encode(input);
126+
127+
for (auto _ : state) {
128+
std::string decoded = rle_decode(encoded);
129+
benchmark::DoNotOptimize(decoded);
130+
benchmark::ClobberMemory();
131+
}
132+
133+
state.SetBytesProcessed(state.iterations() * encoded.size());
134+
}
135+
BENCHMARK(BM_RLE_Decode)->Arg(100)->Arg(1000)->Arg(10000)->Arg(100000);
136+
137+
// Benchmark: Vector allocations (resizing pattern)
138+
static void BM_Vector_PushBack(benchmark::State& state) {
139+
const size_t count = state.range(0);
140+
141+
for (auto _ : state) {
142+
std::vector<int> vec;
143+
for (size_t i = 0; i < count; ++i) {
144+
vec.push_back(static_cast<int>(i));
145+
}
146+
benchmark::DoNotOptimize(vec);
147+
benchmark::ClobberMemory();
148+
}
149+
}
150+
BENCHMARK(BM_Vector_PushBack)->Arg(10)->Arg(100)->Arg(1000)->Arg(10000);
151+
152+
// Benchmark: Vector allocations with reserve (optimized)
153+
static void BM_Vector_Reserve(benchmark::State& state) {
154+
const size_t count = state.range(0);
155+
156+
for (auto _ : state) {
157+
std::vector<int> vec;
158+
vec.reserve(count);
159+
for (size_t i = 0; i < count; ++i) {
160+
vec.push_back(static_cast<int>(i));
161+
}
162+
benchmark::DoNotOptimize(vec);
163+
benchmark::ClobberMemory();
164+
}
165+
}
166+
BENCHMARK(BM_Vector_Reserve)->Arg(10)->Arg(100)->Arg(1000)->Arg(10000);
167+
168+
// Benchmark: String concatenation (many allocations)
169+
static void BM_String_Concatenation(benchmark::State& state) {
170+
const size_t count = state.range(0);
171+
172+
for (auto _ : state) {
173+
std::string result;
174+
for (size_t i = 0; i < count; ++i) {
175+
result += "x";
176+
}
177+
benchmark::DoNotOptimize(result);
178+
benchmark::ClobberMemory();
179+
}
180+
}
181+
BENCHMARK(BM_String_Concatenation)->Arg(10)->Arg(100)->Arg(1000)->Arg(10000);
182+
183+
// Benchmark: String concatenation with reserve (optimized)
184+
static void BM_String_Reserve(benchmark::State& state) {
185+
const size_t count = state.range(0);
186+
187+
for (auto _ : state) {
188+
std::string result;
189+
result.reserve(count);
190+
for (size_t i = 0; i < count; ++i) {
191+
result += "x";
192+
}
193+
benchmark::DoNotOptimize(result);
194+
benchmark::ClobberMemory();
195+
}
196+
}
197+
BENCHMARK(BM_String_Reserve)->Arg(10)->Arg(100)->Arg(1000)->Arg(10000);

0 commit comments

Comments
 (0)