summaryrefslogtreecommitdiffstats
path: root/mailnews/base/util/nsStopwatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/base/util/nsStopwatch.cpp')
-rw-r--r--mailnews/base/util/nsStopwatch.cpp183
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
+}