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

Báo cáo vấn đề Xem nguồn Nightly · 8.0 . 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel rất phức tạp và thực hiện nhiều việc trong quá trình tạo bản dựng, một số việc có thể ảnh hưởng đến hiệu suất bản dựng. Trang này cố gắng liên kết một số khái niệm Bazel này với những tác động của chúng đối với hiệu suất bản dựng. Mặc dù không có nhiều, nhưng chúng tôi đã đưa ra một số ví dụ về cách phát hiện vấn đề về hiệu suất của bản dựng thông qua việc trích xuất chỉ số và những việc bạn có thể làm để khắc phục vấn đề. Với những thông tin 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 sự hồi quy về hiệu suất bản dựng.

Bản dựng sạch so với bản dựng tăng dần

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

Bạn nên xem xét riêng các bản dựng sạch và bản dựng tăng dần, đặc biệt là khi bạn 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 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 đại diện cho 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 (mất nhiều thời gian hơn do bộ nhớ đệm nguội), các bản dựng gia tăng xảy ra thường xuyên hơn nhiều khi các 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 bản dựng. Nếu là num_analyses <= 1, thì đó 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à bản dựng gia tăng – người dùng có thể đã chuyển sang các cờ hoặc mục tiêu khác nhau dẫn đến bản dựng sạch hiệu quả. Mọi định nghĩa nghiêm ngặt hơn về tính gia tăng có thể sẽ phải ở dạng phỏng đoán, ví dụ: xem xét số lượng gói đã tải (PackageMetrics.packages_loaded).

Chỉ số bản dựng xác định là chỉ số đại diện cho hiệu suất bản dựng

Việc đo lường hiệu suất bản dựng có thể gặp khó khăn do bản chất không xác định của một số chỉ số nhất định (ví dụ: thời gian CPU hoặc thời gian xếp hàng của Bazel trên một cụm từ xa). Do đó, bạn có thể sử dụng các chỉ số xác định để thay thế cho lượng công việc mà Bazel thực hiện, từ đó ả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 bản dựng. Một bản dựng lớn hơn có thể đại diện cho nhiều công việc hơn trong việc phân tích và tạo biểu đồ bản dựng. Sự phát triển tự nhiên của các bản dựng đi kèm với quá trình phát triển, vì nhiều phần phụ thuộc được thêm/tạo, do đó, độ phức tạp tăng lên và chi phí xây dựng trở nên đắt đỏ 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ông việc đã thực hiện ở mỗi giai đoạn:

  1. PackageMetrics.packages_loaded: số lượng gói đã tải thành công. Một hồi quy ở đây thể hiện nhiều công việc cần làm hơn để đọ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 closure bắc cầu của chúng.
    • Sử dụng query / cquery để tìm nơi có thể đã thêm các phần phụ thuộc mới.
  2. TargetMetrics.targets_configured: biểu thị số lượng mục tiêu và khía cạnh được định cấu hình trong bản dựng. Phương pháp hồi quy thể hiện nhiều công việc hơn trong việc tạo và duyệt qua biểu đồ mục tiêu đã định cấu hình.

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

  4. ActionSummary.actions_executed: số hành động đượ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 việc thực thi các hành động này.

    • BEP ghi ra số liệu thống kê về hành động ActionData cho biết các loại hành động được thực thi nhiều nhất. Theo mặc định, tính năng này thu thập 20 loại hành động hàng đầu, nhưng bạn có thể truyề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 hành động đã được thực thi.
    • Điều này sẽ giúp bạn tìm hiểu loại hành động nào đã được thực thi (bổ sung).
  5. BuildGraphSummary.outputArtifactCount: số lượng cấu phần phần mềm do các hành động đã thực thi tạo ra.

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

Các chỉ số này đều chịu ảnh hưởng của trạng thái bộ nhớ đệm cục bộ, do đó, bạn nên đả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à các bản dựng sạch.

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

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

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

Thời gian đã đi

Có lẽ chỉ số dễ bị nhiễu nhất (và có thể thay đổi đáng kể giữa các bản dựng) là thời gian; cụ thể là thời gian thực, 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ố lượng --runs đủ lớn, bạn có thể tăng mức độ ý nghĩa thống kê của phép đo.

  • Thời gian thực là thời gian thực tế đã trôi qua.

    • Nếu chỉ thời gian thực tế bị hồi quy, bạn nên thu thập hồ sơ theo dõi JSON và tìm sự khác biệt. Nếu không, 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 thực.
  • Thời gian CPU là thời gian CPU thực thi mã của người dùng.

    • Nếu thời gian CPU hồi quy trên hai lần cam kết dự án, bạn nên thu thập hồ sơ CPU Starlark. 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 tác vụ nặng của CPU.
  • Thời gian hệ thống là thời gian CPU dành cho hạt nhân.

    • Nếu thời gian hệ thống hồi quy, thì thời gian này chủ yếu liên quan đến I/O khi Bazel đọc cá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 tài nguyên theo dõi JSON sẽ thu thập mức tải hệ thống trung bình trong quá trình gọi.

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

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

Mứ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 thao tác cục bộ song song cho máy của bạn. 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 để biết mức sử dụng bộ nhớ của Bazel, đó là Bazel infoBEP.

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

    • Bazel bench cũng cung cấp đ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 đỉnh điểm tính bằng byte sau GC (yêu cầu đặt --memory_profile để cố gắng buộc GC đầy đủ).

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

Để phân tích mức sử dụng bộ nhớ của Bazel ở cấp độ 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.

Phân tích bộ nhớ của worker liên tục

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

Trình phân tích tài nguyên theo dõi JSON cũng thu thập mức sử dụng bộ nhớ của worker ổn định trong quá trì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 mức sử dụng bộ nhớ của worker

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

Việc giảm giá trị của --worker_max_instances (mặc định là 4) có thể giúp giảm dung lượng bộ nhớ mà worker liên tục sử dụng. Chúng tôi đang tích cực nỗ lực để làm cho 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, nhờ đó, trong tương lai, bạn sẽ ít phải điều chỉnh chi tiết như vậy hơn.

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 tạo ra do thực thi các thao tác. 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 tính năng thực thi từ xa cho các bản dựng, bạn nên cân nhắc việc giám sát lưu lượng truy cập mạng trong quá trì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 truyền cờ --experimental_collect_system_network_usage (mới trong Bazel 6.0).

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

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

Mức sử dụng mạng cao nhưng khá ổn định 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; nếu bạn chưa sử dụng tính năng này, hãy cân nhắc bật tính năng Tạo mà không cần Byte bằng cách truyền --remote_download_minimal. Điều này sẽ giúp tăng tốc 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.

Một cách 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.