001/* 002 * JavaCL - Java API and utilities for OpenCL 003 * http://javacl.googlecode.com/ 004 * 005 * Copyright (c) 2009-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050package com.nativelibs4java.opencl; 051import static com.nativelibs4java.opencl.CLException.error; 052import static com.nativelibs4java.opencl.JavaCL.CL; 053import static com.nativelibs4java.opencl.library.OpenCLLibrary.*; 054import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*; 055 056import java.util.Arrays; 057 058import com.nativelibs4java.opencl.library.OpenCLLibrary; 059import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_event; 060import com.nativelibs4java.util.EnumValue; 061import com.nativelibs4java.util.EnumValues; 062import org.bridj.*; 063import org.bridj.ann.Ptr; 064import static org.bridj.Pointer.*; 065import static com.nativelibs4java.opencl.proxy.PointerUtils.*; 066 067/** 068 * OpenCL event object.<br> 069 * Event objects can be used to refer to a kernel execution command (clEnqueueNDRangeKernel, clEnqueueTask, clEnqueueNativeKernel), or read, write, map and copy commands on memory objects (clEnqueue{Read|Write|Map}{Buffer|Image}, clEnqueueCopy{Buffer|Image}, clEnqueueCopyBufferToImage, or clEnqueueCopyImageToBuffer).<br> 070 * An event object can be used to track the execution status of a command. <br> 071 * The API calls that enqueue commands to a command-queue create a new event object that is returned in the event argument. <br> 072 * In case of an error enqueuing the command in the command-queue the event argument does not return an event object.<br> 073 * The execution status of an enqueued command at any given point in time can be CL_QUEUED (command has been enqueued in the command-queue), CL_SUBMITTED (enqueued command has been submitted by the host to the device associated with the command-queue), CL_RUNNING (device is currently executing this command), CL_COMPLETE (command has successfully completed) or the appropriate error code if the command was abnormally terminated (this may be caused by a bad memory access etc.). <br> 074 * The error code returned by a terminated command is a negative integer value. <br> 075 * A command is considered to be complete if its execution status is CL_COMPLETE or is a negative integer value.<br> 076 * If the execution of a command is terminated, the command-queue associated with this terminated command, and the associated context (and all other command-queues in this context) may no longer be available. <br> 077 * The behavior of OpenCL API calls that use this context (and command-queues associated with this context) are now considered to be implementation- defined. <br> 078 * The user registered callback function specified when context is created can be used to report appropriate error information.<br> 079 * 080 * @author ochafik 081 */ 082public class CLEvent extends CLAbstractEntity { 083 084 /** 085 * Pass this to special value to any method that expects a variable number of events to wait for and that returns an event, to completely avoid returning the completion event (will return null instead of the event). 086 */ 087 public static final CLEvent FIRE_AND_FORGET = new CLEvent(null, -1); 088 089 protected static CLInfoGetter infos = new CLInfoGetter() { 090 @Override 091 protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer<SizeT> sizeOut) { 092 return CL.clGetEventInfo(entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut)); 093 } 094 }; 095 096 protected static CLInfoGetter profilingInfos = new CLInfoGetter() { 097 @Override 098 protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer<SizeT> sizeOut) { 099 return CL.clGetEventProfilingInfo(entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut)); 100 } 101 }; 102 103 private final CLQueue queue; 104 105 CLEvent(CLQueue queue, long evt) { 106 super(evt, false); 107 this.queue = queue; 108 } 109 110 public CLQueue getQueue() { 111 return queue; 112 } 113 114 public interface EventCallback { 115 public void callback(int executionStatus); 116 } 117 118 /** 119 * Registers a user callback function for the completion execution status (CL_COMPLETE). <br> 120 * @param callback 121 * @throws UnsupportedOperationException in OpenCL 1.0 122 * @since OpenCL 1.1 123 */ 124 public void setCompletionCallback(final EventCallback callback) { 125 setCallback(CL_COMPLETE, callback); 126 } 127 128 private static final clSetEventCallback_arg1_callback eventCallback = new clSetEventCallback_arg1_callback() { 129 public void apply(@Ptr long evt, int executionStatus, @Ptr long callbackPeer) { 130 EventCallback callback = (EventCallback)JNI.refToObject(callbackPeer); 131 try { 132 callback.callback(executionStatus); 133 } finally { 134 JNI.deleteGlobalRef(callbackPeer); 135 } 136 } 137 }; 138 private static final long eventCallbackPeer = getPeer(getPointer(eventCallback)); 139 140 /** 141 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetEventCallback.html">clSetEventCallback</a>.<br> 142 * Registers a user callback function for a specific command execution status. <br> 143 * The registered callback function will be called when the execution status of command associated with event changes to the execution status specified by command_exec_status. 144 * @param commandExecStatus specifies the command execution status for which the callback is registered. The command execution callback values for which a callback can be registered are: CL_COMPLETE. There is no guarantee that the callback functions registered for various execution status values for an event will be called in the exact order that the execution status of a command changes. 145 * @param callback 146 * @throws UnsupportedOperationException in OpenCL 1.0 147 * @since OpenCL 1.1 148 */ 149 public void setCallback(int commandExecStatus, final EventCallback callback) { 150 queue.getContext().getPlatform().requireMinVersionValue("clSetEventCallback", 1.1); 151 error(CL.clSetEventCallback(getEntity(), commandExecStatus, eventCallbackPeer, JNI.newGlobalRef(callback))); 152 } 153 154 static CLEvent createEvent(final CLQueue queue, long evt) { 155 return createEvent(queue, evt, false); 156 } 157 158 static CLEvent createEvent(final CLQueue queue, long evt, boolean isUserEvent) { 159 if (evt == 0) 160 return null; 161 162 return isUserEvent ? 163 new CLUserEvent(queue, evt) : 164 new CLEvent(queue, evt); 165 } 166 167 static CLEvent createEventFromPointer(CLQueue queue, Pointer<cl_event> evt1) { 168 if (evt1 == null) 169 return null; 170 171 long peer = evt1.getSizeT(); 172 if (peer == 0) 173 return null; 174 175 return new CLEvent(queue, peer); 176 } 177 178 179 /** 180 * Wait for this event, blocking the caller thread independently of any queue until all of the command associated with this events completes. 181 */ 182 public void waitFor() { 183 waitFor(this); 184 } 185 186 /** 187 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clWaitForEvents.html">clWaitForEvents</a>.<br> 188 * Wait for events, blocking the caller thread independently of any queue until all of the commands associated with the events completed. 189 * @param eventsToWaitFor List of events which completion is to be waited for 190 */ 191 public static void waitFor(CLEvent... eventsToWaitFor) { 192 if (eventsToWaitFor.length == 0) 193 return; 194 195 try { 196 ReusablePointers ptrs = ReusablePointers.get(); 197 int[] eventsInCount = ptrs.int1Array; 198 Pointer<cl_event> eventsIn = 199 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 200 if (eventsIn == null) 201 return; 202 error(CL.clWaitForEvents( eventsInCount[0], getPeer(eventsIn) )); 203 } catch (Exception ex) { 204 throw new RuntimeException("Exception while waiting for events " + Arrays.asList(eventsToWaitFor), ex); 205 } 206 } 207 208 /** 209 * Invoke an action in a separate thread only after completion of the command associated with this event.<br> 210 * Returns immediately. 211 * @param action an action to be ran 212 * @throws IllegalArgumentException if action is null 213 */ 214 public void invokeUponCompletion(final Runnable action) { 215 invokeUponCompletion(action, this); 216 } 217 218 /** 219 * Invoke an action in a separate thread only after completion of all of the commands associated with the specified events.<br> 220 * Returns immediately. 221 * @param action an action to be ran 222 * @param eventsToWaitFor list of events which commands's completion should be waited for before the action is ran 223 * @throws IllegalArgumentException if action is null 224 */ 225 public static void invokeUponCompletion(final Runnable action, final CLEvent... eventsToWaitFor) { 226 if (action == null) 227 throw new IllegalArgumentException("Null action !"); 228 229 new Thread() { 230 public void run() { 231 waitFor(eventsToWaitFor); 232 action.run(); 233 } 234 }.start(); 235 } 236 237 static boolean containsFireAndForget(CLEvent[] eventsToWaitFor) { 238 for (int i = eventsToWaitFor.length; i-- != 0;) { 239 if (eventsToWaitFor[i] == FIRE_AND_FORGET) 240 return true; 241 } 242 return false; 243 } 244 245 @Override 246 protected void clear() { 247 error(CL.clReleaseEvent(getEntity())); 248 } 249 250 /** Values for CL_EVENT_COMMAND_EXECUTION_STATUS */ 251 public enum CommandExecutionStatus implements com.nativelibs4java.util.ValuedEnum { 252 /** command has been enqueued in the command-queue */ 253 Queued(CL_QUEUED), 254 /** enqueued command has been submitted by the host to the device associated with the command-queue */ 255 Submitted(CL_SUBMITTED), 256 /** device is currently executing this command */ 257 Running(CL_RUNNING), 258 /** the command has completed */ 259 Complete(CL_COMPLETE); 260 261 CommandExecutionStatus(long value) { this.value = value; } 262 long value; 263 @Override 264 public long value() { return value; } 265 public static CommandExecutionStatus getEnum(long v) { return EnumValues.getEnum(v, CommandExecutionStatus.class); } 266 } 267 268 /** 269 * Return the execution status of the command identified by event. <br> 270 * @throws CLException is the execution status denotes an error 271 */ 272 public CommandExecutionStatus getCommandExecutionStatus() { 273 int v = infos.getInt(getEntity(), CL_EVENT_COMMAND_EXECUTION_STATUS); 274 CommandExecutionStatus status = CommandExecutionStatus.getEnum(v); 275 if (status == null) 276 error(v); 277 return status; 278 } 279 /** 280 * Return the execution status of the command identified by event. <br> 281 * @throws CLException is the execution status denotes an error 282 */ 283 @InfoName("CL_EVENT_COMMAND_EXECUTION_STATUS") 284 public int getCommandExecutionStatusValue() { 285 return infos.getInt(getEntity(), CL_EVENT_COMMAND_EXECUTION_STATUS); 286 } 287 288 /** Values for CL_EVENT_COMMAND_TYPE */ 289 public enum CommandType implements com.nativelibs4java.util.ValuedEnum { 290 NDRangeKernel(CL_COMMAND_NDRANGE_KERNEL), 291 Task(CL_COMMAND_TASK), 292 NativeKernel(CL_COMMAND_NATIVE_KERNEL), 293 ReadBuffer(CL_COMMAND_READ_BUFFER), 294 WriteBuffer(CL_COMMAND_WRITE_BUFFER), 295 CopyBuffer(CL_COMMAND_COPY_BUFFER), 296 ReadImage(CL_COMMAND_READ_IMAGE), 297 WriteImage(CL_COMMAND_WRITE_IMAGE), 298 CopyImage(CL_COMMAND_COPY_IMAGE), 299 CopyBufferToImage(CL_COMMAND_COPY_BUFFER_TO_IMAGE), 300 CopyImageToBuffer(CL_COMMAND_COPY_IMAGE_TO_BUFFER), 301 MapBuffer(CL_COMMAND_MAP_BUFFER), 302 CommandMapImage(CL_COMMAND_MAP_IMAGE), 303 UnmapMemObject(CL_COMMAND_UNMAP_MEM_OBJECT), 304 Marker(CL_COMMAND_MARKER), 305 AcquireGLObjects(CL_COMMAND_ACQUIRE_GL_OBJECTS), 306 ReleaseGLObjects(CL_COMMAND_RELEASE_GL_OBJECTS); 307 308 CommandType(long value) { this.value = value; } 309 long value; 310 @Override 311 public long value() { return value; } 312 public static CommandType getEnum(long v) { return EnumValues.getEnum(v, CommandType.class); } 313 } 314 315 /** 316 * Return the command associated with event. 317 */ 318 @InfoName("CL_EVENT_COMMAND_TYPE") 319 public CommandType getCommandType() { 320 return CommandType.getEnum(infos.getInt(getEntity(), CL_EVENT_COMMAND_TYPE)); 321 } 322 323 324 /** 325 * A 64-bit value that describes the current device time counter in nanoseconds when the command identified by event is enqueued in a command-queue by the host. 326 */ 327 @InfoName("CL_CL_PROFILING_COMMAND_QUEUED") 328 public long getProfilingCommandQueued() { 329 return profilingInfos.getIntOrLong(getEntity(), CL_PROFILING_COMMAND_QUEUED); 330 } 331 332 /** 333 * A 64-bit value that describes the current device time counter in nanoseconds when the command identified by event that has been enqueued is submitted by the host to the device associated with the command- queue. 334 */ 335 @InfoName("CL_CL_PROFILING_COMMAND_SUBMIT") 336 public long getProfilingCommandSubmit() { 337 return profilingInfos.getIntOrLong(getEntity(), CL_PROFILING_COMMAND_SUBMIT); 338 } 339 340 /** 341 * A 64-bit value that describes the current device time counter in nanoseconds when the command identified by event starts execution on the device. 342 */ 343 @InfoName("CL_CL_PROFILING_COMMAND_START") 344 public long getProfilingCommandStart() { 345 return profilingInfos.getIntOrLong(getEntity(), CL_PROFILING_COMMAND_START); 346 } 347 348 /** 349 * A 64-bit value that describes the current device time counter in nanoseconds when the command identified by event has finished execution on the device. 350 */ 351 @InfoName("CL_CL_PROFILING_COMMAND_END") 352 public long getProfilingCommandEnd() { 353 return profilingInfos.getIntOrLong(getEntity(), CL_PROFILING_COMMAND_END); 354 } 355 356 357 @Override 358 public String toString() { 359 return "Event {commandType: " + getCommandType() + "}"; 360 } 361}