views:

994

answers:

5

Write code in your favorite language and let Windows Task Manager represent a sine wave in CPU Usage History.

This is a technical interview quiz from Microsoft China. I think it's a good question. Especially it's worth knowing how candidate understand and figure out the solution.

Edit: It's a good point if may involve multi-core(cpu) cases.

+3  A: 

With the literally hundreds (thousands?) of threads a PC runs today, the only way I can think to even come close would be to poll CPU usage as fast as possible, and if the usage% was below where it should be on the curve, to fire off a short method that just churns numbers. That will at least bring the typical low usage UP where needed, but I can't think of a good way to LOWER it without somehow taking control of other threads, and doing something such as forcing thier priority lower.

Neil N
+4  A: 

Ok I have a different, probably BETTER solution than my first answer.

Instead of trying to manipulate the CPU, instead hook into the task manager app, force it to draw what you want it to instead of CPU results. Take over the GDI object that plots the graph, etc. Sort of "Cheating" but they didnt say you had to manipulate the CPU

Or even hook the call from task manager that gets the CPU %, returning a sine result instead.

Neil N
I guess it's possible if we call performance monitor on cpu.
chagel
This illustrates the difference between bad requirements (too general, room for interpretation) and great requirements (specific and concrete). And... the difference between thinking in the box and out of the box.
Kit
+9  A: 

A thread time slice in Windows is 40ms, iirc, so that might be a good number to use as the 100% mark.

unsigned const TIME_SLICE = 40;
float const PI = 3.14159265358979323846f;
while(true)
{
    for(unsigned x=0; x!=360; ++x)
    {
        float t = sin(static_cast<float>(x)/180*PI)*0.5f + 0.5f;
        DWORD busy_time = static_cast<DWORD>(t*TIME_SLICE);
        DWORD wait_start = GetTickCount();
        while(GetTickCount() - wait_start < busy_time)
        {
        }
        Sleep(TIME_SLICE - busy_time);    
    }
}

This would give a period of about 14 seconds. Obviously this assumes there is no other significant cpu usage in the system, and that you are only running it on a single CPU. Neither of these is really that common in reality.

flodin
The loop test should be GetTickCount() - wait_start < busy_time, to cope with overflow.
peterchen
Right, I have revixed the code.
flodin
if`x > 180` then `t < 0`, DWORD is unsigned therefore you are plotting abs(sin(x)), not sin(x). http://stackoverflow.com/questions/551494/write-code-to-make-cpu-usage-display-a-sine-wave/551696#551696 –
J.F. Sebastian
Fixed for the range of sin(x). I have now actually tried this on Windows, I didn't have access to a Windows machine yesterday. It works... OK, but you need to set the CPU affinity of the process. Also the precision is quite poor, especially at low cpu usage levels.
flodin
A: 

Something like this:

while(true)
{
    for(int i=0;i<360;i++)
    {
       // some code to convert i into radians if needed
       ...
       Thread.Sleep(Math.Sin(i)*something_that_makes_it_noticeable_number_of_ms+something_that_makes_it_non_negative)
       // some work to make cpu busy, may be increased to bigger number to see the influence on the cpu.
       for(j=0;j<100;j++);
    }
}
Alex Reitbort
the for loop does nothing, and as such it gets optimized out. You're left with a infinite while loop that just does a sleep. e.g. you get almot zero load.
Nils Pipenbrinck
It was just an example, to represent "work".
Alex Reitbort
+3  A: 

Here's a slightly modified @flodin's solution in Python:

#!/usr/bin/env python
import itertools, math, time, sys

time_period = float(sys.argv[1]) if len(sys.argv) > 1 else 30   # seconds
time_slice  = float(sys.argv[2]) if len(sys.argv) > 2 else 0.04 # seconds

N = int(time_period / time_slice)
for i in itertools.cycle(range(N)):
    busy_time = time_slice / 2 * (math.sin(2*math.pi*i/N) + 1)
    t = time.clock() + busy_time
    while t > time.clock():
        pass
    time.sleep(time_slice - busy_time);

A CPU-curve can be fine-tuned using time_period and time_slice parameters.

J.F. Sebastian