Skip to content
This repository was archived by the owner on Jan 22, 2024. It is now read-only.

Commit f8c07fb

Browse files
committed
Split iterations into outer and inner iterations
Outer iterations have different inputs (=run the generator again), inner iterations are run on the same data
1 parent 2bab156 commit f8c07fb

File tree

3 files changed

+111
-74
lines changed

3 files changed

+111
-74
lines changed

benchmark.h

Lines changed: 76 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,13 @@ struct statistics {
7373
};
7474

7575
template <typename T, typename Sorter>
76-
statistics run(T* data, const T* const copy, T* out, size_t size, Sorter sorter,
77-
size_t iterations, const std::string &algoname,
78-
bool reset_out = true) {
79-
progress_bar bar(iterations + 1, algoname);
76+
void run(T* data, const T* const copy, T* out, size_t size, Sorter sorter,
77+
size_t iterations, statistics& stats, progress_bar &bar,
78+
bool reset_out = true) {
8079
// warmup
8180
sorter(data, out, size);
8281
++bar;
8382

84-
statistics stats;
8583
Timer timer;
8684
for (size_t it = 0; it < iterations; ++it) {
8785
// reset data and timer
@@ -95,61 +93,83 @@ statistics run(T* data, const T* const copy, T* out, size_t size, Sorter sorter,
9593
stats.push(timer.get());
9694
++bar;
9795
}
98-
bar.undraw();
99-
return stats;
10096
}
10197

10298
template <typename T, typename Generator>
103-
size_t benchmark(size_t size, size_t iterations, Generator generator,
104-
const std::string &name, std::ofstream *stat_stream) {
99+
size_t benchmark(size_t size, Generator generator, const std::string &name,
100+
size_t outer_its, size_t inner_its,
101+
std::ofstream *stat_stream) {
105102
T *data = new T[size],
106103
*out = new T[size],
107104
*copy = new T[size];
108105

106+
// Number of iterations
107+
if (outer_its == static_cast<size_t>(-1)) {
108+
if (size < (1<<16)) outer_its = 100;
109+
else if (size < (1<<18)) outer_its = 50;
110+
else if (size < (1<<20)) outer_its = 25;
111+
else if (size < (1<<24)) outer_its = 10;
112+
else outer_its = 5;
113+
}
114+
if (inner_its == static_cast<size_t>(-1)) {
115+
inner_its = 10;
116+
}
117+
118+
// the label maker
119+
auto bar_label = [&](size_t it) {
120+
return name + " (" + std::to_string(it + 1) + "/" +
121+
std::to_string(outer_its) + "): ";
122+
};
123+
124+
progress_bar bar(2 * outer_its * (inner_its + 1), bar_label(0));
109125
Timer timer;
110-
// Generate random numbers as input
111-
size = generator(data, size);
112126

113-
// create a copy to be able to sort it multiple times
114-
std::copy(data, data+size, copy);
115-
double t_generate = timer.get_and_reset();
127+
double t_generate(0.0), t_verify(0.0);
128+
bool incorrect = false;
129+
statistics t_ssssort, t_stdsort;
130+
for (size_t it = 0; it < outer_its; ++it) {
131+
bar.set_extra(bar_label(it));
132+
// Generate random numbers as input
133+
timer.reset();
134+
size = generator(data, size);
116135

117-
// Number of iterations
118-
if (iterations == static_cast<size_t>(-1)) {
119-
if (size < (1<<16)) iterations = 1000;
120-
else if (size < (1<<18)) iterations = 500;
121-
else if (size < (1<<20)) iterations = 250;
122-
else if (size < (1<<24)) iterations = 100;
123-
else iterations = 50;
124-
}
136+
// create a copy to be able to sort it multiple times
137+
std::copy(data, data+size, copy);
138+
t_generate += timer.get_and_reset();
125139

126-
// 1. Super Scalar Sample Sort
127-
auto t_ssssort = run(data, copy, out, size,
128-
[](T* data, T* out, size_t size)
129-
{ ssssort::ssssort(data, data + size, out); },
130-
iterations, "ssssort: ");
140+
// Sorting algorithms have their own time tracking
141+
// 1. Super Scalar Sample Sort
142+
run(data, copy, out, size,
143+
[](T* data, T* out, size_t size)
144+
{ ssssort::ssssort(data, data + size, out); },
145+
inner_its, t_ssssort, bar);
131146

132-
// 2. std::sort
133-
auto t_stdsort = run(data, copy, out, size,
134-
[](T* data, T* /*ignored*/, size_t size)
135-
{ std::sort(data, data + size); },
136-
iterations, "std::sort: ", false);
147+
// 2. std::sort
148+
run(data, copy, out, size,
149+
[](T* data, T* /*ignored*/, size_t size)
150+
{ std::sort(data, data + size); },
151+
inner_its, t_stdsort, bar, false);
137152

138153

139-
// verify
140-
timer.reset();
141-
bool incorrect = !std::is_sorted(out, out + size);
142-
if (incorrect) {
143-
std::cerr << "Output data isn't sorted" << std::endl;
144-
}
145-
for (size_t i = 0; i < size; ++i) {
146-
incorrect |= (out[i] != data[i]);
147-
if (debug && out[i] != data[i]) {
148-
std::cerr << "Err at pos " << i << " expected " << data[i]
149-
<< " got " << out[i] << std::endl;
154+
// verify
155+
timer.reset();
156+
bool it_incorrect = !std::is_sorted(out, out + size);
157+
if (it_incorrect) {
158+
std::cerr << "Output data isn't sorted" << std::endl;
150159
}
160+
for (size_t i = 0; i < size; ++i) {
161+
it_incorrect |= (out[i] != data[i]);
162+
if (debug && out[i] != data[i]) {
163+
std::cerr << "Err at pos " << i << " expected " << data[i]
164+
<< " got " << out[i] << std::endl;
165+
}
166+
}
167+
incorrect |= it_incorrect;
168+
t_verify += timer.get_and_reset();
169+
151170
}
152-
double t_verify = timer.get_and_reset();
171+
172+
bar.undraw();
153173

154174
delete[] out;
155175
delete[] data;
@@ -159,7 +179,7 @@ size_t benchmark(size_t size, size_t iterations, Generator generator,
159179
output << "RESULT algo=ssssort"
160180
<< " name=" << name
161181
<< " size=" << size
162-
<< " iters=" << iterations
182+
<< " iters=" << outer_its << "*" << inner_its
163183
<< " time=" << t_ssssort.avg()
164184
<< " stddev=" << t_ssssort.stddev()
165185
<< " t_gen=" << t_generate
@@ -169,7 +189,7 @@ size_t benchmark(size_t size, size_t iterations, Generator generator,
169189
<< "RESULT algo=stdsort"
170190
<< " name=" << name
171191
<< " size=" << size
172-
<< " iters=" << iterations
192+
<< " iters=" << outer_its << "*" << inner_its
173193
<< " time=" << t_stdsort.avg()
174194
<< " stddev=" << t_stdsort.stddev()
175195
<< " t_gen=" << t_generate
@@ -186,33 +206,35 @@ size_t benchmark(size_t size, size_t iterations, Generator generator,
186206

187207
template <typename T, typename Generator>
188208
void benchmark_generator(Generator generator, const std::string &name,
189-
size_t iterations, std::ofstream *stat_stream,
190-
size_t max_log_size = 27) {
209+
const size_t outer_its, const size_t inner_its,
210+
std::ofstream *stat_stream,
211+
const size_t max_log_size = 27) {
191212
auto wrapped_generator = [generator](auto data, size_t size) {
192213
generator(data, size);
193214
return size;
194215
};
195216

196217
// warmup
197-
benchmark<T>(1<<10, 10, wrapped_generator, "warmup", nullptr);
218+
benchmark<T>(1<<10, wrapped_generator, "warmup", 1, 10, nullptr);
198219

199220
for (size_t log_size = 10; log_size < max_log_size; ++log_size) {
200221
size_t size = 1 << log_size;
201-
benchmark<T>(size, iterations, wrapped_generator, name, stat_stream);
222+
benchmark<T>(size, wrapped_generator, name, outer_its, inner_its, stat_stream);
202223
}
203224
}
204225

205226

206227
template <typename T, typename Generator>
207228
void sized_benchmark_generator(Generator generator, const std::string &name,
208-
size_t iterations, std::ofstream *stat_stream,
209-
size_t max_log_size = 27) {
229+
const size_t outer_its, const size_t inner_its,
230+
std::ofstream *stat_stream,
231+
const size_t max_log_size = 27) {
210232
// warmup
211-
benchmark<T>(1<<10, 10, generator, "warmup", nullptr);
233+
benchmark<T>(1<<10, 10, generator, "warmup", 0, nullptr);
212234

213235
for (size_t log_size = 10; log_size < max_log_size; ++log_size) {
214236
size_t size = 1 << log_size;
215-
auto last_size = benchmark<T>(size, iterations, generator, name, stat_stream);
237+
size_t last_size = benchmark<T>(size, generator, name, outer_its, inner_its, stat_stream);
216238
if (last_size < size) break;
217239
}
218240
}

progress_bar.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ class progress_bar {
7777
out << "\r";
7878
}
7979

80+
void set_extra(const std::string &new_extra) {
81+
undraw();
82+
extra = new_extra;
83+
draw();
84+
}
85+
8086
protected:
8187
// adapted from StackOverflow user "leemes":
8288
// http://stackoverflow.com/a/14539953
@@ -104,7 +110,7 @@ class progress_bar {
104110

105111
private:
106112
std::ostream &out;
107-
const std::string &extra;
113+
std::string extra;
108114
unsigned long long max;
109115
unsigned long long pos;
110116
int lastprogress;

sort.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ using data_t = int;
4343
int main(int argc, char *argv[]) {
4444
if (argc > 1 && std::string{argv[1]} == "-h") {
4545
std::cout << "Usage: " << argv[0]
46-
<< " [iteratons] [statistics output file]" << std::endl
47-
<< "Defaults are 10 iterations and output to stats.txt"
48-
<< std::endl;
46+
<< " [outer iteratons] [inner iterations]"
47+
<< " [statistics output file]" << std::endl
48+
<< "Defaults are 5 outer iteration, 3 inner iterations,"
49+
<< " and output to stats.txt" << std::endl;
4950
return 0;
5051
}
5152

@@ -55,11 +56,12 @@ int main(int argc, char *argv[]) {
5556
<< "speed.plot and run gnuplot on it!" << std::endl;
5657

5758
// Parse flags
58-
size_t iterations = 10;
59-
if (argc > 1) iterations = static_cast<size_t>(atol(argv[1]));
59+
size_t outer_its = 5, inner_its = 3;
60+
if (argc > 1) outer_its = static_cast<size_t>(atol(argv[1]));
61+
if (argc > 2) inner_its = static_cast<size_t>(atol(argv[2]));
6062

6163
std::string stat_file = "stats.txt";
62-
if (argc > 2) stat_file = std::string{argv[2]};
64+
if (argc > 3) stat_file = std::string{argv[3]};
6365
std::ofstream *stat_stream = nullptr;
6466
if (stat_file != "-") {
6567
stat_stream = new std::ofstream;
@@ -75,11 +77,12 @@ int main(int argc, char *argv[]) {
7577
};
7678

7779
// Warmup
78-
benchmark_generator<data_t>(random_gen, "warmup", 3, stat_stream, 20);
80+
benchmark_generator<data_t>(random_gen, "warmup", 1, 3, stat_stream, 20);
7981

8082

8183
// Run Benchmarks
82-
benchmark_generator<data_t>(random_gen, "random", iterations, stat_stream);
84+
benchmark_generator<data_t>(random_gen, "random", outer_its, inner_its,
85+
stat_stream);
8386

8487

8588
// nearly sorted data generator factory
@@ -99,10 +102,14 @@ int main(int argc, char *argv[]) {
99102
};
100103
};
101104

102-
benchmark_generator<data_t>(nearly_sorted_gen(5), "80pcsorted", iterations, stat_stream);
103-
benchmark_generator<data_t>(nearly_sorted_gen(10), "90pcsorted", iterations, stat_stream);
104-
benchmark_generator<data_t>(nearly_sorted_gen(100), "99pcsorted", iterations, stat_stream);
105-
benchmark_generator<data_t>(nearly_sorted_gen(1000), "99.9pcsorted", iterations, stat_stream);
105+
benchmark_generator<data_t>(nearly_sorted_gen(5), "80pcsorted",
106+
outer_its, inner_its, stat_stream);
107+
benchmark_generator<data_t>(nearly_sorted_gen(10), "90pcsorted",
108+
outer_its, inner_its, stat_stream);
109+
benchmark_generator<data_t>(nearly_sorted_gen(100), "99pcsorted",
110+
outer_its, inner_its, stat_stream);
111+
benchmark_generator<data_t>(nearly_sorted_gen(1000), "99.9pcsorted",
112+
outer_its, inner_its, stat_stream);
106113

107114

108115
// nearly sorted data generator factory
@@ -123,24 +130,26 @@ int main(int argc, char *argv[]) {
123130
};
124131
};
125132

126-
benchmark_generator<data_t>(unsorted_tail_gen(10), "tail90", iterations, stat_stream);
127-
benchmark_generator<data_t>(unsorted_tail_gen(100), "tail99", iterations, stat_stream);
133+
benchmark_generator<data_t>(unsorted_tail_gen(10), "tail90",
134+
outer_its, inner_its, stat_stream);
135+
benchmark_generator<data_t>(unsorted_tail_gen(100), "tail99",
136+
outer_its, inner_its, stat_stream);
128137

129138

130139
benchmark_generator<data_t>([](auto data, size_t size){
131140
using T = std::remove_reference_t<decltype(*data)>;
132141
for (size_t i = 0; i < size; ++i) {
133142
data[i] = static_cast<T>(i);
134143
}
135-
}, "sorted", iterations, stat_stream);
144+
}, "sorted", outer_its, inner_its, stat_stream);
136145

137146

138147
benchmark_generator<data_t>([](auto data, size_t size){
139148
using T = std::remove_reference_t<decltype(*data)>;
140149
for (size_t i = 0; i < size; ++i) {
141150
data[i] = static_cast<T>(size - i);
142151
}
143-
}, "reverse", iterations, stat_stream);
152+
}, "reverse", outer_its, inner_its, stat_stream);
144153

145154

146155
// Benchmark due to Armin Weiß at Universität Stuttgart
@@ -154,7 +163,7 @@ int main(int argc, char *argv[]) {
154163
j *= j; j *= j; j *= j; j *= j;
155164
data[i] = static_cast<T>(j % flogn);
156165
}
157-
}, "many-dupes", iterations, stat_stream);
166+
}, "many-dupes", outer_its, inner_its, stat_stream);
158167

159168

160169
/* Benchmark due to Armin Weiß at Universität Stuttgart
@@ -176,14 +185,14 @@ int main(int argc, char *argv[]) {
176185
data[i] = static_cast<T>(
177186
(offset_zw + temp*temp) % prev_pow_2);
178187
}
179-
}, "few-spikes-with-noise", iterations, stat_stream);
188+
}, "few-spikes-with-noise", outer_its, inner_its, stat_stream);
180189

181190

182191
benchmark_generator<data_t>([](auto data, size_t size){
183192
for (size_t i = 0; i < size; ++i) {
184193
data[i] = 1;
185194
}
186-
}, "ones", iterations, stat_stream);
195+
}, "ones", outer_its, inner_its, stat_stream);
187196

188197

189198
if (stat_stream != nullptr) {

0 commit comments

Comments
 (0)