Skip to main content

Place, compute, read back

sf.asarray(..., device=...) quantizes on the host and uploads; .to("host") downloads; .numpy() downloads and converts. Only sf16 is accepted on Atreides.

What runs where

Two operands on different devices, or one on the host and one on a device, raise SFTypeError; move one side with .to(...).

Before the launch

Every heavy operation passes the pre-flight gate. In order: static checks (shape, dtype, limits), known answers (a divisor with a zero, a NaN), the range bound, and the golden-vector probe. See Host and device for the reasoning; here is what you observe:
Both exceptions came from the host before any launch: the zero is visible in the inputs, and the range bound proves 0.6 + 0.6 cannot fit anywhere. Under sf.config(preflight="warn") the second one launches with a warning instead.

After the launch

The result’s status says what the runtime knows. When the host proved the operation safe, exact=True and saturated=0. Otherwise, for an elementwise op the count is an upper bound from scanning the output; for a reduction it is unknown. Reading status → The policy is applied to the status after the launch, in catalogue order. An exact count honours over="raise"; an upper bound only warns (SFDeviceOverflowWarning); an unknown count says nothing.
Here the bound could not decide (two elements fit, two do not), so the operation ran and the output was scanned: two outputs sit at max, which is an upper bound, hence <=2 and a warning rather than an exception.

Offloading host work automatically

sf.config(offload_threshold=n) sends host operations with more than n elements to the default device, so a large host computation gets the device path (and a status) without changing the code:

Choosing a target

atreides is the v1 mock (no flags). atreides-flags reports sticky flags, so statuses are exact and over="raise" works for heavy ops. atreides-sim is the kernel simulator, which also runs the built-ins. atreides-hw waits for the real driver. Devices reference →