Avoid blocking AsyncOpen on URL classification for annotation-only features
Categories
(Core :: Privacy: Anti-Tracking, task)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox152 | --- | fixed |
People
(Reporter: acreskey, Assigned: bvandersloot)
References
(Blocks 1 open bug)
Details
Attachments
(11 files, 1 obsolete file)
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
Bug 2030021, part 7 - Allow network request to proceed while annotating trackers - r=#anti-tracking!
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
327.71 KB,
image/png
|
Details | |
|
414.20 KB,
image/png
|
Details |
I don't have a deep understanding of our URL classification requirements, but I'm wondering whether or not we need to classify first party sub resources.
Each classification that's not short circuited dispatches to the URL Classifier background thread for table lookups, then dispatches back to the main thread to proceed with the connection.
This profile shows the first party subresource runnables being processed on the URL classifier thread (www.amazon.ca navigation).
https://share.firefox.dev/4cbvJbF
Numerous verbose URL classification markers added.
Binary here.
I can see that Content Classifier Engine exits early on first party subresources. (comment does not match code).
(although the runnables have already been created and dispatched to the URL classifier thread).
While AsyncChannelClassifier::FeatureTask::DoLookup() is processing the requests.
https://searchfox.org/firefox-main/rev/187dc6baf299450446944dc90ba2239913004ba8/netwerk/url-classifier/AsyncUrlChannelClassifier.cpp#732-749
If we could indeed skip classification of first party sub resources it would reduce the number of runnables, thread hops, and to some degree, latency.
| Reporter | ||
Comment 1•3 months ago
|
||
Tim, Benjamin, Emma - per our discussion, would you be able to confirm if we need to run the async url classification on first party sub resources?
As far as I can tell, for Safebrowsing we already skip sub resources in NS_ShouldClassifyChannel().
And the Content Classifier only runs on third party resource classification.
So, at least though NS_ShouldClassifyChannel(), I believe it's only the NS_ShouldClassifyChannel(this, ClassifyType::ETP) calls in nsHttpChannel::AsyncOpenFinal that are creating the async url classifications for first party sub resources.
Comment 2•3 months ago
|
||
In the current implementation, we skip creating URLClassifier blocking features for first-party sub-resources. However, we still need to run the URL classification on them for annotation. We also annotate first-party tracking flags, but I don't think any privacy feature uses them; perhaps some UI code does. I need to double check.
So, I think we can not block AsyncOpen for first-party sub-resources and annotate in a later loading phase.
| Assignee | ||
Comment 3•3 months ago
|
||
Unfortunately, UrlClassifierFeatureHarmfulAddonProtection is not third-party only. Though, maybe that is an acceptable restriction? @baku: do you know if this is the case, or have thoughts on this perf improvement?
Comment 4•3 months ago
|
||
The harmful add-on protection blocks first-party requests generated by add-ons. A better approach would be to ask the URL-Classifier features if asyncOpen must be blocked or not. For annotation features maybe the answer is no. For the harmful add-on feature, it can check if the request comes from an extended principal.
Updated•3 months ago
|
| Reporter | ||
Comment 5•2 months ago
|
||
Thank for you input -- I've renamed the bug to make it more specific. Feel free to modify it.
| Reporter | ||
Comment 6•2 months ago
•
|
||
In terms of performance impact, there could be measurable improvements, depending on how the site was structured and hosted.
This try push adds a series of url classification markers including one, [UrlClassify] WaitTime that reports how long we waited for classification.
On www.apple.com I see a series of first party critical resources like .css and fonts that generally wait a few ms, up to 6ms for the longest one.
Not huge delays individually, but in total it adds up.
https://share.firefox.dev/4ck3zez
| Reporter | ||
Comment 7•2 months ago
|
||
Loading www.ikea.com on Fenix is a good example of a top site we could make faster if we could defer annotations for first party subresources:
https://share.firefox.dev/47WJ2vj
I can see about 18 early resources that each wait over 20ms, and about 15 resources that wait between ~10ms to 19ms
I imagine that the improvement from skipping the blocking would be roughly equal to the duration of the longest classification delay for a critical resource.
So probably something like 27ms-28ms for this navigation (on my Samsung A54), based on the delays for these resources:
Livingrrom_16, 28.0ms
PAX_startpage_poster, 27ms
| Assignee | ||
Comment 8•2 months ago
|
||
Yeah, this should be a nice addition. We are working on some major revisions to the channel classifier already, but I'm willing to put the time in now to fix this in the pre-revision state and make sure we don't regress it going forward. This isn't just a few lines of diff, but it should be alright.
I'm planning to add a boolean member function to all of the classifier rules that says whether it may block the channel. Then only grab those ones in the existing AsyncOpen callsite. The rest of them I will kick off async further down the connection initialization. I know the Safebrowsing classification suspends the channel in BeginConnect and resumes it after classification, so maybe something of that structure would be good. I wonder if that is also blocking the request's progress before we send headers.
| Reporter | ||
Comment 9•2 months ago
|
||
(In reply to Benjamin VanderSloot [:bvandersloot] from comment #8)
Yeah, this should be a nice addition. We are working on some major revisions to the channel classifier already, but I'm willing to put the time in now to fix this in the pre-revision state and make sure we don't regress it going forward. This isn't just a few lines of diff, but it should be alright.
I'm planning to add a boolean member function to all of the classifier rules that says whether it may block the channel. Then only grab those ones in the existing AsyncOpen callsite. The rest of them I will kick off async further down the connection initialization. I know the Safebrowsing classification suspends the channel in BeginConnect and resumes it after classification, so maybe something of that structure would be good. I wonder if that is also blocking the request's progress before we send headers.
Great news -- I'm happy to help quantify the impact of any possible solutions :)
| Assignee | ||
Comment 10•2 months ago
|
||
For posterity:
I wonder if that is also blocking the request's progress before we send headers.
it does not- suspension doesn't seem to stall the channel before OnStartRequest (when we have data from the server)
| Assignee | ||
Comment 11•2 months ago
|
||
This is early WIP soon, and is likely to change.
- I don't like exactly how the refactor shook out.
- We need to make sure that suspending a channel in OnBeforeConnect
allows the channel to send data before its resumption. - I need to double check the logic in the new annotation-only path in
SerialChannelClassifier - Annotations from the new engine should be moved over too
| Assignee | ||
Comment 12•2 months ago
|
||
Updated•2 months ago
|
| Assignee | ||
Comment 13•2 months ago
|
||
| Assignee | ||
Comment 14•2 months ago
|
||
| Assignee | ||
Comment 15•2 months ago
|
||
| Assignee | ||
Comment 16•2 months ago
|
||
| Assignee | ||
Comment 17•2 months ago
|
||
| Assignee | ||
Comment 18•2 months ago
|
||
| Assignee | ||
Comment 19•2 months ago
|
||
| Assignee | ||
Comment 20•2 months ago
|
||
Updated•2 months ago
|
| Reporter | ||
Comment 21•2 months ago
|
||
I was watching this bug with the intention of jumping in and adding telemetry to measure the classification time but it looks like you've already done that Benjamin. :)
| Assignee | ||
Comment 22•2 months ago
|
||
Glad to take it off your plate. Feel free to give a drive by review if you have any different measurements!
Comment 23•2 months ago
|
||
Comment 24•2 months ago
|
||
| bugherder | ||
https://hg.mozilla.org/mozilla-central/rev/f7c35b75ca12
https://hg.mozilla.org/mozilla-central/rev/9cc558447e22
https://hg.mozilla.org/mozilla-central/rev/287bc0c6367f
https://hg.mozilla.org/mozilla-central/rev/3eb414679ebd
https://hg.mozilla.org/mozilla-central/rev/9647c9aeda78
https://hg.mozilla.org/mozilla-central/rev/462e30702d71
https://hg.mozilla.org/mozilla-central/rev/10817c138761
https://hg.mozilla.org/mozilla-central/rev/5929a4c1ff93
https://hg.mozilla.org/mozilla-central/rev/b429e06cdf71
Updated•1 month ago
|
| Reporter | ||
Comment 25•1 month ago
|
||
Ni' myself to see if I can get some early measurements of impact potential from this.
| Reporter | ||
Comment 26•1 month ago
|
||
The newly-landed annotation deferral system is currently disabled in nightly: privacy.trackingprotection.defer_annotation.enabled
Looking at the probe that now tracks the entire classification time, glam: urlclassifier_check_channel_helper_time we can see that classification time is longer on Android, as expected.
Custom query: Fenix, urlclassifier_check_channel_helper_time time in ms
There is significant delay in later percentiles (ms)
e.g.
p_50 p_75 p_80 p_90 p_95 p_99
2.72 5.44 7.05 12.94 23.73 103.50
On desktop, the problem looks to be mostly at the tail
Custom query: Desktop, urlclassifier_check_channel_helper_time time in ms
p_50 p_75 p_80 p_90 p_95 p_99
0.96 1.05 1.36 3.23 7.69 47.45
I'll capture Fenix profiles with privacy.trackingprotection.defer_annotation.enabled enabled and disabled and share them here.
But we could consider simply enabling the feature, or else running a Nimbus experiment to measure impact.
Gecko pref-flip experiments on Android no longer require all the of additional plumbing of the past.
| Reporter | ||
Comment 27•1 month ago
|
||
This Navigation PerfCompare adds a temporary PerfStat, mirroring the new glean probe check_channel_helper_time to see if we can detect a change from enabling privacy.trackingprotection.defer_annotation.enabled on our CI tests. (will take some days to resolve).
| Assignee | ||
Comment 28•1 month ago
|
||
I was working on some of this code for another bug and came to a realization: the check_channel_helper_time is capturing a fair bit of extra work.
The callbacks (incl. task->CompleteClassification(), which is the enabled path) are non-trivial.
Additionally we are capturing data on both the initial and deferred (non-blocking) classification.
I'm going to add a dependent bug to fix these issues on top of the bug I was working on (merge conflicts will abound). We probably will have some signal without this patch, but it definitely will be much cleaner after.
| Reporter | ||
Comment 29•1 month ago
|
||
Thanks for the update, Benjamin. I'll keep an eye on bug 2043215.
In my current CI test where I enabled privacy.trackingprotection.defer_annotation.enabled I am generally seeing a huge regression in overall check_channel_helper_time (up to 90%!) -- maybe because of the time capturing issue?
Perf Compare
Related, this PerfStat for check_channel_helper_time might be worth landing
https://hg-edge.mozilla.org/try/rev/6981d626474d756dd31a8263c05d4ebf966827e4
| Assignee | ||
Comment 30•1 month ago
|
||
(up to 90%!)
Ouch! I don't think the fix to reduce noise would revert a performance regression if it is real.
The regression might be noise, but it also might be additional thread contention causing a performance degradation! I think we should revisit this once bug 2043215 lands. If there is still a degradation, we should pull out privacy.trackingprotection.defer_annotation.enabled and see if there is a different implementation approach that doesn't induce the thread contention.
| Reporter | ||
Comment 31•1 month ago
|
||
A new PerfCompare showing the impact of enabling privacy.trackingprotection.defer_annotation.enabled on check_channel_helper_time in our Android CI pageload tests.
Jobs still running but looks very promising. Of course it's a new metric, so we will have to see.
| Reporter | ||
Comment 32•1 month ago
|
||
Benjamin, the CI results of privacy.trackingprotection.defer_annotation.enabled look really good.
Picking two examples from the PerfCompare, (privacy.trackingprotection.defer_annotation.enabled as the new):
bing-search-restaurants perfstat-UrlClassifierCheckChannel, Android a55
From 67.91ms total channel classification time to 1.4ms
a 97.93 % Improvement
bild-de
From 266.38 ms total channel classification time to 104.28 ms
A -60.85 % Improvement of about 160ms.
The distributions look very solid [attached].
| Reporter | ||
Comment 33•1 month ago
|
||
| Reporter | ||
Comment 34•1 month ago
|
||
| Reporter | ||
Comment 35•1 month ago
•
|
||
If the privacy.trackingprotection.defer_annotation.enabled feature is ready, my suggestion would be to run a Nimbus pref-flip experiment on Android to better quantify field impact. As I was saying, these experiments no longer require extensive geckoview/fenix plumbing and I'm happy to help set it up and kick it off.
Alternatively, the pref could be landed enabled and we can try to observe impact (noting that nightly is very busy at the moment with happy eyeballs v3 changes landing).
| Assignee | ||
Comment 36•1 month ago
|
||
The feature is ready for experimentation in my view. I only wonder if these changes show up in less-specific metrics.
I think running an A/B experiment would be wise. And I would be interested to see what desktop does as well. But if Android is where you expect sensitivity, I'm here for just testing there. I'd just want to ship them together to keep the complexity down.
| Reporter | ||
Comment 37•1 month ago
|
||
So far I would say that I'm seeing more signal of improvement on Android, and mostly on lower level timings like classification and overall network timings like HttpChannelAsyncOpenToTransactionPending.
However the PerfCompare did pickup significant improvements to document load time on two sites:
amazon loadtime
Android a55
1,161.56 ms > 1,111.14 ms
-4.822 % Improvement
bing-search-restaurants loadtime
Android a55
329.88 ms > 295.46 ms
-3.943 % Improvement
I'll see if anything can observed in a local run.
Changes on MacOS look very modest (no Perfstats in this run, unfortunately)
PerfCompare
And we will have Windows numbers with Perfstats likely today.
(In reply to Benjamin VanderSloot [:bvandersloot] from comment #36)
The feature is ready for experimentation in my view. I only wonder if these changes show up in less-specific metrics.
I think running an A/B experiment would be wise. And I would be interested to see what desktop does as well. But if Android is where you expect sensitivity, I'm here for just testing there. I'd just want to ship them together to keep the complexity down.
Let me get some experiments ready then - we can do Desktop & Android simultaneously.
| Reporter | ||
Comment 38•1 month ago
•
|
||
On a test of lives sites in Fenix, we see statistically significant improvements to the time spent blocking channels during classification:
Looking at the new Perfstat, UrlClassifierCheckChannel
(baseline β defer_annotation, median ms)
| Site | Baseline | defer_annotation | Ξ | Significant |
|---|---|---|---|---|
| bing obama | 781 | 2 | β99.7% | yes (p=0.0000) |
| bing restaurants | 590 | 2 | β99.7% | yes (p=0.0000) |
| ikea | 420 | 7 | β98.3% | yes (p=0.0000) |
| ikea outdoor | 2563 | 233 | β90.9% | yes (p=0.0000) |
| en.wikipedia Elvis | 43 | 6 | β86.0% | yes (p=0.0000) |
| wiki Mozilla | 49 | 11 | β77.6% | yes (p=0.0000) |
| cnn | 47 | 11 | β76.3% | yes (p=0.0000) |
| bild.de_ | 817 | 473 | β42.2% | yes (p=0.0000) |
| bild royals article | 369 | 408 | +10.7% | no (p=0.47) |
From the 9 urls that I checked, we picked up significant and reproduced improvements to a wikipedia page:
https://en.wikipedia.org/wiki/Elvis_Presley
en.wikipedia (Elvis)
| Metric | Baseline | defer_annotation | Ξ | p |
|---|---|---|---|---|
| SpeedIndex | 1259 | 1237 | β1.7% | 0.0127 |
| ContentfulSpeedIndex | 886 | 856 | β3.4% | 0.0204 |
| PerceptualSpeedIndex | 1340 | 1298 | β3.1% | 0.0047 |
| FirstVisualChange | 848 | 799 | β5.7% | 0.0111 |
| LastVisualChange | 1724 | 1659 | β3.8% | 0.0138 |
| VisualComplete85 | 1615 | 1566 | β3.0% | 0.0075 |
| VisualComplete95 | 1704 | 1633 | β4.2% | 0.0048 |
| FCP | 826 | 772 | β6.5% | 0.0189 |
| LCP renderTime | 826 | 780 | β5.6% | 0.0304 |
All metrics reported here in google sheets.
| Reporter | ||
Comment 39•1 month ago
|
||
I'll wait until the newly-added jobs complete before I summarize, but the Windows CI run has picked up improvements to URL classification delays as well as to higher order metrics user facing metrics including fcp and lcp.
Fenix and Desktop experiments are being put together, tentatively targeting a start date of Nightly, June 15th, 2026
| Reporter | ||
Comment 40•1 month ago
|
||
Enabling privacy.trackingprotection.defer_annotation.enabled is showing improvements via our Windows CI navigation tests.
PerfCompare
UrlClassifierCheckChannel perfstat, URL classification delays is reduced:
| Suite | Variant | BaseβNew (ms) | Ξ |
|---|---|---|---|
| cnn | cold | 47.4 β 2.1 | β95.6% |
| cold | 61.1 β 49.9 | β18.3% | |
| warm | 49.1 β 40.9 | β16.8% | |
| amazon | cold | 861.7 β 745.3 | β13.5% |
And we see broad cold-load user-facing improvements across sites
| Suite | Metric | BaseβNew (ms) | Ξ |
|---|---|---|---|
| cnn-nav.landing | FirstVisualChange | 731.96 β 711.80 | β4.63% |
| fcp | 72.87 β 66.96 | β4.62% | |
| microsoft | largestContentfulPaint | 348.39 β 342.15 | β1.74% |
| paypal cold | fcp / largestContentfulPaint | 185.07 β 182.20 ms | β2.19% |
| paypal warm | fcp / largestContentfulPaint | 70.91 β 69.45 ms | β2.86% |
| facebook-nav.marketplace | SpeedIndex | 386.99 β 385.39 | β2.71% |
| facebook-nav.marketplace cold | largestContentfulPaint | 530.91 β 521.32 ms | β1.98% |
| facebook-nav.marketplace | loadtime | 563.83 β 549.07 | β2.68% |
| fcp / fnbpaint | 270.5 β 264.9 | β1.13% |
wikipedia cold showed mixed results, but given the broad improvements I don't think it's an issue.
| Metric | Variant | BaseβNew | Ξ (MWU) |
|---|---|---|---|
| HttpChannelCompletion (Network) | cold | 29237 β 27398 ms | β7.7% |
| loadtime | cold | 649.3 β 587.9 ms | β3.7% |
| fcp / fnbpaint | cold | 320.9 β 333.8 ms | +4.5% |
| largestContentfulPaint | cold | 331.8 β 343.9 ms | +5.0% |
| Reporter | ||
Comment 41•17 days ago
|
||
Nightly desktop and fenix experiments are underway.
This dashboard tracks the data as it arrives (sorry, requires mozilla SSO)
Benjamin, just to be sure, can you confirm that with privacy.trackingprotection.defer_annotation.enabled I should expect to see fewer submissions of the probe glean::urlclassifier::check_channel_helper_time?
In AntiTrackingChannelClassifierUtils::CheckChannelHelper. (To my understanding because we frequently skip the blocking task).
| Assignee | ||
Comment 42•16 days ago
|
||
Benjamin, just to be sure, can you confirm that with privacy.trackingprotection.defer_annotation.enabled I should expect to see fewer submissions of the probe glean::urlclassifier::check_channel_helper_time?
Yes, that would be expected. Since Bug 2043215's cleanup we don't measure the deferred annotation in the glean probes, so it we are only measuring the blocking urlclassifier queries. If there is no chance to block, we skip it.
| Reporter | ||
Comment 43•16 days ago
|
||
Excellent, thank you.
So far I am seeing that the trend of improvements to url classification delays we observed in CI and in live site performance tests is playing out in both Firefox desktop and Fenix nightly populations via the experiment.
Dashboard - Defer URL Classification Annotation Experiment
Time spent waiting on URL classification, per client day, P75
Desktop: from ~84 seconds to ~40 seconds with deferred URL annotation
Fenix: ~27 seconds to ~13 seconds with deferred URL annotation
All data is preliminary
I think we would have to walk this experiment out to Release in order to look for broad improvements to higher order metrics like FCP and LCP. Happy to do so, as cloning and re-running experiments is very easy to do.
In the meantime, I think we should add a bug to enable this change by default since from everything I see we want to get this out to users as soon as possible.
| Assignee | ||
Comment 44•15 days ago
|
||
That's pretty remarkable, especially when you include the ~50% reduction in probes. P75 in the control is more fairly compared to P50 in the treatment.
Yeah, let's walk this out to release. We should also see if we can validate that our tracker annotation counts are not different between the branches before we pick a winner.
I'll file a bug blocked by this one to turn this on :)
Updated•5 days ago
|
Description
•