تجزیه و تحلیل با نمایه GPU Rendering

ابزار Profile GPU Rendering زمان نسبی را نشان می دهد که هر مرحله از خط لوله رندر برای رندر فریم قبلی طول می کشد. این دانش می تواند به شما در شناسایی تنگناها در خط لوله کمک کند، به طوری که می توانید بدانید چه چیزی را برای بهبود عملکرد رندر برنامه خود بهینه کنید.

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

بازنمایی بصری

ابزار Profile GPU Rendering مراحل و زمان های نسبی آنها را در قالب یک نمودار نمایش می دهد: یک هیستوگرام با کد رنگی. شکل 1 نمونه ای از چنین نمایشگری را نشان می دهد.

شکل 1. نمودار رندر GPU نمایه

هر بخش از هر نوار عمودی که در نمودار نمایش GPU نمایه نمایش داده می شود، مرحله ای از خط لوله را نشان می دهد و با استفاده از یک رنگ خاص در نمودار میله ای برجسته می شود. شکل 2 یک کلید برای معنای هر رنگ نمایش داده شده را نشان می دهد.

شکل 2. نمایه GPU Rendering Graph Legend

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

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

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

مدیریت ورودی

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

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

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

همچنین شایان ذکر است که پیمایش RecyclerView می تواند در این مرحله ظاهر شود. RecyclerView بلافاصله هنگامی که رویداد لمسی را مصرف می کند، پیمایش می کند. در نتیجه، می‌تواند نماهای آیتم‌های جدیدی را افزایش یا پر کند. به همین دلیل، مهم است که این عملیات در سریع ترین زمان ممکن انجام شود. ابزارهای پروفایل مانند Traceview یا Systrace می توانند به شما در بررسی بیشتر کمک کنند.

انیمیشن

مرحله انیمیشن‌ها به شما نشان می‌دهد که ارزیابی همه انیماتورهایی که در آن فریم در حال اجرا بودند چقدر طول کشیده است. متداول ترین انیماتورها ObjectAnimator ، ViewPropertyAnimator و Transitions هستند.

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

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

اندازه گیری / چیدمان

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

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

دوم، سیستم آیتم های مشاهده را تنظیم می کند. هنگامی که سیستم اندازه نماهای کودکان را محاسبه می کند، سیستم می تواند با چیدمان، اندازه و موقعیت نماها روی صفحه ادامه دهد.

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

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

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

کدی که به onLayout(boolean, int, int, int, int) یا onMeasure(int, int) اضافه کرده‌اید نیز می‌تواند باعث مشکلات عملکرد شود. Traceview و Systrace می توانند به شما کمک کنند تا پشته های تماس را بررسی کنید تا مشکلاتی که ممکن است کد شما داشته باشد را شناسایی کنید.

قرعه کشی کنید

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

نوار Draw ثبت می‌کند که برای تمام نماهایی که باید روی صفحه نمایش این قاب به‌روزرسانی شوند، چقدر زمان طول می‌کشد تا تکمیل دستورات در لیست نمایش داده شود. زمان اندازه گیری شده برای هر کدی که به اشیاء رابط کاربری در برنامه خود اضافه کرده اید اعمال می شود. نمونه هایی از چنین کدهایی ممکن است onDraw() ، dispatchDraw() و draw ()methods متعلق به زیر کلاس های کلاس Drawable باشد.

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

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

همگام سازی/آپلود

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

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

نکته: در دستگاه های آب نبات چوبی این مرحله به رنگ بنفش است.

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

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

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

  • اطمینان حاصل کنید که وضوح بیت مپ شما خیلی بزرگتر از اندازه ای نیست که در آن نمایش داده می شود. به عنوان مثال، برنامه شما باید از نمایش تصویر 1024x1024 به عنوان یک تصویر 48x48 اجتناب کند.
  • استفاده از prepareToDraw() برای آپلود ناهمزمان یک بیت مپ قبل از مرحله همگام سازی بعدی.

دستورات را صادر کنید

بخش Issue Commands نشان دهنده زمان لازم برای صدور همه دستورات لازم برای رسم لیست های نمایشی روی صفحه است.

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

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

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

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

کاتلین

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

جاوا

for (int i = 0; i < 1000; i++) {
    canvas.drawPoint()
}

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

کاتلین

canvas.drawPoints(thousandPointArray)

جاوا

canvas.drawPoints(thousandPointArray);

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

این تفاوت به این دلیل به وجود می آید که لیست های نمایش در هر جایی که امکان داشته باشد توسط سیستم ذخیره می شوند. در نتیجه، موقعیت‌هایی وجود دارد که در آن یک اسکرول، تبدیل، یا انیمیشن به سیستم نیاز دارد تا یک لیست نمایشگر را دوباره بفرستد، اما نیازی به بازسازی آن - بازیابی دستورات ترسیم - از ابتدا ندارد. در نتیجه، می‌توانید یک نوار بالا «Issue commands» را بدون مشاهده نوار دستورات Draw بالا ببینید.

بافرهای پردازش/مبادله

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

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

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

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

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

متفرقه

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

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

اگر این مقدار زیاد است، احتمالاً برنامه شما دارای تماس‌ها، هدف‌ها یا کارهای دیگری است که باید در رشته دیگری انجام شود. ابزارهایی مانند Method Tracing یا Systrace می‌توانند قابلیت مشاهده وظایفی را که در رشته اصلی در حال اجرا هستند فراهم کنند. این اطلاعات می تواند به شما در هدف گذاری بهبود عملکرد کمک کند.