assertOpenCL  September 19, 2018
Example.scala
Go to the documentation of this file.
1 /* -*- coding: latin-1 -*- */
2 /** \file examples/Scala/Example.scala
3  * \brief
4  * Simple Scala example
5  * to show how run a kernel with assert*() and PRINT*() macros
6  * and test them.
7  *
8  * Piece of assertOpenCL
9  * --- GPLv3 --- Copyright (C) 2018 Olivier Pirson
10  * --- http://www.opimedia.be/
11  * --- September 19, 2018
12  */
13 
14 import scala.math.BigInt
15 import scala.io.Source
16 
17 
18 import org.jocl.CL._ // http://www.jocl.org/
19 
20 import org.jocl._
21 
22 
23 
24 /**
25  * Simple Scala example to show how run a kernel with assert*() and PRINT*() macros
26  * and test them.
27  *
28  * Piece of assertOpenCL
29  *
30  * @author Olivier Pirson --- http://www.opimedia.be/
31  * @version September 19, 2018
32  */
33 object Example {
34  /** Number of bytes for the float type. */
35  val FLOAT_FIELD_SIZE: Int = 4
36 
37  /** Number of bytes for the int type. */
38  val INT_FIELD_SIZE: Int = 4
39 
40  /** Number of bytes for the long type. */
41  val LONG_FIELD_SIZE: Int = 8
42 
43 
44 
45  /**
46  * True iff assertions are enabled.
47  */
48  private var assertsEnabled: Boolean = false
49  try {
50  assert(false)
51  }
52  catch {
53  case e: AssertionError => assertsEnabled = true
54  }
55 
56 
57 
58  /**
59  * Read the file and return its content to a string.
60  * If failed then throw an exception.
61  */
62  def fileToString(filename: String): String =
63  "#line 1 \"" + filename + "\"\n" + Source.fromFile(filename).mkString
64 
65 
66  /**
67  * Return the given id device of the given platform OpenCL,
68  * or exit if doesn't exists.
69  */
70  def getDeviceId(platformI: Int, deviceI: Int): cl_device_id = {
71  assert(platformI >= 0)
72  assert(deviceI >= 0)
73 
74  // Get number of platforms
75  val platformNbArray: Array[Int] = Array.ofDim[Int](1)
76 
77  clGetPlatformIDs(0, null, platformNbArray)
78 
79  val platformNb: Int = platformNbArray(0)
80 
81  if (platformI >= platformNb) {
82  throw new Exception("Wrong platformI: " + platformI)
83  }
84 
85  // Get all platform ids
86  val platformIds: Array[cl_platform_id] = Array.ofDim[cl_platform_id](platformNb)
87 
88  clGetPlatformIDs(platformIds.length, platformIds, null)
89 
90  // The wanted platform
91  val platformId: cl_platform_id = platformIds(platformI)
92 
93  // Get number of devices for the wanted platform
94  val deviceNbArray: Array[Int] = Array.ofDim[Int](1)
95 
96  clGetDeviceIDs(platformId, CL_DEVICE_TYPE_ALL, 0, null, deviceNbArray)
97 
98  val deviceNb: Int = deviceNbArray(0)
99 
100  if (deviceI >= deviceNb) {
101  throw new Exception("Wrong deviceI: " + deviceI)
102  }
103 
104  // Get all device ids for the wanted platform
105  val deviceIds: Array[cl_device_id] = Array.ofDim[cl_device_id](deviceNb)
106 
107  clGetDeviceIDs(platformId, CL_DEVICE_TYPE_ALL, deviceNb, deviceIds, null)
108 
109  // The wanted device
110  deviceIds(deviceI)
111  }
112 
113 
114  /**
115  * Return a string corresponding to device info parameter.
116  */
117  def getDeviceInfoString(deviceId: cl_device_id, paramName: Int): String = {
118  // Get length of result
119  val size: Array[Long] = Array.ofDim[Long](1)
120 
121  clGetDeviceInfo(deviceId, paramName, 0, null, size)
122 
123  // Get the wanted string
124  val buffer: Array[Byte] = Array.ofDim[Byte](size(0).toInt)
125 
126  clGetDeviceInfo(deviceId, paramName, buffer.length, Pointer.to(buffer), null)
127 
128  new String(buffer, 0, buffer.length - 1)
129  }
130 
131 
132  /**
133  * Run the kernel ../kernel/example.cl.
134 
135  * If debug
136  * then run the kernel in debug mode,
137  * else run the kernel with the macro NDEBUG defined.
138  */
139  def runExample(nbWorkGroup: Int, nbWorkItemsByWorkGroup: Int,
140  deviceId: cl_device_id, debug: Boolean) {
141  // Host buffer
142  val hOuts: Array[Int] = Array.ofDim[Int](2)
143  val hOutsByteSize: Int = INT_FIELD_SIZE * 2
144 
145  val hAsserts: Array[Long] = Array[Long](0, 0)
146  val hAssertsByteSize: Int = LONG_FIELD_SIZE * 2
147 
148  val hAssertFloat: Array[Float] = Array[Float](0)
149  val hAssertFloatByteSize: Int = FLOAT_FIELD_SIZE
150 
151 
152  // OpenCL context
153  val devicesIds: Array[cl_device_id] = Array[cl_device_id](deviceId)
154  val context: cl_context = clCreateContext(null, 1, devicesIds, null, null, null)
155 
156 
157  // OpenCL kernel
158  var options: String = "-I../../OpenCL/"
159 
160  if (debug) {
161  System.err.println("OpenCL in DEBUG mode!")
162  System.err.flush()
163  } else {
164  options += " -DNDEBUG"
165  }
166 
167  val kernelFilename: String = "../kernel/example.cl"
168  val kernelSrc: String = fileToString(kernelFilename)
169  val program: cl_program = clCreateProgramWithSource(context,
170  1, Array[String](kernelSrc),
171  null, null)
172 
173  clBuildProgram(program, 1, devicesIds, options, null, null)
174 
175  val kernel: cl_kernel = clCreateKernel(program, "example", null)
176 
177 
178  // OpenCL queue
179  val queue:cl_command_queue = clCreateCommandQueue(context, deviceId,
180  CL_QUEUE_PROFILING_ENABLE, null)
181 
182 
183  // OpenCL buffers
184  val dOuts: cl_mem = clCreateBuffer(context, CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
185  hOutsByteSize, Pointer.to(hOuts), null)
186 
187  var dAsserts: cl_mem = null
188  var dAssertFloat: cl_mem = null
189 
190  if (debug) {
191  dAsserts = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
192  hAssertsByteSize, Pointer.to(hAsserts), null)
193  dAssertFloat = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
194  hAssertFloatByteSize, Pointer.to(hAssertFloat), null)
195  }
196 
197 
198  // Params: just two parameters for the example
199  clSetKernelArg(kernel, 0, Sizeof.cl_uint, Pointer.to(Array[Int](666)))
200  clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(dOuts))
201 
202  if (debug) { // extra parameters to receive assertion information
203  val nbArgs: Int = 2
204 
205  clSetKernelArg(kernel, nbArgs, Sizeof.cl_mem, Pointer.to(dAsserts))
206  clSetKernelArg(kernel, nbArgs + 1, Sizeof.cl_mem, Pointer.to(dAssertFloat))
207  }
208 
209 
210  // Run
211  val globalSize: Int = nbWorkItemsByWorkGroup * nbWorkGroup
212 
213  println("===== run kernel =====")
214  System.out.flush()
215 
216  clEnqueueNDRangeKernel(queue, kernel,
217  1,
218  null,
219  Array[Long](globalSize),
220  Array[Long](nbWorkItemsByWorkGroup),
221  0,
222  null,
223  null)
224 
225  clFinish(queue)
226  clFlush(queue)
227  System.out.flush()
228  System.err.flush()
229  println("===== end kernel =====")
230  System.out.flush()
231 
232 
233  // Results
234  clEnqueueReadBuffer(queue, dOuts, CL_TRUE, 0,
235  hOutsByteSize, Pointer.to(hOuts), 0, null, null)
236 
237  if (debug) {
238  clEnqueueReadBuffer(queue, dAsserts, CL_TRUE, 0,
239  hAssertsByteSize, Pointer.to(hAsserts), 0, null, null)
240  clEnqueueReadBuffer(queue, dAssertFloat, CL_TRUE, 0,
241  hAssertFloatByteSize, Pointer.to(hAssertFloat), 0, null, null)
242 
243  val line: Long = hAsserts(0)
244 
245  if (line != 0) { // there had (at least) an assertion
246  val uint64Value: BigInt = uint64(hAsserts(1))
247  val sint64Value: Long = hAsserts(1)
248  val floatValue: Float = hAssertFloat(0)
249 
250  System.err.println(s"$kernelFilename:$line\tAssertion failed | Maybe\t$uint64Value\t$sint64Value | Maybe\t$floatValue")
251  /*
252  Maybe incoherent assert information because the parallel execution of work items.
253  But each element of these information concern assertion(s) that failed.
254  */
255  System.err.flush()
256  }
257  }
258 
259  println(s"Results: (${uint32(hOuts(0))}, ${uint32(hOuts(1))})")
260 
261 
262  // Free OpenCL resources
263  clReleaseMemObject(dOuts)
264  if (debug) {
265  clReleaseMemObject(dAsserts)
266  clReleaseMemObject(dAssertFloat)
267  }
268 
269  clReleaseCommandQueue(queue)
270  clReleaseProgram(program)
271  clReleaseKernel(kernel)
272  clReleaseContext(context)
273  }
274 
275 
276  /**
277  * Return in a Long the value of n considered as an unsigned integer on 32 bits.
278  */
279  def uint32(n: Int): Long =
280  if (n >= 0) n
281  else (4294967296L + n) // 2^32 + n
282 
283 
284  /**
285  * Return in a BigInt the value of n considered as an unsigned integer on 64 bits.
286  */
287  def uint64(n: Long): BigInt =
288  if (n >= 0) BigInt(n)
289  else BigInt("18446744073709551616") + n // 2^64 + n
290 
291 
292 
293  /**
294  * Get the optional parameter --device platform:device
295  * and run the kernel ../kernel/example.cl .
296  */
297  def main(args: Array[String]): Unit = {
298  var debug: Boolean = assertsEnabled
299  var deviceI: Int = 0
300  var platformI: Int = 0
301 
302  // Read parameters
303  {
304  var i: Int = 0
305 
306  while (i < args.length) {
307  val arg: String = args(i)
308 
309  if ("--debug".equals(arg) || "--ndebug".equals(arg)) {
310  debug = "--debug".equals(arg)
311  }
312  else if ("--device".equals(arg)) {
313  i += 1
314 
315  if (i >= args.length) {
316  throw new Exception("Missing parameter")
317  }
318 
319  val bothI: Array[String] = args(i).split(":")
320 
321  platformI = Integer.parseInt(bothI(0))
322  if (bothI.length >= 2) {
323  deviceI = Integer.parseInt(bothI(1))
324  }
325 
326  if ((platformI < 0) || (deviceI < 0)) {
327  throw new Exception("Wrong parameter: " + args(i))
328  }
329  }
330  i += 1
331  }
332  }
333 
334  // Get wanted device
335  val deviceId: cl_device_id = getDeviceId(platformI, deviceI)
336 
337  // Get device name and print
338  println(s"Device $platformI:$deviceI ${getDeviceInfoString(deviceId, CL_DEVICE_NAME)}")
339  System.out.flush()
340 
341  // Run
342  runExample(3, 4, deviceId, debug)
343  }
344 }
#define assert(test)
If test is true then do nothing. Else init (if they are still null) assert_result and assert_result_f...
Definition: assert.cl:162
Simple Java example to show how run a kernel with assert*() and PRINT*() macros and test them...
Definition: Example.java:30