QML Profiler
2018年1月26日 vincent
對于一個程序的開發,性能優化是開發中的一個重要步驟。
我們肯定不希望開發出來的程序表現出卡頓,最好是處處流暢,絲滑般的體驗。
對于C++程序,我們有很多方法可以做性能優化,例如Visual Studio Profiler。
而對于QML(QtQuick)程序,我們可以選擇QML Profiler,這是QtCreator的一個功能。
那么QML Profiler是什么呢,官方的描述如下:
You can use the QML Profiler to find causes for typical performance problems in your applications, such as slowness and unresponsive, stuttering user interfaces. Typical causes include executing too much JavaScript in too few frames. All JavaScript must return before the GUI thread can proceed, and frames are delayed or dropped if the GUI thread is not ready.
也就是說,QML Profiler主要功能就是幫助我們去解決程序中典型的性能問題,說簡單就是幫助我們做性能優化。
注意:這個性能優化,僅指QML這里,一般來說就是界面,可能還包含點界面邏輯代碼(JS),而C++這塊,QML Profiler幾乎幫不上忙,最多是能給在QML中調用的槽函數記個耗時。
時間的考慮
作為一名程序開發者,應該努力使渲染引擎的刷新率維持在60fps,也就是說在每幀之間大約有16ms,這段時間包括了基本圖元在圖形硬件上的描畫。具體內容如下:
- 盡可能的使用異步事件驅動來編程。
- 使用工作者線程來處理重要的事情,比如說QML的WorkerScript類型就是起用了一個新的線程。
- 不要手動重復事件循環。
- 每幀的函數阻塞的時間不要超過幾毫秒。
++如果不注意上面提到的內容,就會導致跳幀,影響用戶體驗。++
注意:
QML 與 C++ 交互時,為了避免阻塞就去創建自己的
QEventLoop 或調用QCoreApplication::processEvents(),
這雖說是一種常見的模式,但也是危險的,因為信號處理
或綁定進入事件循環時,QML 引擎會繼續運行其它的綁定、
動畫、狀態遷移等,這些動作就可能帶來副作用,例如,
破壞包含了事件循環的層級結構。
性能分析
借助于QML Profiler,我們快速的了解程序運行中的主要情況和耗時細則(可以精確到微秒),其中包括但不限于:
- 圖片緩存使用情況
- 渲染耗時
- 內存使用情況
- 輸入事件
- 動畫幀率
- 編譯耗時
- 創建耗時
- 綁定耗時
- 信號處理耗時
- JS代碼耗時
如何使用QML性能分析工具
QML Profiler的功能開放是從Qt5.7開始的,之前一直是企業版才有的,也就是花錢版。
使用步驟
- 打開Qt Creator
默認安裝了Qt5.7或更高版本。 - 打開一個QML項目
選擇debug模式:
- 啟動QML Profiler
啟動工具后,等待程序運行起來,并且運行一段時間。然后點擊Stop按鈕,停止QML Profiler。
時間軸視圖
在這里,我們可以以時間軸角度,查看各個細節的耗時。時間軸的起點,就是QQmlApplication實例化的時間。我們可能看不到零點,因為在QQmlApplication被實例化到第一個元素被開始處理,時間可能會有其他的耗時。
在視圖中,從左到右,就是QML Profiler從開始到停止的所有記錄了。越小的塊表示時間越短,反之越大的塊,表示時間越長。這里的方塊具有一定的嵌套關系,下面的方塊對象隸屬于上面的對象。比如說 Windows { } 里面還可能會有一個 Item { } 這樣的嵌套關系。
- 詳細信息查看
通過鼠標左鍵點擊顏色區域即可查看詳細信息,如下:
看下面這個例子:
我們可以看出這里Image創建時間消耗78.7ms,對應的代碼文件是main.qml和行數37行。
- 根據事件類型展開
在左側不同類型的事件中,我們可以點擊那個展開按鈕,這樣我們就可以看到展開的詳細數據,這樣看數據對應關系時會更加的清楚,但是當數據很多的時候也會更加的凌亂,所以酌情使用。
- 縮放按鈕
在左側有一個放大鏡,可以縮放視圖的比例,這對于分析一段比較長的QML Profiler或者想看某一個細節點的數據會非常有用
詳細介紹:
- Pixmap Cache
在QML中使用的Image,默認是開緩存的。而所有緩存的圖片,都會在這里顯示,包括用了多少像素的緩存,還包括了圖片的加載耗時、文件名等信息。(沒有緩存的圖片也會顯示,但不會記入到緩存的階梯里)
- Scene Graph
這里顯示渲染時各個階段的耗時,如果我們發現程序的動畫有卡頓,除了一些函數的阻塞導致的卡頓外,還可以分析一下渲染的耗時開銷,看看是不是渲染的量太大導致的卡頓。
這里我們主要關注Render Render這個數據,這個數據表示將OpenGL數據發送到GPU的過程。看到一個Render Render的結束,基本表示這一幀已經結束渲染,并且即將顯示出來了。
另外還有Glyph Upload這個數據,這個數據表示字形紋路上傳。如果你的程序是嵌入式,并且有很多的字,那么Glyph Upload有可能會帶來一定的性能開銷。減少這個開銷的方式基本就是減少字,比如說用圖片(Image)代替文字(Text或者Label)。
- Memory Usage
顯示內存使用情況,如果這里有大塊的內存增長,看看是不是這里在初始化很多東西,或者是有很多不必要的組件被創建出來了。
- Input Events
顯示用戶輸入事件,例如鼠標和鍵盤事件
- Debug Messages
顯示調試輸出的時間點,如果你需要對照Debug輸出和對應的QML事件,那么這會很有幫助
- Animations
顯示是否有動畫在執行,以及動畫的FPS,在多線程渲染時還會顯示多線程的信息。如果我們發現FPS低于18,那么視覺上可能就會有明顯的卡頓了。而30到60的FPS,一般就可以認為是流暢的。
- Compiling
顯示編譯的耗時。這里要說下,從Qt5.8開始,QtQuick引入了qmlc機制,讓編譯時間大幅度縮減,基本上是從幾百毫秒,縮減到幾十甚至十毫秒以內。之前在csdn發過文章講這個,這里再放下鏈接:
- Creating
顯示創建的耗時,一般也是啟動優化的主要部分
- Binding
顯示綁定的耗時
- Hangling Signal
顯示信號處理的耗時
- Javascript
顯示JS執行的耗時。如果在QML里調用了一個C++的槽,那么這里也會有計時,但是也只有槽函數的總耗時,C++那里的運行情況這里看不出來。
統計圖視圖
選擇統計Statistic Tab如下:
在這里,我們可以看到每個細則,例如編譯、創建、綁定、JavaScript或者信號處理的次數以及它們所消耗的時間。
除了在時間軸那里,通過肉眼觀察,我們在這里,通過對百分比的排序,也可以迅速的看出哪個東西最耗時。
火焰視圖
選擇Flame Graph Tab。
在這里,我們可以看到更加簡潔的QML和JS統計。其中也直觀的告訴了我們一些嵌套關系。
綜上,這是最基本的3個功能區,構成了QML Profiler。我們程序的性能分析,主要也圍繞著這三點展開。
性能優化建議
如果程序有明顯的加載慢問題,那么可以先去看創建,找大塊,去延后加載或者異步加載。讓首界面先顯示出來。尤其是圖片,圖片的加載比較慢,盡量選擇合適分辨率的圖片,不要過大。對于不會再第一時間顯示的東西,盡量不要在第一時間加載。
如果程序有明顯卡頓問題,那么可以看渲染那里,是不是渲染的東西太多了,例如用了過多的clip。或者有很多在視覺上看不到的元素,例如xy為-1000這樣的Item,沒有被隱藏,這些Item照樣會渲染,照樣會有性能開銷,對于這些元素可以將visible設置為false,直接影藏掉,這就不會有渲染耗時了。例外值得一提的是,對于有動畫的場景,建議把每幀時間控制在16ms以內,以維持60FPS的流暢界面。
關于性能優化進一步的細節點,這里不展開,以后單獨發文章講,本文只講QML Profiler的基礎。更多關于QML Profiler的信息,可以前往官網查看:
Profiling QML Applications