Much slower than v8 on function creation microbenchmark




JavaScript Engine
3 years ago
3 years ago


(Reporter: sstangl, Unassigned)



Firefox Tracking Flags

(Not tracked)


(Whiteboard: [shumway])


(1 attachment)



3 years ago
Created attachment 8556126 [details]

The attached microbenchmark is a reduced version of Shumway's createCompiledFunction(), which is extremely hot during slow Shumway startup. The benchmark concatenates a bunch of strings, then feeds them into |new Function()|.

Performance on the microbenchmark is currently as follows:
> SM: 1.067s
> d8: 0.136s

Optimizing this microbenchmark should make headway toward improving Shumway startup.
Profile says 60+% of the time is under CompileFunctionBody.  Lots of Parser<FullParseHandler> stuff under there.  Presumably if we could get away with just doing a SyntaxParseHandler parse here that would help.

Even when the functions are called, the CompileFunctionBody is still about 46% of the time...

One curious thing about this testcase.  Why does it create a new Function which when called just returns another function object?
Also, is your actual use case like this, where you create a bunch of functions all with the same function body?  Because if I pass "bodies[i % bodies.length] + i" as the second argument to createCompiledFunction, the SpiderMonkey time stays about the same but the V8 time goes up by a factor of 15 or so, putting it at well over 2x slower than SpiderMonkey.  So it seems like you're just hitting some sort of Function constructor cache in V8, which is only relevant to your real-life use case if your function bodies do in fact get repeated.
Flags: needinfo?(sstangl)

Comment 3

3 years ago
Answered on IRC last week. In summary: this is a synthetic benchmark that assumes that a cache isn't being used; Shumway has its own cache to prevent regenerating identical functions; Shumway should remove the level of indirection in generated functions.
Flags: needinfo?(sstangl)
(In reply to Sean Stangl [:sstangl] from comment #3)
> Shumway should remove the level of indirection in generated functions.

Does that cause any actual slowdown?

The reason we're using it is because before there was no good way to invoke the Function constructor with a variable number of arguments. Which we have to do to compile functions without statically knowing their parameters count.

Note that we can probably just change this to use eval instead of new Function since we're moving to globally unique names for the generated functions anyway. I'm mostly curious.
> Does that cause any actual slowdown?

Unclear; would have to measure.
(In reply to Boris Zbarsky [:bz] from comment #5)
> > Does that cause any actual slowdown?
> Unclear; would have to measure.

Ok, sure. I just wanted to make sure I'm not overlooking something in not seeing proof for it in this test case.
Well, if I modify the testcase to do:

	return new Function(fnbody);

instead of the thing it does now, the time does drop significantly.  But that's because the function bodies are all very short.  If I just make them a bit longer, the time goes back up.  So it depends on what your function bodies look like.
Blocks: 1140984
Keywords: perf
You need to log in before you can comment on or make changes to this bug.