تجزیه‌وتحلیل با «نمایه پردازش گرافیکی»

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

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

نمایش تصویری

ابزار «پردازش GPU نمایه» مراحل و زمان‌های نسبی آن‌ها را به‌شکل نمودار نمایش می‌دهد: بافت‌نگاشتی با کدگذاری رنگی. شکل ۱ نمونه‌ای از چنین نمایشی را نشان می‌دهد.

نمودار پرداز واحد پردازش گرافیکی نمایه
شکل ۱. نمایه نمودار پردازش گرافیکی GPU

هر بخش از هر نوار عمودی که در نمودار «نمایه پردازش GPU» نمایش داده می‌شود، نشان‌دهنده مرحله‌ای از خط لوله است و با رنگ خاصی در نمودار میله‌ای برجسته شده است. شکل ۲ راهنمای معنی هر رنگ نمایش‌داده‌شده را نشان می‌دهد.

راهنمای نمودار پرداز کردن واحد پردازش گرافیکی نمایه
شکل ۲. راهنمای نمودار پردازش GPU نمایه

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

مراحل و معانی آن‌ها

این بخش توضیح می‌دهد که درطول هر مرحله چه اتفاقی می‌افتد و همچنین دلایل گلوگاه را که باید مراقب آن‌ها بود توضیح می‌دهد.

مدیریت ورودی

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

وقتی این بخش بزرگ است

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

پیمایش در LazyColumn یا LazyRow نیز می‌تواند در این مرحله ظاهر شود. وقتی لمس کاربر به‌عنوان پیمایش واجدشرایط باشد، فهرست تنبل رویدادهای لمسی را برای ترکیب و چیدمان پویای موارد مصرف می‌کند. اگر برنامه‌تان کار سفارشی‌ای را در پاسخ به تغییرات موقعیت پیمایش انجام می‌دهد، مهم است که این عملیات را در سریع‌ترین زمان ممکن انجام دهید تا از افت فریم جلوگیری شود. ابزارهای نمایه‌سازی مانند «تحلیل‌گر واحد پردازش مرکزی» در «استودیو Android» یا Perfetto می‌توانند به شما کمک کنند بیشتر بررسی کنید. برای اطلاعات بیشتر، نمای کلی ردیابی سیستم را ببینید.

پویانمایی

فاز پویانمایی‌ها به شما نشان می‌دهد که ارزیابی همه حالت‌های پویانمایی که در آن فریم درحال اجرا بودند چقدر طول کشیده است. برخی‌از میاناهای برنامه‌سازی کاربردی پویانمایی رایج در Compose عبارت‌اند از animate*AsState، Transition، و Animatable. علاوه‌براین، Recomposer درطول این مرحله اجرا می‌شود تا تغییرات وضعیت عکس آنی را پردازش کند و ترکیب‌بندی‌ها را به‌روز کند. این یعنی سربار بازترکیب اغلب مستقیماً در مرحله پویانمایی ظاهر می‌شود.

برای رابط‌های کاربری Jetpack Compose، کتابخانه Compose Runtime Tracing را اضافه کنید تا ردیابی‌های ترکیب‌بندی دقیق را درکنار رویدادهای سیستم ببینید.

وقتی این بخش بزرگ است

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

Measure

برای ترسیم composable در صفحه، Android سه فاز را در گره‌های چیدمان در درخت UI اجرا می‌کند.

ابتدا، سیستم گره‌های چیدمان را اندازه‌گیری می‌کند. هر ترکیب‌پذیر دارای محدودیت‌ها و اصلاح‌کننده‌های خاصی است که حدود اندازه شیء را در صفحه توصیف می‌کند. برخی‌از ترکیب‌پذیرها می‌توانند اندازه ثابت و مشخصی داشته باشند؛ برخی دیگر اندازه‌ای دارند که با محدودیت‌های منتقل‌شده از ظرف چیدمان ولی سازگار می‌شود.

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

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

وقتی این بخش بزرگ است

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

از «تحلیل‌گر واحد پردازش مرکزی» در «استودیو Android» یا Perfetto برای بررسی گذرهای چیدمان و شناسایی گلوگاه‌ها استفاده کنید. برای اطلاعات بیشتر، نمای کلی ردیابی سیستم را ببینید.

طراحی کردن

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

نوار «ترسیم» مدت زمان لازم برای تکمیل ضبط فرمان‌ها در فهرست نمایش را برای همه گره‌های چیدمانی که لازم است در این فریم در صفحه به‌روز شوند ثبت می‌کند. زمان اندازه‌گیری‌شده برای هرگونه منطق ترسیم سفارشی که ممکن است در اصلاح‌کننده‌های ترسیم یا Canvas composable داشته باشید نیز اعمال می‌شود.

وقتی این بخش بزرگ است

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

علاوه‌براین، Compose اغلب مراحل اندازه‌گیری و چیدمان داخلی خود را در چارچوب آنچه پلاتفرم به‌عنوان فاز «ترسیم» درنظر می‌گیرد، مدیریت می‌کند. درنتیجه، نوار «ترسیم» بالا می‌تواند به‌دلیل عملیات‌های اندازه‌گیری/چیدمان داخلی پرهزینه یا بیش‌ازحد باشد، نه فقط به‌دلیل فرمان‌های ترسیم. اگر شک دارید، ردیابی Perfetto را ضبط کنید تا ببینید آیا سربار ناشی از روال‌های ترسیم است یا مراحل اندازه‌گیری و چیدمان Compose.

بارگذاری

سنجه بارگذاری نشان‌دهنده زمان لازم برای انتقال اشیاء بیت‌مپ از حافظه CPU به حافظه GPU درطول قاب فعلی است.

به‌عنوان پردازنده‌های متفاوت، CPU و GPU دارای نواحی RAM متفاوتی هستند که به پردازش اختصاص داده شده‌اند. وقتی بیت‌مپ را در Android ترسیم می‌کنید، سیستم بیت‌مپ را به حافظه واحد پردازش گرافیکی (GPU) منتقل می‌کند تا GPU بتواند آن را در صفحه‌نمایش ارائه کند. سپس، GPU نقشه بیتی را ذخیره می‌کند تا سیستم نیازی به انتقال مجدد داده‌ها نداشته باشد، مگر اینکه بافت از حافظه پنهان بافت GPU حذف شود.

توجه: در دستگاه‌های Lollipop، این مرحله بنفش است.

وقتی این بخش بزرگ است

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

برای کوچک کردن این نوار، می‌توانید از تکنیک‌هایی مانند موارد زیر استفاده کنید:

  • مطمئن شوید وضوح نگاشت بیتی شما خیلی بزرگ‌تر از اندازه‌ای که نمایش داده خواهد شد نباشد. برای مثال، از نمایش تصویر ۱۰۲۴×۱۰۲۴ به‌صورت تصویر ۴۸×۴۸ خودداری کنید.
  • بهره‌برداری از کتابخانه‌های مدرن مانند Coil برای پیش‌بارگذاری ناهمگام نقشه بیتی قبل‌از مرحله همگام‌سازی بعدی.

فرمان‌های مشکل

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

برای اینکه سیستم فهرست‌های نمایش را روی صفحه‌نمایش ترسیم کند، فرمان‌های لازم را به GPU ارسال می‌کند. معمولاً این کار را ازطریق میانای برنامه‌سازی کاربردی OpenGL ES انجام می‌دهد.

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

وقتی این بخش بزرگ است

زمان صرف‌شده در این مرحله معیار مستقیمی از پیچیدگی و تعداد فهرست‌های نمایشی است که سیستم در یک قاب معین ارائه می‌کند. برای مثال، داشتن عملیات‌های ترسیم متعدد، به‌ویژه در مواردی که هزینه ذاتی کوچکی برای هر ترسیم اولیه وجود دارد، می‌تواند این زمان را افزایش دهد. برای مثال:

for (i in 0 until 1000) {
    canvas.drawPoint()
}

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

canvas.drawPoints(thousandPointArray)

همیشه همبستگی ۱:۱ بین صدور فرمان‌ها و ترسیم واقعی فهرست‌های نمایش وجود ندارد. برخلاف نوار فرمان‌های مشکل، که مدت‌زمان لازم برای ارسال فرمان‌های ترسیم به GPU را ثبت می‌کند، سنجه ترسیم نشان‌دهنده مدت‌زمان لازم برای ثبت فرمان‌های صادرشده در فهرست نمایش است.

این تفاوت به این دلیل است که فهرست‌های نمایش هرجا که ممکن باشد توسط سیستم در حافظه نهان ذخیره می‌شوند. درنتیجه، موقعیت‌هایی وجود دارد که در آن پیمایش، تبدیل، یا پویانمایی سیستم را ملزم می‌کند تا فهرست نمایش را دوباره ارسال کند، اما درواقع مجبور نیست آن را از ابتدا بازسازی کند (دستورات طراحی را دوباره ضبط کند). درنتیجه، ممکن است نوار فرمان‌های صدور بالا را ببینید بدون اینکه نوار فرمان‌های ترسیم بالا را ببینید.

میان‌گیرهای جابه‌جایی

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

وقتی این بخش بزرگ است

باید بدانید که GPU کار را به‌طور موازی با CPU اجرا می‌کند. سیستم Android فرمان‌های ترسیم را به GPU صادر می‌کند و سپس به تکلیف بعدی می‌رود. واحد پردازش گرافیکی این فرمان‌های ترسیم را از صف می‌خواند و آن‌ها را پردازش می‌کند.

در شرایطی که CPU دستورات را سریع‌تر از مصرف GPU صادر می‌کند، صف ارتباطات بین پردازنده‌ها ممکن است پر شود. وقتی این اتفاق می‌افتد، CPU مسدود می‌شود و منتظر می‌ماند تا فضایی در صف برای قرار دادن فرمان بعدی ایجاد شود. این حالت صف کامل اغلب درطول مرحله بافرهای مبادله ایجاد می‌شود، زیرا در آن نقطه، دستوراتی به‌اندازه یک قاب کامل ارسال شده است.

کلید کاهش این مشکل، کاهش پیچیدگی کاری است که در GPU انجام می‌شود، به روشی مشابه آنچه برای مرحله صدور فرمان انجام می‌دهید.

متفرقه

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

وقتی این بخش بزرگ است

اگر این مقدار بالا باشد، احتمالاً برنامه‌تان دارای فراخوانی‌های برگشتی، هدف‌ها، یا کارهای دیگری است که باید در رشته دیگری اتفاق بیفتد. ابزارهایی مانند نمایه‌ساز CPU در Android Studio یا Perfetto می‌توانند دیدی نسبت به وظایفی که در رشته اصلی درحال اجرا هستند ارائه دهند. این اطلاعات می‌تواند به شما کمک کند بهبودهای عملکرد را هدف‌یابی کنید. برای اطلاعات بیشتر، نمای کلی ردیابی سیستم را ببینید.