1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can
5 * be found in the LICENSE file.
6 *
7 */
8
9 //
10 // squelch OpenCL 1.2 deprecation warning
11 //
12
13 #ifndef CL_USE_DEPRECATED_OPENCL_1_2_APIS
14 #define CL_USE_DEPRECATED_OPENCL_1_2_APIS
15 #endif
16
17 //
18 //
19 //
20
21 #include <stdio.h>
22 #include <string.h>
23
24 //
25 //
26 //
27
28 #include "runtime_cl_12.h"
29 #include "common/cl/assert_cl.h"
30
31 //
32 // This implementation is probably excessive.
33 //
34 // The command queue pool could easily be replaced with simply an LRU
35 // or even round-robin reuse pool. Even a small number of aliased
36 // command queues can probably enough concurrency.
37 //
38
39 #define SKC_CQ_POOL_EXPAND 1
40
41 //
42 //
43 //
44
45 static
46 cl_command_queue
skc_runtime_cl_12_create_cq(struct skc_runtime * const runtime,struct skc_cq_pool * const pool)47 skc_runtime_cl_12_create_cq(struct skc_runtime * const runtime,
48 struct skc_cq_pool * const pool)
49
50 {
51 cl_command_queue cq;
52
53 #if 1
54 //
55 // <= OpenCL 1.2
56 //
57 cl_int cl_err;
58
59 cq = clCreateCommandQueue(runtime->cl.context,
60 runtime->cl.device_id,
61 pool->cq_props,
62 &cl_err); cl_ok(cl_err);
63 #else
64 if (runtime_cl->version.major < 2)
65 {
66 //
67 // <= OpenCL 1.2
68 //
69 cl_int cl_err;
70
71 cq = clCreateCommandQueue(runtime_cl->context,
72 runtime_cl->device_id,
73 (cl_command_queue_properties)type,
74 &cl_err); cl_ok(cl_err);
75 }
76 else
77 {
78 //
79 // >= OpenCL 2.0
80 //
81 cl_int cl_err;
82 cl_queue_properties const queue_properties[] = {
83 CL_QUEUE_PROPERTIES,(cl_queue_properties)type,0
84 };
85
86 cq = clCreateCommandQueueWithProperties(runtime_cl->context,
87 runtime_cl->device_id,
88 queue_properties,
89 &cl_err); cl_ok(cl_err);
90 }
91 #endif
92
93 return cq;
94 }
95
96 //
97 //
98 //
99
100 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)101 skc_cq_pool_create(struct skc_runtime * const runtime,
102 struct skc_cq_pool * const pool,
103 cl_command_queue_properties const cq_props,
104 skc_uint const size)
105 {
106 pool->size = size + 1; // an empty spot
107 pool->reads = 0;
108 pool->writes = size;
109
110 pool->cq_props = cq_props;
111 pool->cq = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,
112 pool->size * sizeof(*pool->cq));
113 for (skc_uint ii=0; ii<size; ii++)
114 pool->cq[ii] = skc_runtime_cl_12_create_cq(runtime,pool);
115
116 pool->cq[size] = NULL;
117 }
118
119 //
120 //
121 //
122
123 void
skc_cq_pool_dispose(struct skc_runtime * const runtime,struct skc_cq_pool * pool)124 skc_cq_pool_dispose(struct skc_runtime * const runtime,
125 struct skc_cq_pool * pool)
126 {
127 //
128 // FIXME -- release the command queues after waiting for the ring to
129 // be full with pool.size queues?
130 //
131 skc_runtime_host_perm_free(runtime,pool->cq);
132 }
133
134 //
135 //
136 //
137
138 static
139 void
skc_cq_pool_write(struct skc_cq_pool * const pool,cl_command_queue cq)140 skc_cq_pool_write(struct skc_cq_pool * const pool,
141 cl_command_queue cq)
142 {
143 pool->cq[pool->writes++ % pool->size] = cq;
144 }
145
146 //
147 // only expand when completely empty
148 //
149
150 static
151 void
skc_cq_pool_expand(struct skc_runtime * const runtime,struct skc_cq_pool * const pool,skc_uint expand)152 skc_cq_pool_expand(struct skc_runtime * const runtime,
153 struct skc_cq_pool * const pool,
154 skc_uint expand)
155 {
156 #ifndef NDEBUG
157 fprintf(stderr,"Expanding the cq_pool by: %u (%u)\n",expand,pool->size);
158 #endif
159
160 // free old
161 skc_runtime_host_perm_free(runtime,pool->cq);
162
163 // the ring is empty
164 pool->size += expand;
165 pool->cq = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,pool->size * sizeof(*pool->cq));
166 pool->reads = 0;
167 pool->writes = expand;
168
169 for (skc_uint ii=0; ii<expand; ii++)
170 pool->cq[ii] = skc_runtime_cl_12_create_cq(runtime,pool);
171 }
172
173 //
174 //
175 //
176
177 static
178 cl_command_queue
skc_cq_pool_read(struct skc_runtime * const runtime,struct skc_cq_pool * const pool)179 skc_cq_pool_read(struct skc_runtime * const runtime,
180 struct skc_cq_pool * const pool)
181 {
182 // any command queues left?
183 if (pool->reads == pool->writes)
184 skc_cq_pool_expand(runtime,pool,SKC_CQ_POOL_EXPAND);
185
186 cl_command_queue cq = pool->cq[pool->reads++ % pool->size];
187
188 return cq;
189 }
190
191 //
192 //
193 //
194
195 cl_command_queue
skc_runtime_acquire_cq_in_order(struct skc_runtime * const runtime)196 skc_runtime_acquire_cq_in_order(struct skc_runtime * const runtime)
197 {
198 return skc_cq_pool_read(runtime,&runtime->cq_pool);
199 }
200
201 void
skc_runtime_release_cq_in_order(struct skc_runtime * const runtime,cl_command_queue cq)202 skc_runtime_release_cq_in_order(struct skc_runtime * const runtime,
203 cl_command_queue cq)
204 {
205 skc_cq_pool_write(&runtime->cq_pool,cq);
206 }
207
208 //
209 //
210 //
211