Bug 1371882 - MEMORYBLOCKCACHE_ERRORS telemetry to catch unexpected errors without crashing - r?cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Mon, 12 Jun 2017 16:22:28 +1200
changeset 593034 3c5860f2e71156c44edcbf2a0ddef63cced9925f
parent 593033 dfd54d50eb3cbfd92958022b81ac4fc27a36120b
child 593035 094ffbfcdf257b4755b33a36e040e17728f57cb8
push id63579
push usergsquelart@mozilla.com
push dateTue, 13 Jun 2017 05:16:04 +0000
reviewerscpearce
bugs1371882
milestone56.0a1
Bug 1371882 - MEMORYBLOCKCACHE_ERRORS telemetry to catch unexpected errors without crashing - r?cpearce No errors are expected to happen in MemoryBlockCache (except a few 'InitAllocation', which would still be good to know about), but instead of taking drastic measures in these cases (i.e., crash), I would prefer to collect some telemetry first. MozReview-Commit-ID: 4WdFS34lgzj
dom/media/MemoryBlockCache.cpp
toolkit/components/telemetry/Histograms.json
--- a/dom/media/MemoryBlockCache.cpp
+++ b/dom/media/MemoryBlockCache.cpp
@@ -10,16 +10,30 @@
 
 namespace mozilla {
 
 #undef LOG
 LazyLogModule gMemoryBlockCacheLog("MemoryBlockCache");
 #define LOG(x, ...)                                                            \
   MOZ_LOG(gMemoryBlockCacheLog, LogLevel::Debug, ("%p " x, this, ##__VA_ARGS__))
 
+enum MemoryBlockCacheTelemetryErrors
+{
+  // Don't change order/numbers! Add new values at the end and update
+  // MEMORYBLOCKCACHE_ERRORS description in Histograms.json.
+  InitUnderuse = 0,
+  InitAllocation = 1,
+  ReadClosed = 2,
+  ReadOverflow = 3,
+  WriteBlockClosed = 4,
+  WriteBlockOverflow = 5,
+  MoveBlockClosed = 6,
+  MoveBlockOverflow = 7,
+};
+
 MemoryBlockCache::MemoryBlockCache(int64_t aContentLength)
   // Buffer whole blocks.
   : mBufferLength(size_t(((aContentLength - 1) / BLOCK_SIZE + 1) * BLOCK_SIZE))
   , mMutex("MemoryBlockCache")
 {
   MOZ_ASSERT(aContentLength > 0);
 }
 
@@ -29,23 +43,33 @@ MemoryBlockCache::~MemoryBlockCache()
 }
 
 nsresult
 MemoryBlockCache::Init()
 {
   LOG("Init()");
 
   if (mBufferLength <= 0) {
+    LOG("MemoryBlockCache::WriteBlock(this=%p) MEMORYBLOCKCACHE_ERRORS='InitUnderuse'",
+        this);
+    Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
+                          InitUnderuse);
     return NS_ERROR_FAILURE;
   }
 
   MutexAutoLock lock(mMutex);
 
-  return mBuffer.SetLength(mBufferLength, mozilla::fallible) ? NS_OK
-                                                             : NS_ERROR_FAILURE;
+  if (!mBuffer.SetLength(mBufferLength, mozilla::fallible)) {
+    LOG("MemoryBlockCache::Init(this=%p) MEMORYBLOCKCACHE_ERRORS='InitAllocation'",
+        this);
+    Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
+                          InitAllocation);
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
 }
 
 void
 MemoryBlockCache::Close()
 {
   LOG("Close()");
   MutexAutoLock lock(mMutex);
   mBuffer.SetLength(0);
@@ -56,16 +80,20 @@ MemoryBlockCache::WriteBlock(uint32_t aB
                              Span<const uint8_t> aData1,
                              Span<const uint8_t> aData2)
 {
   MutexAutoLock lock(mMutex);
 
   size_t offset = BlockIndexToOffset(aBlockIndex);
   if (offset + aData1.Length() + aData2.Length() > mBuffer.Length()) {
     // Closed, or trying to write over the expected limit.
+    LOG("MemoryBlockCache::WriteBlock(this=%p) MEMORYBLOCKCACHE_ERRORS='%s'",
+        this, mBuffer.IsEmpty() ? "WriteBlockClosed" : "WriteBlockOverflow");
+    Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
+                          mBuffer.IsEmpty() ? WriteBlockClosed : WriteBlockOverflow);
     return NS_ERROR_FAILURE;
   }
 
   memcpy(mBuffer.Elements() + offset, aData1.Elements(), aData1.Length());
   if (aData2.Length() > 0) {
     memcpy(mBuffer.Elements() + offset + aData1.Length(),
            aData2.Elements(),
            aData2.Length());
@@ -80,16 +108,20 @@ MemoryBlockCache::Read(int64_t aOffset,
                        int32_t aLength,
                        int32_t* aBytes)
 {
   MutexAutoLock lock(mMutex);
 
   MOZ_ASSERT(aOffset >= 0);
   if (aOffset + aLength > int64_t(mBuffer.Length())) {
     // Closed, or trying to write over the expected limit.
+    LOG("MemoryBlockCache::Read(this=%p) MEMORYBLOCKCACHE_ERRORS='%s'",
+        this, mBuffer.IsEmpty() ? "ReadClosed" : "ReadOverflow");
+    Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
+                          mBuffer.IsEmpty() ? ReadClosed : ReadOverflow);
     return NS_ERROR_FAILURE;
   }
 
   memcpy(aData, mBuffer.Elements() + aOffset, aLength);
   *aBytes = aLength;
 
   return NS_OK;
 }
@@ -99,16 +131,20 @@ MemoryBlockCache::MoveBlock(int32_t aSou
 {
   MutexAutoLock lock(mMutex);
 
   size_t sourceOffset = BlockIndexToOffset(aSourceBlockIndex);
   size_t destOffset = BlockIndexToOffset(aDestBlockIndex);
   if (sourceOffset + BLOCK_SIZE > mBuffer.Length() ||
       destOffset + BLOCK_SIZE > mBuffer.Length()) {
     // Closed, or trying to reach past the buffer.
+    LOG("MemoryBlockCache::MoveBlock(this=%p) MEMORYBLOCKCACHE_ERRORS='%s'",
+        this, mBuffer.IsEmpty() ? "MoveBlockClosed" : "MoveBlockOverflow");
+    Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
+                          mBuffer.IsEmpty() ? MoveBlockClosed : MoveBlockOverflow);
     return NS_ERROR_FAILURE;
   }
 
   memcpy(mBuffer.Elements() + destOffset,
          mBuffer.Elements() + sourceOffset,
          BLOCK_SIZE);
 
   return NS_OK;
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8447,16 +8447,25 @@
     "alert_emails": ["gsquelart@mozilla.com"],
     "bug_numbers": [1371205],
     "expires_in_version": "60",
     "kind": "linear",
     "high": 16777216,
     "n_buckets": 66,
     "description": "MediaCacheStream stream notified length size in bytes, from the HTTP header. Recorded when each MediaCacheStream is first notified."
   },
+  "MEMORYBLOCKCACHE_ERRORS": {
+    "record_in_processes": ["main", "content"],
+    "alert_emails": ["gsquelart@mozilla.com"],
+    "bug_numbers": [1371882],
+    "expires_in_version": "60",
+    "kind": "enumerated",
+    "n_values": 16,
+    "description": "Unexpected errors encountered during use of MemoryBlockCache. 0=InitUnderuse, 1=InitAllocation, 2=ReadClosed, 3=ReadOverflow, 4=WriteBlockClosed, 5=WriteBlockOverflow, 6=MoveBlockClosed, 7=MoveBlockOverflow"
+  },
   "VIDEO_MFT_OUTPUT_NULL_SAMPLES": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["cpearce@mozilla.com"],
     "expires_in_version": "53",
     "kind": "enumerated",
     "n_values": 10,
     "description": "Does the WMF video decoder return success but null output? 0 = playback successful, 1 = excessive null output but able to decode some frames, 2 = excessive null output and gave up, 3 = null output but recovered, 4 = non-excessive null output without being able to decode frames.",
     "bug_numbers": [1176071]