Почему неявное расширение не всегда выполняется быстрее на GPU?

#matlab

#matlab

Вопрос:

Я пытаюсь вычесть две матрицы «разных» размеров в Matlab на моем графическом процессоре.

 a = randn(87,1,10,'single','gpuArray');
b = randn(87,100000,1,'single','gpuArray');

dev = gpuDevice;
tic
out1 = a-b;
wait(dev)
toc

tic
a = repmat(a,[1 size(b,2) 1]);
b = repmat(b,[1 1 size(a,3)]);
out2 = a-b;
wait(dev)
toc
  

Как вы можете видеть, неявное расширение происходит во втором и третьем измерениях. Как правило, неявное расширение выполняется намного быстрее, чем репликация матриц. Однако в этом случае это дает результат:

 Elapsed time is 0.033324 seconds.
Elapsed time is 0.018052 seconds.
  

Это вызывает недоумение, потому что репликация матриц происходит намного быстрее, чем просто предоставление неявному расширению возможности обрабатывать разницу. Я протестировал это на процессоре и получил:

 Elapsed time is 0.078726 seconds.
Elapsed time is 0.356435 seconds.
  

Что именно здесь происходит? Почему неявное расширение происходит намного медленнее?

Я протестировал это на предварительных версиях Matlab 2018b и 2019a и получил этот результат на обоих.

Редактировать: по многочисленным просьбам я использовал функции timeit и gputimeit для обеих, и это только подтвердило мои результаты

 clear
close all
a = randn(87,1,10,'single','gpuArray');
b = randn(87,100000,1,'single','gpuArray');

dev = gpuDevice;
disp(gputimeit(@() a-b))

disp(gputimeit(@() a>b))

t1 = gputimeit(@() repmat(a,[1 size(b,2) 1])) gputimeit(@() repmat(b,[1 1 size(a,3)]));
a = repmat(a,[1 size(b,2) 1]);
b = repmat(b,[1 1 size(a,3)]);

disp(t1 gputimeit(@() a-b))

disp(gputimeit(@() a>b))

clear
close all
a = randn(87,1,10,'single');
b = randn(87,100000,1,'single');

disp(timeit(@() a-b))

disp(timeit(@() a>b))

t1 = timeit(@() repmat(a,[1 size(b,2) 1])) timeit(@() repmat(b,[1 1 size(a,3)]));
a = repmat(a,[1 size(b,2) 1]);
b = repmat(b,[1 1 size(a,3)]);

disp(t1 timeit(@() a-b))

disp(timeit(@() a>b))
  

И времена:

     0.0249880485773384

    0.0191386963821538

    0.0159509649972431

   0.00518230250048866

    0.0980248506300088

    0.0545817410501994

     0.283484452903233

    0.0540456719899175
  

Комментарии:

1. Предварительный выпуск @SardarUsama

2. tic / too не самый лучший способ рассчитать время. При загрузке функций в первый раз возникают накладные расходы, а быстрые операции будут иметь большую неопределенность во времени. Вам лучше поместить код для синхронизации в функцию, а затем использовать timeit для измерения времени, необходимого для запуска этой функции.

3.В продолжение комментария @Cris соответствующая команда для синхронизации на графических процессорах gputimeit mathworks.com/help/distcomp/gputimeit.html

4. @NickyMattsson Я сделал это, и это не имеет значения. Для этого и предназначены wait(dev) инструкции, это именно то, что gputimeit делает

5. tic toc с wait(dev) — это не то же самое, что gputimeit . tic toc это простой секундомер, timeit который gputimeit может запускать код несколько раз и находить медиану времени выполнения. Но, конечно, есть много случаев, когда простой секундомер является репрезентативным, и они дадут тот же ответ.