CPU パフォーマンスのヒントを使用すると、ゲームは動的な CPU パフォーマンス動作に影響を与えて、ニーズに合った動作にすることができます。ほとんどのデバイスでは、Android は以前の需要に基づいて、ワークロードの CPU クロック速度とコアの種類を動的に調整します。ワークロードによる CPU リソースの使用量が多くなると、クロック速度が上がり、ワークロードは最終的により大きなコアに移行します。ワークロードによるリソースの使用量が少なくなると、Android はリソースの割り当てを減らします。ADPF を使用すると、アプリやゲームはパフォーマンスと期限に関する追加のシグナルを送信できます。これにより、システムはより積極的にランプアップし(パフォーマンスが向上)、ワークロードが完了するとクロックをすばやく下げることができます(消費電力を節約)。
クロック速度
Android デバイスが CPU クロック速度を動的に調整する場合は、周波数により、コードのパフォーマンスが変化することがあります。動的なクロック速度に対応するコード設計は、パフォーマンスの最大化、安全な温度状態の維持、効率的な電力の使用にとって重要です。アプリのコードで CPU 周波数を直接割り当てることはできません。そのため、アプリは CPU クロック速度を上げて実行しようとすると一般的に、バックグラウンド スレッドでビジーループを実行することになるため、ワークロードがより求められるようになります。これは、アプリが実際に追加リソースを使用していないときも無駄な電力がかかり、デバイスの熱負荷が高まるため、望ましくありません。CPU PerformanceHint API は、この問題に対処するように設計されています。実際の処理時間と目標処理時間をシステムに知らせることで、Android はアプリの CPU ニーズの概要を把握し、リソースを効率的に割り当てることができます。これにより、効率的な電力消費レベルで最適なパフォーマンスを実現できます。
コアの種類
ゲームを実行する CPU コアの種類も、もう 1 つの重要なパフォーマンス要因です。Android デバイスは、一般に、スレッドに割り当てられた CPU コアを最近のワークロード動作に基づいて動的に変更します。コアの種類が複数ある SoC では、CPU コアの割り当てはさらに複雑になります。これらのデバイスの一部では、大きなコアは短時間しか使用できず、温度的に持続できない状態になることはありません。
int[]tids=newint[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 レベルが低い場合は、スレッド ID を変更するたびにセッションを破棄して新しいセッションを作成する必要があります。
clock_gettime(CLOCK_MONOTONIC,&clock);// if you prefer "C" way from <time.h>// orstd::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, ...)`autostart_time=std::chrono::high_resolution_clock::now();// do workautoend_time=std::chrono::high_resolution_clock::now();autoduration=std::chrono::duration_cast<std::chrono::nanoseconds>(end_time-start_time).count();int64_tactual_duration=static_cast<int64_t>(duration);APerformanceHint_reportActualWorkDuration(hint_session,actual_duration);
Java
longstartTime=System.nanoTime();// do worklongendTime=System.nanoTime();longduration=endTime-startTime;hintSession.reportActualWorkDuration(duration);
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-07-26 UTC。"],[],[],null,["# Performance Hint API\n\n**Released**:\n\nAndroid 12 (API Level 31) - [Performance Hint API](/reference/android/os/PerformanceHintManager)\n\nAndroid 13 (API Level 33) - [Performance Hint Manager in the NDK API](/ndk/reference/group/a-performance-hint)\n\n(Preview) Android 15 (DP1) - [`reportActualWorkDuration()`](/reference/android/os/PerformanceHintManager.Session#reportActualWorkDuration(android.os.WorkDuration))\n\nWith CPU performance hints, a game can influence dynamic CPU performance\nbehavior to better match its needs. On most devices, Android dynamically adjusts\nthe CPU clock speed and core type for a workload based on the previous demands.\nIf a workload uses more CPU resources, the clock speed is increased and the\nworkload is eventually moved to a larger core. If the workload uses less\nresources, then Android lowers resource allocation. With ADPF, the application\nor game can send an additional signal about its performance and deadlines. This\nhelps the system ramp up more aggressively (improving performance) and lower the\nclocks quickly when the workload is complete (saving power usage).\n\nClock speed\n-----------\n\nWhen Android devices dynamically adjust their CPU clock speed, the frequency can\nchange the performance of your code. Designing code that addresses dynamic clock\nspeeds is important for maximizing performance, maintaining a safe thermal\nstate, and using power efficiently. You cannot directly assign CPU frequencies\nin your app code. As a result, a common way for apps to attempt to run at higher\nCPU clock speeds is to run a busy loop in a background thread so the workload\nseems more demanding. This is a bad practice as it wastes power and increases\nthe thermal load on the device when the app isn't actually using the additional\nresources. The CPU `PerformanceHint` API is designed to address this problem. By\nletting the system know the actual work duration and the target work duration,\nAndroid will be able to get an overview of the app's CPU needs and allocate\nresources efficiently. This will lead to optimum performance at efficient power\nconsumption level.\n\nCore types\n----------\n\nThe CPU core types that your game runs on are another important performance\nfactor. Android devices often change the CPU core assigned to a thread\ndynamically based on recent workload behavior. CPU core assignment is even more\ncomplex on SoCs with multiple core types. On some of these devices, the larger\ncores can only be used briefly without going into a thermally unsustainable\nstate.\n\nYour game shouldn't try to set the CPU core affinity for the following reasons:\n\n- The best core type for a workload varies by device model.\n- The sustainability of running larger cores varies by SoC and by the various thermal solutions provided by each device model.\n- The environmental impact on the thermal state can further complicate core choice. For example, the weather or a phone case can change the thermal state of a device.\n- Core selection can't accommodate new devices with additional performance and thermal capabilities. As a result, devices often ignore a game's processor affinity.\n\n### Example of default Linux scheduler behavior\n\n**Figure 1.** Governor can take \\~200ms to ramp up or down CPU frequency. ADPF works with the Dynamic Voltage and Frequency Scaling system (DVFS) to provide best performance per watt\n\n### PerformanceHint API abstracts more than DVFS latencies\n\n**Figure 2.** ADPF knows how to make the best decision on your behalf\n\n- If the tasks need to run on a specific CPU, PerformanceHint API knows how to make that decision on your behalf.\n- Therefore, you need not use affinity.\n- Devices come with various topologies; Power and thermal characteristics are too varied to be exposed to app developer.\n- You can't make any assumptions about the underlying system you're running on.\n\nSolution\n--------\n\nADPF provides the [`PerformanceHintManager`](/reference/android/os/PerformanceHintManager)\nclass so games can send performance hints to Android for CPU clock speed and\ncore type. The OS can then decide how to best use the hints based on the SoC and\nthermal solution of the device. If your app uses this API along with thermal\nstate monitoring, it can provide more informed hints to the OS instead of using\nbusy loops and other coding techniques that can cause throttling.\n\nThis is how a game uses performance hints:\n\n1. [Create hint sessions](/reference/android/os/PerformanceHintManager#createHintSession(int%5B%5D,%20long)) for key threads that behave similarly. For example:\n - Rendering thread and its dependencies get one session\n 1. In Cocos, the main engine thread and render thread gets [one\n session](https://github.com/cocos/cocos-engine/blob/v3.8.5-dianchu/native/cocos/base/threading/MessageQueue.cpp)\n 2. In Unity, integrate [Adaptive Performance Android Provider plugin](https://docs.unity3d.com/Packages/com.unity.adaptiveperformance.google.android@1.2/manual/index.html)\n 3. In Unreal, integrate Unreal Adaptive Performance plugin and use [Scalability options](https://docs.unrealengine.com/4.27/en-US/TestingAndOptimization/PerformanceAndProfiling/Scalability/ScalabilityReference/) to support multiple quality levels\n - IO threads get another session\n - Audio threads get a third session\n2. The game should do this early, at least 2ms and preferably more than 4ms before a session needs increased system resources.\n3. In each hint session, predict the duration needed for each session to run. The typical duration is equivalent to a frame interval, but the app can use a shorter interval if the workload does not vary significantly across frames.\n\nHere is how to put the theory into practice:\n\n### Initialize PerformanceHintManager and createHintSession\n\nGet the manager using system service and create a hint session for your thread\nor thread group working on the same workload. \n\n### C++\n\n int32_t tids[1];\n tids[0] = gettid();\n int64_t target_fps_nanos = getFpsNanos();\n APerformanceHintManager* hint_manager = APerformanceHint_getManager();\n APerformanceHintSession* hint_session =\n APerformanceHint_createSession(hint_manager, tids, 1, target_fps_nanos);\n\n### Java\n\n int[] tids = {\n android.os.Process.myTid()\n };\n long targetFpsNanos = getFpsNanos();\n PerformanceHintManager performanceHintManager =\n (PerformanceHintManager) this.getSystemService(Context.PERFORMANCE_HINT_SERVICE);\n PerformanceHintManager.Session hintSession =\n performanceHintManager.createHintSession(tids, targetFpsNanos);\n\n### Set threads if necessary\n\n**Released**:\n\nAndroid 11 (API Level 34)\n\nUse the [`setThreads`](/reference/android/os/PerformanceHintManager.Session#setThreads(int%5B%5D))\nfunction of the `PerformanceHintManager.Session` when you have other threads\nthat need to be added later. For example, if you create your physics thread\nlater and need to add it to the session, you can use this `setThreads` API. \n\n### C++\n\n auto tids = thread_ids.data();\n std::size_t size = thread_ids_.size();\n APerformanceHint_setThreads(hint_session, tids, size);\n\n### Java\n\n int[] tids = new int[3];\n\n // add all your thread IDs. Remember to use android.os.Process.myTid() as that\n // is the linux native thread-id.\n // Thread.currentThread().getId() will not work because it is jvm's thread-id.\n hintSession.setThreads(tids);\n\nIf you are targeting lower API Levels, you will need to destroy the session and\nre-create a new session every time you need to change the thread IDs.\n\n### Report Actual Work Duration\n\nTrack the actual duration needed to complete the work in nanoseconds and report\nit to the system upon completion of the work on every cycle. For example, if\nthis is for your rendering threads, call this on every frame.\n\nTo get the actual time reliably, use: \n\n### C++\n\n clock_gettime(CLOCK_MONOTONIC, &clock); // if you prefer \"C\" way from \u003ctime.h\u003e\n // or\n std::chrono::high_resolution_clock::now(); // if you prefer \"C++\" way from \u003cchrono\u003e\n\n### Java\n\n System.nanoTime();\n\nFor example: \n\n### C++\n\n // All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)`\n auto start_time = std::chrono::high_resolution_clock::now();\n\n // do work\n\n auto end_time = std::chrono::high_resolution_clock::now();\n auto duration = std::chrono::duration_cast\u003cstd::chrono::nanoseconds\u003e(end_time - start_time).count();\n int64_t actual_duration = static_cast\u003cint64_t\u003e(duration);\n\n APerformanceHint_reportActualWorkDuration(hint_session, actual_duration);\n\n### Java\n\n long startTime = System.nanoTime();\n\n // do work\n\n long endTime = System.nanoTime();\n long duration = endTime - startTime;\n\n hintSession.reportActualWorkDuration(duration);\n\n### Update Target Work Duration when necessary\n\nWhenever your target work duration changes, for example if the player chooses a\ndifferent target fps, call the [`updateTargetWorkDuration`](/reference/android/os/PerformanceHintManager.Session#updateTargetWorkDuration(long))\nmethod to let the system know so that the OS can adjust the resources according\nto the new target. You don't have to call it on every frame and only need to\ncall it when the target duration changes. \n\n### C++\n\n APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);\n\n### Java\n\n hintSession.updateTargetWorkDuration(targetDuration);"]]