RAZOR: help with perfproc

- / -
April 1, 2009 at 22:19:30
Specs: XP, P4 & 1GB
original script is written by razor, from this thread http://www.computing.net/answers/pr...

the modified version:

Set WMI = GetObject("winmgmts:")
q="SELECT * FROM __instancedeletionevent WITHIN 0.1 " & _
  "WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfProc_Process'" '& _
'  "AND TargetInstance.IDProcess=" & PID
With WMI.ExecNotificationQuery(q)

For Each a In WScript.Arguments
	If WMI.Get("Win32_Process").Create(a, Null, Null, PID) Then
		WScript.Echo "Process start failed."	
		WScript.Quit 1
	End If
	wsh.echo "Created Process PID = " & PID 
	do
		set e=.nextevent
		wsh.echo e.path_.class, e.TargetInstance.IDProcess, _
			e.TargetInstance.Name
	loop until e.TargetInstance.IdProcess=PID
	display e.TargetInstance
Next
End With

sub display(targetinstance)
with targetinstance
	WScript.Echo "Caption: " & .Caption
	WScript.Echo "CreatingProcessID: " & .CreatingProcessID
	WScript.Echo "Description: " & .Description
	WScript.Echo "ElapsedTime: " & .ElapsedTime
	WScript.Echo "Frequency_Object: " & .Frequency_Object
	WScript.Echo "Frequency_PerfTime: " & .Frequency_PerfTime
	WScript.Echo "Frequency_Sys100NS: " & .Frequency_Sys100NS
	WScript.Echo "HandleCount: " & .HandleCount
	WScript.Echo "IDProcess: " & .IDProcess
	WScript.Echo "IODataBytesPersec: " & .IODataBytesPersec
	WScript.Echo "IODataOperationsPersec: " & .IODataOperationsPersec
	WScript.Echo "IOOtherBytesPersec: " & .IOOtherBytesPersec
	WScript.Echo "IOOtherOperationsPersec: " & .IOOtherOperationsPersec
	WScript.Echo "IOReadBytesPersec: " & .IOReadBytesPersec
	WScript.Echo "IOReadOperationsPersec: " & .IOReadOperationsPersec
	WScript.Echo "IOWriteBytesPersec: " & .IOWriteBytesPersec
	WScript.Echo "IOWriteOperationsPersec: " & .IOWriteOperationsPersec
	WScript.Echo "Name: " & .Name
	WScript.Echo "PageFaultsPersec: " & .PageFaultsPersec
	WScript.Echo "PageFileBytes: " & .PageFileBytes
	WScript.Echo "PageFileBytesPeak: " & .PageFileBytesPeak
	WScript.Echo "PercentPrivilegedTime: " & .PercentPrivilegedTime
	WScript.Echo "PercentProcessorTime: " & .PercentProcessorTime
	WScript.Echo "PercentUserTime: " & .PercentUserTime
	WScript.Echo "PoolNonpagedBytes: " & .PoolNonpagedBytes
	WScript.Echo "PoolPagedBytes: " & .PoolPagedBytes
	WScript.Echo "PriorityBase: " & .PriorityBase
	WScript.Echo "PrivateBytes: " & .PrivateBytes
	WScript.Echo "ThreadCount: " & .ThreadCount
	WScript.Echo "Timestamp_Object: " & .Timestamp_Object
	WScript.Echo "Timestamp_PerfTime: " & .Timestamp_PerfTime
	WScript.Echo "Timestamp_Sys100NS: " & .Timestamp_Sys100NS
	WScript.Echo "VirtualBytes: " & .VirtualBytes
	WScript.Echo "VirtualBytesPeak: " & .VirtualBytesPeak
	WScript.Echo "WorkingSet: " & .WorkingSet
	WScript.Echo "WorkingSetPeak: " & .WorkingSetPeak
end with
end sub

i type at commandprompt:
razor c:\batch\tester.bat

the problem is:
1. when the batch is terminated in less than a second, nextevent method unable to catch it.

2. after i run the script, there is a process call wmiprvse.exe that eat up CPU cycle. around 40-50%. my guess is the WMI.ExecNotificationQuery(q) is still running. what's the syntax to stop it. eg, WMI.stop??

3. where can i download WMI programming reference? that contains available class, method, property.

help me with what i am doing wrong in the above script. thanks.


See More: RAZOR: help with perfproc

Report •


#1
April 2, 2009 at 15:10:16
1. when the batch is terminated in less than a second, nextevent method unable to catch it.
This is a problem with my original script, and it would appear you suspect the issue. The original script had to make it from the Win32_Process.Create() to the ExecNotificationQuery() before the spawned process quit. This is why I ensured what the script was running would last at least 5 seconds.

2. after i run the script, there is a process call wmiprvse.exe that eat up CPU cycle. around 40-50%. my guess is the WMI.ExecNotificationQuery(q) is still running. what's the syntax to stop it. eg, WMI.stop??
It should happen automatically, but you told WMI to poll the state of the processes 10 times a second. WMI probably just hasn't had the chance to process the stop request. If not, congratulations, you just crashed WMI. You should be able to safely kill wmiprvse.exe. Just an FYI: PID comes from the Win32_Process.Create(). By placing the query before the Create(), you're looking for PID 0 to terminate, aka "System Idle Process."

3. where can i download WMI programming reference? that contains available class, method, property.
I use MSDN for reference. Both for the script objects, and the WMI classes. I wish I could recommend a good book on the subject, but I've never read any of them.

EDIT: It would be remiss of me not to mention MS' Script Repository, which has some good examples of simple WMI scripts.


Report •

#2
April 2, 2009 at 21:32:25
The original script had to make it from the Win32_Process.Create() to the ExecNotificationQuery() before the spawned process quit. This is why I ensured what the script was running would last at least 5 seconds.
yes, that's the reason i move the ExecNotificationQuery to the top, and change the timepoll to 0.1, and i commented out the IDProcess where condition. but still it doesn't work. is there any way to get around this for a process less than a sec???

wmiprvse.exe can't be killed once created, it just keep respawning. the good news is after taskkill, it's cpu cycle down to 0% =)
C:\>for /l %a in (1 1 100) do @taskkill /f /im wmiprvse.exe

Just an FYI: PID comes from the Win32_Process.Create(). By placing the query before the Create(), you're looking for PID 0 to terminate, aka "System Idle Process."
i check the PID inside a "do-loop until"

for some reason, i am unable to access MSDN lately. looking for something in CHM format.

thanks razor for looking into this.


Report •

#3
April 3, 2009 at 03:50:41
i commented out the IDProcess where condition
So you did. It's hard to see VBScript comments when they're not colored green.

wmiprvse.exe can't be killed once created, it just keep respawning. the good news is after taskkill, it's cpu cycle down to 0% =)
That's by design; WMI can crash without taking down the entire WMI subsystem.

is there any way to get around this for a process less than a sec???
On my work PC, an application needs to run for at least half a second before WMI will notice it. Your application might be too fast for WMI.

looking for something in CHM format.
I'm not finding anything. The Windows SDK has a file called WMISDK.hxs, but I don't have anything that can read .HXS files at the moment.

EDIT: Okay, WMISDK.HXS is the offline version of MSDN's WMI reference. So if you want to go that option, you only need to download the entire Windows SDK and the free third party H2Viewer application.


Report •

Related Solutions

#4
April 5, 2009 at 23:34:40
i didn't notice wmisdk.hxs, going to google for it now. thanks.

after few days trying and oscasionallly crashing my pc due to lots of ctrl-c.
the problem is the jump between .createprocess and .nextevent statement going too slow.
i think to solve this is to run the .nextevent listener as a thread, before executing .createprocess. going to think more.


Report •

#5
April 6, 2009 at 03:17:27
the problem is the jump between .createprocess and .nextevent statement going too slow.
It shouldn't be. A queue is built when you use ExecNotificationQuery(); it shouldn't matter when you choose to go though that queue, just so long as you do.

What you doing that requires WMI to be so quick?


Report •

#6
April 6, 2009 at 04:52:15
on my testing, the ExecNotificationQuery doesn't queue up event. it's the nextevent method that is notified when an event has occured.

what i want to do is that this vbscript will be generic so that it can give details information about the performance of exe, vbs, bat, etc.

example helloworld.bat:
echo hello world
tasklist>c:\result.txt

c:\>razor.vbs c:\helloworld.bat



With WMI.ExecNotificationQuery(q) 'listen for event
..
..
If WMI.Get("Win32_Process").Create(a, Null, Null, PID) Then
.. 'helloworld.bat process created
.. ' done helloworld.bat
..
set e=.nextevent 'on nextevent, nothing to do, because helloworld.bat has finished

if i put nextevent before createprocess, it wont work, because nextevent only return after an event has occured.
so i am thinking of running createprocess in a thread.
eg.
With WMI.ExecNotificationQuery(q)
.....
ws.run "createthread.vbs " & a,0,false 'create seperate thread
e.nextevent 'listen for event

contents of createthread.vbs
wsh.sleep 2000
WMI.Get("Win32_Process").Create(wsh.arguments(0), Null, Null, PID)
wsh.quit PID

now i have to think how to pass the PID from createthread.vbs to razor.vbs


Report •

#7
April 6, 2009 at 23:51:24
on my testing, the ExecNotificationQuery doesn't queue up event. it's the nextevent method that is notified when an event has occured.
That's not what I've seen. Case in point:
Set WMI = GetObject("winmgmts:")
WScript.Echo "Spawning Notepad..."
Set cfg = WMI.Get("Win32_ProcessStartup").SpawnInstance_
cfg.ShowWindow = 6
If WMI.Get("Win32_Process").Create("notepad.exe", Null, cfg, PID) Then
  WScript.Echo "Process start failed."
  WScript.Quit 1
End If
WScript.Echo "Notepad's PID = " & PID & vbNewLine

WScript.Echo "Starting ExecNotificationQuery..."
Set ENQ = WMI.ExecNotificationQuery( _
  "SELECT * FROM __instancedeletionevent WITHIN 1 " & _
  "WHERE TargetInstance ISA 'Win32_Process' " & _
  "AND TargetInstance.ProcessID = " & PID)
WScript.Echo "Sleeping for 3..." & vbNewLine
WScript.Sleep 3000

WScript.Echo "Killing notepad..."
WMI.Get("Win32_Process.Handle=" & PID).Terminate
WScript.Echo "Sleeping for 3..." & vbNewLine
WScript.Sleep 3000

WScript.Echo "Processing ExecNotificationQuery..."
On Error Resume Next
Do
  WScript.Echo "Getting next event..."
  Set e = Nothing
  Set e = ENQ.NextEvent(3000).TargetInstance
  If Not e Is Nothing Then
    For Each p In e.Properties_
      WScript.Echo "  " & p.Name & " = " & p
    Next 'p
  End If
Loop Until Err = &H80043001 'NextEvent() timed out
WScript.Echo "Done processing ExecNotificationQuery"

what i want to do is that this vbscript will be generic so that it can give details information about the performance of exe, vbs, bat, etc.
You might need something more robust, like the Win32 API.


Report •

#8
April 7, 2009 at 01:24:06
so it does queue up each of events that occured.
and there is a way enumerate the properties of targetinstance with e.properties and put timeout on the nextevent. thanks for point this out.

You might need something more robust, like the Win32 API.
imo, it's easier to do it in vbscript. btw, which WIN32 API are you referring to get performance of a process?

i tested the above code, it also works with simple helloworld.bat, there must be something very wrong i am doing with the first code.

razor, thanks for putting your time in this and solve this.


Report •

#9
April 8, 2009 at 03:24:57
imo, it's easier to do it in vbscript. btw, which WIN32 API are you referring to get performance of a process?
In these scripts, we're mostly just using WMI as a Win32 wrapper. Win32_Process.Create wraps CreateProcess. Win32_PerfFormattedData_PerfProc_Process wraps . . . a lot of functions.

Let's talk about why you might want to use the Win32 API directly. As far as I can tell, WMI's __instancedeletionevent works like this: WMI processes its query. Next it compares the results of this poll to the previous poll, throwing _instancecreationevents and _instancedeletionevents for new objects and outdated objects, respectively. Obviously if something runs faster than this polling interval, having WMI detect it will be a crapshoot.

This is not the case with the Win32 API. When we use CreateProcess, we get a set of handles. As Windows won't clean up the process until all handles to it are closed, we can examine the now dead process at our leisure; Windows will even tell us the time of death. As for which language to choose, that depends on your personal preference. I'd choose C++, but that's far from the only option. You can use VBA, VB.NET, C# (actually, the .NET platforms might have something built-in, but a quick search turned up nothing), PERL (I think), Python (again, I think), pretty much any language that lets you interact directly with DLLs. (Sadly, this doesn't include VBScript.)

Honestly, I'd just set the polling interval to half a second, and say anything that runs quicker than a second is outside of the scope of the monitoring script.


Report •

#10
April 10, 2009 at 05:39:13
good information you've provided above, teach me a lot of things.

Honestly, I'd just set the polling interval to half a second, and say anything that runs quicker than a second is outside of the scope of the monitoring script.
since it's does queue up the events, it doesnt't matter to me as long as it catch the events.

Win32_Process.Create wraps CreateProcess. Win32_PerfFormattedData_PerfProc_Process wraps . . . a lot of functions.
so it would be something like this:
class Win32_PerfFormattedData_PerfProc_Process extends Win32_Process
class Win32_PerfRawData_PerfProc_Process extends Win32_Process

but if i change the query to:
Set ENQ = WMI.ExecNotificationQuery( _
"SELECT * FROM __instancedeletionevent WITHIN 1 " & _
"WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfProc_Process'" & _
"AND TargetInstance.ProcessID = " & PID)

an error occured:
Starting ExecNotificationQuery...
C:\batch\razor2.vbs(13, 1) SWbemServicesEx: Not found


Report •

#11
April 10, 2009 at 07:18:07
"AND TargetInstance.ProcessID = " & PID)
It should be TargetInstance.IDProcess

Win32_PerfFormattedData_PerfProc_Process extends Win32_Process
Actually, Win32_PerfFormattedData_PerfProc_Process is derived from Win32_PerfFormattedData, which itself is derived from Win32_Perf, which is finally derived from CIM_StatisticalInformation

Win32_Process comes from CIM_Process, and that comes from CIM_LogicalElement, and that comes from CIM_ManagedSystemElement. So there's really no relation.


Report •

#12
April 12, 2009 at 01:56:13
oops, my silly mistake. thanks, it's working well now. =)

Report •


Ask Question