2014-10-31 1 views
0

У меня есть проект в OpenCL. Это матричная декомпозиция на графическом процессоре. Все работает отлично, и результаты в порядке. Единственное, что я вижу, это то, что когда я выполняю программу несколько раз подряд (раз в секунду или около того), я получаю нарушения доступа, когда пишу свои начальные буферы на устройство.Нарушение доступа OpenCL при записи буфера на устройство

Это всегда при записи буферов, которые он застревает. Я очень новичок в OpenCL, и мне интересно, возможно ли мне очистить память в моем GPU, когда я выхожу из своей программы? Иногда он сбой при первом запуске, но после двух или трех попыток. Опять же, иногда это происходит сразу же, как и последующие прогоны. Это просто случайный случай. Реальная запись буфера, которая не работает, также время от времени отличается. Иногда это третий буферный напиток, который терпит неудачу, иногда четвертый.

Параметры, которыми я управляю этой программой, имеют размер рабочей группы 7 и матрицу из 70 * 70 элементов. Сначала я подумал, что может быть, что моя матрица слишком велика для GPU (GT650M с 2 ГБ), но иногда побег с матрицей ox 10.000 элементов также преуспевает.

Код до буфера записи приведен ниже.

Любая помощь с благодарностью.

Ps: для большей ясности, PRECISION - макрос #define PRECISION float.

int main(int argc, char *argv[]) 
{ 
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    //// INITIALIZATION PART /////////////////////////////////////////////////////////////////////////////////////// 
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    try { 
     if (argc != 5) { 
      std::ostringstream oss; 
      oss << "Usage: " << argv[0] << " <kernel_file> <kernel_name> <workgroup_size> <array width>"; 
      throw std::runtime_error(oss.str()); 
     } 
     // Read in arguments. 
     std::string kernel_file(argv[1]); 
     std::string kernel_name(argv[2]); 
     unsigned int workgroup_size = atoi(argv[3]); 
     unsigned int array_dimension = atoi(argv[4]); 
     int total_matrix_length = array_dimension * array_dimension; 

     int total_workgroups = total_matrix_length/workgroup_size; 
     total_workgroups += total_matrix_length % workgroup_size == 0 ? 0 : 1; 

     // Print parameters 
     std::cout << "Workgroup size: " << workgroup_size  << std::endl; 
     std::cout << "Total workgroups: " << total_workgroups << std::endl; 
     std::cout << "Array dimension: " << array_dimension  << " x " << array_dimension << std::endl; 
     std::cout << "Total elements: " << total_matrix_length << std::endl; 


     // OpenCL initialization 
     std::vector<cl::Platform> platforms; 
     std::vector<cl::Device> devices; 
     cl::Platform::get(&platforms); 
     platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices); 
     cl::Context context(devices); 
     cl::CommandQueue queue(context, devices[0], CL_QUEUE_PROFILING_ENABLE); 

     // Load the kernel source. 
     std::string file_text; 
     std::ifstream file_stream(kernel_file.c_str()); 
     if (!file_stream) { 
      std::ostringstream oss; 
      oss << "There is no file called " << kernel_file; 
      throw std::runtime_error(oss.str()); 
     } 
     file_text.assign(std::istreambuf_iterator<char>(file_stream), std::istreambuf_iterator<char>()); 

     // Compile the kernel source. 
     std::string source_code = file_text; 
     std::pair<const char *, size_t> source(source_code.c_str(), source_code.size()); 
     cl::Program::Sources sources; 
     sources.push_back(source); 
     cl::Program program(context, sources); 
     try { 
      program.build(devices); 
     } 
     catch (cl::Error& e) { 
      getchar(); 
      std::string msg; 
      program.getBuildInfo<std::string>(devices[0], CL_PROGRAM_BUILD_LOG, &msg); 
      std::cerr << "Your kernel failed to compile" << std::endl; 
      std::cerr << "-----------------------------" << std::endl; 
      std::cerr << msg; 
      throw(e); 
     } 
     //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     //// CREATE RANDOM INPUT DATA ////////////////////////////////////////////////////////////////////////////////// 
     //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

     // Create matrix to work on. 
     // Create a random array. 
     int matrix_width   = sqrt(total_matrix_length); 
     PRECISION* random_matrix = new PRECISION[total_matrix_length]; 
     random_matrix   = randommatrix(total_matrix_length); 
     PRECISION* A    = new PRECISION[total_matrix_length]; 

     for (int i = 0; i < total_matrix_length; i++) 
      A[i] = random_matrix[i]; 

     PRECISION* L_SEQ = new PRECISION[total_matrix_length]; 
     PRECISION* U_SEQ = new PRECISION[total_matrix_length]; 
     PRECISION* P_SEQ = new PRECISION[total_matrix_length]; 

     // Do the sequential algorithm. 
     decompose(A, L_SEQ, U_SEQ, P_SEQ, matrix_width); 
     float* PA = multiply(P_SEQ, A, total_matrix_length); 
     float* LU = multiply(L_SEQ, U_SEQ, total_matrix_length); 
     std::cout << "PA = LU?" << std::endl; 
     bool eq = equalMatrices(PA, LU, total_matrix_length); 
     std::cout << eq << std::endl; 
     //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     //// RUN AND SETUP KERNELS ///////////////////////////////////////////////////////////////////////////////////// 
     //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

     // Initialize arrays for GPU. 
     PRECISION* L_PAR = new PRECISION[total_matrix_length]; 
     PRECISION* U_PAR = new PRECISION[total_matrix_length]; 
     PRECISION* P_PAR = new PRECISION[total_matrix_length]; 

     PRECISION* ROW_IDX = new PRECISION[matrix_width]; 
     PRECISION* ROW_VAL = new PRECISION[matrix_width]; 
     // Write A to U and initialize P. 
     for (int i = 0; i < total_matrix_length; i++) 
      U_PAR[i] = A[i]; 
     // Initialize P_PAR. 
     for (int row = 0; row < matrix_width; row++) 
     { 
      for (int i = 0; i < matrix_width; i++) 
       IDX(P_PAR, row, i) = 0; 
      IDX(P_PAR, row, row) = 1; 
     } 
     // Allocate memory on the device 
     cl::Buffer P_BUFF(context, CL_MEM_READ_WRITE, total_matrix_length*sizeof(PRECISION)); 
     cl::Buffer L_BUFF(context, CL_MEM_READ_WRITE, total_matrix_length*sizeof(PRECISION)); 
     cl::Buffer U_BUFF(context, CL_MEM_READ_WRITE, total_matrix_length*sizeof(PRECISION)); 
     // Buffer to determine maximum row value. 
     cl::Buffer MAX_ROW_IDX_BUFF(context, CL_MEM_READ_WRITE, total_workgroups*sizeof(PRECISION)); 
     cl::Buffer MAX_ROW_VAL_BUFF(context, CL_MEM_READ_WRITE, total_workgroups*sizeof(PRECISION)); 

     // Create the actual kernels. 
     cl::Kernel kernel(program, kernel_name.c_str()); 

     std::string max_row_kernel_name = "max_row"; 
     cl::Kernel max_row(program, max_row_kernel_name.c_str()); 
     std::string swap_row_kernel_name = "swap_row"; 
     cl::Kernel swap_row(program, swap_row_kernel_name.c_str()); 

     // transfer source data from the host to the device 
     std::cout << "Writing buffers" << std::endl; 
     queue.enqueueWriteBuffer(P_BUFF, CL_TRUE, 0, total_matrix_length*sizeof(PRECISION), P_PAR); 
     queue.enqueueWriteBuffer(L_BUFF, CL_TRUE, 0, total_matrix_length*sizeof(PRECISION), L_PAR); 
     queue.enqueueWriteBuffer(U_BUFF, CL_TRUE, 0, total_matrix_length*sizeof(PRECISION), U_PAR); 

     queue.enqueueWriteBuffer(MAX_ROW_IDX_BUFF, CL_TRUE, 0, total_workgroups*sizeof(PRECISION), ROW_IDX); 
     queue.enqueueWriteBuffer(MAX_ROW_VAL_BUFF, CL_TRUE, 0, total_workgroups*sizeof(PRECISION), ROW_VAL); 

Полная ошибка, которую я получаю, когда я смыться с отладчиком заключается в следующем:

Unhandled exception at 0x55903CC0 (nvopencl.dll) in Project.exe: 
0xC0000005: Access violation reading location 0x0068F004. 

If there is a handler for this exception, the program may be safely continued. 

Функция отладчик показывает мне будет следующее, в пространстве имен cl:

cl_int enqueueWriteBuffer(
    const Buffer& buffer, 
    cl_bool blocking, 
    ::size_t offset, 
    ::size_t size, 
    const void* ptr, 
    const VECTOR_CLASS<Event>* events = NULL, 
    Event* event = NULL) const 
{ 
    return detail::errHandler(
     ::clEnqueueWriteBuffer(
      object_, buffer(), blocking, offset, size, 
      ptr, 
      (events != NULL) ? (cl_uint) events->size() : 0, 
      (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, 
      (cl_event*) event), 
      __ENQUEUE_WRITE_BUFFER_ERR); 

Редактировать: полный исходный код here.

ответ

1

Взгляните на эти строки:

PRECISION* ROW_IDX = new PRECISION[matrix_width]; 
... 
cl::Buffer MAX_ROW_IDX_BUFF(context, CL_MEM_READ_WRITE, total_workgroups*sizeof(PRECISION)); 
... 
queue.enqueueWriteBuffer(MAX_ROW_IDX_BUFF, CL_TRUE, 0, total_workgroups*sizeof(PRECISION), ROW_IDX); 

Итак, вы пытаетесь написать total_workgroups элементы в буфере, но ваш исходный массив был выделен только с matrix_width элементами.Для входных параметров, которые вы упомянули (массив 70x70 с размером рабочей группы 7), это будет пытаться читать 700*4 байтов данных из байт-байт 70*4 - определенное нарушение доступа к памяти.

Далее в вашем коде вы читаете из одного и того же буфера в тот же массив хостов, что приведет к повреждению памяти и вызовут всевозможные другие сбои и необъяснимое поведение при запуске вашего кода в моей собственной системе.

+0

Вот что вызвало ошибку. Спасибо! –

+0

Большое вам спасибо за это, даже если это старый пост, действительно спас мой бекон! –

0

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

Все ваши функции CL возвращают коды ошибок, оценивают их (OpenCL file, containing all error codes), сравнивая их с CL_SUCCESS. Например, если ваш вызов ядра вызвал повреждение памяти, enqueueReadBuffer часто возвращает CL_INVALID_COMMAND_QUEUE.

Из вашего описания проблемы Я предполагаю, что вы на самом деле запускаете ядро ​​повторно, однако я не вижу соответствующий код.

Наиболее вероятная причина: Доступ к памяти в ядре выходит за пределы и повреждает память. Поскольку вы не оцениваете коды ошибок и продолжаете работу с вашей программой, водитель рано или поздно сообщает об ошибке (или просто сбой), , но отсюда мы, вероятно, уже имеем дело с неопределенным поведением, поэтому не важно, что говорит водитель.

+0

Код, который я разместил, это все, что происходит. Таким образом, ошибка возникает, прежде чем я даже запускаю ядро. –

+0

в порядке, то оценка возвращаемых значений 'queue.enqueueWriteBuffer' должна помочь. – Baiz

Смежные вопросы