nintendo
nintendo

Reputation: 140

How to decrease CPU usage of high resolution (10 micro second) precise timer?

I'm writing up a timer for some complex communication application in windows 10 with qt5 and c++. I want to use max 3 percent of CPU with micro second resolution.

Initially i used qTimer (qt5) in this app. It was fine with low CPU usage and developer friendly interface. But It was not precise as i need.It takes only millisecond as parameter but i need microsecond. And the accuracy of the timer wasn't equal this resolution in many real-world situations like heavy load on cpu. Sometimes the timer fires at 1 millisecond, sometimes 15 millisecond. You can see this problem in picture:

enter image description here

I searched a solution for days. But in the end i found Windows is a non real-time Operating System (RTOS) and don't give high resolution and precise timer.

I wrote my own High resolution precise timer with CPU polling for this goal. I developed a singleton class working in separate thread. It works at 10 micro second resolution.

enter image description here

But it is consuming one logical core in CPU. Equivalent to 6.25 percent at ryzen 2700.

enter image description here

For my application this CPU usage is unacceptable. How can i reduce this CPU usage without give high resolution away ?

This is the code that does the job:

void CsPreciseTimerThread::run()
{

while (true)
{
    QMutexLocker locker(&mMutex);
    for (int i=0;i<mTimerList.size();i++) 
    {
        CsPreciseTimerMiddleLayer* timer = mTimerList[i];
        int interval = timer->getInterval();
        if ( (timer->isActive() == true&&timer->remainingTime()<0))
        {
            timer->emitTimeout();
            timer->resetTime();
        }
    }



}
}

I tried to down priority of timer thread. I used this lines:

QThread::start(QThread::Priority::LowestPriority);

And this:

QThread::start(QThread::Priority::IdlePriority);

That changes makes timer less precise but CPU usage didn't decrease.

After that i tried force the current thread to sleep for few microseconds in loop.

QThread::usleep(15);

As you might guess sleep function did screw up the accuracy. Sometimes timer sleeps longer than expected , like 10 ms or 15 ms.

Upvotes: 0

Views: 1037

Answers (1)

selbie
selbie

Reputation: 104484

I'm going to reference Windows APIs directly instead of the Qt abstractions.

I don't think you want to lower your thread priority, I think you want to raise your thread priority and use the smallest amount of Sleep between polling to balance between latency and CPU overhead.

Two ideas:

  1. In Windows Vista, they introduced the Multimedia Class Scheduler Service specifically so that they could move the Windows audio components out of kernel mode and running in user mode, without impacting pro-audio tools. That's probably going to be helpful to you - it's not precisesly "real time" guararteed, but it's meant for low latency operations.

  2. Going the classic way - raise your process and thread priority to high or critical, while using a reasonable sleep statement of a few milliseconds. That is, raise your thread priority to THREAD_PRIORITY_TIME_CRITICAL. Then do a very small Sleep after completion of the for loop. This sleep amount should be between 0..10 milliseconds. Some experimentation required, but I would sleep no more than half the time to the next expected timeout, with a max of 10ms. And when you are within N microseconds of your timer, you might need to just spin instead of yielding. Some experimentation is required. You can also experiment with raising your Process priority to REALTIME_PRIORITY_CLASS.

Be careful - A handful of runaway processes and threads at these higher priority levels that isn't sleeping can lock up the system.

Upvotes: 3

Related Questions