การทดสอบประสิทธิภาพ

Android 8.0 มีการทดสอบประสิทธิภาพ Binder และ HwBinder สำหรับปริมาณงานและเวลาแฝง แม้ว่ามีหลายสถานการณ์สำหรับการตรวจจับปัญหาประสิทธิภาพที่รับรู้ได้ แต่การรันสถานการณ์ดังกล่าวอาจใช้เวลานานและมักจะไม่แสดงผลลัพธ์จนกว่าจะรวมระบบแล้ว การใช้การทดสอบประสิทธิภาพที่ให้มาทำให้ง่ายต่อการทดสอบระหว่างการพัฒนา ตรวจพบปัญหาร้ายแรงตั้งแต่เนิ่นๆ และปรับปรุงประสบการณ์ผู้ใช้

การทดสอบประสิทธิภาพประกอบด้วยสี่ประเภทต่อไปนี้:

  • ปริมาณงานของ Binder (มีอยู่ใน system/libhwbinder/vts/performance/Benchmark_binder.cpp )
  • Binder latency (มีอยู่ใน frameworks/native/libs/binder/tests/schd-dbg.cpp )
  • ปริมาณงาน hwbinder (มีอยู่ใน system/libhwbinder/vts/performance/Benchmark.cpp )
  • hwbinder latency (มีอยู่ใน system/libhwbinder/vts/performance/Latency.cpp )

เกี่ยวกับเครื่องผูกและhwbinder

Binder และ hwbinder เป็นโครงสร้างพื้นฐานการสื่อสารระหว่างกระบวนการ (IPC) ของ Android ที่ใช้ไดรเวอร์ Linux เดียวกัน แต่มีความแตกต่างเชิงคุณภาพดังต่อไปนี้:

ด้าน เครื่องผูก วิธีบินเดอร์
วัตถุประสงค์ จัดให้มีโครงการ IPC สำหรับวัตถุประสงค์ทั่วไปสำหรับกรอบงาน สื่อสารกับฮาร์ดแวร์
คุณสมบัติ ปรับให้เหมาะสมสำหรับการใช้งานกรอบงาน Android ค่าใช้จ่ายขั้นต่ำเวลาแฝงต่ำ
เปลี่ยนนโยบายการกำหนดเวลาสำหรับเบื้องหน้า/เบื้องหลัง ใช่ เลขที่
ข้อโต้แย้งผ่านไป ใช้การทำให้เป็นอนุกรมที่รองรับโดยออบเจ็กต์ Parcel ใช้บัฟเฟอร์กระจายและหลีกเลี่ยงค่าใช้จ่ายในการคัดลอกข้อมูลที่จำเป็นสำหรับการจัดลำดับพัสดุ
มรดกลำดับความสำคัญ เลขที่ ใช่

กระบวนการ Binder และ hwbinder

Visualizer systrace จะแสดงธุรกรรมดังต่อไปนี้:

รูปที่ 1 การแสดงภาพ Systrace ของกระบวนการตัวประสาน

ในตัวอย่างข้างต้น:

  • กระบวนการ schd-dbg สี่ (4) กระบวนการเป็นกระบวนการไคลเอนต์
  • กระบวนการเครื่องผูกสี่ (4) กระบวนการคือกระบวนการเซิร์ฟเวอร์ (ชื่อขึ้นต้นด้วย Binder และลงท้ายด้วยหมายเลขลำดับ)
  • กระบวนการไคลเอนต์จะจับคู่กับกระบวนการเซิร์ฟเวอร์เสมอซึ่งมีไว้สำหรับไคลเอนต์โดยเฉพาะ
  • คู่กระบวนการไคลเอ็นต์-เซิร์ฟเวอร์ทั้งหมดได้รับการกำหนดเวลาอย่างเป็นอิสระโดยเคอร์เนลพร้อมกัน

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

ปริมาณงานเทียบกับเวลาแฝง

ในการทำธุรกรรมที่สมบูรณ์แบบ ซึ่งกระบวนการไคลเอ็นต์และเซิร์ฟเวอร์สลับกันได้อย่างราบรื่น การทดสอบปริมาณงานและค่าหน่วงเวลาไม่ได้สร้างข้อความที่แตกต่างกันอย่างมีนัยสำคัญ อย่างไรก็ตาม เมื่อเคอร์เนล OS จัดการคำขอขัดจังหวะ (IRQ) จากฮาร์ดแวร์ รอการล็อค หรือเพียงแค่เลือกที่จะไม่จัดการข้อความในทันที ฟองเวลาแฝงก็อาจเกิดขึ้นได้

รูปที่ 2 ฟองเวลาในการตอบสนองเนื่องจากความแตกต่างในด้านปริมาณงานและเวลาแฝง

การทดสอบปริมาณงานจะสร้างธุรกรรมจำนวนมากที่มีขนาดเพย์โหลดที่แตกต่างกัน โดยให้การประมาณที่ดีสำหรับเวลาการทำธุรกรรมปกติ (ในกรณีที่ดีที่สุด) และปริมาณงานสูงสุดที่ Binder สามารถทำได้

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

จัดการกับการผกผันลำดับความสำคัญ

การกลับลำดับความสำคัญเกิดขึ้นเมื่อเธรดที่มีลำดับความสำคัญสูงกว่ากำลังรอเธรดที่มีลำดับความสำคัญต่ำกว่าในทางลอจิคัล แอปพลิเคชันแบบเรียลไทม์ (RT) มีปัญหาการกลับลำดับความสำคัญ:

รูปที่ 3 การกลับลำดับความสำคัญในแอปพลิเคชันแบบเรียลไทม์

เมื่อใช้การกำหนดเวลา Linux Completely Fair Scheduler (CFS) เธรดจะมีโอกาสรันเสมอแม้ว่าเธรดอื่นจะมีลำดับความสำคัญสูงกว่าก็ตาม ด้วยเหตุนี้ แอปพลิเคชันที่มีการกำหนดเวลา CFS จึงจัดการการกลับลำดับความสำคัญตามลักษณะการทำงานที่คาดไว้ และไม่เป็นปัญหา ในกรณีที่เฟรมเวิร์ก Android ต้องการการกำหนดเวลา RT เพื่อรับประกันสิทธิ์ของเธรดที่มีลำดับความสำคัญสูง การกลับลำดับความสำคัญจะต้องได้รับการแก้ไข

ตัวอย่างการกลับลำดับความสำคัญระหว่างธุรกรรม Binder (เธรด RT ถูกบล็อกทางตรรกะโดยเธรด CFS อื่น ๆ เมื่อรอเธรด Binder เพื่อให้บริการ):

รูปที่ 4 การกลับลำดับความสำคัญ เธรดแบบเรียลไทม์ที่ถูกบล็อก

เพื่อหลีกเลี่ยงการอุดตัน คุณสามารถใช้การสืบทอดลำดับความสำคัญเพื่อขยายเธรด Binder เป็นเธรด RT ชั่วคราว เมื่อให้บริการคำขอจากไคลเอนต์ RT โปรดทราบว่าการจัดกำหนดการ RT มีทรัพยากรที่จำกัด และควรใช้อย่างระมัดระวัง ในระบบที่มี n CPU จำนวนสูงสุดของเธรด RT ปัจจุบันก็คือ n เช่นกัน เธรด RT เพิ่มเติมอาจต้องรอ (และทำให้พลาดกำหนดเวลา) หากเธรด RT อื่นใช้ CPU ทั้งหมด

หากต้องการแก้ไขการกลับลำดับความสำคัญที่เป็นไปได้ทั้งหมด คุณสามารถใช้การสืบทอดลำดับความสำคัญสำหรับทั้ง Binder และ hwbinder อย่างไรก็ตาม เนื่องจากมีการใช้ Binder กันอย่างแพร่หลายทั่วทั้งระบบ การเปิดใช้งานการสืบทอดลำดับความสำคัญสำหรับธุรกรรม Binder อาจส่งสแปมระบบด้วยเธรด RT มากกว่าที่จะให้บริการได้

รันการทดสอบปริมาณงาน

การทดสอบปริมาณงานจะรันกับปริมาณงานของธุรกรรม Binder/hwbinder ในระบบที่ไม่มีการโอเวอร์โหลด ฟองเวลาแฝงนั้นเกิดขึ้นได้ยาก และผลกระทบของฟองนั้นสามารถขจัดออกไปได้ตราบใดที่จำนวนการวนซ้ำสูงเพียงพอ

  • การทดสอบทรูพุต ของ Binder อยู่ใน system/libhwbinder/vts/performance/Benchmark_binder.cpp
  • การทดสอบปริมาณงาน ของ hwbinder อยู่ใน system/libhwbinder/vts/performance/Benchmark.cpp

ผลการทดสอบ

ตัวอย่างผลการทดสอบปริมาณงานสำหรับธุรกรรมที่ใช้ขนาดเพย์โหลดที่แตกต่างกัน:

Benchmark                      Time          CPU           Iterations
---------------------------------------------------------------------
BM_sendVec_binderize/4         70302 ns      32820 ns      21054
BM_sendVec_binderize/8         69974 ns      32700 ns      21296
BM_sendVec_binderize/16        70079 ns      32750 ns      21365
BM_sendVec_binderize/32        69907 ns      32686 ns      21310
BM_sendVec_binderize/64        70338 ns      32810 ns      21398
BM_sendVec_binderize/128       70012 ns      32768 ns      21377
BM_sendVec_binderize/256       69836 ns      32740 ns      21329
BM_sendVec_binderize/512       69986 ns      32830 ns      21296
BM_sendVec_binderize/1024      69714 ns      32757 ns      21319
BM_sendVec_binderize/2k        75002 ns      34520 ns      20305
BM_sendVec_binderize/4k        81955 ns      39116 ns      17895
BM_sendVec_binderize/8k        95316 ns      45710 ns      15350
BM_sendVec_binderize/16k      112751 ns      54417 ns      12679
BM_sendVec_binderize/32k      146642 ns      71339 ns       9901
BM_sendVec_binderize/64k      214796 ns     104665 ns       6495
  • เวลาบ่ง บอกถึงความล่าช้าในการเดินทางไปกลับที่วัดแบบเรียลไทม์
  • CPU ระบุเวลาสะสมเมื่อมีการกำหนดเวลา CPU สำหรับการทดสอบ
  • การวนซ้ำ ระบุจำนวนครั้งที่ฟังก์ชันทดสอบดำเนินการ

ตัวอย่างเช่น สำหรับเพย์โหลด 8 ไบต์:

BM_sendVec_binderize/8         69974 ns      32700 ns      21296

… ปริมาณงานสูงสุดที่เครื่องผูกสามารถทำได้ได้รับการคำนวณดังนี้:

ปริมาณงานสูงสุดพร้อมเพย์โหลด 8 ไบต์ = (8 * 21296)/69974 ~= 2.423 b/ns ~= 2.268 Gb/s

ตัวเลือกการทดสอบ

หากต้องการรับผลลัพธ์ในรูปแบบ .json ให้รันการทดสอบด้วยอาร์กิวเมนต์ --benchmark_format=json :

libhwbinder_benchmark --benchmark_format=json
{
  "context": {
    "date": "2017-05-17 08:32:47",
    "num_cpus": 4,
    "mhz_per_cpu": 19,
    "cpu_scaling_enabled": true,
    "library_build_type": "release"
  },
  "benchmarks": [
    {
      "name": "BM_sendVec_binderize/4",
      "iterations": 32342,
      "real_time": 47809,
      "cpu_time": 21906,
      "time_unit": "ns"
    },
   ….
}

เรียกใช้การทดสอบเวลาในการตอบสนอง

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

  • การทดสอบเวลาแฝงของ Binder อยู่ใน frameworks/native/libs/binder/tests/schd-dbg.cpp
  • การทดสอบเวลาแฝงของ hwbinder อยู่ใน system/libhwbinder/vts/performance/Latency.cpp

ผลการทดสอบ

ผลลัพธ์ (ในสกุล .json) แสดงสถิติสำหรับเวลาแฝงโดยเฉลี่ย/ดีที่สุด/แย่ที่สุด และจำนวนกำหนดเวลาที่พลาดไป

ตัวเลือกการทดสอบ

การทดสอบเวลาในการตอบสนองใช้ตัวเลือกต่อไปนี้:

สั่งการ คำอธิบาย
-i value ระบุจำนวนการวนซ้ำ
-pair value ระบุจำนวนคู่กระบวนการ
-deadline_us 2500 ระบุกำหนดเวลาในเรา
-v รับเอาต์พุตแบบละเอียด (การดีบัก)
-trace หยุดการติดตามเมื่อถึงกำหนดเวลา

ส่วนต่อไปนี้ให้รายละเอียดแต่ละตัวเลือก อธิบายการใช้งาน และให้ผลลัพธ์ตัวอย่าง

ระบุการวนซ้ำ

ตัวอย่างที่มีการวนซ้ำจำนวนมากและปิดใช้งานเอาต์พุตแบบละเอียด:

libhwbinder_latency -i 5000 -pair 3
{
"cfg":{"pair":3,"iterations":5000,"deadline_us":2500},
"P0":{"SYNC":"GOOD","S":9352,"I":10000,"R":0.9352,
  "other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
},
"P1":{"SYNC":"GOOD","S":9334,"I":10000,"R":0.9334,
  "other_ms":{ "avg":0.19, "wst":2.9 , "bst":0.055, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":3.1 , "bst":0.066, "miss":1, "meetR":0.9998}
},
"P2":{"SYNC":"GOOD","S":9369,"I":10000,"R":0.9369,
  "other_ms":{ "avg":0.19, "wst":4.8 , "bst":0.055, "miss":6, "meetR":0.9988},
  "fifo_ms": { "avg":0.15, "wst":1.8 , "bst":0.067, "miss":0, "meetR":1}
},
"inheritance": "PASS"
}

ผลการทดสอบเหล่านี้แสดงสิ่งต่อไปนี้:

"pair":3
สร้างคู่ไคลเอนต์และเซิร์ฟเวอร์หนึ่งคู่
"iterations": 5000
รวมการวนซ้ำ 5,000 ครั้ง
"deadline_us":2500
กำหนดเวลาคือ 2500us (2.5ms); ธุรกรรมส่วนใหญ่คาดว่าจะเป็นไปตามมูลค่านี้
"I": 10000
การทดสอบซ้ำครั้งเดียวประกอบด้วยธุรกรรมสอง (2) รายการ:
  • หนึ่งธุรกรรมตามลำดับความสำคัญปกติ ( CFS other )
  • หนึ่งธุรกรรมตามลำดับความสำคัญตามเวลาจริง ( RT-fifo )
การวนซ้ำ 5,000 ครั้งเท่ากับธุรกรรมทั้งหมด 10,000 รายการ
"S": 9352
ธุรกรรม 9352 ถูกซิงค์ใน CPU เดียวกัน
"R": 0.9352
ระบุอัตราส่วนที่ไคลเอ็นต์และเซิร์ฟเวอร์ซิงค์กันใน CPU เดียวกัน
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
กรณีเฉลี่ย ( avg ) แย่ที่สุด ( wst ) และดีที่สุด ( bst ) สำหรับธุรกรรมทั้งหมดที่ออกโดยผู้โทรที่มีลำดับความสำคัญปกติ ธุรกรรมสองรายการ miss กำหนดเวลา ทำให้อัตราส่วนตอบสนอง ( meetR ) 0.9996
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
คล้ายกับ other_ms แต่สำหรับธุรกรรมที่ออกโดยลูกค้าที่มีลำดับความสำคัญ rt_fifo เป็นไปได้ (แต่ไม่จำเป็น) ว่า fifo_ms จะให้ผลลัพธ์ที่ดีกว่า other_ms โดยมีค่า avg และ wst ต่ำกว่า และ meetR ที่สูงกว่า (ความแตกต่างอาจมีนัยสำคัญยิ่งขึ้นเมื่อโหลดในพื้นหลัง)

หมายเหตุ: การโหลดในเบื้องหลังอาจส่งผลต่อผลลัพธ์การรับส่งข้อมูลและทูเพิล other_ms ในการทดสอบเวลาแฝง เฉพาะ fifo_ms เท่านั้นที่อาจแสดงผลลัพธ์ที่คล้ายกันตราบใดที่การโหลดพื้นหลังมีลำดับความสำคัญต่ำกว่า RT-fifo

ระบุค่าคู่

กระบวนการไคลเอ็นต์แต่ละกระบวนการจะจับคู่กับกระบวนการเซิร์ฟเวอร์สำหรับไคลเอ็นต์โดยเฉพาะ และแต่ละคู่อาจได้รับการกำหนดเวลาแยกจากกันกับ CPU ใดๆ อย่างไรก็ตาม การโยกย้าย CPU ไม่ควรเกิดขึ้นระหว่างการทำธุรกรรมตราบใดที่แฟล็ก SYNC นั้นเป็น honor

ตรวจสอบให้แน่ใจว่าระบบไม่โอเวอร์โหลด! แม้ว่าคาดว่าจะมีเวลาแฝงสูงในระบบโอเวอร์โหลด แต่ผลการทดสอบสำหรับระบบโอเวอร์โหลดไม่ได้ให้ข้อมูลที่เป็นประโยชน์ หากต้องการทดสอบระบบที่มีแรงดันสูงกว่า ให้ใช้ -pair #cpu-1 (หรือ -pair #cpu ด้วยความระมัดระวัง) การทดสอบโดยใช้ -pair n กับ n > #cpu ทำให้ระบบโอเวอร์โหลดและสร้างข้อมูลที่ไร้ประโยชน์

ระบุค่ากำหนดเวลา

หลังจากการทดสอบสถานการณ์ของผู้ใช้อย่างกว้างขวาง (ทำการทดสอบเวลาแฝงกับผลิตภัณฑ์ที่ผ่านการรับรอง) เราพบว่า 2.5 มิลลิวินาทีคือกำหนดเวลาที่ต้องปฏิบัติตาม สำหรับแอปพลิเคชันใหม่ที่มีความต้องการสูงกว่า (เช่น 1,000 ภาพ/วินาที) ค่ากำหนดเวลานี้จะเปลี่ยนแปลง

ระบุเอาต์พุตแบบละเอียด

การใช้ตัวเลือก -v จะแสดงเอาต์พุตแบบละเอียด ตัวอย่าง:

libhwbinder_latency -i 1 -v

-------------------------------------------------- service pid: 8674 tid: 8674 cpu: 1 SCHED_OTHER 0
-------------------------------------------------- main pid: 8673 tid: 8673 cpu: 1 -------------------------------------------------- client pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0
-------------------------------------------------- fifo-caller pid: 8677 tid: 8678 cpu: 0 SCHED_FIFO 99 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 ??? 99
-------------------------------------------------- other-caller pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 SCHED_OTHER 0
  • เธรดบริการ ถูกสร้างขึ้นโดยมีลำดับความสำคัญ SCHED_OTHER และทำงานใน CPU:1 พร้อมด้วย pid 8674
  • ธุรกรรมแรก จะเริ่มต้นโดย fifo-caller เพื่อให้บริการธุรกรรมนี้ hwbinder จะอัปเกรดลำดับความสำคัญของเซิร์ฟเวอร์ ( pid: 8674 tid: 8676 ) เป็น 99 และยังทำเครื่องหมายด้วยคลาสการกำหนดเวลาชั่วคราว (พิมพ์เป็น ??? ) ตัวกำหนดเวลาจะทำให้กระบวนการเซิร์ฟเวอร์อยู่ใน CPU:0 เพื่อทำงานและซิงค์กับ CPU เดียวกันกับไคลเอนต์
  • ผู้เรียก ธุรกรรมรายที่สอง มีลำดับความสำคัญ SCHED_OTHER เซิร์ฟเวอร์จะดาวน์เกรดตัวเองและให้บริการผู้โทรตามลำดับความสำคัญ SCHED_OTHER

ใช้การติดตามสำหรับการดีบัก

คุณสามารถระบุตัวเลือก -trace เพื่อแก้ไขปัญหาเวลาแฝงได้ เมื่อใช้ การทดสอบเวลาแฝงจะหยุดการบันทึกการติดตามในขณะที่ตรวจพบเวลาแฝงที่ไม่ดี ตัวอย่าง:

atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq
libhwbinder_latency -deadline_us 50000 -trace -i 50000 -pair 3
deadline triggered: halt ∓ stop trace
log:/sys/kernel/debug/tracing/trace

ส่วนประกอบต่อไปนี้อาจส่งผลต่อเวลาแฝง:

  • โหมดการสร้าง Android โหมด Eng มักจะช้ากว่าโหมด userdebug
  • กรอบ . บริการกรอบงานใช้ ioctl เพื่อกำหนดค่าให้กับเครื่องผูกอย่างไร
  • คนขับรถเครื่องผูก . คนขับรองรับการล็อคแบบละเอียดหรือไม่? มันมีแพตช์การเปลี่ยนประสิทธิภาพทั้งหมดหรือไม่?
  • เวอร์ชันเคอร์เนล ยิ่งเคอร์เนลมีความสามารถแบบเรียลไทม์ที่ดีกว่า ผลลัพธ์ก็จะยิ่งดีขึ้นเท่านั้น
  • การกำหนดค่าเคอร์เนล การกำหนดค่าเคอร์เนลมีการกำหนดค่า DEBUG เช่น DEBUG_PREEMPT และ DEBUG_SPIN_LOCK หรือไม่
  • ตัวกำหนดเวลาเคอร์เนล เคอร์เนลมีตัวกำหนดเวลา Energy-Aware (EAS) หรือ Heterogeneous Multi-Processing (HMP) หรือไม่ ไดรเวอร์เคอร์เนลใด ๆ (ไดรเวอร์ cpu-freq , ไดรเวอร์ cpu-idle , cpu-hotplug ฯลฯ ) ส่งผลกระทบต่อตัวกำหนดตารางเวลาหรือไม่