ocl_extras/
command_graph.rs1use std::cell::{Cell, RefCell, Ref};
22use std::collections::{HashMap, BTreeSet};
23use ocl::{Event, EventList};
24
25pub struct RwCmdIdxs {
26 writers: Vec<usize>,
27 readers: Vec<usize>,
28}
29
30impl RwCmdIdxs {
31 fn new() -> RwCmdIdxs {
32 RwCmdIdxs { writers: Vec::new(), readers: Vec::new() }
33 }
34}
35
36#[allow(dead_code)]
37pub struct KernelArgBuffer {
38 arg_idx: usize, buffer_id: usize,
40}
41
42impl KernelArgBuffer {
43 pub fn new(arg_idx: usize, buffer_id: usize) -> KernelArgBuffer {
44 KernelArgBuffer { arg_idx: arg_idx, buffer_id: buffer_id }
45 }
46}
47
48
49pub enum CommandDetails {
51 Fill { target: usize },
52 Write { target: usize },
53 Read { source: usize },
54 Copy { source: usize, target: usize },
55 Kernel { id: usize, sources: Vec<KernelArgBuffer>, targets: Vec<KernelArgBuffer> },
56}
57
58impl CommandDetails {
59 pub fn sources(&self) -> Vec<usize> {
60 match *self {
61 CommandDetails::Fill { .. } => vec![],
62 CommandDetails::Read { source } => vec![source],
63 CommandDetails::Write { .. } => vec![],
64 CommandDetails::Copy { source, .. } => vec![source],
65 CommandDetails::Kernel { ref sources, .. } => {
66 sources.iter().map(|arg| arg.buffer_id).collect()
67 },
68 }
69 }
70
71 pub fn targets(&self) -> Vec<usize> {
72 match *self {
73 CommandDetails::Fill { target } => vec![target],
74 CommandDetails::Read { .. } => vec![],
75 CommandDetails::Write { target } => vec![target],
76 CommandDetails::Copy { target, .. } => vec![target],
77 CommandDetails::Kernel { ref targets, .. } => {
78 targets.iter().map(|arg| arg.buffer_id).collect()
79 },
80 }
81 }
82}
83
84
85pub struct Command {
86 details: CommandDetails,
87 event: RefCell<Option<Event>>,
88 requisite_events: RefCell<EventList>,
89}
90
91impl Command {
92 pub fn new(details: CommandDetails) -> Command {
93 Command {
94 details: details,
95 event: RefCell::new(None),
96 requisite_events: RefCell::new(EventList::new()),
97 }
98 }
99
100 pub fn preceding_writers(&self, cmds: &HashMap<usize, RwCmdIdxs>) -> BTreeSet<usize> {
103 self.details.sources().iter().flat_map(|cmd_src_block|
104 cmds.get(cmd_src_block).unwrap().writers.iter().cloned()).collect()
105 }
106
107 pub fn following_readers(&self, cmds: &HashMap<usize, RwCmdIdxs>) -> BTreeSet<usize> {
110 self.details.targets().iter().flat_map(|cmd_tar_block|
111 cmds.get(cmd_tar_block).unwrap().readers.iter().cloned()).collect()
112 }
113
114 pub fn details(&self) -> &CommandDetails { &self.details }
115}
116
117
118pub struct CommandGraph {
137 commands: Vec<Command>,
138 command_requisites: Vec<Vec<usize>>,
139 ends: (Vec<usize>, Vec<usize>),
140 locked: bool,
141 next_cmd_idx: Cell<usize>,
142}
143
144impl CommandGraph {
145 pub fn new() -> CommandGraph {
147 CommandGraph {
148 commands: Vec::new(),
149 command_requisites: Vec::new(),
150 ends: (Vec::new(), Vec::new()),
151 locked: false,
152 next_cmd_idx: Cell::new(0),
153 }
154 }
155
156 pub fn add(&mut self, command: Command) -> Result<usize, ()> {
158 if self.locked { return Err(()); }
159 self.commands.push(command);
160 self.command_requisites.push(Vec::new());
161 Ok(self.commands.len() - 1)
162 }
163
164 fn readers_and_writers_by_buffer(&self) -> HashMap<usize, RwCmdIdxs> {
167 let mut cmds = HashMap::new();
168
169 for (cmd_idx, cmd) in self.commands.iter().enumerate() {
170 for cmd_src_block in cmd.details.sources().into_iter() {
171 let rw_cmd_idxs = cmds.entry(cmd_src_block.clone())
172 .or_insert(RwCmdIdxs::new());
173
174 rw_cmd_idxs.readers.push(cmd_idx);
175 }
176
177 for cmd_tar_block in cmd.details.targets().into_iter() {
178 let rw_cmd_idxs = cmds.entry(cmd_tar_block.clone())
179 .or_insert(RwCmdIdxs::new());
180
181 rw_cmd_idxs.writers.push(cmd_idx);
182 }
183 }
184
185 cmds
186 }
187
188 pub fn populate_requisites(&mut self) {
202 let cmds = self.readers_and_writers_by_buffer();
203
204 for (cmd_idx, cmd) in self.commands.iter_mut().enumerate() {
205 assert!(self.command_requisites[cmd_idx].is_empty());
206
207 let preceding_writers = cmd.preceding_writers(&cmds);
209
210 if preceding_writers.len() == 0 { self.ends.0.push(cmd_idx); }
212
213 for &req_cmd_idx in preceding_writers.iter() {
215 self.command_requisites[cmd_idx].push(req_cmd_idx);
216 }
217
218 let following_readers = cmd.following_readers(&cmds);
220
221 if following_readers.len() == 0 { self.ends.1.push(cmd_idx); }
223
224 for &req_cmd_idx in following_readers.iter() {
226 self.command_requisites[cmd_idx].push(req_cmd_idx);
227 }
228
229 self.command_requisites[cmd_idx].shrink_to_fit();
230 }
231
232 self.commands.shrink_to_fit();
233 self.command_requisites.shrink_to_fit();
234 self.locked = true;
235 }
236
237 pub fn get_req_events(&self, cmd_idx: usize) -> Result<Ref<EventList>, &'static str> {
239 if !self.locked { return Err("Call '::populate_requisites' first."); }
240 if self.next_cmd_idx.get() != cmd_idx { return Err("Command events requested out of order."); }
241
242 self.commands.get(cmd_idx).unwrap().requisite_events.borrow_mut().clear();
243
244 for &req_idx in self.command_requisites[cmd_idx].iter() {
245 let event_opt = self.commands[req_idx].event.borrow().clone();
246
247 if let Some(event) = event_opt {
248 self.commands[cmd_idx].requisite_events.borrow_mut().push(event);
249 }
250 }
251
252 Ok(self.commands[cmd_idx].requisite_events.borrow())
253 }
254
255 pub fn set_cmd_event(&self, cmd_idx: usize, event: Event) -> Result<(), &'static str> {
257 if !self.locked { return Err("Call '::populate_requisites' first."); }
258
259 *self.commands.get(cmd_idx).unwrap().event.borrow_mut() = Some(event);
262
263 if (self.next_cmd_idx.get() + 1) == self.commands.len() {
264 self.next_cmd_idx.set(0);
265 } else {
266 self.next_cmd_idx.set(self.next_cmd_idx.get() + 1);
268 }
269
270 Ok(())
271 }
272
273 pub fn commands<'a>(&'a self) -> &'a [Command] {
274 self.commands.as_slice()
275 }
276
277 pub fn get_finish_events (&self, event_list: &mut EventList) {
278 assert!(self.next_cmd_idx.get() == 0, "Finish events can only be determined \
279 for each cycle just after the graph has set its last cmd event.");
280
281 for &cmd_idx in self.ends.1.iter() {
282 let event_opt = self.commands[cmd_idx].event.borrow().clone();
283
284 if let Some(event) = event_opt {
285 event_list.push(event);
286 }
287 }
288 }
289}