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

这可能吗?

【问题讨论】:

  • 我从未见过在任何地方测量过这个参数。

标签: c++ opengl


【解决方案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 被限制为最大数字,只有在这种情况下,这才是一个有意义的数字。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-08
        • 2021-01-09
        • 2012-02-11
        • 1970-01-01
        • 2015-12-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多