Profilowanie kompilacji

Większe projekty lub takie, w których zastosowano wiele niestandardowych rozwiązań konstrukcyjnych, mogą wymagają głębszego spojrzenia na proces tworzenia rozwiązań i znalezienia wąskich gardeł. Możesz to zrobić, profilując czas potrzebny Gradle na wykonanie każdej fazy cykl życia kompilacji i każde zadanie. Na przykład, jeśli profil kompilacji pokazuje, że Gradle poświęca zbyt dużo czasu na konfigurowanie projektu, może to sugeruje, że konieczne jest przeniesiej niestandardową logikę kompilacji poza etap konfiguracji. Ponadto, jeśli zadanie mergeDevDebugResources pochłania dużą ilość może oznaczać, że trzeba przekonwertuj obrazy do formatu WebP lub wyłącz crunching PNG.

Jeśli używasz Android Studio 4.0 lub nowszy to najlepszy sposób na sprawdzenie wydajności kompilacji. jest skorzystanie z Analizatora kompilacji.

Dodatkowo dostępne są 2 opcje profilowania kompilacji poza Android Studio:

  1. Oddzielne narzędzie gradle-profiler, potężne narzędzie do szczegółowej analizy kompilacji.

  2. opcję Gradle --profile, wygodnym narzędziu dostępnym z poziomu wiersza poleceń Gradle.

Korzystanie z samodzielnego narzędzia gradle-profiler

Aby znaleźć konfigurację projektu, która zapewnia najlepszą szybkość kompilacji, skorzystaj z narzędzia Gradle Profiler, Narzędzie do gromadzenia informacji o profilowaniu i testów porównawczych dotyczących kompilacji Gradle. Narzędzie do profilowania Gradle umożliwia tworzenie scenariuszy kompilacji i ich wielokrotne uruchamianie co pozwala uniknąć dużych rozbieżności między wynikami i zapewnić odtwarzalność wyników.

Tryb analizy porównawczej powinny służyć do zbierania informacji o czystych i przyrostowych kompilacjach, w trybie profilowania może służyć do zbierania bardziej szczegółowych informacji o uruchomieniach, w tym o procesorze zrzuty ekranu.

Oto niektóre konfiguracje konfiguracji projektu na potrzeby testów porównawczych:

  • Wersje wtyczki
  • Wersje Gradle
  • Ustawienia JVM (rozmiar stosu, stały rozmiar, usuwanie czyszczenia pamięci itp.)
  • Liczba instancji roboczych Gradle (org.gradle.workers.max)
  • Dodatkowe opcje optymalizacji wydajności dla poszczególnych wtyczek

Pierwsze kroki

  • Zainstaluj gradle-profiler, wykonując te instrukcje.
  • Uruchom: gradle-profiler --benchmark --project-dir <root-project> :app:assembleDebug

Sprawdzi to w pełni aktualną kompilację, ponieważ --benchmark uruchamia wiele razy, nie zmieniając projektu. Potem wygeneruje w katalogu profile-out/ raport HTML, pokazując czasy kompilacji.

Istnieją inne scenariusze, które mogą okazać się bardziej przydatne w analizie porównawczej:

  • Kod zmienia się w treści metody w zajęciach, w których wykonujesz większość pracy.
  • zmiany interfejsu API w module, który jest używany w całym projekcie, Choć mniej niż wprowadzanie zmian w kodzie, ma to większy wpływ jest przydatna w pomiarach.
  • Edytowanie układu w celu symulowania iteracji w interfejsie.
  • Wprowadzenie zmian w ciągach znaków, aby symulować obsługę tłumaczenia.
  • Oczyść kompilacje, by symulować zmiany w samej kompilacji (np. Gradle Androida aktualizacja wtyczki, aktualizacja Gradle lub edytowanie własnego kodu kompilacji poniżej buildSrc).

Aby porównać te przypadki użycia, możesz utworzyć scenariusz, służy do uruchomienia funkcji gradle-profiler i ma zastosowanie zmian w źródłach. Poniżej przedstawiamy kilka typowych scenariuszy.

Profilowanie różnych ustawień pamięci/procesora

Aby porównać różne ustawienia pamięci i procesora, możesz utworzyć kilka scenariuszy z różnymi wartościami dla funkcji org.gradle.jvmargs. Dla: można na przykład tworzyć scenariusze:

# <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"]
}

Uruchomiono gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt w trzech scenariuszach, dzięki którym można porównać czas :app:assembleDebug dla każdej z tych konfiguracji.

Profilowanie różnych wersji wtyczki Gradle

Aby dowiedzieć się, jak zmiana wersji wtyczki Gradle wpływa na nią w czasie realizacji, stwórz scenariusz dla takich wyników. Wymaga to aby umożliwić wstrzykiwanie wersji wtyczki zgodnie ze scenariuszem. Zmień Twój główny plik 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"
    }
}

Możesz teraz określić wtyczkę Androida i Kotlin Gradle. z pliku scenariuszy, a do scenariusza dodaje nową metodę pliki źródłowe:

# <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"
}

Profilowanie kompilacji przyrostowej

Większość kompilacji jest przyrostowych, przez co jest to jedna z najważniejszych. do profilowania w różnych scenariuszach. Program profilujący Gradle obsługuje profilowania przyrostowych kompilacji. Może automatycznie stosować zmiany w pliku źródłowym przez zmianę treść metody, dodanie nowej metody albo zmianę układu lub zasobu ciągu znaków. Dla: możesz utworzyć scenariusze przyrostowe podobne do tych:

# <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"
}

Uruchomiono gradle-profiler --benchmark --project-dir &lt;root-project> --scenario-file scenarios.txt wygeneruje raport HTML z danymi porównawczymi.

Możesz łączyć scenariusze przyrostowe z innymi ustawieniami, takimi jak rozmiar sterty, liczba instancji roboczych lub wersja 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"]
}

Profilowanie czystej kompilacji

Aby porównać nienaruszoną kompilację, możesz utworzyć scenariusz, który będzie używana do uruchomienia wykonania narzędzia gradle-profiler:

# <root-project>/scenarios.txt
clean_build {
    tasks = [":app:assembleDebug"]
    cleanup-tasks = ["clean"]
}

Aby uruchomić ten scenariusz, użyj tego polecenia:

gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt

Używanie opcji Gradle --profile

Aby wygenerować i wyświetlić profil kompilacji za pomocą wiersza poleceń Gradle, wykonaj te kroki:

  1. Otwórz terminal wiersza poleceń w katalogu głównym projektu.
  2. Ukończ czystą kompilację, wpisując to polecenie. Po profilu Twoją konstrukcję, należy wykonać czystą kompilację między poszczególnymi profilami. ponieważ Gradle pomija zadania, gdy dane wejściowe do zadania (np. kodu źródłowego) nie są . Dlatego druga kompilacja bez zmian w danych wejściowych zawsze działa szybciej, ponieważ zadania nie są ponownie uruchamiane. Uruchomienie zadania clean między pozwala profilować cały proces kompilacji.
    // On Mac or Linux, run the Gradle wrapper using "./gradlew".
    gradlew clean
    
  3. Wykonaj kompilację do debugowania dla jednego z odmian produktu, np. „dev” smak, z tymi flagami:
    gradlew --profile --offline --rerun-tasks assembleFlavorDebug
    
    • --profile: włącza profilowanie.
    • --offline: wyłącza możliwość pobierania danych online przez Gradle zależności. Dzięki temu nie ma żadnych opóźnień spowodowanych przez Gradle próba zaktualizowania zależności nie będzie zakłócać działania danych profilowania. Powinien być już raz skompilowany projekt, aby upewnić się, że Gradle pobrała już zależności i zapisała je w pamięci podręcznej.
    • --rerun-tasks: wymusza ponowne uruchomienie wszystkich zadań przez Gradle i zignorowanie wszystkich optymalizacji zadań.
  4. Rysunek 1. Widok projektu wskazujący lokalizację: raportów dotyczących profilu.

    Po zakończeniu kompilacji w oknie Projekt przejdź do Katalog project-root/build/reports/profile/ (jako widoczne na ilustracji 1).

  5. Kliknij prawym przyciskiem myszy plik profile-timestamp.html i wybierz Otwórz w przeglądarce > Domyślne. Raport powinien wyglądać podobnie do co pokazano na rys. 2. Na każdej karcie raportu możesz sprawdzić, kompilację, na przykład kartę Task Execution (Wykonywanie zadań), która pokazuje, ile czasu zajęło Gradle. do wykonywania poszczególnych zadań kompilacji.

    Rysunek 2. Wyświetlenie raportu w przeglądarce

  6. Opcjonalnie: przed wprowadzeniem jakichkolwiek zmian w projekcie lub kompilacji. , powtórz polecenie z kroku 3, ale pomiń Flaga --rerun-tasks. Ponieważ Gradle próbuje zaoszczędzić czas przez ponowne wykonywanie zadań, których dane wejściowe się nie zmieniły (są one oznaczone jako UP-TO-DATE na karcie Wykonanie zadania raportu, jak pokazano na ilustracji na ilustracji 3), możesz określić, które zadania są skuteczne, nie powinno tak być. Na przykład, jeśli plik :app:processDevUniversalDebugManifest nie jest oznaczony jako UP-TO-DATE, może on zasugerować, że Twoja konfiguracja kompilacji to dynamiczne aktualizowanie pliku manifestu przy każdej kompilacji. Niektóre zadania muszą jednak uruchamianych podczas każdej kompilacji, na przykład :app:checkDevDebugManifest.

    Rysunek 3. Wyświetlam wyniki wykonania zadania.

Po utworzeniu raportu profilu kompilacji możesz rozpocząć wyszukiwanie możliwości optymalizacji, sprawdzając informacje na każdej karcie raport. Niektóre ustawienia kompilacji wymagają eksperymentów, ponieważ mogą one różnią się w zależności od projektu i stacji roboczych. Na przykład projekty z dużą zmniejszanie kodu może przynieść korzyści aby usunąć nieużywany kod i zmniejszyć rozmiar aplikacji. Jednak mniejszy projektów może mieć więcej korzyści na całkowitemu zmniejszeniu kodu. Dodatkowo: zwiększenie rozmiaru sterty Gradle (za pomocą org.gradle.jvmargs) może negatywnie wpływać na wydajność na komputerach z małą ilością pamięci.

Po wprowadzeniu zmian w konfiguracji kompilacji sprawdź wyniki zmiany, powtórz powyższe kroki i wygeneruj nowy profil kompilacji. Na przykład na rysunku 4 widać raport dotyczący tej samej przykładowej aplikacji po zastosowaniu o kilku podstawowych optymalizacji opisanych na tej stronie.

Rysunek 4. Wyświetlanie nowego raportu po optymalizacji kompilacji prędkość działania.