<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.haidhi.my.id/wiki/index.php?action=history&amp;feed=atom&amp;title=Cache_line</id>
	<title>Cache line - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.haidhi.my.id/wiki/index.php?action=history&amp;feed=atom&amp;title=Cache_line"/>
	<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=Cache_line&amp;action=history"/>
	<updated>2026-11-01T19:54:56Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.haidhi.my.id/wiki/index.php?title=Cache_line&amp;diff=753&amp;oldid=prev</id>
		<title>SanzSkuy at 07:39, 3 July 2026</title>
		<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=Cache_line&amp;diff=753&amp;oldid=prev"/>
		<updated>2026-07-03T07:39:04Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 07:39, 3 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l232&quot;&gt;Line 232:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 232:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[SoA vs AoS]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[SoA vs AoS]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[SIMD]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[SIMD]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Memory &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;coalescing&lt;/del&gt;]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Memory &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Coalescing&lt;/ins&gt;]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Roofline model]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Roofline model]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[NUMA]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[NUMA]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>SanzSkuy</name></author>
	</entry>
	<entry>
		<id>https://wiki.haidhi.my.id/wiki/index.php?title=Cache_line&amp;diff=752&amp;oldid=prev</id>
		<title>SanzSkuy: Created page with &quot;&#039;&#039;&#039;Cache line&#039;&#039;&#039; adalah unit transfer data terkecil antara cache CPU dan memori utama (RAM). Setiap kali CPU butuh data — walaupun cuma 1 byte — yang diangkut dari RAM bukan 1 byte itu saja, melainkan &#039;&#039;&#039;satu blok penuh&#039;&#039;&#039; berukuran tetap, umumnya &#039;&#039;&#039;64 byte&#039;&#039;&#039; pada CPU x86 modern (Apple M-series memakai 128 byte).  Konsep ini kelihatan sepele, tapi hampir semua trik optimasi performa di HPC — mulai dari layout data SoA, loop ordering, cache blocking...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=Cache_line&amp;diff=752&amp;oldid=prev"/>
		<updated>2026-07-03T07:37:26Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;Cache line&amp;#039;&amp;#039;&amp;#039; adalah unit transfer data terkecil antara cache CPU dan memori utama (RAM). Setiap kali CPU butuh data — walaupun cuma 1 byte — yang diangkut dari RAM bukan 1 byte itu saja, melainkan &amp;#039;&amp;#039;&amp;#039;satu blok penuh&amp;#039;&amp;#039;&amp;#039; berukuran tetap, umumnya &amp;#039;&amp;#039;&amp;#039;64 byte&amp;#039;&amp;#039;&amp;#039; pada CPU x86 modern (Apple M-series memakai 128 byte).  Konsep ini kelihatan sepele, tapi hampir semua trik optimasi performa di HPC — mulai dari &lt;a href=&quot;/wiki/index.php/SoA_vs_AoS&quot; title=&quot;SoA vs AoS&quot;&gt;layout data SoA&lt;/a&gt;, loop ordering, cache blocking...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Cache line&amp;#039;&amp;#039;&amp;#039; adalah unit transfer data terkecil antara cache CPU dan memori utama (RAM). Setiap kali CPU butuh data — walaupun cuma 1 byte — yang diangkut dari RAM bukan 1 byte itu saja, melainkan &amp;#039;&amp;#039;&amp;#039;satu blok penuh&amp;#039;&amp;#039;&amp;#039; berukuran tetap, umumnya &amp;#039;&amp;#039;&amp;#039;64 byte&amp;#039;&amp;#039;&amp;#039; pada CPU x86 modern (Apple M-series memakai 128 byte).&lt;br /&gt;
&lt;br /&gt;
Konsep ini kelihatan sepele, tapi hampir semua trik optimasi performa di HPC — mulai dari [[SoA vs AoS|layout data SoA]], loop ordering, cache blocking, sampai menghindari &amp;#039;&amp;#039;false sharing&amp;#039;&amp;#039; — ujung-ujungnya adalah soal memperlakukan cache line dengan benar.&lt;br /&gt;
&lt;br /&gt;
== Analogi Sederhana ==&lt;br /&gt;
&lt;br /&gt;
Bayangkan kamu masak di dapur (CPU) dan bahan-bahannya disimpan di gudang belakang rumah (RAM). Bolak-balik ke gudang itu lama. Jadi aturannya: &amp;#039;&amp;#039;&amp;#039;setiap ke gudang, kamu wajib bawa pulang satu boks penuh&amp;#039;&amp;#039;&amp;#039;, bukan satu bahan saja. Boks itu ditaruh di meja dapur (cache).&lt;br /&gt;
&lt;br /&gt;
* Kalau isi satu boks memang bahan-bahan yang akan kamu pakai berurutan → sekali jalan, kerjaan lancar lama. Ini yang disebut &amp;#039;&amp;#039;&amp;#039;spatial locality&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* Kalau kamu cuma butuh 1 bahan dari boks itu dan sisanya tidak terpakai → kamu tetap capek mengangkut satu boks penuh. Bandwidth terbuang.&lt;br /&gt;
&lt;br /&gt;
Meja dapur juga terbatas — kalau penuh, boks lama harus dikeluarkan (&amp;#039;&amp;#039;eviction&amp;#039;&amp;#039;) untuk memberi tempat boks baru.&lt;br /&gt;
&lt;br /&gt;
== Hierarki Memori ==&lt;br /&gt;
&lt;br /&gt;
Cache bukan cuma satu lapis. Makin dekat ke core, makin cepat tapi makin kecil:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        +-----------+&lt;br /&gt;
        |  Register |   ~0-1 siklus      (byte-an)&lt;br /&gt;
        +-----------+&lt;br /&gt;
        |    L1     |   ~4 siklus        (32-64 KiB per core)&lt;br /&gt;
        +-----------+&lt;br /&gt;
        |    L2     |   ~12-14 siklus    (256 KiB - 2 MiB per core)&lt;br /&gt;
        +-----------+&lt;br /&gt;
        |    L3     |   ~30-50 siklus    (8-128 MiB, dibagi antar core)&lt;br /&gt;
        +-----------+&lt;br /&gt;
        |    RAM    |   ~200-400 siklus  (puluhan GB)&lt;br /&gt;
        +-----------+&lt;br /&gt;
        |  SSD/Disk |   jutaan siklus&lt;br /&gt;
        +-----------+&lt;br /&gt;
&lt;br /&gt;
  makin ke bawah: makin BESAR, makin LAMBAT&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Perhatikan jomplangnya: akses L1 vs RAM bedanya bisa &amp;#039;&amp;#039;&amp;#039;50–100x&amp;#039;&amp;#039;&amp;#039;. Artinya, satu cache miss ke RAM setara ratusan instruksi aritmetika yang &amp;quot;hilang&amp;quot;. Inilah kenapa banyak kode HPC yang bottleneck-nya bukan di kecepatan hitung (FLOPS), tapi di memori (&amp;#039;&amp;#039;memory-bound&amp;#039;&amp;#039;).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Level !! Ukuran tipikal !! Latency (kira-kira) !! Catatan&lt;br /&gt;
|-&lt;br /&gt;
| Register || ratusan byte || 0–1 siklus || bagian dari core&lt;br /&gt;
|-&lt;br /&gt;
| L1 || 32–64 KiB per core || ~4 siklus (~1 ns) || terpisah untuk instruksi (L1i) dan data (L1d)&lt;br /&gt;
|-&lt;br /&gt;
| L2 || 256 KiB – 2 MiB per core || ~12–14 siklus || biasanya privat per core&lt;br /&gt;
|-&lt;br /&gt;
| L3 (LLC) || 8–128 MiB || ~30–50 siklus || dibagi antar core&lt;br /&gt;
|-&lt;br /&gt;
| RAM (DRAM) || puluhan–ratusan GB || ~200–400 siklus (~60–100 ns) || lewat memory controller&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Angka pastinya beda-beda tiap CPU; yang penting dipahami adalah &amp;#039;&amp;#039;&amp;#039;ordo perbandingannya&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Cara Kerja: Alamat Dipecah Tiga ==&lt;br /&gt;
&lt;br /&gt;
RAM secara logis dibagi menjadi blok-blok 64 byte. Blok mana masuk ke slot cache mana ditentukan langsung dari bit-bit alamatnya:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Alamat memori (contoh, cache line 64 byte):&lt;br /&gt;
&lt;br /&gt;
+--------------------------------+-----------+-----------+&lt;br /&gt;
|              TAG               |   INDEX   |  OFFSET   |&lt;br /&gt;
+--------------------------------+-----------+-----------+&lt;br /&gt;
                                       |           |&lt;br /&gt;
                                       |           +--&amp;gt; byte ke berapa&lt;br /&gt;
                                       |                DI DALAM line (0-63,&lt;br /&gt;
                                       |                6 bit karena 2^6=64)&lt;br /&gt;
                                       +--&amp;gt; line ini masuk ke SET&lt;br /&gt;
                                            nomor berapa di cache&lt;br /&gt;
&lt;br /&gt;
TAG disimpan bersama line-nya, dipakai untuk mengecek:&lt;br /&gt;
&amp;quot;line yang nyangkut di slot ini beneran punya alamat X atau bukan?&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contoh konkret: L1d sebesar 32 KiB, 8-way set associative, line 64 byte:&lt;br /&gt;
* 32.768 / 64 = 512 line&lt;br /&gt;
* 512 / 8 way = 64 set → butuh 6 bit index&lt;br /&gt;
* Sisa bit alamat di atasnya jadi tag&lt;br /&gt;
&lt;br /&gt;
Kalau CPU mencari data: hitung set dari index → bandingkan tag dengan 8 line di set itu → cocok = &amp;#039;&amp;#039;&amp;#039;cache hit&amp;#039;&amp;#039;&amp;#039; (cepat), tidak cocok = &amp;#039;&amp;#039;&amp;#039;cache miss&amp;#039;&amp;#039;&amp;#039; (harus turun ke level bawah).&lt;br /&gt;
&lt;br /&gt;
== Spatial Locality: Kenapa Akses Berurutan Cepat ==&lt;br /&gt;
&lt;br /&gt;
Karena satu line = 64 byte = 16 buah &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt;, membaca array secara berurutan cuma kena miss sekali tiap 16 elemen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Akses BERURUTAN (stride 1):&lt;br /&gt;
&lt;br /&gt;
  a[0] a[1] a[2] ... a[15] | a[16] a[17] ... a[31] | a[32] ...&lt;br /&gt;
  MISS  hit  hit ...  hit    MISS   hit  ...  hit    MISS&lt;br /&gt;
  \________ 1 line ______/   \________ 1 line _____/&lt;br /&gt;
&lt;br /&gt;
  --&amp;gt; 1 miss per 16 float. Hardware prefetcher bahkan bisa&lt;br /&gt;
      menebak polanya dan mengambil line berikutnya DULUAN,&lt;br /&gt;
      sehingga miss-nya nyaris tak terasa.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Akses LONCAT-LONCAT (stride 16 float = 64 byte):&lt;br /&gt;
&lt;br /&gt;
  a[0]      a[16]     a[32]     a[48]&lt;br /&gt;
  MISS      MISS      MISS      MISS&lt;br /&gt;
  --&amp;gt; TIAP akses = 1 miss. Dari 64 byte yang diangkut,&lt;br /&gt;
      cuma 4 byte yang dipakai. Bandwidth efektif tinggal 1/16.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dua kode bisa punya jumlah operasi persis sama tapi kecepatannya beda berkali-kali lipat hanya karena pola aksesnya beda. Ini juga alasan utama layout [[SoA vs AoS|SoA]] menang untuk akses per-field.&lt;br /&gt;
&lt;br /&gt;
== Contoh Klasik: Urutan Loop Matriks ==&lt;br /&gt;
&lt;br /&gt;
Array 2D di C/C++ disimpan &amp;#039;&amp;#039;&amp;#039;row-major&amp;#039;&amp;#039;&amp;#039;: satu baris utuh dulu, baru baris berikutnya.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
A[3][4] di memori:&lt;br /&gt;
&lt;br /&gt;
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+&lt;br /&gt;
| A00 | A01 | A02 | A03 | A10 | A11 | A12 | A13 | A20 | A21 | A22 | A23 |&lt;br /&gt;
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+&lt;br /&gt;
 \_______ baris 0 ______/ \_______ baris 1 ______/ \______ baris 2 _____/&lt;br /&gt;
&lt;br /&gt;
Loop i-lalu-j : jalan terus ke kanan     --&amp;gt; ramah cache&lt;br /&gt;
Loop j-lalu-i : loncat antar baris (N*4 byte) --&amp;gt; miss terus-terusan&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// CEPAT: mengikuti layout memori (row-major)&lt;br /&gt;
for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
    for (int j = 0; j &amp;lt; N; ++j)&lt;br /&gt;
        sum += A[i][j];&lt;br /&gt;
&lt;br /&gt;
// LAMBAT: melawan layout — tiap iterasi loncat satu baris penuh&lt;br /&gt;
for (int j = 0; j &amp;lt; N; ++j)&lt;br /&gt;
    for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
        sum += A[i][j];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Untuk N besar (matriks tidak muat di cache), versi kedua bisa lebih lambat berkali-kali lipat, padahal hasil dan jumlah operasinya identik.&lt;br /&gt;
&lt;br /&gt;
== Cache Blocking (Tiling) ==&lt;br /&gt;
&lt;br /&gt;
Kalau datanya terlalu besar untuk cache, strategi standarnya: &amp;#039;&amp;#039;&amp;#039;pecah kerjaan jadi blok-blok kecil yang muat di L1/L2&amp;#039;&amp;#039;&amp;#039;, lalu pakai blok itu berulang kali selagi masih &amp;quot;hangat&amp;quot; di cache.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Matmul naif C = A x B:&lt;br /&gt;
  - baris A dibaca berurutan (aman)&lt;br /&gt;
  - kolom B dibaca loncat-loncat sepanjang N --&amp;gt; badai cache miss&lt;br /&gt;
&lt;br /&gt;
Dengan blocking (mis. blok 64x64):&lt;br /&gt;
&lt;br /&gt;
        B                          Kerjakan per-blok:&lt;br /&gt;
  +----+----+----+                 blok A dan blok B dimuat sekali,&lt;br /&gt;
  | B00| B01| .. |                 dipakai puluhan kali untuk&lt;br /&gt;
  +----+----+----+                 menghitung blok C, BARU pindah&lt;br /&gt;
  | B10| B11| .. |                 ke blok berikutnya.&lt;br /&gt;
  +----+----+----+&lt;br /&gt;
                                   Reuse naik --&amp;gt; traffic ke RAM turun.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Teknik ini (plus SIMD) adalah fondasi kenapa library BLAS seperti OpenBLAS/MKL bisa mendekati peak FLOPS, sementara triple-loop naif cuma dapat beberapa persen.&lt;br /&gt;
&lt;br /&gt;
== False Sharing: Jebakan di Kode Multithread ==&lt;br /&gt;
&lt;br /&gt;
Ini masalah cache line yang paling sering menggigit di kode paralel. &amp;#039;&amp;#039;&amp;#039;Dua thread menulis ke variabel yang berbeda, tapi variabelnya kebetulan tinggal di cache line yang sama.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   Core 0                              Core 1&lt;br /&gt;
   Thread A: counter[0]++              Thread B: counter[1]++&lt;br /&gt;
&lt;br /&gt;
              satu cache line (64 byte)&lt;br /&gt;
            +-------------+-------------+------------------+&lt;br /&gt;
            | counter[0]  | counter[1]  |   (sisa line)    |&lt;br /&gt;
            +-------------+-------------+------------------+&lt;br /&gt;
                  ^               ^&lt;br /&gt;
                  A               B&lt;br /&gt;
&lt;br /&gt;
Protokol koherensi (MESI) bekerja per-LINE, bukan per-variabel:&lt;br /&gt;
  1. A menulis  -&amp;gt; salinan line di Core 1 di-INVALIDATE&lt;br /&gt;
  2. B menulis  -&amp;gt; line harus dipindah/di-invalidate balik&lt;br /&gt;
  3. dst... line &amp;quot;ping-pong&amp;quot; bolak-balik antar core&lt;br /&gt;
&lt;br /&gt;
Hasil: dua thread yang secara logika TIDAK berbagi data apa pun&lt;br /&gt;
saling memperlambat, kadang sampai lebih lambat dari versi serial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solusinya: beri jarak (padding) supaya tiap thread punya line sendiri.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// Bermasalah: 8 counter (8 byte) muat dalam 1 line&lt;br /&gt;
long counter[NUM_THREADS];&lt;br /&gt;
&lt;br /&gt;
// Solusi: paksa tiap counter menempati line sendiri&lt;br /&gt;
struct alignas(64) PaddedCounter {&lt;br /&gt;
    long value;&lt;br /&gt;
    // compiler otomatis menambah padding sampai 64 byte&lt;br /&gt;
};&lt;br /&gt;
PaddedCounter counter[NUM_THREADS];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C++17 menyediakan konstanta &amp;lt;code&amp;gt;std::hardware_destructive_interference_size&amp;lt;/code&amp;gt; sebagai pengganti angka 64 yang di-hardcode.&lt;br /&gt;
&lt;br /&gt;
Catatan singkat soal &amp;#039;&amp;#039;&amp;#039;MESI&amp;#039;&amp;#039;&amp;#039;: tiap line di tiap core punya status &amp;#039;&amp;#039;&amp;#039;M&amp;#039;&amp;#039;&amp;#039;odified / &amp;#039;&amp;#039;&amp;#039;E&amp;#039;&amp;#039;&amp;#039;xclusive / &amp;#039;&amp;#039;&amp;#039;S&amp;#039;&amp;#039;&amp;#039;hared / &amp;#039;&amp;#039;&amp;#039;I&amp;#039;&amp;#039;&amp;#039;nvalid. Menulis ke line yang statusnya Shared memaksa core lain meng-invalidate salinannya — inilah mekanisme yang membuat false sharing mahal.&lt;br /&gt;
&lt;br /&gt;
== Cara Mengecek Ukuran Cache Line ==&lt;br /&gt;
&lt;br /&gt;
Di Linux:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
getconf LEVEL1_DCACHE_LINESIZE&lt;br /&gt;
# atau&lt;br /&gt;
cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size&lt;br /&gt;
# atau lihat kolom COHERENCY-SIZE:&lt;br /&gt;
lscpu -C&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Untuk melihat efek cache miss secara nyata, pakai &amp;lt;code&amp;gt;perf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perf stat -e cache-references,cache-misses,LLC-load-misses ./program&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips Praktis ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Akses memori berurutan&amp;#039;&amp;#039;&amp;#039; sebisa mungkin — susun loop mengikuti layout data (row-major di C/C++), bukan sebaliknya.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Pilih layout data sesuai pola akses&amp;#039;&amp;#039;&amp;#039; — lihat [[SoA vs AoS]].&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Kecilkan working set&amp;#039;&amp;#039;&amp;#039;: struct yang ramping = lebih banyak elemen per line. Urutkan field dari yang terbesar untuk mengurangi padding kompiler.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Blocking/tiling&amp;#039;&amp;#039;&amp;#039; untuk kerjaan yang datanya lebih besar dari cache (matmul, stencil, transpose).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Align data panas&amp;#039;&amp;#039;&amp;#039; ke 64 byte (&amp;lt;code&amp;gt;alignas(64)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;std::aligned_alloc&amp;lt;/code&amp;gt;) — penting juga untuk load SIMD.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Waspadai false sharing&amp;#039;&amp;#039;&amp;#039; di kode multithread: data yang ditulis thread berbeda jangan sampai satu line. Pisahkan dengan padding.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Ukur, jangan menebak&amp;#039;&amp;#039;&amp;#039;: &amp;lt;code&amp;gt;perf stat&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;perf c2c&amp;lt;/code&amp;gt; (khusus mendeteksi false sharing), cachegrind (&amp;lt;code&amp;gt;valgrind --tool=cachegrind&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Lihat Juga ==&lt;br /&gt;
&lt;br /&gt;
* [[SoA vs AoS]]&lt;br /&gt;
* [[SIMD]]&lt;br /&gt;
* [[Memory coalescing]]&lt;br /&gt;
* [[Roofline model]]&lt;br /&gt;
* [[NUMA]]&lt;br /&gt;
&lt;br /&gt;
== Referensi ==&lt;br /&gt;
&lt;br /&gt;
* Ulrich Drepper, &amp;#039;&amp;#039;What Every Programmer Should Know About Memory&amp;#039;&amp;#039;, Red Hat, Inc., 2007 — https://people.freebsd.org/~lstewart/articles/cpumemory.pdf&lt;br /&gt;
* John L. Hennessy &amp;amp; David A. Patterson, &amp;#039;&amp;#039;Computer Architecture: A Quantitative Approach&amp;#039;&amp;#039;, 6th Edition, Morgan Kaufmann, 2017 — Bab 2, Memory Hierarchy Design.&lt;br /&gt;
* Intel Corporation, &amp;#039;&amp;#039;Intel 64 and IA-32 Architectures Optimization Reference Manual&amp;#039;&amp;#039; — bagian cache dan memory subsystem.&lt;br /&gt;
* Agner Fog, &amp;#039;&amp;#039;The Microarchitecture of Intel, AMD and VIA CPUs&amp;#039;&amp;#039; — https://www.agner.org/optimize/&lt;br /&gt;
* Igor Ostrovsky, &amp;quot;Gallery of Processor Cache Effects&amp;quot; — https://igoro.com/archive/gallery-of-processor-cache-effects/&lt;br /&gt;
* Scott Meyers, &amp;quot;CPU Caches and Why You Care&amp;quot;, code::dive 2014 (rekaman talk tersedia di YouTube).&lt;br /&gt;
* cppreference.com — &amp;#039;&amp;#039;std::hardware_destructive_interference_size&amp;#039;&amp;#039; — https://en.cppreference.com/w/cpp/thread/hardware_destructive_interference_size&lt;br /&gt;
&lt;br /&gt;
[[Kategori:HPC]]&lt;br /&gt;
[[Kategori:Arsitektur Komputer]]&lt;br /&gt;
[[Kategori:Optimasi Performa]]&lt;/div&gt;</summary>
		<author><name>SanzSkuy</name></author>
	</entry>
</feed>