Server timing

Questions or HOWTOs about the above? Post 'em here...
Post Reply
catcha
Private First Class
Private First Class
Posts: 22
Joined: Tue Nov 17, 2009 8:24 pm

Server timing

Post by catcha »

Countdown seems to finish before it should: the client's clock is still running when the server ends the game. I've observed this with two windows xp computers, when I run server and (one) client on the same computer. Taking a closer look, the server's clock is running way too fast from the beginning. To my surprise, I couldn't find any previous posts on this topic. Can others confirm this, and do you have any suggestions for correcting this? It seems to me that both server and client use the same (dreadful) TimeKeeper functions. Thanks for your comments.

Edit: This seems to be related to how fast the server's main loop iterates (waitTime): the longer the delay, the more the clock advances. The real delay between loop iterations is almost exactly two times smaller than the intended value in waitTime! No idea how this should happen. If the main loop is set to run continuously, the timing is almost accurate.
"There's no such thing as stupid questions. There's just stupid people." - Mr. Garrison
catcha
Private First Class
Private First Class
Posts: 22
Joined: Tue Nov 17, 2009 8:24 pm

Re: Server timing

Post by catcha »

Ok, think I managed to solve this. The error occurs when two calls to TimeKeeper::getCurrent() function are made too close to each other.

1. The time difference from last measurement is calculated at the beginning of function GetCurrent():

Code: Select all

	LONGLONG diff     = now.QuadPart - qpcLastTime.QuadPart;
2. Then there is some strange code related to the recalibration of QPC frequency:

Code: Select all

	if (clkSpent > qpcFrequency) {
			// Recalibrate Frequency
			DWORD tgt	   = timeGetTime();
			DWORD deltaTgt      = tgt - timeLastCalibration;
			timeLastCalibration = tgt;
			qpcLastCalibration  = now.QuadPart;
			if (deltaTgt > 0) {
				LONGLONG oldqpcfreq = qpcFrequency;
				qpcFrequency	= (clkSpent * 1000) / deltaTgt;
				if (qpcFrequency != oldqpcfreq)
					logDebugMessage(4,"Recalibrated QPC frequency.  Old: %f ; New: %f\n",
					(double)oldqpcfreq, (double)qpcFrequency);
			}
		}
3. Only after this the qpcLastTime gets updated:

Code: Select all

	currentTime += (double) diff / (double) qpcFrequency;
	qpcLastTime = now;
The problem is that because the variable qpcLastTime is static, the second call to getCurrent may use the old value before the first call has had time to update it (its probably stuck in the second phase). So, suppose that two calls close to each other are made 3 seconds after a previous one. Because qpcLastTime is not updated properly, both calls now add 3 seconds to the time, making the clock run at double speed.

To fix this, one perhaps needs to use lock for the last phase. Removing the second phase also seems to work in practise.

Hope this would help someone in the future.
"There's no such thing as stupid questions. There's just stupid people." - Mr. Garrison
User avatar
JeffM
Staff Sergeant
Staff Sergeant
Posts: 5196
Joined: Fri Dec 13, 2002 4:11 am

Re: Server timing

Post by JeffM »

The timekeeper has been re-written significantly in the trunk version of the source code.
ImageJeffM
Post Reply