Qt测量应用程序冻结期间的渲染时间



我有一个Qt应用程序,其中有一个函数render,它遍历对象列表并为每个对象创建一个根据(子类化)QGraphicsPathItem然后它将其作为子级放入(子类化)QGraphicsScene中。(这是在下面的代码中通过访问者GGObjConstructor完成的,该使用变量scene进行初始化,该变量是要添加项目的场景)。

XTimer timer;
timer.start();
gobjlist gobjlis = ogc._gobjectlis;
GGObjConstructor ggoc(scene, z_value, bkground_color);
for(auto obj: gobjlis) {
obj->exec( &ggoc );
}
timer.stop();

我的类 XTimer 以一种明显的方式用于测量此过程的时间。

现在的问题是:只有准备所有项目并插入场景的循环中花费的时间才能用timer来衡量。对于具有 ~165000 个项目的典型示例,这在达到timer.stop()时给出大约 7.5 秒作为计时器值。但是应用程序在这 7.5 秒之后仍然冻结,屏幕窗口所在的场景通过显示仍然不可见,仅在大约 25 秒(手动停止)后突然出现显示窗口,其中包含所有要显示的项目。

现在我当然想测量这些"冻结时间"(或应用程序再次响应的时间,或者显示窗口出现的时间)。但是我发现没有办法做到这一点,尽管我通过堆栈溢出或一般的网络查看了一段时间。我发现的最好的提示是

堆栈溢出问题

那里的答案似乎暗示,实现起来并不简单(覆盖 paintEvent 方法之类的东西)。

问:这是真的吗?或者有没有一种简单的方法来测量应用程序再次响应/图像真正显示的时间?

我曾经遇到过类似的应用程序问题,我想测量应用程序冻结的时间,以找出导致这些冻结的原因。我想到的是测量主线程的 Eventloop 没有响应的时间,因为这直接对应于冻结的应用程序。

基本思想是不运行QApplication而是从QApplication继承并覆盖notify()函数。无论如何,某些应用程序都会这样做以捕获异常,否则这些异常会中断事件循环。这里有一些伪代码,应该能传达这个想法:

bool MyApplication::notify( QObject * receiver, QEvent *  event ) 
{
// something like storing current time like:
// auto start = std::chrono::system_clock::now();
// auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(start - end );
// if( elapsed.count() > 1000 ){
// log something like: Mainthread responds again after <elapsed> seconds
// }
// Note that end must be a member variable
// end = start;
return QApplication::notify(receiver, event);
}

注意 1:如果您的应用程序没有继续运行notify()您可以出于测试目的引入虚拟QTimer,其触发速度超过日志记录时间阈值。

注2:如果您使用多个线程,尤其是。QThreads,可能需要过滤receiver对象,并仅在接收方位于主线程中时才执行该代码。

使用此代码,您可以记录主线程(冻结的GUI)的每次冻结并确定冻结的长度。通过适当的日志记录,您可以找出导致冻结的原因。 请记住,这只会在冻结解决后记录!

补充:它更复杂和缓慢,但出于调试/调查目的,您可以存储接收方的最后一个事件和对象树并记录它们。您甚至不知道哪个是触发冻结和接收对象的最后一个事件。

最新更新