Immer: Drop of performances on node 9

Created on 4 Jan 2018  Β·  8Comments  Β·  Source: immerjs/immer

Hi,

I tried the performance benchmark on different versions of node and i experienced a weird drop of performances.

Here are my computer specifications:

CPU: 2,7 GHz Intel Core i5
RAM: 8 Go 1867 MHz DDR3

On 8.4.0:

  performance
    βœ“ just mutate (2ms)
    βœ“ deepclone, then mutate (475ms)
    βœ“ handcrafted reducer (23ms)
    βœ“ immutableJS (66ms)
    βœ“ immer - with autofreeze (371ms)
    βœ“ immer - without autofreeze (181ms)

On 9.3.0:

  performance
    βœ“ just mutate (5ms)
    βœ“ deepclone, then mutate (324ms)
    βœ“ handcrafted reducer (19ms)
    βœ“ immutableJS (69ms)
    βœ“ immer - with autofreeze (510ms)
    βœ“ immer - without autofreeze (1378ms)

I didn't found out the cause of this.

Most helpful comment

@frinyvonnick optimizations are in progress in the feature/optimization branch, my results are now as follows, completely removing the drop on node 9, and improving the general performance 4-6 times

8.4:

    βœ“ just mutate (3ms)
    βœ“ deepclone, then mutate (417ms)
    βœ“ handcrafted reducer (20ms)
    βœ“ immutableJS (71ms)
    βœ“ immer (proxy) - with autofreeze (118ms)
    βœ“ immer (proxy) - without autofreeze (39ms)
    βœ“ immer (es5) - with autofreeze (421ms)
    βœ“ immer (es5) - without autofreeze (401ms)

9.3:

    βœ“ just mutate (4ms)
    βœ“ deepclone, then mutate (252ms)
    βœ“ handcrafted reducer (17ms)
    βœ“ immutableJS (59ms)
    βœ“ immer (proxy) - with autofreeze (107ms)
    βœ“ immer (proxy) - without autofreeze (34ms)
    βœ“ immer (es5) - with autofreeze (380ms)
    βœ“ immer (es5) - without autofreeze (362ms)

All 8 comments

That is remarkable! Did you try it a few times? You could try to put the immer tests first, as I didn't figure out how to expose the garbage collector api with jest yet, so the performance tests are not really isolated; the garbage collector might kick in at the wrong moment.

Yes i tried multiples times. To see if garbage collector impact tests i forced it before each test and skip other tests so we only test immer and each test is "isolated".

test script:

"test": "node --expose-gc node_modules/.bin/jest",

before each:

beforeEach(() => {
  global.gc()
})

Here are the results:

On 8.4.0:

performance
  βœ“ immer - with autofreeze (466ms)
  βœ“ immer - without autofreeze (326ms)
  β—‹ skipped 4 tests

On 9.3.0:

performance
  βœ“ immer - with autofreeze (670ms)
  βœ“ immer - without autofreeze (748ms)
  β—‹ skipped 4 tests

So garbage collector and other tests had an impact on my first results but there is still a drop of performances.

Just improved the test setup to leverage the garbage collector.

@frinyvonnick could you check again if the differences are still as big?

Here are the results with your last update:

On 8.4.0:

  performance
    βœ“ just mutate (3ms)
    βœ“ deepclone, then mutate (422ms)
    βœ“ handcrafted reducer (19ms)
    βœ“ immutableJS (74ms)
    βœ“ immer (proxy) - with autofreeze (331ms)
    βœ“ immer (proxy) - without autofreeze (165ms)
    βœ“ immer (es5) - with autofreeze (445ms)
    βœ“ immer (es5) - without autofreeze (377ms)

On 9.3.0:

  performance
    βœ“ just mutate (5ms)
    βœ“ deepclone, then mutate (246ms)
    βœ“ handcrafted reducer (18ms)
    βœ“ immutableJS (55ms)
    βœ“ immer (proxy) - with autofreeze (509ms)
    βœ“ immer (proxy) - without autofreeze (1296ms)
    βœ“ immer (es5) - with autofreeze (392ms)
    βœ“ immer (es5) - without autofreeze (614ms)

The main problem seems to be related to proxies despite of the overall augmentation

Hi :wave:

I wrote a modified version at immutadot which runs each test in a loop and computes an average execution time.
This way garbage collector time should not mess too badly with execution time...

Node 8.9.4 :

lodash deep cloning, then mutation: ~457.67ms/op on 66ops
ES2015 destructuring: ~9.51ms/op on 1000ops
immutable (w/o conversion to plain JS objects): ~24.63ms/op on 1000ops
immutable (w/ conversion to plain JS objects): ~1041.59ms/op on 29ops
immer (proxy implementation w/o autofreeze): ~139.86ms/op on 215ops
immer (ES5 implementation w/o autofreeze): ~435.78ms/op on 69ops
immutad●t: ~43.82ms/op on 688ops

Node 9.2.0 :

lodash deep cloning, then mutation: ~7386.50ms/op on 10ops
ES2015 destructuring: ~9.25ms/op on 1000ops
immutable (w/o conversion to plain JS objects): ~22.95ms/op on 1000ops
immutable (w/ conversion to plain JS objects): ~978.23ms/op on 31ops
immer (proxy implementation w/o autofreeze): ~1693.50ms/op on 18ops
immer (ES5 implementation w/o autofreeze): ~424.45ms/op on 71ops
immutad●t: ~44.93ms/op on 670ops

Results are staying close except for lodash which nearly stops (might be the gc taking time to clean up clones), and immer with proxies which node 9 definitely messes up...

Maybe try V8 options listed with node --v8-options ? Tried --trace-gc but not sure how to read this...

Feel free to reuse it if you need.

@frinyvonnick optimizations are in progress in the feature/optimization branch, my results are now as follows, completely removing the drop on node 9, and improving the general performance 4-6 times

8.4:

    βœ“ just mutate (3ms)
    βœ“ deepclone, then mutate (417ms)
    βœ“ handcrafted reducer (20ms)
    βœ“ immutableJS (71ms)
    βœ“ immer (proxy) - with autofreeze (118ms)
    βœ“ immer (proxy) - without autofreeze (39ms)
    βœ“ immer (es5) - with autofreeze (421ms)
    βœ“ immer (es5) - without autofreeze (401ms)

9.3:

    βœ“ just mutate (4ms)
    βœ“ deepclone, then mutate (252ms)
    βœ“ handcrafted reducer (17ms)
    βœ“ immutableJS (59ms)
    βœ“ immer (proxy) - with autofreeze (107ms)
    βœ“ immer (proxy) - without autofreeze (34ms)
    βœ“ immer (es5) - with autofreeze (380ms)
    βœ“ immer (es5) - without autofreeze (362ms)

Nice job πŸ‘

Should be solved by 0.3.0

Was this page helpful?
0 / 5 - 0 ratings