tags:

views:

803

answers:

4

I am looking to limit the percentage of the CPU time used by a PowerShell process to a certain number -- for the sake of argument, let's imagine it to be 13%.

Other options that are not precisely what I need: 1) Setting priority. 2) Setting CPU affinity.

Basically, we have monitoring software which complains if the total CPU usage gets too high. We have a daily process that sets this off -- mostly harmlessly, but too many false positives in a monitoring system and people become inured to warnings/errors when we do not wish that.

The process itself gets lsass.exe very excited, too, as it runs, and other processes happen, as well.

I do not know PowerShell and am attempting to fix Somebody Else's Powershell. Obviously, a ground-up rewrite would be nice at some future point, but for now, bells are ringing and annoying people.

+3  A: 

What you're asking for isn't really possible. The Windows kernel is in charge of scheduling the CPU -- and rightfully so. (I for one don't want to return to real-mode DOS).

The best you can do is insert a long Sleep() in between each line of the script. But there's no guarantee that any particular Powershell cmdlet / function / etc will throttle itself the way you want. The Windows API calls that ultimately execute each statement's dirty work certainly won't.

Ironically, Raymond touched on this topic just a few days ago: http://blogs.msdn.com/oldnewthing/archive/2009/07/27/9849503.aspx

My real suggestion is to modify your script so it looks like:

try {
    Stop-CpuMonitor

    # ...the current script contents...
}
finally {
    Start-CpuMonitor
}
Richard Berg
A: 

While I know of no way to actually limit the usage of any process to a particular amount of CPU consumption by percentage, I figured maybe one could alter the priority of the PowerShell thread. So I wrote a quick script and ran a test.

The result was that in both "Normal" and "Lowest", the time taken was about the same. Looking at the CPU meter widget, the CPU usage taken was approximately 27%, but I was running on a quad core box, so that's not surprising. It was taking all of one CPU in both cases. My machine wasn't doing much else at the time, so that was the other 2%, I guess.

Perhaps the results will vary on a busier machine.

Here's the script:

function Spin
{
    param($iterations)

    for($i = 0; $i -lt $iterations; ++$i)
    {
        # Do nothing
    }
}

$thread = [System.Threading.Thread]::CurrentThread

Write-Host $thread.Priority
$start = [DateTime]::Now
Write-Host "[$start] Start"

Spin 10000000

$end = [DateTime]::Now
Write-Host "[$end] End"
$span = $end - $start
Write-Host "Time: $span"

$thread.Priority = "Lowest"
Write-Host $thread.Priority
$start = [DateTime]::Now
Write-Host "[$start] Start"

Spin 10000000

$end = [DateTime]::Now
Write-Host "[$end] End"
$span = $end - $start
Write-Host "Time: $span"

$thread.Priority = "Normal"

And here's the result:

Normal
[08/06/2009 08:12:38] Start
[08/06/2009 08:12:55] End
Time: 00:00:16.7760000
Lowest
[08/06/2009 08:12:55] Start
[08/06/2009 08:13:11] End
Time: 00:00:16.8570000

Notice also that in the documentation for Thread.Priority it states:

Operating systems are not required to honor the priority of a thread.

Lee
A: 

From my experience, there's not a way to stipulate what percentage of the CPU Powershell will get to use. I think the best course of action would be to set the priority of Powershell to Low to allow other tasks/programs to go first. I think the first post has a decent suggestion of using the pauses (I'd upvote, but I'm below the 15 reputation points to do so) and that's something you might look into, but I don't think it will give you the control you're looking for. Sorry my answer is more of a suggestion than a resolution.

/matt

Matt Dewey
+1  A: 

I sincerely doubt there is a particularly simple way to accomplish what you are asking. If CPU concern is a big deal, I would combine a couple of tactics and let the scheduler take care of the rest - it is actually pretty good at managing the load.

The suggestion using ThreadPriority is a bit problematic as PowerShell with spawn each new command in a new Thread, which you could get around by having everything encapsulated on a single line, a cmdlet, or a function of some sort. Better to send the whole powershell process to idle:

Get-Process -name powershell | foreach { $_.PriorityClass = "Idle" }

Note: that will send ALL powershell instances to idle, which may not be the desired effect. And certainly doesn't prevent a script from boosting its own priority either.

Also, as mentioned here - littering your code with sleep commands can be an efficient way to ensure other processes have ample CPU time to process their code. Even 50-100ms is almost an eternity to a processor.

[System.Threading.Thread]::Sleep(50)

Between these two tactics your script will run when it is available, and graciously bow to other CPU demands as they arise.

Goyuix