Reputation: 23
I want to measure the time of a function execution.
I could use something like this:
using namespace std::chrono;
auto start = steady_clock::now();
// process
auto end = duration<double>(steady_clock::now() - start).count();
but I it seems pretty non-DRY to me. So I created a small function to do it:
template <typename Function, typename... Args>
auto measure_time(Function func, Args&&... args)
{
using namespace std::chrono;
auto start = steady_clock::now();
func(std::forward<Args>(args)...); // handle lvalues and rvalues
return duration<double>(steady_clock::now() - start).count();
}
and I call it as such:
measure_time(func, arg1, arg2, arg3); // for common functions
measure_time([](){func(arg1,arg2, arg3);); // for member or template functions
This works fine for me, but it does come with some drawbacks:
func
(which, of course, can also be void
)?important_function(arg1, arg2); // reads well
measure_time(important_function, arg1, arg2); // measure_time steals the spotlight
Are there any guidelines to face these issues?
I forgot to mention that after the execution of the function I need to store the time elapsed to a container.
after @puio 's answer, I ended up with this:
using namespace std::chrono;
template <typename Container>
class Timer{
public:
Timer(Container& _c) : c(_c) {}
~Timer() {
c.push_back(duration<float>(steady_clock::now() - start).count());
}
private:
time_point<steady_clock> start{steady_clock::now()};
Container& c;
};
Usage:
auto mc = MyContainer{};
...
{
auto t = Timer<MyContainer>(mc);
// things to measure
}
// mc.back() is the elapsed time
DRY and clean :)
Upvotes: 2
Views: 863
Reputation: 85266
... it is not clear to me how it be conveniently changed to also retrieve the return value of
func
Another possible solution is to return a tuple
of the duration and (optionally) the function's return value, when it's not void
.
Something like this (C++17):
using Clock = std::chrono::high_resolution_clock;
template <typename Function, typename... Args>
auto measure_time(const Function& function, Args&&... args) {
auto start = Clock::now();
if constexpr (std::is_same_v<std::invoke_result_t<Function, Args...>, void>) {
std::invoke(function, std::forward<Args>(args)...);
return std::make_tuple<Clock::duration>(Clock::now() - start);
}
else {
std::tuple<Clock::duration, std::invoke_result_t<Function, Args...>> res{0, std::invoke(function, std::forward<Args>(args)...) };
std::get<0>(res) = Clock::now() - start;
return res;
}
}
Use as:
using namespace std::chrono_literals;
int main() {
auto [dur, res] = measure_time(&some_func, some_args);
std::cout << "some_func: " << res << ", time: " << dur / 1us << "us\n";
}
Notes:
By creating the tuple together with the invoke result, we benefit from RVO (the result will be stored at the call site, never copied/moved).
std::invoke
allows invoking pointer-to-member functions.
Upvotes: 1
Reputation: 3096
If recording the time is not part of the main goal of your program. You can use GCC -finstrument-functions
option and provide a definition for the functions:
struct Record {
std::chrono::time_point<std::chrono::steady_clock> start, stop;
};
std::map<void *, Record> container;
void __cyg_profile_func_enter (void *this_fn,
void *call_site) {
auto &record = container[this_fn];
auto start = std::chrono::steady_clock::now();
// do something with start
record.start = start;
}
void __cyg_profile_func_exit (void *this_fn,
void *call_site) {
auto stop = std::chrono::steady_clock::now();
// do something with stop
container[this_fn].stop = stop;
}
Upvotes: 1
Reputation: 1278
Instantiate this class in a function and it will print the time when the object goes out of scope.
class Timer {
private:
std::chrono::steady_clock::time_point begin;
std::string_view func_name;
public:
Timer(std::string_view func)
{
func_name = func;
begin = std::chrono::steady_clock::now();
}
~Timer()
{
const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << func_name << " Time: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()
<< " microseconds " << std::endl;
}
};
Usage:
void slow_func(){
Timer timer{__func__};
// ...
// Destruct automatically.
}
The chrono
functions taken from here since I keep forgetting it.
But I need to store the time elapsed in a container
I imagine it is std::vector
, pass it by non-const reference (as a return value) to the Constructor, store the reference in private
access, and push_back
the time to the vector in the destructor.
A public member function to do so, or calling the destructor explicitly with the said std::vector
just makes it cumbersome. Also, callers may miss using that function.
Upvotes: 2