screepers/screeps-profiler

Name: screeps-profiler

Owner: screepers

Description: This is a profiler designed for use in the game of screeps.

Created: 2015-12-28 06:27:25.0

Updated: 2018-01-08 06:06:54.0

Pushed: 2017-10-14 13:39:28.0

Homepage: null

Size: 42

Language: JavaScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Screeps Profiler Build Status Coverage Status

The Screeps Profiler is a library that helps to understand where your CPU is being spent in the game of Screeps.

It works by monkey patching functions on the Global game object prototypes, with a function that record how long each function takes. The primary benefit of using this profiler is that you can get a clear picture of where your CPU is being used over time, and optimize some of the heavier functions. While it works best for players that heavily employ prototypes in their code, it should work to some degree for all players.

Setup
Installation

You have two options for installing this script. You can either use npm and a compiler like webpack, or you can copy/paste the screeps-profiler.js file and use the provided screeps require function.

Main.js

Your main.js will will need to be configured like so.

ny modules that you use that modify the game's prototypes should be require'd
efore you require the profiler.
t profiler = require('screeps-profiler');

his line monkey patches the global prototypes.
iler.enable();
le.exports.loop = function() {
ofiler.wrap(function() {
// Main.js logic should go here.
;

Console API

You can make use of the profiler via the Screeps console.

.profiler.profile(ticks, [functionFilter]);
.profiler.stream(ticks, [functionFilter]);
.profiler.email(ticks, [functionFilter]);
.profiler.background([functionFilter]);

utput current profile data.
.profiler.output([lineCount]);

eset the profiler, disabling any profiling in the process.
.profiler.reset();

.profiler.restart();

Note: It can take up to 30 ticks if you're using module.exports.loop for these commands to work without issue.

profile - Will run for the given number of ticks then will output the gathered information to the console.

stream - Will run for the given number of ticks, and will output the gathered information each tick to the console. The can sometimes be useful for seeing spikes in performance.

email - This will run for the given number of ticks, and will email the output to your registered Screeps email address. Very useful for long running profiles.

background - This will run indefinitely, and will only output data when the output console command is run. Very useful for long running profiles with lots of function calls.

output - Print a report based on the current tick. The profiler will continue to operate normally. This is currently the only way to get data from the background profile.

reset - Stops the profiler and resets its memory. This is currently the only way to stop a background profile.

restart - Restarts the profiler using the same options previously used to start it.

In each case, ticks controls how long the profiler should run before stopping, and the optional functionFilter parameter will limit the scope of the profiler to a specific function.

Example output

Below is a sample output of Game.profiler.profile(1000)

s    time        avg       function
     12293.9,    6.147     Room.work
4    6025.0,     0.552     Creep.work
     3534.5,     1.767     Spawn.work
0    1949.3,     0.028     Structure.work
     1733.8,     0.612     Creep.moveTo
     1093.7,     0.293     Creep.moveToAndHarvest
     886.0,      0.534     Creep.takeEnergyFrom
     871.9,      0.103     Room.createConstructionSite
     852.7,      0.244     Creep.harvest
     745.8,      0.765     Creep.deliverEnergyTo
     741.1,      0.283     Room.needsCouriers
     700.5,      2.520     RoomPosition.findPathTo
     673.6,      2.423     Room.findPath
2    575.4,      0.027     Spawn.availableEnergy
     535.1,      0.191     Room.getStorage
     511.7,      0.243     Creep.move
     487.1,      0.266     Creep.moveByPath
     483.9,      0.336     Creep.moveToAndUpgrade
6    454.5,      0.017     Room.find
     443.1,      0.104     Room.droppedControllerEnergy
 15.43 Total: 15425.31 Ticks: 1000 Est. Bucket (20 limit): 5055

Seeing that Spawn.work is high, we might run Game.profiler.profile(200, 'Spawn.work') to see what about Spawn.work is taking so long. From that we would get:

s    time        avg        function
     137.7,      2.221      Spawn.work
     25.8,       0.251      Room.needsCouriers
     23.9,       0.583      Room.needsUpgraders
     18.6,       0.452      Room.needsHarvesters
     17.6,       0.429      Room.getSourcesNeedingHarvesters
     16.1,       0.154      Room.getStorage
     14.9,       0.027      Spawn.availableEnergy
     12.1,       0.035      Room.find
     8.4,        0.135      Room.harvesterCount
     8.3,        0.174      Spawn.extend
     7.9,        0.037      Room.getExtensions
     7.3,        0.178      Room.droppedControllerEnergy
     7.1,        0.069      Room.courierCount
     7.1,        0.115      Room.getHarvesters
     6.5,        0.158      Room.needsBuilders
     6.1,        0.509      Spawn.buildBuilder
     5.8,        0.094      Room.setupFlags
     5.6,        0.055      Room.getCouriers
     5.0,        0.330      Room.upgraderWorkParts
     4.8,        0.116      Room.builderCount
 13.54 Total: 2707.90 Ticks: 200 Est. Bucket (20 limit): 1774

Note: Each function recorded here was part of a call stack with Spawn.work at the root.

Registering additional code

The profiler automatically registers many of the built in functions in Screeps, but not every player extends the provided prototypes. The profiler supports arbitrary registration of objects and functions as well, but takes a bit more work to setup. In order to do it, you'll need to import the profiler wherever you want to register a function, then call registerClass, registerObject, or registerFN.

Example:

t profiler = require('screeps-profiler');

s SuperOmegaCreep {
rk() {
hiddenManagersPlaybook.delegate();



ach of the functions on this class will be replaced with a profiler wrapper. The second parameter
s a required label.
iler.registerClass(SuperOmegaCreep, 'SuperOmegaCreep');

t gameHandlerObject = {
ndleGame: () => {
// do some work.



ach of the functions on this object will be replaced with a profiler wrapper. The second parameter
s a required label.
iler.registerObject(gameHandlerObject, 'gameHandlerObject');

tion getAllScouts() {
turn Object.keys(Game.creeps).filter(creepName => {
const creep = Game.creeps[creepName];
return creep.memory.role === 'scout';
;


e sure to reassign the function, we can't alter functions that are passed.
llScouts = profiler.registerFN(getAllScouts, 'mySemiOptionalName');

Note: The second param is optional if you pass a named function function x() {}, but required if you pass an anonymous function var x = function(){}.

Potential Overhead

There is some work to setting up the functions for profiling. While this work is kept to a minimum when the profiler is not in use, it may be beneficial to comment out or remove the profiler.enable() call when you know you aren't going to be using it. This will revert the monkey patched functions to their original functions.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.