opencl3/
event.rs

1// Copyright (c) 2020-2024 Via Technology Ltd. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub use cl3::event::*;
16
17use super::Result;
18use libc::c_void;
19
20/// An OpenCL event object.
21///
22/// Has methods to return information from calls to clGetEventInfo and
23/// clGetEventProfilingInfo with the appropriate parameters.  
24/// Implements the Drop trait to call release_event when the object is dropped.
25#[derive(Debug)]
26pub struct Event {
27    event: cl_event,
28}
29
30impl From<cl_event> for Event {
31    fn from(event: cl_event) -> Self {
32        Self { event }
33    }
34}
35
36impl From<Event> for cl_event {
37    fn from(value: Event) -> Self {
38        value.event as Self
39    }
40}
41
42impl Drop for Event {
43    fn drop(&mut self) {
44        unsafe { release_event(self.event).expect("Error: clReleaseEvent") };
45    }
46}
47
48unsafe impl Send for Event {}
49unsafe impl Sync for Event {}
50
51impl Event {
52    /// Create an Event from an OpenCL cl_event.
53    ///
54    /// * `event` - a valid OpenCL cl_event.
55    ///
56    /// returns the new Event
57    pub const fn new(event: cl_event) -> Self {
58        Self { event }
59    }
60
61    /// Get the underlying OpenCL cl_event.
62    pub const fn get(&self) -> cl_event {
63        self.event
64    }
65
66    /// Wait for the event to complete.
67    pub fn wait(&self) -> Result<()> {
68        let events = [self.get()];
69        Ok(wait_for_events(&events)?)
70    }
71
72    pub fn command_execution_status(&self) -> Result<CommandExecutionStatus> {
73        Ok(CommandExecutionStatus(
74            get_event_info(self.event, CL_EVENT_COMMAND_EXECUTION_STATUS)?.into(),
75        ))
76    }
77
78    pub fn command_type(&self) -> Result<EventCommandType> {
79        Ok(EventCommandType(
80            get_event_info(self.event, CL_EVENT_COMMAND_TYPE)?.into(),
81        ))
82    }
83
84    pub fn reference_count(&self) -> Result<cl_uint> {
85        Ok(get_event_info(self.event, CL_EVENT_REFERENCE_COUNT)?.into())
86    }
87
88    pub fn command_queue(&self) -> Result<cl_command_queue> {
89        Ok(isize::from(get_event_info(self.event, CL_EVENT_COMMAND_QUEUE)?) as cl_command_queue)
90    }
91
92    pub fn context(&self) -> Result<cl_context> {
93        Ok(isize::from(get_event_info(self.event, CL_EVENT_CONTEXT)?) as cl_context)
94    }
95
96    /// Get data about an OpenCL event.
97    /// Calls clGetEventInfo to get the desired data about the event.
98    pub fn get_data(&self, param_name: cl_event_info) -> Result<Vec<u8>> {
99        Ok(get_event_data(self.event, param_name)?)
100    }
101
102    pub fn set_callback(
103        &self,
104        command_exec_callback_type: cl_int,
105        pfn_notify: extern "C" fn(cl_event, cl_int, *mut c_void),
106        user_data: *mut c_void,
107    ) -> Result<()> {
108        Ok(set_event_callback(
109            self.event,
110            command_exec_callback_type,
111            pfn_notify,
112            user_data,
113        )?)
114    }
115
116    pub fn profiling_command_queued(&self) -> Result<cl_ulong> {
117        Ok(get_event_profiling_info(self.event, CL_PROFILING_COMMAND_QUEUED)?.into())
118    }
119
120    pub fn profiling_command_submit(&self) -> Result<cl_ulong> {
121        Ok(get_event_profiling_info(self.event, CL_PROFILING_COMMAND_SUBMIT)?.into())
122    }
123
124    pub fn profiling_command_start(&self) -> Result<cl_ulong> {
125        Ok(get_event_profiling_info(self.event, CL_PROFILING_COMMAND_START)?.into())
126    }
127
128    pub fn profiling_command_end(&self) -> Result<cl_ulong> {
129        Ok(get_event_profiling_info(self.event, CL_PROFILING_COMMAND_END)?.into())
130    }
131
132    /// CL_VERSION_2_0
133    pub fn profiling_command_complete(&self) -> Result<cl_ulong> {
134        Ok(get_event_profiling_info(self.event, CL_PROFILING_COMMAND_COMPLETE)?.into())
135    }
136
137    /// Get profiling data about an OpenCL event.
138    /// Calls clGetEventProfilingInfo to get the desired profiling data about the event.
139    pub fn profiling_data(&self, param_name: cl_profiling_info) -> Result<Vec<u8>> {
140        Ok(get_event_profiling_data(self.event, param_name)?)
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use crate::command_queue::{CL_QUEUE_PROFILING_ENABLE, CommandQueue};
148    use crate::context::Context;
149    use crate::device::{CL_DEVICE_TYPE_GPU, Device};
150    use crate::memory::{Buffer, CL_MEM_READ_ONLY};
151    use crate::platform::get_platforms;
152    use crate::types::{CL_NON_BLOCKING, cl_float};
153    use std::ptr;
154
155    extern "C" fn event_callback_function(
156        _event: cl_event,
157        event_command_status: cl_int,
158        _user_data: *mut c_void,
159    ) {
160        println!(
161            "OpenCL event callback command status: {}",
162            event_command_status
163        );
164    }
165
166    #[test]
167    fn test_event() {
168        let platforms = get_platforms().unwrap();
169        assert!(0 < platforms.len());
170
171        // Get the first platform
172        let platform = &platforms[0];
173
174        let devices = platform.get_devices(CL_DEVICE_TYPE_GPU).unwrap();
175        assert!(0 < devices.len());
176
177        // Get the first device
178        let device = Device::new(devices[0]);
179        let context = Context::from_device(&device).unwrap();
180
181        // Create a command_queue on the Context's default device
182        let queue = CommandQueue::create_default(&context, CL_QUEUE_PROFILING_ENABLE)
183            .expect("CommandQueue::create_default failed");
184
185        const ARRAY_SIZE: usize = 1024;
186        let ones: [cl_float; ARRAY_SIZE] = [1.0; ARRAY_SIZE];
187
188        let mut buffer = unsafe {
189            Buffer::<cl_float>::create(&context, CL_MEM_READ_ONLY, ARRAY_SIZE, ptr::null_mut())
190                .unwrap()
191        };
192
193        let events: Vec<cl_event> = Vec::default();
194
195        // Non-blocking write, wait for event
196        let event = unsafe {
197            queue
198                .enqueue_write_buffer(&mut buffer, CL_NON_BLOCKING, 0, &ones, &events)
199                .unwrap()
200        };
201
202        // Set a callback_function on the event (i.e. write) being completed.
203        event
204            .set_callback(CL_COMPLETE, event_callback_function, ptr::null_mut())
205            .unwrap();
206
207        let value = event.command_execution_status().unwrap();
208        println!("event.command_execution_status(): {}", value);
209        // assert_eq!(CL_QUEUED, value.0);
210
211        let value = event.command_type().unwrap();
212        println!("event.command_type(): {}", value);
213        assert_eq!(CL_COMMAND_WRITE_BUFFER, value.0);
214
215        let value = event.reference_count().unwrap();
216        println!("event.reference_count(): {}", value);
217        // assert_eq!(1, value);
218
219        let value = event.command_queue().unwrap();
220        assert!(queue.get() == value);
221
222        let value = event.context().unwrap();
223        assert!(context.get() == value);
224
225        event.wait().unwrap();
226
227        let value = event.command_execution_status().unwrap();
228        println!("event.command_execution_status(): {}", value);
229        assert_eq!(CL_COMPLETE, value.0);
230
231        let value = event.profiling_command_queued().unwrap();
232        println!("event.profiling_command_queued(): {}", value);
233        assert!(0 < value);
234
235        let value = event.profiling_command_submit().unwrap();
236        println!("event.profiling_command_submit(): {}", value);
237        assert!(0 < value);
238
239        let value = event.profiling_command_start().unwrap();
240        println!("event.profiling_command_start(): {}", value);
241        assert!(0 < value);
242
243        let value = event.profiling_command_end().unwrap();
244        println!("event.profiling_command_end(): {}", value);
245        assert!(0 < value);
246
247        // CL_VERSION_2_0
248        match event.profiling_command_complete() {
249            Ok(value) => println!("event.profiling_command_complete(): {}", value),
250            Err(e) => println!("OpenCL error, event.profiling_command_complete(): {}", e),
251        }
252    }
253}