summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--win/tclWinTime.c212
1 files changed, 159 insertions, 53 deletions
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index f8b0712..e956175 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -46,6 +46,7 @@ typedef struct TimeCalibInfo {
ULONGLONG virtTime; /* Last virtual time (in 100-ns) */
LONGLONG perfCounter; /* QPC value of last calibration time */
LONGLONG cntrVariance; /* Current calculated deviation (compensation) */
+ LONGLONG estFrequency; /* Current estimated frequency */
Tcl_WideInt calibNextTime; /* Next time of calibration (in 100-ns ticks) */
} TimeCalibInfo;
@@ -190,10 +191,11 @@ NativeCalc100NsTicks(
ULONGLONG ccVirtTime,
LONGLONG ccPerfCounter,
LONGLONG ccCntrVariance,
+ LONGLONG ccEstFrequency,
LONGLONG curCounter
) {
return ccVirtTime + ( (curCounter - ccPerfCounter) * 10000000
- + ccCntrVariance ) / timeInfo.nominalFreq;
+ + ccCntrVariance ) / ccEstFrequency;
}
/*
@@ -393,7 +395,7 @@ Tcl_WideInt
TclpGetMicroseconds(void)
{
static Tcl_WideInt prevUS = 0;
- static Tcl_WideInt fileTimeLastCall, perfCounterLastCall, curCntrVariance;
+ static Tcl_WideInt fileTimeLastCall, perfCounterLastCall, curCntrVariance, prevEstFrequency;
static LONGLONG prevPerfCounter;
LONGLONG newPerfCounter;
@@ -423,11 +425,11 @@ TclpGetMicroseconds(void)
if (prevUS && usecSincePosixEpoch < prevUS) {
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!time-backwards!!!! pre-struct: %I64d, %I64d, %I64d, %I64d == %I64d \n", fileTimeLastCall, perfCounterLastCall, prevPerfCounter, curCntrVariance,
NativeCalc100NsTicks(fileTimeLastCall,
- perfCounterLastCall, curCntrVariance,
+ perfCounterLastCall, curCntrVariance, prevEstFrequency,
prevPerfCounter));
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!time-backwards!!!! new-struct: %I64d, %I64d, %I64d, %I64d == %I64d \n", timeInfo.lastCC.virtTime, timeInfo.lastCC.perfCounter, newPerfCounter, timeInfo.lastCC.cntrVariance,
NativeCalc100NsTicks(timeInfo.lastCC.virtTime,
- timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance,
+ timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance, timeInfo.lastCC.estFrequency,
newPerfCounter));
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!time-backwards!!!! prev: %I64d - now: %I64d (%I64d usec)\n", prevUS, usecSincePosixEpoch, usecSincePosixEpoch - prevUS);
Tcl_Panic("Time running backwards!!!");
@@ -436,6 +438,7 @@ TclpGetMicroseconds(void)
fileTimeLastCall = timeInfo.lastCC.virtTime;
perfCounterLastCall = timeInfo.lastCC.perfCounter;
curCntrVariance = timeInfo.lastCC.cntrVariance;
+ prevEstFrequency = timeInfo.lastCC.estFrequency;
prevPerfCounter = newPerfCounter;
return usecSincePosixEpoch;
@@ -747,7 +750,7 @@ NativeGetMicroseconds(void)
/* Calibrated file-time is saved from posix in 100-ns ticks */
curTime = NativeCalc100NsTicks(cc.virtTime,
- cc.perfCounter, cc.cntrVariance, curCounter);
+ cc.perfCounter, cc.cntrVariance, cc.estFrequency, curCounter);
/* Be sure the clock ticks never backwards (avoid backwards time-drifts) */
if ( (lastTime = timeInfo.lastUsedTime)
@@ -767,6 +770,9 @@ NativeGetMicroseconds(void)
* loop should recover.
*/
+
+ printf("********* %I64d\n", GetSystemTimeAsVirtual()); /* in 100-ns ticks */
+
if (curTime < cc.calibNextTime + 10000000 /* 1 sec (in 100-ns ticks). */) {
/* save last used time */
timeInfo.lastUsedTime = curTime;
@@ -1220,6 +1226,7 @@ CalibrationThread(
timeInfo.lastCC.perfCounter = NativePerformanceCounter();
timeInfo.lastCC.fileTime = timeInfo.lastCC.virtTime = GetSystemTimeAsVirtual();
+ timeInfo.lastCC.estFrequency = timeInfo.nominalFreq;
/*
* Calibrate first time and wake up the calling thread.
@@ -1288,7 +1295,8 @@ UpdateTimeEachSecond(void)
Tcl_WideInt curFileTime; /* File time at the time this callback was
* scheduled. */
LONGLONG estVariance, /* Estimated variance to compensate ipmact of */
- driftVariance; /* deviations of perfomance counters. */
+ driftVariance, /* deviations of perfomance counters. */
+ estFreq; /* Estimated frequency */
Tcl_WideInt vt0; /* Tcl time right now. */
Tcl_WideInt vt1; /* Interim virtual time used during adjustments */
Tcl_WideInt tdiff, /* Difference between system clock and Tcl time. */
@@ -1300,18 +1308,24 @@ UpdateTimeEachSecond(void)
curFileTime = GetSystemTimeAsVirtual();
curPerfCounter = NativePerformanceCounter();
- printf("-------------calibration start, prev-struct: %I64d, %I64d, %I64d / %I64d, pc-diff: %I64d\n", timeInfo.lastCC.fileTime, timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance, timeInfo.nominalFreq, curPerfCounter - timeInfo.lastCC.perfCounter);
+ printf("-------------calibration start, prev-struct: %I64d, %I64d, %I64d / %I64d, pc-diff: %I64d\n", timeInfo.lastCC.fileTime, timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance, timeInfo.lastCC.estFrequency, curPerfCounter - timeInfo.lastCC.perfCounter);
/*
* Current virtual time (using average between last fileTime and virtTime):
* vt0 = (lastCC.fileTime + lastCC.virtTime) / 2
* + ( (curPerfCounter - lastCC.perfCounter) * 10000000
- * + lastCC.cntrVariance) / nominalFreq
+ * + lastCC.cntrVariance) / lastCC.estFrequency
+ * vt1 = the same with nominalFreq
*/
vt0 = NativeCalc100NsTicks(
(timeInfo.lastCC.fileTime/2 + timeInfo.lastCC.virtTime/2),
timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance,
- curPerfCounter);
+ timeInfo.lastCC.estFrequency, curPerfCounter);
+
+ vt1 = NativeCalc100NsTicks(
+ (timeInfo.lastCC.fileTime/2 + timeInfo.lastCC.virtTime/2),
+ timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance,
+ timeInfo.nominalFreq, curPerfCounter);
/* Differences between virtual and real-time */
tdiff = vt0 - curFileTime;
@@ -1339,44 +1353,60 @@ UpdateTimeEachSecond(void)
/*
* Several things may have gone wrong here that have to be checked for.
* (1) The performance counter may have jumped.
- * (2) The system clock may have been reset.
- */
-
- /*
- * We want to adjust things so that time appears to be continuous.
- * Virtual file time, right now, is vt0.
- *
- * 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
- *
- * vt1 = 10000000 + curFileTime
- *
- * The frequency that we need to use to drift the counter back into place
- * is estFreq * 10000000 / (vt1 - vt0)
- *
- * If we've gotten more than a second away from system time, then drifting
- * the clock is going to be pretty hopeless. Just let it jump. Otherwise,
- * compute the drift frequency and fill in everything.
+ * (2) The system clock may have been reset. Try to compensate rather
+ * with adjustment of variance as of frequency.
*/
if (tdiff > 10000000 || tdiff < -10000000) {
/* More as a second difference, so could be a time-switch (reset)
/* jump to current system time, use curent estimated frequency */
- vt0 = curFileTime;
timeInfo.lastUsedTime = 0; /* reset last used time */
+ estFreq = timeInfo.nominalFreq;
estVariance = 0;
+ vt0 = curFileTime;
} else {
+ int repeatCnt = 2;
+
+ estVariance = timeInfo.lastCC.cntrVariance;
+ estFreq = timeInfo.lastCC.estFrequency;
+
+ /* Check nominal frequency would be better choice (nearby to curFileTime) */
+ if ((tdiff >= 0 && vt1 < vt0) || (tdiff < 0 && vt1 > vt0)) {
+ estFreq = (estFreq + timeInfo.nominalFreq * 3) / 4;
+ }
+
+ /* We want reduce tdiff, so slow drift to the time between vt0 and curFileTime */
+ vt0 -= tdiff * 2 / 3;
+
+
/*
- * Estimate current frequency corresponding current time / counter.
+ * We want to adjust things so that time appears to be continuous.
+ * Virtual file time, right now, is vt0.
+ *
+ * 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
+ *
+ * vt1 = 10000000 + curFileTime
+ *
+ * The frequency that we need to use to drift the counter back into place
+ * is estFreq * 10000000 / (vt1 - vt0)
+ *
+ * If we've gotten more than a second away from system time, then drifting
+ * the clock is going to be pretty hopeless. Just let it jump. Otherwise,
+ * compute the drift frequency and fill in everything.
+ */
+
+ repeatEstimate:
+
+ /*
+ * Estimate current variance corresponding current time / counter.
*/
- if ((curFileTime - timeInfo.lastCC.fileTime) > (10000000 / 2)) {
- estVariance = (curFileTime - timeInfo.lastCC.fileTime)
- * timeInfo.nominalFreq
+ vt1 = vt0 - timeInfo.lastCC.virtTime; /* time since last calibration */
+ if (vt1 > (10000000 / 2)) {
+ estVariance = vt1 * estFreq
- (curPerfCounter- timeInfo.lastCC.perfCounter) * 10000000;
- } else {
- estVariance = timeInfo.lastCC.cntrVariance;
}
/*
@@ -1384,47 +1414,101 @@ UpdateTimeEachSecond(void)
* last difference), with dual falling speed. This indicates better
* choice of lastCC.cntrVariance.
*/
+#if 1
+ if (lastDiff / tdiff >= 2 || lastDiff / tdiff <= -2) {
+ estVariance = timeInfo.lastCC.cntrVariance +
+ (estVariance - timeInfo.lastCC.cntrVariance) / 2;
+ }
+#else
if (tdiff > 0 && tdiff < lastDiff / 2 || tdiff < 0 && tdiff > lastDiff / 2) {
//printf("-----***-----calibration minimize %I64d, %I64d\n", estFreq, lastDiff);
- estVariance = (estVariance + timeInfo.lastCC.cntrVariance) / 2;
+ estVariance = (estVariance + timeInfo.lastCC.cntrVariance * 3) / 2;
//printf("-----***-----calibration minimize %I64d, %I64d\n", estFreq, tdiff);
}
+#endif
+
printf("------**-----calibration estimated, tdiff: %I64d, ** %s ** cntrDiff:%I64d\n", tdiff, (estVariance > timeInfo.lastCC.cntrVariance) ? "^^^" : "vvv", (curPerfCounter - timeInfo.lastCC.perfCounter));
printf("------**-----calibration estimated %I64d, %I64d, %I64d, diff: %I64d\n", curFileTime, curPerfCounter, estVariance, estVariance - timeInfo.lastCC.cntrVariance);
#if 1
/*
- * Calculate new estimate drift variance to the next second
+ * Calculate new estimate drift variance to the next second using new
+ * estimated values and approximated counter driftPerfCounter.
*/
+ driftVariance = estVariance * 2;
vt1 = vt0 - timeInfo.lastCC.virtTime;
if (vt1 > (10000000 / 2)) {
- LONGLONG driftPerfCounter = curPerfCounter +
+ /* approximated counter in 1s from now */
+ LONGLONG driftPerfCounter = curPerfCounter
+ (curPerfCounter - timeInfo.lastCC.perfCounter)
/ vt1 * (vt1 + 10000000);
- vt1 = NativeCalc100NsTicks(curFileTime,
+ /* virtual time in 1s from now */
+ vt1 = NativeCalc100NsTicks(vt0,
curPerfCounter, estVariance,
- driftPerfCounter);
- driftVariance = (vt1 - vt0) * timeInfo.nominalFreq
- //- estVariance
+ estFreq, driftPerfCounter);
+ /* new value of variance for this time */
+ driftVariance = (vt1 - vt0) * estFreq
- (driftPerfCounter - curPerfCounter) * 10000000;
- } else {
- driftVariance = estVariance * 2;
}
/*
* 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 in such cases.
*/
- driftVariance = timeInfo.lastCC.cntrVariance +
- (driftVariance - timeInfo.lastCC.cntrVariance) / 2;
+ driftVariance = estVariance +
+ (driftVariance - estVariance) / 2;
printf("------**-----calibration cntrVariance: %I64d\n", timeInfo.lastCC.cntrVariance);
printf("------**-----calibration estVariance: %I64d\n", estVariance);
printf("------**-----calibration driftVariance:%I64d\n", driftVariance);
+
+ /*
+ * Average between estimated, current and drifted variance,
+ * (do the soft drifting as possible).
+ */
+
+ if (repeatCnt != 1 && tdiff > -10000000 && tdiff < 10000000) { /* bypass time-switch */
+ estVariance = (estVariance * 2 + timeInfo.lastCC.cntrVariance + driftVariance) / 4;
+ } else {
+ estVariance = (estVariance + driftVariance) / 2;
+ }
+
+
+ if (repeatCnt != 1) {
+ /*
+ * Estimate current frequency corresponding current time / counter.
+ */
+
+#if 1
+ vt1 = vt0 - timeInfo.lastCC.virtTime;
+#else
+ vt1 = ((curFileTime - timeInfo.lastCC.fileTime) / 2
+ + (vt0 - timeInfo.lastCC.virtTime) / 2);
+#endif
+ printf("------**-----calibration vt1: %I64d, estFrequency: %I64d\n", vt1, estFreq);
+ if (vt1 > (10000000 / 2)) {
+ estFreq = ( (curPerfCounter - timeInfo.lastCC.perfCounter) * 10000000
+ + estVariance ) / vt1;
+
+ /*
+ * Minimize influence of estFreq if tdiff falls (in relation to
+ * last difference), with dual falling speed. This indicates better
+ * choice of lastCC.estFrequency.
+ */
+ if (tdiff > 0 && tdiff < lastDiff / 2 || tdiff < 0 && tdiff > lastDiff / 2) {
+ //printf("-----***-----calibration minimize %I64d, %I64d\n", estFreq, lastDiff);
+ estFreq = (estFreq + timeInfo.lastCC.estFrequency * 2) / 3;
+ //printf("-----***-----calibration minimize %I64d, %I64d\n", estFreq, tdiff);
+ }
+ } else {
+ estFreq = timeInfo.lastCC.estFrequency;
+ }
+ printf("------**-----calibration estVariance: %I64d, estFrequency: %I64d\n", estVariance, estFreq);
+
/*
* Average between estimated, 2 current and 5 drifted frequencies,
* (do the soft drifting as possible).
@@ -1432,22 +1516,43 @@ UpdateTimeEachSecond(void)
*/
#if 0
if (tdiff > 0 && tdiff < lastDiff / 2 || tdiff < 0 && tdiff > lastDiff / 2) {
- estFreq = (1 * estFreq + 2 * timeInfo.lastCC.counterFreq + 5 * driftFreq) / 8;
+ estFreq = (1 * estFreq + 2 * timeInfo.lastCC.estFrequency + 5 * driftFreq) / 8;
} else {
- estFreq = (3 * estFreq + 3 * timeInfo.lastCC.counterFreq + 2 * driftFreq) / 8;
+ estFreq = (3 * estFreq + 3 * timeInfo.lastCC.estFrequency + 2 * driftFreq) / 8;
}
#else
- estVariance = (estVariance + timeInfo.lastCC.cntrVariance + driftVariance) / 3;
+ estFreq = (estFreq + timeInfo.lastCC.estFrequency * 2) / 3;
#endif
#else
- estVariance = (estVariance + timeInfo.lastCC.cntrVariance) / 2;
+ if (tdiff > -10000000 && tdiff < 10000000) { /* bypass time-switch */
+ estVariance = (estVariance + timeInfo.lastCC.cntrVariance) / 2;
+ }
#endif
+
+ printf("------**-----calibration estVariance: %I64d, estFrequency: %I64d\n", estVariance, estFreq);
+
+ /*
+ * Avoid too large discrepancy from nominal frequency (0.5%)
+ */
+ if ( estFreq > (vt1 = (1000+5)*timeInfo.nominalFreq/1000)
+ || estFreq < (vt1 = (1000-5)*timeInfo.nominalFreq/1000)
+ ) {
+ /* too different */
+ estFreq = vt1;
+ printf("************ too large: %I64d\n", estFreq);
+ }
+
+ }
+
+ if (--repeatCnt) {
+ goto repeatEstimate;
+ }
}
/* If possible backwards time-drifts (larger divider now) */
vt1 = 0;
- if (estVariance < timeInfo.lastCC.cntrVariance) {
+ if (estVariance < timeInfo.lastCC.cntrVariance || estFreq > timeInfo.lastCC.estFrequency) {
Tcl_WideInt nt0, nt1;
/*
@@ -1463,10 +1568,10 @@ UpdateTimeEachSecond(void)
*/
nt0 = NativeCalc100NsTicks(timeInfo.lastCC.virtTime,
timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance,
- vt1);
+ timeInfo.lastCC.estFrequency, vt1);
nt1 = NativeCalc100NsTicks(vt0,
curPerfCounter, estVariance,
- vt1);
+ estFreq, vt1);
vt1 = (nt0 - nt1); /* old time - new time */
if (vt1 > 0 && vt1 < 10000000 /* bypass time-switch */) {
/* base time should jump forwards (the same virtual time using current values) */
@@ -1491,6 +1596,7 @@ UpdateTimeEachSecond(void)
timeInfo.lastCC.fileTime = curFileTime;
timeInfo.lastCC.virtTime = vt0;
timeInfo.lastCC.cntrVariance = estVariance;
+ timeInfo.lastCC.estFrequency = estFreq;
timeInfo.lastCC.calibNextTime = curFileTime + calibrationInterv;
InterlockedIncrement(&timeInfo.calibEpoch);
@@ -1500,7 +1606,7 @@ UpdateTimeEachSecond(void)
//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 / %I64d\n", timeInfo.lastCC.virtTime, timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance, timeInfo.nominalFreq);
+ printf("-------------calibration end , new-struct: %I64d, %I64d, %I64d / %I64d\n", timeInfo.lastCC.virtTime, timeInfo.lastCC.perfCounter, timeInfo.lastCC.cntrVariance, timeInfo.lastCC.estFrequency);
#endif
}