Should I create local copy of global variable?

I’ve got a little script that tracks player input, which can be accessed in other scripts via global variables. Is it fine to just keep calling e.g., ControlInput.movement multiple times in those scripts, or is it better for performance to copy the global variables into a local ones for the purposes of that script?

Sorry, bit of a noob question. It might make no difference at all. Just trying to learn best practices. =]

Not a noob question - on the contrary, that’s a very interesting one! I was just wondering myself about this same subject, and decided to use ILSpy to check the CIL code generated for static and member variables.

It seems that there’s no gain in caching static variables: both, member and static variables are accessed with a single instruction - ldfld for member variables, ldsfld for static ones. These instructions are interpreted and executed in native machine code, but for sure there’s no significant difference in CPU cycles - it would be a lot different if several CIL instructions were needed to access static fields, what’s not the case.

You can see below the significant part of the simple JS code converted to CIL, with comments linking the CIL instructions to the JS ones:

Script CheckVPort.js:

static var vStatic = 0;

Script Zoom.js:

var vLocal = 0;

function Start(){
    vLocal += 1;
    CheckVPort.vStatic += 1;
}

The same Zoom.js compiled to CIL:

//var vLocal = 0;
    .field public int32 vLocal 

//function Start(){
    .method public hidebysig virtual 
        instance void Start () cil managed 
    {
        // Method begins at RVA 0x88e0
        // Code size 27 (0x1b)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldarg.0
//    vLocal += 1;
        IL_0002: ldfld int32 Zoom::vLocal // read int variable vLocal...
        IL_0007: ldc.i4.1 // load constant 1...
        IL_0008: add.ovf // add constant to it...
        IL_0009: stfld int32 Zoom::vLocal // and store in vLocal
//    CheckVPort.vStatic += 1;
        IL_000e: ldsfld int32 CheckVPort::vStatic // read int static vStatic...
        IL_0013: ldc.i4.1 // load constant 1...
        IL_0014: add.ovf // add constant to variable's value...
        IL_0015: stsfld int32 CheckVPort::vStatic // and store in vStatic
        IL_001a: ret
    } // end of method Zoom::Start
//}

From a conceptual point of view, this makes no difference. From a more practical point of view, this is harder to tell. Local variable may be on the stack, i.e. very close to the code using it. On the other hand variables from other script can also be cached into registers.

Although C# (or JS) runs on a virtual machine (Mono), these concepts are pretty much the same as code running on a CPU (such as C/C++). But this depends exclusively on the implementation and design choice of the VM. As game developer we can’t do anything about it.

Regarding games made with Unity, I don’t think it’s making any difference. You don’t have the same constraints as realtime-guaranteed applications. So just use the way that fit your coding habit.

You can do much better optimization by choosing the right algorithms and data structures.

I’ve read that it’s a lot faster to access a public variable from another class directly (ControlInput.movement) than to make it private and call an accessor function (ControlInput.GetMovement()). Not necessarily as tidy in terms of encapsulation but faster. However, I don’t know if there’s any difference between getting a variable from another object or from the current object. I expect it performs pretty much the same.