C
CellPerformance
cellperformance.beyond3d.com · Personal blog · on HN since 2009
Mike Acton's articles on game and console performance, covering strict aliasing, restrict, concurrency, and data-oriented design.
What HN saysHN cites it for "Three Big Lies" and its data-over-code argument, plus its concurrency introduction and its aliasing articles in C optimizer debates.
19HN people shared it
12linked it in comments
16stories submitted
59story points
1 year agolast shared
2009people per year2026
Most-shared posts
- 1Understanding Strict Aliasing (2006)8 people · 3 points · first shared 2010 · discussion on HN
- 2Three Big Lies (2008)6 people · 49 points · first shared 2010 · 32 comments on HN
- 3Roundup: Recent sketches on concurrency, data design and performance4 people · 4 points · first shared 2009 · 1 comments on HN
- 4Demystifying the Restrict Keyword (2006)3 people · 1 points · first shared 2015 · discussion on HN
- 5Diving Down the Concurrency Rabbit Hole [pdf]1 people · 2 points · first shared 2017 · discussion on HN
- 6Performance and good data design1 people · first shared 2010
What HN people wrote when they linked it
matheusmoreira · 2023-09-28
> he needs to accommodate that
Clearly he doesn't. He just disabled harmful features and called it a day. Stuff like strict aliasing and undefined signed integer overflow apparently do nothing but serve as an excuse for the optimizer to screw up perfectly reasonable code.
https://cellperformance.beyond3d.com/articles/2006/06/understanding-st…
https://stackoverflow.com/q/2958633/512904
Looks like this is a pretty good approach to fixing the C language. Take the nonsensical undefined stuff and tell the compiler to define it.
Looks like there is a may_alias type attribute to tell GCC that some types may alias:
https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-m…
I'm not sure if it's worth the effort though.
Impossible · 2020-08-13
Rule 5 (data dominates) is exactly the same as lie 3 (code is more important than data) of Mike Acton's Three Big Lies (https://cellperformance.beyond3d.com/articles/2008/03/three-big-lies.h… Rob Pike's rule 3 (don't use fancy algorithms) is closely related to Mike Acton's lie 1 (software is a platform) as well.
A part of me wonders if Mike was influenced by Rob Pike's rules directly or indirectly. It's also something that an experienced programmer can discover independently easily enough. Mike Acton was clearly heavily influenced by some of the failures of classic OOP design (lie 2 of Three Big lies).
beefhash · 2018-11-12
If uint8_t exists, then I believe the following ought to be true:
1. CHAR_BITS == 8, and
2. the compiler is required to make uint8_t an alias of unsigned char.
Point 2 is there so that you can cast to uint8_t safely, which some cryptographic code tends to rely on. If uint8_t is just any integer type, there's no safe cast to uint8_t due to strict aliasing rules[1]. That's what I want to fix. CHAR_BITS == 8 if uint8_t exists is just a collateral.
[1] https://cellperformance.beyond3d.com/articles/2006/06/understanding-st…
mischanix · 2015-03-16
If you're interested in writing concurrent code worth running, Mike Acton has a nice introduction:
http://cellperformance.beyond3d.com/articles/2009/08/roundup-recent-sk…
davidmathers · 2010-12-10
I think this is pretty well stated:
There is no value in code being some kind of model or map of an imaginary world. I don't know why this one is so compelling for some programmers, but it is extremely popular. If there's a rocket in the game, rest assured that there is a "Rocket" class (Assuming the code is C++) which contains data for exactly one rocket and does rockety stuff. With no regard at all for what data tranformation is really being done, or for the layout of the data. Or for that matter, without the basic understanding that where there's one thing, there's probably more than one.
Though there are a lot of performance penalties for this kind of design, the most significant one is that it doesn't scale. At all. One hundred rockets costs one hundred times as much as one rocket. And it's extremely likely it costs even more than that! Even to a non-programmer, that shouldn't make any sense. Economy of scale. If you have more of something, it should get cheaper, not more expensive. And the way to do that is to design the data properly and group things by similar transformations.
It's from this blog post called "3 Big Lies": http://cellperformance.beyond3d.com/articles/2008/03/three-big-lies.ht…
When I read it I thought: "That's a pretty common understanding isn't it? Not really a big lie." Then a few days ago I saw this: http://www.quora.com/What-is-the-best-mental-model-for-object-oriented…
Facepalm. Note the "M.S. degree in computer science." WTF? To…
zsmi · 2021-04-21
One should never loose to the complier, after all you can see it's output and it can't see yours.
Also, the programmer can "cheat" by doing things the compiler would consider invalid but are known to be ok given the larger context of the application.
The restrict keyword in c gives an example of how one can optimize code by knowing the larger context.
https://cellperformance.beyond3d.com/articles/2006/05/demystifying-the…
The problem is the ROI is usually pretty bad as these assumptions rarely hold as the code evolves, in my experience, and the optimization usually only lasts for finite (sometimes shockingly short) amount of time. i.e. OS changes, hardware changes, memory changes, etc. etc. etc.
dmm · 2016-11-07
Strict aliasing can worked around by casting through a union, essentially introducing a new type which can alias any of its component types. Mike Acton has a good description of it with lots of assembly examples here:
http://cellperformance.beyond3d.com/articles/2006/06/understanding-str…
raymondh · 2015-11-24
premchai21 · 2012-09-16
I actually use macros along the lines of:
#define LOAD(TYP, ptr) (*((TYP *)memcpy((TYP[1]){ }, ptr, sizeof(TYP))))
#define REINTERPRET(AS_TYP, FROM_TYP, val) LOAD(AS_TYP, (FROM_TYP[1]){ val })
In practice (that I've found, with GCC), the memcpy and single-use temporaries get optimized away entirely. In strict C99, writing one member of a union and then reading a different member of the same union is undefined in the general case, last I checked. http://cellperformance.beyond3d.com/articles/2006/06/understanding-str… seems to agree, but suggests that every major compiler recognizes it as a de facto idiom and supports it anyway.
corysama · 2010-12-01
Unfortunately, not much. The first page of google hits are all pretty good, but short. Also, Mike Acton of Insomniac has ranted about it a couple of times.
http://cellperformance.beyond3d.com/articles/2006/04/performance-and-g…
http://cellperformance.beyond3d.com/articles/2009/08/roundup-recent-sk…
There are a lot of component-design links here:
http://stackoverflow.com/questions/1901251/component-based-game-engine…
I don't know if any of them address batch-processing though...
wizeman · 2022-11-14
> Therefore the existence of the q pointer does not tell the compiler what type actually exists at memory address p/q. Is it invalid to construct q from p? I wouldn't think so as long as they are in the same allocation, but maybe I'm forgetting a rule.
But then the question is, how would you construct an allocation where both q[-1] and *p are guaranteed to be valid objects of their respective types, using standard C? (i.e. without relying on implementation-specific behavior).
> Surely there's a way to allocate two different types up against each other, though?
If by "against each other" you mean without padding between them, then I think the C standard allows that but there's no reliable/portable/guaranteed way to do it (that I know of).
By that I mean that specific implementations can guarantee that, either with struct packing or, in some cases, by carefully aligning them within a struct or a union. But this depends on the implementation/architecture, so it's not strictly portable/standard C, I think.
> Even if you don't make an actual struct, you can grab some char and say that X bytes are size_t and Y bytes are something else, can't you?
I'm not sure that is possible according to the standard, unless they already were objects of those types. See this[0]:
> It is always presumed that a char* may refer to an alias of any object. It is therefore quite safe, if perhaps a bit unoptimal (for architecture with wide loads and stores) to cast any pointer of any type to a…
strangetortoise · 2022-10-10
Not sure if you're familiar with Mike Acton (as mentioned in the article). One of his key points of focus is data-oriented design, and that when designing software, ignoring the architectural realities of the hardware is ignoring one of your responsibilities as an engineer to deliver performant software.
Now, it's possible to argue that writing performant software is not important. The prevailing modern sentiment definitely seems to be "The compiler / interpreter takes care of that". But given his track record of delivering high performant running software, and the trend in computing towards sluggishness, I'm trending more and more towards his camp, than the "don't micro-manage the runtime" camp (which is starting to feel more and more like a thinly-veiled "I don't want to have to think about it").
Edit: A summary post he wrote as a source https://cellperformance.beyond3d.com/articles/2008/03/three-big-lies.h…