แจกแจงประสิทธิภาพของบิลด์

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Bazel มีความซับซ้อนและทำสิ่งต่างๆ มากมายในระหว่างการบิลด์ ซึ่งบางอย่างอาจส่งผลต่อประสิทธิภาพการบิลด์ หน้านี้พยายามเชื่อมโยง แนวคิด Bazel บางอย่างเหล่านี้กับผลกระทบต่อประสิทธิภาพการสร้าง แม้ว่าเราจะไม่ได้อธิบายอย่างละเอียด แต่เราได้รวมตัวอย่างวิธีตรวจหาปัญหาด้านประสิทธิภาพการบิลด์ ผ่านการดึงข้อมูลเมตริก และสิ่งที่คุณทำได้เพื่อแก้ไขปัญหา เราหวังว่าคุณจะนำแนวคิดเหล่านี้ไปใช้ได้ เมื่อตรวจสอบการถดถอยของประสิทธิภาพการสร้าง

การสร้างแบบคลีนเทียบกับการสร้างแบบเพิ่ม

การสร้างแบบคลีนคือการสร้างทุกอย่างตั้งแต่ต้น ส่วนการสร้างแบบเพิ่มทีละรายการ จะนำงานที่เสร็จแล้วบางส่วนมาใช้ซ้ำ

เราขอแนะนำให้ดูการสร้างแบบคลีนและการสร้างแบบเพิ่มทีละรายการแยกกัน โดยเฉพาะอย่างยิ่งเมื่อคุณรวบรวม / รวมเมตริกที่ขึ้นอยู่กับสถานะของแคชของ Bazel (เช่น เมตริกขนาดคำขอสร้าง) นอกจากนี้ยังแสดงถึงประสบการณ์ของผู้ใช้ 2 แบบที่แตกต่างกันด้วย เมื่อเทียบกับการเริ่มต้นสร้างใหม่ตั้งแต่ต้น (ซึ่งใช้เวลานานกว่าเนื่องจากแคชเย็น) การสร้างแบบเพิ่มจะเกิดขึ้นบ่อยกว่ามากเมื่อนักพัฒนาซอฟต์แวร์ทำซ้ำในโค้ด (โดยปกติจะเร็วกว่าเนื่องจากแคชมักจะพร้อมใช้งานอยู่แล้ว)

คุณใช้ฟิลด์ CumulativeMetrics.num_analyses ใน BEP เพื่อจัดประเภทบิลด์ได้ หากเป็น num_analyses <= 1 แสดงว่าเป็นการสร้างใหม่ทั้งหมด ไม่เช่นนั้นเราจะจัดหมวดหมู่ได้กว้างๆ ว่าน่าจะเป็นการสร้างแบบเพิ่มทีละรายการ ซึ่งผู้ใช้อาจเปลี่ยนไปใช้ฟีเจอร์หรือเป้าหมายอื่นที่ทำให้เกิดการสร้างใหม่ทั้งหมด คำจำกัดความที่เข้มงวดมากขึ้นเกี่ยวกับส่วนเพิ่มอาจต้องอยู่ในรูปแบบของฮิวริสติก เช่น การดูจำนวนแพ็กเกจที่โหลด (PackageMetrics.packages_loaded)

สร้างเมตริกการสร้างที่แน่นอนเป็นพร็อกซีสำหรับประสิทธิภาพการสร้าง

การวัดประสิทธิภาพการสร้างอาจเป็นเรื่องยากเนื่องจากลักษณะที่ไม่แน่นอน ของเมตริกบางอย่าง (เช่น เวลา CPU ของ Bazel หรือเวลาในคิวในคลัสเตอร์ระยะไกล ) ดังนั้น การใช้เมตริกที่แน่นอนเป็นตัวแทนของ ปริมาณงานที่ Bazel ทำ ซึ่งส่งผลต่อประสิทธิภาพของ Bazel จึงอาจเป็นประโยชน์

ขนาดของคำขอสร้างอาจส่งผลต่อประสิทธิภาพการสร้างอย่างมาก บิลด์ที่ใหญ่ขึ้นอาจหมายถึงงานที่มากขึ้นในการวิเคราะห์และ สร้างกราฟบิลด์ การเติบโตของบิลด์ด้วยตนเองจะเกิดขึ้นตามธรรมชาติเมื่อมีการพัฒนา เนื่องจากมีการเพิ่ม/สร้างการพึ่งพามากขึ้น จึงมีความซับซ้อนมากขึ้น และมีค่าใช้จ่ายในการสร้างมากขึ้น

เราสามารถแบ่งปัญหานี้ออกเป็นระยะการสร้างต่างๆ และใช้เมตริกต่อไปนี้เป็นเมตริกพร็อกซีสำหรับงานที่ทำในแต่ละระยะ

  1. PackageMetrics.packages_loaded: จำนวนแพ็กเกจที่โหลดสำเร็จ การถดถอยในที่นี้หมายถึงงานเพิ่มเติมที่ต้องทำเพื่ออ่านและแยกวิเคราะห์ ไฟล์ BUILD เพิ่มเติมแต่ละไฟล์ในระยะการโหลด

    • ซึ่งมักเกิดจากการเพิ่มการอ้างอิงและต้องโหลดการปิดทรานซิทีฟ
    • ใช้ query / cquery เพื่อค้นหา ตำแหน่งที่อาจมีการเพิ่มการอ้างอิงใหม่
  2. TargetMetrics.targets_configured: แสดงจำนวนเป้าหมายและ แง่มุมที่กำหนดค่าในการบิลด์ การถดถอยแสดงถึงการทำงานที่มากขึ้นในการสร้างและสำรวจกราฟเป้าหมายที่กำหนดค่าไว้

    • ซึ่งมักเกิดจากการเพิ่มการอ้างอิงและการสร้างกราฟของการปิดทรานซิทีฟ
    • ใช้ cquery เพื่อดูว่ามีการเพิ่มทรัพยากร ใหม่ๆ ที่ใด
  3. ActionSummary.actions_created: แสดงการดำเนินการที่สร้างขึ้นในการสร้าง และการถดถอยแสดงถึงงานเพิ่มเติมในการสร้างกราฟการดำเนินการ โปรดทราบ ว่าการดำเนินการนี้รวมถึงการดำเนินการที่ไม่ได้ใช้ซึ่งอาจไม่ได้ดำเนินการด้วย

    • ใช้ aquery เพื่อแก้ไขข้อบกพร่องของการถดถอย เราขอแนะนำให้เริ่มต้นด้วย --output=summary ก่อนที่จะเจาะลึกลงไปอีกด้วย --skyframe_state
  4. ActionSummary.actions_executed: จำนวนการดำเนินการที่ดำเนินการ การถดถอยแสดงถึงงานที่มากขึ้นในการดำเนินการเหล่านี้โดยตรง

    • BEP จะเขียนสถิติการดำเนินการ ActionData ซึ่งแสดงประเภทการดำเนินการที่ดำเนินการมากที่สุด โดยค่าเริ่มต้น ระบบจะรวบรวมประเภทการกระทํา 20 อันดับแรก แต่คุณสามารถส่ง --experimental_record_metrics_for_all_mnemonics เพื่อรวบรวมข้อมูลนี้สําหรับการกระทําทุกประเภทที่ดําเนินการ
    • ซึ่งจะช่วยให้คุณทราบว่ามีการดำเนินการประเภทใดบ้าง (เพิ่มเติม)
  5. BuildGraphSummary.outputArtifactCount: จำนวนอาร์ติแฟกต์ที่สร้างขึ้นโดย การดำเนินการที่ดำเนินการ

    • หากจำนวนการดำเนินการที่ดำเนินการไม่เพิ่มขึ้น แสดงว่าน่าจะมีการเปลี่ยนแปลงการใช้งานกฎ

เมตริกเหล่านี้ทั้งหมดได้รับผลกระทบจากสถานะของแคชในเครื่อง ดังนั้นคุณจึงควรตรวจสอบว่าบิลด์ที่คุณดึงเมตริกเหล่านี้ออกมาเป็นบิลด์ที่สะอาด

เราสังเกตว่าการถดถอยของเมตริกใดๆ เหล่านี้อาจมาพร้อมกับการถดถอยของเวลาจริง เวลา CPU และการใช้หน่วยความจำ

การใช้ทรัพยากรในพื้นที่

Bazel ใช้ทรัพยากรต่างๆ ในเครื่องของคุณ (ทั้งสำหรับการวิเคราะห์กราฟการสร้างและการขับเคลื่อนการดำเนินการ รวมถึงการเรียกใช้การดำเนินการในเครื่อง) ซึ่งอาจส่งผลต่อประสิทธิภาพ / ความพร้อมใช้งานของเครื่องในการดำเนินการสร้าง และงานอื่นๆ ด้วย

เวลาที่ใช้

เมตริกที่อาจได้รับผลกระทบจากสัญญาณรบกวนมากที่สุด (และอาจแตกต่างกันอย่างมากในแต่ละบิลด์) คือเวลา โดยเฉพาะเวลาจริง เวลา CPU และเวลาของระบบ คุณสามารถ ใช้ bazel-bench เพื่อรับ เกณฑ์มาตรฐานสำหรับเมตริกเหล่านี้ และเมื่อมีจำนวน --runs เพียงพอ คุณจะ เพิ่มนัยสำคัญทางสถิติของการวัดผลได้

  • เวลาจริงคือเวลาที่ผ่านไปในโลกแห่งความเป็นจริง

    • หากเวลาจริงเท่านั้นที่ถดถอย เราขอแนะนำให้รวบรวมโปรไฟล์การติดตาม JSON และดูความแตกต่าง ไม่เช่นนั้น การตรวจสอบเมตริกอื่นๆ ที่ถดถอยอาจมีประสิทธิภาพมากกว่า เนื่องจากอาจส่งผลต่อเวลาที่ใช้จริง
  • เวลา CPU คือเวลาที่ CPU ใช้ในการดำเนินการโค้ดของผู้ใช้

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

    • หากเวลาของระบบถดถอย ส่วนใหญ่จะสัมพันธ์กับ I/O เมื่อ Bazel อ่าน ไฟล์จากระบบไฟล์

การสร้างโปรไฟล์การโหลดทั่วทั้งระบบ

เมื่อใช้แฟล็ก --experimental_collect_load_average_in_profiler ที่เปิดตัวใน Bazel 6.0 โปรไฟล์เลส JSON Trace จะรวบรวมค่าเฉลี่ยของโหลดระบบระหว่างการเรียกใช้

โปรไฟล์ที่มีค่าเฉลี่ยของภาระงานของระบบ

รูปที่ 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 (ดูเอกสารประกอบ) แต่มีความเกี่ยวข้องน้อยกว่า
  • BEP MemoryMetrics.peak_post_gc_heap_size: ขนาดของฮีป JVM สูงสุดใน ไบต์หลัง GC (ต้องตั้งค่า --memory_profile ที่พยายามบังคับให้ทำ GC แบบเต็ม)

โดยปกติแล้ว การถดถอยในการใช้หน่วยความจำมักเป็นผลมาจากการถดถอยในเมตริกขนาดคำขอสร้าง ซึ่งมักเกิดจากการเพิ่มการอ้างอิงหรือการเปลี่ยนแปลงในการใช้งานกฎ

หากต้องการวิเคราะห์การใช้หน่วยความจำของ Bazel ในระดับที่ละเอียดยิ่งขึ้น เราขอแนะนำให้ใช้ โปรไฟล์เลอร์หน่วยความจำในตัว สำหรับกฎ

การสร้างโปรไฟล์หน่วยความจำของผู้ปฏิบัติงานแบบถาวร

แม้ว่าWorker ที่ทำงานอย่างต่อเนื่องจะช่วยเร่งความเร็วในการสร้างได้อย่างมาก (โดยเฉพาะภาษาที่ตีความ) แต่การใช้หน่วยความจำอาจเป็นปัญหาได้ Bazel จะรวบรวมเมตริกเกี่ยวกับ Worker โดยเฉพาะอย่างยิ่ง ฟิลด์ WorkerMetrics.WorkerStats.worker_memory_in_kb จะบอกว่า Worker ใช้หน่วยความจำมากน้อยเพียงใด (ตามนิโมนิก)

โปรไฟล์เลอร์การติดตาม 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 ยังช่วยให้คุณดูการใช้งานเครือข่ายทั่วทั้งระบบตลอดการสร้างได้ โดยส่งแฟล็ก --experimental_collect_system_network_usage (ใหม่ใน Bazel 6.0)

โปรไฟล์ที่มีการใช้งานเครือข่ายทั้งระบบ

รูปที่ 3 โปรไฟล์ที่มีการใช้งานเครือข่ายทั้งระบบ

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

อีกตัวเลือกหนึ่งคือการกำหนดค่าแคชดิสก์ในเครื่องเพื่อประหยัดแบนด์วิดท์ในการดาวน์โหลด