Bernstein agrees with you. His point isn't that it's dumb that CPUs are optimized for games. It's that cipher designers should have enough awareness of trends in CPU development to design ciphers that take advantage of the same features that games do. That's what he did with Salsa/ChaCha. His subtext is that over the medium term he believes his ciphers will outperform AES, despite AES having AES-NI hardware support.
Besides, CPUs are only optimized for games if you write your code to take advantage of it.
I worked on AAA engines that completely disregarded caches and branch prediction and while that worked great 10 years ago the same architecture became crippled on modern CPUs. Its so very easy to trash CPU resources that at this point I'm convinced most programs easily waste 90% of their CPU time.
For the last AAA title I shipped we spent weeks optimizing the threads scheduling, priorities and affinities along with profiling and whatnot; it was still an incredible challenge to use the main core above 80% and the other cores above 60%. If your architecture doesn't take the hardware into account from the ground up, you're not going to fully use the hardware :)
There is a potential counter-argument that this is because multicore is an example of a CPU feature that was not designed for videogames. :)
I don't know if that's strictly true, but I do feel games aren't as easy to split across threads/cores as many other types of software. Ultimately, a game boils down to one big giant blob of highly mutable and intertwined state (the world) that is modified very frequently with very low latency and where all reads should show a consistent view.
In other domains, avoiding interaction between different parts of your application state is a good thing that leads to easier maintenance and often better behavior. In a game, the whole point is having a rich world where entities in it interact with each other in interesting ways.
I don't think any CPU features were designed specifically for video games. But video games often have workloads that fit nicely on top of the CPU.
You don't need interactions between entities at every point in time. There are very specific sync points during a frame and there isn't many of them (maybe 5 or 6). Your units can also be organized in a table where each row can be updated in parallel before moving on to the next.
Many types of software can get away using only concurrency or parallelism. Game engines have to master both. You want parallelism to crunch your unit updates and you want concurrency to overlap your render pass on top of the next frame's update pass.
To me the whole view of the game world being a "giant blob of highly mutable and intertwined state" stems from the fact that for over a decade all games had to do was have an update and a render pass in the main loop. So you could have a big mess because all of the world updates were serial, and so the developers didn't really experience the problems arising from such design.
Now it takes a change in perspective on how to structure code and data to properly exploit multiple cores to their full potential. It is certainly possible to have interaction in the game world and do it in a multi-core multi-threaded way, it just needs smarter structures and better organisation of data.
Its not nearly as easy as it sounds. I think game engine developers now understand multi-core a LOT better than programmers from most other domains.
Games are still just an update and render pass in a loop. Nothing will change that, they might be decoupled and overlapped but they're still present. They're just much more complex than they used to be. Some engines will fork/join at every step (sometimes hundreds of times per frame), others will build task graphs and reduce them and a 3rd team will use fibers to build implicit graphs. No matter what you do you're still executing code with very clean sequential dependencies.
Game engines started going multi-core at least a decade ago. First by using one thread per system, then moving towards tasks. Today I don't know of any AAA game engine not already parallelizing its render path and unit updates massively.
> There is a potential counter-argument that this is because multicore is an example of a CPU feature that was not designed for videogames.
That's a common trope; it mostly applies to the rendering path. AI / Physic engines are nicely scalable with the number of cores (AI in particular, because a) it's oftern agent based, which naturally work concurrently and b) with AI, slighly relaxed synchronization constraints sometimes generate some desirable degrees of fuzziness and unpredictability ... although this is probably a very slippery slope ...)
> I'm convinced most programs easily waste 90% of their CPU time.
Hah, in my experience that's hopelessly optimistic. The C I write is probably 10-100x slower than it should be (leaving SSE and threading aside entirely), but the Python I write most days is a hundred times slower still.
This is optimizing the same numeric algorithm (word2vec) using different languages and tricks, from naive pure-Python down to compiled Cython with optimized CPU-specific assembly/Fortran (BLAS) for the hotspots [0].
Eh, doubtful. Sure, it'll be faster than unoptimized C. But when you observe strict aliasing rules in C a modern compiler will generally produce similar quality assembly for both languages. The reason BLAS is so fast is that every single line of code in a hot loop has been hand-optimized and tons of CPU-specific optimizations exist
Fortran yields some of the fastest code out of the box, yes, but C/C++ can yield equivalent performance by adhering to certain basic rules.
Even with strict aliasing, the only way C/C++ standard effectively lets one type to be cast to another is incurring a copy. Tell me what can be done better for performance in C that can't be done in Fortran or "another static language without pointer indirection".
You can get a lot of performance back just by taking branch predictions and cache misses into your designs.
I did just that in C# last years and got at least two orders of magnitude of performance gain from it. Still, I constantly wished I was working in C instead :)
On consoles we get access to the hardware specs and profilers for everything - even if behind huge paywalls and confidentiality contracts. Yet with all that information available its still insanely hard to optimize the codebase.
There's absolutely no incentive to push these tools/specs to hobbyists because even professionals have a hard time getting them. Its also worth mentioning that having access to the tools and specs doesn't mean you'll understand how to properly use them.
It is in retrospect a pretty banal observation. If cipher design is about achieving a certain security level at the lowest cost per byte, it sort of stands to reason that you'd want to design them around those features of a CPU on which the market is going to put the most pressure to improve.
In fairness, some of this design philosophy --- which Bernstein has held for a very long time! --- gets a lot clearer with the advent of modern ARX ciphers, which dispense with a lot of black magic in earlier block cipher designs.
A really good paper to read here is the original Salsa20 paper, which explains operation-by-operation why Bernstein chose each component of the cipher.
Eh. Remember that a lot of these guys think about hardware implementations, so they're fixated on ASICs, not GPUs.
At some point the inequality gets too far out of whack and it's time to reconsider your values. Same reason we keep switching back and forth between dominant network architectures every 8 years. Local storage gets too fast or too slow relative to network overhead and everyone wants to move the data. Then we catch up and they move it back.
There can often be a strong disconnect between theory and implementation. I don't believe you can be truly effective unless you can get your hands dirty with both. Although if you have to choose, I'd rather know a bit of theory, and a whole lot about reality, than vice versa. Constants factors matter in big O.