diff options
Diffstat (limited to 'mailnews/base/util/nsStopwatch.cpp')
-rw-r--r-- | mailnews/base/util/nsStopwatch.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/mailnews/base/util/nsStopwatch.cpp b/mailnews/base/util/nsStopwatch.cpp new file mode 100644 index 000000000..137c456e7 --- /dev/null +++ b/mailnews/base/util/nsStopwatch.cpp @@ -0,0 +1,183 @@ +/* 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 <stdio.h> +#include <time.h> +#if defined(XP_UNIX) +#include <unistd.h> +#include <sys/times.h> +#include <sys/time.h> +#include <errno.h> +#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<double>(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<double>(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 +} |