pub struct Device(/* private fields */);Expand description
An activated native address/execution domain, independent of any program.
Implementations§
Source§impl Device
impl Device
Sourcepub unsafe fn prepare_xdna(
&self,
artifact: &Artifact,
columns: u16,
bindings: &[XdnaBinding<'_>],
) -> Result<XdnaProgram>
pub unsafe fn prepare_xdna( &self, artifact: &Artifact, columns: u16, bindings: &[XdnaBinding<'_>], ) -> Result<XdnaProgram>
Load and bind a canonical XDNA image for the selected logical width.
§Safety
The native executable must be trusted and obey its binding contracts.
Examples found in repository?
10fn main() -> Result<()> {
11 let seconds: f64 = std::env::args()
12 .nth(1)
13 .unwrap_or_else(|| "2".into())
14 .parse()
15 .map_err(|e: std::num::ParseFloatError| hrx::Error::Message(e.to_string()))?;
16 if !seconds.is_finite() || !(0.01..=3600.0).contains(&seconds) {
17 return Err(hrx::Error::Message("seconds must be in 0.01..=3600".into()));
18 }
19 let device = Device::open(Engine::Xdna, 0)?;
20 let compiler = Compiler::for_target(None, device.target())?;
21 println!("working_set_MiB GB/s dispatches/s");
22 for mib in [1, 4, 8, 16, 32, 64] {
23 let bytes = mib * 1024 * 1024;
24 let artifact = compiler
25 .module(include_str!("../tests/kernels/copy.xdna.loom"))
26 .compile(
27 &Specialization::new("copy")
28 .with_config("copy.packets", (bytes / 4096).to_string()),
29 )?;
30 let input = device
31 .fabric()
32 .allocate(bytes, std::slice::from_ref(&device))?;
33 let output = device
34 .fabric()
35 .allocate(bytes, std::slice::from_ref(&device))?;
36 input.write(0, &vec![0x5a; bytes])?;
37 let program = unsafe {
38 device.prepare_xdna(
39 &artifact,
40 1,
41 &[
42 XdnaBinding {
43 buffer: &input,
44 offset: 0,
45 length: bytes,
46 },
47 XdnaBinding {
48 buffer: &output,
49 offset: 0,
50 length: bytes,
51 },
52 ],
53 )
54 }?;
55 unsafe { program.dispatch() }?.wait()?;
56 let mut check = vec![0; bytes];
57 output.read(0, &mut check)?;
58 assert!(check.iter().all(|&b| b == 0x5a));
59 let start = Instant::now();
60 let mut count = 0;
61 while start.elapsed() < Duration::from_secs_f64(seconds) {
62 unsafe { program.dispatch() }?.wait()?;
63 count += 1;
64 }
65 let elapsed = start.elapsed().as_secs_f64();
66 println!(
67 "{} {:.3} {:.1}",
68 2 * mib,
69 2.0 * bytes as f64 * count as f64 / elapsed / 1e9,
70 count as f64 / elapsed
71 );
72 }
73 Ok(())
74}Source§impl Device
impl Device
Sourcepub fn queue(&self) -> Result<Queue>
pub fn queue(&self) -> Result<Queue>
Create a native PM4 queue with one serialized host producer.
Examples found in repository?
6fn main() -> Result<()> {
7 let fabric = Fabric::resolve()?;
8 let gpu = Device::open(Engine::Gpu, 0)?;
9 let npu = Device::open(Engine::Xdna, 0)?;
10 let buffer = fabric.allocate(1 << 20, &[gpu.clone(), npu.clone()])?;
11 println!(
12 "GPU address={:#x}, XDNA DMA address={:#x}",
13 buffer.device_address(&gpu)?,
14 buffer.device_address(&npu)?
15 );
16 let fill = gpu.queue()?.prepare_fill(&buffer, 0, buffer.len(), 0x5a)?;
17 unsafe { fill.dispatch() }?.wait()?;
18 let mut bytes = vec![0; buffer.len()];
19 buffer.read(0, &mut bytes)?;
20 assert!(bytes.iter().all(|&byte| byte == 0x5a));
21 println!("native shared allocation: {} bytes verified", bytes.len());
22 Ok(())
23}Sourcepub fn sdma_queue(&self) -> Result<Queue>
pub fn sdma_queue(&self) -> Result<Queue>
Create a native SDMA transfer queue without loading compute kernels.
Source§impl Device
impl Device
Sourcepub unsafe fn load(&self, artifact: &Artifact) -> Result<Kernel>
pub unsafe fn load(&self, artifact: &Artifact) -> Result<Kernel>
Load an entry from a compiler-produced artifact onto this GPU.
§Safety
The executable is native code. The caller must trust its code and its declared memory/argument contract; parsing is not a sandbox.
Sourcepub unsafe fn load_sanitized(
&self,
artifact: &Artifact,
options: &SanitizerRuntimeOptions,
) -> Result<Kernel>
pub unsafe fn load_sanitized( &self, artifact: &Artifact, options: &SanitizerRuntimeOptions, ) -> Result<Kernel>
Load an artifact with an owned, bounded sanitizer feedback channel. Supports address/value/operation reports and workgroup-local race checking. Address shadow covers the complete bound allocations and executable storage. Allocation starts must be 8-byte aligned; undeclared pointers stay poisoned. Preparation rejects an address span whose shadow exceeds the configured limit. Dispatch through an AQL queue, which supplies the native dispatch pointer.
§Safety
The artifact must use the current compiler and its bounded shadow checks. It remains trusted native code. Use report-only instrumentation when execution must complete after a diagnostic; trap mode can fault the queue.
Source§impl Device
impl Device
Sourcepub fn aql_queue(&self, maximum_private_bytes: u32) -> Result<AqlQueue>
pub fn aql_queue(&self, maximum_private_bytes: u32) -> Result<AqlQueue>
Create an AQL queue with fixed per-workitem scratch capacity. Zero admits kernels with no private segment. All physical scratch slots are allocated before returning; dispatch never grows the pool.
Sourcepub fn aql_queue_budgeted(
&self,
maximum_private_bytes: u32,
budget: Option<&MemoryBudget>,
) -> Result<AqlQueue>
pub fn aql_queue_budgeted( &self, maximum_private_bytes: u32, budget: Option<&MemoryBudget>, ) -> Result<AqlQueue>
Create a queue whose scratch and prepared dispatch storage share a byte ceiling.
Source§impl Device
impl Device
Sourcepub fn target(&self) -> &Target
pub fn target(&self) -> &Target
Exact target for offline compilation and executable admission.
Examples found in repository?
10fn main() -> Result<()> {
11 let seconds: f64 = std::env::args()
12 .nth(1)
13 .unwrap_or_else(|| "2".into())
14 .parse()
15 .map_err(|e: std::num::ParseFloatError| hrx::Error::Message(e.to_string()))?;
16 if !seconds.is_finite() || !(0.01..=3600.0).contains(&seconds) {
17 return Err(hrx::Error::Message("seconds must be in 0.01..=3600".into()));
18 }
19 let device = Device::open(Engine::Xdna, 0)?;
20 let compiler = Compiler::for_target(None, device.target())?;
21 println!("working_set_MiB GB/s dispatches/s");
22 for mib in [1, 4, 8, 16, 32, 64] {
23 let bytes = mib * 1024 * 1024;
24 let artifact = compiler
25 .module(include_str!("../tests/kernels/copy.xdna.loom"))
26 .compile(
27 &Specialization::new("copy")
28 .with_config("copy.packets", (bytes / 4096).to_string()),
29 )?;
30 let input = device
31 .fabric()
32 .allocate(bytes, std::slice::from_ref(&device))?;
33 let output = device
34 .fabric()
35 .allocate(bytes, std::slice::from_ref(&device))?;
36 input.write(0, &vec![0x5a; bytes])?;
37 let program = unsafe {
38 device.prepare_xdna(
39 &artifact,
40 1,
41 &[
42 XdnaBinding {
43 buffer: &input,
44 offset: 0,
45 length: bytes,
46 },
47 XdnaBinding {
48 buffer: &output,
49 offset: 0,
50 length: bytes,
51 },
52 ],
53 )
54 }?;
55 unsafe { program.dispatch() }?.wait()?;
56 let mut check = vec![0; bytes];
57 output.read(0, &mut check)?;
58 assert!(check.iter().all(|&b| b == 0x5a));
59 let start = Instant::now();
60 let mut count = 0;
61 while start.elapsed() < Duration::from_secs_f64(seconds) {
62 unsafe { program.dispatch() }?.wait()?;
63 count += 1;
64 }
65 let elapsed = start.elapsed().as_secs_f64();
66 println!(
67 "{} {:.3} {:.1}",
68 2 * mib,
69 2.0 * bytes as f64 * count as f64 / elapsed / 1e9,
70 count as f64 / elapsed
71 );
72 }
73 Ok(())
74}Source§impl Device
impl Device
Sourcepub fn open(engine: Engine, index: usize) -> Result<Self>
pub fn open(engine: Engine, index: usize) -> Result<Self>
Open a selected engine ordinal in the shared, weakly cached provider. Live buffers keep their exact device identity; the registry owns no device.
Examples found in repository?
6fn main() -> Result<()> {
7 let fabric = Fabric::resolve()?;
8 let gpu = Device::open(Engine::Gpu, 0)?;
9 let npu = Device::open(Engine::Xdna, 0)?;
10 let buffer = fabric.allocate(1 << 20, &[gpu.clone(), npu.clone()])?;
11 println!(
12 "GPU address={:#x}, XDNA DMA address={:#x}",
13 buffer.device_address(&gpu)?,
14 buffer.device_address(&npu)?
15 );
16 let fill = gpu.queue()?.prepare_fill(&buffer, 0, buffer.len(), 0x5a)?;
17 unsafe { fill.dispatch() }?.wait()?;
18 let mut bytes = vec![0; buffer.len()];
19 buffer.read(0, &mut bytes)?;
20 assert!(bytes.iter().all(|&byte| byte == 0x5a));
21 println!("native shared allocation: {} bytes verified", bytes.len());
22 Ok(())
23}More examples
10fn main() -> Result<()> {
11 let seconds: f64 = std::env::args()
12 .nth(1)
13 .unwrap_or_else(|| "2".into())
14 .parse()
15 .map_err(|e: std::num::ParseFloatError| hrx::Error::Message(e.to_string()))?;
16 if !seconds.is_finite() || !(0.01..=3600.0).contains(&seconds) {
17 return Err(hrx::Error::Message("seconds must be in 0.01..=3600".into()));
18 }
19 let device = Device::open(Engine::Xdna, 0)?;
20 let compiler = Compiler::for_target(None, device.target())?;
21 println!("working_set_MiB GB/s dispatches/s");
22 for mib in [1, 4, 8, 16, 32, 64] {
23 let bytes = mib * 1024 * 1024;
24 let artifact = compiler
25 .module(include_str!("../tests/kernels/copy.xdna.loom"))
26 .compile(
27 &Specialization::new("copy")
28 .with_config("copy.packets", (bytes / 4096).to_string()),
29 )?;
30 let input = device
31 .fabric()
32 .allocate(bytes, std::slice::from_ref(&device))?;
33 let output = device
34 .fabric()
35 .allocate(bytes, std::slice::from_ref(&device))?;
36 input.write(0, &vec![0x5a; bytes])?;
37 let program = unsafe {
38 device.prepare_xdna(
39 &artifact,
40 1,
41 &[
42 XdnaBinding {
43 buffer: &input,
44 offset: 0,
45 length: bytes,
46 },
47 XdnaBinding {
48 buffer: &output,
49 offset: 0,
50 length: bytes,
51 },
52 ],
53 )
54 }?;
55 unsafe { program.dispatch() }?.wait()?;
56 let mut check = vec![0; bytes];
57 output.read(0, &mut check)?;
58 assert!(check.iter().all(|&b| b == 0x5a));
59 let start = Instant::now();
60 let mut count = 0;
61 while start.elapsed() < Duration::from_secs_f64(seconds) {
62 unsafe { program.dispatch() }?.wait()?;
63 count += 1;
64 }
65 let elapsed = start.elapsed().as_secs_f64();
66 println!(
67 "{} {:.3} {:.1}",
68 2 * mib,
69 2.0 * bytes as f64 * count as f64 / elapsed / 1e9,
70 count as f64 / elapsed
71 );
72 }
73 Ok(())
74}Sourcepub fn open_with_lifetime(
engine: Engine,
index: usize,
lifetime: NativeLifetime,
) -> Result<Self>
pub fn open_with_lifetime( engine: Engine, index: usize, lifetime: NativeLifetime, ) -> Result<Self>
Open in an explicitly selected native ownership domain.
Sourcepub fn fabric(&self) -> Fabric
pub fn fabric(&self) -> Fabric
Allocation and discovery domain retained by this device.
Examples found in repository?
10fn main() -> Result<()> {
11 let seconds: f64 = std::env::args()
12 .nth(1)
13 .unwrap_or_else(|| "2".into())
14 .parse()
15 .map_err(|e: std::num::ParseFloatError| hrx::Error::Message(e.to_string()))?;
16 if !seconds.is_finite() || !(0.01..=3600.0).contains(&seconds) {
17 return Err(hrx::Error::Message("seconds must be in 0.01..=3600".into()));
18 }
19 let device = Device::open(Engine::Xdna, 0)?;
20 let compiler = Compiler::for_target(None, device.target())?;
21 println!("working_set_MiB GB/s dispatches/s");
22 for mib in [1, 4, 8, 16, 32, 64] {
23 let bytes = mib * 1024 * 1024;
24 let artifact = compiler
25 .module(include_str!("../tests/kernels/copy.xdna.loom"))
26 .compile(
27 &Specialization::new("copy")
28 .with_config("copy.packets", (bytes / 4096).to_string()),
29 )?;
30 let input = device
31 .fabric()
32 .allocate(bytes, std::slice::from_ref(&device))?;
33 let output = device
34 .fabric()
35 .allocate(bytes, std::slice::from_ref(&device))?;
36 input.write(0, &vec![0x5a; bytes])?;
37 let program = unsafe {
38 device.prepare_xdna(
39 &artifact,
40 1,
41 &[
42 XdnaBinding {
43 buffer: &input,
44 offset: 0,
45 length: bytes,
46 },
47 XdnaBinding {
48 buffer: &output,
49 offset: 0,
50 length: bytes,
51 },
52 ],
53 )
54 }?;
55 unsafe { program.dispatch() }?.wait()?;
56 let mut check = vec![0; bytes];
57 output.read(0, &mut check)?;
58 assert!(check.iter().all(|&b| b == 0x5a));
59 let start = Instant::now();
60 let mut count = 0;
61 while start.elapsed() < Duration::from_secs_f64(seconds) {
62 unsafe { program.dispatch() }?.wait()?;
63 count += 1;
64 }
65 let elapsed = start.elapsed().as_secs_f64();
66 println!(
67 "{} {:.3} {:.1}",
68 2 * mib,
69 2.0 * bytes as f64 * count as f64 / elapsed / 1e9,
70 count as f64 / elapsed
71 );
72 }
73 Ok(())
74}Trait Implementations§
Auto Trait Implementations§
impl Freeze for Device
impl RefUnwindSafe for Device
impl Send for Device
impl Sync for Device
impl Unpin for Device
impl UnsafeUnpin for Device
impl UnwindSafe for Device
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> DropFlavorWrapper<T> for T
impl<T> DropFlavorWrapper<T> for T
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more