Sunday, November 01, 2026

counter_game Has Been Released Upon the Unsuspecting World!

Today, I bring you: counter_game, the most simplified of idle games that I can come up with that is still somewhat meaningful.

The premise is simple: increment a 64-bit unsigned integer counter, one at a time.

And that's it.

It's fun because it is hilariously straightforward in terms of what it seeks to do. No funny multipliers, no annoying precision-loss when double-precision floating point numbers are inevitably used (staring at you, Cookie Clicker). Just good old fashioned incrementing of an integer variable.

What's really interesting are two things.

The first, is that modern CPUs are scary fast, even without taking into consideration that there are multiple cores per CPU. On a thermally limited machine that is Eileen-III, I am consistently seeing 5e+09-ish increments per second, while on a machine that does not have that limitation (i.e. running in an air-conditioned room), I had seen 7.4e+09 increments per second.

That's actually more than the burst clock speed of 5.5 GHz to 6.1 GHz that is common these days.

And yet, it still takes decades to truly rollover all 264 different values of the counter.

The second, is the iterations that I had went through to fixing the code up. The original code was written a few months ago, and its requirements were more or less the same as what I had released---increment a large unsigned integer counter in as tight a loop as possible, but have a means of keeping track of the work to resume later on somehow. And maybe have some simple output that is user-triggered to avoid the penalty of doing I/O for something that is ``obviously'' CPU bound.

Oh, and avoid the compiler from optimising away the ``obviously'' do-nothing increment loop.

I started with C99, and wrote something very similar to what I currently have, with the following major differences:
  1. The counter was originally of type static volatile uint64_t, which was because...
  2. ...the original signal handler was doing the actual saving of state, which meant that volatile was needed to tell the compiler to not optimise away what is effectively a ``do-nothing tight loop'' to the compiler; and
  3. I had to resort to some GCC extension of locale to enable thousands separators for the ludicrously large integers because I was too lazy to write my own C99-compliant version.
Reading the current code base should reveal that these things that I talked about were no longer there.

What happened?

Well, I chucked it into GPT-6 to see what the LLM could suggest as code improvements, and through to and fro, managed to converge to the current released version.

The only thing that wasn't really suggested by the LLM was the removal of that volatile specifier---with the signal handler only setting some atomic signal outside of the tight loop, and the logic for the I/O pushed into the tight loop but guarded by a signal comparison, the volatile storage class was no longer needed since the counter variable was in scope for both increment, and reference for the purposes of doing I/O.

For the confused, volatile tells the C99-compiler that a particular variable should be assumed to be backed by memory, which means that when optimising/generating code, the register-only optimisation is not allowed; all references to the volatile variable must load the value from the memory, and subsequently written back, without assuming/keeping the value based on what is in the register.

That change dramatically sped up the increment rate by more than 10-fold, since each increment no longer needed to go through the entire memory hierarchy of L*-caches before reaching RAM.

So with my foray into using LLM for support in software programming, what do I feel? Honestly, it isn't too bad, but to be fair, this is merely about improving an existing program that does something pretty simple---it is not a multi-file project with the full backing documentation of user requirements, project specifications, and everything else under the sun.

As a tool, it is fine for this case, but in some future post, I might talk about another different programming project that I had GPT-6 assist me. Spoiler: that one was a doozy, even though the outcome is still better than what I would do myself.

The key thing to take away is that using these tools really does make me lazier in some ways, and more hardworking in others. Yes, I wouldn't set out to write my own custom C99-compliant code to output the large integers in groups of six digits due to how annoying it was, but with the LLM yelling at me often enough about ``hur hur you claim C99 compliance but you're using GNU extensions you dumbass'' was enough to start the skeleton of that code, and have the GPT-6 finish it up.

``MT, what's the purpose of counter_game then?''

It's an idle game where a counter is diligently incremented one at a time by the CPU without funny modifiers, exponentiation shenanigans, and bad floating point numbers. That's its purpose. It can also act as a low-resource single-thread (not core since I do not put in non-C99-compliant CPU affinity setting code) performance tester for a computer that runs Cygwin/Linux, at least on the dimension of incrementing a register.

I think that's as pithy a response as I have.

Till the next update.