Я пытаюсь оценить производительность простых операций с матричной матрицей GPU с помощью ArrayFire.Сроки в ArrayFire
В частности, с учетом
int N1 = something;
int N2 = something;
array A_D = constant(1.,N1*N2,1,f64);
array B_D = constant(1.,N1*N2,1,f64);
array C_D = constant(1.,N1*N2,1,f64);
array D_D = constant(1.,N1*N2,1,f64);
Я хотел бы выполнить синхронизацию следующей инструкции
D_D = A_D + B_D + C_D + 3.;
Я использую два подхода. Первый
timer time_last;
time_last = timer::start();
D_D = A_D + B_D + C_D + 3.;
double elapsed = timer::stop(time_last);
printf("elapsed time using start and stop = %g ms \n",1000.*elapsed);
второй один является определяющим следующую функцию
void timing_test()
{
int N1 = something;
int N2 = something;
array A_D = constant(1.,N1*N2,1,f64);
array B_D = constant(1.,N1*N2,1,f64);
array C_D = constant(1.,N1*N2,1,f64);
array D_D = constant(1.,N1*N2,1,f64);
D_D = A_D + B_D + C_D + 3.;
}
и затем вызвать
printf("elapsed time using timeit %g ms \n", 1000.*timeit(timing_test));
я получил следующие результаты:
(N1,N2)=(256,256)
первый подход = 0.0456ms
второй подход = 0.264ms
(N1,N2)=(512,512)
Первый подход = 0.0451ms
Второй подход = 0.264ms
(N1,N2)=(1024,1024)
Первый подход = 0.0457ms
Второй подход = 0.263ms
(N1,N2)=(2048,2048)
Первый подход = 0.127ms
Второй подход = 0.265ms
Я также с использованием после «ручной кодированной» версии выражения в соответствии с
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
eval_matrix_wrap_handcoded(A_D,B_D,C_D,D_D,N1*N2);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time, start, stop);
template <class T1, class T2, class T3, class T4>
__global__ inline void evaluation_matrix_handcoded(T1 *A_D, T2 *B_D, T3 *C_D, T4 *D_D, int NumElements)
{
const int i = blockDim.x * blockIdx.x + threadIdx.x;
if(i < NumElements) D_D[i]=A_D[i]+B_D[i]+C_D[i]+3.;
}
__host__ void eval_matrix_wrap_handcoded(double *A_D, double *B_D, double *C_D, double *D_D, int NumElements)
{
dim3 dimGrid(iDivUp(NumElements,dimBlock.x));
evaluation_matrix_handcoded<<<dimGrid,dimBlock>>>(A_D,B_D,C_D,D_D,NumElements);
}
получения следующего
(N1,N2)=(256,256)
0.0897ms
(N1,N2)=(512,512)
0.339ms
(N1,N2)=(1024,1024)
1.3ms
(N1,N2)=(2048,2048)
5.37ms
Странная вещь:
- Результаты двух подходов разные. Это может быть связано с накладными расходами на функции, но в любом случае странно, что эти накладные расходы меняются, когда
(N1,N2)=(2048,2048)
. - Результаты двух подходов практически не зависят от размеров матрицы.
- Результаты значительно отличаются от «выраженной вручную» версии выражения (я предполагаю, что библиотека должна иметь компромисс производительности производительности).
Обратите внимание, что перед любой операцией, я прогрев GPU с использованием кода
array test1(1,5);
test1(0,0)=1;
test1(0,1)=2;
test1(0,2)=3;
test1(0,3)=4;
test1(0,4)=5;
Может кто-то помочь мне интерпретировать полученные результаты? Благодарю.
РЕДАКТИРОВАТЬ ответить на следующий PAVAN'S
Первого метод модифицировано для
timer time_last;
time_last = timer::start();
D_D = A_D + B_D + C_D + 3.;
D_D.eval();
af::sync();
double elapsed = timer::stop(time_last);
printf("elapsed time using start and stop = %g ms \n",1000.*elapsed);
Второго метода модифицированного
void timing_test()
{
int N1 = something;
int N2 = something;
array A_D = constant(1.,N1*N2,1,f64);
array B_D = constant(1.,N1*N2,1,f64);
array C_D = constant(1.,N1*N2,1,f64);
array D_D = constant(1.,N1*N2,1,f64);
D_D = A_D + B_D + C_D + 3.;
D_D.eval();
}
Однако время сейчас
`(N1,N2)=(256,256)` first approach = `14.7ms` second approach = `2.04ms`
`(N1,N2)=(512,512)` first approach = `14.3ms` second approach = `2.04ms`
`(N1,N2)=(1024,1024)` first approach = `14.09ms` second approach = `2.04ms`
`(N1,N2)=(2048,2048)` first approach = `16.47ms` second approach = `2.04ms`
, и у меня все еще есть разные тайминги и независимы от размера векторов.
Если я изменить первый метод
D_D = A_D + B_D + C_D + 3.;
D_D.eval();
timer time_last;
time_last = timer::start();
D_D = A_D + B_D + C_D + 3.;
D_D.eval();
af::sync();
double elapsed = timer::stop(time_last);
printf("elapsed time using start and stop = %g ms \n",1000.*elapsed);
а именно, я «увеличение» ГПУ разогрев этап, я получить, для первого метода,
`(N1,N2)=(256,256)` `0.19ms`
`(N1,N2)=(512,512)` `0.42ms`
`(N1,N2)=(1024,1024)` `1.18ms`
`(N1,N2)=(2048,2048)` `4.2ms`
, который появляется более разумный для меня, поскольку время зависит от размера данных и ближе к ручному кодированию.
ВТОРОЙ EDIT Подводя итог: я приходилась на ответ и комментарий, и, на первый подход, я использую
D_D = A_D + B_D + C_D + 3.;
D_D.eval();
timer time_last;
af::sync();
time_last = timer::start();
D_D = A_D + B_D + C_D + 3.;
D_D.eval();
af::sync();
double elapsed = timer::stop(time_last);
printf("elapsed time using start and stop = %g ms \n",1000.*elapsed);
я получить следующие (новые) результаты:
`(N1,N2)=(256,256)` `0.18ms`
`(N1,N2)=(512,512)` `0.30ms`
`(N1,N2)=(1024,1024)` `0.66ms`
`(N1,N2)=(2048,2048)` `2.18ms`
Большое спасибо за ваш ответ. Я применил ваши предложения, но, похоже, у меня все еще есть проблемы. Я также отредактировал свой пост, чтобы представить последние результаты. Похоже, что если я «увеличу количество» разминки ГПУ, я получу более разумные результаты. Являются ли они окончательными таймингами. Я что-то пропустил? – JackOLantern
Спасибо. Я обновил свой пост с новыми результатами, включая дополнительный 'af :: sync()', который вы рекомендовали. Они выглядят разумно, так как время увеличивается с размером векторов. Но должен ли я теперь делать какие-либо действия для случая «timeit» (второй подход) для получения аналогичных результатов? Я все еще получаю постоянное время '2ms'. Заранее благодарим за любую дальнейшую помощь. – JackOLantern