Jika aplikasi lambat tapi tidak jelas bagian mana, flame graph adalah alat diagnosa terbaik. Satu gambar langsung menunjukkan function mana yang menghabiskan paling banyak waktu CPU.
Cara baca flame graph:
┌──────────────────────────────────────────────┐
│ main (60ms) │
├──────────────┬───────────────────────────────┤
│ renderPage │ fetchUsers (40ms) │
│ (20ms) ├──────────┬────────────────────┤
├──────────────┤ parseJSON│ transformUsers (30)│
│ layout (15) │ (5ms) ├──────────┬─────────┤
├────┬─────────┤ │ normalize│ validate│
│ dom│ paint │ │ (15ms) │ (10ms) │
└────┴─────────┴──────────┴──────────┴─────────┘
Aturan baca:
- Lebar batang = waktu yang dihabiskan (bukan timeline; urutan horizontal hanya alfabet)
- Tumpukan vertikal = call stack (atas = fungsi yang dipanggil, bawah = caller)
- Warna = kategorisasi (bukan prioritas — biasanya random untuk kontras)
- Plateau lebar di atas = fungsi yang banyak menghabiskan waktu sendiri (bukan anak-anaknya)
Cara generate di browser:
Chrome DevTools → Performance tab → Record → interact → Stop
→ "Bottom-Up" view untuk list fungsi terberat
→ "Call Tree" view untuk flame-graph-style
→ "Flame Chart" section di bawah untuk visualisasi horizontal
Cara generate di Node.js:
# Built-in profiler
node --prof app.js
# Jalankan workload, lalu:
node --prof-process isolate-*.log > profile.txt
# Better: clinic.js
npx clinic flame -- node app.js
# hasil: flamegraph.html
# Alternative: 0x
npx 0x app.js
Yang perlu dicari:
1. Plateau lebar di bagian atas (self time tinggi)
│ calculateSomething (45ms self) │
Fungsi ini sendiri yang lambat, bukan yang dipanggilnya. Optimasi langsung di sini.
2. Stack dalam + kepala kecil (waterfall) Fungsi manggil fungsi manggil fungsi. Bukan lambat per se, tapi indikator over-engineering atau middleware chain terlalu dalam.
3. Function yang tidak diharapkan muncul
JSON.parse30ms? Mungkin parsing data besar yang tidak perlu.forEachdi runtime hot path? Cobaforloop.- Regex yang di-compile setiap panggilan?
CPU profiler vs sampling profiler:
| Jenis | Cara kerja | Akurasi | Overhead |
|---|---|---|---|
| Sampling | Snapshot stack tiap X ms | Approximate | Rendah |
| Instrumentation | Hook masuk/keluar fungsi | Exact | Tinggi |
Chrome DevTools pakai sampling (1ms default). Cukup akurat untuk 99% kasus.
Membedakan flame graph vs icicle chart:
- Flame graph: stack tumbuh ke ATAS (root di bawah)
- Icicle chart: stack tumbuh ke BAWAH (root di atas)
Chrome DevTools pakai icicle (root di atas). Brendan Gregg's original flame graph root di bawah. Sama konsep, hanya orientasi.
Kesalahan interpretasi umum:
❌ "Function paling lebar pasti bottleneck" — bisa jadi lebar karena banyak panggilan (total time), tapi self time kecil.
✅ Selalu cek self time vs total time. Self time tinggi = fungsi ini lambat. Total time tinggi tapi self time rendah = fungsi ini hanya delegate ke fungsi lain.
Workflow optimasi tipikal:
- Reproduce slow scenario dengan ukuran data realistik
- Record profile
- Identifikasi top 3 fungsi dengan self time tertinggi
- Optimasi yang paling tinggi (hukum Amdahl: fokus ke yang paling berat)
- Re-record untuk verify improvement
- Ulangi jika masih lambat
Jangan optimasi tanpa profil! Intuisi developer sering salah tentang bagian mana yang lambat.