Overview
This rather big devlog is entirely dedicated to optimizing the previous implementation as per the optimization sidequest. To sum it up, I implemented a more optimized data structure to hold the grid and a more optimized way of counting neighbors and computing the next generation in the game. Below you can find a more detailed explanation of the commits that contain this work.
Optimized data structure & functions
The biggest change here is the aforementioned optimized data structure, which is the bitmap. Instead of storing each cell as a char (8 bits per cell), each cell gets a bit inside a bitmap (1 bit per cell), which drastically decreases the memory usage of this program by 8 times.
For this to work, I had to implement functions to work with the bitmap instead of the char array. They’re named exactly the same as the older functions, just with Bitmap prefixed to clearly indicate the use case.
Benchmark
Another notable change in this commit is the addition of a benchmark, which compares the old and new implementations of the function that computes the next generation. You can run a benchmark by passing an option --bench <number> where <number> is the desired amount of iterations to test. Optionally, you can also pass the width and height of the grid that will be benchmarked.
The actual benchmark is not primitive either - it first warms up the caches by running a few iterations before actually timing the functions. Both the functions get the same starting grid to ensure fairness while comparing. The timing uses CLOCK_MONOTONIC, which is NOT affected by system time changes and it can only move forward.
Optimization results
As mentioned before, the memory usage is 8x lower now, due to storing one cell in one bit rather than one cell in 8 bits. The new function to compute the next generation is also much faster, and from my testing can vary between 3x-4x speedup (see image 1). These are by no means small gains, and you would see the difference especially if you’re trying to simulate huge grids. More details can be found in the Optimizations section of the README here.
Overview
This is a bugfix/slight improvements commit. I focused on memory leaks, which I initially missed. I also fixed inconsistent naming of the new functions. I have also gone through and improved checks in some functions that were missing to ensure that no incorrect behavior will go on unnoticed.
One small improvement I have made that I find quite noticable is the fact that if you forget to include a value where you’re supposed to have one, the program won’t silently continue and just skip that argument, but rather terminate after printing the help message (see image 2).