views:

263

answers:

8

The case:

  • A scheduled task running on Windows.
  • The program's job is to extract some information from text documents. It uses a lot of regular expressions to do this. The program is therefore CPU Bound.
  • The service takes every document it finds in a folder and converts them one after another.

Normally, everything is OK, the service finds a few documents every now and then and converts them.

But on some occasions, due to a misconfiguration on the system that delivers the documents, a few thousand documents has been in queue for conversion at the same time. When this happens, the service process stays at 100% CPU for a long time, causing the server to become unresponsive to other types of requests.

On Linux, I could probably use nice or cpulimit to limit the CPU usage, but all customers run this on Windows.

There are obvious ways I can work around this, for instance I could let the service sleep a bit between every file it handles (but this feels a bit clunky). Or I could let the extraction process sleep a bit between every regexp match (feels even clunkier).

Questions:

  • Why does the application developer (me) even need to worry about this? I thought that assigning resources to processes was the operating system's job? I mean, seriously: Do I really need to make my program slower by design (by introducing some sleep() calls)?
  • Is there a way I can configure Windows to give my scheduled task some CPU limit?
  • Is this a general problem with CPU bound programs? (or am I doing something fundamentally wrong)

Edit:

  • Some answers and comments suggest that I should check my assumption that my process is CPU bound. And that I/O load might be the problem. I want to check on the I/O load, is there a something simple I can look for in the task manager? Would a quickly increasing I/O Reads/Writes values be an indication?
+9  A: 

If it's only CPU-bound, then there should be no problem, the scheduler can handle it.

However, I suspect the thousands of files impose an I/O-load as well, which is currently an unsolved problem in modern OSes. Try to limit the disk reads first, and see if that helps.

Jurily
Agreed. I question the OP's assumption that his task is CPU-bound. Try replacing your task with a while(true){;} loop, and see how the performance degradation compares.
Michael Petrotta
I am quite confident that there is very little IO load. The program reads the entire file into memory, then does the regexp matching stuff, which builds an in-memory result, then writes the result to disk. There is no way that the single read and single write would cause the CPU to peak.
codeape
Another agreement: when I see someone claim they are CPU bound *and* slowing the operating system down, I have to wonder if they haven't already been playing with priority *OR* something else is the cause. In general I have found that modern machines have far more chances of becoming I/O bound (either through direct file activity or swapping).
Godeke
Hmm. I will indeed do as @Michael Petrotta suggests. Perhaps my assumptions are wrong.
codeape
But then: Is it not a safe assumption that a process that basically only does a lot of regexp matching is CPU bound? If I read @Godeke right: If I am CPU bound, it would not have caused those problems I describe?
codeape
@codeape: It's not a safe assumption unless you've tested it, and controlled for other variables. Here's another way to test: load the file once, and do your regexs over it a few thousand times. Your CPU load will peak, but will your server performance degrade in the same way it did before?
Michael Petrotta
@Michael Petrotta: Yes, but the pattern is: 1. read a single file 2. process the file 3. write the output file. 4. goto 1. Time is mostly spent on step 2.
codeape
Basically, the CPU meter is not a good measure of server load, the way it was a decade or two ago. The disk has become much more of a bottleneck.
Michael Petrotta
@codeape: I understand time is spent on step 2. I'm claiming that that **doesn't matter**, when it comes to server responsiveness.
Michael Petrotta
OK, it seems I need to investigate a bit further. Will try to figure out if it is in fact the I/O that is causing the problems.
codeape
+12  A: 

The Windows equivilent to nice would be SetPriorityClass(). If you know your app is CPU bound you may want to set it to lower than normal priority.

Aaron
+1 beat me to it.
Jon Seigel
Thanks, I will try that.
codeape
+3  A: 

You can set the process priority to be "below normal" with >start /low app.exe for the scheduled task on launch.

Mike Atlas
Either low or belownormal are options for start. /low | /belownormal | /normal | /abovenormal | /high | /realtime
Xepoch
Great, thanks. I had forgotten about the arguments to ``start.exe``.
codeape
+1  A: 

Actually, it is your responsibility as a developer to ensure you don't consume too many system resources at once. I had an issue where a program I was maintaining drove the CPU to 100% quite often when run in a certain mode. When idle it used >50% CPU. That doesn't seem too bad but when deployed we ran into some unforeseen uses... the system it was running on was old hardware and was being used as a server for some thin client workstations. So when the CPU usage was high, none of the thin clients could communicate with the server. This was medical equipment too.. can you imagine?

In your case, you could probably get away with using SetPriorityClass to lower your process's priority (the equivalent of nice for Windows processes). You can also lower your thread priorities as well, if you're multithreaded.

Jeff Paquette
This seems like exactly the problem that I am describing (it's not on medical equipment, luckily...). Most commenters/answers claim that the OS handles a CPU intensive process OK. Your experiences goes against that.
codeape
Even though this was technically an 'edge case' in the product -- old hardware, weird display mode -- it made the customer's systems unusable and that was not acceptable. Most places make sure developers have modern hardware and that results in a product that runs well on that hardware. It's when the customer is using older hardware that performance problems creep up. A good lesson to keep in mind is that you can't predict behavior outside your lab.
Jeff Paquette
+1  A: 

You could always use SetThreadPriority or its .NET equivalent to effectively 'renice' your CPU-bound thread so that it runs at a lower priority.

Eric Brown
A: 
  1. You shouldn't worry about it unless its an actual issue. Premature optimization, etc.
  2. You can lower the priority of the executing thread, or even throw file processing delegates onto the ThreadPool. Letting the OS decide whether or not your application's work should be offloaded for more important threads is a decent strategy if you're worried about choking the server.
  3. It depends on what you're doing. If you are doing lots of work in a normal priority thread, other normal priority threads will have to compete with you on an equal basis for resources.
Will
On 1.: I agree abt. premature optimization. But here it is an actual issue. Customer's systems have become unresponsive.
codeape
Low priority background threads.
Will
A: 

Setting priorities is all fine and good, but often there is a simpler alternative. In fact, I found that setting priority was not the best alternative in one case.

I once built a program that ran in a very tight loop most of the time - it was doing something very close to the hardware. The system manager applet (whatever it's called?) always showed 100% CPU useage. The customer was a bit concerned because someone needed to do some data processing in Excel while this process was running.

My solution was to simply insert short sleep()'s (of 1 ms or 1 ns, I forget) into the loop. CPU usage was still at 100% according to the resource monitor, but the PC was fully and briskly responsive to user input anyway. My code was only taking time away from that left over from the user's tasks, and the frequent sleep() calls were giving the system a nice hint to do a task switch.

It turns out this worked fine even at normal priority for my CPU-hogging code.

Carl Smotricz
+1  A: 
  1. You always need to worry about your programs runtime behaviour and that includes the use of system resources. As others already have suggested you should use SetThreadPriority() and set the lowest priority possible. The Windows CPU scheduler should be intelligent enough to figure out the rest. Configuring priorities correctly is your job.
  2. see above.
  3. No, there is no general "problem" with CPU bound programs. The nature of a programs defines the "bottleneck" if you wish to say so. But if you now you will spend 99% of the time waiting for the cpu to finish a calculation, you know what to optimize.
  4. To check the I/O load of your program I can strongly recommend ProcessExplorer from the Sysinternals suite. You need to consider that everytime you issue a synchronous I/O request the OS will block your thread of execution and execute another one until the I/O request is completed. This may have unintended side effects.
Johannes Rudolph