Bazel มีความซับซ้อนและทำสิ่งต่างๆ มากมายในระหว่างการบิลด์ ซึ่งบางอย่างอาจส่งผลต่อประสิทธิภาพการบิลด์ หน้านี้พยายามเชื่อมโยงแนวคิดบางอย่างของ Bazel กับผลกระทบต่อประสิทธิภาพการบิลด์ แม้จะไม่ครอบคลุมทั้งหมด แต่เราได้รวมตัวอย่างวิธีตรวจหาปัญหาด้านประสิทธิภาพการบิลด์ผ่านการแยกเมตริกและสิ่งที่คุณทำได้เพื่อแก้ไขปัญหา เราหวังว่าคุณจะนำแนวคิดเหล่านี้ไปใช้ได้เมื่อตรวจสอบการถดถอยของประสิทธิภาพการบิลด์
การบิลด์แบบ Clean กับแบบ Incremental
การบิลด์แบบ Clean คือการบิลด์ทุกอย่างตั้งแต่ต้น ส่วนการบิลด์แบบ Incremental จะใช้ซ้ำงานที่ทำเสร็จแล้ว
เราขอแนะนำให้ดูการบิลด์แบบ Clean และแบบ Incremental แยกกัน โดยเฉพาะอย่างยิ่งเมื่อ คุณรวบรวม / รวมเมตริกที่ขึ้นอยู่กับสถานะของ แคชของ Bazel (เช่น เมตริกขนาดคำขอบิลด์) นอกจากนี้ การบิลด์ทั้ง 2 แบบยังแสดงถึงประสบการณ์ของผู้ใช้ที่แตกต่างกันด้วย การบิลด์แบบ Incremental เกิดขึ้นบ่อยกว่ามากเมื่อนักพัฒนาซอฟต์แวร์ทำการวนซ้ำในโค้ด (โดยปกติจะเร็วกว่าเนื่องจากแคชมักจะพร้อมใช้งานอยู่แล้ว) เมื่อเทียบกับการเริ่มต้นการบิลด์แบบ Clean ตั้งแต่ต้น (ซึ่งใช้เวลานานกว่าเนื่องจากแคชยังไม่พร้อมใช้งาน)
คุณสามารถใช้ช่อง CumulativeMetrics.num_analyses ใน BEP เพื่อจัดประเภทการบิลด์ หาก num_analyses <= 1 แสดงว่าเป็นการบิลด์แบบ Clean แต่หากไม่เป็นเช่นนั้น เราจะจัดประเภทการบิลด์นั้นเป็นการบิลด์แบบ Incremental โดยทั่วไป ซึ่งผู้ใช้อาจเปลี่ยนไปใช้แฟล็กหรือเป้าหมายอื่นที่ทำให้เกิดการบิลด์แบบ Clean คำจำกัดความที่เข้มงวดมากขึ้นของการบิลด์แบบ Incremental น่าจะอยู่ในรูปแบบของฮิวริสติก เช่น การดูจำนวนแพ็กเกจที่โหลด (PackageMetrics.packages_loaded)
เมตริกการบิลด์เชิงกำหนดเป็นตัวแทนของประสิทธิภาพการบิลด์
การวัดประสิทธิภาพการบิลด์อาจทำได้ยากเนื่องจากเมตริกบางอย่างมีลักษณะแบบ Non-Deterministic (เช่น เวลา CPU ของ Bazel หรือเวลาคิวในคลัสเตอร์ระยะไกล) ดังนั้น การใช้เมตริกแบบเชิงกำหนดเป็นตัวแทนของปริมาณงานที่ Bazel ทำจึงอาจเป็นประโยชน์ ซึ่งจะส่งผลต่อประสิทธิภาพของ Bazel
ขนาดของคำขอบิลด์อาจส่งผลอย่างมากต่อประสิทธิภาพการบิลด์ การบิลด์ขนาดใหญ่อาจแสดงถึงงานที่มากขึ้นในการวิเคราะห์และสร้างกราฟการบิลด์ การเติบโตแบบออร์แกนิกของการบิลด์เกิดขึ้นตามธรรมชาติพร้อมกับการพัฒนา เนื่องจากมีการเพิ่ม/สร้างการขึ้นต่อกันมากขึ้น จึงมีความซับซ้อนมากขึ้นและใช้ค่าใช้จ่ายในการบิลด์มากขึ้น
เราสามารถแบ่งปัญหานี้ออกเป็นระยะต่างๆ ของการบิลด์ และใช้เมตริกต่อไปนี้เป็นเมตริกตัวแทนสำหรับงานที่ทำในแต่ละระยะ
PackageMetrics.packages_loaded: จำนวนแพ็กเกจที่โหลดสำเร็จ การถดถอยในส่วนนี้แสดงถึงงานที่ต้องทำมากขึ้นในการอ่านและแยกวิเคราะห์ไฟล์ BUILD เพิ่มเติมแต่ละไฟล์ในระยะการโหลดTargetMetrics.targets_configured: แสดงจำนวนเป้าหมายและแง่มุมที่กำหนดค่าในการบิลด์ การเกิดปัญหาซ้ำแสดงถึงงานที่มากขึ้นในการสร้างและข้ามผ่านกราฟเป้าหมายที่กำหนดค่า- ซึ่งมักเกิดจากการเพิ่มการขึ้นต่อกันและต้องสร้างกราฟการปิดทรานซิทีฟของการขึ้นต่อกันเหล่านั้น
- ใช้ cquery เพื่อดูว่ามีการเพิ่มการขึ้นต่อกันใหม่ที่ใด
ActionSummary.actions_created: แสดงการดำเนินการที่สร้างขึ้นในการบิลด์ และการเกิดปัญหาซ้ำแสดงถึงงานที่มากขึ้นในการสร้างกราฟการดำเนินการ โปรดทราบว่าการดำเนินการนี้ยังรวมถึงการดำเนินการที่ไม่ได้ใช้ซึ่งอาจไม่ได้ดำเนินการ- ใช้ aquery เพื่อแก้ไขข้อบกพร่องของการถดถอย
เราขอแนะนำให้เริ่มต้นด้วย
--output=summaryก่อนที่จะเจาะลึกลงไปอีกด้วย--skyframe_state
- ใช้ aquery เพื่อแก้ไขข้อบกพร่องของการถดถอย
เราขอแนะนำให้เริ่มต้นด้วย
ActionSummary.actions_executed: จำนวนการดำเนินการที่ดำเนินการ การเกิดปัญหาซ้ำแสดงถึงงานที่มากขึ้นในการดำเนินการเหล่านี้โดยตรง- BEP จะเขียนสถิติการดำเนินการ
ActionDataที่แสดงประเภทการดำเนินการที่ดำเนินการมากที่สุด โดยค่าเริ่มต้น ระบบจะรวบรวมประเภทการดำเนินการ 20 อันดับแรก แต่คุณสามารถส่ง--experimental_record_metrics_for_all_mnemonicsเพื่อรวบรวมข้อมูลนี้สำหรับประเภทการดำเนินการทั้งหมดที่ดำเนินการ - ซึ่งจะช่วยให้คุณทราบว่ามีการดำเนินการประเภทใด (เพิ่มเติม)
- BEP จะเขียนสถิติการดำเนินการ
BuildGraphSummary.outputArtifactCount: จำนวนอาร์ติแฟกต์ที่สร้างขึ้นโดยการดำเนินการที่ดำเนินการ- หากจำนวนการดำเนินการที่ดำเนินการไม่เพิ่มขึ้น แสดงว่ามีการเปลี่ยนแปลงการใช้งานกฎ
เมตริกเหล่านี้ทั้งหมดได้รับผลกระทบจากสถานะของแคชในเครื่อง ดังนั้นคุณจึงต้องตรวจสอบว่าการบิลด์ที่คุณแยกเมตริกเหล่านี้ออกมาเป็นการบิลด์แบบ Clean
เราสังเกตว่าการถดถอยในเมตริกเหล่านี้อาจมาพร้อมกับการถดถอยในเวลาจริง เวลา CPU และการใช้งานหน่วยความจำ
การใช้ทรัพยากรในเครื่อง
Bazel ใช้ทรัพยากรต่างๆ ในเครื่องของคุณ (ทั้งสำหรับการวิเคราะห์กราฟการบิลด์และการขับเคลื่อนการดำเนินการ รวมถึงสำหรับการดำเนินการในเครื่อง) ซึ่งอาจส่งผลต่อประสิทธิภาพ / ความพร้อมใช้งานของเครื่องในการดำเนินการบิลด์ รวมถึงงานอื่นๆ
เวลาที่ใช้
เมตริกที่อาจได้รับผลกระทบจากสัญญาณรบกวนมากที่สุด (และอาจแตกต่างกันอย่างมากจากการบิลด์หนึ่งไปยังอีกการบิลด์หนึ่ง) คือเวลา โดยเฉพาะเวลาจริง เวลา CPU และเวลาของระบบ คุณสามารถ ใช้ bazel-bench เพื่อรับ การเปรียบเทียบสำหรับเมตริกเหล่านี้ และใช้ --runs จำนวนมากพอเพื่อเพิ่มนัยสำคัญทางสถิติของการวัด
เวลาจริง คือเวลาที่ผ่านไปในโลกจริง
- หากเวลาจริง เท่านั้น ที่ถดถอย เราขอแนะนำให้รวบรวม โปรไฟล์การติดตาม JSON และดู ความแตกต่าง มิฉะนั้น การตรวจสอบเมตริกอื่นๆ ที่ถดถอยน่าจะมีประสิทธิภาพมากกว่า เนื่องจากเมตริกเหล่านั้นอาจส่งผลต่อเวลาจริง
เวลา CPU คือเวลาที่ CPU ใช้ในการดำเนินการโค้ดของผู้ใช้
- หากเวลา CPU ถดถอยในการคอมมิตโปรเจ็กต์ 2 รายการ เราขอแนะนำให้รวบรวมโปรไฟล์ CPU ของ Starlark นอกจากนี้ คุณควรใช้
--nobuildเพื่อจำกัดการบิลด์ไว้ที่ระยะการวิเคราะห์ เนื่องจากเป็นระยะที่มีการทำงานที่ใช้ CPU มากที่สุด
- หากเวลา CPU ถดถอยในการคอมมิตโปรเจ็กต์ 2 รายการ เราขอแนะนำให้รวบรวมโปรไฟล์ CPU ของ Starlark นอกจากนี้ คุณควรใช้
เวลาของระบบคือเวลาที่ CPU ใช้ในเคอร์เนล
- หากเวลาของระบบถดถอย มักจะสัมพันธ์กับ I/O เมื่อ Bazel อ่านไฟล์จากระบบไฟล์ของคุณ
การสร้างโปรไฟล์การโหลดทั้งระบบ
แฟล็ก
--experimental_collect_load_average_in_profiler
ที่เปิดตัวใน Bazel 6.0 ช่วยให้โปรไฟล์การติดตาม JSONรวบรวมค่าเฉลี่ยการโหลดของ
ระบบระหว่างการเรียกใช้

รูปที่ 1 โปรไฟล์ที่มีค่าเฉลี่ยการโหลดของระบบ
การโหลดสูงระหว่างการเรียกใช้ Bazel อาจบ่งชี้ว่า Bazel กำหนดเวลาการดำเนินการในเครื่องมากเกินไปพร้อมกันสำหรับเครื่องของคุณ คุณอาจต้องพิจารณา
ปรับ
--local_cpu_resources
และ
--local_ram_resources,
โดยเฉพาะในสภาพแวดล้อมคอนเทนเนอร์ (อย่างน้อยจนกว่าจะมีการผสาน
#16512)
การตรวจสอบการใช้งานหน่วยความจำของ Bazel
คุณสามารถดูการใช้งานหน่วยความจำของ Bazel ได้จาก 2 แหล่งหลัก ได้แก่ Bazel info และ
BEP
bazel info used-heap-size-after-gc: ปริมาณหน่วยความจำที่ใช้เป็นไบต์หลังจากเรียกSystem.gc()- bazel bench ยังมีการเปรียบเทียบ สำหรับเมตริกนี้ด้วย
- นอกจากนี้ ยังมี
peak-heap-size,max-heap-size,used-heap-sizeและcommitted-heap-size(ดู เอกสารประกอบ), แต่มีความเกี่ยวข้องน้อยกว่า
BEP
MemoryMetrics.peak_post_gc_heap_sizeของ: ขนาดฮีป JVM สูงสุดเป็นไบต์หลัง GC (ต้องตั้งค่า--memory_profileที่พยายามบังคับให้ทำ GC แบบเต็ม)
การถดถอยในการใช้งานหน่วยความจำมักเกิดจากการถดถอยในเมตริกขนาดคำขอบิลด์ ซึ่งมักเกิดจากการเพิ่มทรัพยากร Dependency หรือการเปลี่ยนแปลงการใช้งานกฎ
การสร้างโปรไฟล์หน่วยความจำของผู้ปฏิบัติงานแบบถาวร
แม้ว่าผู้ปฏิบัติงานแบบถาวรจะช่วยเร่งการบิลด์ได้อย่างมาก (โดยเฉพาะภาษาที่ตีความ) แต่การใช้หน่วยความจำอาจเป็นปัญหาได้ Bazel จะรวบรวมเมตริกเกี่ยวกับผู้ปฏิบัติงาน โดยเฉพาะช่อง WorkerMetrics.WorkerStats.worker_memory_in_kb จะบอกปริมาณหน่วยความจำที่ผู้ปฏิบัติงานใช้ (ตามคำช่วยจำ)
โปรไฟล์การติดตาม JSON
โปรไฟล์ยังรวบรวม
การใช้งานหน่วยความจำของผู้ปฏิบัติงานแบบถาวรระหว่างการเรียกใช้ด้วยการส่งแฟล็ก
--experimental_collect_system_network_usage (ใหม่ใน Bazel 6.0)

รูปที่ 2 โปรไฟล์ที่มีการใช้งานหน่วยความจำของผู้ปฏิบัติงาน
การลดค่า
--worker_max_instances
(ค่าเริ่มต้นคือ 4) อาจช่วยลดปริมาณหน่วยความจำที่ผู้ปฏิบัติงานแบบถาวรใช้
เรากำลังดำเนินการอย่างเต็มที่เพื่อทำให้ตัวจัดการทรัพยากรและตัวกำหนดเวลาของ Bazel มีประสิทธิภาพมากขึ้น เพื่อให้คุณไม่จำเป็นต้องปรับแต่งอย่างละเอียดเช่นนี้บ่อยนักในอนาคต
การตรวจสอบการจราจรของข้อมูลในเครือข่ายสำหรับการบิลด์ระยะไกล
ในการดำเนินการระยะไกล Bazel จะดาวน์โหลดอาร์ติแฟกต์ที่สร้างขึ้นจากการดำเนินการ ดังนั้น แบนด์วิดท์ของเครือข่ายจึงอาจส่งผลต่อประสิทธิภาพการบิลด์
หากคุณใช้การดำเนินการระยะไกลสำหรับการบิลด์ คุณอาจต้องพิจารณาตรวจสอบการจราจรของข้อมูลในเครือข่ายระหว่างการเรียกใช้โดยใช้NetworkMetrics.SystemNetworkStats โปรโตจากBEP (ต้องส่ง--experimental_collect_system_network_usage)
นอกจากนี้ โปรไฟล์การติดตาม JSONยังช่วยให้คุณ
ดูการใช้งานเครือข่ายทั้งระบบตลอดระยะเวลาการบิลด์ได้ด้วยการส่งแฟล็ก
--experimental_collect_system_network_usage (ใหม่ใน Bazel
6.0)

รูปที่ 3 โปรไฟล์ที่มีการใช้งานเครือข่ายทั้งระบบ
การใช้งานเครือข่ายสูงแต่ค่อนข้างคงที่เมื่อใช้การดำเนินการระยะไกลอาจบ่งชี้ว่าเครือข่ายเป็นจุดคอขวดในการบิลด์ หากยังไม่ได้ใช้ ให้ลองเปิดใช้การบิลด์โดยไม่ใช้ไบต์ด้วยการส่ง--remote_download_minimal
ซึ่งจะช่วยเร่งการบิลด์โดยหลีกเลี่ยงการดาวน์โหลดอาร์ติแฟกต์ระดับกลางที่ไม่จำเป็น
อีกตัวเลือกหนึ่งคือการกำหนดค่าแคชดิสก์ในเครื่องเพื่อประหยัดแบนด์วิดท์ในการดาวน์โหลด