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

ดูวิธีใช้คลัง 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 เพื่อเพิ่มการเปรียบเทียบ ดูข้อมูลเพิ่มเติมเกี่ยวกับการเขียนการเปรียบเทียบได้ที่สร้างคลาสการเปรียบเทียบประสิทธิภาพระดับไมโคร

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

    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()
                );
           }
        }
    }

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

การตั้งค่าโปรเจ็กต์แบบสมบูรณ์

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

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

โครงสร้างแอป
รูปที่ 1 โครงสร้างแอปที่มีโมดูล :app, :microbenchmark และ :benchmarkable Gradle ซึ่งช่วยให้ Microbenchmarks ทำการทดสอบประสิทธิภาพโค้ดใน :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')
}

สร้างคลาสการทดสอบประสิทธิภาพระดับไมโคร

การเปรียบเทียบเป็นการทดสอบการวัดผลมาตรฐาน หากต้องการสร้างการเปรียบเทียบ ให้ใช้คลาส 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

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

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

./gradlew benchmark:connectedCheck

หรือทดสอบครั้งเดียว

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

ผลลัพธ์การเปรียบเทียบ

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

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

ระบบจะคัดลอกรายงาน 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

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

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

  • ตั้งค่า "แก้ไขได้" เป็น 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_ ไว้หน้าชื่อการทดสอบ