I want to do per-tab memory accounting in about:memory. I have
reasonably good ideas how to do this, but any feedback would be
welcome. Below is something of a brain-dump.
A feature often requested by users is per-tab CPU and memory
accounting. Eg. https://bugzilla.mozilla.org/show_bug.cgi?id=400120.
It's also often suggested in forums. Per add-on accounting is also
Once process separation is fully implemented, this won't be too hard,
because you can get that stuff from the OS. However, until then, it
would be good to have something.
Per-tab CPU accounting without process separation seems impossible.
(I'd love to be told otherwise, though.)
Per-tab memory accounting without process separation seems quite
possible. Here are the main memory reporter groups currently shown in
It would be great to have the structure changed to something like this:
I think doing memory reporting for images and layout (and the DOM,
when we get it --
https://bugzilla.mozilla.org/show_bug.cgi?id=663271) on a per-tab
basis shouldn't be too difficult.
I think storage memory (which is all SQLite) can't be easily split
among tabs, so putting it in the "Chrome" section seems the right
thing to do.
The heap-unclassified stuff obviously can't be broken down by a
per-tab basis. (https://bugzilla.mozilla.org/show_bug.cgi?id=563700
is open to add more reporters, thereby reducing the size of
For JS the situation is trickier. There the natural division is
is open for adding per-compartment reporters to about:memory. (Note
that I've found this per-compartment info to be really useful already;
https://bugzilla.mozilla.org/show_bug.cgi?id=664067 were created as a
Currently, one compartment can be shared between multiple tabs, which
makes a per-tab presentation difficult. But there are plans
(https://bugzilla.mozilla.org/show_bug.cgi?id=650353) for giving each
global its own compartment. Then compartments wouldn't be shared
between tabs, which would make per-tab accounting easier.
Another issue is that nsIMemoryReporter is not really a good interface
for per-tab reporters. The problem is that each memory reporter is
standalone and reports a single measurement, and about:memory iterates
over all of them. So if you open a new tab, you have to create
numerous new reporters: ones for images, ones for layout, etc. This
is doable -- it's what I've done for the per-compartment accounting --
but it's a bit painful and unnatural. What we really want is an
interface where about:memory says "give me all the JS numbers" and a
bit of code can go off and e.g. traverse the JS heap once, and return
N results, as opposed to N reporters which each traverse part of the
JS heap and each return 1 result. Shaver implemented something along
these lines in his prototype patch for about:compartments
(https://bugzilla.mozilla.org/show_bug.cgi?id=625305). So I can see
the current nsIMemoryReporter interface being phased out in favour of
Now, what about add-ons? AFAICT Jetpacks may open their own JS
compartment, so there is some scope for separate accounting there.
Other than that, I have no idea. It sure would be wonderful to be
able to avoid the "have you tried disabling add-ons?" ritual in leak
Another interesting problem is that this could become too successful.
Currently about:memory is a resource for developers and very technical
users. But if it has per-tab info, it becomes useful to less
technical users, for the use case "Firefox is crawling, which tab
should I close, or which add-on should I disable?" And then
about:memory's shortcomings -- lack of localization
over-reliance on ASCII art
(https://bugzilla.mozilla.org/show_bug.cgi?id=654917) will become
bigger issues. In which case a simpler task manager
(https://bugzilla.mozilla.org/show_bug.cgi?id=515352) would probably
be better. But that's a problem I'd be happy to have!
If there is a way to tell to what tab a specific event on the main event
loop is bound to, we might be able to do some accounting through the
main event loop.
... mmmm with all the caches we have around, aren't there a bunch of
things that are likely to be shared across tabs?
Per nsIDOMWindow would be *much* more useful. Modern apps have iframes
for components and addons often have their own windows. Being able to
zero in on the functional unit is key for finding problems. Organizing
the UI to put the nsIDOMWindows in a tree with tabs contentWindows
prominent would be great.
And/or: present the accounting so it matches the architecture. Tabs do
not in themselves hold memory. Apparently things called compartments do
hold memory. Presenting memory as it actually is used in the system
would go a long way towards helping developers improve their code.
Below is something of a brain-dump.
> A feature often requested by users is per-tab CPU and memory
> accounting. Eg. https://bugzilla.mozilla.org/show_bug.cgi?id=400120.
> It's also often suggested in forums. Per add-on accounting is also
> often requested.
At present most addons are not distinguishable from the browser:
overlays by design meld with the browser. Many addons do have
distinguishable parts. For example, Firebug has two iframe elements.
However the JS that runs those iframes is in browser.xul (up to 1.8). So
the memory for the JS is not in iframes.
There is not at the moment.
> .... mmmm with all the caches we have around, aren't there a bunch of
> things that are likely to be shared across tabs?
Images are shared across tabs.
Layout data is not (it's allocated in per-presshell arenas). JS njn
> Per-tab memory accounting without process separation seems quite
> possible. Here are the main memory reporter groups currently shown in
> - js
> - images
> - storage
> - layout
> - heap-unclassified
There are some architecture issues which may make this difficult,
particularly in the image data. The image cache isn't directly
associated with tabs or DOM windows, especially when you have multiple
tabs open for the same site and they are sharing the image data.
> Now, what about add-ons? AFAICT Jetpacks may open their own JS
> compartment, so there is some scope for separate accounting there.
> Other than that, I have no idea. It sure would be wonderful to be
> able to avoid the "have you tried disabling add-ons?" ritual in leak
We are actively working on moving at least jetpack-style addons into a
separate process. This was part of the original goal for the Jetpack SDK
1.0 but was not feasible this time. But even there, the addon will also
be able to run code in the context of content (content scripts), so
we'll have to do some combination of measurements. It probably isn't
feasible to do this work for old-style addons because they are basically
chrome and much of their code runs in the main browser window global.
This relates to the multiple use cases that I talked about. You're
focussing on the developer case. Users want per-tab stats so they
know which tab to close if memory use is excessive.
(Hmm, which developers do you mean -- Firefox developers, or web
developers? I'll assume the former.)
I was wondering/hoping to be able to satisfy both use cases in a
single view. Eg. if each JS compartment cannot be shared between
multiple tabs, it's reasonable to have a structure like this:
which satisfies a user (per-tab info is there) and also a developer
(the compartments, which reflect the internal architecture, are
But it sounds like there's more things shared across tabs (eg. images)
than I thought. So satisfying both kinds of user with about:memory
may be difficult.
Can you clarify? If I have the same webpage open in multiple tabs,
will the images be shared between the tabs? In other words, any
single image doesn't necessarily belong to a single tab?
Yes. We only ever have one copy of a given image in memory, even if it's
referenced on multiple pages.
(There are, I think, a couple of edge cases where this isn't the case,
but you can pretty much rely upon it.)
> Once process separation is fully implemented, this won't be too hard,
> because you can get that stuff from the OS. However, until then, it
> would be good to have something.
As Benjamin said, process separation doesn't solve this problem, so whatever
you do will be relevant indefinitely. That's good news! :-)
Per-tab CPU accounting without process separation seems impossible.
> (I'd love to be told otherwise, though.)
I don't think it's impossible, in fact I think it might not be too hard, at
least for a partial solution. Here's a brainstorm for associating CPU usage
with documents (from which you can aggregate to get usage for tabs):
-- Give each thread a "current document" thread-local variable (which can be
null, since sometimes we don't know or it's browser-global). This would be
some sort of ID since document objects aren't thread-safe.
-- Create a "context switch" API that changes the current thread's current
document. This could help with the CPU accounting (or you could do sampling
-- Add document context switch calls at various places:
-- Layout phase-checking code (for reflows and restyles)
-- Triggering a DOM event handler
-- JS timers
-- Other async JS callbacks
-- Parser ops
-- Media decoding
-- Display list construction and ThebesLayer painting (some of the
painting is hard to account for because all the documents are mixed
I reckon it wouldn't be hard to account for the majority of what most Web
Bonus points if the context switch API takes a "type" parameter so we can
account for the *kind* of activity that's being triggered, and gets the
ability to log timestamps so we can get fine-grained performance timelines.
"Now the Bereans were of more noble character than the Thessalonians, for
they received the message with great eagerness and examined the Scriptures
every day to see if what Paul said was true." [Acts 17:11]
I had a prototype of this for JS compartments, including the types
(GC, parse/compile, script execute) based on the compartment-enter API
and rdtsc. I'll see if I can remember which computer I left it on.
Because developers are the ones who can and will use the information.
Look at what happened with the Firebug Net panel, YSlow, Google page
speed, etc: now there is a whole industry built around load performance.
> Users want per-tab stats so they
> know which tab to close if memory use is excessive.
Really? I'd guess it's more like a tiny (relative to Firefox total)
number of (possibly vocal) technical users. We know what users want: the
Web content in that tab. We know that because they opened the tab. They
don't want to close the tab, they can't see the site then! Anyway, if
they run out of memory they'll probably reboot or go have a cup of tea,
because checking for tab memory is just not something they want to have
to do for their Web browser.
> (Hmm, which developers do you mean -- Firefox developers, or web
> developers? I'll assume the former.)
I don't think Firefox developers are in a position to do much about
memory. They are experts in their own areas and they are not sloppy. Web
developers on the other hand have no clue how much memory they are
using. On the other hand, Web developers have the expertise to find the
memory hog cases which can be fixed by the browser team. It's not going
to be "images take too many bits"; it's going to be "when we use ajax to
load images into iframes and the cache fails". You need information that
crosses expertise areas because the in-domain cases are well understood.
(plus I guess your tool is has real potential for web devs, but will be
too limited for specialty areas).
> I was wondering/hoping to be able to satisfy both use cases in a
> single view. Eg. if each JS compartment cannot be shared between
> multiple tabs, it's reasonable to have a structure like this:
> - TabA
> - compartmentA1
> - compartmentA2
> which satisfies a user (per-tab info is there) and also a developer
> (the compartments, which reflect the internal architecture, are
Yes, but this arrangement has the flaw that developers don't understand
how compartments are related to their code. We don't create
compartments, we don't see them.
> But it sounds like there's more things shared across tabs (eg. images)
> than I thought. So satisfying both kinds of user with about:memory
> may be difficult.
Since your goal is to blame particular web sites, just count the images
against all sites that use them. No one says the totals have to add up.
and record the process memory values at the switch points. Presto,
divide-and-conquer for memory.
> On 6/16/2011 5:07 PM, Nicholas Nethercote wrote:
>> This relates to the multiple use cases that I talked about. You're
>> focussing on the developer case.
> Because developers are the ones who can and will use the information. Look
> at what happened with the Firebug Net panel, YSlow, Google page speed, etc:
> now there is a whole industry built around load performance.
I think for Web developers we clearly want per-document (or per-DOM-window,
they're mostly equivalent here) data. Finer granularity is neither feasible
nor needed. So any infrastructure and APIs should be built around
How we present the UI is another matter. I can definitely see per-tab usage
being useful to expose to users --- lots of non-developers use Task Manager
to see what's hogging their system, and killing off hoggy Web pages is
something that we should facilitate for normal users. But we can easily
compute per-tab information by aggregating per-document stats.
Can we? My impression from this thread was that we can't, eg. because
images are shared between tabs, and other sharing.
You're worried about double-counting resources that are shared across
multiple documents in the same tab?
That is a tough one, but I don't know how big a problem it would be in
The "explicit allocations" tree in about:memory (the version in FF6)
assumes no memory is double-counted and gives bogus results if it is.
Several cases of double-counting have been reported and fixed.
Now, we could present per-tab information through another channel, one
where overlaps could be tolerated. But that won't happen any time
Dream on. We know that this is just not true, we have found memory usage
improvements in our own code time and again. And sometimes it's not
trivial to find out why or where you used more memory than wanted,
And I know more educated users who want to know what Firefox is using
all that memory for than I know web developers, let alone those who are
concerned about their memory use. Those vocal, technical users are very
often those who tell web developers to actually look into the amount of
memory they're using.
Note that any statements of mine - no matter how passionate - are never
meant to be offensive but very often as food for thought or possible
arguments that we as a community should think about. And most of the
time, I even appreciate irony and fun! :)
I don't think that's a huge problem. All modern operating systems have this
sharing, and people still manage to use process managers to reasonable
Put another way, I look forward to you creating for us the problem that our
memory accounting is too thorough, and that we therefore need to solve this
Sounds like the solution will be the same too: "Private" and "Shared".
Firefox (at least the mobile version) could avoid keeping loaded (and/or
decoded) images that are not inside the view port of the page that uses
them. Would be interesting to see how much that would help.
Re-downloading on scroll would be a terrible user experience, IMO, but
just decoding again would be a good idea. We do it in Firefox 4. :-)
> On Fri, Jun 17, 2011 at 1:46 PM, Jean-Marc Desperrier <jmd...@gmail.com>
> > Firefox (at least the mobile version) could avoid keeping loaded (and/or
> > decoded) images that are not inside the view port of the page that uses
> > them. Would be interesting to see how much that would help.
> Re-downloading on scroll would be a terrible user experience, IMO, but
> just decoding again would be a good idea. We do it in Firefox 4. :-)
We do? I thought all of the images on the current tab were locked and not
subject to discarding.
You are correct, thank you.
It depends on which Firefox 4 you're talking about, no? Desktop and
mobile have somewhat different behavior here.
https://bugzilla.mozilla.org/show_bug.cgi?id=660577 is related to that.
Actually bug 573583, enable decode-on-draw, has not landed yet (has
been causing regression)
Comment 6 on it is very much what I was thinking.
This would have the neat side-effect that we could also use this data
for crash reporting to more accurately blame the correct URL...
To be clear, landing bug 573583 should not have the "decode-on-draw"
functionality that most people expect it to have. As currently
formulated, "decode on draw" being turned on simply means that when you
open background tabs, the images on those tabs won't be decoded until
you bring that tab to the foreground, at which time all the images
visible on it will be decoded.
So, comment 6 seems to me to contain some good idea (even if experience
may show it doesn't actually work so well), will there be a specific bug
to test that sort of thing ?
> at which time all the images visible on it will be decoded.
You mean all the images referenced from it ? What does "visible" mean in
this context ?
>> at which time all the images visible on it will be decoded.
> You mean all the images referenced from it ? What does "visible" mean in
> this context ?
At minimum all the images *drawn* (that is, the ones currently in the
viewport) will be decoded. I still need to check whether *all* the
images referenced on the webpage will be decoded at that time, so I made
a more restricted statement.
Given the success of per-compartment memory accounting (see
https://bugzilla.mozilla.org/show_bug.cgi?id=668871 for details ) I
think per-compartment CPU accounting is a great place to start.
billm had a copy of shaver's code and it's attached to the newly filed
https://bugzilla.mozilla.org/show_bug.cgi?id=674779, if anyone's
feeling inspired to take it on.