API حرارتی

منتشر شد :

اندروید ۱۱ (API سطح ۳۰) - API حرارتی

Android 12 (API سطح 31) - NDK API

(پیش‌نمایش) اندروید ۱۵ (DP1) - getThermalHeadroomThresholds()

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

موتورهای بازی معمولاً پارامترهای عملکرد زمان اجرا دارند که می‌توانند بار کاری که موتور روی دستگاه اعمال می‌کند را تنظیم کنند. به عنوان مثال، این پارامترها می‌توانند تعداد رشته‌های کارگر، وابستگی رشته‌های کارگر برای هسته‌های بزرگ و کوچک، گزینه‌های وفاداری GPU و وضوح فریم بافر را تنظیم کنند. در موتور Unity، توسعه‌دهندگان بازی می‌توانند بار کاری را با تغییر تنظیمات کیفیت با استفاده از افزونه Adaptive Performance تنظیم کنند. برای موتور Unreal، از تنظیمات مقیاس‌پذیری برای تنظیم پویای سطوح کیفیت استفاده کنید.

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

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

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

ADPF Thermal API Pre-integration
شکل ۱. سقف حرارتی بدون نظارت فعال
ADPF حرارتی API پس از ادغام
شکل ۲. سقف حرارتی با نظارت فعال `getThermalHeadroom`

مدیریت حرارتی را بدست آورید

برای استفاده از Thermal API، ابتدا باید Thermal Manager را دریافت کنید.

سی++

AThermalManager* thermal_manager = AThermal_acquireManager();

جاوا

PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);

برای کنترل بیشتر، ارتفاع سقف حرارتی را x ثانیه جلوتر پیش‌بینی کنید

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

نتیجه از 0.0f (بدون تنظیم گلوگاه، THERMAL_STATUS_NONE ) متغیر است.

به ۱.۰f (گلوگاه شدید، THERMAL_STATUS_SEVERE ). اگر در بازی‌های خود سطوح کیفیت گرافیکی متفاوتی دارید، می‌توانید دستورالعمل‌های مربوط به فضای حرارتی ما را دنبال کنید.

سی++

float thermal_headroom = AThermal_getThermalHeadroom(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);

جاوا

float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + thermalHeadroom);

از طرف دیگر، برای روشن شدن موضوع، به وضعیت حرارتی تکیه کنید

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

سی++

AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);

جاوا

int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);

هنگام تغییر وضعیت حرارتی مطلع شوید

همچنین می‌توانید از ارسال اطلاعات به thermalHeadroom تا زمانی که thermalStatus به سطح خاصی نرسد (مثلاً: THERMAL_STATUS_LIGHT ) خودداری کنید. برای انجام این کار، می‌توانید یک callback ثبت کنید تا سیستم هر زمان که وضعیت تغییر کرد، به شما اطلاع دهد.

سی++

int result = AThermal_registerThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether you have previously registered callback that
  // hasn’t been unregistered
}

جاوا

// PowerManager.OnThermalStatusChangedListener is an interface, thus you can
// also define a class that implements the methods
PowerManager.OnThermalStatusChangedListener listener = new
  PowerManager.OnThermalStatusChangedListener() {
    @Override
    public void onThermalStatusChanged(int status) {
        Log.d("ADPF", "ThermalStatus changed: " + status);
        // check the status and flip the flag to start/stop pooling when
        // applicable
    }
};
powerManager.addThermalStatusListener(listener);

به یاد داشته باشید که پس از اتمام کار، شنونده را حذف کنید

سی++

int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether the callback has been registered previously
}

جاوا

powerManager.removeThermalStatusListener(listener);

پاکسازی

پس از اتمام کار، باید thermal_manager که به دست آورده‌اید را پاک کنید. اگر از جاوا استفاده می‌کنید، مرجع PowerManager می‌تواند به طور خودکار برای شما جمع‌آوری زباله شود. اما اگر از API جاوا از طریق JNI استفاده می‌کنید و یک مرجع را نگه داشته‌اید، به یاد داشته باشید که آن مرجع را پاک کنید!

سی++

AThermal_releaseManager(thermal_manager);

برای راهنمای کامل در مورد نحوه پیاده‌سازی API حرارتی در یک بازی بومی C++ با استفاده از API سی‌پلاس‌پلاس (NDK API) و API جاوا (از طریق JNI)، بخش ادغام API حرارتی را در بخش آزمایشگاه کد Adaptability بررسی کنید.

دستورالعمل‌های مربوط به فضای بالای سر حرارتی

شما می‌توانید وضعیت حرارتی دستگاه را با استفاده از روش getThermalHeadroom بررسی کنید. این روش پیش‌بینی می‌کند که دستگاه چه مدت می‌تواند سطح عملکرد فعلی را قبل از رسیدن به THERMAL_STATUS_SEVERE حفظ کند. به عنوان مثال، اگر getThermalHeadroom(30) مقدار 0.8 را برگرداند، نشان می‌دهد که انتظار می‌رود در 30 ثانیه، سقف به 0.8 برسد، که در آن 0.2 فاصله تا گلوگاه شدید یا 1.0 وجود دارد. اگر زمان کمتر از مقدار مورد نیاز برای اجرای حجم کار باشد، بازی شما باید حجم کار را تا سطح پایداری کاهش دهد. به عنوان مثال، بازی می‌تواند نرخ فریم را کاهش دهد، وفاداری را پایین بیاورد یا کار اتصال به شبکه را کاهش دهد.

وضعیت‌های حرارتی و معانی آنها

محدودیت‌های دستگاه API حرارتی

به دلیل پیاده‌سازی API حرارتی در دستگاه‌های قدیمی‌تر، محدودیت‌های شناخته‌شده یا الزامات اضافی برای API حرارتی وجود دارد. این محدودیت‌ها و نحوه‌ی رفع آن‌ها به شرح زیر است:

  • تابع GetThermalHeadroom() را زیاد فراخوانی نکنید. اگر این کار را انجام دهید، API NaN را برمی‌گرداند. نباید بیش از هر 10 ثانیه یکبار آن را فراخوانی کنید.
  • از فراخوانی از چندین نخ خودداری کنید، زیرا اطمینان از فرکانس فراخوانی دشوارتر است و ممکن است باعث شود API NaN را برگرداند.
  • اگر مقدار اولیه‌ی GetThermalHeadroom() برابر با NaN باشد، API روی دستگاه در دسترس نیست.
  • اگر GetThermalHeadroom() مقدار بالایی (مثلاً: 0.85 یا بیشتر) را برگرداند و GetCurrentThermalStatus() همچنان THERMAL_STATUS_NONE را برگرداند، احتمالاً وضعیت به‌روزرسانی نشده است. از روش‌های اکتشافی برای تخمین وضعیت صحیح گلوگاه حرارتی استفاده کنید یا فقط getThermalHeadroom() بدون getCurrentThermalStatus() استفاده کنید.

مثال اکتشافی:

  1. بررسی کنید که آیا API حرارتی پشتیبانی می‌شود یا خیر. isAPISupported() مقدار اولین فراخوانی getThermalHeadroom را بررسی می‌کند تا مطمئن شود که ۰ یا NaN نیست و اگر مقدار اول ۰ یا NaN باشد، از استفاده از API صرف نظر می‌کند.
  2. اگر getCurrentThermalStatus() مقداری غیر از THERMAL_STATUS_NONE را برگرداند، دستگاه از نظر حرارتی در حالت تنظیم دما قرار دارد.
  3. اگر getCurrentThermalStatus() مرتباً مقدار THERMAL_STATUS_NONE را برمی‌گرداند، لزوماً به این معنی نیست که دستگاه از نظر حرارتی در حالت throttling نیست. این می‌تواند به این معنی باشد که getCurrentThermalStatus() در دستگاه پشتیبانی نمی‌شود. برای اطمینان از وضعیت دستگاه، مقدار بازگشتی تابع getThermalHeadroom() را بررسی کنید.
  4. اگر تابع getThermalHeadroom() مقداری بزرگتر از ۱.۰ برگرداند، وضعیت در واقع می‌تواند THERMAL_STATUS_SEVERE یا بالاتر باشد، بنابراین فوراً حجم کار را کاهش دهید و حجم کار را تا زمانی که getThermalHeadroom() مقدار کمتری برگرداند، پایین نگه دارید.
  5. اگر getThermalHeadroom() مقدار ۰.۹۵ را برگرداند، وضعیت می‌تواند در واقع THERMAL_STATUS_MODERATE یا بالاتر باشد، فوراً حجم کار را کاهش دهید و مراقب باشید تا از خواندن مقادیر بالاتر جلوگیری شود.
  6. اگر getThermalHeadroom() مقدار 0.85 را برگرداند، وضعیت در واقع می‌تواند THERMAL_STATUS_LIGHT باشد، مراقب باشید و در صورت امکان حجم کار را کاهش دهید.

شبه‌کد:

  bool isAPISupported() {
    float first_value_of_thermal_headroom = getThermalHeadroom();
    if ( first_value_of_thermal_headroom == 0 ||
      first_value_of_thermal_headroom == NaN ) {
        // Checked the thermal Headroom API's initial return value
        // it is NaN or 0,so, return false (not supported)
        return false;
    }
    return true;
  }

  if (!isAPISupported()) {
    // Checked the thermal Headroom API's initial return value, it is NaN or 0
    // Don’t use the API
  } else {
      // Use thermalStatus API to check if it returns valid values.
      if (getCurrentThermalStatus() > THERMAL_STATUS_NONE) {
          // The device IS being thermally throttled
      } else {
      // The device is not being thermally throttled currently. However, it
      // could also be an indicator that the ThermalStatus API may not be
      // supported in the device.
      // Currently this API uses predefined threshold values for thermal status
      // mapping. In the future  you may be able to query this directly.
      float thermal_headroom = getThermalHeadroom();
      if ( thermal_headroom > 1.0) {
            // The device COULD be severely throttled.
      } else  if ( thermal_headroom > 0.95) {
            // The device COULD be moderately throttled.
      } else if ( thermal_headroom > 0.85) {
            // The device COULD be experiencing light throttling.
      }
    }
  }

نمودار:

مثال اکتشافی ADPF
شکل ۳. مثالی از روش اکتشافی برای تعیین پشتیبانی از API حرارتی در دستگاه‌های قدیمی‌تر