FlashAttention Implementation › CUDA Kernel Basics

Michael BrenndoerferUpdated June 30, 20255 min read
Language AI HandbookAll chapters
Part 17 of 67Efficient Attention
Chapter 125FlashAttention Implementation › CUDA Kernel Basics
Reading section 3 of 10 · CUDA Kernel Basics · 5 minSection 3 of 10 · 5 min

Book contents

Section 3 of 10 · 5 min read

FlashAttention Implementation › CUDA Kernel BasicsOne section · Sections in this chapter3 / 10 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

FlashAttention is implemented as a custom CUDA kernel, meaning it runs directly on GPU hardware with fine-grained control over memory access. Understanding a few CUDA concepts helps appreciate what FlashAttention does under the hood.

CUDA Kernel

A CUDA kernel is a function that runs on the GPU across many parallel threads. Threads are organized into blocks, and blocks are organized into a grid. Each thread can access different levels of memory: registers (private to the thread), shared memory (shared within a block), and global memory (HBM, accessible by all threads).

Thread Organization

CUDA organizes computation into a hierarchy. At the lowest level, individual threads execute the same code on different data. Threads are grouped into blocks, typically containing 256-1024 threads. All threads in a block can communicate through shared memory and synchronize their execution. Blocks are grouped into a grid that covers the entire problem.

For attention, a natural mapping assigns one block to compute attention for one query block against all key-value blocks. Within a block, threads collaborate to load data into shared memory, compute dot products, and accumulate results.

Out[8]:
Visualization
Diagram showing grid of thread blocks, with each block containing threads that access shared memory.
CUDA thread organization for FlashAttention. Each thread block computes attention for a tile of queries against all key-value tiles. Threads within a block collaborate through shared memory.

Memory Access Patterns

The key to GPU performance is coalesced memory access. When threads in a warp (a group of 32 threads that execute in lockstep) access consecutive memory addresses, the hardware combines these into a single efficient transaction. When threads access scattered addresses, each access becomes a separate transaction, significantly slowing execution.

FlashAttention carefully structures its memory access to achieve coalescing. When loading a block of K from HBM, consecutive threads load consecutive elements. When writing results, the same pattern applies. This attention to memory layout is one reason FlashAttention achieves such high hardware utilization.

In[9]:
Code
def demonstrate_memory_access_patterns():
    """
    Illustrate the difference between coalesced and strided memory access.
    """
    patterns = {
        "coalesced": {
            "description": "Thread i accesses address i",
            "transactions": 1,
            "effective_bandwidth": "100%",
        },
        "strided_2": {
            "description": "Thread i accesses address 2*i",
            "transactions": 2,
            "effective_bandwidth": "50%",
        },
        "random": {
            "description": "Thread i accesses random address",
            "transactions": 32,
            "effective_bandwidth": "3%",
        },
    }
    return patterns


patterns = demonstrate_memory_access_patterns()
Out[10]:
Console
Memory Access Patterns (32-thread warp, 4-byte elements):

Pattern            Transactions    Effective BW
-----------------------------------------------
coalesced                     1            100%
strided_2                     2             50%
random                       32              3%

FlashAttention uses coalesced access patterns throughout.
Out[11]:
Visualization
Two-panel visualization showing coalesced threads accessing consecutive memory versus strided threads causing separate memory transactions.
Memory access patterns significantly affect GPU throughput. Coalesced access (left) achieves nearly full bandwidth because threads access consecutive addresses. Strided or random access (right) causes multiple memory transactions, wasting bandwidth.