In this study, we show
Here, we present a detailed analysis of the performance of some of the most popular adblockers and content-blocker engines: uBlock Origin, Adblock Plus, Brave, DuckDuckGo and Cliqz/Ghostery's advanced adblocker (shipped since Ghostery 8), which we will refer to as Ghostery for the rest of the article.
This study was motivated by the recent Manifest V3 controversy. One of the proposed changes involves crippling the WebRequest APIs to limit their blocking abilities.
Two justifications were put forth: one related to performance and another related to privacy. The privacy argument deserves its own separate analysis and will not be covered here.
In this study, we show that the performance argument does not hold. Our comparison demonstrates that the most popular content-blockers and adblockers are already very efficient (having a sub-millisecond median decision time per request) and should not result in any overhead noticeable by users.
We showed in another study The Tracker Tax that blocking ads and trackers actually reduces the loading time of websites by up to a factor of 2. Besides, efficiency is continuously improved and technologies such as WebAssembly will enable further optimizations.
This comparison does not involve full extensions, but instead focuses on network request-blocking engines. This is the most CPU-intensive task performed by content-blockers (in particular, this does not account for cosmetics engines or subscription management).
Here are the home pages for all content-blockers compared:
We did not include native blockers from Chromium and Safari projects as this would require some significant effort to package them in a way that allows benchmarking against the other libraries. We leave this for future work.
All benchmarks were run on an X1 Carbon 2016 (i7 U6600 + 16 GB) in Node.js 11.9.0. Memory measurements were performed in Google Chrome version 72.0.3626.96 using the memory snapshot tool.
Before presenting the detailed analysis of the results, let us highlight our findings in a nutshell:
All content-blockers except DuckDuckGo have sub-millisecond median decision time per request.
Time to Process a Request in Ghostery (median): 0.007 ms
Loading Ghostery's Blocking Engine (from cache): 0.03 ms
Memory Consumption of Ghostery's Blocking Engine (at startup, in Chrome): 1.8 MB
To measure the performance of each adblocker, we replayed requests from popular domains and tracked the time it took to decide if they should be blocked or not.
We then analyzed the results in three different ways: all requests, blocked only and not blocked (taken from the same run).
The dataset was created using a pool of Chrome
headless browsers (driven by the
to visit home pages of the top 500 domains (as reported by Cliqz
Search). Up to 3 pages of each domain (picked randomly from
the home page) and all the network requests seen (URL, frame
URL and type) were also collected.
The dataset was shuffled in such a way that the different pages were visited in a random order, but requests seen on each page were replayed as they were recorded initially.
For the purpose of this comparison, we consider that each network request can be either blocked or allowed by the content-blocker; we call the process of deciding whether a request should be blocked or not: matching.
We observed that from our dataset, only ~19.2% are blocked (average across all content-blockers).
This observation suggests that content-blockers will perform better on average if they can efficiently decide which requests to not block.
The filters used to determine whether or not a request is to be blocked are the ones from Easylist, where we removed all the cosmetic rules before running the benchmarks. The final list contains 38978 network filters and is available here: easylist.txt.
It should be noted at this point that a larger proportion of requests would be blocked by enabling extra filters lists such as EasyPrivacy.
We first look at all of the requests (whether they will eventually be blocked or not).
We use a log scale for the x-axis (time in milliseconds) to facilitate the comparison of the cumulative distribution of the time it takes for adblockers to decide whether or not a request should be blocked.
Here is a break-down of the 99th percentile and median times for each content-blocker:
|99% OF REQUESTS
|0.124ms (2.5x slower)
|0.017ms (2.7x slower)
|0.103ms (2.1x slower)
|0.019ms (2.9x slower)
|1.288ms (25.9x slower)
|0.041ms (6.3x slower)
|12.085ms (242.5x slower)
|8.270ms (1258.4x slower)
Below you can find the cumulative distribution plots of these timings:
The following table details 99th percentile and median timings for requests not blocked:
|99% OF REQUESTS
|0.112ms (2.3x slower)
|0.018ms (2.8x slower)
|0.105ms (2.2x slower)
|0.020ms (3.1x slower)
|1.270ms (26.2x slower)
|0.038ms (5.9x slower)
|11.190ms (230.5x slower)
|6.781ms (1060.5x slower)
The following table details 99th percentile and median timings for requests blocked:
|99% OF REQUESTS
|0.165ms (3.1x slower)
|0.016ms (2.2x slower)
|0.099ms (1.9x slower)
|0.014ms (1.9x slower)
|1.468ms (28.0x slower)
|0.062ms (8.5x slower)
|13.025ms (248.5x slower)
|8.31ms (1130.6x slower)
On these graphs, we observe a plateau for Adblock Plus, Brave and Duckduckgo.
This can be explained by the fact that these engines implement some form of caching internally, thus having a very fast response time for some requests (redundancy in requests comes from both common third parties seen on multiple websites as well as the fact that we load several pages for each domain).
This caching can be implemented on top of any content-blocker and does not tell much about the efficiency of each. We can see this as a means to trade memory against CPU usage.
From the previous measurements, we see that Ghostery outperforms other libraries in terms of matching speed. Without going into too many details, here are some of the optimizations which can explain these results:
In this section, we have a look at the performance of content-blockers when it comes to serializing their internal representation for faster subsequent loading.
Only DuckDuckGo's engine does not provide this feature. uBlock Origin, Ghostery, Adblock Plus and Brave all allow to serialize or cache (uBlock Origin's terminology is: selfies) the entire blocking engine to either a string or a buffer, which can then be used to speed-up subsequent loads.
As this is a one-time operation, having a higher loading time does not impact desktop users significantly. On the other hand, the ability to quickly initialize the content-blocker is critical on mobile.
Another use-case allowed by such capability is to perform the parsing of the lists on the backend and ship the serialized form of the content-blocker to clients directly. This removes the cost of initialization completely.
We performed 100 serializations for each content-blocker and display the results below:
This bar plot contains the median time taken to serialize the engine for each content-blocker:
Similarly, we measure the time it takes to restore the content-blocker from its serialized form:
And here is the median time:
Last but not least, we measured the size of the serialized buffer for each content-blocker:
From these measurements, we see that Ghostery offers both significantly faster serialization and deserialization times as well as a smaller cache size.
The reason is the following:
* The internal representation is already
mostly stored in a compact form (using typed arrays).
* This means that serialization only adds a small amount of metadata
alongside the already available arrays. Deserialization is
essentially instantaneous since it's enough to create some typed array
views on top of the serialized buffer (think of
mmap but using typed
* This also explains the very low memory consumption: after
initialization, the memory footprint is only slightly higher than the size
of the serialized form.
Here, we consider the memory usage of each content-blocker, initialized from lists (not from cache) after one full garbage collection.
The measurements were performed using Chrome's devtools memory snapshot. We did not measure Brave here since the memory used from C++ side does not seem to be taken into account in the snapshot. Keep in mind that this memory usage can vary at run-time as content-blockers might cache frequently used resources, etc.
As mentioned in the previous section on serialization, the very low memory usage of Ghostery can be explained by the fact that the internal representation mostly consists of very compact typed arrays with some small overhead for extra meta-data.
Again, we need to stress here that this measures the network filtering engine of Ghostery only, not the full extension, as described in the introduction.
In this graph, we present the time it takes for each content-blocker to be initialized from the lists (without any prior caching, which means initializing all internal resources by parsing the raw list).
We see that only Brave seems to be significantly slower and that uBlock Origin, Ghostery, Adblock Plus and DuckDuckGo all perform well.
It seems that the long parsing time for Brave is a known issue tracked on their GitHub repository.
If we remove Brave, we see that there are still differences between uBlock Origin, Ghostery, Adblock Plus and DuckDuckGo. One reason Ghostery is slower than uBlock Origin and AdblockPlus here is that to achieve maximum performance while matching as well as minimize memory usage, there is a bit more work to do up-front.
In practice, this does not matter so much since it is a one-time operation and subsequent loads are performed from cache. This is really fast. In fact, we can even perform the parsing backend-side and just ship the serialized version of the blocker, which removes this step completely.
In this study, we looked closely at the performance of some of the most popular content-blockers in use today. In particular, we focused on the efficiency of their network filtering engines, which is the most CPU intensive task they perform.
We hope these benchmarks will give content-blocker developers the opportunity to measure their own progress against other popular libraries. This will benefit all users, no matter which extension they use, as the efficiency of content-blockers improves.
Edit of 20-02-2019: The study has been updated with the specific version of each content-blocker measured.
Edit of 15-03-2019: DuckDuckGo's description has been amended to more accurately describe the way their content-blocker is used in practice: focusing on blocking third-party trackers, but not ads.