Перемножение матриц на разных вычислителях¶
В этом примере мы покажем, как изучить производительность кода при помощи инструментария BenchmarkTools
и сравним его выполнение на CPU и на GPU.
Подключение к GPU¶
Наличие у пользователей ресурсов GPU пока остается премиум-функцией платформы Engee. GPU – графическая видеокарта, позволяющая существенно распараллелить выполнение кода путем его выполнения на десятках тысячах вычислительных ядер, находящихся внутри графического сопроцессора.
Основной библиотекой для работы с GPU является CUDA.jl
(есть и другие, не такие стабильные). Установим эту библиотеку, а вместе с ней – инструментарий для оценки производительности кода.
# Закомментируйте эту строку, если будете устанавливать библиотеки другим образом
using Pkg; Pkg.add( ["CUDA", "BenchmarkTools"] ); # <- может занять много времени
Перемножение матриц на CPU¶
Посмотрим, сколько времени в среднем занимает перемножение матриц на обычном процессоре.
N = 1_000
A = rand(ComplexF64, (N,N))
B = rand(ComplexF64, (N,N))
using BenchmarkTools
@benchmark A*B
Выполнение этой ячейки заняло довольно много времени, поскольку команда @benchmark
запускает переданную ей операцию много тысяч раз, чтобы исключить эффект "разогрева", присущий Julia. Иногда это также сглаживает влияние плохого стечения обстоятельств, когда код показывает минимально возможную производительность.
В данном конкретном случае показал, что перемножение матриц комплексных чисел размером 1000 на 1000 в среднем занимает 300 миллисекунд.
Перемножение матриц на GPU¶
Чтобы перемножить матрицы на видеокарте их нужно перенести на нее, что можно сделать множеством способов. Например, командой A |> gpu
, но поскольку в системе может не оказаться GPU, мы проверим конфигурацию вычислительного пространства и выберем доступный вычислитель.
После переноса матрицы Matrix
теперь являются объектами CuArray
. Их перемножение между собой выполняется без дополнительного кода (благодаря перегрузке оператора умножения). Но умножить матрицу A_gpu
на матрицу B
мы не сможем без переноса обеих матриц на один и тот же вычислитель (иначе вы получите ошибку KernelError: kernel returns a value of type Union{}
).
using CUDA
if CUDA.functional()
A_gpu = A |> gpu
B_gpu = B |> gpu
@benchmark A_gpu * B_gpu
end
На GPU A100 перемножение тех же матриц занимает около 20 микросекунд, то есть операция выполнилась в 15 000 раз быстрее, чем на CPU.
Заключение¶
Julia позволяет переносить вычисления на GPU и многие библиотеки поддерживают этот способ работы. Мы выполнили перемножение матриц на процессоре и на графической видеокарте и определили, что матрицы квадратные матрицы с размером стороны 1000, состоящие из случайных комплексных чисел, графическая видеокарта перемножила в 15 000 раз быстрее, чем процессор.