Live data from Hacker News

Random Acts of Optimization

engineering.riotgames.com

81–90 of 128 posts

Re: Random Acts of Optimization

#81
post #70

Earlier quoted context omitted.

Profiling comes with its own baggage, nothing's perfect. A lot of times one actually knows the likely/unlikely paths at development time; that's certainly true for error conditions. It makes sense to inform the compiler of those cases using the builtins.

Sure I'm not saying profiling is perfect. I was just taking exception to the statement that profiling is nothing but a poor man's substitute for a cost model. Explicit annotations for hot/cold paths are useful, I agree. I would probably be more excited about them except last time I actually tried them with GCC, they slowed my code down (admittedly this was five years ago or so). But that's just an implementation prob…

I agree - profile and cost model are orthogonal and complementary. Former tells you what to optimize, latter dictates how to optimize it.

Re: Random Acts of Optimization

#82
post #71

Earlier quoted context omitted.

>For example, error paths are generally very cold, but how is a compiler supposed to know that a path is an error path? They just look like regular conditionals. At least for .NET that path is likely throwing an exception. If you don't have a profile, statically assuming those paths are cold is likely to be correct.

That's an interesting point -- my background is more in C and C++-without-exceptions. But in exception-based languages, I can see how the presence of "throw" would be a very useful signal for static analysis.

Yes, this is a side benefit to exceptions (or some other language's way to highlight errors and thus likely cold paths).

Re: Random Acts of Optimization

#83
post #56

Hey everyone, I'm the author of this article and I'm glad you've found it interesting. I'll be keeping an eye on this thread, so if you have any questions or comments I'll address them as soon as I can. I can already see some awesome questions here - looking forward to the discussion.

Why scan the table of precomputed values? It seems like the code would be both cleaner and faster like this: class AnimatedVariable { int numValues; std::vector values; // ... } Then: if (!mPrecomputed) { float idx = time * numValues; float before = values[idx], after = values[idx+1]; return lerp(before, after, idx - (int)idx); } I guess there's a bit of float -> int coercion going on there, but it shouldn't be too b…

Because we are interpolating between keys which aren't evenly distributed in time. What you have there is pretty much what we do when looking up the precomputed values from the table.

Re: Random Acts of Optimization

#84

Earlier quoted context omitted.

Actually, they can, and quite well actually. The dotnet native compiler actually does quite a few analyses for "hotness", mostly centered around maintaining cache locality. However if there is a lot of entropy in the possible code paths, it might not be computationally feasible to analyze the hotness of all of the paths. In those cases, we accept heuristic substitutes, of which both JITs and PGO have shown good resul…

> it might not be computationally feasible to analyze the hotness of all of the paths It has nothing to do with computational feasibility. It has to do with the fact that it depends on the input. In many cases there simply is not enough information at compile time to determine which paths are hotter than others. For example, error paths are generally very cold, but how is a compiler supposed to know that a path is an…

> It has nothing to do with computational feasibility. It has to do with the fact that it depends on the input. In many cases there simply is not enough information at compile time to determine which paths are hotter than others.

That's a fair point, but still quite a bit overstated. There are a variety of analyses that compilers can and do perform to understand possible input before it ever receives the input. I'm familiar with a handful of probabilistic and set-cardinality estimation techniques used in math optimization pre-solvers (a form of compiler) that do exactly this, and I'm pretty sure both GCC and LLVM already do several similar analyses.

Furthermore, a very large subset of optimizations won't have any path dependence in the optimization that it choses, and a significant subset after that has choice thresholds that are trivially computable given an accurate cost model. When the former happens, profiling gives no advantage at all, and when the latter happens, it is typically more efficient to branch on that threshold than it is to try to guess at which choice is more efficient by measuring sample input.

> For example, error paths are generally very cold, but how is a compiler supposed to know that a path is an error path? They just look like regular conditionals.

That might be true of some languages, but not so with others. Exceptions are obviously error paths, and several strongly typed languages have error paths encoded in the type system.

> JIT and PGO aren't heuristic, they are based on measurement. By your logic, if I look at the speedometer in my car that is just a "heuristic" of my speed. It's not a heuristic, it's an empirical measurement.

But that's the thing, measurement of your input is a heuristic. If your program execution is heavily influenced by its input, and you optimize using profiling, you are assuming that past input is predictive of future input. That assumption is a heuristic. It might be a really good heuristic, but it still is a heuristic.

Re: Random Acts of Optimization

#85

Hi all, I work with Tony the author of the article and answer (or find someone to answer) any league questions you might have. Tony will be most likely be online later in the day as he works remotely with us from Australia.

Could the order of condition-statements-machine-code (as in the case handling code)e.g. in the particle code be made rearranging according to in-game-heat-counting?

You could, but I doubt it would have much of an effect on performance. Modern CPUs are ridiculously good at looking ahead and executing paths pre-emptively, meaning that branching is far less of an issue. On the older consoles, branching was a big issue, so that would have helped there.

Re: Random Acts of Optimization

#86
post #72
post #64

Earlier quoted context omitted.

>Perhaps I'm being overly idealistic, but I can't help but hope for a day that I can work with a high level language and have the compiler take care of optimizations I believe optimizing compilers are already a thing. Am I missing something here?

Currently for game development optimizing compilers are useful but hardly free you from worrying about optimizations. At least when you are using C++: a) Optimizing compilers can't organize your data to be cache friendly. b) optimizing compilers can't re-organize your code to prefer sequential access to that data so the HW prefetch can prevent cache misses c) optimizing compilers can't separate out the parallelizable…

Optimizers are mostly about stripping away abstraction costs of the language. If anyone is asking for more, they're disillusioned :).

Re: Random Acts of Optimization

#87

Earlier quoted context omitted.

For video games you usually have at least Debug, Release, Retail builds. Where Retail turns on Link Time Code Generation (LTCG) which is quite slow but can give a few percent extra perf. If PGO took 10x to compile but gave a 20% perf boost it'd be an absolute no brainer for game development. Keeping in mind that article shared here was a video game. It's possible that PGO is pretty awesome these days and people just…

I work on a major AAA title due to be released in a few months - our compile times are 20-25 minutes for Windows build(Debug/Release/Final), 10-15 minutes for Xbox One/PS4(consoles link much faster), and for Retail builds, with link time optimization, the build takes anywhere between an hour, hour and a half. That's on a machine with a 6-core, 12 threaded intel Xeon(we use distributed build anyway), 64GB of ram and t…

Thank you for proving my point gambiting. @forrestthewoods, asset baking is already 50-200% of the gambiting's non-Retail workflow build time. This is before PGO. Ask him, if had to choose between reducing his build time 10% (without a game performance penalty), or, increasing his build time 1000% (with a game performance improvement of 15%), I think he'll quickly choose the first option. Debug time/feedback is much more valuable (usually) [0].

[0] http://prog21.dadgum.com/47.html

Re: Random Acts of Optimization

#88

This brings up a thought that I've had for a very long time. Almost every type of optimization that a programmer could employ is repeatable. It involves matching patterns ("Identification" in the context of this article), analysis ("Comprehension"), and rewriting ("Iteration"). All of these steps can be efficiently automated. And it turns out that compiler writers collectively know about the vast majority of these te…

Please show us some of these promised optimizations. I don't think they actually exist. Most of the larger code / algorithm tweaks require subtle changes to the behaviour. The compiler can't choose to do that by itself, as it could break the program. Programmers need to make these choices for themselves. Besides which, compilers can already select slow or fast optimizations on the command line, so users can minimize…

> Please show us some of these promised optimizations. I don't think they actually exist.

I already gave two examples: "removing redundant elements from struct definitions all the way down to bitshift optimizations like i * 28 == i> Most of the larger code / algorithm tweaks require subtle changes to the behaviour. The compiler can't choose to do that by itself, as it could break the program. Programmers need to make these choices for themselves.

If it introduces a bug, then it is not an optimization, and it has no business being included in an optimizer (at least without explicit flags like -ffast-math).

> Besides which, compilers can already select slow or fast optimizations on the command line, so users can minimize compile time if they wish. There are plenty of people who would give anything for faster code, no matter what the compile time is.

My whole point is that -O3 is still weak sauce. There are tons of compiler optimizations that are excluded from both GCC and LLVM because of fears of compilation time impacts. Take a look at the specific techniques section of this wiki article: https://en.wikipedia.org/wiki/Optimizing_compiler

I can guarantee you that the mainstream C compilers cover maybe half of those, and for lesser known languages far less than half.

Re: Random Acts of Optimization

#89

Earlier quoted context omitted.

> it might not be computationally feasible to analyze the hotness of all of the paths It has nothing to do with computational feasibility. It has to do with the fact that it depends on the input. In many cases there simply is not enough information at compile time to determine which paths are hotter than others. For example, error paths are generally very cold, but how is a compiler supposed to know that a path is an…

> It has nothing to do with computational feasibility. It has to do with the fact that it depends on the input. In many cases there simply is not enough information at compile time to determine which paths are hotter than others. That's a fair point, but still quite a bit overstated. There are a variety of analyses that compilers can and do perform to understand possible input before it ever receives the input . I'm…

> Furthermore, a very large subset of optimizations won't have any path dependence in the optimization that it choses

Hot code should be: optimized for speed, inlined, unrolled (where it helps), kept local with other hot code, and register-allocated with other hot code.

Cold code should be: optimized for size, not inlined, not unrolled, kept away from hot code, and should never be accommodated in register allocation for any reason (ie. should never reduce availability of registers needed by hot paths).

So I don't agree that optimizations should be performed in a path-independent way.

> But that's the thing, measurement of your input is a heuristic.

By that standard, everything is heuristic. The assumption that your cost model matches the actual CPU the code will run on is a heuristic.

Re: Random Acts of Optimization

#90

Earlier quoted context omitted.

Actually, they can, and quite well actually. The dotnet native compiler actually does quite a few analyses for "hotness", mostly centered around maintaining cache locality. However if there is a lot of entropy in the possible code paths, it might not be computationally feasible to analyze the hotness of all of the paths. In those cases, we accept heuristic substitutes, of which both JITs and PGO have shown good resul…

> it might not be computationally feasible to analyze the hotness of all of the paths It has nothing to do with computational feasibility. It has to do with the fact that it depends on the input. In many cases there simply is not enough information at compile time to determine which paths are hotter than others. For example, error paths are generally very cold, but how is a compiler supposed to know that a path is an…

> It has to do with the fact that it depends on the input.

A special case of: https://en.wikipedia.org/wiki/No_free_lunch_in_search_and_op...

This does not hold, of course, if you could automatically simulate the users themselves...

Post reply on HN