電力と温度の管理

HoloLens 2 が暖かい環境で実行されている場合、または高パフォーマンス要件 (CPU/GPU 使用率、周辺機器の使用状況など) で実行されている場合は、オーバーヒートを防ぐために自動的にアクションが実行されるほど熱くなることがあります。 これらのアクションには、次のようなものが含まれます。

  • 充電パフォーマンスの調整
  • ユーザー フィードバックの提供
  • アプリケーションの終了

...最悪のシナリオでは、次のようになります。

  • HoloLens 2 のシャットダウン

アプリケーションで周辺機器の高いパフォーマンスが要求される場合は、PowerThermalNotification ソフトウェア開発キット (SDK) を使用して、通知イベントをサブスクライブし、独自のカスタム アクションを実装することを検討してください。 そうすることで、アプリケーションがシステムによって終了させられる可能性がある状況で、デバイスがより長く動作することができる場合があります。

Note

Microsoft.MixedReality.PowerThermalNotification SDK のサポートは、22H1 リリースに含まれています。

この記事では、PowerThermalNotification SDK の概要と、使用開始するための基本的な使用方法について説明します。

SDK の入手場所

PowerThermalNotification SDK は、Mixed Reality Feature Tool を使用してダウンロードできます。

PowerThermalNotification SDK では C# および C++ の言語プロジェクションがサポートされており、開発者は Win32 または UWP プラットフォーム用のアプリケーションを開発できます。

概念の概要

HoloLens 2 で消費される電力は、熱として放散されます。 従来の PC デバイスには、この問題に対処するためのファンが備わっていますが、ウェアラブル デバイスは軽量である必要があります。 このため、冷却対策がより複雑になります。 HoloLens 2 には、ヘッドセットがユーザーにとって熱くなりすぎないようにするハードウェアとソフトウェアの安全性機能が組み込まれていますが、これらの機能はユーザー エクスペリエンスとバランスを取る必要があります。 たとえば、HoloLens 2 のどの部分が熱くなっているかがわかっている場合は、この熱の原因である周辺機器を調整することができます。 最後の手段として、この熱を生み出した電力を使用していると考えられるアプリケーションを閉じる場合があります。

HoloLens 2 では、温度センサーを使用して、熱の問題に対処しています。 サーマル フレームワークでは、センサーのグループをデバイス上のさまざまな周辺機器と結び付けます。 センサーがグループ化されるのは、HoloLens 2 を発熱させる電力消費を行っている物理領域の周辺機器を判別することが不可能である可能性があるためです。

PowerThermalNotification SDK では、これらのセンサーのグループを監視するために必要な API を公開しています。 アプリケーションで使用されている周辺機器で軽減策が必要である兆候が示されている場合に、SDK のイベントが発生します。 その後、アプリケーションでカスタマー エクスペリエンスを調整して、熱の影響を軽減できます。 影響を減らすことにより、アプリケーションやデバイスのシャットダウンなどのシステム アクションのリスクが軽減されます。

簡単な例としては、CPU を使用して大量のビデオ データを処理するアプリケーションがあります。 アプリケーションでは、CPU コンポーネントのパフォーマンス通知をサブスクライブできます。 アプリケーションで通知を受信したときに、CPU のワークロードを減らすことができます。 それ以上の軽減策が必要ないことを示す別のイベントを受信したら、その CPU ワークロードを復元できます。

プラットフォームによる対応

次の表は、周辺機器別のシステム アクションの内容です。 以下で説明するアクションは、この SDK を使用して抑制できます。 「システムによる既定の軽減策の抑制」を参照してください

周辺装置 MinimumUserImpact MediumUserImpact MaximumUserImpact 最後の手段 ソフトウェアのシャットダウン フェールセーフ
GPU MRC 品質の調整
VSYNC 間隔の調整
表示 深度 FPS の削減
すべての周辺機器 警告の表示
アプリケーションの終了
MRC キャプチャの停止
OS のシャットダウン ハードウェアのシャットダウン

Note

"最後の手段"、"ソフトウェアのシャットダウン"、"フェールセーフ" 列のアクションは抑制できません。

アプリケーションによる対応に関する提案

軽減策が必要な周辺機器に基づいてアプリケーションが実行できる推奨される軽減策の具体的な内容を次に示します。 すべてのアプリケーションは異なるものであるため、これらのアクションのどれが各周辺機器により大きな影響を与える可能性があるかは、アプリケーション開発者が判断する必要があります。 開発者は、エンド ユーザーへの影響に基づいて、実行するアクションに優先順位を付ける必要があります。

周辺機器別の推奨される軽減策

CPU

GPU

DRAM

ネットワーク

バッテリ

表示

写真/ビデオ カメラ

  • 概要
  • カメラの解像度を下げます
  • カメラ のフレーム レートを下げます
  • カメラ画像のアプリの後処理を減らします
  • 写真/ビデオ カメラの使用を停止します

実装のユースケース

この SDK は、情報取得のための 2 つの標準的なユースケースをサポートするように設計されています。

  • イベントベース
  • ポーリングベース

イベントベースの通知では、アクションを実行する必要がある場合に、アプリケーションへの最も迅速なフィードバック パスが提供されます。 ただし、ポーリングを使用する方が開発者にとって便利な場合もあります。

Note

各周辺機器での状態情報の更新は、最大で数秒ごとであるため、それより速くポーリングすると、CPU サイクルが無駄になる可能性があります。

イベントベースの API の使用方法

イベントの登録

通知を取得するためには、次の 3 つの要件があります。

アプリケーションでこれらの要件が満たされていない場合、イベントは通知されません。

最初の項目は、IsSupported 関数を使用して確認できます。 マスク内の少なくとも 1 つの周辺機器の通知がシステムでサポートされている場合、この関数では true を返します。 アプリケーションが PowerThermalNotification SDK イベントに明示的に依存している場合を除き、この関数を使用してサポートを確認しないことを選択できます。

上記の 3 つの要件を満たしていると、サポートされているすべての PeripheralsOfInterest の初期通知を受け取ります。 後で PeripheralsOfInterest またはいずれかのイベント ハンドラーを変更すると、現在の状態に基づいて別の一連の通知を受け取ります。

PowerThermalNotification クラスのインスタンスを取得し、それを PowerThermalPeripheralFlags.CpuPowerThermalPeripheralFlags.PhotoVideoCamera の両方の通知用に構成するためのコード スニペットを次に示します。

using Microsoft.MixedReality.PowerThermalNotification;

private void NotificationHandler(object sender, PowerThermalEventArgs args)
{
    //  Notification handling can be done here using information contained in args
}

private void InitializeThermalNotifications()
{
    PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();
    
    PowerThermalPeripheralFlags requestedFlags = PowerThermalPeripheralFlags.Cpu | PowerThermalPeripheralFlags.PhotoVideoCamera;
     if (PowerThermalNotification.IsSupported(requestedFlags))
    {
        //At least one of these peripherals is supported by the system
        p.PeripheralsOfInterest = requestedFlags;
        p.PowerThermalMitigationLevelChanged += NotificationHandler;
    }  
}

イベントの処理

PowerThermalMitigationLevelChanged イベントが発生すると、PowerThermalEventArgs も一緒に送られてきます。 これらは、イベントを理解するために使用する必要があります。

同様に、PowerThermalThermalScoreChanged イベントが発生すると、PowerThermalScoreArgs も一緒に送られてきます。

イベントを受信したら、イベント ハンドラーでは影響を受けた周辺機器 (複数ある可能性があります) を識別する args.ImpactedPeripherals を検査する必要があります。

PowerThermalMitigationLevelChanged イベントの場合、指定された周辺機器に対してどの程度の軽減策が推奨されるかが args.MitigationLevel に示されます。 args.MitigationLevelPowerThermalMitigationLevel.NoUserImpact の場合、指定した周辺機器に関連付けられているすべての軽減策を削除する必要があります。

PowerThermalThermalScoreChanged イベントの場合は、アプリケーション シャットダウン イベント (ゼロ) に近づく線形スケールが反映された 100 から 0 のスコアが args.ThermalScore に示されます。 温度スコアの範囲は、軽減策の必要性に近づいたときにアプリケーションに早期に通知できるように、軽減策のレポート範囲外で始まります。

ハンドラーの例を次に示します。

bool doCpuThrottle = false;

private void NotificationHandler(object sender, PowerThermalEventArgs args)
{
    if (args.ImpactedPeripherals.HasFlag(PowerThermalPeripheralFlags.Cpu))
    {
        if(args.MitigationLevel = PowerThermalMitigationLevel.NoUserImpact)
        {
            doCpuThrottle = false;
        }
        else if(args.MitigationLevel >= PowerThermalMitigationLevel.MinimumUserImpact)
        {
            // Note that this only kicks in at MinimumUserImpact and does not get released until NoUserImpact
            doCpuThrottle = true;
        }
    }

    if (args.ImpactedPeripherals.HasFlag(PowerThermalPeripheralFlags.PhotoVideoCamera))
    {
        SetMitigationStatus(PhotoVideoCameraStatusText, PhotoVideoRectangle, args.MitigationLevel);
    }
}

Note

args の ImpactedPeripherals パラメーターでは、影響を受けていて、かつ PeripheralsOfInterest の一部である周辺機器だけが識別されます。 PeripheralsOfInterest に含まれていなかったその他の影響を受けた周辺機器は識別されません。

Note

周辺機器の軽減策のレベルにはヒステリシスがあります。 レベルが上がると、リリースされるまで減少しません。 リリースは、args.MitigationLevel を PowerThermalMitigationLevel.NoUserImpact に設定したイベントです。

まとめ (イベントベース モデル)

この機能を有効にするために Unity で使用できる一連のスクリプトの簡単な例を次に示します。 NotificationComponent クラスは任意のゲーム オブジェクトに追加でき、そのゲーム オブジェクトでは割り当てられている周辺機器の軽減策のレベルを追跡できます。 NotificationManager クラスでは、PowerThermalNotification クラスの単一のインスタンスを通じてサブスクリプションを管理する SDK を処理します。

NotificationManager クラスを次に示します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

using Microsoft.MixedReality.PowerThermalNotification;

public class NotificationManager
{
    private static readonly object listLock = new object();
    private static List<NotificationComponent> components = new List<NotificationComponent>();
    private static PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();
    private static bool FirstTime = true;

    private static void NotificationHandler(object sender, PowerThermalEventArgs args)
    {
        lock (listLock)
        {
            foreach (NotificationComponent c in components)
            {
                UnityEngine.WSA.Application.InvokeOnAppThread(() =>
                {
                    c.SetMitigationLevel(args.ImpactedPeripherals, args.MitigationLevel);
                }, false);
            }
        } 
    }

    public static void ChangeSuppression(PowerThermalPeripheralFlags peripherals, bool suppress)
    {
        p.SuppressPlatformMitigation(peripherals, suppress);
    }

    public static void AddNotification(NotificationComponent component, PowerThermalPeripheralFlags peripheralsOfInterest)
    {
        if (FirstTime)
        {
            p.PowerThermalMitigationLevelChanged += NotificationHandler;
            FirstTime = false;
        }
        
        if (PowerThermalNotification.IsSupported(peripheralsOfInterest))
        {
            lock (listLock)
            {
                component.SetMitigationLevel(peripheralsOfInterest, (PowerThermalMitigationLevel)0);
                components.Add(component);
            }
            p.PeripheralsOfInterest |= peripheralsOfInterest;
        }
    }
}

NotificationComponent クラスを次に示します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Microsoft.MixedReality.PowerThermalNotification;

public class NotificationComponent : MonoBehaviour
{
    //Note that this could be multiple peripherals, just need to make sure to look at impactedPeripherals in the handler
    public PowerThermalPeripheralFlags monitoredPeripheral = (PowerThermalPeripheralFlags) 0;
    public bool isSuppressed = false;

    public void SetMitigationLevel(PowerThermalMitigationLevel level)
    {
        Color newColor = Color.white;

        if (level == PowerThermalMitigationLevel.NoUserImpact)
        {
            newColor = Color.green;
        }
        else if (level == PowerThermalMitigationLevel.MinimumUserImpact)
        {
            newColor = Color.yellow;
        }
        else if (level == PowerThermalMitigationLevel.MediumUserImpact)
        {
            newColor = new Color32(255, 127, 37, 255);//Orange
        }
        else
        {
            newColor = Color.red;
        }

        MaterialPropertyBlock props = new MaterialPropertyBlock();
        props.SetColor("_Color", newColor);
        GetComponent<Renderer>().SetPropertyBlock(props);
    }

    public void SetMitigationLevel(PowerThermalPeripheralFlags impactedPeripherals, PowerThermalMitigationLevel level)
    {
        if (impactedPeripherals.HasFlag(monitoredPeripheral))
        {
            SetMitigationLevel(level);
        }
    }

    void Start()
    {
        NotificationManager.AddNotification(this, monitoredPeripheral);
        NotificationManager.ChangeSuppression(monitoredPeripheral, isSuppressed);
    }

}

ポーリングベースの API の使用方法

関心のある周辺機器の更新

イベントベースの使用方法と同様に、特定の周辺機器をポーリングするには、PeripheralsOfInterest プロパティを設定する必要があります。

警告

特定の周辺機器に対して、最初に PeripheralsOfInterest にそのフラグを設定せずに GetLastPeripheralState を呼び出そうとすると、例外がスローされます。 同様に、無効な値 (複数のフラグ ビットの設定またはサポートされていないビット) を設定して GetLastPeripheralState を使用しようとすると、例外がスローされます。

ポーリング API の呼び出し

ポーリングする周辺機器のビットを PeripheralsOfInterest に設定したら、GetLastPeripheralState を呼び出すことができます。

返される PowerThermalPeripheralState には、指定された周辺機器の温度スコアと軽減策レベルの最新の値が含まれています。

Note

今後のプラットフォームでは、特定の周辺機器がサポートされない可能性があります。 このような場合、API では温度スコアに対して 100、軽減レベルに対して NoUserImpact を返します。 このアプリケーションでは、構造体の Issupportedperipheral フィールドをチェックして、これが特定の周辺機器の場合であるかどうかを確認できます。

PowerThermalPeripheralState によって返される ThermalScoreMitigationLevel の処理の詳細については、「イベントの処理」を参照してください。

ポーリングを示す小さいスニペットを次に示します。

private async void timerCallback(object state)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();

        PowerThermalPeripheralState CpuState = p.GetLatestPeripheralState(PowerThermalPeripheralFlags.Cpu);
        PowerThermalPeripheralState PhotoVideoCameraState = p.GetLatestPeripheralState(PowerThermalPeripheralFlags.PhotoVideoCamera);
        
        CpuScoreText.Text = CpuState.ThermalScore.ToString();
        PhotoVideoScoreText.Text = PhotoVideoCameraState.ThermalScore.ToString();
    });
}

private void InitializeThermalNotifications()
{
    PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();

    PowerThermalPeripheralFlags requestedFlags = PowerThermalPeripheralFlags.Cpu | PowerThermalPeripheralFlags.PhotoVideoCamera;
    p.SuppressedPlatformMitigationForPeripherals = requestedFlags;//Suppress any platform mitigation on CPU or PhotoVideoCamera

    if (PowerThermalNotification.IsSupported(requestedFlags))
    {
        p.PeripheralsOfInterest = requestedFlags;

        Timer timer = new Timer(timerCallback, null, 0, 3000);
    }
    else
    {
        TitleLabel.Text = "Not Supported";
    }
}

システムによる既定の軽減策の抑制

システムによって特定の周辺機器に対して軽減策が試みられることを望まない場合は、それを抑制することができます。 これを行うには、SuppressedPlatformMitigationForPeripherals プロパティを更新するか、SuppressPlatformMitigation 関数を呼び出します。

小さいスニペットを次に示します。

PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();
PowerThermalPeripheralFlags requestedFlags = PowerThermalPeripheralFlags.Cpu | PowerThermalPeripheralFlags.PhotoVideoCamera;

//You can do this to set the property explicitly
p.SuppressedPlatformMitigationForPeripherals = requestedFlags;

//Or you can do this to manipulate the property mask. 
//This specific example clears the CPU, leaving the PhotoVideoCamera suppressed
p.SuppressPlatformMitigation(PowerThermalPeripheralFlags.Cpu, false);

Note

抑制 API は、PowerThermalNotification クラスを使用するプロセスがフォアグラウンドにある場合にのみ機能します。 バックグラウンド プロセスでは引き続きイベントをサブスクライブできますが、HoloLens 2 のアクションを無効にすることはできません。

テスト

この SDK をアプリケーションに統合したら、テストします。 この SDK がサポートされる HoloLens 2 オペレーティング システムの場合は、デバイス ポータルで開発者ページを利用できます。 このページでは、各周辺機器の軽減策レベルと温度スコアを制御できます。 また、軽減策がアクティブに抑制されている周辺機器を監視することもできます。

また、REST API を利用して、別のデバイスから軽減レベルと温度スコアを監視/テストすることもできます。 詳細については、「Device Portal API リファレンス」を参照してください