blob: 8d1537dc40451073a10fc336a68fbed0b3fa240e [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the LICENSE file.
*
*/
//
// squelch OpenCL 1.2 deprecation warning
//
#ifndef CL_USE_DEPRECATED_OPENCL_1_2_APIS
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
#endif
//
//
//
#include <stdio.h>
#include <string.h>
//
//
//
#include "runtime_cl_12.h"
#include "common/cl/assert_cl.h"
//
// This implementation is probably excessive.
//
// The command queue pool could easily be replaced with simply an LRU
// or even round-robin reuse pool. Even a small number of aliased
// command queues can probably enough concurrency.
//
#define SKC_CQ_POOL_EXPAND 1
//
//
//
static
cl_command_queue
skc_runtime_cl_12_create_cq(struct skc_runtime * const runtime,
struct skc_cq_pool * const pool)
{
cl_command_queue cq;
#if 1
//
// <= OpenCL 1.2
//
cl_int cl_err;
cq = clCreateCommandQueue(runtime->cl.context,
runtime->cl.device_id,
pool->cq_props,
&cl_err); cl_ok(cl_err);
#else
if (runtime_cl->version.major < 2)
{
//
// <= OpenCL 1.2
//
cl_int cl_err;
cq = clCreateCommandQueue(runtime_cl->context,
runtime_cl->device_id,
(cl_command_queue_properties)type,
&cl_err); cl_ok(cl_err);
}
else
{
//
// >= OpenCL 2.0
//
cl_int cl_err;
cl_queue_properties const queue_properties[] = {
CL_QUEUE_PROPERTIES,(cl_queue_properties)type,0
};
cq = clCreateCommandQueueWithProperties(runtime_cl->context,
runtime_cl->device_id,
queue_properties,
&cl_err); cl_ok(cl_err);
}
#endif
return cq;
}
//
//
//
void
skc_cq_pool_create(struct skc_runtime * const runtime,
struct skc_cq_pool * const pool,
cl_command_queue_properties const cq_props,
skc_uint const size)
{
pool->size = size + 1; // an empty spot
pool->reads = 0;
pool->writes = size;
pool->cq_props = cq_props;
pool->cq = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,
pool->size * sizeof(*pool->cq));
for (skc_uint ii=0; ii<size; ii++)
pool->cq[ii] = skc_runtime_cl_12_create_cq(runtime,pool);
pool->cq[size] = NULL;
}
//
//
//
void
skc_cq_pool_dispose(struct skc_runtime * const runtime,
struct skc_cq_pool * pool)
{
//
// FIXME -- release the command queues after waiting for the ring to
// be full with pool.size queues?
//
skc_runtime_host_perm_free(runtime,pool->cq);
}
//
//
//
static
void
skc_cq_pool_write(struct skc_cq_pool * const pool,
cl_command_queue cq)
{
pool->cq[pool->writes++ % pool->size] = cq;
}
//
// only expand when completely empty
//
static
void
skc_cq_pool_expand(struct skc_runtime * const runtime,
struct skc_cq_pool * const pool,
skc_uint expand)
{
#ifndef NDEBUG
fprintf(stderr,"Expanding the cq_pool by: %u (%u)\n",expand,pool->size);
#endif
// free old
skc_runtime_host_perm_free(runtime,pool->cq);
// the ring is empty
pool->size += expand;
pool->cq = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,pool->size * sizeof(*pool->cq));
pool->reads = 0;
pool->writes = expand;
for (skc_uint ii=0; ii<expand; ii++)
pool->cq[ii] = skc_runtime_cl_12_create_cq(runtime,pool);
}
//
//
//
static
cl_command_queue
skc_cq_pool_read(struct skc_runtime * const runtime,
struct skc_cq_pool * const pool)
{
// any command queues left?
if (pool->reads == pool->writes)
skc_cq_pool_expand(runtime,pool,SKC_CQ_POOL_EXPAND);
cl_command_queue cq = pool->cq[pool->reads++ % pool->size];
return cq;
}
//
//
//
cl_command_queue
skc_runtime_acquire_cq_in_order(struct skc_runtime * const runtime)
{
return skc_cq_pool_read(runtime,&runtime->cq_pool);
}
void
skc_runtime_release_cq_in_order(struct skc_runtime * const runtime,
cl_command_queue cq)
{
skc_cq_pool_write(&runtime->cq_pool,cq);
}
//
//
//