界面FPS流暢度(卡頓值)評估公式

界面fps能達(dá)到60 且每幀間隔在16.7ms左右,用戶流暢度體感為最高。出現(xiàn)掉幀(幀速減少), 抖幀(幀速不均勻),則認(rèn)為會影響到用戶流暢度體驗(yàn)。目前

百度

開發(fā)同學(xué)提供了可以設(shè)置一段時間內(nèi)幀長的Demo,經(jīng)過產(chǎn)品同學(xué)多輪、多人的試驗(yàn)結(jié)論:

連續(xù)5幀幀長為30ms時,能夠在網(wǎng)頁瀏覽的界面滑動時明確感覺到抖動。

單幀幀長為70ms時,能夠在網(wǎng)頁瀏覽的界面滑動時明確感覺到界面頓住。

騰訊

PerfDog Jank計算方法:

1.??????同時滿足以下兩條件,則認(rèn)為是一次卡頓Jank.

a)??????當(dāng)前幀耗時>前三幀平均耗時2倍。

b)??????當(dāng)前幀耗時>兩幀電影幀耗時(1000ms/24*2=84ms)。

2.??????同時滿足兩條件,則認(rèn)為是一次嚴(yán)重卡頓BigJank.

a)??????當(dāng)前幀耗時>前三幀平均耗時2倍。

b)??????當(dāng)前幀耗時>三幀電影幀耗時(1000ms/24*3=125ms)。

1)??????BigJank:1s內(nèi)嚴(yán)重卡頓次數(shù)

2)??????Jank(/10min):平均每10分鐘卡頓次數(shù)。

3)??????BigJank(/10min):平均每10分鐘嚴(yán)重卡頓次數(shù)

目前市面上有些做卡頓評估的方案,但是計算方法取值太過離散,不具備連續(xù)性。我們需要一個能評測當(dāng)前幀率的公式,計算出每幀的評分。來對界面流暢度有個完善的評估。


幾個重要指標(biāo)

1.平均幀率 (平均幀率不能檢測出短時間內(nèi)突然卡頓后又恢復(fù)的情況)

2.幀率方差 (方差只能檢測幀速的波動,如果幀速一直是30,方差也會為0)

3.掉幀卡頓比率? (若某幀時長超過了30ms 則認(rèn)為丟失了一幀)

4.降幀次數(shù) (平均每秒相鄰兩個FPS點(diǎn)下降大于8幀的次數(shù))

5. Ft?當(dāng)前幀耗時

FS = FrameSpeed?= 16.7/Ft : 手機(jī)滿幀率是一秒60幀,平均每幀16.7ms,?假定滿幀速=16.7/16.7 = 1 , 當(dāng)前幀耗時越多,速度越慢,最低趨近于0. 故幀速取值區(qū)間為(0, 1]

由于用戶感知卡頓與幀速和幀速波動值有關(guān), 所以計算流暢值的公式應(yīng)該與用戶當(dāng)前幀速,與幀速的導(dǎo)數(shù)dx相關(guān), 由于導(dǎo)數(shù)的取值范圍為(-∞, +∞), 因此我們使用上下兩幀幀速差值的平方來評估速率波動,整體公式為: 其中 為當(dāng)前幀幀速FS。


如果當(dāng)前幀為連續(xù)的第四幀滿幀速(遇到連續(xù)的4幀,幀速為1)則把當(dāng)前幀流暢值恢復(fù)為100

式中?a=4 ?b=1 t = 0.85 ?t=>(0,1]

公式說明:

其中a?為當(dāng)前幀速的權(quán)重值,??b為當(dāng)前幀與上一幀速波動的權(quán)重值

由于:


使用試驗(yàn)數(shù)據(jù)

[16.7, 16.7, 32, 32, 32, 32, 32, 16.7, 16.7, 70, 170, 170, 170, 170, 16.7, 16.7, 16.7, 16.7, 120, 16.7]

當(dāng)a=1 b=1 時計算出流暢值為

[100, 100, 64, 58, 55, 53, 52, 65, 82, 24, 16, 12, 11, 10, 14, 57, 78, 89, 14, 20]

當(dāng)a=2 b=1 時流暢值為

[100, 100, 60, 54, 53, 52, 52, 76, 92, 27, 14, 11, 10, 10, 42, 80, 93, 97, 17, 47]

當(dāng)a=3 b=1 時流暢值為

[100, 100, 58, 53, 52, 52, 52, 82, 95, 27, 13, 10, 10, 9, 57, 89, 97, 99, 16, 60]

[100.0, 100.0, 61.3, 61.3, 60.2, 58.1, 57.9, 87.1, 91.5, 32.1, 16.7, 18.0, 15.5, 14.4, 66.9, 79.2, 88.9, 95.6, 17.6, 91.8]

import os, sys, math

import queue, random

import matplotlib.pyplot as plt

import numpy as np

class SmoothAlgrithm:

? ? frameFullTime = 1000/60

? ? speedQueue = [1.0, 1.0, 1.0]

? ? smoothQueue = [1.0, 1.0, 1.0]

? ? smoothLayout = {}

? ? totalSmooth = 0

? ? duration = 0

? ? calDuration = 0

? ? frameCount = 0

? ? originSmoothArr = []

? ? curSmoothArr = []

def __init__(self):

self.smoothLayout = {'A':0, 'B':0, 'C':0, 'D':0, 'E':0}

def getFrameSmooth(self, frameTime):

self.duration += frameTime

if (frameTime < self.frameFullTime):

? ? ? ? ? ? frameTime = self.frameFullTime

self.calDuration += frameTime

? ? ? ? speed = self.frameFullTime / frameTime

? ? ? ? avgSpeed = sum(self.speedQueue) / len(self.speedQueue)

? ? ? ? avgSmooth = sum(self.smoothQueue) / len(self.smoothQueue)

if (avgSpeed == 1.0 and speed == 1.0):

? ? ? ? ? ? score = 1

? ? ? ? ? ? smooth = 100

else:

? ? ? ? ? ? score = (4*math.pow(speed, 0.90) - pow((speed - avgSpeed), 2) + avgSmooth) / 5

? ? ? ? ? ? smooth = (score*100)

self.speedQueue.insert(0, speed)

del self.speedQueue[-1]

self.smoothQueue.insert(0, score)

del self.smoothQueue[-1]

if (smooth > 80):

self.smoothLayout['A'] =? self.smoothLayout['A'] + 1

elif (smooth > 60):

self.smoothLayout['B'] =? self.smoothLayout['B'] + 1

elif (smooth > 40):

self.smoothLayout['C'] =? self.smoothLayout['C'] + 1

elif (smooth > 20):

self.smoothLayout['D'] =? self.smoothLayout['D'] + 1

else:

self.smoothLayout['E'] =? self.smoothLayout['E'] + 1

self.frameCount += 1

self.originSmoothArr.append(int(smooth))

self.totalSmooth += smooth / speed

self.curSmoothArr.append(int(smooth / speed))

return smooth

def setFrameArr(self, arr):

? ? ? ? smooths = []

for ft in arr:

? ? ? ? ? ? smooth = int(self.getFrameSmooth(ft)*10)/10

? ? ? ? ? ? smooths.append(smooth)

print(smooths)

def calAvgSmooth(self):

? ? ? ? frameNumber = self.duration / self.frameFullTime

print('Origin smooth:', int(sum(self.originSmoothArr)/self.frameCount))

print('cur smooth:', int(sum(self.curSmoothArr)/frameNumber))

? ? ? ? calFrames = self.calDuration / self.frameFullTime

print('cal smooth:', int(sum(self.curSmoothArr)/calFrames))

def calFPS(self):

print('cur fps:', int(self.frameCount*1000/self.duration))

maxFrameTime = 200

def randomFrametime():

? ? rdnum = random.randint(0, 100)

if (rdnum < 90): #70%的滿幀

return 16;

? ? rdnum = random.randint(0, 350) #20% 16.7-35

if (rdnum > 167):

return rdnum / 10.0

? ? rdnum = random.randint(350, maxFrameTime*10) / 10.0 #10 分布在35-200

return rdnum

def randPrduceSmooth():

? ? smoothAlg = SmoothAlgrithm()

? ? ftSmoothTuple = [(0,0, []) for x in range(0, maxFrameTime+1)]

for i in range (0, maxFrameTime*1000):

? ? ? ? ft = randomFrametime()

? ? ? ? smooth = smoothAlg.getFrameSmooth(ft)

? ? ? ? idx = int(ft)

? ? ? ? ftSmoothTuple[idx][-1].append(smooth)

for idx in range(16, maxFrameTime+1):

? ? ? ? ftSmooth = ftSmoothTuple[idx]

? ? ? ? count = len(ftSmooth[-1]) or 1

? ? ? ? avgFtSmooth = sum(ftSmooth[-1]) / count

? ? ? ? avgFtSmooth = int(avgFtSmooth*10)/10.0

? ? ? ? ftSmoothTuple[idx] = (avgFtSmooth, count, ftSmooth[-1])

print((idx, count, avgFtSmooth))

? ? x = np.arange(16,maxFrameTime)

? ? y = [ftSmoothTuple[idx][0] for idx in range(16,maxFrameTime)]

? ? plt.plot(x,y,"ob")

? ? plt.ylabel('smooth')

? ? plt.xlabel('frametime')

? ? plt.show()

smoothAlg = SmoothAlgrithm()

#arr = [2, 11.0, 13.4, 16.7, 32, 32, 32, 32, 32, 16.7, 16.7, 70, 170, 170, 170, 170, 16.7, 16.7, 16.7, 16.7, 120, 16.7]

arr = [1 for x in range(0, 60)]

smoothAlg.setFrameArr(arr)

print("framecount: ", len(arr),? "framenumber:",? int(sum(arr)/smoothAlg.frameFullTime), "? duration:", sum(arr))

print("\n orignarr:", smoothAlg.originSmoothArr)

print("\n curarr:", smoothAlg.curSmoothArr)

smoothAlg.calFPS()

smoothAlg.calAvgSmooth()


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容