Bug 1320312 - Disable Telemetry stack capturing if stack walking is not available. r=gfritzsche
authorGeorg Fritzsche <georg.fritzsche@googlemail.com>
Mon, 28 Nov 2016 18:00:19 +0100
changeset 324722 15d6ef5ef0e2dfba731d4045813bf0f3828eb5b8
parent 324721 5e8406f38c0936d8626a9dc0debc23b5ea7138bd
child 324723 3a6e867880dae0d26767bf1653731e92b3e8789d
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersgfritzsche
bugs1320312
milestone53.0a1
Bug 1320312 - Disable Telemetry stack capturing if stack walking is not available. r=gfritzsche MozReview-Commit-ID: AQsMm2fWWV8
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/tests/unit/test_TelemetryCaptureStack.js
toolkit/modules/AppConstants.jsm
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -68,21 +68,25 @@
 #include "mozilla/Mutex.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/PoisonIOInterposer.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/HangMonitor.h"
+
 #if defined(MOZ_ENABLE_PROFILER_SPS)
 #include "shared-libraries.h"
+#if defined(MOZ_STACKWALKING)
+#define ENABLE_STACK_CAPTURE
 #include "mozilla/StackWalk.h"
 #include "nsPrintfCString.h"
-#endif
+#endif // MOZ_STACKWALKING
+#endif // MOZ_ENABLE_PROFILER_SPS
 
 namespace {
 
 using namespace mozilla;
 using namespace mozilla::HangMonitor;
 using Telemetry::Common::AutoHashtable;
 
 // The maximum number of chrome hangs stacks that we're keeping.
@@ -390,17 +394,17 @@ HangReports::GetFirefoxUptime(unsigned a
   return mHangInfo[aIndex].mFirefoxUptime;
 }
 
 const nsClassHashtable<nsStringHashKey, HangReports::AnnotationInfo>&
 HangReports::GetAnnotationInfo() const {
   return mAnnotationInfo;
 }
 
-#if defined(MOZ_ENABLE_PROFILER_SPS)
+#if defined(ENABLE_STACK_CAPTURE)
 
 const uint8_t kMaxKeyLength = 50;
 
 /**
  * Checks if a single character of the key string is valid.
  *
  * @param aChar a character to validate.
  * @return True, if the char is valid, False - otherwise.
@@ -878,16 +882,18 @@ public:
   static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName,
                                   uint32_t delay);
 #if defined(MOZ_ENABLE_PROFILER_SPS)
   static void RecordChromeHang(uint32_t aDuration,
                                Telemetry::ProcessedStack &aStack,
                                int32_t aSystemUptime,
                                int32_t aFirefoxUptime,
                                HangAnnotationsPtr aAnnotations);
+#endif
+#if defined(ENABLE_STACK_CAPTURE)
   static void DoStackCapture(const nsACString& aKey);
 #endif
   static void RecordThreadHangStats(Telemetry::ThreadHangStats& aStats);
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
   struct Stat {
     uint32_t hitCount;
     uint32_t totalTime;
   };
@@ -926,17 +932,17 @@ private:
 
   static TelemetryImpl *sTelemetry;
   AutoHashtable<SlowSQLEntryType> mPrivateSQL;
   AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
   Mutex mHashMutex;
   HangReports mHangReports;
   Mutex mHangReportsMutex;
 
-#if defined(MOZ_ENABLE_PROFILER_SPS)
+#if defined(ENABLE_STACK_CAPTURE)
   // Stores data about stacks captured on demand.
   KeyedStackCapturer mStackCapturer;
 #endif
 
   // mThreadHangStats stores recorded, inactive thread hang stats
   Vector<Telemetry::ThreadHangStats> mThreadHangStats;
   Mutex mThreadHangStatsMutex;
 
@@ -1523,17 +1529,17 @@ TelemetryImpl::GetChromeHangs(JSContext 
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelemetryImpl::SnapshotCapturedStacks(bool clear, JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
-#if defined(MOZ_ENABLE_PROFILER_SPS)
+#if defined(ENABLE_STACK_CAPTURE)
   nsresult rv = mStackCapturer.ReflectCapturedStacks(cx, ret);
   if (clear) {
     mStackCapturer.Clear();
   }
   return rv;
 #else
   return NS_OK;
 #endif
@@ -2456,27 +2462,29 @@ TelemetryImpl::RecordChromeHang(uint32_t
 
   MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex);
 
   sTelemetry->mHangReports.AddHang(aStack, aDuration,
                                    aSystemUptime, aFirefoxUptime,
                                    Move(annotations));
 }
 
+#if defined(ENABLE_STACK_CAPTURE)
 void
 TelemetryImpl::DoStackCapture(const nsACString& aKey) {
   if (Telemetry::CanRecordExtended() && XRE_IsParentProcess()) {
     sTelemetry->mStackCapturer.Capture(aKey);
   }
 }
 #endif
+#endif
 
 nsresult
 TelemetryImpl::CaptureStack(const nsACString& aKey) {
-#if defined(MOZ_ENABLE_PROFILER_SPS)
+#if defined(ENABLE_STACK_CAPTURE)
   TelemetryImpl::DoStackCapture(aKey);
 #endif
   return NS_OK;
 }
 
 void
 TelemetryImpl::RecordThreadHangStats(Telemetry::ThreadHangStats& aStats)
 {
@@ -3143,17 +3151,19 @@ void RecordChromeHang(uint32_t duration,
 {
   TelemetryImpl::RecordChromeHang(duration, aStack,
                                   aSystemUptime, aFirefoxUptime,
                                   Move(aAnnotations));
 }
 
 void CaptureStack(const nsACString& aKey)
 {
+#if defined(ENABLE_STACK_CAPTURE)
   TelemetryImpl::DoStackCapture(aKey);
+#endif
 }
 #endif
 
 void RecordThreadHangStats(ThreadHangStats& aStats)
 {
   TelemetryImpl::RecordThreadHangStats(aStats);
 }
 
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryCaptureStack.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryCaptureStack.js
@@ -1,14 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://gre/modules/TelemetryController.jsm", this);
 Cu.import("resource://gre/modules/AppConstants.jsm", this);
 
+// We need both in order to capture stacks.
+const ENABLE_TESTS = AppConstants.MOZ_ENABLE_PROFILER_SPS &&
+                     AppConstants.MOZ_STACKWALKING;
+
 /**
  * Ensures that the sctucture of the javascript object used for capturing stacks
  * is as intended. The structure is expected to be as in this example:
  *
  * {
  *  "memoryMap": [
  *      [String, String],
  *      ...
@@ -61,34 +65,34 @@ function captureStacks(key, clear = true
 }
 
 const TEST_STACK_KEYS = ["TEST-KEY1", "TEST-KEY2"];
 
 /**
  * Ensures that captured stacks appear in pings, if any were captured.
  */
 add_task({
-  skip_if: () => !AppConstants.MOZ_ENABLE_PROFILER_SPS
+  skip_if: () => !ENABLE_TESTS
 }, function* test_capturedStacksAppearInPings() {
   yield TelemetryController.testSetup();
   captureStacks("DOES-NOT-MATTER", false);
 
   let ping = TelemetryController.getCurrentPingData();
   Assert.ok("capturedStacks" in ping.payload.processes.parent);
 
   let capturedStacks = ping.payload.processes.parent.capturedStacks;
   Assert.ok(checkObjectStructure(capturedStacks));
 });
 
 /**
  * Ensures that capturing a stack for a new key increases the number
  * of captured stacks and adds a new entry to captures.
  */
 add_task({
-  skip_if: () => !AppConstants.MOZ_ENABLE_PROFILER_SPS
+  skip_if: () => !ENABLE_TESTS
 }, function* test_CaptureStacksIncreasesNumberOfCapturedStacks() {
   // Construct a unique key for this test.
   let key = TEST_STACK_KEYS[0] + "-UNIQUE-KEY-1";
 
   // Ensure that no captures for the key exist.
   let original = Telemetry.snapshotCapturedStacks();
   Assert.equal(undefined, original.captures.find(capture => capture[0] === key));
 
@@ -106,17 +110,17 @@ add_task({
   );
 });
 
 /**
  * Ensures that stacks are grouped by the key. If a stack is captured
  * more than once for the key, the length of stacks does not increase.
  */
  add_task({
-   skip_if: () => !AppConstants.MOZ_ENABLE_PROFILER_SPS
+   skip_if: () => !ENABLE_TESTS
  }, function* test_CaptureStacksGroupsDuplicateStacks() {
   // Make sure that there are initial captures for TEST_STACK_KEYS[0].
   let stacks = captureStacks(TEST_STACK_KEYS[0], false);
   let original = {
     captures: stacks.captures.find(capture => capture[0] === TEST_STACK_KEYS[0]),
     stacks: stacks.stacks
   };
 
@@ -137,17 +141,17 @@ add_task({
   Assert.deepEqual(expectedCaptures, updated.captures);
 });
 
 /**
  * Ensure that capturing the stack for a key does not affect info
  * for other keys.
  */
 add_task({
-  skip_if: () => !AppConstants.MOZ_ENABLE_PROFILER_SPS
+  skip_if: () => !ENABLE_TESTS
 }, function* test_CaptureStacksSeparatesInformationByKeys() {
   // Make sure that there are initial captures for TEST_STACK_KEYS[0].
   let stacks = captureStacks(TEST_STACK_KEYS[0], false);
   let original = {
     captures: stacks.captures.find(capture => capture[0] === TEST_STACK_KEYS[0]),
     stacks: stacks.stacks
   };
 
@@ -164,17 +168,17 @@ add_task({
     updated.captures.find(capture => capture[0] === TEST_STACK_KEYS[0])
   );
 });
 
 /**
  * Ensure that Telemetry does not allow weird keys.
  */
 add_task({
-  skip_if: () => !AppConstants.MOZ_ENABLE_PROFILER_SPS
+  skip_if: () => !ENABLE_TESTS
 }, function* test_CaptureStacksDoesNotAllowBadKey() {
   for (let badKey of [null, "KEY-!@\"#$%^&*()_"]) {
     let stacks = captureStacks(badKey);
     let captureData = stacks.captures.find(capture => capture[0] === badKey)
     Assert.ok(!captureData, `"${badKey}" should not be allowed as a key`);
   }
 });
 
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -290,16 +290,23 @@ this.AppConstants = Object.freeze({
 
   MOZ_ENABLE_PROFILER_SPS:
 #ifdef MOZ_ENABLE_PROFILER_SPS
   true,
 #else
   false,
 #endif
 
+  MOZ_STACKWALKING:
+#ifdef MOZ_STACKWALKING
+  true,
+#else
+  false,
+#endif
+
   MOZ_ANDROID_ACTIVITY_STREAM:
 #ifdef MOZ_ANDROID_ACTIVITY_STREAM
   true,
 #else
   false,
 #endif
 
   DLL_PREFIX: "@DLL_PREFIX@",