Skip to main content

News

Topic: JS performance profiler - for use in sphere (Read 253 times) previous topic - next topic

  • Rhuan
  • [*][*][*][*]
JS performance profiler - for use in sphere
The below code creates a timer object that you can use to profile the speed of various functions in your project/game. It is intended for people who either:
a) have a slow running large/complex game system and wish to find the part causing the slow down OR
b) are obsessive micro-optimisers like me

It will output the results in a csv file that you can open with excel or openoffice to do some stats/analysis with.

(I'm afraid it uses v1 file handling as v2 file writing still does not seem to work on Mac)

Usage:
1. Create a timer object - needs to be global or at least available in the whole of the scope you're going to use it in:
var time_logger = new Timer("log");
If you have multiple separate scopes and no global available you could make one in each scope with different names.

2. At the start of each portion of code you wish to time put in a record call:
time_logger.record("Update function", false);//the false parameter is optional
NOTE: the string must not contain a comma

3.The Timer will time the section until the next record call, you can end a section either by beginning another section:
time_logger.record("Render function", false);
OR by calling record with the second parameter set to true
time_logger.record("this string is ignored", true);
When true is set no new section is begun but the previous section is ended - this is so when one seciton follows another you only need one function call whereas if there's a big gap you can end the section off without creating a log entry for the gap that doesn't interest you.

4. Call the end function before you exit
time_logger.end();//this writes everything out to a file
Output is not done to a file during execution as this can significantly impact performance and hence skew the results.

Code: [Select]
function Timer(file_name)
{
  this.output_file = OpenRawFile(file_name + ".csv", true);
  this.output_file.write(CreateByteArrayFromString("Time,Event,TimeTaken\n"));
  this.start = new Date().getTime();
  this.records = [];
  this.open = false;
}

Timer.prototype.record = function(status, end)
{
  var time = new Date().getTime() - this.start;
  var length = this.records.length;
  if(this.open === true)
  {
    this.records[length -1].time_taken = time - this.records[length -1].time;
    this.open = false;
  }
  if(end !== true)
  {
    this.records[length] = new Record(time, status);
    this.open = true;
  }
}


Timer.prototype.end = function()
{
  var time = new Date().getTime() - this.start;
  this.record("",true);
  var string = "";
  for(var i = 0; i < this.records.length; ++i)
  {
    string = string + this.records[i].time +"," +this.records[i].status +","+this.records[i].time_taken +"\n";
  }
  string = string +time + ", Total time running, "+ time +"\n";
  this.output_file.write(CreateByteArrayFromString(string));
  this.output_file.close();
}

function Record(time, status)
{
  this.time = time;
  this.status = status;
  this.time_taken = 0;
}
  • Last Edit: September 17, 2017, 08:42:39 am by Rhuan

  • Rhuan
  • [*][*][*][*]
Re: JS performance profiler - for use in sphere
Reply #1
Note, I've just discovered that there was a mistake in the above that would have resulted in incorrect timings for the 1st and last blocks timed in each run, I have fixed by editing the post please update your script if using it; sorry about this.
  • Last Edit: September 17, 2017, 03:52:00 am by Rhuan

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • miniSphere Developer
Re: JS performance profiler - for use in sphere
Reply #2
Quote
If you have multiple separate scopes and no global available you could make one in each scope with different names.

Tip: Global scope is always directly accessible in Sphere v2 via global, i.e.:
Code: [Select]
global.time_logger = new Timer("log");

You need that with ES modules since var, let and const are module-local and directly assigning to an undeclared global is a strict-mode violation.
miniSphere 5.0.1 - Cell compiler - SSj debugger - thread | on GitHub
For the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enourmous man eating pigs ~Rhuan

  • Rhuan
  • [*][*][*][*]
Re: JS performance profiler - for use in sphere
Reply #3
Tip: Global scope is always directly accessible in Sphere v2 via global, i.e.:
Code: [Select]
global.time_logger = new Timer("log");

You need that with ES modules since var, let and const are module-local and directly assigning to an undeclared global is a strict-mode violation.
I'm trying to think why you have to have that in v2 stirct mode. Surely you can have one primary module that passes information between all the others and avoids ever needing a global? (this is how my map engine and sprite engine are set up - though the sprite engine does end up being a property of the map engine and they both end up being properties of the collision engine, good thing no ones trying to do a recursive deep copy on them....)
  • Last Edit: September 17, 2017, 08:43:01 am by Rhuan

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • miniSphere Developer
Re: JS performance profiler - for use in sphere
Reply #4
Yes, definitely better to have a global module that everything imports (with ES6 the imports are even verified at load time); that said there are some cases where you need to explicitly set globals for compatibility with, especially, browser code.  See my mp3 demo for what I had to do to get Aurora.js to function in Sphere :)
miniSphere 5.0.1 - Cell compiler - SSj debugger - thread | on GitHub
For the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enourmous man eating pigs ~Rhuan