123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- unit GR32_System;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Graphics32
- *
- * The Initial Developer of the Original Code is
- * Alex A. Denisov
- *
- * Portions created by the Initial Developer are Copyright (C) 2000-2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Andre Beckedorf
- * Michael Hansen <[email protected]>
- * - CPU type & feature-set aware function binding
- * - Runtime function template and extension binding system
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$I GR32.inc}
- uses
- SysUtils;
- type
- TPerfTimer = class
- private
- FStart: Int64;
- public
- procedure Start;
- function ReadNanoseconds: string;
- function ReadMilliseconds: string;
- function ReadSeconds: string;
- function ReadValue: Int64;
- end;
- { Pseudo GetTickCount implementation for Linux - for compatibility
- This works for basic time testing, however, it doesnt work like its
- Windows counterpart, ie. it doesnt return the number of milliseconds since
- system boot. Will definitely overflow. }
- function GetTickCount: Cardinal;
- { Returns the number of processors configured by the operating system. }
- function GetProcessorCount: Cardinal;
- type
- {$IFNDEF PUREPASCAL}
- { TCPUInstructionSet, defines specific CPU technologies }
- TCPUInstructionSet = (ciMMX, ciEMMX, ciSSE, ciSSE2, ci3DNow, ci3DNowExt);
- {$ELSE}
- TCPUInstructionSet = (ciDummy);
- {$DEFINE NO_REQUIREMENTS}
- {$ENDIF}
- PCPUFeatures = ^TCPUFeatures;
- TCPUFeatures = set of TCPUInstructionSet;
- { General function that returns whether a particular instruction set is
- supported for the current CPU or not }
- function HasInstructionSet(const InstructionSet: TCPUInstructionSet): Boolean;
- function CPUFeatures: TCPUFeatures;
- var
- GlobalPerfTimer: TPerfTimer;
- implementation
- uses
- {$IF defined(MSWINDOWS)}
- Winapi.Windows
- {$ELSEIF defined(MACOS)}
- Macapi.Mach
- {$ELSEIF defined(POSIX)}
- Posix.Time
- {$ENDIF}
- ,
- Classes, TypInfo;
- var
- CPUFeaturesInitialized : Boolean = False;
- CPUFeaturesData: TCPUFeatures;
- function GetTickCount: Cardinal;
- begin
- Result := TThread.GetTickCount;
- end;
- { TPerfTimer }
- function TPerfTimer.ReadNanoseconds: string;
- begin
- Result := IntToStr(ReadValue);
- end;
- function TPerfTimer.ReadMilliseconds: string;
- begin
- Result := IntToStr(ReadValue div 1000);
- end;
- function TPerfTimer.ReadSeconds: string;
- begin
- Result := IntToStr(ReadValue div 1000000);
- end;
- function TPerfTimer.ReadValue: Int64;
- begin
- Result := GetTickCount - FStart;
- end;
- procedure TPerfTimer.Start;
- begin
- FStart := GetTickCount;
- end;
- function GetProcessorCount: Cardinal;
- begin
- Result := 1;
- end;
- {$IFNDEF PUREPASCAL}
- const
- CPUISChecks: array [TCPUInstructionSet] of Cardinal =
- ($800000, $400000, $2000000, $4000000, $80000000, $40000000);
- {ciMMX , ciEMMX, ciSSE , ciSSE2 , ci3DNow , ci3DNowExt}
- function CPUID_Available: Boolean;
- asm
- {$IFDEF TARGET_x86}
- MOV EDX,False
- PUSHFD
- POP EAX
- MOV ECX,EAX
- XOR EAX,$00200000
- PUSH EAX
- POPFD
- PUSHFD
- POP EAX
- XOR ECX,EAX
- JZ @1
- MOV EDX,True
- @1: PUSH EAX
- POPFD
- MOV EAX,EDX
- {$ENDIF}
- {$IFDEF TARGET_x64}
- MOV EDX,False
- PUSHFQ
- POP RAX
- MOV ECX,EAX
- XOR EAX,$00200000
- PUSH RAX
- POPFQ
- PUSHFQ
- POP RAX
- XOR ECX,EAX
- JZ @1
- MOV EDX,True
- @1: PUSH RAX
- POPFQ
- MOV EAX,EDX
- {$ENDIF}
- end;
- function CPU_Signature: Integer;
- asm
- {$IFDEF TARGET_x86}
- PUSH EBX
- MOV EAX,1
- {$IFDEF FPC}
- CPUID
- {$ELSE}
- DW $A20F // CPUID
- {$ENDIF}
- POP EBX
- {$ENDIF}
- {$IFDEF TARGET_x64}
- PUSH RBX
- MOV EAX,1
- CPUID
- POP RBX
- {$ENDIF}
- end;
- function CPU_Features: Integer;
- asm
- {$IFDEF TARGET_x86}
- PUSH EBX
- MOV EAX,1
- {$IFDEF FPC}
- CPUID
- {$ELSE}
- DW $A20F // CPUID
- {$ENDIF}
- POP EBX
- MOV EAX,EDX
- {$ENDIF}
- {$IFDEF TARGET_x64}
- PUSH RBX
- MOV EAX,1
- CPUID
- POP RBX
- MOV EAX,EDX
- {$ENDIF}
- end;
- function CPU_ExtensionsAvailable: Boolean;
- asm
- {$IFDEF TARGET_x86}
- PUSH EBX
- MOV @Result, True
- MOV EAX, $80000000
- {$IFDEF FPC}
- CPUID
- {$ELSE}
- DW $A20F // CPUID
- {$ENDIF}
- CMP EAX, $80000000
- JBE @NOEXTENSION
- JMP @EXIT
- @NOEXTENSION:
- MOV @Result, False
- @EXIT:
- POP EBX
- {$ENDIF}
- {$IFDEF TARGET_x64}
- PUSH RBX
- MOV @Result, True
- MOV EAX, $80000000
- CPUID
- CMP EAX, $80000000
- JBE @NOEXTENSION
- JMP @EXIT
- @NOEXTENSION:
- MOV @Result, False
- @EXIT:
- POP RBX
- {$ENDIF}
- end;
- function CPU_ExtFeatures: Integer;
- asm
- {$IFDEF TARGET_x86}
- PUSH EBX
- MOV EAX, $80000001
- {$IFDEF FPC}
- CPUID
- {$ELSE}
- DW $A20F // CPUID
- {$ENDIF}
- POP EBX
- MOV EAX,EDX
- {$ENDIF}
- {$IFDEF TARGET_x64}
- PUSH RBX
- MOV EAX, $80000001
- CPUID
- POP RBX
- MOV EAX,EDX
- {$ENDIF}
- end;
- function HasInstructionSet(const InstructionSet: TCPUInstructionSet): Boolean;
- // Must be implemented for each target CPU on which specific functions rely
- begin
- Result := False;
- if not CPUID_Available then Exit; // no CPUID available
- if CPU_Signature shr 8 and $0F < 5 then Exit; // not a Pentium class
- case InstructionSet of
- ci3DNow, ci3DNowExt:
- {$IFNDEF FPC}
- if not CPU_ExtensionsAvailable or (CPU_ExtFeatures and CPUISChecks[InstructionSet] = 0) then
- {$ENDIF}
- Exit;
- ciEMMX:
- begin
- // check for SSE, necessary for Intel CPUs because they don't implement the
- // extended info
- if (CPU_Features and CPUISChecks[ciSSE] = 0) and
- (not CPU_ExtensionsAvailable or (CPU_ExtFeatures and CPUISChecks[ciEMMX] = 0)) then
- Exit;
- end;
- else
- if CPU_Features and CPUISChecks[InstructionSet] = 0 then
- Exit; // return -> instruction set not supported
- end;
- Result := True;
- end;
- {$ELSE}
- function HasInstructionSet(const InstructionSet: TCPUInstructionSet): Boolean;
- begin
- Result := False;
- end;
- {$ENDIF}
- procedure InitCPUFeaturesData;
- var
- I: TCPUInstructionSet;
- begin
- if CPUFeaturesInitialized then Exit;
- CPUFeaturesData := [];
- for I := Low(TCPUInstructionSet) to High(TCPUInstructionSet) do
- if HasInstructionSet(I) then CPUFeaturesData := CPUFeaturesData + [I];
- CPUFeaturesInitialized := True;
- end;
- function CPUFeatures: TCPUFeatures;
- begin
- if not CPUFeaturesInitialized then
- InitCPUFeaturesData;
- Result := CPUFeaturesData;
- end;
- initialization
- InitCPUFeaturesData;
- GlobalPerfTimer := TPerfTimer.Create;
- finalization
- GlobalPerfTimer.Free;
- end.
|