summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-02-09 13:45:14 (GMT)
committersebres <sebres@users.sourceforge.net>2017-02-09 13:45:14 (GMT)
commitc88fb138612db4499a9e841453cd14bfd5db7224 (patch)
treeb5047ac8c5dbb28b0abc02d0c9d32893bae6ef97
parentfb811680f60f0555a27685601c519ff931956593 (diff)
downloadtcl-c88fb138612db4499a9e841453cd14bfd5db7224.zip
tcl-c88fb138612db4499a9e841453cd14bfd5db7224.tar.gz
tcl-c88fb138612db4499a9e841453cd14bfd5db7224.tar.bz2
[win] accomplished winTime module using very fast wide clicks, with denominator scale to/from microseconds, and therefore more precise "timerate" results under windows (using similar mechanisms as by Mac OSX).
Especially multi-threaded, because it works without lock opposite to microseconds (that use crictical section, because of the calibration thread). The reason for usage of wide clicks instead microseconds explains following example (shows 20% performance deference): % timerate -calibrate {} % timerate {clock microseconds} 5000 0.297037 µs/# 14465901 # 3366585 #/sec 4296.906 nett-ms % timerate {clock clicks} 5000 0.247797 µs/# 16869084 # 4035554 #/sec 4180.116 nett-ms
-rw-r--r--generic/tclInt.h10
-rw-r--r--win/tclWinTime.c107
2 files changed, 103 insertions, 14 deletions
diff --git a/generic/tclInt.h b/generic/tclInt.h
index fb0bcb7..3c21de0 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -3186,6 +3186,7 @@ MODULE_SCOPE int TclpLoadMemory(Tcl_Interp *interp, void *buffer,
MODULE_SCOPE void TclInitThreadStorage(void);
MODULE_SCOPE void TclFinalizeThreadDataThread(void);
MODULE_SCOPE void TclFinalizeThreadStorage(void);
+
#ifdef TCL_WIDE_CLICKS
MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
MODULE_SCOPE double TclpWideClicksToNanoseconds(Tcl_WideInt clicks);
@@ -3194,17 +3195,12 @@ MODULE_SCOPE double TclpWideClickInMicrosec(void);
# ifdef _WIN32
# define TCL_WIDE_CLICKS 1
MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
+MODULE_SCOPE double TclpWideClickInMicrosec(void);
# define TclpWideClicksToNanoseconds(clicks) \
- ((double)(clicks) * 1000)
-# define TclpWideClickInMicrosec() (1)
+ ((double)(clicks) * TclpWideClickInMicrosec() * 1000)
# 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);
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 06ea6cd..7cbc1ba 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -110,6 +110,17 @@ static TimeInfo timeInfo = {
};
/*
+ * Scale to convert wide click values from the TclpGetWideClicks native
+ * resolution to microsecond resolution and back.
+ */
+static struct {
+ int initialized; /* 1 if initialized, 0 otherwise */
+ int perfCounter; /* 1 if performance counter usable for wide clicks */
+ double microsecsScale; /* Denominator scale between clock / microsecs */
+} wideClick = {0, 0.0};
+
+
+/*
* Declarations for functions defined later in this file.
*/
@@ -221,7 +232,7 @@ TclpGetClicks(void)
* resolution clock in microseconds available on the system.
*
* Results:
- * Number of microseconds (from the epoch).
+ * Number of microseconds (from some start time).
*
* Side effects:
* This should be used for time-delta resp. for measurement purposes
@@ -234,6 +245,87 @@ TclpGetClicks(void)
Tcl_WideInt
TclpGetWideClicks(void)
{
+ LARGE_INTEGER curCounter;
+
+ if (!wideClick.initialized) {
+ LARGE_INTEGER perfCounterFreq;
+
+ /*
+ * The frequency of the performance counter is fixed at system boot and
+ * is consistent across all processors. Therefore, the frequency need
+ * only be queried upon application initialization.
+ */
+ if (QueryPerformanceFrequency(&perfCounterFreq)) {
+ wideClick.perfCounter = 1;
+ wideClick.microsecsScale = 1000000.0 / perfCounterFreq.QuadPart;
+ } else {
+ /* fallback using microseconds */
+ wideClick.perfCounter = 0;
+ wideClick.microsecsScale = 1;
+ }
+
+ wideClick.initialized = 1;
+ }
+ if (wideClick.perfCounter) {
+ if (QueryPerformanceCounter(&curCounter)) {
+ return (Tcl_WideInt)curCounter.QuadPart;
+ }
+ /* fallback using microseconds */
+ wideClick.perfCounter = 0;
+ wideClick.microsecsScale = 1;
+ return TclpGetMicroseconds();
+ } else {
+ return TclpGetMicroseconds();
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpWideClickInMicrosec --
+ *
+ * This procedure return scale to convert wide 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 (!wideClick.initialized) {
+ (void)TclpGetWideClicks(); /* initialize */
+ }
+ return wideClick.microsecsScale;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpGetMicroseconds --
+ *
+ * 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:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_WideInt
+TclpGetMicroseconds(void)
+{
Tcl_WideInt usecSincePosixEpoch;
/* Try to use high resolution timer */
@@ -346,6 +438,9 @@ NativeScaleTime(
static Tcl_WideInt
NativeGetMicroseconds(void)
{
+ static LARGE_INTEGER posixEpoch;
+ /* Posix epoch expressed as 100-ns ticks since
+ * the windows epoch. */
/*
* Initialize static storage on the first trip through.
*
@@ -356,6 +451,10 @@ NativeGetMicroseconds(void)
if (!timeInfo.initialized) {
TclpInitLock();
if (!timeInfo.initialized) {
+
+ posixEpoch.LowPart = 0xD53E8000;
+ posixEpoch.HighPart = 0x019DB1DE;
+
timeInfo.perfCounterAvailable =
QueryPerformanceFrequency(&timeInfo.nominalFreq);
@@ -468,15 +567,9 @@ NativeGetMicroseconds(void)
/* Current performance counter. */
Tcl_WideInt curFileTime;/* Current estimated time, expressed as 100-ns
* ticks since the Windows epoch. */
- static LARGE_INTEGER posixEpoch;
- /* Posix epoch expressed as 100-ns ticks since
- * the windows epoch. */
Tcl_WideInt usecSincePosixEpoch;
/* Current microseconds since Posix epoch. */
- posixEpoch.LowPart = 0xD53E8000;
- posixEpoch.HighPart = 0x019DB1DE;
-
QueryPerformanceCounter(&curCounter);
/*