API Nhiệt

Ngày phát hành:

Android 11 (API cấp 30) – API Nhiệt

Android 12 (API cấp 31) – API NDK

(Xem trước) Android 15 (DP1) – getThermalHeadroomThresholds()

Hiệu suất tiềm năng của ứng dụng bị giới hạn bởi trạng thái nhiệt của thiết bị. Trạng thái nhiệt có thể thay đổi tuỳ theo các yếu tố đặc thù như thời tiết, mức sử dụng gần đây và thiết kế tản nhiệt của thiết bị. Các thiết bị chỉ có thể duy trì hiệu suất cao trong một khoảng thời gian giới hạn trước khi bị điều tiết nhiệt. Mục tiêu chính của việc triển khai là đạt được mục tiêu về hiệu suất mà không bị vượt quá giới hạn nhiệt. API Nhiệt giúp bạn có thể thực hiện việc này mà không cần các phương pháp tối ưu hoá dành riêng cho thiết bị. Hơn nữa, khi gỡ lỗi các vấn đề về hiệu suất, bạn cần phải biết liệu trạng thái nhiệt của thiết bị có đang làm hạn chế hiệu suất hay không. Hơn nữa, khi gỡ lỗi các vấn đề về hiệu suất, bạn cần phải biết liệu trạng thái nhiệt của thiết bị có đang làm hạn chế hiệu suất hay không.

Các công cụ phát triển trò chơi thường có các thông số hiệu suất trong thời gian chạy giúp điều chỉnh mức tải mà công cụ phân cho thiết bị. Ví dụ: các thông số này có thể thiết lập số lượng luồng công việc, chỉ định luồng công việc cho các nhân xử lý lớn và nhỏ, các tuỳ chọn về độ trung thực của GPU cũng như độ phân giải bộ đệm khung. Trong Unity Engine, các nhà phát triển trò chơi có thể điều chỉnh khối lượng công việc bằng cách thay đổi phần Cài đặt chất lượng thông qua trình bổ trợ Hiệu suất thích ứng. Đối với Unreal Engine, hãy sử dụng Scalability Settings (Cài đặt khả năng mở rộng) để điều chỉnh mức chất lượng một cách linh hoạt.

Khi thiết bị đạt đến trạng thái nhiệt không an toàn, trò chơi có thể tránh bị điều tiết bằng cách giảm mức tải thông qua các thông số này. Để tránh việc bị điều tiết, bạn nên theo dõi trạng thái nhiệt của thiết bị và chủ động điều chỉnh mức tải của công cụ phát triển trò chơi. Khi thiết bị quá nóng, mức tải phải giảm xuống dưới mức hiệu suất ổn định để phân tán nhiệt. Sau khi khoảng nhiệt giảm xuống mức an toàn hơn, trò chơi có thể tăng lại chế độ cài đặt chất lượng nhưng đảm bảo tìm được mức chất lượng bền vững để có thời gian chơi tối ưu.

Bạn có thể theo dõi trạng thái nhiệt của thiết bị bằng cách thăm dò phương thức getThermalHeadroom. Phương thức này dự đoán khoảng thời gian thiết bị có thể duy trì mức hiệu suất hiện tại mà không quá nóng. Nếu khoảng thời gian này ít hơn thời gian cần thiết để chạy mức tải, thì trò chơi sẽ giảm mức tải xuống một mức ổn định. Ví dụ: trò chơi có thể chuyển sang các nhân xử lý nhỏ hơn, giảm tốc độ khung hình hoặc giảm độ trung thực.

Tích hợp trước API Nhiệt ADPF
Hình 1. Khoảng nhiệt mà không cần chủ động giám sát getThermalHeadroom
Tích hợp sau khi tích hợp API Nhiệt ADPF
Hình 2. Khoảng nhiệt với chức năng giám sát chủ động "getThermalHeadroom"

Mua bộ quản lý nhiệt

Để sử dụng Thermal API (API Nhiệt), trước tiên, bạn cần có Trình quản lý nhiệt

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

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

Dự báo Khoảng nhiệt lên trước x giây để kiểm soát tốt hơn

Bạn có thể yêu cầu hệ thống dự báo nhiệt độ x giây trước với khối lượng công việc hiện tại. Điều này giúp bạn kiểm soát chi tiết hơn và có thêm thời gian để phản ứng bằng cách giảm khối lượng công việc để ngăn điều tiết nhiệt hoạt động.

Kết quả dao động từ 0.0f (không điều tiết, THERMAL_STATUS_NONE) đến 1.0f (điều tiết nhiều, THERMAL_STATUS_SEVERE). Nếu trò chơi của bạn có nhiều mức chất lượng đồ hoạ, thì bạn có thể làm theo Nguyên tắc về khoảng nhiệt của chúng tôi.

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

Ngoài ra, hãy dựa vào trạng thái nhiệt để làm rõ

Mỗi mẫu thiết bị có thể được thiết kế theo cách khác nhau. Một số thiết bị có thể phân phối nhiệt tốt hơn, do đó có thể chịu được khoảng nhiệt cao hơn trước khi bị điều tiết. Nếu muốn đọc một nhóm các khoảng nhiệt được đơn giản hoá, bạn có thể kiểm tra trạng thái nhiệt để biết được giá trị khoảng nhiệt trên thiết bị hiện tại.

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

Nhận thông báo khi trạng thái nhiệt thay đổi

Bạn cũng có thể tránh thăm dò thermalHeadroom cho đến khi thermalStatus đạt đến một mức nhất định (ví dụ: THERMAL_STATUS_LIGHT). Để thực hiện việc này, bạn có thể đăng ký lệnh gọi lại để hệ thống thông báo cho bạn bất cứ khi nào trạng thái thay đổi.

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

Nhớ loại bỏ trình nghe khi hoàn tất

C++

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

Java

powerManager.removeThermalStatusListener(listener);

Dọn dẹp

Sau khi hoàn tất, bạn sẽ cần dọn dẹp thermal_manager mà mình đã mua. Nếu bạn đang sử dụng Java, tệp tham chiếu PowerManager có thể tự động được thu thập rác cho bạn. Nhưng nếu bạn đang sử dụng API Java thông qua JNI và đã giữ lại một tệp tham chiếu, hãy nhớ dọn dẹp tệp tham chiếu đó!

C++

AThermal_releaseManager(thermal_manager);

Để xem hướng dẫn đầy đủ về cách triển khai API Nhiệt trên trò chơi C++ gốc bằng cả API C++ (API NDK) và API Java (thông qua JNI), hãy xem phần Tích hợp API Nhiệt trong phần Lớp học lập trình về khả năng thích ứng.

Nguyên tắc về khoảng nhiệt

Bạn có thể theo dõi trạng thái nhiệt của thiết bị bằng cách thăm dò phương thức getThermalHeadroom. Phương thức này dự đoán khoảng thời gian thiết bị có thể duy trì mức hiệu suất hiện tại trước khi đạt đến THERMAL_STATUS_SEVERE. Ví dụ: nếu getThermalHeadroom(30) trả về 0,8, thì điều đó cho biết rằng trong 30 giây, mức trần dự kiến sẽ đạt 0,8, khi khoảng cách so với mức điều tiết nghiêm trọng là 0,2 hoặc 1,0. Nếu thời gian ít hơn thời gian cần thiết để chạy khối lượng công việc, thì trò chơi sẽ giảm khối lượng công việc xuống một mức bền vững. Ví dụ: trò chơi có thể làm giảm tốc độ khung hình, giảm độ chân thực hoặc giảm hoạt động kết nối mạng.

Trạng thái nhiệt và ý nghĩa

Giới hạn của thiết bị về API Nhiệt

Do việc triển khai API Nhiệt trên các thiết bị cũ, có một số giới hạn đã biết hoặc yêu cầu bổ sung của API Nhiệt. Sau đây là các giới hạn và cách khắc phục:

  • Đừng gọi API GetThermalHeadroom() quá thường xuyên. Nếu làm như vậy, API sẽ trả về NaN. Bạn nên gọi hàm này tối đa một lần mỗi giây.
  • Nếu giá trị ban đầu của GetThermalHeadroom() là NaN, thì API này sẽ không có sẵn trên thiết bị
  • Nếu GetThermalHeadroom() trả về một giá trị cao (ví dụ: 0,85 trở lên) và GetCurrentThermalStatus() vẫn trả về THERMAL_STATUS_NONE, thì trạng thái có thể chưa được cập nhật. Sử dụng thông tin phỏng đoán để ước tính trạng thái điều tiết nhiệt chính xác hoặc chỉ sử dụng getThermalHeadroom() mà không có getCurrentThermalStatus().

Ví dụ về Heuristics:

  1. Kiểm tra để đảm bảo rằng API Nhiệt được hỗ trợ. isAPISupported() kiểm tra giá trị của lệnh gọi đầu tiên đến getThermalHeadroom để đảm bảo rằng giá trị đó không phải là 0 hoặc NaN và bỏ qua việc sử dụng API nếu giá trị đầu tiên là 0 hoặc NaN.
  2. Nếu getCurrentThermalStatus() trả về một giá trị không phải THERMAL_STATUS_NONE, thì thiết bị đang được điều tiết nhiệt.
  3. Nếu getCurrentThermalStatus() liên tục trả về THERMAL_STATUS_NONE, thì không nhất thiết có nghĩa là thiết bị không được điều tiết nhiệt. Điều này có thể nghĩa là getCurrentThermalStatus() không được thiết bị hỗ trợ. Hãy kiểm tra giá trị trả về của getThermalHeadroom() để đảm bảo điều kiện của thiết bị.
  4. Nếu getThermalHeadroom() trả về giá trị > 1,0, thì trạng thái thực sự có thể là THERMAL_STATUS_SEVERE trở lên, hãy giảm khối lượng công việc ngay lập tức và duy trì khối lượng công việc thấp hơn cho đến khi getThermalHeadroom() trả về giá trị thấp hơn
  5. Nếu getThermalHeadroom() trả về giá trị 0,95, thì trạng thái thực sự có thể là THERMAL_STATUS_MODERATE trở lên, hãy giảm khối lượng công việc ngay lập tức và luôn chú ý để tránh tình trạng đọc cao hơn
  6. Nếu getThermalHeadroom() trả về giá trị 0,85, thì trạng thái thực sự có thể là THERMAL_STATUS_LIGHT, hãy chú ý theo dõi và giảm khối lượng công việc nếu có thể

Mã giả:

  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.
      }
    }
  }

Sơ đồ:

Ví dụ về kết quả thử nghiệm ADPF
Hình 3. Ví dụ về Heuristic để xác định tính năng hỗ trợ API Nhiệt trên các thiết bị cũ