OpenCL: Реализовать проблему столовых философов? - PullRequest
0 голосов
/ 08 апреля 2019

Я пытаюсь реализовать вариант проблемы «Обедающих философов» с помощью OpenCL. Я разместил код ниже, но он не дает ожидаемого результата. Я использую массив семафоров для палочек и в зависимости от того, использует ли Философ пару палочек для еды, значение может быть равно единице или нулю (или в этом варианте CLEAN или DIRTY).

Пробовал использовать атомный обмен для основного алгоритма.

Код ядра: .cl файл

#pragma OPENCL EXTENSION cl_khr_global_int64_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int64_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_global_int64_extended_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int64_extended_atomics : enable

void GetSem(__global int * sem) 
{
    int occupied = atom_xchg(sem, 1);
    while(occupied > 0)
      printf("\n hung \n");
        occupied = atom_xchg(sem, 1);
}

void ReleaseSem(__global int * sem)
{
    int prevVal = atom_xchg(sem, 0);
}

__kernel void dine(__global int * semaphor)
{
      printf("\n kernel exec \n");
      int i = get_global_id(0);
      printf("\n %d \n",semaphor[i]);
      GetSem(&semaphor[i%5]);
      GetSem(&semaphor[(i+1)%5]);
      printf("\n stuck \n");
      int a=(i%5)+1;
      int b=((i+1)%5)+1;
      printf("Philoshper %d has %d and %d Chop Sticks.\n",i+1,a,b);

      ReleaseSem(&semaphor[(i+1)%5]);
      ReleaseSem(&semaphor[i%5]);
      printf("\n done \n");
}

Я инициализировал массив семафоров 0 в коде хоста. Глобальный размер работы, который я использую, равен 5, а локальный размер работы равен 1.

Вот код хоста (файл .c) для справки:

#include <OpenCL/opencl.h>
#include<stdio.h>
#include<stdlib.h>
#define MAX_SOURCE_SIZE (0x100000)

int main(void) {
FILE *fp;
    char *source_str;
    size_t source_size;
    int i;
#pragma OPENCL EXTENSION cl_amd_printf:enable
    fp = fopen("dine.cl", "r");
    if (!fp) {
        fprintf(stderr, "Failed to load kernel.\n");
        exit(1);
    }
    source_str = (char*)malloc(MAX_SOURCE_SIZE);
    source_size = fread( source_str, 1, MAX_SOURCE_SIZE, fp);
  //  printf("\n********************Source code is*****************\n %s \n********************end************* ",source_str);
    fclose( fp );
char *info;
    cl_uint infoSize;
    cl_platform_id platform_id = NULL;
    cl_device_id device_id = NULL;   
    cl_uint ret_num_devices;
    cl_uint ret_num_platforms;
    cl_int ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
  //  clGetPlatformInfo(platform_id,CL_PLATFORM_NAME,0, NULL, &infoSize);
    info=(char *)malloc(sizeof(char)*infoSize);
    clGetPlatformInfo(platform_id,CL_PLATFORM_NAME,infoSize, info, NULL);
    ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_ALL, 1, 
            &device_id, &ret_num_devices);


//printf("Number of platforms %d and number of devices are %d",ret_num_platforms,ret_num_devices);

//printf("\n Device Propoerties are %s",info);
    cl_context context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);

    // Create a command queue
    cl_command_queue command_queue = clCreateCommandQueue(context, device_id, 0, &ret);

    // Create memory buffers on the device for each vector 

       cl_mem c_mem_obj = clCreateBuffer(context, CL_MEM_READ_ONLY , sizeof(int)*5, NULL, &ret);
      int *C = (int *)malloc(sizeof(int)*5);
    for(i=0;i<5;i++)
    {
       C[i]=0;
    }

      clEnqueueWriteBuffer(command_queue, c_mem_obj, CL_TRUE, 0,
                                 sizeof(int)*5 , C, 0, NULL, NULL);

    cl_program program = clCreateProgramWithSource(context, 1, 
            (const char **)&source_str, (const size_t *)&source_size, &ret);

    // Build the program
    ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);

    // Create the OpenCL kernel
    cl_kernel kernel = clCreateKernel(program, "dine", &ret);

    ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&c_mem_obj);

    // Execute the OpenCL kernel on the list
    size_t global_item_size = 5; // Process the entire lists
    size_t local_item_size = 1; // Process in groups of 64
    ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global_item_size, &local_item_size, 0, NULL, NULL);
    printf("Return code is %d\n",ret);
}

Ожидаемый результат: программа должна продолжать работать столько, сколько пожелает пользователь, и показывать состояние тех философов, которые едят.

Фактические результаты: случайный вывод каждый раз, когда код исполняется.

1) OP: код возврата 0

ядро ​​exec

2) OP: код возврата 0

ядро ​​exec

0

...