API ความร้อน

เผยแพร่:

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

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

(เวอร์ชันตัวอย่าง) Android 15 (DP1) - getThermalHeadroomThresholds()

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

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

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

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

วันที่ การผสานรวม ADPF Thermal API ล่วงหน้า
รูปที่ 1 Thermal Headroom โดยไม่ตรวจสอบ getThermalHeadroom อย่างสม่ำเสมอ
ADPF Thermal API หลังการผสานรวม
รูปที่ 2 Thermal Headroom พร้อมการตรวจสอบ "getThermalHeadroom" ที่ทำงานอยู่

รับ Thermal Manager

คุณต้องหา Thermal Manager ก่อนจึงจะใช้ Thermal API ได้

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(10);
ALOGI("ThermalHeadroom in 10 sec: %f", thermal_headroom);

Java

float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + 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 ได้จนกว่า Hit 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 ใน Adaptability Codelab

หลักเกณฑ์ช่องว่างทางความร้อน

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

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

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

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

  • อย่าเรียกใช้ GetThermalHeadroom() API บ่อยเกินไป การดำเนินการนี้จะ ทำให้ API แสดงผล NaN คุณควรโทรอย่างน้อย 1 ครั้งต่อวินาที
  • หากค่าเริ่มต้นของ 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 รักษาการเฝ้าระวังและลดปริมาณงาน ถ้าเป็นไปได้

ซูโดโค้ด:

  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 ตัวอย่าง Heuristic เพื่อกำหนดการรองรับ Thermal API ในอุปกรณ์รุ่นเก่า