Hacker News new | ask | show | jobs
by mattnewport 3106 days ago
A pretty common trick that was part of game programmer lore back in the PS2 / Xbox era was to have a large static array hidden away in some code file somewhere. When days before shipping you couldn't quite fit the release build in to memory this allowed a heroic programmer to miraculously 'find' a few hundred extra kilobytes of memory by reducing the size of the array by just enough to fit.

There was a less common variant of this for finding some extra performance by reducing the iterations of a loop doing no-ops somewhere in the main game loop.

5 comments

Sadly this usually works only once, especially if it's one person doing it.

I used to work on the performance team at a Bay Area company. One of the things we did to keep our JavaScript bundle sizes under control was introduce a "ratchet". There was a threshold, enforced by CI, that you couldn't let the bundle size exceed without getting in touch with us first and figuring something out. [0]

This worked wonders for a while, until a few different teams were starting new feature development. At that point, the ratchet was forcing teams to pause their feature development to do cleanup work, which made the PMs very unhappy. Engineers got salty because they would remove dead code, only to find that another engineer had gobbled up the space they'd freed before they could land their own commit.

Engineers started working around the ratchet by hoarding dead code and disguising it to look "not dead" so that it could be easily removed later when a few dozen kilobytes were needed.

There were many thing that weren't good at this company, and the culture around ownership of the shared codebase was definitely one of them. I'd like to think that there are plenty of teams that don't have this problem, but I'm inclined to think that it's human nature to subvert these sorts of things by default.

[0] This was necessary because of the volume of tech debt. Teams/engineers had a bad habit of building new things, then not cleaning up the stuff the new things replaced. At one point, we estimated that over a third of the JavaScript was dead code. Some teams had gotten to the point where the codebase contained >2 versions of their product, while only one of them was physically accessible to users.

Back in the era where this was somewhat common on games it only had to work once. In those days you burned a master for a console game and once it shipped that game was done. There were no zero day patches (or any other kind of patches) and no updates to the game once it shipped.

Often it would be the lead programmer on the game who put this array in and it wouldn't necessarily be known about by everyone. It wouldn't have worked well if people were constantly grabbing bits of memory from it during development. It worked because it was a 'secret' and its use was reserved for shipping.

> Engineers started working around the ratchet by hoarding dead code and disguising it to look "not dead" so that it could be easily removed later when a few dozen kilobytes were needed.

Sounds like an example of the cobra effect[1]

[1] https://en.wikipedia.org/wiki/Cobra_effect

Not only in game programming.

Chet Haase & Romain Guy also told on their Android history keynote that the kernel team did the same. They have hidden 20 MB.

https://www.youtube.com/watch?v=rimXGaUdaLg&t=773s

I used to be a huge gamasutra reader so I've read the postmortem that described this.

I was under the assumption that it was more of an apocryphal story that didn't actually happen. I mean how can someone hide a static array or no op loop from a team of 20+ programmers in a game code base.

As far as I'm aware, it was never confirmed and seems a bit to far fetched to be real, but then again.... :)

I've seen it done. In those days programming teams were usually smaller and this would be something put in place by a lead (usually a grizzled veteran of shipping multiple titles) and not advertised to the entire team. It might be hidden away somewhere like the core memory manager which would be owned by that lead and not generally touched by anyone else without consulting them. If someone happened to find it when running a memory profile they'd probably go and ask the lead about it and be let in on the 'secret'.

I actually found one of these when pulled in to help a title ship that had been put in for a previous title in the franchise and forgotten about when the lead moved on. I found it when memory profiling and after talking with a few people we figured out what it was there for and I got to be the 'hero' who found some extra memory to ship.

> If someone happened to find it when running a memory profile they'd probably go and ask the lead about it and be let in on the 'secret'.

Perhaps the obvious question here is "hidden from who?" Blinding the entire dev team to the trick might be possible for the lead, but sounds like a pain.

But squirreling away a bit of memory that won't be announced to PMs/artists/designers/producers? I can certainly picture a couple of programmers realizing that the person calling the shots intended to push them to the absolute limits of "what will fit", and deciding to fudge those limits. Hell, hedging is common practice for programmers and freelancers today when they anticipate bad requirements, and everything I know of the game development's history says the problem used to be much worse.

It's pretty normal for game assets to follow their own version of Parkinson's Law https://en.wikipedia.org/wiki/Parkinson%27s_law and expand to fill the memory / performance budget available (usually at least +5-10%). That can be just a consequence of artists and designers trying to make the best game they can within the budget available to them and so isn't particularly a bad thing. That's why an experienced programmer building in a 'secret' extra buffer for use around ship became a thing.
Yeah, I've seen something similar done to the art budgets, but hiding memory from programmers is impossible if they had any clue, especially on PS2/Xbox (32M/64M RAM). You could read .map in 5 minutes and see anything suspicious. Same with delay loops - good luck with that. Though I've observed some "miraculous" recoveries due to utter idiocy. E.g. a PS2 game using double floats (because your time calculations will break after few hours with a 32-bit float, duh!). The CPU had 0 double support so they were all done in software and the library with it was rolled into the standard math lib. Or some incredibly misguided GPU programming done to a "non-lead SKU". Nobody notices that one system runs 5 times slower than another until it's close to shipping and you try to bring it to QA.
The point was not to hide memory from programmers who "had a clue" if they went looking. During production, most programmers on the team would be focused on delivering features they were responsible for and fixing bugs. If they were doing perf or memory profiling it would mostly be focused on whatever feature they were implementing. Only a few people on the team, perhaps only the lead, would be looking at global memory usage / perf on a regular basis and even then they'd mostly be looking for regressions. If anyone did happen across this they'd probably go talk to the lead (there might even be a comment directing them to do so) and be let in on the 'secret'.

At the end of production coming up to release is when there'd be a wider focus on general perf / memory usage to get everything to fit for the final release build. In my anecdote above, the reason I happened to find an example of reserved memory was just that I happened to be the first person to go looking in the right place with the right tools, not due to any particular skill or experience on my part (I was pretty junior at the time, this would probably have been around 2004 towards the end of the PS2 / Xbox console generation).

I don't buy it. If you need to shave some bytes the first thing you do is look at the map file or run a binary analysis tool to figure out what the best candidates for optimisation are.

And if your performance is poor the first thing you do is add some debug code to measure what is taking too long and where the biggest gains can be made.

The whole point of these tools is to make this stuff easy to find.

Noel Llopis is quoted here as saying it did happen: https://www.gamasutra.com/view/feature/132500/dirty_coding_t...

I'd assume that in the era where lots of stuff was global and code was messy and convoluted to fit into a console no one would take issue with yet another global variable if it was named a clever enough name as some buffer, temporary, cache, etc. and compilers didn't yet warn about unused variables or remove them (which is an easy fix in C anyway with a single totally portable line or a special compiler specific directive).

I have seen it mentioned here on page 4: https://www.gamasutra.com/view/feature/132500/dirty_coding_t...

There's yet another article on dirty game hacks that I recall due to EULA self-hack: https://www.gamasutra.com/view/feature/194772/dirty_game_dev...

I have no idea why this article doesn't link to these two and just to the 2017 one because it's not like these are current generation tricks, it's just that Brandon Sheffield took to write about them again (one of the articles above is actually his and the other one is by GDM that he is editor in chief of).

Also, the Crash Bandicoot text is the most impressive one and the first in this article but it was very widely circulated for a while now on several sites (including on HN once), despite the "nobody was the wiser until now" at the start of the article.

The one on the last page about using dexdrive was pretty cool. I used a similar technique to create ps1 save files that would trigger an exploit on the ps2 that would load unsigned code. I miss being able to do stuff like that. Modern systems are so locked down.
Hah yup, we kept 15M tucked away on the last game I shipped. Came in handy for demos more than anything else.