 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
shimanov Guest
|
Posted: Wed Aug 24, 2005 8:07 am Post subject: a method to determine processor utilization |
|
|
| Code: | SetBatchLines, -1
SetFormat, float, 0.0
CoordMode, ToolTip, screen
period = 1000
loop
{
idleTime = idleTime1
GetIdleTime( idleTime )
start := a_TickCount
Sleep, %period%
elapsed := a_TickCount-start
idleTime = idleTime2
GetIdleTime( idleTime )
total_idle_ticks := ( idleTime2?ticks_high-idleTime1?ticks_high ) << 32
total_idle_ticks := total_idle_ticks+( idleTime2?ticks_low-idleTime1?ticks_low )
total_idle_ticks := total_idle_ticks*0.0001
ppu_idle := total_idle_ticks/elapsed*100
total := elapsed-total_idle_ticks
ppu := 100-ppu_idle
ToolTip, period = %period% (ideal)`nelapsed = %elapsed% (actual)`n`nppu = %total% ms (%ppu%`%)`nidle = %total_idle_ticks% ms (%ppu_idle%`%), 10, 10
}
ReadInteger( p_address, p_offset, p_size, p_hex=true )
{
old_FormatInteger := a_FormatInteger
if ( p_hex )
SetFormat, integer, hex
else
SetFormat, integer, dec
value = 0
loop, %p_size%
value := value+( *( ( p_address+p_offset )+( a_Index-1 ) ) << ( 8* ( a_Index-1 ) ) )
SetFormat, integer, %old_FormatInteger%
return, value
}
GetIdleTime( p_IdleTime )
{
global
local success
/*
struct FILETIME {
DWORD dwLowDateTime; uint4 0
DWORD dwHighDateTime; uint4 4
}
*/
VarSetCapacity( %p_IdleTime%?ticks, 4+4 )
success := DllCall( "kernel32.dll\GetSystemTimes", "uint", &%p_IdleTime%?ticks, "uint", 0, "uint", 0 )
if ( ! success )
{
MsgBox, GetSystemTimes failed!
ExitApp
}
%p_IdleTime%?ticks_low := ReadInteger( &%p_IdleTime%?ticks, 0, 4 )
%p_IdleTime%?ticks_high := ReadInteger( &%p_IdleTime%?ticks, 4, 4 )
}
|
This method tracks the system idle time (i.e., the OS idle process). The assumption is that processor utilization can be determined by examining the difference between system idle time and elapsed time during any given period.
I have tested this against the "CPU Usage" and "System Idle Process - CPU Usage" statistics as presented by Process Explorer (PE) from SysInternals. In my testing I noticed that this method produces a processor utilization which fairly accurately tracks that given by PE. In fact, this method produces statistics which seem to anticipate that given by PE.
The code above is a proof-of-concept. A preferred implementation would likely use a timer to gather statistics and save them in a temporal list which could later be accessed as needed.
Anyway... no guarantees. |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3910 Location: Bremen, Germany
|
Posted: Wed Aug 24, 2005 9:01 am Post subject: |
|
|
Hi shimanov,
Thank you so much for your script. That was one of the things I always wanted to have. I tested your script at it worked accourate enough. I have modified it. But in between I ran into trouble. It doesn't work any more. Could I ask you to have a look at it, please?
I added some msgbox into the code to see where it stops, but is was working, only when i click the msgboxes very fast, the code just stoped working. I do not know what I messed up, that causes such a behavior.
Thanks.
toralf
EDIT: Found it. It was just missing a #persistent. Now it works.
| Code: | #Persistent
period = 1000
SetBatchLines, -1
SetFormat, float, 0.0
CoordMode, ToolTip, screen
SetTimer, CheckCPULoad, %period%
return
CheckCPULoad:
start := a_TickCount
elapsed := start - Laststart
GetIdleTime( Low, High )
If Laststart
{
Idle_ticks := ( High - Lasthigh ) << 32
Idle_ticks := ( Idle_ticks + ( Low - Lastlow ) ) * 0.0001
ppu_idle := Idle_ticks / elapsed * 100
total := elapsed - Idle_ticks
ppu := 100 - ppu_idle
ToolTip,
(LTrim
period = %period% (ideal)
elapsed = %elapsed% (actual)
ppu = %total% ms (%ppu%`%)
idle = %Idle_ticks% ms (%ppu_idle%`%)
), 10, 10
}
Laststart := start
Lastlow := Low
Lasthigh := High
return
GetIdleTime( ByRef Low, ByRef High )
{
VarSetCapacity( Ticks, 4+4 )
success := DllCall( "kernel32.dll\GetSystemTimes", "uint", &Ticks, "uint", 0, "uint", 0 )
if ( ! success )
{
MsgBox, GetSystemTimes failed!
ExitApp
}
Low := ReadInteger( &Ticks, 0, 4 )
High := ReadInteger( &Ticks, 4, 4 )
}
ReadInteger( Address, Offset, Size )
{
old_FormatInteger := A_FormatInteger
SetFormat, Integer, hex
value = 0
Loop, %Size%
value := value + ( *( ( Address + Offset ) + ( A_Index - 1 ) ) << ( 8 * ( A_Index - 1 ) ) )
SetFormat, Integer, %old_FormatInteger%
Return, value
} |
_________________ Ciao
toralf  |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10716
|
Posted: Wed Aug 24, 2005 12:21 pm Post subject: |
|
|
Really nice. I tried it on my system and it seems exactly accurate. For example, it indicates 50% CPU utilitization when some other script runs an infinite loop with SetBatchLines 10ms, which is exactly what it is designed to use and what Task Manager says it uses.
Many people have asked for this, so thanks for spending the time to create and post it. |
|
| Back to top |
|
 |
shimanov Guest
|
Posted: Thu Aug 25, 2005 6:35 am Post subject: glad to help |
|
|
I am glad you have found value in my demo.
to: toralf
It's always good to know others can read your code. You have quickly transformed it to something of practical use. Thanks.
to: Chris
It is the least I can do. I have found AHk useful and purposeful. I appreciate your thoughtful design of the language, and the extensibility inherent to its design. Of course, the best part, is the AHk community. It draws you in, and then you have to participate. An enjoyable experience. |
|
| Back to top |
|
 |
toralf
Joined: 31 Jan 2005 Posts: 3910 Location: Bremen, Germany
|
Posted: Thu Aug 25, 2005 7:33 am Post subject: Re: glad to help |
|
|
| shimanov wrote: | | It's always good to know others can read your code. | I admit I had some problems. You used a "?" inside your var names, which caused some irritations in my head.
And I still do not understand some of the math you did (bitshift and *). But I didn't mess with that. The rest was easy, just some re-structuring. I currently have it running all day in the upper left corner (0,0) just as a one-liner ToolTip. Very neat. Thanks for your participation. I can't wait for more shimanov-code. :) _________________ Ciao
toralf  |
|
| Back to top |
|
 |
shimanov Guest
|
Posted: Fri Aug 26, 2005 10:01 am Post subject: Re: glad to help - revised code |
|
|
I forgot to mention, the "GetSystemTimes" routine requires, at minimum, Windows XP SP1.
| toralf wrote: | | You used a "?" inside your var names |
I use "?" as a record operator to denote a field, as opposed to "." since that is unavailable.
| toralf wrote: | | And I still do not understand some of the math you did (bitshift and *). |
First, all times are stored in ms. Second, most of the math is irrelevant -- my mistake. I forgot AHk (and ReadInteger) supports 64-bit signed integers.
Below is the revised version with some comments to explain why?:
| Code: |
SetBatchLines, -1
SetFormat, float, 0.0 ; set same display format as that in Process Explorer
CoordMode, ToolTip, screen
period = 1000 ; sample period
loop
{
; first sample
idleTime = idleTime1
GetIdleTime( idleTime )
start := a_TickCount
Sleep, %period%
; second sample
elapsed := a_TickCount-start
idleTime = idleTime2
GetIdleTime( idleTime )
total_idle_ticks := ( idleTime2?ticks-idleTime1?ticks )*0.0001 ; calculate difference and convert to ms
ppu_idle := total_idle_ticks/elapsed*100 ; ppu = Percentage Processor Usage
total := elapsed-total_idle_ticks
ppu := 100-ppu_idle
ToolTip, period = %period% (ideal)`nelapsed = %elapsed% (actual)`n`nppu = %total% ms (%ppu%`%)`nidle = %total_idle_ticks% ms (%ppu_idle%`%), 10, 10
}
ReadInteger( p_address, p_offset, p_size, p_hex=true )
{
old_FormatInteger := a_FormatInteger
if ( p_hex )
SetFormat, integer, hex
else
SetFormat, integer, dec
value = 0
loop, %p_size%
value := value+( *( ( p_address+p_offset )+( a_Index-1 ) ) << ( 8* ( a_Index-1 ) ) )
SetFormat, integer, %old_FormatInteger%
return, value
}
GetIdleTime( p_IdleTime )
{
global
local success
/*
struct FILETIME {
DWORD dwLowDateTime; uint4 0
DWORD dwHighDateTime; uint4 4
}
*/
VarSetCapacity( %p_IdleTime%?ticks, 4+4 )
; GetSystemTimes returns pointers to 64-bit signed integers (aka, ticks). ticks are are the
; number of 100-nanosecond intervals since January 1, 1601 -- a Microsoft thing.
success := DllCall( "kernel32.dll\GetSystemTimes", "uint", &%p_IdleTime%?ticks, "uint", 0, "uint", 0 )
if ( ! success )
{
MsgBox, GetSystemTimes failed!
ExitApp
}
; convert binary 64-bit signed integer to AHk format
%p_IdleTime%?ticks := ReadInteger( &%p_IdleTime%?ticks, 0, 8 )
}
|
When evaluating discrepancies between the processor usage (PU) as given by this method and others, consider the following:
1. The sample period is set at 1 s.
2. The clock resolution for timing may only be 10 ms.
3. The system PU is tracking the PU of the System Idle Process. This may or may not be the statistic used by the Windows performance library to determine the system PU.
4. There may occur an offset, due to indirect tracking of the System Idle Process. Code within the Idle Process, will produce the most accurate results (i.e., discrepancy between retrieving system idle time and elapsed time). |
|
| Back to top |
|
 |
Decarlo110
Joined: 15 Dec 2004 Posts: 303 Location: United States
|
Posted: Tue Nov 08, 2005 9:27 pm Post subject: |
|
|
This is a very nice script, which can be used, among other things, for keeping script/prog activity within a certain threshold. As far as i know, this cpu monitoring code is unique in the forum. Thanks for sharing it. _________________ 1) The Open Source Definition http://www.opensource.org/docs/definition_plain.php
2) Intuitive. Logical. Versatile. Adaptable. <<AutoHotkey>> |
|
| Back to top |
|
 |
shimanov
Joined: 25 Sep 2005 Posts: 610
|
Posted: Tue Nov 08, 2005 9:55 pm Post subject: |
|
|
| Decarlo110 wrote: | | This is a very nice script, which can be used, among other things, for keeping script/prog activity within a certain threshold. As far as i know, this cpu monitoring code is unique in the forum. Thanks for sharing it. |
Thanks. It was one of my early attempts to "get to know" Windows.
To monitor processor usage for a particular process, you may want to consider "GetProcessTimes". |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Wed Nov 09, 2005 12:38 am Post subject: |
|
|
| Shimanov, is there a simple modification which calculates also the available free memory? |
|
| Back to top |
|
 |
shimanov
Joined: 25 Sep 2005 Posts: 610
|
Posted: Wed Nov 09, 2005 1:33 am Post subject: |
|
|
| Laszlo wrote: | | Shimanov, is there a simple modification which calculates also the available free memory? |
Very simple indeed. Check this post. |
|
| Back to top |
|
 |
Bobo8
Joined: 09 Sep 2008 Posts: 5 Location: Czech rep.
|
Posted: Mon Feb 22, 2010 12:06 pm Post subject: Not working with multicore CPU |
|
|
This helpful script didn't count with multi core CPU. I have included 1 line, where I'v found out number of (logical, I hope that it is correct) processors and then only I'v divided total_idle_ticks by this:
| Code: |
EnvGet, ProcessorCount, NUMBER_OF_PROCESSORS
SetBatchLines, -1
SetFormat, float, 0.0 ; set same display format as that in Process Explorer
CoordMode, ToolTip, screen
period = 1000 ; sample period
loop
{
; first sample
idleTime = idleTime1
GetIdleTime( idleTime )
start := a_TickCount
Sleep, %period%
; second sample
elapsed := a_TickCount-start
idleTime = idleTime2
GetIdleTime( idleTime )
total_idle_ticks := ( idleTime2?ticks-idleTime1?ticks )*0.0001/ProcessorCount ; calculate difference and convert to ms
ppu_idle := total_idle_ticks/elapsed*100 ; ppu = Percentage Processor Usage
total := elapsed-total_idle_ticks
ppu := 100-ppu_idle
ToolTip, period = %period% (ideal)`nelapsed = %elapsed% (actual)`n`nppu = %total% ms (%ppu%`%)`nidle = %total_idle_ticks% ms (%ppu_idle%`%) , 10, 10
}
ReadInteger( p_address, p_offset, p_size, p_hex=true )
{
old_FormatInteger := a_FormatInteger
if ( p_hex )
SetFormat, integer, hex
else
SetFormat, integer, dec
value = 0
loop, %p_size%
value := value+( *( ( p_address+p_offset )+( a_Index-1 ) ) << ( 8* ( a_Index-1 ) ) )
SetFormat, integer, %old_FormatInteger%
return, value
}
GetIdleTime( p_IdleTime )
{
global
local success
/*
struct FILETIME {
DWORD dwLowDateTime; uint4 0
DWORD dwHighDateTime; uint4 4
}
*/
VarSetCapacity( %p_IdleTime%?ticks, 4+4 )
; GetSystemTimes returns pointers to 64-bit signed integers (aka, ticks). ticks are are the
; number of 100-nanosecond intervals since January 1, 1601 -- a Microsoft thing.
success := DllCall( "kernel32.dll\GetSystemTimes", "uint", &%p_IdleTime%?ticks, "uint", 0, "uint", 0 )
if ( ! success )
{
MsgBox, GetSystemTimes failed!
ExitApp
}
; convert binary 64-bit signed integer to AHk format
%p_IdleTime%?ticks := ReadInteger( &%p_IdleTime%?ticks, 0, 8 )
}
|
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|