44
\$\begingroup\$

I am coming from software development background. During the software development cycle, we usually focus on functionalities and the working product. At the end of development, we start optimizing the code and improving performance.

Now the question is, do we need to think about performance in every single line of code in game development?

Doing so I feel we miss the design patterns and clean code. I was wondering if there is any best practice approach in game development industry?

\$\endgroup\$
7
  • 8
    \$\begingroup\$ You may find the discussion on this previous question about premature optimization useful. \$\endgroup\$
    – DMGregory
    Oct 15, 2017 at 3:06
  • 10
    \$\begingroup\$ In the beginning. As the project drags on, the performance will only get worse. \$\endgroup\$ Oct 15, 2017 at 19:18
  • 10
    \$\begingroup\$ The software development background you come from does not sound wholesome. Designs must take performance considerations into effect in all fields. How many network round trips, how many and how big database queries, how much memory used, and so on. It doesn't matter what field of engineering you do this in; if you fail to plan for performance, you plan for performance failure. \$\endgroup\$
    – Jon Watte
    Oct 15, 2017 at 20:17
  • 1
    \$\begingroup\$ All. The. Time. Save yourself some time and boring tasks by just doing all the time and you'll find yourself doing very cool and geeky tasks by trying to further optimize code than it already is (if necessary). That's where the fun begins. \$\endgroup\$
    – Yates
    Oct 16, 2017 at 14:15
  • 6
    \$\begingroup\$ "Considering" performance should happen on the day that you decide to make a product that has users. Users have minimum performance expectations, and if they are not met, then your product will fail. Performance has costs and products have budgets. If the minimum acceptable performance costs more than your budget, your project will fail. It's smart to think about that on day one, not day one hundred. \$\endgroup\$ Oct 16, 2017 at 20:49

6 Answers 6

89
\$\begingroup\$

Engineering for Performance

  • Follow vendor recommendations.
  • Use the correct data structures.
  • Implement the correct usage patterns.
  • Don't do anything stupid.

Optimization

  • When already written code is running slow, measure it, find out why, implement what is required to make it fast.

Premature Optimization

  • Make assumptions about what is fast or slow without measurements, build these assumptions into how code is designed and written.

These three things are not the same.

In particular Engineering for Performance is something you should be doing from the very start and it is most definitely not the same as Premature Optimization because it is drawing on actual measurements; in this case drawing on experience and recommendations as to how hardware works and what usage patterns are going to be fast or slow.

Failing to engineer for performance can lead to results as bad as needing an entire redesign and rewrite by the time you notice anything is wrong.

For example: all of the GPU vendors advise that doing readbacks from the GPU every frame is slow. Designing your code to not do readbacks is not premature optimization.

\$\endgroup\$
7
  • 28
    \$\begingroup\$ Thank you so very much for mentioning this. Developers always promulgate the evils of premature optimization with advice that's worded extremely to make the point, but often less experienced developers don't understand the nuance. Design it correctly from the beginning. That's NOT premature optimization. I say that you SHOULD be conscious of performance for every line you write. As a developer you should be aware of best practices so that you don't do stupid stuff. That said, you shouldn't paralyze yourself with optimization. Get something to run first, THEN focus on what's slowing it down. \$\endgroup\$
    – A C
    Oct 15, 2017 at 16:03
  • 2
    \$\begingroup\$ @AC I also feel like pointing out that good design might take time to start out with, but in the end it will probably mean you're done faster as well, which means more time over for optimization if needed. My experience (with a single, half-done solo hobby project to back it up) is that once your project gets large enough, the big time consumption is 1) "How am I going to weave this into everything that's already there", and 2) "Damnit, the code I wrote a week ago that fit perfectly then doesn't work at all with what I want to do next". Good design (which I haven't done) helps both of those. \$\endgroup\$
    – Arthur
    Oct 16, 2017 at 7:58
  • 5
    \$\begingroup\$ Failing to properly engineer for performance could also be thought of as pessimizing the design. So, if premature optimization is the root of all evil, what does that make of premature pessimization? ;P \$\endgroup\$
    – ninjalj
    Oct 16, 2017 at 10:47
  • 1
    \$\begingroup\$ @Arthur "more time [left] over for optimization" ? That's a good way to look at it as well, optimizing your own limited development resources (& workflow) so that you get optimum impact from your optimization effort! Also, I know we're not on Stack Overflow proper, but it amazes me that we're talking optimization and the Pareto Principle has not yet been mentioned in an answer... I don't even see the word "percent" ! \$\endgroup\$
    – A C
    Oct 16, 2017 at 17:04
  • 1
    \$\begingroup\$ When designing your data structures for good performance, you have to know computers can do efficiently and what they can't. e.g. modern CPUs looping over arrays can apply a huge amount of brute force, especially if you set things up so compilers can auto-vectorize with SSE / AVX. (e.g. use arrays of x coordinates and arrays of y coordinates, not arrays of xy pair structs or xyz triples. See stackoverflow.com/tags/sse/info for some links, especially SIMD at Insomniac Games (GDC 2015) \$\endgroup\$ Oct 17, 2017 at 14:02
22
\$\begingroup\$

If you want to do optimization at the right times, have slow machines and use them. For a small shop, a good option is to use a slow laptop on the commute and a fast desktop in the office. As an additional benefit, if you're a one man shop this also forces you to properly back up the entire build environment.

By using a slow machine you'll know when you need to improve performance.

do we need to think about performance in every single line of code in game development?

Absolutely not. Performance of a line of code is usually irrelevant in any kind of development. You need to think in terms of algorithms and algorithmic complexity, rather than in terms of lines. In many cases, decent programming means you can get about a 2 times speedup by optimizing lines of code, but choosing the right or wrong algorithm will result in factors between tens and millions.

The talk about premature optimization isn't actually about optimization being a bad thing. It's about people failing to optimize the right thing. Your time is one of the variables that needs to be optimized, which is achieved by not wasting time to "optimize" a function that is called once every 30 milliseconds and takes 100 microseconds to execute.

In other words: Making something "faster" is pointless. Your goal is "fast enough". Making something "faster" that is already "fast enough" is a waste of time, and making something "faster" that still isn't "fast enough" just means it's still too slow. "faster" is irrelevant, only "fast enough" is relevant.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ algorithms are only half the solution, correct use of data structures is also very important. Also, plan ahead for possibly introducing multithreading and 64 bit compilation - while not needed in every case, sometimes these features do matter, and they usually aren't easy/cheap to fit in retroactively if not planned for. (I know some games suffering from both of these issues.). \$\endgroup\$
    – hoffmale
    Oct 15, 2017 at 17:40
  • \$\begingroup\$ Much development is done with Debug builds that are much slower than the Release builds. This means a much faster machine is required for development than is required to run the game at an acceptable speed. \$\endgroup\$ Oct 16, 2017 at 14:43
  • \$\begingroup\$ Cache access patterns are also important, and can make factors of 10 or 100 difference. e.g. consider a naive matrix multiply (for a large matrix). Looping over one column of a row-major matrix is horrible. e.g. this Q&A has a factor of 13 perf difference for the same algorithmic complexity for adding a transpose before the loops, just for fixing the horrible access pattern. (Another factor of 10 or more can be gained from an optimized BLAS library, which cares even more about cache and SIMD...) \$\endgroup\$ Oct 17, 2017 at 13:53
9
\$\begingroup\$

No, you don't have to check after every line because not every line is performance-relevant. It mostly depends on how often a line is executed. A code section which takes 1 ms to be executed is completely irrelevant when it is executed once at game startup, worth watching when executed every frame and must definitely be optimized if executed for every game object each frame.

It also depends on what kind of game you are developing. When you are developing a very graphic-intense 3d shooter, you need to be much more performance-aware than when you are programming a retro-style RPG game.

In the end, the best advise is test, test, test. Build some realistic test-scenes for your game which put slightly more stuff on the screen than would be expected in the real game. Test it on hardware which is at the lower end of your targeted specs. Make sure the performance is as expected. When it gets worse, use a profiler to find the bottlenecks.

\$\endgroup\$
3
\$\begingroup\$

You need to put in enough effort to at least go "is this potentially going to be a bottleneck, and if so, how involved a change will it be to fix it?".

Generally speaking, this involves a balance between time/resources spent figuring out if something is the right direction and time/resources spent undoing bad decisions.

Think of it somewhat like renovating an apartment. Some decisions can have lasting repercussions ("Whoops, the fridge no longer fits in its cubby." "Whoops, where I want to put my bathroom has no water"), but you'll not think about how every stroke of your paint brush may affect e.g. the structural stability of the building.

Or, to put it another way, don't back yourself into a corner. Or at least know when you are backing yourself into a corner and make sure that is the corner you want to back into. For instance:

  • Am I tying game update rate to graphical framerate?
  • Am I forcing synchronous saving?
  • Am I forcing (non)-determinism?
\$\endgroup\$
1
\$\begingroup\$

For a game, your primary goal is to meet the target framerate on the target minimum spec machine (and possibly a maximum load time, etc).

In order to do that, no, you do not have to worry after every line.

You have to worry early whenever you select a particular strategy, algorithm, or container. If you make it literally impossible to meet the target by making inadequate design decisions, then any optimization that you may do later is to no avail.

Next, you have to worry whenever something is parallel or parallelizable. Games are massively parallel, if for no other reason, then because graphics are.
Therefore, parallel doesn't just mean "threads" but also for example the graphics API, disk access, or network. Whenever you miss the opportunity of having something that could easily and natively be parallelized run in parallel, for example due to synchronizing badly (or due to not using an asynchronous API at all), you lose more than you can ever optimize by other means.
You also have to worry whenever something is well-known to be a bottleneck or a source of stalls, or a hindrance to scaling. Such as, for example, switching render states, draw calls, reading back from the GPU, or opening files.

Last, when you are done, and testing shows that you do not meet the target frame rate, you need to optimize. Find the one biggest bottleneck that takes 90% of the time, and optimize that. If this is not enough, find the seconds biggest.
If you do meet the target, congratulations. Move on and forget it.

\$\endgroup\$
0
\$\begingroup\$

Get real. The answer is simply totally NO. No discussion.

The main problem is the way you ask:

do we need to think about performance in every single line of code in game development?

You mean, also in things like the config screens? Like a one time parser for a small 1kb max config file? Seriously?

It does not matter how time critical most of your code is. There is not a single software where every single line is time critical. Nowhere.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .