Noah Kochavi's blog

How fast can computers count? Part 1

How fast can computers count?

This is the first post in a series of writing programs to see how fast computers can count. The series will start with naive methods, then will make use of optimization and later parallelism within the CPU, then will utilize a GPU, and the finale will use a dedicated FPGA for counting.

Hardware specs:

The most naive method of all

Let’s start our journey in JavaScript, which is one of the easiest languages to make a minimum viable prototype of simple actions. Unlike something like Python, your computer already contains a JavaScript runtime: It’s known as a web browser.

To write and run snippets of JavaScript code, just press F12 in a browser tab, preferably a light tab. Then, navigate to your browser’s console. You can simply copy and paste some JavaScript code and hit enter to run it.

Here is my most naive code:

var startTime = Date.now();
var count = 0;
while(Date.now() - 1000 < startTime) {
    count++;
}
console.log(count); 

12644980

The computer counted from 0 to 12.6 million in one second. This may seem fast, but the CPU has 12 modern cores running at 3+ GHz. This is unimpressive for such hardware.

Less naive than before

Notice something about the while loop from before. It checks for the elapsed time and makes a comparison to the start time on every increment. This is terribly inefficient.

From now forth, we will record the time only at the start and end of the program to maximize focus on the counting part. Here is an implementation:

var startTime = Date.now();
var count = 0;
while(count < 1e8) {
    count++;
}
var endTime = Date.now();
var elapsedTime = ((endTime - startTime) / 1000).toFixed(3);
console.log("Counted to 100 million in " + elapsedTime + " seconds.");

Counted to 100 million in 0.271 seconds.

Here, the computer counts at a rate of 369 million increments a second! This is a nearly 30x improvement, just by writing the code in a more efficient manner. The algorithmic complexity is the same here, it’s just that each iteration takes that much less time to run. Still, it takes about 10 CPU cycles per increment, so let’s see if changing to a faster language speeds things up.

Switching to a faster language

The journey continues by porting this JavaScript code into C. The code is a little more terse, but it is doing the exact same thing as the JavaScript version.

#include <stdint.h>
#include <stdio.h>
#include <sys/time.h>

int main()
{
	uint64_t count = 0;
	struct timeval startTime, endTime;
	gettimeofday(&startTime, NULL);
	while(count < 1e8)
	{
		count++;
	}
	gettimeofday(&endTime, NULL);
	long long elapsedTime = \
		(endTime.tv_sec - startTime.tv_sec) * 1000000 + \
		(endTime.tv_usec - startTime.tv_usec);
	printf("Counted to 100 million in %lld microseconds.", elapsedTime);
	return 0;
}

Counted to 100 million in 174476 microseconds.

Hmm… That’s not all that much faster then the JS verison, let’s try it again…

Counted to 100 million in 64323 microseconds.

That’s really weird. Why would such a program be that much faster to run in some scenarios than others? To be clear, I ran this program several times and got a bimodal output, with the elapsed time being either ~65ms or ~170ms. I would occasionally also get values in the middle. The JavaScript runs were much more consistent.

The program is probably too small for caching to be a significant aspect. It’s only a few instructions of code, at least in the time-sensitive loop. My hypothesis is that CPU clock speed is a major factor here, but when trying to count higher, the count speed decreased on average, with a speed of 500M-1.0B / sec as opposed to the 573M-1.55B / sec when counting to 100 million.

I will dig deeper into what is actually going on in the next blog post!

Summary table of counting speed

Method Increments / second
Very naive JavaScript 12.6M
Naive JavaScript 369M
Naive C 573M - 1.55B