Sign in to follow this  
ic0de

Optimization philosophy and what to do when performance doesn't cut it?

Recommended Posts

Personally, I tend to prototype a feature first until it's functional and then spend a bit of time to clean up the code and optimize it straight after (hopefully without breaking it -.-). Then once a week or so I spend a day reviewing all the things I did that week and refactoring. There's no set schedule for this, I just do it when the mess starts bugging me (which is at pretty regular intervals). I don't go overboard with optimization though - just enough to keep things from getting too ridiculous.

Share this post


Link to post
Share on other sites

Typically at the start of a project you establish a performance target you need to hit on some particular configuration of hardware (often the minimum and regular specification hardware), and then at regular intervals throughout development perform benchmark tests on this hardware using consistent procedures, and schedule optimizations based on the results. Ideally this process is automated, so that you can perform a ton of benchmarking test across all the various game levels and content without requiring dedicated developer time. Automated testing also helps ensure that the testing procedures remain as consistent as possible and you eliminate any human error.

 

If you blow your performance target, or there's some change made that drastically alters performance, you know it's time to take a look at what happened. The more often the benchmarking is performed, the less code you need to review and profile.

 

Edit: To expand on what I alluded to above, overall performance is about more than just code itself. Sometimes perfectly reasonable code will interact with certain content in ways you didn't expect.

Edited by Zipster

Share this post


Link to post
Share on other sites

I frequently find myself having to choose between a more readable line and a faster line. I then leave myself a big comment like this:

// Performance: use Hard2ReadFunc1() + Hard2ReadFunc2()
x = EasyToReadFunction()

That way I can save the brain power, but I will only optimize it if profiling leads me to that spot.

Share this post


Link to post
Share on other sites

So we have 2 ways of looking at this where both have truth.

 

It's worth noting that some design-time choices will have a major impact on speed. Choosing to implement some system around data access patterns instead of some sort of object hierarchy is a pretty big decision, and with just a little experience can easily be determined before-hand, even though it could be considered a type of optimization. I would rather do this before rather than after.

 

However, optimizing my collision detection system for 2 days when I only have 10 objects on the screen at a given time is almost guaranteed a waste of time, but profiling later on will help us determine this for sure.

Share this post


Link to post
Share on other sites

Spiro, for your #2, and that sin/cos, do you think the compiler wouldn't optimize the initial version?

 

(Not disagreeing with your point, there are lots of instances of small optimizations that, as long as they don't make the code less clear, and don't take a lot of time, should just be done.)

Share this post


Link to post
Share on other sites

Spiro, for your #2, and that sin/cos, do you think the compiler wouldn't optimize the initial version?

You can look into your compiler-of-choice and check, and it might, but-
#1: Will it always? Are there edge cases where it can’t or certain situations where it misses the chance?
#2: What about when you port over to another platform or even if you upgrade the same compiler? Does every single compiler do it?

The only way to know that it gets done is to do it yourself.

 

They say to trust your compiler and that it does a better job than you can.

They for some reason never say, “Oh, and remember, they are extremely complicated pieces of machinery and in any given case what it can and can’t do will be up to hundreds of variables, including aliasing, side-effect evaluation, etc.”

Compilers are reliable at removing unused code and unreferenced functions and data, scheduling, register assignment, etc.

Beyond that, never make assumptions.

 

 

L. Spiro

Share this post


Link to post
Share on other sites

It is the difference between acting wisely versus blindly following a mantra.

 

The mantra is generally correct. It serves as a simple reminder of a larger concept.

 

There is a big difference between making obvious, direct, simple improvements such as removing duplication, versus what the original talk was talking about 'worrying about the speed of non-critical parts of the program'.

 

The first one is appropriate, often given terms like 'refactoring', 'paying technical debt', or 'code clean up'. You see something that is messy, a duplicate calculation, some loop-invariant code, or some easy tree pruning, and you fix it when it is noticed. That is not premature, that is the perfect time to do it.  It doesn't matter if the compiler might have caught it, the change is an improvement. No worry or stress is involved. This is a great option.

 

The second one is common to see. In fact, we had one in the For Beginners forum earlier this week. The quote is about worrying and fretting over something that may not even be a problem: "I think my program might potentially be slow, I don't know if it will be slow, and if it is slow, I don't know where, so I need to write crazy things that I don't even know if they are faster at every step."  Might as well start hiding in a cave now because there might be a zombie outbreak someday. That falls under the 'premature' umbrella. That is typically a bad option. 

 

The quote also talks about the small number of things that you expect from the outset might need some performance tuning.  Your first pass at an A* search algorithm that will be used by thousands of game actors? Yeah, anyone can tell you up front that is going to need some care so it doesn't explode either in terms of memory or computation. A particle system where you want up to a million active particles running at 120 FPS? Yeah, that's going to take some careful thought. But even in these cases you make a plan, implement the plan, and then test, measure, and compare like a computer scientist.

Share this post


Link to post
Share on other sites

As many have been saying, use any mantra with wisdom. Not optimising prematurely is different to intentionally writing something the slowest possible way. Use the correct data types and standard techniques. Don't use a linked list if you should be using a hashtable. Keep the intention of the mantra in mind. The purpose is to avoid writing hard to read code, and to avoid spending a long time optimising what may not need to be optimised. Any optimisation that doesn't fall under those categories is fine.

Share this post


Link to post
Share on other sites

I dislike the way the "premature optimisation.." quote is misused, and quoted without the benefit of its original context. 

 

I take the quote to have 2 meanings:

  1. Get the code working first then worry about optimising.
  2. Don't rush into optimisation without profiling the code first.

The benefit of #1 is that you can keep your working, reference implementation and ensure the output of your optimised version is still working correctly. And #2 gives you the best bang for buck, since as developers, our time is precious. 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this