OpenCL: Implementing Dining Philosophers problem?

时间:2019-04-08 13:37:55

标签: c parallel-processing opencl opencl-c

I'm trying to implement a variation of the Dining Philosophers problem using OpenCL. I have posted the code below but it's not giving the expected output. I'm using a semaphore array for the chopsticks and based on whether a Philosopher is using a pair of chopsticks, the value might be one or zero(or in this variation CLEAN or DIRTY).

Tried using atomic exchange for the core algorithm.

Kernel Code: .cl file

#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");
}

I have initialised the semaphore array to 0 in the host code. The global work size that I'm using is 5 and the local work size is 1.

Here's the host code (.c file) for reference:

#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);
}

Expected result: The program should keep running as long as the user desires and it should keep showing the state of the Philosophers who are eating.

Actual results: Random output every time the code is exec.

1) OP: Return code is 0

kernel exec

2) OP: Return code is 0

kernel exec

0

0 个答案:

没有答案