Programming
Cache-Friendly Code
Computer Science
Code Optimization
Software Development

What is a cache-friendly code?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

When we talk about "cache-friendly" code, we refer to code that is written in a way that optimizes the usage of the CPU cache, which is a smaller, faster memory component located closer to the CPU than RAM. By understanding how cache works and by structuring software to utilize this component efficiently, performance can be significantly improved, especially in data-intensive applications. To fully appreciate what makes code cache-friendly, it’s important to understand some underlying principles of how computer memory is structured and accessed.

Understanding CPU Caches

A CPU cache is a hardware resource designed to speed up the process of data retrieval. It stores copies of the frequently accessed data from main memory, reducing the need for the CPU to fetch this data from the slower RAM. CPU caches are smaller but much faster than RAM, and they operate on principles that can be leveraged to write more efficient code.

Levels of CPU Cache:

  • L1 Cache: This is the smallest and fastest layer, typically ranging from 8 KB to 64 KB, and is primarily used for immediate data retrieval.
  • L2 Cache: Slightly larger and slower than L1, L2 cache typically ranges from 256 KB to 2 MB.
  • L3 Cache: This cache is slower and larger than L2, often shared between cores in multi-core processors.

Principles of Cache-Friendly Code

Spatial Locality:

This principle states that data locations close to those recently accessed are likely to be accessed soon. By keeping data elements that are used together close to each other in memory, you can increase the likelihood that they will be loaded into the cache together.

Temporal Locality:

This principle involves data being accessed repeatedly within a short time period. Reusing data that's already in the cache can drastically speed up performance.

Techniques to Write Cache-Friendly Code

  1. Loop Interchange: Modifying nested loops so that the data accessed is contiguous in memory. For instance, accessing a multi-dimensional array row-wise instead of column-wise can significantly enhance cache usage because of the way data is typically stored in memory.
  2. Blocking: Also known as loop tiling, this technique involves breaking down a loop into smaller blocks that can fit into the cache, thereby minimizing cache misses.
  3. Data Structure Choice: Using linear data structures like arrays can enhance spatial locality. In contrast, pointer-based structures like linked lists can lead to frequent cache misses.
  4. Reduce Recursive Function Calls: Recursive calls can be heavy on the stack and might scatter data accesses in a way that's not friendly to the cache mechanism.

Examples and Implications

Consider accessing a 2D array in C/C++:

c
1#define SIZE 1024
2int a[SIZE][SIZE];
3for (int i = 0; i < SIZE; i++) {
4    for (int j = 0; j < SIZE; j++) {
5        a[j][i] = 2 * a[j][i];  // Non cache-friendly due to column-wise access
6    }
7}

Changing the loops to access the elements row-wise will make it more cache-friendly:

c
1for (int i = 0; i < SIZE; i++) {
2    for (int j = 0; j < SIZE; j++) {
3        a[i][j] = 2 * a[i][j];  // More cache-friendly
4    }
5}

Summary Table

TechniqueDescriptionBenefit
Loop InterchangeAccessing data in the memory lag orderEnhances spatial locality
BlockingProcessing small blocks that fit into the cacheReduces cache misses
Data Structure ChoiceChoosing linear over non-linear structuresImproves spatial locality
Avoiding RecursionMinimizing deep recursive function callsHelps maintain data locality and reduces overhead associated with function calls

In conclusion, writing cache-friendly code involves understanding and leveraging the CPU's caching mechanisms to enhance application performance. By considering data locality and structuring code and data efficiently, developers can significantly speed up execution times, especially in scenarios where large data processing is required.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.