[ZScript] new(object) vs Performance

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
difficultoldstuff
Posts: 38
Joined: Fri Jul 17, 2020 5:38 am
Operating System Version (Optional): Windows 7
Graphics Processor: nVidia with Vulkan support
Contact:

[ZScript] new(object) vs Performance

Post by difficultoldstuff »

Hello, can anybody shed some insight on the performance issues that might come along with this piece of code?

My main issue right now is creation of a new ArrayShuffler instance each second. I'm trying to streamline my code and couldn't really find much info on the new() method. Will this be safe to use in such a context? Will the object created with new() be destroyed and cleaned up after EachSecond()? I don't want to clog the memory or waste resources, and rewriting the array shuffling code in multiple places just feels wrong. If there's anything else you'd change in the code you see below - please let me know! Thank you for your time and effort.

Code: Select all

class ExampleClass : Actor
{
    int internalTick;
    
    override void Tick()
    {
        Super.Tick();
        
        internalTick += 1;
        
        if (internalTick >= 35)
        {
            internalTick = 0;
            EachSecond();
        }
    }
    
    void EachSecond()
    {
        Array<int> intArray = {0, 1, 2, 3};
        ArrayShuffler aShuffler = new("ArrayShuffler");
        aShuffler.intArray.Copy(intArray);
        aShuffler.ShuffleInt();
        intArray.Copy(aShuffler.intArray);
    }
}

class ArrayShuffler
{
    // WHAT IS MY PURPOSE?
    // YOU SHUFFLE ARRAYS.
    // OH MY GOD.
    
    Array<int> intArray;
    
    void ShuffleInt()
    {
        if (intArray.Size() > 1)
        {
            for (int i = 0; i < intArray.Size(); i++)
            {
                int rID = random(i, intArray.Size() - 1);
                int rOrg = intArray[i];
                
                intArray[i] = intArray[rID];
                intArray[rID] = rOrg;
            }
        }
    }
}
User avatar
m8f
 
 
Posts: 1445
Joined: Fri Dec 29, 2017 4:15 am
Preferred Pronouns: He/Him
Operating System Version (Optional): Manjaro Linux
Location: Siberia (UTC+7)
Contact:

Re: [ZScript] new(object) vs Performance

Post by m8f »

You can put ArrayShuffler into ExampleClass:

Code: Select all

class ExampleClass : Actor
{
    int internalTick;
    ArrayShuffler aShuffler;
and then make a new only if it doesn't exist yet:

Code: Select all

void EachSecond()
    {
        ...
        if (aShuffler == NULL) aShuffler = new("ArrayShuffler");
        ...
}
Also, you may want to use Move instead of Copy, it's a cheaper operation:

Code: Select all

 void Move(array<T> other)
    Moves all of the elements of other into this array, emptying the original array completely.
Edit: to answer your questions: yes, an object created in a function will be eventually destroyed, and memory will be cleaned up by garbage collector. It will cost a little bit cost of performance each time, though, so it's recommended to avoid creating objects repeatedly if you can cache them somewhere.
User avatar
difficultoldstuff
Posts: 38
Joined: Fri Jul 17, 2020 5:38 am
Operating System Version (Optional): Windows 7
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [ZScript] new(object) vs Performance

Post by difficultoldstuff »

Thank you very much for your insight on this.

I was initially thinking about referencing only one instance of the ArrayShuffler at the beginning and reusing it every time without creating new instances - but! My fear was that the way it's written now it would override its internal intArray value if used recursively or without retrieving the shuffled value before using it again in the same function. Same thing with array.Move(). Sure, it could and should be used like you mentioned in cases that don't need to worry about such intense array juggling. Maybe creating an individual ArrayShuffler once for different use cases and storing those in class references could be a (bit messy name-wise) middle ground solution...

Anyway, thank you for your fast response! It cleared things up and made me understand the new() method a bit more for future uses.

Edit: Ended up using one static reference to the ArrayShuffler instance, created at PostBeginPlay() and the array.move() method wherever I can.
User avatar
Sir Robin
Posts: 537
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: [ZScript] new(object) vs Performance

Post by Sir Robin »

Quick tip: You can avoid that internalTick thing if you just use a modulus:

Code: Select all

if (level.time % 35 == 0){EachSecond();}
level.time is the count of ticks since you started playing this hub, so modulus it by 35 will break it down by seconds.
User avatar
difficultoldstuff
Posts: 38
Joined: Fri Jul 17, 2020 5:38 am
Operating System Version (Optional): Windows 7
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [ZScript] new(object) vs Performance

Post by difficultoldstuff »

@SirRobin, a very curious, nice snippet, thank you! Might use it in some cases, but

Code: Select all

if (!actPlayer.paused)
{
    internal.tick += 1;
    
    if (internal.tick >= 35) { EachSecond() };
}
Allows me to introduce a custom state of "pause" for certain game elements during some special menus / cutscenes, while I doubt I could pause level.tick. Either way, great stuff!
Post Reply

Return to “Scripting”