Skip to content

Commit a94015e

Browse files
authored
ScopeTimer (#26)
Adds a new utility `ScopeTimer` that measures the duration of its lifecycle using RAII. e.g.: ```cpp void critical_operation() { ScopeTimer<> _timer([](double elapsed_sec){ std::cout << "critical_operation() took " << elapsed_sec << " seconds." << std::endl; }); // do stuff } ```
1 parent 6ea0686 commit a94015e

File tree

3 files changed

+74
-35
lines changed

3 files changed

+74
-35
lines changed

include/metrics/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,6 @@ We currently rely on [*prometheus-cpp*](https://github.com/jupp0r/prometheus-cpp
154154
### Efficient lookup
155155
* Lookup of existing metric object is supported by *prometheus-cpp* but inefficient. A more optimized lookup would make metric values more accessible in disjoint places within ApertureDB.
156156
### Typed metric values
157-
* Metric values with templatized value types may provide performance, memory, and/or payload improvements.
157+
* Metric values with templatized value types may provide performance, memory, and/or payload improvements. For example, integer-valued counters.
158158
### Remove redundancy
159159
* Histograms and Summaries currently encode redundant data in the distribution. As an added benefit, this may remove the need to represent infinite floating point values in JSON.

include/metrics/Timer.h

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66

77
#pragma once
88

9-
#include <time.h>
10-
#include <math.h>
11-
#include <chrono>
9+
#include <memory>
1210
#include <prometheus/histogram.h>
1311
#include <prometheus/counter.h>
12+
#include "util/ScopeTimer.h"
1413

1514
namespace metrics
1615
{
@@ -23,28 +22,20 @@ template<
2322
class Timer
2423
{
2524
public:
25+
using this_type = Timer< METRIC_TYPE, TIME_UNIT >;
2626
using metric_type = METRIC_TYPE;
27-
using duration_type = typename std::chrono::duration< double, typename TIME_UNIT::period >;
27+
using timer_type = ScopeTimer< TIME_UNIT, double >;
28+
using duration_type = typename timer_type::duration_type;
2829

2930
private:
30-
metric_type* _timer;
31-
timespec _start;
31+
std::unique_ptr< timer_type > _timer;
3232

3333
public:
34-
explicit Timer(metric_type* timer = nullptr,
34+
explicit Timer(metric_type* metric = nullptr,
3535
prometheus::Counter* start_counter = nullptr)
36-
: _timer(timer)
37-
, _start()
36+
: _timer()
3837
{
39-
clock_gettime(CLOCK_MONOTONIC, &_start);
40-
if (start_counter)
41-
start_counter->Increment();
42-
}
43-
44-
~Timer() {
45-
try {
46-
reset();
47-
} catch (...) {}
38+
reset(metric, start_counter);
4839
}
4940

5041
// not copyable
@@ -53,34 +44,28 @@ class Timer
5344

5445
// noexcept moveable
5546
explicit Timer(Timer&& other) noexcept
56-
: _timer( other._timer )
57-
, _start( std::move(other._start) )
47+
: _timer(std::move(other._timer))
5848
{
59-
other._timer = nullptr;
6049
}
6150

6251
Timer& operator=(Timer&& other) noexcept {
6352
if (&other != this) {
64-
_timer = other._timer;
65-
other._timer = nullptr;
66-
_start = std::move( other._start );
53+
_timer = std::move( other._timer );
6754
}
6855
return *this;
6956
}
7057

71-
void reset(metric_type* timer = nullptr,
58+
void reset(metric_type* metric = nullptr,
7259
prometheus::Counter* start_counter = nullptr)
7360
{
74-
timespec now;
75-
clock_gettime(CLOCK_MONOTONIC, &now);
76-
if (_timer) {
77-
duration_type dur =
78-
std::chrono::nanoseconds(now.tv_nsec - _start.tv_nsec) +
79-
std::chrono::seconds(now.tv_sec - _start.tv_sec);
80-
_timer->Observe(dur.count());
61+
if (metric) {
62+
_timer = std::make_unique< timer_type >([metric](double elapsed) {
63+
metric->Observe(elapsed);
64+
});
65+
}
66+
else {
67+
_timer.reset();
8168
}
82-
_timer = timer;
83-
_start = std::move( now );
8469
if ( start_counter ) start_counter->Increment();
8570
}
8671
};

include/util/ScopeTimer.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
*
3+
* @copyright Copyright (c) 2022 ApertureData
4+
*
5+
*/
6+
7+
#pragma once
8+
9+
#include <time.h>
10+
#include <math.h>
11+
#include <chrono>
12+
13+
// A scoped timer that calls the provided callback on destruction passing the elapsed time as arg.
14+
// Usage example:
15+
// void profile_foo() {
16+
// ScopeTimer<> _timer([](double elapsed_sec){
17+
// std::cout << "foo() took " << elapsed_sec << " seconds." << std::endl;
18+
// });
19+
// foo();
20+
// }
21+
template<
22+
typename TIME_UNIT = std::chrono::seconds,
23+
typename TIME_REP = double
24+
>
25+
class ScopeTimer {
26+
public:
27+
using callback_type = std::function< void(TIME_REP) >;
28+
using duration_type = typename std::chrono::duration< TIME_REP, typename TIME_UNIT::period >;
29+
30+
private:
31+
callback_type _cb;
32+
timespec _start;
33+
34+
public:
35+
explicit ScopeTimer(callback_type cb)
36+
: _cb(std::move(cb))
37+
, _start()
38+
{
39+
clock_gettime(CLOCK_MONOTONIC, &_start);
40+
}
41+
42+
~ScopeTimer() {
43+
try {
44+
timespec now;
45+
clock_gettime(CLOCK_MONOTONIC, &now);
46+
if (_cb) {
47+
duration_type dur =
48+
std::chrono::nanoseconds(now.tv_nsec - _start.tv_nsec) +
49+
std::chrono::seconds(now.tv_sec - _start.tv_sec);
50+
_cb(std::move(dur).count());
51+
}
52+
} catch (...) {}
53+
}
54+
};

0 commit comments

Comments
 (0)