Closed Bug 854763 Opened 11 years ago Closed 11 years ago

Add a memory reporter for asm.js array buffers.

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla23
Tracking Status
firefox22 --- fixed
firefox23 --- fixed

People

(Reporter: n.nethercote, Assigned: n.nethercote)

Details

(Whiteboard: [MemShrink])

Attachments

(3 files)

asm.js array buffers aren't being reported on x64.
This patch cleaves the "objects-extra/elements" measurement in twain:
"elements/non-asm.js" and "elements/asm.js".  I moved
JSObject::sizeOfExcludingThis into jsobj.cpp to avoid mutual dependence between
between jsobjinlines.h and jstypedinlines.h.

I've tested on x64 on Citadel, because that's the only asm.js example I know
of!  The output looks reasonable -- we have a 512 MiB buffer.

1,729.85 MB (100.0%) -- explicit
├────899.29 MB (51.99%) -- window-objects
│    ├──889.18 MB (51.40%) -- top(file:///home/njn/Downloads/asm.js/Citadel.html, id=8)
│    │  ├──886.54 MB (51.25%) -- active/window(file:///home/njn/Downloads/asm.js/Citadel.html)
│    │  │  ├──886.26 MB (51.23%) -- js-compartment(file:///home/njn/Downloads/asm.js/Citadel.html)
│    │  │  │  ├──884.47 MB (51.13%) -- objects-extra
│    │  │  │  │  ├──884.31 MB (51.12%) -- elements
│    │  │  │  │  │  ├──512.00 MB (29.60%) ── asm.js
│    │  │  │  │  │  └──372.31 MB (21.52%) ── non-asm.js
Attachment #729387 - Flags: review?(luke)
Part of me is bothered by the fact that we'll have objects-extra/elements/non-asm.js on the 99.9% of pages that don't have asm.js, but I don't have any better suggestion aside from maybe splitting it into objects-extra/elements and objects-extra/elements-asm.js or something so I'll just stay over here in the peanut gallery.
Whiteboard: [MemShrink]
> maybe splitting it
> into objects-extra/elements and objects-extra/elements-asm.js or something
> so I'll just stay over here in the peanut gallery.

I had something like that originally, but then added the suffix because "elements-asm.js" sounds like a subset of "elements".
Comment on attachment 729387 [details] [diff] [review]
Add a memory reporter for asm.js array buffers.

Thanks!
Attachment #729387 - Flags: review?(luke) → review+
https://hg.mozilla.org/mozilla-central/rev/e47387009162
Status: NEW → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla22
Bugger, I just realized there's a big problem with this.

Each multi-reporter has a GetExplicitNonHeap() method, which returns the sum of the sizes of all the KIND_NONHEAP reports it would report for the "explicit" tree.  This is used for fast computation of the "explicit" measurement, which is used in telemetry pings and is also available via nsIMemoryReporterManager::explicit.

For the JS multi-reporter, GetExplicitNonHeap() just gets the size of the entire heap (quick and easy) and the size of a handful of other things (the stack, and generated code).

But, thanks to asm.js, arbitrary JS objects can now hold pointers to non-heap memory, and GetExplicitNonHeap() isn't measuring these.  For example, when running Citadel, the measurement at the top of the explicit tree (which is computed by summing all the individual reports) is this:

  2,263.30 MB (100.0%) -- explicit

but the one in the "Other Measurements" section, which uses GetExplicitNonHeap() and is used by telemetry is this:

  1,751.22 MB ── explicit

It's missing exactly the 512 MiB asm.js array buffer.

To make GetExplicitNonHeap() accurate we'd need to iterate over every object in the JS heap, which is slow and entirely defeats the purpose of GetExplicitNonHeap().

Options I can see:

- Live with the discrepancy -- it only occurs for asm.js.  Yuk.

- Change things so that asm.js puts the 4 GiB allocation on the heap.  I don't know if this can be done in a sensible way that avoids committing most of it.

- Give up on measuring "explicit" for telemetry.  We'd also need to remove nsIMemoryReporterManager::explicit, which would break the endurance tests.  (AWSY would be ok, though, because it runs all the reporters.)

From a code maintenance POV, that third option would be a good thing -- you wouldn't have to worry about forgetting to update GetExplicitNonHeap.  (Note that there is a warning that gets printed if the two measurements don't match, but I didn't see it because it's only in debug builds and Citadel runs too slowly in debug builds to be usable...)
Target Milestone: mozilla22 → ---
> - Change things so that asm.js puts the 4 GiB allocation on the heap.  I don't know if 
> this can be done in a sensible way that avoids committing most of it.

On Linux and probably mac, sure.  I'm not so sure about Windows.

Ideally only the committed part of the array buffer would be in explicit...
> Ideally only the committed part of the array buffer would be in explicit...

It is.  The array has a certain size (e.g. 512 MiB) and everything past that up to the 4 GiB limit isn't counted.  (The 4 GiB is somehow used to catch out-of-bounds accesses, AIUI.)  So that's not a problem.
>> Ideally only the committed part of the array buffer would be in explicit...
> 
> It is. 

Okay, that's good.  But if we allocated it on the heap all 4gb would be in explicit, right?  If so, that speaks against that solution...
I worked out a way to fix this problem with a counter.  Patch coming shortly.
Please don't ask me how long it took to get this patch working reliably.  I
could tell you but then I'd have to kill you.

This patch also fixes a leak in a failure case -- if the
mprotect/VirtualAlloc(MEM_COMMIT) call fails, we need to release the array
buffer.
Attachment #730402 - Flags: review?(luke)
Comment on attachment 730402 [details] [diff] [review]
(follow-up): Include asm.js arrays the standalone "explicit" reporter.

Review of attachment 730402 [details] [diff] [review]:
-----------------------------------------------------------------

::: js/src/jstypedarray.cpp
@@ +366,5 @@
>      // Enable access to the valid region.
>      JS_ASSERT(buffer->byteLength() % AsmJSAllocationGranularity == 0);
>  # ifdef XP_WIN
> +    if (!VirtualAlloc(p, PageSize + buffer->byteLength(), MEM_COMMIT, PAGE_READWRITE)) {
> +        VirtualAlloc(p, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);

Holy crap, I think I should've used VirtualFree in ArrayBufferObject::releaseAsmJSArrayBuffer, to actually release the virtual address space allocation.  If you agree, can you change this failure case to use VirtualFree as well as in releaseAsmJSArrayBuffer?
Attachment #730402 - Flags: review?(luke) → review+
> Holy crap, I think I should've used VirtualFree in
> ArrayBufferObject::releaseAsmJSArrayBuffer, to actually release the virtual
> address space allocation.

Indeed.  I'll fix both instances.  I just started a try run, I'll land once it's done.
This part seems worth backporting to Aurora.
Attachment #732626 - Flags: review?(luke)
Comment on attachment 732626 [details] [diff] [review]
(part 2, Aurora) - Use VirtualFree instead of VirtualAlloc where appropriate.

[Approval Request Comment]
Bug caused by (feature/regressing bug #): asm.js.

User impact if declined: a 4 GiB memory leak for each asm.js array on Win64. Win64 is a non-tier-1 platform but it is the platform that was (ahem) used for the GDC demo.

Testing completed (on m-c, etc.): landed on m-c.

Risk to taking this patch (and alternatives if risky): negligible.

String or IDL/UUID changes made by this patch:
Attachment #732626 - Flags: approval-mozilla-aurora?
Comment on attachment 732626 [details] [diff] [review]
(part 2, Aurora) - Use VirtualFree instead of VirtualAlloc where appropriate.

Thanks!
Attachment #732626 - Flags: review?(luke) → review+
Comment on attachment 732626 [details] [diff] [review]
(part 2, Aurora) - Use VirtualFree instead of VirtualAlloc where appropriate.

If the risk is negligible and limited to ASM.js, we can take this on Aurora.
Attachment #732626 - Flags: approval-mozilla-aurora? → approval-mozilla-aurora+
Target Milestone: --- → mozilla23
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: