boop
boop

Reputation: 7788

New temporarily variables in a frequently called method

Would it more efficient to not assign new temporarily variables in a method that is called very frequently? (> 1000x s)

So a current example. I'm assigning 3 new integer values, instead passing these values directly to another method.

// What I'm currently doing
public virtual byte GetByte(Vector3 worldPos) {
    worldPos -= transform.position;
    int x = Mathf.FloorToInt(worldPos.x);
    int y = Mathf.FloorToInt(worldPos.y);
    int z = Mathf.FloorToInt(worldPos.z);
    return GetByte(x, y, z);
}

But would it be more efficient to pass these values direct, instead of assigning 3 new variables?

// would this be more efficient?
public virtual byte GetByte(Vector3 worldPos) {
    worldPos -= transform.position;
    return GetByte(
        Mathf.FloorToInt(worldPos.x),
        Mathf.FloorToInt(worldPos.y),
        Mathf.FloorToInt(worldPos.z));
}

Upvotes: 0

Views: 86

Answers (2)

Trevor Pilley
Trevor Pilley

Reputation: 16393

They do result in different IL being generated.

Current (using int x = Mathf.FloorToInt(worldPos.x);...):

.method public hidebysig newslot virtual instance uint8 GetByte1 (
        valuetype ConsoleApplication5.Vector3 worldPos
    ) cil managed 
{
    .locals init (
        [0] int32 x,
        [1] int32 y,
        [2] int32 z
    )

    IL_0000: ldarga.s worldPos
    IL_0002: ldfld int32 ConsoleApplication5.Vector3::x
    IL_0007: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_000c: stloc.0
    IL_000d: ldarga.s worldPos
    IL_000f: ldfld int32 ConsoleApplication5.Vector3::y
    IL_0014: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0019: stloc.1
    IL_001a: ldarga.s worldPos
    IL_001c: ldfld int32 ConsoleApplication5.Vector3::z
    IL_0021: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0026: stloc.2
    IL_0027: ldarg.0
    IL_0028: ldloc.0
    IL_0029: ldloc.1
    IL_002a: ldloc.2
    IL_002b: call instance uint8 ConsoleApplication5.X::GetByte(int32,  int32,  int32)
    IL_0030: ret
}

Alternative:

.method public hidebysig newslot virtual instance uint8 GetByte2 (
        valuetype ConsoleApplication5.Vector3 worldPos
    ) cil managed 
{
    IL_0000: ldarg.0
    IL_0001: ldarga.s worldPos
    IL_0003: ldfld int32 ConsoleApplication5.Vector3::x
    IL_0008: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_000d: ldarga.s worldPos
    IL_000f: ldfld int32 ConsoleApplication5.Vector3::y
    IL_0014: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0019: ldarga.s worldPos
    IL_001b: ldfld int32 ConsoleApplication5.Vector3::z
    IL_0020: call int32 ConsoleApplication5.Mathf::FloorToInt(int32)
    IL_0025: call instance uint8 ConsoleApplication5.X::GetByte(int32,  int32,  int32)
    IL_002a: ret
}

In theory, the alternative could be more efficient as it doesn't incur the cost of storing and retrieving the int values from the local variables so there are less instructions needed to execute the method. However, the code MSIL will still be JITted at runtime and may end up the same depending on how it is optimised.

I would stick with the current version as it makes debugging easier as you can see the result of the FloorToInt calls by inspecting the variable.

The only way to know for sure is to benchmark the code, odds are though that this is a rather pointless "optimisation", there are probably much better ways to speed up your application!

Upvotes: 1

poke
poke

Reputation: 387745

It makes no difference. Local variables are added to the stack. And values that are used as function parameters are also added to the stack. So in both cases, the same things are added to the stack.

So just use whatever you think is more readable.

Upvotes: 5

Related Questions