locked
Limiting CPU usage

    Question

  • Hi;

    I am trying to limit the percentage of CPU usage that my application consumes, I am wondering if there is any code to do this in VB??

    Say as an example, I want to limit the CPU usage of my application to be %15.4, so when this limit is exceded the application pauses then and when below the limit the application would continue.


    Thanks for your help

    Wednesday, August 15, 2007 1:08 PM

Answers

  •  

    Public Class Form1

        Private Const Granularity As Integer = 1000 ' ms

        Private Proc As New Process

        Private CpuLimit As Single = 15.9

        Private PrcntUtilization As Single

        Private Sleeptime = 500

        Private ProcTime As TimeSpan

        Private DeltaTime As New Stopwatch

        Private LastTicks As Int64

        Protected Friend WithEvents tmr As New Timer

        Private Sub Form1_Load(ByVal sender As Object, _

                          ByVal e As System.EventArgs) Handles Me.Load

            tmr.Interval = Granularity

            tmr.Start()

            Proc = Process.GetCurrentProcess

            DeltaTime.Start()

     

        End Sub

     

      

        Private Sub tmr_Tick(ByVal sender As Object, _

                             ByVal e As System.EventArgs) Handles tmr.Tick

            DeltaTime.Stop()

            ProcTime = Proc.TotalProcessorTime

            PrcntUtilization = _

                (ProcTime.Milliseconds / DeltaTime.ElapsedMilliseconds) * 100

            If PrcntUtilization >= CpuLimit Then

                'System.Threading.Thread.Sleep(Sleeptime)

                Proc.PriorityClass = ProcessPriorityClass.Idle

            Else

                If Proc.PriorityClass <> ProcessPriorityClass.Normal Then

                    Proc.PriorityClass = ProcessPriorityClass.Normal

                End If

            End If

            DeltaTime.Reset()

            DeltaTime.Start()

        End Sub

    End Class

     

     

    Oh, Goddess… for a second, I thought I had a found a legitimate use for threading.sleep.

    Actually this is how the pros would do it. It makes use of any spare CPU cycles no matter what.

    It will run at normal priority unless it exceeds its utilization threshold and then it will reduce its priority.  If there is nothing going on the system, the system will schedule it to run. However it when it has been greedy, it will not be able to compete for time with other processes that need the time. If it is getting less than its time, it will re-adjust its priority back up to normal.

     

    Thursday, August 16, 2007 12:33 AM

All replies

  •  

    Public Class Form1

        Private Const Granularity As Integer = 1000 ' ms

        Private Proc As New Process

        Private CpuLimit As Single = 15.9

        Private PrcntUtilization As Single

        Private Sleeptime = 500

        Private ProcTime As TimeSpan

        Private DeltaTime As New Stopwatch

        Private LastTicks As Int64

        Protected Friend WithEvents tmr As New Timer

        Private Sub Form1_Load(ByVal sender As Object, _

                          ByVal e As System.EventArgs) Handles Me.Load

            tmr.Interval = Granularity

            tmr.Start()

            Proc = Process.GetCurrentProcess

            DeltaTime.Start()

     

        End Sub

     

      

        Private Sub tmr_Tick(ByVal sender As Object, _

                             ByVal e As System.EventArgs) Handles tmr.Tick

            DeltaTime.Stop()

            ProcTime = Proc.TotalProcessorTime

            PrcntUtilization = _

                (ProcTime.Milliseconds / DeltaTime.ElapsedMilliseconds) * 100

            If PrcntUtilization >= CpuLimit Then

                'System.Threading.Thread.Sleep(Sleeptime)

                Proc.PriorityClass = ProcessPriorityClass.Idle

            Else

                If Proc.PriorityClass <> ProcessPriorityClass.Normal Then

                    Proc.PriorityClass = ProcessPriorityClass.Normal

                End If

            End If

            DeltaTime.Reset()

            DeltaTime.Start()

        End Sub

    End Class

     

     

    Oh, Goddess… for a second, I thought I had a found a legitimate use for threading.sleep.

    Actually this is how the pros would do it. It makes use of any spare CPU cycles no matter what.

    It will run at normal priority unless it exceeds its utilization threshold and then it will reduce its priority.  If there is nothing going on the system, the system will schedule it to run. However it when it has been greedy, it will not be able to compete for time with other processes that need the time. If it is getting less than its time, it will re-adjust its priority back up to normal.

     

    Thursday, August 16, 2007 12:33 AM
  • Are you sure about this ReneeC?

     

    Maybe I am wrong, but if you reduce the priority of your process, you may never know when you get the control back.

     

    I am really not sure about this so please correct me if I am wrong, but as I understand it, all hardware timer ticks are handled at IRQL 28. However, as thread switching is done on IRQL 2 (DPC level), the hardware ISR is not allowed to do any thread related jobs. Instead it must post an APC routine to the APC queue of the thread, but this routine is not activated until the thread is scheduled and because the priority is reduced you will never know when this will take place, that is, when tmr_Tick will run and can change the priority back. Therefore, if the CPU limit is exceeded, the load may drop far below the wanted limit for quite a while.

     

    Maybe a little power nap is a better solution anyway ?

     

    PS. "Windows Internals" describes the interrupt system quite well, but unfortunately it does not describe the connection to the usual calls like timers, callback routines etc. For example, what exactly gets posted to the APC queue in case of a Sleep or a timer tick? In the previous Sleep discussion, even sleeping a background thread is considered bad programming by somebody, but in fact I think that the overhead including APC routine is less than the overhead using a timer, which will also post an APC routine for the callback. If you know, or know where I can find such a description, please let me know.

    Thursday, August 16, 2007 9:54 AM
  •  

    "Maybe I am wrong, but if you reduce the priority of your process, you may never know when you get the control back."

     

    Wouldn't this be a case where there is zero Idle time on a system? There would be something way out of kilter for the conditions you describe.

    Thursday, August 16, 2007 12:28 PM
  • I presume that the reason for reducing the CPU load is to avoid blocking other applications and in that case there may be zero idle time.

     

    When I run my Actel Libero software for FPGA design it constantly uses approximately 25-33% of the CPU time (doing absolutely nothing - just bad design), and during load it uses 100% for several minutes, so a situation with no idle time is something I see regulary, but I agree with you that in most cases there will be some idle time where tmr_Tick can get some time to run. It is just not guaranteed. If you reduce your priority and start Actel Libero or something as bad as this, you could loose control for maybe 5 minutes. When I calculated CRC-polynomials for our new fieldbus system, my CPU load was constant 100% for 3 days and nights!

     

    EDIT

     

    Perhaps Sleep(0) is the ideal solution?

     

    If PrcntUtilization > CpuLimit Then

        Sleep(0)

    Else

        ' Do whatever you have to do

    End If

     

    Thursday, August 16, 2007 1:11 PM
  •  

    "my CPU load was constant 100% for 3 days"

     

    You can't just look at a running program and say this. To get a clearer picture, one must observe the behavior in the face of competition for the cpu meaning what does the scheduler do with this. If you have only one compute bound task running and it's taking 100% of the processor - so what?

     

    Quiet seriously the efficacy of a timesharing/multi-tasking system is in answering the question of, "under these conditions, what happens when you want to run explorer."

     

    In terms of the solution I provided, the answer is it all depends on relative application priorities. The OP's question is rather strange to begin with. What is going on that the OP wants to limit the cpu consumption of a particular process? What problem is he attempting to solve with that?

     

    When you begin to play these games, you begin to customize for an exacting mix as we can see here. That's rarely ever a good idea.

     

    Pssst, Carsten... note how my solution is consistent with my signature.

    Thursday, August 16, 2007 2:44 PM
  • The CPU load was actually very close to 100% from the graph in the job list, but I agree with you that this is a very unusual situation, which you probably don't need to design for. I tried to test some of the polynomials on another, faster computer, but it got a heat stroke after just ½ hour!

     

    I also find the demand for 15.8% CPU load rather strange and probably impossible to achive precisely. However, my personal experience with the Actel software is that if a program uses more than 25% CPU time (graph in job list), everything is slowed down considerably and at approximately 33% the system becomes dead slow. I don't know what courses this. There ought to be a big head room, but it may be resonable to limit any program to less than approximately 25%, so the question is very relevant.

     

    And I do like your signature. That exactly how I design electronics and programs myself, so we agree in many things and I would also have hired you. You don't even Sleep() on your job !!!

     

     

    Thursday, August 16, 2007 8:33 PM
  •  

    No I don't. Smile And thank you. I still may take you up on it. Smile

     

    I actually have a great tiny realtine performance monitor that show cpu activity for single and dual core or hyperthreaded machines. It's deliberately tiny and runs all the time on all of systems.

     

    Yes of course, it's highly effiient and wastes nary a byte or a cycle. Wink

    Thursday, August 16, 2007 10:27 PM
  • Carsten,

     

    I think you need to separate .NET threads and how they are scheduled from how PC hardware interrupts work. They are not related and this is the reason that while ManagedThreadId might differ the actual underlying windows thread Id can be the same.

     

    Do not apply Windows Internals interrupts to how .NET threads are scheduled.

    Friday, August 17, 2007 1:58 AM
  •  

    Andreas,

     

    Can you make any illuminating comments on the scheduler and any parameters relevant to the schedulers timeslicing and quanta?

    Friday, August 17, 2007 3:18 AM
  • Andreas

     

    I agree with ReneeC. Could you please explain that in more details!

     

    Since Windows uses time slicing I find it very hard to understand that there is no connection between the interrupt system and .NET thread scheduling, and that .NET threads are not the same as Windows threads. As I understand it, all thread switching is done at IRQL 2 (DPC) level by means of a DCP routine posted by the timer ISR at IRQL 28. How can thread scheduling be time sliced if there is no connection to the timer system (IRQL 28)?

     

    Friday, August 17, 2007 8:03 AM
  •  ReneeC wrote:

    Can you make any illuminating comments on the scheduler and any parameters relevant to the schedulers timeslicing and quanta?

     

    I find this KB quite good in explaining the scheduler. No need to read about the sql server specific part.

    http://support.microsoft.com/kb/111405

     

     Carsten Kanstrup wrote:

    Since Windows uses time slicing I find it very hard to understand that there is no connection between the interrupt system and .NET thread scheduling, and that .NET threads are not the same as Windows threads. As I understand it, all thread switching is done at IRQL 2 (DPC) level by means of a DCP routine posted by the timer ISR at IRQL 28. How can thread scheduling be time sliced if there is no connection to the timer system (IRQL 28)?

     

    I am not saying you are incorrect. If we look specifically at Microsoft .NET it is using Win32 API for its CLR implementation that is running on x86/x86-64 architecture.

     

    However, you need to think abstract. .NET and the CLR are not locked to a specific OS or hardware architecture. Consider the compact framework that runs on mobile devices or look at the Mono project and the various combinations of OS and architectures it runs on. This is why you can not make any assumption on how a CLR thread is actually scheduled and gets it time-slice to run.

     

    There is a note in the about Thread.Class that highlight that the implementation of .NET managed threads should never be assumed to have anything to do with threads on the OS it is running on.

     

    An operating-system ThreadId has no fixed relationship to a managed thread, because an unmanaged host can control the relationship between managed and unmanaged threads. Specifically, a sophisticated host can use the CLR Hosting API to schedule many managed threads against the same operating system thread, or to move a managed thread between different operating system threads.

     

    When talking about .NET development we usually do not need to discuss how it actually is implemented in the CLR.

    Friday, August 17, 2007 1:10 PM
  • Thanks for everyone's help and comment, I really didn't expect that much of complication and high level discutions about a simple question.

    On the other hand when I tried to modify the code that Reneec had kindly posted I came accross with a problem!
    Although the current process would be but on Idle when the CPU limit has been reached, but the overall CPU usage could allready be very high, for the sake of argument say 85%, but still the CPU lmit might have not been reached. I say this as ia have had many experiments with the code, somtimes the CPU usage is shown to be 100% in the taskmgr but the application is on full throttle!

    I am not sure if I could write a code that ensures the Total CPU usage is bellow a certain level when that specific thread is being executed.But at least I know how to change the priority level of an application to RealTime in .NET !

    I am a complete Newbie on .NET, and this is a bit of achievment for me! Big Smile

    Thank you all
    Sunday, August 19, 2007 2:01 AM
  •  

    There's something many people don't realize which is that when your machine is doing nothing, it's running a null job. There's is never a time when a mchine is doing nothing. Taking a sinle process and running it doesn't show much because if the machine has nothing to do, it'll run even a low priority process at 100 percent and I say that's desireable.

     

    Your question is an unusual and it involves the operating system which is why people are intersted in threads like this. I hope you found the code usable.

    • Proposed as answer by alsaluti4 Wednesday, February 16, 2011 12:52 PM
    Sunday, August 19, 2007 4:19 AM
  • Thanks Reneec;

    The code has done the trick, and my free software is going to be distributed soon. When it is distributed I would like to add your name to the credits list if I may? Because you have been very helpful in answering most of my threads.





    Sunday, August 19, 2007 5:41 PM
  •  

    I am humbled.
    Sunday, August 19, 2007 5:56 PM