Поделиться через


Запросы данных производительности на стороне сервера

Правильная производительность отрисовки на сервере крайне важна для стабильной частоты кадров и обеспечения эффективного взаимодействия с пользовательским интерфейсом. Важно тщательно отслеживать характеристики производительности на сервере и при необходимости оптимизировать их. Данные производительности можно запрашивать с помощью выделенных функций API.

Наибольшее влияние на производительность отрисовки оказывают входные данные модели. Сведения о настройке входных данных см. в статье Настройка преобразования модели.

Производительность приложений на стороне клиента также может быть узким местом. Для подробного анализа производительности на стороне клиента рекомендуется использовать performance trace.

Временная шкала клиента и сервера

Прежде чем подробно ознакомиться с различными значениями задержки, стоит ознакомиться с точками синхронизации между клиентом и сервером на временная шкала:

Pipeline timeline

На рисунке показано как:

  • оценка положения запускается клиентом при постоянной частоте кадров 60 Гц (каждые 16,6 мс);
  • затем сервер запускает отрисовку на основе положения;
  • сервер отправляет обратно закодированное видеоизображение;
  • клиент декодирует изображение, выполняет над ним некоторую работу ЦП и GPU, а затем показывает образ.

Запросы данных о статистике кадров

В статистике кадров предоставлены некоторые важные сведения о последнем кадре, например задержка. Данные, предоставленные в структуре FrameStatistics, измеряются на стороне клиента, поэтому API является синхронным вызовом:

void QueryFrameData(RenderingSession session)
{
    FrameStatistics frameStatistics;
    if (session.GraphicsBinding.GetLastFrameStatistics(out frameStatistics) == Result.Success)
    {
        // do something with the result
    }
}
void QueryFrameData(ApiHandle<RenderingSession> session)
{
    FrameStatistics frameStatistics;
    if (session->GetGraphicsBinding()->GetLastFrameStatistics(&frameStatistics) == Result::Success)
    {
        // do something with the result
    }
}

Полученный объект FrameStatistics содержит следующие элементы:

Элемент Описание
LatencyPoseToReceive Задержка оценки положения камеры на устройстве клиента происходит до тех пор, пока кадр сервера для этого положения не будет полностью доступен клиентскому приложению. Это значение содержит цикл обращений по сети, время преобразования сервера для просмотра, сведения о декодировании видео и компенсации дрожания. См. интервал 1 на приведенной выше иллюстрации.
LatencyReceiveToPresent Задержка доступности полученного удаленного кадра происходит до тех пор, пока клиентское приложение не вызовет PresentFrame в ЦП. См. интервал 2 на приведенной выше иллюстрации.
LatencyPresentToDisplay Задержка предоставления кадра в ЦП происходит до тех пор, пока не загорится экран. Это значение содержит время GPU клиента, любую буферизацию кадров, выполняемую операционной системой, и время считывания данных с дисплея, зависящее от устройства. См. интервал 3 на приведенной выше иллюстрации.
TimeSinceLastPresent Время между последовательными вызовами PresentFrame в ЦП. Значения, превышающие длительность отображения (например, 16,6 мс на клиентском устройстве с частотой 60 Гц), указывают на проблемы, вызванные тем, что клиентское приложение не завершило рабочую нагрузку ЦП вовремя.
VideoFramesReceived Число кадров, полученных с сервера за последнюю секунду.
VideoFrameReusedCount Число полученных кадров за последнюю секунду, которые использовались на устройстве несколько раз. Ненулевые значения указывают на то, что кадры пришлось повторно использовать и репроецировать из-за дрожаний в сети или длительной отрисовки сервера.
VideoFramesSkipped Число полученных кадров за последнюю секунду, которые были декодированы, но не показаны на экране, так как поступил более новый кадр. Ненулевые значения указывают на то, что дрожание в сети привело к задержке нескольких кадров, а затем поступило на клиентское устройство вместе с пакетом.
VideoFramesDiscarded Очень похоже на videoFramesSkipped, но причина отмены заключается в том, что кадр поступил так поздно, что его уже нельзя коррелировать с каким-либо ожидающим положением. Если это не карта происходит, есть некоторые серьезные проблемы сети.
VideoFrameMinDelta Минимальное количество времени между двумя последовательными кадрами, поступающими за последнюю секунду. Вместе с VideoFrameMaxDelta этот диапазон указывает на дрожание, вызванное либо сетью, либо видеокодеком.
VideoFrameMaxDelta Максимальное количество времени между двумя последовательными кадрами, поступающими за последнюю секунду. Вместе с videoFrameMinDelta этот диапазон указывает на дрожание, вызванное либо сетью, либо видеокодеком.

Сумма всех значений задержки обычно гораздо больше, чем доступное время кадра с частотой 60 Гц. Это нормально, так как к нескольким кадрам предоставлен параллельный доступ, а новые запросы к кадрам запускаются с требуемой частотой, как показано на рисунке. Однако если задержка станет слишком большой, она повлияет на качество перепроецирования на позднем этапе и может нарушить общую работу.

VideoFramesReceived, VideoFrameReusedCount и VideoFramesDiscarded можно использовать для производительности сети и сервера датчика. Сочетание низкого VideoFramesReceived и высокого значения VideoFrameReusedCount может указывать на перегрузку сети или низкую производительность сервера. Высокое значение VideoFramesDiscarded также указывает на перегрузку сети.

Наконец, TimeSinceLastPresent, VideoFrameMinDelta и VideoFrameMaxDelta дают общее представление о вариантности входящих видеокадров и локальных текущих вызовах. Высокая вариантность означает нестабильную частоту кадров.

Ни одно из приведенных выше значений четко не указывает на чистую задержку сети (красные стрелки на рисунке), так как точное время выполнения отрисовки сервером необходимо вычесть из значения цикла LatencyPoseToReceive. Информация об общей задержке на стороне сервера недоступна для клиента. Однако следующий абзац объясняет, как это значение приблизительно через дополнительные входные данные с сервера и предоставляется через NetworkLatency значение.

Запросы для оценки производительности

Запросы для оценки производительности предоставляют более подробные сведения о рабочей нагрузке ЦП и GPU на сервере. Так как данные запрашиваются с сервера, запрос моментального снимка показателей производительности соответствует обычному асинхронному шаблону:

async void QueryPerformanceAssessment(RenderingSession session)
{
    try
    {
        PerformanceAssessment result = await session.Connection.QueryServerPerformanceAssessmentAsync();
        // do something with result...
    }
    catch (RRException ex)
    {
    }
}
void QueryPerformanceAssessment(ApiHandle<RenderingSession> session)
{
    session->Connection()->QueryServerPerformanceAssessmentAsync([](Status status, PerformanceAssessment result) {
        if (status == Status::OK)
        {
            // do something with result...
        }
    });
}

В отличие от объекта FrameStatistics, объект PerformanceAssessment содержит сведения на стороне сервера:

Элемент Описание
TimeCPU Среднее время ЦП сервера на кадр в миллисекундах
TimeGPU Среднее время GPU сервера на кадр в миллисекундах
UtilizationCPU Общее использование ЦП в процентах
UtilizationGPU Общее использование GPU в процентах
MemoryCPU Общее использование основной памяти сервера в процентах
MemoryGPU Общее использование выделенной видеопамяти в процентах на сервере GPU
NetworkLatency Приблизительная средняя цикличная задержка сети в миллисекундах. На приведенном выше рисунке значение соответствует сумме красных стрелок. Значение вычисляется путем вычитания фактического времени отрисовки на сервере из значения LatencyPoseToReceive в FrameStatistics. Хотя это приближение не является точным, он указывает на задержку сети, изолированную от значений задержки, вычисляемых на клиенте.
PolygonsRendered Число треугольников, преобразуемых для просмотра в одном кадре. Сюда также относятся треугольники, которые исключаются во время подготовки к просмотру. Это означает, что это число не зависит от разных позиций камеры, но производительность может резко отличаться в зависимости от скорости выбрасывания треугольника.
PointsRendered Количество точек в точках облаков, отрисованных в одном кадре. Те же критерии выбрасывания, что и упоминание выше для PolygonsRendered применения здесь.

Чтобы помочь вам оценить значения, у каждого из них есть классификация качества, например Great (Отлично), Good (Хорошо), Mediocre (Средне) или Bad (Плохо). Эта метрика оценки предоставляет грубое представление о работоспособности сервера, но оно не должно рассматриваться как абсолютное. Например, предположим, что для времени GPU отображается оценка Mediocre "Средне". Считается посредственным, потому что он приближается к ограничению для общего бюджета времени кадров. Однако в вашем случае это может быть хорошим значением, так как вы выполняете отрисовку сложной модели.

Выходные данные отладки статистики

Класс ServiceStatistics — это класс C#, который обтекает как статистику кадров, так и запросы для оценки производительности и предоставляет удобные функциональные возможности для возврата статистики в виде статистических значений или предварительно созданной строки. Следующий код является самым простым способом показать статистику на стороне сервера в клиентском приложении.

ServiceStatistics _stats = null;

void OnConnect()
{
    _stats = new ServiceStatistics();
}

void OnDisconnect()
{
    _stats = null;
}

void Update()
{
    if (_stats != null)
    {
        // update once a frame to retrieve new information and build average values
        _stats.Update(Service.CurrentActiveSession);

        // retrieve a string with relevant stats information
        InfoLabel.text = _stats.GetStatsString();
    }
}

Приведенный выше код заполняет текстовую метку следующим текстом:

ArrServiceStats string output

API GetStatsString форматирует строку всех значений, но каждое отдельное значение может также запрашиваться программно из экземпляра ServiceStatistics.

Существуют также варианты элементов, которые агрегируют значения с течением времени. Ознакомьтесь с элементами с суффиксом *Avg, *Max или *Total. Элемент FramesUsedForAverage указывает, сколько кадров использовалось для этого агрегирования.

Документация по API

Следующие шаги