Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Improve performance #69

Closed
wants to merge 9 commits into from
Closed

perf: Improve performance #69

wants to merge 9 commits into from

Conversation

Uzlopak
Copy link
Contributor

@Uzlopak Uzlopak commented Nov 30, 2022

I assume that a Set is more performant than a Map with checking the value.

Checklist

index.js Show resolved Hide resolved
index.js Show resolved Hide resolved
@Uzlopak
Copy link
Contributor Author

Uzlopak commented Nov 30, 2022

We could replace codes Object with a codes-Map and after warning we could actually delete the warning from the codes Map

delete warning after emitting
@Uzlopak Uzlopak changed the title Use Set instead of Map Use Set instead of Map for emitted and Map instead of Object for codes Nov 30, 2022
@Uzlopak
Copy link
Contributor Author

Uzlopak commented Nov 30, 2022

@jsumners

I resolved that remark. Open a new remark if you still disagree.

@Uzlopak
Copy link
Contributor Author

Uzlopak commented Nov 30, 2022

I added label semver-major because the emitted-property gets changed from a Map to Set, breaking the api contract.

@jsumners
Copy link
Member

@jsumners

I resolved that remark. Open a new remark if you still disagree.

Please don't mark other people's reviews resolved unless they indicate it is resolved.

@Uzlopak
Copy link
Contributor Author

Uzlopak commented Nov 30, 2022

Could you please describe what you have in mind? I dont expect that you will take over this PR. But you have to give me more than a "I think this PR has shown that the current implementation can remove the codes plain JavaScript object and utilize a single Map for emitted", so that I could have the slightest chance go implement what you have in mind.

Imho the double structure should have the best performance. So i am in doubt that having a single structure will have benefits other than a little bit less memory

@jsumners
Copy link
Member

When we add a new code, we add it to the emitted map with a value of false. This indicates two things: 1. the code has been defined and 2. it has not been emitted yet. This seems to make the codes POJO redundant.

@climba03003
Copy link
Member

climba03003 commented Dec 1, 2022

Using a single object would be something like below.

const codes = new Map()

function create (name, code, message) {
  // ...
  return { name, code, message: formatted, emitted: false }
}

function emit (code, a, b, c) {
  const info = codes.get(code)
  if (info === undefined) throw new Error(`The code '${code}' does not exist`)
  if (info.emitted === true) return
  
  // ...
  
  info.emitted = true
}

index.js Show resolved Hide resolved
@Uzlopak
Copy link
Contributor Author

Uzlopak commented Dec 1, 2022

I benched a little. It seems like that using Objects in both cases boosts the performance significantly. As if v8 optimizes it away.

uzlopak@Battlestation:~/workspace/process-warning$ npm run benchmark

> process-warning@2.0.0 benchmark
> node benchmark/benchmark.js

warn x 1,250,369,939 ops/sec ±0.17% (98 runs sampled)
(node:109564) [FST_ERROR_CODE] FastifyWarning: message
(Use `node --trace-warnings ...` to show where the warning was created)

@Uzlopak
Copy link
Contributor Author

Uzlopak commented Dec 1, 2022

Same benchmark on master

uzlopak@Battlestation:~/workspace/process-warning$ node benchmark/benchmark.js 
warn x 155,841,579 ops/sec ±0.24% (96 runs sampled)
(node:114029) [FST_ERROR_CODE] FastifyWarning: message
(Use `node --trace-warnings ...` to show where the warning was created)

@Uzlopak
Copy link
Contributor Author

Uzlopak commented Dec 1, 2022

@mcollina

Would you please give a statement?

If my changes are negligible than please close this PR.

@Uzlopak Uzlopak changed the title Use Set instead of Map for emitted and Map instead of Object for codes perf: Improve performance Dec 1, 2022
@mcollina
Copy link
Member

mcollina commented Dec 1, 2022

Is this sitting in a hot path of some kind? How did you reach the conclusion to optimize this?

The change looks ok to me.

@Uzlopak
Copy link
Contributor Author

Uzlopak commented Dec 1, 2022

node16:
before:

uzlopak@Battlestation:~/workspace/process-warning$ node benchmark/benchmark.js 
warn x 39,713,659 ops/sec ±0.98% (97 runs sampled)
(node:119186) [FST_ERROR_CODE_1] FastifyWarning: message
(Use `node --trace-warnings ...` to show where the warning was created)
(node:119186) [FST_ERROR_CODE_3] FastifyWarning: message

after:

uzlopak@Battlestation:~/workspace/process-warning$ node benchmark/benchmark.js 
warn x 77,635,234 ops/sec ±0.40% (98 runs sampled)
(node:119394) [FST_ERROR_CODE_1] FastifyWarning: message
(Use `node --trace-warnings ...` to show where the warning was created)
(node:119394) [FST_ERROR_CODE_3] FastifyWarning: message

In node14 the I even get 105m ops/s. Really strange.

@mcollina
I assumed, that this can be potentially performance eater, when adding those warnings to deprecated functionality in fastify, which means that if you update fastify-core you get also a performance penalty even though the code is still valid till v5.

return codes[code]
}

function emit (code, a, b, c) {
if (emitted[code] === true) return
Copy link
Member

@climba03003 climba03003 Dec 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main performance gain is the return line moved above the check of codes exist.
Since the function here is simple enough, one more check means double of time.

@jsumners
Copy link
Member

jsumners commented Dec 4, 2022

For what it's worth, the exported emitted object needs to remain a hash. I have literally just needed to update the hash during testing to verify two different cases emit the same warning.

@Uzlopak
Copy link
Contributor Author

Uzlopak commented Dec 4, 2022

@jsumners

Good point. I will modify it.

@Uzlopak Uzlopak mentioned this pull request Dec 4, 2022
4 tasks
@Uzlopak
Copy link
Contributor Author

Uzlopak commented Dec 4, 2022

Closing in favor of #70

@Uzlopak Uzlopak closed this Dec 4, 2022
@Uzlopak Uzlopak deleted the use-set-instead-of-map branch December 4, 2022 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants