显示 cpu 使用率


看到 yrt888 提出的问题,抽空研究了一下,发现其实并不像网上那些示例写的,计算其实很简单,只要使用 SystemProcessorPerformanceInformation 参数反复调用 NtQuerySystemInformation,然后根据返回的 IdleTime, KernelTime, UserTime 值,分别用后一次调用取得的值减去前一次调用取得的值,得到各增量值,之后一个除法就得到使用率了。这里唯一要注意的就是 KernelTime 成员的值包含了 IdleTime 和核心调用使用时间。另外发现当使用 SystemBasicInformation 调用 NtQuerySystemInformation 来试图获取 cpu 个数时会失败,返回 0xC0000004 错误码,好在还有 GetSystemInfo 这个 api 可以用来查出 cpu 的个数。所以下面的示例中核心的部分只有一个方法,就是 getCpuTimeInfo,其它只是用来显示使用率的 GUI 界面设计。这个示例对系统安装的每个 cpu 分别使用一个自定义容器来显示使用率图像/数据,不过我们通常只有一个 cpu,而且即使有双核,一般的软件也只能使用到其中的一个,不过印象中有些影片编辑软件可以使用多处理器,例如像“小日本”。

示例代码只在 Windows2003+vfp9 上测试,其他环境未测试。

  1. public oForm
  2. oForm = newobject("myform")
  3. oForm.show
  4. define class myform as form
  5.   top = 0
  6.   left = 0
  7.   height = 200
  8.   width = 100
  9.   showwindow = 2
  10.   showintaskbar = .f.
  11.   caption = "CPU Usage"
  12.   alwaysontop = .t.
  13.   allowoutput = .f.
  14.   maxbutton = .f.
  15.   minbutton = .f.
  16.   name = "form1"
  17.   cpu_nums = 0              && 系统拥有的 cpu 个数
  18.   dimension aCpuInfo[1,4]       && 1/2/3/4 - t_idle / t_kernel / t_user / usage
  19.   procedure updateUsage         && 获取最新的 cpu 使用率信息
  20.     local array laTemp[1]
  21.     local liIdleTime, liKernelTime, liUserTime, lnUsage, loUsage
  22.     acopy( this.aCpuInfo, m.laTemp )
  23.     this.getCpuTimeInfo()
  24.     for m.ii = 1 to this.cpu_nums
  25.       m.liIdleTime  = m.laTemp[m.ii,1]
  26.       m.liKernelTime    = m.laTemp[m.ii,2]
  27.       m.liUserTime  = m.laTemp[m.ii,3]
  28.       m.lnUsage = ;
  29.         ( this.aCpuInfo[m.ii,1] - m.liIdletime ) / ;
  30.         ( this.aCpuInfo[m.ii,2] + this.aCpuInfo[m.ii,3] ;
  31.         - m.liKernelTime - m.liUserTime )
  32.       this.aCpuInfo[m.ii,4] = ( 1.00 - m.lnUsage )          && * 100
  33.       m.loUsage = evaluate( 'this.cntUsage' +  transform(m.ii))
  34.       m.loUsage.value = this.aCpuInfo[m.ii,4]
  35.     endfor
  36.   endproc
  37.   procedure getCpuTimeInfo      && 获取最新的 cpu 空闲/核心/用户用时信息
  38.     #define SystemProcessorPerformanceInformation   8
  39.     local liSize, lcBuff, liBase, ii
  40.     m.liSize = 48 * this.cpu_nums
  41.     m.lcBuff = replicate( chr(0), m.liSize )
  42.     if ( 0 != NtQuerySystemInformation( ;
  43.         SystemProcessorPerformanceInformation, @ m.lcBuff, m.liSize, 0 ))
  44.       wait window nowait '获取 cpu 信息失败: ' + transform( m.iresult, '@0' )
  45.       return
  46.     endif
  47.     for m.ii = 1 to this.cpu_nums
  48.       m.liBase = 1 + ( m.ii - 1 ) * 48
  49.       this.aCpuInfo[ m.ii, 1 ] = ;
  50.         this.ctobin_big( substr( m.lcBuff, m.liBase +  0, 8 ))
  51.       this.aCpuInfo[ m.ii, 2 ] = ;
  52.         this.ctobin_big( substr( m.lcBuff, m.liBase +  8, 8 ))
  53.       this.aCpuInfo[ m.ii, 3 ] = ;
  54.         this.ctobin_big( substr( m.lcBuff, m.liBase + 16, 8 ))
  55.     endfor
  56.   endproc
  57.   function ctobin_big( tcstring as string )
  58.     return ;
  59.         ctobin( substr( m.tcstring, 1, 2 ) + 0h0000, 'rs' ) ;
  60.       + ctobin( substr( m.tcstring, 3, 2 ) + 0h0000, 'rs' ) * 0x10000 ;
  61.       + ctobin( substr( m.tcstring, 5, 2 ) + 0h0000, 'rs' ) * 0x100000000 ;
  62.       + ctobin( substr( m.tcstring, 7, 2 ) + 0h0000, 'rs' ) * 0x1000000000000
  63.   endfunc
  64.   procedure init
  65.     declare long GetSystemInfo in win32api ;
  66.       string @ lpsysteminfo
  67.     declare long NtQuerySystemInformation in ntdll ;
  68.       long systeminformationclass, ;
  69.       string @ systeminformation, ;
  70.       long systeminformationlength, ;
  71.       long @ returnlength
  72.     local lcBuff, lcName, loUsage, ii
  73. *!* 获取本机已安装的 cpu 数量
  74.     m.lcBuff = replicate( chr(0), 0x40 )
  75.     GetSystemInfo( @ m.lcBuff )
  76.     this.cpu_nums = ctobin( substr( m.lcBuff, 21, 4 ), 'rs' )
  77.     dimension this.aCpuInfo[this.cpu_nums, 4]
  78. *!* 创建更新计时器
  79.     this.newobject( 'tmrUpdate', 'myTimer' )
  80. *!* cpu 使用率显示对象, 每个 cpu 一个
  81.     for m.ii = 1 to this.cpu_nums
  82.       m.lcName = 'cntUsage' + transform(m.ii)
  83.       this.newobject( m.lcName,  'myUsage' )
  84.       m.loUsage = evaluate( 'this.' + m.lcName )
  85.       with m.loUsage
  86.         .move( 10+(m.ii-1)*(10+.width), 10, .width, this.height-20 )
  87.         .anchor = 5
  88.         .visible = .t.
  89.       endwith
  90.     endfor
  91. *!* 调整表单宽度以显示所有使用率对象
  92.     this.width = 10 + ( 10 + this.cntUsage1.width ) * this.cpu_nums
  93.     this.getCpuTimeInfo()
  94.   endproc
  95. enddefine
  96. define class myTimer as timer
  97.   interval = 500            && 使用率更新间隔( ms )
  98.   name = "timer1"
  99.   procedure timer
  100.     thisform.updateUsage()
  101.   endproc
  102. enddefine
  103. define class myUsage as container
  104.   borderwidth = 0
  105.   backstyle = 0
  106.   width = 50
  107.   height = 100
  108.   value = 0
  109.   function value_assign( tnNewVal )     && 更新显示值
  110.     this.lblUsage.caption = transform(round(m.tnNewVal*100,0)) + '%'
  111.     with this
  112.       .cntBar.height = ( .cntFull.height - 2 ) * m.tnNewVal
  113.       .cntBar.top = .cntFull.height + .cntFull.top - .cntBar.height - 1
  114.       .cntBar.backcolor = icase( ;
  115.         m.tnNewVal <= 0.50, rgb(0,255,0), ;
  116.         m.tnNewVal <= 0.75, rgb(255,255,0), rgb(255,0,0))
  117.     endwith
  118.   endfunc
  119.   procedure init
  120.     this.newobject( 'lblUsage', 'label' )
  121.     with this.lblUsage
  122.       .move( 0, 2, this.width, 16 )
  123.       .alignment = 2
  124.       .backstyle = 0
  125.       .anchor = 11
  126.       .visible = .t.
  127.     endwith
  128.     this.newobject( 'cntFull', 'container' )
  129.     with this.cntFull
  130.       .backcolor = rgb(255,255,255)
  131.       .move( 0, 20, this.width, this.height - 20 )
  132.       .anchor = 15
  133.       .visible = .t.
  134.     endwith
  135.     this.newobject( 'cntBar', 'container' )
  136.     with this.cntBar
  137.       .backcolor = rgb(0,255,0)
  138.       .borderwidth = 0
  139.       .move( 1, 0, this.width-2, 0 )
  140.       .visible = .t.
  141.     endwith
  142.     this.value = 0
  143.   endproc
  144. enddefine

单独做成一个类来使用的示例:
由于示例中要使用 inkey 函数来延时,所以类库中不能在使用 vfp 自己的计时器来定义更新 cpu 使用率数据,否则 inkey 函数将导致 vfp 的计时器暂停运行,所以这里用 api 函数 SetTimer 来生成一个外部的计时器,并将类库的 updateUsage 方法绑定到这个计时器上。但这也会带了一些问题,因为 inkey 函数肯定也会使用 SetTimer 来创建计时器,这样就可能发生冲突,由于只是想示例 NtQuerySystemInformation 函数的用法,所以类库中也没有仔细处理这些问题,如果你要用它且遇到了问题,可能要从下面几个方面来着手解决:
1. 绑定到 _vfp.hwnd 的 WM_TIMER 事件之前,先用 GetWindowLong 获取并保存好 vfp 原来的缺省窗口处理过程。
2. 被绑定的 updateUsage 处理过程中,应该先判断 p3 是否就是我们定义的 TIMER_ID 值,如果是才执行其中的更新代码,否则调用第一步中保存的 _vfp 缺省处理过程。
3. 定义不同的 TIMER_ID 试试,例如: 0x12345
4. 如果你的程序中使用这个类库的代码段内没有使用 inkey 函数,就恢复使用 vfp 的计时器事件来调用 updateUsage 方法。

  1. clear
  2. oo = newobject( 'cpuUsage' )
  3. for m.ii = 1 to 50
  4.   inkey(0.5)      && 这时候你应该干点别的什么,免得 cpu 一只闲着而总是显示 0
  5.   ? oo.GetUsage(1)
  6. endfor
  7. oo = null
  8. * ----------------------------------------------------
  9. #define WM_TIMER        0x0113
  10. #define TIMER_ID        200
  11. define class cpuUsage as session
  12.   cpu_nums = 0                  && 系统拥有的 cpu 个数
  13.   dimension aCpuInfo[1,4]       && 1/2/3/4 - t_idle / t_kernel / t_user / usage
  14.   
  15.   procedure getUsage
  16.     lparameters tiCpuNo         && 要获取使用率的 cpu 编号
  17.     
  18.     if ( pcount() < 1 ) or ( 'N' != vartype( m.tiCpuNo ))
  19.       m.tiCpuNo = 1
  20.     endif
  21.     m.tiCpuNo = max( 1, min( this.cpu_nums, m.tiCpuNo ))
  22.     return this.aCpuInfo[ m.tiCpuNo, 4 ]
  23.   endproc
  24.   
  25.   procedure updateUsage          && 获取最新的 cpu 使用率信息
  26.     lparameters p1, p2, p3, p4
  27.     
  28.     local array laTemp[1]
  29.     local liIdleTime, liKernelTime, liUserTime, lnUsage, loUsage, ii
  30.     acopy( this.aCpuInfo, m.laTemp )
  31.     this.getCpuTimeInfo()
  32.     for m.ii = 1 to this.cpu_nums
  33.       m.liIdleTime  = m.laTemp[m.ii,1]
  34.       m.liKernelTime    = m.laTemp[m.ii,2]
  35.       m.liUserTime  = m.laTemp[m.ii,3]
  36.       m.lnUsage = ;
  37.         ( this.aCpuInfo[m.ii,1] - m.liIdletime ) / ;
  38.         ( this.aCpuInfo[m.ii,2] + this.aCpuInfo[m.ii,3] ;
  39.         - m.liKernelTime - m.liUserTime )
  40.       this.aCpuInfo[m.ii,4] = round(( 1.00 - m.lnUsage ) * 100, 0 )
  41.     endfor
  42.   endproc
  43.   procedure getCpuTimeInfo      && 获取最新的 cpu 空闲/核心/用户用时信息
  44.     #define SystemProcessorPerformanceInformation   8
  45.     local liSize, lcBuff, liBase, ii
  46.     m.liSize = 48 * this.cpu_nums
  47.     m.lcBuff = replicate( chr(0), m.liSize )
  48.     if ( 0 != NtQuerySystemInformation( ;
  49.         SystemProcessorPerformanceInformation, @ m.lcBuff, m.liSize, 0 ))
  50.       wait window nowait '获取 cpu 信息失败: ' + transform( m.iresult, '@0' )
  51.       return
  52.     endif
  53.     for m.ii = 1 to this.cpu_nums
  54.       m.liBase = 1 + ( m.ii - 1 ) * 48
  55.       this.aCpuInfo[ m.ii, 1 ] = ;
  56.         this.ctobin_big( substr( m.lcBuff, m.liBase +  0, 8 ))
  57.       this.aCpuInfo[ m.ii, 2 ] = ;
  58.         this.ctobin_big( substr( m.lcBuff, m.liBase +  8, 8 ))
  59.       this.aCpuInfo[ m.ii, 3 ] = ;
  60.         this.ctobin_big( substr( m.lcBuff, m.liBase + 16, 8 ))
  61.     endfor
  62.   endproc
  63.   function ctobin_big( tcstring as string )
  64.     return ;
  65.         ctobin( substr( m.tcstring, 1, 2 ) + 0h0000, 'rs' ) ;
  66.       + ctobin( substr( m.tcstring, 3, 2 ) + 0h0000, 'rs' ) * 0x10000 ;
  67.       + ctobin( substr( m.tcstring, 5, 2 ) + 0h0000, 'rs' ) * 0x100000000 ;
  68.       + ctobin( substr( m.tcstring, 7, 2 ) + 0h0000, 'rs' ) * 0x1000000000000
  69.   endfunc
  70.   procedure init
  71.     declare long GetSystemInfo in win32api ;
  72.       string @ lpSystemInfo
  73.     declare long NtQuerySystemInformation in ntdll ;
  74.       long SystemInformationClass, ;
  75.       string @ SystemInformation, ;
  76.       long SystemInformationLength, ;
  77.       long @ ReturnLength
  78.     declare long SetTimer in win32api ;
  79.       long hWnd, long nIDEvent, long uElapse, long lpTimerFunc
  80.     declare long KillTimer in win32api ;
  81.       long hWnd, long uIDEvent
  82.     local lcBuff
  83.     *!* 获取本机已安装的 cpu 数量
  84.     m.lcBuff = replicate( chr(0), 0x40 )
  85.     GetSystemInfo( @ m.lcBuff )
  86.     this.cpu_nums = ctobin( substr( m.lcBuff, 21, 4 ), 'rs' )
  87.     dimension this.aCpuInfo[this.cpu_nums, 4]
  88.     this.aCpuInfo = 0
  89.     SetTimer( _vfp.hwnd, TIMER_ID, 200, 0 )
  90.     bindevent( _vfp.hwnd, WM_TIMER, this, 'updateUsage' )
  91.     this.getCpuTimeInfo()
  92.   endproc
  93.   
  94.   procedure destroy
  95.     unbindevent( _vfp.hwnd, WM_TIMER )
  96.     KillTimer( _vfp.hwnd, TIMER_ID )
  97.   endproc
  98. enddefine

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值