(Gast)
n/a Beiträge
|
Re: Level 2 Cache
20. Apr 2004, 23:32
Moin!
Mensch, manchmal wird man auch betriebsblind... Die If Bedingung ist einfach falsch herum gestellt (Wenn mehr als 1000 KB, dann zeige in KB an, ansonsten in MB)...
Ok, ich ändere den Code mal schnell...
@other: Falls ihr den Code schon genutzt habt, If Bedingung 2x ändern (ja ja Copy&Paste) oder nochmals neu kopieren und einfügen...
/EDIT: Ok, ändern geht nicht mehr in diesem Forum und dafür den Mod belästigen muss nicht sein, daher jetzt der funktionierende Code...
Delphi-Quellcode:
Unit L2Cache;
Interface
Function GetL2CacheSize : String;
Implementation
uses
sysutils;
// prüfen, ob die CPU die CPUID Instruktion unterstützt
//
// Anmerkung: Bei Cyrix M2 CPU's muss man die Instruktion vorher in einem
// Cyrix spezifischen Register enablen, sonst ist sie unbekannt
// und die EFlags verhalten sich dem entsprechend. In diesem Falle
// ist das aber hinfällig, da Cyrix CPU's keine Cache Informationen
// über CPUID zurückliefern sondern nur über ihre Configuration
// Register auf Port $FE und $FF...
Function CheckForCPUID : Boolean; Assembler;
Asm
push ebx
push ecx
pushfd // save EFLAGS
pop eax // store EFLAGS in EAX
mov ebx, eax // save in EBX for later testing
xor eax, 00200000h // toggle bit 21
push eax // put to stack
popfd // save changed EAX to ELFAGS
pushfd // push EFLAGS on stack
pop ecx // store EFLAGS in EAX
mov Result, False
cmp ecx, ebx // see if bit 21 has changed
jz @@no_CPUID // if no change, no CPUID
mov Result, True // set flag
@@no_CPUID:
pop ecx
pop ebx
End;
Function GetL2CacheSize : String;
Var
CPUID_VendorID : Array[0..11] Of Char; // für den Vendor-String
MaxStdLevel, // höchstes CPUID Standardlevel
MaxExtLevel : LongWord; // höchstes CPUID erweitertes Level
// Unterfunktion für Intel CPU's
Function GetIntelCacheInfo : String;
Var
CallCtr : Byte; // gibt an, wie oft CPUID 02h aufgerufen
// werden muss, um alle Cache Info's zu
// bekommen
Regs : array[0..3] Of LongWord; // Speicher für die Register nach CPUID 02h
i : Integer; // Zählvariable
KBSize : Word; // die Grösse des L2 Caches in KByte
// die Intel CPU's geben in mehreren Byte Werten ihre Info's an, und
// es kann mehrere ID's für den selben Cache Typ geben, daher hier anhand
// der ID die Grösse zurückgeben oder 0, wenn es kein L2 Cache Deskriptor war
Function CacheInfo(CacheID : Byte): Word;
Begin
Case CacheID Of
$39, $3B,
$41, $79 : Result := 128;
$3C, $42,
$7A, $82 : Result := 256;
$43, $7B,
$83, $86 : Result := 512;
$44, $7C,
$84, $87 : Result := 1024;
$85, $45 : Result := 2048;
Else
Result := 0;
End;
End;
// ok, ans eingemachte für die Intel Cache Info's
Begin
Asm
push eax // register sichern - alle - auch wenn in der Delphi Hilfe
push ebx // steht, das man einzelne Register frei verändern darf.
push ecx // Diese Aussage trifft nur bei nicht optimierte Codes zu, wenn
push edx // die Optimierung an ist (default), dann fällt Delphi dadurch
// gerne auf die Schnauze...
mov eax, 2 // Funktion laden (hier: 0000.0002h)
db 00fh, 0a2h // CPUID
mov CallCtr, al // CallCtr merken
mov Regs[0].longword, eax // Register sichern zum auswerten
mov Regs[1].longword, ebx
mov Regs[2].longword, ecx
mov Regs[3].longword, edx
pop edx // Register wiederherstellen, damit Delphi keine Problem bekommt
pop ecx
pop ebx
pop eax
End;
// CallCtr lass ich mal aussen vor, wird bisher noch nicht benutzt von Intel
// (also noch nicht > 1)
// ok, dann zählen wir mal die KBytes zusammen der einzelnen Deskriptoren
KBSize := 0;
If ( Regs[0] And $80000000 ) = 0 Then // prüfen ob gültige Angabe
Begin
If ( ( Regs[0] Shr 8 ) And $ff ) > 0 Then // wenn was drinne steht ...
Inc(KBSize, CacheInfo(( Regs[0] Shr 8 ) And $ff)); // ... dann auswerten
If ( ( Regs[0] Shr 16 ) And $ff ) > 0 Then
Inc(KBSize, CacheInfo(( Regs[0] Shr 16 ) And $ff));
If ( ( Regs[0] Shr 24 ) And $ff ) > 0 Then
Inc(KBSize, CacheInfo(( Regs[0] Shr 24 ) And $ff));
End;
// da in EAX der CallCtr mit drinne steht, wird das hier drüber extra behandelt
// und die restlichen können wir in einem Rutsch durchgehen
For i := 1 To 3 Do
Begin
If ( Regs[i] And $80000000 ) = 0 Then
Begin
If ( ( Regs[i] Shr 8 ) And $ff ) > 0 Then
Inc(KBSize, CacheInfo(( Regs[i] Shr 8 ) And $ff));
If ( ( Regs[i] Shr 16 ) And $ff ) > 0 Then
Inc(KBSize, CacheInfo(( Regs[i] Shr 16 ) And $ff));
If ( ( Regs[i] Shr 24 ) And $ff ) > 0 Then
Inc(KBSize, CacheInfo(( Regs[i] Shr 24 ) And $ff));
End;
End;
// Ausgabe bilden
If ( KBSize < 1024 ) Then // noch im KByte Bereich?
Result := IntToStr(KBSize) + ' KB' // ok, dann KByte
Else
Result := IntToStr(KBSize Div 1024) + ' MB'; // nein, also MByte
End;
// ok, gleiches für AMD
Function GetAMDCacheInfo : String;
Var
KBSize : Word;
Begin
// AMD macht es uns einfacher, die haben direkt eine Angabe des L1 und L2
// Cache-Grösse in KByte als Rückgabewert
Asm
push eax // siehe oben
push ebx
push ecx
push edx
mov eax, 080000006h // Funktionsnummer laden (hier: 8000.0006h)
db 00fh, 0a2h // CPUID
shr ecx, 16 // in Bits 16..31 steht die Grösse in KByte
mov KBSize, cx // daher: runterschieben und die 16 Bits merken
pop edx
pop ecx
pop ebx
pop eax
End;
// Ausgabe bilden - same procedure as every cpu... ;-)
If ( KBSize < 1024 ) Then
Result := IntToStr(KBSize) + ' KB'
Else
Result := IntToStr(KBSize Div 1024) + ' MB';
End;
Begin
// ok, hier gehts los
If ( CheckForCPUID ) Then // haben wir überhaupt eine Chance, oder anders:
Begin // bietet die CPU einen CPUID Befehl?
Asm
push eax // wieder Register sichern...
push ebx
push ecx
push edx
// xor eax, eax setzt eax auf 0 - laut AMD Optimizing Doc ist mov eax, 0
// schneller beim AMD. Laut Intel ist xor eax, eax schneller bei Intel...
xor eax, eax // Funktionsnummer laden (hier: 0000.0000h)
db 00fh, 0a2h // CPUID
// in EAX steht das höchste Standard CPUID Level -> merken
mov MaxStdLevel, eax
// wir wollen den Vendor String speichern - und das geht am einfachsten
// mit den String Befehlen der CPU...
push edi // enhanced destination index = Zieladresse
// vorher aber erstmal sichern...
lea edi, CPUID_VendorID // dann die Adresse der Variablen holen
cld // direction flag löschen, wir wollen EDI erhöhen...
mov eax, ebx // als erstes muss der Inhalt von EBX gespeichert
// werden, und da SToreStringDword immer EAX
// schreibt, muss EBX in EAX gepackt werden...
stosd // ok, schreiben
mov eax, edx // gleiches mit EDX
stosd // und hinten ranhängen
// (EDI ist jetzt schon auf CPUID_VendorID[4])
mov eax, ecx // gleiches mit ECX
stosd
pop edi // ok, Inhalt von EDI wiederherstellen
// auf erweiterten CPUID testen
mov eax, 080000000h // Funktionsnummer laden (hier: 8000.0000h)
db 00fh, 0a2h // CPUID
mov MaxExtLevel, eax // maximale Funktionsnummer sichern...
pop edx // Register wiederherstellen
pop ecx
pop ebx
pop eax
End;
// nun gehts an die Auswertung und da kocht jeder Hersteller sein eigenes
// Süppchen...
If ( String(CPUID_VendorID) = ' GenuineIntel' ) Then // Intel
Begin
If ( MaxStdLevel >= 2 ) Then // wir brauchen min. CPUID 0000.0002h
Result := GetIntelCacheInfo
Else
Result := ' unkown';
End
Else If ( String(CPUID_VendorID) = ' AuthenticAMD' ) Then // AMD
Begin
// wir brauchen min. CPUID 8000.0006h
If ( MaxExtLevel >= $80000006 ) Then // ab K6-III
Result := GetAMDCacheInfo
Else
Result := ' unkown';
End
Else If ( String(CPUID_VendorID) = ' CyrixInstead' ) Then
Begin
// tja, die Cyrix'e - keine Cache Info im CPUID, alles per Cyrix
// specific Register...
Result := ' no cache info';
End;
// Transmeta und weitere erstmal wegfallen lassen...
End
Else
Result := ' no CPUID support';
End;
End.
Ich habe den Code gleich mal ein wenig kommentiert, damit kommt vielleicht ein wenig Klarheit auf über das was ich da überhaupt mache...
MfG
Muetze1
|