Add a tab turtle(!) API

RESOLVED WORKSFORME

Status

()

RESOLVED WORKSFORME
3 years ago
3 years ago

People

(Reporter: Ehsan, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

(Reporter)

Description

3 years ago
We're trying to build some kind of UI that shows you when a tab is being slow.  One idea is to paint a turtle in the tab when it becomes slow.  Another one is modify its color (for example going from pink to red as the tab keeps being slow) or an OSX Activity Monitor like icon that appears when the tab becomes slow.

We came up with a rough sketch of what the API would look like in a meeting today.  I'll try to summarize.

tab.registerSlowCallback()
This would let you register a callback that will fire every time that the tab becomes "slow".

tab.unregisterSlowCallback()
Called when we are no longer interested in the above callback.

tab.startGatheringPerformanceData()
Called when the caller is interested in polling the tab for periodical performance data such as CPU usage

tab.stopGatheringPerformanceData()
Signals that we're no longer interested in the above data.

tab.getPerformanceData()
Would throw if startGatheringPerformanceData() is not called, otherwise would return the last measured CPU time/etc. for the tab.

Benoit, Yoric, please let me know if I didn't capture everything correctly.
r+, where tab is the 'browser' object.

If we don't want to add these to the browser objectfor some reason then we could just replace 'tab.*' with PerfAPIThing.registerSlowCallback(tab, cb), PerfAPIThing.unregisterSlowCallback(tab, cb), etc...
From JSAPI, we want to be able to trigger an async callback with a list of PerformanceGroup that have been marked at slow. The issue here is that the JSAPI cannot extract itself the necessary data to identify a PerformanceGroup to a tab (or addon, etc.), so we need to somehow pass the JSContext to XPCOM world to have XPCOM identify it. The real difficulty is that storing a JSContext for future use is not trivial, as JSContext is generally handled by the SpiderMonkey GC. So either I define a nice GC-friendly data structure for storing JSContext or I somehow pass the JSContext to XPCOM earlier, possibly before we even know that something is slow, for identification purposes, and store it somewhere nice and also GC-friendly.

Once we have that, defining `registerSlowCallback`/`unregisterSlowCallback` should not be too difficult.
No longer depends on: 1186491
(Reporter)

Comment 3

3 years ago
(In reply to Benoit Girard (:BenWa) from comment #1)
> r+, where tab is the 'browser' object.
> 
> If we don't want to add these to the browser objectfor some reason then we
> could just replace 'tab.*' with PerfAPIThing.registerSlowCallback(tab, cb),
> PerfAPIThing.unregisterSlowCallback(tab, cb), etc...

Yeah, sorry, I meant browser everywhere I said tab.  :-)

(In reply to David Rajchenbach-Teller [:Yoric] (use "needinfo") from comment #2)
> From JSAPI, we want to be able to trigger an async callback with a list of
> PerformanceGroup that have been marked at slow. The issue here is that the
> JSAPI cannot extract itself the necessary data to identify a
> PerformanceGroup to a tab (or addon, etc.), so we need to somehow pass the
> JSContext to XPCOM world to have XPCOM identify it. The real difficulty is
> that storing a JSContext for future use is not trivial, as JSContext is
> generally handled by the SpiderMonkey GC. So either I define a nice
> GC-friendly data structure for storing JSContext or I somehow pass the
> JSContext to XPCOM earlier, possibly before we even know that something is
> slow, for identification purposes, and store it somewhere nice and also
> GC-friendly.

Hmm, you should be able to use something like <https://dxr.mozilla.org/mozilla-central/source/js/xpconnect/src/xpcpublic.h#475> to get an nsGlobalWindow from a JSContext.  This will work for normal JS running in a page.  There are similar helpers for add-ons too, and I think we're not worrying about workers right now.  bholley should be able to help you find the best solution here.
> Hmm, you should be able to use something like <https://dxr.mozilla.org/mozilla-central/source/js/xpconnect/src/xpcpublic.h#475> to get an nsGlobalWindow from a JSContext.  This will work for normal JS running in a page.  There are similar helpers for add-ons too, and I think we're not worrying about workers right now.  bholley should be able to help you find the best solution here.

I'm not worried about that part. The difficulty is in either keeping the JSContext alive until we perform an async call, or making sure that the memory that we allocate outside of the JSAPI to store information on that JSContext is cleaned up once the JSContext is garbage-collected. I think I have a way to do the latter without too much pain.
Ok, I have an early prototype of a subset of the features. For the moment, the high-level API looks like

PerformanceStats.addPerformanceListener(target, options, listener);
PerformanceStats.removePerformanceListener(target, listener);

Where
* `target` can be either `{addon: "myaddon@foobar"}`, `{tab: someXulTab}`, `{addon: "*"}` for all add-ons, `{tab: "*"}` for all tabs ;
* `options` can only be `{ jankThreshHold: numberOfConsecutiveMilliseconds }` for the moment ;
* `listener` receive an object with the addon id, the window id, the unique-to-application group id, and another value with the actual jank.

For the moment, I have implemented watching performance for addons in the parent process. Extending this to tabs and multi-process should mostly be (lots of) plumbing.

This looks like a saner foundation for the add-on watcher, although it might complicate (re)-implementing about:performance.
Also, for the moment, the PerformanceStatsService was theoretically usable from any thread. My ongoing work restricts the use to the main thread. I don't think that this is an issue.
Well, this has landed a few months ago.
Status: NEW → RESOLVED
Last Resolved: 3 years ago
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.