summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/nsStopwatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/base/src/nsStopwatch.cpp')
-rw-r--r--comm/mailnews/base/src/nsStopwatch.cpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsStopwatch.cpp b/comm/mailnews/base/src/nsStopwatch.cpp
new file mode 100644
index 0000000000..585450d113
--- /dev/null
+++ b/comm/mailnews/base/src/nsStopwatch.cpp
@@ -0,0 +1,164 @@
+/* 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
+# include "nsPrintfCString.h"
+# 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
+ if (!ret)
+ NS_ERROR(nsPrintfCString("GetProcessTimes() failed, error=0x%lx.",
+ GetLastError())
+ .get());
+# 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
+}