Update
This commit is contained in:
parent
aadf27a49f
commit
65fdd3799d
31 changed files with 1913 additions and 1808 deletions
|
@ -19,6 +19,7 @@ These are mainly for [C](c.md), but may be usable in other languages as well.
|
|||
- **You can almost always trade space (memory usage) for time (CPU demand) and vice versa** and you can also fine-tune this. You typically gain speed by precomputation (look up tables, more demanding on memory) and memory with [compression](compression.md) (more demanding on CPU).
|
||||
- **[Static](static.md) things are faster and smaller than [dynamic](dynamic.md) things.** This means that things that are somehow fixed/unchangeable are better in terms of performance (and usually also safer and better testable) than things that are allowed to change during [run time](runtime.md) -- for example calling a function directly (e.g. `myVar = myFunc();`) is both faster and requires fewer instructions than calling a function by pointer (e.g. `myVar = myFuncPointer();`): the latter is more flexible but for the price of performance, so if you don't need flexibility (dynamic behavior), use static behavior. This also applies to using [constants](constant.md) (faster/smaller) vs [variables](variable.md), static vs dynamic [typing](typing.md), normal vs dynamic [arrays](array.md) etc.
|
||||
- **Be smart, use [math](math.md)**, for example simplify [expressions](expression.md) using known formulas, minimize [logic circuits](logic_circuit.md) etc. Example: let's say you want to compute the radius of a zero-centered [bounding sphere](bounding_sphere.md) of an *N*-point [point cloud](point_cloud.md). Naively you might be computing the Euclidean distance (*sqrt(x^2 + y^2 + z^2)*) to each point and taking a maximum of them, however you can just find the maximum of squared distances (*x^2 + y^2 + z^2*) and return a square root of that maximum. This saves you a computation of *N - 1* square roots.
|
||||
- **Fancier algorithms will very often be slower than simpler ones, even if they are theoretically faster**, i.e. don't get too smart and first try the simple algorithm, greater complexity has to be justified. This was commented on e.g. by [Rob Pike](rob_pike.md) who said that "fancy algorithms are slow when n is small, and n is usually small", i.e. if you're sorting an array of 10 items, just use bubble sort, not quick sort etc.
|
||||
- **Learn about [dynamic programming](dynamic_programming.md)**.
|
||||
- **Avoid branches (ifs)** if you can (remember [ternary operators](ternary_operator.md), loop conditions etc. are branches as well). They break prediction in CPU pipelines and instruction preloading and are often source of great performance losses. Don't forget that you can many times compare and use the result of operations without using any branching (e.g. `x = (y == 5) + 1;` instead of `x = (y == 5) ? 2 : 1;`).
|
||||
- **Use iteration instead of [recursion](recursion.md)** if possible (calling a function costs something).
|
||||
|
@ -33,7 +34,7 @@ These are mainly for [C](c.md), but may be usable in other languages as well.
|
|||
- **Consider moving computation from run time to compile time**, see [preprocessor](preprocessor.md), [macros](macro.md) and [metaprogramming](metaprogramming.md). E.g. if you make a resolution of your game constant (as opposed to a variable), the compiler will be able to partially precompute expressions with the display dimensions and so speed up your program (but you won't be able to dynamically change resolution).
|
||||
- On some platforms such as [ARM](arm.md) the first **arguments to a function may be passed via registers**, so it may be better to have fewer parameters in functions.
|
||||
- **Passing arguments costs something**: passing a value to a function requires a push onto the stack and later its pop, so minimizing the number of parameters a function has, using global variables to pass arguments and doing things like passing structs by pointers rather than by value can help speed. { from *Game Programming Gurus* -drummyfish }
|
||||
- **Optimize when you already have a working code**. As [Donald Knuth](knuth.md) put it: "premature optimization is the root of all evil". Nevertheless you should get used to simple nobrainer efficient patterns by default and just write them automatically. Also do one optimization at a time, don't try to put in more optimizations at once.
|
||||
- **Optimize when you already have a working code** and when you can measure your optimizations. As [Donald Knuth](knuth.md) put it: "premature optimization is the root of all evil". Nevertheless you should get used to simple nobrainer efficient patterns by default and just write them automatically. Also do one optimization at a time, don't try to put in more optimizations at once.
|
||||
- **Use your own [caches](cache.md) where they help**, for example if you're frequently working with some database item you better pull it to memory and work with it there, then write it back once you're done (as opposed to communicating with the DB there and back).
|
||||
- **[Single compilation unit](single_compilation_unit.md) (one big program without [linking](linking.md)) can help compiler optimize better** because it can see the whole code at once, not just its parts. It will also make your program compile faster.
|
||||
- Search literature for **algorithms with better [complexity class](complexity_class.md)** ([sorts](sorting.md) are a nice example).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue