blob: 093660d83572e873532769370921cc8ff25de226 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __STOUT_STOPWATCH_HPP__
#define __STOUT_STOPWATCH_HPP__
#include <stdint.h>
#include <time.h>
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif // __MACH__
#ifndef __WINDOWS__
#include <sys/time.h>
#endif
#include "duration.hpp"
class Stopwatch
{
public:
Stopwatch()
: running(false)
{
started.tv_sec = 0;
started.tv_nsec = 0;
stopped.tv_sec = 0;
stopped.tv_nsec = 0;
}
void start()
{
started = now();
running = true;
}
void stop()
{
stopped = now();
running = false;
}
Nanoseconds elapsed() const
{
if (!running) {
return Nanoseconds(diff(stopped, started));
}
return Nanoseconds(diff(now(), started));
}
private:
static timespec now()
{
timespec ts;
#ifdef __MACH__
// OS X does not have clock_gettime, use clock_get_time.
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#elif __WINDOWS__
const static __int64 ticks_in_second = 10000000i64;
const static __int64 ns_in_tick = 100;
// Interpret the filetime as a 64-bit unsigned integer to simplify the math
// of converting to `timespec`.
static_assert(
sizeof(FILETIME) == sizeof(__int64),
"stopwatch: We currently require `FILETIME` to be 64 bits in size");
__int64 filetime_in_ticks;
GetSystemTimeAsFileTime(reinterpret_cast<FILETIME*>(&filetime_in_ticks));
// Conversions. `tv_sec` is elapsed seconds, and `tv_nsec` is the remainder
// of the elapsed time, in nanoseconds.
ts.tv_sec = filetime_in_ticks / ticks_in_second;
ts.tv_nsec = filetime_in_ticks % ticks_in_second * ns_in_tick;
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif // __MACH__
return ts;
}
static uint64_t diff(const timespec& from, const timespec& to)
{
return ((from.tv_sec - to.tv_sec) * 1000000000LL)
+ (from.tv_nsec - to.tv_nsec);
}
bool running;
timespec started, stopped;
};
#endif // __STOUT_STOPWATCH_HPP__