Thermal API

เผยแพร่

Android 11 (API ระดับ 30) - Thermal API

Android 12 (API ระดับ 31) - API ของ NDK

(ตัวอย่าง) Android 15 (DP1) - getThermalHeadroomThresholds()

ประสิทธิภาพที่อาจเกิดขึ้นของแอปจะถูกจำกัดโดยสถานะความร้อนของ อุปกรณ์ ซึ่งอาจแตกต่างกันไปตามลักษณะต่างๆ เช่น สภาพอากาศ การใช้งานล่าสุด และการออกแบบการระบายความร้อนของอุปกรณ์ อุปกรณ์จะรักษาประสิทธิภาพในระดับสูงได้เพียงระยะเวลาหนึ่งเท่านั้นก่อนที่จะถูกจำกัดความร้อน เป้าหมายหลักของการติดตั้งใช้งานควรเป็นการบรรลุเป้าหมายด้านประสิทธิภาพโดยไม่เกินข้อจำกัดด้านความร้อน Thermal API ช่วยให้ทำได้โดยไม่ต้อง มีการเพิ่มประสิทธิภาพเฉพาะอุปกรณ์ นอกจากนี้ เมื่อแก้ไขข้อบกพร่องด้านประสิทธิภาพ การทราบว่าสถานะความร้อนของอุปกรณ์จำกัดประสิทธิภาพหรือไม่ก็เป็นสิ่งสำคัญ

โดยปกติแล้ว Game Engine จะมีพารามิเตอร์ประสิทธิภาพรันไทม์ที่สามารถปรับ ภาระงานที่ Engine ใส่ไว้ในอุปกรณ์ได้ เช่น พารามิเตอร์เหล่านี้สามารถตั้งค่า จำนวนเทรดของผู้ปฏิบัติงาน ความสัมพันธ์ของเทรดของผู้ปฏิบัติงานสำหรับคอร์ขนาดใหญ่และขนาดเล็ก ตัวเลือกความเที่ยงตรงของ GPU และความละเอียดของเฟรมบัฟเฟอร์ ใน Unity Engine นักพัฒนาเกมสามารถปรับปริมาณงานได้โดยการเปลี่ยนการตั้งค่าคุณภาพโดยใช้ปลั๊กอิน Adaptive Performance สำหรับ Unreal Engine ให้ใช้การตั้งค่าความสามารถในการปรับขนาดเพื่อปรับ ระดับคุณภาพแบบไดนามิก

เมื่ออุปกรณ์เข้าใกล้สถานะความร้อนที่ไม่ปลอดภัย เกมจะหลีกเลี่ยงการถูกควบคุมได้โดยการลดภาระงานผ่านพารามิเตอร์เหล่านี้ คุณควรตรวจสอบสถานะความร้อนของอุปกรณ์และปรับปริมาณงานของเอนจินเกม ล่วงหน้าเพื่อหลีกเลี่ยงการควบคุมปริมาณ

เมื่ออุปกรณ์ร้อนเกินไป ภาระงานจะต้อง ลดลงต่ำกว่าระดับประสิทธิภาพที่ยั่งยืนเพื่อระบายความร้อน หลังจาก ส่วนต่างของอุณหภูมิลดลงไปอยู่ในระดับที่ปลอดภัยมากขึ้นแล้ว เกมจะเพิ่ม การตั้งค่าคุณภาพได้อีกครั้ง แต่โปรดตรวจสอบว่าได้ตั้งค่าคุณภาพในระดับที่ยั่งยืนเพื่อ เวลาในการเล่นที่เหมาะสม

คุณตรวจสอบสถานะความร้อนของอุปกรณ์ได้โดยการสำรวจเมธอด getThermalHeadroom วิธีนี้จะคาดการณ์ระยะเวลาที่อุปกรณ์จะ รักษาระดับประสิทธิภาพปัจจุบันได้โดยไม่ร้อนเกินไป หากเวลาเหลือน้อยกว่าเวลาที่จำเป็นในการเรียกใช้เวิร์กโหลด เกมควรลดเวิร์กโหลดลงให้อยู่ในระดับที่ยั่งยืน เช่น เกมอาจเปลี่ยนไปใช้คอร์ขนาดเล็ก ลดอัตราเฟรม หรือลดความเที่ยงตรง

การผสานรวม Thermal API ของ ADPF ล่วงหน้า
รูปที่ 1 ส่วนหัวระบายความร้อนโดยไม่ต้องตรวจสอบอย่างต่อเนื่อง getThermalHeadroom
ADPF Thermal API Post-Integration
รูปที่ 2 โอกาสในการเพิ่มประสิทธิภาพด้านความร้อนด้วยการตรวจสอบ `getThermalHeadroom`อย่างต่อเนื่อง

ดาวน์โหลด Thermal Manager

หากต้องการใช้ Thermal API คุณจะต้องรับ Thermal Manager ก่อน

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

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

คาดการณ์ Thermal Headroom ล่วงหน้า x วินาทีเพื่อควบคุมได้มากขึ้น

คุณขอให้ระบบคาดการณ์อุณหภูมิในอีก x วินาทีข้างหน้าได้โดยใช้ ปริมาณงานปัจจุบัน ซึ่งช่วยให้คุณควบคุมได้อย่างละเอียดมากขึ้นและมีเวลาตอบสนองมากขึ้น โดยการลดปริมาณงานเพื่อป้องกันไม่ให้เกิดการควบคุมความร้อน

ผลลัพธ์มีตั้งแต่ 0.0f (ไม่มีการจำกัดอัตรา THERMAL_STATUS_NONE)

เป็น 1.0f (การควบคุมปริมาณอย่างหนัก THERMAL_STATUS_SEVERE) หากเกมของคุณมีระดับคุณภาพกราฟิกที่แตกต่างกัน คุณสามารถทำตามหลักเกณฑ์เกี่ยวกับส่วนต่างของอุณหภูมิ

C++

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

Java

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

หรือจะดูสถานะความร้อนเพื่อความชัดเจนก็ได้

อุปกรณ์แต่ละรุ่นอาจได้รับการออกแบบแตกต่างกัน อุปกรณ์บางเครื่องอาจระบายความร้อนได้ดีกว่า จึงทนต่อส่วนต่างของอุณหภูมิที่สูงขึ้นได้ก่อนที่จะถูกจำกัด หากต้องการอ่านการจัดกลุ่มช่วงของ ส่วนต่างอุณหภูมิที่ง่ายขึ้น ให้ตรวจสอบสถานะความร้อนเพื่อทำความเข้าใจค่า ส่วนต่างอุณหภูมิในอุปกรณ์ปัจจุบัน

C++

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

Java

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

รับการแจ้งเตือนเมื่อสถานะความร้อนเปลี่ยนแปลง

นอกจากนี้ คุณยังหลีกเลี่ยงการสำรวจthermalHeadroomจนกว่าthermalStatusจะถึงระดับหนึ่งได้ด้วย (เช่น THERMAL_STATUS_LIGHT) โดยลงทะเบียนการเรียกกลับเพื่อให้ระบบแจ้งเตือนคุณทุกครั้งที่สถานะมีการเปลี่ยนแปลง

C++

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

Java

// 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);

อย่าลืมนำ Listener ออกเมื่อเสร็จสิ้น

C++

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

Java

powerManager.removeThermalStatusListener(listener);

ทำความสะอาดข้อมูล

เมื่อเสร็จแล้ว คุณจะต้องล้างข้อมูล thermal_manager ที่คุณได้รับ หากคุณใช้ Java ระบบจะรวบรวมข้อมูลอ้างอิง PowerManager ให้คุณโดยอัตโนมัติ แต่หากคุณใช้ Java API ผ่าน JNI และเก็บข้อมูลอ้างอิงไว้ โปรดอย่าลืมล้างข้อมูลอ้างอิง

C++

AThermal_releaseManager(thermal_manager);

ดูคำแนะนำฉบับสมบูรณ์เกี่ยวกับวิธีใช้ Thermal API ในเกม C++ แบบเนทีฟโดยใช้ทั้ง C++ API (NDK API) และ Java API (ผ่าน JNI) ได้ที่ส่วนผสานรวม Thermal API ในส่วนCodelab เกี่ยวกับความสามารถในการปรับตัว

หลักเกณฑ์เกี่ยวกับส่วนต่างของอุณหภูมิ

คุณตรวจสอบสถานะความร้อนของอุปกรณ์ได้โดยการสำรวจเมธอด getThermalHeadroom วิธีนี้จะคาดการณ์ระยะเวลาที่อุปกรณ์จะรักษาระดับประสิทธิภาพปัจจุบันได้ก่อนที่จะถึงTHERMAL_STATUS_SEVERE เช่น หาก getThermalHeadroom(30) แสดงผล 0.8 แสดงว่าในอีก 30 วินาที คาดว่าเฮดรูมจะอยู่ที่ 0.8 ซึ่งอยู่ห่างจากขีดจำกัดการควบคุมอย่างรุนแรงหรือ 1.0 เป็นระยะทาง 0.2 หากเวลาที่เหลืออยู่น้อยกว่าเวลาที่จำเป็นในการเรียกใช้ภาระงาน เกมของคุณควรลดภาระงานลงให้อยู่ในระดับที่ยั่งยืน ตัวอย่างเช่น เกมสามารถลดอัตราเฟรม ลดความเที่ยงตรง หรือ ลดการทำงานของการเชื่อมต่อเครือข่าย

สถานะความร้อนและความหมาย

ข้อจำกัดของอุปกรณ์ใน Thermal API

API ความร้อนมีข้อจำกัดที่ทราบหรือข้อกำหนดเพิ่มเติมบางอย่างเนื่องจากการติดตั้งใช้งาน API ความร้อนในอุปกรณ์รุ่นเก่า ข้อจำกัดและวิธี แก้ไขมีดังนี้

  • อย่าเรียกใช้ API GetThermalHeadroom() บ่อยเกินไป หากดำเนินการดังกล่าว API จะแสดง NaN คุณไม่ควรเรียกใช้มากกว่า 1 ครั้งทุกๆ 10 วินาที
  • หลีกเลี่ยงการเรียกจากหลายเธรด เนื่องจากจะทำให้ควบคุมความถี่ในการเรียกได้ยากขึ้น และอาจทำให้ API แสดงผล NaN
  • หากค่าเริ่มต้นของ GetThermalHeadroom() เป็น NaN แสดงว่า API ไม่พร้อมใช้งานในอุปกรณ์
  • หาก GetThermalHeadroom() แสดงค่าสูง (เช่น 0.85 ขึ้นไป) และ GetCurrentThermalStatus() ยังคงแสดง THERMAL_STATUS_NONE อยู่ สถานะ อาจยังไม่อัปเดต ใช้ฮิวริสติกเพื่อประมาณสถานะการควบคุมอุณหภูมิที่ถูกต้อง หรือใช้ getThermalHeadroom() โดยไม่มี getCurrentThermalStatus()

ตัวอย่างการคาดคะเน

  1. ตรวจสอบว่าอุปกรณ์รองรับ Thermal API isAPISupported() จะตรวจสอบค่าของการเรียกครั้งแรกไปยัง getThermalHeadroom เพื่อให้แน่ใจว่าค่าดังกล่าวไม่ใช่ 0 หรือ NaN และ ข้ามการใช้ API หากค่าแรกเป็น 0 หรือ NaN
  2. หาก getCurrentThermalStatus() แสดงผลค่าอื่นที่ไม่ใช่ THERMAL_STATUS_NONE แสดงว่าอุปกรณ์กำลังถูกจำกัดความเร็วเนื่องจากความร้อน
  3. หาก getCurrentThermalStatus() แสดง THERMAL_STATUS_NONE ต่อไปเรื่อยๆ ไม่ได้หมายความว่าอุปกรณ์ไม่ได้ถูกจำกัดความเร็วเนื่องจากความร้อน ซึ่งอาจหมายความว่าอุปกรณ์ไม่รองรับ getCurrentThermalStatus() ตรวจสอบค่าที่ส่งคืนของ getThermalHeadroom() เพื่อให้แน่ใจว่าอุปกรณ์มีสภาพเป็นไปตามที่ระบุ
  4. หาก getThermalHeadroom() แสดงค่า > 1.0 สถานะอาจเป็น THERMAL_STATUS_SEVERE หรือสูงกว่า ให้ลดภาระงานทันที และคงภาระงานไว้ในระดับต่ำจนกว่า getThermalHeadroom() จะแสดงค่าที่ต่ำกว่า
  5. หาก getThermalHeadroom() แสดงค่า 0.95 สถานะอาจเป็น THERMAL_STATUS_MODERATE หรือสูงกว่านั้น ลดภาระงานทันทีและคอยสังเกตเพื่อป้องกันไม่ให้ค่าสูงขึ้น
  6. หาก getThermalHeadroom() แสดงค่า 0.85 สถานะอาจเป็น THERMAL_STATUS_LIGHT โปรดระมัดระวังและลดภาระงานหากเป็นไปได้

Pseudocode:

  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
ตัวอย่าง
รูปที่ 3 ตัวอย่างฮิวริสติกเพื่อพิจารณาการรองรับ Thermal API ในอุปกรณ์รุ่นเก่า