ทำโปรไฟล์สิ่งที่สร้าง

โปรเจ็กต์ขนาดใหญ่หรือโปรเจ็กต์ที่ใช้ตรรกะการบิลด์ที่กำหนดเองจำนวนมากอาจกำหนดให้คุณต้องพิจารณากระบวนการบิลด์อย่างละเอียดมากขึ้นเพื่อค้นหาจุดคอขวด คุณทำได้โดยการทำโปรไฟล์ระยะเวลาที่ Gradle ใช้ในการดำเนินการแต่ละระยะของวงจรการสร้างและงานการสร้างแต่ละงาน ตัวอย่างเช่น หากโปรไฟล์บิลด์แสดงว่า Gradle ใช้เวลามากเกินไปในการกำหนดค่าโปรเจ็กต์ ระบบอาจแนะนำว่าคุณต้องย้ายตรรกะบิลด์ที่กำหนดเองออกจากระยะการกำหนดค่า นอกจากนี้ หากงาน mergeDevDebugResources ใช้เวลาในการบิลด์นาน อาจบ่งบอกว่าคุณต้องแปลงรูปภาพเป็น WebP หรือปิดใช้การบีบอัด PNG

หากคุณใช้ Android Studio 4.0 ขึ้นไป วิธีที่ดีที่สุดในการตรวจสอบปัญหาด้านประสิทธิภาพของบิลด์คือการใช้ตัววิเคราะห์บิลด์

นอกจากนี้ ยังมี 2 ตัวเลือกสำหรับการทำโปรไฟล์บิลด์นอก Android Studio ดังนี้

  1. เครื่องมือ gradle-profiler แบบสแตนด์อโลน ซึ่งเป็นเครื่องมือที่มีประสิทธิภาพสำหรับการวิเคราะห์บิลด์อย่างละเอียด

  2. ตัวเลือก --profile ของ Gradle ซึ่งเป็นเครื่องมือที่สะดวกซึ่งพร้อมใช้งานจากบรรทัดคำสั่ง Gradle

การใช้เครื่องมือ gradle-profiler แบบสแตนด์อโลน

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

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

การกำหนดค่าการตั้งค่าโปรเจ็กต์สำหรับการเปรียบเทียบมีดังนี้

  • เวอร์ชันปลั๊กอิน
  • เวอร์ชัน Gradle
  • การตั้งค่า JVM (ขนาดฮีป, ขนาด PermGen, การเก็บขยะ ฯลฯ)
  • จำนวนเวิร์กเกอร์ Gradle (org.gradle.workers.max)
  • ตัวเลือกต่อปลั๊กอินเพื่อเพิ่มประสิทธิภาพให้ดียิ่งขึ้น

เริ่มต้นใช้งาน

ซึ่งจะเปรียบเทียบกับบิลด์ที่อัปเดตอย่างสมบูรณ์ เนื่องจาก --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 ให้ทำตามขั้นตอนต่อไปนี้

  1. เปิดเทอร์มินัลบรรทัดคำสั่งที่รูทของโปรเจ็กต์

  2. ทำการบิลด์ใหม่ทั้งหมดโดยป้อนคำสั่งต่อไปนี้ ขณะทำโปรไฟล์บิลด์ คุณควรทำการคลีนบิลด์ระหว่างแต่ละบิลด์ที่ทำโปรไฟล์ เนื่องจาก Gradle จะข้ามงานเมื่ออินพุตของงาน (เช่น ซอร์สโค้ด) ไม่มีการเปลี่ยนแปลง ดังนั้น การบิลด์ครั้งที่ 2 ที่ไม่มีการเปลี่ยนแปลงอินพุตจึงทำงานได้เร็วกว่าเสมอเนื่องจากไม่มีการรันงานซ้ำ ดังนั้นการเรียกใช้ clean ระหว่างบิลด์จะช่วยให้คุณสร้างโปรไฟล์กระบวนการบิลด์ทั้งหมดได้

    // On Mac or Linux, run the Gradle wrapper using "./gradlew".
    gradlew clean
    
  3. เรียกใช้บิลด์การแก้ไขข้อบกพร่องของเวอร์ชันผลิตภัณฑ์รายการใดรายการหนึ่ง เช่น เวอร์ชัน "dev" โดยใช้แฟล็กต่อไปนี้

    gradlew --profile --offline --rerun-tasks assemble<var>Flavor</var>Debug
    
    • --profile: เปิดใช้การทำโปรไฟล์

    • --offline: ปิดใช้ Gradle ไม่ให้ดึงข้อมูลทรัพยากร Dependency ออนไลน์ ซึ่งจะช่วยให้มั่นใจว่าความล่าช้าที่เกิดจาก Gradle ที่พยายามอัปเดตทรัพยากร Dependency จะไม่รบกวนข้อมูลการทำโปรไฟล์ คุณควรสร้างโปรเจ็กต์ไว้แล้ว 1 ครั้งเพื่อให้แน่ใจว่า Gradle ได้ดาวน์โหลดและแคชทรัพยากร Dependency ไว้แล้ว

    • --rerun-tasks: บังคับให้ Gradle เรียกใช้งานทั้งหมดอีกครั้งและละเว้นการเพิ่มประสิทธิภาพงาน

  4. หลังจากสร้างเสร็จแล้ว ให้ใช้หน้าต่างโปรเจ็กต์เพื่อไปยังไดเรกทอรี project-root/build/reports/profile/ (ดังที่แสดงในรูปที่ 1)

    รูปที่ 1 มุมมองโปรเจ็กต์ที่แสดงตำแหน่งของรายงานโปรไฟล์

  5. คลิกขวาที่ไฟล์ profile-timestamp.html แล้วเลือกเปิดในเบราว์เซอร์ > ค่าเริ่มต้น รายงานควรมีลักษณะคล้ายกับที่แสดงในรูปที่ 2 คุณสามารถตรวจสอบแต่ละแท็บในรายงานเพื่อดูข้อมูลเกี่ยวกับบิลด์ เช่น แท็บการดำเนินการงาน ซึ่งแสดงระยะเวลาที่ Gradle ใช้ในการดำเนินการงานบิลด์แต่ละรายการ

    รูปที่ 2 การดูรายงานในเบราว์เซอร์

  6. ไม่บังคับ: ก่อนทำการเปลี่ยนแปลงใดๆ กับโปรเจ็กต์หรือการกำหนดค่าบิลด์ ให้ทำซ้ำคำสั่งในขั้นตอนที่ 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 การดูรายงานใหม่หลังจากเพิ่มประสิทธิภาพความเร็วในการสร้าง