/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsStopwatch.h" #include #include #if defined(XP_UNIX) #include #include #include #include #elif defined(XP_WIN) #include "windows.h" #endif // elif defined(XP_WIN) #include "nsMemory.h" /* * This basis for the logic in this file comes from (will used to come from): * (mozilla/)modules/libutil/public/stopwatch.cpp. * * It was no longer used in the mozilla tree, and is being migrated to * comm-central where we actually have a need for it. ("Being" in the sense * that it will not be removed immediately from mozilla-central.) * * Simplification and general clean-up has been performed and the fix for * bug 96669 has been integrated. */ NS_IMPL_ISUPPORTS(nsStopwatch, nsIStopwatch) #if defined(XP_UNIX) /** the number of ticks per second */ static double gTicks = 0; #define MICRO_SECONDS_TO_SECONDS_MULT static_cast(1.0e-6) #elif defined(WIN32) #ifdef DEBUG #ifdef MOZILLA_INTERNAL_API #include "nsPrintfCString.h" #endif #endif // 1 tick per 100ns = 10 per us = 10 * 1,000 per ms = 10 * 1,000 * 1,000 per sec. #define WIN32_TICK_RESOLUTION static_cast(1.0e-7) // subtract off to get to the unix epoch #define UNIX_EPOCH_IN_FILE_TIME 116444736000000000L #endif // elif defined(WIN32) nsStopwatch::nsStopwatch() : fTotalRealTimeSecs(0.0) , fTotalCpuTimeSecs(0.0) , fRunning(false) { #if defined(XP_UNIX) // idempotent in the event of a race under all coherency models if (!gTicks) { // we need to clear errno because sysconf's spec says it leaves it the same // on success and only sets it on failure. errno = 0; gTicks = (clock_t)sysconf(_SC_CLK_TCK); // in event of failure, pick an arbitrary value so we don't divide by zero. if (errno) gTicks = 1000000L; } #endif } nsStopwatch::~nsStopwatch() { } NS_IMETHODIMP nsStopwatch::Start() { fTotalRealTimeSecs = 0.0; fTotalCpuTimeSecs = 0.0; return Resume(); } NS_IMETHODIMP nsStopwatch::Stop() { fStopRealTimeSecs = GetRealTime(); fStopCpuTimeSecs = GetCPUTime(); if (fRunning) { fTotalCpuTimeSecs += fStopCpuTimeSecs - fStartCpuTimeSecs; fTotalRealTimeSecs += fStopRealTimeSecs - fStartRealTimeSecs; } fRunning = false; return NS_OK; } NS_IMETHODIMP nsStopwatch::Resume() { if (!fRunning) { fStartRealTimeSecs = GetRealTime(); fStartCpuTimeSecs = GetCPUTime(); } fRunning = true; return NS_OK; } NS_IMETHODIMP nsStopwatch::GetCpuTimeSeconds(double *result) { NS_ENSURE_ARG_POINTER(result); *result = fTotalCpuTimeSecs; return NS_OK; } NS_IMETHODIMP nsStopwatch::GetRealTimeSeconds(double *result) { NS_ENSURE_ARG_POINTER(result); *result = fTotalRealTimeSecs; return NS_OK; } double nsStopwatch::GetRealTime() { #if defined(XP_UNIX) struct timeval t; gettimeofday(&t, NULL); return t.tv_sec + t.tv_usec * MICRO_SECONDS_TO_SECONDS_MULT; #elif defined(WIN32) union {FILETIME ftFileTime; __int64 ftInt64; } ftRealTime; // time the process has spent in kernel mode SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, &ftRealTime.ftFileTime); return (ftRealTime.ftInt64 - UNIX_EPOCH_IN_FILE_TIME) * WIN32_TICK_RESOLUTION; #else #error "nsStopwatch not supported on this platform." #endif } double nsStopwatch::GetCPUTime() { #if defined(XP_UNIX) struct tms cpt; times(&cpt); return (double)(cpt.tms_utime+cpt.tms_stime) / gTicks; #elif defined(WIN32) FILETIME ftCreate, // when the process was created ftExit; // when the process exited union {FILETIME ftFileTime; __int64 ftInt64; } ftKernel; // time the process has spent in kernel mode union {FILETIME ftFileTime; __int64 ftInt64; } ftUser; // time the process has spent in user mode HANDLE hProcess = GetCurrentProcess(); #ifdef DEBUG BOOL ret = #endif GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel.ftFileTime, &ftUser.ftFileTime); #ifdef DEBUG #ifdef MOZILLA_INTERNAL_API if (!ret) NS_ERROR(nsPrintfCString("GetProcessTimes() failed, error=0x%lx.", GetLastError()).get()); #else if (!ret) { // nsPrintfCString() is unavailable to report GetLastError(). NS_ERROR("GetProcessTimes() failed."); } #endif #endif /* * Process times are returned in a 64-bit structure, as the number of * 100 nanosecond ticks since 1 January 1601. User mode and kernel mode * times for this process are in separate 64-bit structures. * Add them and convert the result to seconds. */ return (ftKernel.ftInt64 + ftUser.ftInt64) * WIN32_TICK_RESOLUTION; #else #error "nsStopwatch not supported on this platform." #endif }