1#![forbid(unsafe_code)]
13#![no_std]
14
15use core::sync::atomic::{AtomicU64, Ordering};
16use core::{convert::TryFrom, result::Result};
17
18use virtio_accel_core::{
19 Accelerator, AllocatedBuffer, ArtifactRef, BackendError, BindingRef, BufferDesc, ByteSink,
20 ByteSource, ContextDesc, DeviceInfo, EventState, QueueDesc, ReleaseFailure, SubmitFailure,
21 Timeout,
22};
23
24#[derive(Debug, Default)]
25struct SubmissionPathCounters {
26 direct_bindings: AtomicU64,
27 explicit_transfer_bytes: AtomicU64,
28}
29
30impl SubmissionPathCounters {
31 fn direct_binding_admissions(&self) -> u64 {
32 self.direct_bindings.load(Ordering::Relaxed)
33 }
34
35 fn explicit_transfer_bytes(&self) -> u64 {
36 self.explicit_transfer_bytes.load(Ordering::Relaxed)
37 }
38
39 fn reset(&self) {
40 self.direct_bindings.store(0, Ordering::Relaxed);
41 self.explicit_transfer_bytes.store(0, Ordering::Relaxed);
42 }
43
44 fn record_submission(&self, bindings: usize) {
45 self.direct_bindings.fetch_add(
46 u64::try_from(bindings).unwrap_or(u64::MAX),
47 Ordering::Relaxed,
48 );
49 }
50
51 fn record_explicit_transfer(&self, bytes: u64) {
52 self.explicit_transfer_bytes
53 .fetch_add(bytes, Ordering::Relaxed);
54 }
55}
56
57#[derive(Debug)]
59pub struct VAccelAdapter<A> {
60 inner: A,
61 counters: SubmissionPathCounters,
62}
63
64impl<A> VAccelAdapter<A> {
65 pub fn new(inner: A) -> Self {
67 Self {
68 inner,
69 counters: SubmissionPathCounters::default(),
70 }
71 }
72
73 pub fn backend(&self) -> &A {
75 &self.inner
76 }
77
78 pub fn backend_mut(&mut self) -> &mut A {
80 &mut self.inner
81 }
82
83 pub fn into_inner(self) -> A {
85 self.inner
86 }
87
88 pub fn direct_binding_admissions(&self) -> u64 {
93 self.counters.direct_binding_admissions()
94 }
95
96 pub fn explicit_transfer_bytes(&self) -> u64 {
100 self.counters.explicit_transfer_bytes()
101 }
102
103 pub fn reset_submission_path_metrics(&self) {
105 self.counters.reset();
106 }
107}
108
109impl<A: Accelerator> Accelerator for VAccelAdapter<A> {
110 type Context = A::Context;
111 type Buffer = A::Buffer;
112 type Program = A::Program;
113 type Queue = A::Queue;
114 type Event = A::Event;
115
116 fn device_info(&self) -> Result<DeviceInfo, BackendError> {
117 self.inner.device_info()
118 }
119
120 fn create_context(&self, desc: ContextDesc) -> Result<Self::Context, BackendError> {
121 self.inner.create_context(desc)
122 }
123
124 fn destroy_context(&self, context: Self::Context) -> Result<(), ReleaseFailure<Self::Context>> {
125 self.inner.destroy_context(context)
126 }
127
128 fn allocate_buffer(
129 &self,
130 context: &Self::Context,
131 desc: BufferDesc,
132 ) -> Result<AllocatedBuffer<Self::Buffer>, BackendError> {
133 self.inner.allocate_buffer(context, desc)
134 }
135
136 fn write_buffer(
137 &self,
138 buffer: &mut Self::Buffer,
139 offset: u64,
140 data: &dyn ByteSource,
141 ) -> Result<(), BackendError> {
142 let result = self.inner.write_buffer(buffer, offset, data);
143 if result.is_ok() {
144 self.counters.record_explicit_transfer(data.len());
145 }
146 result
147 }
148
149 fn read_buffer(
150 &self,
151 buffer: &Self::Buffer,
152 offset: u64,
153 data: &mut dyn ByteSink,
154 ) -> Result<(), BackendError> {
155 let result = self.inner.read_buffer(buffer, offset, data);
156 if result.is_ok() {
157 self.counters.record_explicit_transfer(data.len());
158 }
159 result
160 }
161
162 fn free_buffer(&self, buffer: Self::Buffer) -> Result<(), ReleaseFailure<Self::Buffer>> {
163 self.inner.free_buffer(buffer)
164 }
165
166 fn load_program(
167 &self,
168 context: &Self::Context,
169 artifact: ArtifactRef<'_>,
170 ) -> Result<Self::Program, BackendError> {
171 self.inner.load_program(context, artifact)
172 }
173
174 fn unload_program(&self, program: Self::Program) -> Result<(), ReleaseFailure<Self::Program>> {
175 self.inner.unload_program(program)
176 }
177
178 fn create_queue(
179 &self,
180 context: &Self::Context,
181 desc: QueueDesc,
182 ) -> Result<Self::Queue, BackendError> {
183 self.inner.create_queue(context, desc)
184 }
185
186 fn destroy_queue(&self, queue: Self::Queue) -> Result<(), ReleaseFailure<Self::Queue>> {
187 self.inner.destroy_queue(queue)
188 }
189
190 fn submit(
191 &self,
192 queue: &Self::Queue,
193 program: &Self::Program,
194 bindings: &[BindingRef<'_, Self::Buffer>],
195 timeout: Timeout,
196 ) -> Result<Self::Event, SubmitFailure<Self::Event>> {
197 let result = self.inner.submit(queue, program, bindings, timeout);
198 match &result {
199 Ok(_) => self.counters.record_submission(bindings.len()),
200 Err(SubmitFailure::Indeterminate { .. }) => {
201 self.counters.record_submission(bindings.len())
202 }
203 Err(SubmitFailure::Rejected(_)) => {}
204 }
205 result
206 }
207
208 fn poll_event(&self, event: &Self::Event) -> Result<EventState, BackendError> {
209 self.inner.poll_event(event)
210 }
211
212 fn cancel_event(&self, event: &Self::Event) -> Result<(), BackendError> {
213 self.inner.cancel_event(event)
214 }
215
216 fn destroy_event(&self, event: Self::Event) -> Result<(), ReleaseFailure<Self::Event>> {
217 self.inner.destroy_event(event)
218 }
219}