Cover image for ARM Cache Coherency

ARM Cache Coherency

Timeline

Timeline

2025-10-26

init

This article introduces the basic concepts and evolution of cache coherence in the ARM architecture, discusses different solutions for maintaining coherence in software and hardware, and provides an in-depth analysis of the working principles and operation examples of coherence protocols such as MESI, as well as solutions to the cache false sharing problem.

Reference documents:

Why cache coherency?

  • Each level of cache in the system has different data copies, for example, each CPU core hasL1 cache

Each level of cache in the system has different data copies
Each level of cache in the system has different data copies

  • Cache coherency concerns the consistency of the same data across multiple caches and memory, the main method to solve cache coherency isbus snooping protocol, such asMESIprotocol
  • Examples requiring attention to cache coherency:
    • Using DMA in drivers(data cache and memory inconsistency)
    • Self-modifying code(Data in the data cache may be newer than that in the instruction cache)
    • Modified the page table(Data stored in the TLB may be outdated)

ARM’scacheEvolution of coherence

Evolution of ARM cache coherence
Evolution of ARM cache coherence

  • Cortex-A8 is a single-core architecture with no cache coherence issues between cores, but there are coherence issues between DMA and cache

  • The multi-core version of Cortex-A9 (MPCore) has cache coherence issues between cores, and the common approach is to implement aMESIprotocol

  • Cortex-A15 introduced a big.LITTLE architecture (big.LITTLE), for example, one cluster consists entirely of big cores and another entirely of little cores, socache coherence is also needed between clusters, requiringAMBA Coherency Extensionto handle it, and there is an existingIP(inIC designHere, IP core = a pre-designed and verified circuit module that can be directly reused as a “building block”), for example,CCI-400andCCI-500

  • Single-core processor (Cortex-A8)

    • Single-core, no cache coherence issue
    • Cache management instructions only affect a single core
  • Multi-core processor (Cortex-A9 MP and later processors)

    • Hardware supports cache coherence
    • Cache management instructions are broadcast to other CPU cores

Cache coherence in multi-core processors
Cache coherence in multi-core processors

Cortex-A72 processor
Cortex-A72 processor

System-level cache coherence

  • System cache coherence requires a cache-coherent internal bus (cache coherent interconnect)
    • AMBA 4protocols includeACE(AXI Coherency Extensions)
    • AMBA 5protocols includeCHI

System-level cache coherence
System-level cache coherence

Solutions for Cache Coherence

  1. Disable Cache

    • Advantage: Simple
    • Disadvantage: Low performance, increased power consumption
  2. Software Maintains Cache Coherence

    • Advantage: Simple hardware RTL implementation
    • Disadvantage:
      • Increased software complexity. Software needs to manually clean/flush cache or invalidate cache
      • Increased debugging difficulty
      • Reduced performance and increased power consumption
  3. Hardware Maintains Cache Coherence

    MESIMaintained via protocolMulti-core Cache CoherenceACE InterfaceTo achieve system-level cache coherence

    • Advantage: transparent to software
    • Disadvantage: increases the difficulty and complexity of hardware RTL implementation

Cache coherence among multiple cores

  • Reasons for cache coherence issues in multi-core CPUs:The same memory data has multiple different copies in the L1 caches of multiple CPU cores, leading to data inconsistency

  • The key to maintaining cache coherence istracking the state of each cache line, and updating the state of cache lines on different CPU cores based on processor read/write operations and corresponding bus transactions, thereby maintaining cache coherence

Cache coherence protocol

  • Snooping protocol (snooping protocol), where each cache must be snooped or snoop on the bus activities of other caches

  • Directory protocol (directory protocol), which manages cache states globally and uniformly

  • MESIProtocol:

    • In 1983,James GoodmanproposedWrite-Oncethe bus snooping protocol, which later evolved into the most popularMESIprotocol
    • All bus transactions are visible to all other units in the system, because the bus is abroadcast-based communicationmedium, thus can be snooped by each processor’s cache

Bus snooping and broadcast
Bus snooping and broadcast

Snoop control unitunit implementationBus snooping and broadcast

Each CPU’s L1 cache also implements bus snooping functionality

MESI protocol

  • Each cache line has four states
    • Modified (Modified)
    • Exclusive (Exclusive)
    • Shared (Shared)
    • Invalid (Invalid)

Four states of the MESI protocol
Four states of the MESI protocol

  • ModifiedMand Exclusive stateEFor cache lines in Modified and Exclusive states, the data is unique. The difference is that data in Modified state is dirty and inconsistent with memory, while data in Exclusive state is clean and consistent with memory. Dirty cache lines will be written back to memory, after which the state becomes Shared.
  • Shared stateSFor cache lines in Shared state, data is shared with other caches. Only clean data can be shared by multiple caches.
  • IThe Invalid state indicates that this cache line is invalid.

MESI operations

MESI operations
MESI operations

MESI state diagram

MESI state diagram
MESI state diagram

MESI mainly solvesConsistency between local caches in each CPUProblem

Cache coherence issue of local cache lines in each CPU
Cache coherence issue of local cache lines in each CPU

Explanation of MESI M state
Explanation of MESI M state

Explanation of MESI E and S states
Explanation of MESI E and S states

Explanation of MESI I state
Explanation of MESI I state

An example of MESI protocol analysis

  • Assume there are 4 CPUs in the system, each with its own L1 cache, and they all want to access data A at the same address, which is 64 bytes in size.
    • Time T0: None of the 4 CPUs’ L1 caches have cached data A, and the cache line state is I (Invalid).
    • Time T1: CPU0 initiates an operation to access data A first.
    • Time T2: CPU1 also initiates a read data operation.
    • Time T3: CPU2’s program wants to modify the data in data A.
  • Please analyze the changes in MESI states during the above process.

Time T0None of the 4 CPUs’ L1 caches have cached data A, and the cache line state is I.

Time T0
Time T0

Time T1CPU0 initiates the operation to access data A first

Time T1
Time T1

Time T2CPU1 also initiates a read data operation

Time T2
Time T2

Time T3CPU2’s program wants to modify the data in data A

Time T3
Time T3

Cache False Sharing

  • When multiple processors simultaneously access different data within the same cache line, it causes performance issues
  • For example: Suppose thread 0 on CPU0 wants to access and update the x member of the struct data structure, and similarly thread 1 on CPU1 wants to access and update the y member of the struct data structure, where both x and y members are cached in the same cache line.

An example of False Sharing
An example of False Sharing

Analysis:

Time T0
Time T0

Time T1
Time T1

Time T2
Time T2

Time T4
Time T4

Time T5
Time T5

Afterwards, it will repeatedly cycle between T4 and T5, contending for the cache line, continuously invalidating each other’s cache lines, triggering cache write-backs to memory.

Solution

  • The solution to cache false sharing isto ensure that data operated on by multiple threads resides in different cache lines. Typically, this can be achieved usingcache line padding technologyorcache line alignment technology, which means aligning data structures to cache line boundaries and filling them to the size of a cache line as much as possible.
  • The following code defines a counter_The data structure s has its starting address aligned to the cache line size, and its members are padded with pad[4]. Thus, counter_The size of s is exactly one cache line, 64 bytes, and its starting address is also cache line aligned

pad
pad

Make counter_s occupy a cache line exclusively as much as possible, without sharing a cache line with other data structures

MOESI protocol

The ARMv8 processors use the MOESI protocol

  • Modified

    • The most up-to-date version of the cache line is within this cache.

    • No other copies of the memory location exist within other caches.

    • The contents of the cache line are no longer coherent with main memory.

  • Owned

    • This describes a line that is dirty and in possibly more than one cache.

    • A cache line in the owned state holds the most recent, correct copy of the data.

    • Only one core can hold the data in the owned state. The other cores can hold the data in the shared state.

  • Exclusive

    • The cache line is present in this cache and coherent with main memory.
    • No other copies of the memory location exist within other caches.
  • Shared

    • The cache line is present in this cache and is not necessarily coherent with memory, given that the definition of Owned allows for a dirty line to be duplicated into shared lines.

    • It will, however, have the most recent version of the data.

    • Copies of it can also exist in other caches in the coherency scheme.

  • Invalid

    • The cache line is invalid.

The following rules apply for the standard implementation of the protocol:

  • A write can only be performed if the cache line is in a Modified or Exclusive state. If it is
    in a Shared state, all other cached copies must be invalidated first. A write moves the line
    into a Modified state.
  • A cache can discard a shared line at any time, changing it to an Invalid state.
  • A Modified line is written back first.
  • If a cache holds a line in a Modified state, reads from other caches in the system receive
    the updated data from the cache. Conventionally, this is achieved by first writing the data
    to main memory and then changing the cache line to a Shared state, before performing a
    read.
  • A cache that has a line in an Exclusive state must move the line to a Shared state when
    another cache reads that line.
  • A Shared state might not be precise. If one cache discards a Shared line, another cache
    might not be aware that it can now move the line to an Exclusive state.

Snoop Control Unit(SCU)

The processor cluster contains a Snoop Control Unit (SCU) that contains duplicate copies of the tags stored in the individual L1 Data Caches. The cache coherency logic therefore:

  • Maintains coherency between L1 data caches.
  • Arbitrates accesses to L2 interfaces, for both instructions and data.
  • Has duplicated Tag RAMs to keep track of what data is allocated in each core’s data.

SCU
SCU

Each core in the diagram has its own data and instruction caches. The cache coherence logic includes local copies of tags from the D cache. However,the instruction cache does not participate in coherence. There is 2-way communication between the data cache and the coherence logic. ARM multi-core processors also implement optimizations to copy clean data and move dirty data directly between participating L1 caches without accessing and waiting for external memory. This activity is handled by the SCU in multi-core systems.

The Snoop Control Unit (SCU) maintains coherence among each core’s L1 data caches and is responsible for managing the following interconnect operations:

  • Arbitration.
  • Communication.
  • Cache-2-cache and system memory transfers.

The processor also provides these capabilities to other system accelerators and non-cached DMA-driven peripherals to improve performance and reduce system-wide power consumption.

This system coherence also reduces the software complexity involved in maintaining software coherence within each operating system driver. Each core can be individually configured to participate or not in the data cache coherence management scheme. The SCU device inside the processor automatically maintains L1 data cache coherence among cores within the cluster.

Since executable code changes much less frequently,this feature does not extend to the L1 instruction cache. Coherence management is implemented using a MOESI-based protocol, optimized to reduce the number of external memory accesses. For coherence management to be effective for memory accesses, all of the following conditions must be true:

  • The SCU is enabled via control registers located in a private memory region. The SCU has configurable access control, restricting which processors can
    configure it.
  • MMU enabled.
  • The accessed page is marked as Normal Shareable, with a cache policy of write-back, write-allocate. However, device and strongly-ordered memory are non-cacheable; from the kernel’s perspective, write-through cache behaves like uncached memory.

The SCU can only maintain coherence within a single cluster. If there are additional processors or other bus masters in the system, explicit software synchronization is required when they share memory with the MP block.

Cache coherence between systems

Inter-system cache coherence
Inter-system cache coherence

CoreLink CCI-400
CoreLink CCI-400

ARM’s CCI for the server market is CoreLink CCN

CoreLink Cache Coherent Network Family
CoreLink Cache Coherent Network Family

CCN-512
CCN-512

Example of reading data

Time T0
Time T0

Time T1
Time T1

Time T2
Time T2

Time T3
Time T3

Another scenario at time T3
Another scenario at time T3

Example of writing data

Time T0
Time T0

Time T1
Time T1

Time T2
Time T2

Time T3
Time T3

Time T4
Time T4

Cache Coherence Cases

Case 1: Avoiding Cache False Sharing

  • Some commonly used data structures are defined with conventionsData structures are aligned to L1 cache. For example, use the following macro to align the starting address of a data structure to L1 cache
1
#define cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
  • Frequently accessed members of a data structure can occupy a single cache line, or related members arestaggered within cache linesto improve access efficiency. For example, the struct zone data structure usesZONE_PADDINGa technique (padding bytesapproach) to place frequently accessed members in different cache lines

    Frequently accessed members of a data structure can occupy a separate cache line.
    Frequently accessed members of a data structure can occupy a separate cache line.

Case 2: DMA cache coherence

DMA (Direct Memory Access) allows reading and writing data directly from memory without CPU intervention during transmission.

  • Reasons for DMA causing cache coherence issues:
    • DMA directly operates the system bus to read and write memory, while the CPU is unaware.
    • If**the memory address modified by DMA is cached in the CPU’s cache,**then the CPU does not know that the memory data has been modified, and it still accesses the old data in the cache, leading to cache coherence issues.

DMA cache coherence issue
DMA cache coherence issue

Solutions for DMA cache coherence

  • Hardware solution requiresACE bus support(consult SoC vendor)

  • Use non-cacheable memory for DMA transfers

    • Disadvantage: When DMA is not in use, CPU access to this buffer leads to performance degradation.
  • Software intervenes in cache coherence, maintaining cache coherence based on the direction of DMA data transfer.

    • Case 1: Memory -> Device FIFO (device such as a network card,DMA reads memory data into the device FIFO.)

      • Before DMA transfer, the CPU’s cache may have cached memory data. A cache clean/flush operation is needed to write the cache contents to memory, because the CPU cache may contain the latest data.

      The CPU's cache has the latest data, but DMA reads old data from memory.
      The CPU's cache has the latest data, but DMA reads old data from memory.

    • Case 2: Device FIFO -> Memory (device writes data to memory)

      • Before DMA transfer, the cache needs to be invalidated. Because the latest data is in the device FIFO, the CPU’s cached data is outdated, and new data will be written soon, so an invalidate operation is performed.

      The CPU's cache may still contain useless data.
      The CPU's cache may still contain useless data.

Case 3: Self-modifying code

  • Instruction cache and data cache are separate. The instruction cache is generally read-only.

  • Coherence issue between instruction cache and data cache. Instructions are usually not modifiable, but in some special cases, instructions may be modified.

  • Self-modifying code modifies its own instructions during execution (to prevent software cracking, or when GDB debugging dynamically modifies the program). The process is as follows:

    • The modified instructions need to be loaded into the data cache.
    • The program (CPU) modifies the new instructions, and the data caches the latest instructions.

Issues:

  • The instruction cache still caches old instructions, and the new instructions are still in the data cache

Self modifying code
Self modifying code

Solution approach

  • Use the cache clean operation to write the cache line data back to memory
  • Use the DSB instruction to ensure other observers see that the clean operation has completed
  • Invalidate the instruction cache
  • Use the DSB instruction to ensure other observers see that the invalidation operation has completed
  • The ISB instruction causes the program to re-fetch instructions

ARMv8.6 manual, section B2.4.4
ARMv8.6 manual, section B2.4.4

Cache experiment 2: false sharing

Experiment 2
Experiment 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>

struct data_with_false_sharing {

unsigned long x;
unsigned long y;

} __attribute__((__align__(64)));

struct padding {

char x[0]
} __attribute__((__align__(64)));

struct data_without_false_sharing {

unsigned long x;
struct padding _pad;
unsigned long y;
} __attribute__((__align__(64)));

#define MAX_LOOP 10000000000
void *access_data(void *param) {
unsigned long *data = (unsigned long *)param;
unsigned long i;
for (i = 0; i < MAX_LOOP; i++) {
*data = i;
}
}

int main(void) {
struct data_with_false_sharing data_wfs = {1, 2};
struct data_without_false_sharing data_wofs = {.x = 1, .y = 2};
pthread_t thread_1;
pthread_t thread_2;
unsigned long total_time;

struct timespec time_start, time_end;
clock_gettime(CLOCK_REALTIME, &time_start);
pthread_create(&thread_1, NULL, &access_data, (void *)&data_wfs.x);
pthread_create(&thread_2, NULL, &access_data, (void *)&data_wfs.y);
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
clock_gettime(CLOCK_REALTIME, &time_end);
total_time = (time_end.tv_sec - time_start.tv_sec) * 1000 +
(time_end.tv_nsec - time_start.tv_nsec) / 1000000;
printf("cache with false sharing: %lu ms \n", total_time);

clock_gettime(CLOCK_REALTIME, &time_start);
pthread_create(&thread_1, NULL, &access_data, (void *)&data_wofs.x);
pthread_create(&thread_2, NULL, &access_data, (void *)&data_wofs.y);
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
clock_gettime(CLOCK_REALTIME, &time_end);
total_time = (time_end.tv_sec - time_start.tv_sec) * 1000 +
(time_end.tv_nsec - time_start.tv_nsec) / 1000000;
printf("cache without false sharing: %lu ms \n", total_time);
}

Experiment 2 results (qemu)
Experiment 2 results (qemu)

Cache experiment 3: flush cache experiment

Experiment 3
Experiment 3

Result:

Experiment 3 results
Experiment 3 results

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.global get_cache_line_size
get_cache_line_size:
mrs x0, ctr_el0
ubfm x0, x0, #16, #19
mov x1, #4
lsl x0, x1, x0
ret

/*
flush_cache_range(start, end)
*/
.global flush_cache_range
flush_cache_range:
stp x29, x30, [sp, -16]!
// start
mov x8, x0
// end
mov x9, x1

bl get_cache_line_size
// x3 = cache_line_size -1
sub x3, x0, #1
// bit clear, x4 = x8 & (~x3)
// Align the start address down to the cache line boundary
bic x4, x8, x3
// Iteratively clean cache lines
1:
dc civac, x4
add x4, x4, x0
cmp x4, x9
b.lo 1b

dsb ish

ldp x29, x30, [sp], 16

ret

  • ARM Architecture Reference Manual Armv8, for Armv8-A architecture profile

    • B2.4 Caches and memory hierarchy

    • D4.4 Cache Support

    • D5.11 Caches in a VMSAv8-64 implementation

  • ARM Cortex-A Series Programmer’s Guide for ARMv8-A

    • Chapter 11 Cache
  • ARM Cortex-A72 MPCore Processor Technical Reference Manual

    • 6: Level 1 Memory System
    • 7:Level 2 Memory System