OpenCL pinned memory vs Heap Memory
<p>I have written a sample program to understand the effects of GPU/CPU pinned memory and Heap memory. The following code illustrates this. I have allocated three buffers of dimensions say 1280x720. I have filled buffers 1 &amp; 2 with some data and in turn used these buffers to fill buffer 3. The mathematical operatio involved in filling buffer 3 is insignificant. In case 1, the memory allocated from these buffers are from heap (malloc call). In case 2, the memory for these buffers are allocated from OpenCL API calls (clCreateBuffer()). There is a performance difference between these 2 cases. I tested it on Intel integrated GPU's. I am unable to explain this difference in performance. Does it have some thing to do with cacheable properties of CPU/GPU pinned memory vs Heap memory. </p>

<p>Have you encountered such behavior before or am i doing something wrong?</p>

<pre><code>#include &lt;stdio.h&gt;
#include &lt;malloc.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;inttypes.h&gt;

#define OPENCL

#if defined(_WIN32)
/*
 * Win32 specific includes
 */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include &lt;windows.h&gt;
#else
#include &lt;sys/time.h&gt;

/* timersub is not provided by msys at this time. */
#ifndef timersub
#define timersub(a, b, result) \
    do { \
      (result)-&gt;tv_sec = (a)-&gt;tv_sec - (b)-&gt;tv_sec; \
      (result)-&gt;tv_usec = (a)-&gt;tv_usec - (b)-&gt;tv_usec; \
      if ((result)-&gt;tv_usec &lt; 0) { \
        --(result)-&gt;tv_sec; \
        (result)-&gt;tv_usec += 1000000; \
      } \
    } while (0)
#endif
#endif


struct usec_timer {
#if defined(_WIN32)
  LARGE_INTEGER  begin, end;
#else
  struct timeval begin, end;
#endif
};


static void usec_timer_start(struct usec_timer *t) {
#if defined(_WIN32)
  QueryPerformanceCounter(&amp;t-&gt;begin);
#else
  gettimeofday(&amp;t-&gt;begin, NULL);
#endif
}


static void usec_timer_mark(struct usec_timer *t) {
#if defined(_WIN32)
  QueryPerformanceCounter(&amp;t-&gt;end);
#else
  gettimeofday(&amp;t-&gt;end, NULL);
#endif
}


static int64_t usec_timer_elapsed(struct usec_timer *t) {
#if defined(_WIN32)
  LARGE_INTEGER freq, diff;

  diff.QuadPart = t-&gt;end.QuadPart - t-&gt;begin.QuadPart;

  QueryPerformanceFrequency(&amp;freq);
  return diff.QuadPart * 1000000 / freq.QuadPart;
#else
  struct timeval diff;

  timersub(&amp;t-&gt;end, &amp;t-&gt;begin, &amp;diff);
  return diff.tv_sec * 1000000 + diff.tv_usec;
#endif
}


#ifdef OPENCL
#include ".\CL\cl.h"

int opencl_init(cl_context *context, cl_command_queue *cmd_queue) {
  cl_int status;
  cl_uint num_platforms = 0;
  cl_platform_id platform;
  cl_uint num_devices = 0;
  cl_device_id device;
  cl_command_queue_properties command_queue_properties = 0;

  // Get the number of platforms in the system.
  status = clGetPlatformIDs(0, NULL, &amp;num_platforms);
  if (status != CL_SUCCESS || num_platforms == 0)
    goto fail;

  // Get the platform ID for one platform
  status = clGetPlatformIDs(1, &amp;platform, NULL);
  if (status != CL_SUCCESS)
    goto fail;

  // Get the number of devices available on the platform
  status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &amp;num_devices);
  if (status != CL_SUCCESS || num_devices == 0)
    goto fail;

  // Get the device ID for one device
  status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &amp;device, NULL);
  if (status != CL_SUCCESS)
    goto fail;

  // Create OpenCL context for one device
  *context = clCreateContext(NULL, 1, &amp;device, NULL, NULL, &amp;status);
  if (status != CL_SUCCESS || *context == NULL)
    goto fail;

  // Create command queues for the device
  *cmd_queue = clCreateCommandQueue(*context, device, command_queue_properties, &amp;status);
  if (status != CL_SUCCESS || *cmd_queue == NULL)
    goto fail;
  return 0;

fail:
  return 1;
}
#endif

int main(int argc, char **argv) {
  int x, y, z;
  int width = 1280, height = 720;
  unsigned char *buffer[3];
  int use_gpu;
  cl_mem opencl_mem[3];
  cl_context context;
  cl_command_queue cmd_queue;
  cl_int status;

  if (argc != 2)
    return 0;

  use_gpu = atoi(argv[1]);

  if (use_gpu) {
    if (opencl_init(&amp;context, &amp;cmd_queue))
      printf("OpenCL init failure");
  }

  if (use_gpu) {
    for (x = 0; x &lt; 3; x++) {
      opencl_mem[x] = clCreateBuffer(context,
                                     CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR,
                                     width * height * sizeof(*buffer[x]), NULL,
                                     &amp;status);
      if (status != CL_SUCCESS)
        return 0;
      buffer[x] = clEnqueueMapBuffer(cmd_queue, opencl_mem[x], CL_TRUE,
                                     CL_MAP_READ | CL_MAP_WRITE, 0,
                                     width * height * sizeof(*buffer[x]), 0,
                                     NULL, NULL, &amp;status);
      if (status != CL_SUCCESS) {
        clReleaseMemObject(opencl_mem[x]);
        opencl_mem[x] = NULL;
        return 0;
      }
    }
  } else {
    for (x = 0; x &lt; 3; x++) {
      buffer[x] = malloc(width * height * sizeof(*buffer[x]));
      if (buffer[x] == NULL) {
        printf("Unable to alloc memory");
      }
    }
  }

  memset(buffer[0], 1, width * height * sizeof(*buffer[0]));
  memset(buffer[1], 2, width * height * sizeof(*buffer[1]));
  memset(buffer[2], 0, width * height * sizeof(*buffer[2]));

  {
    struct usec_timer emr_timer;
    usec_timer_start(&amp;emr_timer);
    for (z = 0; z &lt; 600; z++) {
      for (y = 0; y &lt; height; y++) {
        for (x = 0; x &lt; width; x++) {
          // don't worry about overflows
          buffer[2][y * width + x] += buffer[0][y * width + x]
                                     + buffer[1][y * width + x];
        }
      }
    }
    usec_timer_mark(&amp;emr_timer);
    printf("Elapsed time %"PRIu64"\n", usec_timer_elapsed(&amp;emr_timer));
  }

  if (use_gpu) {
    for (x = 0; x &lt; 3; x++) {
      if (buffer[x] != NULL) {
        status = clEnqueueUnmapMemObject(cmd_queue, opencl_mem[0], buffer[0], 0,
                                         NULL, NULL);
        status |= clFinish(cmd_queue);
        if (status != CL_SUCCESS)
          return 0;
        buffer[0] = NULL;
      }

      if (opencl_mem[0] != NULL) {
        status = clReleaseMemObject(opencl_mem[0]);
        if (status != CL_SUCCESS)
          return 0;
        opencl_mem[0] = NULL;
      }
    }

    clReleaseCommandQueue(cmd_queue);
    clReleaseContext(context);
  } else {
    for (x = 0; x &lt; 3; x++) {
      free(buffer[x]);
      buffer[x] = NULL;
    }
  }
  return 0;
}
</code></pre>