Profiling Go Program với Pprof và các gói Trace

Cải thiện hiệu quả của các chương trình Go bằng kỹ thuật profiling đơn giản. Dưới đây là cách profiling Go Program bằng Pprof và các gói Trace.

Profiling chương trình Go

Profiling là một kỹ thuật thường được dùng trong chu kỳ phát triển phần mềm để phân tích hiệu quả của 1 chương trình, thường để so sánh sự khác biệt giữa các chương trình hoặc xác định vấn đề gây trì trệ và các vùng cần cải tiến. Profiling liên quan tới việc đo và phân tích nhiều chỉ số như mức sử dụng bộ nhớ, sử dụng CPU, thời gian chạy và các chỉ số cấp hệ thống khác.

Profiling nhằm xác định các phần “ngốn” tài nguyên trong một chương trình để có thể tối ưu hóa nó cho hiệu suất tốt hơn. Profiling cũng giúp gỡ lỗi, tối ưu hóa quản lý bộ nhớ và điều chỉnh đồng thời.

Profiling trong Go

Bạn có nhiều công cụ để profiling trong Go. Một số công cụ phổ biến khác bao gồm công cụ profiling pprof có sẵn trong Go và các gói bên thứ ba phổ biến như Go Tool Trace và gói Go-Torch.

Gói pprof là một phần của runtime. Gói pprof cung cấp chức năng ghi dữ liệu profiling chạy ở định dạng mà công cụ trực quan hóa pprof có thể diễn giải.

Dưới đây là cách bạn có thể nhập gói pprof vào chương trình Go:

import "pprof"

Go cung cấp một số lệnh và flag để hoạt động với mã nguồn. Chạy lệnh tool sau để truy cập các kết quả profiling ở định dạng khác nhau.

go tool pprof

Lệnh này xuất chi tiết cách dùng về lệnh pprof.

Kết quả khi dùng lệnh pprof

CPU Profiling trong Go

CPU profiling đo thời gian một chương trình dùng trong khi chạy các chức năng. CPU profiling hữu ích trong việc nhận dạng các phần code “ngốn” CPU nhất.

Gói pprof cung cấp các hàm để thu thập profile CPU, bắt đầu và dừng CPU profiling và một hàm để ghi dữ liệu profile vào file.

Dưới đây là cách bắt đầu và dừng một CPU profile, viết dữ liệu vào một file profiling:

import (
    "os"
    "runtime/pprof"
)

func main() {
    f, err := os.Create("cpu_profile.prof")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    err = pprof.StartCPUProfile(f)
    if err != nil {
        panic(err)
    }
    defer pprof.StopCPUProfile()

    // code to be profiled
}

Hàm main tạo một file và đóng file stream với một lệnh defer & hàm Close của phiên bản tệp. Hàm StartCPUProfile khởi động cấu hình CPU và ghi dữ liệu vào tệp. StopCPUProfile đóng luồng cấu hình bằng câu lệnh defer. Sau khi khởi động và dừng cấu hình CPU, bạn có thể tiếp tục viết mã muốn phân tích.

Đây là kết quả của lệnh pprof với file profile từ chương trình này:

Kết quả sau khi dùng lệnh pprof

Chạy lệnh pprof với file bắt đầu một shell tương tác mà cho phép bạn khám phá dữ liệu profiling. Bạn có thể dùng các lệnh như top list để xem các hàm mất nhiều thời gian chạy nhất.

Profiling bộ nhớ trong Go

Profiling bộ nhớ là một kỹ thuật được dùng để xác định sự cố rò rỉ và sử dụng quá nhiều bộ nhớ trong code bằng cách đo mức độ sử dụng memory trong code.

Bạn có thể bắt đầu tạo một cấu hình bộ nhớ bằng hàm WriteHeapProfile. Hàm này lấy phiên bản file và ghi dữ liệu cấu hình vào tập tin.

import (
    "os"
    "runtime/pprof"
)

func main() {
    f, err := os.Create("mem_profile.prof")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    err = pprof.WriteHeapProfile(f)
    if err != nil {
        panic(err)
    }

    // code to be profiled
}

Hàm main tạo một file profiling. Hàm WriteHeapProfile lấy phiên bản tệp làm đối số và trả về một kiểu lỗi viết sau khi ghi file.

Block profiling với Go

Block profiling đo thời gian đợi của một chương trình cho quá trình đồng bộ hóa như bộ chuyển đổi và kênh. Block profiling hữu ích trong việc nhận diện các phần code gây ra sự cố chặn.

Hàm Lookup trả về profile với tên của một chuỗi cụ thể. Hàm WriteGo của Lookup viết một snapshot định dạng pprof của cấu hình đó cho file.

Đây là cách bạn có thể triển khai block profiling cho chương trình Go:

import (
    "os"
    "runtime/pprof"
)

func main() {
    f, err := os.Create("block_profile.prof")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    err = pprof.Lookup("block").WriteTo(f, 0)
    if err != nil {
        panic(err)
    }

    // code to be profiled
}

Hàm này tạo một file lưu dữ liệu block profile, tìm các block bằng hàm Lookup và viết dữ liệu block profile cho tập tin đó.

Trace Profiling với Go

Trace Profiling là một kỹ thuật để đo việc thực thi chương trình, bao gồm lập lịch goroutine và các cuộc gọi hệ thống. Trace Profiling rất hữu ích để xác định các khu vực bị “tắc nghẽn”, đồng thời, hiểu được sự tương tác giữa các phần chương trình khác nhau.

Gói trace cung cấp các hàm cho trace profiling. Gói này cũng là một phần của gói runtime.

import (
    "os"
    "runtime/trace"
)

func main() {
    f, err := os.Create("trace.out")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    err = trace.Start(f)
    if err != nil {
        panic(err)
    }
    defer trace.Stop()

    // code to be profiled
}

Chương trình này tạo một file trace để lưu trữ dữ liệu theo dõi, khởi động một trình theo dõi bằng hàm Start lấy phiên bản tệp và trả về một kiểu lỗi, đồng thời trì hoãn trình theo dõi bằng hàm Stop.

Trên đây là cách profiling chương trình Go. Hi vọng bài viết hữu ích với các bạn.

Thứ Bảy, 11/03/2023 10:19
51 👨 402
0 Bình luận
Sắp xếp theo