-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbench_throughput.cpp
More file actions
97 lines (79 loc) · 2.67 KB
/
bench_throughput.cpp
File metadata and controls
97 lines (79 loc) · 2.67 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
#include <chrono>
#include <cstddef>
#include <future>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
#include "tp/thread_pool.hpp"
namespace {
void busy_work(size_t iters) {
volatile std::size_t sink = 0;
for (size_t i = 0; i < iters; ++i) {
sink += i;
}
}
struct BenchConfig {
size_t tasks = 20000;
size_t work_iters = 5000;
size_t workers = std::thread::hardware_concurrency();
};
BenchConfig parse_args(int argc, char** argv) {
BenchConfig cfg;
if (argc > 1) cfg.tasks = static_cast<size_t>(std::stoull(argv[1]));
if (argc > 2) cfg.work_iters = static_cast<size_t>(std::stoull(argv[2]));
if (argc > 3) cfg.workers = static_cast<size_t>(std::stoull(argv[3]));
if (cfg.workers == 0) cfg.workers = 1;
return cfg;
}
double run_pool(const BenchConfig& cfg) {
tp::ThreadPool pool(cfg.workers);
std::vector<std::future<void>> futures;
futures.reserve(cfg.tasks);
auto start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < cfg.tasks; ++i) {
auto fut_opt = pool.submit([iters = cfg.work_iters]() { busy_work(iters); });
if (fut_opt.has_value()) {
futures.push_back(std::move(*fut_opt));
}
}
for (auto& fut : futures) {
fut.get();
}
auto end = std::chrono::high_resolution_clock::now();
pool.shutdown();
std::chrono::duration<double> seconds = end - start;
return seconds.count();
}
double run_async(const BenchConfig& cfg) {
std::vector<std::future<void>> futures;
futures.reserve(cfg.tasks);
auto start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < cfg.tasks; ++i) {
futures.push_back(std::async(std::launch::async, [iters = cfg.work_iters]() {
busy_work(iters);
}));
}
for (auto& fut : futures) {
fut.get();
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> seconds = end - start;
return seconds.count();
}
} // namespace
int main(int argc, char** argv) {
auto cfg = parse_args(argc, argv);
std::cout << "Throughput benchmark\n";
std::cout << "tasks=" << cfg.tasks << " work_iters=" << cfg.work_iters
<< " workers=" << cfg.workers << "\n";
auto pool_sec = run_pool(cfg);
auto async_sec = run_async(cfg);
auto pool_tps = static_cast<double>(cfg.tasks) / pool_sec;
auto async_tps = static_cast<double>(cfg.tasks) / async_sec;
std::cout << "thread_pool_sec=" << pool_sec
<< " tasks_per_sec=" << pool_tps << "\n";
std::cout << "std_async_sec=" << async_sec
<< " tasks_per_sec=" << async_tps << "\n";
return 0;
}