diff --git a/README.md b/README.md index 6cfe5ab..f296dfb 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ The reported number of bytes will be bytes / second. - [ ] max - [ ] JSON reporter - [ ] Benchmark registration - - [ ] static - - [ ] Auto-generated main function + - [x] static + - [x] Auto-generated main function - [x] function pointer - [ ] lambda function \ No newline at end of file diff --git a/bin/allreduce.cpp b/bin/allreduce.cpp index dd46a32..01958ec 100644 --- a/bin/allreduce.cpp +++ b/bin/allreduce.cpp @@ -4,24 +4,19 @@ void allreduce(bench::State &state) { + const int rank = bench::world_rank(); + const int size = bench::world_size(); - const int rank = bench::world_rank(); - const int size = bench::world_size(); + const size_t sz = 100000; - const size_t sz = 1000; + char *data = new char[sz]; + for (auto _ : state) { + MPI_Allreduce(MPI_IN_PLACE, data, sz, MPI_BYTE, MPI_SUM, MPI_COMM_WORLD); + } - char *data = new char[sz]; - for (auto _ : state) { - MPI_Allreduce(MPI_IN_PLACE, data, sz, MPI_BYTE, MPI_SUM, MPI_COMM_WORLD); - } - - state.set_bytes_processed(sz * size); - delete[] data; + state.set_bytes_processed(sz); + delete[] data; } -int main(int argc, char **argv) { - bench::init(argc, argv); - bench::register_bench("allreduce", allreduce)->timing_max_rank(); - bench::run_benchmarks(); - bench::finalize(); -} \ No newline at end of file +BENCH(allreduce)->timing_max_rank(); +BENCH_MAIN() \ No newline at end of file diff --git a/bin/empty.cpp b/bin/empty.cpp index 7e258f5..4cc3fe9 100644 --- a/bin/empty.cpp +++ b/bin/empty.cpp @@ -7,10 +7,5 @@ void empty(bench::State &state) { } } -int main(int argc, char **argv) { - - bench::init(argc, argv); - bench::register_bench("empty", empty)->timing_root_rank()->no_iter_barrier(); - bench::run_benchmarks(); - bench::finalize(); -} \ No newline at end of file +BENCH(empty)->timing_root_rank()->no_iter_barrier(); +BENCH_MAIN() \ No newline at end of file diff --git a/bin/pingpong.cpp b/bin/pingpong.cpp index 08166c9..2dcc74a 100644 --- a/bin/pingpong.cpp +++ b/bin/pingpong.cpp @@ -27,9 +27,5 @@ void pingpong(bench::State &state) { delete[] rbuf; } -int main(int argc, char **argv) { - bench::init(argc, argv); - bench::register_bench("pingpong", pingpong)->timing_root_rank()->no_iter_barrier(); - bench::run_benchmarks(); - bench::finalize(); -} \ No newline at end of file +BENCH(pingpong)->timing_root_rank()->no_iter_barrier(); +BENCH_MAIN() \ No newline at end of file diff --git a/include/bench/bench.hpp b/include/bench/bench.hpp index 20176f0..dba44c8 100644 --- a/include/bench/bench.hpp +++ b/include/bench/bench.hpp @@ -86,8 +86,8 @@ public: : iterations_(iterations), bytesProcessed_(0), error_(false), timer_(timer), iterBarrier_(iterBarrier) {} - Iterator begin(); - Iterator end(); + BENCH_ALWAYS_INLINE Iterator begin(); + BENCH_ALWAYS_INLINE Iterator end(); void start_running() { timer_->resume(); } void finish_running() { timer_->pause(); } @@ -126,14 +126,14 @@ public: #ifdef BENCH_USE_MPI if (iterBarrier_) { - // timing was paused in operator++ MPI_Barrier(MPI_COMM_WORLD); + // timing was paused in operator++ resume_timing(); } #endif // if (__builtin_expect(remaining_ != 0, true)) { - if (remaining_ != 0, false) { + if (remaining_ != 0) { return true; } parent_->finish_running(); @@ -144,7 +144,7 @@ public: #ifdef BENCH_USE_MPI if (iterBarrier_) { - // pause timer before barrier + // pause timer before barrier, to be resumed in operator!= pause_timing(); } #endif @@ -157,8 +157,8 @@ public: BENCH_ALWAYS_INLINE void resume_timing() { parent_->timer_->resume(); } }; -inline State::Iterator State::begin() { return State::Iterator(this); } -inline State::Iterator State::end() { +inline BENCH_ALWAYS_INLINE State::Iterator State::begin() { return State::Iterator(this); } +inline BENCH_ALWAYS_INLINE State::Iterator State::end() { start_running(); return State::Iterator(); } @@ -174,11 +174,13 @@ public: bool iter_barrier() { return iterBarrier_; } // only record time at rank 0 + Benchmark *timing_root_rank() { if (timer_) { delete timer_; } + // FIXME: during static registration, this will be before MPI_Init if (world_rank() == 0) { timer_ = new WallTimer(); } else { @@ -204,7 +206,8 @@ private: bool iterBarrier_; }; -extern std::vector benchmarks; +// get all registered benchmarks +std::vector &benchmarks(); typedef void (*Function)(State &); @@ -228,4 +231,27 @@ Benchmark *RegisterBenchmark(const char *name, Fn &&fn, Args &&... args) { } #endif -} // namespace bench \ No newline at end of file +} // namespace bench + +#if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) +#define BENCH_PRIVATE_UNIQUE_ID __COUNTER__ +#else +#define BENCH_PRIVATE_UNIQUE_ID __LINE__ +#endif + +// Helpers for generating unique variable names +#define BENCH_UNIQUE_NAME(n) \ + BENCH_PRIVATE_CONCAT(_bench_, BENCH_PRIVATE_UNIQUE_ID, n) +#define BENCH_PRIVATE_CONCAT(a, b, c) BENCH_PRIVATE_CONCAT2(a, b, c) +#define BENCH_PRIVATE_CONCAT2(a, b, c) a##b##c + +#define BENCH_DECLARE(x) static bench::Benchmark *BENCH_UNIQUE_NAME(x) + +#define BENCH(x) BENCH_DECLARE(x) = bench::register_bench(#x, x) + +#define BENCH_MAIN() \ + int main(int argc, char **argv) { \ + bench::init(argc, argv); \ + bench::run_benchmarks(); \ + bench::finalize(); \ + } diff --git a/src/bench.cpp b/src/bench.cpp index 317f1a1..842eba5 100644 --- a/src/bench.cpp +++ b/src/bench.cpp @@ -9,6 +9,11 @@ namespace bench { +std::vector &benchmarks() { + static std::vector benchmarks; + return benchmarks; +} + void init(int &argc, char **&argv) { #ifdef BENCH_USE_MPI MPI_Init(&argc, &argv); @@ -41,7 +46,7 @@ int world_size() { void run_benchmarks() { - for (Benchmark *benchmark : benchmarks) { + for (Benchmark *benchmark : benchmarks()) { if (0 == world_rank()) { std::cerr << "running " << benchmark->name() << "\n"; } @@ -68,7 +73,6 @@ void run_benchmarks() { double sElapsed = nsElapsed / 1e9; double bytes = state.bytes_processed(); - std::cout << benchmark->name() << ": " << nsElapsed << "ns"; if (state.bytes_processed()) { std::cout << " " << bytes / sElapsed << "B/s"; @@ -79,12 +83,10 @@ void run_benchmarks() { } Benchmark *register_bench(const char *name, Function fn) { - benchmarks.push_back(new FunctionBenchmark(name, fn)); - return benchmarks.back(); + benchmarks().push_back(new FunctionBenchmark(name, fn)); + return benchmarks().back(); } void FunctionBenchmark::run(State &state) { fn_(state); } -/*extern*/ std::vector benchmarks; - } // namespace bench \ No newline at end of file