การปรับปรุง ART ของ Android 8.0

รันไทม์ของ Android (ART) ได้รับการปรับปรุงอย่างมีนัยสำคัญในการเปิดตัว Android 8.0 รายการด้านล่างสรุปการปรับปรุงที่ผู้ผลิตอุปกรณ์สามารถคาดหวังได้ใน ART

เครื่องรวบรวมขยะขนาดกะทัดรัดพร้อมกัน

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

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

การเพิ่มประสิทธิภาพลูป

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

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

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

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

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

นี่คือบทสรุปของการปรับปรุงที่เกี่ยวข้อง:

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

แคชแบบอินไลน์ในไฟล์ .oat

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

Dexlayout

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

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

การลบแคช Dex

จนถึง Android 7.0 วัตถุ DexCache เป็นเจ้าของอาร์เรย์ขนาดใหญ่สี่ชุด ซึ่งสัดส่วนกับจำนวนขององค์ประกอบบางอย่างใน DexFile กล่าวคือ:

  • สตริง (หนึ่งการอ้างอิงต่อ DexFile::StringId)
  • ประเภท (หนึ่งการอ้างอิงต่อ DexFile::TypeId)
  • วิธีการ (หนึ่งตัวชี้ดั้งเดิมต่อ DexFile::MethodId)
  • (หนึ่งตัวชี้เนทิฟต่อ 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 ที่แตกต่างกันเท่านั้น มีเหตุผลสองประการสำหรับข้อจำกัดนี้:

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

เพื่อแก้ไขข้อจำกัดเหล่านี้ Android 8.0:

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

การปรับปรุงการซิงโครไนซ์

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

วิธีการดั้งเดิมที่เร็วขึ้น

การเรียกเนทิฟที่เร็วขึ้นไปยัง 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) เวลาดำเนินการ (เป็นนาโนวินาที)
เจเอ็นไอประจำ 115
!ปัง JNI 60
@FastNative 35
@CriticalNative 25