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

The merge function is slow #1016

Closed
1 task done
cesarfd opened this issue Jan 8, 2020 · 30 comments · Fixed by #1051
Closed
1 task done

The merge function is slow #1016

cesarfd opened this issue Jan 8, 2020 · 30 comments · Fixed by #1051
Labels
enhancement This change will extend Got features ✭ help wanted ✭

Comments

@cesarfd
Copy link

cesarfd commented Jan 8, 2020

What would you like to discuss?

Hi, we are using got heavily in my company to send several thousand requests/s so I'm doing some profiling to see in which places our app spends its time the most.

I've recently upgraded to Got 10 and I've seen that the library spends a significant (though, not alarming) percentage of the time in the normalize arguments phase, which at the same time calls the aforementioned merge function.

Captura de pantalla 2020-01-08 a las 15 50 59

It looks like this single slice call to clone the array seems to spend quite a lot of time. So, my question is, do we really need to clone the array or could it be just referenced? If we need a copy, is slice() the fastest method?

I tried https://jsperf.com/cloning-arrays/3 in Chrome 79 and it seems that there're faster (not so much tbh) alternatives.

Checklist

  • I have read the documentation.
@szmarczak szmarczak added enhancement This change will extend Got features ✭ help wanted ✭ labels Jan 8, 2020
@szmarczak szmarczak changed the title About the utils/merge function The merge function is slow Jan 8, 2020
@szmarczak
Copy link
Collaborator

image

Ran on i7-7700k Intel CPU.

@szmarczak
Copy link
Collaborator

Hi, we are using got heavily in my company to send several thousand requests/s so I'm doing some profiling to see in which places our app spends its time the most.

Are there any other heavy places like merge.ts? This is very interesting work.

@cesarfd
Copy link
Author

cesarfd commented Jan 8, 2020

image

Ran on i7-7700k Intel CPU.

Captura de pantalla 2020-01-08 a las 20 30 49

On Intel i7-5557U

Weird.

@yovanoc
Copy link

yovanoc commented Jan 8, 2020

I don't know if it will help but on my 2.3 GHz 8-Core Intel Core i9
image

@cesarfd
Copy link
Author

cesarfd commented Jan 8, 2020

Hi, we are using got heavily in my company to send several thousand requests/s so I'm doing some profiling to see in which places our app spends its time the most.

Are there any other heavy places like merge.ts? This is very interesting work.

Here's a more detailed tree where we can see what the code does when we invoke got:

got normalize options

This comes from a 70 second profiling. There are more places where we call got with a different option object each time as we are performing POST json requests.

It seems the normalizeArguments section (and the whole merging process) is the only place where got spends a noticeable amount of time, at least with our use case.

@szmarczak
Copy link
Collaborator

@sindresorhus You need to see this:

image

@sindresorhus
Copy link
Owner

@szmarczak Micro-benchmarks are pretty useless without context. If you run Got seven million times in real-world situations, the network is going to be the bottleneck, not a simple loop.

@sindresorhus
Copy link
Owner

@cesarfd What Node.js version and OS?

@szmarczak
Copy link
Collaborator

Micro-benchmarks are pretty useless without context. If you run Got seven million times in real-world situations, the network is going to be the bottleneck, not a simple loop.

I think it depends if you're running a very very very low-spec machine / VPS and make thousands of requests...

@szmarczak
Copy link
Collaborator

szmarczak commented Jan 11, 2020

@sindresorhus Also shouldn't we deep clone arrays too? For example you can do:

got.extend({hooks: {beforeRequest}});
beforeRequest.push(fn);

and the instance will be affected. I think it's a regression.

@szmarczak
Copy link
Collaborator

@cesarfd Could you also provide performance profiling for normalize-arguments.js?

@cesarfd
Copy link
Author

cesarfd commented Jan 11, 2020

@cesarfd What Node.js version and OS?

Node 12.13.1 under a buster-slim docker image + Linux AMI

@cesarfd
Copy link
Author

cesarfd commented Jan 11, 2020

@cesarfd Could you also provide performance profiling for normalize-arguments.js?

Yes, I'll rerun the profiler on Monday.

@szmarczak
Copy link
Collaborator

@cesarfd
Copy link
Author

cesarfd commented Jan 13, 2020

@szmarczak normalize-arguments.js:

Captura de pantalla 2020-01-13 a las 9 19 59

Captura de pantalla 2020-01-13 a las 9 20 22

@szmarczak
Copy link
Collaborator

Thank you very much, if you provide also profiling for mergeOptions and normalizeArguments (it's in the normalize-arguments.js file) that will be great! I've got a few ideas on how to improve the performance.

@sindresorhus
Copy link
Owner

I think it depends if you're running a very very very low-spec machine / VPS and make thousands of requests...

Sure. My point was that standalone micro-benchmarks doesn't mean anything without the context. It's better to profile the actual running code on the actual system.

@sindresorhus
Copy link
Owner

Also shouldn't we deep clone arrays too? For example you can do:

Yes

@cesarfd
Copy link
Author

cesarfd commented Jan 13, 2020

Thank you very much, if you provide also profiling for mergeOptions and normalizeArguments (it's in the normalize-arguments.js file) that will be great! I've got a few ideas on how to improve the performance.

Wops, I pasted the pre normalize function before, sorry.

mergeOptions:
Captura de pantalla 2020-01-13 a las 11 17 21

normalizeArguments:
Captura de pantalla 2020-01-13 a las 11 17 42

@Jolg42
Copy link

Jolg42 commented Jan 24, 2020

I also noticed that got can be "relatively slow" to create an instance, If you have any improvements I'm interested to try them :)

In my case the request is done on localhost so the network is fast.

@szmarczak
Copy link
Collaborator

@cesarfd What tool do you use to display the performance timings? Could you tell me how to enable it please? That'd be very useful.

@cesarfd
Copy link
Author

cesarfd commented Jan 31, 2020

@szmarczak It's all in the chrome inspect tool. basically the procedure is as follows:

  • Start a node process with the --inspect flag or send a kill -USR1 <node pid>. This will enable the debug mode on the process, by default it listens to port 9229.
  • Fire up a chrome://inspect, this will show you an available remote target in localhost, just click it and it will show the tools, including a drop down menu for the flame graph.

https://nodejs.org/en/docs/guides/debugging-getting-started/

@szmarczak
Copy link
Collaborator

@cesarfd I already know that, I thought you were running a fork of Chrome Dev Tools because I can't find anywhere the option to enable the timings in the Source tab...

@szmarczak
Copy link
Collaborator

@cesarfd Friendly ping :)

@szmarczak
Copy link
Collaborator

I meant this, not the flamegraph (sorry if I got you confused):

image

@cesarfd
Copy link
Author

cesarfd commented Feb 1, 2020 via email

@szmarczak
Copy link
Collaborator

Hmm... It takes me there but there are no timings... Will try a different Chromium browser.

@szmarczak
Copy link
Collaborator

szmarczak commented Feb 1, 2020

@cesarfd Oh, I've got it now! The running node script must not exit in order to display the timings (at least in my case I think). Thank you :)

@szmarczak
Copy link
Collaborator

szmarczak commented Feb 1, 2020

image

image

lol I didn't know that comments take CPU time (just kidding). It gives me wrong results. Some functions aren't called at all and it says it took 7ms to run them. The flamegraph gives good results tho. Tried two different browsers: Google Chrome and Brave. I run Node 13.7.0. Will try Node 10 & 12.

@szmarczak szmarczak mentioned this issue Feb 6, 2020
18 tasks
@resynth1943
Copy link

Maybe Sindre should consider removing comments as an optimization. 😛

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement This change will extend Got features ✭ help wanted ✭
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants