У меня есть код MATLAB с ускорением на GPU, который тратит 80% -90% своего времени на вычисления
sum(a.*exp(b.*c),1)
, где
size(a) = [n 1]
size(b) = [n 1]
size(c) = [1 m]
n можно выбрать для быть сколь угодно большим (в пределах ограничений памяти)
5000 <<strong> m <20000 </p>
Я хотел бы ускорить это больше, чем просто используя gpuArrays (примерно 17x для удвоения точность).
Сравнительный анализ
Используя MATLAB 2018b и графический процессор NVIDIA P100, я запустил следующий скрипт, чтобы найти оптимальный размер n . Это показывает, что я достигаю 17-кратного ускорения по сравнению с процессором (Dual Socket Intel Xeon E5-2650v2) с двойной точностью. Могу ли я улучшить это, сделав что-то более продвинутое, например, используя GPU-кодер, или даже совместно используемую память или текстурную память, как описано ниже? https://uk.mathworks.com/help/parallel-computing/examples/accessing-advanced-cuda-features-using-mex.html
%% Optimisation MWE
nVec = 1000:1000:60000; % Vector of candidate n values
m = 5000;
f1 = figure(1);
ax(1) = subplot(3,1,1);
ax(2) = subplot(3,1,2);
ax(3) = subplot(3,1,3);
% Preallocate time outputs
t = nan(length(nVec),3);
speedupGPU = nan(length(nVec),2);
% Loop over candidate n values
for n = 1:length(nVec)
%% CPU code
a = rand(nVec(n),1);
b = rand(nVec(n),1);
c = rand(1,m);
f1 = @() sum(a.*exp(b.*c),1);
t(n,1) = timeit(f1,1);
%% GPU code (double precision)
a = gpuArray(a);
b = gpuArray(b);
c = gpuArray(c);
f2 = @() sum(a.*exp(b.*c),1);
t(n,2) = gputimeit(f2);
%% GPU code (single precision)
a = single(a);
b = single(b);
c = single(c);
f3 = @() sum(a.*exp(b.*c),1);
t(n,3) = gputimeit(f3);
%% Calculate speedup
speedupGPU(n,1) = t(n,1)/t(n,2);
speedupGPU(n,2) = t(n,1)/t(n,3);
%% Plot
plot(ax(1),nVec,t,'.-') % Plot compute time
plot(ax(2),nVec,t./nVec(:),'.-') % Plot normalised compute time
plot(ax(3),nVec,speedupGPU,'.-') % Plot Speedup
%% Label plots
xlabel(ax(1),'n')
ylabel(ax(1),'Time')
legend(ax(1),'CPU','GPU double','GPU single')
xlabel(ax(2),'n')
ylabel(ax(2),'Normalised Time')
legend(ax(2),'CPU','GPU double','GPU single')
xlabel(ax(3),'n')
ylabel(ax(3),'Speedup')
legend(ax(3),'CPU/GPU double','CPU/GPU single')
drawnow
end
Это приводит к следующему рисунку (вверху: время выполнения с увеличением n (чем меньше, тем лучше), в середине: время выполнения, нормализованное на n (чем меньше, тем лучше) , снизу: ускорение относительно процессора (чем больше, тем лучше)):