Skip to content

Commit

Permalink
Update performance section
Browse files Browse the repository at this point in the history
  • Loading branch information
fuodorov committed Feb 7, 2024
1 parent 7bac182 commit 11620cd
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 0 deletions.
1 change: 1 addition & 0 deletions main.tex
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@
\input{src/texts/kenv_listing}
\input{src/texts/kenv_gui}
\input{src/texts/redpic_dockerfile}
\input{src/texts/redpic_test_performance}

\end{document}
Binary file added src/figures/test_redpic_performance_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/figures/test_redpic_performance_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/texts/abbreviations.tex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
\item GUI "--- graphical user interface (графический интерфейс пользователя)
\item ОДУ "--- обыкновенное дифференциальное уравнение
\item ЭВМ "--- электронная вычислительная машина
\item ПК "--- персональный компьютер
\item ОС "--- операционная система
\item ПО "--- программное обеспечение
\item ООП "--- объектно ориентированное программирование
Expand Down
35 changes: 35 additions & 0 deletions src/texts/redpic_performance.tex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,41 @@ \subsubsection{Параллелизм на GPU}
Это позволяет выполнять параллельные операции над большими объемами данных с высокой производительностью.
Задача разбивается на блоки и потоки, что позволяет эффективно использовать ресурсы GPU.

\subsection{Анализ производительности в разных режимах работы}
Проанализируем производительность ПО для разного количества частиц на примере его одной из самых затратных по количеству элементарных операций функции \lstinline{sum_field_particles} (см. листинг~\ref{lst:sum_field_particles}), которая нужна для расчета эффекта пространственного заряда.
Вычислительная сложность данной функции $O(N^2)$, где $N$ "--- это количество частиц.
Подробное описание теста и код приведен в приложении~\ref{lst:appendix_test_performance_redpic}.

\begin{lstlisting}[language=python, caption={Функция для расчета эффекта пространственного заряда}, label={lst:sum_field_particles}]
def sum_field_particles(
x: np.array, y: np.array, z: np.array, z_start: float, z_stop: float, Fx: np.array, Fy: np.array, Fz: np.array
) -> None:
for i in range(int(len(x))): # pylint: disable=E1133
if z_start <= z[i] <= z_stop:
for j in range(int(len(x))):
if z_start <= z[j] <= z_stop and i != j:
Fx[i] += (x[i] - x[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
Fy[i] += (y[i] - y[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
Fz[i] += (z[i] - z[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
\end{lstlisting}

На рисунке~\ref{fig:test_performance_redpic} представлены графики, показывающие зависимость времени выполнения функции от количества частиц для трех различных режимов: без JIT-оптимизации, с JIT-оптимизацией и с JIT-оптимизацией с параллелизмом.
Есть значительное улучшение производительности при использовании JIT и дополнительное ускорение при включении параллелизма для больших наборов данных.
Для тестирования использовался ПК с процессором \lstinline{Intel(R) Xeon(R) E-2288G CPU @ 3.70GHz} (8~ядер).

\begin{figure}[!h]
\centering
\begin{minipage}[h]{0.49\linewidth}
\center{\includegraphics[width=1\textwidth]{test_redpic_performance_1}}
\end{minipage}
\hfill
\begin{minipage}[h]{0.49\linewidth}
\center{\includegraphics[width=1\textwidth]{test_redpic_performance_2}}
\end{minipage}
\caption{Зависимость времени выполнения функции \lstinline{sum_field_particles} от количества частиц для трех различных режимов}
\label{fig:test_performance_redpic}
\end{figure}

Использование JIT-компиляции и параллельных вычислений с помощью библиотеки Numba позволяет значительно повысить производительность программ на Python.
Это делает возможным решение вычислительно сложных задач без использования суперкомпьютеров.

Expand Down
67 changes: 67 additions & 0 deletions src/texts/redpic_test_performance.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
\Appendix
\begin{center}
Тест производительности функции для расчета эффекта пространственного заряда в разных режимах работы REDPIC
\end{center}

\begin{lstlisting}[language=python, caption={Тест производительности функции для расчета эффекта пространственного заряда в разных режимах работы REDPIC}, label={lst:appendix_test_performance_redpic}]
import numpy as np
from numba import njit, prange
import matplotlib.pyplot as plt
import time

def sum_field_particles(
x: np.array, y: np.array, z: np.array, z_start: float, z_stop: float, Fx: np.array, Fy: np.array, Fz: np.array
) -> None:
for i in range(int(len(x))): # pylint: disable=E1133
if z_start <= z[i] <= z_stop:
for j in range(int(len(x))):
if z_start <= z[j] <= z_stop and i != j:
Fx[i] += (x[i] - x[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
Fy[i] += (y[i] - y[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
Fz[i] += (z[i] - z[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)


def sum_field_particles_parallel_cpu(
x: np.array, y: np.array, z: np.array, z_start: float, z_stop: float, Fx: np.array, Fy: np.array, Fz: np.array
) -> None:
for i in prange(int(len(x))): # pylint: disable=E1133
if z_start <= z[i] <= z_stop:
for j in range(int(len(x))):
if z_start <= z[j] <= z_stop and i != j:
Fx[i] += (x[i] - x[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
Fy[i] += (y[i] - y[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)
Fz[i] += (z[i] - z[j]) / ((x[j] - x[i]) ** 2 + (y[j] - y[i]) ** 2 + (z[j] - z[i]) ** 2) ** (3 / 2)


jit_sum_field_particles = njit(sum_field_particles)
cpu_parallel_jit_sum_field_particles = njit(parallel=True)(sum_field_particles_parallel_cpu)

def measure_time(func, *args):
start_time = time.time()
func(*args)
return time.time() - start_time

particle_counts = [2**i for i in range(13)]
times_no_jit = []
times_jit = []
times_cpu_parallel_jit = []

for N in particle_counts:
x, y, z = np.random.rand(N), np.random.rand(N), np.random.rand(N)
Fx, Fy, Fz = np.zeros(N), np.zeros(N), np.zeros(N)
z_start, z_stop = 0.0, 1.0

times_no_jit.append(measure_time(sum_field_particles, x, y, z, z_start, z_stop, Fx, Fy, Fz))
times_jit.append(measure_time(jit_sum_field_particles, x, y, z, z_start, z_stop, Fx, Fy, Fz))
times_cpu_parallel_jit.append(measure_time(cpu_parallel_jit_sum_field_particles, x, y, z, z_start, z_stop, Fx, Fy, Fz))

plt.figure(figsize=(10, 6))
plt.plot(particle_counts, times_no_jit, label='without JIT', marker='o')
plt.plot(particle_counts, times_jit, label='with JIT', marker='s')
plt.plot(particle_counts, times_cpu_parallel_jit, label='with parallel CPU', marker='^')
plt.xlabel('Particles, $N$')
plt.ylabel('Time, $t$ [s]')
plt.legend()
plt.grid(True)
plt.show()
\end{lstlisting}

0 comments on commit 11620cd

Please sign in to comment.