mirror of
https://github.com/kuhyx/praca_magisterska.git
synced 2026-07-04 13:43:05 +02:00
fix: hbox testy wydajnosci
This commit is contained in:
parent
7404b1c173
commit
eb2422c45c
BIN
latex/main.pdf
BIN
latex/main.pdf
Binary file not shown.
@ -140,7 +140,7 @@ Game development, Frame time, Engine architecture, Version control, GPU
|
|||||||
\input{tex/wywiady-analiza}
|
\input{tex/wywiady-analiza}
|
||||||
\input{tex/implementacja-gry} % Analiza wywiadów z deweloperami gier
|
\input{tex/implementacja-gry} % Analiza wywiadów z deweloperami gier
|
||||||
\input{tex/narzedzia-profilowania} % Narzędzia profilowania wydajności
|
\input{tex/narzedzia-profilowania} % Narzędzia profilowania wydajności
|
||||||
%\input{tex/5-testy-wydajnosci} % Testy wydajności
|
\input{tex/5-testy-wydajnosci} % Testy wydajności
|
||||||
% \input{tex/6-analiza-mozliwosci} % Analiza możliwości i funkcjonalności
|
% \input{tex/6-analiza-mozliwosci} % Analiza możliwości i funkcjonalności
|
||||||
% \input{tex/7-porownanie-wynikow} % Porównanie wyników i analiza
|
% \input{tex/7-porownanie-wynikow} % Porównanie wyników i analiza
|
||||||
% \input{tex/8-podsumowanie}
|
% \input{tex/8-podsumowanie}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Dla każdego scenariusza i~silnika rejestrowano następujące metryki przy użyc
|
|||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Czas klatki} (frame time) -- czas renderowania pojedynczej klatki w~milisekundach
|
\item \textbf{Czas klatki} (frame time) -- czas renderowania pojedynczej klatki w~milisekundach
|
||||||
\item \textbf{FPS} (frames per second) -- liczba klatek na sekundę, wyliczana jako $1000 / \text{frame time}$
|
\item \textbf{FPS} (frames per second) -- liczba klatek na sekundę, wyliczana jako \\ $1000 / \text{frame time}$
|
||||||
\item \textbf{Wykorzystanie GPU} -- procent wykorzystania mocy obliczeniowej karty graficznej
|
\item \textbf{Wykorzystanie GPU} -- procent wykorzystania mocy obliczeniowej karty graficznej
|
||||||
\item \textbf{Zużycie pamięci VRAM} -- ilość zajętej pamięci karty graficznej w~megabajtach
|
\item \textbf{Zużycie pamięci VRAM} -- ilość zajętej pamięci karty graficznej w~megabajtach
|
||||||
\item \textbf{Liczba wywołań rysowania} (draw calls) -- liczba instrukcji renderowania na klatkę
|
\item \textbf{Liczba wywołań rysowania} (draw calls) -- liczba instrukcji renderowania na klatkę
|
||||||
@ -20,17 +20,24 @@ Dla każdego scenariusza i~silnika rejestrowano następujące metryki przy użyc
|
|||||||
\subsection{Wyniki testów dla silnika Unity}
|
\subsection{Wyniki testów dla silnika Unity}
|
||||||
\label{subsec:wyniki-unity}
|
\label{subsec:wyniki-unity}
|
||||||
|
|
||||||
Profilowanie silnika Unity przeprowadzono przy użyciu narzędzia NVIDIA Nsight Systems w wersji 2025.5.2, które umożliwia szczegółową analizę wywołań
|
Profilowanie silnika Unity przeprowadzono przy użyciu narzędzia NVIDIA Nsight Systems w wersji 2025.5.2,
|
||||||
API graficznych oraz funkcji systemowych na poziomie pojedynczych mikrosekund. Test trwał 95 sekund, podczas których gra działała w
|
które umożliwia szczegółową analizę wywołań
|
||||||
trybie stacjonarnym (gracz nieruchomy) z włączoną nieśmiertelnością, co pozwoliło na stabilne pomiary bez przerwania rozgrywki.
|
API graficznych oraz funkcji systemowych na poziomie pojedynczych mikrosekund. Test trwał 95 sekund,
|
||||||
|
podczas których gra działała w
|
||||||
|
trybie stacjonarnym (gracz nieruchomy) z włączoną nieśmiertelnością, co pozwoliło na stabilne pomiary
|
||||||
|
bez przerwania rozgrywki.
|
||||||
|
|
||||||
\subsubsection{Ogólne wyniki wydajności}
|
\subsubsection{Ogólne wyniki wydajności}
|
||||||
|
|
||||||
Podczas 94,16-sekundowego okresu aktywnego renderowania zarejestrowano łącznie 13\,556 klatek, co przekłada się na średnią wydajność
|
Podczas 94,16-sekundowego okresu aktywnego renderowania zarejestrowano łącznie 13\,556 klatek,
|
||||||
\textbf{143,96 klatek na sekundę} (FPS). Jest to wynik znacząco przewyższający standardowy cel wydajnościowy 60 FPS dla aplikacji
|
co przekłada się na średnią wydajność
|
||||||
interaktywnych, wskazujący na bardzo dobrą optymalizację silnika Unity dla testowanej sceny.
|
\textbf{143,96 klatek na sekundę} (FPS). Wartość ta niemal dokładnie odpowiada częstotliwości
|
||||||
|
odświeżania monitora testowego (144 Hz),
|
||||||
|
co wskazuje na \textbf{włączoną synchronizację pionową} (V-Sync) podczas testu. Oznacza to,
|
||||||
|
że zmierzona wydajność reprezentuje
|
||||||
|
górny limit narzucony przez monitor, a nie rzeczywistą maksymalną wydajność silnika Unity.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Ogólne metryki wydajności silnika Unity}
|
\caption{Ogólne metryki wydajności silnika Unity}
|
||||||
\label{tab:unity-performance-summary}
|
\label{tab:unity-performance-summary}
|
||||||
@ -50,25 +57,33 @@ Współczynnik zmienności & 153,24\% \\
|
|||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
Tabela~\ref{tab:unity-performance-summary} przedstawia podstawowe metryki wydajności. Średni czas klatki wynoszący 6,95 ms oznacza, że silnik
|
Tabela~\ref{tab:unity-performance-summary} przedstawia podstawowe metryki wydajności. Średni czas
|
||||||
Unity jest w stanie wyrenderować pojedynczą klatkę w czasie znacznie krótszym niż wymagane 16,67 ms dla osiągnięcia 60 FPS. Minimalny czas
|
klatki wynoszący 6,95 ms oznacza, że silnik
|
||||||
klatki 0,08 ms odpowiada sytuacjom, gdy kolejne wywołania prezentacji następują niemal natychmiast po sobie -- może to wynikać z mechanizmu
|
Unity jest w stanie wyrenderować pojedynczą klatkę w czasie znacznie krótszym niż wymagane 16,67 ms
|
||||||
|
dla osiągnięcia 60 FPS. Minimalny czas
|
||||||
|
klatki 0,08 ms odpowiada sytuacjom, gdy kolejne wywołania prezentacji następują niemal natychmiast po
|
||||||
|
sobie -- może to wynikać z mechanizmu
|
||||||
podwójnego buforowania (ang. \textit{double buffering}) lub chwilowego braku pracy do wykonania przez GPU.
|
podwójnego buforowania (ang. \textit{double buffering}) lub chwilowego braku pracy do wykonania przez GPU.
|
||||||
|
|
||||||
Wartość maksymalna 1\,239,62 ms (ponad sekunda) wymaga szczególnej uwagi. Tak długi czas klatki występuje podczas fazy inicjalizacji aplikacji,
|
Wartość maksymalna 1\,239,62 ms (ponad sekunda) występuje podczas \\ fazy inicjalizacji aplikacji,
|
||||||
gdy silnik Unity wykonuje jednorazowe operacje: kompilację shaderów, alokację dużych bloków pamięci GPU, tworzenie obiektów swapchain oraz
|
gdy silnik Unity wykonuje jednorazowe \\ operacje: kompilację shaderów, alokację dużych bloków pamięci \\ GPU,
|
||||||
inicjalizację systemu renderowania. Jest to zachowanie typowe dla aplikacji Vulkan, gdzie znaczna część pracy inicjalizacyjnej wykonywana jest przy
|
tworzenie obiektów swapchain oraz
|
||||||
starcie, w przeciwieństwie do OpenGL, gdzie inicjalizacja jest bardziej rozłożona w czasie.
|
inicjalizację systemu renderowania. \\ Jest to zachowanie typowe dla aplikacji Vulkan, gdzie znaczna część
|
||||||
|
pracy inicjalizacyjnej wykonywana jest przy
|
||||||
|
starcie, w przeciwieństwie \\ do OpenGL, gdzie inicjalizacja jest bardziej rozłożona w czasie.
|
||||||
|
|
||||||
Współczynnik zmienności (CV) wynoszący 153,24\% jest wysoki, jednak wynika on głównie z uwzględnienia ekstremalnych wartości inicjalizacyjnych.
|
Współczynnik zmienności (CV) wynoszący 153,24\% jest wysoki, jednak wynika on głównie z
|
||||||
Po wykluczeniu pierwszych kilku klatek, stabilność renderowania jest znacznie wyższa, co potwierdza analiza percentylowa przedstawiona w dalszej części.
|
uwzględnienia ekstremalnych wartości inicjalizacyjnych.
|
||||||
|
Po wykluczeniu pierwszych kilku klatek, stabilność renderowania jest znacznie wyższa, co potwierdza
|
||||||
|
analiza percentylowa przedstawiona w dalszej części.
|
||||||
|
|
||||||
\subsubsection{Analiza rozkładu czasów klatek}
|
\subsubsection{Analiza rozkładu czasów klatek}
|
||||||
|
|
||||||
Szczegółowa analiza rozkładu czasów klatek pozwala ocenić nie tylko średnią wydajność, ale przede wszystkim stabilność i przewidywalność działania
|
Szczegółowa analiza rozkładu czasów klatek pozwala ocenić nie tylko średnią wydajność, ale przede
|
||||||
|
wszystkim stabilność i przewidywalność działania
|
||||||
silnika -- aspekty kluczowe dla komfortu odbiorcy gry.
|
silnika -- aspekty kluczowe dla komfortu odbiorcy gry.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Rozkład percentylowy czasów klatek silnika Unity}
|
\caption{Rozkład percentylowy czasów klatek silnika Unity}
|
||||||
\label{tab:unity-percentiles}
|
\label{tab:unity-percentiles}
|
||||||
@ -87,19 +102,28 @@ silnika -- aspekty kluczowe dla komfortu odbiorcy gry.
|
|||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
Tabela~\ref{tab:unity-percentiles} prezentuje rozkład percentylowy czasów klatek. \textbf{Mediana} (50. percentyl) wynosząca 6,94 ms jest niemal
|
Tabela~\ref{tab:unity-percentiles} prezentuje rozkład percentylowy czasów klatek. \textbf{Mediana}
|
||||||
identyczna ze średnią arytmetyczną (6,95 ms), co wskazuje na symetryczny rozkład czasów klatek w normalnych warunkach pracy. W praktyce oznacza to,
|
(50. percentyl) wynosząca 6,94 ms jest niemal
|
||||||
że typowa klatka renderowana jest w czasie bardzo zbliżonym do wartości średniej.
|
identyczna z teoretycznym czasem klatki przy 144 Hz (6,944 ms), co potwierdza aktywną
|
||||||
|
synchronizację pionową. Wąski rozstęp między 5. percentylem
|
||||||
|
(6,69 ms, 149 FPS) a 95. percentylem (7,18 ms, 139 FPS) -- zaledwie 0,49 ms --
|
||||||
|
jest charakterystyczny dla V-Sync, gdzie czas klatki jest
|
||||||
|
sztucznie stabilizowany przez oczekiwanie na sygnał odświeżania monitora.
|
||||||
|
|
||||||
Szczególnie istotny jest \textbf{99. percentyl} wynoszący 7,58 ms. Wartość ta, określana w środowisku graczy jako ,,1\% low'', reprezentuje wydajność
|
Szczególnie istotny jest \textbf{99. percentyl} wynoszący 7,58 ms, określany w środowisku graczy
|
||||||
w najgorszych 1\% przypadków. Różnica między medianą (6,94 ms) a 99. percentylem (7,58 ms) wynosi zaledwie 0,64 ms (9,2\%), co świadczy o
|
jako ,,1\% low'' (132 FPS). Wartość ta reprezentuje
|
||||||
\textbf{wyjątkowej stabilności} renderowania. Dla porównania, w wielu grach różnica ta przekracza 50\%, co objawia się zauważalnymi ,,przycięciami''
|
wydajność w najgorszych 1\% przypadków i jest kluczową metryką dla oceny płynności rozgrywki.
|
||||||
obrazu.
|
Różnica między medianą (6,94 ms) a 99. percentylem
|
||||||
|
(7,58 ms) wynosi 0,64 ms (9,2\%). Należy jednak zauważyć, że niska zmienność jest częściowo
|
||||||
|
wynikiem działania V-Sync, który stabilizuje
|
||||||
|
czas klatki kosztem wprowadzenia opóźnienia wejścia (ang. \textit{input lag}).
|
||||||
|
|
||||||
\textbf{Rozstęp międzykwartylowy} (IQR), czyli różnica między 75. a 25. percentylem, wynosi zaledwie 0,08 ms. Tak niski IQR potwierdza, że 50\%
|
\textbf{Rozstęp międzykwartylowy} (IQR), czyli różnica między 75. a 25. percentylem, wynosi zaledwie
|
||||||
środkowych czasów klatek mieści się w niezwykle wąskim przedziale, co jest oznaką deterministycznego i przewidywalnego zachowania potoku renderowania.
|
0,08 ms. Tak niski IQR potwierdza, że 50\%
|
||||||
|
środkowych czasów klatek mieści się w niezwykle wąskim przedziale, co jest oznaką deterministycznego i
|
||||||
|
przewidywalnego zachowania potoku renderowania.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Histogram czasów klatek silnika Unity}
|
\caption{Histogram czasów klatek silnika Unity}
|
||||||
\label{tab:unity-histogram}
|
\label{tab:unity-histogram}
|
||||||
@ -116,11 +140,15 @@ obrazu.
|
|||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
Histogram przedstawiony w tabeli~\ref{tab:unity-histogram} dostarcza dodatkowego wglądu w rozkład wydajności. \textbf{98,24\% wszystkich klatek}
|
Histogram przedstawiony w tabeli~\ref{tab:unity-histogram} dostarcza dodatkowego wglądu w rozkład
|
||||||
zostało wyrenderowanych w czasie 5--10 ms, co odpowiada wydajności 100--200 FPS. Jedynie 8 klatek (0,06\%) przekroczyło próg 10 ms, przy czym klatki
|
wydajności. \textbf{98,24\% wszystkich klatek}
|
||||||
poniżej 60 FPS (>16,67 ms) stanowiły zaledwie 0,02\% -- praktycznie wszystkie z nich przypadły na fazę inicjalizacji.
|
zostało wyrenderowanych w czasie 5--10 ms, co odpowiada wydajności 100--200 FPS. Jedynie 8 klatek
|
||||||
|
(0,06\%) przekroczyło próg 10 ms, przy czym klatki
|
||||||
|
poniżej 60 FPS (>16,67 ms) stanowiły zaledwie 0,02\% -- praktycznie wszystkie z nich przypadły na fazę
|
||||||
|
inicjalizacji.
|
||||||
|
|
||||||
Kategoria 0--5 ms (230 klatek, 1,70\%) reprezentuje sytuacje szczególne: bardzo szybkie klatki podczas przejść między scenami, momenty niskiego
|
Kategoria 0--5 ms (230 klatek, 1,70\%) reprezentuje sytuacje szczególne: bardzo szybkie klatki podczas
|
||||||
|
przejść między scenami, momenty niskiego
|
||||||
obciążenia lub artefakty pomiarowe wynikające z mechanizmu synchronizacji swapchain.
|
obciążenia lub artefakty pomiarowe wynikające z mechanizmu synchronizacji swapchain.
|
||||||
|
|
||||||
\subsubsection{Szczegółowa analiza wywołań Vulkan API}
|
\subsubsection{Szczegółowa analiza wywołań Vulkan API}
|
||||||
@ -128,7 +156,7 @@ obciążenia lub artefakty pomiarowe wynikające z mechanizmu synchronizacji swa
|
|||||||
NVIDIA Nsight Systems przechwytuje wszystkie wywołania interfejsu programistycznego Vulkan, umożliwiając dokładną analizę zachowania silnika
|
NVIDIA Nsight Systems przechwytuje wszystkie wywołania interfejsu programistycznego Vulkan, umożliwiając dokładną analizę zachowania silnika
|
||||||
renderującego na poziomie pojedynczych funkcji API. Podczas testu zarejestrowano łącznie \textbf{218\,815 wywołań} 31 różnych funkcji Vulkan API.
|
renderującego na poziomie pojedynczych funkcji API. Podczas testu zarejestrowano łącznie \textbf{218\,815 wywołań} 31 różnych funkcji Vulkan API.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania Vulkan API silnika Unity -- funkcje synchronizacji i prezentacji}
|
\caption{Wywołania Vulkan API silnika Unity -- funkcje synchronizacji i prezentacji}
|
||||||
\label{tab:unity-vulkan-sync}
|
\label{tab:unity-vulkan-sync}
|
||||||
@ -146,30 +174,37 @@ renderującego na poziomie pojedynczych funkcji API. Podczas testu zarejestrowan
|
|||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
\paragraph{Funkcja vkWaitForFences -- synchronizacja CPU-GPU}
|
\paragraph{Funkcja vkWaitForFences -- synchronizacja CPU-GPU}
|
||||||
|
\texttt{vkWaitForFences} \\ pochłonęła \textbf{95,2\% całkowitego czasu}
|
||||||
Funkcja \texttt{vkWaitForFences} pochłonęła \textbf{95,2\% całkowitego czasu} profilowania wywołań Vulkan API, co stanowi 77,04 sekundy z
|
profilowania wywołań Vulkan API, co stanowi 77,04 sekundy z
|
||||||
94-sekundowego testu. Funkcja ta, zdefiniowana w specyfikacji Vulkan w rozdziale 7.3 dotyczącym synchronizacji, realizuje blokujące oczekiwanie
|
94-sekundowego testu. Funkcja ta, zdefiniowana w specyfikacji Vulkan w rozdziale 7.3 dotyczącym
|
||||||
|
synchronizacji, realizuje blokujące oczekiwanie
|
||||||
procesora na sygnalizację obiektów ogrodzenia (ang. \textit{fence}) przez GPU.
|
procesora na sygnalizację obiektów ogrodzenia (ang. \textit{fence}) przez GPU.
|
||||||
|
|
||||||
Mechanizm ogrodzeń w Vulkan działa następująco: aplikacja tworzy obiekt fence, dołącza go do operacji przesyłanej do kolejki GPU
|
Mechanizm ogrodzeń w Vulkan działa następująco: aplikacja tworzy \\ obiekt fence,
|
||||||
(np. poprzez \texttt{vkQueueSubmit}), a następnie może wywołać \texttt{vkWaitForFences}, aby zablokować wątek CPU do momentu zakończenia
|
dołącza go do operacji przesyłanej do kolejki GPU \\
|
||||||
powiązanej pracy przez GPU. Jest to fundamentalny mechanizm synchronizacji w architekturze producent-konsument między CPU a GPU.
|
(np. poprzez \texttt{vkQueueSubmit}), a następnie może \\wywołać \texttt{vkWaitForFences},
|
||||||
|
aby zablokować wątek CPU do momentu zakończenia
|
||||||
|
powiązanej pracy przez GPU. Jest to fundamentalny mechanizm synchronizacji w architekturze
|
||||||
|
producent-konsument między CPU a GPU.
|
||||||
|
|
||||||
Tak wysoki udział procentowy (95,2\%) jednoznacznie wskazuje na scenariusz \textbf{ograniczenia wydajności przez GPU} (ang. \textit{GPU-bound}).
|
Tak wysoki udział procentowy (95,2\%) jednoznacznie wskazuje na scenariusz \textbf{ograniczenia wydajności przez GPU} (ang. \textit{GPU-bound}).
|
||||||
W tym scenariuszu procesor główny zakończył przygotowywanie i przesyłanie poleceń renderowania, a następnie oczekuje na ukończenie ich wykonania
|
W tym scenariuszu procesor główny zakończył przygotowywanie i przesyłanie poleceń renderowania, a następnie oczekuje na ukończenie ich wykonania
|
||||||
przez kartę graficzną. Jest to pożądany wzorzec w dobrze zoptymalizowanych aplikacjach graficznych -- procesor nie stanowi wąskiego gardła i
|
przez kartę graficzną. Jest to pożądany wzorzec w dobrze zoptymalizowanych aplikacjach graficznych -- procesor nie stanowi wąskiego gardła i
|
||||||
zdąża przygotować pracę dla GPU przed zakończeniem poprzedniej klatki.
|
zdąża przygotować pracę dla GPU przed zakończeniem poprzedniej klatki.
|
||||||
|
|
||||||
Średni czas pojedynczego wywołania wyniósł 5,97 ms przy medianie 6,23 ms. Różnica między średnią a medianą (0,26 ms) wynika z obecności bardzo krótkich
|
Średni czas pojedynczego wywołania wyniósł 5,97 ms przy medianie 6,23 ms.
|
||||||
czasów oczekiwania w niektórych sytuacjach (np. gdy GPU zakończył pracę przed wywołaniem wait). Maksymalny czas 1\,181,17 ms odpowiada fazie
|
Różnica między średnią a medianą (0,26 ms) wynika z obecności bardzo krótkich
|
||||||
inicjalizacji, podczas której GPU wykonuje jednorazowe, kosztowne operacje.
|
czasów oczekiwania w niektórych sytuacjach (np. gdy GPU zakończył pracę przed wywołaniem wait).
|
||||||
|
Maksymalny czas 1\,181,17 ms odpowiada fazie
|
||||||
|
inicjalizacji, \\ podczas której GPU wykonuje jednorazowe, kosztowne operacje.
|
||||||
|
|
||||||
Stosunek liczby wywołań \texttt{vkWaitForFences} (12\,895) do liczby klatek (13\,556) wskazuje, że Unity stosuje strategię oczekiwania, prawie na
|
Stosunek liczby wywołań \texttt{vkWaitForFences} (12\,895) do liczby klatek (13\,556) wskazuje, że
|
||||||
|
Unity stosuje strategię oczekiwania, prawie na
|
||||||
każdą klatkę z pewnymi optymalizacjami pozwalającymi pominąć oczekiwanie w niektórych przypadkach.
|
każdą klatkę z pewnymi optymalizacjami pozwalającymi pominąć oczekiwanie w niektórych przypadkach.
|
||||||
|
|
||||||
\paragraph{Funkcja vkQueuePresentKHR -- prezentacja klatek}
|
\paragraph{Funkcja vkQueuePresentKHR -- prezentacja klatek}
|
||||||
|
|
||||||
Funkcja \texttt{vkQueuePresentKHR}, zdefiniowana w rozszerzeniu \texttt{VK\_KHR\_swapchain}, odpowiada za przesłanie żądania prezentacji
|
\texttt{vkQueuePresentKHR}, zdefiniowana w rozszerzeniu \texttt{VK\_KHR\_swapchain}, odpowiada za przesłanie żądania prezentacji
|
||||||
wyrenderowanego obrazu do silnika prezentacji (ang. \textit{presentation engine}). Każde wywołanie tej funkcji reprezentuje jedną klatkę przekazaną
|
wyrenderowanego obrazu do silnika prezentacji (ang. \textit{presentation engine}). Każde wywołanie tej funkcji reprezentuje jedną klatkę przekazaną
|
||||||
do wyświetlenia, dlatego liczba wywołań (13\,556) równa jest liczbie wyrenderowanych klatek.
|
do wyświetlenia, dlatego liczba wywołań (13\,556) równa jest liczbie wyrenderowanych klatek.
|
||||||
|
|
||||||
@ -186,7 +221,7 @@ oznacza średnio 2 wywołania na klatkę. Taki wzorzec sugeruje, że Unity stosu
|
|||||||
Niski średni czas (0,03 ms) potwierdza, że \texttt{vkQueueSubmit} jedynie kolejkuje pracę bez oczekiwania na jej wykonanie -- faktyczne renderowanie
|
Niski średni czas (0,03 ms) potwierdza, że \texttt{vkQueueSubmit} jedynie kolejkuje pracę bez oczekiwania na jej wykonanie -- faktyczne renderowanie
|
||||||
odbywa się asynchronicznie na GPU.
|
odbywa się asynchronicznie na GPU.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania Vulkan API silnika Unity -- bufory poleceń}
|
\caption{Wywołania Vulkan API silnika Unity -- bufory poleceń}
|
||||||
\label{tab:unity-vulkan-cmd}
|
\label{tab:unity-vulkan-cmd}
|
||||||
@ -206,7 +241,8 @@ odbywa się asynchronicznie na GPU.
|
|||||||
|
|
||||||
\paragraph{Nagrywanie buforów poleceń}
|
\paragraph{Nagrywanie buforów poleceń}
|
||||||
|
|
||||||
Tabela~\ref{tab:unity-vulkan-cmd} przedstawia statystyki funkcji związanych z buforami poleceń. Liczba wywołań \texttt{vkBeginCommandBuffer} i
|
Tabela~\ref{tab:unity-vulkan-cmd} przedstawia statystyki funkcji związanych z buforami poleceń.
|
||||||
|
Liczba wywołań \texttt{vkBeginCommandBuffer} \\ oraz
|
||||||
\texttt{vkEndCommandBuffer} (po 40\,679) oznacza, że Unity nagrywa średnio 3 bufory poleceń na klatkę. Jest to typowa wartość dla nowoczesnych
|
\texttt{vkEndCommandBuffer} (po 40\,679) oznacza, że Unity nagrywa średnio 3 bufory poleceń na klatkę. Jest to typowa wartość dla nowoczesnych
|
||||||
silników stosujących wielowątkowe nagrywanie poleceń.
|
silników stosujących wielowątkowe nagrywanie poleceń.
|
||||||
|
|
||||||
@ -216,7 +252,7 @@ operacji. Wysoka liczba wywołań wskazuje na staranną kontrolę zależności m
|
|||||||
\texttt{vkCmdBindPipeline} (27\,027 wywołań, ~2 na klatkę) przełącza aktywny stan potoku graficznego. Relatywnie niska liczba wywołań sugeruje efektywne
|
\texttt{vkCmdBindPipeline} (27\,027 wywołań, ~2 na klatkę) przełącza aktywny stan potoku graficznego. Relatywnie niska liczba wywołań sugeruje efektywne
|
||||||
grupowanie obiektów według używanego potoku, minimalizując kosztowne zmiany stanu.
|
grupowanie obiektów według używanego potoku, minimalizując kosztowne zmiany stanu.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania Vulkan API silnika Unity -- inicjalizacja i zasoby}
|
\caption{Wywołania Vulkan API silnika Unity -- inicjalizacja i zasoby}
|
||||||
\label{tab:unity-vulkan-init}
|
\label{tab:unity-vulkan-init}
|
||||||
@ -243,7 +279,8 @@ Tabela~\ref{tab:unity-vulkan-init} przedstawia jednorazowe operacje inicjalizacy
|
|||||||
urządzenie Vulkan -- jest to najdroższa pojedyncza operacja, obejmująca negocjację możliwości GPU, alokację struktur wewnętrznych sterownika i
|
urządzenie Vulkan -- jest to najdroższa pojedyncza operacja, obejmująca negocjację możliwości GPU, alokację struktur wewnętrznych sterownika i
|
||||||
inicjalizację kolejek.
|
inicjalizację kolejek.
|
||||||
|
|
||||||
\texttt{vkCreateSwapchainKHR} (77,02 ms) tworzy łańcuch wymiany (swapchain), czyli zestaw buforów służących do prezentacji obrazu. Operacja ta
|
\texttt{vkCreateSwapchainKHR} (77,02 ms) tworzy łańcuch wymiany (swapchain), \\ czyli zestaw
|
||||||
|
buforów służących do prezentacji obrazu. Operacja ta
|
||||||
obejmuje alokację pamięci dla buforów, konfigurację formatów i synchronizację z systemem okienkowym.
|
obejmuje alokację pamięci dla buforów, konfigurację formatów i synchronizację z systemem okienkowym.
|
||||||
|
|
||||||
Utworzenie 341 obiektów fence (łącznie 135,60 ms) wskazuje na przygotowanie puli ogrodzeń do wielokrotnego użytku w cyklu renderowania. Unity stosuje
|
Utworzenie 341 obiektów fence (łącznie 135,60 ms) wskazuje na przygotowanie puli ogrodzeń do wielokrotnego użytku w cyklu renderowania. Unity stosuje
|
||||||
@ -254,7 +291,7 @@ strategię pre-alokacji zamiast tworzenia ogrodzeń na żądanie, co jest prakty
|
|||||||
Oprócz wywołań Vulkan API, Nsight Systems przechwytuje również wywołania funkcji systemowych, umożliwiając analizę zachowania aplikacji na poziomie
|
Oprócz wywołań Vulkan API, Nsight Systems przechwytuje również wywołania funkcji systemowych, umożliwiając analizę zachowania aplikacji na poziomie
|
||||||
systemu operacyjnego. Zarejestrowano \textbf{29\,383 wywołania} 65 różnych funkcji systemowych.
|
systemu operacyjnego. Zarejestrowano \textbf{29\,383 wywołania} 65 różnych funkcji systemowych.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania systemowe silnika Unity -- synchronizacja wątków}
|
\caption{Wywołania systemowe silnika Unity -- synchronizacja wątków}
|
||||||
\label{tab:unity-osrt-sync}
|
\label{tab:unity-osrt-sync}
|
||||||
@ -304,7 +341,7 @@ responsywność systemu.
|
|||||||
Utworzenie 81 wątków (\texttt{pthread\_create}) podczas testu potwierdza rozbudowaną architekturę wielowątkową. Przy założeniu, że część wątków to wątki
|
Utworzenie 81 wątków (\texttt{pthread\_create}) podczas testu potwierdza rozbudowaną architekturę wielowątkową. Przy założeniu, że część wątków to wątki
|
||||||
robocze systemu zadań, sugeruje to pulę kilkudziesięciu wątków aktywnie uczestniczących w renderowaniu i logice gry.
|
robocze systemu zadań, sugeruje to pulę kilkudziesięciu wątków aktywnie uczestniczących w renderowaniu i logice gry.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania systemowe silnika Unity -- operacje I/O}
|
\caption{Wywołania systemowe silnika Unity -- operacje I/O}
|
||||||
\label{tab:unity-osrt-io}
|
\label{tab:unity-osrt-io}
|
||||||
@ -333,7 +370,8 @@ oraz urządzeniami wejścia.
|
|||||||
Duża liczba wywołań \texttt{openat64} (22\,155) wskazuje na intensywne operacje na systemie plików, prawdopodobnie związane z wczytywaniem zasobów
|
Duża liczba wywołań \texttt{openat64} (22\,155) wskazuje na intensywne operacje na systemie plików, prawdopodobnie związane z wczytywaniem zasobów
|
||||||
gry (tekstur, modeli, shaderów) z dysku. Średni czas 1,07 \textmu{}s potwierdza efektywne buforowanie przez system operacyjny.
|
gry (tekstur, modeli, shaderów) z dysku. Średni czas 1,07 \textmu{}s potwierdza efektywne buforowanie przez system operacyjny.
|
||||||
|
|
||||||
\texttt{ioctl} (1\,907 wywołań) służy do kontroli urządzeń -- w kontekście grafiki Vulkan jest używane do komunikacji ze sterownikiem GPU poprzez
|
\texttt{ioctl} (1\,907 wywołań) służy do kontroli urządzeń -- w kontekście grafiki Vulkan jest
|
||||||
|
używane do komunikacji ze sterownikiem GPU poprzez \\
|
||||||
interfejs DRM/KMS (Direct Rendering Manager / Kernel Mode Setting).
|
interfejs DRM/KMS (Direct Rendering Manager / Kernel Mode Setting).
|
||||||
|
|
||||||
\subsubsection{Interpretacja wyników i wnioski}
|
\subsubsection{Interpretacja wyników i wnioski}
|
||||||
@ -342,11 +380,13 @@ Przeprowadzona analiza pozwala na sformułowanie następujących wniosków dotyc
|
|||||||
|
|
||||||
\paragraph{Charakterystyka ograniczenia wydajności}
|
\paragraph{Charakterystyka ograniczenia wydajności}
|
||||||
|
|
||||||
Dominacja \texttt{vkWaitForFences} (95,2\% czasu Vulkan) i \texttt{futex} (95,9\% czasu systemowego) jednoznacznie wskazuje na scenariusz
|
Dominacja \texttt{vkWaitForFences} \\ (95,2\% czasu Vulkan) i \texttt{futex} (95,9\% czasu systemowego)
|
||||||
|
jednoznacznie wskazuje na scenariusz
|
||||||
\textbf{GPU-bound}. Procesor główny efektywnie przygotowuje i przesyła pracę renderowania, po czym oczekuje na GPU. Jest to optymalny wzorzec dla
|
\textbf{GPU-bound}. Procesor główny efektywnie przygotowuje i przesyła pracę renderowania, po czym oczekuje na GPU. Jest to optymalny wzorzec dla
|
||||||
aplikacji graficznych, gdzie GPU wykonuje większość obliczeniowo intensywnej pracy.
|
aplikacji graficznych, gdzie GPU wykonuje większość obliczeniowo intensywnej pracy.
|
||||||
|
|
||||||
W scenariuszu CPU-bound obserwowalibyśmy niższy udział funkcji synchronizacyjnych i wyższy udział funkcji przygotowujących polecenia
|
W scenariuszu CPU-bound obserwowalibyśmy niższy udział funkcji synchronizacyjnych i wyższy udział
|
||||||
|
funkcji przygotowujących polecenia \\
|
||||||
(\texttt{vkBeginCommandBuffer}, \texttt{vkCmdBindPipeline} itp.), co wskazywałoby na wąskie gardło po stronie procesora.
|
(\texttt{vkBeginCommandBuffer}, \texttt{vkCmdBindPipeline} itp.), co wskazywałoby na wąskie gardło po stronie procesora.
|
||||||
|
|
||||||
\paragraph{Efektywność potoku renderowania}
|
\paragraph{Efektywność potoku renderowania}
|
||||||
@ -355,13 +395,15 @@ Stosunek liczby wywołań \texttt{vkQueueSubmit} (27\,112) do \texttt{vkQueuePre
|
|||||||
renderowania dla każdej klatki. Może to odpowiadać architekturze z oddzielnymi przebiegami dla sceny 3D i interfejsu użytkownika, lub użyciu techniki
|
renderowania dla każdej klatki. Może to odpowiadać architekturze z oddzielnymi przebiegami dla sceny 3D i interfejsu użytkownika, lub użyciu techniki
|
||||||
odroczonego renderowania (ang. \textit{deferred rendering}).
|
odroczonego renderowania (ang. \textit{deferred rendering}).
|
||||||
|
|
||||||
Niska liczba wywołań \texttt{vkCmdBindPipeline} (27\,027, ~2 na klatkę) sugeruje efektywne grupowanie obiektów renderowanych tym samym shaderem,
|
Niska liczba wywołań \texttt{vkCmdBindPipeline} (27\,027, ~2 na klatkę)
|
||||||
|
sugeruje \\ efektywne grupowanie obiektów renderowanych tym samym shaderem,
|
||||||
minimalizujące kosztowne zmiany stanu GPU.
|
minimalizujące kosztowne zmiany stanu GPU.
|
||||||
|
|
||||||
\paragraph{Stabilność czasów klatek}
|
\paragraph{Stabilność czasów klatek}
|
||||||
|
|
||||||
Pomimo wysokiego współczynnika zmienności (153\%) wynikającego z wartości ekstremalnych podczas inicjalizacji, właściwa stabilność renderowania jest
|
Pomimo wysokiego współczynnika zmienności (153\%) wynikającego z wartości ekstremalnych podczas
|
||||||
\textbf{doskonała}. Świadczy o tym:
|
inicjalizacji, właściwa stabilność renderowania jest
|
||||||
|
wysoka. Świadczy o tym:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Wąski rozstęp międzykwartylowy (0,08 ms)
|
\item Wąski rozstęp międzykwartylowy (0,08 ms)
|
||||||
\item Zbieżność mediany (6,94 ms) ze średnią (6,95 ms)
|
\item Zbieżność mediany (6,94 ms) ze średnią (6,95 ms)
|
||||||
@ -369,8 +411,10 @@ Pomimo wysokiego współczynnika zmienności (153\%) wynikającego z wartości e
|
|||||||
\item 98,24\% klatek w przedziale 5--10 ms
|
\item 98,24\% klatek w przedziale 5--10 ms
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Tak wysoka stabilność jest kluczowa dla komfortu gracza -- nawet wysoki FPS nie gwarantuje płynności, jeśli czasy klatek są zmienne. Unity osiąga
|
Należy jednak podkreślić, że obserwowana stabilność jest w znacznej mierze wynikiem
|
||||||
tutaj wynik zbliżony do standardów wymaganych przez aplikacje VR.
|
działania synchronizacji pionowej (V-Sync), która sztucznie \\
|
||||||
|
wyrównuje czasy klatek poprzez oczekiwanie na sygnał odświeżania monitora. \\ Bez V-Sync
|
||||||
|
zmienność czasów klatek mogłaby być wyższa.
|
||||||
|
|
||||||
\paragraph{Architektura wielowątkowa}
|
\paragraph{Architektura wielowątkowa}
|
||||||
|
|
||||||
@ -387,16 +431,19 @@ dostępne rdzenie procesora. Wyniki profilowania potwierdzają aktywne wykorzyst
|
|||||||
\subsection{Wyniki testów dla silnika Unreal Engine}
|
\subsection{Wyniki testów dla silnika Unreal Engine}
|
||||||
\label{subsec:wyniki-unreal}
|
\label{subsec:wyniki-unreal}
|
||||||
|
|
||||||
Profilowanie silnika Unreal Engine 5.5 przeprowadzono przy użyciu NVIDIA Nsight Systems w wersji 2025.5.2. Ze względu na problemy ze stabilnością
|
Profilowanie silnika Unreal Engine 5.5 przeprowadzono przy użyciu NVIDIA Nsight Systems w
|
||||||
połączenia agenta Nsight podczas długich sesji profilowania, 90-sekundową rozgrywkę podzielono na \textbf{trzy fazy po 30 sekund każda}:
|
wersji 2025.5.2. Ze względu na problemy ze stabilnością
|
||||||
|
połączenia agenta Nsight podczas długich sesji profilowania, 90-sekundową \\ rozgrywkę
|
||||||
|
podzielono na \textbf{trzy fazy po 30 sekund każda}:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Faza 1} (0--30 s): Początkowa rozgrywka z niską trudnością
|
\item \textbf{Faza 1} (0--30 s): Początkowa rozgrywka z niską trudnością
|
||||||
\item \textbf{Faza 2} (30--60 s): Środkowa rozgrywka ze średnią trudnością
|
\item \textbf{Faza 2} (30--60 s): Środkowa rozgrywka ze średnią trudnością
|
||||||
\item \textbf{Faza 3} (60--90 s): Końcowa rozgrywka z wysoką trudnością + ekran zwycięstwa
|
\item \textbf{Faza 3} (60--90 s): Końcowa rozgrywka z wysoką trudnością + ekran zwycięstwa
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Każda faza była uruchamiana z flagą \texttt{--start-time=N}, która przesuwa zarówno stan gry (w \texttt{STGGameDirector}), jak i poziom trudności
|
Każda faza była uruchamiana z flagą \texttt{--start-time=N}, która przesuwa \\ zarówno stan gry
|
||||||
spawnu przeciwników (w \texttt{STGEnemySpawner}) do odpowiedniej sekundy. Grę skompilowano w konfiguracji DebugGame, która zachowuje symbole
|
(w \texttt{STGGameDirector}), jak i poziom trudności
|
||||||
|
spawnu przeciwników \\ (w \texttt{STGEnemySpawner}) do odpowiedniej sekundy. \\ Grę skompilowano w konfiguracji DebugGame, która zachowuje symbole
|
||||||
debugowania przy częściowych optymalizacjach.
|
debugowania przy częściowych optymalizacjach.
|
||||||
|
|
||||||
\subsubsection{Ograniczenia metodologiczne profilowania Unreal Engine}
|
\subsubsection{Ograniczenia metodologiczne profilowania Unreal Engine}
|
||||||
@ -410,7 +457,8 @@ bezpieczne przechwytywanie wywołań Vulkan.
|
|||||||
|
|
||||||
W związku z tym ograniczeniem, profilowanie Unreal Engine przeprowadzono z wykorzystaniem:
|
W związku z tym ograniczeniem, profilowanie Unreal Engine przeprowadzono z wykorzystaniem:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Metryk sprzętowych GPU} (\texttt{--gpu-metrics-devices=0}) -- bezpośrednie próbkowanie liczników wydajności karty graficznej NVIDIA z częstotliwością 10\,000 Hz
|
\item \textbf{Metryk sprzętowych GPU} (\texttt{--gpu-metrics-devices=0}) -- bezpośrednie
|
||||||
|
\\ próbkowanie liczników wydajności karty graficznej NVIDIA z częstotliwością 10\,000 Hz
|
||||||
\item \textbf{Śledzenia wywołań systemowych} (\texttt{--trace=osrt}) -- przechwytywanie funkcji OS Runtime (pthread, futex, poll itp.)
|
\item \textbf{Śledzenia wywołań systemowych} (\texttt{--trace=osrt}) -- przechwytywanie funkcji OS Runtime (pthread, futex, poll itp.)
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
@ -420,11 +468,12 @@ wydajności renderowania.
|
|||||||
|
|
||||||
\subsubsection{Metryki wykorzystania GPU}
|
\subsubsection{Metryki wykorzystania GPU}
|
||||||
|
|
||||||
NVIDIA Nsight Systems zbiera metryki sprzętowe GPU poprzez bezpośredni dostęp do liczników wydajności zintegrowanych w karcie graficznej.
|
NVIDIA Nsight Systems zbiera metryki sprzętowe GPU poprzez bezpośredni dostęp do liczników
|
||||||
Podczas trzech 35-sekundowych sesji (30 sekund rozgrywki + 5 sekund buforu) zebrano łącznie \textbf{1\,050\,555 próbek} dla każdej z
|
wydajności zintegrowanych w karcie graficznej.
|
||||||
|
\\ Podczas trzech 35-sekundowych sesji (30 sekund rozgrywki + 5 sekund buforu) zebrano łącznie \textbf{1\,050\,555 próbek} dla każdej z
|
||||||
31 monitorowanych metryk.
|
31 monitorowanych metryk.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Kluczowe metryki wykorzystania GPU dla silnika Unreal Engine (fazy 1--2, aktywna rozgrywka)}
|
\caption{Kluczowe metryki wykorzystania GPU dla silnika Unreal Engine (fazy 1--2, aktywna rozgrywka)}
|
||||||
\label{tab:unreal-gpu-metrics}
|
\label{tab:unreal-gpu-metrics}
|
||||||
@ -448,7 +497,7 @@ Metryka \texttt{GPU Active} określa procentowy udział czasu, w którym karta g
|
|||||||
Średnia wartość \textbf{90,98\%} dla faz 1--2 (aktywna rozgrywka) oznacza, że GPU był niemal w pełni wykorzystany podczas właściwej rozgrywki.
|
Średnia wartość \textbf{90,98\%} dla faz 1--2 (aktywna rozgrywka) oznacza, że GPU był niemal w pełni wykorzystany podczas właściwej rozgrywki.
|
||||||
Faza 3 wykazała niższą wartość (49,55\%) ze względu na włączenie ekranu zwycięstwa i procesu zamykania gry.
|
Faza 3 wykazała niższą wartość (49,55\%) ze względu na włączenie ekranu zwycięstwa i procesu zamykania gry.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie metryk GPU między fazami testu Unreal Engine}
|
\caption{Porównanie metryk GPU między fazami testu Unreal Engine}
|
||||||
\label{tab:unreal-gpu-phases}
|
\label{tab:unreal-gpu-phases}
|
||||||
@ -468,8 +517,12 @@ Liczba próbek & 350\,205 & 350\,249 & 350\,101 \\
|
|||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
Tabela~\ref{tab:unreal-gpu-phases} pokazuje stabilność metryk GPU między fazami 1 i 2 (różnice <0,5 pp.), co potwierdza poprawność metodologii
|
Tabela~\ref{tab:unreal-gpu-phases} pokazuje stabilność metryk GPU między fazami 1 i 2
|
||||||
fazowego profilowania. Wyraźny spadek w fazie 3 odzwierciedla zakończenie aktywnej rozgrywki i przejście do ekranu zwycięstwa.
|
różnice <0,5 pp.),
|
||||||
|
co potwierdza poprawność metodologii
|
||||||
|
fazowego profilowania. \\
|
||||||
|
Wyraźny spadek w fazie
|
||||||
|
3 odzwierciedla zakończenie aktywnej rozgrywki i przejście do ekranu zwycięstwa.
|
||||||
|
|
||||||
\paragraph{GR Active -- aktywność silnika graficznego}
|
\paragraph{GR Active -- aktywność silnika graficznego}
|
||||||
|
|
||||||
@ -488,7 +541,7 @@ strumieniowych jest aktywna jednocześnie. Karta NVIDIA RTX 3090 posiada 82 jedn
|
|||||||
Wartość \texttt{Sync Compute in Flight} (43,23\%) wskazuje na znaczące wykorzystanie synchronicznych shaderów obliczeniowych,
|
Wartość \texttt{Sync Compute in Flight} (43,23\%) wskazuje na znaczące wykorzystanie synchronicznych shaderów obliczeniowych,
|
||||||
prawdopodobnie do operacji post-processingu, culling GPU lub przygotowania danych renderowania.
|
prawdopodobnie do operacji post-processingu, culling GPU lub przygotowania danych renderowania.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Metryki przepustowości pamięci GPU dla silnika Unreal Engine (fazy 1--2)}
|
\caption{Metryki przepustowości pamięci GPU dla silnika Unreal Engine (fazy 1--2)}
|
||||||
\label{tab:unreal-memory-metrics}
|
\label{tab:unreal-memory-metrics}
|
||||||
@ -513,7 +566,7 @@ Wartości maksymalne (68\% i 78\%) pokazują, że w momentach szczytowych obcią
|
|||||||
Stosunek odczytu do zapisu (10,30:10,10 $\approx$ 1,02:1) jest zbliżony do jedności, co sugeruje zbalansowany przepływ danych --
|
Stosunek odczytu do zapisu (10,30:10,10 $\approx$ 1,02:1) jest zbliżony do jedności, co sugeruje zbalansowany przepływ danych --
|
||||||
typowy dla nowoczesnych technik renderowania z wieloma przejściami i render targets.
|
typowy dla nowoczesnych technik renderowania z wieloma przejściami i render targets.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wykorzystanie różnych typów wątków shader GPU w silniku Unreal Engine (fazy 1--2)}
|
\caption{Wykorzystanie różnych typów wątków shader GPU w silniku Unreal Engine (fazy 1--2)}
|
||||||
\label{tab:unreal-warps}
|
\label{tab:unreal-warps}
|
||||||
@ -531,8 +584,9 @@ Unallocated Warps in Active SMs & 20,73 & 90,0 \\
|
|||||||
|
|
||||||
\paragraph{Analiza wątków shaderów (warps)}
|
\paragraph{Analiza wątków shaderów (warps)}
|
||||||
|
|
||||||
Tabela~\ref{tab:unreal-warps} przedstawia rozkład typów aktywnych wątków shader (warps -- grupy 32 wątków CUDA wykonywanych synchronicznie).
|
Tabela~\ref{tab:unreal-warps} przedstawia rozkład typów aktywnych wątków shader
|
||||||
Dominacja \texttt{Compute Warps} (13,03\%) nad \texttt{Pixel Warps} (9,36\%) wskazuje na znaczące wykorzystanie compute shaderów, prawdopodobnie do:
|
(warps -- grupy 32 wątków CUDA wykonywanych synchronicznie).
|
||||||
|
\\Dominacja \texttt{Compute Warps} (13,03\%) nad \texttt{Pixel Warps} (9,36\%) wskazuje na znaczące wykorzystanie compute shaderów, prawdopodobnie do:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Culling (odrzucanie niewidocznych obiektów na GPU)
|
\item Culling (odrzucanie niewidocznych obiektów na GPU)
|
||||||
\item Post-processing i tone mapping
|
\item Post-processing i tone mapping
|
||||||
@ -542,10 +596,11 @@ Dominacja \texttt{Compute Warps} (13,03\%) nad \texttt{Pixel Warps} (9,36\%) wsk
|
|||||||
Niski udział \texttt{Vertex/Tess/Geometry Warps} (0,45\%) sugeruje prostą geometrię sceny bez intensywnego wykorzystania teselacji --
|
Niski udział \texttt{Vertex/Tess/Geometry Warps} (0,45\%) sugeruje prostą geometrię sceny bez intensywnego wykorzystania teselacji --
|
||||||
co jest zgodne z charakterystyką testowanej gry bullet-hell, gdzie większość efektów wizualnych to płaskie sprite'y i efekty cząsteczkowe.
|
co jest zgodne z charakterystyką testowanej gry bullet-hell, gdzie większość efektów wizualnych to płaskie sprite'y i efekty cząsteczkowe.
|
||||||
|
|
||||||
\texttt{Unallocated Warps in Active SMs} (20,73\%) reprezentuje niewykorzystaną pojemność aktywnych multiprocesorów. Wartość ta wskazuje na
|
\texttt{Unallocated Warps in Active SMs} (20,73\%) reprezentuje \\ niewykorzystaną pojemność
|
||||||
|
aktywnych multiprocesorów. Wartość ta wskazuje na
|
||||||
potencjał optymalizacji przez zwiększenie granularności pracy lub lepsze grupowanie operacji.
|
potencjał optymalizacji przez zwiększenie granularności pracy lub lepsze grupowanie operacji.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Częstotliwości zegara GPU podczas testu Unreal Engine}
|
\caption{Częstotliwości zegara GPU podczas testu Unreal Engine}
|
||||||
\label{tab:unreal-gpu-clocks}
|
\label{tab:unreal-gpu-clocks}
|
||||||
@ -568,7 +623,7 @@ Minimalne wartości odpowiadają krótkim momentom niższego obciążenia podcza
|
|||||||
Dzięki zastosowaniu profilowania fazowego uzyskano \textbf{kompletne dane} śledzenia Vulkan API z całego 90-sekundowego przebiegu gry Unreal Engine.
|
Dzięki zastosowaniu profilowania fazowego uzyskano \textbf{kompletne dane} śledzenia Vulkan API z całego 90-sekundowego przebiegu gry Unreal Engine.
|
||||||
Dane podzielone na trzy fazy (0--30s, 30--60s, 60--90s) umożliwiają szczegółową analizę ewolucji wykorzystania GPU w czasie rozgrywki.
|
Dane podzielone na trzy fazy (0--30s, 30--60s, 60--90s) umożliwiają szczegółową analizę ewolucji wykorzystania GPU w czasie rozgrywki.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie wywołań Vulkan API silnika Unreal Engine między fazami}
|
\caption{Porównanie wywołań Vulkan API silnika Unreal Engine między fazami}
|
||||||
\label{tab:unreal-vulkan-phases}
|
\label{tab:unreal-vulkan-phases}
|
||||||
@ -589,14 +644,25 @@ vkCmdBindPipeline & 2\,236\,013 & 2\,528\,014 & 1\,007\,615 \\
|
|||||||
|
|
||||||
\paragraph{Dynamika wydajności między fazami}
|
\paragraph{Dynamika wydajności między fazami}
|
||||||
|
|
||||||
Tabela~\ref{tab:unreal-vulkan-phases} ujawnia interesującą dynamikę wydajności. Faza 2 (środkowa część rozgrywki) osiąga najwyższą wydajność ze
|
Tabela~\ref{tab:unreal-vulkan-phases} ujawnia znaczącą dynamikę wydajności między fazami.
|
||||||
średnio \textbf{384 FPS}, podczas gdy faza 3 (zawierająca ekran zwycięstwa) pokazuje znaczący spadek do \textbf{153 FPS}. Spadek ten związany jest z
|
Fazy 1 i 2 (aktywna rozgrywka) osiągają wysoką wydajność
|
||||||
zakończeniem rozgrywki i przejściem do ekranu końcowego.
|
(343--384 FPS), natomiast faza 3 pokazuje \textbf{dramatyczny spadek do 153 FPS} -- redukcję o
|
||||||
|
ponad 60\%. Spadek ten występuje w końcowej fazie
|
||||||
|
rozgrywki, gdy na ekranie znajduje się największa liczba przeciwników i pocisków, co stanowi
|
||||||
|
najbardziej wymagający moment dla silnika renderującego.
|
||||||
|
Dodatkowo faza 3 zawiera ekran zwycięstwa, który również wpływa na średnią wydajność.
|
||||||
|
|
||||||
|
\textbf{Uwaga metodologiczna:} W przeciwieństwie do Unity, dla Unreal Engine nie dysponujemy danymi o
|
||||||
|
rozkładzie percentylowym czasów klatek
|
||||||
|
(1\% low, 0.1\% low), ponieważ śledzenie Vulkan API powoduje awarię aplikacji. Średnie wartości FPS
|
||||||
|
mogą być zawyżone przez początkowe klatki
|
||||||
|
o niskim obciążeniu, dlatego wartość 153 FPS z fazy 3 lepiej reprezentuje wydajność w wymagających
|
||||||
|
scenach niż średnia z faz 1--2.
|
||||||
|
|
||||||
Stosunek wywołań \texttt{vkQueueSubmit} do \texttt{vkQueuePresentKHR} pozostaje stabilny na poziomie \textbf{16,2:1} we wszystkich fazach, co
|
Stosunek wywołań \texttt{vkQueueSubmit} do \texttt{vkQueuePresentKHR} pozostaje stabilny na poziomie \textbf{16,2:1} we wszystkich fazach, co
|
||||||
wskazuje na konsystentną architekturę potoku renderowania niezależną od obciążenia sceny.
|
wskazuje na konsystentną architekturę potoku renderowania niezależną od obciążenia sceny.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania Vulkan API silnika Unreal Engine -- tworzenie potoków (wszystkie fazy)}
|
\caption{Wywołania Vulkan API silnika Unreal Engine -- tworzenie potoków (wszystkie fazy)}
|
||||||
\label{tab:unreal-vulkan-pipelines}
|
\label{tab:unreal-vulkan-pipelines}
|
||||||
@ -627,21 +693,25 @@ wskazuje na konsystentną architekturę potoku renderowania niezależną od obci
|
|||||||
|
|
||||||
\paragraph{Kompilacja potoków -- ciągły proces}
|
\paragraph{Kompilacja potoków -- ciągły proces}
|
||||||
|
|
||||||
W przeciwieństwie do Unity, gdzie dominującą funkcją był \texttt{vkWaitForFences}, w Unreal Engine \textbf{57--72\% czasu} Vulkan API
|
W przeciwieństwie do Unity, gdzie dominującą funkcją był \texttt{vkWaitForFences},
|
||||||
pochłonęły funkcje tworzenia potoków. Co istotne, liczba wywołań \texttt{vkCreateComputePipelines} i \texttt{vkCreateGraphicsPipelines} jest
|
w Unreal Engine \textbf{57--72\% czasu} Vulkan API
|
||||||
|
pochłonęły funkcje tworzenia potoków.
|
||||||
|
\\ Co istotne, liczba wywołań \texttt{vkCreateComputePipelines} i \\
|
||||||
|
\texttt{vkCreateGraphicsPipelines} jest
|
||||||
\textbf{niemal identyczna we wszystkich trzech fazach}, co wskazuje na strategię \textbf{ciągłej rekompilacji potoków} (Pipeline State Object)
|
\textbf{niemal identyczna we wszystkich trzech fazach}, co wskazuje na strategię \textbf{ciągłej rekompilacji potoków} (Pipeline State Object)
|
||||||
przez cały czas działania gry.
|
przez cały czas działania gry.
|
||||||
|
|
||||||
Łącznie w każdej 30-sekundowej fazie tworzonych jest około \textbf{1\,024--1\,047 potoków} (231 compute + 793--816 graphics). Porównując z Unity
|
Łącznie w każdej 30-sekundowej fazie tworzonych jest około \textbf{1\,024--1\,047 potoków} (231 compute + 793--816 graphics). Porównując z Unity
|
||||||
(który utworzył tylko 3 potoki graficzne w całym 95-sekundowym teście), Unreal Engine generuje \textbf{ponad 300 razy więcej potoków}.
|
(który utworzył tylko 3 potoki graficzne w całym 95-sekundowym teście), Unreal Engine generuje \textbf{ponad 300 razy więcej potoków}.
|
||||||
|
|
||||||
Średni czas tworzenia potoku compute (18,63--19,21 ms) jest ponad \textbf{14 razy dłuższy} niż dla potoku graficznego (1,14--1,39 ms). Różnica ta
|
Średni czas tworzenia potoku compute (18,63--19,21 ms) jest ponad \textbf{14 razy dłuższy}
|
||||||
wynika z większej złożoności shaderów obliczeniowych używanych przez Unreal Engine do culling, post-processingu i systemu Nanite.
|
niż dla potoku graficznego (1,14--1,39 ms). Różnica ta
|
||||||
|
wynika z większej złożoności shaderów obliczeniowych używanych \\ przez Unreal Engine do culling, post-processingu i systemu Nanite.
|
||||||
|
|
||||||
Wywołanie \texttt{vkCreateDevice} pojawia się raz w każdej fazie z czasem 541--590 ms, co odpowiada momentowi startu gry w tej fazie -- narzędzie
|
Wywołanie \texttt{vkCreateDevice} pojawia się raz w każdej fazie z czasem 541--590 ms, co odpowiada momentowi startu gry w tej fazie -- narzędzie
|
||||||
Nsight Systems tworzy nową sesję dla każdej fazy.
|
Nsight Systems tworzy nową sesję dla każdej fazy.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania Vulkan API silnika Unreal Engine -- synchronizacja i prezentacja (faza 2)}
|
\caption{Wywołania Vulkan API silnika Unreal Engine -- synchronizacja i prezentacja (faza 2)}
|
||||||
\label{tab:unreal-vulkan-sync}
|
\label{tab:unreal-vulkan-sync}
|
||||||
@ -667,11 +737,13 @@ W ostrzym kontraście z Unity (gdzie \texttt{vkWaitForFences} stanowił 95,2\% c
|
|||||||
\item Lepsze rozłożenie pracy między CPU a GPU eliminujące przestoje
|
\item Lepsze rozłożenie pracy między CPU a GPU eliminujące przestoje
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Stosunek wywołań \texttt{vkQueueSubmit} (186\,589) do \texttt{vkQueuePresentKHR} (11\,531) wynosi \textbf{16,2:1}, co oznacza średnio 16
|
Stosunek wywołań \texttt{vkQueueSubmit} (186\,589) do \\ \texttt{vkQueuePresentKHR} (11\,531)
|
||||||
przesyłek pracy na klatkę. Jest to znacznie więcej niż w Unity (2:1), odzwierciedlając bardziej złożony potok renderowania Unreal Engine z
|
wynosi \textbf{16,2:1}, co oznacza średnio \\ 16
|
||||||
|
przesyłek pracy na klatkę. Jest to znacznie więcej niż w Unity (2:1), odzwierciedlając
|
||||||
|
bardziej złożony potok renderowania Unreal Engine z
|
||||||
wieloma przebiegami (deferred rendering, post-processing, UI).
|
wieloma przebiegami (deferred rendering, post-processing, UI).
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania Vulkan API silnika Unreal Engine -- bufory poleceń (wszystkie fazy łącznie)}
|
\caption{Wywołania Vulkan API silnika Unreal Engine -- bufory poleceń (wszystkie fazy łącznie)}
|
||||||
\label{tab:unreal-vulkan-cmd}
|
\label{tab:unreal-vulkan-cmd}
|
||||||
@ -689,8 +761,9 @@ wieloma przebiegami (deferred rendering, post-processing, UI).
|
|||||||
|
|
||||||
\paragraph{Bufory poleceń -- intensywna zmiana stanów}
|
\paragraph{Bufory poleceń -- intensywna zmiana stanów}
|
||||||
|
|
||||||
Liczba wywołań \texttt{vkCmdBindPipeline} (\textbf{5\,771\,642} łącznie we wszystkich fazach) jest ponad \textbf{213 razy większa} niż w
|
Liczba wywołań \\ \texttt{vkCmdBindPipeline} (\textbf{5\,771\,642}
|
||||||
Unity (27\,027), co odpowiada około 218 zmianom potoku na klatkę. Tak wysoka wartość wynika z:
|
łącznie we wszystkich fazach) jest \\ ponad \textbf{213 razy większa} niż w
|
||||||
|
Unity (27\,027), \\ co odpowiada około 218 zmianom potoku na klatkę. Tak wysoka wartość wynika z:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Dynamicznego systemu materiałów Unreal Engine
|
\item Dynamicznego systemu materiałów Unreal Engine
|
||||||
\item Wielu wariantów shaderów dla różnych kombinacji oświetlenia
|
\item Wielu wariantów shaderów dla różnych kombinacji oświetlenia
|
||||||
@ -718,7 +791,7 @@ i zniszczeń sugeruje akumulację struktur w pamięci GPU podczas rozgrywki.
|
|||||||
Podobnie jak dla Unity, Nsight Systems przechwycił wywołania funkcji systemowych we wszystkich trzech fazach, umożliwiając analizę zachowania
|
Podobnie jak dla Unity, Nsight Systems przechwycił wywołania funkcji systemowych we wszystkich trzech fazach, umożliwiając analizę zachowania
|
||||||
wielowątkowego Unreal Engine. Łącznie zarejestrowano ponad \textbf{9 milionów wywołań} funkcji synchronizacji.
|
wielowątkowego Unreal Engine. Łącznie zarejestrowano ponad \textbf{9 milionów wywołań} funkcji synchronizacji.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Wywołania systemowe silnika Unreal Engine -- synchronizacja wątków (wszystkie fazy)}
|
\caption{Wywołania systemowe silnika Unreal Engine -- synchronizacja wątków (wszystkie fazy)}
|
||||||
\label{tab:unreal-osrt-sync}
|
\label{tab:unreal-osrt-sync}
|
||||||
@ -738,20 +811,23 @@ wielowątkowego Unreal Engine. Łącznie zarejestrowano ponad \textbf{9 milionó
|
|||||||
|
|
||||||
\paragraph{pthread\_cond\_wait -- architektura TaskGraph}
|
\paragraph{pthread\_cond\_wait -- architektura TaskGraph}
|
||||||
|
|
||||||
Funkcja \texttt{pthread\_cond\_wait} pochłonęła \textbf{64,6\% czasu} przy \textbf{3\,095\,188 wywołaniach} we wszystkich trzech fazach.
|
Funkcja \texttt{pthread\_cond\_wait} \\ pochłonęła \textbf{64,6\% czasu} przy
|
||||||
|
\textbf{3\,095\,188 wywołaniach} we wszystkich trzech fazach.
|
||||||
Jest to funkcja POSIX do oczekiwania na zmienną warunkową, używana gdy wątek musi czekać na spełnienie określonego warunku sygnalizowanego przez
|
Jest to funkcja POSIX do oczekiwania na zmienną warunkową, używana gdy wątek musi czekać na spełnienie określonego warunku sygnalizowanego przez
|
||||||
inny wątek.
|
inny wątek.
|
||||||
|
|
||||||
Tak wysoka liczba wywołań (ponad 40 razy więcej niż dla Unity) odzwierciedla architekturę wielowątkową Unreal Engine opartą na systemie
|
Tak wysoka liczba wywołań (ponad 40 razy więcej niż dla Unity)
|
||||||
\textbf{TaskGraph}. System ten dekomponuje pracę renderowania na małe zadania (ang. \textit{tasks}), które są wykonywane przez pulę wątków roboczych.
|
odzwierciedla architekturę wielowątkową Unreal Engine opartą na systemie
|
||||||
Każde zadanie po zakończeniu sygnalizuje swoją gotowość, a zależne zadania są budzone poprzez
|
\textbf{TaskGraph}. System ten dekomponuje pracę renderowania na małe zadania (ang. \textit{tasks}),
|
||||||
|
które są wykonywane przez pulę wątków roboczych.
|
||||||
|
Każde zadanie po zakończeniu sygnalizuje swoją gotowość, a zależne zadania są budzone \\ poprzez
|
||||||
\texttt{pthread\_cond\_signal}/\texttt{pthread\_cond\_broadcast}.
|
\texttt{pthread\_cond\_signal}/\texttt{pthread\_cond\_broadcast}.
|
||||||
|
|
||||||
Średni czas pojedynczego oczekiwania (0,97 ms) jest krótki, co wskazuje na częste, ale krótkotrwałe synchronizacje --
|
Średni czas pojedynczego oczekiwania (0,97 ms) jest krótki, co wskazuje \\ na częste, ale krótkotrwałe synchronizacje --
|
||||||
typowe dla drobnoziarnistego paralelizmu. Maksymalny czas 22,23 sekundy odpowiada prawdopodobnie wywołaniu podczas długotrwałej operacji
|
typowe dla drobnoziarnistego paralelizmu. Maksymalny czas 22,23 sekundy odpowiada prawdopodobnie wywołaniu podczas długotrwałej operacji
|
||||||
inicjalizacyjnej w fazie 2.
|
inicjalizacyjnej w fazie 2.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie wywołań synchronizacyjnych między fazami Unreal Engine}
|
\caption{Porównanie wywołań synchronizacyjnych między fazami Unreal Engine}
|
||||||
\label{tab:unreal-osrt-phases}
|
\label{tab:unreal-osrt-phases}
|
||||||
@ -772,9 +848,9 @@ Tabela~\ref{tab:unreal-osrt-phases} pokazuje konsystencję wzorców wywołań mi
|
|||||||
fazie 3 (zawierającej ekran zwycięstwa). Szczególnie interesująca jest wysoka liczba wywołań \texttt{backtrace} (ponad 5,5 miliona łącznie),
|
fazie 3 (zawierającej ekran zwycięstwa). Szczególnie interesująca jest wysoka liczba wywołań \texttt{backtrace} (ponad 5,5 miliona łącznie),
|
||||||
co sugeruje intensywne wykorzystanie mechanizmów debugowania lub profilowania wbudowanych w Unreal Engine nawet w konfiguracji DebugGame.
|
co sugeruje intensywne wykorzystanie mechanizmów debugowania lub profilowania wbudowanych w Unreal Engine nawet w konfiguracji DebugGame.
|
||||||
|
|
||||||
\paragraph{pthread\_cond\_timedwait -- synchronizacja z limitem czasowym}
|
\paragraph{synchronizacja z limitem czasowym pthread\_cond\_timedwait}
|
||||||
|
(19,2\%, 163\,783 \\ wywołań) różni się od
|
||||||
\texttt{pthread\_cond\_timedwait} (19,2\%, 163\,783 wywołań) różni się od \texttt{pthread\_cond\_wait} możliwością określenia maksymalnego czasu
|
\texttt{pthread\_cond\_wait} możliwością określenia maksymalnego czasu
|
||||||
oczekiwania. Użycie tej funkcji wskazuje na mechanizmy:
|
oczekiwania. Użycie tej funkcji wskazuje na mechanizmy:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Timeoutów zapobiegających zakleszczeniom (deadlock prevention)
|
\item Timeoutów zapobiegających zakleszczeniom (deadlock prevention)
|
||||||
@ -782,15 +858,16 @@ oczekiwania. Użycie tej funkcji wskazuje na mechanizmy:
|
|||||||
\item Synchronizacji czasowej dla frame pacing
|
\item Synchronizacji czasowej dla frame pacing
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Średni czas 5,46 ms sugeruje użycie do synchronizacji między-klatkowej, gdzie wątki oczekują na gotowość kolejnej klatki z timeout'em
|
Średni czas 5,46 ms sugeruje użycie do synchronizacji między-klatkowej, \\
|
||||||
zapobiegającym nieskończonemu oczekiwaniu w przypadku błędu.
|
gdzie wątki oczekują na gotowość kolejnej klatki z timeout'em
|
||||||
|
\\ zapobiegającym nieskończonemu oczekiwaniu w przypadku błędu.
|
||||||
|
|
||||||
\paragraph{usleep -- precyzyjne opóźnienia}
|
\paragraph{usleep -- precyzyjne opóźnienia}
|
||||||
|
|
||||||
Funkcja \texttt{usleep} (4,7\%, 26\,062 wywołań, średnio 7,79 ms) wprowadza precyzyjne opóźnienia czasowe. Średni czas 7,79 ms jest zbliżony do
|
Funkcja \texttt{usleep} (4,7\%, 26\,062 wywołań, średnio 7,79 ms) wprowadza precyzyjne opóźnienia czasowe. Średni czas 7,79 ms jest zbliżony do
|
||||||
czasu klatki przy ~128 FPS, co może sugerować mechanizm regulacji tempa renderowania lub oszczędzanie energii poprzez redukcję spin-waitingu.
|
czasu klatki przy ~128 FPS, co może sugerować mechanizm regulacji tempa renderowania lub oszczędzanie energii poprzez redukcję spin-waitingu.
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie mechanizmów synchronizacji Unity i Unreal Engine (zaktualizowane)}
|
\caption{Porównanie mechanizmów synchronizacji Unity i Unreal Engine (zaktualizowane)}
|
||||||
\label{tab:sync-comparison}
|
\label{tab:sync-comparison}
|
||||||
@ -811,17 +888,19 @@ Liczba próbek GPU (10 kHz) & -- & 1\,050\,555 \\
|
|||||||
|
|
||||||
Tabela~\ref{tab:sync-comparison} ujawnia fundamentalną różnicę architektoniczną między silnikami:
|
Tabela~\ref{tab:sync-comparison} ujawnia fundamentalną różnicę architektoniczną między silnikami:
|
||||||
|
|
||||||
\textbf{Unity} stosuje mechanizm \texttt{futex} z niewielką liczbą wywołań (247) i długim średnim czasem (444 ms). Wskazuje to na architekturę z
|
\textbf{Unity} stosuje mechanizm \texttt{futex} z niewielką liczbą wywołań (247) \\ i
|
||||||
|
długim średnim czasem (444 ms). Wskazuje to na architekturę z
|
||||||
większymi, bardziej autonomicznymi jednostkami pracy i rzadszą synchronizacją między wątkami.
|
większymi, bardziej autonomicznymi jednostkami pracy i rzadszą synchronizacją między wątkami.
|
||||||
|
|
||||||
\textbf{Unreal Engine} używa \texttt{pthread\_cond\_wait} z ogromną liczbą wywołań (ponad 3 miliony w 90-sekundowym teście) i bardzo krótkim średnim
|
\textbf{Unreal Engine} używa \texttt{pthread\_cond\_wait} z ogromną liczbą wywołań
|
||||||
|
\\ (ponad 3 miliony w 90-sekundowym teście) \\ i bardzo krótkim średnim
|
||||||
czasem (0,97 ms). Odzwierciedla to drobnoziarnisty paralelizm systemu TaskGraph, gdzie praca jest dzielona na małe zadania często komunikujące się ze
|
czasem (0,97 ms). Odzwierciedla to drobnoziarnisty paralelizm systemu TaskGraph, gdzie praca jest dzielona na małe zadania często komunikujące się ze
|
||||||
sobą.
|
sobą.
|
||||||
|
|
||||||
Różnica ta ma implikacje praktyczne:
|
Różnica ta ma implikacje praktyczne:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Skalowalność}: Drobnoziarnisty model Unreal lepiej skaluje się na procesory z wieloma rdzeniami
|
\item \textbf{Skalowalność}: Drobnoziarnisty model Unreal lepiej skaluje się na procesory z wieloma rdzeniami
|
||||||
\item \textbf{Narzut synchronizacji}: Model Unity ma mniejszy narzut z powodu rzadszych wywołań
|
\item \textbf{Narzut synchronizacji}: Model Unity ma mniejszy narzut \\ z powodu rzadszych wywołań
|
||||||
\item \textbf{Responsywność}: Unreal może szybciej reagować na zmiany (np. przerwanie zadania)
|
\item \textbf{Responsywność}: Unreal może szybciej reagować na zmiany (np. przerwanie zadania)
|
||||||
\item \textbf{Debugowanie}: Model Unity jest łatwiejszy do analizy ze względu na prostszą strukturę
|
\item \textbf{Debugowanie}: Model Unity jest łatwiejszy do analizy ze względu na prostszą strukturę
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
@ -840,12 +919,14 @@ Unreal Engine 5 stosuje zaawansowaną architekturę wielowątkową złożoną z:
|
|||||||
\item \textbf{Worker Threads} -- pula wątków roboczych systemu TaskGraph
|
\item \textbf{Worker Threads} -- pula wątków roboczych systemu TaskGraph
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Obserwowana dominacja \texttt{pthread\_cond\_wait} (3+ miliony wywołań) potwierdza intensywną komunikację między tymi wątkami. Wysokie wykorzystanie
|
Obserwowana dominacja \texttt{pthread\_cond\_wait} (3+ miliony wywołań) \\ potwierdza intensywną
|
||||||
|
komunikację między tymi wątkami.
|
||||||
|
\\ Wysokie wykorzystanie
|
||||||
GPU (90,98\% w fazach aktywnej rozgrywki) przy jednoczesnej intensywnej synchronizacji CPU sugeruje efektywne wykorzystanie zasobów obu procesorów.
|
GPU (90,98\% w fazach aktywnej rozgrywki) przy jednoczesnej intensywnej synchronizacji CPU sugeruje efektywne wykorzystanie zasobów obu procesorów.
|
||||||
|
|
||||||
\paragraph{Profil obciążenia GPU}
|
\paragraph{Profil obciążenia GPU}
|
||||||
|
|
||||||
Na podstawie zebranych metryk można scharakteryzować profil obciążenia GPU:
|
Na podstawie zebranych metryk można \\ scharakteryzować profil obciążenia GPU:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Charakter pracy}: Mieszany graficzno-obliczeniowy (GR Active 85,59\%, Sync Compute 43,23\%)
|
\item \textbf{Charakter pracy}: Mieszany graficzno-obliczeniowy (GR Active 85,59\%, Sync Compute 43,23\%)
|
||||||
\item \textbf{Wykorzystanie SM}: Umiarkowane (42,88\%), wskazujące na potencjał optymalizacji
|
\item \textbf{Wykorzystanie SM}: Umiarkowane (42,88\%), wskazujące na potencjał optymalizacji
|
||||||
@ -884,7 +965,7 @@ charakterystykę wydajnościową silnika, pozwalając na porównanie architekton
|
|||||||
|
|
||||||
\subsubsection{Porównanie czasu klatki}
|
\subsubsection{Porównanie czasu klatki}
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie czasów klatek i wydajności między silnikami}
|
\caption{Porównanie czasów klatek i wydajności między silnikami}
|
||||||
\label{tab:frame-time-comparison}
|
\label{tab:frame-time-comparison}
|
||||||
@ -892,34 +973,42 @@ charakterystykę wydajnościową silnika, pozwalając na porównanie architekton
|
|||||||
\hline
|
\hline
|
||||||
\textbf{Metryka} & \textbf{Unity} & \textbf{Unreal Engine} \\
|
\textbf{Metryka} & \textbf{Unity} & \textbf{Unreal Engine} \\
|
||||||
\hline
|
\hline
|
||||||
Średni FPS (aktywna rozgrywka) & 144 & 343--384 \\
|
Średni FPS (fazy 1--2) & 144 (V-Sync) & 343--384 \\
|
||||||
Mediana czasu klatki (ms) & 6,94 & 2,60--2,91 \\
|
Średni FPS (faza 3, wymagająca) & 144 (V-Sync) & 153 \\
|
||||||
99. percentyl czasu klatki (ms) & 7,58 & -- \\
|
1\% low (99. percentyl) & 132 FPS & brak danych \\
|
||||||
Całkowita liczba klatek (90s) & 13\,556 & 26\,419 \\
|
Całkowita liczba klatek (90s) & 13\,556 & 26\,407 \\
|
||||||
\hline
|
\hline
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
Tabela~\ref{tab:frame-time-comparison} przedstawia bezpośrednie porównanie wydajności obu silników. Unreal Engine osiągnął
|
Tabela~\ref{tab:frame-time-comparison} przedstawia porównanie wydajności obu silników.
|
||||||
\textbf{ponad 2,5-krotnie wyższy FPS} niż Unity (343--384 vs 144 FPS) podczas aktywnej rozgrywki. Różnica ta jest
|
\textbf{Bezpośrednie porównanie średnich
|
||||||
zaskakująca, biorąc pod uwagę, że Unity jest powszechnie uważany za lepiej zoptymalizowany dla gier 2D.
|
wartości FPS jest jednak problematyczne} z następujących powodów:
|
||||||
|
|
||||||
Możliwe przyczyny przewagi Unreal Engine:
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Architektura renderowania} -- Unreal stosuje bardziej agresywne techniki optymalizacji (culling na GPU,
|
\item \textbf{Unity działał z włączonym V-Sync} -- wydajność była sztucznie ograniczona do
|
||||||
batching dynamiczny), które są efektywne nawet dla prostych scen 2D
|
144 FPS (częstotliwość
|
||||||
\item \textbf{Kompilacja natywna} -- kod C++ Unreal jest kompilowany bezpośrednio do kodu maszynowego, eliminując
|
odświeżania monitora), co uniemożliwia ocenę rzeczywistej maksymalnej wydajności silnika
|
||||||
narzut maszyny wirtualnej .NET/Mono
|
\item \textbf{Brak danych percentylowych dla Unreal} -- nie dysponujemy wartościami 1\% low
|
||||||
\item \textbf{Wielowątkowość} -- drobnoziarnisty paralelizm TaskGraph pozwala na lepsze wykorzystanie
|
ani 0.1\% low, które
|
||||||
wielordzeniowego procesora
|
lepiej reprezentują wydajność w wymagających momentach niż średnia arytmetyczna
|
||||||
|
\item \textbf{Średnie FPS Unreal mogą być zawyżone} -- początkowe klatki o niskim obciążeniu
|
||||||
|
podnoszą średnią,
|
||||||
|
podczas gdy w fazie 3 (najbardziej wymagającej) wydajność spadła do 153 FPS
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Należy jednak zauważyć, że Unity wykazał \textbf{lepszą stabilność czasów klatek} -- 99. percentyl (7,58 ms) był
|
Porównując wartości bardziej reprezentatywne dla rzeczywistej rozgrywki: \\
|
||||||
zaledwie 9,2\% wyższy od mediany (6,94 ms), co świadczy o przewidywalnym zachowaniu potoku renderowania.
|
\textbf{Unity 1\% low (132 FPS) vs Unreal faza 3 (153 FPS)},
|
||||||
|
różnica wynosi zaledwie 16\%, co jest znacznie mniejsze niż sugerowałoby porównanie średnich
|
||||||
|
(144 vs 384 FPS).
|
||||||
|
|
||||||
|
Jednoznaczne stwierdzenie, który silnik jest wydajniejszy, wymaga powtórzenia testów z
|
||||||
|
wyłączonym V-Sync dla Unity oraz
|
||||||
|
uzyskania danych percentylowych dla Unreal Engine.
|
||||||
|
|
||||||
\subsubsection{Porównanie wykorzystania GPU}
|
\subsubsection{Porównanie wykorzystania GPU}
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie wykorzystania GPU między silnikami}
|
\caption{Porównanie wykorzystania GPU między silnikami}
|
||||||
\label{tab:gpu-comparison}
|
\label{tab:gpu-comparison}
|
||||||
@ -938,12 +1027,12 @@ vkCmdBindPipeline / klatkę & 2 & 218 \\
|
|||||||
Analiza wywołań Vulkan API ujawnia fundamentalnie różne profile obciążenia (tabela~\ref{tab:gpu-comparison}):
|
Analiza wywołań Vulkan API ujawnia fundamentalnie różne profile obciążenia (tabela~\ref{tab:gpu-comparison}):
|
||||||
|
|
||||||
\paragraph{Unity -- scenariusz GPU-bound}
|
\paragraph{Unity -- scenariusz GPU-bound}
|
||||||
Dominacja \texttt{vkWaitForFences} (95,2\% czasu) wskazuje, że CPU efektywnie przygotowuje pracę i oczekuje na GPU.
|
Dominacja \texttt{vkWaitForFences} (95,2\% czasu) \\ wskazuje, że CPU efektywnie przygotowuje pracę i oczekuje na GPU.
|
||||||
Jest to pożądany wzorzec w aplikacjach graficznych, gdzie GPU wykonuje większość obliczeń. Niski stosunek
|
Jest to pożądany wzorzec w aplikacjach graficznych, gdzie GPU wykonuje większość obliczeń. \\ Niski stosunek
|
||||||
\texttt{vkQueueSubmit}/klatkę (2:1) świadczy o prostym, dwuetapowym potoku renderowania.
|
\texttt{vkQueueSubmit}/klatkę (2:1) świadczy o prostym, dwuetapowym potoku renderowania.
|
||||||
|
|
||||||
\paragraph{Unreal Engine -- kompilacja potoków jako wąskie gardło}
|
\paragraph{Unreal Engine -- kompilacja potoków jako wąskie gardło}
|
||||||
W Unreal Engine dominującymi operacjami były \texttt{vkCreateComputePipelines} i \texttt{vkCreateGraphicsPipelines},
|
W Unreal Engine dominującymi operacjami były \texttt{vkCreateComputePipelines} \\ oraz \texttt{vkCreateGraphicsPipelines},
|
||||||
pochłaniające łącznie 57--72\% czasu Vulkan. Silnik tworzy około \textbf{1000 potoków w każdej 30-sekundowej fazie}
|
pochłaniające łącznie 57--72\% czasu Vulkan. Silnik tworzy około \textbf{1000 potoków w każdej 30-sekundowej fazie}
|
||||||
(vs 3 potoki w całym teście Unity), co wskazuje na strategię dynamicznej kompilacji shaderów.
|
(vs 3 potoki w całym teście Unity), co wskazuje na strategię dynamicznej kompilacji shaderów.
|
||||||
|
|
||||||
@ -952,7 +1041,7 @@ z wieloma wariantami shaderów, co wprowadza znaczący narzut zmian stanu GPU.
|
|||||||
|
|
||||||
\subsubsection{Porównanie architektury wielowątkowej}
|
\subsubsection{Porównanie architektury wielowątkowej}
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Porównanie mechanizmów synchronizacji między silnikami}
|
\caption{Porównanie mechanizmów synchronizacji między silnikami}
|
||||||
\label{tab:threading-comparison}
|
\label{tab:threading-comparison}
|
||||||
@ -979,7 +1068,7 @@ małych zadań często komunikujących się ze sobą (ponad 3 miliony wywołań
|
|||||||
\subsection{Podsumowanie wyników testów wydajności}
|
\subsection{Podsumowanie wyników testów wydajności}
|
||||||
\label{subsec:podsumowanie-testow}
|
\label{subsec:podsumowanie-testow}
|
||||||
|
|
||||||
\begin{table}[htbp]
|
\begin{table}[H]
|
||||||
\centering
|
\centering
|
||||||
\caption{Zestawienie kluczowych wyników testów wydajności}
|
\caption{Zestawienie kluczowych wyników testów wydajności}
|
||||||
\label{tab:wyniki-wydajnosci}
|
\label{tab:wyniki-wydajnosci}
|
||||||
@ -987,9 +1076,9 @@ małych zadań często komunikujących się ze sobą (ponad 3 miliony wywołań
|
|||||||
\hline
|
\hline
|
||||||
\textbf{Metryka} & \textbf{Unity} & \textbf{Unreal Engine} \\
|
\textbf{Metryka} & \textbf{Unity} & \textbf{Unreal Engine} \\
|
||||||
\hline
|
\hline
|
||||||
Średni FPS & 144 & 343--384 \\
|
Średni FPS (fazy 1--2) & 144 (V-Sync) & 343--384 \\
|
||||||
Mediana czasu klatki (ms) & 6,94 & 2,60--2,91 \\
|
FPS w wymagającej scenie & 132 (1\% low) & 153 (faza 3) \\
|
||||||
GPU Active (\%) & -- & 90,98 \\
|
GPU Active (\%) & -- & 91 (fazy 1--2), 50 (faza 3) \\
|
||||||
Dominujące wąskie gardło & GPU (rendering) & CPU (kompilacja potoków) \\
|
Dominujące wąskie gardło & GPU (rendering) & CPU (kompilacja potoków) \\
|
||||||
Wywołania Vulkan API & 218\,815 & $\sim$15 mln \\
|
Wywołania Vulkan API & 218\,815 & $\sim$15 mln \\
|
||||||
Wywołania synchronizacji OS & 29\,383 & $\sim$9 mln \\
|
Wywołania synchronizacji OS & 29\,383 & $\sim$9 mln \\
|
||||||
@ -1001,15 +1090,26 @@ Potoki graficzne utworzone & 3 & $\sim$2\,400 \\
|
|||||||
Przeprowadzone testy wydajnościowe pozwalają na sformułowanie następujących wniosków:
|
Przeprowadzone testy wydajnościowe pozwalają na sformułowanie następujących wniosków:
|
||||||
|
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
\item \textbf{Surowa wydajność}: Unreal Engine osiągnął wyższą liczbę klatek na sekundę (343--384 vs 144 FPS),
|
\item \textbf{Wydajność w wymagających scenach}: Porównanie to Unity
|
||||||
co przeczy hipotezie o przewadze Unity w grach 2D
|
1\% low (132 FPS) vs
|
||||||
|
Unreal faza 3 (153 FPS), gdzie różnica wynosi około 16\%. Unreal Engine wykazuje jednak
|
||||||
|
znaczący spadek wydajności
|
||||||
|
(o ponad 60\%) w końcowej fazie rozgrywki z dużą liczbą obiektów na ekranie.
|
||||||
|
|
||||||
\item \textbf{Stabilność}: Unity wykazał lepszą stabilność czasów klatek z wąskim rozstępem międzykwartylowym
|
\item \textbf{Stabilność}: Unity wykazał stabilne czasy klatek dzięki V-Sync, \\ natomiast
|
||||||
(0,08 ms) i małą różnicą między medianą a 99. percentylem (9,2\%)
|
Unreal Engine pokazał
|
||||||
|
dużą zmienność między fazami (343--384 FPS w fazach 1--2 vs 153 FPS w fazie 3).
|
||||||
|
|
||||||
\item \textbf{Architektura}: Silniki stosują fundamentalnie różne podejścia do wielowątkowości i zarządzania
|
\item \textbf{Architektura}: Silniki stosują fundamentalnie różne podejścia do \\
|
||||||
potokami renderowania, co ma implikacje dla skalowalności i responsywności
|
wielowątkowości
|
||||||
|
i zarządzania
|
||||||
|
potokami renderowania. Unity używa gruboziarnistego paralelizmu z rzadkimi synchronizacjami,
|
||||||
|
podczas gdy Unreal
|
||||||
|
stosuje drobnoziarnisty system TaskGraph z milionami wywołań synchronizacyjnych.
|
||||||
|
|
||||||
\item \textbf{Narzut Unreal}: Dynamiczna kompilacja potoków i drobnoziarnisty paralelizm wprowadzają znaczący
|
\item \textbf{Narzut Unreal}: Dynamiczna kompilacja potoków (ponad 1000 potoków na
|
||||||
narzut (15 mln wywołań Vulkan vs 219 tys.), który jednak nie przekłada się na niższą wydajność końcową
|
30-sekundową fazę vs 3 w całym
|
||||||
|
teście Unity) i intensywna komunikacja międzywątkowa stanowią znaczący narzut, który
|
||||||
|
może przyczyniać się do
|
||||||
|
spadków wydajności w wymagających scenach.
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user