summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-02-09 11:36:17 (GMT)
committersebres <sebres@users.sourceforge.net>2017-02-09 11:36:17 (GMT)
commitfb811680f60f0555a27685601c519ff931956593 (patch)
tree1fd7d26262a58c457148ba5448a9339c3d92771a
parent1ff982ffd6785745b647bbe0bb46aca7e13ace8e (diff)
downloadtcl-fb811680f60f0555a27685601c519ff931956593.zip
tcl-fb811680f60f0555a27685601c519ff931956593.tar.gz
tcl-fb811680f60f0555a27685601c519ff931956593.tar.bz2
[timerate] bug fix: missing scale conversion by Mac OSX on platform where high resolution clicks are not microseconds based;
[win] use high resolution timer for the wide clicks and microseconds directly, prevent several forwards/backwards conversions; [win, unix, mac-osx] normalize some functions for common usage in different time units (clicks, micro- and nanoseconds)
-rw-r--r--generic/tclClock.c9
-rw-r--r--generic/tclCmdMZ.c24
-rw-r--r--generic/tclInt.h16
-rw-r--r--unix/tclUnixTime.c71
-rw-r--r--win/tclWinTime.c166
5 files changed, 238 insertions, 48 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c
index 27009fd..5da9511 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -1760,8 +1760,7 @@ ClockClicksObjCmd(
#endif
break;
case CLICKS_MICROS:
- Tcl_GetTime(&now);
- clicks = ((Tcl_WideInt) now.sec * 1000000) + now.usec;
+ clicks = TclpGetMicroseconds();
break;
}
@@ -1831,15 +1830,11 @@ ClockMicrosecondsObjCmd(
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter values */
{
- Tcl_Time now;
-
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
- Tcl_GetTime(&now);
- Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
- ((Tcl_WideInt) now.sec * 1000000) + now.usec));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(TclpGetMicroseconds()));
return TCL_OK;
}
diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c
index 319799c..b0212c3 100644
--- a/generic/tclCmdMZ.c
+++ b/generic/tclCmdMZ.c
@@ -4215,16 +4215,19 @@ usage:
}
/* get start and stop time */
-#ifndef TCL_WIDE_CLICKS
+#ifdef TCL_WIDE_CLICKS
+ start = middle = TclpGetWideClicks();
+ /* time to stop execution (in wide clicks) */
+ stop = start + (maxms * 1000 / TclpWideClickInMicrosec());
+#else
Tcl_GetTime(&now);
start = now.sec; start *= 1000000; start += now.usec;
-#else
- start = TclpGetWideClicks();
+ middle = start;
+ /* time to stop execution (in microsecs) */
+ stop = start + maxms * 1000;
#endif
/* start measurement */
- stop = start + maxms * 1000;
- middle = start;
while (1) {
/* eval single iteration */
count++;
@@ -4246,11 +4249,11 @@ usage:
if (--threshold > 0) continue;
/* check stop time reached, estimate new threshold */
- #ifndef TCL_WIDE_CLICKS
+ #ifdef TCL_WIDE_CLICKS
+ middle = TclpGetWideClicks();
+ #else
Tcl_GetTime(&now);
middle = now.sec; middle *= 1000000; middle += now.usec;
- #else
- middle = TclpGetWideClicks();
#endif
if (middle >= stop) {
break;
@@ -4274,6 +4277,11 @@ usage:
middle -= start; /* execution time in microsecs */
+ #ifdef TCL_WIDE_CLICKS
+ /* convert execution time in wide clicks to microsecs */
+ middle *= TclpWideClickInMicrosec();
+ #endif
+
/* if not calibrate */
if (!calibrate) {
/* minimize influence of measurement overhead */
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 1b37d84..fb0bcb7 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -3189,7 +3189,23 @@ MODULE_SCOPE void TclFinalizeThreadStorage(void);
#ifdef TCL_WIDE_CLICKS
MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
MODULE_SCOPE double TclpWideClicksToNanoseconds(Tcl_WideInt clicks);
+MODULE_SCOPE double TclpWideClickInMicrosec(void);
+#else
+# ifdef _WIN32
+# define TCL_WIDE_CLICKS 1
+MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
+# define TclpWideClicksToNanoseconds(clicks) \
+ ((double)(clicks) * 1000)
+# define TclpWideClickInMicrosec() (1)
+# endif
#endif
+#ifndef _WIN32
+MODULE_SCOPE Tcl_WideInt TclpGetMicroseconds(void);
+#else
+# define TclpGetMicroseconds() \
+ TclpGetWideClicks()
+#endif
+
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
MODULE_SCOPE void * TclpThreadCreateKey(void);
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index d634449..8ec6e8a 100644
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -84,6 +84,32 @@ TclpGetSeconds(void)
/*
*----------------------------------------------------------------------
*
+ * TclpGetMicroseconds --
+ *
+ * This procedure returns the number of microseconds from the epoch.
+ * On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
+ *
+ * Results:
+ * Number of microseconds from the epoch.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_WideInt
+TclpGetMicroseconds(void)
+{
+ Tcl_Time time;
+
+ tclGetTimeProcPtr(&time, tclTimeClientData);
+ return ((Tcl_WideInt)time.sec)*1000000 + time.usec;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclpGetClicks --
*
* This procedure returns a value that represents the highest resolution
@@ -216,6 +242,51 @@ TclpWideClicksToNanoseconds(
return nsec;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpWideClickInMicrosec --
+ *
+ * This procedure return scale to convert click values from the
+ * TclpGetWideClicks native resolution to microsecond resolution
+ * and back.
+ *
+ * Results:
+ * 1 click in microseconds as double.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+double
+TclpWideClickInMicrosec(void)
+{
+ if (tclGetTimeProcPtr != NativeGetTime) {
+ return 1.0;
+ } else {
+#ifdef MAC_OSX_TCL
+ static int initialized = 0;
+ static double scale = 0.0;
+
+ if (initialized) {
+ return scale;
+ } else {
+ mach_timebase_info_data_t tb;
+
+ mach_timebase_info(&tb);
+ /* value of tb.numer / tb.denom = 1 click in nanoseconds */
+ scale = ((double)tb.numer) / tb.denom / 1000;
+ initialized = 1;
+ return scale;
+ }
+#else
+#error Wide high-resolution clicks not implemented on this platform
+#endif
+ }
+}
#endif /* TCL_WIDE_CLICKS */
/*
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 81d9458..06ea6cd 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -123,6 +123,7 @@ static Tcl_WideInt AccumulateSample(Tcl_WideInt perfCounter,
Tcl_WideUInt fileTime);
static void NativeScaleTime(Tcl_Time* timebuf,
ClientData clientData);
+static Tcl_WideInt NativeGetMicroseconds(void);
static void NativeGetTime(Tcl_Time* timebuf,
ClientData clientData);
@@ -154,10 +155,19 @@ ClientData tclTimeClientData = NULL;
unsigned long
TclpGetSeconds(void)
{
- Tcl_Time t;
+ Tcl_WideInt usecSincePosixEpoch;
- tclGetTimeProcPtr(&t, tclTimeClientData); /* Tcl_GetTime inlined. */
- return t.sec;
+ /* Try to use high resolution timer */
+ if ( tclGetTimeProcPtr == NativeGetTime
+ && (usecSincePosixEpoch = NativeGetMicroseconds())
+ ) {
+ return usecSincePosixEpoch / 1000000;
+ } else {
+ Tcl_Time t;
+
+ tclGetTimeProcPtr(&t, tclTimeClientData); /* Tcl_GetTime inlined. */
+ return t.sec;
+ }
}
/*
@@ -182,19 +192,66 @@ TclpGetSeconds(void)
unsigned long
TclpGetClicks(void)
{
- /*
- * Use the Tcl_GetTime abstraction to get the time in microseconds, as
- * nearly as we can, and return it.
- */
+ Tcl_WideInt usecSincePosixEpoch;
- Tcl_Time now; /* Current Tcl time */
- unsigned long retval; /* Value to return */
+ /* Try to use high resolution timer */
+ if ( tclGetTimeProcPtr == NativeGetTime
+ && (usecSincePosixEpoch = NativeGetMicroseconds())
+ ) {
+ return (unsigned long)usecSincePosixEpoch;
+ } else {
+ /*
+ * Use the Tcl_GetTime abstraction to get the time in microseconds, as
+ * nearly as we can, and return it.
+ */
- tclGetTimeProcPtr(&now, tclTimeClientData); /* Tcl_GetTime inlined */
+ Tcl_Time now; /* Current Tcl time */
- retval = (now.sec * 1000000) + now.usec;
- return retval;
+ tclGetTimeProcPtr(&now, tclTimeClientData); /* Tcl_GetTime inlined */
+ return (unsigned long)(now.sec * 1000000) + now.usec;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpGetWideClicks --
+ *
+ * This procedure returns a WideInt value that represents the highest
+ * resolution clock in microseconds available on the system.
+ *
+ * Results:
+ * Number of microseconds (from the epoch).
+ *
+ * Side effects:
+ * This should be used for time-delta resp. for measurement purposes
+ * only, because on some platforms can return microseconds from some
+ * start time (not from the epoch).
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_WideInt
+TclpGetWideClicks(void)
+{
+ Tcl_WideInt usecSincePosixEpoch;
+
+ /* Try to use high resolution timer */
+ if ( tclGetTimeProcPtr == NativeGetTime
+ && (usecSincePosixEpoch = NativeGetMicroseconds())
+ ) {
+ return usecSincePosixEpoch;
+ } else {
+ /*
+ * Use the Tcl_GetTime abstraction to get the time in microseconds, as
+ * nearly as we can, and return it.
+ */
+
+ Tcl_Time now;
+ tclGetTimeProcPtr(&now, tclTimeClientData); /* Tcl_GetTime inlined */
+ return (((Tcl_WideInt)now.sec) * 1000000) + now.usec;
+ }
}
/*
@@ -223,7 +280,17 @@ void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
- tclGetTimeProcPtr(timePtr, tclTimeClientData);
+ Tcl_WideInt usecSincePosixEpoch;
+
+ /* Try to use high resolution timer */
+ if ( tclGetTimeProcPtr == NativeGetTime
+ && (usecSincePosixEpoch = NativeGetMicroseconds())
+ ) {
+ timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
+ timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
+ } else {
+ tclGetTimeProcPtr(timePtr, tclTimeClientData);
+ }
}
/*
@@ -256,13 +323,14 @@ NativeScaleTime(
/*
*----------------------------------------------------------------------
*
- * NativeGetTime --
+ * NativeGetMicroseconds --
*
- * TIP #233: Gets the current system time in seconds and microseconds
- * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
+ * Gets the current system time in microseconds since the beginning
+ * of the epoch: 00:00 UCT, January 1, 1970.
*
* Results:
- * Returns the current time in timePtr.
+ * Returns the wide integer with number of microseconds from the epoch, or
+ * 0 if high resolution timer is not available.
*
* Side effects:
* On the first call, initializes a set of static variables to keep track
@@ -275,13 +343,9 @@ NativeScaleTime(
*----------------------------------------------------------------------
*/
-static void
-NativeGetTime(
- Tcl_Time *timePtr,
- ClientData clientData)
+static Tcl_WideInt
+NativeGetMicroseconds(void)
{
- struct _timeb t;
-
/*
* Initialize static storage on the first trip through.
*
@@ -432,9 +496,7 @@ NativeGetTime(
if (curCounter.QuadPart <= perfCounterLastCall.QuadPart) {
usecSincePosixEpoch =
(fileTimeLastCall.QuadPart - posixEpoch.QuadPart) / 10;
- timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
- timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
- return;
+ return usecSincePosixEpoch;
}
/*
@@ -455,19 +517,57 @@ NativeGetTime(
* 10000000 / curCounterFreq.QuadPart);
usecSincePosixEpoch = (curFileTime - posixEpoch.QuadPart) / 10;
- timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
- timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
- return;
+ return usecSincePosixEpoch;
}
}
/*
- * High resolution timer is not available. Just use ftime.
+ * High resolution timer is not available.
*/
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NativeGetTime --
+ *
+ * TIP #233: Gets the current system time in seconds and microseconds
+ * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
+ *
+ * Results:
+ * Returns the current time in timePtr.
+ *
+ * Side effects:
+ * See NativeGetMicroseconds for more information.
+ *
+ *----------------------------------------------------------------------
+ */
- _ftime(&t);
- timePtr->sec = (long)t.time;
- timePtr->usec = t.millitm * 1000;
+static void
+NativeGetTime(
+ Tcl_Time *timePtr,
+ ClientData clientData)
+{
+ Tcl_WideInt usecSincePosixEpoch;
+
+ /*
+ * Try to use high resolution timer.
+ */
+ if ( (usecSincePosixEpoch = NativeGetMicroseconds()) ) {
+ timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
+ timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
+ } else {
+ /*
+ * High resolution timer is not available. Just use ftime.
+ */
+
+ struct _timeb t;
+
+ _ftime(&t);
+ timePtr->sec = (long)t.time;
+ timePtr->usec = t.millitm * 1000;
+ }
}
/*