pub struct DepthwiseTiling {
pub rows: usize,
pub cols: usize,
pub chans: usize,
pub lines: usize,
}Expand description
How one cube’s share of the output is shaped, and how the cube’s threads divide it.
The three numbers are three different jobs, which is why they are not one “tile size”:
rowsis the plane count. One plane per output row, so it is what fills the cube.colsis the accumulator block one lane keeps in registers. Every column of it re-reads the same filter and overlapping input, so it is what amortises both.chansis how many channel lines one lane owns. Lanes are dealt lines interleaved, so whatever this is, consecutive lanes still read consecutive channels and the read coalesces.linesis how many channels one of those lines covers — the width every operand is served in. It is the one knob that trades the two things a depthwise pass is limited by against each other, which is why it is stated and not derived: a wider line is fewer instructions per channel, and also more registers per lane and a wider channel tile, so fewer lanes with anything to do when the block is narrow. It is a ceiling, not a demand — the launch drops to what the buffers can actually be served in.
The cube’s channel tile is plane_size · lines · chans.
Fields§
§rows: usize§cols: usize§chans: usize§lines: usizeImplementations§
Source§impl DepthwiseTiling
impl DepthwiseTiling
Sourcepub fn for_problem(channels: usize, taps: usize, lanes: usize) -> Self
pub fn for_problem(channels: usize, taps: usize, lanes: usize) -> Self
The tiling to run a problem of this shape under.
Only lines is decided here, and it is close to a single question: is this
convolution short of instructions or short of bandwidth? A wide line is four times fewer
instructions per channel, and also four times the registers per lane and a four-times
wider channel tile. A deep window over a wide block is instruction-bound and takes the
trade; everything else is already reading memory as fast as the device will read it, and
pays the registers for nothing.
Both thresholds are where that turnover was observed rather than where a model of the
hardware puts it, so this is a derivation a device is allowed to disagree with. The
depthwise benchmark catalogue is the instrument that settles it: running its Fixed
entries against Routine is what says whether this rule still picks the right line.
Trait Implementations§
Source§impl Clone for DepthwiseTiling
impl Clone for DepthwiseTiling
impl Copy for DepthwiseTiling
Source§impl Debug for DepthwiseTiling
impl Debug for DepthwiseTiling
Source§impl Default for DepthwiseTiling
impl Default for DepthwiseTiling
Source§fn default() -> Self
fn default() -> Self
Four planes of one row each, four output columns per lane, scalar channels.
Small on both spatial axes on purpose: the window overlaps, so a cube’s halo is what it
re-reads, but a wide tile is also what pushes its far corner past the padded border and
costs every instance in it the guarded walk. Four each is where those two meet on the
shapes an encoder actually runs. The line width is the knob worth deciding per problem,
which for_problem is.
impl Eq for DepthwiseTiling
Source§impl Hash for DepthwiseTiling
impl Hash for DepthwiseTiling
Source§impl PartialEq for DepthwiseTiling
impl PartialEq for DepthwiseTiling
impl StructuralPartialEq for DepthwiseTiling
Auto Trait Implementations§
impl Freeze for DepthwiseTiling
impl RefUnwindSafe for DepthwiseTiling
impl Send for DepthwiseTiling
impl Sync for DepthwiseTiling
impl Unpin for DepthwiseTiling
impl UnsafeUnpin for DepthwiseTiling
impl UnwindSafe for DepthwiseTiling
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneExpand for Twhere
T: Clone,
impl<T> CloneExpand for Twhere
T: Clone,
fn __expand_clone_method(&self, _: &Scope) -> T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> CompilationArg for T
impl<T> CompilationArg for T
Source§fn dynamic_cast<Arg>(&self) -> Argwhere
Arg: CompilationArg,
fn dynamic_cast<Arg>(&self) -> Argwhere
Arg: CompilationArg,
impl<T> CubeComptime for T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<K, Q> Equivalent<Q> for K
impl<K, Q> Equivalent<Q> for K
Source§fn equivalent(&self, key: &Q) -> bool
fn equivalent(&self, key: &Q) -> bool
key and return true if they are equal.impl<T> ErasedDestructor for Twhere
T: 'static,
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