GPU Lab / interactive book
GPU mapSource ↗

CHAPTER 1

One operation, many numbers

Start with a short PyTorch program, then follow how the GPU handles its numbers. By the end, you will be able to trace one input to its output and explain why extra threads need a bounds check. Each example below keeps its own controls and results, so you can look back as you go.

Start with a PyTorch operation

PyTorch

import torch
x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0], device="cuda")
y = x * 2
Desktop setup

Definition

Tensor
A collection of numbers arranged in one or more dimensions. Here, our tensor is a one-dimensional list of five numbers.

import torch loads PyTorch. Here x holds five inputs. device="cuda" places them on an NVIDIA GPU, and y = x * 2 multiplies each number by two to produce y.

Input x
[1, 2, 3, 4, 5]
Result y
[2, 4, 6, 8, 10]

Run the examples below in your browser with no installation or GPU required. The browser simulates the calculation; it does not execute PyTorch or GPU code. To run the PyTorch snippet itself, use a Python environment with PyTorch and an NVIDIA GPU.

How does the GPU calculate these results?

Idea 1 of 5

One calculation for five inputs

The PyTorch operation multiplies every input by the same amount. Follow the five numbers through the picture, then try a different multiplier.

PyTorch operation

y = x * 2

Try it

Predict the outputs, then run. Change the multiplier and predict again.

Browser simulation · this example has its own controls

Input1Calculation× 2Output?
Input2Calculation× 2Output?
Input3Calculation× 2Output?
Input4Calculation× 2Output?
Input5Calculation× 2Output?

Predict the outputs, then press Run.

Idea 2 of 5

Which number does each thread use?

The previous picture showed the same calculation applied to five inputs. A GPU can divide that work among many executions of a small program: each reads an input, multiplies it, and writes a result. These executions are called threads, and many can make progress in parallel.

Definitions

Thread
One execution of a GPU program. Many threads can run the same code, each working on different data.
Array
An ordered collection of values.
Index
A number that identifies a position in an array, starting at zero.

In this picture, one thread handles one input. Its index tells it which input to read and where to write the result. This is a simplified mapping; PyTorch chooses the actual implementation.

PyTorch operation

y = x * 2

Try it

Select a thread in the picture. Follow its index from one input to one output.

Browser simulation · this example has its own controls

Predict the outputs, then press Run.

Select a thread to follow its input and output.

Idea 3 of 5

Threads are organised into blocks

How do we ask the GPU to start those threads? We specify groups rather than starting each thread separately. The GPU can distribute these groups, and threads within a group can cooperate when an algorithm needs them to.

Definitions

Launch
Starting a GPU function with a chosen number of blocks and threads per block.
Block
A group of threads in a launch. Threads in the same block can cooperate.

Here each thread multiplies its own input independently, so it needs no cooperation. Threads in a block do not necessarily all execute at once. Later, we will use cooperation to add many inputs into one result.

PyTorch operation

y = x * 2

For our example we choose four threads per block. Two blocks provide eight threads for five inputs. Each thread has a position within its block. Its index across the array is: block number × threads per block + position within the block.

Block 1, position 0 gives 1 × 4 + 0 = 4: the fifth input. The extra three threads still exist, but have no input. A check makes them skip the read, multiplication and write. Their cards are grey and say “No calculation”; select one to inspect its index. The next experiment lets you turn that check off.

Try it

Select thread 4 in the second block to follow the fifth input and see how its index is calculated. The three extra threads skip the arrays; we will explore that check next.

Browser simulation · this example has its own controls

Block 0

Block 1

Predict the outputs, then press Run.

Select a thread to follow its input and output.

Idea 4 of 5

More threads than numbers

Definition

Bounds check
A check that an index refers to an element that exists before accessing it.

Keep the same five inputs and two blocks of four threads. The extra three threads must skip the arrays because their indices have no input or output element.

PyTorch operation

y = x * 2

Here, the bounds check asks whether a thread’s index is smaller than the number of inputs. Indices 0–4 pass; indices 5–7 skip the read, multiplication and write. Turn the check off below to see why it matters.

Try it

Run with the check enabled. Then turn it off and see which threads would access beyond the arrays.

Browser simulation · this example has its own controls

Block 0

Block 1

Predict the outputs, then press Run.

Select a thread to follow its input and output.

Idea 5 of 5

From Python to a GPU kernel

We have followed the work in pictures. Now we can write the small program each thread follows and show the code that starts the groups.

Definition

Kernel
A GPU function executed by the threads in a launch.

Each thread executes the complete function below with its own index. Here is a CUDA kernel and the launch that starts it, putting together the index, calculation and bounds check you have just explored.

PyTorch operation

y = x * 2

PyTorch selects an optimised implementation and handles its launch; y = x * 2 does not choose blocks or threads. CUDA lets us write the GPU function and choose those settings ourselves. The compiler also optimises our code. Our runKernel is a separate teaching function; PyTorch does not call it when evaluating this expression. The example makes the work visible and is not intended to outperform PyTorch.

CUDA C++ · complete GPU function (kernel)

__global__ void runKernel(const float* input, float* output, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n) {
        output[i] = input[i] * 2.0f;
    }
}

CUDA C++ · launch from the CPU

runKernel<<<2, 4>>>(d_input, d_output, 5);
  1. Find the input. blockIdx.x is the block number, blockDim.x is its size, and threadIdx.x is the position within it. Their calculation gives the integer index i. The .x selects the first dimension of our one-dimensional launch.
  2. Check the index. n is the input count. if (i < n) lets only existing elements reach the calculation.
  3. Calculate one result. The assignment reads input[i], multiplies it and writes output[i]. 2.0f is a floating-point number; ; ends the statement.

The launch’s <<<2, 4>>> starts two blocks of four threads. d_input and d_output refer to arrays already allocated in GPU memory; the final 5 supplies n. The download below includes that allocation and the copies.

Read the function declaration

__global__ marks a GPU kernel. void means it writes results through output rather than returning a value. float* passes the location of an array of floating-point values; const means this function does not change the input. int declares an integer.

Try it

Run once more, then compare the Python operation with the complete CUDA example.

Browser simulation · this example has its own controls

Block 0

Block 1

Predict the outputs, then press Run.

Select a thread to follow its input and output.

Run the CUDA example on your computer

The download contains this kernel and a separate CPU-side C++ program that allocates memory, copies inputs, launches the kernel and reads the output. It is not a Python extension.

With an NVIDIA GPU: install a compatible driver, CUDA Toolkit and host C++ compiler, then run:

nvcc -std=c++17 hello.cu -o hello
./hello

Without an NVIDIA GPU: use our GPGPU-Sim Docker container to compile and simulate the download on your desktop.

Desktop setup and output checks

CI compiles generated chapter 1 examples with the CUDA Toolkit and checks their outputs in GPGPU-Sim. Physical NVIDIA GPU execution has not yet been validated.

Later: how the GPU schedules blocks and warps →

Try a new case

Predict a new case

Keep four threads per block. Choose an input count, then predict how many blocks you need and which thread indices should skip the arrays.

Predict first, then check.

Optional practice: repair a kernel →

Run it with PyTorch

Run the opening snippet in your own PyTorch environment with an NVIDIA GPU, then inspect y.cpu(). Chapter 2 explains that copy. The PyTorch companion checks the examples from the opening chapters and offers a CPU-only mode for checking values and layouts.

The companion’s GPU path has not yet been validated on an NVIDIA GPU. The CUDA download above is a separate handwritten implementation.

References

Use these official references to check the concepts and code on this page.

runKernel is our example function name, not a CUDA API or a function generated by PyTorch. Follow the CUDA references for the language features it uses.

Optional later reading

These browser exercises do not run an installed PyTorch or CUDA toolkit. For optional local execution, choose documentation matching your installed tools. Links open online in a new tab; the questions and answer comparisons below work offline.

Use the documentation

Use the references to explain each answer, then apply it to this page’s example. No installation is needed.

About the simulation

This browser model computes the illustrated operations on the CPU, including offline. It does not run PyTorch, compile CUDA or execute GPU code. The picture shows which element each thread handles, not hardware placement, execution timing or a promise that all threads run at once.

Install GPU Lab

Give GPU Lab its own icon and window. All lessons and simulators work offline once the course is saved.

Use your browser’s install option:

If your browser has no install option, try Chrome or Edge.

App status

Version

Checking for updates

Offline access

Not saved for offline use

Save all lessons, browser simulators, diagrams and example files. Desktop execution needs separate PyTorch or CUDA/GPGPU-Sim tools; their installations are not part of this offline download. External links need internet access.