perf: align ALIGNMENT to cache line size (16 → 64 bytes) to fix false sharing#16
Closed
viknash wants to merge 1 commit into
Closed
perf: align ALIGNMENT to cache line size (16 → 64 bytes) to fix false sharing#16viknash wants to merge 1 commit into
viknash wants to merge 1 commit into
Conversation
ALIGNMENT was set to 16 bytes, which is only 1/4 of a typical CPU cache line (64 bytes). Every type annotated with `class_alignment` / `alignas(ALIGNMENT)` and every struct packed with `#pragma pack(ALIGNMENT)` could therefore have multiple independently-written fields share the same 64-byte cache line. The most acute example is `queue_rank[num_priority][max_num_threads]` in `threadpool.h`: each worker thread writes its own rank slot on every task dispatch and steal. With ALIGNMENT=16, four thread slots shared one cache line, causing that line to ping-pong between CPU cores — a classic false- sharing bottleneck that degrades O(N²) under thread count. `cache.h` already documents the correct value: `get_cache_line_size()` returns 64. This commit makes ALIGNMENT consistent with that contract. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Updates the project-wide alignment constant in include/alignment.h to target cache-line alignment, aiming to reduce false sharing in concurrent hot paths by increasing ALIGNMENT from 16 to 64 bytes.
Changes:
- Set
ALIGNMENTto 64 and added an explanatory comment referencing cache-line sizing. - Propagates the new
ALIGNMENTvalue toalignas(ALIGNMENT)usage viaclass_alignment. - Indirectly changes
#pragma pack(ALIGNMENT)to#pragma pack(64).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+13
to
16
| #define ALIGNMENT 64 | ||
|
|
||
| #pragma pack(ALIGNMENT) | ||
| #define class_alignment alignas(ALIGNMENT) No newline at end of file |
Comment on lines
+11
to
+13
| // Match the CPU cache line size (see cache.h) to prevent false sharing between | ||
| // concurrently-written fields that happen to land on the same cache line. | ||
| #define ALIGNMENT 64 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ALIGNMENT in �lignment.h was set to 16 bytes — only ¼ of a typical CPU cache line (64 bytes). Every type annotated with \class_alignment\ / \�lignas(ALIGNMENT)\ and every struct packed via #pragma pack(ALIGNMENT)\ could have multiple independently-written fields share a single 64-byte cache line.
The most acute hotspot is \queue_rank[num_priority][max_num_threads]\ in \ hreadpool.h:
\\cpp
optimization std::atomic queue_rank[task_type::num_priority][max_num_threads];
\\
ank_type = int64_t\ (8 bytes). With \ALIGNMENT=16, four thread slots shared one cache line. Every worker thread writes its own rank slot on every task dispatch and steal — so those four cores constantly bounce the same cache line across the L3, causing O(N²) coherency traffic under thread count. This is textbook false sharing.
Root cause
\cache.h\ already documents the correct value:
\\cpp
uint32_t get_cache_line_size() { return 64; }
\
\ALIGNMENT\ was just never updated to match.
Fix
One-line change in \�lignment.h:
\\diff
-#define ALIGNMENT 16
+// Match the CPU cache line size (see cache.h) to prevent false sharing between
+// concurrently-written fields that happen to land on the same cache line.
+#define ALIGNMENT 64
\\
This propagates through every \class_alignment\ and #pragma pack\ use site in the codebase, ensuring hot shared-state structs never straddle a cache line boundary.
Impact
Other identified improvements (follow-up PRs)
This is the highest-impact, lowest-effort item from a broader audit. Other improvements to address: