Dân làm System hay Dev chắc không lạ gì cảnh server bỗng dưng nhảy vọt lên 100% CPU. Mở top hay htop, bạn thấy process đang ngốn tài nguyên. Nhưng câu hỏi cốt lõi là: Cụ thể hàm (function) nào trong code đang chạy chậm? Lúc này, top hoàn toàn bất lực.
Đây là lúc perf thực hiện vai trò của mình. Là công cụ tích hợp sẵn trong nhân Linux, perf cho phép soi tận lõi ứng dụng mà không làm gián đoạn hệ thống. Bài viết này mình sẽ hướng dẫn cách “bắt bệnh” hiệu năng, từ lệnh terminal đến biểu đồ Flame Graph trực quan.
Cài đặt perf trong một nốt nhạc
Để bắt đầu, bạn cần gói linux-tools tương ứng với phiên bản kernel đang chạy. Cài đặt khá đơn giản trên các distro phổ biến.
# Trên Ubuntu/Debian
sudo apt update
sudo apt install linux-tools-common linux-tools-generic linux-tools-$(uname -r)
# Trên RHEL/CentOS/AlmaLinux
sudo yum install perf
Sau khi cài, hãy chạy thử một lệnh record hệ thống trong 5 giây để kiểm tra:
sudo perf record -a -g sleep 5
Trong lệnh này, -a dùng để lấy mẫu trên mọi CPU và -g để lưu lại call-graph. Kết quả lưu tại file perf.data. Muốn xem ngay kết quả dạng text, bạn chỉ cần gõ:
sudo perf report
Giao diện dòng lệnh sẽ hiện ra. Bạn có thể nhấn Enter vào từng dòng để xem chi tiết hàm nào đang chiếm bao nhiêu % CPU.
Cơ chế sampling: Bí mật đằng sau tốc độ của perf
Khác với strace thường làm chậm ứng dụng tới 20-30%, perf hoạt động dựa trên cơ chế lấy mẫu (sampling). Cứ mỗi khoảng thời gian cực ngắn, nó sẽ “chụp ảnh” CPU một lần. Cách làm này giúp overhead cực thấp, thường chỉ dưới 1%.
Mình từng xử lý một ca khó trên server chạy Java. App bị nghẽn cổ chai nhưng top chỉ báo chung chung. Khi dùng perf, mình phát hiện một thư viện JSON cũ đang thực hiện quá nhiều thao tác thừa. Sau khi nâng cấp thư viện và tối ưu lại, CPU load giảm từ 85% xuống còn 20%, giúp công ty tiết kiệm đáng kể chi phí hạ tầng.
Trực quan hóa dữ liệu với Flame Graph
Đọc text trên terminal khá mệt nếu ứng dụng có hàng nghìn hàm gọi nhau. Flame Graph (biểu đồ lửa) giúp biến các con số khô khan thành hình ảnh trực quan. Nhìn vào biểu đồ, bạn sẽ thấy ngay “đám cháy” nằm ở đâu.
Bước 1: Thu thập dữ liệu cho một process cụ thể
Giả sử bạn muốn soi process có PID là 1234 trong 30 giây:
sudo perf record -F 99 -p 1234 -g -- sleep 30
Lưu ý: -F 99 nghĩa là lấy mẫu 99 lần/giây. Con số 99 giúp tránh trùng nhịp với các timer hệ thống thường chạy ở tần số tròn như 100Hz.
Bước 2: Chuẩn bị công cụ vẽ biểu đồ
Chúng ta sử dụng bộ script của Brendan Gregg, chuyên gia hiệu năng hàng đầu tại Netflix:
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
Bước 3: Xuất file SVG
Dùng chuỗi lệnh sau để chuyển dữ liệu thô thành biểu đồ có thể tương tác:
# Parse dữ liệu sang dạng text
sudo perf script > out.perf
# Gom nhóm các stack trace
./stackcollapse-perf.pl out.perf > out.folded
# Vẽ Flame Graph
./flamegraph.pl out.folded > performance_map.svg
Bây giờ, hãy mở file performance_map.svg bằng Chrome hoặc Firefox để xem kết quả.
Đọc Flame Graph như một chuyên gia
Đừng để màu sắc đánh lừa, quy tắc đọc biểu đồ này rất nhất quán:
- Trục X (Ngang): Độ rộng của thanh tương ứng với tổng thời gian CPU. Thanh càng rộng, hàm đó càng tốn tài nguyên.
- Trục Y (Dọc): Hiển thị Call Stack (hàm mẹ gọi hàm con). Càng lên cao, stack càng sâu.
- Cao nguyên (Plateaus): Hãy tìm những thanh dài nằm ở trên cùng. Đó chính là những hàm đang trực tiếp tiêu thụ CPU nhiều nhất.
Những lưu ý quan trọng để không “ăn hành”
Dùng perf rất hiệu quả nhưng cần lưu ý 3 điểm sau để dữ liệu chính xác:
- Debug Symbols: Khi biên dịch code C++ hay Go, bạn phải thêm flag
-g. Nếu không,perfchỉ hiển thị các địa chỉ Hex vô nghĩa thay vì tên hàm. - Tần suất lấy mẫu: Đừng tham đặt
-Fquá cao trên server đang quá tải. Mức 99Hz hoặc 997Hz là điểm cân bằng lý tưởng giữa độ chi tiết và an toàn. - Frame Pointer: Một số compiler hiện đại sẽ bỏ qua frame pointer để tối ưu. Nếu Flame Graph trông vụn vặt và thiếu logic, hãy thử biên dịch lại với flag
-fno-omit-frame-pointer.
Tóm lại, perf và Flame Graph là bộ đôi “vũ khí” cực kỳ lợi hại mà bất kỳ kỹ sư Linux nào cũng nên trang bị trong túi đồ nghề của mình. Thay vì đoán mò, hãy dùng dữ liệu để tối ưu code một cách khoa học. Chúc bạn sớm tìm ra những dòng code đang âm thầm ngốn tài nguyên của mình!
