เขียนเกณฑ์เปรียบเทียบขนาดเล็ก

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

คู่มือเริ่มใช้งานฉบับย่อ

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

หากต้องการทำการเปรียบเทียบแบบครั้งเดียว ให้ทำดังนี้

  1. เพิ่มไลบรารีลงในไฟล์ build.gradle หรือ build.gradle.kts ของโมดูล

    Kotlin

    dependencies {
        implementation("androidx.benchmark:benchmark-junit4:1.2.4")
    }

    Groovy

    dependencies {
        implementation 'androidx.benchmark:benchmark-junit4:1.2.4'
    }

    ใช้การขึ้นต่อกันของ implementation แทนการขึ้นต่อกันของ androidTestImplementation หากคุณใช้ androidTestImplementation การทดสอบประสิทธิภาพจะทำงานไม่สำเร็จเนื่องจากไม่ได้ผสานไฟล์ Manifest ของไลบรารีเข้ากับไฟล์ Manifest ของแอป

  2. อัปเดตdebugประเภทบิลด์เพื่อให้ดีบักไม่ได้

    Kotlin

    android {
        ...
        buildTypes {
            debug {
                isDebuggable = false
            }
        }
    }

    Groovy

    android {
        ...
        buildTypes {
            debug {
                debuggable false
            }
        }
    }
  3. เปลี่ยน testInstrumentationRunner เป็น AndroidBenchmarkRunner:

    Kotlin

    android {
        ...
        defaultConfig {
            testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }

    Groovy

    android {
        ...
        defaultConfig {
            testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
  4. เพิ่มอินสแตนซ์ของ BenchmarkRule ในไฟล์ทดสอบในไดเรกทอรี androidTest เพื่อเพิ่มการเปรียบเทียบ ดูข้อมูลเพิ่มเติม เกี่ยวกับการเขียนการทดสอบประสิทธิภาพได้ที่สร้างคลาส Microbenchmark

    ข้อมูลโค้ดต่อไปนี้แสดงวิธีเพิ่มการเปรียบเทียบในการทดสอบที่วัดประสิทธิภาพ

    Kotlin

    @RunWith(AndroidJUnit4::class)
    class SampleBenchmark {
        @get:Rule
        val benchmarkRule = BenchmarkRule()
    
        @Test
        fun benchmarkSomeWork() {
            benchmarkRule.measureRepeated {
                doSomeWork()
            }
        }
    }

    Java

    @RunWith(AndroidJUnit4.class)
    class SampleBenchmark {
        @Rule
        public BenchmarkRule benchmarkRule = new BenchmarkRule();
    
        @Test
        public void benchmarkSomeWork() {
                BenchmarkRuleKt.measureRepeated(
                    (Function1<BenchmarkRule.Scope, Unit>) scope -> doSomeWork()
                );
           }
        }
    }

หากต้องการดูวิธีเขียนการทดสอบประสิทธิภาพ ให้ข้ามไปที่สร้างคลาส Microbenchmark

การตั้งค่าโปรเจ็กต์ทั้งหมด

หากต้องการตั้งค่าการเปรียบเทียบปกติแทนการเปรียบเทียบแบบครั้งเดียว ให้แยก การเปรียบเทียบเป็นโมดูลของตัวเอง ซึ่งจะช่วยให้มั่นใจว่าการกำหนดค่า เช่น การตั้งค่า debuggable เป็น false จะแยกจากการทดสอบปกติ

เนื่องจาก Microbenchmark จะเรียกใช้โค้ดของคุณโดยตรง ให้วางโค้ดที่ต้องการ ทดสอบประสิทธิภาพลงในโมดูล Gradle แยกต่างหาก แล้วตั้งค่าการอ้างอิงในโมดูลนั้นตามที่แสดงในรูปที่ 1

โครงสร้างแอป
รูปที่ 1 โครงสร้างแอปที่มีโมดูล :app, :microbenchmark และ :benchmarkable Gradle ซึ่งช่วยให้ Microbenchmark สามารถทดสอบโค้ดในโมดูล :benchmarkable ได้

หากต้องการเพิ่มโมดูล Gradle ใหม่ คุณสามารถใช้วิซาร์ดโมดูลใน Android Studio ได้ วิซาร์ดจะสร้างโมดูลที่กำหนดค่าไว้ล่วงหน้าสำหรับการเปรียบเทียบ โดยจะเพิ่ม ไดเรกทอรีการเปรียบเทียบและตั้งค่า debuggable เป็น false

  1. คลิกขวาที่โปรเจ็กต์หรือโมดูลในแผงโปรเจ็กต์ใน Android Studio แล้วคลิกใหม่ > โมดูล

  2. เลือกการเปรียบเทียบในบานหน้าต่างเทมเพลต

  3. เลือก Microbenchmark เป็นประเภทโมดูลการเปรียบเทียบ

  4. พิมพ์ "microbenchmark" สำหรับชื่อโมดูล

  5. คลิกเสร็จสิ้น

กำหนดค่าโมดูลคลังใหม่
รูปที่ 2 เพิ่มโมดูล Gradle ใหม่ใน Android Studio Bumblebee

หลังจากสร้างโมดูลแล้ว ให้เปลี่ยนไฟล์ build.gradle หรือ build.gradle.kts แล้วเพิ่ม androidTestImplementation ลงในโมดูลที่มีโค้ดเพื่อ เปรียบเทียบ

Kotlin

dependencies {
    // The module name might be different.
    androidTestImplementation(project(":benchmarkable"))
}

Groovy

dependencies {
    // The module name might be different.
    androidTestImplementation project(':benchmarkable')
}

สร้างคลาส Microbenchmark

การทดสอบเปรียบเทียบคือการทดสอบการวัดคุมมาตรฐาน หากต้องการสร้างการเปรียบเทียบ ให้ใช้คลาส BenchmarkRule ที่ไลบรารีมีให้ หากต้องการเปรียบเทียบกิจกรรม ให้ใช้ ActivityScenario หรือ ActivityScenarioRule หากต้องการเปรียบเทียบโค้ด UI ให้ใช้ @UiThreadTest

โค้ดต่อไปนี้แสดงเกณฑ์เปรียบเทียบตัวอย่าง

Kotlin

@RunWith(AndroidJUnit4::class)
class SampleBenchmark {
    @get:Rule
    val benchmarkRule = BenchmarkRule()

    @Test
    fun benchmarkSomeWork() {
        benchmarkRule.measureRepeated {
            doSomeWork()
        }
    }
}
    

Java

@RunWith(AndroidJUnit4.class)
class SampleBenchmark {
    @Rule
    public BenchmarkRule benchmarkRule = new BenchmarkRule();

    @Test
    public void benchmarkSomeWork() {
        final BenchmarkState state = benchmarkRule.getState();
        while (state.keepRunning()) {
            doSomeWork();
        }
    }
}
    

ปิดใช้การกำหนดเวลาสำหรับการตั้งค่า

คุณปิดใช้การจับเวลาสำหรับส่วนของโค้ดที่ไม่ต้องการวัดด้วยบล็อก runWithTimingDisabled{} ได้ โดยปกติแล้ว ส่วนเหล่านี้จะแสดงโค้ดบางส่วน ที่คุณต้องเรียกใช้ในการทำซ้ำแต่ละครั้งของการเปรียบเทียบ

Kotlin

// using random with the same seed, so that it generates the same data every run
private val random = Random(0)

// create the array once and just copy it in benchmarks
private val unsorted = IntArray(10_000) { random.nextInt() }

@Test
fun benchmark_quickSort() {
    // ...
    benchmarkRule.measureRepeated {
        // copy the array with timing disabled to measure only the algorithm itself
        listToSort = runWithTimingDisabled { unsorted.copyOf() }

        // sort the array in place and measure how long it takes
        SortingAlgorithms.quickSort(listToSort)
    }

    // assert only once not to add overhead to the benchmarks
    assertTrue(listToSort.isSorted)
}
    

Java

private final int[] unsorted = new int[10000];

public SampleBenchmark() {
    // Use random with the same seed, so that it generates the same data every
    // run.
    Random random = new Random(0);

    // Create the array once and copy it in benchmarks.
    Arrays.setAll(unsorted, (index) -> random.nextInt());
}

@Test
public void benchmark_quickSort() {
    final BenchmarkState state = benchmarkRule.getState();

    int[] listToSort = new int[0];

    while (state.keepRunning()) {
        
        // Copy the array with timing disabled to measure only the algorithm
        // itself.
        state.pauseTiming();
        listToSort = Arrays.copyOf(unsorted, 10000);
        state.resumeTiming();
        
        // Sort the array in place and measure how long it takes.
        SortingAlgorithms.quickSort(listToSort);
    }

    // Assert only once, not to add overhead to the benchmarks.
    assertTrue(SortingAlgorithmsKt.isSorted(listToSort));
}
    

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

เรียกใช้การเปรียบเทียบ

ใน Android Studio ให้เรียกใช้การทดสอบประสิทธิภาพเช่นเดียวกับ@Testโดยใช้ การดำเนินการที่ขอบด้านข้างข้างคลาสหรือเมธอดทดสอบ ดังที่แสดงในรูปที่ 3

เรียกใช้ Microbenchmark
รูปที่ 3 เรียกใช้การทดสอบ Microbenchmark โดยใช้การดำเนินการที่แถบแสดงข้อผิดพลาด ข้างคลาสทดสอบ

หรือจะเรียกใช้ connectedCheck จากบรรทัดคำสั่งเพื่อเรียกใช้การทดสอบทั้งหมดจากโมดูล Gradle ที่ระบุก็ได้

./gradlew benchmark:connectedCheck

หรือการทดสอบเดียว

./gradlew benchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.benchmark.SampleBenchmark#benchmarkSomeWork

ผลการเปรียบเทียบ

หลังจากเรียกใช้ Microbenchmark สำเร็จแล้ว เมตริกจะแสดงใน Android Studio โดยตรง และรายงานการทดสอบประสิทธิภาพฉบับเต็มพร้อมเมตริกเพิ่มเติมและข้อมูลอุปกรณ์ จะอยู่ในรูปแบบ JSON

ผลลัพธ์การทดสอบประสิทธิภาพระดับไมโคร
รูปที่ 4 ผลลัพธ์ของ Microbenchmark

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

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/

โดยค่าเริ่มต้น ระบบจะเขียนรายงาน JSON ลงในดิสก์ในอุปกรณ์ใน โฟลเดอร์สื่อที่แชร์ภายนอกของ APK ทดสอบ ซึ่งโดยปกติจะอยู่ใน /storage/emulated/0/Android/media/**app_id**/**app_id**-benchmarkData.json

ข้อผิดพลาดในการกำหนดค่า

ไลบรารีจะตรวจหาเงื่อนไขต่อไปนี้เพื่อให้แน่ใจว่าโปรเจ็กต์และ สภาพแวดล้อมได้รับการตั้งค่าให้มีประสิทธิภาพที่แม่นยำสำหรับการเผยแพร่

  • ตั้งค่า Debuggable เป็น false
  • มีการใช้อุปกรณ์จริง (ระบบไม่รองรับโปรแกรมจำลอง)
  • นาฬิกาจะล็อกหากอุปกรณ์มีการรูท
  • ระดับแบตเตอรี่ในอุปกรณ์เพียงพออย่างน้อย 25%

หากการตรวจสอบก่อนหน้านี้ล้มเหลว รายงานการเปรียบเทียบจะรายงานข้อผิดพลาดเพื่อ ไม่ให้มีการวัดผลที่ไม่ถูกต้อง

หากต้องการระงับข้อผิดพลาดบางประเภทเป็นคำเตือนและป้องกันไม่ให้หยุดการ ทดสอบประสิทธิภาพ ให้ส่งประเภทข้อผิดพลาดในรายการที่คั่นด้วยคอมมาไปยังอาร์กิวเมนต์การวัดผล androidx.benchmark.suppressErrors

คุณตั้งค่านี้ได้จากสคริปต์ Gradle ดังตัวอย่างต่อไปนี้

Kotlin

android {
    defaultConfig {
       
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

Groovy

android {
    defaultConfig {
       
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

นอกจากนี้ คุณยังระงับข้อผิดพลาดจากบรรทัดคำสั่งได้ด้วย

$ ./gradlew :benchmark:connectedCheck -P andoidtestInstrumentationRunnerArguments.androidx.benchmark.supperssErrors=DEBUGGABLE,LOW-BATTERY

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