Partilhar via


Aquisição de carimbos temporais de alta resolução

O Windows disponibiliza APIs que pode usar para adquirir carimbos de tempo de alta resolução ou medir intervalos de tempo. A API principal para código nativo é o QueryPerformanceCounter (QPC). Para controladores de dispositivos, a API em modo kernel é KeQueryPerformanceCounter. Para código gerido, a classe System.Diagnostics.Stopwatch utiliza QPC como base temporal precisa.

O QPC é independente e não está sincronizado com qualquer referência temporal externa. Para recuperar timestamps que podem ser sincronizados com uma referência temporal externa, como o Tempo Universal Coordenado (UTC) para utilização em medições de alta resolução da hora do dia, use GetSystemTimePreciseAsFileTime.

Carimbos temporais e medições de intervalos de tempo são parte integrante das medições de desempenho em computadores e redes. Estas operações de medição de desempenho incluem o cálculo do tempo de resposta, taxa de transferência e latência, bem como o perfil da execução do código. Cada uma destas operações envolve uma medição das atividades que ocorrem durante um intervalo de tempo definido por um evento de início e um evento final que pode ser independente de qualquer referência externa de hora do dia.

O QPC é tipicamente o melhor método para marcar eventos temporais e medir pequenos intervalos de tempo que ocorrem no mesmo sistema ou máquina virtual. Considere usar o GetSystemTimePreciseAsFileTime quando quiser carimbar eventos em múltiplas máquinas, desde que cada máquina participe num esquema de sincronização temporal, como o Network Time Protocol (NTP). O QPC ajuda-o a evitar dificuldades que podem ser encontradas com outras abordagens de medição do tempo, como ler diretamente o contador de carimbo temporal (TSC) do processador.

Suporte QPC em versões para Windows

O QPC foi introduzido no Windows 2000 e Windows XP e evoluiu para tirar partido das melhorias na plataforma de hardware e nos processadores. Aqui descrevemos as características do QPC em diferentes versões do Windows para o ajudar a manter o software que corre nessas versões do Windows.

Windows XP e Windows 2000

O QPC está disponível no Windows XP e Windows 2000 e funciona bem na maioria dos sistemas. No entanto, a BIOS de alguns sistemas de hardware não indicava corretamente as características do CPU (um TSC não invariante), e alguns sistemas multi-core ou multiprocessador usavam processadores com TSCs que não podiam ser sincronizados entre núcleos. Sistemas com firmware defeituoso que correm estas versões do Windows podem não fornecer a mesma leitura QPC em núcleos diferentes se usarem o TSC como base para o QPC.

Windows Vista e Windows Server 2008

Todos os computadores que vinham com Windows Vista e Windows Server 2008 usavam um contador de plataforma (High Precision Event Timer (HPET)) ou o ACPI Power Management Timer (PM timer) como base para o QPC. Estes temporizadores de plataforma têm uma latência de acesso superior à do TSC e são partilhados entre múltiplos processadores. Isto limita a escalabilidade do QPC se for chamado simultaneamente por múltiplos processadores.

Windows 7 e Windows Server 2008 R2

A maioria dos computadores Windows 7 e Windows Server 2008 R2 tem processadores com TSCs de taxa constante e utilizam estes contadores como base para o QPC. Os TSCs são contadores de hardware de alta resolução por processador que podem ser acedidos com latência e sobrecarga muito baixas (na ordem de dezenas ou centenas de ciclos de máquina, dependendo do tipo de processador). O Windows 7 e o Windows Server 2008 R2 utilizam TSCs como base do QPC em sistemas de domínio de clock único onde o sistema operativo (ou o hipervisor) consegue sincronizar rigorosamente os TSCs individuais em todos os processadores durante a inicialização de sistema. Nestes sistemas, o custo de leitura do contador de desempenho é significativamente inferior em comparação com sistemas que utilizam um contador de plataforma. Além disso, não há sobrecarga adicional para chamadas concorrentes e as consultas em modo utilizador frequentemente contornam chamadas de sistema, o que reduz ainda mais a sobrecarga. Em sistemas onde o TSC não é adequado para controlo do tempo, o Windows seleciona automaticamente um contador de plataforma (seja o temporizador HPET ou o temporizador PM ACPI) como base para o QPC.

Windows 8, Windows 8.1, Windows Server 2012 e Windows Server 2012 R2

O Windows 8, Windows 8.1, Windows Server 2012 e Windows Server 2012 R2 utilizam TSCs como base para o contador de desempenho. O algoritmo de sincronização TSC foi significativamente melhorado para acomodar sistemas grandes com muitos processadores. Além disso, foi adicionado suporte para a nova API de hora precisa do dia, que permite adquirir carimbos de tempo precisos do relógio de parede a partir do sistema operativo. Para mais informações, consulte GetSystemTimePreciseAsFileTime. Em dispositivos Windows RT e Windows 11 e Windows 10 que utilizam processadores Arm, o contador de desempenho baseia-se num contador de plataforma proprietário ou no contador de sistema fornecido pelo Arm Generic Timer, caso a plataforma esteja assim equipada.

Orientações para aquisição de carimbos temporais

A Windows tem investido e continuará a investir em fornecer um contador de desempenho fiável e eficiente. Quando precisar de carimbos temporais com resolução de 1 microssegundo ou superior e não precisar que os carimbos de tempo estejam sincronizados com uma referência temporal externa, escolha QueryPerformanceCounter, KeQueryPerformanceCounter ou KeQueryInterruptTimePrecise. Quando precisar de carimbos temporais sincronizados com UTC com resolução de 1 microssegundo ou superior, escolha GetSystemTimePreciseAsFileTime ou KeQuerySystemTimePrecise.

Num número relativamente pequeno de plataformas que não podem usar o registo TSC como base QPC , por exemplo, por razões explicadas em Hardware timer info, adquirir carimbos temporais de alta resolução pode ser significativamente mais caro do que adquirir carimbos temporais com resolução inferior. Se uma resolução de 10 a 16 milissegundos for suficiente, pode usar GetTickCount64, QueryInterruptTime, QueryUnbiasedInterruptTime, KeQueryInterruptTime ou KeQueryUnbiasedInterruptTime para obter carimbos temporais que não estejam sincronizados com uma referência temporal externa. Para marcações de tempo sincronizadas com UTC, use GetSystemTimeAsFileTime ou KeQuerySystemTime. Se for necessária maior resolução, pode usar QueryInterruptTimePrecise, QueryUnbiasedInterruptTimePrecise ou KeQueryInterruptTimePrecise para obter carimbos temporais em vez disso.

Em geral, os resultados dos contadores de desempenho são consistentes em todos os processadores em sistemas multi-core e multiprocessador, mesmo quando medidos em diferentes threads ou processos. Aqui estão algumas exceções a esta regra:

  • Sistemas operativos pré-Windows Vista que funcionam em certos processadores podiam violar esta consistência por uma destas razões:

    • Os processadores de hardware têm um TSC não invariante e o BIOS não indica corretamente esta condição.
    • O algoritmo de sincronização TSC utilizado não era adequado para sistemas com grandes números de processadores.
  • Ao comparar resultados de contadores de desempenho adquiridos de diferentes threads, considere valores que diferem por ± 1 tick como tendo uma disposição ambígua. Se os carimbos temporais forem retirados do mesmo thread, esta incerteza de ± 1 tick não se aplica. Neste contexto, o termo tick refere-se a um período de tempo igual a 1 ÷ (a frequência do contador de desempenho obtida do QueryPerformanceFrequency).

Quando se usa o contador de desempenho em grandes sistemas servidores com múltiplos domínios de relógio que não estão sincronizados no hardware, o Windows determina que o TSC não pode ser usado para fins de temporização e seleciona um contador de plataforma como base para o QPC. Embora este cenário ainda forneça carimbos temporais fiáveis, a latência de acesso e a escalabilidade são negativamente afetadas. Portanto, como referido anteriormente na orientação de utilização anterior, use apenas as APIs que forneçam 1 microssegundo ou melhor resolução quando tal resolução for necessária. O TSC é usado como base para QPC em sistemas multi-domínio de relógio que incluem sincronização por hardware de todos os domínios de relógio do processador, pois isto faz com que funcionem efetivamente como um sistema de domínio de relógio único.

A frequência do contador de desempenho é fixa no arranque do sistema e é consistente em todos os processadores, por isso só precisa de consultar a frequência do QueryPerformanceFrequency à medida que a aplicação se inicializa e depois armazenar o resultado em cache.

Virtualization

Espera-se que o contador de desempenho funcione de forma confiável em todas as máquinas virtuais convidadas que executam com hipervisores corretamente implementados. No entanto, hipervisores que cumprem a interface do hipervisor versão 1.0 e que exploram a indicação explícita do tempo de referência podem oferecer uma sobrecarga substancialmente inferior. Para mais informações sobre interfaces e esclarecimentos de hipervisores, consulte Especificações do Hipervisor.

Utilização direta do TSC

Desaconselhamos fortemente o uso da instrução RDTSC ou do processador RDTSCP para consultar diretamente o TSC, pois não obterá resultados fiáveis em algumas versões do Windows, em migrações ao vivo de máquinas virtuais e em sistemas de hardware sem TSCs invariantes ou fortemente sincronizados. Em vez disso, encorajamo-lo a usar o QPC para tirar partido da abstração, consistência e portabilidade que oferece.

Exemplos para obter carimbos de data e hora

Os vários exemplos de código nestas secções mostram como adquirir carimbos de data.

Utilização do QPC em código nativo

Este exemplo mostra como usar QPC em código nativo C e C++.

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

QueryPerformanceFrequency(&Frequency); 
QueryPerformanceCounter(&StartingTime);

// Activity to be timed

QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;


//
// We now have the elapsed number of ticks, along with the
// number of ticks-per-second. We use these values
// to convert to the number of elapsed microseconds.
// To guard against loss-of-precision, we convert
// to microseconds *before* dividing by ticks-per-second.
//

ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

Aquisição de marcas temporais de alta resolução em código gerido

Este exemplo mostra como usar a classe de código gerido System.Diagnostics.Stopwatch.

using System.Diagnostics;

long StartingTime = Stopwatch.GetTimestamp();

// Activity to be timed

long EndingTime  = Stopwatch.GetTimestamp();
long ElapsedTime = EndingTime - StartingTime;

double ElapsedSeconds = ElapsedTime * (1.0 / Stopwatch.Frequency);

A classe System.Diagnostics.Stopwatch também fornece vários métodos convenientes para realizar medições em intervalos de tempo.

Utilizar o QPC em modo kernel

O kernel do Windows fornece acesso em modo kernel ao contador de desempenho através do KeQueryPerformanceCounter , a partir do qual se pode obter tanto o contador de desempenho como a frequência de desempenho. KeQueryPerformanceCounter está disponível apenas em modo kernel e é fornecido para escritores de drivers de dispositivos e outros componentes em modo kernel.

Este exemplo mostra como usar o KeQueryPerformanceCounter em modo kernel C e C++.

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

StartingTime = KeQueryPerformanceCounter(&Frequency);

// Activity to be timed

EndingTime = KeQueryPerformanceCounter(NULL);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

Perguntas Frequentes Gerais sobre QPC e TSC

Aqui estão respostas às perguntas frequentes sobre QPC e TSCs em geral.

O QueryPerformanceCounter() é o mesmo que a função Win32 GetTickCount() ou GetTickCount64()?

Não. GetTickCount e GetTickCount64 não estão relacionados com QPC. GetTickCount e GetTickCount64 devolvem o número de milissegundos desde que o sistema foi iniciado.

Devo usar o QPC ou ligar diretamente para as instruções do RDTSC/RDTSCP?

Para evitar incorreções e problemas de portabilidade, encorajamos fortemente que utilize o QPC em vez de usar o registo TSC ou as instruções do processador RDTSC ou RDTSCP .

Qual é a relação da QPC com uma época temporal externa? Pode ser sincronizado com uma época externa como o UTC?

O QPC baseia-se num contador de hardware que não pode ser sincronizado com uma referência temporal externa, como o UTC. Para carimbos de hora do dia precisos que podem ser sincronizados com uma referência UTC externa, use GetSystemTimePreciseAsFileTime.

O QPC é afetado pelo horário de verão, segundos intercalares, fusos horários ou alterações no horário do sistema feitas pelo administrador?

Não. O QPC é completamente independente da hora do sistema e do UTC.

A precisão do QPC é afetada pelas alterações de frequência do processador causadas pela gestão de energia ou pela tecnologia Turbo Boost?

Não. Se o processador tiver um TSC invariante, o QPC não é afetado por este tipo de alterações. Se o processador não tiver um TSC invariante, o QPC reverterá para um temporizador de hardware de plataforma que não será afetado por alterações de frequência do processador ou tecnologia Turbo Boost.

O QPC funciona de forma fiável em sistemas multiprocessador, multi-core e sistemas com hyperthreading?

Yes.

Como posso determinar e validar se o QPC funciona na minha máquina?

Não precisa de fazer essas verificações.

Que processadores têm TSCs não invariantes? Como posso verificar se o meu sistema tem um TSC não invariante?

Não precisas de fazer esta verificação tu próprio. Os sistemas operativos Windows realizam várias verificações na inicialização do sistema para determinar se o TSC é adequado como base para o QPC. No entanto, para referência, pode determinar se o seu processador tem um TSC invariante usando um destes:

  • a utilidade Coreinfo.exe do Windows Sysinternals
  • verificando os valores devolvidos pela instrução CPUID relativas às características do TSC
  • Documentação do fabricante do processador

A seguir é mostrada a informação TSC-INVARIANT fornecida pela utilidade Windows Sysinternals Coreinfo.exe (www.sysinternals.com). Um asterisco significa "Verdadeiro".

> Coreinfo.exe 

Coreinfo v3.2 - Dump information on system CPU and memory topology
Copyright (C) 2008-2012 Mark Russinovich
Sysinternals - www.sysinternals.com

 <unrelated text removed>

RDTSCP          * Supports RDTSCP instruction
TSC             * Supports RDTSC instruction
TSC-DEADLINE    - Local APIC supports one-shot deadline timer
TSC-INVARIANT   * TSC runs at constant rate

O QPC funciona de forma fiável em plataformas de hardware Windows RT?

Yes.

Com que frequência o QPC é reiniciado?

Não menos de 100 anos desde o arranque mais recente do sistema, e potencialmente mais tempo dependendo do temporizador de hardware subjacente utilizado. Na maioria das aplicações, o rollover não é uma preocupação.

Qual é o custo computacional de chamar QPC?

O custo de chamada computacional do QPC é determinado principalmente pela plataforma de hardware subjacente. Se o registo TSC for usado como base para QPC, o custo computacional é determinado principalmente pelo tempo que o processador demora a processar uma instrução RDTSC . Este tempo varia desde dezenas de ciclos de CPU até várias centenas, dependendo do processador utilizado. Se o TSC não puder ser utilizado, o sistema selecionará uma base temporal de hardware diferente. Como estas bases de tempo estão localizadas na motherboard (por exemplo, na PCI South Bridge ou PCH), o custo computacional por chamada é superior ao do TSC, e frequentemente ronda entre 0,8 e 1,0 microssegundos, dependendo da velocidade do processador e outros fatores de hardware. Este custo é dominado pelo tempo necessário para aceder ao dispositivo de hardware na motherboard.

O QPC requer uma transição do kernel (chamada de sistema)?

Não é necessária uma transição de kernel se o sistema puder usar o registo TSC como base para o QPC. Se o sistema tiver de usar uma base de tempo diferente, como o temporizador HPET ou PM, é necessária uma chamada ao sistema.

O contador de desempenho é monotónico (não diminui)?

Yes. O QPC não recua.

O contador de desempenho pode ser usado para ordenar eventos a tempo?

Yes. No entanto, ao comparar resultados de contadores de desempenho adquiridos de diferentes threads, valores que diferem por ± 1 tick têm uma ordem ambígua, como se tivessem um carimbo temporal idêntico.

Quão preciso é o contador de desempenho?

A resposta depende de vários fatores. Para mais informações, veja Características do relógio de hardware de baixo nível.

FAQ sobre programação com QPC e TSC

Aqui estão respostas às perguntas frequentes sobre programação com QPC e TSCs.

Preciso de converter a saída do QPC para milissegundos. Como posso evitar perder precisão ao converter para duplo ou flutuante?

Há vários aspetos a ter em conta ao realizar cálculos em contadores de desempenho inteiros:

  • A divisão inteira perde o resto. Isto pode causar perda de precisão em alguns casos.
  • A conversão entre inteiros de 64 bits e ponto flutuante (duplo) pode causar perda de precisão porque a mantissa em ponto flutuante não consegue representar todos os valores integrais possíveis.
  • A multiplicação de inteiros de 64 bits pode resultar em excesso de inteiros.

Como princípio geral, atrase estes cálculos e conversões o máximo possível para evitar agravar os erros introduzidos.

Como posso converter o QPC para ticks de 100 nanossegundos para poder adicioná-lo a um FILETIME?

Um tempo de ficheiro é um valor de 64 bits que representa o número de intervalos de 100 nanossegundos que decorreram desde as 00:00 da manhã de 1 de janeiro de 1601, Tempo Universal Coordenado (UTC). Os tempos de ficheiro são usados por chamadas de API Win32 que devolvem a hora do dia, como GetSystemTimeAsFileTime e GetSystemTimePreciseAsFileTime. Em contraste, o QueryPerformanceCounter devolve valores que representam o tempo em unidades de 1/(a frequência do contador de desempenho obtido a partir do QueryPerformanceFrequency). A conversão entre os dois requer calcular a razão entre o intervalo QPC e os intervalos de 100 nanossegundos. Tenha cuidado para não perder precisão porque os valores podem ser pequenos (0,0000001 / 0,000000340).

Porque é que o carimbo temporal devolvido pelo QPC é um inteiro assinado?

Cálculos que envolvem carimbos de tempo do QPC podem envolver subtração. Ao usar um valor com assinatura, pode lidar com cálculos que podem resultar em valores negativos.

Como posso obter carimbos de data e hora de alta resolução a partir de código gerido?

Chame o método Stopwatch.GetTimeStamp da classe System.Diagnostics.Stopwatch . Para um exemplo sobre como usar o Stopwatch.GetTimeStamp, veja Adquirir carimbos de tempo de alta resolução a partir de código gerido.

Em que circunstâncias o QueryPerformanceFrequency devolve FALSE, ou o QueryPerformanceCounter devolve zero?

Isto não acontece em nenhum sistema que corra Windows XP ou posterior, desde que passes parâmetros válidos para as funções.

Preciso de definir a afinidade de thread para um único núcleo para usar QPC?

Não. Para mais informações, consulte Orientações para adquirir carimbos temporais. Este cenário não é nem necessário nem desejável. Realizar este cenário pode afetar negativamente o desempenho da sua aplicação ao restringir o processamento a um núcleo ou criar um gargalo num único núcleo se múltiplos threads definirem a sua afinidade para o mesmo núcleo ao chamar o QueryPerformanceCounter.

Características do relógio de hardware de baixo nível

Estas secções mostram características de relógio de hardware de baixo nível.

Relógios absolutos e relógios de diferença

Os relógios absolutos fornecem leituras precisas da hora do dia. Normalmente baseiam-se no Tempo Universal Coordenado (UTC) e, consequentemente, a sua precisão depende em parte de quão bem estão sincronizados com uma referência temporal externa. Os relógios de diferença medem intervalos de tempo e normalmente não se baseiam numa época temporal externa. QPC é um relógio de diferença de tempo e não está sincronizado com uma época de tempo ou referência externa. Quando se usa QPC para medições de intervalos de tempo, normalmente obtém-se melhor precisão do que se usasse carimbos de tempo derivados de um relógio absoluto. Isto deve-se ao facto de o processo de sincronização da hora de um relógio absoluto poder introduzir deslocações de fase e frequência que aumentam a incerteza das medições de intervalos de tempo de curto prazo.

Resolução, Precisão, Exatidão e Estabilidade

O QPC utiliza um contador de hardware como base. Os temporizadores de hardware consistem em três partes: um gerador de ticks, um contador que conta os ticks e um meio de recuperar o valor do contador. As características destes três componentes determinam a resolução, precisão, exatidão e estabilidade da QPC.

Se um gerador de hardware fornece ticks a uma taxa constante, os intervalos de tempo podem ser medidos simplesmente contando esses ticks. A taxa com que os ticks são gerados chama-se frequência e expressa-se em Hertz (Hz). O recíproco da frequência chama-se período ou intervalo de tique e é expresso numa unidade de tempo apropriada do Sistema Internacional de Unidades (SI) (por exemplo, segundo, milissegundo, microssegundo ou nanossegundo).

Intervalo de tempo

A resolução do temporizador é igual ao período. A resolução determina a capacidade de distinguir entre quaisquer dois carimbos temporais e coloca um limite inferior nos menores intervalos de tempo que podem ser medidos. Isto é por vezes chamado de resolução de tick.

A medição digital do tempo introduz uma incerteza de medição de ± 1 tick porque o contador digital avança em passos discretos, enquanto o tempo avança continuamente. Esta incerteza é chamada de erro de quantização. Para medições típicas de intervalo de tempo, este efeito pode muitas vezes ser ignorado porque o erro de quantização é muito menor do que o intervalo de tempo a ser medido.

Medição digital do tempo

No entanto, se o período medido for pequeno e se aproximar da resolução do temporizador, terá de considerar este erro de quantização. O tamanho do erro introduzido é o de um período de relógio.

Os dois diagramas seguintes ilustram o impacto da incerteza de ± 1 tick usando um temporizador com resolução de 1 unidade de tempo.

Incerteza dos carraças

QueryPerformanceFrequency devolve a frequência da QPC, e o período e a resolução são iguais ao recíproco deste valor. A frequência do contador de desempenho que o QueryPerformanceFrequency devolve é determinada durante a inicialização do sistema e não muda enquanto o sistema está a funcionar.

Observação

Muitas vezes , o QueryPerformanceFrequency não devolve a frequência real do gerador de ticks de hardware. Por exemplo, em algumas versões mais antigas do Windows, o QueryPerformanceFrequency devolve a frequência TSC dividida por 1024; e quando a correr sob um hipervisor que implementa a interface do hipervisor versão 1.0 (ou sempre em algumas versões mais recentes do Windows), a frequência contadora de desempenho é fixa a 10 MHz. Como resultado, não presuma que o QueryPerformanceFrequency irá devolver um valor derivado da frequência do hardware.

 

QueryPerformanceCounter lê o contador de desempenho e devolve o número total de ticks que ocorreram desde o início do sistema operativo Windows, incluindo o tempo em que a máquina esteve em estado de repouso, como em standby, hibernação ou standby ligado.

Estes exemplos mostram como calcular o intervalo de ticks e a resolução e como converter a contagem de ticks num valor temporal.

Exemplo 1

QueryPerformanceFrequency devolve o valor 3.125.000 numa determinada máquina. Qual é o intervalo de ciclo e a resolução das medições de QPC nesta máquina? O intervalo de tique, ou período, é o recíproco de 3.125.000, que é 0,000000320 (320 nanossegundos). Portanto, cada tick representa a passagem de 320 nanossegundos. Intervalos de tempo inferiores a 320 nanossegundos não podem ser medidos nesta máquina.

Intervalo de tick = 1/(Frequência de Performance)

Intervalo de tiques = 1/3.125.000 = 320 ns

Exemplo 2

Na mesma máquina do exemplo anterior, a diferença dos valores devolvidos de duas chamadas sucessivas ao QPC é 5. Quanto tempo decorreu entre as duas chamadas? 5 ticks multiplicados por 320 nanossegundos resultam em 1,6 microssegundos.

Tempo Decorrido = Ticks * Intervalo de Ticks

Tempo decorrido = 5 * 320 ns = 1,6 μs

Leva tempo a aceder (ler) ao contador de ticks pelo software, e esse tempo pode reduzir a precisão da medição de tempo. Isto deve-se ao facto de o tempo de intervalo mínimo (o menor intervalo de tempo que pode ser medido) ser o maior entre a resolução e o tempo de acesso.

Precisão = MAX [Resolução, Tempo de Acesso]

Por exemplo, considere um temporizador de hardware hipotético com resolução de 100 nanossegundos e tempo de acesso de 800 nanossegundos. Isto poderia acontecer se o temporizador da plataforma fosse usado em vez do registo TSC como base do QPC. Assim, a precisão seria de 800 nanossegundos e não de 100 nanossegundos, como mostrado neste cálculo.

Precisão = MAX [800 ns, 100 ns] = 800 ns

Estas duas figuras representam este efeito.

Tempo de acesso ao QPC

Se o tempo de acesso for maior que a resolução, não tentes melhorar a precisão adivinhando. Por outras palavras, é um erro assumir que o carimbo de hora é feito exatamente no meio, ou no início ou no fim da chamada.

Em contraste, considere o seguinte exemplo em que o tempo de acesso ao QPC é de apenas 20 nanossegundos e a resolução do relógio de hardware é de 100 nanossegundos. Isto poderia acontecer se o registo TSC fosse usado como base para o QPC. Aqui, a precisão é limitada pela resolução do relógio.

Precisão qpc

Na prática, pode encontrar fontes temporais em que o tempo necessário para ler o contador é maior ou menor do que a resolução. Em qualquer dos casos, a precisão será a maior entre as duas.

Esta tabela fornece informações sobre a resolução aproximada, o tempo de acesso e a precisão de vários relógios. Note que alguns dos valores variam consoante os diferentes processadores, plataformas de hardware e velocidades de processador.

Fonte do relógio Frequência nominal do relógio Resolução do relógio Tempo de Acesso (Típico) Precisão
PC RTC 64 Hz 15,625 milissegundos N/A N/A
Consultar contador de desempenho usando TSC com um relógio de processador de 3 GHz 3 MHz 333 nanossegundos 30 nanossegundos 333 nanossegundos
Instrução de máquina RDTSC num sistema com tempo de ciclo de 3 GHz 3 GHz 333 picosegundos 30 nanossegundos 30 nanossegundos

 

Como o QPC utiliza um contador de hardware, quando se compreendem algumas características básicas dos contadores de hardware, obtém-se compreensão das capacidades e limitações do QPC.

O oscilador de cristal é o gerador de ticks de hardware mais utilizado. O cristal é um pequeno pedaço de quartzo ou outro material cerâmico que apresenta características piezoelétricas que fornecem uma referência de frequência económica com excelente estabilidade e precisão. Esta frequência é usada para gerar os incrementos contados pelo relógio.

A precisão de um temporizador refere-se ao grau de conformidade com um valor verdadeiro ou padrão. Isto depende principalmente da capacidade do oscilador de cristal de fornecer impulsos na frequência especificada. Se a frequência de oscilação for demasiado alta, o relógio irá 'correr rápido' e os intervalos medidos parecerão mais longos do que realmente são; e se a frequência for demasiado baixa, o relógio vai 'correr devagar', e os intervalos medidos parecerão mais curtos do que realmente são.

Para medições típicas de intervalo de tempo para curtas durações (por exemplo, medições de tempo de resposta, medições de latência de rede, e assim por diante), a precisão do oscilador de hardware é geralmente suficiente. No entanto, para algumas medições, a precisão da frequência do oscilador torna-se importante, especialmente para intervalos de tempo longos ou quando se pretende comparar medições feitas em diferentes máquinas. O restante desta secção explora os efeitos da precisão do oscilador.

A frequência de oscilação dos cristais é definida durante o processo de fabrico e é especificada pelo fabricante em termos de uma frequência especificada, mais ou menos uma tolerância de fabrico expressa em 'partes por milhão' (ppm), chamada de deslocamento máximo de frequência. Um cristal com uma frequência especificada de 1.000.000 Hz e um desvio máximo de frequência de ± 10 ppm estaria dentro dos limites especificados se a sua frequência real fosse entre 999.990 Hz e 1.000.010 Hz.

Ao substituir partes por milhão por microssegundos por segundo, podemos aplicar este erro de deslocamento de frequência a medições de intervalos temporais. Um oscilador com um offset de +10 ppm teria um erro de 10 microssegundos por segundo. Assim, ao medir um intervalo de 1 segundo, correria rápido e mediria um intervalo de 1 segundo como 0,999990 segundos.

Uma referência conveniente é que um erro de frequência de 100 ppm causa um erro de 8,64 segundos após 24 horas. Esta tabela apresenta a incerteza da medição devido ao erro acumulado em intervalos de tempo mais longos.

Duração do intervalo de tempo Incerteza da medição devido ao erro acumulado com tolerância de frequência de +/- 10 PPM
1 microssegundo ± 10 picosegundos (10-12)
1 milissegundo ± 10 nanossegundos (10-9)
1 segundo ± 10 microssegundos
1 minuto ± 60 microssegundos
Uma hora ± 36 milissegundos
1 dia ± 0,86 segundos
1 semana ± 6,08 segundos

 

A tabela anterior mostra que, para intervalos de tempo curtos, o erro de deslocamento de frequência pode muitas vezes ser ignorado. No entanto, para longos intervalos de tempo, mesmo um pequeno deslocamento de frequência pode resultar numa incerteza substancial na medição.

Os osciladores de cristal usados em computadores pessoais e servidores são tipicamente fabricados com uma tolerância de frequência de ± 30 a 50 partes por milhão e, raramente, os cristais podem estar desviados em até 500 ppm. Embora existam cristais com tolerâncias de deslocamento de frequência muito mais apertadas, são mais caros e, por isso, não são usados na maioria dos computadores.

Para reduzir os efeitos adversos deste erro de deslocamento de frequência, versões recentes do Windows, particularmente o Windows 8, utilizam múltiplos temporizadores de hardware para detetar o deslocamento de frequência e compensá-lo na medida do possível. Este processo de calibração é realizado quando o Windows é iniciado.

Como mostram os exemplos seguintes, o erro de deslocamento de frequência de um relógio de hardware influencia a precisão alcançável, e a resolução do relógio pode ser menos importante.

O erro de deslocamento de frequência influencia a precisão alcançável

Exemplo 1

Suponha que realiza medições de intervalo de tempo usando um oscilador de 1 MHz, que tem uma resolução de 1 microssegundo e um erro máximo de deslocamento de frequência de ±50 ppm. Agora, suponhamos que o offset é exatamente +50 ppm. Isto significa que a frequência real seria 1.000.050 Hz. Se medissemos um intervalo de tempo de 24 horas, a nossa medição seria 4,3 segundos demasiado curta (23:59:55,700000 medida contra 24:00:00,000000 real).

Segundos num dia = 86400

Erro de deslocamento de frequência = 50 ppm = 0,00005

86.400 segundos * 0,00005 = 4,3 segundos

Exemplo 2

Suponha que o relógio TSC do processador é controlado por um oscilador de cristal e tem uma frequência especificada de 3 GHz. Isto significa que a resolução seria 1/3.000.000.000 ou cerca de 333 picosegundos. Assuma que o cristal usado para controlar o relógio do processador tem uma tolerância de frequência de ±50 ppm e é, na verdade, +50 ppm. Apesar da impressionante resolução, uma medição de intervalo de tempo de 24 horas será ainda 4,3 segundos demasiado curta. (23:59:55,700000000000 medido versus 24:00:00,00000000000 real).

Segundos num dia = 86400

Erro de desvio de frequência = 50 ppm = 0,00005

86.400 segundos * 0,00005 = 4,3 segundos

Isto mostra que um relógio TSC de alta resolução não fornece necessariamente medições mais precisas do que um relógio de resolução inferior.

Exemplo 3

Considere usar dois computadores diferentes para medir o mesmo intervalo de 24 horas. Ambos os computadores têm um oscilador com um deslocamento máximo de frequência de ± 50 ppm. Qual pode ser a diferença na medição do mesmo intervalo de tempo nestes dois sistemas? Tal como nos exemplos anteriores, ± 50 ppm produz um erro máximo de ± 4,3 segundos após 24 horas. Se um sistema funciona 4,3 segundos rápido e o outro 4,3 segundos lento, o erro máximo após 24 horas pode ser de 8,6 segundos.

Segundos num dia = 86400

Erro de deslocamento de frequência = ±50 ppm = ±0,00005

±(86.400 segundos * 0,00005) = ±4,3 segundos

Deslocamento máximo entre os dois sistemas = 8,6 segundos

Em resumo, o erro de deslocamento de frequência torna-se cada vez mais importante ao medir intervalos de tempo longos e ao comparar medições entre diferentes sistemas.

A estabilidade de um temporizador descreve se a frequência dos pulsos muda ao longo do tempo, por exemplo, como resultado de alterações na temperatura. Cristais de quartzo usados para gerar pulsos em computadores apresentam pequenas variações de frequência em função da temperatura. O erro causado pela deriva térmica é tipicamente pequeno comparado com o erro de deslocamento de frequência para intervalos de temperatura comuns. No entanto, os criadores de software para equipamentos portáteis ou sujeitos a grandes flutuações de temperatura podem precisar de considerar este efeito.

Informação do temporizador de hardware

Registo TSC (x86 e x64)

Todos os processadores Intel e AMD modernos contêm um registo TSC que é um registo de 64 bits que aumenta a uma taxa elevada, tipicamente igual ao relógio do processador. O valor deste contador pode ser lido através das instruções de máquina RDTSC ou RDTSCP, proporcionando um tempo de acesso muito baixo e custo computacional na ordem de dezenas ou centenas de ciclos de máquina, dependendo do processador.

Embora o registo TSC pareça um mecanismo ideal de carimbo temporal, aqui estão circunstâncias em que não consegue funcionar de forma fiável para efeitos de marcação do tempo:

  • Nem todos os processadores têm registos TSC utilizáveis, por isso usar o registo TSC no software cria diretamente um problema de portabilidade. (O Windows seleciona uma fonte de tempo alternativa para o QPC neste caso, o que evita o problema de portabilidade.)
  • Alguns processadores podem variar a frequência do relógio do TSC ou travar o avanço do registo TSC, o que torna o TSC inadequado para fins de temporização nestes processadores. Diz-se que estes processadores possuem registos TSC não invariantes. (O Windows irá detetar isto automaticamente e selecionar uma fonte de tempo alternativa para o QPC).
  • Mesmo que um host de virtualização tenha um TSC utilizável, a migração ao vivo de máquinas virtuais em execução quando o host de virtualização alvo não tem ou não utiliza escalabilidade TSC assistida por hardware pode resultar numa alteração na frequência do TSC visível para os convidados. (Espera-se que, se este tipo de migração em tempo real for possível para um convidado, o hipervisor elimine o bit de funcionalidade TSC invariante no CPUID.)
  • Em sistemas multiprocessador ou multi-núcleo, alguns processadores e sistemas não conseguem sincronizar os relógios de cada núcleo para o mesmo valor. (O Windows irá detetar isto automaticamente e selecionar uma fonte de tempo alternativa para o QPC).
  • Em alguns sistemas multiprocessadores grandes, pode não ser possível sincronizar os relógios do processador para o mesmo valor mesmo que o processador tenha um TSC invariante. (O Windows irá detetar isto automaticamente e selecionar uma fonte de tempo alternativa para o QPC).
  • Alguns processadores executam instruções fora de ordem. Isto pode resultar em contagens de ciclo incorretas quando o RDTSC é usado para cronometrar sequências de instruções, pois a instrução RDTSC pode ser executada num momento diferente do especificado no seu programa. A instrução RDTSCP foi introduzida em alguns processadores em resposta a este problema.

Tal como outros temporizadores, o TSC baseia-se num oscilador de cristal cuja frequência exata não é conhecida antecipadamente e que apresenta um erro de deslocamento de frequência. Assim, antes de poder ser utilizado, deve ser calibrado usando outra referência de temporização.

Durante a inicialização do sistema, o Windows verifica se o TSC é adequado para fins de temporização e realiza a calibração de frequência e sincronização do núcleo necessárias.

Relógio PM (x86 e x64)

O temporizador ACPI, também conhecido como relógio PM, foi adicionado à arquitetura do sistema para fornecer carimbos de tempo fiáveis independentemente da velocidade do processador. Como este era o único objetivo deste temporizador, ele fornece um carimbo temporal num único ciclo de relógio, mas não oferece qualquer outra funcionalidade.

Temporizador HPET (x86 e x64)

O High Precision Event Timer (HPET) foi desenvolvido em conjunto pela Intel e Microsoft para satisfazer os requisitos de temporização de aplicações multimédia e outras sensíveis ao tempo. Ao contrário do TSC, que é um recurso por processador, o HPET é um recurso partilhado e de plataforma ampla, embora um sistema possa ter múltiplos HPETs. O suporte ao HPET existe no Windows desde o Windows Vista, e a certificação do Logótipo de Hardware do Windows 7 e Windows 8 requer suporte ao HPET na plataforma de hardware.

Contador Genérico do Sistema de Temporizadores (ARM)

As plataformas baseadas em Arm não têm um relógio TSC, HPET ou PM como há nas plataformas baseadas em Intel ou AMD. Em vez disso, os processadores Arm fornecem o Temporizador Genérico (por vezes chamado de Temporizador de Intervalo Genérico, ou GIT) que contém um registo de Contador de Sistema (por exemplo, CNTVCT_EL0). O Contador Genérico do Sistema de Temporizadores é uma fonte de tempo de frequência fixa para toda a plataforma. Começa em zero no arranque e aumenta a um ritmo elevado. No Armv8.6 ou superior, isto é definido exatamente como 1 GHz, mas deve ser determinado lendo o registo de frequência de relógio definido pelo firmware de arranque inicial. Para mais detalhes, consulte o capítulo "O Temporizador Genérico no modo AArch64" no "Manual de Referência da Arquitetura Arm para perfis A" (DDI 0487).

Contador de Ciclos (Arm)

Plataformas baseadas em Arm fornecem um registo de contador de ciclos dos monitores de desempenho (por exemplo, PMCCNTR_EL0). Este contador conta os ciclos de relógio do processador. É não invariante e as suas unidades podem não estar correlacionadas com o tempo real. Não é aconselhado usar este registo para obter marcas temporais.