2010-09-23 58 views

回答

0

我從來沒有見過類似的東西。通常情況下,您儘可能快地渲染幀,然後執行一些CPU幀後處理或預處理並渲染下一幀,所以使用率在0到100%之間。只有很少的FPS被限制在最大數量,只有在這種情況下,這將是一個有意義的數字。

2

沒有。在這種高度並行的環境中,很難嚴格定義。但是,您可以用ARB_timer_query擴展名來近似它。

+1

可以舉例說明使用ARB_timer_query擴展嗎? – Newbie 2010-10-06 19:37:31

4

並非如此,但您可以使用供應商的實用程序獲得不同的性能計數器,對於NVIDIA,您可以使用NVPerfKit和NVPerfHUD。其他廠商也有類似的實用程序

1

我在我的OpenGL渲染線程實現中實現了基於GPU執行時間測量框架的定時器查詢。我給大家介紹下面的計時器查詢部分:

假設

  • enqueue運行渲染線程
  • limiter.frame60上的功能僅相當於0每隔60幀

代碼:

struct TimerQuery 
{ 
    std::string description; 
    GLuint timer; 
}; 
typedef std::deque<TimerQuery> TimerQueryQueue; 

...

TimerQueryQueue timerQueryQueue; 

...

void GlfwThread::beginTimerQuery(std::string description) 
{ 
    if (limiter.frame60 != 0) 
     return; 

    enqueue([this](std::string const& description) { 
     GLuint id; 
     glGenQueries(1, &id); 
     timerQueryQueue.push_back({ description, id }); 
     glBeginQuery(GL_TIME_ELAPSED, id); 
    }, std::move(description)); 
} 

void GlfwThread::endTimerQuery() 
{ 
    if (limiter.frame60 != 0) 
     return; 

    enqueue([this]{ 
     glEndQuery(GL_TIME_ELAPSED); 
    }); 
} 


void GlfwThread::dumpTimerQueries() 
{ 
    while (!timerQueryQueue.empty()) 
    { 
     TimerQuery& next = timerQueryQueue.front(); 

     int isAvailable = GL_FALSE; 
     glGetQueryObjectiv(next.timer, 
          GL_QUERY_RESULT_AVAILABLE, 
          &isAvailable); 
     if (!isAvailable) 
      return; 

     GLuint64 ns; 
     glGetQueryObjectui64v(next.timer, GL_QUERY_RESULT, &ns); 

     DebugMessage("timer: ", 
        next.description, " ", 
        std::fixed, 
        std::setprecision(3), std::setw(8), 
        ns/1000.0, Stopwatch::microsecText); 

     glDeleteQueries(1, &next.timer); 

     timerQueryQueue.pop_front(); 
    } 
} 

下面是一些例子輸出:

Framerate t=5.14 fps=59.94 fps_err=-0.00 aet=2850.67μs adt=13832.33μs alt=0.00μs cpu_usage=17% 
instanceCount=20301 parallel_μs=2809 
timer: text upload range 0.000μs 
timer: clear and bind 95.200μs 
timer: upload 1.056μs 
timer: draw setup 1.056μs 
timer: draw 281.568μs 
timer: draw cleanup 1.024μs 
timer: renderGlyphs 1.056μs 
Framerate t=6.14 fps=59.94 fps_err=0.00 aet=2984.55μs adt=13698.45μs alt=0.00μs cpu_usage=17% 
instanceCount=20361 parallel_μs=2731 
timer: text upload range 0.000μs 
timer: clear and bind 95.232μs 
timer: upload 1.056μs 
timer: draw setup 1.024μs 
timer: draw 277.536μs 
timer: draw cleanup 1.056μs 
timer: renderGlyphs 1.024μs 
Framerate t=7.14 fps=59.94 fps_err=-0.00 aet=3007.05μs adt=13675.95μs alt=0.00μs cpu_usage=18% 
instanceCount=20421 parallel_μs=2800 
timer: text upload range 0.000μs 
timer: clear and bind 95.232μs 
timer: upload 1.056μs 
timer: draw setup 1.056μs 
timer: draw 281.632μs 
timer: draw cleanup 1.024μs 
timer: renderGlyphs 1.056μs 

這讓我打電話給renderThread->beginTimerQuery("draw some text");在我的OpenGL繪圖調用或什麼的, renderThread->endTimerQuery();之後,測量已經過的GPU執行時間。

這裏的想法是,它在測量部分之前向GPU命令隊列發出命令,因此glBeginQueryTIME_ELAPSED記錄了某個實現定義的計數器的值。 glEndQuery發出GPU命令來存儲當前計數和TIME_ELAPSED查詢開頭存儲的計數之間的差異。該結果由GPU存儲在查詢對象中,並且在將來某個異步時間「可用」。我的代碼保持一個已發佈的定時器查詢的隊列,並且每秒檢查一次完成的測量。只要隊列頭部的定時器查詢仍然可用,我的dumpTimerQueue就會一直打印測量結果。最終它會觸發一個尚未提供的計時器並停止打印消息。

我添加了一個額外的功能,它將60個調用中的59個調出到測量功能,所以它只對我的程序中的所有儀器每秒測量一次。這可以防止太多的垃圾郵件,並使其可用於轉儲到stdout進行開發,並防止由測量引起的太多性能干擾。這就是limiter.frame60的東西,frame60保證是< 60.它包裝。

雖然這並不能完全回答問題,但您可以通過記錄所有繪製調用的經過時間與經過的掛鐘時間來推斷GPU使用情況。如果幀是16ms,並且定時器查詢TIME_ELAPSED是8ms,則可以推斷大約50%的GPU使用率。

還有一點需要注意:測量是通過將GPU命令放入GPU隊列中來度量GPU執行時間。線程與它無關,如果這些enqueue內部的操作在一個線程中執行,它將是等效的。