Skip to content

Tiled Matmul - #140

Closed
mstn wants to merge 25 commits into
masterfrom
marco/gpu
Closed

Tiled Matmul#140
mstn wants to merge 25 commits into
masterfrom
marco/gpu

Conversation

@mstn

@mstn mstn commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Preliminary Tiled Matmul implementation.

Implementation

Stateful primitives taking runtime "wire" gpu.state

  • gpu.shared.alloc: allocates a persistent block-local shared-memory slot and returns its identity, updated proof state, and slot value.
  • gpu.shared.row-major.cooperative-load: cooperatively loads a logical 2D view into a row-major shared slot, with each block thread loading one element.
  • gpu.sync: synchronizes all threads in the block.
  • gpu.shared.materialize: exposes a synchronized, ready shared slot as a borrowed buffer.

gpu.state is an erased, linear description of the block’s execution history.

Each stateful primitive consumes the current state and produces a new state whose event records what happened:

alloc  → allocated(slot)
load   → loaded(slot)
sync   → synchronized(previous-event)

Operations requiring a particular slot condition also consume a proof tied to that exact state:

  • Cooperative load requires allocated-at(slot, state).
  • Materialization requires ready-at(slot, state).

Because the state is linear, operations cannot independently reuse an obsolete execution history. Because proofs mention both the slot identity and state event, a proof for one slot or an earlier state cannot justify access to another slot or later occurrence.

This is intended to prevent:

  • loading into an unallocated slot;
  • reading shared storage before cooperative loading and synchronization complete;

Both states and proofs are compile-time objects and are erased before GPU code generation. Currently, admit-allocated-at, admit-ready-at, and keyed-state operations are temporary axioms. Therefore, the types express the intended safety conditions, but full safety is not yet guaranteed: it will require deriving these proofs from allocation, loading, and synchronization events rather than admitting them.

Next

  • existing materialize launches a kernel, imo it is wrong, only gpu.materialize should launch kernels. Hence, we need to change the implementation of materalize and rewrite tests using gpu.materialize
  • sync should be changed to accept a closure corresponding to a phase. The reason is that we don't want phase "state" to escape the sync.
  • proofs are "admitted" as true but not actually proved. We want to actually prove them. There are other proofs we want to investigate: barrier safety, race free etc... ideally a kernel should return a proof of "correctness"

@mstn mstn self-assigned this Jul 29, 2026
@mstn
mstn requested a review from statusfailed July 30, 2026 16:44
@mstn
mstn marked this pull request as ready for review July 31, 2026 06:28

@statusfailed statusfailed left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions added on the PR. Main confusion is around "slots" - these look sort of like memory pages, but I can't figure out why, or how the f32 / max 1024 slots limits were picked.

Another concern is perfect tiling only- with materialize in naive matmul one can launch more threads than actually write back to the output buffer (threads with indices out of range simply drop the final write value).
Is there a way to extend this to non-perfectly-tiling matmuls?


The runtime allocates its storage with `cudaMallocManaged` or
`hipMallocManaged`. The resulting pointer is accessible by both host code and
GPU kernels.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has changed as of #141 , we now have device-only buffers.

```

Storage placement and lifetime can instead be determined by the operation that
creates or consumes the buffer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean that 'lifetime can be determined by the operation that consumes the buffer'?

# output-coordinate,
# inner-tile-index)
# return accumulator
(def gpu.f32.tiled-matmul.kernel : {[

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this assume perfect tiling? What would need to change to support non-perfect tiles?

("reduce", "reducec"),
("materialize", "materializec"),
(
"gpu.shared.row-major.cooperative-load",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a materialize; is this what you are referring to as a 'sequentialmaterialize' in PR #142 ?

void *data;
uint64_t len;
}} catena_gpu_buf_t;
#define CATENA_GPU_MAX_SHARED_F32_SLOT_ELEMENTS 1024ULL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

I can't really figure out what the 'slot' abstraction is, why it's limited to 1024, f32 only, etc.

@mstn

mstn commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

closing for #152

@mstn mstn closed this Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants