1. ก่อนเริ่มต้น
Codelab นี้จะแสดงวิธีการสร้างโปรไฟล์พื้นฐานเพื่อเพิ่มประสิทธิภาพให้กับแอปพลิเคชันของคุณ และวิธียืนยันประโยชน์ด้านประสิทธิภาพของการใช้โปรไฟล์พื้นฐาน
สิ่งที่คุณต้องมี
- Android Studio Hedgehog (2023.1.1) ขึ้นไป
- ปลั๊กอิน Android Gradle 8.0 ขึ้นไป
- ความเข้าใจขั้นพื้นฐานเกี่ยวกับ Jetpack Macrobenchmark
- อุปกรณ์ Android จริงที่ใช้ Android 7 (API ระดับ 24) ขึ้นไป
สิ่งที่คุณต้องทำ
- ตั้งค่าโปรเจ็กต์เพื่อใช้เครื่องมือสร้างโปรไฟล์พื้นฐาน
- สร้างโปรไฟล์พื้นฐานเพื่อเพิ่มประสิทธิภาพการเริ่มต้นและการเลื่อนแอป
- ตรวจสอบประสิทธิภาพที่ได้รับด้วยไลบรารี Jetpack Macrobenchmark
สิ่งที่คุณจะได้เรียนรู้
- โปรไฟล์พื้นฐานและวิธีที่โปรไฟล์เหล่านี้สามารถปรับปรุงประสิทธิภาพของแอป
- วิธีสร้างโปรไฟล์พื้นฐาน
- ประสิทธิภาพที่เพิ่มขึ้นของโปรไฟล์พื้นฐาน
2. การตั้งค่า
หากต้องการเริ่มต้นใช้งาน ให้โคลนที่เก็บ GitHub จากบรรทัดคำสั่งโดยใช้คำสั่งต่อไปนี้
$ git clone https://github.com/android/codelab-android-performance.git
หรือคุณจะดาวน์โหลดไฟล์ ZIP 2 ไฟล์ได้ดังนี้
เปิดโปรเจ็กต์ใน Android Studio
- ในหน้าต่างยินดีต้อนรับสู่ Android Studio ให้เลือก
เปิดโปรเจ็กต์ที่มีอยู่
- เลือกโฟลเดอร์
[Download Location]/codelab-android-performance/baseline-profiles
โปรดเลือกไดเรกทอรีbaseline-profiles
- เมื่อ Android Studio นำเข้าโปรเจ็กต์ โปรดตรวจสอบว่าคุณสามารถเรียกใช้โมดูล
app
เพื่อสร้างแอปพลิเคชันตัวอย่างที่จะใช้งานในภายหลังได้
แอปตัวอย่าง
ใน Codelab นี้ คุณจะทำงานกับแอปพลิเคชัน JetSnack ตัวอย่างได้ ซึ่งเป็นแอปสั่งซื้อขนมเสมือนจริงที่ใช้ Jetpack Compose
ในการวัดประสิทธิภาพของแอปพลิเคชัน คุณต้องเข้าใจโครงสร้าง UI และลักษณะการทำงานของแอป เพื่อเข้าถึงองค์ประกอบ UI จากการเปรียบเทียบ เรียกใช้แอปและทำความคุ้นเคยกับหน้าจอพื้นฐานด้วยการสั่งขนม คุณไม่จำเป็นต้องทราบรายละเอียดเกี่ยวกับสถาปัตยกรรมของแอป
3. โปรไฟล์พื้นฐานคืออะไร
โปรไฟล์พื้นฐานจะเพิ่มความเร็วในการดำเนินการกับโค้ดได้ประมาณ 30% นับจากการเปิดใช้ครั้งแรกโดยหลีกเลี่ยงการตีความและขั้นตอนการคอมไพล์แบบ Just-In-Time (JIT) สำหรับเส้นทางโค้ดที่รวมไว้ ด้วยการจัดส่งโปรไฟล์พื้นฐานในแอปหรือไลบรารี Android Runtime (ART) จึงสามารถเพิ่มประสิทธิภาพเส้นทางโค้ดที่รวมไว้ผ่านการคอมไพล์ Ahead of Time (AOT) ซึ่งเป็นการเพิ่มประสิทธิภาพสำหรับผู้ใช้ใหม่ทุกรายและในทุกๆ การอัปเดตแอป การเพิ่มประสิทธิภาพตามแนวทางโปรไฟล์ (PGO) นี้ช่วยให้แอปเพิ่มประสิทธิภาพการเริ่มต้น ลดความยุ่งยากในการโต้ตอบ และปรับปรุงประสิทธิภาพรันไทม์โดยรวมสำหรับผู้ใช้ปลายทางตั้งแต่การเปิดใช้ครั้งแรก
เมื่อใช้โปรไฟล์พื้นฐาน การโต้ตอบทั้งหมดของผู้ใช้ เช่น การเริ่มต้นแอป การไปยังหน้าจอต่างๆ หรือการเลื่อนผ่านเนื้อหา จะราบรื่นยิ่งขึ้นตั้งแต่ครั้งแรกที่เรียกใช้ การเพิ่มความเร็วและการตอบสนองของแอปจะทำให้ผู้ใช้ที่ใช้งานอยู่รายวันมากขึ้นและมีอัตราการเยี่ยมชมเฉลี่ยสูงขึ้น
โปรไฟล์พื้นฐานช่วยแนะแนวทางในการเพิ่มประสิทธิภาพนอกเหนือจากการเริ่มต้นแอป โดยแสดงการโต้ตอบของผู้ใช้ทั่วไป ซึ่งจะปรับปรุงรันไทม์ของแอปตั้งแต่การเปิดใช้ครั้งแรก การคอมไพล์ AOT แบบมีคำแนะนำไม่ได้ใช้อุปกรณ์ของผู้ใช้ และสามารถทำได้ 1 ครั้งต่อรุ่นบนเครื่องสำหรับการพัฒนาแทนที่จะใช้อุปกรณ์เคลื่อนที่ การจัดส่งรุ่นที่มีโปรไฟล์พื้นฐานจะทำให้การเพิ่มประสิทธิภาพแอปพร้อมใช้งานเร็วกว่าการใช้โปรไฟล์ Cloud เพียงอย่างเดียวเป็นอย่างมาก
เมื่อไม่ได้ใช้โปรไฟล์พื้นฐาน โค้ดของแอปทั้งหมดจะได้รับการคอมไพล์ JIT ในหน่วยความจำหลังจากตีความหรือลงในไฟล์ odex ในเบื้องหลังเมื่ออุปกรณ์ไม่มีการใช้งาน ผู้ใช้อาจได้รับประสบการณ์ที่ไม่ดีเมื่อเรียกใช้แอปหลังจากติดตั้งหรืออัปเดตแอปเป็นครั้งแรกก่อนที่จะมีการเพิ่มประสิทธิภาพเส้นทางใหม่
4. ตั้งค่าโมดูลตัวสร้างโปรไฟล์พื้นฐาน
คุณสามารถสร้างโปรไฟล์พื้นฐานด้วยคลาสทดสอบการใช้เครื่องมือที่จำเป็นต้องเพิ่มโมดูล Gradle ใหม่ในโปรเจ็กต์ของคุณ วิธีที่ง่ายที่สุดในการเพิ่มลงในโปรเจ็กต์คือการใช้วิซาร์ดโมดูล Android Studio ที่มาพร้อมกับ Android Studio Hedgehog ขึ้นไป
เปิดหน้าต่างวิซาร์ดโมดูลใหม่โดยคลิกขวาที่โปรเจ็กต์หรือโมดูลในแผงโปรเจ็กต์ แล้วเลือกใหม่ > โมดูล
จากหน้าต่างที่เปิดอยู่ ให้เลือกตัวสร้างโปรไฟล์พื้นฐานจากแผงเทมเพลต
นอกเหนือจากพารามิเตอร์ทั่วไป เช่น ชื่อโมดูล ชื่อแพ็กเกจ ภาษา หรือภาษาการกำหนดค่าบิลด์แล้ว ยังมีอินพุต 2 รายการที่ต่างไปจากเดิมสำหรับโมดูลใหม่ ซึ่งได้แก่ แอปพลิเคชันเป้าหมายและใช้อุปกรณ์ที่มีการจัดการโดย Gradle
แอปพลิเคชันเป้าหมายคือโมดูลแอปที่ใช้ในการสร้างโปรไฟล์พื้นฐาน หากคุณมีโมดูลแอปมากกว่า 1 รายการในโปรเจ็กต์ ให้เลือกโมดูลที่ต้องการเรียกใช้โปรแกรมสร้าง
ช่องทำเครื่องหมายใช้อุปกรณ์ที่มีการจัดการจาก Gradle ตั้งค่าโมดูลให้เรียกใช้ตัวสร้างโปรไฟล์พื้นฐานในโปรแกรมจำลอง Android ที่มีการจัดการโดยอัตโนมัติ อ่านเพิ่มเติมเกี่ยวกับอุปกรณ์ที่มีการจัดการโดย Gradle ได้ในปรับขนาดการทดสอบด้วยอุปกรณ์ที่มีการจัดการของ Gradle หากยกเลิกการเลือก เครื่องปั่นไฟจะใช้อุปกรณ์ที่เชื่อมต่ออยู่
เมื่อคุณกำหนดรายละเอียดทั้งหมดเกี่ยวกับโมดูลใหม่แล้ว ให้คลิกเสร็จสิ้นเพื่อสร้างโมดูลต่อ
การเปลี่ยนแปลงที่ทำโดยวิซาร์ดโมดูล
วิซาร์ดโมดูลทำการเปลี่ยนแปลงหลายอย่างกับโครงการของคุณ
ระบบจะเพิ่มโมดูล Gradle ชื่อ baselineprofile
หรือชื่อที่คุณเลือกในวิซาร์ด
โมดูลนี้ใช้ปลั๊กอิน com.android.test
ซึ่งบอกให้ Gradle ไม่รวมปลั๊กอินนี้ในแอปพลิเคชันของคุณ ดังนั้นจึงมีได้เฉพาะโค้ดการทดสอบหรือการเปรียบเทียบเท่านั้น นอกจากนี้ยังใช้ปลั๊กอิน androidx.baselineprofile
ซึ่งทำให้สร้างโปรไฟล์พื้นฐานได้โดยอัตโนมัติ
วิซาร์ดยังทำการเปลี่ยนแปลงโมดูลแอปพลิเคชันเป้าหมายที่คุณเลือกอีกด้วย กล่าวโดยละเอียดคือ ทรัพยากรดังกล่าวใช้ปลั๊กอิน androidx.baselineprofile
, เพิ่มทรัพยากร Dependency ของ androidx.profileinstaller
และเพิ่มทรัพยากร Dependency baselineProfile
ไปยังโมดูล build.gradle(.kts)
ที่สร้างขึ้นใหม่ ดังนี้
plugins {
id("androidx.baselineprofile")
}
dependencies {
// ...
implementation("androidx.profileinstaller:profileinstaller:1.3.0")
"baselineProfile"(project(mapOf("path" to ":baselineprofile")))
}
การเพิ่มทรัพยากร Dependency ของ androidx.profileinstaller
จะช่วยให้คุณทําสิ่งต่อไปนี้ได้
- ตรวจสอบประสิทธิภาพที่เพิ่มขึ้นของโปรไฟล์พื้นฐานที่สร้างขึ้นในพื้นที่
- ใช้โปรไฟล์พื้นฐานใน Android 7 (API ระดับ 24) และ Android 8 (Api ระดับ 26) ซึ่งไม่รองรับโปรไฟล์ Cloud
- ใช้โปรไฟล์พื้นฐานในอุปกรณ์ที่ไม่มีบริการ Google Play
ทรัพยากร Dependency baselineProfile(project(":baselineprofile"))
ทําให้ Gradle ทราบว่าต้องใช้โปรไฟล์พื้นฐานที่สร้างขึ้นจากโมดูลใด
ตอนนี้คุณได้ตั้งค่าโปรเจ็กต์แล้ว ให้เขียนคลาสตัวสร้างโปรไฟล์พื้นฐาน
5. เขียนตัวสร้างโปรไฟล์พื้นฐาน
โดยปกติแล้ว คุณจะสร้างโปรไฟล์พื้นฐานสำหรับเส้นทางของผู้ใช้ทั่วไปในแอป
วิซาร์ดโมดูลจะสร้างคลาสการทดสอบ BaselineProfileGenerator
พื้นฐานที่สามารถสร้างโปรไฟล์พื้นฐานสำหรับการเริ่มต้นแอปของคุณ และจะมีลักษณะดังต่อไปนี้
@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generate() {
rule.collect("com.example.baselineprofiles_codelab") {
// This block defines the app's critical user journey. This is where you
// optimize for app startup. You can also navigate and scroll
// through your most important UI.
// Start default activity for your app.
pressHome()
startActivityAndWait()
// TODO Write more interactions to optimize advanced journeys of your app.
// For example:
// 1. Wait until the content is asynchronously loaded.
// 2. Scroll the feed content.
// 3. Navigate to detail screen.
// Check UiAutomator documentation for more information about how to interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
}
}
ชั้นเรียนนี้ใช้กฎการทดสอบ BaselineProfileRule
และมีวิธีทดสอบ 1 วิธีสำหรับการสร้างโปรไฟล์ จุดแรกเข้าสำหรับการสร้างโปรไฟล์คือฟังก์ชัน collect()
โดยใช้พารามิเตอร์เพียง 2 ตัว ได้แก่
packageName
: แพ็กเกจของแอปprofileBlock
: พารามิเตอร์ lambda สุดท้าย
ใน lambda profileBlock
คุณจะระบุการโต้ตอบที่ครอบคลุมเส้นทางของผู้ใช้ทั่วไปในแอป ไลบรารีจะเรียกใช้ profileBlock
หลายครั้ง รวบรวมคลาสและฟังก์ชันที่เรียกใช้ และสร้างโปรไฟล์พื้นฐานในอุปกรณ์พร้อมกับโค้ดที่จะเพิ่มประสิทธิภาพ
โดยค่าเริ่มต้น คลาสตัวสร้างที่สร้างขึ้นจะมีการโต้ตอบเพื่อเริ่ม Activity
เริ่มต้น และรอจนกว่าเฟรมแรกของแอปจะแสดงผลโดยใช้เมธอด startActivityAndWait()
ขยายเครื่องมือสร้างด้วยเส้นทางที่กำหนดเอง
นอกจากนี้ คุณยังเห็นว่าคลาสที่สร้างขึ้นมี TODO
บางส่วนสำหรับเขียนการโต้ตอบเพิ่มเติมเพื่อเพิ่มประสิทธิภาพเส้นทางขั้นสูงของแอปด้วย ขอแนะนําให้ทําดังนี้เพื่อให้เพิ่มประสิทธิภาพได้นอกเหนือจากการเริ่มต้นแอป
ในแอปตัวอย่างของเรา คุณจะระบุเส้นทางเหล่านี้ได้โดยดำเนินการดังต่อไปนี้
- เริ่มต้นแอปพลิเคชัน คลาสที่สร้างขึ้นครอบคลุมส่วนนี้ไปแล้วบางส่วน
- รอจนกว่าเนื้อหาจะโหลดแบบไม่พร้อมกัน
- เลื่อนดูรายการอาหารว่าง
- ไปที่รายละเอียดอาหารว่าง
เปลี่ยนเครื่องมือสร้างให้มีฟังก์ชันสรุปที่ครอบคลุมเส้นทางทั่วไปในข้อมูลโค้ดต่อไปนี้
// ...
rule.collect("com.example.baselineprofiles_codelab") {
// This block defines the app's critical user journey. This is where you
// optimize for app startup. You can also navigate and scroll
// through your most important UI.
// Start default activity for your app.
pressHome()
startActivityAndWait()
// TODO Write more interactions to optimize advanced journeys of your app.
// For example:
// 1. Wait until the content is asynchronously loaded.
waitForAsyncContent()
// 2. Scroll the feed content.
scrollSnackListJourney()
// 3. Navigate to detail screen.
goToSnackDetailJourney()
// Check UiAutomator documentation for more information about how to interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
// ...
ต่อไป ให้เขียนการโต้ตอบของแต่ละเส้นทางที่กล่าวถึง คุณสามารถเขียนเป็นฟังก์ชันส่วนขยายของ MacrobenchmarkScope
เพื่อให้มีสิทธิ์เข้าถึงพารามิเตอร์และฟังก์ชันที่มี การเขียนในลักษณะนี้ช่วยให้คุณนำการโต้ตอบกับตัวเปรียบเทียบมาใช้ซ้ำเพื่อยืนยันประสิทธิภาพที่ได้รับ
รอเนื้อหาแบบไม่พร้อมกัน
แอปจำนวนมากมีการโหลดแบบไม่พร้อมกันบางอย่างเมื่อเริ่มต้นแอป หรือที่เรียกว่าสถานะแสดงอย่างเต็มที่ ซึ่งจะบอกระบบเมื่อเนื้อหาโหลดและแสดงผล และผู้ใช้จะโต้ตอบกับเนื้อหาได้ รอสถานะในโปรแกรมสร้าง (waitForAsyncContent
) ที่มีการโต้ตอบต่อไปนี้
- ค้นหารายการอาหารว่างในฟีด
- รอจนกว่าบางรายการในลิสต์นั้นจะปรากฏบนหน้าจอ
fun MacrobenchmarkScope.waitForAsyncContent() {
device.wait(Until.hasObject(By.res("snack_list")), 5_000)
val contentList = device.findObject(By.res("snack_list"))
// Wait until a snack collection item within the list is rendered.
contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
}
เส้นทางรายการแบบเลื่อน
สําหรับเส้นทางรายการอาหารว่างแบบเลื่อน (scrollSnackListJourney
) คุณติดตามการโต้ตอบต่อไปนี้ได้
- ค้นหาองค์ประกอบ UI ของรายการอาหารว่าง
- ตั้งค่าระยะขอบของท่าทางสัมผัสไม่ให้เรียกใช้การนำทางของระบบ
- เลื่อนรายการและรอจนกว่า UI จะดีขึ้น
fun MacrobenchmarkScope.scrollSnackListJourney() {
val snackList = device.findObject(By.res("snack_list"))
// Set gesture margin to avoid triggering gesture navigation.
snackList.setGestureMargin(device.displayWidth / 5)
snackList.fling(Direction.DOWN)
device.waitForIdle()
}
ไปที่เส้นทางโดยละเอียด
เส้นทางสุดท้าย (goToSnackDetailJourney
) นำการโต้ตอบต่อไปนี้ไปใช้
- ค้นหารายการอาหารว่างและขนมทั้งหมดที่คุณใช้ได้
- เลือกสินค้าจากรายการ
- คลิกรายการและรอจนกว่าหน้าจอรายละเอียดจะโหลด คุณใช้ประโยชน์จากข้อเท็จจริงที่ว่ารายการอาหารว่างไม่อยู่บนหน้าจออีกแล้ว
fun MacrobenchmarkScope.goToSnackDetailJourney() {
val snackList = device.findObject(By.res("snack_list"))
val snacks = snackList.findObjects(By.res("snack_item"))
// Select snack from the list based on running iteration.
val index = (iteration ?: 0) % snacks.size
snacks[index].click()
// Wait until the screen is gone = the detail is shown.
device.wait(Until.gone(By.res("snack_list")), 5_000)
}
หลังจากที่คุณกำหนดการโต้ตอบทั้งหมดที่จำเป็นเพื่อให้ตัวสร้างโปรไฟล์พื้นฐานพร้อมใช้งาน คุณจะต้องกำหนดอุปกรณ์ที่ใช้
6. เตรียมอุปกรณ์ที่จะเรียกใช้เครื่องกำเนิดไฟฟ้า
หากต้องการสร้างโปรไฟล์พื้นฐาน เราขอแนะนำให้ใช้โปรแกรมจำลอง เช่น อุปกรณ์ที่มีการจัดการโดย Gradle หรืออุปกรณ์ที่ใช้ Android 13 (API 33) ขึ้นไป
คุณสามารถใช้อุปกรณ์ที่มีการจัดการของ Gradle เพื่อทำให้กระบวนการทำซ้ำได้และสร้างโปรไฟล์พื้นฐานโดยอัตโนมัติ อุปกรณ์ที่มีการจัดการของ Gradle ให้คุณเรียกใช้การทดสอบในโปรแกรมจำลองของ Android โดยไม่ต้องเปิดใช้งานและแยกอุปกรณ์ออกด้วยตนเอง ดูข้อมูลเพิ่มเติมเกี่ยวกับอุปกรณ์ที่มีการจัดการของ Gradle ได้ในปรับขนาดการทดสอบด้วยอุปกรณ์ที่มีการจัดการของ Gradle
หากต้องการกำหนดอุปกรณ์ที่มีการจัดการของ Gradle ให้เพิ่มคำจำกัดความลงในไฟล์ :baselineprofile
โมดูล build.gradle.kts
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
android {
// ...
testOptions.managedDevices.devices {
create<ManagedVirtualDevice>("pixel6Api31") {
device = "Pixel 6"
apiLevel = 31
systemImageSource = "aosp"
}
}
}
ในกรณีนี้ เราใช้ Android 11 (API ระดับ 31) และอิมเมจระบบ aosp
มีสิทธิ์เข้าถึงแบบรูทได้
ถัดไป ให้กำหนดค่าปลั๊กอิน Baseline Profile Gradle ใช้อุปกรณ์ที่มีการจัดการโดย Gradle ที่กำหนด ในการดําเนินการดังกล่าว ให้เพิ่มชื่ออุปกรณ์ลงในพร็อพเพอร์ตี้ managedDevices
และปิดใช้ useConnectedDevices
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
android {
// ...
}
baselineProfile {
managedDevices += "pixel6Api31"
useConnectedDevices = false
}
dependencies {
// ...
}
จากนั้นให้สร้างโปรไฟล์พื้นฐาน
7. สร้างโปรไฟล์พื้นฐาน
เมื่ออุปกรณ์พร้อมแล้ว คุณก็สร้างโปรไฟล์พื้นฐานได้ ปลั๊กอิน Baseline Profile Gradle จะสร้างงาน Gradle ขึ้น เพื่อทำให้ขั้นตอนทั้งหมดในการเรียกใช้คลาสทดสอบของโปรแกรมสร้างทำงานโดยอัตโนมัติ และนำโปรไฟล์พื้นฐานที่สร้างขึ้นไปใช้กับแอปของคุณ
วิซาร์ดโมดูลใหม่สร้างการกำหนดค่าการเรียกใช้เพื่อให้เรียกใช้งาน Gradle ที่มีพารามิเตอร์ที่จำเป็นทั้งหมดเพื่อเรียกใช้ได้อย่างรวดเร็วโดยไม่ต้องสลับระหว่างเทอร์มินัลและ Android Studio
หากต้องการเรียกใช้ ให้ค้นหาการกำหนดค่าการเรียกใช้ Generate Baseline Profile
แล้วคลิกปุ่มเรียกใช้
งานจะเริ่มต้นอิมเมจโปรแกรมจำลองที่ระบุไว้ก่อนหน้านี้ เรียกใช้การโต้ตอบจากคลาสทดสอบ BaselineProfileGenerator
หลายๆ ครั้ง จากนั้นแยกโปรแกรมจำลองออกแล้วส่งเอาต์พุตไปยัง Android Studio
เมื่อเครื่องมือสร้างเสร็จสมบูรณ์ ปลั๊กอิน Gradle จะวาง baseline-prof.txt
ที่สร้างขึ้นลงในแอปพลิเคชันเป้าหมาย (โมดูล :app
) ในโฟลเดอร์ src/release/generated/baselineProfile/
โดยอัตโนมัติ
(ไม่บังคับ) เรียกใช้โปรแกรมสร้างจากบรรทัดคำสั่ง
หรือเรียกใช้โปรแกรมสร้างจากบรรทัดคำสั่งก็ได้ คุณสามารถใช้ประโยชน์จากงานที่สร้างโดยอุปกรณ์ที่มีการจัดการของ Gradle - :app:generateBaselineProfile
คำสั่งนี้จะเรียกใช้การทดสอบทั้งหมดในโปรเจ็กต์ที่กำหนดโดยทรัพยากร Dependency baselineProfile(project(:baselineProfile))
เนื่องจากโมดูลยังมีการเปรียบเทียบสำหรับการยืนยันประสิทธิภาพที่เพิ่มขึ้นในภายหลัง การทดสอบดังกล่าวจึงล้มเหลวโดยมีคำเตือนเกี่ยวกับการเรียกใช้การเปรียบเทียบในโปรแกรมจำลอง
android .testInstrumentationRunnerArguments .androidx.benchmark.enabledRules=BaselineProfile
สำหรับกรณีนี้ คุณสามารถกรองตัวสร้างโปรไฟล์พื้นฐานทั้งหมดที่มีอาร์กิวเมนต์ตัวเรียกใช้การวัดต่อไปนี้ และข้ามการเปรียบเทียบทั้งหมด
คำสั่งทั้งหมดจะมีลักษณะดังนี้
./gradlew :app:generateBaselineProfile -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
เผยแพร่แอปด้วยโปรไฟล์พื้นฐาน
เมื่อสร้างโปรไฟล์พื้นฐานและคัดลอกลงในซอร์สโค้ดของแอปแล้ว ให้สร้างแอปเวอร์ชันที่ใช้งานจริงตามปกติ คุณไม่จำเป็นต้องดำเนินการใดๆ เพิ่มเติมเพื่อแจกจ่ายโปรไฟล์พื้นฐานให้กับผู้ใช้ ปลั๊กอินจะเลือกโดยปลั๊กอิน Android Gradle ระหว่างบิลด์และรวมอยู่ใน AAB หรือ APK ต่อไป ให้อัปโหลดบิลด์ไปยัง Google Play
เมื่อผู้ใช้ติดตั้งแอปหรืออัปเดตแอปจากเวอร์ชันก่อนหน้า ระบบจะติดตั้งโปรไฟล์พื้นฐานด้วยเช่นกัน ซึ่งส่งผลให้เกิดประสิทธิภาพที่ดีขึ้นตั้งแต่การเรียกใช้แอปครั้งแรก
ขั้นตอนถัดไปจะแสดงวิธีตรวจสอบว่าประสิทธิภาพของแอปมีการปรับปรุงมากน้อยเพียงใดโดยใช้โปรไฟล์พื้นฐาน
8. (ไม่บังคับ) ปรับแต่งการสร้างโปรไฟล์พื้นฐาน
ปลั๊กอิน Gradle โปรไฟล์พื้นฐานมีตัวเลือกให้คุณปรับแต่งวิธีการสร้างโปรไฟล์ให้ตรงกับความต้องการเฉพาะของคุณ คุณเปลี่ยนลักษณะการทำงานได้ด้วยบล็อกการกำหนดค่า baselineProfile { }
ในสคริปต์บิลด์
บล็อกการกำหนดค่าภายในโมดูล :baselineprofile
จะส่งผลต่อวิธีเรียกใช้เครื่องมือสร้างที่สามารถเพิ่ม managedDevices
และตัดสินใจว่าจะuseConnectedDevices
หรืออุปกรณ์ที่จัดการโดย Gradle
บล็อกการกำหนดค่าภายในโมดูลเป้าหมาย :app
จะกำหนดว่าระบบจะบันทึกโปรไฟล์ไว้ที่ใดหรือสร้างขึ้นอย่างไร คุณสามารถเปลี่ยนพารามิเตอร์ต่อไปนี้ได้
automaticGenerationDuringBuild
: หากเปิดใช้ คุณจะสร้างโปรไฟล์พื้นฐานได้เมื่อสร้างบิลด์เวอร์ชันที่ใช้งานจริง ซึ่งจะเป็นประโยชน์เมื่อสร้างบน CI ก่อนจัดส่งแอปsaveInSrc
: ระบุว่าเก็บโปรไฟล์พื้นฐานที่สร้างขึ้นไว้ในโฟลเดอร์src/
หรือไม่ หรือคุณจะเข้าถึงไฟล์จากโฟลเดอร์บิลด์:baselineprofile
ก็ได้baselineProfileOutputDir
: กำหนดตำแหน่งที่เก็บโปรไฟล์พื้นฐานที่สร้างขึ้นmergeIntoMain
: โดยค่าเริ่มต้น ระบบจะสร้างโปรไฟล์พื้นฐานตามตัวแปรของบิลด์ (เวอร์ชันผลิตภัณฑ์และประเภทบิลด์) หากต้องการรวมโปรไฟล์ทั้งหมดลงในsrc/main
คุณสามารถทำได้โดยเปิดใช้การตั้งค่าสถานะนี้filter
: คุณกรองคลาสหรือวิธีการที่จะรวมหรือยกเว้นจากโปรไฟล์พื้นฐานที่สร้างขึ้นได้ การดำเนินการนี้จะเป็นประโยชน์สำหรับนักพัฒนาไลบรารีที่ต้องการเฉพาะโค้ดจากไลบรารีที่รวมอยู่
9. ยืนยันการปรับปรุงประสิทธิภาพสตาร์ทอัพ
หลังจากสร้างโปรไฟล์พื้นฐานและเพิ่มลงในแอปแล้ว ให้ตรวจสอบว่าโปรไฟล์ดังกล่าวส่งผลต่อประสิทธิภาพของแอปตามที่ต้องการ
วิซาร์ดโมดูลใหม่จะสร้างคลาสการเปรียบเทียบชื่อ StartupBenchmarks
ซึ่งมีการเปรียบเทียบเพื่อวัดเวลาเริ่มต้นของแอป และเปรียบเทียบกับเมื่อแอปใช้โปรไฟล์พื้นฐาน
ชั้นเรียนจะมีลักษณะดังนี้
@RunWith(AndroidJUnit4::class)
@LargeTest
class StartupBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun startupCompilationNone() =
benchmark(CompilationMode.None())
@Test
fun startupCompilationBaselineProfiles() =
benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
private fun benchmark(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(StartupTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.COLD,
iterations = 10,
setupBlock = {
pressHome()
},
measureBlock = {
startActivityAndWait()
// TODO Add interactions to wait for when your app is fully drawn.
// The app is fully drawn when Activity.reportFullyDrawn is called.
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
// from the AndroidX Activity library.
// Check the UiAutomator documentation for more information on how to
// interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
)
}
}
โดยใช้ MacrobenchmarkRule
ที่สามารถเรียกใช้การเปรียบเทียบสำหรับแอปและรวบรวมเมตริกประสิทธิภาพได้ จุดแรกเข้าสำหรับการเขียนการเปรียบเทียบคือฟังก์ชัน measureRepeated
จากกฎ
โดยต้องใช้พารามิเตอร์หลายรายการ ดังนี้
packageName:
แอปพลิเคชันที่จะวัดผลmetrics
: ประเภทข้อมูลที่คุณต้องการวัดในระหว่างการเปรียบเทียบiterations
: จำนวนครั้งที่การเปรียบเทียบเกิดซ้ำstartupMode
: วิธีที่คุณต้องการให้แอปพลิเคชันของคุณเริ่มต้นเมื่อเริ่มการเปรียบเทียบsetupBlock
: การโต้ตอบกับแอปต้องเกิดขึ้นก่อนจึงจะวัดผลได้measureBlock
: การโต้ตอบกับแอปที่คุณต้องการวัดในระหว่างการเปรียบเทียบ
คลาสการทดสอบยังมีการทดสอบ 2 รายการด้วย ได้แก่ startupCompilationeNone()
และ startupCompilationBaselineProfiles()
ซึ่งเรียกใช้ฟังก์ชัน benchmark()
ที่มี compilationMode
ที่แตกต่างกัน
CompilationMode
พารามิเตอร์ CompilationMode
จะกำหนดวิธีคอมไพล์แอปพลิเคชันเป็นโค้ดเครื่องล่วงหน้า ซึ่งมีตัวเลือกดังต่อไปนี้
DEFAULT
: คอมไพล์แอปล่วงหน้าบางส่วนโดยใช้โปรไฟล์พื้นฐาน หากมี ใช้เมื่อไม่มีการใช้พารามิเตอร์compilationMode
None()
: รีเซ็ตสถานะการคอมไพล์แอปและไม่คอมไพล์แอปล่วงหน้า การคอมไพล์แบบทันท่วงที (JIT) ยังคงเปิดใช้ในระหว่างการใช้งานแอปPartial()
: คอมไพล์แอปไว้ล่วงหน้าโดยใช้โปรไฟล์พื้นฐานหรือการอุ่นเครื่อง หรือทั้งสองอย่างFull()
: คอมไพล์โค้ดของแอปพลิเคชันทั้งหมดล่วงหน้า ตัวเลือกนี้เป็นตัวเลือกเดียวใน Android 6 (API 23) หรือต่ำกว่า
ถ้าต้องการเริ่มต้นเพิ่มประสิทธิภาพแอปพลิเคชัน คุณเลือกโหมดคอมไพล์ DEFAULT
ได้ เนื่องจากประสิทธิภาพจะคล้ายกับเวลาที่ติดตั้งแอปจาก Google Play ถ้าคุณต้องการเปรียบเทียบประโยชน์ด้านประสิทธิภาพที่ได้รับจากโปรไฟล์พื้นฐาน คุณสามารถทำได้โดยการเปรียบเทียบผลลัพธ์ของโหมดการรวบรวม None
และ Partial
แก้ไขการเปรียบเทียบเพื่อรอเนื้อหา
การเปรียบเทียบจะเขียนคล้ายกับตัวสร้างโปรไฟล์พื้นฐานด้วยการเขียนการโต้ตอบกับแอปของคุณ โดยค่าเริ่มต้น การเปรียบเทียบที่สร้างขึ้นจะรอให้มีการแสดงผลเฟรมแรกเท่านั้น ซึ่งคล้ายกับการทำงานของ BaselineProfileGenerator
เราจึงแนะนำให้ปรับปรุงเพื่อรอเนื้อหาแบบไม่พร้อมกัน
คุณสามารถทำได้โดยนำฟังก์ชันของส่วนขยายที่คุณเขียนไว้สำหรับโปรแกรมสร้างมาใช้ใหม่ เนื่องจากการเปรียบเทียบนี้จะบันทึกช่วงเวลาเริ่มต้น (เมื่อใช้ StartupTimingMetric()
) เราจึงขอแนะนําให้คุณใส่เฉพาะรอเนื้อหาแบบไม่พร้อมกันที่นี่ แล้วเขียนการเปรียบเทียบแยกต่างหากสำหรับเส้นทางอื่นๆ ของผู้ใช้ที่กำหนดไว้ในเครื่องมือสร้าง
// ...
measureBlock = {
startActivityAndWait()
// The app is fully drawn when Activity.reportFullyDrawn is called.
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
// from the AndroidX Activity library.
waitForAsyncContent() // <------- Added to wait for async content.
// Check the UiAutomator documentation for more information on how to
// interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
ทำการเปรียบเทียบ
คุณสามารถทำการเปรียบเทียบได้ในแบบเดียวกับที่ทำการทดสอบแบบมีเครื่องวัด คุณจะเรียกใช้ฟังก์ชันทดสอบ หรือเรียกใช้ทั้งชั้นเรียนก็ได้ โดยให้มีไอคอนรางน้ำอยู่ข้างๆ
โปรดเลือกอุปกรณ์จริง เนื่องจากการเรียกใช้การเปรียบเทียบในโปรแกรมจำลอง Android ล้มเหลวขณะรันไทม์ โดยมีคำเตือนว่าการเปรียบเทียบอาจให้ผลลัพธ์ที่ไม่ถูกต้อง แม้ว่าในทางเทคนิคคุณจะเรียกใช้ไฟล์ดังกล่าวบนโปรแกรมจำลองได้ แต่คุณกำลังวัดประสิทธิภาพของเครื่องโฮสต์อยู่ หากมีภาระงานหนักเกินไป เกณฑ์การเปรียบเทียบของคุณจะช้าลงและตรงกันข้าม
เมื่อคุณเรียกใช้การเปรียบเทียบ ระบบจะสร้างแอปของคุณขึ้นมาใหม่แล้วจึงเรียกใช้การเปรียบเทียบ การเปรียบเทียบจะเริ่มต้น หยุด และแม้แต่ติดตั้งแอปของคุณอีกครั้งหลายครั้งโดยอิงตามiterations
ที่คุณกำหนดไว้
หลังจากการเปรียบเทียบเสร็จสมบูรณ์ คุณจะดูเวลาได้ในเอาต์พุต Android Studio ดังที่แสดงในภาพหน้าจอต่อไปนี้
จากภาพหน้าจอ คุณจะเห็นว่าเวลาเริ่มต้นของแอปแตกต่างกันใน CompilationMode
แต่ละรายการ ค่ามัธยฐานจะแสดงในตารางต่อไปนี้
timeToInitialDisplay [มิลลิวินาที] | timeToFullDisplay [มิลลิวินาที] | |
ไม่มี | 202.2 | 818.8 |
BaselineProfiles | 193.7 | 637.9 |
การปรับปรุง | 4% | 28% |
ความแตกต่างระหว่างโหมดการรวบรวมสำหรับ timeToFullDisplay
คือ 180 มิลลิวินาที ซึ่งดีขึ้นประมาณ 28% เพียงแค่มีโปรไฟล์พื้นฐานเท่านั้น CompilationNone
ทำงานได้แย่ลงเนื่องจากอุปกรณ์มีการคอมไพล์ JIT บ่อยที่สุดในช่วงที่แอปเริ่มทำงาน CompilationBaselineProfiles
มีประสิทธิภาพดีกว่าเนื่องจากการคอมไพล์บางส่วนโดยใช้โปรไฟล์พื้นฐาน AOT จะรวบรวมโค้ดที่ผู้ใช้มีแนวโน้มจะใช้มากที่สุด และไม่ทำการคอมไพล์โค้ดที่ไม่สำคัญไว้ล่วงหน้าเพื่อไม่ต้องโหลดโดยทันที
10. (ไม่บังคับ) ตรวจสอบการปรับปรุงประสิทธิภาพการเลื่อน
เช่นเดียวกับขั้นตอนก่อนหน้า คุณจะวัดและตรวจสอบประสิทธิภาพในการเลื่อนได้ ขั้นแรก ให้สร้างคลาสการทดสอบ ScrollBenchmarks
ที่มีกฎการเปรียบเทียบและวิธีทดสอบ 2 วิธีที่ใช้โหมดการรวบรวมที่ต่างกัน ดังนี้
@LargeTest
@RunWith(AndroidJUnit4::class)
class ScrollBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun scrollCompilationNone() = scroll(CompilationMode.None())
@Test
fun scrollCompilationBaselineProfiles() = scroll(CompilationMode.Partial())
private fun scroll(compilationMode: CompilationMode) {
// TODO implement
}
}
จากภายในเมธอด scroll
ให้ใช้ฟังก์ชัน measureRepeated
กับพารามิเตอร์ที่ต้องระบุ สำหรับพารามิเตอร์ metrics
ให้ใช้ FrameTimingMetric
ซึ่งจะวัดระยะเวลาที่ใช้ในการสร้างเฟรม UI ดังนี้
private fun scroll(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.WARM,
iterations = 10,
setupBlock = {
// TODO implement
},
measureBlock = {
// TODO implement
}
)
}
ครั้งนี้คุณต้องแบ่งการโต้ตอบระหว่าง setupBlock
กับ measureBlock
ให้มากขึ้นเพื่อวัดระยะเวลาของเฟรมระหว่างเลย์เอาต์แรกและเลื่อนเนื้อหาเท่านั้น ดังนั้น ให้วางฟังก์ชันที่เริ่มต้นหน้าจอเริ่มต้นไว้ที่ setupBlock
และฟังก์ชันของส่วนขยายที่สร้างไว้แล้ว waitForAsyncContent()
และ scrollSnackListJourney()
ลงใน measureBlock
ดังนี้
private fun scroll(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.WARM,
iterations = 10,
setupBlock = {
pressHome()
startActivityAndWait()
},
measureBlock = {
waitForAsyncContent()
scrollSnackListJourney()
}
)
}
เมื่อการเปรียบเทียบพร้อมแล้ว คุณสามารถเรียกใช้การเปรียบเทียบก่อนหน้าเพื่อให้ได้ผลลัพธ์ดังที่แสดงในภาพหน้าจอต่อไปนี้
FrameTimingMetric
จะแสดงระยะเวลาของเฟรมเป็นมิลลิวินาที (frameDurationCpuMs
) ในเปอร์เซ็นไทล์ที่ 50, 90, 95 และ 99 ใน Android 12 (API ระดับ 31) ขึ้นไป ระบบจะแสดงระยะเวลาที่เฟรมเกินขีดจำกัด (frameOverrunMs
) ด้วย ค่าอาจเป็นลบ ซึ่งหมายความว่ามีเวลาเหลือในการสร้างเฟรม
จากผลลัพธ์ คุณจะเห็นว่า CompilationBaselineProfiles
มีระยะเวลาโดยเฉลี่ยของเฟรมที่สั้นลง 2 มิลลิวินาที ซึ่งผู้ใช้อาจมองไม่เห็น อย่างไรก็ตาม สำหรับเปอร์เซ็นไทล์อื่นๆ ผลลัพธ์จะเห็นได้ชัดกว่า สำหรับ P99 ความแตกต่างคือ 43.5 มิลลิวินาที ซึ่งเท่ากับเฟรมที่ข้ามมากกว่า 3 เฟรมในอุปกรณ์ที่ทำงานที่ 90 FPS เช่น สำหรับ Pixel 6 จะใช้เวลา 1, 000 มิลลิวินาที / 90 FPS = เวลาสูงสุดประมาณ 11 มิลลิวินาทีในการแสดงภาพเฟรม
11. ขอแสดงความยินดี
ขอแสดงความยินดี คุณดำเนินการ Codelab นี้เสร็จแล้ว และปรับปรุงประสิทธิภาพของแอปด้วยโปรไฟล์พื้นฐาน
แหล่งข้อมูลเพิ่มเติม
โปรดดูแหล่งข้อมูลเพิ่มเติมต่อไปนี้
- ตรวจสอบประสิทธิภาพของแอปด้วย Macrobenchmark: Codelab ที่เจาะลึกกว่าด้วยการเปรียบเทียบ
- ตัวอย่างประสิทธิภาพ: ที่เก็บที่มีการเปรียบเทียบมาโครและตัวอย่างประสิทธิภาพอื่นๆ
- Now In Android ตัวอย่างแอป: แอปพลิเคชันจริงที่ใช้การเปรียบเทียบและโปรไฟล์พื้นฐานเพื่อปรับปรุงประสิทธิภาพ