Tight loops and high CPU might be good

General Macro Scheduler discussion

Moderators: JRL, Dorian (MJT support)

Post Reply
User avatar
JRL
Automation Wizard
Posts: 3529
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Tight loops and high CPU might be good

Post by JRL » Wed Nov 14, 2007 10:13 pm

Common wisdom dictates a small wait in any tight loop.

I've been working on a long program that has a non-modal dialog and a subroutine that is perpetually checking the status of about 30 checkboxes in the dialog. The subroutine has two repeat loops each looping 30 times. I was getting frustrated with the length of the delay after making any selection in my dialog. It could take nearly 2 seconds after making a selection before the result would be displayed. I knew the cause was the subroutine with Wait>0.01 inserted to prevent high CPU usage. If I changed that wait to zero the delay was gone. But this dialog will be sitting on user's desktops while they are trying to work in multiple other applications so I cannot just let the CPU run at 80 or 90%.

It occurred to me that I can set the Wait> time through a variable and I can control the variable by testing to see if my dialog is the active window or not. Therefore, If the active window is Excel, my program will only use 2% of the CPU. If the active window is my dialog, my program will use whatever it wants of the CPU.

This might not work in all situations but it is going to work in this case and I thought I'd pass along the idea.

Here's a sample script to illustrate the point. Start this script and watch the results for a minute, then open some other application in a way that you can still see the script's dialog window but the focus needs to be on the newly opened app. You should immediately notice the cycle count slow. The CPU percentage only changes after each one second of CPU use by the program so when the cycles slow it might take a while before you see the percentage drop. Switch focus back to the dialog window and the cycle count should increase and the CPU use should go up.

Code: Select all

VBSTART
VBEND

//Press Esc tp quit
OnEvent>KEY_DOWN,VK27,0,Quit
//Press up arrow to raise wait time
OnEvent>KEY_DOWN,VK38,0,Tup
//Press down arrow to reduce wait time
OnEvent>KEY_DOWN,VK40,0,Tdown

//Acquire process filename for cpu info
Separate>%COMMAND_LINE%,\,path
Let>filename=path_%path_count%
StringReplace>%filename%,",,filename

//A few settings
Let>kk=0
Let>LastTime=0
Let>CycleCount=19
Let>CPUThrottle=0
Let>ThrottleValue=0.01
Let>TTmsg=Throttle Time:
Let>PUDmsg=Press up or down arrow keys%CRLF%to raise or lower throttle time

Dialog>Dialog1
   Caption=CPU Time
   Width=168
   Height=259
   Top=CENTER
   Left=CENTER
   Max=0
   Min=1
   Close=1
   Resize=0
   Label=msLabel0,56,48,true
   Label=msLabel1,56,128,true
   Label=mslabel2,96,208,true
   Label=msLabel3,56,88,true
   Label=msLabel4,24,2,true
   Label=cycles,56,112,true
   Label=CPU time (hh:mm:ss),32,32,true
   CheckBox=msCheckBox1,CPU Throttle on,24,152,97,False
   Label=%TTmsg%,24,208,true
   Label=%PUDmsg%,8,176,true
   Label=%,96,88,true
   Label=Approx. CPU use,40,72,true
EndDialog>Dialog1

Show>dialog1

//A few dialog settings
Let>dialog1.mslabel2=%ThrottleValue%
Let>dialog1.mslabel4=%filename%
RDA>dialog1

Label>Start
  GetDialogAction>dialog1,res1
  If>res1=2,EOF

//check the CPUThrottle checkbox value to alter wait settings
//and dialog display
  If>dialog1.mscheckbox1=True
    Let>CPUThrottle=%ThrottleValue%
	Let>CycleCount=19
	Let>dialog1.mslabel2=%ThrottleValue%
	Let>dialog1.mslabel8=%TTmsg%
	Let>dialog1.mslabel9=%PUDmsg%
  Else
	Let>dialog1.mslabel2=%SPACE%
	Let>dialog1.mslabel8=%SPACE%
	Let>dialog1.mslabel9=%SPACE%
//This is the part I am talking about.  If the active window is
//my dialog, set the wait variable to zero thus allowing the process
//to run as quickly as possible.  If not, set the wait variable to an
//appropriate value
    Let>WIN_USEHANDLE=1
	GetActiveWindow>title,WinX,WinY
	Let>WIN_USEHANDLE=0
	If>%title%<>%dialog1.handle%
	  Let>CycleCount=19
	  Let>CPUThrottle=%ThrottleValue%
	Else
	  Let>CycleCount=99
      Let>CPUThrottle=0
	EndIf
  EndIf

//count the cycles through the process for display purposes
  add>kk,1

//run tasklist.exe in DOS to acquire cpu info
  Let>RP_WAIT=1
  Let>RP_WINDOWMODE=0
  Run>cmd /c tasklist /fi "imagename eq %filename%" /v /nh> %TEMP_DIR%~cpu~.txt
  ReadLn>%TEMP_DIR%~cpu~.txt,2,line
  DeleteFile>%TEMP_DIR%~cpu~.txt
  Separate>%line%,:,var
  Length>%var_1%,varlen
  sub>varlen,5
  midstr>%var_1%,%varlen%,10,var_1
  Midstr>%var_3%,1,2,var_3
  concat>var_1,:%var_2%:%var_3%
  StringReplace>%var_1%,%SPACE%,,var_1
  If>%dialog1.mslabel0%<>%var_1%
    GoSub>CPU
    Let>dialog1.mslabel0=%var_1%
  EndIf
  Let>dialog1.mslabel1=%kk%
  GoSub>Blast
  GetDialogAction>dialog1,res1
  RDA>dialog1
Goto>Start

//A little math to simulate doing something useful
//the uses cpu cycles.
SRT>Blast
  Let>user=0
  Repeat>user
    add>user,1
    Random>10000,num1
    random>10000,num2
    Random>10000,num3
    add>num3,1
    Let>num4={(%num1%*%num2%)/%num3%}
    Wait>%CPUThrottle%
  Until>user>%CycleCount%
END>Blast

//Calculate CPU percent of use based on one second of CPU
//usage reported by tasklist, divided by the number of
//seconds elapsed since the last one second of CPU usage.
SRT>CPU
  If>%LastTime%=0
    VBEval>Timer,LastTime
	Let>dialog1.mslabel3=Waiting...
  Else
    VBEval>Timer,timerStarted
    Let>dwell=%timerStarted%-%LastTime%
    Let>dialog1.mslabel3={(round((1/%dwell%)*100000)/1000)}
    //Let>dialog1.mslabel4=%timerStarted%
    //Let>dialog1.mslabel5=%LastTime%
    Let>LastTime=%timerStarted%
  EndIf
  RDA>dialog1
END>CPU

//Press Esc to quit
SRT>Quit
goto>EOF
END>Quit

//Press up arrow to raise wait time
SRT>Tup
If>%ThrottleValue%<0.5
  Let>ThrottleValue=%ThrottleValue%+0.001
  Let>dialog1.mslabel2=%ThrottleValue%
  RDA>dialog1
  wait>0.01
Else
  MDL>MAX Throttle value = 0.5
EndIf
END>Tup

//Press down arrow to reduce wait time
SRT>Tdown
If>%ThrottleValue%>0
  Let>ThrottleValue=%ThrottleValue%-0.001
  Let>dialog1.mslabel2=%ThrottleValue%
  RDA>dialog1
  wait>0.01
Else
  MDL>Minimum Throttle value = 0.001
EndIf
END>Tdown

Label>EOF

mmcbrien
Newbie
Posts: 7
Joined: Thu Jul 31, 2008 9:53 pm

Post by mmcbrien » Tue Jan 27, 2009 10:56 pm

Thank you very much for this idea/ implementation. I have been working on a project similar with non-modal box and slow respsonse time. This is brilliant.

Not to mention the cpu throttle setting is pretty nifty.

Kudo's!

User avatar
Phil Pendlebury
Automation Wizard
Posts: 543
Joined: Tue Jan 16, 2007 9:00 am
Contact:

Post by Phil Pendlebury » Wed Mar 11, 2009 7:21 pm

This post (and another related to it posted by Marcus) has just increased the efficiency of my main script by about 75%.

I didn't bother with the dynamic aspect but simply doing:

At start of code:

Let>LoopWait=0.006

And then inserting:

Wait>%LoopWait%

At various points (about 20 different areas) throughout my various dialog loops, I was able to drastically reduce CPU usage.

By using the above method I was able to very quickly tweak the wait length so as to reduce CPU but not to affect the responsiveness of the dialogs. Only having to change the figure in one place was helpful.

I was spurred to do this by 2 users who were having crashes due to 99% CPU usage. I don't know yet if it has fixed the problem for them but it certainly yielded immediate results for me.

My main dialog loop had become HUGE. But even on a smaller loop the results of adding 1 or 2 of these waits are tremendous.

So... Thank you for the post. Most helpful.
Phil Pendlebury - Linktree

kpassaur
Automation Wizard
Posts: 696
Joined: Wed Jul 07, 2004 1:55 pm

Syntax

Post by kpassaur » Sun Apr 12, 2009 6:24 pm

I am trying to use tasklist and I am having difficulty so I searched the forum and found this post where there was an example.

From above

Run>cmd /c tasklist /fi "imagename eq %filename%" /v /nh> %TEMP_DIR%~cpu~.txt

It does not work on my pc in MS yet it works from the command line, naturally with %filename% and %TEMP_DIR% changed.

I believe it to be the requirements for the command line to have the quote marks. I have tried putting them in numerous ways with no sucess.

Does anyone have any idea how they are supposed to go?

sarver311
Pro Scripter
Posts: 84
Joined: Tue Jun 17, 2008 6:37 pm

Re: Syntax

Post by sarver311 » Mon Apr 27, 2009 7:41 pm

kpassaur wrote:I am trying to use tasklist and I am having difficulty so I searched the forum and found this post where there was an example.

From above

Run>cmd /c tasklist /fi "imagename eq %filename%" /v /nh> %TEMP_DIR%~cpu~.txt

Does anyone have any idea how they are supposed to go?
kpassaur,

You were VERY close, you just need to put run program> instead of run>.

here is an example

let>filename=msched.exe
Run program>cmd /c tasklist /fi "imagename eq %filename%" /v /nh> %TEMP_DIR%~cpu~.txt

That should do the trick

-Josh

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Mon Apr 27, 2009 8:26 pm

Hi kpassaur and sarver311,

Per the Help File, Run> is just the abbreviated form of the full command name Run Program> so either should produce the same results... they do on this machine anyway.

Maybe you are having trouble with trying to read back the created file too soon? Try the following and let us know if it works and displays the info.

Code: Select all

Let>filename=msched.exe

//delete file if it already exists
DeleteFile>%TEMP_DIR%~cpu~.txt

//From the Help File: By setting the RP_WAIT variable to 1 prior to issuing the Run Program command
//the script will wait until the program launched by Run Program has terminated before continuing.
//The default value of RP_WAIT is 0.
Let>RP_WAIT=1

Run>cmd /c tasklist /fi "imagename eq %filename%" /v /nh> %TEMP_DIR%~cpu~.txt

//If I don't set RP_WAIT to 1, I get an IO error or a ##NO FILE## error unless I have a Wait here
//Wait>0.5

ReadFile>%TEMP_DIR%~cpu~.txt,file
MDL>file
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

Post Reply
Sign up to our newsletter for free automation tips, tricks & discounts