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

Parser performance boost #573

Merged
merged 3 commits into from Oct 12, 2011
Merged

Parser performance boost #573

merged 3 commits into from Oct 12, 2011

Conversation

3rd-Eden
Copy link
Contributor

@3rd-Eden
Copy link
Contributor Author

Including loop optimizations: http://cl.ly/0Y2f2J3Y1E311t3Z3C1C

@@ -141,14 +144,15 @@ exports.encodePayload = function (packets) {
var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;

exports.decodePacket = function (data) {
var pieces = data.match(regexp);
var pieces = data.match(regexp)
, parse = JSON.parse;

Choose a reason for hiding this comment

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

Surely a micro-optimisation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw a small increase of decoding per sec because of it.

@ThisIsMissEm
Copy link

For all the cases where you have defaults that are || '', could you perhaps cache that empty string value?

@tj
Copy link
Contributor

tj commented Oct 12, 2011

I just wanted to play with vbench haha. we should find out if it's even remotely a bottleneck first, but the changes are not ugly or anything so it doesn't hurt

@3rd-Eden
Copy link
Contributor Author

@miksago changing the switch statement to a integer switch and changing the empty string both degraded performance. It costed about 1K ops/s. But thanks a lot for the tips!

@visionmedia :p The protocol parser is a hot code path, so If we can optimize it, we should. For some applications these changes might not be noticeable because they are not processing a lot of message per sec, but for busy chat boxes or what ever it could certainly improve performance and response times.

@tj
Copy link
Contributor

tj commented Oct 12, 2011

for sure, that's why I wanted to make sure there was no glaring issues with those first, but we should still profile the system as a whole

@3rd-Eden
Copy link
Contributor Author

Not only that but also run individual parts against the v8 --profile option to see if we can optimize against crankshaft. Just to be sure that we are not causing it to bail out.

Because I'm sure we do that with the parser, because we wrapping JSON.parse in a try catch block.

@ThisIsMissEm
Copy link

@3rd-Eden Aha! That'd be an explaination as to why memoizing JSON.parse speeds up, as it doesn't need to look up that value every time due to try {} catch (e){} breaking crankshaft optimisations.

@ThisIsMissEm
Copy link

@3rd-Eden switch on integers is slower, but if/else on integers may be faster. I'm surprised caching '' is slower.

@rauchg
Copy link
Contributor

rauchg commented Oct 12, 2011

niiiice

rauchg added a commit that referenced this pull request Oct 12, 2011
@rauchg rauchg merged commit 373c729 into socketio:master Oct 12, 2011
@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

@3rd-Eden switch on integers is slower, but if/else on integers may be faster. I'm surprised caching '' is slower.

Not really integers in javascript, but anyway. That switches are marginally faster than if/else is no surprise, but the fact that string switches are quicker than number switches -- if true -- surely must be a javascript artifact.

@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

I did a few simulations on pregenerated sequences of strings / numbers, with switch / ifelse / object-function-lookup for each possible value:

switch and object benchmarks: 
43070 x one of 10 possible 10 letter strings, in a pre-generated random order,
with blocks matching each possible string,
(a) run through a switch, (b) called as methods on an object.

timing shows milliseconds elapsed for 1000 repetitions of the 43070 long sequence.

v0.4.10
switchbench.js 2856ms
objectbench.js 1600ms

v0.5.9
switchbench.js 1879ms
objectbench.js 1319ms

Result: method name lookup on an object is faster.

===

number benchmarks: 
43070 numbers ranging from 0 to 9 inclusive, in a pre-generated random order, 
with blocks matching each possible number,
(a) run through an if/else block matching all 10 possibilities, (b) run through a switch.

timing shows milliseconds elapsed for 1000 repetitions of the 43070 long sequence.

v0.4.10
num-ifelse.js  1636ms
num-switch.js  1318ms

v0.5.9
num-ifelse.js  718ms
num-switch.js  595ms

Result: switch is marginally faster

Combined results: numeric matching should be faster than string matching (as expected)

@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

If this holds true, even without doing more testing with numeric switches, rewriting the switch cases in the code affected by this pull to objects with functions should yield even quicker runtimes.

@ThisIsMissEm
Copy link

I think you may be doing those benchmarks in a slightly wrong way, you should be
trying to do as many calls as possible in a set time frame (as does benchmark.js).

On 13 Oct 2011, at 09:26, Einar Otto Stangvik wrote:

I did a few simulations on pregenerated sequences of strings / numbers, with switch / ifelse / object-function-lookup for each possible value:

switch and object benchmarks:
43070 x one of 10 possible 10 letter strings, in a pre-generated random order,
with blocks matching each possible string,
(a) run through a switch, (b) called as methods on an object.

timing shows milliseconds elapsed for 1000 repetitions of the 43070 long sequence.

v0.4.10
switchbench.js 2856ms
objectbench.js 1600ms

v0.5.9
switchbench.js 1879ms
objectbench.js 1319ms

Result: method name lookup on an object is faster.

===

number benchmarks:
43070 numbers ranging from 0 to 9 inclusive, in a pre-generated random order,
with blocks matching each possible number,
(a) run through an if/else block matching all 10 possibilities, (b) run through a switch.

timing shows milliseconds elapsed for 1000 repetitions of the 43070 long sequence.

v0.4.10
num-ifelse.js 1636ms
num-switch.js 1318ms

v0.5.9
num-ifelse.js 718ms
num-switch.js 595ms

Result: switch is marginally faster

Combined results: numeric matching should be faster than string matching (as expected)

Reply to this email directly or view it on GitHub:
#573 (comment)

@3rd-Eden
Copy link
Contributor Author

I decided to port the current parser benchmark that TJ wrote in vbench to benchmark.js;

https://gist.github.com/1283881

So we can actually do some testing on node 0.5.9

@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

@miksago, Uhm and how do you figure that makes any difference at all? So long as the sequences are equally long, the data doesn't lie.

@ThisIsMissEm
Copy link

@einaros I can't remember all the reasons, but I had a really long discussion with @jdalton about this at JSConf.eu, perhaps he can fill you in on the fine points there?

@ThisIsMissEm
Copy link

@3rd-Eden Nice! I spent about 6 hours trying to get npm to install on 0.5.10-pre :/

@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

@miksago, Well benchmarking differently can paint a more realistic picture in cases where the processing speed increases / decreases over time. Here, however, that's not the case at all. All we really want to see is roughly how much time a single call through if / switch branching takes, vs. e.g. object member lookup.

@tj
Copy link
Contributor

tj commented Oct 13, 2011

@3rd-Eden nice! benchmark.js works for you? it failed miserably last time I tried it so I went with uubench for vbench but if that's working properly we should change vbench to use it

@jdalton
Copy link

jdalton commented Oct 13, 2011

@visionmedia benchmark.js is a too common name :D
The benchmark.js @3rd-Eden is talking about is http://benchmarkjs.com (it powers jsPerf).

@tj
Copy link
Contributor

tj commented Oct 13, 2011

oh, lame. I thought they had that stuff running on node too, but last time i looked it was a huge mess

@3rd-Eden
Copy link
Contributor Author

@visionmedia I have used it couple of times before to benchmark some of my other modules and it worked quite nicely. I have no doubt about the quality of the code as it also powers jspref.

There are some small issues in the code, if you want to run multiple suites. You need to manually clear the cycle event from the last benchmark, or that one will be used.. Which is quite annoying :p

@3rd-Eden
Copy link
Contributor Author

Doh, you guys type way faster than i do ;)

@jdalton
Copy link

jdalton commented Oct 13, 2011

You need to manually clear the cycle event from the last benchmark, or that one will be used.. Which is quite annoying :p

Lemmi know if that's still an issue. The npm module is totally out of date, I will try to push an update to it today.

@tj
Copy link
Contributor

tj commented Oct 13, 2011

looked at it again, looks ok actually, I'd love to try it out for vbench

@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

https://gist.github.com/48bf9fbcdb6993605fee <= Did a quick and dirty test with object method lookup rather than switch. Seems to provide slightly better speeds. More tests will follow.

@einaros
Copy link
Contributor

einaros commented Oct 13, 2011

Using arrays of functions + indexes rather than string types => way slower than all prior approaches. I'm still guessing this is due to javascript numbers being floating point rather than plain ints.

@3rd-Eden
Copy link
Contributor Author

The speed performance isn't coming from changing the switch to a object method lookup, but from moving the try {} catch (e) {} related code blocks to another function. This way V8's crankshaft can fully optimize the rest of the functions.

A gist to illustrate: https://gist.github.com/1285245 =p

@3rd-Eden
Copy link
Contributor Author

@jdalton Great to hear that, can't wait to see it land in npm :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants