boost::this_thread::sleep() precision only reaches milli?!

Started by
14 comments, last by EnlightenedOne 13 years, 6 months ago
Hi there to ensure that my threads do not poll I have a method for getting the resolution of time taken to perform one cycle if its less than the desired time between cycles (in this case once per millisecond) I take the time remaining from the time taken and get this.

boost::this_thread::sleep(boost::posix_time::microseconds(997));

So it took 3 microseconds to process the data to run the thread. I want the thread to be performed every millisecond. So to be efficient I wait for 997 microseconds then go around a while loop again for the thread.

I looked in the function and it states.

inline void sleep(TimeDuration const& rel_time)
{
interruptible_wait(detail::pin_to_zero((long)rel_time.total_milliseconds()));
}

Can I make that rel_time.total_microseconds() without damaging anything?

Why is the precision not documented in the boost library?
Advertisement
Thread sleep is usually bounded by the OS scheduler quantum. This can vary between OSes, but I've heard ~10ms is a good estimate. It can be more or less, depending on how busy the system is. sleep() generally means "sleep for at least this long". It is not deterministic. If you want really short sleeps, you'll want to spin instead. Even that, at any time you can be kicked off the processor and made wait for a quantum or more(unless that process chooses to sleep).

You cannot get real-time guarantees from a general purpose OS.
I dont mind a hickup in precision of 5-10ms on the occasion but only being able to tune down to a 1000th of a second is madness. How can I possibly manage things at a milli seconds precision without being able to pause based on micro second timing!

Here is an example of why its plain dangerous to not have microsecond control.

If it took me 997micro seconds to do something and I pause for a millisecond because I can't read microseconds (even tho I can I just can't use them) and I want a relative ms between ticks (so I add in a ms wait due to the resolution limitation boost is inducing) thats 1.997ms per cycle!

Therefore without microsecond control you leave a valley of despair where real time could run at 50.0000000000000001% of real time!

I tried to rewrite it to take in microseconds but its treating them as milliseconds! which is as you can imagine not good for my real time game :p

    namespace this_thread    {        void BOOST_THREAD_DECL yield();        bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);        inline void interruptible_wait(unsigned long microseconds)        {            //What do I have to do here to get microseconds is the invalid handle value the scope of measurement in some way or another?            interruptible_wait(detail::win32::invalid_handle_value,microseconds);                    }        inline void interruptible_wait(system_time const& abs_time)        {            interruptible_wait(detail::win32::invalid_handle_value,abs_time);        }        template<typename TimeDuration>        inline void sleep(TimeDuration const& rel_time)        {			interruptible_wait(detail::pin_to_zero((long)rel_time.total_microseconds()));            //interruptible_wait(detail::pin_to_zero((long)rel_time.total_milliseconds()));        }        inline void sleep(system_time const& abs_time)        {            interruptible_wait(abs_time);        }    }


I am open to an alternative for thread timing and power saving/efficiency but I see this as an issue in the library not in pragmatism. Unless your polling in every single game that has ever been created this is the only logical alternative for thread management I could see, everyone should be doing this.
You can get between 5ms and I believe to 2 microseconds precision from the function QueryPerformanceCounter.

So with the code below I can show you how I am trying to get things done in terms of thread precision when the loops going too fast. There are other counter measures in place that work for lag at a precision of 5ms.

while (boolStopSafeRequest == false)	{		//On new machines the speed of the machine is dynamic so we need to query the frequency once per cycle :(		QueryPerformanceFrequency((LARGE_INTEGER*)&int64ClockFrequency);		//Get the number of ticks since we began doing anything.		//This is updated based on hardware on really old hardware the resolution is 12ms on normal hardware that could run this game thats 50,000 times thats 0.00002 a second!		QueryPerformanceCounter((LARGE_INTEGER*)&int64StartTimeTicks);                //Do some logic		//If we have done the function in less than the time between cycles we put the thread to sleep to save power!		QueryPerformanceCounter((LARGE_INTEGER*)&int64EndTimeTicks);		                //Calculate to the millisecond the high performance tick against the clock speed.		int64DeltaTimeMicroSec = (int64EndTimeTicks - int64StartTimeTicks) * 1000000 / int64ClockFrequency;		//If we registered more than a millisecond of delay we just run the next cycle to chase up to realtime.		if (int64DeltaTimeMicroSec < 1000)//Every milliseconds we want to cycle so if we did everything faster than											        //within our measure of a ms we wait one ms to garuntee we dont go super fast.		{			if (int64DeltaTimeMicroSec == 0)			{				//So wait for the full time between ticks				boost::this_thread::sleep(boost::posix_time::microseconds(1000));			}			else			{				//Get the inverse of the time in microseconds that was spent against the time we are waiting for.				int64DeltaTimeMicroSec = 1000 - int64DeltaTimeMicroSec;										boost::this_thread::sleep(boost::posix_time::microseconds(int64DeltaTimeMicroSec));			}		}
Im gunna have to rewrite alot of library to get it all working at microsecond level without risking damaging something like a try_lock in milliseconds else where!

It looks possible to fully rewrite...

Does no one have an explanation as to what everyone else is doing? is it common practice for games to poll?

[Edited by - EnlightenedOne on October 22, 2010 4:03:31 PM]
I have been defeated by the complexity of the boost library. I added in a performance counter in thread_data.hpp at the neccessary resolution. I changed all the mechanisms from milli to micro in several of the files linked to the component but still all my waits in microseconds now get treated as milliseconds passed in, so in short I need to keep at it.

I cannot believe I am the first one who has had such significant issues with timing at this level I still don't understand why the API lacked the support in the first place.

I have been told by other coders you cannot use the generic wait functions in c++ to make a native c++ thread wait per microsecond. So there must be a fix everyone uses to bypass needing a resolution of microseconds in a millisecond timed thread!

If you just wait for a millisecond if you know none have passed and tack on a wait for a millisecond how do you avoid the time delay threat of half speed if you perform a task at 0.999.. of a millisecond? I have this bad feeling in my stomach everyone must poll their code.

Please get in touch if you have a solution that doesn't pole.
Quote:Original post by EnlightenedOne
Does no one have an explanation as to what everyone else is doing? is it common practice for games to poll?
If you tell the OS to put a thread to sleep, then you have no control over when it wakes up! The value you give it is only a hint on how long to knock the thread out for.
On Windows, it will sleep for no less than the amount of milliseconds specified, and if still asleep after 5 seconds it will get out the smelling salts and start shaking the thread violently.

Putting a thread to sleep is not something that a game often wants to do... If you don't want to knock a thread out cold for an unpredictable amount of time, then sleep is not what you're looking for.

What are you trying to achieve with this sleeping? Are you trying to optimize a busy-wait / spin-lock?

[edit]
Here's a Windows-specific function that I use to wait on arbitrary conditions. It issues yield/pause/nop instructions and tries to make use of hyper-threading spin times, before telling the OS to sleep the thread for the shortest amount of time possible.
	template<class F> void YieldThreadUntil( F& func, uint spin )	{		while( true )		{			for( uint i=0; i!=spin; ++i )			{				if( func() )					return;				YieldProcessor();				if( func() )					return;				SwitchToThread();			}			if( func() )				return;			Sleep(0);		}	}
[Edit #2]BTW, what kind of variable is boolStopSafeRequest? Is it a native bool or some kind of atomic/volatile variable?

[Edit #3]Also, the "boost way" of doing this would be to wait on a condition variable, and notify the sleeping thread once boolStopSafeRequest has been set to true, however, that still enjoys the lack of sub-millisecond accuracy.
On systems that support yielding the processor how long does it yield for? Ultimately yielding is just another attempt at pausing for scales that can be resolved to an aproximate of the microsecond level on machines that can support it. Thats good as it prevents old machines behaving wierdly to time and lets them just poll. Yield has no detail of timing on MSDN.... can you clarify the details of its behaviour?

I am trying to optimise a thread by making it sleep for a matter of microseconds in between cycles of operation.

If you can control between 0.002ms and aprox 10ms of accuracy and you have 1000 of these things per second your accuracy is between 500,000 and 100 measurements per second. If you want to manage your thread properly at a measurement running 1000 times per second and your precision is only 100 times per second you cannot pause at a precision neccessary to identify and keep a consistent realtime task in operation. You could run at ten times the speed you want to run at because if every task you do takes 9.9milliseconds to perform you wont know it took any time at all!

So you cannot time threads at the millisecond level properly with waits making the entire of the operating system an energy inefficient nightmare as every thread has to poll when it does not spin lock.

The safe boolean value is handled my a mutex. I decided to leave out for simplicity.

//Check if we should continue another cycle.
mutStopnError.lock();
boolStopSafeRequest = boolStopRequest;
mutStopnError.unlock();

Another thread locks a mutex in every threaded class and checks an integer indicating their status as a constant value which returns success/failure/safeexit. Theres alot of other stuff going on but that all works. The value is not "volatile" because that only garuntees for certain scenarios and I like to control my synchronisation like my threads very much to the dot :p

I'm curious as to what work the thread is doing...
Is it not possible to convert it so it will be tolerant of non-deterministic time-steps (or is it already and the result isn't good enough)?
It already does this to account for lag and rapid cycling using a delta time to 5 milliseconds or greater resolution using timeGetTime().

The thread can be made to poll and manage time relative to the millisecond but from an efficiency stand point at university I was taught this was the thread control equivelent of the go_to command in VB. When you do not have to poll waiting for another device you should not poll.

I wrote a stopwatch to the microsecond on some hardware before, so I assumed if a processor was capable of resolving to two microseconds of precision it should be capable of sleeping the thread for that level of resolution with a marginal accuracy loss compared to doing it in milliseconds.

I want to use query high performance counters capacity to determine microseconds to make my threads not be so wasteful. Things like the thread for handling input for a DX input device will not expand greatly or need to run faster than a millisecond for each cycle. All my threads were employing this dysfunctional syntax until I ran the test below.

I just wanted to add in a limit to the cycles for efficiency and good practice. I thought I had done this until I found out that anything below a millisecond and boosts threads do not wait at all. I tested it worked by making a counter that should trigger an if statement every 10 seconds of operation in my logic thread (which should obviously be 10000) this was of course running at a rate of microseconds as it was polling due to the wait function failing to identify a measure of time in microseconds.

Obviously the quantity to increment by could be modified by the delta of time passing to make it scale to the millisecond but that wouldn't help me get my threads to sleep and prove they were sleeping for an appropriate amount of time. I even tried to rewrite the boost library to no avail. It might be inherent of the language or OS that I cannot wait below a millisecond as the default thread available in c++ can only wait to a millisecond according to my trusted sources.

This topic is closed to new replies.

Advertisement