Bazel มีความซับซ้อนและทําสิ่งต่างๆ มากมายตลอดระยะเวลาของบิลด์ ซึ่งบางครั้งอาจมีผลต่อประสิทธิภาพของบิลด์ หน้านี้จะพยายามจับคู่แนวคิดของ Bazel เหล่านี้บางส่วนกับผลกระทบของประสิทธิภาพการสร้าง แม้ว่าเราจะไม่ได้ครอบคลุมมากเท่าไร แต่ เราได้เพิ่มตัวอย่างวิธีการตรวจหาปัญหาด้านประสิทธิภาพของบิลด์ไว้ด้วยการดึงเมตริก และสิ่งที่คุณสามารถทําได้เพื่อแก้ไข เราหวังว่าคุณจะนําแนวคิดเหล่านี้ไปใช้เมื่อตรวจสอบการถดถอยของประสิทธิภาพ
บิลด์ที่สะอาดเทียบกับส่วนเพิ่ม
บิลด์ที่สะอาดคือบิลด์ที่สร้างทุกอย่างใหม่ตั้งแต่ต้น ส่วนบิลด์ที่เพิ่มขึ้นจะนํางานที่เสร็จสมบูรณ์แล้วมาใช้ซ้ํา
เราขอแนะนําให้ดูบิลด์ที่สะอาดและเพิ่มขึ้นแยกกัน โดยเฉพาะเมื่อคุณกําลังรวบรวม / รวบรวมเมตริกที่อ้างอิงสถานะแคชของ Bazel (เช่น เมตริกการสร้างคําขอขนาด) และยังแสดงถึงประสบการณ์ของผู้ใช้ที่แตกต่างกัน 2 รายการด้วย เมื่อเทียบกับการเริ่มบิลด์ใหม่ตั้งแต่ต้น (ซึ่งใช้เวลานานกว่านั้นเนื่องจากแคช Cold) บิลด์ที่เพิ่มขึ้นจะค่อยๆ เกิดขึ้นบ่อยกว่าเนื่องจากนักพัฒนาซอฟต์แวร์ทําซ้ําโค้ด (โดยปกติจะเร็วกว่าเนื่องจากแคชมักจะร้อนอยู่แล้ว)
คุณสามารถใช้ช่อง CumulativeMetrics.num_analyses
ใน BEP เพื่อจําแนกประเภทบิลด์ หาก num_analyses <= 1
นั่นเป็นบิลด์ที่สะอาด มิเช่นนั้น เราอาจจัดหมวดหมู่ให้ในวงกว้างว่าเป็นบิลด์ที่เพิ่มขึ้น ผู้ใช้อาจเปลี่ยนไปใช้แฟล็กอื่นหรือเป้าหมายอื่นที่ก่อให้เกิดบิลด์ที่สะอาดอย่างมีประสิทธิภาพ คําจํากัดความที่เข้มงวดขึ้นของส่วนเพิ่มใดๆ จะต้องมาในรูปแบบของฮิวริสติก เช่น การดูจํานวนแพ็กเกจที่โหลดขึ้นมา (PackageMetrics.packages_loaded
)
เมตริกการสร้างที่กําหนดเป็นพร็อกซีสําหรับประสิทธิภาพของบิลด์
การวัดประสิทธิภาพบิลด์อาจทําได้ยากเนื่องจากเมตริกบางรายการที่ไม่ได้กําหนด (เช่น เวลา CPU หรือเวลาในคิวของคลัสเตอร์บนคลัสเตอร์ระยะไกล) ดังนั้น การใช้เมตริกที่กําหนดล่วงหน้าเป็นพร็อกซีสําหรับจํานวนงานที่ Bazel ทํา ซึ่งอาจเป็นประโยชน์ต่อประสิทธิภาพ
ขนาดของคําขอสร้างอาจมีผลกระทบต่อประสิทธิภาพการสร้างอย่างมาก การสร้างบิลด์ขนาดใหญ่ขึ้นอาจวิเคราะห์งานและสร้างกราฟบิวด์ได้มากขึ้น การเติบโตที่เกิดขึ้นเองตามธรรมชาติของบิลด์จะมาพร้อมกับการพัฒนา เนื่องจากระบบจะเพิ่ม/สร้างทรัพยากร Dependency มากขึ้น จึงทําให้เกิดความซับซ้อนขึ้นและมีค่าใช้จ่ายสูงในการสร้าง
เราอาจแบ่งปัญหานี้ออกเป็นหลายช่วงของบิลด์ และใช้เมตริกต่อไปนี้เป็นเมตริกพร็อกซีสําหรับงานแต่ละช่วง
PackageMetrics.packages_loaded
: จํานวนแพ็กเกจที่โหลดสําเร็จ การถดถอยที่นี่หมายถึงงานที่ต้องดําเนินการเพิ่มเติมเพื่อที่จะอ่านและแยกวิเคราะห์ไฟล์ BUILD แต่ละรายการเพิ่มเติมในขั้นตอนการโหลดTargetMetrics.targets_configured
: แสดงจํานวนเป้าหมายและมุมมองที่กําหนดค่าไว้ในบิลด์ การถดถอยแสดงถึงงานที่มากขึ้น ในการสร้างและข้ามกราฟเป้าหมายที่กําหนดค่า- ปัญหานี้มักเกิดจากการขึ้นต่อกันและต้องสร้างกราฟการปิดชั่วคราว
- ใช้ cquery เพื่อหาจุดที่เพิ่มทรัพยากร Dependency ใหม่ลงไป
ActionSummary.actions_created
: แสดงถึงการดําเนินการที่สร้างขึ้นในบิลด์ และการถดถอยแสดงถึงงานที่มากขึ้นในการสร้างกราฟการดําเนินการ โปรดทราบว่าการดําเนินการนี้รวมถึงการดําเนินการที่ไม่ได้ใช้ซึ่งอาจไม่ได้ดําเนินการ- ใช้ aquery เพื่อดูการถดถอย
ActionSummary.actions_executed
: จํานวนการดําเนินการที่เกิดขึ้น การเกิดปัญหาซ้ําแสดงถึงการดําเนินการเพิ่มเติมโดยตรงในการดําเนินการเหล่านี้- BEP เขียนสถิติการดําเนินการ
ActionData
ซึ่งแสดงประเภทการดําเนินการที่มีการดําเนินการมากที่สุด โดยค่าเริ่มต้น ระบบจะรวบรวมการดําเนินการ 20 ประเภทแรก แต่คุณสามารถส่งใน--experimental_record_metrics_for_all_mnemonics
เพื่อรวบรวมข้อมูลนี้สําหรับการดําเนินการทุกประเภท - ซึ่งจะช่วยให้คุณทราบประเภทการดําเนินการ (เพิ่มเติม)
- BEP เขียนสถิติการดําเนินการ
BuildGraphSummary.outputArtifactCount
: จํานวนอาร์ติแฟกต์ที่สร้างโดยการดําเนินการที่เรียกใช้- หากจํานวนการดําเนินการไม่ได้เพิ่มขึ้น อาจเป็นเพราะมีการเปลี่ยนแปลงการใช้กฎ
เมตริกเหล่านี้ได้รับผลกระทบจากสถานะของแคชในเครื่อง คุณจึงต้องตรวจสอบว่าบิลด์ที่คุณแยกเมตริกเหล่านี้เป็นบิลด์สะอาด
เราพบว่าการถดถอยในเมตริกเหล่านี้สามารถใช้ร่วมกับการถดถอยในเวลาที่เกิดผนัง เวลา CPU และหน่วยความจํา
การใช้ทรัพยากรในเครื่อง
Bazel ใช้ทรัพยากรที่หลากหลายในเครื่องของคุณ (ทั้งสําหรับการวิเคราะห์กราฟบิวด์และการกระตุ้นการดําเนินการ และการเรียกใช้การกระทําภายในเครื่อง) ซึ่งอาจส่งผลต่อประสิทธิภาพ / ความพร้อมใช้งานของเครื่องของคุณในบิลด์และงานอื่นๆ
เวลาที่ใช้
บางทีเมตริกที่มีแนวโน้มที่จะเป็นสัญญาณรบกวนมากที่สุด (และอาจต่างกันไปมากตั้งแต่สร้างไปจนถึงสร้าง) คือเวลา โดยเฉพาะเวลาติดผนัง เวลา CPU และเวลาของระบบ คุณใช้ bazel-carousel เพื่อดูการเปรียบเทียบของเมตริกเหล่านี้ได้ และด้วยจํานวน --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 carousel มีการเปรียบเทียบสําหรับเมตริกนี้ด้วย
- นอกจากนี้ยังมี
peak-heap-size
,max-heap-size
,used-heap-size
และcommitted-heap-size
(ดูเอกสารประกอบ) แต่มีความเกี่ยวข้องน้อย
BEP
MemoryMetrics.peak_post_gc_heap_size
: ขนาดของฮีป 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
จาก BEP (ต้องผ่าน --experimental_collect_system_network_usage
)
นอกจากนี้ โปรไฟล์การติดตาม JSON ยังให้คุณดูการใช้งานเครือข่ายทั่วทั้งระบบได้ทั่วทั้งบิลด์ด้วยการส่งแฟล็ก --experimental_collect_system_network_usage
(ใหม่ใน Bazel
6.0)
รูปที่ 3 โปรไฟล์ที่รวมการใช้งานเครือข่ายทั่วทั้งระบบ
การใช้งานเครือข่ายที่สูงแต่ค่อนข้างแบนเมื่อใช้การดําเนินการระยะไกลอาจบ่งชี้ว่าเครือข่ายเป็นจุดคอขวดในบิลด์ของคุณ หากคุณไม่ได้ใช้งาน ให้พิจารณาเปิดบิลด์ที่ไม่มีไบต์โดยส่ง --remote_download_minimal
การดําเนินการนี้จะช่วยลดความเร็วในการสร้างโดยหลีกเลี่ยงการดาวน์โหลดอาร์ติแฟกต์ระดับกลางที่ไม่จําเป็น
อีกตัวเลือกหนึ่งคือการกําหนดค่าแคชดิสก์ในเครื่องเพื่อประหยัดแบนด์วิดท์การดาวน์โหลด