direct access vs. setter-getter performance

Hello everyone,

I am aware that the performance of my game almost entirely depends on the my algorithms and the effectiveness of my design, but I’m still wondering, is there any non-neglectable performance penalty for using getters and setters (thus always creating a small call stack) in the update method for all objects, instead of directly accessing the properties in a 2D game? Let’s say I have a few hundreds (maybe thousands) of objects on game scene, which are all moving because the camera is scrolling. Would I gain anything on lower end hardware, like a mobile phone or a Switch by using direct access instead of setters-getters?
Also, what is your opinion of inlining these methods using Func<>?

Thank you

I’m not sure the extent of the performance loss. I can’t imagine it’s large, but this is probably something you can definitely do up a small test for. I’d be interested in the results :slight_smile:

You’re actually right, I’ll give that a test and let you know :slight_smile:

1 Like

You probably already know, but I’ll mention this because I forget all the time. Make sure you run your test in a release build outside the debugger when you collect your results! :slight_smile:

1 Like

Getters and setters are essentially sugar-coated wrappers for methods. So it’s going to be slower than directly accessing something. Moreover, things are getting weird with structs.
Let’s say, you’ve got this property:

public Vector2 Foxe {get; set;}

And then you do something like this:

Foxe.X += 1;

This code is not going to compile, because under the hood it looks like this:
private Vector2 _foxe;
public Vector2 GetFoxe() =>
_foxe;
public void SetFoxe(Vector2 value) =>
_foxe = value;

Note that you can only set or set the entirety of Vector2 - and since it’s a struct, we return its copy in Get method. It’s not the original object anymore.

Now if we look at += part:
Foxe.X = Foxe.X + 1;

Still looks ok, so what’s the… wait a minute, we’re getting the copy of the Foxe, then getting its X field, then incrementing it by one, then getting a copy Foxe again, and trying to… set the X field of a copy with the new value? This doesn’t make any sense - and this is why it will not compile.

But either way, writing something like

public Vector2 Foxe {get; set;}

is a terrible practice. Unless there is a valid reason to turn your fields into properties, don’t do it. You’re just performing additional useless operations because suits at bizdev are obsessed with interfaces.

2 Likes

A couple of years ago I ran some timed tests.

If I recall correctly running in debug mode getters and setters where a fair bit slower. But when running in release mode there was no real difference in speed.

1 Like

My rule of thumb, I only use getter and setter only if I need to do something immediately when the value is change or it has an effect to the application, otherwise I just make it accessible directly.

E.g:

I wanted to compute Value of C everytime ?

class Sample
{
    public int ValueA;
    public int ValueB;        
}

// Somewhere in the program

var mValueC = _Sample.ValueA + _Sample.ValueB;

Or do I wanted the value of C already available when value A or value B change ?

class Sample
{
    private int _ValueA;
    private int _ValueB;
    private int _ValueC;

    public int ValueA
    {
       set { _ValueA = value; _ValueC = _ValueA + _ValueB; }
       get { return _ValueA; }
    }

    public int ValueB
    {
       set { _ValueB = value; _ValueC = _ValueA + _ValueB; }
       get { return _ValueB; }
    }

    public int ValueC
    {            
        get { return _ValueC; }            
    }
    // OR | public int GetValueC() { return _ValueC; }

}
2 Likes

Unless you use a custom getter/setter, then in Release mode there actually won’t be a difference. The compiler will in-line your property accessors, and since the default property accessor is simply using a field, the property is essentially compiled down to a field. Check out some of the answers in this SO post.

2 Likes

Honestly, you don’t really have to use a getter/setter, it’s just one of those good habits to be in. It makes code refactor easier and I tend to fall into a pattern of making my stuff testable. It’s a performance cost to be sure, but it’s probably not as bad as you think.

It’s been my experience that designing for testability and maintainability first will always serve you better than designing for performance first. If you follow good patterns, it’s relatively easy to refactor.

… Unless …

You know, beyond a doubt, that the component you’re working in will require the highest performance. Then maybe… :stuck_out_tongue:

In any case, define your [reasonable] performance criteria and test against it often throughout your development, so you know when you’re going off track :slight_smile:

1 Like

Thanks everyone guys, this community is amazing! It’s so great to see how different people see this question (not necessarily from performance point of view), makes me see different perspectives allowing me to define what’s of value for me. Through many years of enterprise java development, I picked up the habit of almost always using property accessors, but game development it’s such a different domain that I’ll have to learn again how to think about things I had established views about. I can define my own approach on this topic now, thanks everyone! :slight_smile:

3 Likes

Personally I think its a good habit using getters and setters. In games a lot of the time you just want to read a variable outside the class and only have it be able to be changed within the class.

You can then lock it with a public get and a private set.

2 Likes

If your using Visual Studio it has a pretty good profiler that you can use to see how long different parts of your code take to run. You could build a test case with thousands of objects and see if it’s an issue.

1 Like

Don’t worry about methods vs properties. If you’re concerned about performance with lots of objects, here’s three areas you can dig into.

  1. Avoid boxing and unboxing. This is where a value type gets packed up in a reference type temporarily. Do some reading.
  2. Too much dynamic allocation will cause longer sweeps in the mono garbage collector and lead to frame rate drops.
  3. Avoid redundant GPU calls. You’ll need to look into monogame source to see where calling something will result in a GPU call. In general, just update anything graphics related once per frame. If your logic can cause more changes between renders, keep an eye on this.
1 Like

Thanks!

Also, what is your opinion of inlining these methods using Func<>?

be aware usage wise <>func<> action <>
Will create garbage collections if you are subscribing unsubscribing to and from them in real time.
I believe in particular unsubscribing and there isn’t anything you can do to stop it.
So doing something like that with say actual game objects like players enemys ect… is a nono for a game.

Other wise if you are just presetting them up to fire calls i think they are ok.

1 Like

Thank you, now I’m only using lambdas and for subscribing events that happens through the whole game :slight_smile:

Complete your game first. AFTER it is done, worry about performance.

Sorry but I strongly disagree.

If your game is a simple 2d pixel art game where even without optimizations at all you’d get over 100 fps on a toaster, then yes you can save it for last.

But if the game is 3d, for example, or have lots and lots of sprites with complex effects, you need to design the engine around performance from day one.

3d is especially a good example for this - if you don’t design your rendering pipeline to properly support instancing and ways to support lots of lights, like deferred rendering, pushing it in the end can be a nightmare and take months of refactoring huge chunks of your code. Not to mention you’ll end up limiting yourself while designing your levels over performance, where in reality you could have designed them a lot more detailed and rich but you didn’t know you’d end up with more fps after optimizing.

1 Like

I think there’s a middle ground here, and @GeonBit has really touched on it. The key part is you need to identify what your performance requirements actually are. As they have pointed out, a good question to ask is what kind of game are you making? What kind of experience do you want to deliver? What platforms do you want to support?

Once you know what you want to build and who you want to build it for, set some benchmark and build to that. Keep it in mind as you’re building and perform frequent checks to make sure you’re within your limits. Only when you find yourself outside your limits, consider refactors.

Considering performance is a good thing, just be wary of falling into the trap of prioritizing it over everything else or you spend all your time writing blazingly fast code and not delivering anything. Just getting a working game is also good, just be wary of falling into the trap of ignoring good practices and ending up with a heap of spaghetti code that yields an unplayable game :wink:

1 Like

Yea I was actually overthinking it, my game hits my performance targets so far without caring about such performance things. Since it’s 2D, I am focusing much more on proper algorithms than setter-getter/function differences, and I’m happy with my results.

1 Like