sleep_until() and steady_clock loop drifting from real time in macOS - c++

Good evening everyone,
I'm trying to learn concurrency using the C++ Concurrency Book by Anthony Williams. Having read the first 2 chapters I thought about coding a simple metronome working in its own thread:
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
class Metro
{
public:
// beats per minute
Metro(int bpm_in);
void start();
private:
// In milliseconds
int mPeriod;
std::vector<std::thread> mThreads;
private:
void loop();
};
Metro::Metro(int bpm_in):
mPeriod(60000/bpm_in)
{}
void Metro::start()
{
mThreads.push_back(std::thread(&Metro::loop, this));
mThreads.back().detach();
}
void Metro::loop()
{
auto x = std::chrono::steady_clock::now();
while(true)
{
x += std::chrono::milliseconds(mPeriod);
std::cout << "\a" << std::flush;
std::this_thread::sleep_until(x);
}
}
Now, this code seems to work properly, except for the time interval: the period (assuming bpm = 60 => mPeriod = 1000ms) is more than 1100ms. I read that sleep_until is not guaranteed to wake the process up exactly at the correct time (cppreference.com), but the lack of precision should not change the average period time, only delay the single "tic" inside the time grid, am I understanding it correctly? I assumed that storing the steady_clock::now() time only the first time and then using only the increment would be the correct way not to add drifting time at every cycle. Nevertheless, I also tried to change the x var update in the while loop to
x = std::chrono::steady_clock::now() + std::chrono::milliseconds(mPeriod);
but the period increases even more. I also tried using std::chrono::system_clock and high_resolution_clock, but the period didn't improve. Also, I think the properties I'm interested in for this application are monotonicity and steadiness, which steady_clock has. My question is: is there anything completely wrong I did in my code? Am I missing something concerning how to use std::chrono clocks and sleep_until? Or is this kind of method inherently not precise?
I've started analyzing the period by simply comparing it against some known metronomes (Logic Pro, Ableton Live, some mobile apps) and then recorded the output sound to have a better measurement. Maybe the sound buffer has some delay on itself, but same problem happens when making the program output a char. Also, the problem I'm concerned about is the drifting, not the single tic being a bit out of time.
I'm compiling from macos 10.15 terminal with g++ --std=c++11 -pthread and running it on Intel i7 4770hq.

Related

Clock timing changes on different computers

I'm working on an implementation for the DMG-01 (A.K.A gameboy 1989) on my github.
I've already implemented both the APU and the PPU, with (almost) perfect timing on my pc (and the pc of my friends).
However, when I run the emulator on one of my friend's pc, it runs twice as fast as mine or the rest of my friends.
The code for syncronizing the clock (between the gameboy and the pc it's running on) is as follows:
Clock.h Header File:
class Clock
{
// ...
public:
void SyncClock();
private:
/* API::LR35902_HZ_CLOCK is 4'194'304 */
using lr35902_clock_period = std::chrono::duration<int64_t, std::ratio<1, API::LR35902_HZ_CLOCK>>;
static constexpr lr35902_clock_period one_clock_period{1};
using clock = std::chrono::high_resolution_clock;
private:
decltype(clock::now()) _last_tick{std::chrono::time_point_cast<clock::duration>(clock::now() + one_clock_period)};
};
Clock.cpp file
void Clock::SyncClock()
{
// Sleep until one tick has passed.
std::this_thread::sleep_until(this->_last_tick);
// Use time_point_cast to convert (via truncation towards zero) back to
// the "native" duration of high_resolution_clock
this->_last_tick = std::chrono::time_point_cast<clock::duration>(this->_last_tick + one_clock_period);
}
Which gets called in main.cpp like this:
int main()
{
// ...
while (true)
{
// processor.Clock() returns the number of clocks it took for the processor to run the
// current instruction. We need to sleep this thread for each clock passed.
for (std::size_t current_clock = processor.Clock(); current_clock > 0; --current_clock)
{
clock.SyncClock();
}
}
// ...
}
Is there a reason why chrono in this case would be affected in a different way in other computers? Time is absolute, I would understand why in one pc, running the emulator would be slower, but why faster?
I checked out the type of my clock (high_resolution_clock) but I don't see why this would be the case.
Thanks!
I think you may be running into overflow under the hood of <chrono>.
The expression:
clock::now() + one_clock_period
is problematic. clock is high_resolution_clock, and it is common for this to have nanoseconds resolution. one_clock_period has units of 1/4'194'304. The resultant expression will be a time_point with a period of 1/8'192'000'000'000.
Using signed 64 bit integral types, the max() on such a precision is slightly over 13 days. So if clock::now() returns a .time_since_epoch() greater than 13 days, _last_tick is going to overflow, and may some times be negative (depending on how much clock::now() is beyond 13 days).
To correct try casting one_clock_period to the precision of clock immediately:
static constexpr clock::duration one_clock_period{
std::chrono::duration_cast<clock::duration>(lr35902_clock_period{1})};

Generating interrupt each 100 microsecond on windows

i want to generate interrupt every 100 microseconds on windows. Actually i couldnt do this on windows,because windows does not guarantee the interrupts less then 500 microseconds. So, i generate 2 threads. One of them is for timer counter(query performance counter), the other thread is the actual work. When timer counter is 100 microseconds, it change the state of the other thread(actual work) . But i have problem with race condition, because i dont want the threads wait each others, they must always run. So actually i need interrupts. How do i write such fast interrupt on windows with c++?
To avoid having two threads communicating when you have these short time windows, I'd put both the work and the timer in a loop in one thread.
Take a sample of the clock when the thread starts and add 100μs to that each loop.
Sleep until the calculated time occurs. Normally, one would use std::this_thread::sleep_until to do such a sleep, but in this case, when the naps are so short, it often becomes a little too inaccurate, so I suggest busy-waiting in a tight loop that just checks the time.
Do your work.
In this example a worker thread runs for 10s without doing any real work. On my machine I could add work consisting of ~3000 additions in the slot where you are supposed to do your work before the whole loop started taking more than 100μs, so you'd better do what you aim to do really fast.
Example:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;
static std::atomic<bool> running = true;
using myclock = std::chrono::steady_clock;
void worker() {
int loops = 0;
auto sleeper = myclock::now();
while(running) {
++loops; // count loops to check that it's good enough afterwards
// add 100us to the sleeper time_point
sleeper += 100us;
// busy-wait until it's time to do some work
while(myclock::now() < sleeper);
// do your work here
}
std::cout << loops << " (should be ~100000)\n";
}
int main() {
auto th = std::thread(worker);
// let the thread work for 10 seconds
std::this_thread::sleep_for(10s);
running = false;
th.join();
}
Possible output:
99996 (should be ~100000)
It takes a few clock cycles to get the thread started so don't worry about the number of loops not being exactly on target. Double the time the thread runs and you should still stay close to the target number of loops. What matters is that it's pretty good (but not realtime-good) once it's started running.

std::this_thread::sleep_for sleeps for too long

Can anyone tell what the problem with following example is?
It produces 65 instead of 300 frames per second.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Thread>
#include <Chrono>
#include <String>
int main(int argc, const char* argv[]) {
using namespace std::chrono_literals;
constexpr unsigned short FPS_Limit = 300;
std::chrono::duration<double, std::ratio<1, FPS_Limit>> FrameDelay = std::chrono::duration<double, std::ratio<1, FPS_Limit>>(1.0f);
unsigned int FPS = 0;
std::chrono::steady_clock SecondTimer;
std::chrono::steady_clock ProcessTimer;
std::chrono::steady_clock::time_point TpS = SecondTimer.now();
std::chrono::steady_clock::time_point TpP = ProcessTimer.now();
while (true) {
// ...
// Count FPS
FPS++;
if ((TpS + (SecondTimer.now() - TpS)) > (TpS + 1s)) {
OutputDebugString(std::to_string(FPS).c_str()); OutputDebugString("\n");
FPS = 0;
TpS = SecondTimer.now();
}
// Sleep
std::this_thread::sleep_for(FrameDelay - (ProcessTimer.now() - TpP)); // FrameDelay minus time needed to execute other things
TpP = ProcessTimer.now();
}
return 0;
}
I guess it has something to do with std::chrono::duration<double, std::ratio<1, FPS_Limit>>, but when it is multiplied by FPS_Limit the correct 1 frames per second are produced.
Note that the limit of 300 frames per second is just an example.
It can be replaced by any other number and the program would still sleep for way too long.
In short, the problem is that you use std::this_thread::sleep_for at all. Or, any kind of "sleep" for that matter. Sleeping to limit the frame rate is just utterly wrong.
The purpose of sleep functionality is, well... I don't know to be honest. There are very few good uses for it at all, and in practically every situation, a different mechanism is better.
What std::this_thread::sleep_for does (give or take a few lines of sanity tests and error checking) is, it calls the Win32 Sleep function (or, on a different OS, a different, similar function such as nanosleep).
Now, what does Sleep do? It makes a note somewhere in the operating system's little red book that your thread needs to be made ready again at some future time, and then renders your thread not-ready. Being not-ready means simply that your thread is not on the list of candidates to be scheduled for getting CPU time.
Sometimes, eventually, a hardware timer will fire an interrupt. That can be a periodic timer (pre Windows 8) with an embarrassingly bad default resolution, or programmable one-shot interrupt, whatever. You can even adjust that timer's resolution, but doing so is a global thing which greatly increases the number of context switches. Plus, it doesn't solve the actual problem. When the OS handles the interrupt, it looks in its book to see which threads need to be made ready, and it does that.
That, however, is not the same as running your thread. It is merely a candidate for being run again (maybe, some time).
So, there's timer granularity, inaccuracy in your measurement, plus scheduling... which altogether is very, very unsuitable for short, periodic intervals. Also, different Windows versions are known to round differently to the scheduler's granularity.
Solution: Do not sleep. Enable vertical sync, or leave it to the user to enable it.

C++ While loop, usleep()/sleep() how not to use 90% of CPU? (Ubuntu 12.04)

Suppose I have C++ code such as
#include "myheaderfiles.h"
//..some stuff
//...some more stuff
int main()
{
double milliseconds;
int seconds;
int minutes;
int timelimit=2;
...
...
//...code here that increments
//.....milliseconds,seconds, and minutes
while(minutes <=timelimit)
{
//...do stuff
if(milliseconds>500)
{
//...do stuff
//...every half second
} //end if
} //end while
}//end main
The program will run fine and does what its supposed to do but it will use up 90%+ of my cpu.
It was suggested to me to use usleep() in my while loop ever 100ms or so since I really only care about doing stuff every 500ms anyway. That way, it hog the CPU when its not needed.
So I added it to my while loop like so
while(minutes <=timelimit)
{
//...do stuff
if(milliseconds>500)
{
//...do stuff
//...every half second
} //end if
usleep(100000);
} //end while
It compiles fine, but when I run it, the program will hang right at usleep and never return. I read somewhere that before calling usleep, one needs to flush all buffers, so I flushed all file streams and couts etc etc. Still no luck.
I've searched for 2 days for a solution. I've used sleep() too, with no luck.
I found a few alternatives but they seem complicated and will add a lot of code to my program that I dont really fully understand which will complicate it and make it messy, plus it might not work.
I never really put too much thought in my while() loops before because most of the programs I wrote were for microcontrollers or FPGAs which is no problem to hog the processor.
If anyone can help.... any resources, links,books? Thanks.
Your approach somewhat comes from the wrong end. A program should consume 90-100% CPU as long as it has something useful to do (and it should block otherwise, consuming zero CPU).
Sleeping in between will cause execution being longer for no good reason, and consume more energy than just doing the work as fast as possible (at 100% CPU) and then completely blocking until more work is available or until some other significant thing (e.g. half a second has passed, if that matters for you) happens.
With that in mind, structure your program in a way conceptually like:
while(blocking_call() != exit_condition)
{
while(have_work)
do_work();
}
Also, do not sleep during execution, but use timers (e.g. setitimer) to do something at regular intervals. Not only will this be more efficient, but also a lot more precise and reliable.
How exactly you implement this depends on how portable you want your software to be. Under Ubuntu/Linux, you can for example use APIs such as epoll_wait with eventfd rather than writing a signal handler for the timer.
This code works as expected for me (running on OSX though).
#include <unistd.h>
#include <iostream>
int main() {
std::cout << "hello" << std::endl;
int i = 0;
while(i < 10) {
++i;
usleep(100000);
std::cout << "i = " << i << std::endl;
}
std::cout << "bye" << std::endl;
return 0;
}
There is a logical issue or maybe you're making multiple counters? Since you said you've done microcontrollers, I assume you're trying to use clock-cycles as a method of counting while calling the system timers? Also, what has me questioning is if you're recommended to use usleep(x), why are you using double for millisecond? usleep(1) is 1 microsecond == 1000 milliseconds. The sleep(x) is a counter per x second, so the system will suspend it's current task for x amount of seconds.
#include <iostream>
#include <unistd.h>
using namespace std;
#define MILLISECOND 1000
#define SECOND 1000*MILLISECOND
int main(int argc, char *argv[]){
int time = 20;
int sec_counter = 0;
do{
cout<<sec_counter<<" second"<<endl;
usleep(SECOND);
sec_counter++;
} while(sec_counter<time+1);
return 0;
}
If you wanted to use 500ms then replace usleep(SECOND) with usleep(500*MILLISECOND).
I suggest you use a debugger and step through your code to see what's happening.

c++ get elapsed time platform independent

For a game I wanna measure the time that has passed since the last frame.
I used glutGet(GLUT_ELAPSED_TIME) to do that. But after including glew the compiler can't find the glutGet function anymore (strange). So I need an alternative.
Most sites I found so far suggest using clock in ctime but that function only measures the cpu time of the program not the real time! The time function in ctime is only accurate to seconds. I need at least millisecond accuracy.
I can use C++11.
I don't think there is a high resolution clock built-in C++ before C++11. If you are unable to use C++11 you have to either fix your error with glut and glew or use the platform dependent timer functions.
#include <chrono>
class Timer {
public:
Timer() {
reset();
}
void reset() {
m_timestamp = std::chrono::high_resolution_clock::now();
}
float diff() {
std::chrono::duration<float> fs = std::chrono::high_resolution_clock::now() - m_timestamp;
return fs.count();
}
private:
std::chrono::high_resolution_clock::time_point m_timestamp;
};
Boost provides std::chrono like clocks: boost::chrono
You should consider using std::chrono::steady_clock (or boost equivalent) as opposed to std::chrono::high_resolution_clock - or at least ensure std::chrono::steady_clock::is_steady() == true - if you want to use it to calculate duration, as the time returned by a non-steady clock might even decrease as physical time moves forward.