Compose function to measure function call times

If you want to do serious measurements of you code use one of the existing libraries for this purpose, for example google-benchmark or Celero.
But if you just want to do simple and maybe temporary measure parts of your code, todays C++ with std::chrono provides some very useful helpers for this purpose.

Measure by using std::chrono

Just take std::chrono::system_clock::now() to get a start and an end time point, take the difference of these (end - start), and cast it into a time duration, maybe nanoseconds.

The example code will not much differ from that one in next section, so no need to be repetitive here.

Write a stop watch using std::chrono

While writing code like mentioned above is easy, it soon becomes tedious. Maybe already after the second time of writing it. The natural reflex of a programmer is to encapsulate this. One way would be to create a StopWatch class.

A possible implementation could look like this, of course various variations of this are possible.

class StopWatch
{
public:

  void start()
  {
    Expects(not started) ;
    started=true ;
    start_time = std::chrono::system_clock::now();
  }

  std::chrono::nanoseconds stop()
  {
    using namespace std::chrono ;
    auto end_time = system_clock::now();
    Expects(started) ;
    started = false ;
    return duration_cast<nanoseconds>(end_time -start_time) ;
  }

private:
  decltype(std::chrono::system_clock::now()) start_time ;
  bool started{false} ;
};

int main ()
{

   StopWatch sw ;
   sw.start() ;
   std::cout << "This took now "
             << sw.stop().count()
             << " nanoseconds" <<std::endl ;
   return 0 ;
}

There are of course some variations possible, like starting the StopWatch in the constructor, and each stop call returns the time since construction. Such details are up to personal taste and the current use case. The hardest problem for such implementations might be to find good names for the classes.

Compose function to measure function call times

It is very likely that the code we want to measure is already packed into a function, and the actual point if interest is: How long does it take to call this function.

We can of course also use the StopWatch from above to simple measure the duration of the function call, and it is maybe the best solution.

But than I would have to stop the post here and chose some different title ;-)

So lets see this also a nice possibility to show how to compose functions add compile time and select different implementations depending on the return type of a function.
For this purpose, timing a function call and get its return value is a good example.

Therefore, say I have a function that
  • takes 0..n arguments

  • might return something or not

  • needs to be pass into an other function that returns the duration of the call plus, if there is, the return value of the other function

Lets call the function that returns the duration timed_call, and something like this should work

void print_hello(){ std::cout << "hello" << std::endl; }
template<typename T> T sum(const T& a, const T& b) { return a + b ;}

auto timed = timed_call(print_hello) ;
std::cout << "print_hello needs " << timed.duration.count()  << "nanoseconds" << std::endl;

// or

auto timed = timed_call(sum<int>,1,3) ;
std::cout << "sum needs " << timed.duration.count()  << "nanoseconds"
            << " and returns " << timed.return_value << std::endl ;

The return value of timed_call need to be a duration, and if the given function returns something, also a return value. This could be a tuple with one or 2 elements, or a struct.
I prefer the struct since it allows me to name the elements what produces imho better readable code.
And I call this struct TimedCallResult for now.

To be able to model the different return types I need, either just a duration or a duration with some value, tepmlate specialization can be used.

template<typename ResultType>
struct TimedCallResult
{
  std::chrono::nanoseconds duration ;
  ResultType return_value;

};

template<>
struct TimedCallResult<void>
{
  std::chrono::nanoseconds duration ;
};

To get the TimedCallResult from a timed_call some glue is needed to select the correct result type.

The glue from timed_call to select and create the TimedCallResult. Buy doing this, the actual measurement can also be done.

The glue code takes one additional template parameter, what is the return type of the function to be called. It is implemented as a functor, or functor, or function object, with partial specialization for the void (not jet but soon) type.

This is not pretty and therefore 'hidden' in a detail namespace. timed_call will later do the work and select and call one of these for us.

namespace details
{
  template<typename ResultType, typename Invokable, typename... Args>
  struct
  TimedCall
  {
    auto operator()(Invokable f, Args&&... args)
      ->TimedCallResult<ResultType>
    {
      using namespace std::chrono ;
      auto start = system_clock::now();
      TimedCallResult<ResultType> r{ nanoseconds{0},
                                     f(std::forward<Args>(args)...)} ;

      r.duration = duration_cast<nanoseconds>(system_clock::now() - start);
      return r ;
    }
  };

  template<typename Invokable, typename... Args>
  struct
  TimedCall<void,Invokable, Args...>
  {
    auto operator()(Invokable f, Args&&... args)
     ->TimedCallResult<void>
    {
      using namespace std::chrono ;
      auto start = system_clock::now();
      f(std::forward<Args>(args)...) ;

      return {duration_cast<nanoseconds>(system_clock::now() - start)} ;
    }
  };
}

There are fore sure different - and maybe more elegant - ways to solve this but this works and is straight forward.

The timed_call function using just the glue in details to get a TimedCallResult

template<typename Invokable, typename... Args>
auto
timed_call(Invokable f, Args&&... args)
->  TimedCallResult<decltype(f(std::forward<Args>(args)...))>
{
  using ResultType = decltype(f(std::forward<Args>(args)...));
  details::TimedCall<ResultType ,Invokable, Args...> meassure;
  return meassure(f, std::forward<Args>(args)...) ;
}

Not a lot to do, just get the return type of the function call and forward it to the implementation details (call the glue in detail).

All the code to play around with here

rextester.com/LDKO62679

Challenge for the reader

I think that C++17 will make the code above much shorter, a static_if should allow to get rid of all the glue code and have just TimedCallResult and timed_call.
Write a StopWatch than make sense to use in the detail::TimeCall glue code

The pleasant anticipation that C++17 will reduce the amount of glue code, beside of showing some functional compositions, is the main reason for writing this blogpost.
But I would also like to mention that having such simple measurement utilities, and some advanced ones, can reduce your OBP dramatically.

Thanks for reading

As usual, if you find any mistakes, in the code or in my spelling, please let me know.
Ideas for improvements, or any other feedback, is also very much welcome.