เปิดตัว:
Android 12 (API ระดับ 31) - PerformanceHintManager
Android 13 (API ระดับ 33) - Performance Hint Manager ใน NDK API
Android 15 (DP1) - reportActualWorkDuration()
คำแนะนำด้านประสิทธิภาพของ CPU ช่วยให้แอปมีอิทธิพลต่อลักษณะการทำงานด้านประสิทธิภาพของ CPU แบบไดนามิกเพื่อให้ตรงกับความต้องการของแอปได้ดียิ่งขึ้น ในอุปกรณ์ส่วนใหญ่ Android จะปรับความเร็วนาฬิกาและประเภทคอร์ของ CPU แบบไดนามิกสำหรับภาระงานโดยอิงตามความต้องการก่อนหน้านี้ หากภาระงานใช้ทรัพยากร CPU มากขึ้น ระบบจะเพิ่มความเร็วนาฬิกาและย้ายภาระงานไปยังคอร์ที่ใหญ่ขึ้นในที่สุด หากภาระงานใช้ทรัพยากรน้อยลง Android จะลดการจัดสรรทรัพยากร ADPF ช่วยให้แอปส่งสัญญาณเพิ่มเติมเกี่ยวกับประสิทธิภาพและกำหนดเวลาได้ ซึ่งจะช่วยให้ระบบเพิ่มความเร็วในการทำงานได้มากขึ้น (ปรับปรุงประสิทธิภาพ) และลดความเร็วนาฬิกาลงอย่างรวดเร็วเมื่อภาระงานเสร็จสมบูรณ์ (ประหยัดการใช้พลังงาน)
ความเร็วนาฬิกา
เมื่ออุปกรณ์ Android ปรับความเร็วนาฬิกาของ CPU แบบไดนามิก ความถี่อาจเปลี่ยนประสิทธิภาพของโค้ดได้ การออกแบบโค้ดที่จัดการความเร็วนาฬิกาแบบไดนามิกมีความสำคัญต่อการเพิ่มประสิทธิภาพให้สูงสุด รักษาสถานะความร้อนที่ปลอดภัย และใช้พลังงานอย่างมีประสิทธิภาพ คุณไม่สามารถกำหนดความถี่ของ CPU ในโค้ดแอปได้โดยตรง ด้วยเหตุนี้ วิธีทั่วไปที่แอปใช้เพื่อพยายามทำงานด้วยความเร็วนาฬิกาของ CPU ที่สูงขึ้นคือการเรียกใช้ลูปที่ทำงานตลอดเวลาในเธรดเบื้องหลังเพื่อให้ภาระงานดูเหมือนมีความต้องการทรัพยากรมากขึ้น ซึ่งเป็นแนวทางปฏิบัติที่ไม่ดีเนื่องจากทำให้สิ้นเปลืองพลังงานและเพิ่มภาระความร้อนให้กับอุปกรณ์เมื่อแอปไม่ได้ใช้ทรัพยากรเพิ่มเติมจริงๆ API PerformanceHint ของ CPU ได้รับการออกแบบมาเพื่อแก้ปัญหานี้
การแจ้งให้ระบบทราบระยะเวลาการทำงานจริงและระยะเวลาการทำงานเป้าหมายจะช่วยให้ Android ได้ภาพรวมของความต้องการ CPU ของแอปและจัดสรรทรัพยากรได้อย่างมีประสิทธิภาพ ซึ่งจะนำไปสู่ประสิทธิภาพสูงสุดที่ระดับการใช้พลังงานอย่างมีประสิทธิภาพ
ประเภทคอร์
ประเภทคอร์ของ CPU ที่แอปทำงานอยู่เป็นอีกปัจจัยสำคัญด้านประสิทธิภาพ อุปกรณ์ Android มักจะเปลี่ยนคอร์ของ CPU ที่กำหนดให้กับเธรดแบบไดนามิกโดยอิงตามลักษณะการทำงานของภาระงานล่าสุด การกำหนดคอร์ของ CPU มีความซับซ้อนมากยิ่งขึ้นใน SoC ที่มีคอร์หลายประเภท ในอุปกรณ์บางรุ่น คอร์ที่ใหญ่กว่าจะใช้ได้เพียงระยะเวลาสั้นๆ เท่านั้น หากใช้เป็นเวลานาน อุปกรณ์จะเข้าสู่สถานะความร้อนที่ไม่ยั่งยืน
แอปไม่ควรพยายามตั้งค่าความสัมพันธ์ของคอร์ของ CPU ด้วยเหตุผลต่อไปนี้
- ประเภทคอร์ที่ดีที่สุดสำหรับภาระงานจะแตกต่างกันไปตามรุ่นของอุปกรณ์
- ความยั่งยืนในการเรียกใช้คอร์ที่ใหญ่กว่าจะแตกต่างกันไปตาม SoC และโซลูชันด้านความร้อนต่างๆ ที่รุ่นของอุปกรณ์แต่ละรุ่นมีให้
- ผลกระทบต่อสิ่งแวดล้อมต่อสถานะความร้อนอาจทำให้การเลือกคอร์มีความซับซ้อนมากยิ่งขึ้น เช่น สภาพอากาศหรือเคสโทรศัพท์อาจเปลี่ยนสถานะความร้อนของอุปกรณ์ได้
- การเลือกคอร์ไม่สามารถรองรับอุปกรณ์ใหม่ที่มีประสิทธิภาพและความสามารถด้านความร้อนเพิ่มเติมได้ ด้วยเหตุนี้ อุปกรณ์จึงมักจะละเลยความสัมพันธ์ของโปรเซสเซอร์ของแอป
ตัวอย่างลักษณะการทำงานของตัวกำหนดตารางเวลา Linux เริ่มต้น
API PerformanceHint จะสรุปเวลาในการตอบสนองของ DVFS และอื่นๆ
- หากงานต้องทำงานใน CPU ที่เฉพาะเจาะจง API PerformanceHint จะทราบวิธีตัดสินใจในนามของคุณ
- ดังนั้น คุณจึงไม่จำเป็นต้องใช้ความสัมพันธ์
- อุปกรณ์มาพร้อมกับโทโพโลยีที่หลากหลาย ลักษณะการทำงานด้านพลังงานและความร้อนมีความหลากหลายมากเกินกว่าที่จะเปิดเผยให้นักพัฒนาแอปทราบ
- คุณไม่สามารถตั้งสมมติฐานใดๆ เกี่ยวกับระบบพื้นฐานที่คุณกำลังใช้งานอยู่ได้
โซลูชัน
ADPF มีคลาส PerformanceHintManager
เพื่อให้แอปส่งคำแนะนำด้านประสิทธิภาพไปยัง Android สำหรับความเร็วนาฬิกาและ
ประเภทคอร์ของ CPU ได้ จากนั้นระบบปฏิบัติการจะตัดสินใจว่าจะใช้คำแนะนำอย่างไรให้ดีที่สุดโดยอิงตาม SoC และโซลูชันด้านความร้อนของอุปกรณ์ หากแอปใช้ API นี้ร่วมกับการตรวจสอบสถานะความร้อน แอปจะให้คำแนะนำที่อิงตามข้อมูลมากขึ้นแก่ระบบปฏิบัติการแทนที่จะใช้ลูปที่ทำงานตลอดเวลาและเทคนิคการเขียนโค้ดอื่นๆ ที่อาจทำให้เกิดการควบคุมปริมาณ
วิธีนำทฤษฎีไปใช้จริง
เริ่มต้น PerformanceHintManager และสร้าง HintSession
รับตัวจัดการโดยใช้บริการของระบบและสร้างเซสชันคำแนะนำสำหรับเธรดหรือกลุ่มเธรดที่ทำงานในภาระงานเดียวกัน
C++
int32_t tids[1];
tids[0] = gettid();
int64_t target_fps_nanos = getFpsNanos();
APerformanceHintManager* hint_manager = APerformanceHint_getManager();
APerformanceHintSession* hint_session =
APerformanceHint_createSession(hint_manager, tids, 1, target_fps_nanos);
Java
int[] tids = {
android.os.Process.myTid()
};
long targetFpsNanos = getFpsNanos();
PerformanceHintManager performanceHintManager =
(PerformanceHintManager) this.getSystemService(Context.PERFORMANCE_HINT_SERVICE);
PerformanceHintManager.Session hintSession =
performanceHintManager.createHintSession(tids, targetFpsNanos);
ตั้งค่าเธรดหากจำเป็น
เปิดตัว:
Android 11 (API ระดับ 34)
ใช้ setThreads
ฟังก์ชันของ PerformanceHintManager.Session เมื่อคุณมีเธรดอื่นๆ
ที่ต้องเพิ่มในภายหลัง ตัวอย่างเช่น หากคุณสร้างเธรดฟิสิกส์ในภายหลังและต้องการเพิ่มเธรดลงในเซสชัน คุณสามารถใช้ API setThreads นี้ได้
C++
auto tids = thread_ids.data();
std::size_t size = thread_ids_.size();
APerformanceHint_setThreads(hint_session, tids, size);
Java
int[] tids = new int[3];
// add all your thread IDs. Remember to use android.os.Process.myTid() as that
// is the linux native thread-id.
// Thread.currentThread().getId() will not work because it is jvm's thread-id.
hintSession.setThreads(tids);
หากกำหนดเป้าหมายเป็น API ระดับต่ำกว่า คุณจะต้องทำลายเซสชันและสร้างเซสชันใหม่ทุกครั้งที่ต้องการเปลี่ยนรหัสเธรด
รายงานระยะเวลาการทำงานจริง
ติดตามระยะเวลาจริงที่ต้องใช้ในการทำงานให้เสร็จสมบูรณ์เป็นหน่วยนาโนวินาทีและรายงานไปยังระบบเมื่อทำงานเสร็จสมบูรณ์ในทุกรอบ ตัวอย่างเช่น หากเป็นการติดตามสำหรับเธรดการแสดงผล ให้เรียกใช้ฟังก์ชันนี้ในทุกเฟรม
หากต้องการรับเวลาจริงอย่างน่าเชื่อถือ ให้ใช้โค้ดต่อไปนี้
C++
clock_gettime(CLOCK_MONOTONIC, &clock); // if you prefer "C" way from <time.h>
// or
std::chrono::high_resolution_clock::now(); // if you prefer "C++" way from <chrono>
Java
System.nanoTime();
ตัวอย่าง
C++
// All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)`
auto start_time = std::chrono::high_resolution_clock::now();
// do work
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
int64_t actual_duration = static_cast<int64_t>(duration);
APerformanceHint_reportActualWorkDuration(hint_session, actual_duration);
Java
long startTime = System.nanoTime();
// do work
long endTime = System.nanoTime();
long duration = endTime - startTime;
hintSession.reportActualWorkDuration(duration);
อัปเดตระยะเวลาการทำงานเป้าหมายเมื่อจำเป็น
เมื่อใดก็ตามที่ระยะเวลาการทำงานเป้าหมายเปลี่ยนแปลง เช่น หากผู้เล่นเลือก
FPS เป้าหมายอื่น ให้เรียกใช้updateTargetWorkDuration
เมธอดเพื่อแจ้งให้ระบบทราบเพื่อให้ระบบปฏิบัติการปรับทรัพยากรตามเป้าหมายใหม่ได้
คุณไม่จำเป็นต้องเรียกใช้เมธอดนี้ในทุกเฟรมและต้องเรียกใช้เฉพาะเมื่อระยะเวลาเป้าหมายเปลี่ยนแปลงเท่านั้น
C++
APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);
Java
hintSession.updateTargetWorkDuration(targetDuration);