我使用std :: chrono c ++库编写了下面的代码,我想做的是
在60上修复应用程序的FPS
,但我得到50 FPS
,而不是确定性能问题
因为我一无所有。但它肯定是无效的用法或错误。
将TARGET_FPS
宏设置为我想要的目标FPS
,然后是控制台窗口
显示实际的实际FPS,以下这些行显示我设置为TARGET_FPS
的值,并且每个值都与最终的FPS
相关联。
TARGET_FPS---->FPS
60----->50
90----->50
100----->100
1000----->100
10000----->100
whatever ----->100
即使我将TARGET_FPS
定义为1000000000,我也得到100 FPS
,即使我将其定义为458或任何超过100的值,我也会得到100 FPS
作为输出。
#include <chrono> /// to use std::chrono namespace
#include <iostream> /// for console output
#include <thread> /// for std::this_thread::sleep_for()
#define TARGET_FPS 60// our target FPS
using frame_len_type = std::chrono::duration<float,std::ratio<1,TARGET_FPS>>; /// this is the duration that defines the length of a frame
using fsecond = std::chrono::duration<float>; /// this duration represents once second and uses 'float' type as internal representation
const frame_len_type target_frame_len(1); /// we will define this constant here , to represent on frame duration ( defined to avoid construction inside a loop )
void app_logic(){ /** ... All application logic goes here ... **/}
int main() /// our main function !
{
using sys_clock = std::chrono::system_clock; /// simplify the type name to make the code readable
sys_clock::time_point frame_begin,frame_end; /// we will use these time points to point to frame begin and end
while (true)
{
frame_begin = sys_clock::now(); /// there we go !
app_logic(); /// lets be logical here :)
frame_end = sys_clock::now(); /// we are done so quick !
std::this_thread::sleep_for( target_frame_len- (frame_end.time_since_epoch()-frame_begin.time_since_epoch()) ); /// we will take a rest that is equal to what we where supposed to take to finish the actual target frame length
std::cout<< fsecond(1) / ( sys_clock::now() - frame_begin) <<std::endl; /// this will show ass the current FPS
}
return 0; /// return to OS
} /// end of code
答案 0 :(得分:2)
std :: chrono的时序分辨率取决于系统:
休眠间隔过后,线程就可以运行了。如果 你指定0毫秒,线程将放弃余数 它的时间片但仍然准备好了。请注意,就绪线程不是 保证立即运行。因此,线程可能无法运行 直到睡眠间隔过去一段时间后。
sleep_for
提供更好的保证:30.3.2 / 7:效果:阻止调用线程的相对超时(...)
后果:
app_logic()
超快,您的线程将至少休眠15.6毫秒。如果逻辑需要1 ms才能执行,那么你的精确度将达到60 FPS。 但是,根据API文档,如果[等待时间]大于一个刻度但小于2,则等待可以是一到两个刻度之间的任何位置,以便平均睡眠时间在15.6到31.2毫秒之间,相反,你的FPS将在60到32 FPS之间。这就解释了为什么你只能达到50 FPS。
当您将FPS设置为100时,每10ms应该有一个帧。这低于计时器精度。可能根本没有睡眠。如果没有其他线程准备好运行,该函数将立即返回,这样您将达到最大吞吐量。如果设置更高的FPS,则情况与预期等待时间始终低于计时器精度的情况完全相同。因此结果不会改善。
答案 1 :(得分:2)
问题解决了:)
#include <chrono> /// to use std::chrono namespace
#include <iostream> /// for console output
#include <thread> /// for std::this_thread::sleep_for()
#include <windows.h>
#define TARGET_FPS 500 /// our target fps as a macro
const float target_fps = (float)TARGET_FPS; /// our target fps
float tmp_target_fps = target_fps; /// used to adjust the target fps depending on the actual real fps to reach the real target fps
using frame_len_type = std::chrono::duration<float,std::ratio<1,TARGET_FPS>>; /// this is the duration that defines the length of a frame
using fsecond = std::chrono::duration<float>; /// this duration represents once second and uses 'float' type as internal representation
fsecond target_frame_len(1.0f/tmp_target_fps); /// we will define this constant here , to represent on frame duration ( defined to avoid construction inside a loop )
bool enable_fps_oscillation = true;
void app_logic()
{
/** ... All application logic goes here ... **/
}
class HeighResolutionClockKeeper
{
private :
bool using_higher_res_timer;
public :
HeighResolutionClockKeeper() : using_higher_res_timer(false) {}
void QueryHeighResolutionClock()
{
if (timeBeginPeriod(1) != TIMERR_NOCANDO)
{
using_higher_res_timer = true;
}
}
void FreeHeighResolutionClock()
{
if (using_higher_res_timer)
{
timeEndPeriod(1);
}
}
~HeighResolutionClockKeeper()
{
FreeHeighResolutionClock(); /// if exception is thrown , if not this wont cause problems thanks to the flag we put
}
};
int main() /// our main function !
{
HeighResolutionClockKeeper MyHeighResolutionClockKeeper;
MyHeighResolutionClockKeeper.QueryHeighResolutionClock();
using sys_clock = std::chrono::system_clock; /// simplify the type name to make the code readable
sys_clock::time_point frame_begin,frame_end; /// we will use these time points to point to frame begin and end
sys_clock::time_point start_point = sys_clock::now();
float accum_fps = 0.0f;
int frames_count = 0;
while (true)
{
frame_begin = sys_clock::now(); /// there we go !
app_logic(); /// lets be logical here :)
frame_end = sys_clock::now(); /// we are done so quick !
std::this_thread::sleep_for( target_frame_len- (frame_end.time_since_epoch()-frame_begin.time_since_epoch()) ); /// we will take a rest that is equal to what we where supposed to take to finish the actual target frame length
float fps = fsecond(1) / ( sys_clock::now() - frame_begin) ; /// this will show ass the current FPS
/// obviously we will not be able to hit the exact FPS we want se we need to oscillate around until we
/// get a very close average FPS by time .
if (fps < target_fps) /// our real fps is less than what we want
tmp_target_fps += 0.01; /// lets asl for more !
else if (fps > target_fps ) /// it is more than what we want
tmp_target_fps -=0.01; /// lets ask for less
if(enable_fps_oscillation == true)
{
/// now we will adjust our target frame length for match the new target FPS
target_frame_len = fsecond(1.0f/tmp_target_fps);
/// used to calculate average FPS
accum_fps+=fps;
frames_count++;
/// each 1 second
if( (sys_clock::now()-start_point)>fsecond(1.0f)) /// show average each 1 sec
{
start_point=sys_clock::now();
std::cout<<accum_fps/frames_count<<std::endl; /// it is getting more close each time to our target FPS
}
}
else
{
/// each frame
std::cout<<fps<<std::endl;
}
}
MyHeighResolutionClockKeeper.FreeHeighResolutionClock();
return 0; /// return to OS
} /// end of code
我必须在Windows平台上添加timeBeginPeriod()
和timeEndPeriod()
,感谢来自http://www.geisswerks.com/ryan/FAQS/timing.html的这个非常棒的,迷失方向的网站Ryan Geiss 。
详细信息:
因为我们实际上无法达到我们想要的精确fps(非常略高于或低于,但由于timeXPeriod(1)而高达1000 fps并且低至1 fps)因此我使用了一些额外的转储fps变量调整我们分区的目标fps,增加它并减少它...,这将让我们控制实际的应用程序fps以平均值命中我们的真实目标fps(你可以使用&#39; enable_fps_oscillation&#39启用和禁用它;标志)这解决了fps = 60的问题,因为我们无法击中它(+/- 0.5),但是如果我们设置fps = 500,我们就会击中它而我们不需要在它下面振动