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

Báo cáo vấn đề Xem nguồn Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Bazel rất phức tạp và thực hiện nhiều việc khác nhau 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 tác động của chúng đến hiệu suất bản dựng. Mặc dù không đầy đủ, nhưng chúng tôi đã đưa ra 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 việc trích xuất các chỉ số và những việc bạn có thể làm để khắc phục cá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ự sụt giảm hiệu suất bản dựng.

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

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

Bạn nên xem xét các bản dựng sạch và gia tăng riêng biệt, đặ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 Bazel (ví dụ: chỉ số về kích thước yêu cầu bản dựng). Chúng 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 (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 nhà phát triển lặp lại mã (thường nhanh hơn vì bộ nhớ đệm thường đã được khởi động).

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, 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 là bản dựng gia tăng – người dùng có thể đã chuyển sang các cờ khác hoặc các mục tiêu khác, dẫn đến một bản dựng sạch hiệu quả. Mọi định nghĩa chặt chẽ hơn về mức tăng có thể sẽ phải ở dạng một phương pháp phỏng đoán, chẳng hạn như xem xét số lượng gói đã tải (PackageMetrics.packages_loaded).

Các chỉ số bản dựng xác định trước làm 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ố (ví dụ: thời gian CPU của Bazel hoặc thời gian chờ trong 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 chỉ số đại diện 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 một yêu cầu tạo bản dựng có thể ảnh hưởng đáng kể đến hiệu suất tạo bản dựng. Bản dựng lớn hơn có thể biểu thị nhiều công việc hơn trong việc phân tích và xây dựng biểu đồ bản dựng. Sự tăng trưởng tự nhiên của các bản dựng sẽ diễn ra trong quá trình phát triển, khi có thêm các phần phụ thuộc được thêm/tạo, do đó, độ phức tạp sẽ tăng lên và chi phí xây dựng cũng tăng theo.

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 đây làm chỉ số proxy cho công việc đượ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 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 bao đóng bắc cầu của chúng.
    • Sử dụng query / cquery để tìm vị trí 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. Một 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 đồ về bao đóng của chúng.
    • 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: biểu thị các thao tác được tạo trong bản dựng và một hồi quy biểu thị nhiều công việc hơn trong việc tạo biểu đồ thao tác. Lưu ý rằng điều này cũng bao gồm cả những thao tác chưa dùng đến và có thể chưa được thực hiện.

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

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

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

Tất cả 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 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à 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 đều 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à điều khiển 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 của máy trong quá trình thực hiện bản dựng và các tác vụ khác.

Thời gian đã đi

Có lẽ chỉ số dễ bị ảnh hưởng nhất bởi nhiễu (và có thể thay đổi đáng kể từ bản dựng này sang bản dựng khác) 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 để nhận điểm chuẩn cho các chỉ số này. Với đủ số lượng --runs, bạn có thể tăng ý nghĩa thống kê của phép đo.

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

    • Nếu chỉ thời gian thực giảm, bạn nên thu thập hồ sơ theo dõi JSON và tìm kiếm sự khác biệt. Nếu không, bạn nên điều tra các chỉ số giảm sút 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 dành cho việc thực thi mã người dùng.

    • Nếu thời gian CPU giảm trên hai lần xác nhận 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ì đây là nơi hầu hết công việc nặng về CPU được thực hiện.
  • Thời gian hệ thống là thời gian CPU dành cho nhân.

    • Nếu thời gian hệ thống giảm, thì điều này thường tương quan với 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

Khi 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 JSON sẽ thu thập mức tải trung bình của hệ thống trong quá trì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 mức tải trung bình của hệ thống.

Tải cao trong quá trì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 có thể muố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ớ của Bazel

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

  • bazel info used-heap-size-after-gc: Lượng bộ nhớ đã dùng tính bằng byte sau khi gọi 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.
  • BEP của MemoryMetrics.peak_post_gc_heap_size: Kích thước của kích thước vùng nhớ xếp JVM cao nhất tính bằng byte sau khi GC (yêu cầu thiết lập --memory_profile để cố gắng buộc GC đầy đủ).

Mức sử dụng bộ nhớ giảm thường là do mức giảm trong các chỉ số về kích thước yêu cầu bản dựng. Mức giảm này thường là do việc bổ sung 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 ở mức chi tiết hơn, bạn nên dùng trình phân tích bộ nhớ tích hợp cho các quy tắc.

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

Mặc dù persistent workers có thể giúp tăng tốc đáng kể 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 chúng 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 từ viết tắt).

Trình phân tích tài nguyên 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 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 các worker

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

Việc giảm giá trị của --worker_max_instances (mặc định là 4) có thể giúp giảm lượng bộ nhớ mà các worker liên tục sử dụng. Chúng tôi đang tích cực làm việc để cải thiện trình quản lý tài nguyên và trình lập lịch của Bazel sao cho thông minh hơn để bạn ít phải điều chỉnh như vậy trong tương lai.

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 do thực thi các thao tác xuống. 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 có thể 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 giao thức NetworkMetrics.SystemNetworkStats từ BEP (cần truyền --experimental_collect_system_network_usage).

Ngoài ra, hồ sơ dấu vết 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 tạo 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 thấy mạng là nút thắt trong bản dựng của bạn; nếu bạn chưa sử dụng, 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 xuống.

Một lựa 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.