OpenGL: Как получить процент использования графического процессора? - PullRequest
5 голосов
/ 23 сентября 2010

Возможно ли это вообще?

Ответы [ 4 ]

4 голосов
/ 23 сентября 2010

Не совсем, но вы можете получить разные счетчики производительности, используя утилиты вашего поставщика, для NVIDIA у вас есть NVPerfKit и NVPerfHUD. Другие поставщики имеют аналогичные утилиты.

2 голосов
/ 23 сентября 2010

Неа.Это даже трудно строго определить в такой сильно параллельной среде.Однако вы можете приблизить его с расширением ARB_timer_query.

1 голос
/ 23 марта 2016

В моей реализации потока рендеринга OpenGL я реализовал инфраструктуру измерения времени выполнения на основе запросов по таймеру. Я поделюсь частями запроса таймера ниже:

Пусть

  • 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 draw или чем-то еще, и renderThread->endTimerQuery(); сразу после него, чтобы измерить истекшее время выполнения GPU.

Идея здесь в том, что она выдает команду в очередь команд графического процессора непосредственно перед измеряемой секцией, поэтому glBeginQuery TIME_ELAPSED записывает значение некоторого счетчика, определенного реализацией. glEndQuery выдает команду GPU для сохранения разницы между текущим счетчиком и счетчиком, сохраненным в начале запроса TIME_ELAPSED. Этот результат хранится в графическом процессоре в объекте запроса и становится «доступным» в будущем. Мой код хранит очередь отправленных запросов таймера и проверяет один раз в секунду для завершенных измерений. Мой dumpTimerQueue продолжает печатать измерения до тех пор, пока все еще доступен запрос таймера в начале очереди. В конце концов он срабатывает по таймеру, который еще не доступен, и останавливает печать сообщений.

Я добавил дополнительную функцию, которая исключает 59 из 60 вызовов функций измерения, поэтому он измеряет только один раз в секунду для всех инструментов в моей программе. Это предотвращает слишком много спама и делает его пригодным для передачи в стандартный вывод для разработки, а также предотвращает слишком большое влияние на производительность, вызванное измерениями. Это то, что является функцией limiter.frame60, frame60 гарантированно будет <60. Это обертка. </p>

Хотя это не совсем отвечает на вопрос, вы можете сделать вывод об использовании графического процессора, отметив истекшее время для всех вызовов отрисовки по сравнению с истекшим временем настенных часов. Если время кадра составляло 16 мс, а время запроса таймера TIME_ELAPSED составляло 8 мс, можно сделать вывод, что использование графического процессора составляет приблизительно 50%.

Еще одно примечание: измерение измеряется временем выполнения графического процессора путем помещения команд графического процессора в очередь графического процессора. Поток не имеет к этому никакого отношения, если операции внутри этих enqueue были выполнены в одном потоке, это было бы эквивалентно.

0 голосов
/ 23 сентября 2010

Я никогда не видел ничего подобного.Обычно вы визуализируете фрейм как можно быстрее, выполняете некоторую обработку кадров ЦП после или предварительной обработкой и рендеринге следующего, поэтому использование колеблется между 0 и 100%.Лишь в редких случаях число FPS ограничено максимальным числом, и только в этом случае это будет значимое число.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...