Bug 1472145 - Part 2. Add telemetry to track how frequently WebP images are used. r=tnikkel data-r=chutten
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 29 Jun 2018 20:30:08 -0400
changeset 424485 8d1f4fe78843a2948e244414ee8bdf46660bea39
parent 424484 2a57944df012f4654b8f929132d7e3c5ab4193d0
child 424486 2ca43c308ce1c5063fd1f2be7984dc781ab70c0c
push id104834
push useraosmond@gmail.com
push dateSat, 30 Jun 2018 00:30:18 +0000
treeherdermozilla-inbound@8d1f4fe78843 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1472145
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1472145 - Part 2. Add telemetry to track how frequently WebP images are used. r=tnikkel data-r=chutten This patch adds three telemetry scalars to track how WebP is used. All of these scalars are updated when we do the MIME type confirmation for an imgRequest when the first data comes in. We know at this point we decided to load the given content, so there should be minimal false positives for data the browser loaded but never displayed. The first two scalars are merely whether or not WebP was observed. One is for probes, which are tiny WebP images suggested by the Google WebP FAQ to probe for different aspects of WebP support (lossy, animated, etc). We want to count this separately as actual WebP content that the website wishes us to display. Probes will give a measure of how many users visit websites that probe for WebP support, and content will give a measure of how many websites don't care and just give us WebP images regardless. The third scalar is intended to give a relative measure of how many WebP images we are being served relative to all other image types. We expect the ratio to be small, but it would be good to confirm this from the data.
image/imgRequest.cpp
toolkit/components/telemetry/Scalars.yaml
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -34,16 +34,17 @@
 
 #include "plstr.h" // PL_strcasestr(...)
 #include "prtime.h" // for PR_Now
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 #include "imgIRequest.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 using namespace mozilla::image;
 
 #define LOG_TEST(level) (MOZ_LOG_TEST(gImgLog, (level)))
 
 NS_IMPL_ISUPPORTS(imgRequest,
                   nsIStreamListener, nsIRequestObserver,
@@ -935,16 +936,17 @@ imgRequest::OnStopRequest(nsIRequest* aR
 
   mTimedChannel = nullptr;
   return NS_OK;
 }
 
 struct mimetype_closure
 {
   nsACString* newType;
+  uint32_t segmentSize;
 };
 
 /* prototype for these defined below */
 static nsresult
 sniff_mimetype_callback(nsIInputStream* in, void* closure,
                         const char* fromRawSegment, uint32_t toOffset,
                         uint32_t count, uint32_t* writeCount);
 
@@ -981,21 +983,59 @@ PrepareForNewPart(nsIRequest* aRequest, 
                   nsIURI* aURI, bool aIsMultipart, image::Image* aExistingImage,
                   ProgressTracker* aProgressTracker, uint32_t aInnerWindowId)
 {
   NewPartResult result(aExistingImage);
 
   if (aInStr) {
     mimetype_closure closure;
     closure.newType = &result.mContentType;
+    closure.segmentSize = 0;
 
     // Look at the first few bytes and see if we can tell what the data is from
     // that since servers tend to lie. :(
     uint32_t out;
     aInStr->ReadSegments(sniff_mimetype_callback, &closure, aCount, &out);
+
+    // We don't support WebP but we are getting reports of Firefox being served
+    // WebP content in the wild. In particular this appears to be a problem on
+    // Fennec where content authors assume Android implies WebP support. The
+    // telemetry below is intended to get a sense of how prevalent this is.
+    //
+    // From the Google WebP FAQ example and the Modernizr library, websites may
+    // supply a tiny WebP image to probe for feature support using scripts. The
+    // probes are implemented as data URIs thus we should have all the content
+    // upfront. We don't want to consider a probe as having observed WebP since
+    // in theory the client should do the right thing when we fail to decode it.
+    // See https://developers.google.com/speed/webp/faq for details.
+    bool webp = result.mContentType.EqualsLiteral(IMAGE_WEBP);
+    bool webpProbe = false;
+    if (webp) {
+      // The probes from the example/library are all < 90 bytes. Round it up
+      // just in case.
+      const uint32_t kMaxProbeSize = 100;
+      if (closure.segmentSize < kMaxProbeSize &&
+          NS_FAILED(aURI->SchemeIs("data", &webpProbe))) {
+        webpProbe = false;
+      }
+
+      if (webpProbe) {
+        Telemetry::ScalarSet(Telemetry::ScalarID::IMAGES_WEBP_PROBE_OBSERVED,
+                             true);
+      } else {
+        Telemetry::ScalarSet(Telemetry::ScalarID::IMAGES_WEBP_CONTENT_OBSERVED,
+                             true);
+      }
+    }
+
+    if (!webpProbe) {
+      Telemetry::ScalarAdd(Telemetry::ScalarID::IMAGES_WEBP_CONTENT_FREQUENCY,
+                           webp ? NS_LITERAL_STRING("webp") :
+                                  NS_LITERAL_STRING("other"), 1);
+    }
   }
 
   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
   if (result.mContentType.IsEmpty()) {
     nsresult rv = chan ? chan->GetContentType(result.mContentType)
                        : NS_ERROR_FAILURE;
     if (NS_FAILED(rv)) {
       MOZ_LOG(gImgLog,
@@ -1236,16 +1276,17 @@ sniff_mimetype_callback(nsIInputStream* 
                         uint32_t toOffset,
                         uint32_t count,
                         uint32_t* writeCount)
 {
   mimetype_closure* closure = static_cast<mimetype_closure*>(data);
 
   NS_ASSERTION(closure, "closure is null!");
 
+  closure->segmentSize = count;
   if (count > 0) {
     imgLoader::GetMimeTypeFromContent(fromRawSegment, count, *closure->newType);
   }
 
   *writeCount = 0;
   return NS_ERROR_FAILURE;
 }
 
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -1436,16 +1436,63 @@ gfx.omtp:
     kind: uint
     expires: "66"
     notification_emails:
       - gfx-telemetry-alerts@mozilla.com
       - rhunt@mozilla.com
     record_in_processes:
       - 'content'
 
+images.webp:
+  probe_observed:
+    bug_numbers:
+      - 1472145
+    description: >
+      Whether we received a probe detecting our WebP image support.
+    kind: boolean
+    expires: "65"
+    notification_emails:
+      - gfx-telemetry-alerts@mozilla.com
+      - aosmond@mozilla.com
+    release_channel_collection: opt-out
+    record_in_processes:
+      - 'main'
+      - 'content'
+
+  content_observed:
+    bug_numbers:
+      - 1472145
+    description: >
+      Whether we received a request to decode a WebP image, excluding probes.
+    kind: boolean
+    expires: "65"
+    notification_emails:
+      - gfx-telemetry-alerts@mozilla.com
+      - aosmond@mozilla.com
+    release_channel_collection: opt-out
+    record_in_processes:
+      - 'main'
+      - 'content'
+
+  content_frequency:
+    bug_numbers:
+      - 1472145
+    description: >
+      How many image requests are WebP images, excluding probes.
+    kind: uint
+    keyed: true
+    expires: "65"
+    notification_emails:
+      - gfx-telemetry-alerts@mozilla.com
+      - aosmond@mozilla.com
+    release_channel_collection: opt-out
+    record_in_processes:
+      - 'main'
+      - 'content'
+
 # The following section contains the form autofill related scalars.
 formautofill:
   availability:
     bug_numbers:
       - 1386959
     description: A boolean sent once per session to represent whether the formautofill is available in the build
     expires: never
     kind: boolean