29 de outubro de 2010

Levantando os recursos existentes na CPU

Há um post aqui no blog onde mostrei como obter informações sobre a CPU em Delphi usando a instrução assembly CPUID. O foco lá era obter apenas o modelo da CPU, informação usada para fazer um licenciamento de software. Aqui eu vou mostrar como fazer um levantamento sobre os recursos implementados numa CPU dos dois principais fabricantes - Intel e AMD.

Em ambos os fabricantes, o levantamento proposto é executado pela função 1 da CPUID. Isto signfica que teremos que mover o valor 1 para o registrador EAX, que armazena o código da função a ser executada. Os valores que buscamos são armazenados pela instrução CPUID no registrador EDX.
var REGEDX : LongWord;
begin
asm
MOV EAX, 1
CPUID
MOV [REGEDX], EDX
end;
{ ... }

Então, após a execução do código acima, teremos na variável REGEDX o mapa de bits para as características presentes no processador. São 32 bits ao todo, cada um sinalizando se um determinado recurso está presente na CPU do seu computador. Portanto, para ter acesso a cada bit isoladamente, teremos que trabalhar com aritmética binária no Delphi - principalmente com o operador AND aplicado bit a bit.

A ideia é preparar outra variável com 32 bits mas apenas um dos bits estará ligado de cada vez. Ao aplicar o AND binário entre essa variável e o conteúdo de REGEDX nós obtemos a sinalização se o recurso representado nesse bit específico está presente ou não. A imagem abaixo ilustra a extração do recurso representado pelo primeiro bit:
Extração do primeiro bit

Repare que, na variável preparada, apenas o primeiro bit está ligado, isto é, possui valor 1. Comos os demais bits estão em zero, o AND binário com o REGEDX retornará um valor diferente de zero caso seu primeiro bit também esteja ligado.

Para ligar um bit de cada vez na variável, podemos montar um laço iniciando em 1 (liga o primeiro bit) e ir multiplicando-a por 2 para fazer o bit ir "avançando" :
var REGEDX, Mascara : LongWord;
Suportado : array[0..31] of byte;
i : integer;
begin
{ ... }
Mascara := 1;
for i := 0 to 31 do begin
if (REGEDX and Mascara) <> 0 then
Suportado[i] := 1 { Suportado }
else
Suportado[i] := 0; { Não suportado }
Mascara := Mascara * 2;
end;
{ ... }

No código acima, a variável preparada para auxiliar na extração dos bits chama-se Mascara. Ao final da execução desse trecho, teremos em cada posição do array Suportado um sinal indicando se o recurso existe ou não na CPU. Mas qual recurso ?

O significado de cada posição varia de acordo com o fabricante da CPU, sendo que até mesmo o conjunto de recursos incluídos em um e outro é diferente. Para facilitar a exibição das informações sobre os recursos podemos montar um array com 32 posições para texto e alimentar cada uma com um lembrete do significado do recurso. O quadro abaixo mostra os recursos disponíveis em processadores Intel:
if(StrComp(VendorID, 'GenuineIntel') = 0)
then begin
Recurso[0]:='FPU'; { Floating Point Unit }
Recurso[1]:='VME'; { Virtual Mode Extension }
Recurso[2]:='DE'; { Debugging Extension }
Recurso[3]:='PSE'; { Page Size Extension }
Recurso[4]:='TSC'; { Time Stamp Counter }
Recurso[5]:='MSR'; { Model Specific Registers }
Recurso[6]:='PAE'; { Physical Address Extension }
Recurso[7]:='MCE'; { Machine Check Extension }
Recurso[8]:='CX8'; { CMPXCHG8 Instruction}
Recurso[9]:='APIC'; { On-chip APIC Hardware }
Recurso[10]:=''; { Reserved }
Recurso[11]:='SEP'; { Fast system call }
Recurso[12]:='MTRR'; { Machine Type Range Registers }
Recurso[13]:='PGE'; { Global Paging Extension }
Recurso[14]:='MCA'; { Machine Check Architecture }
Recurso[15]:='CMOV'; { Conditional Move Instruction }
Recurso[16]:='PAT'; { Page Attribute Table }
Recurso[17]:='PSE-36'; { 36-bit Page Size Extension }
Recurso[18]:='PSN'; { 96-bit Processor Serial Number }
Recurso[19]:='CLFSH'; { CLFLUSH Instruction }
Recurso[20]:=''; { Reserved }
Recurso[21]:='DS'; { Debug Trace Store }
Recurso[22]:='ACPI'; { ACPI Support }
Recurso[23]:='MMX'; { MMX Technology }
Recurso[24]:='FXSR'; { FXSAVE FXRSTOR (Fast save and restore) }
Recurso[25]:='SSE'; { Streaming SIMD Extensions }
Recurso[26]:='SSE2'; { Streaming SIMD Extensions 2 }
Recurso[27]:='SS'; { Self-Snoop }
Recurso[28]:='HTT'; { Hyper-Threading Technology }
Recurso[29]:='TM'; { Thermal Monitor Supported }
Recurso[30]:=''; { Reserved }
Recurso[31]:='PBE'; { Pending Break Enable }
end;

Veja este link para saber como obter o nome do fabricante. A documentação sobre o uso do CPUID em processadores Intel pode ser acessada aqui.

O quadro abaixo mostra os recursos disponíveis em processadores AMD:
if(StrComp(VendorID, 'AuthenticAMD') = 0)
then begin
Recurso[0]:='FPU'; { Floating Point Unit }
Recurso[1]:='VME'; { Virtual Mode Extension }
Recurso[2]:='DE'; { Debugging Extension }
Recurso[3]:='PSE'; { Page Size Extension }
Recurso[4]:='TSC'; { Time Stamp Counter }
Recurso[5]:='MSR'; { Model Specific Registers }
Recurso[6]:='PAE'; { Physical Address Extesnion }
Recurso[7]:='MCE'; { Machine Check Extension }
Recurso[8]:='CX8'; { CMPXCHG8 Instruction }
Recurso[9]:='APIC'; { On-chip APIC Hardware }
Recurso[10]:=''; { Reserved }
Recurso[11]:='SEP'; { SYSENTER and SYSEXIT instructions }
Recurso[12]:='MTRR'; { Machine Type Range Registers }
Recurso[13]:='PGE'; { Global Paging Extension }
Recurso[14]:='MCA'; { Machine Check Architecture }
Recurso[15]:='CMOV'; { Conditional Move Instruction }
Recurso[16]:='PAT'; { Page Attribute Table }
Recurso[17]:='PSE-36'; { 36-bit Page Size Extension }
Recurso[18]:=''; { Reserved }
Recurso[19]:='CLFSH'; { CLFLUSH instruction support }
Recurso[20]:=''; { Reserved }
Recurso[21]:=''; { Reserved }
Recurso[22]:=''; { Reserved }
Recurso[23]:='MMX'; { MMX Technology }
Recurso[24]:='FXSR'; { FXSAVE FXRSTOR (Fast save and restore) }
Recurso[25]:='SSE'; { Streaming SIMD Extensions }
Recurso[26]:='SSE2'; { SSE2 instruction support }
Recurso[27]:=''; { Reserved }
Recurso[28]:='HTT'; { Hyper-Threading Technology }
Recurso[29]:=''; { Reserved }
Recurso[30]:=''; { Reserved }
Recurso[31]:=''; { Reserved }
end;

A documentação sobre o uso do CPUID em processadores AMD pode ser acessada aqui.

Ambos os arrays montados neste post - Suportado e Recurso - estão sincronizados. Então, para mostrar se um recurso está ou não presente basta percorrer os arrays usando o mesmo índice e mostrando lado a lado o nome do recurso e o flag indicativo de suporte a este recurso.

5 comentários :

Anônimo disse...

Muito bom o post, parabens!!
Obrigado por ter postado, me ajudou bastante.

Precisa de mais uma ajuda sua. Gostaria de saber se existe alguma identificação única no micro que eu consiga diferenciar as maquinas, pois o serial da placa mae, sempre será o mesmo dependendo do modelo. A Bios eu achei uma função que da Access Violation, devido a Microsft ter bloqueado para se obter esse tipo de informação do Windows NT para frente. O Mac Address não seria uma informação confiavel, pois é facil de ser clonado. Você tem alguma outra sugestão?

Abraços

Felipe Luiz Carnevali

Luís Gustavo Fabbro disse...

Felipe

Uma solução seria tentar obter o serial do Processador mas nem todos os modelos/fabricantes implementam esse recurso. Veja aqui. Dependendo do cenário com que você está trabalhando, pode tentar usar o WMI para obter os dados da classe WIN32_Processor.

Uma solução mais simples seria usar o MAC Address em associação com informações da CPU e/ou do HD. Ao misturar os bytes desses dados todos você estará criando seu próprio padrão e impedirá que a simples clonagem do MAC permita a alguém burlar sua solução.

Amorim disse...

Parabéns pelo post!
Gostaria de saber se há como recuperar uma lista de processos com o consumo de CPU de cada PID. Já pesquisei e encontrei como retornar a quantidade de memória utilizada, mas quanto o processo esta consumindo de processamento e/ou em quanto está o processamento da maquina ainda não encontrei.

Qualquer ajuda é bem vinda.

At.
Rafael Amorim

Luís Gustavo Fabbro disse...

Rafael

A informação que você quer está disponível através da classe Win32_PerfFormattedData_PerfProc_Process do WMI (Windows Management Instrumentation). Veja no post Obtendo nível de sinal do Wifi usando WMI com Delphi, publicado aqui no blog, um exemplo de como trabalhar com o WMI em Delphi.

[]s

Amorim disse...

Muito Obrigado!
Estou lendo o seu post informado acima, e pesquisando mais sobre wmi, acredito estar chegando aonde preciso.

Foi de grande ajuda, mais uma vez agradeço.

sds.

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.