yuniframe: スレッドのQoSインターフェース
いくつかのOSではスレッドのQoSを設定できるようになっている。例えば、WindowsにはMMCSSサービスがあり、オーディオスレッドは遅延が少くなるように調整される。
残念ながら各社に共通集合は無いのでどういう形で抽象化するかはちょっと考える必要がある。
Apple (Darwin)
iOSやmacOSはMachの影響を強く受けていてスレッドの代わりにタスクの語がよく使われる。
最悪の場合、一応AppleでもEコアPコアそれぞれにスレッドアフィニティを設定できるが、そのためにはsysctlbynameでトポロジを取る必要がある https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_system_capabilities 。
Workgroup
スレッドよりも抽象化されたものとしてWorkgroupを用意している。
- https://developer.apple.com/documentation/apple-silicon/tuning-your-code-s-performance-for-apple-silicon
- https://developer.apple.com/documentation/os/workgroups
AudioWorkIntervalCreate
から interval オブジェクトを受けて、それに合わせてスケジュールするように要請できる。
pthread QoS
Energy Efficiency Guide for Mac Apps にひととおり解説がある https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/PrioritizeWorkAtTheTaskLevel.html が、このドキュメントはメンテナンスされていない。
pthreadのAPIとしては pthread_attr_set_qos_class_np
が出ている。
QOS_CLASS_USER_INTERACTIVE
QOS_CLASS_USER_INITIATED
QOS_CLASS_UTILITY
QOS_CLASS_BACKGROUND
の4段階が定義されているが、pthreadのインターフェースでは USER_INTERACTIVE
は公開されていない(main thread用)。
Windows
Windows(NT)は長いことマルチスレッドOSとして機能してきたが、いわゆるリアルタイムOSとしての歴史はあまりない。
E-Core/P-Coreの運用をカーネルに任せる
2.6.5. ハイブリッド・オペレーティング・システム (OS) の検出
Windows* 11 では、インテル® スレッド・ディレクター (ITD) のハードウェア・ヒントを利用して、OS がスレッドを自動的にスケジューリングできます。スレッドのスケジュールを OS や ITD に任せるには、最初にアプリケーションが動作している Windows* のバージョンを検出する必要があります。
Windows11以降では、スレッドの命令ミックスに応じてE-Core/P-Coreの振り分けを行える。
MMCSS と QoS
MMCSS(Multimeda Class Scheduler Service) https://learn.microsoft.com/en-us/windows/win32/procthread/multimedia-class-scheduler-service は名前付きの優先度プロファイルをレジストリに定義させ、 AvSetMmThreadCharacteristics
等のAPIで個々のスレッドをそのプロファイルに設定できる。
MMCSSを使うと、カーネルが管理するスレッドにQoS https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service を設定できる。MMCSSはQoSを設定するための唯一のインターフェースではなく、 SetThreadInformation
でEcoQoS/HighQoS等の設定もできる。
Win32スレッドAPI
通常のユーザーのプロセスにもTime critical優先度を公開 https://learn.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities している。
Android
AndroidはDarwinやWindowsに見られるような明示的なインターフェースではなく、もう一段階抽象化したPerformance Hintインターフェースを提供している。
Performance Hint API
Androidでは、そもそもアフィニティの設定自体を推奨していない。
このため、デバイスは一般に、ゲームのプロセッサ アフィニティを無視します。
(この記述はあるものの、実際のところどうなのかは不明 -- Performance Hint APIはAndroid12以降の導入)
アフィニティの代わりに、Performance Hint APIを通じて "セッション" を取得し設定することを求めている。このインターフェースにはNDK(C版)も用意されている https://developer.android.com/ndk/reference/group/a-performance-hint 。
つまり:
-
APerformanceHint_createSession
に必要なフレームあたりのCPU処理時間(ターゲットフレームレートの逆数)を渡してセッションを作成する - (
APerformanceHint_setThreads
にスレッドIDのリストを渡して追加のスレッドをセッションに紐付ける) - 処理が完了したら
APerformanceHint_reportActualWorkDuration2
に実際の処理時間を渡す
Unity等のゲームエンジンはこれを行うプラグインを用意している。
WindowsやDarwinと違い、Androidはアプリケーションからのフィードバックを用意しているあたりが特徴的と言える。...そもそもフレームに関連付けられたスレッドはそれ以外の作業はしないことが多いと思うんだけど。。
アプリケーションからフィードバックする処理時間としては WorkDuration
オブジェクトを使う。これにはCPUおよびGPU処理時間、負荷の開始時点の CLOCK_MONOTONIC
時間を含められる。
いわゆるEcoQoSを宣言するためには APerformanceHint_setPreferPowerEfficiency
が使える。
その他のAPDF機能
APDF(Android Dynamic Performance Framework)としてサーマルやゲームモードをサポートしている。
Linuxのpthread
Linuxを含めpthreadプラットフォームでは SCHED_RR
や SCHED_FIFO
の固定優先度ポリシーが使えることが多い。
また、Linuxではカーネルのスケジューラーとして SCHED_DEADLINE
等の拡張が存在する。これらはschedparamで直接指定する必要がある。