Collect UMA data for SiteIsolatedCodeCache

Adds SiteIsolatedCodeCache.Behavour histogram. This collects the
behaviour of site isolated code cache for each request received.
It records if the request was serviced and if serviced how it was
serviced for ex: hit, miss, update.

Bug: chromium:812168
Change-Id: Ie9e45af8e72dee6fafc1b088c139b7b87fcc0851
Reviewed-on: https://chromium-review.googlesource.com/1196430
Reviewed-by: Brian White <bcwhite@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Commit-Queue: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#588047}
diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc
index f1f3ec3..f48d998d 100644
--- a/content/browser/code_cache/generated_code_cache.cc
+++ b/content/browser/code_cache/generated_code_cache.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/code_cache/generated_code_cache.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "net/base/completion_callback.h"
 #include "net/base/completion_once_callback.h"
 #include "net/http/http_util.h"
@@ -52,6 +53,10 @@
   key.append(requesting_origin.Serialize());
   return key;
 }
+
+void CollectStatistics(GeneratedCodeCache::CacheEntryStatus status) {
+  UMA_HISTOGRAM_ENUMERATION("SiteIsolatedCodeCache.Behaviour", status);
+}
 }  // namespace
 
 // Stores the information about a pending request while disk backend is
@@ -156,13 +161,17 @@
                                    const base::Time& response_time,
                                    const std::vector<uint8_t>& data) {
   // Silently ignore the requests.
-  if (backend_state_ == kFailed)
+  if (backend_state_ == kFailed) {
+    CollectStatistics(CacheEntryStatus::kError);
     return;
+  }
 
   // If the url is invalid or if it is from a unique origin, we should not
   // cache the code.
-  if (!IsAllowedToCache(url, origin))
+  if (!IsAllowedToCache(url, origin)) {
+    CollectStatistics(CacheEntryStatus::kError);
     return;
+  }
 
   // Append the response time to the metadata. Code caches store
   // response_time + generated code as a single entry.
@@ -192,6 +201,7 @@
                                     const url::Origin& origin,
                                     ReadDataCallback read_data_callback) {
   if (backend_state_ == kFailed) {
+    CollectStatistics(CacheEntryStatus::kError);
     // Silently ignore the requests.
     std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
     return;
@@ -200,6 +210,7 @@
   // If the url is invalid or if it is from a unique origin, we should not
   // cache the code.
   if (!IsAllowedToCache(url, origin)) {
+    CollectStatistics(CacheEntryStatus::kError);
     std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
     return;
   }
@@ -220,13 +231,17 @@
 void GeneratedCodeCache::DeleteEntry(const GURL& url,
                                      const url::Origin& origin) {
   // Silently ignore the requests.
-  if (backend_state_ == kFailed)
+  if (backend_state_ == kFailed) {
+    CollectStatistics(CacheEntryStatus::kError);
     return;
+  }
 
   // If the url is invalid or if it is from a unique origin, we should not
   // cache the code.
-  if (!IsAllowedToCache(url, origin))
+  if (!IsAllowedToCache(url, origin)) {
+    CollectStatistics(CacheEntryStatus::kError);
     return;
+  }
 
   std::string key = GetCacheKey(url, origin);
   if (backend_state_ != kInitialized) {
@@ -355,6 +370,7 @@
   DCHECK(entry->data);
   disk_cache::ScopedEntryPtr disk_entry(entry->data);
 
+  CollectStatistics(CacheEntryStatus::kUpdate);
   // This call will truncate the data. This is safe to do since we read the
   // entire data at the same time currently. If we want to read in parts we have
   // to doom the entry first.
@@ -366,11 +382,14 @@
     scoped_refptr<net::IOBufferWithSize> buffer,
     scoped_refptr<base::RefCountedData<disk_cache::Entry*>> entry,
     int rv) {
-  if (rv != net::OK)
+  if (rv != net::OK) {
+    CollectStatistics(CacheEntryStatus::kError);
     return;
+  }
 
   DCHECK(entry->data);
   disk_cache::ScopedEntryPtr disk_entry(entry->data);
+  CollectStatistics(CacheEntryStatus::kCreate);
   disk_entry->WriteData(kDataIndex, 0, buffer.get(), buffer->size(),
                         net::CompletionOnceCallback(), true);
 }
@@ -402,6 +421,7 @@
     scoped_refptr<base::RefCountedData<disk_cache::Entry*>> entry,
     int rv) {
   if (rv != net::OK) {
+    CollectStatistics(CacheEntryStatus::kMiss);
     std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
     return;
   }
@@ -427,8 +447,10 @@
     scoped_refptr<net::IOBufferWithSize> buffer,
     int rv) {
   if (rv != buffer->size()) {
+    CollectStatistics(CacheEntryStatus::kMiss);
     std::move(callback).Run(base::Time(), std::vector<uint8_t>());
   } else {
+    CollectStatistics(CacheEntryStatus::kHit);
     int64_t raw_response_time = *(reinterpret_cast<int64_t*>(buffer->data()));
     base::Time response_time = base::Time::FromDeltaSinceWindowsEpoch(
         base::TimeDelta::FromMicroseconds(raw_response_time));
@@ -442,6 +464,7 @@
   if (backend_state_ != kInitialized)
     return;
 
+  CollectStatistics(CacheEntryStatus::kClear);
   backend_->DoomEntry(key, net::LOWEST, net::CompletionOnceCallback());
 }
 
diff --git a/content/browser/code_cache/generated_code_cache.h b/content/browser/code_cache/generated_code_cache.h
index 58e735b44..1f965a9 100644
--- a/content/browser/code_cache/generated_code_cache.h
+++ b/content/browser/code_cache/generated_code_cache.h
@@ -36,6 +36,17 @@
                                    const std::vector<uint8_t>&)>;
   static const int kResponseTimeSizeInBytes = sizeof(int64_t);
 
+  // Used for collecting statistics about cache behaviour.
+  enum CacheEntryStatus {
+    kHit,
+    kMiss,
+    kClear,
+    kUpdate,
+    kCreate,
+    kError,
+    kMaxValue = kError
+  };
+
   // Creates a GeneratedCodeCache with the specified path and the maximum size.
   // If |max_size_bytes| is 0, then disk_cache picks a default size based on
   // some heuristics.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9694b8c..fe68336e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -44611,6 +44611,20 @@
   <int value="9" label="Notification interaction"/>
 </enum>
 
+<enum name="SiteIsolatedCodeCacheBehaviour">
+  <int value="0" label="Hit">Available in code cache</int>
+  <int value="1" label="Miss">Not available in cache</int>
+  <int value="2" label="Clear">
+    Clear a cache entry. Typically used when there is a stale entry
+  </int>
+  <int value="3" label="Update">Update an existing entry</int>
+  <int value="4" label="Create">Create a new entry</int>
+  <int value="5" label="Error">
+    Errror in handling the request because either opening backend failed or URL
+    should not be cached
+  </int>
+</enum>
+
 <enum name="SiteIsolationMimeType">
   <int value="0" label="HTML"/>
   <int value="1" label="XML"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 47d549f..bdf0680 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -97352,6 +97352,16 @@
   </summary>
 </histogram>
 
+<histogram name="SiteIsolatedCodeCache.Behaviour"
+    enum="SiteIsolatedCodeCacheBehaviour" expires_after="2018-12-31">
+  <owner>mythria@chromium.org</owner>
+  <summary>
+    The behaviour of site isolated code cache recorded for each cache
+    transaction. It records if the request was serviced and if serviced how it
+    was serviced for ex: hit, miss, update.
+  </summary>
+</histogram>
+
 <histogram name="SiteIsolation.AllResponses">
   <owner>creis@chromium.org</owner>
   <summary>