[譯]GPUView


【本文翻譯自GPUView的開發者Matt的blog.  https://graphics.stanford.edu/~mdfisher/GPUView.html  】

【 GPUview可以在 https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install 這里下載到】

 

GPUView是Matt在微軟實習的時候和Steve Pronvost一起開發的。它的目標是是分析GPU的硬件、driver、app、CPU cores性能方面的交互。它和IceCap、Vtune、PIX等等標准的profile不同。此工具可以仔細查看CPU和GPU的交互,確定app是被CPU還是GPU限制住了,以及我們需要重新對哪一部分進行優化以提高資源的利用率。GPUView可以解決以下問題:

- 為什么我們錯過了VSync的interval?

- 新的surface是否過度使用了GPU,導致了卡頓的現象?

- 優化CPU部分的code是否能提高性能?還是需要減少GPU部分的工作?

- 我們把task送給GPU的時間是否足夠早?還是GPU一直在等CPU?

 

本文第一部分介紹GPUView的使用和理解,第二部分介紹一些使用GPUView對游戲場景進行性能相關的問題分析。

 GPUView包含在windows performance toolkit里面,首先run log.cmd,然后結束后run log.cmd,會產生Merged.etl的文件,可以由GPUView進行識別。

.etl文件里面的內容包括

- CPU context切換

- kernel mode的入口和退出

- GPU event   cmd buffer提交/resource創建/lock 等

- graphics driver report的事件 cmd buffer的起始和結束的時間

- 其他的影響性能的系統event    page fault等

 

ETW log的overhead非常低,基本上開着log,最多影響1到2個fps

 

==============================

理解GPUView

==============================

安裝GPUView的時候會有一個使用說明文件。不過,GPUView從一開始就是一個非常復雜而強大的工具。由於很多team需要更多新的GPUView的功能,GPUView越來越復雜了。如果只知道D3D API,卻對系統是怎么batch這些API,以及最終GPU硬件是怎么響應不熟悉的話,使用這個tool確實需要費一些功夫。

 

==============================

Windows Vista Display Driver Model

==============================

在windows Vista之后,微軟重新設計的顯卡驅動,以適應多個顯卡應用app同時運行的情況。理解這個模型對於理解顯卡在windows上面的性能至關重要。首先,OS將每個進程中的D3D的deivce和自己的graphics context聯系起來。每一個送到這個context的API call都和一系列的cmd綁定在一起。當有足夠的cmd,或者API覺得可以flush當前的cmd buffer的時候,D3D API會將cmd buffer送到graphics kernel。這些cmd buffer不被立即處理,而是存在一個queue里面。顯卡有一個queue存放正在處理的task。周期性的,當有queue中有空間的時候,graphics scheduler會被wake up然后將cmd buffer queue中的task放入到顯卡work queue里面去。GPU scheduler試圖和CPU的scheduler一樣能夠公平的處理各種task。GPUView能夠讓我們看到每個context的GPU queue和顯卡的queue隨着時間變化是怎么樣的。顯卡總是處理queue最前端的object,如果queue是空的,顯卡處於idle狀態。請注意,GPUView就是為了這樣的driver model設計的,不支持windows XP。

==================

A CPU-only 應用

==================

我們先來講一講對於沒有GPU的app,GPUView是什么樣的。下面是在VS中編譯一個工程的trace.

 

我們來解析一下。GPUView的橫軸永遠都是時間。最頂端一行是時間標尺。下面一行是GPU hardware queue,展現了現在的task在顯卡上是怎么處理的,可以看到,我們這個trace上大部分的都是空的。在hw queue下面的綠色長方形是系統的每個進程。在每個進程中,CPU的graphics queue是第一個,然后是屬於這進程的其他線程。因為系統中有許多線程,GPUView只顯示主要的線程。第一個進程一般都是idel process,並由每個CPU core一個線程。每個core由不同的顏色標注出來,在每個時間間隔里面,每一個core是由一個線程使用,如果沒有線程是work ready狀態,則core為 idle thread占用。因為種種原因,處理器可以在不同的線程之間切換,比如線程執行時間片過期,線程想要sleep,或者被某個event給block了,或者更高優先級的線程處於work ready狀態。

{現在來看上面這個CPU only的case,對於devenv.exe這個進程來說,它的devenec.exe!0x000000001e80d這個線程一開始是占用的白色的core0,然后是紅色的core2,后來又是白色的core0,所以,core0對應的idle線程里面在這兩段時間里面是沒有顯示的,即被其他線程占用,不是idle}

 

=======================

一個簡單的GPU應用

=======================

以下是魔獸世界(wow.exe)的trace

首先注意這些藍色豎線,代表VSync的interrupt。

GPUView支持導入symbol來提供有意義的stack trace。像我們現在看到的wow.exe里面有兩個線程,一個是wow的主線程,另一個是Direct3D創建的用於管理cmd buffer submit的線程,入股哦我們有WoW的pdb的話,就可以看到每一個線程的入口函數

從上面展現的時間段來看,wow的主線程一直不停的向wow的cpu queue上提交work,然后操作系統將cpu的queue中的task提交到GPU的queue中,為了更好的看一下這些queue的行為,讓我們看下面3個VSync段

queue的高度表示的是queue中packet的數量,最先的packet在最下面,新提交的在上面。一個packet通常是包含在一個cmd stream里面的很多API call的集合,准備發給顯卡硬件去執行的。在GPU Hardware Queue底部的是現在被硬件執行的task。如果是空的話,說明GPU此時為空閑。直到hw把task完成之后,才會從CPU queue中消失。

有一些packet使用不同的顏色去標注的,以顯示他的重要性。最重要的packet類型是由交叉線標記出來的。如果app希望達到60fps,需要在每一個VSync的時間內GPU硬件至少處理一個packet。

注意一下這里的dwm.exe進程,這個是desktop windows manager,這個是一直在跑的,除非你是處於全屏狀態。檢查dwm的行為很重要,因為如果你的應用影響了dwm的顯示,你的app的改動就不會對用戶可見了,不過因為windows給dwm.exe一個更高的gpu優先級,這種情況一般不會發生。

======================

單個queue packet

======================

GPUView對每一object存了很多信息。例如,你可以點擊每一個queue packet來看看它的生命周期,以及一些其他的信息

這讓我們可以清楚的看到從這個packet第一次進入到最后完成花了多少時間,這個在debug latency的問題的時候是很有用的。這個packet的起始時間是指API決定將cmd buffer發給queeu的時間。在d3d中有一些函數會force顯卡api flush現在的cmd buffer,一些以前的有心,如warcraf 3,也會用一些lock frame buffer的技術來force顯卡API去flush並處理cmd stream。

==============================

多個GPU應用

==============================

這展示了當多個GPU的應用同時在跑的時候,GPUView是怎么樣的。每一個CPU的contex Queue都會有自己的顏色,所以很容易看到現在graphics硬件正在處理哪個task。GPUView中可以很清楚的看清這些事件。

=========================

問題診斷

=========================

現在我們來看看3個與游戲中低性能有關的問題,並研究下是什么原因引起的。

這是跑在Ultra setting下的SC2,mothership is cloaking 很多的小單元。這個cloaking effect很容易被注意到,在外接的taxing顯卡上。從上面的trace來看,每一個rendering大約花了4個VSync的間隔,所以游戲的fps非常低,只有15。很明顯,問題是由於render的時間過長導致的,單個queue packet花了2個VSync的間隔才完成。GPU的downtime非常短,大約只有5ms,可以通過更快的submite GPU cmd來cover。除此之外,CPU的優化都是無用的,唯一的提高性能的方式就是submit更少的工作量給顯卡。

 CPU延遲過長的案例

這個是魔獸世界的例子。CPU和GPU都是瓶頸,對這二者任何一個的優化都可以提高性能。最大的問題是在目前的buffer提交給GPU時有很大的延遲,前一個buffer提交之后,后一個幾乎用了半個VSync間隔才提交,基本導致WoW不能達到60fps。為了解決這個問題,CPU的工作需要被推遲,這樣一些graphic rendering就可以更早的submit,或者可以在多個線程之間去完成,這樣減少CPU的延遲。這些方法都可以提高GPU的利用率,提高幀率。

GPUView周期性的會log stack trace,也允許app自己去提交自己的event到log stream,這樣便於決定究竟是哪一個CPU的工作在某一時間段進行。

一個在PC上優化應用的比較討厭的地方是每一個用戶有自己不同的硬件配置,性能也不相同。下面是和上面那個case一樣的場景,不過是在一個更慢的CPU和更低的顯卡設置上。場景是類似的,CPU執行時間更加影響到了fps,減少送給顯卡的工作幾乎不影響幀率。

盡管只有一個魔獸世界的線程,WoW實際上創建了很多線程,在這些interval中也有在執行其他的代碼。然而,GPUView自動隱藏了,因為他們幾乎沒有什么工作,而上面展現的線程幾乎占了WoW的98%的執行時間。關於其他的線程,你可以看下面這張圖

Excessive sleep - Ironforge

魔獸世界在Iroforge上跑在一個非常空的狀態。盡管VSync的間隔為60fps,WoW跑在30fps。從上面這個trace,我們可以發現,盡管app沒有被CPU或者GPU所限制,WoW的render線程在整個VSync間隔中都是asleep狀態。比較有可能是sleep在一些graphics API的event上,但是由於通信出現了問題,導致WoW sleep了比預期更長的時間。看看再這個interval中的其他系統線程,可以發現還有很多core可以跑WoW線程。用GPUView導入更多的log可以看到是什么event導致線程被停止執行。

Event Lists

GPUView記錄了每秒發生的很多的event,有一些可以直觀的看到,比如context轉換,queue packet submit,不過還有一些是不能直觀看到的。用GPUView可以直接搜索每個stream,decode了一些最重要的event。例如,有些程序員擔心allocation會引起frame卡住,所以需要高亮所有的allocation event,他們可以立刻放大到allocation比較集中的地方。

用戶可以看關於每個allocation event的信息,像分配的大小,在哪個segement(system memory/video memory)。

GPUView還支持一些簡單的dll model,app可以將被觀察的stream和已知的code聯系起來,並能解碼對應的參數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM