oracle / graaljs

A ECMAScript 2023 compliant JavaScript implementation built on GraalVM. With polyglot language interoperability support. Running Node.js applications!
Universal Permissive License v1.0
1.77k stars 189 forks source link

GraalJS is around 70X slower than NodeJS 14 #360

Closed ciplogic closed 2 years ago

ciplogic commented 3 years ago

Hello, first of all, I don't want to see that is bashing GraalVM/JS and this experiment is not wanting to look I am not appreciating the project as is, I know that it is really a hard work to do a full JS/NodeJS runtime.

So let's dig in: I want to parse large JS files using AcornJS and to try to make a visitor that would replace some construct in that file.

So imagine (or get some generated webpack) large file and parse it as follows:

const fs = require('fs')
const {Parser} = require('acorn')

const walk = require("acorn-walk")

function timeIt(message, action){
    var start = new Date();
    action();
    var end = new Date();
    console.log("Time to "+message, (end-start))
}

function deduplicateTypes(fullAst){
    var map = new Map()
    var keys = []
    var countHits = 0
    walk.fullAncestor(fullAst, (node) => {
        ++countHits;
        if (map.has(node.type)){
            node.type = keys[map.get(node.type)]
            return;
        }
        map.set(node.type, keys.length)
        keys.push(node.type)
    });
    console.log(countHits)
    return keys
}
const content = fs.readFileSync('/path/to/large/js/file', 'utf-8')
for(var i =0;i<10; i++){
    timeIt(`Parse ${i}`, ()=> {
        var tree = Parser.parse(content)
        deduplicateTypes(tree)
    });
}

With package.json file:

{
  "name": "safejs",
  "version": "0.1.0",
  "description": "Prototype JS Replacer",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "acorn": "^6.4.2",
    "acorn-loose": "^8.0.0",
    "acorn-walk": "^8.0.0",
    "htmlparser": "^1.7.7"
  }
}

Instead of "deduplicateTypes" it would be a small checker of type and replacing some constructs (i.e. strings with the some encrypted string routine).

This code using NodeJS would run in around 1300 ms, when with GraalJS runs in around 105 000 ms, and I was iterating the program to wait GraalVM to get it to let's say 10 seconds and at least in up-to 20 iterations it didn't get under 105 seconds. (first iteration though was 141 519 ms). The input file which sadly I cannot share it, is into 12 MB generated JS code, and it is a ReactNative application.

frank-dspeed commented 3 years ago

@cip they are aware of that facts and it will get handeled soon.

Many People are working on that as rule of Thumb that applys at present you can always say when ever you use node-graal and u use Nativ Node Modules you will get that slower results it is also importent that you set the engine to lazy and maybe even put a warmup function into your code.

Revisit that in 6 Month and you will get much better results i have written down your name and will ping you when that point is reached :)

But i want to give you a current example that proves that graaljs is faster in general google for es4x and try it that is using Java + JS and less node modules and outperforms nodejs by 10x times in most scenarios of the empower tech benchmark

ciplogic commented 3 years ago

Thank you @frank-dspeed for your assurance!

To be fair, I don't need to that GraalVM to be that fast, but not to be that slow.

I think that if after warmup in 1 year from now GraalVM would reach let's say 7-8 seconds (so in 5x times slower than NodeJS) for this workload, would make it usable for this type of workload: "parsing medium/large documents".

frank-dspeed commented 3 years ago

@ciplogic i think you understand that a bit wrong https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite when you look here for es4x that is in fact graaljs it ranks on overall rank 9 and nestjs which is in efect optimized nodejs ranks 49

simply wait a bit and see what happens i am confident you will be impressed. else i would not waist my time with that.

Conclusion

As soon as there is no nodejs dependencie needed for graaljs it is up to 13x faster on some workloads as it is overall more memory and cpu efficent. And we did not talk about optimization we talk about the out of the box case.

When we account optimization into that so for example tune the jvm inlining parameters we can end up in hugh bigger numbers !! The JVM has 100+ Options for Compiler tuning and is supporting Custom GC Implementations. All this will never be possible with NodeJS that is a fact. There a boundaries because of the way NodeJS is Designed and this Physical boundaries do not apply to GraalJS.

hope that could sheet some light.

frank-dspeed commented 3 years ago

Or to Explain it even more simple the NodeJS and V8 code is static compiled AOT and only JS gets optimized with GraalJS the Whole NodeJS and V8 Gets Optimized .

frank-dspeed commented 3 years ago

and for your understanding to get a function warm it is enough to call it 100 times fast with example data that takes some ms not hours or years :)

wirthi commented 3 years ago

@frank-dspeed: ciplogic probably meant 1 year of our engineering time to improve warming up, not 1 year of actually warming up :-)

wirthi commented 3 years ago

Hi @ciplogic,

thanks for your request. And thanks for providing a simple to run example, that is much appreciated as it makes my job much easier.

Yes, our warmup performance can be very bad, and also peak performance might not be where we want it to be on some examples. Code patterns like yours will help us improve in the future. Warmup performance is our main focus at the moment, we should significantly improve over the next few versions.

Looking at your example, however, I cannot reproduce the current stage as you do. Yes, we are behind, but not as catastrophically as in your data. Can you please check whether you are using a current version of GraalVM, (20.2.0 being the most recent currently)? Maybe you can also share some basic specs of your machine, like how many cores, how much memory, do you use CE or EE version of GraalVM, etc.

On my machine, I get the following data (warmup generally stabilized after ~5 iterations, that what I show here; I am using Node 12.x because that is what GraalVM provides as well. I also tried with Node 14.x but the results were comparable):

Node.js 12.18.0:

$ ~/software/node-v12.18.0-linux-x64/bin/node index.js
1177427
Time to Parse 0 1901
1177427
Time to Parse 1 1721
1177427
Time to Parse 2 1660
1177427
Time to Parse 3 1695
1177427
Time to Parse 4 1720

GraalVM EE 20.2.0:

$ ~/software/graalvm-ee-java8-20.2.0/bin/node index.js 
1177427
Time to Parse 0 37332
1177427
Time to Parse 1 39480
1177427
Time to Parse 2 11947
1177427
Time to Parse 3 11730
1177427
Time to Parse 4 11315

GraalVM CE 20.2.0:

$ ~/software/graalvm-ce-java8-20.2.0/bin/node index.js 
1177427
Time to Parse 0 73193
1177427
Time to Parse 1 55765
1177427
Time to Parse 2 20624
1177427
Time to Parse 3 16998
1177427
Time to Parse 4 13091

(Using GraalVM EE data unless mentioned otherwise) So while our first iteration is 37s compared to 1.9 seconds, fourth iteration is 1.695 ms VS 11.730 ms - that's a factor of 7.3. Totally agree, we need to improve both warmup AND peak performance on this example, but I still wonder why your data is so much worse? Noteworthy, CE data is worse for the first ~2 iterations, but on peak, it's 11 compared to 13 seconds, so not a huge difference.

A surprise contender might be the --jvm mode of GraalVM (that means, that the JavaScript engine is not using the ahead-of-time-compiled native mode generated by native-image but instead is executed on a plain JVM):

$ ~/software/graalvm-ee-java8-20.2.0/bin/node --jvm index.js 
1177427
Time to Parse 0 55094
1177427
Time to Parse 1 66969
1177427
Time to Parse 2 23395
1177427
Time to Parse 3 6445
1177427
Time to Parse 4 6688
1177427
Time to Parse 5 6127
1177427
Time to Parse 6 5944
1177427
Time to Parse 7 5740
1177427
Time to Parse 8 5452
1177427
Time to Parse 9 5397
1177427
Time to Parse 10 4394
1177427
Time to Parse 11 4300
1177427
Time to Parse 12 4270
1177427
Time to Parse 13 4179
1177427
Time to Parse 14 4426
1177427
Time to Parse 15 4122

While the warmup takes longer than in --native mode on EE (both in terms of time and of number of iterations), the peak performance is significantly better: with 1660 compared to 4122 ms, we are down to a factor of 2.5.

Best, Christian

ciplogic commented 3 years ago

Hi @wirthi , I will do the test with EE and I was using the latest public version of CE.

To me a factor of 2.5X is acceptable, even with a long warm-up! And if you will need, I will try to get some off-the-shelf React-Native application and build it and attach it that would reproduce the behavior. Or other application that has to be quite large.

Also, I personally don't fully care about warmup, my expectation would be that I can wrap it as a web-service (using express maybe!?) and I can expect something like 1-2 minutes warm-up as I can throw some data to this service at startup, obviously, if it would take 1 hour to warm-up, it is impractical.

So let me see when I have time and I will add more data.

So if I understand correctly, you need the following:

  1. CE vs EE data making sure it is the latest version of GraalVM. This is not important, but I remember taking GraalVM/NodeJS based on version 11, Linux/AMD64, do you think I should take version 8? I took 11 because I thought it is newest, but I don't want to. Add also --jvm to testing.
  2. Try to find some sample application that reproduces a similar behavior (at least on my hardware) and attach a zipped archive?
wirthi commented 3 years ago

Hi @ciplogic

yes, an express application is a good example: it will have some slow warmup, i.e. the first few iterations will be significantly slower. The warmup time should be in the seconds to minutes though, until you reach peak (not hours).

Regarding your questions: 1) I assume you mean Java versions. JDK8 VS JDK11. That difference should not matter. 2) yes that would be awesome. I tried with the Octane-Mandreel benchmark (that's a 5MB JS source code file), but the performance might depend on the input of course.

Best, Christian

ciplogic commented 3 years ago

So let's start with the file: this is a real project (React-native) file which is copied 4 times to match the input size of the project I was operating with. (it is 12 MB vs 11.1 MB)

As I understand that there is not a large difference between CE and EE, I will not test it yet (because will take a bit longer to test and just right now I have not that much time to install/download) I will do it with CE. I had the latest version as far as I can see.

My machine spec is: Linux x64 Mint (with all updates), AMD 3900X (12c), 48GB RAM)

Output: (ran under WebStorm)

/home/ciprian/apps/graalvm-ce-java11-20.2.0/bin/node --jvm /home/ciprian/WebstormProjects/untitled/index.js
Time to Parse 0 70220
Time to Parse 1 61477
Time to Parse 2 40816
Time to Parse 3 43564
Time to Parse 4 42268
Time to Parse 5 42782
Time to Parse 6 41679
Time to Parse 7 41548
Time to Parse 8 41579
Time to Parse 9 41013

Removing --jvm flag and the performance is worse:

Time to Parse 0 123402
Time to Parse 1 121786
Time to Parse 2 96481
Time to Parse 3 94285

I ran just 3 iterations, but the choice is clear for --jvm flag for now if you don't recommend me otherwise.

Under NodeJS (version 14)

/home/ciprian/apps/node-v14.13.1-linux-x64/bin/node /home/ciprian/WebstormProjects/untitled/index.js
Time to Parse 0 1950
Time to Parse 1 1666
Time to Parse 2 1871
Time to Parse 3 1579
Time to Parse 4 1587
Time to Parse 5 1781
Time to Parse 6 1881
Time to Parse 7 1629
Time to Parse 8 1616
Time to Parse 9 1765

If you have problems reproducing or you think that I must run EE, I am glad to make it.

main.zip

frank-dspeed commented 3 years ago

@ciplogic could you please also try

/home/ciprian/apps/graalvm-ce-java11-20.2.0/bin/node --jvm --engine.Mode=latency
ciplogic commented 3 years ago

@frank-dspeed here, it is the fastest:

/home/ciprian/apps/graalvm-ce-java11-20.2.0/bin/node --jvm --engine.Mode=latency /home/ciprian/WebstormProjects/untitled/index.js
Time to Parse 0 36469
Time to Parse 1 41001
Time to Parse 2 36078
Time to Parse 3 37431
Time to Parse 4 36812
Time to Parse 5 33830
Time to Parse 6 38036
Time to Parse 7 38100
Time to Parse 8 37899
Time to Parse 9 37963
ciplogic commented 3 years ago

As I updated the EE version, and the numbers do improve, but still, they are quite high.

The code is this, but it should run in basically the same time, but I wanted to give some hint where the time goes (as expected, most of it is in parsing):

const fs = require('fs')
const {Parser} = require('acorn')

const walk = require("acorn-walk")

var indent = 0;
function timeIt(message, action) {
    var start = new Date();
    var indentStr = (' '.repeat(indent*4));
    console.log(`${indentStr}Start ${message}...`)
    indent++;
    action();
    indent--;
    var end = new Date();
    console.log(`${indentStr}Done in (seconds): ${(end - start) / 1000.0}`)
}

function deduplicateTypes(fullAst){
    var map = new Map()
    var keys = []
    var countHits = 0
    walk.fullAncestor(fullAst, (node) => {
        ++countHits;
        if (map.has(node.type)){
            node.type = keys[map.get(node.type)]
            return;
        }
        map.set(node.type, keys.length)
        keys.push(node.type)
    });
    return keys
}
const content = fs.readFileSync('/home/ciprian/WebstormProjects/main.js', 'utf-8')
for(var i =0;i<10; i++){
    timeIt(`Parse ${i}`, ()=> {
        var tree;
        timeIt(`parse JS`, ()=> {
            tree = Parser.parse(content)
        });
        timeIt(`visit tree`, ()=> {
            var keyTypes = deduplicateTypes(tree)
        });
    });
}

And now all the times are with EE version:

With --jvm flag:

/home/ciprian/apps/graalvm-ee-java11-20.2.0/bin/node --jvm  /home/ciprian/WebstormProjects/untitled/index.js
Start Parse 0...
    Start parse JS...
    Done in (seconds): 52.946
    Start visit tree...
    Done in (seconds): 8.816
Done in (seconds): 61.794
Start Parse 1...
    Start parse JS...
    Done in (seconds): 59.015
    Start visit tree...
    Done in (seconds): 8.552
Done in (seconds): 67.57
Start Parse 2...
    Start parse JS...
    Done in (seconds): 37.724
    Start visit tree...
    Done in (seconds): 0.66
Done in (seconds): 38.385
Start Parse 3...
    Start parse JS...
    Done in (seconds): 32.355
    Start visit tree...
    Done in (seconds): 0.658
Done in (seconds): 33.015
Start Parse 4...
    Start parse JS...
    Done in (seconds): 31.201
    Start visit tree...
    Done in (seconds): 0.678
Done in (seconds): 31.88
Start Parse 5...
    Start parse JS...
    Done in (seconds): 30.628
    Start visit tree...
    Done in (seconds): 0.656
Done in (seconds): 31.286
Start Parse 6...
    Start parse JS...
    Done in (seconds): 30.432
    Start visit tree...
    Done in (seconds): 0.66
Done in (seconds): 31.094
Start Parse 7...
    Start parse JS...
    Done in (seconds): 30.654
    Start visit tree...
    Done in (seconds): 0.658
Done in (seconds): 31.313
Start Parse 8...
    Start parse JS...
    Done in (seconds): 30.46
    Start visit tree...
    Done in (seconds): 0.643
Done in (seconds): 31.103
Start Parse 9...
    Start parse JS...
    Done in (seconds): 30.719
    Start visit tree...
    Done in (seconds): 0.664
Done in (seconds): 31.384

JVM mode latency is a wash now with warmed up --jvm

/home/ciprian/apps/graalvm-ee-java11-20.2.0/bin/node --jvm --engine.Mode=latency /home/ciprian/WebstormProjects/untitled/index.js
Start Parse 0...
    Start parse JS...
    Done in (seconds): 34.517
    Start visit tree...
    Done in (seconds): 1.045
Done in (seconds): 35.59
Start Parse 1...
    Start parse JS...
    Done in (seconds): 33.816
    Start visit tree...
    Done in (seconds): 1.016
Done in (seconds): 34.834
Start Parse 2...
    Start parse JS...
    Done in (seconds): 30.893
    Start visit tree...
    Done in (seconds): 0.931
Done in (seconds): 31.826
Start Parse 3...
    Start parse JS...
    Done in (seconds): 30.891
    Start visit tree...
    Done in (seconds): 0.88
Done in (seconds): 31.773
Start Parse 4...
    Start parse JS...
    Done in (seconds): 31.504
    Start visit tree...
    Done in (seconds): 0.873
Done in (seconds): 32.379
Start Parse 5...
    Start parse JS...
    Done in (seconds): 30.89
    Start visit tree...
    Done in (seconds): 0.867
Done in (seconds): 31.758
Start Parse 6...
    Start parse JS...
    Done in (seconds): 30.535
    Start visit tree...
    Done in (seconds): 0.896
Done in (seconds): 31.434
Start Parse 7...
    Start parse JS...
    Done in (seconds): 30.546
    Start visit tree...
    Done in (seconds): 0.9
Done in (seconds): 31.446
Start Parse 8...
    Start parse JS...
    Done in (seconds): 30.97
    Start visit tree...
    Done in (seconds): 0.891
Done in (seconds): 31.863
Start Parse 9...
    Start parse JS...
    Done in (seconds): 31.21
    Start visit tree...
    Done in (seconds): 0.874
Done in (seconds): 32.086

Defaults:

/home/ciprian/apps/graalvm-ee-java11-20.2.0/bin/node /home/ciprian/WebstormProjects/untitled/index.js
Start Parse 0...
    Start parse JS...
    Done in (seconds): 70.468
    Start visit tree...
    Done in (seconds): 2.028
Done in (seconds): 72.503
Start Parse 1...
    Start parse JS...
    Done in (seconds): 78.344
    Start visit tree...
    Done in (seconds): 1.977
Done in (seconds): 80.321
Start Parse 2...
    Start parse JS...
    Done in (seconds): 70.707
    Start visit tree...
    Done in (seconds): 0.943
Done in (seconds): 71.651
Start Parse 3...
    Start parse JS...
    Done in (seconds): 70.774
    Start visit tree...
    Done in (seconds): 0.968
Done in (seconds): 71.743
Start Parse 4...
    Start parse JS...
    Done in (seconds): 70.505
    Start visit tree...
    Done in (seconds): 1.007
Done in (seconds): 71.513
Start Parse 5...
    Start parse JS...
    Done in (seconds): 70.469
    Start visit tree...
    Done in (seconds): 0.981
Done in (seconds): 71.45
Start Parse 6...
    Start parse JS...
    Done in (seconds): 71.202
    Start visit tree...
    Done in (seconds): 0.853
Done in (seconds): 72.056
Start Parse 7...
    Start parse JS...
    Done in (seconds): 72.114
    Start visit tree...
    Done in (seconds): 0.92
Done in (seconds): 73.034

And NodeJS for reference:

/home/ciprian/apps/node-v14.13.1-linux-x64/bin/node /home/ciprian/WebstormProjects/untitled/index.js
Start Parse 0...
    Start parse JS...
    Done in (seconds): 1.605
    Start visit tree...
    Done in (seconds): 0.378
Done in (seconds): 1.985
Start Parse 1...
    Start parse JS...
    Done in (seconds): 1.297
    Start visit tree...
    Done in (seconds): 0.41
Done in (seconds): 1.707
Start Parse 2...
    Start parse JS...
    Done in (seconds): 1.571
    Start visit tree...
    Done in (seconds): 0.394
Done in (seconds): 1.965
Start Parse 3...
    Start parse JS...
    Done in (seconds): 1.292
    Start visit tree...
    Done in (seconds): 0.394
Done in (seconds): 1.686
Start Parse 4...
    Start parse JS...
    Done in (seconds): 1.296
    Start visit tree...
    Done in (seconds): 0.391
Done in (seconds): 1.687
Start Parse 5...
    Start parse JS...
    Done in (seconds): 1.383
    Start visit tree...
    Done in (seconds): 0.392
Done in (seconds): 1.775
Start Parse 6...
    Start parse JS...
    Done in (seconds): 1.321
    Start visit tree...
    Done in (seconds): 0.392
Done in (seconds): 1.713
Start Parse 7...
    Start parse JS...
    Done in (seconds): 1.357
    Start visit tree...
    Done in (seconds): 0.392
Done in (seconds): 1.749
Start Parse 8...
    Start parse JS...
    Done in (seconds): 1.506
    Start visit tree...
    Done in (seconds): 0.391
Done in (seconds): 1.897
Start Parse 9...
    Start parse JS...
    Done in (seconds): 1.23
    Start visit tree...
    Done in (seconds): 0.392
Done in (seconds): 1.623
ciplogic commented 3 years ago

I added a side experiment: increasing GC size (not sure if I done it correctly) but it looks that it saves around 0,6 seconds in warm state (I can see around 30.5 seconds vs 31.1 seconds). To me this shows that the slow-down is not on GC (probably you know it already)

Start Parse 0...
    Start parse JS...
    Done in (seconds): 53.694
    Start visit tree...
    Done in (seconds): 8.775
Done in (seconds): 62.505
Start Parse 1...
    Start parse JS...
    Done in (seconds): 57.565
    Start visit tree...
    Done in (seconds): 8.787
Done in (seconds): 66.354
Start Parse 2...
    Start parse JS...
    Done in (seconds): 38.689
    Start visit tree...
    Done in (seconds): 0.657
Done in (seconds): 39.347
Start Parse 3...
    Start parse JS...
    Done in (seconds): 30.96
    Start visit tree...
    Done in (seconds): 0.671
Done in (seconds): 31.632
Start Parse 4...
    Start parse JS...
    Done in (seconds): 30.498
    Start visit tree...
    Done in (seconds): 0.67
Done in (seconds): 31.17
Start Parse 5...
    Start parse JS...
    Done in (seconds): 30.111
    Start visit tree...
    Done in (seconds): 0.661
Done in (seconds): 30.773
Start Parse 6...
    Start parse JS...
    Done in (seconds): 30.014
    Start visit tree...
    Done in (seconds): 0.653
Done in (seconds): 30.668
Start Parse 7...
    Start parse JS...
    Done in (seconds): 30.285
    Start visit tree...
    Done in (seconds): 0.663
Done in (seconds): 30.95
Start Parse 8...
    Start parse JS...
    Done in (seconds): 29.811
    Start visit tree...
    Done in (seconds): 0.653
Done in (seconds): 30.466
Start Parse 9...
    Start parse JS...
    Done in (seconds): 29.798
    Start visit tree...
    Done in (seconds): 0.652
Done in (seconds): 30.45

Webpacking seems to not improve the runtime, but if it would help, I am glad to consider a webpack like approach :+1:

To generate a webpack file, this 'webpack.config.js' worked for me:

var path = require('path');
module.exports = {
    entry: './index.js',
    target: 'node14.0',
    output: {
        path: path.resolve(__dirname, 'public/'),
        filename: 'runner.js'
    },
    module: {
    }
};

I could not see any relevant speedup from webpack-ing it, maybe the warmup (but I am not sure) looking like it is few seconds shorter.

ciplogic commented 3 years ago

One last spam for today, as I just noticed that there is a: --cpusampler option.

All output is the following:

/home/ciprian/apps/graalvm-ee-java11-20.2.0/bin/node --jvm --cpusampler --cputracer.OutputFile=profile.txt /home/ciprian/WebstormProjects/untitled/index.js
Start Parse 0...
    Start parse JS...
    Done in (seconds): 59.974
    Start visit tree...
    Done in (seconds): 9.307
Done in (seconds): 69.316
Start Parse 1...
    Start parse JS...
    Done in (seconds): 61.189
    Start visit tree...
    Done in (seconds): 9.055
Done in (seconds): 70.246
Start Parse 2...
    Start parse JS...
    Done in (seconds): 38.53
    Start visit tree...
    Done in (seconds): 0.863
Done in (seconds): 39.395
Start Parse 3...
    Start parse JS...
    Done in (seconds): 32.327
    Start visit tree...
    Done in (seconds): 0.619
Done in (seconds): 32.948
Start Parse 4...
    Start parse JS...
    Done in (seconds): 31.327
    Start visit tree...
    Done in (seconds): 0.61
Done in (seconds): 31.938
Start Parse 5...
    Start parse JS...
    Done in (seconds): 31.328
    Start visit tree...
    Done in (seconds): 0.606
Done in (seconds): 31.936
Start Parse 6...
    Start parse JS...
    Done in (seconds): 30.465
    Start visit tree...
    Done in (seconds): 0.642
Done in (seconds): 31.109
Start Parse 7...
    Start parse JS...
    Done in (seconds): 33.867
    Start visit tree...
    Done in (seconds): 0.633
Done in (seconds): 34.501
Start Parse 8...
    Start parse JS...
    Done in (seconds): 31.981
    Start visit tree...
    Done in (seconds): 0.582
Done in (seconds): 32.565
Start Parse 9...
    Start parse JS...
    Done in (seconds): 31.634
    Start visit tree...
    Done in (seconds): 0.595
Done in (seconds): 32.231
----------------------------------------------------------------------------------------------------------------------------------
Sampling Histogram. Recorded 372598 samples with period 1ms.
  Self Time: Time spent on the top of the stack.
  Total Time: Time spent somewhere on the stack.
  Opt %: Percent of time spent in compiled and therefore non-interpreted code.
----------------------------------------------------------------------------------------------------------------------------------
 Thread: Thread[main,5,main]
 Name                                       |      Total Time     |  Opt % ||       Self Time     |  Opt % | Location             
----------------------------------------------------------------------------------------------------------------------------------
 pp$3.parseFunctionBody                     |     346159ms  92.9% |  62.2% ||     194305ms  52.1% |  99.4% | node_modules/acorn/dist/acorn.js~2644-2681:111244-112988 
 pp.strictDirective                         |      74331ms  19.9% |  45.4% ||      74331ms  19.9% |  45.4% | node_modules/acorn/dist/acorn.js~596-612:32146-32703 
 c                                          |      22147ms   5.9% |   0.0% ||       9385ms   2.5% |   1.7% | node_modules/acorn-walk/dist/walk.js~88-95:3511-3842 
 pp$9.readWord                              |      10066ms   2.7% |  31.0% ||       5722ms   1.5% |  54.5% | node_modules/acorn/dist/acorn.js~4905-4913:189702-189995 
 :=>                                        |       4598ms   1.2% |   0.0% ||       4598ms   1.2% |   0.0% | index.js~22-30:548-766 
 pp$3.parseExprAtom                         |     348572ms  93.6% |  79.9% ||       4488ms   1.2% |  38.6% | node_modules/acorn/dist/acorn.js~2167-2272:92604-96518 
 pp$9.finishToken                           |       8071ms   2.2% |   2.8% ||       4061ms   1.1% |   5.5% | node_modules/acorn/dist/acorn.js~4376-4384:170618-170846 
 pp$9.readToken                             |      17014ms   4.6% |  16.3% ||       4025ms   1.1% |  45.3% | node_modules/acorn/dist/acorn.js~4282-4289:167503-167800 
 pp$9.getTokenFromCode                      |       9983ms   2.7% |  34.5% ||       3889ms   1.0% |  34.8% | node_modules/acorn/dist/acorn.js~4489-4561:174835-177493 
 pp$9.nextToken                             |      19184ms   5.1% |   1.0% ||       3714ms   1.0% |   5.1% | node_modules/acorn/dist/acorn.js~4270-4280:167053-167480 
 pp$3.parseMaybeAssign                      |     349321ms  93.8% |  81.6% ||       3243ms   0.9% |  62.9% | node_modules/acorn/dist/acorn.js~1946-1987:81943-84171 
 pp$3.parseIdent                            |      14420ms   3.9% |  38.4% ||       3201ms   0.9% |  59.7% | node_modules/acorn/dist/acorn.js~2760-2786:115874-116948 
 pp$7.updateContext                         |       4009ms   1.1% |   0.1% ||       2918ms   0.8% |   0.1% | node_modules/acorn/dist/acorn.js~3034-3042:125443-125720 
 pp$3.parseMaybeUnary                       |     349281ms  93.7% |  83.9% ||       2896ms   0.8% |  74.3% | node_modules/acorn/dist/acorn.js~2047-2083:86698-88350 
 pp$9.next                                  |      21785ms   5.8% |   4.3% ||       2759ms   0.7% |  19.7% | node_modules/acorn/dist/acorn.js~4228-4237:166005-166270 
 pp$3.parseSubscript                        |     316972ms  85.1% |  83.1% ||       2467ms   0.7% |  51.8% | node_modules/acorn/dist/acorn.js~2110-2160:89802-92355 
 pp$1.parseBlock                            |     273464ms  73.4% |  84.9% ||       1458ms   0.4% |  81.8% | node_modules/acorn/dist/acorn.js~1153-1166:53211-53706 
 skipThrough                                |      22099ms   5.9% |  18.2% ||       1358ms   0.4% |  21.4% | node_modules/acorn-walk/dist/walk.js~186:6901-6950 
 base.CallExpression                        |      21944ms   5.9% |  21.9% ||       1323ms   0.4% |  66.2% | node_modules/acorn-walk/dist/walk.js~388-397:13490-13739 
 pp$9.skipSpace                             |       1287ms   0.3% |   3.3% ||       1287ms   0.3% |   3.3% | node_modules/acorn/dist/acorn.js~4331-4369:169409-170374 
 pp$3.checkUnreserved                       |       1899ms   0.5% |   0.4% ||       1233ms   0.3% |   0.6% | node_modules/acorn/dist/acorn.js~2735-2754:114778-115694 
 pp$9.readString                            |       1432ms   0.4% |   3.0% ||       1229ms   0.3% |   3.5% | node_modules/acorn/dist/acorn.js~4697-4714:182876-183565 
 pp$3.parseExprList                         |     342930ms  92.0% |  79.2% ||       1187ms   0.3% |  51.1% | node_modules/acorn/dist/acorn.js~2712-2733:113933-114749 
 pp$1.parseStatement                        |     349546ms  93.8% |  84.5% ||       1162ms   0.3% |  56.1% | node_modules/acorn/dist/acorn.js~808-882:39583-43160 
 pp$9.readWord1                             |       1924ms   0.5% |   2.3% ||       1111ms   0.3% |   4.1% | node_modules/acorn/dist/acorn.js~4874-4900:188551-189586 
 pp.eat                                     |      11999ms   3.2% |   0.2% ||       1095ms   0.3% |   1.5% | node_modules/acorn/dist/acorn.js~617-624:32837-32961 
 pp$3.parseSubscripts                       |      54331ms  14.6% |   1.0% ||       1089ms   0.3% |   0.1% | node_modules/acorn/dist/acorn.js~2100-2108:89257-89774 
 pp$9.fullCharCodeAtPos                     |       1062ms   0.3% |   4.9% ||       1062ms   0.3% |   4.9% | node_modules/acorn/dist/acorn.js~4291-4296:167831-168047 
 pp$1.parseVar                              |     181093ms  48.6% |  88.4% ||       1054ms   0.3% |  87.1% | node_modules/acorn/dist/acorn.js~1221-1240:55440-56250 
 pp$3.parseExprSubscripts                   |      81496ms  21.9% |  32.0% ||       1012ms   0.3% |  34.7% | node_modules/acorn/dist/acorn.js~2087-2098:88438-89228 
 pp$9.readNumber                            |       1661ms   0.4% |  33.3% ||       1008ms   0.3% |  54.9% | node_modules/acorn/dist/acorn.js~4642-4671:180607-182090 
 pp$3.parseExprOps                          |      79097ms  21.2% |  26.5% ||        966ms   0.3% |   4.9% | node_modules/acorn/dist/acorn.js~2008-2013:84888-85272 
 pp$3.parseLiteral                          |       1982ms   0.5% |  52.1% ||        903ms   0.2% |  78.2% | node_modules/acorn/dist/acorn.js~2283-2290:96753-97045 
 pp$6.finishNode                            |       1529ms   0.4% |   2.5% ||        901ms   0.2% |   4.2% | node_modules/acorn/dist/acorn.js~2965-2967:122935-123044 
 base.MemberExpression                      |       5098ms   1.4% |  20.0% ||        897ms   0.2% |  70.0% | node_modules/acorn-walk/dist/walk.js~398-401:13768-13896 
 pp$9.readToken_dot                         |       1525ms   0.4% |   4.1% ||        871ms   0.2% |   7.2% | node_modules/acorn/dist/acorn.js~4395-4406:171158-171578 
 pp$3.parseObj                              |      76494ms  20.5% |  70.6% ||        856ms   0.2% |  61.0% | node_modules/acorn/dist/acorn.js~2453-2468:103411-104032 
 pp$2.parseBindingAtom                      |       3081ms   0.8% |  39.9% ||        757ms   0.2% |  76.9% | node_modules/acorn/dist/acorn.js~1739-1753:74550-74950 
 pp$1.parseFunction                         |     347257ms  93.2% |  82.8% ||        731ms   0.2% |  65.3% | node_modules/acorn/dist/acorn.js~1253-1289:56697-58395 
 pp$3.parseExprOp                           |       8604ms   2.3% |  47.4% ||        683ms   0.2% |  44.7% | node_modules/acorn/dist/acorn.js~2021-2035:85634-86323 
 pp$3.parseExpression                       |     349315ms  93.8% |  86.5% ||        678ms   0.2% |  61.5% | node_modules/acorn/dist/acorn.js~1931-1941:81331-81819 
 pp$9.finishOp                              |       1341ms   0.4% |   3.1% ||        641ms   0.2% |   6.4% | node_modules/acorn/dist/acorn.js~4563-4567:177515-177660 
 pp$3.parseParenAndDistinguishExpression    |     172696ms  46.3% |  85.7% ||        635ms   0.2% |  70.7% | node_modules/acorn/dist/acorn.js~2299-2359:97257-99794 
 finishNodeAt                               |        629ms   0.2% |   0.0% ||        629ms   0.2% |   0.0% | node_modules/acorn/dist/acorn.js~2955-2963:122684-122912 
 pp$9.readToken_eq_excl                     |       1540ms   0.4% |   6.4% ||        596ms   0.2% |  16.6% | node_modules/acorn/dist/acorn.js~4479-4487:174396-174805 
 base.LogicalExpression                     |       4200ms   1.1% |  21.4% ||        588ms   0.2% |  76.9% | node_modules/acorn-walk/dist/walk.js~375-378:13007-13107 
 base.ObjectExpression                      |       7315ms   2.0% |  18.6% ||        587ms   0.2% |  69.0% | node_modules/acorn-walk/dist/walk.js~339-346:12017-12173 
 pp$2.parseBindingList                      |       2577ms   0.7% |  57.5% ||        539ms   0.1% |  73.3% | node_modules/acorn/dist/acorn.js~1755-1778:74980-75836 
 pp$3.parseMaybeConditional                 |      65336ms  17.5% |   0.0% ||        534ms   0.1% |   0.0% | node_modules/acorn/dist/acorn.js~1991-2004:84257-84827 
 pp$1.parseReturnStatement                  |     116808ms  31.3% |  78.7% ||        502ms   0.1% |  70.5% | node_modules/acorn/dist/acorn.js~995-1007:47632-48174 
 pp$9.readInt                               |        488ms   0.1% |   0.0% ||        488ms   0.1% |   0.0% | node_modules/acorn/dist/acorn.js~4611-4626:179326-179931 
 pp$5.currentVarScope                       |        453ms   0.1% |   3.1% ||        453ms   0.1% |   3.1% | node_modules/acorn/dist/acorn.js~2914-2919:121502-121666 
 pp$3.parseProperty                         |      73616ms  19.8% |  77.9% ||        452ms   0.1% |  40.5% | node_modules/acorn/dist/acorn.js~2470-2519:104059-106203 
 base.VariableDeclaration                   |      12831ms   3.4% |  21.5% ||        441ms   0.1% |  73.2% | node_modules/acorn-walk/dist/walk.js~275-282:10093-10251 
 pp.expect                                  |       5069ms   1.4% |   5.6% ||        411ms   0.1% |  46.2% | node_modules/acorn/dist/acorn.js~682-684:34632-34692 
 base.BlockStatement                        |      22146ms   5.9% |  15.6% ||        404ms   0.1% |  45.5% | node_modules/acorn-walk/dist/walk.js~193-200:7067-7230 
 pp$1.parseVarStatement                     |     181236ms  48.6% |  84.5% ||        392ms   0.1% |  90.6% | node_modules/acorn/dist/acorn.js~1090-1095:51016-51174 
 base.SequenceExpression                    |      10785ms   2.9% |  21.8% ||        389ms   0.1% |  66.1% | node_modules/acorn-walk/dist/walk.js~348-355:12289-12460 
 at                                         |        364ms   0.1% |   0.0% ||        364ms   0.1% |   0.0% | node_modules/acorn/dist/acorn.js~3199-3211:135141-135482 
 pp$3.parsePropertyValue                    |      72265ms  19.4% |  78.3% ||        349ms   0.1% |  60.7% | node_modules/acorn/dist/acorn.js~2521-2569:106235-108684 
 pp$3.checkParams                           |        673ms   0.2% |  30.0% ||        331ms   0.1% |  61.0% | node_modules/acorn/dist/acorn.js~2696-2704:113367-113607 
 base.AssignmentPattern                     |       8971ms   2.4% |  18.0% ||        315ms   0.1% |  59.7% | node_modules/acorn-walk/dist/walk.js~379-382:13165-13262 
 pp$1.parseFunctionParams                   |       3427ms   0.9% |  52.4% ||        284ms   0.1% |  71.8% | node_modules/acorn/dist/acorn.js~1291-1295:58428-58614 
 pp$2.checkLVal                             |        573ms   0.2% |  10.6% ||        283ms   0.1% |  21.6% | node_modules/acorn/dist/acorn.js~1802-1860:76722-78698 
 updateContext                              |        280ms   0.1% |   6.8% ||        280ms   0.1% |   6.8% | node_modules/acorn/dist/acorn.js~3107-3115:127894-128192 
 Node                                       |        266ms   0.1% |   0.0% ||        266ms   0.1% |   0.0% | node_modules/acorn/dist/acorn.js~2929-2939:122008-122358 
 pp$1.parseForStatement                     |      11571ms   3.1% |  42.8% ||        254ms   0.1% |  65.0% | node_modules/acorn/dist/acorn.js~936-979:45059-47012 
 pp$5.declareName                           |        273ms   0.1% |   0.0% ||        248ms   0.1% |   0.0% | node_modules/acorn/dist/acorn.js~2867-2900:119530-121091 
 pp$7.braceIsBlock                          |        245ms   0.1% |   1.2% ||        237ms   0.1% |   1.3% | node_modules/acorn/dist/acorn.js~3004-3023:124199-125175 
 pp$9.readToken_pipe_amp                    |        399ms   0.1% |   8.8% ||        237ms   0.1% |  14.8% | node_modules/acorn/dist/acorn.js~4431-4436:172412-172735 
 pp$1.parseFor                              |       8705ms   2.3% |  50.3% ||        221ms   0.1% |  61.1% | node_modules/acorn/dist/acorn.js~1172-1183:53875-54301 
 pp$3.parseParenExpression                  |       5631ms   1.5% |  61.5% ||        221ms   0.1% |  81.4% | node_modules/acorn/dist/acorn.js~2292-2297:97079-97209 
 updateContext                              |        442ms   0.1% |   0.2% ||        209ms   0.1% |   0.5% | node_modules/acorn/dist/acorn.js~3058-3061:126146-126284 
 pp$9.curContext                            |        207ms   0.1% |  29.0% ||        207ms   0.1% |  29.0% | node_modules/acorn/dist/acorn.js~4263-4265:166879-166943 
 base.Pattern                               |       1340ms   0.4% |   0.3% ||        203ms   0.1% |   2.0% | node_modules/acorn-walk/dist/walk.js~299-306:10719-10943 
 isIdentifierChar                           |        198ms   0.1% |   2.5% ||        198ms   0.1% |   2.5% | node_modules/acorn/dist/acorn.js~83-93:12020-12540 
 ignore                                     |        191ms   0.1% |  30.4% ||        191ms   0.1% |  30.4% | node_modules/acorn-walk/dist/walk.js~187:6954-6987 
 base.ConditionalExpression                 |       2845ms   0.8% |  21.8% ||        190ms   0.1% |  76.3% | node_modules/acorn-walk/dist/walk.js~383-387:13296-13442 
 base.ArrayExpression                       |       3508ms   0.9% |  22.7% ||        189ms   0.1% |  74.1% | node_modules/acorn-walk/dist/walk.js~332-338:11815-11988 
 pp.canInsertSemicolon                      |        187ms   0.1% |   7.5% ||        187ms   0.1% |   7.5% | node_modules/acorn/dist/acorn.js~648-652:33588-33745 
 pp$3.buildBinary                           |        361ms   0.1% |   3.6% ||        178ms   0.0% |   7.3% | node_modules/acorn/dist/acorn.js~2037-2043:86348-86615 
 pp$6.startNode                             |        384ms   0.1% |   8.3% ||        175ms   0.0% |  18.3% | node_modules/acorn/dist/acorn.js~2945-2947:122464-122532 
 pp$1.adaptDirectivePrologue                |        278ms   0.1% |   7.9% ||        168ms   0.0% |  13.1% | node_modules/acorn/dist/acorn.js~1602-1606:69820-70020 
 get                                        |        421ms   0.1% |   0.0% ||        166ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~557:30560-30634 
 eat                                        |        601ms   0.2% |   1.2% ||        164ms   0.0% |   4.3% | node_modules/acorn/dist/acorn.js~3239-3245:136236-136354 
 pp$9.readRegexp                            |       1474ms   0.4% |  14.9% ||        163ms   0.0% |  26.4% | node_modules/acorn/dist/acorn.js~4569-4605:177684-179096 
 updateContext                              |        158ms   0.0% |  18.4% ||        158ms   0.0% |  18.4% | node_modules/acorn/dist/acorn.js~3046-3056:125825-126111 
 pp$1.parseTopLevel                         |     349700ms  93.9% |  49.7% ||        154ms   0.0% |  24.7% | node_modules/acorn/dist/acorn.js~742-760:36991-37633 
 base.Function                              |      16760ms   4.5% |   0.0% ||        153ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~288-297:10417-10698 
 updateContext                              |        145ms   0.0% |  15.9% ||        145ms   0.0% |  15.9% | node_modules/acorn/dist/acorn.js~3068-3072:126443-126703 
 base.FunctionDeclaration                   |      21444ms   5.8% |  18.2% ||        145ms   0.0% |  80.0% | node_modules/acorn-walk/dist/walk.js~274:10004-10061 
 pp$1.parseSwitchStatement                  |       4983ms   1.3% |  52.6% ||        140ms   0.0% |  50.7% | node_modules/acorn/dist/acorn.js~1009-1047:48208-49517 
 pp$3.checkPropClash                        |        130ms   0.0% |   5.4% ||        130ms   0.0% |   5.4% | node_modules/acorn/dist/acorn.js~1871-1914:79085-80547 
 base.ChainExpression                       |      20068ms   5.4% |  10.2% ||        127ms   0.0% |  71.7% | node_modules/acorn-walk/dist/walk.js~204:7384-7454 
 base.AwaitExpression                       |       8596ms   2.3% |  21.5% ||        124ms   0.0% |  76.6% | node_modules/acorn-walk/dist/walk.js~239-241:8655-8745 
 pp$1.parseIfStatement                      |      16999ms   4.6% |  59.0% ||        121ms   0.0% |  69.4% | node_modules/acorn/dist/acorn.js~986-993:47265-47598 
 pp$3.isSimpleParamList                     |        117ms   0.0% |   8.5% ||        117ms   0.0% |   8.5% | node_modules/acorn/dist/acorn.js~2683-2691:113019-113214 
 base.VariableDeclarator                    |       9698ms   2.6% |   0.0% ||        117ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~283-286:10282-10395 
 pp$3.parseNew                              |       4988ms   1.3% |  60.9% ||        117ms   0.0% |  35.0% | node_modules/acorn/dist/acorn.js~2377-2398:100362-101521 
 pp$5.enterScope                            |        123ms   0.0% |   0.0% ||        112ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2852-2854:119055-119119 
 pp$3.parsePropertyName                     |        528ms   0.1% |   0.8% ||        111ms   0.0% |   0.9% | node_modules/acorn/dist/acorn.js~2571-2583:108715-109165 
 pp$1.parseFunctionStatement                |     103611ms  27.8% |  73.9% ||        110ms   0.0% |  75.5% | node_modules/acorn/dist/acorn.js~981-984:47048-47235 
 pp$1.isDirectiveCandidate                  |        110ms   0.0% |   0.0% ||        110ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~1607-1615:70053-70374 
 base.Property                              |       5147ms   1.4% |   0.0% ||        105ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~444-447:15441-15563 
 base.UpdateExpression                      |       1315ms   0.4% |  20.5% ||         97ms   0.0% |  80.4% | node_modules/acorn-walk/dist/walk.js~372-374:12886-12953 
 base.IfStatement                           |       3714ms   1.0% |  22.1% ||         92ms   0.0% |  69.6% | node_modules/acorn-walk/dist/walk.js~205-209:7478-7646 
 current                                    |        452ms   0.1% |   0.0% ||         88ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3227-3229:135905-135958 
 updateContext                              |         88ms   0.0% |  21.6% ||         88ms   0.0% |  21.6% | node_modules/acorn/dist/acorn.js~3078-3086:126858-127310 
 nextIndex                                  |         87ms   0.0% |   0.0% ||         87ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3213-3225:135532-135857 
 pp.insertSemicolon                         |        117ms   0.0% |  13.7% ||         86ms   0.0% |  18.6% | node_modules/acorn/dist/acorn.js~654-660:33772-33975 
 pp$6.startNodeAt                           |        137ms   0.0% |   7.3% ||         80ms   0.0% |  12.5% | node_modules/acorn/dist/acorn.js~2949-2951:122557-122616 
 get                                        |        250ms   0.1% |   2.0% ||         62ms   0.0% |   8.1% | node_modules/acorn/dist/acorn.js~558:30672-30742 
 pp$8.regexp_eatTerm                        |       1152ms   0.3% |   0.1% ||         58ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3351-3371:139766-140424 
 pp.checkExpressionErrors                   |         57ms   0.0% | 100.0% ||         57ms   0.0% | 100.0% | node_modules/acorn/dist/acorn.js~709-718:35545-36091 
 wrapSafe                                   |         54ms   0.0% |   0.0% ||         54ms   0.0% |   0.0% | internal/modules/cjs/loader.js~1038-1086:32549-33665 
 base.SwitchStatement                       |       1002ms   0.3% |  21.3% ||         54ms   0.0% |  63.0% | node_modules/acorn-walk/dist/walk.js~216-229:7949-8334 
 pp$8.regexp_eatAssertion                   |        243ms   0.1% |   0.0% ||         54ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3374-3409:140533-141449 
 base.ForStatement                          |       2402ms   0.6% |  22.7% ||         53ms   0.0% |  75.5% | node_modules/acorn-walk/dist/walk.js~257-262:9378-9606 
 pp$5.exitScope                             |         53ms   0.0% |   3.8% ||         53ms   0.0% |   3.8% | node_modules/acorn/dist/acorn.js~2856-2858:119142-119184 
 pp$1.parseThrowStatement                   |        578ms   0.2% |  34.6% ||         53ms   0.0% |  64.2% | node_modules/acorn/dist/acorn.js~1049-1056:49550-49844 
 pp$1.parseBreakContinueStatement           |        157ms   0.0% |  31.2% ||         52ms   0.0% |  36.5% | node_modules/acorn/dist/acorn.js~884-906:43201-44047 
 pp$2.parseMaybeDefault                     |        447ms   0.1% |   0.0% ||         50ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~1786-1793:76001-76332 
 pp$8.regexp_eatExtendedAtom                |        992ms   0.3% |   6.8% ||         50ms   0.0% |  22.0% | node_modules/acorn/dist/acorn.js~3509-3519:144531-144907 
 pp.semicolon                               |        459ms   0.1% |   0.0% ||         49ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~665-667:34123-34219 
 slice                                      |         49ms   0.0% |   0.0% ||         49ms   0.0% |   0.0% | buffer.js~610:17138-17183 
 pp$2.toAssignable                          |         52ms   0.0% |   5.8% ||         48ms   0.0% |   6.3% | node_modules/acorn/dist/acorn.js~1622-1697:70511-73320 
 pp$1.parseTryStatement                     |       1138ms   0.3% |  34.1% ||         47ms   0.0% |  76.6% | node_modules/acorn/dist/acorn.js~1062-1088:49964-50985 
 pp$1.isLet                                 |         46ms   0.0% |   6.5% ||         46ms   0.0% |   6.5% | node_modules/acorn/dist/acorn.js~764-784:37719-38685 
 pp$9.readToken_plus_min                    |         79ms   0.0% |  31.6% ||         45ms   0.0% |  55.6% | node_modules/acorn/dist/acorn.js~4444-4458:172979-173559 
 pp$9.readToken_lt_gt                       |         92ms   0.0% |  22.8% ||         45ms   0.0% |  46.7% | node_modules/acorn/dist/acorn.js~4460-4477:173588-174365 
 pp$3.initFunction                          |         42ms   0.0% |   0.0% ||         42ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2587-2591:109229-109416 
 pp$8.regexp_eatClassAtom                   |        256ms   0.1% |   0.4% ||         41ms   0.0% |   2.4% | node_modules/acorn/dist/acorn.js~4030-4056:160391-161004 
 :=>                                        |         40ms   0.0% |   0.0% ||         40ms   0.0% |   0.0% | internal/util/inspect.js~134:2592-2627 
 isIdentifierStart                          |         39ms   0.0% |  97.4% ||         39ms   0.0% |  97.4% | node_modules/acorn/dist/acorn.js~71-79:11543-11952 
 pp$8.regexp_alternative                    |       1235ms   0.3% |   6.0% ||         39ms   0.0% |  38.5% | node_modules/acorn/dist/acorn.js~3345-3348:139563-139667 
 pp$1.parseVarId                            |        648ms   0.2% |   1.4% ||         37ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~1242-1245:56274-56416 
 pp$1.parseForIn                            |        817ms   0.2% |  49.7% ||         36ms   0.0% |  75.0% | node_modules/acorn/dist/acorn.js~1188-1217:54425-55373 
 pp$8.regexp_classRanges                    |        314ms   0.1% |   4.1% ||         33ms   0.0% |  33.3% | node_modules/acorn/dist/acorn.js~4013-4026:159730-160214 
 pp$9.readToken_slash                       |       1522ms   0.4% |   7.8% ||         32ms   0.0% |  37.5% | node_modules/acorn/dist/acorn.js~4408-4413:171607-171852 
 :anonymous                                 |         40ms   0.0% |   0.0% ||         32ms   0.0% |   0.0% | buffer.js~1-1228:0-35700 
 :anonymous                                 |         68ms   0.0% |   0.0% ||         31ms   0.0% |   0.0% | internal/errors.js~1-1443:0-52226 
 pp$3.parseMethod                           |       7346ms   2.0% |  86.3% ||         31ms   0.0% |  45.2% | node_modules/acorn/dist/acorn.js~2595-2618:109477-110418 
 E                                          |         37ms   0.0% |   0.0% ||         29ms   0.0% |   0.0% | internal/errors.js~325-341:8887-9394 
 pp$8.regexp_disjunction                    |       1275ms   0.3% |   4.7% ||         28ms   0.0% |  35.7% | node_modules/acorn/dist/acorn.js~3329-3342:139101-139460 
 get                                        |         37ms   0.0% |   0.0% ||         27ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~556:30445-30518 
 pp$5.treatFunctionsAsVarInScope            |         26ms   0.0% |   0.0% ||         26ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2863-2865:119396-119505 
 advance                                    |        113ms   0.0% |   0.9% ||         26ms   0.0% |   3.8% | node_modules/acorn/dist/acorn.js~3235-3237:136127-136192 
 DestructuringErrors                        |         25ms   0.0% |   0.0% ||         25ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~692-699:34845-35025 
 isNewLine                                  |         24ms   0.0% |  54.2% ||         24ms   0.0% |  54.2% | node_modules/acorn/dist/acorn.js~252-254:18545-18689 
 pp$8.regexp_eatQuantifierPrefix            |        168ms   0.0% |   0.0% ||         24ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3423-3430:141877-142078 
 wordsRegexp                                |         24ms   0.0% |   0.0% ||         24ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~274-276:19172-19268 
 :anonymous                                 |         82ms   0.0% |   0.0% ||         23ms   0.0% |   0.0% | events.js~1-758:0-21426 
 pp$9.readEscapedChar                       |         28ms   0.0% |   0.0% ||         21ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4814-4857:186361-188020 
 pp.isContextual                            |         20ms   0.0% | 100.0% ||         20ms   0.0% | 100.0% | node_modules/acorn/dist/acorn.js~628-630:33043-33142 
 pp$8.regexp_eatReverseSolidusAtomEscape    |        122ms   0.0% |   0.0% ||         20ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3467-3476:143334-143538 
 pp$1.parseExpressionStatement              |        164ms   0.0% |   3.7% ||         19ms   0.0% |  31.6% | node_modules/acorn/dist/acorn.js~1143-1147:52900-53031 
 :anonymous                                 |         34ms   0.0% |   0.0% ||         19ms   0.0% |   0.0% | internal/modules/esm/loader.js~1-283:0-9479 
 pp$9.readToken_mult_modulo_exp             |         41ms   0.0% |  17.1% ||         19ms   0.0% |  36.8% | node_modules/acorn/dist/acorn.js~4415-4429:171891-172380 
 :anonymous                                 |        114ms   0.0% |   0.0% ||         17ms   0.0% |   0.0% | internal/modules/cjs/loader.js~1-1295:0-40170 
 pp$8.regexp_eatBracedQuantifier            |         89ms   0.0% |   0.0% ||         17ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3431-3454:142117-142881 
 has                                        |         17ms   0.0% |   0.0% ||         17ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~266-268:18975-19053 
 :anonymous                                 |     372345ms  99.9% |   0.0% ||         16ms   0.0% |   0.0% | internal/main/run_main_module.js~1-17:0-631 
 pp$8.regexp_eatQuantifier                  |        193ms   0.1% |   0.0% ||         16ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3412-3420:141553-141761 
 pp$8.regexp_eatExtendedPatternCharacter    |         42ms   0.0% |   0.0% ||         16ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3562-3578:146236-146610 
 pp$8.regexp_eatClassEscape                 |        169ms   0.0% |   0.0% ||         15ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4059-4083:161117-161669 
 pp$8.regexp_eatCharacterEscape             |        152ms   0.0% |   2.0% ||         15ms   0.0% |  20.0% | node_modules/acorn/dist/acorn.js~3727-3737:151025-151419 
 pp$8.regexp_eatFixedHexDigits              |         50ms   0.0% |   0.0% ||         15ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4192-4205:165055-165406 
 :anonymous                                 |         51ms   0.0% |   0.0% ||         14ms   0.0% |   0.0% | internal/process/esm_loader.js~1-75:0-2392 
 pp$1.parseDoStatement                      |        321ms   0.1% |  13.7% ||         14ms   0.0% |  21.4% | node_modules/acorn/dist/acorn.js~914-926:44225-44597 
 :anonymous                                 |         17ms   0.0% |   0.0% ||         14ms   0.0% |   0.0% | fs.js~1-2043:0-54014 
 :anonymous                                 |         21ms   0.0% |   0.0% ||         14ms   0.0% |   0.0% | internal/url.js~1-1446:0-40638 
 pp.isSimpleAssignTarget                    |         14ms   0.0% |  14.3% ||         14ms   0.0% |  14.3% | node_modules/acorn/dist/acorn.js~727-731:36445-36647 
 loadNativeModule                           |         52ms   0.0% |   0.0% ||         14ms   0.0% |   0.0% | internal/modules/cjs/helpers.js~20-27:507-712 
 pp$8.regexp_eatRegExpUnicodeEscapeSequence |         67ms   0.0% |   0.0% ||         14ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3806-3842:153251-154361 
 :anonymous                                 |         44ms   0.0% |   0.0% ||         13ms   0.0% |   0.0% | internal/source_map/source_map_cache.js~1-256:0-8219 
 :anonymous                                 |         59ms   0.0% |   0.0% ||         13ms   0.0% |   0.0% | internal/util/inspect.js~1-2034:0-67693 
 pp$8.regexp_eatCharacterClass              |        322ms   0.1% |   0.0% ||         12ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3997-4008:159116-159463 
 normalizeString                            |         14ms   0.0% |   0.0% ||         12ms   0.0% |   0.0% | path.js~52-113:1910-3713 
 getOptions                                 |         12ms   0.0% |   0.0% ||         12ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~405-425:24921-25548 
 timeIt                                     |     371930ms  99.8% |   0.0% ||         12ms   0.0% |   0.0% | index.js~7-16:112-414 
 Scope                                      |         11ms   0.0% |   0.0% ||         11ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2840-2848:118553-118897 
 pp$8.regexp_eatCharacterClassEscape        |         29ms   0.0% |   0.0% ||         11ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3885-3912:155605-156205 
 pp$1.parseEmptyStatement                   |         56ms   0.0% |   0.0% ||         11ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~1114-1117:51758-51845 
 :anonymous                                 |         22ms   0.0% |   0.0% ||         11ms   0.0% |   0.0% | stream.js~1-49:0-2143 
 pp$8.validateRegExpFlags                   |         11ms   0.0% |   0.0% ||         11ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3259-3272:136744-137162 
 pp$1.isAsyncFunction                       |         11ms   0.0% |   0.0% ||         11ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~789-799:38849-39298 
 functionFlags                              |         10ms   0.0% |   0.0% ||         10ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~455-457:26315-26450 
 pp$8.regexp_eatAtomEscape                  |         61ms   0.0% |   0.0% ||         10ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3679-3696:149603-150090 
 pp.afterTrailingComma                      |          9ms   0.0% |  44.4% ||          9ms   0.0% |  44.4% | node_modules/acorn/dist/acorn.js~669-677:34249-34505 
 resolveExports                             |         21ms   0.0% |   0.0% ||          9ms   0.0% |   0.0% | internal/modules/cjs/loader.js~498-512:14730-15168 
 :anonymous                                 |         14ms   0.0% |   0.0% ||          9ms   0.0% |   0.0% | internal/modules/cjs/helpers.js~1-211:0-5219 
 :anonymous                                 |          9ms   0.0% |   0.0% ||          9ms   0.0% |   0.0% | internal/modules/esm/module_job.js~1-114:0-3569 
 pp$6.finishNodeAt                          |         10ms   0.0% |   0.0% ||          9ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2971-2973:123106-123198 
 get                                        |         21ms   0.0% |   0.0% ||          9ms   0.0% |   0.0% | internal/console/constructor.js~170-173:5009-5091 
 base.ForOfStatement                        |        270ms   0.1% |  21.9% ||          8ms   0.0% |  62.5% | node_modules/acorn-walk/dist/walk.js~263-267:9655-9787 
 :anonymous                                 |         38ms   0.0% |   0.0% ||          8ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~5-4992:258-192396 
 get                                        |         12ms   0.0% |   0.0% ||          7ms   0.0% |   0.0% | fs.js~2037-2041:53881-54005 
 pp$8.regexp_eatDecimalDigits               |         20ms   0.0% |   0.0% ||          7ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4112-4121:162514-162790 
 makeNodeErrorWithCode                      |          7ms   0.0% |   0.0% ||          7ms   0.0% |   0.0% | internal/errors.js~251-278:6865-7619 
 pp$8.regexp_pattern                        |       1106ms   0.3% |   0.0% ||          7ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3295-3326:138047-138998 
 readSync                                   |          6ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | fs.js~532-566:13406-14240 
 pp$8.regexp_eatZero                        |         17ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3748-3755:151690-151886 
 get                                        |         11ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~561:31029-31103 
 :anonymous                                 |         11ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | internal/console/global.js~1-51:0-1797 
 pp$8.regexp_eatHexEscapeSequence           |         28ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4097-4109:162119-162404 
 pp$3.isAsyncProp                           |          6ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2445-2449:102950-103339 
 :anonymous                                 |          9ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | timers.js~1-321:0-8168 
 pp$8.regexp_eatCapturingGroup              |        468ms   0.1% |   0.0% ||          6ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3491-3506:143970-144416 
 :anonymous                                 |          7ms   0.0% |   0.0% ||          6ms   0.0% |   0.0% | _stream_readable.js~1-1239:0-37408 
 :anonymous                                 |          8ms   0.0% |   0.0% ||          5ms   0.0% |   0.0% | net.js~1-1762:0-47151 
 base.TryStatement                          |        313ms   0.1% |  21.1% ||          5ms   0.0% |  80.0% | node_modules/acorn-walk/dist/walk.js~244-248:8890-9064 
 pp$5.currentScope                          |          5ms   0.0% |   0.0% ||          5ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2910-2912:121403-121473 
 pp.checkYieldAwaitInDefaultParams          |          5ms   0.0% |   0.0% ||          5ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~720-725:36133-36413 
 pp$8.regexp_eatDecimalEscape               |         10ms   0.0% |   0.0% ||          5ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3871-3882:155121-155481 
 reset                                      |          5ms   0.0% |   0.0% ||          5ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3184-3191:134409-134717 
 :anonymous                                 |          5ms   0.0% |   0.0% ||          5ms   0.0% |   0.0% | internal/buffer.js~1-1013:0-28411 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | internal/util.js~1-439:0-12300 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | internal/process/task_queues.js~1-187:0-4827 
 pp$8.validateRegExpPattern                 |       1110ms   0.3% |   0.0% ||          4ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3280-3292:137364-137952 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | internal/console/constructor.js~1-579:0-17448 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | internal/util/types.js~1-81:0-1892 
 TokenType                                  |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~118-131:13558-13978 
 pp$1.parseLabeledStatement                 |       1040ms   0.3% |  22.0% ||          4ms   0.0% |  25.0% | node_modules/acorn/dist/acorn.js~1119-1141:51880-52862 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | internal/querystring.js~1-100:0-2799 
 pp$8.regexp_eatBackReference               |         14ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3697-3714:150126-150612 
 resolve                                    |         18ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | path.js~973-1002:30123-31018 
 isHexDigit                                 |          4ms   0.0% |   0.0% ||          4ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4137-4143:163250-163450 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/encoding.js~1-570:0-15912 
 isCharacterClassEscape                     |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3913-3922:156210-156440 
 URL                                        |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/url.js~324-389:9952-11689 
 pp$3.parseParenItem                        |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~2361-2363:99822-99857 
 Module._findPath                           |         32ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/modules/cjs/loader.js~607-693:18734-21485 
 :anonymous                                 |          5ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/fs/promises.js~1-551:0-15126 
 kw                                         |          4ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~143-148:14269-14432 
 :anonymous                                 |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/idna.js~1-9:0-263 
 debuglogImpl                               |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/util/debuglog.js~36-53:1032-1614 
 :anonymous                                 |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/vm/module.js~1-453:0-12353 
 :anonymous                                 |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/console/constructor.js~278-295:8766-9195 
 base.SpreadElement                         |        103ms   0.0% |  18.4% ||          3ms   0.0% | 100.0% | node_modules/acorn-walk/dist/walk.js~243:8797-8865 
 FastBuffer                                 |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/buffer.js~945:25929-25966 
 getOptionValue                             |          3ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/options.js~8-14:147-285 
 resolveExportsTarget                       |          7ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | internal/modules/cjs/loader.js~526-604:15422-18667 
 lazyLoadStreams                            |         26ms   0.0% |   0.0% ||          3ms   0.0% |   0.0% | fs.js~1879-1884:51191-51384 
 :anonymous                                 |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/modules/esm/translators.js~1-216:0-7302 
 :anonymous                                 |         40ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~1-5:1-249 
 Module._resolveLookupPaths                 |          4ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/modules/cjs/loader.js~777-814:24288-25425 
 pp$9.readCodePoint                         |          5ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4675-4688:182176-182625 
 isPosixPathSeparator                       |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | path.js~42-44:1598-1674 
 hidden                                     |          7ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/errors.js~282-296:7732-8099 
 handleWriteReq                             |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/stream_base_commons.js~45-78:1106-1960 
 pp$8.regexp_eatControlEscape               |          9ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3758-3786:151996-152663 
 pp$8.regexp_eatLegacyOctalEscapeSequence   |          4ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4156-4172:163892-164371 
 getPathFromURLPosix                        |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/url.js~1330-1346:36765-37268 
 :anonymous                                 |          3ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/timers.js~1-615:0-17589 
 :anonymous                                 |         26ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/console/constructor.js~297-300:9237-9352 
 afterWriteDispatched                       |          3ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/stream_base_commons.js~149-161:3530-3838 
 :anonymous                                 |          5ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | url.js~1-982:0-29914 
 validChunk                                 |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | _stream_writable.js~275-289:9397-9770 
 emitHookFactory                            |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/async_hooks.js~194-202:7874-8133 
 codePointToString$1                        |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4690-4695:182631-182853 
 Parser                                     |         20ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~468-546:26894-29979 
 base.ForInit                               |        346ms   0.1% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~268-271:9807-9936 
 :anonymous                                 |         11ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/modules/esm/module_map.js~1-31:0-852 
 hexToInt                                   |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4144-4152:163454-163701 
 pp$8.regexp_eatOctalDigit                  |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4175-4184:164475-164691 
 isArrayIndex                               |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/modules/cjs/loader.js~514-524:15171-15419 
 defineColorAlias                           |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/util/inspect.js~356-367:9873-10114 
 pp$8.regexp_eatInvalidBracedQuantifier     |         26ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3522-3527:145044-145183 
 pp$8.regexp_eatCControlLetter              |          7ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3738-3747:151456-151663 
 :anonymous                                 |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/fs/dir.js~1-236:0-5553 
 defineIDLClass                             |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/url.js~861-887:23981-24668 
 :=>                                        |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/fs/utils.js~244-264:5470-6022 
 Module._load                               |     372192ms  99.9% |   0.0% ||          2ms   0.0% |   0.0% | internal/modules/cjs/loader.js~823-899:25839-28213 
 isUint32                                   |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/validators.js~30-32:531-592 
 pp$8.regexp_eatUncapturingGroup            |        173ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3477-3490:143577-143933 
 _addListener                               |          3ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | events.js~343-403:9920-11974 
 :anonymous                                 |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | internal/options.js~1-35:0-840 
 base.CatchClause                           |         78ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~249-252:9088-9204 
 updateContext                              |          2ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3074-3076:126738-126791 
 realpathSync                               |          8ms   0.0% |   0.0% ||          2ms   0.0% |   0.0% | fs.js~1534-1666:41439-45374 
 :anonymous                                 |     372186ms  99.9% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~1147-1159:35739-36269 
 Socket._writeGeneric                       |          6ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | net.js~760-789:19733-20493 
 pp$8.regexp_groupSpecifier                 |          4ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3583-3594:146711-147065 
 :anonymous                                 |         23ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/fs/streams.js~1-497:0-13094 
 Module._nodeModulePaths                    |          2ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~742-774:23213-24253 
 Module.load                                |     372188ms  99.9% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~974-1013:30522-31951 
 getOptions                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/fs/utils.js~206-223:4150-4689 
 removeListener                             |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | events.js~451-502:13334-14725 
 shouldUseESMLoader                         |          2ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/run_main.js~23-38:660-1222 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/process/signal.js~1-53:0-1123 
 Duplex                                     |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | _stream_duplex.js~51-71:1883-2337 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/priority_queue.js~1-128:0-2923 
 Socket                                     |          4ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | net.js~264-386:6725-10640 
 fromString                                 |          2ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | buffer.js~445-460:12966-13418 
 :=>                                        |          2ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/fs/utils.js~547-551:14814-14948 
 Module._compile                            |     372175ms  99.9% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~1092-1144:33866-35679 
 writeOrBuffer                              |          8ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | _stream_writable.js~355-391:11458-12414 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/streams/buffer_list.js~1-176:0-3783 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/esm/get_source.js~1-35:0-976 
 :anonymous                                 |          4ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/util/debuglog.js~61-69:1882-2120 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | vm.js~1-423:0-12874 
 :=>                                        |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | buffer.js~360-367:10630-10850 
 EventEmitter.init                          |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | events.js~130-152:3647-4376 
 :=>                                        |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/errors.js~336-338:9290-9366 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/console/constructor.js~188-214:5391-6356 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/esm/resolve.js~1-786:0-24713 
 base.LabeledStatement                      |        359ms   0.1% |  19.8% ||          1ms   0.0% | 100.0% | node_modules/acorn-walk/dist/walk.js~210:7675-7738 
 protoGetter                                |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | net.js~707-713:18537-18696 
 addSignalHandler                           |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/process/report.js~99-106:2531-2701 
 isInt32                                    |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/validators.js~26-28:470-528 
 tryStatSync                                |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | fs.js~320-328:8115-8344 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | _stream_duplex.js~1-143:0-3883 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/process/warning.js~1-141:0-3952 
 toString                                   |         50ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | buffer.js~778-808:22971-23549 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/process/execution.js~1-219:0-6906 
 setHasTickScheduled                        |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/process/task_queues.js~53-55:1100-1185 
 Socket._write                              |          7ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | net.js~797-799:20623-20703 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/fs/utils.js~1-625:0-16985 
 nextPart                                   |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | fs.js~1530:41344-41396 
 isConditionalDotExportSugar                |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~417-439:11839-12657 
 write                                      |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | buffer.js~609:17061-17124 
 isURLInstance                              |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/url.js~1398-1401:39344-39496 
 isSignal                                   |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/process/signal.js~16-18:205-300 
 Module._initPaths                          |          6ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~1233-1260:38255-39162 
 emitBeforeScript                           |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/async_hooks.js~354-359:12253-12428 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/net.js~1-70:0-1806 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/validators.js~1-208:0-5939 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | path.js~1-1375:0-41802 
 RegExpValidationState                      |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3165-3182:133706-134363 
 :anonymous                                 |         13ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/console/constructor.js~237-274:7366-8640 
 pp$9.readHexChar                           |          4ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4861-4866:188111-188296 
 isDecimalDigit                             |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~4122-4124:162795-162879 
 readPackage                                |          6ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~245-277:6869-7712 
 log                                        |         40ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/console/constructor.js~308-310:9540-9626 
 pathToFileURL                              |          5ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/url.js~1374-1396:38377-39341 
 makeTextDecoderJS                          |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/encoding.js~431-514:11896-14436 
 base.DoWhileStatement                      |        103ms   0.0% |  12.6% ||          1ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~253-256:9255-9353 
 dirname                                    |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | path.js~1127-1151:34453-35080 
 pp$8.regexp_eatIdentityEscape              |          5ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3848-3868:154553-155011 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | _stream_passthrough.js~1-47:0-1752 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/stream_base_commons.js~1-280:0-6820 
 readPackageScope                           |          5ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/cjs/loader.js~279-295:7715-8187 
 get                                        |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/url.js~612-619:17433-17627 
 :=>                                        |     371899ms  99.8% |   0.0% ||          1ms   0.0% |   0.0% | index.js~35-43:921-1135 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/streams/pipeline.js~1-94:0-2268 
 isFileType                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | fs.js~174-178:4445-4638 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/graal/buffer.js~1-55:0-2610 
 popAsyncContext                            |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/async_hooks.js~408-423:13859-14469 
 :anonymous                                 |          3ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/async_hooks.js~1-475:0-15623 
 set                                        |          3ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/modules/esm/module_map.js~17-25:470-745 
 deprecate                                  |          1ms   0.0% |   0.0% ||          1ms   0.0% |   0.0% | internal/util.js~65-102:1581-2677 
 from                                       |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | buffer.js~307-339:8854-9817 
 :=>                                        |      22147ms   5.9% |   0.0% ||          0ms   0.0% |   0.0% | index.js~40-42:1062-1127 
 emit                                       |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | events.js~263-341:7571-9916 
 Module._resolveFilename                    |         32ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~901-970:28243-30430 
 allocate                                   |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | buffer.js~411-424:12084-12415 
 writeGeneric                               |          5ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/stream_base_commons.js~141-147:3321-3527 
 trySelf                                    |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~396-415:11227-11836 
 format                                     |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/url.js~396-433:11857-13047 
 Module                                     |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~156-165:4993-5229 
 onwrite                                    |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | _stream_writable.js~431-473:13510-14789 
 Readable.on                                |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | _stream_readable.js~871-898:27715-28620 
 tryPackage                                 |          3ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~307-342:8436-9734 
 resolveMainPath                            |          8ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/run_main.js~8-21:220-657 
 toRealPath                                 |          8ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~362-366:10288-10418 
 nextTick                                   |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/process/task_queues.js~105-137:2598-3512 
 parse                                      |     349710ms  93.9% |   0.0% ||          0ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~550-554:30266-30403 
 readPackageExports                         |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~302-305:8310-8433 
 deduplicateTypes                           |      22147ms   5.9% |   0.0% ||          0ms   0.0% |   0.0% | index.js~18-32:417-786 
 toString                                   |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/url.js~445-447:13322-13380 
 :=>                                        |     349730ms  93.9% |   0.0% ||          0ms   0.0% |   0.0% | index.js~37-39:973-1029 
 fileURLToPath                              |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/url.js~1348-1356:37271-37617 
 createPool                                 |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | buffer.js~159-164:4150-4351 
 tryFile                                    |          3ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~353-360:10076-10285 
 applyExports                               |         11ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~441-492:12660-14568 
 tryCreateBuffer                            |          4ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | fs.js~330-343:8347-8655 
 fullAncestor                               |      22147ms   5.9% |   0.0% ||          0ms   0.0% |   0.0% | node_modules/acorn-walk/dist/walk.js~85-96:3376-3861 
 createHandle                               |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | net.js~128-144:3466-3846 
 allocUnsafe                                |          4ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | buffer.js~386-389:11378-11452 
 doWrite                                    |          7ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | _stream_writable.js~393-405:12417-12794 
 :=>                                        |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/validators.js~84-98:2158-2738 
 tryReadSync                                |          6ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | fs.js~345-355:8658-8912 
 :anonymous                                 |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | _stream_writable.js~1-746:0-21376 
 get ReadStream                             |         26ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | fs.js~1982-1985:52782-52849 
 fromStringFast                             |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | buffer.js~426-443:12418-12963 
 Module.require                             |        200ms   0.1% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/loader.js~1018-1030:32070-32368 
 readFileSync                               |         66ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | fs.js~357-406:8915-10297 
 addListener                                |          3ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | events.js~405-407:12014-12105 
 startListeningIfSignal                     |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/process/signal.js~21-40:365-852 
 buildUnicodeData                           |         23ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~3145-3158:133024-133570 
 :anonymous                                 |         40ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~1-4992:0-192401 
 createUnsafeBuffer                         |          3ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | buffer.js~150-157:4012-4147 
 emitAfterScript                            |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/async_hooks.js~362-367:12432-12551 
 parse                                      |     349730ms  93.9% |   0.0% ||          0ms   0.0% |   0.0% | node_modules/acorn/dist/acorn.js~575-577:31554-31634 
 Writable.write                             |         10ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | _stream_writable.js~291-322:9800-10559 
 :=>                                        |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/fs/utils.js~535-545:14499-14768 
 Readable.removeListener                    |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | _stream_readable.js~901-915:28716-29229 
 executeUserEntryPoint                      |     372202ms  99.9% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/run_main.js~64-73:2070-2404 
 EventEmitter                               |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | events.js~64-66:1823-1891 
 require                                    |        200ms   0.1% |   0.0% ||          0ms   0.0% |   0.0% | internal/modules/cjs/helpers.js~71-73:2221-2282 
 openSync                                   |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | fs.js~449-460:11213-11611 
 processTicksAndRejections                  |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/process/task_queues.js~69-101:1486-2453 
 once                                       |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | events.js~434-439:12864-12989 
 toPathIfFileURL                            |          1ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/url.js~1403-1407:39499-39643 
 :anonymous                                 |     372170ms  99.9% |   0.0% ||          0ms   0.0% |   0.0% | index.js~1-44:0-1140 
 :anonymous                                 |          2ms   0.0% |   0.0% ||          0ms   0.0% |   0.0% | internal/fs/rimraf.js~1-296:0-7029 
----------------------------------------------------------------------------------------------------------------------------------

Process finished with exit code 0

If just in case formatting is wrong, I attached as a separate txt file: profile.txt

ciplogic commented 3 years ago

@frank-dspeed this is an off-topic reason why to open this issue and in general about my view on Java/GraalVM/GraalJS.

Let's start with Java: I am a C# developer by trade and I am a good friend with Java from when I was doing High Frequency Trading in C# as Java was miles ahead (I am talking of years around 2010-2016), especially on the workloads where my company was doing at the time. I got to use so much Java in my side projects that when there was a scientific paper published by Intel Research where it shows Go as being faster than Java, I could spot even basic mistakes and I published into a journal a scientific paper showing how to properly use Java, and Java would win by around 1 order of magnitude in this workload. https://github.com/ciplogic/elprep-study/blob/master/paper/elprep-study.pdf

Given my respect I have with Java (earned respect BTW!), I see why a GraalVM like approach (meaning Java on Java) should be the way forward and I really hope that GraalVM will also include value types, because at least it would make some types of coding possible and it is tedious to recycle objects because there is no value type equivalent and you want to remove allocations, and I am sure that GraalVM will get there.

As I was following the GraalVM presentations, one recommendation from InfoQ site (I am not related with Oracle or InfoQ) was to test our workloads and if we find bugs, to report them. This is what I did.

So this workload is similar with my day to day working (I work on a company that does, among other things JavaScript obfuscation) and we do these operations (of parsing code and doing some replacements) using C++. Surprisingly, NodeJS runs faster than C++ in this workload (using Acorn parser), and the reasons are multiple (i.e. C++ allocator is typically slower than a GC, if you don't use a custom allocator, also we use a different parser, so we may have a less optimal algorithm at places), and I wanted to try GraalVM/JS as a curiosity, especially as it was advertised (rightly I would say) as a drop-in replacement for NodeJS.

The original sample was a large customer application that we typically use it as a stress test internally, but it is not the largest.

As described: if GraalVM would be 2.5X slower, will be on-par with our C++ implementation of the JS parser (maybe a bit slower, but not by much), which as a mater of future option, a company like mine could use GraalVM. Though, as I am not into business decisions, I cannot say if this will happen, but I can definitely say that if the runtime is 20X (or 70X if not using --jvm) slower, GraalVM at least with this type of workloads will not happen.

So all is described with this bug is simply a mostly stress test which is more or less like a close-to-large use-cases that some company that parses JavaScript has as a target. And it tried to be a realistic test-case (as it is)

frank-dspeed commented 3 years ago

@ciplogic I love your use case do not get me wrong I am also not affiliated with Oracle but I have the same use case as you I am parsing a lot of code as I am coding a KI Driven Compiler.

And my Point of view is that if we would for example Replace some Methods that Acorn uses with java methods this will blow away any nodejs implementation.

self see it not as a drop-in replacement I see it more as a Migration Tool to Port the Code Partial Incremental to Java.

I am a big fan of Javascript as glue code I do that also on NODEJS whenever I have something expensive to process I go for Rust and neon bindings to create .node modules to process that and use them as it would be Javascript.

Hope that information helps you to optimize your processes.

wirthi commented 3 years ago

@ciplogic

I have tried again your latest example (https://github.com/graalvm/graaljs/issues/360#issuecomment-707262800) on GraalVM 20.3 EE (to be release, but close to our current master or nightlies); I am using octane-mandree.js (5 MB js source) instead of your WebstormProjects/main.js file that I don't have access to.

My measurements are around 4.15 seconds for GraalVM EE--jvm compared to 1.65 seconds on Node.js (14 branch). That is a factor of ~2.5x. Of course, it takes around 20 iterations on my setup to reach that performance (compared to ~4 on Node.js)

For me, --engine.Mode=throughput gives me significantly better PEAK results. WARMUP is much faster with --engine.Mode=latency (already the first iteration is below 12 seconds, and the 4th is close to the peak) but reaches a worse (slower) overall peak (around 6.5 seconds, or 4x compared to Node.js).

-- Christian

frank-dspeed commented 3 years ago

@wirthi why is there no transition possible between latency and throughput i mean can it not do additional optimization ? i am wondering what is blocking that?

can we some how store and preserve the optimization done ? some kind of cache? I know my question is maybe a bit wirred out of your view but i simply wonder what is the blocking part that stops the compiler from improving to the state that throughput gives us.

and maybe we can reach throughput state once and then directly resume from that stage.

wirthi commented 3 years ago

@frank-dspeed this is a huge tradeoff game. We have to trade off compilation speed, compilation memory consumption, peak performance, interpreter performance, compiled code size, how speculative the code is (how often we have to throw it away), memory consumption of the result, security concerns, privacy concerns, and many more into this.

That, while we only have heuristics about all those values (how to guess all those values for a guest language like JavaScript, that the compiler (GraalVM, Java) does not even understand)?

We are doing our best here, and 60 years of compiler research, 20+ years of Java compiler research go into this. Our current focal point is warmup performance.

frank-dspeed commented 3 years ago

we should also point out that this is maybe a doublicate or the same as https://github.com/graalvm/graaljs/issues/74#issuecomment-730429272

ciplogic commented 3 years ago

Sorry @wirthi, the file was under that comment:


main.zip

^ this is the main.zip file which was a react-native packed application.

ciplogic commented 3 years ago

And to re-iterate, in this "main.zip" which is a real application (based on a open source tutorial, just web-packed) would give if I understand right:

30.466 (let's say 30.5 seconds - this is the best time per iteration) vs 2 seconds (it is 1.8 ) but I consider error margins, CPU turbo, whatever). (30.5 seconds are against EE --jvm flags)

So we talk of not 2.5X slow-down, but a 15X slowdown. My client app slows down by around 20X, but it is still one world apart from 2.5X.

My assumption is that mandreel benchmarks are not deep on stack parsing code so the behavior is different around collections and the cost around quite recursive calls. I did not look into GraalJS, but I would assume that there is a cost related in "closure" copying, or something of this sort. Or maybe it is a structure that it stresses out wrongly your optimizer, this is just a guess.

To be clear, the application "main.zip" is a real-world application (though it is not as badly behaving than the client application I was working on), is is basically a "medium sized React-Native tutorial" that is bundled and I share the bundle.

Also, I separately logged, and it looks that on traversal of the tree GraalJS is under 2X slower (than NodeJS), just the parsing code is much more slower - which is more than 15X.

I will write it as a raw link here, in case the main.zip is missed:

https://github.com/graalvm/graaljs/files/5365495/main.zip
ciplogic commented 3 years ago

As a side note: not sure why, but our company works with a C++ implementation of a JS parser, and that code before being optimized was for that particular file (generating the same AST tree) around 7.5 seconds on release and some simple optimizations (around tokenization and some type specialization, i.e. "when strings are lenght 1, we pass a char type instead of the full string") did improve to around 6.3 seconds, so at least for C++ the code is somewhat memory sensitive.

I am saying that maybe there are some optimizations that based on type information, or just that "strings with 1 char are passed as 1 char" could probably speedup the code, or maybe how some collections are iterated (i.e. optimize for "indexOf" when the "array is of strings", to create an internal map, probably lazily), could speed up realistically the code and could improve other similar codebases.

wirthi commented 3 years ago

Hi,

I'll try to run the code on Monday and address it in more detail, but concerting this:

30.466 (let's say 30.5 seconds - this is the best time per iteration) vs 2 seconds (it is 1.8 ) but I consider error margins, CPU turbo, whatever). (30.5 seconds are against EE --jvm flags)

So we talk of not 2.5X slow-down, but a 15X slowdown. My client app slows down by around 20X, but it is still one world apart from 2.5X.

This clearly is warmup performance. As we are a Java-based just-in-time compiler, YES, our warmup performance IS worse than other engines that use other techniques. The 2.5x above is PEAK performance AFTER WARMUP. Our engine is by design optimized for peak performance of long-running server applications, not short-running command line apps. We are trying to improve that as well, this is currently our main focus, but currently that's not where we can shine at.

-- Christian

ciplogic commented 3 years ago

Thank you, but I am going to bet that it was not warmup:

Start Parse 0...
    Start parse JS...
    Done in (seconds): 52.946
    Start visit tree...
    Done in (seconds): 8.816
Done in (seconds): 61.794
Start Parse 1...
    Start parse JS...
    Done in (seconds): 59.015
    Start visit tree...
    Done in (seconds): 8.552
Done in (seconds): 67.57
Start Parse 2...
    Start parse JS...
    Done in (seconds): 37.724
    Start visit tree...
    Done in (seconds): 0.66
Done in (seconds): 38.385
Start Parse 3...
    Start parse JS...
    Done in (seconds): 32.355
    Start visit tree...
    Done in (seconds): 0.658
Done in (seconds): 33.015
Start Parse 4...
    Start parse JS...
    Done in (seconds): 31.201
    Start visit tree...
    Done in (seconds): 0.678
Done in (seconds): 31.88
Start Parse 5...
    Start parse JS...
    Done in (seconds): 30.628
    Start visit tree...
    Done in (seconds): 0.656
Done in (seconds): 31.286
...

It is clear by around iteration 4/5 the code is warmed up and the slow-down is somewhere else.

I am not sure that in Mandreel file you don't have the same behavior and it may be a slow-down specific to samples like React-Native bundled samples.

My work-place sample is a customer's app I cannot share (because I cannot share IP, even though this IP is somewhat public and extractable) which shows a bit worse slow-down (i.e. around 20X slow-down, not 15X) but I assume that the reason is the same, just exacerbated as the customer app has a deep AST tree to parse.

LifeIsStrange commented 3 years ago

Would be nice to benchmarck again with the 2021 release https://github.com/graalvm/graalvm-ce-builds/releases/tag/vm-21.0.0

woess commented 3 years ago

@frank-dspeed regarding your question:

why is there no transition possible between latency and throughput i mean can it not do additional optimization ? i am wondering what is blocking that?

GraalVM 20.1 will have tiered compilation enabled by default which should provide faster warmup at the same peak performance, bridging the gap between throughput and latency modes. So there should be no need for --engine.Mode=latency anymore. It's still far from perfect but we're working on tuning the compilation policy, and of course, improving JS performance in general.

woess commented 3 years ago

I had a look at why we are so slow here and it turns out we spend most of the time in a single string.slice! This is the culprit: https://github.com/acornjs/acorn/blob/6.4.2/acorn/src/parseutil.js#L15

var literal = /^(?:'((?:\\.|[^'\\])*?)'|"((?:\\.|[^"\\])*?)")/;
pp.strictDirective = function(start) {
  for (;;) {
    // Try to find string literal.
    skipWhiteSpace.lastIndex = start;
    start += skipWhiteSpace.exec(this.input)[0].length;
    var match = literal.exec(this.input.slice(start)); // <======== copies everything from start to input.length
    if (!match) { return false }
    if ((match[1] || match[2]) === "use strict") { return true }
    start += match[0].length;

    // Skip semicolon, if any.
    skipWhiteSpace.lastIndex = start;
    start += skipWhiteSpace.exec(this.input)[0].length;
    if (this.input[start] === ";")
      { start++; }
  }
};

Since it is called very often and our string.slice implementation always creates a copy of the substring, this can get very, very slow with large input files (like main.js which is >11MB). If we change this line to avoid excessive copying, Graal.js gets an order of magnitude faster. It's a known issue. Other JS engines use string views to avoid copying substrings, and some JS code relies on this to be fast. We have plans to enable this optimization in GraalVM as well in the future (currently blocked by other string-related work).

ciplogic commented 3 years ago

So, to understand correctly, if you have an open issue for it, I can close this one with referencing the original issue, if not, I think that this bug should be open up to the point the string view implementation is provided.

Though, this is a great find and it is great that you are both aware of the issue and of the solution @woess !

Thank you for the hard work :bouquet:

woess commented 3 years ago

I don't think there's an open issue for it, so you can keep this one open.

BTW, a simple solution would be to change the code to use sticky regex (instead of slice):

var literal = /(?:'((?:\\.|[^'\\])*?)'|"((?:\\.|[^"\\])*?)")/y;
pp.strictDirective = function(start) {
  for (;;) {
    // Try to find string literal.
    skipWhiteSpace.lastIndex = start;
    start += skipWhiteSpace.exec(this.input)[0].length;
    literal.lastIndex = start;
    var match = literal.exec(this.input);
    if (!match) { return false }
    if ((match[1] || match[2]) === "use strict") { return true }
    start += match[0].length;
    //...
ciplogic commented 3 years ago

This is a sensible thing to do, to be fair, but this is not my code. If you want, I can report an issue to recommend them to use Regex and reference this bug.

This AcornJS is in my understanding the most popular parser of JS in the wild (second one would be Esprima), so I am sure that this behavior, would affect other people parsing large JS files.

If you would like, I can create an issue also to Acorn's JS issue tracker, but if you will likely fix it in 1 year from now, I think it is worth not complaining, not for other reason, but that many people may not notice this limitation but on large files, and up to the point they will notice it, GraalVM/JS would fix it by itself.

Bug tracker just for reference: https://github.com/acornjs/acorn/issues

woess commented 3 years ago

I just wanted to mention it for the sake of completeness for anyone interested. I'm not sure they would accept my change, which relies on an ES6 feature, and it does not benefit most users. Acorn is likely not the only popular package using such code patterns, so we'll have to do something about it in GraalVM anyway.

frank-dspeed commented 3 years ago

@woess we use that patterns in ecmascript because it is as fast and even faster then regex while it is more readable and does not require learning regex. you could internal simply implement the string.slice method with regex as workaround.

djoooooe commented 2 years ago

GraalJS supports string views now, which should fix this issue. Benchmark results on my machine:


    Start parse JS...
    Done in (seconds): 8.75
    Start visit tree...
    Done in (seconds): 1.761
Done in (seconds): 10.582
Start Parse 1...
    Start parse JS...
    Done in (seconds): 13.161
    Start visit tree...
    Done in (seconds): 5.579
Done in (seconds): 18.741
Start Parse 2...
    Start parse JS...
    Done in (seconds): 8.275
    Start visit tree...
    Done in (seconds): 4.284
Done in (seconds): 12.56
Start Parse 3...
    Start parse JS...
    Done in (seconds): 3.178
    Start visit tree...
    Done in (seconds): 1.682
Done in (seconds): 4.862
Start Parse 4...
    Start parse JS...
    Done in (seconds): 2.193
    Start visit tree...
    Done in (seconds): 1.202
Done in (seconds): 3.397
Start Parse 5...
    Start parse JS...
    Done in (seconds): 1.699
    Start visit tree...
    Done in (seconds): 0.966
Done in (seconds): 2.666
Start Parse 6...
    Start parse JS...
    Done in (seconds): 1.397
    Start visit tree...
    Done in (seconds): 0.892
Done in (seconds): 2.29
Start Parse 7...
    Start parse JS...
    Done in (seconds): 1.299
    Start visit tree...
    Done in (seconds): 0.828
Done in (seconds): 2.127
Start Parse 8...
    Start parse JS...
    Done in (seconds): 1.401
    Start visit tree...
    Done in (seconds): 0.833
Done in (seconds): 2.236
Start Parse 9...
    Start parse JS...
    Done in (seconds): 1.319
    Start visit tree...
    Done in (seconds): 0.782
Done in (seconds): 2.104
wirthi commented 2 years ago

That should already be fixed in GraalVM 22.1. The feature is on by default. Closing this ticket.

frank-dspeed commented 2 years ago

@wirthi your referencing to the fact that the latency Mode is default now? because this issue is now also about string views

wirthi commented 2 years ago

Yes, and the comment just above mine clarified that this is available now. I just mentioned which GraalVM this is in.

ciplogic commented 2 years ago

This is fantastic work! Thank you!

woess commented 2 years ago

the latency Mode is default now?

Not quite. The default mode is tiered compilation now, which tries to balance latency and throughput. In most cases, it should offer warmup close to latency mode without sacrificing peak performance. So we generally don't recommend it anymore, although it might still make sense for resource-constrained environments and certain workloads.