Systems Unpacked · · 4 min read

How Apple M1 works and what unified memory changes

Apple's M1, announced in November 2020, was the first Apple-designed system on a chip for the Mac. Rather than a CPU on one chip and a graphics card with its own memory elsewhere, M1 put the CPU, GPU, Neural Engine, memory controllers and other components on one chip, with the main memory placed in the same package. Apple announcement (opens in a new tab)

The phrase most people remember is "unified memory". It is a real architectural change. It is also easy to over-read. This article explains what it changes, and what it does not.

What was on the chip

The original M1 had an eight-core CPU: four performance cores and four efficiency cores. The performance cores are larger and aim to finish demanding single-threaded work quickly. The efficiency cores use much less power for background and lighter tasks. The operating system's scheduler decides which threads run where.

The GPU had up to eight cores (some configurations shipped with seven). There was also a 16-core Neural Engine for certain machine-learning operations, plus media encoders, a secure enclave and the controllers that connect everything to memory.

None of these counts is a speed number. A "GPU core" here and a "CPU core" are different structures, and neither count is comparable across vendors. What matters for this article is where they all get their data.

Two ways to give a GPU data

On a typical PC with a discrete graphics card, the CPU uses system memory and the GPU uses its own dedicated memory on the card. To process an image on the GPU, the program copies the bytes across a bus into GPU memory, runs the work, and copies the result back if the CPU needs it.

On M1, the CPU and GPU address the same physical pool of memory. A buffer the CPU fills can be read by the GPU without being duplicated into a separate memory. In Metal, Apple's GPU API, a buffer created with the shared storage mode is accessible to both processors; a private buffer is for GPU-only use. Metal storage modes (opens in a new tab)

That removes a whole class of explicit copies. It does not remove the work of moving bytes.

Discrete GPU

CPU
GPU
System memory
GPU memory

explicit copy across a bus ⇄

Apple M1 (unified)

CPU 4P+4E
GPU ≤8
Neural Engine
One shared memory pool · shared bandwidth and capacity

CPU waits for completion before modifying storage the GPU still uses

Simplified comparison. Unified memory can remove a duplicate copy between two memories; bytes still travel to compute units and access still needs synchronisation.

What unified memory does not change

Data still travels. The GPU's cores do not compute on DRAM directly. Bytes still move from memory, through caches, into the cores, and results move back. Shared physical memory can remove a duplicate copy between two memories; it does not make memory access free or instantaneous, and programs may still copy data deliberately—into GPU-private storage, for instance.

Bandwidth is shared. CPU, GPU and other units draw on the same memory system. A GPU workload that streams large textures and a CPU workload scanning large arrays compete for the same resource.

Capacity is shared. The pool is not unlimited. Memory used by the GPU is memory the rest of the system cannot use.

Synchronisation is still your job. If the CPU writes a shared buffer while the GPU is reading it, the result is a race, exactly as with threads on a CPU. In Metal, the CPU encodes commands and submits a command buffer; it must not modify storage that overlaps what the GPU is still using until it learns that work is complete—for example through the command buffer's completion notification or an appropriate shared event. A host-side semaphore is a common way to limit how many buffers are in flight before reusing one. Resources the GPU is not using need no such wait. Synchronizing CPU and GPU work (opens in a new tab)

A thought experiment: one frame of video

Imagine a program applies a filter to each video frame.

On a discrete-GPU system, each frame might be copied to GPU memory, filtered, and copied back. If the filter is quick, the copies may cost more than the computation.

On M1, the frame can live in a shared buffer. The CPU writes it, submits a command buffer, and the GPU reads the same bytes. But the CPU cannot start writing the next frame into that same buffer until the GPU finishes with it. A common pattern is to rotate through two or three buffers, so the CPU fills one while the GPU processes another—and to wait when all are in use.

The copy disappeared. The ordering problem did not. Neither did the cost of the GPU reading every pixel from memory.

Why it matters beyond Apple

Unified memory is a useful case study because it isolates one variable. It shows that "copying between memories" and "moving data to compute units" are different costs, and that removing the first does not remove the second. The same distinction appears in how a GPU works and in why fast code still waits.

For the underlying ideas—addresses, buffers, ownership and locality—see the memory and data movement section.