summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-07-03 13:29:03 (GMT)
committersebres <sebres@users.sourceforge.net>2017-07-03 13:29:03 (GMT)
commit418300bd6d16dcb6a02fad92ce471e69ce17fc7d (patch)
tree32c17f660984780d83c89924e17c4b07b35a3fa8
parent97b969c05b650e02efd46fb0db7305c847d98230 (diff)
downloadtcl-418300bd6d16dcb6a02fad92ce471e69ce17fc7d.zip
tcl-418300bd6d16dcb6a02fad92ce471e69ce17fc7d.tar.gz
tcl-418300bd6d16dcb6a02fad92ce471e69ce17fc7d.tar.bz2
interim commit: try to fix time-drift backwards (too long offset after calibration? something else?)...
-rw-r--r--generic/tclInt.h2
-rw-r--r--generic/tclTimer.c25
-rw-r--r--win/tclWinTime.c376
3 files changed, 260 insertions, 143 deletions
diff --git a/generic/tclInt.h b/generic/tclInt.h
index f13af82..fad78f2 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -2894,8 +2894,8 @@ TclTimeAddMilliseconds(
timePtr->sec += (long)(ms / 1000);
timePtr->usec += (((long)ms) % 1000) * 1000 + (((long)(ms*1000)) % 1000);
if (timePtr->usec > 1000000) {
- timePtr->sec++;
timePtr->usec -= 1000000;
+ timePtr->sec++;
}
}
diff --git a/generic/tclTimer.c b/generic/tclTimer.c
index df974ab..d9e25de 100644
--- a/generic/tclTimer.c
+++ b/generic/tclTimer.c
@@ -108,6 +108,9 @@ static Tcl_ThreadDataKey dataKey;
#define TCL_TIME_DIFF_MS(t1, t2) \
(1000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
((long)(t1).usec - (long)(t2).usec)/1000)
+#define TCL_TIME_DIFF_US(t1, t2) \
+ (1000000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
+ ((long)(t1).usec - (long)(t2).usec))
/*
* Prototypes for functions referenced only in this file:
@@ -1382,8 +1385,8 @@ AfterDelay(
{
Interp *iPtr = (Interp *) interp;
- Tcl_Time endTime, now;
- Tcl_WideInt diff;
+ Tcl_Time endTime, now, prevNow;
+ Tcl_WideInt diff, prevUS, nowUS;
#ifdef TMR_RES_TOLERANCE
long tolerance;
#endif
@@ -1399,11 +1402,20 @@ AfterDelay(
tolerance = ((ms < 1000) ? ms : 1000) * (1000 * TMR_RES_TOLERANCE / 100);
#endif
- Tcl_GetTime(&endTime);
+ prevUS = TclpGetMicroseconds();
+ Tcl_GetTime(&endTime); now = endTime;
+ prevNow = now;
TclTimeAddMilliseconds(&endTime, ms);
do {
+ nowUS = TclpGetMicroseconds();
Tcl_GetTime(&now);
+ if (now.sec < prevNow.sec || (now.sec == prevNow.sec && now.usec < prevNow.usec) ) {
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!long-diff!!!! %5.3f, prev: %d.%06d - now: %d.%06d (%d usec)\n", ms, prevNow.sec, prevNow.usec, now.sec, now.usec, now.usec - prevNow.usec);
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!long-diff!!!! %5.3f, prev: %I64d - now: %I64d (%I64d usec)\n", ms, prevUS, nowUS, nowUS - prevUS);
+ //Tcl_Panic("Time running backwards!");
+ //return TCL_ERROR;
+ }
if (iPtr->limit.timeEvent != NULL
&& TCL_TIME_BEFORE(iPtr->limit.time, now)) {
iPtr->limit.granularityTicker = 0;
@@ -1414,6 +1426,9 @@ AfterDelay(
if (iPtr->limit.timeEvent == NULL
|| TCL_TIME_BEFORE(endTime, iPtr->limit.time)) {
diff = TCL_TIME_DIFF_MS(endTime, now);
+ if (TCL_TIME_DIFF_US(endTime, now) > 500 || TCL_TIME_DIFF_US(endTime, now) < -500) {
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!drift!!!! %5.3f, diff: %d -- %d.%06d - %d.%06d (%d usec)\n", ms, (int)diff, endTime.sec, endTime.usec, now.sec, now.usec, TCL_TIME_DIFF_US(endTime, now));
+ }
#ifndef TCL_WIDE_INT_IS_LONG
if (diff > LONG_MAX) {
diff = LONG_MAX;
@@ -1421,6 +1436,7 @@ AfterDelay(
#endif
if (diff > 0) {
Tcl_Sleep((long)diff);
+ nowUS = TclpGetMicroseconds();
Tcl_GetTime(&now);
}
} else {
@@ -1432,6 +1448,7 @@ AfterDelay(
#endif
if (diff > 0) {
Tcl_Sleep((long)diff);
+ nowUS = TclpGetMicroseconds();
Tcl_GetTime(&now);
}
if (Tcl_LimitCheck(interp) != TCL_OK) {
@@ -1439,6 +1456,8 @@ AfterDelay(
}
}
/* consider timer resolution tolerance (avoid busy wait) */
+ prevNow = now;
+ prevUS = nowUS;
#ifdef TMR_RES_TOLERANCE
now.usec += tolerance;
if (now.usec > 1000000) {
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index def4548..8576656 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -51,7 +51,7 @@ typedef struct TimeInfo {
* initialized. */
int perfCounterAvailable; /* Flag == 1 if the hardware has a performance
* counter. */
- DWORD calibrationInterv; /* Calibration interval in seconds (start 1 sec) */
+ Tcl_WideInt calibNextTime; /* Next time of calibration (in 100-ns ticks) */
HANDLE calibrationThread; /* Handle to the thread that keeps the virtual
* clock calibrated. */
HANDLE readyEvent; /* System event used to trigger the requesting
@@ -62,20 +62,24 @@ typedef struct TimeInfo {
LARGE_INTEGER nominalFreq; /* Nominal frequency of the system performance
* counter, that is, the value returned from
* QueryPerformanceFrequency. */
+ LARGE_INTEGER posixEpoch; /* Posix epoch expressed as 100-ns ticks since
+ * the windows epoch. */
/*
* The following values are used for calculating virtual time. Virtual
* time is always equal to:
- * lastFileTime + (current perf counter - lastCounter)
- * * 10000000 / curCounterFreq
- * and lastFileTime and lastCounter are updated any time that virtual time
- * is returned to a caller.
+ * fileTime + (current perf counter - lastCounter)
+ * * 10000000 / counterFreq
*/
- ULARGE_INTEGER fileTimeLastCall;
- LARGE_INTEGER perfCounterLastCall;
- LARGE_INTEGER curCounterFreq;
- LARGE_INTEGER posixEpoch; /* Posix epoch expressed as 100-ns ticks since
- * the windows epoch. */
+ struct {
+ ULONGLONG fileTime;
+ volatile /* used also to compare calibration epoch */
+ LONGLONG perfCounter;
+ LONGLONG counterFreq;
+ } lastCC; /* Last data updated in calibration cycle */
+
+ Tcl_WideInt lastUsedTime; /* Last known (caller) virtual time in 100-ns
+ * (used to avoid drifts after calibrate) */
/*
* Data used in developing the estimate of performance counter frequency
@@ -92,25 +96,25 @@ static TimeInfo timeInfo = {
{ NULL, 0, 0, NULL, NULL, 0 },
0,
0,
- 1,
+ (Tcl_WideInt) 0,
(HANDLE) NULL,
(HANDLE) NULL,
(HANDLE) NULL,
#ifdef HAVE_CAST_TO_UNION
(LARGE_INTEGER) (Tcl_WideInt) 0,
- (ULARGE_INTEGER) (DWORDLONG) 0,
- (LARGE_INTEGER) (Tcl_WideInt) 0,
- (LARGE_INTEGER) (Tcl_WideInt) 0,
(LARGE_INTEGER) (Tcl_WideInt) 0,
#else
{0, 0},
{0, 0},
- {0, 0},
- {0, 0},
- {0, 0},
#endif
- { 0 },
- { 0 },
+ {
+ (ULONGLONG) 0,
+ (LONGLONG) 0,
+ (LONGLONG) 0
+ },
+ (Tcl_WideInt) 0,
+ { (Tcl_WideUInt) 0 },
+ { (Tcl_WideInt) 0 },
0
};
@@ -154,6 +158,50 @@ ClientData tclTimeClientData = NULL;
/*
*----------------------------------------------------------------------
*
+ * NativeCalc100NsTicks --
+ *
+ * Calculate the current system time in 100-ns ticks since posix epoch,
+ * for current performance counter (curCounter), using given calibrated values.
+ *
+ * Results:
+ * Returns the wide integer with number of microseconds from the epoch.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static inline Tcl_WideInt
+NativeCalc100NsTicks(
+ ULONGLONG ccFileTime,
+ LONGLONG ccPerfCounter,
+ LONGLONG ccCounterFreq,
+ LONGLONG curCounter
+) {
+ return ccFileTime +
+ ((curCounter - ccPerfCounter) * 10000000 / ccCounterFreq);
+}
+
+/*
+ * Representing the number of 100-nanosecond intervals since posix epoch.
+ */
+static inline Tcl_WideInt
+GetSystemTimeAsVirtual(void)
+{
+ FILETIME curSysTime; /* Current system time. */
+ LARGE_INTEGER curFileTime;
+
+ /* 100-ns ticks since since Jan 1, 1601 (UTC) */
+ GetSystemTimeAsFileTime(&curSysTime);
+ curFileTime.LowPart = curSysTime.dwLowDateTime;
+ curFileTime.HighPart = curSysTime.dwHighDateTime;
+ return (Tcl_WideInt)(curFileTime.QuadPart - timeInfo.posixEpoch.QuadPart);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclpGetSeconds --
*
* This procedure returns the number of seconds from the epoch. On most
@@ -331,13 +379,19 @@ TclpWideClickInMicrosec(void)
Tcl_WideInt
TclpGetMicroseconds(void)
{
+ static Tcl_WideInt prevUS = 0;
+ static Tcl_WideInt fileTimeLastCall, perfCounterLastCall, curCounterFreq;
+ static LARGE_INTEGER prevPerfCounter;
+ LARGE_INTEGER newPerfCounter;
+
Tcl_WideInt usecSincePosixEpoch;
/* Try to use high resolution timer */
- if ( tclGetTimeProcPtr == NativeGetTime
- && (usecSincePosixEpoch = NativeGetMicroseconds())
- ) {
- return usecSincePosixEpoch;
+ if (tclGetTimeProcPtr == NativeGetTime) {
+ if ( !(usecSincePosixEpoch = NativeGetMicroseconds()) ) {
+ usecSincePosixEpoch = GetSystemTimeAsVirtual() / 10; /* in 100-ns */
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!no-native-ms!!!!!!!!!!!\n");
+ }
} else {
/*
* Use the Tcl_GetTime abstraction to get the time in microseconds, as
@@ -347,8 +401,31 @@ TclpGetMicroseconds(void)
Tcl_Time now;
tclGetTimeProcPtr(&now, tclTimeClientData); /* Tcl_GetTime inlined */
- return (((Tcl_WideInt)now.sec) * 1000000) + now.usec;
+ usecSincePosixEpoch = (((Tcl_WideInt)now.sec) * 1000000) + now.usec;
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!no-native-ms!!!!!!!!!!!\n");
}
+
+ QueryPerformanceCounter(&newPerfCounter);
+
+ if (prevUS && usecSincePosixEpoch < prevUS) {
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!time-backwards!!!! pre-struct: %I64d, %I64d, %I64d, %I64d == %I64d \n", fileTimeLastCall, perfCounterLastCall, prevPerfCounter.QuadPart, curCounterFreq,
+ NativeCalc100NsTicks(fileTimeLastCall,
+ perfCounterLastCall, curCounterFreq,
+ prevPerfCounter.QuadPart));
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!time-backwards!!!! new-struct: %I64d, %I64d, %I64d, %I64d == %I64d \n", timeInfo.lastCC.fileTime, timeInfo.lastCC.perfCounter, newPerfCounter.QuadPart, timeInfo.lastCC.counterFreq,
+ NativeCalc100NsTicks(timeInfo.lastCC.fileTime,
+ timeInfo.lastCC.perfCounter, timeInfo.lastCC.counterFreq,
+ newPerfCounter.QuadPart));
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!time-backwards!!!! prev: %I64d - now: %I64d (%I64d usec)\n", prevUS, usecSincePosixEpoch, usecSincePosixEpoch - prevUS);
+ Tcl_Panic("Time running backwards!!!");
+ }
+ prevUS = usecSincePosixEpoch;
+ fileTimeLastCall = timeInfo.lastCC.fileTime;
+ perfCounterLastCall = timeInfo.lastCC.perfCounter;
+ curCounterFreq = timeInfo.lastCC.counterFreq;
+ prevPerfCounter.QuadPart = newPerfCounter.QuadPart;
+
+ return usecSincePosixEpoch;
}
/*
@@ -469,20 +546,12 @@ NativeScaleTime(
*----------------------------------------------------------------------
*/
-static inline Tcl_WideInt
-NativeCalc100NsTicks(
- ULONGLONG fileTimeLastCall,
- LONGLONG perfCounterLastCall,
- LONGLONG curCounterFreq,
- LONGLONG curCounter
-) {
- return fileTimeLastCall +
- ((curCounter - perfCounterLastCall) * 10000000 / curCounterFreq);
-}
-
static Tcl_WideInt
NativeGetMicroseconds(void)
{
+ Tcl_WideInt curTime; /* Current time in 100-ns ticks since epoch */
+ Tcl_WideInt lastTime; /* Used to compare with last known time */
+
/*
* Initialize static storage on the first trip through.
*
@@ -595,42 +664,52 @@ NativeGetMicroseconds(void)
TclpInitUnlock();
}
- if (timeInfo.perfCounterAvailable && timeInfo.curCounterFreq.QuadPart!=0) {
- /*
- * Query the performance counter and use it to calculate the current
- * time.
- */
+ if (timeInfo.perfCounterAvailable && timeInfo.lastCC.counterFreq!=0) {
- ULONGLONG fileTimeLastCall;
- LONGLONG perfCounterLastCall, curCounterFreq;
- /* Copy with current data of calibration cycle */
+ static struct {
+ ULONGLONG fileTime;
+ volatile /* don't optimize */
+ LONGLONG perfCounter;
+ LONGLONG counterFreq;
+ Tcl_WideInt calibNextTime;
+ } cc = {0, 0, 0, 0}; /* Copy with current data of calibration cycle */
LARGE_INTEGER curCounter;
/* Current performance counter. */
- QueryPerformanceCounter(&curCounter);
-
/*
* Hold time section locked as short as possible
*/
- EnterCriticalSection(&timeInfo.cs);
-
- fileTimeLastCall = timeInfo.fileTimeLastCall.QuadPart;
- perfCounterLastCall = timeInfo.perfCounterLastCall.QuadPart;
- curCounterFreq = timeInfo.curCounterFreq.QuadPart;
-
- LeaveCriticalSection(&timeInfo.cs);
+ if (cc.perfCounter != timeInfo.lastCC.perfCounter) {
+ EnterCriticalSection(&timeInfo.cs);
+ if (cc.perfCounter != timeInfo.lastCC.perfCounter) {
+ cc.perfCounter = timeInfo.lastCC.perfCounter;
+ cc.fileTime = timeInfo.lastCC.fileTime;
+ cc.counterFreq = timeInfo.lastCC.counterFreq;
+ cc.calibNextTime = timeInfo.calibNextTime;
+ }
+ LeaveCriticalSection(&timeInfo.cs);
+ }
/*
- * If calibration cycle occurred after we get curCounter
+ * Query the performance counter and use it to calculate the current
+ * time.
*/
- if (curCounter.QuadPart <= perfCounterLastCall) {
- /* Calibrated file-time is saved from posix in 100-ns ticks */
- return fileTimeLastCall / 10;
+ QueryPerformanceCounter(&curCounter);
+
+ /* Calibrated file-time is saved from posix in 100-ns ticks */
+ curTime = NativeCalc100NsTicks(cc.fileTime,
+ cc.perfCounter, cc.counterFreq, curCounter.QuadPart);
+
+ /* Be sure the clock ticks never backwards (avoid backwards time-drifts) */
+ if ( (lastTime = timeInfo.lastUsedTime) && lastTime > curTime
+ && lastTime - curTime < 1000000 /* bypass time-switch (drifts only) */
+ ) {
+ curTime = timeInfo.lastUsedTime;
}
/*
- * If it appears to be more than 1.1 seconds since the last trip
+ * If it appears to be more than 1.5 seconds since the last trip
* through the calibration loop, the performance counter may have
* jumped forward. (See MSDN Knowledge Base article Q274323 for a
* description of the hardware problem that makes this test
@@ -639,19 +718,26 @@ NativeGetMicroseconds(void)
* loop should recover.
*/
- if (curCounter.QuadPart - perfCounterLastCall <
- 11 * curCounterFreq * timeInfo.calibrationInterv / 10
- ) {
- /* Calibrated file-time is saved from posix in 100-ns ticks */
- return NativeCalc100NsTicks(fileTimeLastCall,
- perfCounterLastCall, curCounterFreq, curCounter.QuadPart) / 10;
+ if (curTime < cc.calibNextTime + 5000000 /* 500 millisec (in 100-ns ticks). */) {
+ /* save last used time */
+ timeInfo.lastUsedTime = curTime;
+ return curTime / 10;
}
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!calibration-error!!!! cur: %I64d - call: %I64d (%I64d) -- prev: %I64d - now: %I64d (%I64d)\n", curTime, cc.calibNextTime, cc.calibNextTime - curTime, cc.perfCounter, curCounter.QuadPart, curCounter.QuadPart - cc.perfCounter);
}
/*
* High resolution timer is not available.
*/
- return 0;
+ curTime = GetSystemTimeAsVirtual(); /* in 100-ns ticks */
+ /* Be sure the clock ticks never backwards (avoid backwards time-drifts) */
+ if ( (lastTime = timeInfo.lastUsedTime) && lastTime > curTime
+ && lastTime - curTime < 1000000 /* bypass time-switch (drifts only) */
+ ) {
+ curTime = timeInfo.lastUsedTime;
+ }
+ timeInfo.lastUsedTime = curTime;
+ return curTime / 10;
}
/*
@@ -1076,30 +1162,32 @@ static DWORD WINAPI
CalibrationThread(
LPVOID arg)
{
- FILETIME curFileTime;
DWORD waitResult;
/*
* Get initial system time and performance counter.
*/
- GetSystemTimeAsFileTime(&curFileTime);
- QueryPerformanceCounter(&timeInfo.perfCounterLastCall);
- QueryPerformanceFrequency(&timeInfo.curCounterFreq);
- timeInfo.fileTimeLastCall.LowPart = curFileTime.dwLowDateTime;
- timeInfo.fileTimeLastCall.HighPart = curFileTime.dwHighDateTime;
- /* Calibrated file-time will be saved from posix in 100-ns ticks */
- timeInfo.fileTimeLastCall.QuadPart -= timeInfo.posixEpoch.QuadPart;
+ LARGE_INTEGER curPerfCounter;
+
+ QueryPerformanceCounter(&curPerfCounter);
+ timeInfo.lastCC.perfCounter = curPerfCounter.QuadPart;
+ timeInfo.lastCC.counterFreq = timeInfo.nominalFreq.QuadPart;
+ timeInfo.lastCC.fileTime = GetSystemTimeAsVirtual();
- ResetCounterSamples(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart,
- timeInfo.curCounterFreq.QuadPart);
+ ResetCounterSamples(timeInfo.lastCC.fileTime,
+ timeInfo.lastCC.perfCounter,
+ timeInfo.lastCC.counterFreq);
/*
- * Wake up the calling thread. When it wakes up, it will release the
- * initialization lock.
+ * Calibrate first time and wake up the calling thread.
+ * When it wakes up, it will release the initialization lock.
*/
+ if (timeInfo.perfCounterAvailable) {
+ UpdateTimeEachSecond();
+ }
+
SetEvent(timeInfo.readyEvent);
/*
@@ -1153,13 +1241,13 @@ UpdateTimeEachSecond(void)
LARGE_INTEGER curPerfCounter;
/* Current value returned from
* QueryPerformanceCounter. */
- FILETIME curSysTime; /* Current system time. */
- static LARGE_INTEGER lastFileTime; /* File time of the previous calibration */
- LARGE_INTEGER curFileTime; /* File time at the time this callback was
+ static int calibrationInterv = 10000000;
+ /* Calibration interval in 100-ns ticks (starts from 1s) */
+ Tcl_WideInt curFileTime; /* File time at the time this callback was
* scheduled. */
Tcl_WideInt estFreq; /* Estimated perf counter frequency. */
Tcl_WideInt vt0; /* Tcl time right now. */
- Tcl_WideInt vt1; /* Tcl time one second from now. */
+ Tcl_WideInt vt1, nt0, nt1; /* Interim virtual time used during adjustments */
Tcl_WideInt tdiff; /* Difference between system clock and Tcl
* time. */
Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time into
@@ -1169,24 +1257,23 @@ UpdateTimeEachSecond(void)
* Sample performance counter and system time (from posix epoch).
*/
- GetSystemTimeAsFileTime(&curSysTime);
- curFileTime.LowPart = curSysTime.dwLowDateTime;
- curFileTime.HighPart = curSysTime.dwHighDateTime;
- curFileTime.QuadPart -= timeInfo.posixEpoch.QuadPart;
- /* If calibration still not needed (check for possible time switch) */
- if ( curFileTime.QuadPart > lastFileTime.QuadPart
- && curFileTime.QuadPart < lastFileTime.QuadPart +
- (timeInfo.calibrationInterv * 10000000)
+ printf("-------------calibration start, prev-struct: %I64d, %I64d, %I64d\n", timeInfo.lastCC.fileTime, timeInfo.lastCC.perfCounter, timeInfo.lastCC.counterFreq);
+ curFileTime = GetSystemTimeAsVirtual();
+ /*
+ * If calibration still not needed (check for possible time-switch). Note, that
+ * NativeGetMicroseconds checks calibNextTime also, be sure it does not overflow.
+ */
+ if ( curFileTime < timeInfo.calibNextTime - 10000000 /* 1 sec (in 100-ns ticks). */
+ && timeInfo.calibNextTime - curFileTime < 10 * 10000000 /* max. 10 seconds in-between */
) {
/* again in next one second */
+// printf("-------------calibration end, not needed. ------ cur:%I64d - next:%I64d (d: %I64d) ------\n", curFileTime, timeInfo.calibNextTime, timeInfo.calibNextTime - curFileTime);
return;
}
QueryPerformanceCounter(&curPerfCounter);
- lastFileTime.QuadPart = curFileTime.QuadPart;
-
/*
- * We devide by timeInfo.curCounterFreq.QuadPart in several places. That
+ * We devide by timeInfo.lastCC.counterFreq in several places. That
* value should always be positive on a correctly functioning system. But
* it is good to be defensive about such matters. So if something goes
* wrong and the value does goes to zero, we clear the
@@ -1194,7 +1281,7 @@ UpdateTimeEachSecond(void)
* to shut itself down, then return without additional processing.
*/
- if (timeInfo.curCounterFreq.QuadPart == 0){
+ if (timeInfo.lastCC.counterFreq == 0) {
timeInfo.perfCounterAvailable = 0;
return;
}
@@ -1213,16 +1300,15 @@ UpdateTimeEachSecond(void)
* estimate the performance counter frequency.
*/
- estFreq = AccumulateSample(curPerfCounter.QuadPart,
- (Tcl_WideUInt) curFileTime.QuadPart);
+ estFreq = AccumulateSample(curPerfCounter.QuadPart, curFileTime);
/*
* We want to adjust things so that time appears to be continuous.
* Virtual file time, right now, is
*
- * vt0 = 10000000 * (curPerfCounter - perfCounterLastCall)
- * / curCounterFreq
- * + fileTimeLastCall
+ * vt0 = 10000000 * (curPerfCounter - lastCC.perfCounter)
+ * / lastCC.counterFreq
+ * + lastCC.fileTime
*
* Ideally, we would like to drift the clock into place over a period of 2
* sec, so that virtual time 2 sec from now will be
@@ -1233,8 +1319,8 @@ UpdateTimeEachSecond(void)
* is estFreq * 20000000 / (vt1 - vt0)
*/
- vt0 = NativeCalc100NsTicks(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart, timeInfo.curCounterFreq.QuadPart,
+ vt0 = NativeCalc100NsTicks(timeInfo.lastCC.fileTime,
+ timeInfo.lastCC.perfCounter, timeInfo.lastCC.counterFreq,
curPerfCounter.QuadPart);
/*
* If we've gotten more than a second away from system time, then drifting
@@ -1242,80 +1328,92 @@ UpdateTimeEachSecond(void)
* compute the drift frequency and fill in everything.
*/
- tdiff = vt0 - curFileTime.QuadPart;
+ tdiff = vt0 - curFileTime;
if (tdiff > 10000000 || tdiff < -10000000) {
+ /* More as a second difference, so could be a time-switch
/* jump to current system time, use curent estimated frequency */
- vt0 = curFileTime.QuadPart;
+ vt0 = curFileTime;
+ timeInfo.lastUsedTime = 0; /* reset last used time */
} else {
/* calculate new frequency and estimate drift to the next second */
- vt1 = 20000000 + curFileTime.QuadPart;
+ vt1 = 20000000 + curFileTime;
driftFreq = (estFreq * 20000000 / (vt1 - vt0));
/*
* Avoid too large drifts (only half of the current difference),
* that allows also be more accurate (aspire to the smallest tdiff),
* so then we can prolong calibration interval by tdiff < 100000
*/
- driftFreq = timeInfo.curCounterFreq.QuadPart +
- (driftFreq - timeInfo.curCounterFreq.QuadPart) / 2;
+ driftFreq = timeInfo.lastCC.counterFreq +
+ (driftFreq - timeInfo.lastCC.counterFreq) / 2;
/*
* Average between estimated, 2 current and 5 drifted frequencies,
* (do the soft drifting as possible)
*/
- estFreq = (estFreq + 2 * timeInfo.curCounterFreq.QuadPart + 5 * driftFreq) / 8;
+ estFreq = (estFreq + 2 * timeInfo.lastCC.counterFreq + 5 * driftFreq) / 8;
}
- /* Avoid too large discrepancy from nominal frequency */
+ /*
+ * Avoid too large discrepancy from nominal frequency
+ */
if (estFreq > 1003*timeInfo.nominalFreq.QuadPart/1000) {
estFreq = 1003*timeInfo.nominalFreq.QuadPart/1000;
- vt0 = curFileTime.QuadPart;
+ vt0 = curFileTime;
} else if (estFreq < 997*timeInfo.nominalFreq.QuadPart/1000) {
estFreq = 997*timeInfo.nominalFreq.QuadPart/1000;
- vt0 = curFileTime.QuadPart;
- } else if (vt0 != curFileTime.QuadPart) {
+ vt0 = curFileTime;
+ }
+
+ /* If possible backwards time-drifts */
+ if (estFreq > timeInfo.lastCC.counterFreq) {
/*
+ * Calculate the time using new calibration values (and compare with old),
+ * to avoid possible backwards drifts (adjust current base time).
+ * This should affect at least next 10 ticks.
+ */
+ vt1 = curPerfCounter.QuadPart + 10;
+ /*
* Be sure the clock ticks never backwards (avoid it by negative drifting)
* just compare native time (in 100-ns) before and hereafter using
- * new calibrated values) and do a small adjustment (short time freeze)
+ * previous/new calibrated values) and do a small adjustment
*/
- LARGE_INTEGER newPerfCounter;
- Tcl_WideInt nt0, nt1;
-
- QueryPerformanceCounter(&newPerfCounter);
- nt0 = NativeCalc100NsTicks(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart, timeInfo.curCounterFreq.QuadPart,
- newPerfCounter.QuadPart);
- nt1 = NativeCalc100NsTicks(vt0,
+ nt0 = NativeCalc100NsTicks(timeInfo.lastCC.fileTime,
+ timeInfo.lastCC.perfCounter, timeInfo.lastCC.counterFreq,
+ vt1);
+ nt1 = NativeCalc100NsTicks(curFileTime,
curPerfCounter.QuadPart, estFreq,
- newPerfCounter.QuadPart);
- if (nt0 > nt1) { /* drifted backwards, try to compensate with new base */
- /* first adjust with a micro jump (short frozen time is acceptable) */
- vt0 += nt0 - nt1;
- /* if drift unavoidable (e. g. we had a time switch), then reset it */
- vt1 = vt0 - curFileTime.QuadPart;
- if (vt1 > 10000000 || vt1 < -10000000) {
- /* larger jump resp. shift relative new file-time */
- vt0 = curFileTime.QuadPart;
- }
+ vt1);
+ vt1 = (nt0 - nt1); /* old time - new time */
+ if (vt1 > 0 && vt1 < 10000000) {
+ /* base time should jump forwards (the same virtual time using current values) */
+ vt0 += vt1;
}
}
- /* In lock commit new values to timeInfo (hold lock as short as possible) */
- EnterCriticalSection(&timeInfo.cs);
-
/* grow calibration interval up to 10 seconds (if still precise enough) */
if (tdiff < -100000 || tdiff > 100000) {
- /* too long drift - reset calibration interval to 1000 second */
- timeInfo.calibrationInterv = 1;
- } else if (timeInfo.calibrationInterv < 10) {
- timeInfo.calibrationInterv++;
+ /* too long drift - reset calibration interval to 1 second */
+ calibrationInterv = 10000000;
+ } else if (calibrationInterv < 10*10000000) {
+ calibrationInterv += 10000000;
}
- timeInfo.fileTimeLastCall.QuadPart = vt0;
- timeInfo.curCounterFreq.QuadPart = estFreq;
- timeInfo.perfCounterLastCall.QuadPart = curPerfCounter.QuadPart;
+ /* In lock commit new values to timeInfo (hold lock as short as possible) */
+ EnterCriticalSection(&timeInfo.cs);
+
+ timeInfo.lastCC.perfCounter = curPerfCounter.QuadPart;
+ timeInfo.lastCC.fileTime = vt0;
+ timeInfo.lastCC.counterFreq = estFreq;
+
+ timeInfo.calibNextTime = curFileTime + calibrationInterv;
LeaveCriticalSection(&timeInfo.cs);
+#if 1
+ printf("-------------calibration adj -- nt1:%I64d - nt0:%I64d: adj: %I64d\n", nt1, nt0, vt1);
+ printf("-------------calibration end, tdiff %I64d, jump -- vt:%I64d - st:%I64d: %I64d, adj: %I64d\n", tdiff,
+ vt0, curFileTime, (vt0 - curFileTime), vt1);
+ printf("-------------calibration end , new-struct: %I64d, %I64d, %I64d\n", timeInfo.lastCC.fileTime, timeInfo.lastCC.perfCounter, timeInfo.lastCC.counterFreq);
+#endif
}
/*