การปรับปรุง ART ใน Android 8.0

Android Runtime (ART) ได้รับการปรับปรุงอย่างมากในรุ่น Android 8.0 รายการด้านล่างสรุปการปรับปรุงที่ผู้ผลิตอุปกรณ์จะได้รับใน ART

Garbage Collector แบบการบีบอัดพร้อมกัน

ตามที่ได้ประกาศไปในงาน Google I/O ว่า ART มีเครื่องมือรวบรวมขยะ (GC) แบบใหม่แบบพร้อมกันใน Android 8.0 ตัวรวบรวมนี้จะบีบอัดกองทุกครั้งที่ GC ทำงานและขณะที่แอปทำงาน โดยหยุดชั่วคราวเพียงครั้งเดียวเพื่อประมวลผลรูทของชุดข้อความ ประโยชน์ของฟีเจอร์มีดังนี้

  • GC จะบีบอัดกองเสมอ โดยขนาดกองจะเล็กลงโดยเฉลี่ย 32% เมื่อเทียบกับ Android 7.0
  • การบีบอัดช่วยให้การจัดสรรออบเจ็กต์ตัวชี้การเลื่อนตำแหน่งในท้องถิ่นของเธรดทำได้เร็วขึ้น 70% เมื่อเทียบกับใน Android 7.0
  • เพิ่มเวลาหยุดชั่วคราวที่น้อยลง 85% สำหรับการทดสอบประสิทธิภาพ H2 เมื่อเทียบกับ GC ของ Android 7.0
  • ระยะเวลาการหยุดชั่วคราวจะไม่ปรับตามขนาดกองอีกต่อไป แอปควรใช้กองขนาดใหญ่ได้โดยไม่ต้องกังวลเรื่องความกระตุก
  • รายละเอียดการใช้งาน GC - Read Barriers
    • แถบการอ่านคืองานจำนวนเล็กน้อยที่ทําสําหรับการอ่านแต่ละช่องออบเจ็กต์
    • ตัวแปรเหล่านี้ได้รับการเพิ่มประสิทธิภาพในคอมไพเลอร์ แต่อาจทําให้บางกรณีการใช้งานช้าลง

การเพิ่มประสิทธิภาพการวนซ้ำ

ART ใช้การเพิ่มประสิทธิภาพลูปที่หลากหลายในรุ่น Android 8.0 ดังนี้

  • การยกเลิกการตรวจสอบขอบเขต
    • แบบคงที่: ช่วงที่พิสูจน์แล้วว่าอยู่ภายในขอบเขตเมื่อคอมไพล์
    • แบบไดนามิก: การทดสอบรันไทม์ช่วยให้มั่นใจว่าลูปจะอยู่ในขอบเขต (หากไม่ใช้ ให้เลือก "ปิดใช้")
  • การนําตัวแปรอินดuction ออก
    • นำอินดัคชันที่ตายแล้วออก
    • แทนที่การอินดักชันที่ใช้หลังจากลูปเท่านั้นด้วยนิพจน์แบบปิด
  • การกำจัดโค้ดที่ตายแล้วภายในตัวลูป การนำลูปทั้งลูปที่ตายแล้วออก
  • การลดระดับ
  • การเปลี่ยนรูปแบบของลูป: การกลับรายการ การสลับ แยก การเลิกม้วน การเปลี่ยนรูปแบบเป็นโมดูลเดียว ฯลฯ
  • SIMDization (หรือที่เรียกว่า Vectorization)

เครื่องมือเพิ่มประสิทธิภาพของลูปจะอยู่ในรอบการเพิ่มประสิทธิภาพของตัวเองในคอมไพเลอร์ ART การเพิ่มประสิทธิภาพลูปส่วนใหญ่จะคล้ายกับการเพิ่มประสิทธิภาพและการลดความซับซ้อนในส่วนอื่นๆ ปัญหาเกิดขึ้นเมื่อการเพิ่มประสิทธิภาพบางอย่างเขียน CFG ใหม่ในลักษณะที่ซับซ้อนกว่าปกติ เนื่องจากยูทิลิตี CFG ส่วนใหญ่ (ดู nodes.h) มุ่งเน้นที่การสร้าง CFG ไม่ใช่การเขียนใหม่

การวิเคราะห์ลําดับชั้นของชั้นเรียน

ART ใน Android 8.0 ใช้การวิเคราะห์ลําดับชั้นของคลาส (CHA) ซึ่งเป็นการเพิ่มประสิทธิภาพคอมไพเลอร์ที่แปลงการเรียกเสมือนให้เป็นคําเรียกโดยตรงตามข้อมูลที่สร้างขึ้นจากการวิเคราะห์ลําดับชั้นของคลาส การเรียกเสมือนมีราคาแพงเนื่องจากมีการใช้งานกับการค้นหา vtable และต้องใช้การโหลดแบบมีเงื่อนไข 2 ครั้ง นอกจากนี้ คุณยังแทรกการโทรเสมือนในบรรทัดไม่ได้

สรุปการปรับปรุงที่เกี่ยวข้องมีดังนี้

  • การอัปเดตสถานะเมธอดการใช้งานแบบไดนามิกรายการเดียว - เมื่อสิ้นสุดเวลาการลิงก์คลาสแล้ว เมื่อมีการป้อนข้อมูล vtable แล้ว ART จะทำการเปรียบเทียบทีละรายการกับ vtable ของคลาสหลัก
  • การเพิ่มประสิทธิภาพคอมไพเลอร์ - คอมไพเลอร์จะใช้ประโยชน์จากข้อมูลการใช้งานแบบครั้งเดียวของเมธอด หากเมธอด A.foo มีการตั้งค่า Flag การใช้งานแบบเดี่ยว คอมไพเลอร์จะแปลงการเรียกเสมือนจริงเป็นการเรียกโดยตรง และพยายามแทรกการเรียกโดยตรงนั้นในบรรทัด
  • โค้ดที่คอมไพล์แล้วใช้งานไม่ได้ - เมื่อถึงเวลาสิ้นสุดการลิงก์คลาสเมื่อมีการอัปเดตข้อมูลการใช้งานแบบครั้งเดียว หากเมธอด A.foo ที่เคยมีการใช้งานแบบครั้งเดียวแต่ตอนนี้สถานะนั้นใช้งานไม่ได้ โค้ดที่คอมไพล์แล้วทั้งหมดซึ่งขึ้นอยู่กับการคาดการณ์ว่าเมธอด A.foo มีการใช้งานแบบครั้งเดียวจะต้องใช้งานไม่ได้
  • การปรับประสิทธิภาพออก - สําหรับโค้ดที่คอมไพล์แล้วซึ่งอยู่ในสแต็ก ระบบจะเริ่มการปรับประสิทธิภาพออกเพื่อบังคับให้โค้ดที่คอมไพล์แล้วซึ่งใช้งานไม่ได้เข้าสู่โหมดล่ามเพื่อรับประกันความถูกต้อง ระบบจะใช้กลไกใหม่ในการยกเลิกการเพิ่มประสิทธิภาพ ซึ่งเป็นการผสมผสานระหว่างการยกเลิกการเพิ่มประสิทธิภาพแบบซิงค์และแบบแอซิงค์

แคชในบรรทัดในไฟล์ .oat

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

Dexlayout

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

เนื่องจากปัจจุบันข้อมูลโปรไฟล์จะพร้อมใช้งานหลังจากที่แอปทำงานแล้วเท่านั้น ระบบจึงผสานรวม dexlayout ไว้ในการคอมไพล์ในอุปกรณ์ของ dex2oat ในระหว่างการบำรุงรักษาที่ไม่ได้ใช้งาน

การนำแคช Dex ออก

จนถึง Android 7.0 ออบเจ็กต์ DexCache เป็นเจ้าของอาร์เรย์ขนาดใหญ่ 4 รายการตามสัดส่วนกับจํานวนองค์ประกอบบางอย่างใน DexFile ดังนี้

  • สตริง (การอ้างอิง 1 รายการต่อ DexFile::StringId)
  • ประเภท (การอ้างอิง 1 รายการต่อ DexFile::TypeId)
  • วิธีการ (ตัวชี้เนทีฟ 1 รายการต่อ DexFile::MethodId)
  • ฟิลด์ (ตัวชี้แบบเนทีฟ 1 ตัวต่อ DexFile::FieldId)

อาร์เรย์เหล่านี้ใช้สําหรับการดึงข้อมูลออบเจ็กต์ที่แก้ไขแล้วก่อนหน้านี้อย่างรวดเร็ว ใน Android 8.0 ระบบจะนำอาร์เรย์ทั้งหมดออก ยกเว้นอาร์เรย์เมธอด

ประสิทธิภาพของอินเทอร์พรีเตอร์

ประสิทธิภาพของโปรแกรมล่ามได้รับการปรับปรุงอย่างมากในรุ่น Android 7.0 ด้วยการเปิดตัว "mterp" ซึ่งเป็นโปรแกรมล่ามที่แสดงกลไกการดึงข้อมูล/ถอดรหัส/ตีความหลักที่เขียนด้วยภาษาแอสเซมบลี Mterp ทำงานตามรูปแบบของโปรแกรมแปลภาษา Dalvik ที่ทำงานเร็ว และรองรับ arm, arm64, x86, x86_64, mips และ mips64 สำหรับโค้ดการประมวลผล mterp ของ Art มีประสิทธิภาพเทียบเท่ากับโปรแกรมล่ามแบบเร็วของ Dalvik อย่างไรก็ตาม ในบางสถานการณ์ ความเร็วในการค้นหาอาจช้าลงอย่างมาก

  1. เรียกใช้ประสิทธิภาพ
  2. การจัดการสตริง และผู้ใช้เมธอดอื่นๆ จำนวนมากที่ระบบจดจำว่าเป็นเมธอดภายในใน Dalvik
  3. การใช้หน่วยความจําสแต็กสูงขึ้น

Android 8.0 แก้ไขปัญหาเหล่านี้

แทรกโค้ดเพิ่มเติม

ตั้งแต่ Android 6.0 เป็นต้นไป ART สามารถแทรกคําเรียกใดๆ ในไฟล์ dex เดียวกันได้ แต่แทรกได้เฉพาะเมธอดระดับล่างจากไฟล์ dex อื่น ข้อจำกัดนี้เกิดขึ้นจากสาเหตุ 2 ประการ ดังนี้

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

Android 8.0 แก้ปัญหาข้อจำกัดเหล่านี้ด้วยการดำเนินการต่อไปนี้

  1. นำสิทธิ์เข้าถึงแคช Dex ออกจากโค้ดที่คอมไพล์แล้ว (ดูส่วน "การนำแคช Dex ออก" ด้วย)
  2. ขยายการเข้ารหัสแผนที่กอง

การปรับปรุงการซิงค์ข้อมูล

ทีม ART ได้ปรับเส้นทางโค้ด MonitorEnter/MonitorExit และลดการพึ่งพาตัวกั้นหน่วยความจำแบบดั้งเดิมใน ARMv8 โดยแทนที่ด้วยคำสั่ง (acquire/release) รุ่นใหม่เมื่อเป็นไปได้

วิธีการเนทีฟที่เร็วขึ้น

การเรียก Java Native Interface (JNI) แบบเนทีฟที่เร็วขึ้นพร้อมใช้งานโดยใช้คำอธิบายประกอบ @FastNative และ @CriticalNative การเพิ่มประสิทธิภาพรันไทม์ ART ในตัวเหล่านี้จะเร่งการเปลี่ยน JNI และแทนที่รูปแบบคำสั่ง !bang JNI ที่เลิกใช้งานแล้ว คําอธิบายประกอบจะไม่มีผลกับเมธอดที่ไม่ใช่เนทีฟ และใช้ได้กับโค้ดภาษา Java ของแพลตฟอร์มใน bootclasspath เท่านั้น (ไม่มีการอัปเดต Play Store)

คําอธิบายประกอบ @FastNative รองรับเมธอดแบบไม่คงที่ ใช้รูปแบบนี้หากเมธอดเข้าถึง jobject ในฐานะพารามิเตอร์หรือค่าที่แสดงผล

คําอธิบายประกอบ @CriticalNative เป็นวิธีที่รวดเร็วยิ่งขึ้นในการเรียกใช้เมธอดเนทีฟ โดยมีข้อจํากัดต่อไปนี้

  • เมธอดต้องเป็นแบบคงที่ โดยไม่มีออบเจ็กต์สำหรับพารามิเตอร์ ค่าที่แสดงผล หรือ this ที่ไม่ระบุ
  • ระบบจะส่งเฉพาะประเภทพื้นฐานไปยังเมธอดเนทีฟ
  • เมธอดเนทีฟไม่ได้ใช้พารามิเตอร์ JNIEnv และ jclass ในคําจํากัดความของฟังก์ชัน
  • โดยต้องลงทะเบียนเมธอดกับ RegisterNatives แทนที่จะใช้การลิงก์ JNI แบบไดนามิก

@FastNative ช่วยปรับปรุงประสิทธิภาพของวิธีการแบบเนทีฟได้สูงสุด 3 เท่า และ @CriticalNative ช่วยปรับปรุงประสิทธิภาพได้สูงสุด 5 เท่า ตัวอย่างเช่น การเปลี่ยน JNI ที่วัดในอุปกรณ์ Nexus 6P

การเรียก Java Native Interface (JNI) เวลาดำเนินการ (ในนาโนวินาที)
JNI ปกติ 115
!bang JNI 60
@FastNative 35
@CriticalNative 25