پروفایل های پایه را به صورت دستی ایجاد و اندازه گیری کنید

ما اکیداً توصیه می‌کنیم که با استفاده از کتابخانه Jetpack Macrobenchmark، تولید خودکار قوانین پروفایل را انجام دهید تا از حجم کار دستی کاسته و مقیاس‌پذیری عمومی افزایش یابد. با این حال، ایجاد و اندازه‌گیری دستی قوانین پروفایل در برنامه شما امکان‌پذیر است.

تعریف دستی قوانین پروفایل

شما می‌توانید با ایجاد فایلی به نام baseline-prof.txt که در دایرکتوری src/main قرار دارد، قوانین پروفایل را به صورت دستی در یک برنامه یا یک ماژول کتابخانه تعریف کنید. این همان پوشه‌ای است که فایل AndroidManifest.xml در آن قرار دارد.

این فایل در هر خط یک قانون را مشخص می‌کند. هر قانون، الگویی را برای تطبیق متدها یا کلاس‌ها در برنامه یا کتابخانه‌ای که نیاز به بهینه‌سازی دارد، نشان می‌دهد.

نحو این قوانین، مجموعه‌ای از قالب پروفایل ART (HRF) قابل خواندن توسط انسان هنگام استفاده از adb shell profman --dump-classes-and-methods است. این نحو مشابه نحو توصیف‌کننده‌ها و امضاها است، اما اجازه می‌دهد تا از کاراکترهای جایگزین (wildcards) برای ساده‌سازی فرآیند نوشتن قانون استفاده شود.

مثال زیر چند قانون پروفایل پایه موجود در کتابخانه Jetpack Compose را نشان می‌دهد:

HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;

می‌توانید قوانین پروفایل را در این پروژه نمونه Compiler Explorer تغییر دهید. توجه داشته باشید که Compiler Explorer فقط از قالب پروفایل ART (HRF) که توسط انسان قابل خواندن است پشتیبانی می‌کند، بنابراین از wildcardها پشتیبانی نمی‌شود.

نحو قاعده

این قوانین برای هدف قرار دادن متدها یا کلاس‌ها، یکی از دو شکل زیر را به خود می‌گیرند:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

یک قانون کلاس از الگوی زیر استفاده می‌کند:

[CLASS_DESCRIPTOR]

برای توضیحات دقیق به جدول زیر مراجعه کنید:

نحو توضیحات
FLAGS نشان‌دهنده‌ی یک یا چند کاراکتر H ، S و P است که نشان می‌دهد آیا این متد باید بسته به نوع راه‌اندازی، به صورت Hot ، Startup یا Post Startup علامت‌گذاری شود.

متدی با پرچم H نشان می‌دهد که یک متد "داغ" است، به این معنی که در طول عمر برنامه بارها فراخوانی می‌شود.

متدی با پرچم S نشان می‌دهد که این متدی است که در هنگام راه‌اندازی فراخوانی می‌شود.

متدی با پرچم P نشان می‌دهد که این متدی است که پس از راه‌اندازی فراخوانی می‌شود.

کلاسی که در این فایل وجود دارد نشان می‌دهد که در هنگام راه‌اندازی استفاده می‌شود و باید از قبل در هیپ تخصیص داده شود تا از هزینه بارگذاری کلاس جلوگیری شود. کامپایلر ART از استراتژی‌های بهینه‌سازی مختلفی مانند کامپایل AOT این متدها و انجام بهینه‌سازی‌های طرح‌بندی در فایل AOT تولید شده استفاده می‌کند.
CLASS_DESCRIPTOR توصیف‌گر کلاس متد مورد نظر. برای مثال، androidx.compose.runtime.SlotTable دارای توصیف‌گری به صورت Landroidx/compose/runtime/SlotTable; است. در اینجا طبق فرمت Dalvik Executable (DEX) حرف L اضافه شده است.
METHOD_SIGNATURE امضای متد، شامل نام، نوع پارامترها و نوع داده‌های برگشتی متد. برای مثال:

// LayoutNode.kt

fun isPlaced():Boolean {
// ...
}

در LayoutNode امضای isPlaced()Z را دارد.

این الگوها می‌توانند دارای wildcard باشند تا یک قانون واحد شامل چندین متد یا کلاس باشد. برای راهنمایی هنگام نوشتن با سینتکس قانون در اندروید استودیو، به افزونه Android Baseline Profiles مراجعه کنید.

یک مثال از قانون wildcard می‌تواند چیزی شبیه به این باشد:

HSPLandroidx/compose/ui/layout/**->**(**)**

انواع پشتیبانی شده در قوانین نمایه پایه

قوانین پروفایل پایه از انواع زیر پشتیبانی می‌کنند. برای جزئیات بیشتر در مورد این نوع‌ها، به فرمت Dalvik Executable (DEX) مراجعه کنید.

شخصیت نوع توضیحات
B بایت بایت امضا شده
C کاراکتر نقطه کد کاراکتر یونیکد در UTF-16 کدگذاری شده است
D دو برابر مقدار ممیز شناور با دقت مضاعف
F شناور مقدار ممیز شناور با دقت تکی
I عدد صحیح عدد صحیح
J طولانی عدد صحیح بلند
S کوتاه کوتاه امضا شده
V باطل باطل
Z بولی درست یا غلط
L (نام کلاس) مرجع نمونه‌ای از نام کلاس

علاوه بر این، کتابخانه‌ها می‌توانند قوانینی را تعریف کنند که در مصنوعات AAR بسته‌بندی شده‌اند. وقتی یک APK برای گنجاندن این مصنوعات می‌سازید، قوانین با هم ادغام می‌شوند - مشابه نحوه ادغام مانیفست - و در یک پروفایل ART باینری فشرده که مختص APK است، کامپایل می‌شوند.

ART از این پروفایل زمانی که APK روی دستگاه‌ها استفاده می‌شود، برای کامپایل AOT زیرمجموعه خاصی از برنامه در زمان نصب در اندروید ۹ (سطح API ۲۸) یا اندروید ۷ (سطح API ۲۴) هنگام استفاده از ProfileInstaller استفاده می‌کند.

جمع‌آوری دستی پروفایل‌های پایه

شما می‌توانید بدون تنظیم کتابخانه Macrobenchmark، یک Baseline Profile به صورت دستی ایجاد کنید و UI خودکاری از مسیرهای حیاتی کاربر خود ایجاد کنید. اگرچه ما استفاده از Macrobenchmarks را توصیه می‌کنیم، اما ممکن است همیشه امکان‌پذیر نباشد. به عنوان مثال، اگر از یک سیستم ساخت غیر Gradle استفاده می‌کنید، نمی‌توانید از افزونه Baseline Profile Gradle استفاده کنید. در چنین مواردی، می‌توانید به صورت دستی قوانین Baseline Profile را جمع‌آوری کنید. اگر از دستگاه یا شبیه‌ساز با API 34 و بالاتر استفاده می‌کنید، این کار بسیار آسان‌تر است. اگرچه هنوز هم با سطوح API پایین‌تر امکان‌پذیر است، اما به دسترسی روت نیاز دارد و باید از یک شبیه‌ساز با اجرای یک تصویر AOSP استفاده کنید. می‌توانید با انجام موارد زیر، قوانین را مستقیماً جمع‌آوری کنید:

  1. یک نسخه آزمایشی از برنامه خود را روی یک دستگاه آزمایشی نصب کنید. نوع ساخت برنامه نباید برای R8 بهینه شده باشد و نباید قابل اشکال‌زدایی باشد تا بتواند پروفایلی را که می‌تواند توسط سیستم ساخت استفاده شود، ثبت کند.
  2. نصب پروفایل را غیرفعال کنید و برنامه را ببندید.

    اگر APK شما به کتابخانه Jetpack Profile Installer وابسته باشد، این کتابخانه در اولین اجرای APK شما، یک پروفایل را به صورت خودکار راه‌اندازی می‌کند. این می‌تواند در فرآیند تولید پروفایل اختلال ایجاد کند، بنابراین آن را با دستور زیر غیرفعال کنید:

    adb shell am broadcast -a androidx.profileinstaller.action.SKIP_FILE WRITE_SKIP_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
  3. کامپایل برنامه را ریست کنید و پروفایل‌ها را پاک کنید.

    API 34 و بالاتر

    adb shell cmd package compile -f -m verify $PACKAGE_NAME
    adb shell pm art clear-app-profiles $PACKAGE_NAME

    API 33 و پایین‌تر

    adb root
    adb shell cmd package compile --reset $PACKAGE_NAME

  4. برنامه را اجرا کنید و به صورت دستی در مسیرهای کاربری حیاتی که می‌خواهید برای آنها پروفایل جمع‌آوری کنید، پیمایش کنید.

  5. حداقل پنج ثانیه صبر کنید تا پروفایل‌ها تثبیت شوند.

  6. عمل ذخیره را انجام دهید و منتظر بمانید تا ذخیره کامل شود. اگر APK شما به کتابخانه Jetpack Profile Installer وابستگی دارد، از آن برای حذف پروفایل‌ها استفاده کنید:

    adb shell am broadcast -a androidx.profileinstaller.action.SAVE_PROFILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    sleep 1 # wait 1 second
    adb shell am force-stop $PACKAGE_NAME
    اگر از نصب‌کننده پروفایل استفاده نمی‌کنید، پروفایل‌ها را با استفاده از دستور زیر به صورت دستی روی یک شبیه‌ساز کپی کنید:

    adb root
    adb shell killall -s SIGUSR1 $PACKAGE_NAME
    sleep 1 # wait 1 second
    adb shell am force-stop $PACKAGE_NAME

  7. پروفایل‌های دودویی تولید شده را به متن تبدیل کنید:

    API 34 و بالاتر

    adb shell pm dump-profiles --dump-classes-and-methods $PACKAGE_NAME

    API 33 و پایین‌تر

    تعیین کنید که آیا یک پروفایل مرجع یا یک پروفایل فعلی ایجاد شده است. یک پروفایل مرجع در مکان زیر قرار دارد:

    /data/misc/profiles/ref/$$PACKAGE_NAME/primary.prof

    یک نمایه فعلی در مکان زیر قرار دارد:

    /data/misc/profiles/cur/0/$PACKAGE_NAME/primary.prof

    محل فایل APK را مشخص کنید:

    adb root
    adb shell pm path $PACKAGE_NAME

    تبدیل را انجام دهید:

    adb root
    adb shell profman --dump-classes-and-methods --profile-file=$PROFILE_PATH --apk=$APK_PATH > /data/misc/profman/$PACKAGE_NAME-primary.prof.txt

  8. از adb برای بازیابی پروفایل dump شده از دستگاه استفاده کنید:

    adb pull /data/misc/profman/$PACKAGE_NAME-primary.prof.txt PATH_TO_APP_MODULE/src/main/

این کار، قوانین پروفایل تولید شده را دریافت کرده و آنها را در ماژول برنامه شما نصب می‌کند. دفعه بعد که برنامه را می‌سازید، پروفایل پایه نیز گنجانده شده است. با دنبال کردن مراحل موجود در بخش «مسائل مربوط به نصب» ، این موضوع را تأیید کنید.

اندازه‌گیری دستی بهبودهای برنامه

ما اکیداً توصیه می‌کنیم که پیشرفت‌های برنامه را از طریق بنچمارک اندازه‌گیری کنید. با این حال، اگر می‌خواهید پیشرفت‌ها را به صورت دستی اندازه‌گیری کنید، می‌توانید با اندازه‌گیری شروع برنامه بهینه نشده به عنوان مرجع، شروع کنید.

PACKAGE_NAME=com.example.app
# Force Stop App
adb shell am force-stop $PACKAGE_NAME
# Reset compiled state
adb shell cmd package compile --reset $PACKAGE_NAME
# Measure App startup
# This corresponds to `Time to initial display` metric.
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

در مرحله بعد، پروفایل پایه را دانلود کنید.

# Unzip the Release APK first.
unzip release.apk
# Create a ZIP archive.
# The name should match the name of the APK.
# Copy `baseline.prof{m}` and rename it `primary.prof{m}`.
cp assets/dexopt/baseline.prof primary.prof
cp assets/dexopt/baseline.profm primary.profm
# Create an archive.
zip -r release.dm primary.prof primary.profm
# Confirm that release.dm only contains the two profile files:
unzip -l release.dm
# Archive:  release.dm
#   Length      Date    Time    Name
# ---------  ---------- -----   ----
#      3885  1980-12-31 17:01   primary.prof
#      1024  1980-12-31 17:01   primary.profm
# ---------                     -------
#                               2 files
# Install APK + Profile together.
adb install-multiple release.apk release.dm

برای تأیید اینکه بسته در هنگام نصب بهینه شده است، دستور زیر را اجرا کنید:

# Check dexopt state.
adb shell dumpsys package dexopt | grep -A 1 $PACKAGE_NAME

خروجی باید بیان کند که بسته کامپایل شده است:

[com.example.app]
  path: /data/app/~~YvNxUxuP2e5xA6EGtM5i9A==/com.example.app-zQ0tkJN8tDrEZXTlrDUSBg==/base.apk
  arm64: [status=speed-profile] [reason=install-dm]

اکنون، می‌توانید عملکرد راه‌اندازی برنامه را مانند قبل اندازه‌گیری کنید، اما بدون تنظیم مجدد حالت کامپایل شده. مطمئن شوید که حالت کامپایل شده را برای بسته تنظیم مجدد نمی‌کنید.

# Force stop app
adb shell am force-stop $PACKAGE_NAME
# Measure app startup
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

پروفایل‌های پایه و پروفایل‌های حرفه‌ای

این بخش توضیح می‌دهد که ابزار profgen هنگام ساخت یک نسخه دودویی فشرده از یک Baseline Profile چه کاری انجام می‌دهد.

Profgen-cli به کامپایل پروفایل، درون‌نگری و انتقال پروفایل‌های ART کمک می‌کند، بنابراین می‌توان آنها را صرف نظر از نسخه SDK هدف، روی دستگاه‌های دارای اندروید نصب کرد.

Profgen-cli یک رابط خط فرمان (CLI) است که HRF یک پروفایل پایه (Baseline Profile) را به فرمت کامپایل شده آن کامپایل می‌کند. این رابط خط فرمان همچنین به عنوان بخشی از SDK اندروید در مخزن cmdline-tools موجود است.

این ویژگی‌ها در شاخه studio-main موجود است:

 ../cmdline-tools/latest/bin
apkanalyzer
avdmanager
lint
profgen
retrace
screenshot2
sdkmanager

ساخت پروفایل‌های دودویی فشرده با Profgen-cli

دستورات موجود با Profgen-cli عبارتند از bin ، validate و dumpProfile . برای مشاهده دستورات موجود، از profgen --help استفاده کنید:

  profgen --help
Usage: profgen options_list
Subcommands:
    bin - Generate Binary Profile
    validate - Validate Profile
    dumpProfile - Dump a binary profile to a HRF

Options:
    --help, -h -> Usage info

از دستور bin برای تولید پروفایل دودویی فشرده استفاده کنید. در زیر یک نمونه فراخوانی آمده است:

profgen bin ./baseline-prof.txt \
  --apk ./release.apk \
  --map ./obfuscation-map.txt \
  --profile-format v0_1_0_p \
  --output ./baseline.prof \

برای دیدن گزینه‌های موجود، profgen bin options_list استفاده کنید:

Usage: profgen bin options_list
Arguments:
    profile -> File path to Human Readable profile { String }
Options:
    --apk, -a -> File path to apk (always required) { String }
    --output, -o -> File path to generated binary profile (always required)
    --map, -m -> File path to name obfuscation map { String }
    --output-meta, -om -> File path to generated metadata output { String }
    --profile-format, -pf [V0_1_0_P] -> The ART profile format version
      { Value should be one of [
         v0_1_5_s, v0_1_0_p, v0_0_9_omr1, v0_0_5_o, v0_0_1_n
        ]
      }
    --help, -h -> Usage info

آرگومان اول مسیر فایل baseline-prof.txt HRF را نشان می‌دهد.

Profgen-cli همچنین به مسیر نسخه آزمایشی APK و یک نقشه مبهم‌سازی که برای مبهم‌سازی APK هنگام استفاده از R8 یا Proguard استفاده می‌شود، نیاز دارد. به این ترتیب، profgen می‌تواند نمادهای منبع در HRF را هنگام ساخت پروفایل کامپایل‌شده به نام‌های مبهم‌سازی‌شده مربوطه ترجمه کند.

از آنجا که قالب‌های پروفایل‌های ART با نسخه‌های قبلی یا بعدی سازگار نیستند، یک قالب پروفایل ارائه دهید تا profgen فراداده پروفایل ( profm ) را بسته‌بندی کند که بتوانید در صورت لزوم برای تبدیل کد یک قالب پروفایل ART به قالب دیگر از آن استفاده کنید.

قالب‌های پروفایل و نسخه‌های پلتفرم

هنگام انتخاب قالب پروفایل، گزینه‌های زیر در دسترس هستند:

قالب پروفایل نسخه پلتفرم سطح API
v0_1_5_s اندروید اس پلاس ۳۱+
v0_1_0_p اندروید P، Q و R ۲۸-۳۰
v0_0_9_omr1 اندروید O MR1 ۲۷
v0_0_5_o اندروید O ۲۶
v0_0_1_n اندروید N ۲۴-۲۵

فایل‌های خروجی baseline.prof و baseline.profm را در پوشه assets یا dexopt در فایل APK کپی کنید.

نقشه‌های مبهم‌سازی

شما فقط در صورتی نیاز به ارائه نقشه مبهم‌سازی دارید که HRF از نمادهای منبع استفاده کند. اگر HRF از یک نسخه آزمایشی که از قبل مبهم‌سازی شده است تولید شده باشد و هیچ نگاشتی لازم نباشد، می‌توانید آن گزینه را نادیده بگیرید و خروجی‌ها را در پوشه assets یا dexopt کپی کنید.

نصب سنتی پروفیل‌های پایه

پروفایل‌های پایه به طور سنتی به یکی از دو روش زیر به دستگاه ارسال می‌شوند.

استفاده از install-multiple به همراه DexMetadata

در دستگاه‌هایی که از API 28 و بالاتر استفاده می‌کنند، کلاینت Play، فایل APK و DexMetadata (DM) را برای نسخه APK در حال نصب دانلود می‌کند. DM شامل اطلاعات پروفایل است که به Package Manager در دستگاه منتقل می‌شود.

APK و DM به عنوان بخشی از یک جلسه نصب واحد با استفاده از چیزی شبیه به این نصب می‌شوند:

adb install-multiple base.apk base.dm

نصب‌کننده پروفایل جت‌پک

در دستگاه‌هایی که API سطح ۲۹ و بالاتر را اجرا می‌کنند، کتابخانه Jetpack ProfileInstaller یک مکانیسم جایگزین برای نصب یک پروفایل بسته‌بندی شده در assets یا dexopt پس از نصب APK روی دستگاه ارائه می‌دهد. ProfileInstaller توسط ProfileInstallReceiver یا مستقیماً توسط برنامه فراخوانی می‌شود.

کتابخانه ProfileInstaller، پروفایل را بر اساس نسخه SDK دستگاه هدف، کدگذاری می‌کند و آن را در دایرکتوری cur روی دستگاه (یک دایرکتوری مرحله‌بندی مخصوص بسته برای پروفایل‌های ART روی دستگاه) کپی می‌کند.

هنگامی که دستگاه بیکار است، پروفایل توسط فرآیندی به نام bg-dexopt روی دستگاه دریافت می‌شود.

یک پروفایل پایه را دانلود کنید

این بخش نحوه نصب پروفایل پایه با توجه به APK را شرح می‌دهد.

پخش با androidx.profileinstaller

در دستگاه‌هایی که API 24 و بالاتر را اجرا می‌کنند، می‌توانید دستوری را برای نصب پروفایل پخش کنید:

# Broadcast the install profile command - moves binary profile from assets
#     to a location where ART uses it for the next compile.
#     When successful, the following command prints "1":
adb shell am broadcast \
    -a androidx.profileinstaller.action.INSTALL_PROFILE \
    <pkg>/androidx.profileinstaller.ProfileInstallReceiver

# Kill the process
am force-stop <pkg>

# Compile the package based on profile
adb shell cmd package compile -f -m speed-profile <pkg>

ProfileInstaller در اکثر APKهایی که از Baseline Profiles استفاده می‌کنند - که در حدود ۷۷ هزار از ۴۵۰ هزار برنامه در Play وجود دارد - وجود ندارد، اگرچه عملاً در هر APK که از Compose استفاده می‌کند، وجود دارد. دلیل این امر این است که کتابخانه‌ها می‌توانند پروفایل‌ها را بدون اعلام وابستگی به ProfileInstaller ارائه دهند. افزودن وابستگی در هر کتابخانه‌ای که دارای پروفایل است، از Jetpack شروع می‌شود.

از install-multiple به همراه profgen یا DexMetaData استفاده کنید

در دستگاه‌هایی که API 28 و بالاتر را اجرا می‌کنند، می‌توانید بدون نیاز به داشتن کتابخانه ProfileInstaller در برنامه، یک Baseline Profile را از طریق Sideload نصب کنید.

برای این کار، از Profgen-cli استفاده کنید:

profgen extractProfile \
        --apk app-release.apk \
        --output-dex-metadata app-release.dm \
        --profile-format V0_1_5_S # Select based on device and the preceding table.

# Install APK and the profile together
adb install-multiple appname-release.apk appname-release.dm

برای پشتیبانی از تقسیم فایل‌های APK، مراحل استخراج پروفایل قبلی را یک بار برای هر APK اجرا کنید. در زمان نصب، هر APK و فایل .dm مرتبط را ارسال کنید و مطمئن شوید که نام‌های APK و .dm با هم مطابقت دارند:

adb install-multiple appname-base.apk appname-base.dm \
appname-split1.apk appname-split1.dm

تأیید

برای تأیید نصب صحیح پروفایل، می‌توانید از مراحل موجود در «اندازه‌گیری دستی بهبودهای برنامه» استفاده کنید.

محتویات یک پروفایل دودویی را تخلیه کنید

برای بررسی محتویات یک نسخه باینری فشرده از یک Baseline Profile، از گزینه Profgen-cli dumpProfile استفاده کنید:

Usage: profgen dumpProfile options_list
Options:
    --profile, -p -> File path to the binary profile (always required)
    --apk, -a -> File path to apk (always required) { String }
    --map, -m -> File path to name obfuscation map { String }
    --strict, -s [true] -> Strict mode
    --output, -o -> File path for the HRF (always required) { String }
    --help, -h -> Usage info

dumpProfile به APK نیاز دارد زیرا نمایش دودویی فشرده فقط آفست‌های DEX را ذخیره می‌کند و بنابراین، برای بازسازی نام کلاس‌ها و متدها به آنها نیاز دارد.

حالت سختگیرانه (Strict mode) به طور پیش‌فرض فعال است و این حالت، سازگاری پروفایل را با فایل‌های DEX در APK بررسی می‌کند. اگر سعی دارید پروفایل‌هایی را که توسط ابزار دیگری ایجاد شده‌اند، اشکال‌زدایی کنید، ممکن است با خطاهای سازگاری مواجه شوید که مانع از امکان بررسی و ارسال فایل‌ها می‌شود. در چنین مواردی، می‌توانید حالت سختگیرانه را با استفاده از --strict false غیرفعال کنید. با این حال، در بیشتر موارد، باید حالت سختگیرانه را فعال نگه دارید.

نقشه مبهم‌سازی اختیاری است؛ در صورت ارائه، به نگاشت مجدد نمادهای مبهم‌سازی شده به نسخه‌های قابل خواندن توسط انسان برای سهولت استفاده کمک می‌کند.

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}