Draw with your CPU



I have come across an article where students used network traffic to draw their university on the country's IPv6 graph. [image]

Your goal is simple to tell, but hard to implement. Draw the text MAIL (as it is one of the few words that can be read on a 1D graph) on the CPU graph.

It should look something like this:


Elaborating a bit more on what qualifies:

  • The code does not need to be cross-platform (so you won't need unknown APIs to deal with).
  • You may capture it in any general CPU usage utility that you have.
  • The graph looks a bit worse on a different machine: I trust you this time.
  • The base CPU usage % must be continuous, so if you generate a random wave and highlight something that looks like the word MAIL, it's obviously cheating.
  • You may choose the maximum load to use, but it has to be substantial enough to clearly see it.
  • You must follow the linearity of the example. (For M it looks like this: base %, then sudden increase to the specified max, fall gradually to a lower %, rise back to max and sudden drop to the base % again.)
  • If it's unreadable, voters will notice after all.

Standard loopholes apply. Post the images too!


Posted 2014-07-06T20:35:49.140

Reputation: 3 916

Interesting idea, but this question is about drawing pictures more than anything else. Wasting computer cycles isn't really much of a programming challenge, and art competitions don't belong here. – r3mainer – 2014-07-06T20:52:32.503

2i changed the goal to code-golf so that it can be more challenging and less artistic :) – bebe – 2014-07-06T21:11:45.690

9I don't see a reason for the close vote anymore. I personally find this a fun challenge, albeit a little system specific. – seequ – 2014-07-06T21:22:27.350

Well at least it's original! I like it, might have a go. – tomsmeding – 2014-07-06T21:29:27.813

@bebe that's better – r3mainer – 2014-07-06T21:53:30.910

6The problem I see with code golf is to judge how legible is legible enough. If you can think of a way to specify that objectively, that would greatly improve the challenge, but it's a really nice idea anyway! – Martin Ender – 2014-07-06T22:03:36.960

@m.buettner i'm really thinking but i can't find a solution to check the entries' legibility. maybe fourier series to check the error rate compared to the example... no. i'm trying though. – bebe – 2014-07-06T22:27:26.927

@bebe you could specify the shape a bit more precisely. say: the user may choose the maximum load he's going to use, but it has to be substantial enough to clearly see it. then: have a sudden increase to that maximum, fall gradually off to ~half of that, and then rise back to the maximum at the same rate. sudden drop to 0. then rise gradually to the top, fall off with the same rate to 0. sudden rise to the top, sudden drop to 0. sudden rise to the top, sudden drop to ~one third, sudden drop to 0. – Martin Ender – 2014-07-07T00:54:16.890

3it's really just the same as your picture, but I guarantee you if you don't put it in words, people will interpret "draw MAIL" very liberally. – Martin Ender – 2014-07-07T00:54:58.373

34+1, it is so absurd I almost chuckled myself to death... "this is madness..." "madness.. THIS IS CODEGOLF!!!" – None – 2014-07-07T12:18:49.770

5This is a friggin awesome question. I wish I was smart enough to participate. That doesn't really matter, I'm interested in the creative solutions by other people :P – Chris Cirefice – 2014-07-08T15:25:45.357

1I wonder if a solution could be made to both look and sound good. Close to the end of the last millennium, I wrote a DOS program, that would play a sound with alternating pitch on my sound card without ever sending a byte to the sound card. Instead I just exploited that the sound card was overly sensitive to variations in the current drawn by the CPU. – kasperd – 2014-07-08T15:33:25.400

3The most useless waist of bandwidth ever. – sergiol – 2014-07-14T01:37:51.043



Python, 143

from time import*
while 1:
 while x:x-=1

Each character of the string corresponds to one second of activity, from the ASCII character 0 (max load) through to ~ (very light load). The program runs on a time-synchronised loop, so you can run multiple instances for nicer results.

I used Python 2.7.6 on OS X with an Intel Core i7, but it should work on other computers with a bit of tweaking (adjust the 0.001). The screenshot below was taken with significant background activity.


Update - I was able to produce a clearer graph with time()/10 and a lower update frequency:


And finally, here's a more golfed version (123 bytes) and its result:

from time import*
while 1:
 while x:x-=1


Posted 2014-07-06T20:35:49.140

Reputation: 18 565


Python, 358 281 268 221 194 bytes

Monochrome is so last year. This uses multiple processes and syscalls to achieve two color CPU graphs!

import os,time
for i in'0123456':
 while t<1:T=int(time.time())%50;(time.sleep,(id,os.urandom)[i<A[T+49]])[i<A[T]](1)

Output from Activity Monitor (OS X 10.9):

Activity Monitor CPU Load graph Activity Monitor CPU History graph

Repeats on the CPU History graph

Output from MenuMeters:

MenuMeters output

All outputs were generated with an update speed of 1s. No significant background tasks were running, though this output quite easily beats out any single-threaded CPU task.

This code assumes you have 8 cores. It should be pretty easy to modify for fewer/more. It is portable to Linux/UNIX systems (though it has only been tested on OS X), and should produce the same two-color output for any CPU monitor that can distinguish User from System CPU time.

Essentially, this works by forking off seven processes, each of which will choose to spend 1 second sleeping, spinning in usermode, or spinning the kernel. Spinning in kernel mode is achieved by requesting large globs of data from /dev/urandom, which forces the driver backing /dev/urandom to spend a lot of "system" CPU cycles.

EDITED [07/21]: Shortened significantly by using fork() instead of multiprocessing.Process (/dev/urandom only works on *NIX systems anyway so this doesn't reduce portability). Note however that the program now spawns background tasks; you may have to killall Python (or similar) to get rid of the CPU-eaters.

I couldn't resist implementing a few more letters. I got 16 letters, plus a few symbols:

~/._PIN ANCHO... ...VY

The complete alphabet is "ACDFHILMNOPTUVWY", with symbols "._~/\". There are probably lots more characters that can be represented.

Entirely ungolfed code for the extra letters:

from time import*
from multiprocessing import*

chars6 = {
'A': ('123456654321',
'C': ('344556666666',
'D': ('666666655443',
'F': ('66666666666666',
'H': ('666664444466666',
'I': ('66666',
'L': ('666662222222',
'M': ('6665544334455666',
'N': ('66665544336666',
'O': ('3445556666555443',
'P': ('666666666555',
'T': ('777776666677777',
'U': ('6666322236666',
'V': ('66654322345666',
'W': ('66542466424566',
'Y': ('66665433456666',
'_': ('1111111111',
' ': ('000',
'.': ('12221',
'~': ('44445544334444',
'/': ('2234566',
'\\': ('6654322',

s = 'ANCHOVY '
A = '000'.join(chars6[t][0] for t in s)
B = '000'.join(chars6[t][1] for t in s)

def F(n):
 while 1:T=int(time()-t)%len(A);[sleep,[].count,lambda x:f.read(4**9)][(n<int(A[T]))+(n<int(B[T]))](1)
for i in range(7):Process(target=F,args=(i,)).start()


Posted 2014-07-06T20:35:49.140

Reputation: 11 445

34+1 for giving the letters more definition using 2 colors – DustinDavis – 2014-07-10T05:25:35.747

4And +1 for table-driven letter creation – GreenAsJade – 2014-07-11T05:31:06.750

1The A could in fact be properly rendered (with a hole) with 4 threads. Would have to set some CPU monitor colors to coincide though. – Ruslan – 2014-07-12T16:44:24.963

@Ruslan: What CPU monitor are you thinking of? My monitor shows only one aggregate graph, with 0 <= system <= user <= 100 at each point (which makes "holes" impossible AFAIK). – nneonneo – 2014-07-12T19:05:52.487


@nneonneo I mean monitors similar to yours. See this picture. Here if we change blue to green and red and purple to white, we'll get a nice "A" with holes.

– Ruslan – 2014-07-13T06:42:37.717

@Ruslan: I don't have four colors on my CPU monitor, unfortunately. I would love to find one that does, for even more pixel art madness, though! – nneonneo – 2014-07-13T06:50:15.967

@nneonneo you'd need 4 CPU cores or 2 cores*2 hyperthreads. I think you could try using a VM emulating 4 logical CPUs. – Ruslan – 2014-07-13T07:55:34.060


C (Intel Core Duo + OS X/Darwin), 248 bytes

#include <unistd.h>
#include <mach/mach_time.h>
#define M mach_absolute_time()
main(){char*s="JJJIHGFGHIJJJ@BDFHJJJHFDB@JJJJ@JJJJBBBBBBB";uint64_t i,t,y=1;for(;*s;s++){

This code is about as portable as the Great Pyramid of Cheops. Sorry about that. The values returned from mach_absolute_time() are hardware-dependent, but on my machine the value increments about once per nanosecond.

Here's the result:

The word "MAIL" shown in my CPU history graph

There are two graphs because the processor has two cores. I set the maximum CPU load to about 90% because the process is liable to switch between cores whenever I call usleep(). With a 100% load, the process is chained to one core and the results are illegible (see this, for example)


Posted 2014-07-06T20:35:49.140

Reputation: 19 135

Can't you use #include<unistd.h>? – Rizze – 2016-09-08T11:38:31.220

1Good job! This looks very interesting. Could you please post a little explanation of the code? :) – duci9y – 2014-07-07T14:34:21.123

1i see braces. why are there braces in the for loops? you can put usleep into the second for loop's last block. i think you can golf down a little more easily. – bebe – 2014-07-07T15:20:59.267

Couldn't you put the declaration and initialisation of the uint64_t variables into the header of the following for loop? – Joey – 2014-07-07T19:29:01.217

74+1: "This code is about as portable as the Great Pyramid of Cheops" – Uwe Keim – 2014-07-08T07:00:18.320

@Јοеу no, C variables must be declared at the beginning of a block. putting it in the initializtion block of for will throw an error. of course it only applies to <C99 – bebe – 2014-07-08T07:52:31.313

@bebe: Hm, I thought since the for loop extends until the end of the program it would be okay, as it's still in the same scope. Cannot test, though. – Joey – 2014-07-08T08:01:35.713

Congrats on your 1st gold badge. =) – Vectorized – 2014-07-12T20:15:48.350


Ruby, 150 characters

1until Time.now-c>x/3
sleep y||x%3}

This isn't all that short so far, but in my opinion the output's rather nice, so I figured I'd post this anyway. As with most other solutions, you may have to pin the Ruby process to a certain core by prefixing it with taskset -c $core.

The code is a simple combination of spinning/sleeping for a certain amount of time, which should make it somewhat portable. Smooth gradients are created by varying the ratio of spin/sleep time.

MAIL written CPU monitor

Lowering the CPU sampling frequency makes the edges look a bit better:

Lower sampling frequency

By adding a few more letters to the alphabet (AILMNUVW are somewhat recognizable), we can also write some other words:


These pictures were generated with the following code:

def gradient num_samples, direction, base = 0.3, increment = 0.02, scale = 1
    range = [*0..num_samples]

    samples = case direction
        when :up then range.reverse
        when :down then range
        when :updown then range.reverse + range
        when :downup then range + range.reverse

        i *= increment
        [base - scale * i, i]

# letters are defined as a series of pairs of (spin-time, sleep-time)
# with the time in seconds
THIN_A = gradient(15, :updown, 0.2, 0.2/15)
A = gradient(15, :updown)
I = 2,0
L = 1.5,0, [[0.1,0.2]]*9
M = 2,0, gradient(9, :downup), 2,0
N = 1,0, gradient(9, :down), 2,0
U = 1,0, gradient(9, :downup, 0.1, 0.03, 0.1), 1,0
V = 0.5,0, gradient(12, :downup, 0.25, 0.02), 0.5,0
W = 0.5,0, [gradient(12, :downup, 0.25, 0.02)]*2, 0.5,0

    # add 2 second pause after each letter
    i + [0,2]
    # spin, then sleep
    c = Time.now
    1 until Time.now-c > x
    sleep y

Words that can be written with the implemented letters can be found with

grep -E '^[aijlmnuvw]+$' /usr/share/dict/words 


Posted 2014-07-06T20:35:49.140

Reputation: 9 842

You could have made the word "aluminium". – Oliver Daugherty-Long – 2016-08-09T02:06:20.270

@OliverDaugherty-Long aluminum* – TuxCrafting – 2017-01-11T19:42:31.210

1@TùxCräftîñg Aluminium is a variant spelling that has an extra letter, and is the longest word I can think of that works. – Oliver Daugherty-Long – 2017-01-13T22:00:17.343

4+1 for the extension into more words! – Chris Cirefice – 2014-07-08T15:29:08.413


Python, on Intel Pentium 4 3.0Ghz, 180 166 145 141 138 bytes

Call with taskset -c 0 python cpu_graph_drawer.py.

taskset is needed to restrict the process to use only one CPU/core (hyperthreading in my case.)

from time import*;c=clock
for x,y in a:
    while c()-t<x:pass

Result isn't that great. This one with taskset -c 1


Posted 2014-07-06T20:35:49.140

Reputation: 2 520

FYI: you can golf a bunch of chars out by using a=[...]+[(.1,.2)]*10 instead of .extend. – nneonneo – 2015-11-06T18:53:20.877

9I'd love to see this with a CPU monitor that doesn't smoothen the curves... – Szabolcs – 2014-07-07T14:41:51.153

1Me too, but I don't feel like writing up a conky cpu-usage graph and gnome-system-monitor is the only thing I know. Got any alternatives that would run on LMDE Cinnamon? – user80551 – 2014-07-07T16:42:54.387

Enable the "Draw CPU as stacked area chart", and set all colors to black. – Tejas Kale – 2014-07-08T06:31:11.977

@TejasKale The lines would still be curved. – user80551 – 2014-07-08T07:22:41.837


Java 8, 482 characters

Every character in the String means number of threads, that will be utilized. Image taken on Intel Core i3 (2 cores / 4 threads).


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Mail{
public static void main(String[] args) throws InterruptedException{
for(char c:"123432234321000012343210000444000044441111111".toCharArray()){
ExecutorService executorService = Executors.newScheduledThreadPool(4);
for(int i=1;i<c-48;i++)executorService.execute(()->{while(!Thread.interrupted());});

Edit: more golfed version (322 chars), same functionality:

import java.util.concurrent.*;
class M{
public static void main(String[]a)throws Exception{
for(int c:"123432234321000012343210000444000044441111111".toCharArray()){
ExecutorService s=Executors.newFixedThreadPool(4);

Tomáš Dvořák

Posted 2014-07-06T20:35:49.140

Reputation: 621

1There's a less than sign there that got interpreted as HTML and messed up the formatting. – David Conrad – 2014-07-08T20:46:50.317

@ValekHalfHeart next two lines should explain it. Executor is a thread(asynchronous task manager) executing task(s) (here loops) until interruption. After creating it, main thread waits for 1.5s and then interrupts all tasks.

– PTwr – 2014-07-09T07:32:07.643

45By just opening Eclipse, my CPU graph wrote "Simple Mail Transfer Protocol". – lolesque – 2014-07-11T10:08:40.113


C, 78 bytes

You never said we couldn't accept user input, sooo..

#include <unistd.h>
int main(){int x=0;for(;x<1<<26;++x);read(0,&x,1);main();}

This program reads from standard in and every time it reads a character it executes a gratuitous CPU wasting for loop, then calls main again. You control the amount of CPU time it uses by spamming the enter key at different speeds.

I ran this on an intel i3 4130T, which is a reasonably new processor. But your mileage may vary, if it's using more or less CPU time than is practical for you to observe, try playing with the shift amount in the delay loop.

My program is awesome because it:

  • is mostly cross platform, it should work with very little fiddling on any *nix
  • defeats the question
  • great endgame play

After a few tries I produced a graph that looked like this:CPU graph


Posted 2014-07-06T20:35:49.140

Reputation: 1 607

1This answer is too good though, loopholes be damned xD! – Magic Octopus Urn – 2017-04-19T17:14:16.510

It helps to restrict it to one CPU core with taskset, a.la. taskset -c 1 [file] – Wug – 2014-07-13T09:01:01.590

Running it with yes|test gives me constant 100% CPU usage, so the code doesn't work. – Ruslan – 2014-07-13T16:28:58.350

2I don't see anything in the problem requirements that says our submissions will be invoked as yes | [program] – Wug – 2014-07-14T01:15:03.163

And I don't see how else I could make it work. It wants input, I give it with yes, but don't get the expected result. I even tried then as you say, "spamming enter key", which is almost the same, but results still are the same. – Ruslan – 2014-07-14T05:15:55.887

I'll give you a hint. the CPU usage is proportional to the rate at which you send it lines. – Wug – 2014-07-14T05:56:31.080

Ah... so you have to drive it manually. Okaaay... – Ruslan – 2014-07-14T08:46:23.493

12Standard loophole...also falls under http://meta.codegolf.stackexchange.com/a/1085/6699. – nneonneo – 2014-07-14T18:50:13.290

1"great endgame play" made me lol hard. +1 – Christoph – 2014-07-24T12:37:41.420