New main loop architecture

We have just implemented an important feature which affects how the runtime engine treats your script modules. Now we have two module architectures available at the same time.

What is new here is the way you main module is executed. In the old-style architecture, it is executed every tick, and every module required from it is also executed every tick. In the new architecture, your main module should contain the module.exports.loop function which is executed in a game loop, while the rest of the main module contents are executed only after a new global is instantiated. It's the same with required modules - their contents are executed only once per global instantiation, after which they get cached. You have to export some functions from your required module and run it explicitly from the main loop. The architecture is switched automatically upon detecting module.exports.loop function in the main.

Here is a comparison table:

OLD NEW

main:

// executed every tick

var mod = require('mod');

mod.foo();


main:

// executed on new global 
var mod = require('mod');

module.exports.loop = function() {
    // executed every tick
    mod.foo();
}

mod:

// executed every tick

module.exports.foo = function() {
    // executed every tick
}

mod:

// executed on new global

module.exports.foo = function() {
    // executed every tick
}

This new style is now recommended. It allows caching of your modules which drastically affects your script performance. Also, you can perform some initial operatons in your modules body (e.g. extending prototypes) which won't be executed every tick, thus saving your CPU.

Have more questions? Submit a request

Comments

  • nezrel

    Very neat and much appreciated update for caching.

    You should also consider updating "How to play -> Understanding game loop" or API reference table for this information. As it is now the only way for new players to be aware of this functionality is to read this specific change log.

  • sveri

    Hi,

    maybe I misunderstood, but, from what I gathered this:

    console.log('only once!');
    
    module.exports.loop = function() {
        console.log('tick!');
    }
    

    should print only once only once and tick on every tick. However, in my simulation it prints only once and tick on every tick.

  • TheNumberOne

    @sveri

    In world mode, a new global is created every few ticks. module.exports.loop will always be ran every tick. The rest of the module is ran every time a new global is created. I would assume that the global is recreated each tick in the case of the simulation.

  • Avatar
    Artem from Screeps

    Correct, it is not activated yet in the Simulation mode.

  • ZoeyAlyx

    It appears to be running the uncached version in more than half of all occurring ticks. With require's performance issues, performance is still somewhat dismal.

  • Actium

    Unfortunately, the new "architecture" is 1.5 times more greedy for CPU.

  • RaskVann

    I'm initializing 8 modules at the start of my main. These take up between 6-20 CPU each tick, no real gains from this change. Any way this can be fixed on the back end?

  • bnm12

    I went from never really hitting my CPU limit, to now getting mail after mail after mail about my CPU limit being hit... Somehow everything just got more greedy... Even switching what limited code I have to the new architecture it still hits the CPU limit...

  • Avatar
    Artem from Screeps

    The fix has been deployed, CPU usage of new loop must be fine now. Also, this new style is now available in the Simulation as well.

  • RaskVann

    I'm seeing a significant drop in CPU for initializing the the global modules. It will usually sits between 0.05-0.43 but will occasionally jump to 6 or as high as 13 CPU for reasons unknown in my code. Nice job guys, excellent fix.

  • Avatar
    Artem from Screeps

    Optimized new main loop caching. The global object must be fully cached in 20-30 ticks after commiting a script.

Powered by Zendesk