/// <summary cref="Accelerator.Synchronize"/> protected unsafe override void SynchronizeInternal() { // All the events to wait on. Each event represents the completion // of all operations queued prior to said event. var streamInstances = InlineList <CLStream> .Create(4); var streamEvents = InlineList <IntPtr> .Create(4); try { ForEachChildObject <CLStream>(stream => { // Ignore disposed command queues at this point if (stream.CommandQueue == IntPtr.Zero) { return; } // Low cost IntPtr* (cl_event*) allocation IntPtr *resultEvent = stackalloc IntPtr[1]; CLException.ThrowIfFailed( CurrentAPI.EnqueueBarrierWithWaitList( stream.CommandQueue, Array.Empty <IntPtr>(), resultEvent)); // Dereference the pointer so we can store it streamEvents.Add(*resultEvent); // Keep the stream instance alive to avoid automatic disposal streamInstances.Add(stream); }); // Wait for all the events to fire, which would mean all operations // queued on an accelerator prior to synchronization have finished if (streamEvents.Count > 0) { CLException.ThrowIfFailed( CurrentAPI.WaitForEvents(streamEvents)); } } finally { // Clean up the events we made foreach (var streamEvent in streamEvents) { CLException.ThrowIfFailed( CurrentAPI.ReleaseEvent(streamEvent)); } } }
/// <inheritdoc/> protected unsafe override ProfilingMarker AddProfilingMarkerInternal() { IntPtr *profilingEvent = stackalloc IntPtr[1]; CLException.ThrowIfFailed( CurrentAPI.EnqueueBarrierWithWaitList( queuePtr, Array.Empty <IntPtr>(), profilingEvent)); // WORKAROUND: The OpenCL event needs to be awaited now, otherwise // it does not contain the correct timing - it appears to have the timing // of whenever it gets awaited. var marker = new CLProfilingMarker(*profilingEvent); marker.Synchronize(); return(marker); }