advanced24 min studyLesson 471 in Engineering

Tensor strides: prove which element an address represents

Derive storage addresses for views, transposes, padding, and broadcasts before choosing a contiguous or strided kernel path.

On this page

What you’ll understand

  • Calculate an element address from shape, strides, element size, and storage offset.
  • Distinguish a metadata-only transpose from a contiguous copy.
  • Identify when broadcast or overlapping views require additional write restrictions.

A tensor's shape tells you how many logical elements it has, not how those elements occupy storage. Strides connect logical indices to addresses. A kernel that assumes contiguous rows can silently read the wrong values from a perfectly valid transposed or padded view. Establish the storage mapping first, then choose an implementation whose access and aliasing assumptions match it.

An address calculation needs all the metadata

Let strides count storage elements rather than bytes, and let the storage offset locate the logical origin within a backing allocation. Multiply the resulting element offset by bytes per element before adding it to the storage base. Each logical index must be within its dimension, and the complete typed access must stay within valid storage. Checked arithmetic, alignment, initialization, lifetime, and permitted aliasing remain separate obligations. Merely multiplying dimensions gives a logical count; it does not establish the highest accessed address of a padded view.

A transpose can exchange dimensions and strides without moving any element. The new logical element at column-row coordinates then refers to the same original storage as the corresponding row-column element. A slice can change the origin and introduce gaps. Some APIs support only particular stride classes; do not assume that a generic signed-stride formula means every framework accepts negative strides. PyTorch's documented view operations share underlying data, while reshape and contiguous conversion have operation-specific conditions determining whether storage must be copied.

addr⁡(i0,…,id−1)=b+e(o+∑j=0d−1ijsj)\operatorname{addr}(i_0,\ldots,i_{d-1})=b+e\left(o+\sum_{j=0}^{d-1}i_js_j\right)
b is the backing allocation's byte address, e is positive bytes per element, o is the storage offset in elements, and s_j are element strides. This lesson's examples use nonnegative strides and checked representable arithmetic. The formula does not itself prove bounds, alignment, initialization, or lifetime.↔ Scroll wide equations horizontally.

Contiguous is a layout property with a convention

For the usual dense row-major convention with every dimension larger than one, the last stride is one and each earlier stride is the product of later dimension sizes. Singleton dimensions can allow additional equivalent stride values because their index never advances. Frameworks also recognize alternative memory formats, such as channel-oriented layouts. State which definition a kernel dispatch checks. A shape alone cannot prove row-major contiguity, and an array occupying one backing allocation can still contain gaps between logical rows.

Broadcast views can use a zero stride so many logical coordinates read the same stored value. That is useful for a read-only bias but dangerous for an output kernel that assumes each coordinate owns an independent destination. Overlapping views create related aliasing obligations even when strides are nonzero. A correct general-stride reader is not automatically a correct general-stride writer. Either reject unsupported overlap, use a semantics-preserving implementation, or establish an independent-output contract before parallel writes begin.

sd−1=1,sj=∏k=j+1d−1nks_{d-1}=1,\qquad s_j=\prod_{k=j+1}^{d-1}n_k
This is the standard dense row-major stride pattern in elements for positive dimension lengths n_k, with singleton-dimension equivalences excluded for simplicity. It describes one layout convention, not every framework memory format or an arbitrary noncontiguous view.↔ Scroll wide equations horizontally.

A copy is a costed alternative to a strided kernel

A contiguous conversion can simplify downstream indexing and improve some access patterns, but it introduces a copy and additional live storage. Include that conversion in an end-to-end benchmark unless the production pipeline genuinely reuses the converted tensor enough to amortize it. Check whether the consuming operation already handles the given strides efficiently. For GPU code, logical stride affects which addresses adjacent lanes request, while coalescing and caches depend on the actual architecture and access grouping. Avoid declaring every larger stride slow without tracing addresses.

The cache lab illustrates only a deterministic address cycle. Reset, set C=4 and s=1, predict zero hits among its sixteen initial requests, then Play or Step. Separately Reset, set C=4 and s=4, predict twelve hits, then Play or Step. The larger toy stride visits only four residues modulo sixteen, so this comparison is not a rule that larger tensor strides improve GPU access. It contains no tensor metadata or memory transactions. Use it to separate a measured working set from a layout label, and do the actual tensor-address proof on paper.

Index a padded view and its transpose

A two-by-three tensor has element strides (5,1), storage offset 2, four-byte elements, and backing byte address 1,000. The backing allocation has ten elements.

  1. Logical element (1,2) has storage offset 2+1×5+2×1=9 elements. Its byte address is 1,000+4×9=1,036, and its four bytes fit the ten-element allocation.

  2. Transposing creates shape (3,2) and strides (1,5). Logical element (2,1) has the same storage offset 2+2×1+1×5=9, so it refers to the same stored value without a required copy.

  3. The six logical elements have 24 bytes of element payload, but their padded storage span is larger. A new contiguous copy can use strides (3,1) and its own storage; the original view is not dense row-major.

The result

Shape, strides, offset, and element width together establish the address. Logical payload alone does not describe the backing span or copy cost.

Explore the model

Interactive lab

Interactive lab · cache

A stride label does not determine the working set

Reset, set C=4 and s=1, predict zero initial hits in 16 requests, then Play or Step. Separately Reset, set C=4 and s=4, predict 12 hits, then Play or Step. This modulo-16 LRU stream has no tensor shape, coalescing, or GPU transaction model.

A stride label does not determine the working setA fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Current readings: Hits / requests: 0 / 16; Hit rate: 0%; Address-stream period: 16 addresses. All parameters are adjustable with the labeled controls below.Fully associative LRU cache after 16 deterministic requests: 0 hits and 16 misses.Most recent 16 requestsaddress = i × 3 mod 160M3M6M9M12M15M2M5M8M11M14M1M4M7M10M13MCurrent cache order · oldest → newest471013Latest address 13 · miss: inserted as newestToy address stream · period 16 · starts empty
Cached addressMiss / evictionMost recent request
Hits / requests
0 / 16
Hit rate
0%
Address-stream period
16 addresses
t = 0 s

A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forTrace the real address pattern before translating a stride into a performance claim.

Check your understanding

Why is a zero-stride broadcast view unsafe for an arbitrary parallel output kernel?

Try it yourself

A three-by-four view has strides (6,1), storage offset 1, four-byte elements, and backing address 2,048. Find element (2,3)'s address and the minimum element count of a backing allocation starting at that base.

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

The last used storage index is not the logical element count.

Compare with the solution

The storage index is 1+2×6+3=16, giving address 2,048+4×16=2,112. A valid allocation needs at least seventeen elements so index sixteen and its full four-byte value fit. The logical twelve-element payload is only 48 bytes; padding and the leading offset explain the larger required allocation.

Take it with you

  • Shape does not establish a tensor's address mapping.
  • Views can share storage without preserving dense row-major layout.
  • Copy cost and overlapping-write semantics belong in dispatch and validation.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.