Phân tích hiệu suất bản dựng

Báo cáo sự cố Xem nguồn

Bazel phức tạp và làm được nhiều việc trong quá trình xây dựng, một số tác vụ có thể ảnh hưởng đến hiệu suất của bản dựng. Trang này sẽ cố gắng liên kết một số khái niệm Bazel này với các hệ quả của chúng về hiệu suất bản dựng. Mặc dù không rộng, chúng tôi đã đưa vào một số ví dụ về cách phát hiện các vấn đề về hiệu suất bản dựng thông qua chỉ số trích xuất và những việc bạn có thể làm để khắc phục vấn đề. Bằng cách này, chúng tôi hy vọng bạn có thể áp dụng các khái niệm này khi điều tra hồi quy hiệu suất của bản dựng.

Bản dựng sạch và bản dựng tăng dần

Bản dựng sạch là một bản dựng xây dựng mọi thứ từ đầu, trong khi một bản dựng tăng dần sử dụng lại một số công việc đã hoàn thành.

Bạn nên tách riêng các bản dựng sạch và tăng dần, đặc biệt là khi bạn đang thu thập / tổng hợp các chỉ số phụ thuộc vào trạng thái của bộ nhớ đệm của Bazel (ví dụ: chỉ số kích thước yêu cầu bản dựng). Các bản dựng này cũng thể hiện hai trải nghiệm người dùng khác nhau. So với việc bắt đầu một bản dựng sạch từ đầu (kéo dài hơn do bộ nhớ đệm nguội), các bản dựng tăng dần xảy ra thường xuyên hơn khi nhà phát triển lặp lại mã (thường nhanh hơn vì bộ nhớ đệm thường đã ấm).

Bạn có thể sử dụng trường CumulativeMetrics.num_analyses trong BEP để phân loại các bản dựng. Nếu num_analyses <= 1 là bản dựng sạch; nếu không, chúng ta có thể phân loại rộng rãi bản dựng đó có thể là một bản dựng tăng dần – người dùng có thể đã chuyển sang các cờ hoặc mục tiêu khác nhau tạo ra một bản dựng sạch hiệu quả. Mọi định nghĩa nghiêm ngặt hơn về mức độ gia tăng có thể sẽ phải tồn tại dưới dạng phương pháp phỏng đoán, chẳng hạn như xem xét số lượng gói được tải (PackageMetrics.packages_loaded).

Xác định các chỉ số bản dựng làm proxy cho hiệu suất của bản dựng

Việc đo lường hiệu suất bản dựng có thể khó khăn do tính chất không xác định của một số chỉ số nhất định (ví dụ: thời gian CPU của Bazel hoặc thời gian hàng đợi trên một cụm từ xa). Do đó, bạn nên sử dụng các chỉ số xác định làm proxy cho lượng công việc do Bazel thực hiện, và điều này sẽ ảnh hưởng đến hiệu suất của Bazel.

Kích thước của yêu cầu bản dựng có thể ảnh hưởng đáng kể đến hiệu suất của bản dựng. Bản dựng lớn hơn có thể đại diện cho nhiều công việc phân tích và xây dựng biểu đồ bản dựng hơn. Sự phát triển tự nhiên của các bản dựng thường phát triển tự nhiên, khi có nhiều phần phụ thuộc được thêm/tạo hơn, do đó độ phức tạp tăng lên và việc xây dựng sẽ trở nên tốn kém hơn.

Chúng ta có thể chia vấn đề này thành nhiều giai đoạn xây dựng và sử dụng các chỉ số sau làm chỉ số proxy cho các công việc đã thực hiện ở mỗi giai đoạn:

  1. PackageMetrics.packages_loaded: số gói đã tải thành công. Hồi quy ở đây thể hiện nhiều việc hơn cần làm để đọc và phân tích cú pháp từng tệp BUILD bổ sung trong giai đoạn tải.

    • Điều này thường là do việc thêm các phần phụ thuộc và phải tải các lệnh đóng bắc cầu.
    • Sử dụng query / cquery để tìm vị trí có thể đã thêm phần phụ thuộc mới.
  2. TargetMetrics.targets_configured: biểu thị số lượng mục tiêu và các khía cạnh được định cấu hình trong bản dựng. Hồi quy thể hiện nhiều công việc hơn trong việc xây dựng và truyền tải biểu đồ mục tiêu đã được định cấu hình.

    • Điều này thường xảy ra do các phần phụ thuộc được bổ sung và phải tạo biểu đồ trạng thái đóng bắc cầu.
    • Sử dụng cquery để tìm vị trí có thể đã thêm các phần phụ thuộc mới.
  3. ActionSummary.actions_created: đại diện cho các hành động được tạo trong bản dựng, và hồi quy thể hiện nhiều công việc hơn trong việc tạo biểu đồ hành động. Xin lưu ý rằng mã này cũng bao gồm các thao tác không sử dụng có thể chưa được thực thi.

  4. ActionSummary.actions_executed: số lượng thao tác được thực thi, một hồi quy trực tiếp thể hiện nhiều công việc hơn trong quá trình thực thi các thao tác này.

    • BEP viết ra số liệu thống kê về hành động ActionData cho biết những loại hành động được thực thi nhiều nhất. Theo mặc định, công cụ này sẽ thu thập 20 loại thao tác hàng đầu, nhưng bạn có thể chuyển vào --experimental_record_metrics_for_all_mnemonics để thu thập dữ liệu này cho tất cả các loại thao tác đã được thực thi.
    • Điều này sẽ giúp bạn tìm ra loại hành động nào đã được thực thi (bổ sung).
  5. BuildGraphSummary.outputArtifactCount: số cấu phần phần mềm được tạo bởi các hành động đã thực thi.

    • Nếu số lượng hành động được thực thi không tăng, thì có thể cách triển khai một quy tắc đã thay đổi.

Các chỉ số này đều bị ảnh hưởng bởi trạng thái của bộ nhớ đệm cục bộ. Do đó, bạn phải đảm bảo rằng các bản dựng mà bạn trích xuất các chỉ số này là bản dựng sạch.

Chúng tôi nhận thấy rằng sự hồi quy ở bất kỳ chỉ số nào trong số này đều có thể đi kèm với sự hồi quy về thời gian bức tường, thời gian CPU và mức sử dụng bộ nhớ.

Sử dụng tài nguyên cục bộ

Bazel tiêu thụ nhiều tài nguyên trên máy cục bộ (cả để phân tích biểu đồ bản dựng lẫn điều khiển quá trình thực thi, cũng như để chạy các hành động cục bộ), điều này có thể ảnh hưởng đến hiệu suất / khả năng hoạt động của máy trong việc thực hiện bản dựng, cũng như các tác vụ khác.

Thời gian đã đi

Có thể những chỉ số dễ bị nhiễu nhất (và có thể khác nhau rất nhiều giữa các bản dựng) là thời gian; cụ thể là - thời gian tạo tường, thời gian CPU và thời gian hệ thống. Bạn có thể sử dụng bazel-bench để lấy điểm chuẩn cho các chỉ số này và với đủ số --runs, bạn có thể tăng mức ý nghĩa thống kê cho kết quả đo lường của mình.

  • Thời gian quảng cáo là thời gian thực trong thế giới đã trôi qua.

    • Nếu chỉ hồi quy theo thời gian cố định, bạn nên thu thập hồ sơ theo dõi JSON và tìm kiếm các điểm khác biệt. Nếu không, tốt hơn là bạn nên điều tra các chỉ số hồi quy khác vì chúng có thể ảnh hưởng đến thời gian của tường.
  • Thời gian CPU là thời gian mà CPU thực thi mã người dùng.

    • Nếu thời gian CPU hồi quy trên hai thay đổi dự án, bạn nên thu thập cấu hình CPU Starlark. Có thể bạn cũng nên sử dụng --nobuild để hạn chế bản dựng ở giai đoạn phân tích vì đó là nơi thực hiện hầu hết các công việc phức tạp về CPU.
  • Thời gian hệ thống là thời gian mà CPU dành cho nhân.

    • Nếu hồi quy thời gian hệ thống chủ yếu tương quan với I/O khi Bazel đọc tệp từ hệ thống tệp của bạn.

Lập hồ sơ tải trên toàn hệ thống

Bằng cách sử dụng cờ --experimental_collect_load_average_in_profiler được giới thiệu trong Bazel 6.0, trình phân tích theo dõi JSON sẽ thu thập mức trung bình tải hệ thống trong lệnh gọi.

Hồ sơ bao gồm mức tải trung bình của hệ thống

Hình 1. Hồ sơ bao gồm giá trị trung bình của các lần tải hệ thống.

Việc tải cao trong lệnh gọi Bazel có thể là dấu hiệu cho thấy Bazel đã lên lịch quá nhiều hành động cục bộ song song cho máy. Bạn nên xem xét việc điều chỉnh --local_cpu_resources--local_ram_resources, đặc biệt là trong môi trường vùng chứa (ít nhất là cho đến khi #16512 được hợp nhất).

Giám sát mức sử dụng bộ nhớ Bazel

Có hai nguồn chính để sử dụng bộ nhớ của Bazel, Bazel infoBEP.

  • bazel info used-heap-size-after-gc: Dung lượng bộ nhớ đã sử dụng tính bằng byte sau khi gọi System.gc().

    • Bazel bench cũng cung cấp các điểm chuẩn cho chỉ số này.
    • Ngoài ra, còn có peak-heap-size, max-heap-size, used-heap-sizecommitted-heap-size (xem tài liệu), nhưng ít liên quan hơn.
  • MemoryMetrics.peak_post_gc_heap_size của BEP: Kích thước của vùng nhớ khối xếp JVM tối đa trong các byte sau khi GC (yêu cầu đặt --memory_profile cố gắng buộc GC đầy đủ).

Hồi quy về mức sử dụng bộ nhớ thường là kết quả của sự hồi quy trong chỉ số kích thước yêu cầu bản dựng, thường là do có các phần phụ thuộc hoặc sự thay đổi trong cách triển khai quy tắc.

Để phân tích dấu vết bộ nhớ của Bazel ở mức độ chi tiết hơn, bạn nên sử dụng trình phân tích bộ nhớ tích hợp sẵn cho các quy tắc.

Lập hồ sơ bộ nhớ của trình chạy cố định

Mặc dù nhân viên bền vững có thể giúp tăng tốc đáng kể các bản dựng (đặc biệt là đối với những ngôn ngữ được diễn giải), nhưng dấu vết bộ nhớ của họ có thể gặp sự cố. Bazel thu thập các chỉ số về trình chạy, đặc biệt là trường WorkerMetrics.WorkerStats.worker_memory_in_kb, cho biết lượng công việc của bộ nhớ sử dụng (theo bộ nhớ).

Trình phân tích dấu vết JSON cũng thu thập mức sử dụng bộ nhớ của worker liên tục trong lệnh gọi bằng cách truyền cờ --experimental_collect_system_network_usage (mới trong Bazel 6.0).

Hồ sơ bao gồm cả mức sử dụng bộ nhớ của worker

Hình 2. Hồ sơ bao gồm cả mức sử dụng bộ nhớ của worker.

Việc giảm giá trị của --worker_max_instances (mặc định 4) có thể giúp giảm mức sử dụng bộ nhớ của trình chạy cố định. Chúng tôi đang tích cực làm việc để giúp trình quản lý tài nguyên và trình lập lịch biểu của Bazel trở nên thông minh hơn để sau này, chúng tôi sẽ ít phải điều chỉnh hơn nữa.

Giám sát lưu lượng truy cập mạng cho các bản dựng từ xa

Trong quá trình thực thi từ xa, Bazel sẽ tải các cấu phần phần mềm được xây dựng lên nhờ các quá trình thực thi. Do đó, băng thông mạng có thể ảnh hưởng đến hiệu suất của bản dựng.

Nếu đang sử dụng phương thức thực thi từ xa cho bản dựng, bạn nên xem xét việc theo dõi lưu lượng truy cập mạng trong lệnh gọi bằng cách sử dụng proto NetworkMetrics.SystemNetworkStats từ BEP (yêu cầu truyền --experimental_collect_system_network_usage).

Hơn nữa, hồ sơ theo dõi JSON cho phép bạn xem mức sử dụng mạng trên toàn hệ thống trong suốt quá trình xây dựng bằng cách chuyển cờ --experimental_collect_system_network_usage (mới trong Bazel 6.0).

Hồ sơ bao gồm cả mức sử dụng mạng trên toàn hệ thống

Hình 3. Hồ sơ bao gồm cả mức sử dụng mạng trên toàn hệ thống.

Việc sử dụng mạng cao nhưng khá phẳng khi sử dụng tính năng thực thi từ xa có thể cho biết rằng mạng là nút thắt cổ chai trong bản dựng của bạn; nếu bạn chưa sử dụng tính năng này, hãy cân nhắc bật Bản dựng không có Byte bằng cách chuyển --remote_download_minimal. Điều này sẽ tăng tốc độ cho bản dựng bằng cách tránh tải các cấu phần phần mềm trung gian không cần thiết xuống.

Một tuỳ chọn khác là định cấu hình bộ nhớ đệm trên đĩa cục bộ để tiết kiệm băng thông tải xuống.