Как повысить производительность с помощью асинхронного копирования в OpenCL? - PullRequest
0 голосов
/ 16 мая 2019

Я пишу программу, которая выполняет Matrix-Vector-Multiplication на всех доступных устройствах OpenCL. Любое устройство работает в потоке с собственным контекстом и CommandQueue. Матрица разделена на двумерные сегменты определенного пользователем размера.

Проблема в том, что функция enqueueReadBuffer вызывается в режиме блокировки, поскольку возвращаемый результат должен суммироваться с общим результатом. Из-за этого сегментные буферы не могут заполняться параллельно для следующей итерации.

Вот фрагмент кода, который выполняет каждый поток / устройство:

vector<cl::Event> write_events(2, cl::Event()), calc_events(1, cl::Event());

while (_segment_queue->get_next_segment(&_next_x_offset, &_next_y_offset, _device_nr) != -1){
    for(int i = 0; i < _segment_size_y; i++) {//ToDo: Eventuell Einsatz von CopyBuffer
        if(i < _segment_size_y -1)
            _command_queue.enqueueWriteBuffer(_device_buffer_A, CL_FALSE, sizeof(float) * i * _segment_size_x, sizeof(float) * _segment_size_x,
                                          (void *) &_host_Buffer_A[(_next_y_offset + i) * _x_count + _next_x_offset], NULL, NULL);
        else
            _command_queue.enqueueWriteBuffer(_device_buffer_A, CL_FALSE, sizeof(float) * i * _segment_size_x, sizeof(float) * _segment_size_x,
                                              (void *) &_host_Buffer_A[(_next_y_offset + i) * _x_count + _next_x_offset], NULL, &write_events[0]);
    }
    _command_queue.enqueueWriteBuffer(_device_buffer_B,CL_FALSE,0,sizeof(float)*_segment_size_x, (void *) &_host_Buffer_B[_next_x_offset], NULL, &write_events[1]);


    cl::Kernel MV_Mul(_program, "matrixVectorMul");
    MV_Mul.setArg(0, _device_buffer_A);
    MV_Mul.setArg(1, _device_buffer_B);
    MV_Mul.setArg(2, _device_buffer_C);
    MV_Mul.setArg(3, _segment_size_x);

    _command_queue.enqueueNDRangeKernel(MV_Mul,cl::NullRange, cl::NDRange(_segment_size_y), cl::NDRange(_wg_size), &write_events, &calc_events[0]);
    _command_queue.enqueueReadBuffer(_device_buffer_C, CL_TRUE, 0, sizeof(float)*_segment_size_y, _C_temp, &calc_events, NULL);
    {
        unique_lock<mutex> lock(_mut[_next_y_offset/_segment_size_y]);
        for(int i = 0; i<_segment_size_y; i++)
            _host_Buffer_C[_next_y_offset + i] += _C_temp[i];
    }
}

У меня вопрос: есть ли простой способ, как я могу выполнить вызов enqueueWriteBuffer параллельно с вызовом enqueueReadBuffer?

...