โปรเจ็กต์ขนาดใหญ่หรือโปรเจ็กต์ที่ใช้ตรรกะการบิลด์ที่กำหนดเองจำนวนมากอาจกำหนดให้คุณต้องพิจารณากระบวนการบิลด์อย่างละเอียดมากขึ้นเพื่อค้นหาจุดคอขวด
คุณทำได้โดยการทำโปรไฟล์ระยะเวลาที่ Gradle ใช้ในการดำเนินการแต่ละระยะของวงจรการสร้างและงานการสร้างแต่ละงาน ตัวอย่างเช่น หากโปรไฟล์บิลด์แสดงว่า Gradle ใช้เวลามากเกินไปในการกำหนดค่าโปรเจ็กต์ ระบบอาจแนะนำว่าคุณต้องย้ายตรรกะบิลด์ที่กำหนดเองออกจากระยะการกำหนดค่า
นอกจากนี้ หากงาน mergeDevDebugResources ใช้เวลาในการบิลด์นาน อาจบ่งบอกว่าคุณต้องแปลงรูปภาพเป็น WebP หรือปิดใช้การบีบอัด PNG
หากคุณใช้ Android Studio 4.0 ขึ้นไป วิธีที่ดีที่สุดในการตรวจสอบปัญหาด้านประสิทธิภาพของบิลด์คือการใช้ตัววิเคราะห์บิลด์
นอกจากนี้ ยังมี 2 ตัวเลือกสำหรับการทำโปรไฟล์บิลด์นอก Android Studio ดังนี้
เครื่องมือ
gradle-profilerแบบสแตนด์อโลน ซึ่งเป็นเครื่องมือที่มีประสิทธิภาพสำหรับการวิเคราะห์บิลด์อย่างละเอียดตัวเลือก
--profileของ Gradle ซึ่งเป็นเครื่องมือที่สะดวกซึ่งพร้อมใช้งานจากบรรทัดคำสั่ง Gradle
การใช้เครื่องมือ gradle-profiler แบบสแตนด์อโลน
หากต้องการค้นหาการตั้งค่าโปรเจ็กต์ที่ให้ความเร็วในการบิลด์ที่ดีที่สุด คุณควรใช้ Gradle Profiler ซึ่งเป็นเครื่องมือสำหรับรวบรวมข้อมูลการทำโปรไฟล์และการเปรียบเทียบสำหรับบิลด์ Gradle เครื่องมือสร้างโปรไฟล์ Gradle ช่วยให้คุณสร้างสถานการณ์การบิลด์และเรียกใช้หลายครั้งได้ ซึ่งจะช่วยป้องกันความแปรปรวนสูงระหว่างผลลัพธ์และทำให้ผลลัพธ์ทำซ้ำได้
คุณควรใช้โหมดการเปรียบเทียบเพื่อรวบรวมข้อมูลเกี่ยวกับบิลด์ใหม่และบิลด์ที่เพิ่มขึ้น ส่วนโหมดการทำโปรไฟล์สามารถใช้เพื่อรวบรวมข้อมูลที่ละเอียดยิ่งขึ้นเกี่ยวกับการเรียกใช้ รวมถึงสแนปชอต CPU
การกำหนดค่าการตั้งค่าโปรเจ็กต์สำหรับการเปรียบเทียบมีดังนี้
- เวอร์ชันปลั๊กอิน
- เวอร์ชัน Gradle
- การตั้งค่า JVM (ขนาดฮีป, ขนาด PermGen, การเก็บขยะ ฯลฯ)
- จำนวนเวิร์กเกอร์ Gradle (
org.gradle.workers.max) - ตัวเลือกต่อปลั๊กอินเพื่อเพิ่มประสิทธิภาพให้ดียิ่งขึ้น
เริ่มต้นใช้งาน
- ติดตั้ง gradle-profiler โดยทำตามวิธีการเหล่านี้
- วิ่ง:
gradle-profiler --benchmark --project-dir <root-project> :app:assembleDebug
ซึ่งจะเปรียบเทียบกับบิลด์ที่อัปเดตอย่างสมบูรณ์ เนื่องจาก --benchmark จะเรียกใช้งานหลายครั้งโดยไม่มีการเปลี่ยนแปลงโปรเจ็กต์ในระหว่างนั้น จากนั้นจะสร้างรายงาน HTML ในไดเรกทอรี profile-out/ ซึ่งแสดงเวลาในการสร้าง
ยังมีสถานการณ์อื่นๆ ที่อาจมีประโยชน์มากกว่าในการเปรียบเทียบ ดังนี้
- การเปลี่ยนแปลงโค้ดในเนื้อหาเมธอดในคลาสที่คุณทำงานส่วนใหญ่
- การเปลี่ยนแปลง API ในโมดูลที่ใช้ทั่วทั้งโปรเจ็กต์ แม้ว่าจะเกิดขึ้นไม่บ่อยเท่ากับการเปลี่ยนแปลงโค้ดของคุณเอง แต่ก็มีผลกระทบมากกว่าและควรวัดผล
- การแก้ไขเลย์เอาต์เพื่อจำลองการทำซ้ำในงาน UI
- String edits to simulate dealing with translation work.
- ล้างบิลด์เพื่อจำลองการเปลี่ยนแปลงในบิลด์เอง (เช่น การอัปเดตปลั๊กอิน Android Gradle, การอัปเดต Gradle หรือการแก้ไขโค้ดบิลด์ของคุณเองใน
buildSrc)
หากต้องการเปรียบเทียบ Use Case เหล่านี้ คุณสามารถสร้างสถานการณ์ที่จะใช้เพื่อขับเคลื่อนการดำเนินการ gradle-profiler และใช้การเปลี่ยนแปลงที่เหมาะสมกับแหล่งที่มาของคุณ ส่วนต่อไปนี้จะอธิบายสถานการณ์ที่พบบ่อยบางสถานการณ์
การทำโปรไฟล์การตั้งค่าหน่วยความจำ/CPU ที่แตกต่างกัน
หากต้องการเปรียบเทียบการตั้งค่าหน่วยความจำและ CPU ที่แตกต่างกัน คุณสามารถสร้างสถานการณ์หลายรายการที่ใช้ค่า org.gradle.jvmargs ต่างกันได้ ตัวอย่างเช่น คุณสามารถสร้างสถานการณ์ต่อไปนี้ได้
# <root-project>/scenarios.txt
clean_build_2gb_4workers {
tasks = [":app:assembleDebug"]
gradle-args = ["--max-workers=4"]
jvm-args = ["-Xmx2048m"]
cleanup-tasks = ["clean"]
}
clean_build_parallelGC {
tasks = [":app:assembleDebug"]
jvm-args = ["-XX:+UseParallelGC"]
cleanup-tasks = ["clean"]
}
clean_build_G1GC_4gb {
tasks = [":app:assembleDebug"]
jvm-args = ["-Xmx4096m", "-XX:+UseG1GC"]
cleanup-tasks = ["clean"]
}
การเรียกใช้ gradle-profiler --benchmark --project-dir
<root-project> --scenario-file scenarios.txt จะเรียกใช้ 3 สถานการณ์ และคุณจะเปรียบเทียบได้ว่า :app:assembleDebug ใช้เวลานานเท่าใดสำหรับการตั้งค่าแต่ละรายการเหล่านี้
การทำโปรไฟล์ปลั๊กอิน Gradle เวอร์ชันต่างๆ
หากต้องการดูว่าการเปลี่ยนเวอร์ชันของปลั๊กอิน Gradle ส่งผลต่อเวลาในการสร้างอย่างไร ให้สร้างสถานการณ์สำหรับการเปรียบเทียบ ซึ่งต้องมีการเตรียมการบางอย่างเพื่อให้สามารถแทรกเวอร์ชันปลั๊กอินจากสถานการณ์ได้ เปลี่ยน build.gradle ระดับรูท:
# <root-project>/build.gradle
buildscript {
def agpVersion = providers.systemProperty("agpVersion").forUseAtConfigurationTime().orNull ?: '4.1.0'
ext.kotlin = providers.systemProperty('kotlinVersion').forUseAtConfigurationTime().orNull ?: '1.4.0'
dependencies {
classpath "com.android.tools.build:gradle:$agpVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
}
}
ตอนนี้คุณสามารถระบุเวอร์ชันปลั๊กอิน Android Gradle และปลั๊กอิน Kotlin Gradle จากไฟล์สถานการณ์ และให้สถานการณ์เพิ่มเมธอดใหม่ลงในไฟล์ต้นฉบับได้แล้ว
# <root-project>/scenarios.txt
non_abi_change_agp4.1.0_kotlin1.4.10 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.1.0"
"kotlinVersion" = "1.4.10"
}
non_abi_change_agp4.2.0_kotlin1.4.20 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.2.0-alpha16"
"kotlinVersion" = "1.4.20"
}
การทำโปรไฟล์บิลด์แบบเพิ่ม
บิลด์ส่วนใหญ่เป็นแบบเพิ่มขึ้นทีละน้อย ซึ่งทำให้เป็นหนึ่งในสถานการณ์ที่สำคัญที่สุดในการทำโปรไฟล์ เครื่องมือสร้างโปรไฟล์ Gradle รองรับการสร้างโปรไฟล์บิลด์ที่เพิ่มขึ้นอย่างครอบคลุม โดยสามารถใช้การเปลี่ยนแปลงกับไฟล์ต้นฉบับโดยอัตโนมัติด้วยการเปลี่ยนเนื้อหาเมธอด เพิ่มเมธอดใหม่ หรือเปลี่ยนเลย์เอาต์หรือทรัพยากรสตริง ตัวอย่างเช่น คุณสามารถสร้างสถานการณ์ที่เพิ่มขึ้นได้ดังนี้
# <root-project>/scenarios.txt
non_abi_change {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
abi_change {
tasks = [":app:assembleDebug"]
apply-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
layout_change {
tasks = [":app:assembleDebug"]
apply-android-layout-change-to = "app/src/main/res/your_layout_file.xml"
}
string_resource_change {
tasks = [":app:assembleDebug"]
apply-android-resource-value-change-to = "app/src/main/res/values/strings.xml"
}
การเรียกใช้ gradle-profiler --benchmark --project-dir <root-project>
--scenario-file scenarios.txt จะสร้างรายงาน HTML ที่มีข้อมูลการเปรียบเทียบ
คุณสามารถรวมสถานการณ์แบบเพิ่มทีละส่วนกับการตั้งค่าอื่นๆ ได้ เช่น ขนาดฮีป จำนวนผู้ปฏิบัติงาน หรือเวอร์ชัน Gradle ดังนี้
# <root-project>/scenarios.txt
non_abi_change_4g {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
}
non_abi_change_4g_8workers {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
gradle-args = ["--max-workers=8"]
}
non_abi_change_3g_gradle67 {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx3072m"]
version = ["6.7"]
}
การทำโปรไฟล์บิลด์เปล่า
หากต้องการเปรียบเทียบการบิลด์ใหม่ คุณสามารถสร้างสถานการณ์ที่จะใช้เพื่อขับเคลื่อนการดำเนินการ gradle-profiler ได้ดังนี้
# <root-project>/scenarios.txt
clean_build {
tasks = [":app:assembleDebug"]
cleanup-tasks = ["clean"]
}
หากต้องการเรียกใช้สถานการณ์นี้ ให้ใช้คำสั่งต่อไปนี้
gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt
การใช้ตัวเลือก Gradle --profile
หากต้องการสร้างและดูโปรไฟล์บิลด์จากบรรทัดคำสั่ง Gradle ให้ทำตามขั้นตอนต่อไปนี้
เปิดเทอร์มินัลบรรทัดคำสั่งที่รูทของโปรเจ็กต์
ทำการบิลด์ใหม่ทั้งหมดโดยป้อนคำสั่งต่อไปนี้ ขณะทำโปรไฟล์บิลด์ คุณควรทำการคลีนบิลด์ระหว่างแต่ละบิลด์ที่ทำโปรไฟล์ เนื่องจาก Gradle จะข้ามงานเมื่ออินพุตของงาน (เช่น ซอร์สโค้ด) ไม่มีการเปลี่ยนแปลง ดังนั้น การบิลด์ครั้งที่ 2 ที่ไม่มีการเปลี่ยนแปลงอินพุตจึงทำงานได้เร็วกว่าเสมอเนื่องจากไม่มีการรันงานซ้ำ ดังนั้นการเรียกใช้
cleanระหว่างบิลด์จะช่วยให้คุณสร้างโปรไฟล์กระบวนการบิลด์ทั้งหมดได้// On Mac or Linux, run the Gradle wrapper using "./gradlew". gradlew cleanเรียกใช้บิลด์การแก้ไขข้อบกพร่องของเวอร์ชันผลิตภัณฑ์รายการใดรายการหนึ่ง เช่น เวอร์ชัน "dev" โดยใช้แฟล็กต่อไปนี้
gradlew --profile --offline --rerun-tasks assemble<var>Flavor</var>Debug--profile: เปิดใช้การทำโปรไฟล์--offline: ปิดใช้ Gradle ไม่ให้ดึงข้อมูลทรัพยากร Dependency ออนไลน์ ซึ่งจะช่วยให้มั่นใจว่าความล่าช้าที่เกิดจาก Gradle ที่พยายามอัปเดตทรัพยากร Dependency จะไม่รบกวนข้อมูลการทำโปรไฟล์ คุณควรสร้างโปรเจ็กต์ไว้แล้ว 1 ครั้งเพื่อให้แน่ใจว่า Gradle ได้ดาวน์โหลดและแคชทรัพยากร Dependency ไว้แล้ว--rerun-tasks: บังคับให้ Gradle เรียกใช้งานทั้งหมดอีกครั้งและละเว้นการเพิ่มประสิทธิภาพงาน
หลังจากสร้างเสร็จแล้ว ให้ใช้หน้าต่างโปรเจ็กต์เพื่อไปยังไดเรกทอรี
project-root/build/reports/profile/(ดังที่แสดงในรูปที่ 1)
รูปที่ 1 มุมมองโปรเจ็กต์ที่แสดงตำแหน่งของรายงานโปรไฟล์
คลิกขวาที่ไฟล์
profile-timestamp.htmlแล้วเลือกเปิดในเบราว์เซอร์ > ค่าเริ่มต้น รายงานควรมีลักษณะคล้ายกับที่แสดงในรูปที่ 2 คุณสามารถตรวจสอบแต่ละแท็บในรายงานเพื่อดูข้อมูลเกี่ยวกับบิลด์ เช่น แท็บการดำเนินการงาน ซึ่งแสดงระยะเวลาที่ Gradle ใช้ในการดำเนินการงานบิลด์แต่ละรายการ
รูปที่ 2 การดูรายงานในเบราว์เซอร์
ไม่บังคับ: ก่อนทำการเปลี่ยนแปลงใดๆ กับโปรเจ็กต์หรือการกำหนดค่าบิลด์ ให้ทำซ้ำคำสั่งในขั้นตอนที่ 3 แต่ไม่ต้องใส่แฟล็ก
--rerun-tasksเนื่องจาก Gradle พยายามประหยัดเวลาโดยไม่เรียกใช้งานซ้ำซึ่งอินพุตไม่มีการเปลี่ยนแปลง (งานเหล่านี้จะแสดงเป็นUP-TO-DATEในแท็บ Task Execution ของรายงาน ดังที่แสดงในรูปที่ 3) คุณจึงระบุได้ว่างานใดกำลังทำงานอยู่เมื่อไม่ควรทำ ตัวอย่างเช่น หากไม่ได้ทำเครื่องหมาย:app:processDevUniversalDebugManifestเป็นUP-TO-DATEอาจหมายความว่าการกำหนดค่าบิลด์กำลังอัปเดตไฟล์ Manifest แบบไดนามิกในทุกบิลด์ อย่างไรก็ตาม งานบางอย่างต้องทำงานในระหว่างการสร้างแต่ละครั้ง เช่น:app:checkDevDebugManifest
รูปที่ 3 กำลังดูผลการดำเนินการของงาน
เมื่อมีรายงานโปรไฟล์บิลด์แล้ว คุณจะเริ่มมองหาโอกาสในการเพิ่มประสิทธิภาพได้โดยตรวจสอบข้อมูลในแต่ละแท็บของรายงาน การตั้งค่าบิลด์บางอย่างต้องมีการทดสอบเนื่องจากประโยชน์ที่ได้รับอาจแตกต่างกันไปตามโปรเจ็กต์และเวิร์กสเตชัน ตัวอย่างเช่น โปรเจ็กต์ที่มีฐานของโค้ดขนาดใหญ่อาจได้รับประโยชน์จากการลดขนาดโค้ดเพื่อนำโค้ดที่ไม่ได้ใช้ออกและลดขนาดแอป
อย่างไรก็ตาม โปรเจ็กต์ขนาดเล็กอาจได้รับประโยชน์มากกว่าจากการปิดใช้การลดขนาดโค้ดทั้งหมด นอกจากนี้ การเพิ่มขนาดฮีปของ Gradle (โดยใช้ org.gradle.jvmargs) อาจส่งผลเสียต่อประสิทธิภาพในเครื่องที่มีหน่วยความจำต่ำ
หลังจากทำการเปลี่ยนแปลงการกำหนดค่าบิลด์แล้ว ให้สังเกตผลลัพธ์ของการเปลี่ยนแปลงโดยทำตามขั้นตอนก่อนหน้าซ้ำและสร้างโปรไฟล์บิลด์ใหม่ ตัวอย่างเช่น รูปที่ 4 แสดงรายงานสำหรับแอปตัวอย่างเดียวกันหลังจากใช้การเพิ่มประสิทธิภาพพื้นฐานบางอย่างที่อธิบายไว้ในหน้านี้
รูปที่ 4 การดูรายงานใหม่หลังจากเพิ่มประสิทธิภาพความเร็วในการสร้าง