8

Problem Description

  • The goal of the problem is to write a program on Windows to keep the CPU usage at about 50% percent.
  • On Windows we can use Task Manager or Perfmon.exe to monitor the CPU usage.
  • The CPU usage percentage should be near 50%, since there're many other tasks in the operating system, we just take the approximate usage percent of the CPU.
  • The CPU could be a multiple core processor or a single core processor, so a generic solution is favored

Origin of The Problem

The original question is from chapter 1.1 of Beauty of Programming

Personal Efforts On The Problem

Environments

  • Processor: Intel i5-3470, 4 cores, 4 threads
  • System: Windows 7
  • Development Environment: Visual Studio 2010, boost library

First Try

My first try didn't put multicore and multithread in consideration, so it didn't work, but it provides the idea: if we want the processor half loaded, we could create a infinite loop which sleeps half of the time, and occupies the processor the other half.

I'll just skip the detail of first try.

Second Try

In my second effort, things went well, but there're still some problems that bothers me.

My First Solution

The following snippets is the first possible solution. It uses GetTickCount() from Windows API, and uses two threads to get the processor loaded at 50%.

The solution one gist.

#include <boost/thread.hpp>
#include "windows.h"
#define INTERVAL 10

void infiniteLoop() {
    while (1) {
        DWORD startTime = GetTickCount();
        while (GetTickCount() - startTime <= INTERVAL)
            ; 
        boost::posix_time::millisec sleepTime(INTERVAL);
        boost::this_thread::sleep(sleepTime);
    }
}

int main() {
    boost::thread thread1(infiniteLoop);
    boost::thread thread2(infiniteLoop);
    thread1.join();
    thread2.join();
    char c;
    std::cin >> c;
}

The solution is successful, but I don't quite understand why I can use only two thread to get CPU half loaded, since i5-3470 processor is a quad-core processor, theoretically, I could only get the processor loaded at 25% using two threads.

Why I use two threads instead of four threads?
At first, I thought the processor is a dual-core processor, XD.

Q1: here is my first question: Why two threads of this infiniteLoop() could consume 50% of a qual-core CPU capacity?

I tried hard to figure this problem out, but I'm really not capable to do it myself.. :X

My Second Solution

The second solution is exactly the same as the first one, except that I use clock() from time.h to replace GetTickCount() function. In this solution, I really needs 4 threads to get the processor loaded at 50%.

Here is the code.

#include <boost/thread.hpp>
#include "windows.h"
#include <ctime>
#define INTERVAL 10

void infiniteLoop() {
    while (1) {
        clock_t startTime = clock();
        while (clock() - startTime <= INTERVAL)
            ;
        boost::posix_time::millisec sleepTime(INTERVAL);
        boost::this_thread::sleep(sleepTime);
    }
}

int main() {
    boost::thread thread1(infiniteLoop);
    boost::thread thread2(infiniteLoop);
    boost::thread thread3(infiniteLoop);
    boost::thread thread4(infiniteLoop);
    thread1.join();
    thread2.join();
    thread3.join();
    thread4.join();
    char c;
    std::cin >> c;
}

This solution makes the total usage of the processor almost at 50%, but by observing task manager->performance->CPU record, I find that the usage of four cores is not uniformly distributed, the first two cores have a load of almost 60%, the third one is about 50%, and the last one is merely about 30% of the maximum load.

So it's my second question.
Q2: Why are those cores not uniformly loaded, does there exist some mechanism inside the operating system behind this phenomenon?

My Third Solution

Another idea is to totally block two threads, thus making the CPU loaded at 50%.

Here is the code.

#include <boost/thread.hpp>
#include "windows.h"
#include <iostream>

void infiniteRunningLoop() {
    while (1) {
        ;
    }
}

int main() {
  boost::thread thread1(infiniteRunningLoop)
  boost::thread thread2(infiniteRunningLoop)
  thread1.join();
  thread2.join();
}

Thought About The Three Solutions

  • Those three solutions are not generic solutions to get CPU loaded at 50%, since if you have other programs running in the system, they will also consume CPU capacity.
  • The solution only works in quad-core processor, if you want to use it on other processors, for example, dual-core processor, you have to modify the number of the thread.
  • None of these three solutions is elegant..XD

So, Q3: Could someone provides an elegant solution that could fulfill the target and is portable among different kinds of processors?

Many thanks to those who read through the question, and even lots more thanks to those who may answer this question in advance!

XD

8
  • On windows 2 cores (real or virtual) out of 4 running at 100% = 50% CPU usage according to taskmanager. On linux each core (real or virtual) counts as 100%. So top will show 200% CPU load in this case. Commented Nov 12, 2013 at 14:20
  • That's the exact approach I used in my third solution, but for the first one, the infiniteLoop really sleeps for about 50% of the thread time. One thread takes one core's 50% capacity, two threads will make it 100% capacity, and that's 25% capacity of a quad-core processor instead of 50%, isn't it? Commented Nov 12, 2013 at 14:39
  • I think your interval is too small so it may not sleeping at all. Commented Nov 12, 2013 at 14:52
  • Please correct me if I'm wrong..Well for about 10 milliseconds, the thread is blocked in the second while loop, because GetTickCount() - startTime <= INTERVAL says to the thread: you cannot jump out of the loop until INTERVAL(10) milliseconds has passed. After 10 milliseconds, the thread will then sleep for 10 milliseconds due to the next two statements. Commented Nov 12, 2013 at 14:57
  • sleep in windows was not that accurate (you could not sleep for 10ms since that was less than the resolution of the clock) when I used it years ago. However I am not sure of the current resolution of the clock. msdn.microsoft.com/en-us/library/windows/desktop/… Commented Nov 12, 2013 at 15:00

3 Answers 3

1

I think the key thing you are missing is the ability to get a count of the number of processors. You can do it like this:

SYSTEM_INFO sysinfo;
GetSystemInfo( &sysinfo );
numCPU = sysinfo.dwNumberOfProcessors;

The count from this will be the same as the number you see listed in Task Manager.

If you combine this with your existing approaches, you should get something quite generic working.

Sign up to request clarification or add additional context in comments.

3 Comments

I believe boost thread can also tell the user this information. boost.org/doc/libs/1_54_0/doc/html/thread/…
This shall solve one aspect of the third problem. Nice advice! And now I'm looking for a solution to dynamically maintain the CPU usage at 50 percent.
@Baldrick Can you solve this confusion please
1
  • Q1: seeing as going from using GetTickCount() to clock() solved the problem, I guess GetTickCount() doesn't work as expected, but I really can't think why.
  • Q2: If the thread doesn't start and end at exactly the same time, there is an overlap so it could be that, for example, thread 3 starts just while thread 1 is waiting and it's spawned on core 1 (available because thread 1 is suspended).
  • Q3: I think just as Baldrick said, getting the number of cores and spawning the right number of threads would make your second solution quite general.

Comments

0

For Q1: The it seems the resolution of the GetTickCount() is larger than 10 ms. At least on my i7 860 based windows 7 box at work.

#include "stdafx.h"
#include <iostream>
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    while(1) {
        std::cout <<GetTickCount() << std::endl;
    }
    return 0;
}

Some output:

510948811 510948811 510948811 510948811 510948811 510948811 510948811 510948811 510948811 510948811 510948811 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948826 510948842 510948842 510948842 510948842 510948842 510948842

Although then I would expect you to get between 25% and 50% utilization.

Edit: I created a project using your code for Q1 on my i7 adjusted the code to 4 threads and I am seeing 50% utilization. Interesting.

Edit2: If you make interval in the first example code to 30 I now get the expected behavior.

1 Comment

I see the point, the resolution of GetTickCount() is independent on different processors, say if the resolution of GetTickCount() is 15ms, and you set the interval to 10ms, and create (number of cores in processor) threads, then the program would stuck in while for 15ms then sleep for 10ms, the utilization should be around 10/25. So I think using GetTickCount() is not really a viable solution.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.