前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >APP性能测评分析

APP性能测评分析

原创
作者头像
用户10443079
发布2023-03-21 17:32:48
1.6K0
发布2023-03-21 17:32:48
举报

1.1流畅度相关概念 刷新率 vs 帧率 刷新率:美妙屏幕刷新次数,手机品目的刷新率是60HZ 帧率:GPU在一秒内绘制的帧率

撕裂 vs 掉帧 撕裂:因为屏幕的刷新过程是自上而下、自左向右的, 如果帧率>刷新率,当屏幕还没有刷新n-1帧的数据时, 就开始生成第n帧的数据了,从上到下,覆盖第n-1帧。如果此时刷新屏幕, 就会出现图像的上半部分是第n帧的,下半部分是第n帧的现象。CPU/GPU一直都在渲染。 掉帧:Android系统每隔16ms发出VSYNC信号,触发GPU对UI进行渲染, 如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候由于还没有准备好, 就无法进行更新任何内容,那么用户在32ms内看到的会是同一帧画面(卡顿现象),即丢帧现象。

单缓冲 vs VSYNC vs 双缓存 vs 三缓存 单缓冲(没有引入CSync): GPU向缓存中写入数据,屏幕从缓冲中读取数据,刷新后显示。有余刷新率和帧率并不总是一致的, 很可能导致撕裂现象。为了解决单缓冲的画面撕裂问题,出现了双缓存和VSYCNC VSYCNC和双缓存: 双缓存是用来两个缓存去:Back Buffer、Frame Buffer 当写入下一帧是,GPU会先填充 Back Buffer中, 当刷新屏幕时,屏幕从Frame Buffer 中读取数据,VSYNC主要是完成帧的复制,下一帧的渲染 三重缓存: 双重缓存的缺陷在于:当 CPU/GPU 绘制一帧的时间超过 16 ms 时,会产生 Jank。更要命的是, 产生 Jank 的那一帧的显示期间,GPU/CPU 都是在闲置的。

FPS原理 FPS是Frame per second的缩写,即每秒的帧数.这一术语广泛的应用于计算机图形学,视频采集,游戏等。

这里主要介绍一下视频游戏中的帧率,第一个First person shooter game的帧率只有大概6FPS,但是依然很成功。不过随着硬件设备,尤其是显卡性能的加强,现在游戏的帧率一般在30FPS~100FPS之间。由于每帧图像所消耗的时间不一样,造成帧率是在不断变化的,所以每个游戏都会设定一个最大的帧率,以保证平滑的切换。

  // Timing...
        static QTime time;
        static int frames = 0;
        static bool started = false;
 
        if (!started || time.elapsed() > 1000) {
            qreal fps = frames * 1000. / time.elapsed();
            if (fps == 0)
                m_current_fps = "counting fps...";
            else
                m_current_fps = QString::fromLatin1("%3 FPS").arg((int) qRound(fps));
 
            time.start();
            started = true;
            frames = 0;
 
        } else {
            ++frames;
 
            p.setOpacity(1);
            p.setFont(QFont("times", 30));
            p.fillRect(5, height() - 40, 250, 40, Qt::white);
            p.drawText(10, height() - 8, m_current_fps);
        }
    }

由于一般实时的游戏都已一个定时器不断地刷新画面,所以每一帧的输出都是通过paintEvent来完成的。将上面这段代码放入paintEvent就可以统计出每秒的帧率。

那么怎么控制最大的帧率呢?

其实也很简单,就是通过设置定时器的interval来完成的,考虑到现在显示器的显示频率一般在60HZ,所以interval一般设置为1000/60ms 比较好,即60FPS是一个理论上最大的帧率。

帧率(FPS)计算的六种方法总结: 一、固定时间帧数法 帧率计算的公式为:

fps = frameNum / elapsedTime; 如果记录固定时间内的帧数,就可以计算出同步率。此种方法用得较多。

int fps()
{
    static int fps = 0;
    static int lastTime = getTime(); // ms
    static int frameCount = 0;
    ++frameCount;
    int curTime = getTime();
    if (curTime - lastTime > 1000) // 取固定时间间隔为1秒
    {
        fps = frameCount;
        frameCount = 0;
        lastTime = curTime;
    }
    return fps;
}
还有另一种写法:

int fps(int deltaTime)
{
    static int fps = 0;
    static int timeLeft = 1000; // 取固定时间间隔为1秒
    static int frameCount = 0;

    ++frameCount;
    timeLeft -= deltaTime;
    if (timeLeft < 0)
    {
        fps = frameCount;
        frameCount = 0;
        timeLeft = 1000;
    }
    return fps;
}

二、固定帧数时间法 帧率计算的公式为: fps = frameNum / elapsedTime; 如果每隔固定的帧数,计算帧数使用的时间,也可求出帧率。此种方法使用得较少。

int fps()
{
    static int fps = 0;
    static int frameCount = 0;
    static int lastTime = getTime(); // ms
    ++frameCount;
    if (frameCount >= 100) // 取固定帧数为100帧
    {
        int curTime = getTime();
        fps = frameCount / (curTime - lastTime) * 1000;
        lastTime = curTime;
        frameCount = 0;
    }
    return fps;
}

三、实时计算法 实时计算法直接使用上一帧的时间间隔进行计算,结果具有实时性,但平滑性不好。

int fps(int deltaTime) // ms
{
    int fps = static_cast<int>(1.f / deltaTime * 1000); // 别忘了先转换为浮点数,否则会有精度丢失
    return fps;
}

四、总平均法 总平均法使用全局帧数除以全局时间,以求出帧率。

int beginTime = getTime();
int fps()
{
    static int frameCount = 0;
    ++frameCount;
    int deltaTime = getTime() - beginTime();
    return static_cast<int>(frameCount * 1.f / deltaTime * 1000); // 别忘了先转换为浮点数,否则会有精度丢失
}

五、精确采样法 精确采样法采样前N个帧,然后计算平均值。此种方法需要额外的内存空间,所以不常用。

int fps(int deltaTime) // ms
{
    static std::queue<int> q;
    static int sumDuration = 0; // ms
    int fps = 0;
    if (q.size() < 100) // 样本数设为100
    {
        sumDuration += deltaTime;
        q.push(deltaTime);
        fps = static_cast<int>(q.size() * 1.f / sumDuration * 1000.f); // 别忘了转换为浮点数,否则会有精度丢失
    }
    else
    {
        sumDuration -= q.front();
        sumDuration += deltaTime;
        sumDuration.pop();
        sumDuration.push(deltaTime);
        fps = static_cast<int>(100.f / sumDuration * 1000.f); // 别忘了转换为浮点数,否则会有精度丢失
    }
    return fps;
}

六、平均采样法 平均采样法利用上次的统计结果,克服了精确采样法需要使用额外空间的缺点。此种方法较常用。

int fps(int deltaTime) // ms
{
    static float avgDuration = 0.f;
    static alpha = 1.f / 100.f; // 采样数设置为100
    static int frameCount = 0;
    ++frameCount;
    int fps = 0;
    if (1 == frameCount)
    {
        avgDuration = static_cast<float>(deltaTime);
    }
    else
    {
        avgDuration = avgDuration * (1 - alpha) + deltaTime * alpha; 
    }
    fps = static_cast<int>(1.f / avgDuration * 1000);
    return fps;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
流计算 Oceanus
流计算 Oceanus 是大数据产品生态体系的实时化分析利器,是基于 Apache Flink 构建的企业级实时大数据分析平台,具备一站开发、无缝连接、亚秒延时、低廉成本、安全稳定等特点。流计算 Oceanus 以实现企业数据价值最大化为目标,加速企业实时化数字化的建设进程。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档