{"slug": "why-false-sharing-alignment-should-be-128-bytes-on-x64", "title": "Why false sharing alignment should be 128 bytes on x64", "summary": "False sharing alignment on x64 should be 128 bytes instead of the traditional 64 bytes because Intel's Sandy Bridge architecture and later CPUs may load cache lines in pairs via a spatial prefetcher, causing performance degradation when atomics are placed 64 bytes apart. Libraries like crossbeam-utils and Facebook's folly already use 128-byte alignment to avoid this issue, and benchmarks confirm the improvement.", "body_md": "# What is false sharing[#](#what-is-false-sharing)\n\nWhat is [false sharing](https://en.wikipedia.org/wiki/False_sharing)? When CPUs\nand their cores read and update atomic variables, special hardware protocols\nmake it correct and efficient, while keeping each core’s caches consistent. The\ncoordination doesn’t happen per-address: these protocols work on\ncache-line-sized chunks.\n\nWhat happens when two atomic variables happen to reside on the same cache line? For example:\n\n- an array of atomics where each atomic is used by a separate thread (e.g. per-thread counters);\n- a queue with two atomic pointers where a writer updates the tail and a reader updates the head. Of course, you declare both pointers in the same struct and they have adjacent addresses!\n\nEach update operation makes the cache line dirty and requires coordination between CPUs. The CPUs are essentially playing ping pong with the chunk of memory.\n\n# What to do[#](#what-to-do)\n\nThe solution is simple: separate the atomics by making them reside in different cache lines. It is done with some language-dependent alignment directive, though it is not the alignment but the spacing that matters.\n\n| Rust | `#[repr(align(N))]` on the type declaration (or use a type wrapper) |\n| C11 | `_Alignas(N)` on type or variable declaration |\n| C++11 | `alignas(N)` on type, field or variable declaration |\n| GCC/Clang | `__attribute__((aligned(N)))` |\n\nBoth *Rust Atomics and Locks* by Mara Bos and *Performance Analysis and Tuning on\nModern CPUs* by Denis Bakhvalov recommend using cache line size, which is\n64 bytes for `x86_64`\n\n.\nHowever, libraries ([ crossbeam-utils](https://github.com/crossbeam-rs/crossbeam/blob/822eb3abf00094fab5d817538aab42477c62c42a/crossbeam-utils/src/cache_padded.rs#L82-L90), Facebook’s\n\n[) use 128 bytes here.](https://github.com/facebook/folly/blob/4d6b3c7999940ddf2e9c1eb9ed2c9cf3d8c2280f/folly/lang/Align.h#L186-L187)\n\n`folly`\n\n**Why?**\n\nThe reason is that since the Intel Sandy Bridge architecture, the spatial\nprefetcher may load cache lines *in pairs*. It doesn’t make the\neffective cache line size equal to 128 bytes, but still has its side-effects.\n\nMoreover, this behavior is controlled by a per-core MSR setting called either “Adjacent Cache Line Prefetcher Disable” or “L2 Adjacent Cache Line Prefetcher Disable”. Check it before benchmarking! If you can.\n\n# Benchmark[#](#benchmark)\n\nI tried to reproduce the 128-byte alignment improvement on a real benchmark. It wasn’t easy! Just starting 2 threads updating an atomic each is not enough: once the atomics are in the respective CPU caches, no MESI interaction seems to be done. Let’s try something more involved: a vector of atomics should do the trick.\n\nLet’s imitate a classical two-pointer atomic queue: an atomic for head being\nincremented by reader, and an atomic for tail incremented by writer. Using\neither `#[repr(align(64))]`\n\nor `#[repr(align(128))]`\n\nin the Rust code below for\na wrapper type similar to `crossbeam-utils`\n\nwill place the atomics either 64\nor 128 bytes apart.\n\nSingle pair of atomics may be not enough to create a pressure to the memory;\nlet’s get a vector of records of length `SIZE`\n\n. Each thread of two modifies\neither `add`\n\nor `sub`\n\nfield of each record in loop.\n\nThe thread body looks bit odd:\n\n```\nfor _ in 0..(N / SIZE) {\n    for elt in addsub {\n        elt.add.fetch_add(1u64, ORDERING);\n    }\n}\n```\n\nYou may notice that number of operations is `SIZE*floor(N/SIZE)`\n\nwhich is not\nequal to `N`\n\n. It makes comparing different `SIZE`\n\nharder… until we notice that\ndifference is really negligible, because our `SIZE`\n\nare small and `N`\n\nis large.\nBut the inner loop is very simple, and it makes the benchmark more reliable.\n\nYou can get the runnable code at\n[https://github.com/monoid/junk/tree/master/false_sharing](https://github.com/monoid/junk/tree/master/false_sharing), but for your\nconvenience, simplified code is below.\n\n## Source code\n\n```\nuse std::ops::Deref;\nuse std::sync::atomic::{AtomicU64, Ordering};\n\n// Number of steps.\nconst N: usize = 1_000_000_000;\nconst ORDERING: Ordering = Ordering::AcqRel;\n// The length of vector of AddSubs.\nconst SIZE: usize = 8;\n\n// Uncomment any of these lines.\n// #[repr(align(64))]\n// #[repr(align(128))]\n#[derive(Default, Debug)]\nstruct CachePadded<T> {\n    value: T,\n}\n\nimpl<T> Deref for CachePadded<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        &self.value\n    }\n}\n\n// Two atomics side-by-side separated by cache padding configured above.\n#[derive(Default, Debug)]\nstruct AddSub {\n    // Updated by the first thread.\n    add: CachePadded<AtomicU64>,\n    // Updated by the second thread.\n    sub: CachePadded<AtomicU64>,\n}\n\nimpl AddSub {\n    fn get_value(&self) -> u64 {\n        let add = self.add.load(Ordering::Relaxed);\n        let sub = self.sub.load(Ordering::Relaxed);\n        add.wrapping_sub(sub)\n    }\n}\n\nfn main() {\n    let data = Vec::from_iter(std::iter::repeat_with(|| AddSub::default()).take(SIZE));\n    let addsub: Box<[AddSub]> = data.into();\n    let addsub = &*Box::leak(addsub);\n\n    let t1 = std::thread::spawn(move || {\n        #[cfg(target_arch = \"x86_64\")]\n        affinity::set_thread_affinity(&[0]).unwrap();\n\n        for _ in 0..(N / SIZE) {\n            for elt in addsub {\n                elt.add.fetch_add(1u64, ORDERING);\n            }\n        }\n    });\n    let t2 = std::thread::spawn(move || {\n        #[cfg(target_arch = \"x86_64\")]\n        // Not 1! Core 1 is usually a virtual core of the same physical one as core 0, sharing the same caches.\n        affinity::set_thread_affinity(&[2]).unwrap();\n\n        for _ in 0..(N / SIZE) {\n            for elt in addsub {\n                elt.sub.fetch_add(1u64, ORDERING);\n            }\n        }\n    });\n    t1.join().unwrap();\n    t2.join().unwrap();\n\n    for item in &*addsub {\n        eprintln!(\"{}\", item.get_value());\n    }\n}\n```\n\nPinning makes the benchmark more predictable. It avoids both noise from a thread migrating from a core to core and the same-core situation when threads use the same cache.\n\nI’ve compiled a bunch of binaries with different parameters, and ran them with\n\n```\nfor i in $(seq 1 8) 12 16; do\n   for bits in 64 128; do\n      FSHARING_SIZE=$i cargo build --release --features cache_line_${bits}\n      mv target/release/false_sharing ./false_sharing_${i}_${bits}\n   done\ndone\n\nhyperfine --warmup 3  --export-json results.json ./false_sharing_*\n```\n\n## Digital Ocean[#](#digital-ocean)\n\nI started by benchmarking at a Digital Ocean VPS instance. Unfortunately, I wasn’t able to reproduce anything reliably. I suspect that the Adjacent Prefetcher is simply disabled on Digital Ocean. Standard deviation was also quite large for both 128 and 64-byte alignment.\n\n## Amazon Web Services, c5d (Skylake)[#](#amazon-web-services-c5d-skylake)\n\nI was able to reliably reproduce the difference at AWS’s `c5d.4xlarge`\n\ninstance\n(Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz). And execution time was not the\nonly difference between 64 and 128 byte alignment!\n\nUnfortunately, I was not able to analyze programs’ execution on AWS as most of hardware counters are restricted here.\n\n## CPU info\n\n```\nprocessor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 85\nmodel name      : Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz\nstepping        : 4\nmicrocode       : 0x2007006\ncpu MHz         : 3354.253\ncache size      : 25344 KB\nphysical id     : 0\nsiblings        : 16\ncore id         : 0\ncpu cores       : 8\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 13\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault pti fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves ida arat pku ospke\nbugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit mmio_stale_data retbleed gds bhi spectre_v2_user its\nbogomips        : 6000.01\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 46 bits physical, 48 bits virtual\npower management:\n```\n\n## Results[#](#results)\n\n| Size | align 64, time (mean ± σ) | align 128, time (mean ± σ) |\n|---|---|---|\n| 1 | 7.426 s ± 0.001 s | 7.427 s ± 0.001 s |\n| 2 | 5.464 s ± 0.002 s | 5.349 s ± 0.001 s |\n| 3 | 5.475 s ± 0.093 s | 5.249 s ± 0.002 s |\n| 4 | 5.541 s ± 0.092 s | 5.420 s ± 0.001 s |\n| 5 | 5.696 s ± 0.247 s | 5.363 s ± 0.002 s |\n| 6 | 5.609 s ± 0.239 s | 5.396 s ± 0.001 s |\n| 7 | 5.684 s ± 0.201 s | 5.137 s ± 0.001 s |\n| 8 | 6.800 s ± 0.241 s | 6.679 s ± 0.000 s |\n| 12 | 6.258 s ± 0.064 s | 6.189 s ± 0.001 s |\n| 16 | 6.943 s ± 0.281 s | 6.646 s ± 0.001 s |\n\n128-byte alignment is not just a few percent faster, it also demonstrates **more\nconsistent timings**, which may be crucial for real-time and latency-sensitive\napplications like HFT. The reason is clear: prefetcher-induced cache coherence\nin 64-byte alignment happens in unpredictable order and takes unpredictable\ntime, while 128-byte alignment eliminates this contention.\n\n## Raw results, AWS c5d.4xlarge\n\n``` bash\n$ hyperfine --warmup 3  --export-json results.json ./false_sharing_* ./false_sharing_12_128\nBenchmark 1: ./false_sharing_12_128\n  Time (mean ± σ):      6.189 s ±  0.001 s    [User: 12.373 s, System: 0.001 s]\n  Range (min … max):    6.188 s …  6.190 s    10 runs\n \nBenchmark 2: ./false_sharing_12_64\n  Time (mean ± σ):      6.258 s ±  0.064 s    [User: 12.497 s, System: 0.002 s]\n  Range (min … max):    6.206 s …  6.415 s    10 runs\n \nBenchmark 3: ./false_sharing_16_128\n  Time (mean ± σ):      6.646 s ±  0.001 s    [User: 13.285 s, System: 0.002 s]\n  Range (min … max):    6.645 s …  6.647 s    10 runs\n \nBenchmark 4: ./false_sharing_16_64\n  Time (mean ± σ):      6.943 s ±  0.281 s    [User: 13.878 s, System: 0.001 s]\n  Range (min … max):    6.649 s …  7.378 s    10 runs\n \nBenchmark 5: ./false_sharing_1_128\n  Time (mean ± σ):      7.427 s ±  0.001 s    [User: 14.845 s, System: 0.001 s]\n  Range (min … max):    7.426 s …  7.428 s    10 runs\n \nBenchmark 6: ./false_sharing_1_64\n  Time (mean ± σ):      7.426 s ±  0.001 s    [User: 14.843 s, System: 0.002 s]\n  Range (min … max):    7.424 s …  7.427 s    10 runs\n \nBenchmark 7: ./false_sharing_2_128\n  Time (mean ± σ):      5.349 s ±  0.001 s    [User: 10.690 s, System: 0.001 s]\n  Range (min … max):    5.348 s …  5.349 s    10 runs\n \nBenchmark 8: ./false_sharing_2_64\n  Time (mean ± σ):      5.464 s ±  0.002 s    [User: 10.809 s, System: 0.001 s]\n  Range (min … max):    5.463 s …  5.468 s    10 runs\n \nBenchmark 9: ./false_sharing_3_128\n  Time (mean ± σ):      5.249 s ±  0.002 s    [User: 10.492 s, System: 0.001 s]\n  Range (min … max):    5.247 s …  5.251 s    10 runs\n \nBenchmark 10: ./false_sharing_3_64\n  Time (mean ± σ):      5.475 s ±  0.093 s    [User: 10.923 s, System: 0.001 s]\n  Range (min … max):    5.414 s …  5.726 s    10 runs\n \nBenchmark 11: ./false_sharing_4_128\n  Time (mean ± σ):      5.420 s ±  0.001 s    [User: 10.832 s, System: 0.001 s]\n  Range (min … max):    5.419 s …  5.421 s    10 runs\n \nBenchmark 12: ./false_sharing_4_64\n  Time (mean ± σ):      5.541 s ±  0.092 s    [User: 11.073 s, System: 0.001 s]\n  Range (min … max):    5.439 s …  5.757 s    10 runs\n \nBenchmark 13: ./false_sharing_5_128\n  Time (mean ± σ):      5.363 s ±  0.002 s    [User: 10.717 s, System: 0.002 s]\n  Range (min … max):    5.359 s …  5.367 s    10 runs\n \nBenchmark 14: ./false_sharing_5_64\n  Time (mean ± σ):      5.696 s ±  0.247 s    [User: 11.387 s, System: 0.001 s]\n  Range (min … max):    5.361 s …  6.235 s    10 runs\n \nBenchmark 15: ./false_sharing_6_128\n  Time (mean ± σ):      5.396 s ±  0.001 s    [User: 10.785 s, System: 0.001 s]\n  Range (min … max):    5.395 s …  5.397 s    10 runs\n \nBenchmark 16: ./false_sharing_6_64\n  Time (mean ± σ):      5.609 s ±  0.239 s    [User: 11.210 s, System: 0.001 s]\n  Range (min … max):    5.371 s …  6.012 s    10 runs\n \nBenchmark 17: ./false_sharing_7_128\n  Time (mean ± σ):      5.137 s ±  0.001 s    [User: 10.265 s, System: 0.001 s]\n  Range (min … max):    5.135 s …  5.138 s    10 runs\n \nBenchmark 18: ./false_sharing_7_64\n  Time (mean ± σ):      5.684 s ±  0.201 s    [User: 11.362 s, System: 0.001 s]\n  Range (min … max):    5.343 s …  6.057 s    10 runs\n \nBenchmark 19: ./false_sharing_8_128\n  Time (mean ± σ):      6.679 s ±  0.000 s    [User: 13.136 s, System: 0.001 s]\n  Range (min … max):    6.678 s …  6.679 s    10 runs\n \nBenchmark 20: ./false_sharing_8_64\n  Time (mean ± σ):      6.800 s ±  0.241 s    [User: 13.590 s, System: 0.002 s]\n  Range (min … max):    6.684 s …  7.473 s    10 runs\n \nBenchmark 21: ./false_sharing_12_128\n  Time (mean ± σ):      6.189 s ±  0.000 s    [User: 12.375 s, System: 0.001 s]\n  Range (min … max):    6.189 s …  6.190 s    10 runs\n \nSummary\n  ./false_sharing_7_128 ran\n    1.02 ± 0.00 times faster than ./false_sharing_3_128\n    1.04 ± 0.00 times faster than ./false_sharing_2_128\n    1.04 ± 0.00 times faster than ./false_sharing_5_128\n    1.05 ± 0.00 times faster than ./false_sharing_6_128\n    1.06 ± 0.00 times faster than ./false_sharing_4_128\n    1.06 ± 0.00 times faster than ./false_sharing_2_64\n    1.07 ± 0.02 times faster than ./false_sharing_3_64\n    1.08 ± 0.02 times faster than ./false_sharing_4_64\n    1.09 ± 0.05 times faster than ./false_sharing_6_64\n    1.11 ± 0.04 times faster than ./false_sharing_7_64\n    1.11 ± 0.05 times faster than ./false_sharing_5_64\n    1.20 ± 0.00 times faster than ./false_sharing_12_128\n    1.20 ± 0.00 times faster than ./false_sharing_12_128\n    1.22 ± 0.01 times faster than ./false_sharing_12_64\n    1.29 ± 0.00 times faster than ./false_sharing_16_128\n    1.30 ± 0.00 times faster than ./false_sharing_8_128\n    1.32 ± 0.05 times faster than ./false_sharing_8_64\n    1.35 ± 0.05 times faster than ./false_sharing_16_64\n    1.45 ± 0.00 times faster than ./false_sharing_1_64\n    1.45 ± 0.00 times faster than ./false_sharing_1_128\n```\n\n## Amazon Web Services, c6i (Ice Lake)[#](#amazon-web-services-c6i-ice-lake)\n\nTo my surprise, the `c6i.4xlarge`\n\ninstance with Intel(R) Xeon(R) Platinum 8375C\nCPU @ 2.90GHz (Ice Lake) demonstrates practically no difference between 64 and\n128 case, while standard deviation always stays very small. I can only speculate\nthat the prefetcher is more sophisticated here, and another approach may be\nneeded to reproduce the problem.\n\n| Size | align 64, time (mean ± σ) | align 128, time (mean ± σ) |\n|---|---|---|\n| 1 | 6.073 s ± 0.001 s | 6.073 s ± 0.001 s |\n| 2 | 5.624 s ± 0.004 s | 5.608 s ± 0.003 s |\n| 5 | 5.539 s ± 0.000 s | 5.546 s ± 0.000 s |\n| 12 | 5.512 s ± 0.000 s | 5.512 s ± 0.000 s |\n\n## Raw results, AWS c6i.4xlarge\n\n``` bash\n$ hyperfine --warmup 3 --export-json c6i.json ./false_sharing_*\nBenchmark 1: ./false_sharing_12_128\n  Time (mean ± σ):      5.512 s ±  0.000 s    [User: 11.012 s, System: 0.001 s]\n  Range (min … max):    5.512 s …  5.513 s    10 runs\n \nBenchmark 2: ./false_sharing_12_64\n  Time (mean ± σ):      5.512 s ±  0.000 s    [User: 11.011 s, System: 0.001 s]\n  Range (min … max):    5.512 s …  5.513 s    10 runs\n \nBenchmark 3: ./false_sharing_16_128\n  Time (mean ± σ):      5.506 s ±  0.000 s    [User: 10.998 s, System: 0.001 s]\n  Range (min … max):    5.505 s …  5.507 s    10 runs\n \n  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.\n \nBenchmark 4: ./false_sharing_16_64\n  Time (mean ± σ):      5.506 s ±  0.000 s    [User: 10.999 s, System: 0.001 s]\n  Range (min … max):    5.506 s …  5.507 s    10 runs\n \nBenchmark 5: ./false_sharing_1_128\n  Time (mean ± σ):      6.073 s ±  0.001 s    [User: 12.136 s, System: 0.001 s]\n  Range (min … max):    6.071 s …  6.074 s    10 runs\n \nBenchmark 6: ./false_sharing_1_64\n  Time (mean ± σ):      6.073 s ±  0.001 s    [User: 12.136 s, System: 0.001 s]\n  Range (min … max):    6.071 s …  6.075 s    10 runs\n \nBenchmark 7: ./false_sharing_2_128\n  Time (mean ± σ):      5.608 s ±  0.003 s    [User: 11.205 s, System: 0.001 s]\n  Range (min … max):    5.604 s …  5.612 s    10 runs\n \nBenchmark 8: ./false_sharing_2_64\n  Time (mean ± σ):      5.624 s ±  0.004 s    [User: 11.236 s, System: 0.001 s]\n  Range (min … max):    5.617 s …  5.630 s    10 runs\n \nBenchmark 9: ./false_sharing_3_128\n  Time (mean ± σ):      5.574 s ±  0.001 s    [User: 11.135 s, System: 0.001 s]\n  Range (min … max):    5.572 s …  5.576 s    10 runs\n \nBenchmark 10: ./false_sharing_3_64\n  Time (mean ± σ):      5.577 s ±  0.003 s    [User: 11.130 s, System: 0.001 s]\n  Range (min … max):    5.571 s …  5.580 s    10 runs\n \nBenchmark 11: ./false_sharing_4_128\n  Time (mean ± σ):      5.560 s ±  0.000 s    [User: 11.109 s, System: 0.001 s]\n  Range (min … max):    5.560 s …  5.561 s    10 runs\n \nBenchmark 12: ./false_sharing_4_64\n  Time (mean ± σ):      5.560 s ±  0.000 s    [User: 11.099 s, System: 0.001 s]\n  Range (min … max):    5.560 s …  5.561 s    10 runs\n \nBenchmark 13: ./false_sharing_5_128\n  Time (mean ± σ):      5.546 s ±  0.000 s    [User: 11.066 s, System: 0.001 s]\n  Range (min … max):    5.545 s …  5.547 s    10 runs\n \nBenchmark 14: ./false_sharing_5_64\n  Time (mean ± σ):      5.539 s ±  0.000 s    [User: 11.075 s, System: 0.001 s]\n  Range (min … max):    5.539 s …  5.540 s    10 runs\n```\n\n## Apple Silicon M1[#](#apple-silicon-m1)\n\nApple Silicon CPUs have 128-byte cache lines. It should demonstrate the effect even more strikingly than Intel’s spatial prefetcher. But it doesn’t. Here are some samples:\n\n| Size | align 64, time (mean ± σ) | align 128, time (mean ± σ) |\n|---|---|---|\n| 1 | 7.130 s ± 0.025 s | 7.125 s ± 0.006 s |\n| 3 | 2.391 s ± 0.002 s | 2.425 s ± 0.002 s |\n| 6 | 2.265 s ± 0.003 s | 2.263 s ± 0.000 s |\n\nI wasn’t able to determine what is happening here, but here is\n[an independent confirmation of my findings]\n([https://www.linkedin.com/posts/taras-tsugrii-8117a313_apple-silicon-taught-me-that-what-is-the-activity-7453243815299072000-Cdqw/)](https://www.linkedin.com/posts/taras-tsugrii-8117a313_apple-silicon-taught-me-that-what-is-the-activity-7453243815299072000-Cdqw/)).\n\n# Conclusion[#](#conclusion)\n\nI was able to reproduce the spatial prefetcher-induced false sharing on a Skylake CPU, but Ice Lake seems to require another approach.\n\nApple Silicon M1 formally has 128-byte cache lines, but experiments do not confirm that.\n\n# Reading list[#](#reading-list)\n\n- Mara Bos,\n*Rust Atomics and Locks*. O’Reilly Media, 2023. ISBN 978-1098119447. - Denis Bakhvalov,\n*Performance Analysis and Tuning on Modern CPUs*. 2024, ISBN 979-8869584229. [Intel® 64 and IA-32 Architectures Software Developer’s Manual](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html).\n\n# Disclaimer[#](#disclaimer)\n\nThis text was written by Ivan Boldyrev. No hallucinations, no slop, no homogenization. I used AI only for brainstorming and proofreading.", "url": "https://wpnews.pro/news/why-false-sharing-alignment-should-be-128-bytes-on-x64", "canonical_source": "https://monoid.github.io/posts/false-sharing-alignment/", "published_at": "2026-07-07 08:22:58+00:00", "updated_at": "2026-07-07 08:29:21.866665+00:00", "lang": "en", "topics": ["computer-vision"], "entities": ["Intel", "Sandy Bridge", "crossbeam-utils", "Facebook", "folly", "Rust", "C++", "GCC"], "alternates": {"html": "https://wpnews.pro/news/why-false-sharing-alignment-should-be-128-bytes-on-x64", "markdown": "https://wpnews.pro/news/why-false-sharing-alignment-should-be-128-bytes-on-x64.md", "text": "https://wpnews.pro/news/why-false-sharing-alignment-should-be-128-bytes-on-x64.txt", "jsonld": "https://wpnews.pro/news/why-false-sharing-alignment-should-be-128-bytes-on-x64.jsonld"}}