Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write Program to Make CPU Usage About 50%

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

like image 522
Yichao Avatar asked Nov 12 '13 14:11

Yichao


People also ask

Is 50 CPU usage normal?

For less demanding games, if you are running a PC with an SSD, decent GPU like GTX 1660 and Ryzen 5 CPU (or another brand equivalent), the CPU usage from 10% to 30% is normal. For more demanding games, the CPU usage can be from 30% to 70%.

Why is my CPU usage at 60%?

It is normal for it to be high because the processor is not doing much at the moment. So, if your System Idle process is using 60% - 70% of your CPU, it means you're actually using 40% - 30% of it. Was this reply helpful? No the System Idle Process is only using 20-30% when running no or very few programs.


2 Answers

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.

like image 155
Baldrick Avatar answered Sep 17 '22 15:09

Baldrick


  • 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.
like image 43
ghembo Avatar answered Sep 20 '22 15:09

ghembo