1. ก่อนเริ่มต้น
โค้ดแล็บนี้แสดงวิธีสร้างโปรไฟล์พื้นฐานเพื่อเพิ่มประสิทธิภาพของแอปพลิเคชัน และวิธียืนยันประโยชน์ด้านประสิทธิภาพของการใช้โปรไฟล์พื้นฐาน
สิ่งที่ต้องมี
- Android Studio Hedgehog (2023.1.1) ขึ้นไป
- ปลั๊กอิน Android Gradle 8.0 ขึ้นไป
- ความเข้าใจพื้นฐานเกี่ยวกับ Macrobenchmark ของ Jetpack
- อุปกรณ์ Android ที่ใช้ Android 7 (API ระดับ 24) ขึ้นไป
สิ่งที่ต้องทำ
- ตั้งค่าโปรเจ็กต์เพื่อใช้เครื่องมือสร้างโปรไฟล์พื้นฐาน
- สร้างโปรไฟล์พื้นฐานเพื่อเพิ่มประสิทธิภาพการเริ่มเปิดแอปและการเลื่อน
- ยืนยันประสิทธิภาพที่เพิ่มขึ้นด้วยคลัง Macrobenchmark ของ Jetpack
สิ่งที่คุณจะได้เรียนรู้
- โปรไฟล์พื้นฐานและวิธีที่โปรไฟล์พื้นฐานช่วยปรับปรุงประสิทธิภาพของแอป
- วิธีสร้างโปรไฟล์พื้นฐาน
- ประสิทธิภาพที่เพิ่มขึ้นของโปรไฟล์พื้นฐาน
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) สามารถเพิ่มประสิทธิภาพเส้นทางโค้ดที่รวมไว้ผ่านการคอมไพล์ล่วงหน้า (AOT) ซึ่งจะปรับปรุงประสิทธิภาพให้กับผู้ใช้ใหม่ทุกคนและในการอัปเดตแอปทุกครั้ง การเพิ่มประสิทธิภาพที่แนะนำโดยโปรไฟล์ (PGO) นี้ช่วยให้แอปเพิ่มประสิทธิภาพการเริ่มต้น ลดการกระตุกในการโต้ตอบ และปรับปรุงประสิทธิภาพรันไทม์โดยรวมสำหรับผู้ใช้ปลายทางตั้งแต่การเปิดตัวครั้งแรก
การใช้โปรไฟล์พื้นฐานจะทำให้การโต้ตอบทั้งหมดของผู้ใช้ เช่น การเริ่มต้นแอป การไปยังส่วนต่างๆ ของหน้าจอ หรือการเลื่อนดูเนื้อหา เป็นไปอย่างราบรื่นตั้งแต่ครั้งแรกที่ใช้งาน การเพิ่มความเร็วและการตอบสนองของแอปจะทำให้มีผู้ใช้ที่ใช้งานอยู่รายวันมากขึ้นและอัตรากลับมาเข้าชมโดยเฉลี่ยสูงขึ้น
โปรไฟล์พื้นฐานช่วยแนะแนวทางในการเพิ่มประสิทธิภาพที่มากกว่าการเริ่มต้นใช้งานแอป ด้วยการแสดงการโต้ตอบของผู้ใช้ทั่วไป ซึ่งจะปรับปรุงรันไทม์ของแอปตั้งแต่การเปิดใช้ครั้งแรก การคอมไพล์ AOT แบบมีคำแนะนำไม่ได้ใช้อุปกรณ์ของผู้ใช้ และสามารถทำได้ 1 ครั้งต่อรุ่นบนเครื่องสำหรับการพัฒนาแทนที่จะใช้อุปกรณ์เคลื่อนที่ การใช้โปรไฟล์พื้นฐานในรุ่นที่เผยแพร่จะช่วยให้การเพิ่มประสิทธิภาพแอปพร้อมใช้งานเร็วกว่ามากเมื่อเทียบกับการใช้โปรไฟล์ในระบบคลาวด์เพียงอย่างเดียว
เมื่อไม่ได้ใช้โปรไฟล์พื้นฐาน โค้ดแอปทั้งหมดจะได้รับการคอมไพล์แบบ 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) ซึ่งไม่รองรับโปรไฟล์ระบบคลาวด์
- ใช้โปรไฟล์พื้นฐานในอุปกรณ์ที่ไม่มีบริการ 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 รายการสําหรับการสร้างโปรไฟล์ EntryPoint ในการสร้างโปรไฟล์คือฟังก์ชัน collect()
โดยต้องใช้พารามิเตอร์เพียง 2 รายการ ได้แก่
packageName
: แพ็กเกจของแอปprofileBlock
: พารามิเตอร์ lambda สุดท้าย
ใน lambda ของ profileBlock
คุณจะระบุการโต้ตอบที่ครอบคลุมเส้นทางผู้ใช้ทั่วไปของแอป ไลบรารีจะเรียกใช้ profileBlock
หลายครั้ง รวบรวมคลาสและฟังก์ชันที่เรียก และสร้างโปรไฟล์พื้นฐานในอุปกรณ์พร้อมกับโค้ดที่จะเพิ่มประสิทธิภาพ
โดยค่าเริ่มต้น คลาส Generator ที่สร้างขึ้นจะมีการโต้ตอบเพื่อเริ่ม 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
module 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 [ms] | |
ไม่มี | 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 ที่เจาะลึกการเปรียบเทียบประสิทธิภาพ
- ตัวอย่างประสิทธิภาพ: ที่เก็บซึ่งมี Macrobenchmark และตัวอย่างประสิทธิภาพอื่นๆ
- ตอนนี้มีในแอปตัวอย่างของ Android: แอปพลิเคชันในชีวิตจริงที่ใช้การเปรียบเทียบและโปรไฟล์พื้นฐานเพื่อปรับปรุงประสิทธิภาพ