Ok, I really have no idea why this is happening. I'm currently implementing a thread container which runs an infinite loop in a detached manner, limited to a certain speed between each iteration.
Header:
class timeloop
{
public:
std::thread thread = { };
bool state = true;
void (*function_pointer)() = nullptr;
double ratio = 1.0f;
std::chrono::nanoseconds elapsed = { };
timeloop(
void (*function_pointer)() = nullptr
);
void function();
};
Definition:
void timeloop::start()
{
this->thread = std::thread(
&loop::function,
this
);
}
void timeloop::function()
{
std::chrono::steady_clock::time_point next;
std::chrono::steady_clock::time_point start;
std::chrono::steady_clock::time_point end;
while (
this->state
)
{
start = std::chrono::high_resolution_clock::now();
next = start + std::chrono::nanoseconds(
(long long) (this->ratio * (double) std::chrono::nanoseconds::period::den)
);
if (
this->function_pointer != nullptr
)
{
this->function_pointer();
}
/***************************
this is the culprit
***************************/
std::this_thread::sleep_until(
next
);
end = std::chrono::high_resolution_clock::now();
this->elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(
end - start
);
}
}
Calling code:
timeloop* thread_draw = new timeloop(
&some_void_function
);
thread_draw->ratio = 1.0 / 128.0;
thread_draw->start();
thread_draw->thread.detach();
The definition code is behaving weirdly, specifically std::this_thread::sleep_until
. With this->ratio = 1.0 / 128.0
I'm expecting a framerate of around 128, the computed values of start
and next
reinforce this, yet it inexplicably hovers at around 60. And yeah, I tried just dividing next
by 2, but that actually made it drop to around 40.
Extra code to verify the normal time to sleep for:
auto diff = std::chrono::nanoseconds(
next - start
).count() / (double) std::chrono::nanoseconds::period::den;
auto equal = diff == this->ratio;
where equal evaluates to true
.
Frame rate calculation:
double time = (double) thread_draw->elapsed.count() / (double) std::chrono::nanoseconds::period::den;
double fps = 1.0 / time;
Though I also used external FPS counters to verify (NVIDIA ShadowPlay and RivaTuner/MSI Afterburner), and they were in a range of about +-5 of the calculated value.
And I know it's std::this_thread::sleep_until
because once I comment that out, the frame rate jumps up to around 2000. Yeah...
I'm truly baffled at this, especially seeing how I can't find any evidence of anybody else ever having had this problem. And yes, I'm aware that sleep functions aren't perfectly accurate, and there's bound to be hiccups every now and then, but consistently sleeping for pretty much double the scheduled time is just absurd.
Did I perhaps misconfigure a compiler option or something? It's definitely not a performance problem, and I'm reasonably sure it's not a logic error either (seeing how all the calculations check out) [unless I'm abusing chrono somewhere].