Bazel นั้นซับซ้อนและทำสิ่งต่างๆ ได้มากมายตลอดการสร้าง ซึ่งบางอย่างอาจส่งผลต่อประสิทธิภาพการสร้างได้ หน้านี้จะพยายามจับคู่แนวคิดบางอย่างของ Bazel กับผลกระทบต่อประสิทธิภาพการสร้าง แม้จะไม่ได้ครอบคลุมเนื้อหามากมาย เราได้รวบรวมตัวอย่างบางส่วนของวิธีตรวจหาปัญหาด้านประสิทธิภาพของบิลด์ผ่านการดึงข้อมูลเมตริกและสิ่งที่คุณทำได้เพื่อแก้ไขปัญหา เราหวังว่าคุณจะนำแนวคิดเหล่านี้ไปใช้ เมื่อตรวจสอบการถดถอยของประสิทธิภาพ
บิลด์แบบสะอาดกับบิลด์แบบเพิ่ม
บิลด์ที่สะอาดคือบิลด์ที่สร้างทุกอย่างตั้งแต่ต้น ส่วนบิลด์แบบเพิ่มจะนํางานที่ทำเสร็จแล้วบางส่วนมาใช้ซ้ำ
เราขอแนะนำให้ดูบิลด์ที่สะอาดและบิลด์ที่เพิ่มเข้ามาแยกกัน โดยเฉพาะเมื่อคุณรวบรวม / รวบรวมเมตริกที่ขึ้นอยู่กับสถานะของแคชของ Bazel (เช่น เมตริกขนาดคำขอบิลด์) นอกจากนี้ บิลด์เหล่านี้ยังแสดงถึงประสบการณ์การใช้งานที่แตกต่างกัน 2 แบบ เมื่อเทียบกับการเริ่มสร้างบิลด์ใหม่ตั้งแต่ต้น (ซึ่งใช้เวลานานกว่าเนื่องจากแคช Cold) การสร้างแบบส่วนเพิ่มจะเกิดขึ้นบ่อยกว่ามากเมื่อนักพัฒนาซอฟต์แวร์ดำเนินการโค้ดซ้ำๆ (โดยปกติจะเร็วกว่าเนื่องจากแคชร้อนอยู่แล้ว)
คุณสามารถใช้ช่อง CumulativeMetrics.num_analyses
ใน BEP เพื่อจัดประเภทบิลด์ได้ หากเป็น num_analyses <= 1
แสดงว่าเป็นบิลด์ที่สะอาด หากไม่ใช่ เราอาจจัดหมวดหมู่อย่างคร่าวๆ ว่าน่าจะเป็นบิลด์ที่เพิ่มเข้ามา เนื่องจากผู้ใช้อาจเปลี่ยนไปใช้ Flag หรือเป้าหมายอื่นซึ่งทำให้บิลด์สะอาด คำจำกัดความที่เข้มงวดยิ่งขึ้นของการเพิ่มจำนวนมีแนวโน้มที่จะอยู่ในรูปแบบของการเฮิวริสติก เช่น การดูจำนวนแพ็กเกจที่โหลด (PackageMetrics.packages_loaded
)
เมตริกการสร้างแบบกำหนดได้เพื่อใช้แทนประสิทธิภาพการสร้าง
การวัดประสิทธิภาพการสร้างอาจเป็นเรื่องยากเนื่องจากเมตริกบางรายการมีลักษณะที่ไม่แน่นอน (เช่น เวลา CPU ของ Bazel หรือเวลาคิวในคลัสเตอร์ระยะไกล) ดังนั้นจึงอาจมีประโยชน์ในการใช้เมตริกแบบกำหนดได้เพื่อประเมินปริมาณงานที่ Bazel ดำเนินการ ซึ่งจะส่งผลต่อประสิทธิภาพของ Bazel
ขนาดของคําขอสร้างอาจส่งผลต่อประสิทธิภาพการสร้างอย่างมาก บิลด์ที่ใหญ่ขึ้นอาจแสดงให้เห็นถึงงานที่มากขึ้นในการวิเคราะห์และสร้างกราฟบิลด์ การเติบโตแบบออร์แกนิกของบิลด์มาพร้อมกับการพัฒนาตามธรรมชาติ เมื่อมีการเพิ่ม/สร้างทรัพยากร Dependency มากขึ้น จึงมีความซับซ้อนมากขึ้นและมีค่าใช้จ่ายในการสร้างมากขึ้น
เราแบ่งปัญหานี้ออกเป็นระยะต่างๆ ของการสร้างได้ และใช้เมตริกต่อไปนี้เป็นเมตริกพร็อกซีสําหรับงานที่ทําในแต่ละระยะ
PackageMetrics.packages_loaded
: จํานวนแพ็กเกจที่โหลดสําเร็จ การถดถอยที่นี่แสดงถึงงานเพิ่มเติมที่ต้องทำเพื่ออ่านและแยกวิเคราะห์ไฟล์ BUILD เพิ่มเติมแต่ละไฟล์ในระยะการโหลดTargetMetrics.targets_configured
: แสดงจำนวนเป้าหมายและมุมมองที่กำหนดค่าไว้ในบิลด์ การถดถอยแสดงถึงงานเพิ่มเติมในการสร้างและเรียกดูกราฟเป้าหมายที่กําหนดค่าไว้- ซึ่งมักเกิดจากการเพิ่มการพึ่งพาและต้องสร้างกราฟของ Closure แบบทรานซิทีฟ
- ใช้ 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
: จํานวนรายการต่างๆ ที่สร้างขึ้นจากการดำเนินการที่ดำเนินการ- หากจํานวนการดําเนินการที่ดำเนินการไม่ได้เพิ่มขึ้น แสดงว่าอาจมีการเปลี่ยนแปลงการใช้งานกฎ
เมตริกเหล่านี้ทั้งหมดได้รับผลกระทบจากสถานะของแคชในเครื่อง คุณจึงต้องตรวจสอบว่าบิลด์ที่คุณดึงข้อมูลเมตริกเหล่านี้ออกมาเป็นบิลด์ที่สะอาด
เราพบว่าการถดถอยของเมตริกเหล่านี้อาจมาพร้อมกับการถดถอยของเวลาจริง เวลาที่ใช้ 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
แหล่งที่มาหลักๆ 2 แห่งสําหรับดูการใช้งานหน่วยความจําของ Bazel ได้แก่ 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
(ดูเอกสารประกอบ) แต่มีความเกี่ยวข้องน้อยกว่า
MemoryMetrics.peak_post_gc_heap_size
ของ BEP: ขนาดของฮีป JVM สูงสุดเป็นไบต์หลัง GC (กำหนดการตั้งค่า--memory_profile
ที่พยายามบังคับให้ GC แบบสมบูรณ์)
การใช้งานหน่วยความจําที่ลดลงมักจะเป็นผลมาจากเมตริกขนาดคําขอบิลด์ที่ลดลง ซึ่งมักเกิดจากการเพิ่มข้อกําหนดหรือการเปลี่ยนแปลงการใช้งานกฎ
หากต้องการวิเคราะห์พื้นที่หน่วยความจำของ Bazel ในรายละเอียดยิ่งขึ้น เราขอแนะนำให้ใช้เครื่องมือวิเคราะห์หน่วยความจำในตัวสำหรับกฎ
การสร้างโปรไฟล์หน่วยความจําของผู้ปฏิบัติงานแบบถาวร
แม้ว่าเวิร์กเกอร์แบบถาวรจะช่วยเร่งความเร็วการสร้างได้อย่างมาก (โดยเฉพาะสำหรับภาษาแบบตีความ) แต่การใช้หน่วยความจำก็อาจทำให้เกิดปัญหาได้ 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
proto จาก BEP (ต้องส่ง --experimental_collect_system_network_usage
)
นอกจากนี้ โปรไฟล์การติดตาม JSON ยังช่วยให้คุณดูการใช้งานเครือข่ายทั้งระบบตลอดกระบวนการสร้างได้ด้วยการส่ง Flag --experimental_collect_system_network_usage
(ใหม่ใน Bazel 6.0)
รูปที่ 3 โปรไฟล์ที่มีการใช้งานเครือข่ายทั้งระบบ
การใช้เครือข่ายที่สูงแต่ค่อนข้างคงที่เมื่อใช้การดําเนินการจากระยะไกลอาจบ่งชี้ว่าเครือข่ายเป็นคอขวดในการสร้าง หากยังไม่ได้ใช้ ให้ลองเปิด "สร้างโดยไม่ใช้ Bytes" โดยส่ง --remote_download_minimal
ซึ่งจะช่วยให้งานสร้างของคุณเร็วขึ้นโดยหลีกเลี่ยงการดาวน์โหลดอาร์ติแฟกต์ระดับกลางที่ไม่จำเป็น
อีกตัวเลือกหนึ่งคือการกำหนดค่าแคชดิสก์ในเครื่องเพื่อประหยัดแบนด์วิดท์การดาวน์โหลด