delphi 模仿任务管理器 - 图文

更新时间:2024-03-24 18:06:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

以前,我在delphi的一个网站写过一个帖子,但那个网站的读者群水平太低,基本没有人阅读,因为没有人阅读,所以那个帖子没有

个帖子就是讨论如何计算CPU的各种占有率,下面将那个帖子转帖在这里,帖子很长,耐心读:

就别看。

己没有什么技术,不得用于商业用途,否则老盖找你打官司,可别来找我。

使用未公开的函数 NtQuerySystemInformation 点滴(自己动手写任务管理器)

并增加一些TaskMgr没有的功能) gzgzlxg 2005年4月12日

忘了。该文章将分若干篇来写,这是第一段。

,用SoftIce跟踪 TaskMgr 居然看出点门道来,将这些见解和大家共享,文章可能很长,也可能要花很长的时间,反正爱看就看

提供了相应的 .PDB 和 .DBG文件,使跟踪变的比较容易。本文所有提到的技术都属于微软,我只不过是读懂了然后用Delphi

己写一个任务管理器,从显示到功能和Windows TaskMgr完全一样,包括从注册表中读取Windows TaskMgr的所有启动参数(170

近一个月研究Windows 2000和Windows 2003的任务管理器的体会,研究还没有最后结束,但文章必须先写,否则许多东西不

ystemInformation 是所谓 Undocuments 函数,主要用来获取系统各类信息。Windows 2000的任务管理器 TaskMgr 主要就

取各类信息,如CPU使用率,内核使用率,句柄总数,线程总数,进程总数...等等在任务管理器中的几乎所有信息都是来自该函数

TaskMgr 为什么使用该函数的原因。) 在MSDN知识库中是这样描写该函数的:

subsequent versions. Applications should use the alternate functions listed in this topic.]

但幸运的是,至少在Windows 2003 的任务管理器中仍然是使用该函数来获取系统各类信息的。

下面将具体讲述该函数在Delphi中的使用 1. 函数NtQuerySystemInformation

别的函数完成类似的工作,如PDH,ToolHelp,或读取注册表等方法,各种方法中,应该以使用NtQuerySystemInformation 最好,

SystemInformation is available for use in Windows 2000 and Windows XP. It may be altered or unava

rySystemInformation函数隶属Ntdll.dll,函数的调用非常复杂,有许多入口参数,MSDN知识库中基本都是一带而过,没有具体的说

有任何问题,概不负责。

1.1函数的调用格式:

function NtQuerySystemInformation(

SystemInformationClass: TSystemInformationClass;

{ SystemInformationClass

retrieved.}

pSystemInformation: PVOID; { SystemInformation

是自己具体使用的感受,和网站上一些少的可怜的资料,而这些可怜的资料也都是别人自己的体会,所以难免有错误,因此在具体使

of the values enumerated in SYSTEM_INFORMATION_CLASS, indicating the kind of system information

] Points to a buffer where the requested information is/ to be returned. The size and structure of th

mation varies depending on the value of the SystemInformationClass parameter:}

uSystemInformationLength: ULONG;

{ SystemInformationLength

[in] Size of the buffer pointed to by the SystemInformation parameter, in bytes.}

puReturnLength: PULONG

{ ReturnLength

ptional] Optional pointer to a location where the function writes the actual size of the information reque

size is less than or equal to the SystemInformationLength parameter, the function copies the information

r required to receive the requested information. }

): NTSTATUS; stdcall;

{Return Values

Information buffer; otherwise, it returns an NTSTATUS error code and returns in ReturnLength the size

an NTSTATUS success or error code. The forms and significance of NTSTATUS error codes are listed

s.h header file available in the Windows Device Driver Kit (DDK), and are described in the DDK do

NtQuerySystemInformation call to obtain information about the Cache 's settings and NtSetSystemInformation

under Kernel-Mode Driver Architecture / Design Guide / Driver Programming Techniques / Logging Error

ing information. The working-set information for a process serves as guidelines for NT 's Memory Manage

many pages of/ physical memory should be assigned to the application. Because they are guidelines, c

result such that the Memory Manager grows a working-set to a size greater than the maximum, or sh

siveness, of an application. In the case of CacheSet the application is the file system Cache.}

1.2 参数说明:

NtQuerySystemInformation的调用参数非常多,我这里只列出在TaskMgr中调用的部分。

1.2.1 TSystemInformationClass

TSystemInformationClass有许多类,这里列出的是能够找到的,可能还有一些。

PSystemInformationClass = ^TSystemInformationClass;

_SYSTEM_INFORMATION_CLASS = (

SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation,

SystemPathInformation, SystemProcessInformation, SystemCallCountInformation, SystemConfigurationInformation,

ss than the minimum. However, the settings are factors that will affect the overall allocation, and hence

SystemProcessorPerformanceInformation,

SystemGlobalFlag, SystemCallTimeInformation, SystemModuleInformation, SystemLockInformation, SystemStackTraceInformation, SystemPagedPoolInformation, SystemNonPagedPoolInformation,

SystemHandleInformation, SystemObjectInformation, SystemPageFileInformation, SystemVdmInstemulInformation, SystemVdmBopInformation, SystemFileCacheInformation, SystemPoolTagInformation, SystemInterruptInformation, SystemDpcBehaviorInformation, SystemFullMemoryInformation, SystemLoadGdiDriverInformation, SystemUnloadGdiDriverInformation, SystemTimeAdjustmentInformation, SystemSummaryMemoryInformation, SystemNextEventIdInformation, SystemEventIdsInformation, SystemCrashDumpInformation, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemExtendServiceTableInformation,

SystemPrioritySeperation, SystemPlugPlayBusInformation, SystemDockInformation, SystemPowerInformation, SystemProcessorSpeedInformation, SystemCurrentTimeZoneInformation,

SystemLookasideInformation, SystemSetTimeSlipEvent,

SystemCreateSession, // set mode only SystemDeleteSession, // set mode only SystemInvalidInfoClass1, // invalid info class

SystemRangeStartInformation, // 0x0004 (fails if size != 4)

SystemVerifierInformation,

SystemAddVerifier,

SystemSessionProcessesInformation, // checked build only

MaxSystemInfoClass);

TSystemInformationClass = _SYSTEM_INFORMATION_CLASS;

的途径得到的,所以在网上,你可以见到不同的叫法,我这里列出的命名是我个人认为比较合适的或者说我比较喜欢的。

在TaskMgr中只使用了下面列出的5个,本文将主要介绍这5个类的具体调用。

SystemBasicInformation // 0 SystemPerformanceInformation // 2 SystemProcessInformation // 5 SystemProcessorPerformanceInformation // 8

SystemFileCacheInformation // 21

elphi的枚举类型列出了 SYSTEM_INFORMAION_CLASS,这些命名除了少数在MSDN上有简单的说明外,其余的都是根据使用

有用[0]

板砖[0]

#13楼 得分:0回复于:2008-09-01 14:22:33 1.2.2 SystemInformation 根据 SYSTEM_INFORMAION_CLASS 类,SystemInformation 是相应的结构,下面只列出在TaskMgr中使用构,用Delphi的格式列出: //---------- //对应 SystemBasicInformation 0号调用 PSYSTEM_BASIC_INFORMATION = ^TSystemBasicInformation; _SYSTEM_BASIC_INFORMATION = packed record dwUnknown1: DWORD; //34 uKeMaximumIncrement: ULONG; //一个时钟的计量单位 //30 zlxg 级: XG) uPageSize: ULONG; //一个内存页的大小 //2c uMmNumberOfPhysicalPages: ULONG; //系统管理着多少个页 //28 uMmLowestPhysicalPage: ULONG; //低端内存页 //24 uMmHighestPhysicalPage: ULONG; //高端内存页 //20 uAllocationGranularity: ULONG; //1c pLowestUserAddress: Pointer; //低端用户地址 //18 pMmHighestUserAddress: Pointer; //高端用户地址 //14 uKeActiveProcessors: ULONG; //激活的处理器 //10 bKeNumberProcessors: BYTE; //有多少个处理器 //0c bUnknown2: BYTE; wUnknown3: WORD; end; TSystemBasicInformation = _SYSTEM_BASIC_INFORMATION; SYSTEM_BASIC_INFORMATION = _SYSTEM_BASIC_INFORMATION; //---------- //对应 SystemPerformanceInformation 2号调用 PSYSTEM_PERFORMANCE_INFORMATION = ^TSystemPerformanceInformation; _SYSTEM_PERFORMANCE_INFORMATION = packed record liIdleTime: LARGE_INTEGER; IoReadTransferCount: LARGE_INTEGER; IoWriteTransferCount: LARGE_INTEGER; IoOtherTransferCount: LARGE_INTEGER; IoReadOperationCount: ULONG; IoWriteOperationCount: ULONG; IoOtherOperationCount: ULONG; AvailablePages: ULONG; CommittedPages: ULONG; CommitLimit: ULONG; PeakCommitment: ULONG; PageFaultCount: ULONG; CopyOnWriteCount: ULONG; TransitionCount: ULONG; CacheTransitionCount: ULONG; DemandZeroCount: ULONG; PageReadCount: ULONG; PageReadIoCount: ULONG; CacheReadCount: ULONG;

CacheIoCount: ULONG; DirtyPagesWriteCount: ULONG; DirtyWriteIoCount: ULONG; MappedPagesWriteCount: ULONG; MappedWriteIoCount: ULONG; PagedPoolPages: ULONG; NonPagedPoolPages: ULONG; PagedPoolAllocs: ULONG; PagedPoolFrees: ULONG; NonPagedPoolAllocs: ULONG; NonPagedPoolFrees: ULONG; FreeSystemPtes: ULONG; ResidentSystemCodePage: ULONG; TotalSystemDriverPages: ULONG; TotalSystemCodePages: ULONG; NonPagedPoolLookasideHits: ULONG; PagedPoolLookasideHits: ULONG; Spare3Count: ULONG; ResidentSystemCachePage: ULONG; ResidentPagedPoolPage: ULONG; ResidentSystemDriverPage: ULONG; CcFastReadNoWait: ULONG; CcFastReadWait: ULONG; CcFastReadResourceMiss: ULONG; CcFastReadNotPossible: ULONG; CcFastMdlReadNoWait: ULONG; CcFastMdlReadWait: ULONG; CcFastMdlReadResourceMiss: ULONG; CcFastMdlReadNotPossible: ULONG; CcMapDataNoWait: ULONG; CcMapDataWait: ULONG; CcMapDataNoWaitMiss: ULONG; CcMapDataWaitMiss: ULONG; CcPinMappedDataCount: ULONG; CcPinReadNoWait: ULONG; CcPinReadWait: ULONG; CcPinReadNoWaitMiss: ULONG; CcPinReadWaitMiss: ULONG; CcCopyReadNoWait: ULONG; CcCopyReadWait: ULONG; CcCopyReadNoWaitMiss: ULONG; CcCopyReadWaitMiss: ULONG; CcMdlReadNoWait: ULONG; CcMdlReadWait: ULONG; CcMdlReadNoWaitMiss: ULONG; CcMdlReadWaitMiss: ULONG; CcReadAheadIos: ULONG; CcLazyWriteIos: ULONG; CcLazyWritePages: ULONG; CcDataFlushes: ULONG; CcDataPages: ULONG; ContextSwitches: ULONG; FirstLevelTbFills: ULONG; SecondLevelTbFills: ULONG; SystemCalls: ULONG; end; TSystemPerformanceInformation = _SYSTEM_PERFORMANCE_INFORMATION; SYSTEM_PERFORMANCE_INFORMATION = _SYSTEM_PERFORMANCE_INFORMATION; //---------- PVM_COUNTERS = ^TVmCounters; _VM_COUNTERS = packed record uPeakVirtualSize: ULONG; uVirtualSize: ULONG; uPageFaultCount: ULONG; uPeakWorkingSetSize: ULONG; uWorkingSetSize: ULONG; uQuotaPeakPagedPoolUsage: ULONG; uQuotaPagedPoolUsage: ULONG; uQuotaPeakNonPagedPoolUsage: ULONG; uQuotaNonPagedPoolUsage: ULONG; uPagefileUsage: ULONG; uPeakPagefileUsage: ULONG; end; TVmCounters = _VM_COUNTERS; VM_COUNTERS = _VM_COUNTERS; PIO_COUNTERSEX = ^TIoCountersex; _IO_COUNTERSEX = packed record ReadOperationCount: LARGE_INTEGER; WriteOperationCount: LARGE_INTEGER; OtherOperationCount: LARGE_INTEGER; ReadTransferCount: LARGE_INTEGER; WriteTransferCount: LARGE_INTEGER; OtherTransferCount: LARGE_INTEGER; end; TIoCountersex = _IO_COUNTERSEX; IO_COUNTERSEX = _IO_COUNTERSEX; PSYSTEM_THREAD_INFORMATION = ^TSystemThreadInfo; _SYSTEM_THREAD_INFORMATION = packed record KernelTime: LARGE_INTEGER; // 100 nsec units //$000 UserTime: LARGE_INTEGER; // 100 nsec units //$008 CreateTime: LARGE_INTEGER; // relative to 01-01-1601 //$010 WaitTime: DWORD; //$018 pStartAddress: PVOID; //$01C Cid: CLIENT_ID; // process/thread ids //$020 Priority: DWORD; //$028 BasePriority: DWORD; //$02C ContextSwitches: DWORD; //$030 ThreadState: DWORD; // 2=running, 5=waiting //$034 WaitReason: DWORD; //KWAIT_REASON; //$038 uReserved01: DWORD; //$03C end; //$040 TSystemThreadInfo = _SYSTEM_THREAD_INFORMATION; SYSTEM_THREAD_INFORMATION = _SYSTEM_THREAD_INFORMATION; PSYSTEM_PROCESS = ^TSystemProcess; _SYSTEM_PROCESS = packed record // common members uNext: DWORD; // relative offset //$000 ThreadCount: DWORD; //$004 Reserved01: LARGE_INTEGER; //$008 Reserved02: LARGE_INTEGER; //$010 Reserved03: LARGE_INTEGER; //$018 CreateTime: LARGE_INTEGER; // relative to 01-01-1601 //$020 UserTime: LARGE_INTEGER; // 100 nsec units //$028 KernelTime: LARGE_INTEGER; // 100 nsec units //$030 usName: UNICODE_STRING; //$038 BasePriority: DWORD; //KPRIORITY; //$040 UniqueProcessId: DWORD; //$044 InheritedFromUniqueProcessId: DWORD; //$048 HandleCount: DWORD; //$04C SessionId: DWORD; //$050 W2K Only Reserved08: DWORD; //$054 VmCounters: VM_COUNTERS; // see ntddk.h //$058 CommitCharge: DWORD; // bytes //$084 end; //$088 TSystemProcess = _SYSTEM_PROCESS; SYSTEM_PROCESS = _SYSTEM_PROCESS; PSYSTEM_PROCESS_NT4 = ^TSystemProcessNt4; _SYSTEM_PROCESS_NT4 = packed record // Windows NT 4.0 Process: SYSTEM_PROCESS; // common members //$000 Threads: SYSTEM_THREAD_INFORMATION; // thread array //$088 end; //$088 TSystemProcessNt4 = _SYSTEM_PROCESS_NT4; SYSTEM_PROCESS_NT4 = _SYSTEM_PROCESS_NT4; PSYSTEM_PROCESS_NT5 = ^TSystemProcessNt5; _SYSTEM_PROCESS_NT5 = packed record // Windows 2000 Process: SYSTEM_PROCESS; // common members //$000 IoCounters: IO_COUNTERSEX; // see ntddk.h //$088 aThreads: SYSTEM_THREAD_INFORMATION; // thread array //$0B8 end; //$0B8 TSystemProcessNt5 = _SYSTEM_PROCESS_NT5; SYSTEM_PROCESS_NT5 = _SYSTEM_PROCESS_NT5; //对应 SystemProcessInformation 5号调用 PSYSTEM_PROCESS_INFORMATION = ^TSystemProcessInformation; _SYSTEM_PROCESS_INFORMATION = packed record case Integer of 0: (Process_NT4: SYSTEM_PROCESS_NT4); 1: (Process_NT5: SYSTEM_PROCESS_NT5); end; TSystemProcessInformation = _SYSTEM_PROCESS_INFORMATION; SYSTEM_PROCESS_INFORMATION = _SYSTEM_PROCESS_INFORMATION; 对我有用[0] 丢个板砖[0] 引用 举报 管理 TOP #14楼 得分:0回复于:2008-09-01 14:23:18 //---------- //对应 SystemProcessorPerformanceInformation 8号调用 _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = packed record IdleTime: LARGE_INTEGER; KernelTime: LARGE_INTEGER; UserTime: LARGE_INTEGER; DpcTime: LARGE_INTEGER; InterruptTime: LARGE_INTEGER; InterruptCount: DWORD; dwUnknown1: DWORD; end; zlxg 级: XG) PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = ^TSystemProcessorPerformanceInformati TSystemProcessorPerformanceInformation = _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATIOTION; //---------- // 对应 SystemFileCacheInformation 21号调用 PSYSTEM_CACHE_INFORMATION = ^TSystemCacheInformation; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = _SYSTEM_PROCESSOR_PERFORMANCE_I

_SYSTEM_CACHE_INFORMATION = packed record uFileCache: ULONG; // bytes uFileCachePeak: ULONG; // bytes PageFaultCount: ULONG; MinimumWorkingSet: ULONG; MaximumWorkingSet: ULONG; TransitionSharedPages: ULONG; TransitionSharedPagesPeak: ULONG; Reserved: array[0..1] of ULONG; end; TSystemCacheInformation = _SYSTEM_CACHE_INFORMATION; SYSTEM_CACHE_INFORMATION = _SYSTEM_CACHE_INFORMATION; 2. 任务管理器――》性能 在讲述性能前先大致描述任务管理器的三大部分。 和【进程】,【性能】中除了CPU使用率以外,其余的数据都是由进程模块顺便取得的。 任务管理器由【性能】、【进程】、【应用程序】三大部分组成。其实这三大部分是有机的联系在一起的,尤其 TaskMgr可能是一个叫David的人主持开发的,程序启动初始化的时候,将系统的 Button Class 类的Wnd用指向自己(DavesFrameWndProc),将类名改为DavesFrameClass,保存原来的地址,在处理完DavesFrameWndple、Banana、Peach、Pear。 2.1 获取CPU、内核、内存使用率、: 得 CPU、内核使用率,SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 的结构如下: _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = packed record IdleTime: LARGE_INTEGER; KernelTime: LARGE_INTEGER; UserTime: LARGE_INTEGER; DpcTime: LARGE_INTEGER; InterruptTime: LARGE_INTEGER; InterruptCount: DWORD; dwUnknown1: DWORD; end; 息后调用原来的过程,也就是所谓的钩子。David也许很喜欢各类水果,程序中有四个菜单是用水果来命名的,分别 TaskMge 通过 NtQuerySystemInformation 的SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = ^TSystemProcessorPerformanceInformati TSystemProcessorPerformanceInformation = _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATIOTION; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = _SYSTEM_PROCESSOR_PERFORMANCE_I这个结构为48个字节,当调用 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 时,返回的结果为 字节,WINDOWS 操作系统最多允许配置 32 颗 CPU,所以返回的结果存放了 32 颗CPU的运行状态U占48个字节,头尾相连。我见过许多文章都使用这个调用或部分的使用这个调用获取 CPU使用率,但都没有个调用的返回结果的长度,幸亏 WINDOWS 操作系统往往在一个新区域分配内存,所以即使你只申请了48个时都会发生系统崩溃的致命错误。 内存使用率是通过 SYSTEM_PERFORMANCE_INFORMATION 调用获得。 计算公式如下: 存来存放返回结果,在许多情况下不至于因为返回结果太长而覆盖了程序代码或其他的数据,但这确实是一个大的 CpuUsage = (IdleTime - PreviousCPUIdleTime) / (UserTime + KernelTime - PreviousCPUToreviousCPUTotalTime); 其中: IdleTime = TSystemProcessorPerformanceInformation.IdleTime; // CPU 空闲时间 UserTime = TSystemProcessorPerformanceInformation.UserTime; // CPU 使用时间 KernelTime = TSystemProcessorPerformanceInformation.KernelTime; // 内核使用时间 PreviousCPUIdleTime = IdleTime; //上一次 CPU 空闲时间 PreviousCPUTotalTime = (UserTime + KernelTime); //上一次 CPU 总使用时间 PreviousCPUKernelTime = (KernelTime - IdleTime); //上一次内核时间 叫人产生误解。似乎应该取这样的名字比较合适:KernelAndIdle_Time; KernelUsage = (KernelTime - IdleTime - PreviousCPUKernelTime) / (UserTime + KernelTim从上面的计算公式可以看出 TSystemProcessorPerformanceInformation.KernelTime 其实是 内核+空闲,这个命下面是具体程序实现,这个程序完全是模仿 TaskMgr 写的,版权属于微软,这里只是从技术角度来研究,请不其余部分将在后面阐明。 CalcCPUTime的命名也是微软的版权; 业用途。当然你硬要用,我也没有办法,但我声明了,我就推卸责任了,这也是跟微软学的。这里只列出了获取CPUTaskMgr 在初始化过程时根据 CPU的个数,为每个 CPU 使用率和内核使用率各自固定分配了8000个字节放CPU和内核使用率的历史记录。每个新产生的使用率总是放在首位,然后利用memmove函数将历史记录向后移我采用了略微不同的方法,我建立了一个记录,并在记录中设立了记录长度,位置,和记录数三个参数。根据CPUtype UsageRecord = packed record uLength: Word; //记录的长度 Position: Word; //当前指针位置 ReNo: Word; //现在已经有的记录数 Usages: array of Word; // 使用率 动态数组根据绘图需要分配长度。 end; var SysBaseInfo: TSystemBasicInformation; 绘图需要的记录长度动态的分配内存,并且也避免了每次使用memmove来移动记录,而只是移动记录的指针 SysProcPerfInfo: array[0..31] of TSystemProcessorPerformanceInformation; SysPerfInfo: TSystemPerformanceInformation; PreviousCPUIdleTime: array[0..31] of LARGE_INTEGER; PreviousCPUTotalTime: array[0..31] of LARGE_INTEGER; PreviousCPUKernelTime: array[0..31] of LARGE_INTEGER; CPUUsage: DWORD; KernelUsage: DWORD; MEMUsage: DWORD; CPUHistory: array of UsageRecord; KernelHistory: array of UsageRecord; 对我有用[0] 丢个板砖[0] 引用 举报 管理 TOP #15楼 得分:0回复于:2008-09-01 14:23:51 procedure TFormMainWin.CalcCPUTime; var status: NTSTATUS; SumCPUIdleTime: LARGE_INTEGER; SumCPUTotalTime: LARGE_INTEGER; SumCPUKernelTime: LARGE_INTEGER; tmpCPUIdleTime: LARGE_INTEGER; tmpCPUKernelTime: LARGE_INTEGER; tmpCPUTotalTime: LARGE_INTEGER; I: DWORD; begin //一次读取32颗CPU的数据,不管你实际安装了几颗CPU。 SizeOf(TSystemProcessorPerformanceInformation) * 32, nil); zlxg 级: XG) Status := NtQuerySystemInformation(SystemProcessorPerformanceInformation, @sysprocperfInfo, //如果 Status不等于零,发生错误,退出,这里非常奇怪,为什么不显示错误信息?例如相这样加一句 //if status <> 0 then // mtConfirmation, [mbYes, mbNo], 0) = mrYes then // Exit; // 其中 GetNtstatus(Status) 是将返回的错误号转换成错误解释 // 既然原程序不做处理,我们也不做处理,忠于原作。 if status <> 0 then Exit; I := 0; SumCPUIdleTime.QuadPart := 0; SumCPUKernelTime.QuadPart := 0; SumCPUTotalTime.QuadPart := 0; // 循环体,遍历每一个 CPU,如果有这么多 repeat with SysProcPerfInfo[I] do begin //计算每一颗CPU 空闲时间 tmpCPUIdleTime.QuadPart := (IdleTime.QuadPart - PreviousCPUIdleTime[I].QuadPart); //计算每一颗CPU 总使用时间 (空闲+内核+使用) adPart; //计算每一颗 CPU 内核使用时间 uadPart; //所有CPU 空闲时间 Sum(0..CPU个数)(空闲时间) SumCPUIdleTime.QuadPart := SumCPUIdleTime.QuadPart + tmpCPUIdleTime.QuadPart; //所有CPU 总使用时间 Sum(0..CPU个数)(空闲+内核+使用) //所有 CPU 内核使用时间 Sum(0..CPU个数)(内核使用时间) //保存 CPU 空闲时间 PreviousCPUIdleTime[I].QuadPart := IdleTime.QuadPart; //保存 CPU 总使用时间 PreviousCPUTotalTime[I].QuadPart := (UserTime.QuadPart + KernelTime.QuadPart); //保存 CPU 内核使用时间 PreviousCPUKernelTime[I].QuadPart := KernelTime.QuadPart - IdleTime.QuadPart; end; // if MessageDlg( 'NtQuerySystemInformation ' + GetNTSTATUS(Status) + ' Exit now? tmpCPUTotalTime.QuadPart := (UserTime.QuadPart + KernelTime.QuadPart) - PreviousCPUTotalT tmpCPUKernelTime.QuadPart := (KernelTime.QuadPart - IdleTime.QuadPart) - PreviousCPUKernel SumCPUTotalTime.QuadPart := SumCPUTotalTime.QuadPart + tmpCPUTotalTime.QuadPart; SumCPUKernelTime.QuadPart := SumCPUKernelTime.QuadPart + tmpCPUKernelTime.QuadPar //这段程序如果用Delphi实现编译后代码太长,因为任务管理器是实时采集CPU数据,程序应尽可能简练 //所以保留了原TaskMgr的处理方法,这里采用了汇编语言来实现; asm MOV EAX, tmpCPUTotalTime.LowPart MOV EDX, tmpCPUTotalTime.HighPart OR EAX, EDX JE @@exit //计算CPU使用百分比 //入口参数 PUSH 0 //乘数的高位 PUSH $00000064 //乘数的低位 $64=100 PUSH tmpCPUIdleTime.HighPart //被乘数高位 PUSH tmpCPUIdleTime.LowPart //被乘数低位 PUSH tmpCPUTotalTime.HighPart //除数高位 PUSH tmpCPUTotalTime.LowPart //除数低位 PUSH EDX //被除数高位 _allmul的返回结果高位 PUSH EAX //被除数低位 _allmul的返回结果低位 XOR EDX, EDX MOV DL, $64 SUB DL, AL //CpuUsage = 100 - AL (_alldiv返回的结果) PUSH EDX POP CpuUsage //CpuUsage 百分数 //计算内核使用百分比和上面的类同 PUSH $00000000 PUSH $00000064 PUSH tmpCPUKernelTime.HighPart PUSH tmpCPUKernelTime.LowPart CALL _allmul PUSH tmpCPUTotalTime.HighPart PUSH tmpCPUTotalTime.LowPart PUSH EDX PUSH EAX CALL _alldiv XOR EDX, EDX MOV DL, $64 CALL _allmul //_allmul 用于处理LARGE_INTEGER 的乘法函数,在ntdll CALL _alldiv //_alldiv 用于处理 LARGE_INTEGER 的除法函数,在ntdl

SUB DL, AL PUSH EDX POP KernelUsage @@exit: end; //保存CPU使用率,并移记录指针 if CPUHistory[i].Position = CPUHistory[i].uLength then CPUHistory[i].Position := 0 else inc(CPUHistory[i].Position); CPUHistory[i].Usages[CPUHistory[i].Position] := CPUUsage; if CPUHistory[i].ReNo < CPUHistory[i].uLength then inc(CPUHistory[i].ReNo); //保存内核使用率,并移动记录指针 if KernelHistory[i].Position = KernelHistory[i].uLength then KernelHistory[i].Position := 0 else inc(KernelHistory[i].Position); KernelHistory[i].Usages[KernelHistory[i].Position] := KernelUsage; if KernelHistory[i].ReNo < KernelHistory[i].uLength then inc(KernelHistory[i].ReNo); //CPU的个数加一 inc(I); //Processors 是系统CPU的个数,在前面初始化单元中通过调用NtQuerySystemInformation的 //SYSTEM_BASES_INFORMATION功能获得 //遍历每一颗CPU until I > = Processors; //下面是计算所有CPU的平均(总)使用率,使用方法和上面相同。 I := Processors - 1; asm MOV EAX, SumCPUTotalTime.LowPart MOV EDX, SumCPUTotalTime.HighPart OR EAX, EDX JE @@exit PUSH I PUSH $00000064 PUSH SumCPUIdleTime.HighPart PUSH SumCPUIdleTime.LowPart CALL _allmul PUSH SumCPUTotalTime.HighPart PUSH SumCPUTotalTime.LowPart PUSH EDX PUSH EAX CALL _alldiv XOR EDX, EDX MOV DL, $64 SUB DL, AL PUSH EDX POP CpuUsage PUSH $00000000 PUSH $00000064 PUSH SumCPUKernelTime.HighPart PUSH SumCPUKernelTime.LowPart CALL _allmul PUSH SumCPUTotalTime.HighPart PUSH SumCPUTotalTime.LowPart PUSH EDX PUSH EAX CALL _alldiv XOR EDX, EDX MOV DL, $64 SUB DL, AL PUSH EDX POP KernelUsage @@exit: end; //这里开始计算内存使用率 mation), nil); if status <> 0 then Exit; // PageSize 页面大小是在前面初始化单元中通过调用NtQuerySystemInformation的 //SYSTEM_BASES_INFORMATION功能获得, //内存使用率 = (页面大小 / 1024) * CommittedPages MEMUsage := (PageSize shr 10) * SysPerfInfo.CommittedPages; status := NtQuerySystemInformation(SystemPerformanceInformation, @SysPerfInfo, SizeOf(TSystemPerform //保存内存使用率,并移动记录指针 if MEMHistory.Position = MEMHistory.uLength then MEMHistory.Position := 0 else inc(MEMHistory.Position); MEMHistory.Usages[MEMHistory.Position] := tmpMem; if MEMHistory.ReNo < MEMHistory.uLength then inc(MEMHistory.ReNo); end; 分,随着讨论问题的深入,或许会修正一些地方,后面就不在特别说明了。 2、因为是一边写一边帖(包括程序),所以会很慢,大家给点耐性。 下一段将讨论如何取得性能中的其他数据: 分页数、未分页。 注:1、这些程序在后面出现时也许会有不同,因为这些程序都是在写这篇东西时根据需要而写的,并不是完整程序句柄数、线程数、进程数、物理内存总数、可用数系统缓存、认可用量总数、限制、峰值、核心内存总数、分页数、另外,这些程序在我的文档中排列是非常整齐的,不知为什么一贴上来就乱七八糟了,这可不是我的错。2.2 获取 句柄数、线程数、进程数、物理内存总数、可用数,系统缓存、认可用量总数、限制、峰值、核心内 TaskMgr 调用 NtQuerySystemInformation 的 SystemProcessInformation Class类 通过结构 SYSTEM版本的结构,随着Windows的升级,结构会不断的发生变化。 SS_INFORMATION 返回结果,SYSTEM_PROCESS_INFORMATION 的结构如上显示,非常复杂,我在上面列 SystemProcessInformation 的具体调用和上面讨论的 SystemProcessorPerformanceInformation 有异曲同工之 SYSTEM_PROCESS_INFORMATION 结构的简化表示如下: 为复杂,下面我们分析一下 SYSTEM_PROCESS_INFORMATION 的结构,我们略去第四版,从第五版讨 对我有用[0] 丢个板砖[0] 引用 举报 管理 TOP #16楼 得分:0回复于:2008-09-01 14:24:17 zlxg XG) 级: PSYSTEM_PROCESS_INFORMATION = ^TSystemProcessInformation; _SYSTEM_PROCESS_INFORMATION = packed record Process: SYSTEM_PROCESS; // common members //$000 IoCounters: IO_COUNTERSEX; // see ntddk.h //$088 aThreads: SYSTEM_THREAD_INFORMATION; // thread array //$0B8 end; //$0B8 TSystemProcessInformation = _SYSTEM_PROCESS_INFORMATION; SYSTEM_PROCESS_INFORMATION = _SYSTEM_PROCESS_INFORMATION; 和aThreads,其中 aThreads,的声明其实不太正确,正确的应该如下: aThreads: array[0..0] of SYSTEM_THREAD_INFORMATION; 或 aThreads: array of SYSTEM_THREAD_INFORMATION; 所以才有这样的结果。 决于系统有多少进程,每个进程有多少线程。 Undocuments 就把你搞晕了。 当中去掉了第四版的声明,其中Process: SYSTEM_PROCESS 是最早版的结构,后来不断的扩充,增加了 Io既是一个动态结构,为什么改成现在这样,主要是因为在计算结构长度时 Delpyi 的 SizeOf 不能返回动态结构 从上面的对athreads的声明,可以看出,SYSTEM_PROCESS_INFORMATION 是一个不定长的结构,它的具 我在网上查阅资料时,发现所有使用这个结构的应用,都没有正确的调用这个结构,原因是什么,老盖真厉害 因为这个调用返回结果长度是不可确定的,按正常的调用,将在程序中造成一个大的 Bug,调用返回的结果有 返回结果的结构大致如下: 第一个进程: TSystemProcessInformation.Process.Next; //下一个记录的偏移量 ... ... 第一个进程的第一个线程: TSystemProcessInformation.aThreads. .... .... 第二个进程: TSystemProcessInformation.Process.Next; 第二个进程的第一个线程: TSystemProcessInformation.aThreads. ... ... 你的程序代码区,你的堆栈区,你的数据区,引发系统崩溃,其危险性更胜前一个,所以它的调用要采取特殊的 第N个进程: TSystemProcessInformation.aThreads. ... ... 第N个进程的第一个线程: TSystemProcessInformation.aThreads. ... ... 最后一个进程: TSystemProcessInformation.aThreads. ... ... 最后一个的第一个线程: TSystemProcessInformation.aThreads. ... ... 结束。 现在一切都明了了,我想大部分的人都会完成这个调用了,自己动手写一个试试。注意:将记录放在那里,弄不好程序覆盖了。 要知后事如何,请看下回分解。看看你写的对不对。

本文来源:https://www.bwwdw.com/article/jl68.html

Top