Skip to content

Commit ff52bbc

Browse files
committed
High-Resolution timers benchmarks
1 parent 355c127 commit ff52bbc

20 files changed

+556
-269
lines changed

.idea/workspace.xml

+245-225
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
C++ Benchmark Library
33

44
# Todo
5-
* Doxygen documentation
5+
* Port to Linux
6+
* Doxygen summary
67
* Github documentation

bin/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Ignore everything in this directory
2+
*
3+
# Except this file
4+
!.gitignore

examples/timers.cpp

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//
2+
// Created by Ivan Shynkarenka on 31.07.2015.
3+
//
4+
5+
#ifdef _WIN32
6+
#define _WIN32_WINNT 0x0601
7+
#include <windows.h>
8+
#undef max
9+
#undef min
10+
#endif
11+
12+
#ifdef __unix__
13+
#include <time.h>
14+
#endif
15+
16+
#include "macros.h"
17+
18+
#include <limits>
19+
20+
const int iterations = 10000000;
21+
22+
BENCHMARK("std::chrono::high_resolution_clock::now", iterations)
23+
{
24+
static auto timestamp = std::chrono::high_resolution_clock::now();
25+
static int64_t resolution = std::numeric_limits<int64_t>::max();
26+
27+
auto current = std::chrono::high_resolution_clock::now();
28+
int64_t duration = std::chrono::duration_cast<std::chrono::nanoseconds>(current - timestamp).count();
29+
if ((duration > 0) && (duration < resolution)) {
30+
timestamp = current;
31+
resolution = duration;
32+
context.metrics().SetCustom("Resolution", (int)resolution);
33+
}
34+
}
35+
36+
#ifdef _WIN32
37+
BENCHMARK("GetTickCount", iterations)
38+
{
39+
static DWORD timestamp = GetTickCount();
40+
static int64_t resolution = std::numeric_limits<int64_t>::max();
41+
42+
DWORD current = GetTickCount();
43+
int64_t duration = current - timestamp;
44+
if ((duration > 0) && (duration < resolution)) {
45+
timestamp = current;
46+
resolution = duration;
47+
context.metrics().SetCustom("Resolution", (int)(resolution * 1000 * 1000));
48+
}
49+
}
50+
#endif
51+
52+
#ifdef _WIN32
53+
BENCHMARK("GetTickCount64", iterations)
54+
{
55+
static ULONGLONG timestamp = GetTickCount64();
56+
static int64_t resolution = std::numeric_limits<int64_t>::max();
57+
58+
ULONGLONG current = GetTickCount64();
59+
int64_t duration = current - timestamp;
60+
if ((duration > 0) && (duration < resolution)) {
61+
timestamp = current;
62+
resolution = duration;
63+
context.metrics().SetCustom("Resolution", (int)(resolution * 1000 * 1000));
64+
}
65+
}
66+
#endif
67+
68+
#ifdef _WIN32
69+
BENCHMARK("QueryPerformanceCounter", iterations)
70+
{
71+
static LARGE_INTEGER timestamp{0};
72+
static int64_t resolution = std::numeric_limits<int64_t>::max();
73+
74+
LARGE_INTEGER current;
75+
QueryPerformanceCounter(&current);
76+
int64_t duration = current.QuadPart - timestamp.QuadPart;
77+
if ((duration > 0) && (duration < resolution)) {
78+
timestamp = current;
79+
resolution = duration;
80+
81+
LARGE_INTEGER frequency;
82+
QueryPerformanceFrequency(&frequency);
83+
84+
context.metrics().SetCustom("Resolution", (int)(resolution * 1000 * 1000 * 1000 / frequency.QuadPart));
85+
}
86+
}
87+
#endif
88+
89+
#ifdef __unix__
90+
BENCHMARK("clock_gettime", iterations)
91+
{
92+
static timespec timestamp{0};
93+
static int64_t resolution = std::numeric_limits<int64_t>::max();
94+
95+
timespec current;
96+
clock_gettime(CLOCK_REALTIME, &current);
97+
int64_t duration = ((current.tv_sec - timestamp.tv_sec) * 1000 * 1000 * 1000) + (current.tv_nsec - timestamp.tv_nsec);
98+
if ((duration > 0) && (duration < resolution)) {
99+
timestamp = current;
100+
resolution = duration;
101+
context.metrics().SetCustom("Resolution", (int)resolution);
102+
103+
timespec res;
104+
clock_getres(CLOCK_REALTIME, &res);
105+
context.metrics().SetCustom("Resolution (system)", (int)((res.tv_sec * 1000 * 1000 * 1000) + res.tv_nsec));
106+
}
107+
}
108+
#endif
109+
110+
BENCHMARK_MAIN()

include/launcher_console.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class LauncherConsole : public Launcher
3838
\param argc - Arguments count
3939
\param argv - Arguments values
4040
*/
41-
void Initialize(int argc, char** argv);
41+
void Initialize(const int argc, char const* const* const argv);
4242
//! Launch benchmarks executions and show progress in console
4343
void Launch();
4444
//! Report benchmarks results in console

include/phase_core.h

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
//
2-
// Created by Ivan Shynkarenka on 02.07.2015.
3-
//
1+
/*!
2+
\file phase_core.h
3+
\brief Benchmark phase core definition
4+
\author Ivan Shynkarenka
5+
\date 02.07.2015
6+
\copyright MIT License
7+
*/
48

59
#ifndef CPPBENCHMARK_PHASE_CORE_H
610
#define CPPBENCHMARK_PHASE_CORE_H
@@ -16,6 +20,10 @@
1620

1721
namespace CppBenchmark {
1822

23+
//! Benchmark phase core
24+
/*!
25+
Implementation of the Phase interface.
26+
*/
1927
class PhaseCore : public Phase
2028
{
2129
friend class Benchmark;
@@ -24,6 +32,10 @@ class PhaseCore : public Phase
2432
friend class Launcher;
2533

2634
public:
35+
//! Create a new benchmark phase core with a given name
36+
/*!
37+
\param name - Benchmark phase name
38+
*/
2739
explicit PhaseCore(const std::string& name) : _name(name), _thread(System::CurrentThreadId())
2840
{ _metrics_result._total_time = std::numeric_limits<int64_t>::max(); }
2941
PhaseCore(const PhaseCore&) = delete;
@@ -33,6 +45,7 @@ class PhaseCore : public Phase
3345
PhaseCore& operator=(const PhaseCore&) = delete;
3446
PhaseCore& operator=(PhaseCore&&) = delete;
3547

48+
//! Current benchmark phase metrics
3649
PhaseMetrics& current() { return _metrics_current; }
3750

3851
// Implementation of Phase
@@ -47,21 +60,32 @@ class PhaseCore : public Phase
4760
{ return std::make_shared<PhaseScope>(StartPhaseThreadSafe(phase)); }
4861

4962
protected:
63+
//! Synchronization mutex
5064
std::mutex _mutex;
65+
//! Phase name
5166
std::string _name;
67+
//! Thread Id
5268
int _thread;
69+
//! Child phases container
5370
std::vector<std::shared_ptr<PhaseCore>> _child;
71+
//! Current phase metrics
5472
PhaseMetrics _metrics_current;
73+
//! Result phase metrics
5574
PhaseMetrics _metrics_result;
5675

76+
//! Start collecting metrics in the current phase
5777
void StartCollectingMetrics() noexcept
5878
{ _metrics_current.StartCollecting(); }
79+
//! Stop collecting metrics in the current phase
5980
void StopCollectingMetrics() noexcept
6081
{ _metrics_current.StopCollecting(); }
82+
//! Merge phase metrics (current to result)
6183
void MergeMetrics() noexcept
6284
{ _metrics_result.MergeMetrics(_metrics_current); }
85+
//! Merge metrics of the two phases
6386
void MergeMetrics(const PhaseCore& phase) noexcept
6487
{ _metrics_result.MergeMetrics(phase._metrics_result); }
88+
//! Reset current phase metrics
6589
void ResetMetrics() noexcept
6690
{ _metrics_current = PhaseMetrics(); }
6791
};

include/phase_metrics.h

+70-3
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,44 @@
1-
//
2-
// Created by Ivan Shynkarenka on 03.07.2015.
3-
//
1+
/*!
2+
\file phase_metrics.h
3+
\brief Benchmark phase metrics definition
4+
\author Ivan Shynkarenka
5+
\date 03.07.2015
6+
\copyright MIT License
7+
*/
48

59
#ifndef CPPBENCHMARK_PHASE_METRICS_H
610
#define CPPBENCHMARK_PHASE_METRICS_H
711

812
#include <chrono>
913
#include <cstdint>
1014
#include <limits>
15+
#include <unordered_map>
1116

1217
namespace CppBenchmark {
1318

19+
//! Benchmark phase metrics
20+
/*!
21+
Provides interface of the phase metrics to collect benchmark running statistics:
22+
- Average time of the phase execution
23+
- Minimal time of the phase execution
24+
- Maximal time of the phase execution
25+
- Total time of the phase execution
26+
- Total iterations made in the phase
27+
- Total items processed in the phase
28+
- Total bytes processed in the phase
29+
30+
If the phase metrics is accessed from benchmark running Context you can update some metrics values:
31+
- increase iterations count with AddIterations() method
32+
- register processed items with AddItems() method
33+
- register processed bytes with AddBytes() method
34+
- set custom integer/string values by name
35+
*/
1436
class PhaseMetrics
1537
{
1638
friend class PhaseCore;
1739

1840
public:
41+
//! Default constructor
1942
PhaseMetrics() noexcept
2043
: _min_time(std::numeric_limits<int64_t>::max()),
2144
_max_time(std::numeric_limits<int64_t>::min()),
@@ -31,33 +54,77 @@ class PhaseMetrics
3154
PhaseMetrics& operator=(const PhaseMetrics&) noexcept = default;
3255
PhaseMetrics& operator=(PhaseMetrics&&) noexcept = default;
3356

57+
//! Get average time of the phase execution
3458
int64_t avg_time() const noexcept;
59+
//! Get minimal time of the phase execution
3560
int64_t min_time() const noexcept;
61+
//! Get maximal time of the phase execution
3662
int64_t max_time() const noexcept;
3763

64+
//! Get total time of the phase execution
3865
int64_t total_time() const noexcept { return _total_time; }
66+
//! Get total iterations made in the phase
3967
int64_t total_iterations() const noexcept { return _total_iterations; }
68+
//! Get total items processed in the phase
4069
int64_t total_items() const noexcept { return _total_items; }
70+
//! Get total bytes processed in the phase
4171
int64_t total_bytes() const noexcept { return _total_bytes; }
4272

73+
//! Get iterations throughput (iterations / second)
4374
int64_t iterations_per_second() const noexcept;
75+
//! Get items throughput (items / second)
4476
int64_t items_per_second() const noexcept;
77+
//! Get data throughput (bytes / second)
4578
int64_t bytes_per_second() const noexcept;
4679

80+
//! Get custom integers hash table
81+
const std::unordered_map<std::string, int>& custom_int() const noexcept { return _custom_int; }
82+
//! Get custom strings hash table
83+
const std::unordered_map<std::string, std::string>& custom_str() const noexcept { return _custom_str; }
84+
85+
//! Increase iterations count of the current phase
86+
/*!
87+
\param iterations - Iterations count
88+
*/
4789
void AddIterations(int64_t iterations) noexcept
4890
{ _total_iterations += iterations; }
91+
//! Register processed items in the current phase
92+
/*!
93+
\param items - Items count
94+
*/
4995
void AddItems(int64_t items) noexcept
5096
{ _total_items += items; }
97+
//! Register processed bytes in the current phase
98+
/*!
99+
\param bytes - Bytes count
100+
*/
51101
void AddBytes(int64_t bytes) noexcept
52102
{ _total_bytes += bytes; }
53103

104+
//! Set custom integer value
105+
/*!
106+
\param name - Name
107+
\param value - Value
108+
*/
109+
void SetCustom(const std::string& name, int value) noexcept
110+
{ _custom_int[name] = value; }
111+
//! Set custom string value
112+
/*!
113+
\param name - Name
114+
\param value - Value
115+
*/
116+
void SetCustom(const std::string& name, const std::string& value) noexcept
117+
{ _custom_str[name] = value; }
118+
54119
private:
55120
int64_t _min_time;
56121
int64_t _max_time;
57122
int64_t _total_time;
58123
int64_t _total_iterations;
59124
int64_t _total_items;
60125
int64_t _total_bytes;
126+
std::unordered_map<std::string, int> _custom_int;
127+
std::unordered_map<std::string, std::string> _custom_str;
61128

62129
std::chrono::high_resolution_clock::time_point _timestamp;
63130

include/settings.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ class Settings
4949
//! Get count of iterations
5050
int64_t iterations() const { return _iterations; }
5151
//! Get collection of independent threads counts in a benchmark plan
52-
const std::vector<int> threads() const { return _threads; }
52+
const std::vector<int>& threads() const { return _threads; }
5353
//! Get collection of independent producers/consumers counts in a benchmark plan
54-
const std::vector<std::tuple<int, int>> pc() const { return _pc; }
54+
const std::vector<std::tuple<int, int>>& pc() const { return _pc; }
5555
//! Get collection of independent parameters in a benchmark plan
56-
const std::vector<std::tuple<int, int, int>> params() const { return _params; }
56+
const std::vector<std::tuple<int, int, int>>& params() const { return _params; }
5757

5858
//! Set independent benchmark attempts
5959
/*!

source/benchmark.cpp

+1-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include "benchmark.h"
1010

1111
#include <algorithm>
12-
#include <chrono>
1312

1413
#include "launcher_handler.h"
1514

@@ -47,9 +46,6 @@ void Benchmark::Launch(int& current, int total, LauncherHandler& handler)
4746
bool infinite = _settings.infinite();
4847
int64_t iterations = _settings.iterations();
4948

50-
std::chrono::time_point<std::chrono::high_resolution_clock> start;
51-
std::chrono::time_point<std::chrono::high_resolution_clock> stop;
52-
5349
context._current->StartCollectingMetrics();
5450
while (!context.canceled() && (infinite || (iterations > 0)))
5551
{
@@ -163,9 +159,8 @@ void Benchmark::UpdateBenchmarkNames()
163159
void Benchmark::UpdateBenchmarkNames(PhaseCore& phase, const std::string& name)
164160
{
165161
for (auto it = phase._child.begin(); it != phase._child.end(); ++it)
166-
UpdateBenchmarkNames(**it, name + '.' + (*it)->name());
162+
UpdateBenchmarkNames(**it, name + "." + (*it)->name());
167163
phase._name = name;
168-
169164
}
170165

171166
} // namespace CppBenchmark

source/context.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ std::string Context::to_string() const
1515
if ((_x < 0) && (_y < 0) && (_z < 0))
1616
return "()";
1717
else if ((_y < 0) && (_z < 0))
18-
return '(' + std::to_string(_x) + ')';
18+
return "(" + std::to_string(_x) + ")";
1919
else if ((_z < 0))
20-
return '(' + std::to_string(_x) + ',' + std::to_string(_y) + ')';
20+
return "(" + std::to_string(_x) + "," + std::to_string(_y) + ")";
2121
else
22-
return '(' + std::to_string(_x) + ',' + std::to_string(_y) + ',' + std::to_string(_z) + ')';
22+
return "(" + std::to_string(_x) + "," + std::to_string(_y) + "," + std::to_string(_z) + ")";
2323
}
2424

2525
} // namespace CppBenchmark

0 commit comments

Comments
 (0)