Top
Best
New

Posted by mariuz 1 day ago

The gold standard of optimization: A look under the hood of RollerCoaster Tycoon(larstofus.com)
556 points | 153 commentspage 3
makapuf 14 hours ago|
Compilers won't do multiplication by power of two to bit shift for you ? I remember reading in ~2000: the only thing writing a<<2 instead of a/4 will do is make your compiler yawn
zekica 11 hours ago|
Even gcc's -O0 will do the bitshift, but even dividing with 5 on x86_64 will not do idiv:

        imul    rdx, rdx, 1717986919
        shr     rdx, 32
        sar     edx
        sar     eax, 31
        sub     edx, eax
        mov     eax, edx
bze12 14 hours ago||
> This part is especially fascinating to me, since it turns an optimization done out of technical necessity into a gameplay feature.

Reminds me of blood moons in Zelda https://www.polygon.com/legend-zelda-tears-kingdom/23834440/...

egypturnash 19 hours ago||
I have to wonder how much of the original assembly source looked a lot more succinct than whatever's in OpenRCT due to the use of macros. Looking up his gameography on Mobygames, Chris had been writing stuff since 1984 when RCT came out in 1999, it's hard to imagine he was still writing every single opcode out by hand given that I had some macros in the assembler I was fooling around with on my c64 back in the eighties.
MisterTea 22 hours ago||
While it has been a while since playing RCT, one thing that was really nice about the game is that it runs flawlessly under Wine.

I really wish I could see the source code.

lefty2 1 day ago||
> The same trick can also be used for the other direction to save a division:

> NewValue = OldValue >> 3;

You need to be careful, because this doesn't work if the value is negative. A

whizzter 1 day ago||
Most CPU's has signed and unsigned right shift instructions (left shift is the same), so yes it works (You can test this in C by casting a signed to unsigned before shifting).

The biggest caveat is that right shifting -1 still produces -1 instead of 0, but that's usually fine for much older game fixed-point maths since -1 is close enough to 0.

lefty2 20 minutes ago|||
> -1 still produces -1 instead of 0 That could be a problem depending how you are using it.
adrian_b 23 hours ago||
It works fine when the value is negative.

However, there is a quirk of the hardware of most CPUs that has been inherited by the C language and by other languages.

There are multiple ways of defining integer division when the dividend is not a multiple of the divisor, depending on the rounding rule used for the quotient.

The 2 most frequently used definitions is to have a positive remainder, which corresponds to rounding the quotient by using the floor function, and to have a remainder of the same sign with the quotient, which corresponds to rounding the quotient by truncation.

In most CPUs, the hardware is designed such that for signed integers the division instruction uses the second definition, while the right shift uses the first definition.

This means that when the dividend is a multiple of the divisor, division and right shift are the same, but otherwise the quotient may differ by one unit due to different rounding rules.

Because of this, compilers will not replace automatically divisions with right shifts, because there are operands where the result is different.

Nevertheless, the programmer can always replace a division by a power of two with a right shift. In all the programs that I have ever seen, either the rounding rule for the quotient does not matter or the desired definition for the division is the one with positive remainder, i.e. the definition implemented by right shift.

In those cases when the rounding rule matters, the worrisome case is when you must use division not when you can use right shift, so you must correct the result to correspond to rounding by floor, instead of the rounding by truncation provided by the hardware. For this, you must not use the "/" operator of the C language, but one of the "div" functions from "stdlib.h", or you may use "/" but divide the absolute values of the operands, after which you compute the correct signed results.

londons_explore 1 day ago||
> it turns an optimization done out of technical necessity into a gameplay feature

And this folks is why an optimizing compiler can never beat sufficient quantities of human optimization.

The human can decide when the abstraction layers should be deliberately broken for performance reasons. A compiler cannot do that.

nulltrace 23 hours ago||
The LEA-vs-shift thread here kind of proves the point. Compilers are insanely good at that stuff now. Where they completely fall short is data layout. I had a message parser using `std::map<int, std::string>` for field lookup and the fix was just... a flat array indexed by tag number. No compiler is ever going to suggest that. Same deal with allocation. I spent a while messing with SIMD scanning and consteval tricks chasing latency, and the single biggest win turned out to be boring. Switched from per-message heap allocs to a pre-allocated buffer with `std::span` views into the original data. ~12 allocations per message down to zero. Compiler will optimize the hell out of your allocator code, it just won't tell you to stop calling it.
timschmidt 1 day ago|||
Agreed. It really requires an understanding of not just the software and computer it's running on, but the goal the combined system was meant to accomplish. Maybe some of us are starting to feed that sort of information into LLMs as part of spec-driven development, and maybe an LLM of tomorrow will be capable of noticing and exploiting such optimizations.
hrmtst93837 14 hours ago|||
If you think compilers can't punch through abstractions, you haven't seen what whole-program optimization does to an overengineered stack when the programer gives it enough visibility. They still miss intent, so the game-specific hack can win.
gwern 23 hours ago||
End-to-end optimization in action! Although I'd've liked more than 1 example (pathfinding) here.
random__duck 7 hours ago||
So this is what programing on hard mode looks like ?
throw_m239339 8 hours ago||
Fantastic write-up, that's exactly why I came to HN many years ago, to find such articles about mundane things or products, but the technical aspect is just fascinating.
rajan2 14 hours ago||
This is insane
rajan2 14 hours ago|
This is Insane
More comments...