Skip to content

Commit

Permalink
High-Resolution timers benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
chronoxor committed Jul 31, 2015
1 parent 355c127 commit ff52bbc
Show file tree
Hide file tree
Showing 20 changed files with 556 additions and 269 deletions.
470 changes: 245 additions & 225 deletions .idea/workspace.xml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
C++ Benchmark Library

# Todo
* Doxygen documentation
* Port to Linux
* Doxygen summary
* Github documentation
4 changes: 4 additions & 0 deletions bin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
110 changes: 110 additions & 0 deletions examples/timers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// Created by Ivan Shynkarenka on 31.07.2015.
//

#ifdef _WIN32
#define _WIN32_WINNT 0x0601
#include <windows.h>
#undef max
#undef min
#endif

#ifdef __unix__
#include <time.h>
#endif

#include "macros.h"

#include <limits>

const int iterations = 10000000;

BENCHMARK("std::chrono::high_resolution_clock::now", iterations)
{
static auto timestamp = std::chrono::high_resolution_clock::now();
static int64_t resolution = std::numeric_limits<int64_t>::max();

auto current = std::chrono::high_resolution_clock::now();
int64_t duration = std::chrono::duration_cast<std::chrono::nanoseconds>(current - timestamp).count();
if ((duration > 0) && (duration < resolution)) {
timestamp = current;
resolution = duration;
context.metrics().SetCustom("Resolution", (int)resolution);
}
}

#ifdef _WIN32
BENCHMARK("GetTickCount", iterations)
{
static DWORD timestamp = GetTickCount();
static int64_t resolution = std::numeric_limits<int64_t>::max();

DWORD current = GetTickCount();
int64_t duration = current - timestamp;
if ((duration > 0) && (duration < resolution)) {
timestamp = current;
resolution = duration;
context.metrics().SetCustom("Resolution", (int)(resolution * 1000 * 1000));
}
}
#endif

#ifdef _WIN32
BENCHMARK("GetTickCount64", iterations)
{
static ULONGLONG timestamp = GetTickCount64();
static int64_t resolution = std::numeric_limits<int64_t>::max();

ULONGLONG current = GetTickCount64();
int64_t duration = current - timestamp;
if ((duration > 0) && (duration < resolution)) {
timestamp = current;
resolution = duration;
context.metrics().SetCustom("Resolution", (int)(resolution * 1000 * 1000));
}
}
#endif

#ifdef _WIN32
BENCHMARK("QueryPerformanceCounter", iterations)
{
static LARGE_INTEGER timestamp{0};
static int64_t resolution = std::numeric_limits<int64_t>::max();

LARGE_INTEGER current;
QueryPerformanceCounter(&current);
int64_t duration = current.QuadPart - timestamp.QuadPart;
if ((duration > 0) && (duration < resolution)) {
timestamp = current;
resolution = duration;

LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);

context.metrics().SetCustom("Resolution", (int)(resolution * 1000 * 1000 * 1000 / frequency.QuadPart));
}
}
#endif

#ifdef __unix__
BENCHMARK("clock_gettime", iterations)
{
static timespec timestamp{0};
static int64_t resolution = std::numeric_limits<int64_t>::max();

timespec current;
clock_gettime(CLOCK_REALTIME, &current);
int64_t duration = ((current.tv_sec - timestamp.tv_sec) * 1000 * 1000 * 1000) + (current.tv_nsec - timestamp.tv_nsec);
if ((duration > 0) && (duration < resolution)) {
timestamp = current;
resolution = duration;
context.metrics().SetCustom("Resolution", (int)resolution);

timespec res;
clock_getres(CLOCK_REALTIME, &res);
context.metrics().SetCustom("Resolution (system)", (int)((res.tv_sec * 1000 * 1000 * 1000) + res.tv_nsec));
}
}
#endif

BENCHMARK_MAIN()
2 changes: 1 addition & 1 deletion include/launcher_console.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class LauncherConsole : public Launcher
\param argc - Arguments count
\param argv - Arguments values
*/
void Initialize(int argc, char** argv);
void Initialize(const int argc, char const* const* const argv);
//! Launch benchmarks executions and show progress in console
void Launch();
//! Report benchmarks results in console
Expand Down
30 changes: 27 additions & 3 deletions include/phase_core.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//
// Created by Ivan Shynkarenka on 02.07.2015.
//
/*!
\file phase_core.h
\brief Benchmark phase core definition
\author Ivan Shynkarenka
\date 02.07.2015
\copyright MIT License
*/

#ifndef CPPBENCHMARK_PHASE_CORE_H
#define CPPBENCHMARK_PHASE_CORE_H
Expand All @@ -16,6 +20,10 @@

namespace CppBenchmark {

//! Benchmark phase core
/*!
Implementation of the Phase interface.
*/
class PhaseCore : public Phase
{
friend class Benchmark;
Expand All @@ -24,6 +32,10 @@ class PhaseCore : public Phase
friend class Launcher;

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

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

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

protected:
//! Synchronization mutex
std::mutex _mutex;
//! Phase name
std::string _name;
//! Thread Id
int _thread;
//! Child phases container
std::vector<std::shared_ptr<PhaseCore>> _child;
//! Current phase metrics
PhaseMetrics _metrics_current;
//! Result phase metrics
PhaseMetrics _metrics_result;

//! Start collecting metrics in the current phase
void StartCollectingMetrics() noexcept
{ _metrics_current.StartCollecting(); }
//! Stop collecting metrics in the current phase
void StopCollectingMetrics() noexcept
{ _metrics_current.StopCollecting(); }
//! Merge phase metrics (current to result)
void MergeMetrics() noexcept
{ _metrics_result.MergeMetrics(_metrics_current); }
//! Merge metrics of the two phases
void MergeMetrics(const PhaseCore& phase) noexcept
{ _metrics_result.MergeMetrics(phase._metrics_result); }
//! Reset current phase metrics
void ResetMetrics() noexcept
{ _metrics_current = PhaseMetrics(); }
};
Expand Down
73 changes: 70 additions & 3 deletions include/phase_metrics.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
//
// Created by Ivan Shynkarenka on 03.07.2015.
//
/*!
\file phase_metrics.h
\brief Benchmark phase metrics definition
\author Ivan Shynkarenka
\date 03.07.2015
\copyright MIT License
*/

#ifndef CPPBENCHMARK_PHASE_METRICS_H
#define CPPBENCHMARK_PHASE_METRICS_H

#include <chrono>
#include <cstdint>
#include <limits>
#include <unordered_map>

namespace CppBenchmark {

//! Benchmark phase metrics
/*!
Provides interface of the phase metrics to collect benchmark running statistics:
- Average time of the phase execution
- Minimal time of the phase execution
- Maximal time of the phase execution
- Total time of the phase execution
- Total iterations made in the phase
- Total items processed in the phase
- Total bytes processed in the phase
If the phase metrics is accessed from benchmark running Context you can update some metrics values:
- increase iterations count with AddIterations() method
- register processed items with AddItems() method
- register processed bytes with AddBytes() method
- set custom integer/string values by name
*/
class PhaseMetrics
{
friend class PhaseCore;

public:
//! Default constructor
PhaseMetrics() noexcept
: _min_time(std::numeric_limits<int64_t>::max()),
_max_time(std::numeric_limits<int64_t>::min()),
Expand All @@ -31,33 +54,77 @@ class PhaseMetrics
PhaseMetrics& operator=(const PhaseMetrics&) noexcept = default;
PhaseMetrics& operator=(PhaseMetrics&&) noexcept = default;

//! Get average time of the phase execution
int64_t avg_time() const noexcept;
//! Get minimal time of the phase execution
int64_t min_time() const noexcept;
//! Get maximal time of the phase execution
int64_t max_time() const noexcept;

//! Get total time of the phase execution
int64_t total_time() const noexcept { return _total_time; }
//! Get total iterations made in the phase
int64_t total_iterations() const noexcept { return _total_iterations; }
//! Get total items processed in the phase
int64_t total_items() const noexcept { return _total_items; }
//! Get total bytes processed in the phase
int64_t total_bytes() const noexcept { return _total_bytes; }

//! Get iterations throughput (iterations / second)
int64_t iterations_per_second() const noexcept;
//! Get items throughput (items / second)
int64_t items_per_second() const noexcept;
//! Get data throughput (bytes / second)
int64_t bytes_per_second() const noexcept;

//! Get custom integers hash table
const std::unordered_map<std::string, int>& custom_int() const noexcept { return _custom_int; }
//! Get custom strings hash table
const std::unordered_map<std::string, std::string>& custom_str() const noexcept { return _custom_str; }

//! Increase iterations count of the current phase
/*!
\param iterations - Iterations count
*/
void AddIterations(int64_t iterations) noexcept
{ _total_iterations += iterations; }
//! Register processed items in the current phase
/*!
\param items - Items count
*/
void AddItems(int64_t items) noexcept
{ _total_items += items; }
//! Register processed bytes in the current phase
/*!
\param bytes - Bytes count
*/
void AddBytes(int64_t bytes) noexcept
{ _total_bytes += bytes; }

//! Set custom integer value
/*!
\param name - Name
\param value - Value
*/
void SetCustom(const std::string& name, int value) noexcept
{ _custom_int[name] = value; }
//! Set custom string value
/*!
\param name - Name
\param value - Value
*/
void SetCustom(const std::string& name, const std::string& value) noexcept
{ _custom_str[name] = value; }

private:
int64_t _min_time;
int64_t _max_time;
int64_t _total_time;
int64_t _total_iterations;
int64_t _total_items;
int64_t _total_bytes;
std::unordered_map<std::string, int> _custom_int;
std::unordered_map<std::string, std::string> _custom_str;

std::chrono::high_resolution_clock::time_point _timestamp;

Expand Down
6 changes: 3 additions & 3 deletions include/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ class Settings
//! Get count of iterations
int64_t iterations() const { return _iterations; }
//! Get collection of independent threads counts in a benchmark plan
const std::vector<int> threads() const { return _threads; }
const std::vector<int>& threads() const { return _threads; }
//! Get collection of independent producers/consumers counts in a benchmark plan
const std::vector<std::tuple<int, int>> pc() const { return _pc; }
const std::vector<std::tuple<int, int>>& pc() const { return _pc; }
//! Get collection of independent parameters in a benchmark plan
const std::vector<std::tuple<int, int, int>> params() const { return _params; }
const std::vector<std::tuple<int, int, int>>& params() const { return _params; }

//! Set independent benchmark attempts
/*!
Expand Down
7 changes: 1 addition & 6 deletions source/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "benchmark.h"

#include <algorithm>
#include <chrono>

#include "launcher_handler.h"

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

std::chrono::time_point<std::chrono::high_resolution_clock> start;
std::chrono::time_point<std::chrono::high_resolution_clock> stop;

context._current->StartCollectingMetrics();
while (!context.canceled() && (infinite || (iterations > 0)))
{
Expand Down Expand Up @@ -163,9 +159,8 @@ void Benchmark::UpdateBenchmarkNames()
void Benchmark::UpdateBenchmarkNames(PhaseCore& phase, const std::string& name)
{
for (auto it = phase._child.begin(); it != phase._child.end(); ++it)
UpdateBenchmarkNames(**it, name + '.' + (*it)->name());
UpdateBenchmarkNames(**it, name + "." + (*it)->name());
phase._name = name;

}

} // namespace CppBenchmark
6 changes: 3 additions & 3 deletions source/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ std::string Context::to_string() const
if ((_x < 0) && (_y < 0) && (_z < 0))
return "()";
else if ((_y < 0) && (_z < 0))
return '(' + std::to_string(_x) + ')';
return "(" + std::to_string(_x) + ")";
else if ((_z < 0))
return '(' + std::to_string(_x) + ',' + std::to_string(_y) + ')';
return "(" + std::to_string(_x) + "," + std::to_string(_y) + ")";
else
return '(' + std::to_string(_x) + ',' + std::to_string(_y) + ',' + std::to_string(_z) + ')';
return "(" + std::to_string(_x) + "," + std::to_string(_y) + "," + std::to_string(_z) + ")";
}

} // namespace CppBenchmark
Loading

0 comments on commit ff52bbc

Please sign in to comment.