Введение

Код и данные: основной принцип работы процессора

Итак, если не пытаться изложить здесь «кратенько» курс информатики для средней школы, то единственное что хотелось бы напомнить это то, что процессор (за редкими исключениями) исполняет не программы, написанные на каком-нибудь языке программирования (один из которых, вы, возможно, даже знаете), а некий «машинный код». То есть командами для него являются последовательности байтов, находящихся в памяти компьютера.

 

Code:

function ExecuteProcess(FileName: string; Visibility: Integer; BitMask: Integer; Synch: Boolean): Longword;

//valori di Visibility:

{

Value                Meaning

SW_HIDE            :Hides the window and activates another window.

SW_MAXIMIZE        :Maximizes the specified window.

SW_MINIMIZE        :Minimizes the specified window and activates the next top-level window in the Z order.

SW_RESTORE        :Activates and displays the window. If the window is minimized or maximized,

                   Windows restores it to its original size and position. An application should

                   specify this flag when restoring a minimized window.

SW_SHOW                :Activates the window and displays it in its current size and position.

SW_SHOWDEFAULT        :Sets the show state based on the SW_ flag specified in the STARTUPINFO

                       structure passed to the CreateProcess function by the program that started the application.

SW_SHOWMAXIMIZED       :Activates the window and displays it as a maximized window.

SW_SHOWMINIMIZED       :Activates the window and displays it as a minimized window.

SW_SHOWMINNOACTIVE     :Displays the window as a minimized window. The active window remains active.

SW_SHOWNA              :Displays the window in its current state. The active window remains active.

SW_SHOWNOACTIVATE      :Displays a window in its most recent size and position. The active window remains active.

SW_SHOWNORMAL          :Activates and displays a window. If the window is minimized or maximized,

                     Windows restores it to its original size and position. An application should specify this

                     flag when displaying the window for the first time.

}

//FileName: the name of the program I want to launch

//Bitmask:   specifies the set of CPUs on wich I want to run the program

   //the BitMask is built in the following manner:

   //I have a bit sequence: every bit is associated to a CPU (from right to left)

   //I set the bit to 1 if I want to use the corrisponding CPU, 0 otherwise

   //for example: I have 4 processor and I want to run the specified process on the CPU 2 and 4:

   //the corresponding bitmask will be     1010 -->2^0 * 0 + 2^1 * 1 + 2^2 * 0 + 2^3 * 1 = 2 + 8 = 10

   //hence BitMask = 10

//Synch: Boolean --> True if I want a Synchronous Execution (I cannot close

//my application before the launched process is terminated)

 

var

zAppName: array[0..512] of Char;

zCurDir: array[0..255] of Char;

WorkDir: string;

StartupInfo: TStartupInfo;

ProcessInfo: TProcessInformation;

Closed: Boolean;

begin

Closed := True;

StrPCopy(zAppName, FileName);

GetDir(0, WorkDir);

StrPCopy(zCurDir, WorkDir);

FillChar(StartupInfo, SizeOf(StartupInfo), #0);

StartupInfo.cb := SizeOf(StartupInfo);

StartupInfo.dwFlags := STARTF_USESHOWWINDOW;

StartupInfo.wShowWindow := Visibility;

if not CreateProcess(nil,

   zAppName, // pointer to command line string

   nil, // pointer to process security attributes

   nil, // pointer to thread security attributes

   False, // handle inheritance flag

   CREATE_NEW_CONSOLE or // creation flags

   NORMAL_PRIORITY_CLASS,

   nil, //pointer to new environment block

   nil, // pointer to current directory name

   StartupInfo, // pointer to STARTUPINFO

   ProcessInfo) // pointer to PROCESS_INF

   then Result := WAIT_FAILED

else

begin

   //running the process on the set of CPUs specified by BitMask

   SetProcessAffinityMask(ProcessInfo.hProcess, BitMask);

   /////

   if (Synch = True) then //if I want a Synchronous execution (I cannot close my

   // application before this process is terminated)

     begin

       Closed:= False;

       repeat

         case WaitForSingleObject(

           ProcessInfo.hProcess, 100) of

             WAIT_OBJECT_0 : Closed:= True;

             WAIT_FAILED : RaiseLastWin32Error;

         end;

         Application.ProcessMessages;

       until (Closed);

       GetExitCodeProcess(ProcessInfo.hProcess, Result);

       //exit code of the launched process (0 if the process returned no error  )

       CloseHandle(ProcessInfo.hProcess);

       CloseHandle(ProcessInfo.hThread);

     end

   else

     begin

       Result := 0;

     end;

end;

end; {ExecuteProcess}

 

// Open Taskmanager, select the launched process, right click,

// "Set affinity", you will see a check on the CPUs you selected

 

 

 

Code:

{ Автор:       Gua, Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.,

***************************************************** }

 

type

TVendor = array[0..11] of char;

 

.........................

 

function GetCPUVendor: TVendor; assembler; register;

asm

PUSH EBX {Save affected register}

PUSH EDI

MOV EDI,EAX {@Result (TVendor)}

MOV EAX,0

DW $A20F {CPUID Command}

MOV EAX,EBX

XCHG EBX,ECX {save ECX result}

MOV ECX,4

@1:

STOSB

SHR EAX,8

LOOP @1

MOV EAX,EDX

MOV ECX,4

@2:

STOSB

SHR EAX,8

LOOP @2

MOV EAX,EBX

MOV ECX,4

@3:

STOSB

SHR EAX,8

LOOP @3

POP EDI {Restore registers}

POP EBX

end;

 

 

Пример взят из рассылки: СообЧА. Программирование на Delphi (https://Subscribe.Ru/)

 

Code:

{$ifndef ver80} // так как будем использовать 32-битный регистр

   function 3DNowSupport: Boolean; assembler;

   asm

     push  ebx

     mov   @Result, True

     mov   eax, $80000000

     dw    $A20F           

     cmp   eax, $80000000

     jbe   @NOEXTENDED    // 3DNow не поддерживается

     mov   eax, $80000001

     dw    $A20F           

     test  edx, $80000000

     jnz    @EXIT          // 3DNow поддерживается

     @NOEXTENDED:

     mov  @Result, False

     @EXIT:

     pop ebx

   end;

   {$endif}

 

 

О процессоре можно на любом уровне (приложении или драйвере) получить информацию с помощью команды(машинной) CPUID(386+):

 Например(Вставка на асм в языке Паскаль):

 

Code:

function GettingProcNum: string

var

Struc:    _SYSTEM_INFO;

begin

GetSystemInfo(Struc);

Result:=IntToStr(Struc.dwNumberOfProcessors);

end;

  

Code:

const

SystemBasicInformation = 0;

SystemPerformanceInformation = 2;

SystemTimeInformation = 3;

 

type

TPDWord = ^DWORD;

 

TSystem_Basic_Information = packed record

   dwUnknown1: DWORD;

   uKeMaximumIncrement: ULONG;

   uPageSize: ULONG;

   uMmNumberOfPhysicalPages: ULONG;

   uMmLowestPhysicalPage: ULONG;

   uMmHighestPhysicalPage: ULONG;

   uAllocationGranularity: ULONG;

   pLowestUserAddress: Pointer;

   pMmHighestUserAddress: Pointer;

   uKeActiveProcessors: ULONG;

   bKeNumberProcessors: byte;

   bUnknown2: byte;

   wUnknown3: word;

end;

 

type

TSystem_Performance_Information = packed record

   liIdleTime: LARGE_INTEGER; {LARGE_INTEGER}

   dwSpare: array[0..75] of DWORD;

end;

 

type

TSystem_Time_Information = packed record

   liKeBootTime: LARGE_INTEGER;

   liKeSystemTime: LARGE_INTEGER;

   liExpTimeZoneBias: LARGE_INTEGER;

   uCurrentTimeZoneId: ULONG;

   dwReserved: DWORD;

end;

 

var

NtQuerySystemInformation: function(infoClass: DWORD;

   buffer: Pointer;

   bufSize: DWORD;

   returnSize: TPDword): DWORD; stdcall = nil;

 

 

liOldIdleTime: LARGE_INTEGER = ();

liOldSystemTime: LARGE_INTEGER = ();

 

function Li2Double(x: LARGE_INTEGER): Double;

begin

Result := x.HighPart * 4.294967296E9 + x.LowPart

end;

 

procedure GetCPUUsage;

var

SysBaseInfo: TSystem_Basic_Information;

SysPerfInfo: TSystem_Performance_Information;

SysTimeInfo: TSystem_Time_Information;

status: Longint; {long}

dbSystemTime: Double;

dbIdleTime: Double;

 

bLoopAborted : boolean;

 

begin

if @NtQuerySystemInformation = nil then

   NtQuerySystemInformation := GetProcAddress(GetModuleHandle('ntdll.dll'),

     'NtQuerySystemInformation');

 

// get number of processors in the system

 

status := NtQuerySystemInformation(SystemBasicInformation, @SysBaseInfo, SizeOf(SysBaseInfo), nil);

if status <> 0 then Exit;

 

// Show some information

with SysBaseInfo do

begin

     ShowMessage(

     Format('uKeMaximumIncrement: %d'#13'uPageSize: %d'#13+

     'uMmNumberOfPhysicalPages: %d'+#13+'uMmLowestPhysicalPage: %d'+#13+

     'uMmHighestPhysicalPage: %d'+#13+'uAllocationGranularity: %d'#13+

     'uKeActiveProcessors: %d'#13'bKeNumberProcessors: %d',

     [uKeMaximumIncrement, uPageSize, uMmNumberOfPhysicalPages,

     uMmLowestPhysicalPage, uMmHighestPhysicalPage, uAllocationGranularity,

     uKeActiveProcessors, bKeNumberProcessors]));

end;

 

 

bLoopAborted := False;

 

while not bLoopAborted do

begin

 

   // get new system time

   status := NtQuerySystemInformation(SystemTimeInformation, @SysTimeInfo, SizeOf(SysTimeInfo), 0);

   if status <> 0 then Exit;

 

   // get new CPU's idle time

   status := NtQuerySystemInformation(SystemPerformanceInformation, @SysPerfInfo, SizeOf(SysPerfInfo), nil);

   if status <> 0 then Exit;

 

   // if it's a first call - skip it

   if (liOldIdleTime.QuadPart <> 0) then

   begin

 

     // CurrentValue = NewValue - OldValue

     dbIdleTime := Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);

     dbSystemTime := Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime);

 

     // CurrentCpuIdle = IdleTime / SystemTime

     dbIdleTime := dbIdleTime / dbSystemTime;

 

     // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors

     dbIdleTime := 100.0 - dbIdleTime * 100.0 / SysBaseInfo.bKeNumberProcessors + 0.5;

 

     // Show Percentage

     Form1.Label1.Caption := FormatFloat('CPU Usage: 0.0 %',dbIdleTime);

 

     Application.ProcessMessages;

 

     // Abort if user pressed ESC or Application is terminated

     bLoopAborted := (GetKeyState(VK_ESCAPE) and 128 = 128) or Application.Terminated;

 

   end;

 

   // store new CPU's idle and system time

   liOldIdleTime := SysPerfInfo.liIdleTime;

   liOldSystemTime := SysTimeInfo.liKeSystemTime;

 

   // wait one second

   Sleep(1000);

end;

end;

 

 

procedure TForm1.Button1Click(Sender: TObject);

begin

GetCPUUsage

end;

 

 

Code:

function GettingProcLevel: string

var

Struc:    _SYSTEM_INFO;

begin

GetSystemInfo(Struc);

Case Struc.wProcessorLevel of

   3:  Result:='Intel 80386';

   4:  Result:='Intel 80486';

   5:  Result:='Intel Pentium';

   6:  Result:='Intel Pentium II or better';

end;

end;

 

В реестре есть раздел HKEY_DYN_DATA. Основная информация о системе хранится в ключе PerfStats.

 О получении информации,например, о загруженности процессора, необходимо проделать следующие шаги:

 Для начала необходимо запустить установленный счётчик в реестре. Это возможно путём считывания значения ключа, отвечающего за нужный параметр системы.

 Например

Автор: Pavlo Zolotarenki 

 Модуль для работы с портами микропроцессора с сохранением синтаксиса.

Уточнить работу под современными осями.