Below are some tests comparing the speed of the Adobe Analytics API to the Google Analytics API. To do the comparison, we’ve looked at two sites – one small and one quite large – that are both running both Adobe Analytics and Google Analytics. To keep the comparison, well, comparable, the queries stick to standard dimensions and metrics so that the “same” data is being pulled from both systems. The queries all pull for the last 365 days.

This is a test comparing the speed of the Adobe Analytics Reporting API to the Google Analytics Reporting API. A few notes about that:

The current test just runs each query once. Eventually, I may update this to run each query multiple times (and possibly try at different days of the week and times of day) to get a more robust set of data. But, I’m starting simple! I haven’t included the setup code here, as that’s a little tedious. But, I’ve tried to include all of the salient code for transparency purposes.

The Queries

This is certainly something that can be fiddled with a bit, but, for the initial test, I set up two queries:

For now, I haven’t added any segments to either query – either inline (dynamic) or named. But, that may be something to add in the future.

The functions below can then be run on different accounts to make these queries:

## COMPARISON #1: DAILY METRICS
# Adobe Analytics
daily_data_aa <- function(rsid, date_from, date_to){
  aa_data <- QueueOvertime(rsid,
                         date.from = date_from,
                         date.to = date_to,
                         metrics = c("uniquevisitors", "visits", "pageviews"),
                         date.granularity = "day")
}
# Google Analytics
# This includes the "unsampled" flag to ensure more of an apples-to-apples comparison
daily_data_ga <- function(view_id, date_from, date_to){
  ga_data <- google_analytics_4(view_id,
                                date_range = c(date_from, date_to),
                                metrics = c("users", "sessions", "pageviews"),
                                dimensions = "date",
                                anti_sample = TRUE)
}
## COMPARISON #2: DEVICE TYPE + BROWSER AGGREGATION
# Adobe Analytics
ranked_data_aa <- function(rsid, date_from, date_to){
  aa_data <- QueueRanked(rsid,
                           date.from = date_from,
                           date.to = date_to,
                           metrics = "visits",
                           elements = c("mobiledevicetype", "browsertype"),
                         top = c(25,25))
}
# Google Analytics
# This includes the "unsampled" flag to ensure more of an apples-to-apples comparison. One
# extra step is required here to get the data to come back similarly -- specifying the order.
order_ga <- order_type("sessions", sort_order = "DESCENDING", orderType = "VALUE")
ranked_data_ga <- function(view_id, date_from, date_to){
  ga_data <- google_analytics_4(view_id,
                                date_range = c(date_from, date_to),
                                metrics = "sessions",
                                dimensions = c("deviceCategory", "browser"),
                                order = order_ga,
                                anti_sample = TRUE)
}

Small Site First!

We’ll start with a small site. The first query is the daily data for 365 days. A bit of the data itself is included below to show that they two platforms return comparable results. All that is being recorded for the time is the time to actually make and retrieve the results of the query.

Adobe Analytics: Daily Trend - Small Site

# Adobe Analytics
time_daily_aa <- system.time(aa_data <- daily_data_aa(aa_rsid, start_date_year, end_date))
[1] "Requesting URL attempt #1"
[1] "Requesting URL attempt #2"
[1] "Received overtime report."
aa_data <- aa_data %>% 
  select(datetime, uniquevisitors, visits, pageviews) %>% 
  mutate(datetime = as.Date(datetime))
kable(head(aa_data))
datetime uniquevisitors visits pageviews
2016-07-12 1493 1600 2156
2016-07-13 1484 1597 2124
2016-07-14 1527 1608 2163
2016-07-15 1108 1187 1572
2016-07-16 338 365 494
2016-07-17 542 583 779

Google Analytics: Daily Trend - Small Site

# Google Analytics
time_daily_ga <- system.time(ga_data <- daily_data_ga(ga_view_id, start_date_year, end_date))
kable(head(ga_data))
date users sessions pageviews
2016-07-12 1507 1628 2188
2016-07-13 1479 1620 2126
2016-07-14 1505 1596 2132
2016-07-15 1096 1187 1589
2016-07-16 335 365 490
2016-07-17 549 598 786

This query took 13.12 seconds for the Adobe Analytics API and 1.66 seconds for the Google Analytics API.

Now, let’s pull the device type and browser data – also for a year.

Adobe Analytics: Ranked Data - Small Site

# Adobe Analytics
time_ranked_aa <- system.time(aa_data <- ranked_data_aa(aa_rsid, start_date_year, end_date))
[1] "Requesting URL attempt #1"
[1] "Requesting URL attempt #2"
[1] "Received ranked report."
# We're not counting this in the time calculation -- just making it a bit more apples-to-apples with
# Google Analytics.
  aa_data <- aa_data %>% 
    arrange(-visits) %>% 
    mutate(mobiledevicetype = ifelse(mobiledevicetype=="Other", "Desktop", mobiledevicetype)) %>%
    select(mobiledevicetype, browsertype, visits)
kable(head(aa_data))
mobiledevicetype browsertype visits
Desktop Google 284833
Desktop Microsoft 60961
Desktop Mozilla 39910
Mobile Phone Apple 16831
Desktop Apple 13570
Mobile Phone Google 13483

Google Analytics: Ranked Data - Small Site

# Google Analytics
time_ranked_ga <- system.time(ga_data <- ranked_data_ga(ga_view_id, start_date_year, end_date))
kable(head(ga_data))
deviceCategory browser sessions
desktop Chrome 284983
desktop Internet Explorer 50327
desktop Firefox 39297
mobile Safari 14351
mobile Chrome 13939
desktop Safari 13184

This query took 12.8 seconds for the Adobe Analytics API and 1.59 seconds for the Google Analytics API.

Now, A Much Larger Site

This is a much larger site – primarily an Adobe Analytics shop, but they also have Google Analytics implemented (lightly), so it suits our purposes. Again, the first query is the daily data for 365 days. We’re not going to show the code here, because it’s identical to the code above.

Adobe Analytics: Daily Trend - Large Site

[1] "Requesting URL attempt #1"
[1] "Requesting URL attempt #2"
[1] "Requesting URL attempt #3"
[1] "Received overtime report."
datetime uniquevisitors visits pageviews
2016-07-12 90375 114619 692623
2016-07-13 97333 122789 737202
2016-07-14 94911 119724 708964
2016-07-15 76312 94919 547828
2016-07-16 11084 12459 70326
2016-07-17 9013 10003 48970

Google Analytics: Daily Trend - Large Site

date users sessions pageviews
2016-07-12 92946 122265 711739
2016-07-13 99901 130705 740745
2016-07-14 97663 127825 721988
2016-07-15 78651 101623 564974
2016-07-16 11226 12812 71551
2016-07-17 9145 10250 49598

This query took 22.55 seconds for the Adobe Analytics API and 2.15 seconds for the Google Analytics API.

Now, let’s pull the device type and browser data – also for a year.

Adobe Analytics: Ranked Data - Large Site

[1] "Requesting URL attempt #1"
[1] "Requesting URL attempt #2"
[1] "Received ranked report."
mobiledevicetype browsertype visits
Desktop Microsoft 14624108
Desktop Google 13528832
Desktop Mozilla 4192844
Tablet Apple 1132420
Desktop Apple 734011
Mobile Phone Apple 298861

Google Analytics: Ranked Data - Large Site

deviceCategory browser sessions
desktop Chrome 14255211
desktop Internet Explorer 13774114
desktop Firefox 4308947
desktop Edge 1522778
tablet Safari 1174571
desktop Safari 754205

This query took 11.5 seconds for the Adobe Analytics API and 80.47 seconds for the Google Analytics API.

Results Summary

Below is a summary of the results.

Query Adobe Analytics Time (seconds) Google Analytics Time (seconds)
Small Site: Daily Trends 13.1 1.7
Small Site: Ranked Values 12.8 1.6
Large Site: Daily Trends 22.5 2.1
Large Site: Ranked Values 11.5 80.5

Google Analytics got killed on the ranked data. For a large site, and with the “anti-sampling” flag being used in the query, that is because there were many calls to the API. If the site was a GA360 site with a custom table set up, it would have come back much faster (but custom tables only go back 30 days, so, even with GA360, this may be a tough one.)

LS0tCnRpdGxlOiAiQWRvYmUgQW5hbHl0aWNzIC8gR29vZ2xlIEFuYWx5dGljcyBBUEkgU3BlZWQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkJlbG93IGFyZSBzb21lIHRlc3RzIGNvbXBhcmluZyB0aGUgc3BlZWQgb2YgdGhlIEFkb2JlIEFuYWx5dGljcyBBUEkgdG8gdGhlIEdvb2dsZSBBbmFseXRpY3MgQVBJLiBUbyBkbyB0aGUgY29tcGFyaXNvbiwgd2UndmUgbG9va2VkIGF0IHR3byBzaXRlcyAtLSBvbmUgc21hbGwgYW5kIG9uZSBxdWl0ZSBsYXJnZSAtLSB0aGF0IGFyZSBib3RoIHJ1bm5pbmcgYm90aCBBZG9iZSBBbmFseXRpY3MgYW5kIEdvb2dsZSBBbmFseXRpY3MuIFRvIGtlZXAgdGhlIGNvbXBhcmlzb24sIHdlbGwsIGNvbXBhcmFibGUsIHRoZSBxdWVyaWVzIHN0aWNrIHRvIHN0YW5kYXJkIGRpbWVuc2lvbnMgYW5kIG1ldHJpY3Mgc28gdGhhdCB0aGUgInNhbWUiIGRhdGEgaXMgYmVpbmcgcHVsbGVkIGZyb20gYm90aCBzeXN0ZW1zLiBUaGUgcXVlcmllcyBhbGwgcHVsbCBmb3IgdGhlIGxhc3QgMzY1IGRheXMuCgpUaGlzIGlzIGEgdGVzdCBjb21wYXJpbmcgdGhlIHNwZWVkIG9mIHRoZSBBZG9iZSBBbmFseXRpY3MgUmVwb3J0aW5nIEFQSSB0byB0aGUgR29vZ2xlIEFuYWx5dGljcyBSZXBvcnRpbmcgQVBJLiBBIGZldyBub3RlcyBhYm91dCB0aGF0OgoKKiBUaGlzIGlzIGZvY3VzZWQgb24gdGhlIGZyZWUgdmVyc2lvbiBvZiBHb29nbGUgQW5hbHl0aWNzOyBpbiB0aGUgY2FzZSBvZiB0aGUgbGFyZ2Ugc2l0ZSwgdGhhdCBtZWFucyBzYW1wbGluZyBjb21lcyBpbnRvIHBsYXksIGFuZCwgdG8gbWFrZSBpdCBhbiBhcHBsZXMtdG8tYXBwbGVzIGNvbXBhcmlzb24sIHRoZSBxdWVyeSB1c2VzIHRoZSBgYW50aV9zYW1wbGUgPSBUUlVFYCBmbGFnIGluIGBnb29nbGVBbmFseXRpY3NSYC4gVGhhdCdzLCBiYXNpY2FsbHksIGEgYml0IG9mIGEgaGFjayB0byB3b3JrIGFyb3VuZCBHb29nbGUgQW5hbHl0aWNzIHNhbXBsaW5nLiBUaGF0IHNob3dzIGluIHRoZSByZXN1bHRzLgoKKiBBIHNlcGFyYXRlIGNvbXBhcmlzb24gY291bGQgYmUgY29tcGFyaW5nIHRoZSBjcnVuY2hpbmcgb2YgQWRvYmUgQW5hbHl0aWNzIGRhdGEgZmVlZCBkYXRhIHRvIEdvb2dsZSBBbmFseXRpY3MgMzYwIGRhdGEgdGhhdCBoYXMgYmVlbiBwdXNoZWQgaW50byBCaWdRdWVyeS4gVGhhdCdzIHdheXl5eSBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgYXNzZXNzbWVudCwgdGhvdWdoLgoKVGhlIGN1cnJlbnQgdGVzdCBqdXN0IHJ1bnMgZWFjaCBxdWVyeSBvbmNlLiBFdmVudHVhbGx5LCBJIG1heSB1cGRhdGUgdGhpcyB0byBydW4gZWFjaCBxdWVyeSBtdWx0aXBsZSB0aW1lcyAoYW5kIHBvc3NpYmx5IHRyeSBhdCBkaWZmZXJlbnQgZGF5cyBvZiB0aGUgd2VlayBhbmQgdGltZXMgb2YgZGF5KSB0byBnZXQgYSBtb3JlIHJvYnVzdCBzZXQgb2YgZGF0YS4gQnV0LCBJJ20gc3RhcnRpbmcgc2ltcGxlISBJIGhhdmVuJ3QgaW5jbHVkZWQgdGhlIHNldHVwIGNvZGUgaGVyZSwgYXMgdGhhdCdzIGEgbGl0dGxlIHRlZGlvdXMuIEJ1dCwgSSd2ZSB0cmllZCB0byBpbmNsdWRlIGFsbCBvZiB0aGUgc2FsaWVudCBjb2RlIGZvciB0cmFuc3BhcmVuY3kgcHVycG9zZXMuCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCiMgR2V0IEdvb2dsZSBBbmFseXRpY3MgY3JlZGVudGlhbHMgYW5kIHNldCB0aGVtLiBUaGlzIGlzIGp1c3QgZm9yIHRoZSB1c2VyIHJ1bm5pbmcKIyB0aGUgZmlsZSBhbmQgd2lsbCB3b3JrIGFjcm9zcyBtdWx0aXBsZSBzaXRlcy4gRm9yIEFkb2JlLCBzZXBhcmF0ZSBjcmVkZW50aWFscwojIGFyZSBuZWVkZWQgZm9yIGVhY2ggc2l0ZS4KZ2FfY2xpZW50X2lkIDwtIFN5cy5nZXRlbnYoIkdBX0NMSUVOVF9JRCIpCmdhX2NsaWVudF9zZWNyZXQgPC0gU3lzLmdldGVudigiR0FfQ0xJRU5UX1NFQ1JFVCIpCgpvcHRpb25zKGdvb2dsZUF1dGhSLmNsaWVudF9pZCA9IGdhX2NsaWVudF9pZCkKb3B0aW9ucyhnb29nbGVBdXRoUi5jbGllbnRfc2VjcmV0ID0gZ2FfY2xpZW50X3NlY3JldCkgCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnb29nbGVBbmFseXRpY3NSKQpsaWJyYXJ5KFJTaXRlQ2F0YWx5c3QpCmxpYnJhcnkoa25pdHIpCgplbmRfZGF0ZSA8LSBTeXMuRGF0ZSgpIC0gMQpzdGFydF9kYXRlX3llYXIgPC0gZW5kX2RhdGUtMzY0CgojIEF1dGhvcml6ZSBHb29nbGUgQW5hbHl0aWNzCmdhX2F1dGgoKQoKIyBJbml0aWFsaXplIGEgZGF0YSBmcmFtZSB0aGF0IHdpbGwgbG9nIGFsbCB0aGUgcmVzdWx0cwpyZXN1bHRzX2xvZyA8LSBkYXRhLmZyYW1lKHRlc3RuYW1lID0gY2hhcmFjdGVyKCksIGFhX3RpbWUgPSBudW1lcmljKCksIGdhX3RpbWUgPSBudW1lcmljKCksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmBgYAoKIyMgVGhlIFF1ZXJpZXMKClRoaXMgaXMgY2VydGFpbmx5IHNvbWV0aGluZyB0aGF0IGNhbiBiZSBmaWRkbGVkIHdpdGggYSBiaXQsIGJ1dCwgZm9yIHRoZSBpbml0aWFsIHRlc3QsIEkgc2V0IHVwIHR3byBxdWVyaWVzOgoKKiBEYWlseSAqKnVuaXF1ZSB2aXNpdG9ycyoqICh1c2VycyksICoqdmlzaXRzKiogKHNlc3Npb25zKSwgYW5kICoqcGFnZSB2aWV3cyoqIChwYWdldmlld3MpCiogKipWaXNpdHMqKiAoc2Vzc2lvbnMpIGJyb2tlbiBkb3duIGJ5ICoqZGV2aWNlIHR5cGUqKiBhbmQgKipicm93c2VyKioKCkZvciBub3csIEkgaGF2ZW4ndCBhZGRlZCBhbnkgc2VnbWVudHMgdG8gZWl0aGVyIHF1ZXJ5IC0tIGVpdGhlciBpbmxpbmUgKGR5bmFtaWMpIG9yIG5hbWVkLiBCdXQsIHRoYXQgbWF5IGJlIHNvbWV0aGluZyB0byBhZGQgaW4gdGhlIGZ1dHVyZS4KClRoZSBmdW5jdGlvbnMgYmVsb3cgY2FuIHRoZW4gYmUgcnVuIG9uIGRpZmZlcmVudCBhY2NvdW50cyB0byBtYWtlIHRoZXNlIHF1ZXJpZXM6CgpgYGB7ciBkYXRhX2Z1bmN0aW9ucywgZWNobz1UUlVFfQoKIyMgQ09NUEFSSVNPTiAjMTogREFJTFkgTUVUUklDUwoKIyBBZG9iZSBBbmFseXRpY3MKZGFpbHlfZGF0YV9hYSA8LSBmdW5jdGlvbihyc2lkLCBkYXRlX2Zyb20sIGRhdGVfdG8pewogIGFhX2RhdGEgPC0gUXVldWVPdmVydGltZShyc2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZS5mcm9tID0gZGF0ZV9mcm9tLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZS50byA9IGRhdGVfdG8sCiAgICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzID0gYygidW5pcXVldmlzaXRvcnMiLCAidmlzaXRzIiwgInBhZ2V2aWV3cyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZS5ncmFudWxhcml0eSA9ICJkYXkiKQp9CgojIEdvb2dsZSBBbmFseXRpY3MKIyBUaGlzIGluY2x1ZGVzIHRoZSAidW5zYW1wbGVkIiBmbGFnIHRvIGVuc3VyZSBtb3JlIG9mIGFuIGFwcGxlcy10by1hcHBsZXMgY29tcGFyaXNvbgpkYWlseV9kYXRhX2dhIDwtIGZ1bmN0aW9uKHZpZXdfaWQsIGRhdGVfZnJvbSwgZGF0ZV90byl7CiAgZ2FfZGF0YSA8LSBnb29nbGVfYW5hbHl0aWNzXzQodmlld19pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRlX3JhbmdlID0gYyhkYXRlX2Zyb20sIGRhdGVfdG8pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MgPSBjKCJ1c2VycyIsICJzZXNzaW9ucyIsICJwYWdldmlld3MiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1lbnNpb25zID0gImRhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFudGlfc2FtcGxlID0gVFJVRSkKfQoKIyMgQ09NUEFSSVNPTiAjMjogREVWSUNFIFRZUEUgKyBCUk9XU0VSIEFHR1JFR0FUSU9OCgojIEFkb2JlIEFuYWx5dGljcwpyYW5rZWRfZGF0YV9hYSA8LSBmdW5jdGlvbihyc2lkLCBkYXRlX2Zyb20sIGRhdGVfdG8pewogIGFhX2RhdGEgPC0gUXVldWVSYW5rZWQocnNpZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZS5mcm9tID0gZGF0ZV9mcm9tLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRlLnRvID0gZGF0ZV90bywKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcyA9ICJ2aXNpdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50cyA9IGMoIm1vYmlsZWRldmljZXR5cGUiLCAiYnJvd3NlcnR5cGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHRvcCA9IGMoMjUsMjUpKQp9CgojIEdvb2dsZSBBbmFseXRpY3MKIyBUaGlzIGluY2x1ZGVzIHRoZSAidW5zYW1wbGVkIiBmbGFnIHRvIGVuc3VyZSBtb3JlIG9mIGFuIGFwcGxlcy10by1hcHBsZXMgY29tcGFyaXNvbi4gT25lCiMgZXh0cmEgc3RlcCBpcyByZXF1aXJlZCBoZXJlIHRvIGdldCB0aGUgZGF0YSB0byBjb21lIGJhY2sgc2ltaWxhcmx5IC0tIHNwZWNpZnlpbmcgdGhlIG9yZGVyLgoKb3JkZXJfZ2EgPC0gb3JkZXJfdHlwZSgic2Vzc2lvbnMiLCBzb3J0X29yZGVyID0gIkRFU0NFTkRJTkciLCBvcmRlclR5cGUgPSAiVkFMVUUiKQoKcmFua2VkX2RhdGFfZ2EgPC0gZnVuY3Rpb24odmlld19pZCwgZGF0ZV9mcm9tLCBkYXRlX3RvKXsKICBnYV9kYXRhIDwtIGdvb2dsZV9hbmFseXRpY3NfNCh2aWV3X2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGVfcmFuZ2UgPSBjKGRhdGVfZnJvbSwgZGF0ZV90byksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcyA9ICJzZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltZW5zaW9ucyA9IGMoImRldmljZUNhdGVnb3J5IiwgImJyb3dzZXIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9IG9yZGVyX2dhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFudGlfc2FtcGxlID0gVFJVRSkKfQoKYGBgCgojIyBTbWFsbCBTaXRlIEZpcnN0IQoKYGBge3Igc2V0dXBfc21hbGwsIGluY2x1ZGU9RkFMU0V9CiMgU2V0IHVwIHRoZSB0ZXN0cyBmb3IgdGhlIHNtYWxsIHNpdGUKCiMgQWRvYmUgQW5hbHl0aWNzCmFhX3VzZXJuYW1lIDwtIFN5cy5nZXRlbnYoIkFET0JFX0FQSV9VU0VSTkFNRSIpCmFhX3NlY3JldCA8LSBTeXMuZ2V0ZW52KCJBRE9CRV9BUElfU0VDUkVUIikKYWFfcnNpZCA8LVN5cy5nZXRlbnYoIkFET0JFX1JTSUQiKQoKIyBBdXRob3JpemUgQWRvYmUgQW5hbHl0aWNzClNDQXV0aChhYV91c2VybmFtZSwgYWFfc2VjcmV0KQoKIyBHb29nbGUgQW5hbHl0aWNzCmdhX3ZpZXdfaWQgPC0gU3lzLmdldGVudigiR0FfVklFV19JRCIpCgpgYGAKCldlJ2xsIHN0YXJ0IHdpdGggYSBzbWFsbCBzaXRlLiBUaGUgZmlyc3QgcXVlcnkgaXMgdGhlIGRhaWx5IGRhdGEgZm9yIDM2NSBkYXlzLiBBIGJpdCBvZiB0aGUgZGF0YSBpdHNlbGYgaXMgaW5jbHVkZWQgYmVsb3cgdG8gc2hvdyB0aGF0IHRoZXkgdHdvIHBsYXRmb3JtcyByZXR1cm4gY29tcGFyYWJsZSByZXN1bHRzLiBBbGwgdGhhdCBpcyBiZWluZyByZWNvcmRlZCBmb3IgdGhlIHRpbWUgaXMgdGhlIHRpbWUgdG8gYWN0dWFsbHkgbWFrZSBhbmQgcmV0cmlldmUgdGhlIHJlc3VsdHMgb2YgdGhlIHF1ZXJ5LgoKIyMjIEFkb2JlIEFuYWx5dGljczogRGFpbHkgVHJlbmQgLSBTbWFsbCBTaXRlCgpgYGB7ciBkYWlseV9kYXRhX3NtYWxsX2FhLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0V9CiMgQWRvYmUgQW5hbHl0aWNzCnRpbWVfZGFpbHlfYWEgPC0gc3lzdGVtLnRpbWUoYWFfZGF0YSA8LSBkYWlseV9kYXRhX2FhKGFhX3JzaWQsIHN0YXJ0X2RhdGVfeWVhciwgZW5kX2RhdGUpKQphYV9kYXRhIDwtIGFhX2RhdGEgJT4lIAogIHNlbGVjdChkYXRldGltZSwgdW5pcXVldmlzaXRvcnMsIHZpc2l0cywgcGFnZXZpZXdzKSAlPiUgCiAgbXV0YXRlKGRhdGV0aW1lID0gYXMuRGF0ZShkYXRldGltZSkpCmthYmxlKGhlYWQoYWFfZGF0YSkpCmBgYAoKIyMjIEdvb2dsZSBBbmFseXRpY3M6IERhaWx5IFRyZW5kIC0gU21hbGwgU2l0ZQoKYGBge3IgZGFpbHlfZGF0YV9zbWFsbF9nYSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFfQojIEdvb2dsZSBBbmFseXRpY3MKdGltZV9kYWlseV9nYSA8LSBzeXN0ZW0udGltZShnYV9kYXRhIDwtIGRhaWx5X2RhdGFfZ2EoZ2Ffdmlld19pZCwgc3RhcnRfZGF0ZV95ZWFyLCBlbmRfZGF0ZSkpCmthYmxlKGhlYWQoZ2FfZGF0YSkpCmBgYAoKVGhpcyBxdWVyeSB0b29rICoqYHIgcm91bmQodGltZV9kYWlseV9hYVtbM11dLDIpYCoqIHNlY29uZHMgZm9yIHRoZSBBZG9iZSBBbmFseXRpY3MgQVBJIGFuZCAqKmByIHJvdW5kKHRpbWVfZGFpbHlfZ2FbWzNdXSwyKWAqKiBzZWNvbmRzIGZvciB0aGUgR29vZ2xlIEFuYWx5dGljcyBBUEkuCgpgYGB7ciBsb2dfZGFpbHlfc21hbGwsIGluY2x1ZGU9RkFMU0V9CiMgTG9nIHRoZSByZXN1bHRzCnJlc3VsdHNfbG9nW25yb3cocmVzdWx0c19sb2cpKzEsXSA8LSBjKCJTbWFsbCBTaXRlOiBEYWlseSBUcmVuZHMiLCB0aW1lX2RhaWx5X2FhW1szXV0sIHRpbWVfZGFpbHlfZ2FbWzNdXSkKYGBgCgpOb3csIGxldCdzIHB1bGwgdGhlICoqZGV2aWNlIHR5cGUqKiBhbmQgKipicm93c2VyKiogZGF0YSAtLSBhbHNvIGZvciBhIHllYXIuCgojIyMgQWRvYmUgQW5hbHl0aWNzOiBSYW5rZWQgRGF0YSAtIFNtYWxsIFNpdGUKCmBgYHtyIHJhbmtlZF9kYXRhX3NtYWxsX2FhLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgQWRvYmUgQW5hbHl0aWNzCnRpbWVfcmFua2VkX2FhIDwtIHN5c3RlbS50aW1lKGFhX2RhdGEgPC0gcmFua2VkX2RhdGFfYWEoYWFfcnNpZCwgc3RhcnRfZGF0ZV95ZWFyLCBlbmRfZGF0ZSkpCgojIFdlJ3JlIG5vdCBjb3VudGluZyB0aGlzIGluIHRoZSB0aW1lIGNhbGN1bGF0aW9uIC0tIGp1c3QgbWFraW5nIGl0IGEgYml0IG1vcmUgYXBwbGVzLXRvLWFwcGxlcyB3aXRoCiMgR29vZ2xlIEFuYWx5dGljcy4KICBhYV9kYXRhIDwtIGFhX2RhdGEgJT4lIAogICAgYXJyYW5nZSgtdmlzaXRzKSAlPiUgCiAgICBtdXRhdGUobW9iaWxlZGV2aWNldHlwZSA9IGlmZWxzZShtb2JpbGVkZXZpY2V0eXBlPT0iT3RoZXIiLCAiRGVza3RvcCIsIG1vYmlsZWRldmljZXR5cGUpKSAlPiUKICAgIHNlbGVjdChtb2JpbGVkZXZpY2V0eXBlLCBicm93c2VydHlwZSwgdmlzaXRzKQoKa2FibGUoaGVhZChhYV9kYXRhKSkKYGBgCgojIyMgR29vZ2xlIEFuYWx5dGljczogUmFua2VkIERhdGEgLSBTbWFsbCBTaXRlCgpgYGB7ciByYW5rZWRfZGF0YV9zbWFsbF9nYSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIEdvb2dsZSBBbmFseXRpY3MKdGltZV9yYW5rZWRfZ2EgPC0gc3lzdGVtLnRpbWUoZ2FfZGF0YSA8LSByYW5rZWRfZGF0YV9nYShnYV92aWV3X2lkLCBzdGFydF9kYXRlX3llYXIsIGVuZF9kYXRlKSkKa2FibGUoaGVhZChnYV9kYXRhKSkKYGBgCgpUaGlzIHF1ZXJ5IHRvb2sgKipgciByb3VuZCh0aW1lX3JhbmtlZF9hYVtbM11dLDIpYCoqIHNlY29uZHMgZm9yIHRoZSBBZG9iZSBBbmFseXRpY3MgQVBJIGFuZCAqKmByIHJvdW5kKHRpbWVfcmFua2VkX2dhW1szXV0sMilgKiogc2Vjb25kcyBmb3IgdGhlIEdvb2dsZSBBbmFseXRpY3MgQVBJLgoKYGBge3IgbG9nX3JhbmtlZF9zbWFsbCwgaW5jbHVkZT1GQUxTRX0KIyBMb2cgdGhlIHJlc3VsdHMKcmVzdWx0c19sb2dbbnJvdyhyZXN1bHRzX2xvZykrMSxdIDwtIGMoIlNtYWxsIFNpdGU6IFJhbmtlZCBWYWx1ZXMiLCB0aW1lX3JhbmtlZF9hYVtbM11dLCB0aW1lX3JhbmtlZF9nYVtbM11dKQpgYGAKCiMjIE5vdywgQSBNdWNoIExhcmdlciBTaXRlCgpgYGB7ciBzZXR1cF9sYXJnZSwgaW5jbHVkZT1GQUxTRX0KIyBTZXQgdXAgdGhlIHRlc3RzIGZvciB0aGUgbGFyZ2VyIHNpdGUKCiMgQWRvYmUgQW5hbHl0aWNzCmFhX3VzZXJuYW1lIDwtIFN5cy5nZXRlbnYoIkFET0JFX0FQSV9VU0VSTkFNRV9NIikKYWFfc2VjcmV0IDwtIFN5cy5nZXRlbnYoIkFET0JFX0FQSV9TRUNSRVRfTSIpCmFhX3JzaWQgPC1TeXMuZ2V0ZW52KCJBRE9CRV9SU0lEX00iKQoKIyBBdXRob3JpemUgQWRvYmUgQW5hbHl0aWNzClNDQXV0aChhYV91c2VybmFtZSwgYWFfc2VjcmV0KQoKIyBHb29nbGUgQW5hbHl0aWNzCmdhX3ZpZXdfaWQgPC0gU3lzLmdldGVudigiR0FfVklFV19JRF9NIikKCmBgYAoKVGhpcyBpcyBhIG11Y2ggbGFyZ2VyIHNpdGUgLS0gcHJpbWFyaWx5IGFuIEFkb2JlIEFuYWx5dGljcyBzaG9wLCBidXQgdGhleSBhbHNvIGhhdmUgR29vZ2xlIEFuYWx5dGljcyBpbXBsZW1lbnRlZCAobGlnaHRseSksIHNvIGl0IHN1aXRzIG91ciBwdXJwb3Nlcy4gQWdhaW4sIHRoZSBmaXJzdCBxdWVyeSBpcyB0aGUgZGFpbHkgZGF0YSBmb3IgMzY1IGRheXMuIFdlJ3JlIG5vdCBnb2luZyB0byBzaG93IHRoZSBjb2RlIGhlcmUsIGJlY2F1c2UgaXQncyBpZGVudGljYWwgdG8gdGhlIGNvZGUgYWJvdmUuCgojIyMgQWRvYmUgQW5hbHl0aWNzOiBEYWlseSBUcmVuZCAtIExhcmdlIFNpdGUKCmBgYHtyIGRhaWx5X2RhdGFfbGFyZ2VfYWEsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMgQWRvYmUgQW5hbHl0aWNzCnRpbWVfZGFpbHlfbGFyZ2VfYWEgPC0gc3lzdGVtLnRpbWUoYWFfZGF0YSA8LSBkYWlseV9kYXRhX2FhKGFhX3JzaWQsIHN0YXJ0X2RhdGVfeWVhciwgZW5kX2RhdGUpKQphYV9kYXRhIDwtIGFhX2RhdGEgJT4lIAogIHNlbGVjdChkYXRldGltZSwgdW5pcXVldmlzaXRvcnMsIHZpc2l0cywgcGFnZXZpZXdzKSAlPiUgCiAgbXV0YXRlKGRhdGV0aW1lID0gYXMuRGF0ZShkYXRldGltZSkpCmthYmxlKGhlYWQoYWFfZGF0YSkpCmBgYAoKIyMjIEdvb2dsZSBBbmFseXRpY3M6IERhaWx5IFRyZW5kIC0gTGFyZ2UgU2l0ZQoKYGBge3IgZGFpbHlfZGF0YV9sYXJnZV9nYSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBHb29nbGUgQW5hbHl0aWNzCnRpbWVfZGFpbHlfbGFyZ2VfZ2EgPC0gc3lzdGVtLnRpbWUoZ2FfZGF0YSA8LSBkYWlseV9kYXRhX2dhKGdhX3ZpZXdfaWQsIHN0YXJ0X2RhdGVfeWVhciwgZW5kX2RhdGUpKQprYWJsZShoZWFkKGdhX2RhdGEpKQpgYGAKClRoaXMgcXVlcnkgdG9vayAqKmByIHJvdW5kKHRpbWVfZGFpbHlfbGFyZ2VfYWFbWzNdXSwyKWAqKiBzZWNvbmRzIGZvciB0aGUgQWRvYmUgQW5hbHl0aWNzIEFQSSBhbmQgKipgciByb3VuZCh0aW1lX2RhaWx5X2xhcmdlX2dhW1szXV0sMilgKiogc2Vjb25kcyBmb3IgdGhlIEdvb2dsZSBBbmFseXRpY3MgQVBJLgoKYGBge3IgbG9nX2RhaWx5X2xhcmdlLCBpbmNsdWRlPUZBTFNFfQojIExvZyB0aGUgcmVzdWx0cwpyZXN1bHRzX2xvZ1tucm93KHJlc3VsdHNfbG9nKSsxLF0gPC0gYygiTGFyZ2UgU2l0ZTogRGFpbHkgVHJlbmRzIiwgdGltZV9kYWlseV9sYXJnZV9hYVtbM11dLCB0aW1lX2RhaWx5X2xhcmdlX2dhW1szXV0pCmBgYAoKTm93LCBsZXQncyBwdWxsIHRoZSAqKmRldmljZSB0eXBlKiogYW5kICoqYnJvd3NlcioqIGRhdGEgLS0gYWxzbyBmb3IgYSB5ZWFyLgoKIyMjIEFkb2JlIEFuYWx5dGljczogUmFua2VkIERhdGEgLSBMYXJnZSBTaXRlCgpgYGB7ciByYW5rZWRfZGF0YV9sYXJnZV9hYSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBBZG9iZSBBbmFseXRpY3MKdGltZV9yYW5rZWRfbGFyZ2VfYWEgPC0gc3lzdGVtLnRpbWUoYWFfZGF0YSA8LSByYW5rZWRfZGF0YV9hYShhYV9yc2lkLCBzdGFydF9kYXRlX3llYXIsIGVuZF9kYXRlKSkKCiMgV2UncmUgbm90IGNvdW50aW5nIHRoaXMgaW4gdGhlIHRpbWUgY2FsY3VsYXRpb24gLS0ganVzdCBtYWtpbmcgaXQgYSBiaXQgbW9yZSBhcHBsZXMtdG8tYXBwbGVzIHdpdGgKIyBHb29nbGUgQW5hbHl0aWNzLgogIGFhX2RhdGEgPC0gYWFfZGF0YSAlPiUgCiAgICBhcnJhbmdlKC12aXNpdHMpICU+JSAKICAgIG11dGF0ZShtb2JpbGVkZXZpY2V0eXBlID0gaWZlbHNlKG1vYmlsZWRldmljZXR5cGU9PSJPdGhlciIsICJEZXNrdG9wIiwgbW9iaWxlZGV2aWNldHlwZSkpICU+JQogICAgc2VsZWN0KG1vYmlsZWRldmljZXR5cGUsIGJyb3dzZXJ0eXBlLCB2aXNpdHMpCgprYWJsZShoZWFkKGFhX2RhdGEpKQpgYGAKCiMjIyBHb29nbGUgQW5hbHl0aWNzOiBSYW5rZWQgRGF0YSAtIExhcmdlIFNpdGUKCmBgYHtyIHJhbmtlZF9kYXRhX2xhcmdlX2dhLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBHb29nbGUgQW5hbHl0aWNzCnRpbWVfcmFua2VkX2xhcmdlX2dhIDwtIHN5c3RlbS50aW1lKGdhX2RhdGEgPC0gcmFua2VkX2RhdGFfZ2EoZ2Ffdmlld19pZCwgc3RhcnRfZGF0ZV95ZWFyLCBlbmRfZGF0ZSkpCgpnYV9kYXRhIDwtIGdhX2RhdGEgJT4lIAogIGFycmFuZ2UoLXNlc3Npb25zKQoKa2FibGUoaGVhZChnYV9kYXRhKSkKYGBgCgpUaGlzIHF1ZXJ5IHRvb2sgKipgciByb3VuZCh0aW1lX3JhbmtlZF9sYXJnZV9hYVtbM11dLDIpYCoqIHNlY29uZHMgZm9yIHRoZSBBZG9iZSBBbmFseXRpY3MgQVBJIGFuZCAqKmByIHJvdW5kKHRpbWVfcmFua2VkX2xhcmdlX2dhW1szXV0sMilgKiogc2Vjb25kcyBmb3IgdGhlIEdvb2dsZSBBbmFseXRpY3MgQVBJLgoKYGBge3IgbG9nX3JhbmtlZF9sYXJnZSwgaW5jbHVkZT1GQUxTRX0KIyBMb2cgdGhlIHJlc3VsdHMKcmVzdWx0c19sb2dbbnJvdyhyZXN1bHRzX2xvZykrMSxdIDwtIGMoIkxhcmdlIFNpdGU6IFJhbmtlZCBWYWx1ZXMiLCB0aW1lX3JhbmtlZF9sYXJnZV9hYVtbM11dLCB0aW1lX3JhbmtlZF9sYXJnZV9nYVtbM11dKQpgYGAKCiMjIFJlc3VsdHMgU3VtbWFyeQoKQmVsb3cgaXMgYSBzdW1tYXJ5IG9mIHRoZSByZXN1bHRzLgoKYGBge3IgcmVzdWx0cywgZWNobz1GQUxTRX0KCnJlc3VsdHNfbG9nIDwtIHJlc3VsdHNfbG9nICU+JSAKICBtdXRhdGUoYWFfdGltZSA9IHJvdW5kKGFzLm51bWVyaWMoYWFfdGltZSksMSksIGdhX3RpbWUgPSByb3VuZChhcy5udW1lcmljKGdhX3RpbWUpLDEpKQoKbmFtZXMocmVzdWx0c19sb2cpIDwtIGMoIlF1ZXJ5IiwgIkFkb2JlIEFuYWx5dGljcyBUaW1lIChzZWNvbmRzKSIsICJHb29nbGUgQW5hbHl0aWNzIFRpbWUgKHNlY29uZHMpIikKCmthYmxlKHJlc3VsdHNfbG9nKQoKIyAjIENvbnZlcnQgdG8gbG9uZwojIHJlc3VsdHNfbG9uZyA8LSBnYXRoZXIocmVzdWx0c19sb2csIHBsYXRmb3JtLCB0aW1lLCBgQWRvYmUgQW5hbHl0aWNzIFRpbWUgKHNlY29uZHMpYCwgYEdvb2dsZSBBbmFseXRpY3MgVGltZSAoc2Vjb25kcylgKQojIAojIHJlc3VsdHNfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHJlc3VsdHNfbG9uZywgbWFwcGluZyA9IGFlcyh4PWBRdWVyeWAsIHk9dGltZSkpICsKIyAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikKIyAKIyByZXN1bHRzX3Bsb3QKCmBgYAoKR29vZ2xlIEFuYWx5dGljcyBnb3Qga2lsbGVkIG9uIHRoZSByYW5rZWQgZGF0YS4gRm9yIGEgbGFyZ2Ugc2l0ZSwgYW5kIHdpdGggdGhlICJhbnRpLXNhbXBsaW5nIiBmbGFnIGJlaW5nIHVzZWQgaW4gdGhlIHF1ZXJ5LCB0aGF0IGlzIGJlY2F1c2UgdGhlcmUgd2VyZSBtYW55IGNhbGxzIHRvIHRoZSBBUEkuIElmIHRoZSBzaXRlIHdhcyBhIEdBMzYwIHNpdGUgd2l0aCBhIGN1c3RvbSB0YWJsZSBzZXQgdXAsIGl0IHdvdWxkIGhhdmUgY29tZSBiYWNrIG11Y2ggZmFzdGVyIChidXQgY3VzdG9tIHRhYmxlcyBvbmx5IGdvIGJhY2sgMzAgZGF5cywgc28sIGV2ZW4gd2l0aCBHQTM2MCwgdGhpcyBtYXkgYmUgYSB0b3VnaCBvbmUuKQo=