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

Qt measuring rendering time during which application is frozen

我有一个 Qt 应用程序,其中有一个函数 render 遍历对象列表并为每个对象创建一个相应的 (subclassed) QGraphicsPathItem 然后将其作为子项放入 (subclassed) 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();

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

现在的问题是:timer只测量了所有项目准备好并插入场景的循环所花费的时间。对于具有 ~165000 个项目的典型示例,这给出了大约 7.5 秒的定时器值达到 timer.stop()。但是应用程序在这 7.5 秒之后仍然冻结,屏幕 -window 场景将被显示但不可见,并且仅在大约 25 秒(手动停止)后突然显示 window 出现所有要显示的项目。

现在我当然想测量这些 "freeze time"(或者应用程序再次响应的时间,或者显示 window 出现的时间)。但是我发现没有办法做到这一点,尽管我通过 Whosebug 或一般的网络看了一些时间。我发现的最佳提示是

Whosebug question

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

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

我曾经在一个应用程序中遇到过类似的问题,我想测量应用程序冻结的时间,以通过记录导致这些冻结的原因来找出原因。我想到的是测量主线程的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)的每次冻结并确定冻结的长度。通过适当的日志记录,您可以找出导致冻结的原因。 请记住,这只会在冻结解决后才会记录!

加法: 它更复杂也更慢,但出于 debugging/investigation 目的,您可以存储接收者的最后一个事件和对象树,并将其记录下来。比你甚至知道哪个是触发冻结和接收对象的最后一个事件。