Someone just told me that SS2.1 UE scripts are slo...
# suitescript
a
Someone just told me that SS2.1 UE scripts are slower than 2.0, that it is a known defect. Anyone else heard this ?
c
That's interesting. I'm guessing that person that told you didn't show you any metrics?
I'm not saying they're wrong though.
a
no, it was a general statement made in a job interview. I am trying to find out if there is any validity to it.
e
I just searched and I saw this in the forum on 10/5... reza.seedin  [3:35 PM] Hi Everyone, Slightly odd question. Has anyone found that using SS 2.1 is slower than 2.0? I have not seen any noticeable slowdown other than NS being NS slow 🙂. Also does anyone know when 2.1 will be released for PROD use? (edited)
So I stand corrected, it looks like this user is saying that they have NOT noticed any difference
a
the interesting part is that it is supposedly a known defect. Seems like someone would have said something about it though if that were the case.
m
I read that as well a few weeks ago in this channel and ran my own simple comparisons and didn’t find anything noticeable.
b
in a casual test of using a map/reduce script to trigger 10,000 before submits
a non scripted custom record has a summary that looks like:
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-07T22:46:15.778Z",
  "seconds": 1239,
  "usage": 60005,
  "concurrency": 2,
  "yields": 5
}
a 2.0 scripted custom record has a summary that looks like
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-07T23:01:21.439Z",
  "seconds": 3263,
  "usage": 60005,
  "concurrency": 2,
  "yields": 5
}
a 2.1 scripted custom record has a summary that looks like
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-07T23:32:11.777Z",
  "seconds": 3909,
  "usage": 60005,
  "concurrency": 2,
  "yields": 5
}
the user event did nonthing but log:
Copy code
/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 * @NModuleScope SameAccount
 */
define([], function () {
  return {
    beforeSubmit: function (context) {
      log.debug("beforeSubmit", context);
    },
  };
});
so its more of a test of the 2.1 overhead vs the 2.0 overhead
in this case, the 2.1 does appear to have a minor performance decrease over 2.0
c
@battk did you run the tests more than once?
Minor degradation in performance could be anything. If you see it over and over again then I guess it's true that 2.1 is a little slower in this context.
I'm in Australia at the moment with the nearest data centre in the US West Coast so we don't really need slower 🙂
b
its a boring 10000 record test over about 30 minutes
a
it would be interesting to try some other tests. Like using the performance module and creating two scripts that do the same thing at the same time, see which one is worse.
b
the apm module will give about the same information
message has been deleted
message has been deleted
number of logs is not consistent because apm evidently is not very good at capturing, my guess is the concurrency level of 2 of the map reduce did it in
a
what if it did something different like loaded a record and then saved it again ?
or ran a saved search
b
potentially could give different information, my test is more about the script overhead vs performance of particular modules
keep in mind that 2.0 and 2.1 are backed by the same java backend
a
yes but if the performance of 2.1 is better once you get to doing something practical with it, that is still useful information
b
the difference would be how they call that backend
a
yes, exactly
b
i personally would expect that unless they are doing something wrong, the java backend takes up most of the script time
but pick what you want done and ill give it a try
i personally chose to do nothing in the script because I expected the script overhead to be the biggest difference between 2.0 and 2.1
a
can you try loading a record? not even saving it again, just loading one ?
using the map/reduce ?
b
which record
a
sales order
always where the most crap is ...
b
well, ill load the same sales order 10000 times
dont have many sales orders in test accounts
did you want a user event deployed on beforeLoad?
a
no
b
boring script will look like:
Copy code
/**
 * @NApiVersion 2.0
 * @NScriptType MapReduceScript
 */
define(["N/record"], function (record) {

  function getInputData() {
    return new Array(10000)
  }

  function map(context) {
    record.load({id: '4956', type: 'salesorder'});
  }

  function reduce(context) {
    log.debug("reduce context", context);
  }

  function summarize(summary) {
    log.debug("summary", summary);

    if (summary.inputSummary.error) {
      log.error({
        title: "Input Error",
        details: summary.inputSummary.error,
      });
    }

    summary.mapSummary.errors
      .iterator()
      .each(function (key, error, executionNumber) {
        log.error({
          title:
            "Map error on key: " +
            key +
            ", executionNumber: " +
            executionNumber,
          details: error,
        });
        return true;
      });

    summary.reduceSummary.errors
      .iterator()
      .each(function (key, error, executionNumber) {
        log.error({
          title:
            "Reduce error on key: " +
            key +
            ", executionNumber: " +
            executionNumber,
          details: error,
        });
        return true;
      });
  }

  return {
    getInputData: getInputData,
    map: map,
    reduce: reduce,
    summarize: summarize,
  };
});
a
that looks good.
b
whoops, i forgot why i did the stuff on the user event script
apm doesnt support map/reduce, so we will only have the summary object for timing
m
keep in mind that 2.0 and 2.1 are backed by the same java backend
@battk 2.0 is backed by Rhino and 2.1 by GraalVM
b
there is java code that runs the record loading
its the same for both
m
are you saying that js engine (rhino/graalvm) is ultimately calling the same backend java code which is the real bottleneck for IO?
i wouldn't be surprised at all if there is a SS2.1 -> SS2.0 bridge for the API and it's using Rhino as well
i know for a fact that is happening for SS2.0 -> SS1.0
b
same backend code is probably serving all versions of suitescript
most obvious was the ss1 code, where you can tell things like nlobjServerRequest corresponds to parts of HttpServletRequest
m
at one point i starting writing a whole suite of performance benchmarks for SS2.1 to 2.0 which i intended to share with the community
however someone pointed out to me it's officially against the terms of service
https://www.netsuite.com/portal/assets/pdf/terms-of-service-v032618.pdf
perform or disclose any benchmarking, availability or performance testing of the Service
the high level takeaway i got (hope they don't come after me for this lol) is that when it comes to pure computational speed (e.g. calculating pi) it's faster, but slower for IO which what almost always matters in NetSuite dev work
b
it would be very sad for graal if old man rhino was better at computing pi
😆 1
though evidently rhino has got some updates since the last time i checked
i doubt netsuite applied them
b
A little bird at NS told me they're migrating to kubernetes. This is speculation, but I would anticipate if they're doing that, and running graalvm, they would eventually move the java code base to quarkus compiled to bytecode on graalvm. If that can back the SS API, it will eventually become muuuuch faster. Quarkus benchmarks are super fast...
It's a compelling case. If they ain't doin it they should be 😬 https://quarkus.io/blog/runtime-performance/
b
@aerin I shall say that the results of your test are bad enough that I suspect I screwed up somewhere
the 2.0 summary object looks like:
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-08T01:02:17.346Z",
  "seconds": 4427,
  "usage": 100000,
  "concurrency": 2,
  "yields": 9
}
the 2.1 summary object looks like
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-08T02:19:22.791Z",
  "seconds": 17321,
  "usage": 100000,
  "concurrency": 2,
  "yields": 9
}
I had to change the getInputData function for 2.1 to be
Copy code
function getInputData() {
    var arr = [];
    for (var i = 0; i < 10000; i++) {
      arr.push('{}')
    }
    return arr;
  }
since 2.1 took offense to returning an array with empty elements
ill basically try again with concurrency level set to 1 and both scripts running at the same time to see if for some reason the server decided to get slower during off peak hours
c
Super interesting @battk
b
minor spoiler, does not appear to be a fluke
😔 1
pretty bad showing from the 2.1 record.load. not as bad as the first time but generally something is wrong with such a major performance decrease for 2.0 the summary object was:
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-08T06:33:02.635Z",
  "seconds": 5599,
  "usage": 100000,
  "concurrency": 1,
  "yields": 10
}
for 2.1 the summary object was
Copy code
{
  "type": "mapreduce.Summary",
  "dateCreated": "2020-10-08T06:33:02.192Z",
  "seconds": 19197,
  "usage": 100000,
  "concurrency": 1,
  "yields": 10
}
script used was (in case someone wants to verify). you would probably need to choose a different sales order to load
Copy code
define(["N/record"], function (record) {
  function getInputData() {
    var arr = [];
    for (var i = 0; i < 10000; i++) {
      arr.push('{}')
    }
    return arr;
  }

  function map(context) {
    record.load({id: '4956', type: 'salesorder'});
  }

  function summarize(summary) {
    log.debug("summary", summary);

    if (summary.inputSummary.error) {
      log.error({
        title: "Input Error",
        details: summary.inputSummary.error,
      });
    }

    summary.mapSummary.errors
      .iterator()
      .each(function (key, error, executionNumber) {
        log.error({
          title:
            "Map error on key: " +
            key +
            ", executionNumber: " +
            executionNumber,
          details: error,
        });
        return true;
      });

    summary.reduceSummary.errors
      .iterator()
      .each(function (key, error, executionNumber) {
        log.error({
          title:
            "Reduce error on key: " +
            key +
            ", executionNumber: " +
            executionNumber,
          details: error,
        });
        return true;
      });
  }

  return {
    getInputData: getInputData,
    map: map,
    summarize: summarize,
  };
});
m
yikes
message has been deleted
🤔 1
a
@michoel where is that from ?
b
hopefully they have average numbers too or something
listing maximums is boring
and can be deceptive if the average is much lower
👀 1
m
@aerin it's from a presentation at the NetSuite Now On Air event. I noticed when the presenter read it he specifically said faster at "pure" JavaScript execution.