Gerir energia e térmicas

Quando o HoloLens 2 está em execução em ambientes quentes ou com requisitos de desempenho pesados (utilização da CPU/GPU, utilização de periféricos, etc.), pode ficar suficientemente quente para tomar medidas automaticamente para evitar o sobreaquecimento. Estas ações incluem aspetos como:

  • Ajustar o desempenho do carregamento
  • Fornecer feedback dos utilizadores
  • Fechar aplicações

... e nos piores cenários:

  • Encerrar o HoloLens 2

Se a sua aplicação exigir um elevado desempenho periférico, considere utilizar o PowerThermalNotification Software Development Kit (SDK) para subscrever eventos de notificação e implementar as suas próprias ações personalizadas. Fazê-lo pode permitir que o dispositivo funcione mais tempo em situações em que, caso contrário, uma aplicação pode ser terminada pelo sistema.

Nota

O suporte para o SDK Microsoft.MixedReality.PowerThermalNotification está incluído na versão 22H1.

Este artigo descreve o SDK PowerThermalNotification e a utilização básica para começar.

Onde obtenho o SDK?

O SDK powerThermalNotification é transferível através da Ferramenta de Funcionalidades do Mixed Reality.

O SDK PowerThermalNotification suporta projeções de linguagem para C# e C++, permitindo aos programadores desenvolverem aplicações para plataformas Win32 ou UWP.

Descrição geral conceptual

O poder consumido pelo HoloLens 2 é dissipado no calor. Um dispositivo pc tradicional teria um ventilador para resolver este problema, mas um dispositivo wearable tem de ser leve. Por este motivo, a solução de arrefecimento é mais complexa. HoloLens 2 tem funcionalidades de segurança de hardware e software incorporadas para garantir que os auscultadores não ficam muito quentes para o utilizador, mas estas funcionalidades também têm de ser equilibradas com a experiência do utilizador. Por exemplo, se soubermos que parte do HoloLens 2 está a aquecer, podemos optar por limitar os periféricos responsáveis por este calor. Como último recurso, podemos fechar uma aplicação que se pensa ser responsável pela energia que levou a este calor.

HoloLens 2 lida com problemas de calor com sensores de temperatura. Uma arquitetura térmica associa grupos de sensores a diferentes periféricos no dispositivo. Os sensores estão agrupados porque pode ser impossível determinar que periférico numa área física é responsável pela tomada de energia que aquece o HoloLens 2.

O SDK PowerThermalNotification expõe as APIs necessárias para monitorizar estes grupos de sensores. Os eventos do SDK são acionados quando um periférico que está a ser utilizado pela aplicação mostra sinais de que pode ser necessária uma mitigação. Em seguida, a aplicação pode adaptar a experiência do cliente para reduzir o impacto térmico. Reduzir o impacto significa menos risco de ação do sistema, como a aplicação ou o encerramento do dispositivo.

Um exemplo simples seria uma aplicação que está a utilizar a CPU para processar uma grande quantidade de dados de vídeo. A aplicação pode subscrever uma notificação de desempenho para o componente da CPU. Quando a aplicação recebe uma notificação, pode reduzir a carga de trabalho da CPU. Se for recebido outro evento que indique que não é necessária qualquer mitigação adicional, a carga de trabalho da CPU pode ser restaurada.

Resposta da plataforma

A tabela seguinte é uma discriminação das ações do sistema por periférico. As ações descritas abaixo podem ser suprimidas com o SDK. Veja Suprimir Mitigações do Sistema Predefinidas

Periférico MinimumUserImpact MediumUserImpact MaximumUserImpact Último Recurso Encerramento de Software Segurança pós-falha
GPU Limitar o Intervalo VSYNC de Ajuste da Qualidade
do MRC
Apresentar Redução de FPS de Profundidade
Qualquer Periférico Aviso de
apresentação Fechar Aplicação
Parar Captura de MRC
Encerramento do SO Encerramento de Hardware

Nota

As ações nas colunas "Last Resort", "Software Shutdown" e "Failsafe" não podem ser suprimidas.

Sugestões para a resposta da aplicação

Segue-se uma discriminação das mitigações sugeridas que uma aplicação pode tomar com base nos periféricos que precisam de mitigação. Cabe ao programador da aplicação determinar qual destas ações pode ter um efeito mais significativo em cada periférico, uma vez que cada aplicação é diferente. Os programadores devem priorizar as ações que efetuam com base no impacto para o utilizador final.

Mitigações sugeridas por periférico

CPU

GPU

DRAM

Rede

Bateria

Apresentar

  • Aumentar o número de píxeis pretos na cena
  • Utilizar cores de baixa potência (por exemplo, verde)
  • Desativar o ecrã

Câmara de fotografia/vídeo

  • Descrição geral
  • Reduzir a resolução da câmara
  • Reduzir a taxa de fotogramas da câmara
  • Reduzir o pós-processamento de imagens da câmara na aplicação
  • Parar de utilizar a câmara de fotografia/vídeo

Casos de utilização da implementação

O SDK foi concebido para suportar dois casos de utilização padrão para obter informações:

  • Baseado em eventos
  • Baseado em consultas

A notificação baseada em eventos fornecerá o caminho de feedback mais rápido para a aplicação, caso precise de tomar medidas. No entanto, em alguns casos, pode ser mais conveniente para o programador utilizar consultas.

Nota

As informações de estado são atualizadas, no máximo, a cada poucos segundos para cada periférico, pelo que a consulta é mais rápida do que a que pode desperdiçar ciclos de CPU.

Utilização da API baseada em eventos

Registar-se para eventos

Para receber notificações, existem três requisitos:

Não receberá eventos se a sua aplicação não cumprir estes requisitos.

O primeiro item pode ser verificado com a função IsSupported . Se o sistema suportar notificações para, pelo menos, um dos periféricos na máscara, a função devolverá verdadeiro. Pode optar por não verificar o suporte com esta função, desde que a sua aplicação não dependa explicitamente dos eventos do SDK PowerThermalNotification.

Depois de cumprir os três requisitos acima, receberá notificações iniciais para todos os PeriféricosOfInterest suportados. Se posteriormente alterar PeripheralsOfInterest ou qualquer um dos processadores de eventos, receberá outro conjunto de notificações com base no estado atual.

Eis um fragmento de código para obter a instância de classe PowerThermalNotification e configurá-la para notificações para PowerThermalPeripheralFlags.Cpu e PowerThermalPeripheralFlags.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;
    }  
}

Processar eventos

Quando o evento PowerThermalMitigationLevelChanged é acionado , é fornecido com PowerThermalEventArgs. Estes devem ser utilizados para compreender o evento.

Da mesma forma, quando o evento PowerThermalThermalScoreChanged é acionado , vem com PowerThermalScoreArgs.

Quando um evento é recebido, o processador de eventos deve inspecionar os args. ImpactedPeripherals, que identifica que periféricos são afetados (pode haver mais do que um).

Para eventos PowerThermalMitigationLevelChanged , os args. MitigationLevel indica a gravidade de uma mitigação recomendada para os periféricos especificados. Se os args. MitigationLevel é PowerThermalMitigationLevel.NoUserImpact e, em seguida, quaisquer mitigações associadas aos periféricos especificados devem ser removidas.

Para eventos PowerThermalThermalScoreChanged , os args. ThermalScore indica uma classificação de 100 a 0 que reflete uma escala linear que se aproxima de um evento de encerramento da aplicação (zero). O intervalo de Pontuação Térmica começa fora do intervalo de relatórios de mitigação para permitir notificações anteriores à aplicação quando se aproxima da necessidade de mitigações.

Eis um processador de exemplo:

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

Nota

O parâmetro ImpactedPeripherals dos args identifica apenas os periféricos que foram afetados E parte de PeripheralsOfInterest. Outros periféricos afetados que não foram incluídos em PeripheralsOfInterest não serão identificados.

Nota

Os níveis de mitigação para periféricos têm histerese. Assim que o nível aumentar, não diminui até que seja lançado. A versão é um evento com args. MitigationLevel definido como PowerThermalMitigationLevel.NoUserImpact.

Reuni-lo (modelo baseado em eventos)

Eis um exemplo simples de um conjunto de scripts que podem ser utilizados no Unity para ativar esta funcionalidade. A classe NotificationComponent pode ser adicionada a qualquer objeto de jogo e esse objeto de jogo pode controlar o nível de mitigação do periférico atribuído. A classe NotificationManager lida com a gestão de subscrições do SDK através da instância única da classe PowerThermalNotification .

Eis a classe 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;
        }
    }
}

Eis a classe 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);
    }

}

Utilização da API baseada em consultas

Atualizar periféricos de interesse

Semelhante à utilização baseada em eventos, a definição da propriedade PeripheralsOfInterest é necessária para consultar um determinado periférico.

Aviso

Se tentar chamar GetLastPeripheralState para um determinado periférico sem definir primeiro esse sinalizador em PeripheralsOfInterest, será emitida uma exceção. Da mesma forma, se tentar utilizar GetLastPeripheralState com um valor inválido (múltiplos bits de sinalizador definidos ou um bit não suportado), será emitida uma exceção.

Chamar as APIs de consulta

Assim que PeripheralsOfInterest tiver o(s) bit(s) periférico(s) definido(s) que pretende consultar, pode ligar para GetLastPeripheralState.

O PowerThermalPeripheralState devolvido contém os valores mais recentes para Pontuação Térmica e Nível de Mitigação para o periférico especificado.

Nota

É possível que, em futuras plataformas, determinados periféricos não sejam suportados. Nestes casos, a API devolverá uma Classificação Térmica de 100 e um Nível de Mitigação de NoUserImpact. A aplicação pode verificar o campo IsSupportedPeripheral da estrutura para verificar se é ou não o caso de um determinado periférico.

Veja Handling Events (Processar Eventos ) para obter detalhes sobre o processamento da Pontuação Térmica e mitigationLevel devolvidas pelo PowerThermalPeripheralState.

Eis um pequeno fragmento que mostra a consulta:

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";
    }
}

Suprimir mitigações de sistema predefinidas

Se não quiser que o sistema tente mitigar determinados periféricos, pode suprimi-los. Para tal, basta atualizar a propriedade SuppressedPlatformMitigationForPeripherals ou chamar a função SuppressPlatformMitigation .

Eis um pequeno fragmento:

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

Nota

As APIs de supressão só funcionarão se o processo que utiliza a classe PowerThermalNotification estiver em primeiro plano. Os processos em segundo plano ainda podem subscrever eventos, mas podem não desativar HoloLens 2 ações.

Testar

Depois de integrar o SDK na sua aplicação, deverá testá-lo. Para HoloLens 2 sistemas operativos que suportam o SDK, estará disponível uma página de programador no Portal do Dispositivo. A partir desta página, pode controlar os níveis de mitigação e as classificações térmicas de cada periférico. Também pode monitorizar que periféricos têm mitigações que estão a ser suprimidas ativamente.

Também pode tirar partido das APIs REST para monitorizar/testar níveis de mitigação e pontuações térmicas de outro dispositivo. Pode encontrar mais informações na Referência da API do Portal do Dispositivo