Skip to main content

Device

Struct Device 

Source
pub struct Device(/* private fields */);
Expand description

An activated native address/execution domain, independent of any program.

Implementations§

Source§

impl Device

Source

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?
examples/mall_probe.rs (lines 38-53)
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

Source

pub fn queue(&self) -> Result<Queue>

Create a native PM4 queue with one serialized host producer.

Examples found in repository?
examples/unified_probe.rs (line 16)
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}
Source

pub fn sdma_queue(&self) -> Result<Queue>

Create a native SDMA transfer queue without loading compute kernels.

Source§

impl Device

Source

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.

Source

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

pub unsafe fn load_bytes(&self, bytes: &[u8], symbol: &str) -> Result<Kernel>

Load a native gfx1151 code object and select its named entry.

§Safety

The native code must be trusted and obey its declared memory contract.

Source§

impl Device

Source

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.

Source

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

Source

pub fn endpoint(&self) -> &Endpoint

Passive identity retained by the activated device.

Source

pub fn target(&self) -> &Target

Exact target for offline compilation and executable admission.

Examples found in repository?
examples/mall_probe.rs (line 20)
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

Source

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?
examples/unified_probe.rs (line 8)
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
Hide additional examples
examples/mall_probe.rs (line 19)
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

pub fn open_with_lifetime( engine: Engine, index: usize, lifetime: NativeLifetime, ) -> Result<Self>

Open in an explicitly selected native ownership domain.

Source

pub fn id(&self) -> usize

Stable identity while this device or any dependent owner is live.

Source

pub fn fabric(&self) -> Fabric

Allocation and discovery domain retained by this device.

Examples found in repository?
examples/mall_probe.rs (line 31)
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§

Source§

impl Clone for Device

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DropFlavorWrapper<T> for T

Source§

type Flavor = MayDrop

The DropFlavor that wraps T into Self
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more