Flame Graphs & CPU Profiling — Debugging

Jika aplikasi lambat tapi tidak jelas bagian mana, flame graph adalah alat diagnosa terbaik. Satu gambar langsung menunjukkan function mana yang menghabiskan…

CPU profile adalah rekaman function mana yang sedang dikerjakan CPU, dan berapa lama. Flame graph menggambarnya: tiap function jadi satu batang, lebarnya adalah waktu, dan batang yang bertumpuk menunjukkan siapa memanggil siapa. Bayangin laporan jam kerja satu tim. Manajer tercatat 100 jam karena semua kerjaan timnya dihitung di bawah namanya, padahal dia sendiri cuma kerja 5 jam. Mau proyeknya cepat selesai? Bantu orang yang jam kerjanya sendiri paling banyak, bukan yang namanya paling atas di laporan.

🧪 Tebakan cepat: Di profil halaman yang lambat, batang paling lebar adalah main, 100 ms. Kalau kode di dalam main sendiri kamu bikin dua kali lebih cepat, halamannya jadi lebih cepat berapa ms? Jawabannya ada di bagian "Self time dan total time".

Merekam profil di Chrome DevTools

  1. Buka DevTools, pilih panel Performance.
  2. Klik tombol Record, lakukan hal yang terasa lambat (klik tombol, scroll, muat data), lalu klik Stop.
  3. Di track Main muncul flame chart. Di panel bawahnya ada tab Summary, Bottom-up, Call tree, dan Event log.

Profiler ini bekerja dengan sampling: berkali-kali tiap detik, dia mencatat function apa yang sedang jalan beserta pemanggilnya. Angkanya perkiraan yang sangat dekat, cukup untuk menemukan bagian yang lambat.

Cara baca flame chart

Ini profil yang dipakai di Lab dan di latihan. Halamannya butuh 100 ms:

Batang Dipanggil oleh Mulai Selesai Lebar
main 0 ms 100 ms 100 ms
renderPage main 2 ms 62 ms 60 ms
parseJSON renderPage 4 ms 34 ms 30 ms
compile parseJSON 20 ms 25 ms 5 ms
loadAsset renderPage 38 ms 58 ms 20 ms
compile main 64 ms 99 ms 35 ms

Self time dan total time

Tab Bottom-up menyusunnya per function:

Function Total time Self time
main 100 ms 5 ms
renderPage 60 ms 10 ms
compile 40 ms 40 ms
parseJSON 30 ms 25 ms
loadAsset 20 ms 20 ms

Jadi kode main sendiri cuma 5 ms. Dibikin dua kali lebih cepat pun cuma hemat 2,5 ms: 100 ms jadi 97,5 ms. Itu jawaban tebakannya.

Optimasi yang paling berat dulu

Hukum Amdahl bilang: percepatan total dibatasi oleh seberapa besar bagian yang kamu percepat. Function yang cuma memakai 5% waktu, dibikin instan pun cuma menghemat 5%.

Dipercepat 2x Self time Hemat Profil jadi
compile 40 ms 20 ms 80 ms
parseJSON 25 ms 12,5 ms 87,5 ms
renderPage 10 ms 5 ms 95 ms
main 5 ms 2,5 ms 97,5 ms

renderPage punya total time 60 ms, tapi mempercepat kodenya sendiri cuma hemat 5 ms. Target pertama adalah self time tertinggi: compile, 40% dari seluruh waktu. Alurnya: rekam, cari self time tertinggi, perbaiki satu, lalu rekam ulang untuk membuktikan hasilnya.

Menganalisis profil dengan kode

Di latihan, profil Bottom-up tadi jadi array, dan kamu menulis empat function untuk membacanya:

const profile = [
  { name: "main", totalMs: 100, selfMs: 5 },
  { name: "renderPage", totalMs: 60, selfMs: 10 },
  { name: "parseJSON", totalMs: 30, selfMs: 25 },
  { name: "compile", totalMs: 40, selfMs: 40 },
  { name: "loadAsset", totalMs: 20, selfMs: 20 },
]

function topBySelf(profile, n) {
  return [...profile]                      // salin dulu, sort mengubah array aslinya
    .sort((a, b) => b.selfMs - a.selfMs)   // terbesar dulu
    .slice(0, n)                           // ambil n teratas
    .map((f) => f.name)                    // namanya saja
}

function selfTimePercent(profile, name) {
  const fn = profile.find((f) => f.name === name)
  if (!fn) return 0
  const totalSelf = profile.reduce((sum, f) => sum + f.selfMs, 0) // 100
  return Math.round((fn.selfMs / totalSelf) * 100)
}

console.log(topBySelf(profile, 2).join(","))     // compile,parseJSON
console.log(selfTimePercent(profile, "compile")) // 40
console.log(selfTimePercent(profile, "unknown")) // 0

🤔 Flame graph, flame chart, dan sampling

⚠️ Jebakan yang sering ketemu

TL;DR: Rekam profil di panel Performance: Record, lakukan yang lambat, Stop. Di flame chart Chrome, sumbu mendatar adalah waktu, lebar batang adalah total time (termasuk function yang dipanggilnya), dan batang di bawah adalah yang dipanggil. Self time adalah waktu di kode function itu sendiri, total time dikurangi anak-anaknya, dan Bottom-up menjumlahkan function yang muncul di beberapa tempat. Hukum Amdahl: optimasi function dengan self time tertinggi dulu, karena hematnya paling besar (compile 40 ms, 40%), sedangkan main yang paling lebar cuma punya 5 ms. Di latihan: salin lalu urutkan menurun, ambil n nama, saring dengan >=, dan hitung persen dari jumlah self time dengan Math.round, dengan 0 untuk nama yang gak ada.

Yang akan kamu pelajari