-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbenchmark_construction.cpp
More file actions
196 lines (163 loc) · 5.63 KB
/
benchmark_construction.cpp
File metadata and controls
196 lines (163 loc) · 5.63 KB
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Phase 0: Construction Phase Benchmark
// Measures tree construction performance across different workloads
#include "workloads.h"
#include "benchmark_utils.h"
#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
#include <cstring>
#include <unistd.h>
// Simple BB class for benchmarking (extracted from prtree.h)
template <int D = 2>
class BB {
private:
float values[2 * D];
public:
BB() {
for (int i = 0; i < 2 * D; i++) values[i] = 0.0f;
}
BB(const float *minima, const float *maxima) {
for (int i = 0; i < D; i++) {
values[i] = minima[i];
values[i + D] = maxima[i];
}
}
inline float min(int i) const { return values[i]; }
inline float max(int i) const { return values[i + D]; }
inline float operator[](const int i) const { return values[i]; }
};
// Simple DataType class for benchmarking
template <class T, int D = 2>
class DataType {
public:
T first;
BB<D> second;
DataType() = default;
DataType(const T &f, const BB<D> &s) : first(f), second(s) {}
};
// Simplified tree construction simulation
// This mimics the core construction logic without full PRTree implementation
template<typename T, int D>
class SimplePRTreeBenchmark {
public:
using BBox = std::array<float, D * 2>;
using Data = DataType<T, D>;
void construct(const std::vector<BBox>& data) {
elements_.clear();
elements_.reserve(data.size());
// Convert input data to DataType format
for (size_t i = 0; i < data.size(); ++i) {
float minima[D], maxima[D];
for (int d = 0; d < D; ++d) {
minima[d] = data[i][d];
maxima[d] = data[i][d + D];
}
BB<D> bb(minima, maxima);
elements_.emplace_back(static_cast<T>(i), bb);
}
// Simulate partitioning/sorting work
// This represents the dominant cost in PRTree construction
std::sort(elements_.begin(), elements_.end(),
[](const Data& a, const Data& b) {
return a.second[0] < b.second[0];
});
// Simulate tree building overhead
build_tree_structure();
}
size_t size() const { return elements_.size(); }
private:
std::vector<Data> elements_;
void build_tree_structure() {
// Simulate recursive tree building
// In real PRTree, this involves complex partitioning
if (elements_.size() <= 6) return;
// Simulate some memory access patterns
float total = 0.0f;
for (const auto& elem : elements_) {
for (int d = 0; d < D; ++d) {
total += elem.second.min(d) + elem.second.max(d);
}
}
// Prevent optimization
if (total < 0) std::cout << total;
}
};
// Get current memory usage (RSS) in bytes
size_t get_memory_usage() {
long rss = 0L;
FILE* fp = fopen("/proc/self/statm", "r");
if (fp) {
if (fscanf(fp, "%*s%ld", &rss) == 1) {
fclose(fp);
return rss * sysconf(_SC_PAGESIZE);
}
fclose(fp);
}
return 0;
}
void run_construction_benchmark(const benchmark::WorkloadConfig& config,
benchmark::BenchmarkReporter& reporter) {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << "Running construction benchmark: " << config.name << "\n";
std::cout << "Elements: " << config.n_elements << "\n";
std::cout << std::string(60, '=') << "\n";
// Generate data
benchmark::DataGenerator<2> generator;
auto data = generator.generate(config);
size_t mem_before = get_memory_usage();
// Benchmark construction
SimplePRTreeBenchmark<int64_t, 2> tree;
benchmark::Timer timer;
tree.construct(data);
double elapsed_ms = timer.elapsed_ms();
size_t mem_after = get_memory_usage();
size_t mem_delta = (mem_after > mem_before) ? (mem_after - mem_before) : 0;
// Calculate throughput
double throughput = (config.n_elements / elapsed_ms) * 1000.0;
// Record results
benchmark::BenchmarkResult result;
result.workload_name = config.name;
result.operation = "construction";
result.n_elements = config.n_elements;
result.n_queries = 0;
result.time_ms = elapsed_ms;
result.throughput = throughput;
result.memory_bytes = mem_delta;
result.print();
reporter.add_result(result);
}
int main(int argc, char** argv) {
std::cout << "PRTree Phase 0: Construction Benchmark\n";
std::cout << "========================================\n\n";
benchmark::BenchmarkReporter reporter;
// Get workloads to run
auto workloads = benchmark::get_standard_workloads();
// If specific workload requested via command line
if (argc > 1) {
std::string requested = argv[1];
auto it = std::find_if(workloads.begin(), workloads.end(),
[&requested](const auto& w) {
return w.name == requested;
});
if (it != workloads.end()) {
run_construction_benchmark(*it, reporter);
} else {
std::cerr << "Unknown workload: " << requested << "\n";
std::cerr << "Available workloads:\n";
for (const auto& w : workloads) {
std::cerr << " - " << w.name << "\n";
}
return 1;
}
} else {
// Run all workloads
for (const auto& workload : workloads) {
run_construction_benchmark(workload, reporter);
}
}
// Print summary and save results
reporter.print_summary();
reporter.save_csv("construction_benchmark_results.csv");
return 0;
}