Zapytania wydajności po stronie serwera

Dobra wydajność renderowania na serwerze ma kluczowe znaczenie dla stabilnych szybkości klatek i dobrego środowiska użytkownika. Ważne jest, aby dokładnie monitorować charakterystykę wydajności na serwerze i w razie potrzeby zoptymalizować. Dane wydajności mogą być odpytywane za pomocą dedykowanych funkcji interfejsu API.

Najbardziej wpływ na wydajność renderowania to dane wejściowe modelu. Dane wejściowe można dostosować zgodnie z opisem w temacie Konfigurowanie konwersji modelu.

Wydajność aplikacji po stronie klienta może być również wąskim gardłem. Aby uzyskać szczegółową analizę wydajności po stronie klienta, zaleca się wykonanie operacji performance trace.

Oś czasu klienta/serwera

Zanim przejdziesz do szczegółów dotyczących różnych wartości opóźnienia, warto zapoznać się z punktami synchronizacji między klientem a serwerem na osi czasu:

Pipeline timeline

Na ilustracji pokazano, jak:

  • Oszacowanie pose jest uruchamiane przez klienta z stałą szybkością klatek 60-Hz (co 16,6 ms)
  • następnie serwer uruchamia renderowanie na podstawie pozy
  • serwer wysyła z powrotem zakodowany obraz wideo
  • klient dekoduje obraz, wykonuje niektóre operacje procesora CPU i procesora GPU na nim, a następnie wyświetla obraz

Zapytania statystyk ramek

Statystyki ramek zapewniają pewne informacje wysokiego poziomu dla ostatniej ramki, takie jak opóźnienie. Dane podane w FrameStatistics strukturze są mierzone po stronie klienta, więc interfejs API jest synchronicznym wywołaniem:

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
    }
}

Pobrany FrameStatistics obiekt zawiera następujące elementy członkowskie:

Element członkowski Wyjaśnienie
OpóźnieniePoseToReceive Opóźnienie z aparatu stanowi oszacowanie na urządzeniu klienckim, dopóki ramka serwera dla tej pozy jest w pełni dostępna dla aplikacji klienckiej. Ta wartość obejmuje roundtrip sieci, czas renderowania serwera, dekodowanie wideo i kompensację zakłócenia. Zobacz interwał 1 na powyższej ilustracji.
OpóźnienieReceiveToPresent Opóźnienie z dostępności odebranej ramki zdalnej do momentu wywołania elementu PresentFrame przez aplikację kliencką na procesorze CPU. Zobacz interwał 2 na powyższej ilustracji.
LatencyPresentToDisplay Opóźnienie podczas prezentowania ramki na procesorze do momentu zaświetlania wyświetlacza. Ta wartość obejmuje czas procesora GPU klienta, buforowanie ramek wykonywane przez system operacyjny, ponowne projekty sprzętowe i czas skanowania wyświetlania zależnego od urządzenia. Zobacz interwał 3 na powyższej ilustracji.
TimeSinceLastPresent Czas między kolejnymi wywołaniami elementu PresentFrame na procesorze CPU. Wartości większe niż czas trwania wyświetlania (na przykład 16,6 ms na urządzeniu klienckim 60-Hz) wskazują problemy spowodowane przez aplikację kliencką, która nie kończy obciążenia procesora CPU w czasie.
VideoFramesReceived Liczba ramek odebranych z serwera w ciągu ostatniej sekundy.
VideoFrameReusedCount Liczba odebranych ramek w ciągu ostatniej sekundy, które były używane na urządzeniu więcej niż raz. Wartości inne niż zero wskazują, że ramki musiały być ponownie używane i ponownie projektowane z powodu zakłócenia sieci lub nadmiernego czasu renderowania serwera.
VideoFramesSkipped Liczba odebranych ramek w ciągu ostatniej sekundy, które zostały zdekodowane, ale nie są wyświetlane na wyświetlaczu, ponieważ przybyła nowsza ramka. Wartości inne niż zero wskazują, że zakłócenia sieci spowodowały opóźnienie wielu ramek, a następnie przybyć na urządzeniu klienckim razem w serii.
VideoFramesDiscarded Bardzo podobne do VideoFramesSkipped, ale powodem odrzucenia jest to, że ramka pojawiła się tak późno, że nie może być nawet skorelowana z żadną oczekującą pozą. W przypadku tego odrzucenia występuje poważna rywalizacja sieciowa.
VideoFrameMinDelta Minimalny czas między dwoma kolejnymi ramkami przybywającymi w ciągu ostatniej sekundy. Wraz z videoFrameMaxDelta ten zakres wskazuje na zakłócenia spowodowane przez sieć lub koder wideo.
VideoFrameMaxDelta Maksymalny czas między dwoma kolejnymi ramkami przybywającymi w ciągu ostatniej sekundy. Wraz z elementem VideoFrameMinDelta ten zakres wskazuje na zakłócenia spowodowane przez sieć lub koder wideo.

Suma wszystkich wartości opóźnienia jest zwykle znacznie większa niż dostępny czas ramki na 60 Hz. Jest to ok, ponieważ wiele ramek jest w locie równolegle, a nowe żądania klatek są uruchamiane z żądaną szybkością klatek, jak pokazano na ilustracji. Jednak jeśli opóźnienie stanie się zbyt duże, wpływa na jakość ponownego projektu na późnym etapie i może naruszyć ogólne środowisko.

VideoFramesReceived, VideoFrameReusedCounti VideoFramesDiscarded może służyć do pomiaru wydajności sieci i serwera. Połączenie niskiej VideoFramesReceived wartości i wysokiej VideoFrameReusedCount wartości może wskazywać na przeciążenie sieci lub niską wydajność serwera. Wysoka VideoFramesDiscarded wartość wskazuje również przeciążenie sieci.

Na koniecTimeSinceLastPresent, VideoFrameMinDelta, i VideoFrameMaxDelta dać pojęcie wariancji przychodzących ramek wideo i lokalnych obecnych wywołań. Wysoka wariancja oznacza szybkość ramki w tabeli.

Żadna z powyższych wartości nie wskazuje na czyste opóźnienie sieci (czerwone strzałki na ilustracji), ponieważ dokładny czas, w jaki serwer jest zajęty renderowaniem, musi zostać odjęty od wartości LatencyPoseToReceivedwukierunkowej . Część ogólnego opóźnienia po stronie serwera to informacje, które są niedostępne dla klienta. W następnym akapicie wyjaśniono jednak, w jaki sposób ta wartość jest przybliżona przez dodatkowe dane wejściowe z serwera i uwidoczniona za pośrednictwem NetworkLatency wartości.

Zapytania dotyczące oceny wydajności

Zapytania dotyczące oceny wydajności zawierają bardziej szczegółowe informacje o obciążeniu procesora CPU i procesora GPU na serwerze. Ponieważ dane są żądane z serwera, wykonywanie zapytań dotyczących migawki wydajności jest zgodne ze zwykłym wzorcem asynchronicznym:

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...
        }
    });
}

W przeciwieństwie do FrameStatistics obiektu obiekt PerformanceAssessment zawiera informacje po stronie serwera:

Element członkowski Wyjaśnienie
TimeCPU Średni czas procesora CPU serwera na ramkę w milisekundach
TimeGPU Średni czas procesora GPU serwera na ramkę w milisekundach
Użycie procesora CPUU Łączne wykorzystanie procesora CPU serwera w procentach
Użycie procesoraGPU Łączne wykorzystanie procesora GPU serwera w procentach
Procesor pamięci Całkowite wykorzystanie pamięci głównej serwera w procentach
PamięćGPU Całkowite wykorzystanie pamięci wideo w procentach procesora GPU serwera
Opóźnienie sieci Przybliżone średnie opóźnienie sieci w obie strony w milisekundach. Na powyższej ilustracji ta wartość odpowiada sumie czerwonych strzałek. Wartość jest obliczana przez odjęcie rzeczywistego LatencyPoseToReceiveFrameStatisticsczasu renderowania serwera z wartości . Chociaż to przybliżenie nie jest dokładne, daje pewne wskazanie opóźnienia sieci, odizolowane od wartości opóźnień obliczonych na kliencie.
WielokątyRenderowane Liczba trójkątów renderowanych w jednej ramce. Ta liczba obejmuje również trójkąty, które zostaną później uśmierczone podczas renderowania. Oznacza to, że ta liczba nie różni się znacznie w różnych pozycjach aparatu, ale wydajność może się znacząco różnić, w zależności od współczynnika uścisk trójkąta.
PointRendered Liczba punktów w chmurach punktowych renderowanych w jednej ramce. Te same kryteria uboju, jak wspomniano powyżej, mają PolygonsRendered zastosowanie tutaj.

Aby ułatwić ocenę wartości, każda część zawiera klasyfikację jakości, na przykład Great, Good, Mediocre lub Bad. Ta metryka oceny zapewnia przybliżone wskazanie kondycji serwera, ale nie powinna być postrzegana jako bezwzględna. Załóżmy na przykład, że zobaczysz wynik "przeciętny" dla czasu procesora GPU. Jest to uważane za przeciętne, ponieważ zbliża się do limitu ogólnego budżetu czasu. Jednak w Twoim przypadku może to być dobra wartość, ponieważ renderujesz złożony model.

Dane wyjściowe debugowania statystyk

Klasa jest klasą ServiceStatistics języka C#, która opakowuje zarówno statystyki ramki, jak i zapytania oceny wydajności oraz zapewnia wygodne funkcje zwracania statystyk jako zagregowanych wartości lub jako wstępnie skompilowanego ciągu. Poniższy kod jest najprostszym sposobem wyświetlania statystyk po stronie serwera w aplikacji klienckiej.

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();
    }
}

Powyższy kod wypełnia etykietę tekstową następującym tekstem:

ArrServiceStats string output

Interfejs GetStatsString API formatuje ciąg wszystkich wartości, ale każda pojedyncza wartość może być również odpytywane programowo z ServiceStatistics wystąpienia.

Istnieją również warianty elementów członkowskich, które agregują wartości w czasie. Zobacz elementy członkowskie z sufiksem *Avg, *Maxlub *Total. Element członkowski FramesUsedForAverage wskazuje, ile ramek zostało użytych do tej agregacji.

Dokumentacja interfejsu API

Następne kroki