SkTime::GetNSecs()
- Move high-precision wall timers from tools/timer to SkTime. - Implement SkTime::GetMSecs() in terms of SkTime::GetNSecs(). - Delete unused tools/timer code. I have no idea what's going on there in src/animator. I don't intend to investigate. BUG=skia: Committed: https://skia.googlesource.com/skia/+/70084cbc16ee8162649f2601377feb6e49de0217 CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Debug-CrOS_Link-Trybot Review URL: https://codereview.chromium.org/1422513003
This commit is contained in:
parent
c9b5f8b152
commit
a1840d50e2
@ -40,6 +40,7 @@
|
||||
[ 'skia_os in ["linux", "freebsd", "openbsd", "solaris", "chromeos"]', {
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-lrt',
|
||||
'-lpthread',
|
||||
],
|
||||
},
|
||||
|
@ -132,39 +132,11 @@
|
||||
{
|
||||
'target_name' : 'timer',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'../tools/timer/Timer.cpp',
|
||||
'../tools/timer/TimerData.cpp',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../include/private',
|
||||
'../src/core',
|
||||
'../src/gpu',
|
||||
],
|
||||
'sources': [ '../tools/timer/Timer.cpp' ],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': ['../tools/timer'],
|
||||
},
|
||||
'dependencies': [
|
||||
'skia_lib.gyp:skia_lib',
|
||||
'jsoncpp.gyp:jsoncpp',
|
||||
],
|
||||
'conditions': [
|
||||
['skia_gpu == 1', {
|
||||
'sources': [ '../tools/timer/GpuTimer.cpp' ],
|
||||
}],
|
||||
[ 'skia_os in ["mac", "ios"]', {
|
||||
'sources': [ '../tools/timer/SysTimer_mach.cpp' ],
|
||||
}],
|
||||
[ 'skia_os == "win"', {
|
||||
'sources': [ '../tools/timer/SysTimer_windows.cpp' ],
|
||||
}],
|
||||
[ 'skia_os in ["linux", "freebsd", "openbsd", "solaris", "android", "chromeos"]', {
|
||||
'sources': [ '../tools/timer/SysTimer_posix.cpp' ],
|
||||
}],
|
||||
[ 'skia_os in ["linux", "freebsd", "openbsd", "solaris", "chromeos"]', {
|
||||
'link_settings': { 'libraries': [ '-lrt' ] },
|
||||
}],
|
||||
],
|
||||
'dependencies': [ 'skia_lib.gyp:skia_lib' ],
|
||||
},
|
||||
{
|
||||
'target_name': 'skdiff',
|
||||
|
@ -34,7 +34,8 @@ public:
|
||||
};
|
||||
static void GetDateTime(DateTime*);
|
||||
|
||||
static SkMSec GetMSecs();
|
||||
static SkMSec GetMSecs() { return (SkMSec)(GetNSecs() * 1e-6); }
|
||||
static double GetNSecs();
|
||||
};
|
||||
|
||||
#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN32)
|
||||
|
@ -28,15 +28,6 @@ void SkTime::GetDateTime(DateTime* t) {
|
||||
}
|
||||
}
|
||||
|
||||
SkMSec SkTime::GetMSecs() {
|
||||
#ifdef SK_DEBUG
|
||||
if (gForceTickCount != (SkMSec) -1) {
|
||||
return gForceTickCount;
|
||||
}
|
||||
#endif
|
||||
return ::GetTickCount();
|
||||
}
|
||||
|
||||
#elif defined(xSK_BUILD_FOR_MAC)
|
||||
|
||||
#include <time.h>
|
||||
@ -58,13 +49,4 @@ void SkTime::GetDateTime(DateTime* t) {
|
||||
}
|
||||
}
|
||||
|
||||
SkMSec SkTime::GetMSecs() {
|
||||
UnsignedWide wide;
|
||||
::Microseconds(&wide);
|
||||
|
||||
int64_t s = ((int64_t)wide.hi << 32) | wide.lo;
|
||||
s = (s + 500) / 1000; // rounded divide
|
||||
return (SkMSec)s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -5,6 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkOncePtr.h"
|
||||
#include "SkString.h"
|
||||
#include "SkTime.h"
|
||||
|
||||
@ -22,3 +23,37 @@ void SkTime::DateTime::toISO8601(SkString* dst) const {
|
||||
timeZoneMinutes);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use rdtscp when (runtime) available
|
||||
// TODO: use std::chrono when (compile-time) available
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
SK_DECLARE_STATIC_ONCE_PTR(double, ns_per_tick);
|
||||
double SkTime::GetNSecs() {
|
||||
uint64_t ticks = __rdtsc();
|
||||
return ticks * *ns_per_tick.get([]{
|
||||
LARGE_INTEGER khz; // The docs say this returns Hz, but it returns KHz.
|
||||
QueryPerformanceFrequency(&khz);
|
||||
return new double(1e6 / khz.QuadPart);
|
||||
});
|
||||
}
|
||||
#elif defined(__MACH__)
|
||||
#include <mach/mach_time.h>
|
||||
SK_DECLARE_STATIC_ONCE_PTR(double, ns_per_tick);
|
||||
double SkTime::GetNSecs() {
|
||||
uint64_t ticks = mach_absolute_time();
|
||||
return ticks * *ns_per_tick.get([]{
|
||||
mach_timebase_info_data_t timebase;
|
||||
(void)mach_timebase_info(&timebase);
|
||||
return new double(timebase.numer * 1.0 / timebase.denom);
|
||||
});
|
||||
}
|
||||
#else
|
||||
#include <time.h>
|
||||
double SkTime::GetNSecs() {
|
||||
struct timespec ts = {0, 0};
|
||||
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1e9 + ts.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
@ -34,10 +34,3 @@ void SkTime::GetDateTime(DateTime* dt)
|
||||
dt->fSecond = SkToU8(tstruct->tm_sec);
|
||||
}
|
||||
}
|
||||
|
||||
SkMSec SkTime::GetMSecs()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return (SkMSec) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds
|
||||
}
|
||||
|
@ -39,14 +39,3 @@ void SkTime::GetDateTime(DateTime* dt)
|
||||
dt->fSecond = SkToU8(st.wSecond);
|
||||
}
|
||||
}
|
||||
|
||||
SkMSec SkTime::GetMSecs()
|
||||
{
|
||||
FILETIME ft;
|
||||
LARGE_INTEGER li;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
li.LowPart = ft.dwLowDateTime;
|
||||
li.HighPart = ft.dwHighDateTime;
|
||||
__int64 t = li.QuadPart; /* In 100-nanosecond intervals */
|
||||
return (SkMSec)(t / 10000); /* In milliseconds */
|
||||
}
|
||||
|
@ -1,77 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "GpuTimer.h"
|
||||
#include "gl/SkGLContext.h"
|
||||
#include "gl/GrGLUtil.h"
|
||||
|
||||
GpuTimer::GpuTimer(const SkGLContext* glctx) : fContext(glctx) {
|
||||
if (fContext) {
|
||||
fContext->ref();
|
||||
fContext->makeCurrent();
|
||||
fStarted = false;
|
||||
fSupported = GrGLGetVersion(fContext->gl()) > GR_GL_VER(3,3) ||
|
||||
fContext->gl()->hasExtension("GL_ARB_timer_query") ||
|
||||
fContext->gl()->hasExtension("GL_EXT_timer_query");
|
||||
|
||||
if (fSupported) {
|
||||
SK_GL(*fContext, GenQueries(1, &fQuery));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GpuTimer::~GpuTimer() {
|
||||
if (fContext) {
|
||||
if (fSupported) {
|
||||
fContext->makeCurrent();
|
||||
SK_GL(*fContext, DeleteQueries(1, &fQuery));
|
||||
}
|
||||
fContext->unref();
|
||||
}
|
||||
}
|
||||
|
||||
void GpuTimer::start() {
|
||||
if (fContext && fSupported) {
|
||||
fContext->makeCurrent();
|
||||
fStarted = true;
|
||||
SK_GL(*fContext, BeginQuery(GR_GL_TIME_ELAPSED, fQuery));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It is important to stop the cpu clocks first,
|
||||
* as this will cpu wait for the gpu to finish.
|
||||
*/
|
||||
double GpuTimer::end() {
|
||||
if (fContext && fSupported) {
|
||||
fStarted = false;
|
||||
fContext->makeCurrent();
|
||||
SK_GL(*fContext, EndQuery(GR_GL_TIME_ELAPSED));
|
||||
|
||||
GrGLint available = 0;
|
||||
while (!available) {
|
||||
SK_GL_NOERRCHECK(*fContext, GetQueryObjectiv(fQuery,
|
||||
GR_GL_QUERY_RESULT_AVAILABLE,
|
||||
&available));
|
||||
// If GetQueryObjectiv is erroring out we need some alternative
|
||||
// means of breaking out of this loop
|
||||
GrGLenum error;
|
||||
SK_GL_RET_NOERRCHECK(*fContext, error, GetError());
|
||||
if (GR_GL_NO_ERROR != error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
GrGLuint64 totalGPUTimeElapsed = 0;
|
||||
SK_GL(*fContext, GetQueryObjectui64v(fQuery,
|
||||
GR_GL_QUERY_RESULT,
|
||||
&totalGPUTimeElapsed));
|
||||
|
||||
return totalGPUTimeElapsed / 1000000.0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef GpuTimer_DEFINED
|
||||
#define GpuTimer_DEFINED
|
||||
|
||||
class SkGLContext;
|
||||
|
||||
class GpuTimer {
|
||||
public:
|
||||
GpuTimer(const SkGLContext*);
|
||||
~GpuTimer();
|
||||
void start();
|
||||
double end();
|
||||
private:
|
||||
unsigned fQuery;
|
||||
int fStarted;
|
||||
const SkGLContext* fContext;
|
||||
bool fSupported;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SysTimer_mach.h"
|
||||
|
||||
static time_value_t mac_cpu_time() {
|
||||
mach_port_t task = mach_task_self();
|
||||
if (task == MACH_PORT_NULL) {
|
||||
time_value_t none = {0, 0};
|
||||
return none;
|
||||
}
|
||||
|
||||
task_thread_times_info thread_info_data;
|
||||
mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
|
||||
if (KERN_SUCCESS != task_info(task,
|
||||
TASK_THREAD_TIMES_INFO,
|
||||
reinterpret_cast<task_info_t>(&thread_info_data),
|
||||
&thread_info_count)) {
|
||||
time_value_t none = {0, 0};
|
||||
return none;
|
||||
}
|
||||
|
||||
time_value_add(&thread_info_data.user_time, &thread_info_data.system_time)
|
||||
return thread_info_data.user_time;
|
||||
}
|
||||
|
||||
static double interval_in_ms(time_value_t start_clock, time_value_t end_clock) {
|
||||
double duration_clock;
|
||||
if ((end_clock.microseconds - start_clock.microseconds) < 0) {
|
||||
duration_clock = (end_clock.seconds - start_clock.seconds-1) * 1000;
|
||||
duration_clock += (1000000 + end_clock.microseconds - start_clock.microseconds) / 1000.0;
|
||||
} else {
|
||||
duration_clock = (end_clock.seconds - start_clock.seconds) * 1000;
|
||||
duration_clock += (end_clock.microseconds - start_clock.microseconds) / 1000.0;
|
||||
}
|
||||
return duration_clock;
|
||||
}
|
||||
|
||||
void SysTimer::startWall() {
|
||||
fStartWall = mach_absolute_time();
|
||||
}
|
||||
|
||||
void SysTimer::startCpu() {
|
||||
fStartCpu = mac_cpu_time();
|
||||
}
|
||||
|
||||
double SysTimer::endCpu() {
|
||||
time_value_t end_cpu = mac_cpu_time();
|
||||
return interval_in_ms(fStartCpu, end_cpu);
|
||||
}
|
||||
|
||||
double SysTimer::endWall() {
|
||||
uint64_t end_wall = mach_absolute_time();
|
||||
|
||||
uint64_t elapsed = end_wall - fStartWall;
|
||||
mach_timebase_info_data_t sTimebaseInfo;
|
||||
if (KERN_SUCCESS != mach_timebase_info(&sTimebaseInfo)) {
|
||||
return 0;
|
||||
} else {
|
||||
uint64_t elapsedNano = elapsed * sTimebaseInfo.numer / sTimebaseInfo.denom;
|
||||
return elapsedNano / 1000000.0;
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef SysTimer_DEFINED
|
||||
#define SysTimer_DEFINED
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
class SysTimer {
|
||||
public:
|
||||
void startWall();
|
||||
void startCpu();
|
||||
double endCpu();
|
||||
double endWall();
|
||||
private:
|
||||
time_value_t fStartCpu;
|
||||
uint64_t fStartWall;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SysTimer_posix.h"
|
||||
|
||||
static double interval_in_ms(timespec start_clock, timespec end_clock)
|
||||
{
|
||||
double duration_clock;
|
||||
if ((end_clock.tv_nsec - start_clock.tv_nsec) < 0) {
|
||||
duration_clock = (end_clock.tv_sec - start_clock.tv_sec - 1) * 1000;
|
||||
duration_clock += (1000000000 + end_clock.tv_nsec - start_clock.tv_nsec) / 1000000.0;
|
||||
} else {
|
||||
duration_clock = (end_clock.tv_sec - start_clock.tv_sec) * 1000;
|
||||
duration_clock += (end_clock.tv_nsec - start_clock.tv_nsec) / 1000000.0;
|
||||
}
|
||||
return duration_clock;
|
||||
}
|
||||
|
||||
void SysTimer::startWall() {
|
||||
if (-1 == clock_gettime(CLOCK_MONOTONIC, &fWall)) {
|
||||
timespec none = {0, 0};
|
||||
fWall = none;
|
||||
}
|
||||
}
|
||||
void SysTimer::startCpu() {
|
||||
if (-1 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &fCpu)) {
|
||||
timespec none = {0, 0};
|
||||
fCpu = none;
|
||||
}
|
||||
}
|
||||
|
||||
double SysTimer::endCpu() {
|
||||
timespec end_cpu;
|
||||
if (-1 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_cpu)) {
|
||||
timespec none = {0, 0};
|
||||
end_cpu = none;
|
||||
}
|
||||
return interval_in_ms(fCpu, end_cpu);
|
||||
}
|
||||
|
||||
double SysTimer::endWall() {
|
||||
timespec end_wall;
|
||||
if (-1 == clock_gettime(CLOCK_MONOTONIC, &end_wall)) {
|
||||
timespec none = {0, 0};
|
||||
end_wall = none;
|
||||
}
|
||||
return interval_in_ms(fWall, end_wall);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef SysTimer_DEFINED
|
||||
#define SysTimer_DEFINED
|
||||
|
||||
#include <time.h>
|
||||
|
||||
class SysTimer {
|
||||
public:
|
||||
void startWall();
|
||||
void startCpu();
|
||||
double endCpu();
|
||||
double endWall();
|
||||
private:
|
||||
timespec fCpu;
|
||||
timespec fWall;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SysTimer_windows.h"
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
static ULONGLONG win_cpu_time() {
|
||||
FILETIME createTime;
|
||||
FILETIME exitTime;
|
||||
FILETIME usrTime;
|
||||
FILETIME sysTime;
|
||||
if (0 == GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &sysTime, &usrTime)) {
|
||||
return 0;
|
||||
}
|
||||
ULARGE_INTEGER start_cpu_sys;
|
||||
ULARGE_INTEGER start_cpu_usr;
|
||||
start_cpu_sys.LowPart = sysTime.dwLowDateTime;
|
||||
start_cpu_sys.HighPart = sysTime.dwHighDateTime;
|
||||
start_cpu_usr.LowPart = usrTime.dwLowDateTime;
|
||||
start_cpu_usr.HighPart = usrTime.dwHighDateTime;
|
||||
return start_cpu_sys.QuadPart + start_cpu_usr.QuadPart;
|
||||
}
|
||||
|
||||
void SysTimer::startCpu() {
|
||||
fStartCpu = win_cpu_time();
|
||||
}
|
||||
|
||||
double SysTimer::endCpu() {
|
||||
ULONGLONG end_cpu = win_cpu_time();
|
||||
return static_cast<double>(end_cpu - fStartCpu) / 10000.0L;
|
||||
}
|
||||
|
||||
// On recent Intel chips (roughly, "has Core or Atom in its name") __rdtsc will always tick
|
||||
// at the CPU's maximum rate, even while power management clocks the CPU up and down.
|
||||
// That's great, because it makes measuring wall time super simple.
|
||||
|
||||
void SysTimer::startWall() {
|
||||
fStartWall = __rdtsc();
|
||||
}
|
||||
|
||||
double SysTimer::endWall() {
|
||||
unsigned __int64 end = __rdtsc();
|
||||
|
||||
// This seems to, weirdly, give the CPU frequency in kHz. That's exactly what we want!
|
||||
LARGE_INTEGER freq_khz;
|
||||
QueryPerformanceFrequency(&freq_khz);
|
||||
|
||||
return static_cast<double>(end - fStartWall) / static_cast<double>(freq_khz.QuadPart);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef SysTimer_DEFINED
|
||||
#define SysTimer_DEFINED
|
||||
|
||||
//Time
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
|
||||
class SysTimer {
|
||||
public:
|
||||
void startWall();
|
||||
void startCpu();
|
||||
double endCpu();
|
||||
double endWall();
|
||||
private:
|
||||
ULONGLONG fStartCpu;
|
||||
unsigned __int64 fStartWall;
|
||||
};
|
||||
|
||||
#endif
|
@ -6,52 +6,6 @@
|
||||
*/
|
||||
#include "Timer.h"
|
||||
|
||||
Timer::Timer(SkGLContext* gl)
|
||||
: fCpu(-1.0)
|
||||
, fWall(-1.0)
|
||||
, fTruncatedCpu(-1.0)
|
||||
, fTruncatedWall(-1.0)
|
||||
, fGpu(-1.0)
|
||||
#if SK_SUPPORT_GPU
|
||||
, fGpuTimer(gl)
|
||||
#endif
|
||||
{}
|
||||
|
||||
void Timer::start() {
|
||||
fSysTimer.startWall();
|
||||
fTruncatedSysTimer.startWall();
|
||||
#if SK_SUPPORT_GPU
|
||||
fGpuTimer.start();
|
||||
#endif
|
||||
fSysTimer.startCpu();
|
||||
fTruncatedSysTimer.startCpu();
|
||||
}
|
||||
|
||||
void Timer::end() {
|
||||
fCpu = fSysTimer.endCpu();
|
||||
#if SK_SUPPORT_GPU
|
||||
//It is important to stop the cpu clocks first,
|
||||
//as the following will cpu wait for the gpu to finish.
|
||||
fGpu = fGpuTimer.end();
|
||||
#endif
|
||||
fWall = fSysTimer.endWall();
|
||||
}
|
||||
|
||||
void Timer::truncatedEnd() {
|
||||
fTruncatedCpu = fTruncatedSysTimer.endCpu();
|
||||
fTruncatedWall = fTruncatedSysTimer.endWall();
|
||||
}
|
||||
|
||||
WallTimer::WallTimer() : fWall(-1.0) {}
|
||||
|
||||
void WallTimer::start() {
|
||||
fSysTimer.startWall();
|
||||
}
|
||||
|
||||
void WallTimer::end() {
|
||||
fWall = fSysTimer.endWall();
|
||||
}
|
||||
|
||||
SkString HumanizeMs(double ms) {
|
||||
if (ms > 60e+3) return SkStringPrintf("%.3gm", ms/60e+3);
|
||||
if (ms > 1e+3) return SkStringPrintf("%.3gs", ms/1e+3);
|
||||
|
@ -7,68 +7,18 @@
|
||||
#ifndef Timer_DEFINED
|
||||
#define Timer_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include "SkString.h"
|
||||
#include "SkTime.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN32)
|
||||
#include "SysTimer_windows.h"
|
||||
#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
|
||||
#include "SysTimer_mach.h"
|
||||
#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
|
||||
#include "SysTimer_posix.h"
|
||||
#endif
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GpuTimer.h"
|
||||
#endif
|
||||
|
||||
class SkGLContext;
|
||||
|
||||
/**
|
||||
* SysTimers and GpuTimers are implemented orthogonally.
|
||||
* This class combines 2 SysTimers and a GpuTimer into one single,
|
||||
* platform specific Timer with a simple interface. The truncated
|
||||
* timer doesn't include the time required for the GPU to finish
|
||||
* its rendering. It should always be <= the un-truncated system
|
||||
* times and (for GPU configurations) can be used to roughly (very
|
||||
* roughly) gauge the GPU load/backlog.
|
||||
*/
|
||||
class Timer {
|
||||
public:
|
||||
explicit Timer(SkGLContext* gl = nullptr);
|
||||
|
||||
void start();
|
||||
void truncatedEnd();
|
||||
void end();
|
||||
|
||||
// All times in milliseconds.
|
||||
double fCpu;
|
||||
double fWall;
|
||||
double fTruncatedCpu;
|
||||
double fTruncatedWall;
|
||||
double fGpu;
|
||||
|
||||
private:
|
||||
SysTimer fSysTimer;
|
||||
SysTimer fTruncatedSysTimer;
|
||||
#if SK_SUPPORT_GPU
|
||||
GpuTimer fGpuTimer;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Same as Timer above, supporting only fWall but with much lower overhead.
|
||||
// (Typically, ~30ns instead of Timer's ~1us.)
|
||||
class WallTimer {
|
||||
public:
|
||||
WallTimer();
|
||||
WallTimer() : fWall(-1) {}
|
||||
|
||||
void start();
|
||||
void end();
|
||||
void start() { fWall = SkTime::GetNSecs(); }
|
||||
void end() { fWall = (SkTime::GetNSecs() - fWall) * 1e-6; }
|
||||
|
||||
double fWall; // Milliseconds.
|
||||
|
||||
private:
|
||||
SysTimer fSysTimer;
|
||||
};
|
||||
|
||||
SkString HumanizeMs(double);
|
||||
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "TimerData.h"
|
||||
|
||||
#include "Timer.h"
|
||||
#include <limits>
|
||||
|
||||
TimerData::TimerData(int maxNumTimings)
|
||||
: fMaxNumTimings(maxNumTimings)
|
||||
, fCurrTiming(0)
|
||||
, fWallTimes(maxNumTimings)
|
||||
, fTruncatedWallTimes(maxNumTimings)
|
||||
, fCpuTimes(maxNumTimings)
|
||||
, fTruncatedCpuTimes(maxNumTimings)
|
||||
, fGpuTimes(maxNumTimings) {}
|
||||
|
||||
bool TimerData::appendTimes(Timer* timer) {
|
||||
SkASSERT(timer != nullptr);
|
||||
if (fCurrTiming >= fMaxNumTimings) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fWallTimes[fCurrTiming] = timer->fWall;
|
||||
fTruncatedWallTimes[fCurrTiming] = timer->fTruncatedWall;
|
||||
fCpuTimes[fCurrTiming] = timer->fCpu;
|
||||
fTruncatedCpuTimes[fCurrTiming] = timer->fTruncatedCpu;
|
||||
fGpuTimes[fCurrTiming] = timer->fGpu;
|
||||
|
||||
++fCurrTiming;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SkString TimerData::getResult(const char* doubleFormat,
|
||||
Result result,
|
||||
const char *configName,
|
||||
uint32_t timerFlags,
|
||||
int itersPerTiming) {
|
||||
SkASSERT(itersPerTiming >= 1);
|
||||
|
||||
if (!fCurrTiming) {
|
||||
return SkString("");
|
||||
}
|
||||
|
||||
int numTimings = fCurrTiming;
|
||||
|
||||
SkString wallStr(" msecs = ");
|
||||
SkString truncWallStr(" Wmsecs = ");
|
||||
SkString cpuStr(" cmsecs = ");
|
||||
SkString truncCpuStr(" Cmsecs = ");
|
||||
SkString gpuStr(" gmsecs = ");
|
||||
|
||||
double wallMin = std::numeric_limits<double>::max();
|
||||
double truncWallMin = std::numeric_limits<double>::max();
|
||||
double cpuMin = std::numeric_limits<double>::max();
|
||||
double truncCpuMin = std::numeric_limits<double>::max();
|
||||
double gpuMin = std::numeric_limits<double>::max();
|
||||
|
||||
double wallSum = 0;
|
||||
double truncWallSum = 0;
|
||||
double cpuSum = 0;
|
||||
double truncCpuSum = 0;
|
||||
double gpuSum = 0;
|
||||
|
||||
for (int i = 0; i < numTimings; ++i) {
|
||||
if (kPerIter_Result == result) {
|
||||
wallStr.appendf(doubleFormat, fWallTimes[i] / itersPerTiming);
|
||||
truncWallStr.appendf(doubleFormat, fTruncatedWallTimes[i] / itersPerTiming);
|
||||
cpuStr.appendf(doubleFormat, fCpuTimes[i] / itersPerTiming);
|
||||
truncCpuStr.appendf(doubleFormat, fTruncatedCpuTimes[i] / itersPerTiming);
|
||||
gpuStr.appendf(doubleFormat, fGpuTimes[i] / itersPerTiming);
|
||||
|
||||
if (i != numTimings - 1) {
|
||||
static const char kSep[] = ", ";
|
||||
wallStr.append(kSep);
|
||||
truncWallStr.append(kSep);
|
||||
cpuStr.append(kSep);
|
||||
truncCpuStr.append(kSep);
|
||||
gpuStr.append(kSep);
|
||||
}
|
||||
} else if (kMin_Result == result) {
|
||||
wallMin = SkTMin(wallMin, fWallTimes[i]);
|
||||
truncWallMin = SkTMin(truncWallMin, fTruncatedWallTimes[i]);
|
||||
cpuMin = SkTMin(cpuMin, fCpuTimes[i]);
|
||||
truncCpuMin = SkTMin(truncCpuMin, fTruncatedCpuTimes[i]);
|
||||
gpuMin = SkTMin(gpuMin, fGpuTimes[i]);
|
||||
} else {
|
||||
SkASSERT(kAvg_Result == result);
|
||||
wallSum += fWallTimes[i];
|
||||
truncWallSum += fTruncatedWallTimes[i];
|
||||
cpuSum += fCpuTimes[i];
|
||||
truncCpuSum += fTruncatedCpuTimes[i];
|
||||
}
|
||||
|
||||
// We always track the GPU sum because whether it is non-zero indicates if valid gpu times
|
||||
// were recorded at all.
|
||||
gpuSum += fGpuTimes[i];
|
||||
}
|
||||
|
||||
if (kMin_Result == result) {
|
||||
wallStr.appendf(doubleFormat, wallMin / itersPerTiming);
|
||||
truncWallStr.appendf(doubleFormat, truncWallMin / itersPerTiming);
|
||||
cpuStr.appendf(doubleFormat, cpuMin / itersPerTiming);
|
||||
truncCpuStr.appendf(doubleFormat, truncCpuMin / itersPerTiming);
|
||||
gpuStr.appendf(doubleFormat, gpuMin / itersPerTiming);
|
||||
} else if (kAvg_Result == result) {
|
||||
int divisor = numTimings * itersPerTiming;
|
||||
wallStr.appendf(doubleFormat, wallSum / divisor);
|
||||
truncWallStr.appendf(doubleFormat, truncWallSum / divisor);
|
||||
cpuStr.appendf(doubleFormat, cpuSum / divisor);
|
||||
truncCpuStr.appendf(doubleFormat, truncCpuSum / divisor);
|
||||
gpuStr.appendf(doubleFormat, gpuSum / divisor);
|
||||
}
|
||||
|
||||
SkString str;
|
||||
str.printf(" %4s:", configName);
|
||||
if (timerFlags & kWall_Flag) {
|
||||
str += wallStr;
|
||||
}
|
||||
if (timerFlags & kTruncatedWall_Flag) {
|
||||
str += truncWallStr;
|
||||
}
|
||||
if (timerFlags & kCpu_Flag) {
|
||||
str += cpuStr;
|
||||
}
|
||||
if (timerFlags & kTruncatedCpu_Flag) {
|
||||
str += truncCpuStr;
|
||||
}
|
||||
if ((timerFlags & kGpu_Flag) && gpuSum > 0) {
|
||||
str += gpuStr;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
Json::Value TimerData::getJSON(uint32_t timerFlags,
|
||||
Result result,
|
||||
int itersPerTiming) {
|
||||
SkASSERT(itersPerTiming >= 1);
|
||||
Json::Value dataNode;
|
||||
Json::Value wallNode, truncWall, cpuNode, truncCpu, gpuNode;
|
||||
if (!fCurrTiming) {
|
||||
return dataNode;
|
||||
}
|
||||
|
||||
int numTimings = fCurrTiming;
|
||||
|
||||
double wallMin = std::numeric_limits<double>::max();
|
||||
double truncWallMin = std::numeric_limits<double>::max();
|
||||
double cpuMin = std::numeric_limits<double>::max();
|
||||
double truncCpuMin = std::numeric_limits<double>::max();
|
||||
double gpuMin = std::numeric_limits<double>::max();
|
||||
|
||||
double wallSum = 0;
|
||||
double truncWallSum = 0;
|
||||
double cpuSum = 0;
|
||||
double truncCpuSum = 0;
|
||||
double gpuSum = 0;
|
||||
|
||||
for (int i = 0; i < numTimings; ++i) {
|
||||
if (kPerIter_Result == result) {
|
||||
wallNode.append(fWallTimes[i] / itersPerTiming);
|
||||
truncWall.append(fTruncatedWallTimes[i] / itersPerTiming);
|
||||
cpuNode.append(fCpuTimes[i] / itersPerTiming);
|
||||
truncCpu.append(fTruncatedCpuTimes[i] / itersPerTiming);
|
||||
gpuNode.append(fGpuTimes[i] / itersPerTiming);
|
||||
} else if (kMin_Result == result) {
|
||||
wallMin = SkTMin(wallMin, fWallTimes[i]);
|
||||
truncWallMin = SkTMin(truncWallMin, fTruncatedWallTimes[i]);
|
||||
cpuMin = SkTMin(cpuMin, fCpuTimes[i]);
|
||||
truncCpuMin = SkTMin(truncCpuMin, fTruncatedCpuTimes[i]);
|
||||
gpuMin = SkTMin(gpuMin, fGpuTimes[i]);
|
||||
} else {
|
||||
SkASSERT(kAvg_Result == result);
|
||||
wallSum += fWallTimes[i];
|
||||
truncWallSum += fTruncatedWallTimes[i];
|
||||
cpuSum += fCpuTimes[i];
|
||||
truncCpuSum += fTruncatedCpuTimes[i];
|
||||
}
|
||||
|
||||
// We always track the GPU sum because whether it is non-zero indicates if valid gpu times
|
||||
// were recorded at all.
|
||||
gpuSum += fGpuTimes[i];
|
||||
}
|
||||
|
||||
if (kMin_Result == result) {
|
||||
wallNode.append(wallMin / itersPerTiming);
|
||||
truncWall.append(truncWallMin / itersPerTiming);
|
||||
cpuNode.append(cpuMin / itersPerTiming);
|
||||
truncCpu.append(truncCpuMin / itersPerTiming);
|
||||
gpuNode.append(gpuMin / itersPerTiming);
|
||||
} else if (kAvg_Result == result) {
|
||||
int divisor = numTimings * itersPerTiming;
|
||||
wallNode.append(wallSum / divisor);
|
||||
truncWall.append(truncWallSum / divisor);
|
||||
cpuNode.append(cpuSum / divisor);
|
||||
truncCpu.append(truncCpuSum / divisor);
|
||||
gpuNode.append(gpuSum / divisor);
|
||||
}
|
||||
|
||||
if (timerFlags & kWall_Flag) {
|
||||
dataNode["wall"] = wallNode;
|
||||
}
|
||||
if (timerFlags & kTruncatedWall_Flag) {
|
||||
dataNode["truncWall"] = truncWall;
|
||||
}
|
||||
if (timerFlags & kCpu_Flag) {
|
||||
dataNode["cpu"] = cpuNode;
|
||||
}
|
||||
if (timerFlags & kTruncatedCpu_Flag) {
|
||||
dataNode["trucCpu"] = truncCpu;
|
||||
}
|
||||
if ((timerFlags & kGpu_Flag) && gpuSum > 0) {
|
||||
dataNode["gpu"] = gpuNode;
|
||||
}
|
||||
return dataNode;
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef TimerData_DEFINED
|
||||
#define TimerData_DEFINED
|
||||
|
||||
#include "SkString.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4530)
|
||||
#endif
|
||||
|
||||
#include "SkJSONCPP.h"
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
class Timer;
|
||||
|
||||
class TimerData {
|
||||
public:
|
||||
/**
|
||||
* Constructs a TimerData to hold at most maxNumTimings sets of elapsed timer values.
|
||||
**/
|
||||
explicit TimerData(int maxNumTimings);
|
||||
|
||||
/**
|
||||
* Collect times from the Timer for an iteration. It will fail if called more often than
|
||||
* indicated in the constructor.
|
||||
*
|
||||
* @param Timer Must not be null.
|
||||
*/
|
||||
bool appendTimes(Timer*);
|
||||
|
||||
enum Result {
|
||||
kMin_Result,
|
||||
kAvg_Result,
|
||||
kPerIter_Result
|
||||
};
|
||||
|
||||
enum TimerFlags {
|
||||
kWall_Flag = 0x1,
|
||||
kTruncatedWall_Flag = 0x2,
|
||||
kCpu_Flag = 0x4,
|
||||
kTruncatedCpu_Flag = 0x8,
|
||||
kGpu_Flag = 0x10
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the timer data results as a string.
|
||||
* @param doubleFormat printf-style format for doubles (e.g. "%02d")
|
||||
* @param result the type of result desired
|
||||
* @param the name of the config being timed (prepended to results string)
|
||||
* @param timerFlags bitfield of TimerFlags values indicating which timers should be reported.
|
||||
* @param itersPerTiming the number of test/bench iterations that correspond to each
|
||||
* appendTimes() call, 1 when appendTimes is called for each iteration.
|
||||
*/
|
||||
SkString getResult(const char* doubleFormat,
|
||||
Result result,
|
||||
const char* configName,
|
||||
uint32_t timerFlags,
|
||||
int itersPerTiming = 1);
|
||||
Json::Value getJSON(uint32_t timerFlags,
|
||||
Result result,
|
||||
int itersPerTiming = 1);
|
||||
|
||||
private:
|
||||
int fMaxNumTimings;
|
||||
int fCurrTiming;
|
||||
|
||||
SkAutoTArray<double> fWallTimes;
|
||||
SkAutoTArray<double> fTruncatedWallTimes;
|
||||
SkAutoTArray<double> fCpuTimes;
|
||||
SkAutoTArray<double> fTruncatedCpuTimes;
|
||||
SkAutoTArray<double> fGpuTimes;
|
||||
};
|
||||
|
||||
#endif // TimerData_DEFINED
|
Loading…
Reference in New Issue
Block a user