Aturan dasar sebenarnya cukup sederhana. Di mana itu menjadi rumit adalah bagaimana mereka berlaku untuk kode Anda.
Cache bekerja pada dua prinsip: temporal locality dan spatial locality. Yang pertama adalah gagasan bahwa jika Anda baru-baru ini menggunakan sepotong data tertentu, Anda mungkin akan membutuhkannya lagi segera. Yang terakhir berarti bahwa jika Anda baru-baru ini menggunakan data di alamat X, Anda mungkin akan segera membutuhkan alamat X + 1.
Cache mencoba untuk mengakomodasi ini dengan mengingat potongan data yang terakhir digunakan. Ini beroperasi dengan garis cache, biasanya berukuran 128 byte atau lebih, jadi bahkan jika Anda hanya membutuhkan satu byte, seluruh baris cache yang berisi itu akan ditarik ke dalam cache. Jadi jika Anda memerlukan byte berikut setelahnya, itu sudah ada dalam cache.
Dan ini berarti Anda akan selalu menginginkan kode Anda sendiri untuk mengeksploitasi dua bentuk lokalitas ini sebanyak mungkin. Jangan lompati memori. Lakukan sebanyak mungkin pekerjaan di satu area kecil, dan kemudian pindah ke yang berikutnya, dan lakukan sebanyak mungkin pekerjaan di sana.
Contoh sederhana adalah larik array 2D yang ditunjukkan oleh jawaban 1800. Jika Anda melewatinya satu per satu, Anda membaca memori secara berurutan. Jika Anda melakukannya dengan bijaksana, Anda akan membaca satu entri, lalu melompat ke lokasi yang sama sekali berbeda (awal baris berikutnya), membaca satu entri, dan melompat lagi. Dan ketika Anda akhirnya kembali ke baris pertama, itu tidak akan lagi berada di cache.
Hal yang sama berlaku untuk kode. Lompatan atau cabang berarti penggunaan cache yang kurang efisien (karena Anda tidak membaca instruksi secara berurutan, tetapi melompat ke alamat lain). Tentu saja, pernyataan if kecil mungkin tidak akan mengubah apa pun (Anda hanya melewatkan beberapa byte, sehingga Anda masih akan berakhir di dalam wilayah cache), tetapi pemanggilan fungsi biasanya menyiratkan bahwa Anda melompat ke yang benar-benar berbeda alamat yang mungkin tidak di-cache. Kecuali jika itu disebut baru-baru ini.
Instruksi penggunaan cache biasanya jauh dari masalah. Apa yang biasanya perlu Anda khawatirkan adalah data cache.
Dalam sebuah struct atau kelas, semua anggota diletakkan secara bersebelahan, yang bagus. Dalam sebuah array, semua entri ditata secara bersamaan. Dalam daftar tertaut, setiap node dialokasikan di lokasi yang sama sekali berbeda, yang buruk. Pointer secara umum cenderung mengarah ke alamat yang tidak terkait, yang mungkin akan menghasilkan cache yang hilang jika Anda merujuknya.
Dan jika Anda ingin mengeksploitasi banyak core, itu bisa menjadi sangat menarik, seperti biasanya, hanya satu CPU yang mungkin memiliki alamat yang diberikan dalam cache L1 pada suatu waktu. Jadi jika kedua core secara konstan mengakses alamat yang sama, itu akan mengakibatkan cache yang terus-menerus hilang, karena mereka berebut alamat.