DEV Community

Faiyaz Rahman
Faiyaz Rahman

Posted on

Cache Hit মানেই — কম effort, বেশি Performance!

লুপে হাজার হাজার ডাটা প্রসেস করার সময় অথবা বড় সাইজের array নিয়ে কাজ করার সময় CPU কিভাবে RAM থেকে ডাটা fetch করে সেটা আমাদের জানা খুব গুরুত্বপূর্ণ।

ধরেন আমরা একটা array (int64) নিয়ে কাজ করতেছি যার length 10k অথবা আরো বেশি। তো আমরা যখন arr[0] দিয়ে array এর first element এক্সেস করতে যাবো, আমাদের CPU তখন RAM থেকে শুধু arr[0] fetch করবে না বরং ওই element এর আশেপাশে 64 byte সমতুল্য ডাটা ফেচ করে এনে CPU তে cache করে রেখে দিবে। যেন আমাদের বার বার RAM থেকে read করতে না হয়। Going to the RAM will cost us 100 nanoseconds every time 😛 ।

তো যেহেতু আমাদের ওই array এর 64 byte সমতুল্য ডাটা CPU তে cache করে রাখা আছে, আমার কোড যখন arr[0] থেকে arr[7] এর মধ্যে কোনো এলিমেন্ট এক্সেস করবে তখন সেটা cache এর মধ্যেই পেয়ে যাবে এবং মাত্র 4 nanoseconds এর মধ্যে এক্সেস করে ফেলবে। CPU তে এরকম ৩ লেয়ার cache থাকে L1, L2, L3।

শুধু memory layout ঠিক মতো সাজিয়ে Google একবার Linux TCP stack এর পারফরমেন্স ৪০% বুস্ট করেছিল। struct এর যেসব প্রপার্টি বেশি use হয় সেগুলো সামনে এনেছে আর কম used প্রপার্টিগুলো পিছনের দিকে দিয়েছে, যার ফলে সহজেই CPU cache hit হয়েছে এবং ডাটা পেয়ে গিয়েছে। কোনো কোডে হাত না দিয়েই ৪০% পারফরমেন্স বুস্ট ভাবা যায়?

JavaScript এ traditional array বা object গুলোর memory layout predictable এবং contiguous হয় না। তবে আমরা TypedArray (যেমন Int32Array, Float64Array) ব্যবহার করলে সেটা মেমোরিতে contiguous হয় এবং কিছুটা cache optimization সম্ভব।

কিন্তু Go তে আবার এই CPU cache optimization খুব ভালোভাবেই করা যায়। যদি আমরা struct design করার সময় বেশি ব্যবহার হওয়া ফিল্ডগুলোকে পাশাপাশি রাখি, তাহলে এগুলো একসাথে cache line-এ চলে আসবে। ফলে sequential access বা loop-এর সময় cache hit বেশি হবে, এবং performance gain পাওয়া যাবে।

Go-এর মতো compiled language-এ (যেমন C, Rust) struct ডিজাইন করার সময় আমরা field ordering এবং cache locality মাথায় রেখে struct সাজাতে পারি, যার মাধ্যমে performance gain পাওয়া যায়। কিন্তু JavaScript বা Python-এর মতো interpreted language-এ memory layout আমাদের নিয়ন্ত্রণে থাকে না, তাই সেখানে এই ধরনের low-level optimization সম্ভব না।

type BadStruct struct {
    A int8   // 1 byte
    B int64  // 8 bytes (but alignment requires it to start at 8-byte boundary)
    C int8   // again, padding needed
}

// Better struct layout
type GoodStruct struct {
    B int64  // 8 bytes
    A int8   // 1 byte
    C int8   // 1 byte
}
Enter fullscreen mode Exit fullscreen mode

Hope it Helps! :)

Top comments (0)