OpenGL:如何获得 GPU 使用百分比?

Posted

技术标签:

【中文标题】OpenGL:如何获得 GPU 使用百分比?【英文标题】:OpenGL: How to get GPU usage percent? 【发布时间】:2010-09-23 12:07:22 【问题描述】:

这可能吗?

【问题讨论】:

我从未见过在任何地方测量过这个参数。 【参考方案1】:

并非如此,但您可以使用供应商的实用程序获得不同的性能计数器,对于 NVIDIA,您有 NVPerfKit 和 NVPerfHUD。其他供应商也有类似的实用程序。

【讨论】:

【参考方案2】:

不。在这样一个高度并行的环境中,甚至很难严格定义。但是,您可以使用 ARB_timer_query 扩展来近似它。

【讨论】:

你能举个ARB_timer_query扩展的例子吗?【参考方案3】:

我在我的 OpenGL 渲染线程实现中实现了一个基于计时器查询的 GPU 执行时间测量框架。我将在下面分享计时器查询部分:

假设

enqueue 在渲染线程上运行一个函数 limiter.frame60 每 60 帧只等于 0 一次

代码:

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

这使我可以在我的 opengl 绘图调用或其他任何操作之前调用renderThread-&gt;beginTimerQuery("draw some text");,并在它之后调用renderThread-&gt;endTimerQuery();,以测量经过的 GPU 执行时间。

这里的想法是,它在测量部分之前向GPU命令队列发出命令,因此glBeginQueryTIME_ELAPSED记录了一些实现定义的计数器的值。 glEndQuery 发出一个 GPU 命令来存储当前计数与 TIME_ELAPSED 查询开头存储的计数之间的差异。该结果由 GPU 存储在查询对象中,并且在未来某个异步时间“可用”。我的代码保留已发出的计时器查询队列,并每秒检查一次以完成测量。只要队列头部的计时器查询仍然可用,我的dumpTimerQueue 就会继续打印测量值。最终它会遇到一个尚不可用的计时器并停止打印消息。

我添加了一个附加功能,它在对测量函数的 60 次调用中减少了 59 次,因此它每秒仅对我程序中的所有仪器进行测量一次。这可以防止过多的垃圾邮件并使其可用于转储到标准输出以进行开发,并防止由测量引起的过多性能干扰。这就是limiter.frame60的东西,frame60保证

虽然这不能完美地回答问题,但您可以通过记录所有绘制调用的经过时间与经过的挂钟时间来推断 GPU 使用情况。如果帧为 16 毫秒,定时器查询 TIME_ELAPSED 为 8 毫秒,您可以推断出大约 50% 的 GPU 使用率。

另外一点:测量是通过将 GPU 命令放入 GPU 队列来测量 GPU 执行时间。线程与它无关,如果那些enqueue内部的操作在一个线程中执行,那将是等效的。

【讨论】:

【参考方案4】:

我从来没有见过这样的事情。通常,您会尽可能快地渲染一帧,然后对 CPU 帧进行一些后处理或预处理,然后再渲染下一帧,因此使用率会在 0% 到 100% 之间波动。很少有 FPS 被限制为最大数字,只有在这种情况下,这才是一个有意义的数字。

【讨论】:

以上是关于OpenGL:如何获得 GPU 使用百分比?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sklearn.datasets.load_files 加载数据百分比

C# - 以百分比形式获取 GPU 的总使用量

如何使用 PySpark 逐年获得百分比变化

如何从100分的工资中获得百分比

如何在冲积或桑基图中获得 y 轴上的百分比?

使用 FxCop 获得百分比代码覆盖率