Bug 1318284 - Improve probes measuring Telemetry send times. r=dexter a=jcristau
authorGeorg Fritzsche <georg.fritzsche@googlemail.com>
Mon, 21 Nov 2016 17:48:42 +0100
changeset 353098 1a0393890b94c037b5862b86f3307063eddd29e6
parent 353097 42ed25f0652ccd6e1bf51f24ab0a03d5a701f095
child 353099 5004044ea0c1246cb3c8c4f0b0787d277fc2e037
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdexter, jcristau
bugs1318284
milestone52.0a2
Bug 1318284 - Improve probes measuring Telemetry send times. r=dexter a=jcristau
toolkit/components/telemetry/Histograms.json
toolkit/components/telemetry/TelemetrySend.jsm
toolkit/components/telemetry/histogram-whitelists.json
toolkit/components/telemetry/tests/unit/test_TelemetrySend.js
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5890,29 +5890,33 @@
   },
   "TELEMETRY_COMPRESS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 3000,
     "n_buckets": 10,
     "description": "Time taken to compress telemetry object (ms)"
   },
-  "TELEMETRY_PING": {
-    "expires_in_version": "never",
-    "kind": "exponential",
-    "high": 3000,
-    "n_buckets": 10,
-    "description": "Time taken to submit telemetry info (ms)"
-  },
-  "TELEMETRY_SEND" : {
-    "expires_in_version": "never",
-    "kind": "exponential",
-    "high": 3000,
-    "n_buckets": 10,
-    "description": "Time to send the compressed string to the Telemetry servers and get a reply back (ms)"
+  "TELEMETRY_SEND_SUCCESS" : {
+    "alert_emails": ["telemetry-client-dev@mozilla.com"],
+    "bug_numbers": [1318284],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": 120000,
+    "n_buckets": 20,
+    "description": "Time needed (in ms) for a successful send of a Telemetry ping to the servers and getting a reply back."
+  },
+  "TELEMETRY_SEND_FAILURE" : {
+    "alert_emails": ["telemetry-client-dev@mozilla.com"],
+    "bug_numbers": [1318284],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": 120000,
+    "n_buckets": 20,
+    "description": "Time needed (in ms) for a failed send of a Telemetry ping to the servers and getting a reply back."
   },
   "TELEMETRY_STRINGIFY" : {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 3000,
     "n_buckets": 10,
     "description": "Time to stringify telemetry object (ms)"
   },
--- a/toolkit/components/telemetry/TelemetrySend.jsm
+++ b/toolkit/components/telemetry/TelemetrySend.jsm
@@ -78,16 +78,25 @@ const SEND_TICK_DELAY = 1 * MS_IN_A_MINU
 // for the next ping sends. We increase the delay exponentially up to a limit of
 // SEND_MAXIMUM_BACKOFF_DELAY_MS.
 // This exponential backoff will be reset by external ping submissions & idle-daily.
 const SEND_MAXIMUM_BACKOFF_DELAY_MS = 120 * MS_IN_A_MINUTE;
 
 // The age of a pending ping to be considered overdue (in milliseconds).
 const OVERDUE_PING_FILE_AGE = 7 * 24 * 60 * MS_IN_A_MINUTE; // 1 week
 
+function monotonicNow() {
+  try {
+    return Telemetry.msSinceProcessStart();
+  } catch (ex) {
+    // If this fails fall back to the (non-monotonic) Date value.
+    return Date.now();
+  }
+}
+
 /**
  * This is a policy object used to override behavior within this module.
  * Tests override properties on this object to allow for control of behavior
  * that would otherwise be very hard to cover.
  */
 var Policy = {
   now: () => new Date(),
   midnightPingFuzzingDelay: () => MIDNIGHT_FUZZING_DELAY_MS,
@@ -650,18 +659,18 @@ var TelemetrySendImpl = {
     this._log.trace("reset");
 
     this._shutdown = false;
     this._currentPings = new Map();
     this._overduePingCount = 0;
 
     const histograms = [
       "TELEMETRY_SUCCESS",
-      "TELEMETRY_SEND",
-      "TELEMETRY_PING",
+      "TELEMETRY_SEND_SUCCESS",
+      "TELEMETRY_SEND_FAILURE",
     ];
 
     histograms.forEach(h => Telemetry.getHistogramById(h).clear());
 
     return SendScheduler.reset();
   },
 
   /**
@@ -822,22 +831,22 @@ var TelemetrySendImpl = {
     let promise = Promise.all(pingSendPromises);
     this._trackPendingPingTask(promise);
     yield promise;
   }),
 
   _onPingRequestFinished: function(success, startTime, id, isPersisted) {
     this._log.trace("_onPingRequestFinished - success: " + success + ", persisted: " + isPersisted);
 
-    Telemetry.getHistogramById("TELEMETRY_SEND").add(new Date() - startTime);
-    let hping = Telemetry.getHistogramById("TELEMETRY_PING");
+    let sendId = success ? "TELEMETRY_SEND_SUCCESS" : "TELEMETRY_SEND_FAILURE";
+    let hsend = Telemetry.getHistogramById(sendId);
     let hsuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
 
+    hsend.add(monotonicNow() - startTime);
     hsuccess.add(success);
-    hping.add(new Date() - startTime);
 
     if (!success) {
       // Let the scheduler know about send failures for triggering backoff timeouts.
       SendScheduler.notifySendsFailed();
     }
 
     if (success && isPersisted) {
       if (TelemetryStorage.isDeletionPing(id)) {
@@ -905,17 +914,17 @@ var TelemetrySendImpl = {
     request.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
     request.setRequestHeader("Date", Policy.now().toUTCString());
 
     this._pendingPingRequests.set(id, request);
 
     // Prevent the request channel from running though URLClassifier (bug 1296802)
     request.channel.loadFlags &= ~Ci.nsIChannel.LOAD_CLASSIFY_URI;
 
-    let startTime = new Date();
+    let startTime = monotonicNow();
     let deferred = PromiseUtils.defer();
 
     let onRequestFinished = (success, event) => {
       let onCompletion = () => {
         if (success) {
           deferred.resolve();
         } else {
           deferred.reject(event);
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -661,18 +661,16 @@
     "SUBPROCESS_CRASHES_WITH_DUMP",
     "SYSTEM_FONT_FALLBACK",
     "SYSTEM_FONT_FALLBACK_FIRST",
     "SYSTEM_FONT_FALLBACK_SCRIPT",
     "TAB_SWITCH_CACHE_POSITION",
     "TAP_TO_LOAD_ENABLED",
     "TAP_TO_LOAD_IMAGE_SIZE",
     "TELEMETRY_COMPRESS",
-    "TELEMETRY_PING",
-    "TELEMETRY_SEND",
     "TELEMETRY_STRINGIFY",
     "TELEMETRY_SUCCESS",
     "TELEMETRY_TEST_COUNT",
     "TELEMETRY_TEST_COUNT_INIT_NO_RECORD",
     "TELEMETRY_TEST_EXPIRED",
     "TELEMETRY_TEST_FLAG",
     "TELEMETRY_TEST_KEYED_COUNT",
     "TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD",
@@ -1604,22 +1602,20 @@
     "TELEMETRY_MEMORY_REPORTER_MS",
     "TELEMETRY_PENDING_CHECKING_OVER_QUOTA_MS",
     "TELEMETRY_PENDING_EVICTING_OVER_QUOTA_MS",
     "TELEMETRY_PENDING_LOAD_FAILURE_PARSE",
     "TELEMETRY_PENDING_LOAD_FAILURE_READ",
     "TELEMETRY_PENDING_PINGS_AGE",
     "TELEMETRY_PENDING_PINGS_EVICTED_OVER_QUOTA",
     "TELEMETRY_PENDING_PINGS_SIZE_MB",
-    "TELEMETRY_PING",
     "TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS",
     "TELEMETRY_PING_SIZE_EXCEEDED_ARCHIVED",
     "TELEMETRY_PING_SIZE_EXCEEDED_PENDING",
     "TELEMETRY_PING_SIZE_EXCEEDED_SEND",
-    "TELEMETRY_SEND",
     "TELEMETRY_SESSIONDATA_FAILED_LOAD",
     "TELEMETRY_SESSIONDATA_FAILED_PARSE",
     "TELEMETRY_SESSIONDATA_FAILED_SAVE",
     "TELEMETRY_SESSIONDATA_FAILED_VALIDATION",
     "TELEMETRY_STRINGIFY",
     "TELEMETRY_SUCCESS",
     "TELEMETRY_TEST_COUNT",
     "TELEMETRY_TEST_COUNT_INIT_NO_RECORD",
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js
@@ -64,16 +64,20 @@ var checkPingsSaved = Task.async(functio
       dump("checkPingsSaved - failed to find ping: " + path + "\n");
       allFound = false;
     }
   }
 
   return allFound;
 });
 
+function histogramValueCount(h) {
+  return h.counts.reduce((a, b) => a + b);
+}
+
 add_task(function* test_setup() {
   // Trigger a proper telemetry init.
   do_get_profile(true);
   // Make sure we don't generate unexpected pings due to pref changes.
   yield setEmptyPrefWatchlist();
   Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
 });
 
@@ -81,16 +85,23 @@ add_task(function* test_setup() {
 add_task(function* test_sendPendingPings() {
   const TYPE_PREFIX = "test-sendPendingPings-";
   const TEST_TYPE_A = TYPE_PREFIX + "A";
   const TEST_TYPE_B = TYPE_PREFIX + "B";
 
   const TYPE_A_COUNT = 20;
   const TYPE_B_COUNT = 5;
 
+  let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
+  let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
+  let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
+  histSuccess.clear();
+  histSendTimeSuccess.clear();
+  histSendTimeFail.clear();
+
   // Fake a current date.
   let now = TelemetryUtils.truncateToDays(new Date());
   now = fakeNow(futureDate(now, 10 * 60 * MS_IN_A_MINUTE));
 
   // Enable test-mode for TelemetrySend, otherwise we won't store pending pings
   // before the module is fully initialized later.
   TelemetrySend.setTestModeEnabled(true);
 
@@ -110,16 +121,23 @@ add_task(function* test_sendPendingPings
     fakePingId("b", i);
     const id = yield TelemetryController.submitExternalPing(TEST_TYPE_B, {});
     yield setPingLastModified(id, now.getTime() + (i * 1000));
   }
 
   Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT + TYPE_B_COUNT,
                "Should have correct pending ping count");
 
+  Assert.deepEqual(histSuccess.snapshot().counts, [0, 0, 0],
+               "Should not have recorded any sending in histograms yet.");
+  Assert.equal(histSendTimeSuccess.snapshot().sum, 0,
+               "Should not have recorded any sending in histograms yet.");
+  Assert.equal(histSendTimeFail.snapshot().sum, 0,
+               "Should not have recorded any sending in histograms yet.");
+
   // Now enable sending to the ping server.
   now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
   PingServer.start();
   Preferences.set(PREF_TELEMETRY_SERVER, "http://localhost:" + PingServer.port);
 
   let timerPromise = waitForTimer();
   yield TelemetryController.testReset();
   let [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
@@ -134,16 +152,23 @@ add_task(function* test_sendPendingPings
   PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
   let countByType = countPingTypes(pings);
 
   Assert.equal(countByType.get(TEST_TYPE_B), TYPE_B_COUNT,
                "Should have received the correct amount of type B pings");
   Assert.equal(countByType.get(TEST_TYPE_A), 10 - TYPE_B_COUNT,
                "Should have received the correct amount of type A pings");
 
+  Assert.deepEqual(histSuccess.snapshot().counts, [0, 10, 0],
+               "Should have recorded sending success in histograms.");
+  Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 10,
+               "Should have recorded successful send times in histograms.");
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0,
+               "Should not have recorded any failed sending in histograms yet.");
+
   // As we hit the ping send limit and still have pending pings, a send tick should
   // be scheduled in a minute.
   Assert.ok(!!pingSendTimerCallback, "Timer callback should be set");
   Assert.equal(pingSendTimeout, MS_IN_A_MINUTE, "Send tick timeout should be correct");
 
   // Trigger the next tick - we should receive the next 10 type A pings.
   PingServer.resetPingHandler();
   now = fakeNow(futureDate(now, pingSendTimeout));
@@ -190,51 +215,74 @@ add_task(function* test_sendDateHeader()
 
 // Test the backoff timeout behavior after send failures.
 add_task(function* test_backoffTimeout() {
   const TYPE_PREFIX = "test-backoffTimeout-";
   const TEST_TYPE_C = TYPE_PREFIX + "C";
   const TEST_TYPE_D = TYPE_PREFIX + "D";
   const TEST_TYPE_E = TYPE_PREFIX + "E";
 
+  let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
+  let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
+  let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
+
   // Failing a ping send now should trigger backoff behavior.
   let now = fakeNow(2010, 1, 1, 11, 0, 0);
   yield TelemetrySend.reset();
   PingServer.stop();
+
+  histSuccess.clear();
+  histSendTimeSuccess.clear();
+  histSendTimeFail.clear();
+
   fakePingId("c", 0);
   now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
+  let sendAttempts = 0;
   let timerPromise = waitForTimer();
   yield TelemetryController.submitExternalPing(TEST_TYPE_C, {});
   let [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
   Assert.equal(TelemetrySend.pendingPingCount, 1, "Should have one pending ping.");
+  ++sendAttempts;
 
   const MAX_BACKOFF_TIMEOUT = 120 * MS_IN_A_MINUTE;
   for (let timeout = 2 * MS_IN_A_MINUTE; timeout <= MAX_BACKOFF_TIMEOUT; timeout *= 2) {
     Assert.ok(!!pingSendTimerCallback, "Should have received a timer callback");
     Assert.equal(pingSendTimeout, timeout, "Send tick timeout should be correct");
 
     let callback = pingSendTimerCallback;
     now = fakeNow(futureDate(now, pingSendTimeout));
     timerPromise = waitForTimer();
     yield callback();
     [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
+    ++sendAttempts;
   }
 
   timerPromise = waitForTimer();
   yield pingSendTimerCallback();
   [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
   Assert.equal(pingSendTimeout, MAX_BACKOFF_TIMEOUT, "Tick timeout should be capped");
+  ++sendAttempts;
+
+  Assert.deepEqual(histSuccess.snapshot().counts, [sendAttempts, 0, 0],
+               "Should have recorded sending failure in histograms.");
+  Assert.equal(histSendTimeSuccess.snapshot().sum, 0,
+               "Should not have recorded any sending success in histograms yet.");
+  Assert.greater(histSendTimeFail.snapshot().sum, 0,
+               "Should have recorded send failure times in histograms.");
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), sendAttempts,
+               "Should have recorded send failure times in histograms.");
 
   // Submitting a new ping should reset the backoff behavior.
   fakePingId("d", 0);
   now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
   timerPromise = waitForTimer();
   yield TelemetryController.submitExternalPing(TEST_TYPE_D, {});
   [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
   Assert.equal(pingSendTimeout, 2 * MS_IN_A_MINUTE, "Send tick timeout should be correct");
+  sendAttempts += 2;
 
   // With the server running again, we should send out the pending pings immediately
   // when a new ping is submitted.
   PingServer.start();
   TelemetrySend.setServer("http://localhost:" + PingServer.port);
   fakePingId("e", 0);
   now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
   timerPromise = waitForTimer();
@@ -244,79 +292,117 @@ add_task(function* test_backoffTimeout()
   let countByType = countPingTypes(pings);
 
   Assert.equal(countByType.get(TEST_TYPE_C), 1, "Should have received the correct amount of type C pings");
   Assert.equal(countByType.get(TEST_TYPE_D), 1, "Should have received the correct amount of type D pings");
   Assert.equal(countByType.get(TEST_TYPE_E), 1, "Should have received the correct amount of type E pings");
 
   yield TelemetrySend.testWaitOnOutgoingPings();
   Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings left");
+
+  Assert.deepEqual(histSuccess.snapshot().counts, [sendAttempts, 3, 0],
+               "Should have recorded sending failure in histograms.");
+  Assert.greater(histSendTimeSuccess.snapshot().sum, 0,
+               "Should have recorded sending success in histograms.");
+  Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 3,
+               "Should have recorded sending success in histograms.");
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), sendAttempts,
+               "Should have recorded send failure times in histograms.");
 });
 
 add_task(function* test_discardBigPings() {
   const TEST_PING_TYPE = "test-ping-type";
 
+  let histSizeExceeded = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND");
+  let histDiscardedSize = Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB");
+  let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
+  let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
+  let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
+  for (let h of [histSizeExceeded, histDiscardedSize, histSuccess, histSendTimeSuccess, histSendTimeFail]) {
+    h.clear();
+  }
+
   // Generate a 2MB string and create an oversized payload.
   const OVERSIZED_PAYLOAD = {"data": generateRandomString(2 * 1024 * 1024)};
 
   // Reset the histograms.
   Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND").clear();
   Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB").clear();
 
   // Submit a ping of a normal size and check that we don't count it in the histogram.
   yield TelemetryController.submitExternalPing(TEST_PING_TYPE, { test: "test" });
   yield TelemetrySend.testWaitOnOutgoingPings();
-  let h = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND").snapshot();
-  Assert.equal(h.sum, 0, "Telemetry must report no oversized ping submitted.");
-  h = Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB").snapshot();
-  Assert.equal(h.sum, 0, "Telemetry must report no oversized pings.");
+
+  Assert.equal(histSizeExceeded.snapshot().sum, 0, "Telemetry must report no oversized ping submitted.");
+  Assert.equal(histDiscardedSize.snapshot().sum, 0, "Telemetry must report no oversized pings.");
+  Assert.deepEqual(histSuccess.snapshot().counts, [0, 1, 0], "Should have recorded sending success.");
+  Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1, "Should have recorded send success time.");
+  Assert.greater(histSendTimeSuccess.snapshot().sum, 0, "Should have recorded send success time.");
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0, "Should not have recorded send failure time.");
 
   // Submit an oversized ping and check that it gets discarded.
   yield TelemetryController.submitExternalPing(TEST_PING_TYPE, OVERSIZED_PAYLOAD);
   yield TelemetrySend.testWaitOnOutgoingPings();
-  h = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND").snapshot();
-  Assert.equal(h.sum, 1, "Telemetry must report 1 oversized ping submitted.");
-  h = Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB").snapshot();
-  Assert.equal(h.counts[2], 1, "Telemetry must report a 2MB, oversized, ping submitted.");
+
+  Assert.equal(histSizeExceeded.snapshot().sum, 1, "Telemetry must report 1 oversized ping submitted.");
+  Assert.equal(histDiscardedSize.snapshot().counts[2], 1, "Telemetry must report a 2MB, oversized, ping submitted.");
+  Assert.deepEqual(histSuccess.snapshot().counts, [0, 1, 0], "Should have recorded sending success.");
+  Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1, "Should have recorded send success time.");
+  Assert.greater(histSendTimeSuccess.snapshot().sum, 0, "Should have recorded send success time.");
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0, "Should not have recorded send failure time.");
 });
 
 add_task(function* test_evictedOnServerErrors() {
   const TEST_TYPE = "test-evicted";
 
   yield TelemetrySend.reset();
 
+  let histEvicted = Telemetry.getHistogramById("TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS");
+  let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
+  let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
+  let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
+  for (let h of [histEvicted, histSuccess, histSendTimeSuccess, histSendTimeFail]) {
+    h.clear();
+  }
+
   // Write a custom ping handler which will return 403. This will trigger ping eviction
   // on client side.
   PingServer.registerPingHandler((req, res) => {
     res.setStatusLine(null, 403, "Forbidden");
     res.processAsync();
     res.finish();
   });
 
   // Clear the histogram and submit a ping.
-  Telemetry.getHistogramById("TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS").clear();
   let pingId = yield TelemetryController.submitExternalPing(TEST_TYPE, {});
   yield TelemetrySend.testWaitOnOutgoingPings();
 
-  let h = Telemetry.getHistogramById("TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS").snapshot();
-  Assert.equal(h.sum, 1, "Telemetry must report a ping evicted due to server errors");
+  Assert.equal(histEvicted.snapshot().sum, 1,
+               "Telemetry must report a ping evicted due to server errors");
+  Assert.deepEqual(histSuccess.snapshot().counts, [0, 1, 0]);
+  Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1);
+  Assert.greater(histSendTimeSuccess.snapshot().sum, 0);
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0);
 
   // The ping should not be persisted.
   yield Assert.rejects(TelemetryStorage.loadPendingPing(pingId), "The ping must not be persisted.");
 
   // Reset the ping handler and submit a new ping.
   PingServer.resetPingHandler();
   pingId = yield TelemetryController.submitExternalPing(TEST_TYPE, {});
 
   let ping = yield PingServer.promiseNextPings(1);
   Assert.equal(ping[0].id, pingId, "The correct ping must be received");
 
   // We should not have updated the error histogram.
-  h = Telemetry.getHistogramById("TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS").snapshot();
-  Assert.equal(h.sum, 1, "Telemetry must report a ping evicted due to server errors");
+  yield TelemetrySend.testWaitOnOutgoingPings();
+  Assert.equal(histEvicted.snapshot().sum, 1, "Telemetry must report only one ping evicted due to server errors");
+  Assert.deepEqual(histSuccess.snapshot().counts, [0, 2, 0]);
+  Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 2);
+  Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0);
 });
 
 // Test that the current, non-persisted pending pings are properly saved on shutdown.
 add_task(function* test_persistCurrentPingsOnShutdown() {
   const TEST_TYPE = "test-persistCurrentPingsOnShutdown";
   const PING_COUNT = 5;
   yield TelemetrySend.reset();
   PingServer.stop();
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -362,25 +362,25 @@ function checkPayload(payload, reason, s
 
 
   let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
   if (isWindows) {
     Assert.ok(payload.simpleMeasurements.startupSessionRestoreReadBytes > 0);
     Assert.ok(payload.simpleMeasurements.startupSessionRestoreWriteBytes > 0);
   }
 
-  const TELEMETRY_PING = "TELEMETRY_PING";
+  const TELEMETRY_SEND_SUCCESS = "TELEMETRY_SEND_SUCCESS";
   const TELEMETRY_SUCCESS = "TELEMETRY_SUCCESS";
   const TELEMETRY_TEST_FLAG = "TELEMETRY_TEST_FLAG";
   const TELEMETRY_TEST_COUNT = "TELEMETRY_TEST_COUNT";
   const TELEMETRY_TEST_KEYED_FLAG = "TELEMETRY_TEST_KEYED_FLAG";
   const TELEMETRY_TEST_KEYED_COUNT = "TELEMETRY_TEST_KEYED_COUNT";
 
   if (successfulPings > 0) {
-    Assert.ok(TELEMETRY_PING in payload.histograms);
+    Assert.ok(TELEMETRY_SEND_SUCCESS in payload.histograms);
   }
   Assert.ok(TELEMETRY_TEST_FLAG in payload.histograms);
   Assert.ok(TELEMETRY_TEST_COUNT in payload.histograms);
 
   Assert.ok(!(IGNORE_CLONED_HISTOGRAM in payload.histograms));
 
   // Flag histograms should automagically spring to life.
   const expected_flag = {
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 var tmpScope = {};
 Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", tmpScope);
 var TelemetryStopwatch = tmpScope.TelemetryStopwatch;
 
-const HIST_NAME = "TELEMETRY_PING";
+const HIST_NAME = "TELEMETRY_SEND_SUCCESS";
 const HIST_NAME2 = "RANGE_CHECKSUM_ERRORS";
 const KEYED_HIST = { id: "TELEMETRY_INVALID_PING_TYPE_SUBMITTED", key: "TEST" };
 
 var refObj = {}, refObj2 = {};
 
 var originalCount1, originalCount2;
 
 function run_test() {