Open
Bug 786819
Opened 12 years ago
Updated 1 year ago
reduce number of relocations required by new bindings data structures
Categories
(Core :: DOM: Bindings (WebIDL), defect, P3)
Core
DOM: Bindings (WebIDL)
Tracking
()
NEW
People
(Reporter: froydnj, Unassigned)
References
(Blocks 2 open bugs)
Details
(Whiteboard: [overhead:noted])
The new bindings could use some of the same treatment quickstubs received in bug 711563. Some new JS interfaces will be required, though...
Comment 1•12 years ago
|
||
Do you know offhand which particular parts of the new bindings are getting relocated? I'm happy to rejigger things, but I haven't had a chance to sit down and figure out where the relocations are coming from... I'm also not sure what the effective relocation-reduction techniques are.
Reporter | ||
Comment 2•12 years ago
|
||
(In reply to Boris Zbarsky (:bz) from comment #1) > Do you know offhand which particular parts of the new bindings are getting > relocated? Sure. For instance, WebGLRenderingContextBinding.cpp: static JSFunctionSpec sMethods_specs[] = { JS_FNINFO("getContextAttributes", genericMethod, &getContextAttributes_methodinfo, 0, JSPROP_ENUMERATE), ... That's three relocations: - "getContextAttributes"; - genericMethod, - getContextAttributes_methodinfo. You could avoid the first and third pretty trivially. Notice that you have one relocation for every function due to the genericMethod pointer. I assume you mean to change this at some point so each function has an individual JSNative? If not--or even if you do plan on doing this, but only for a select subset of functions--you could save on relocations by having a table of JSNatives and indexing into that, thus sharing relocations. Whether that's really worth it or not depends on how much sharing you can do, of course... static Prefable<JSFunctionSpec> sMethods[] = { { true, &sMethods_specs[0] }, That's one relocation for the &sMethods_specs[0]. And so on for all instances of Prefable arrays generated by the bindings. static JSPropertySpec sAttributes_specs[] = { { "canvas", 0, JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS, {(JSPropertyOp)genericGetter, &canvas_getterinfo}, JSOP_NULLWRAPPER}, That's three relocations: - "canvas"; - genericGetter; - &canvas_getterinfo. It'd be five with information for the setter (e.g. CSS2PropertiesBinding.cpp). Same comments apply vis a vis genericGetter and getterinfos as for the function specs earlier. static ConstantSpec sConstants_specs[] = { { "DEPTH_BUFFER_BIT", UINT_TO_JSVAL(256) }, One for the string here. "Better" JS interfaces could be built to avoid some relocations with JSJitInfo and the above, though I don't know how we feel about having semi-private interfaces like that; I wouldn't think interfaces that enable avoiding relocations are necessarily good as public interfaces. It seems that we're repeating a lot of information in JSJitInfos that we should be able to compress, too. Those are all the big ones I notice immediately; I haven't combed through looking for others, but I bet that's most of them (other than things like JSClass/DOMJSClass, which are basically vtables and hard to fix). Generating some of the tables--particularly string tables--for the above across all bindings at once would be helpful for space savings, too.
Comment 3•12 years ago
|
||
> You could avoid the first and third pretty trivially. For the string, I guess I could mush up all the strings for the file into a single large static const char[] and then use offsets into that? For the methodinfos, same deal with an array of them and indexing into it? What you said about &sMethods_specs[0] needing a relocation makes it sound like "no" for both of the questions above... > assume you mean to change this at some point so each function has an individual > JSNative? Nope. We used to have that; we moved to this setup to save codesize. I'm not sure what you mean about a table here. There are basically three jsnatives (typically; there might be two or one in some cases) per translation unit: genericGetter, genericSetter, genericMethod. How would I use the table approach for them? Generating things across all bindings is ... doable if we have to. It's a bit suboptimal, not least because it doesn't parallelize well. But I'd like to understand how one actually goes above avoiding relocations first, before I worry about coalescing across bindings.
Reporter | ||
Comment 4•12 years ago
|
||
(In reply to Boris Zbarsky (:bz) from comment #3) > > You could avoid the first and third pretty trivially. > > For the string, I guess I could mush up all the strings for the file into a > single large static const char[] and then use offsets into that? Right. You can usually use uint16_t for indices, which saves space and packs better with other things than pointers, too. > For the methodinfos, same deal with an array of them and indexing into it? Right. Blue-sky wish is sharing most of the methodinfos/getterinfos too. > What you said about &sMethods_specs[0] needing a relocation makes it sound > like "no" for both of the questions above... I'm not sure how that follows. The two cases above are using offsets into a table, not the address of the table element at that offset, as in the &sMethods_specs[0] case. > > assume you mean to change this at some point so each function has an individual > > JSNative? > > Nope. We used to have that; we moved to this setup to save codesize. I'm > not sure what you mean about a table here. There are basically three > jsnatives (typically; there might be two or one in some cases) per > translation unit: genericGetter, genericSetter, genericMethod. How would I > use the table approach for them? I mean that instead of: { ..., genericGetter, ... }, { ..., genericGetter, ... }, { ..., genericGetter, ... }, you could have: typeof(genericGetter) jsnativeFuns[] = { genericGetter, ... }; { ..., /*index into jsnativeFuns*/0, ... }, { ..., 0, ... }, ... which saves relocations and may also enable better packing of structures. That may be too clever for the first cut, though. > Generating things across all bindings is ... doable if we have to. It's a > bit suboptimal, not least because it doesn't parallelize well. But I'd like > to understand how one actually goes above avoiding relocations first, before > I worry about coalescing across bindings. Totally. The big win will be avoiding the relocations in the first place, and then maximally sharing things in each *Binding module; cross-module sharing is probably more of a blue-sky thing.
Comment 5•12 years ago
|
||
> The two cases above are using offsets into a table Ah, so the JSFunctionSpec would store a number, not a string? That would require JSAPI changes, basically: that struct is passed into the JS engine and it expects a const char* there, obviously. Same for the methodinfos. I guess you did say that in comment 0... I could stop using the relevant JSAPI and just manually define everything myself, in which case I can do my own indexing into an array at the definition site, but that would mean a huge number more function calls to set up a DOM prototype... Maybe that's ok.
Comment 6•12 years ago
|
||
How hard would it be to stick all this code somewhere *inside* the engine?
Comment 7•12 years ago
|
||
Probably not terribly hard. Except the Prefable bit, of course. Note that in the common case (nothing is prefable), the one relocation seems somewhat unavoidable...
Reporter | ||
Comment 8•12 years ago
|
||
(In reply to Boris Zbarsky (:bz) from comment #5) > > The two cases above are using offsets into a table > > Ah, so the JSFunctionSpec would store a number, not a string? Yes, at which point we'd have to call it a DOMJSFunctionSpec or somesuch. > I could stop using the relevant JSAPI and just manually define everything > myself, in which case I can do my own indexing into an array at the > definition site, but that would mean a huge number more function calls to > set up a DOM prototype... Maybe that's ok. FWIW, quickstubs doesn't use the "bulk" calls (JS_DefineFunctions), but instead defines them one-by-one. It's not obvious to me that: JS_DefineFunctions(...) is any faster than: for (i = 0; i < ...) JS_DefineFunction(...) since presumably JS_DefineFunctions has to have the same loop *somewhere*.
Comment 9•12 years ago
|
||
It has a loop, but the loop doesn't call JS_DefineFunction. It calls a lower-level method, so you skip several levels of indirection, including the overhead of cross-module calls for each function... But yes, I know quickstubs does this manually. Again, I'd be willing to try it, esp if we come up with a good way to measure the performance. That last is kinda hard until we have more protos hooked up, sadly.
Comment 10•12 years ago
|
||
But maybe setting up a single proto takes long enough we can measure it using performance.now() ?
Comment 11•12 years ago
|
||
<script> var start = performance.now(); WebGLRenderingContext; var stop = performance.now(); document.write(stop - start); </script> Worth measuring that as-is and with manual JS_DefineFunctions calls. As-is is about 0.4ms.
Comment 12•12 years ago
|
||
For what it's worth, profiling that testcase, if I trust my profiler, shows about 2-1 time ratio between JS_DefineProperty (for the constants) and JS_DefineFunctions (for the methods). There are 295 constants and 137 methods. So it might all be a wash. The biggest cost, really, is atomizing all those strings. So another option is to switch to JS_DefinePropertyById and use our existing id arrays to implement that. Should be a perf win in addition to reducing relocations!
Updated•6 years ago
|
Blocks: memshrink-content
Updated•6 years ago
|
Priority: -- → P3
Comment 13•6 years ago
|
||
This is a lower priority for memshrink-content, we think a fork server will help more with relocations than chasing down individual causes. This could still be a perf win and in install size win.
Whiteboard: [overhead:noted]
Assignee | ||
Updated•5 years ago
|
Component: DOM → DOM: Core & HTML
Updated•4 years ago
|
Component: DOM: Core & HTML → DOM: Bindings (WebIDL)
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•