Bug 1330184 - Add some GeckoProfiler tests that call functions on a background thread. r?njn draft
authorMarkus Stange <mstange@themasta.com>
Tue, 30 May 2017 17:48:19 -0400
changeset 586822 a3848dc556dec5c0b057f65e58b48fa42d0d679d
parent 586821 af1132f4b56ba75adc864b029652d69c78d4056d
child 631111 8b1bed2d4e61ca563947029c132423c38ec156f5
push id61536
push userbmo:mstange@themasta.com
push dateWed, 31 May 2017 04:36:41 +0000
reviewersnjn
bugs1330184
milestone55.0a1
Bug 1330184 - Add some GeckoProfiler tests that call functions on a background thread. r?njn MozReview-Commit-ID: 9fMPyQ909PW
tools/profiler/tests/gtest/GeckoProfiler.cpp
--- a/tools/profiler/tests/gtest/GeckoProfiler.cpp
+++ b/tools/profiler/tests/gtest/GeckoProfiler.cpp
@@ -12,16 +12,18 @@
 #include "gtest/gtest.h"
 
 #include "GeckoProfiler.h"
 #include "ProfilerMarkerPayload.h"
 #include "jsapi.h"
 #include "js/Initialization.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "ProfileJSONWriter.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
 
 #include <string.h>
 
 // Note: profiler_init() has already been called in XRE_main(), so we can't
 // test it here. Likewise for profiler_shutdown(), and GeckoProfilerInitRAII
 // (which is just an RAII wrapper for profiler_init() and profiler_shutdown()).
 
 using namespace mozilla;
@@ -163,16 +165,79 @@ TEST(GeckoProfiler, FeaturesAndParams)
     // These calls are no-ops.
     profiler_stop();
     profiler_stop();
 
     InactiveFeaturesAndParamsCheck();
   }
 }
 
+TEST(GeckoProfiler, DifferentThreads)
+{
+  InactiveFeaturesAndParamsCheck();
+
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = NS_NewNamedThread("GeckoProfGTest", getter_AddRefs(thread));
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  // Control the profiler on a background thread and verify flags on the
+  // main thread.
+  {
+    uint32_t features = ProfilerFeature::JS | ProfilerFeature::Threads;
+    const char* filters[] = { "GeckoMain", "Compositor" };
+
+    thread->Dispatch(NS_NewRunnableFunction([&]() {
+      profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
+                    features, filters, MOZ_ARRAY_LENGTH(filters));
+    }), NS_DISPATCH_SYNC);
+
+    ASSERT_TRUE(profiler_is_active());
+    ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::GPU));
+    ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Privacy));
+    ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Restyle));
+
+    ActiveParamsCheck(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
+                      features, filters, MOZ_ARRAY_LENGTH(filters));
+
+    thread->Dispatch(NS_NewRunnableFunction([&]() {
+      profiler_stop();
+    }), NS_DISPATCH_SYNC);
+
+    InactiveFeaturesAndParamsCheck();
+  }
+
+  // Control the profiler on the main thread and verify flags on a
+  // background thread.
+  {
+    uint32_t features = ProfilerFeature::JS | ProfilerFeature::Threads;
+    const char* filters[] = { "GeckoMain", "Compositor" };
+
+    profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
+                  features, filters, MOZ_ARRAY_LENGTH(filters));
+
+    thread->Dispatch(NS_NewRunnableFunction([&]() {
+      ASSERT_TRUE(profiler_is_active());
+      ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::GPU));
+      ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Privacy));
+      ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Restyle));
+
+      ActiveParamsCheck(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
+                        features, filters, MOZ_ARRAY_LENGTH(filters));
+    }), NS_DISPATCH_SYNC);
+
+    profiler_stop();
+
+    thread->Dispatch(NS_NewRunnableFunction([&]() {
+      InactiveFeaturesAndParamsCheck();
+    }), NS_DISPATCH_SYNC);
+  }
+
+  thread->Shutdown();
+}
+
 TEST(GeckoProfiler, GetBacktrace)
 {
   ASSERT_TRUE(!profiler_get_backtrace());
 
   {
     uint32_t features = ProfilerFeature::StackWalk;
     const char* filters[] = { "GeckoMain" };
 
@@ -347,16 +412,55 @@ TEST(GeckoProfiler, StreamJSONForThisPro
   UniquePtr<char[]> profile = w.WriteFunc()->CopyData();
   ASSERT_TRUE(profile && profile[0] == '{');
 
   profiler_stop();
 
   ASSERT_TRUE(!profiler_stream_json_for_this_process(w));
 }
 
+TEST(GeckoProfiler, StreamJSONForThisProcessThreaded)
+{
+  // Same as the previous test, but calling some things on background threads.
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = NS_NewNamedThread("GeckoProfGTest", getter_AddRefs(thread));
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  uint32_t features = ProfilerFeature::StackWalk;
+  const char* filters[] = { "GeckoMain" };
+
+  SpliceableChunkedJSONWriter w;
+  ASSERT_TRUE(!profiler_stream_json_for_this_process(w));
+
+  // Start the profiler on the main thread.
+  profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
+                features, filters, MOZ_ARRAY_LENGTH(filters));
+
+  // Call profiler_stream_json_for_this_process on a background thread.
+  thread->Dispatch(NS_NewRunnableFunction([&]() {
+    w.Start(SpliceableJSONWriter::SingleLineStyle);
+    ASSERT_TRUE(profiler_stream_json_for_this_process(w));
+    w.End();
+  }), NS_DISPATCH_SYNC);
+
+  UniquePtr<char[]> profile = w.WriteFunc()->CopyData();
+  ASSERT_TRUE(profile && profile[0] == '{');
+
+  // Stop the profiler and call profiler_stream_json_for_this_process on a
+  // background thread.
+  thread->Dispatch(NS_NewRunnableFunction([&]() {
+    profiler_stop();
+    ASSERT_TRUE(!profiler_stream_json_for_this_process(w));
+  }), NS_DISPATCH_SYNC);
+  thread->Shutdown();
+
+  // Call profiler_stream_json_for_this_process on the main thread.
+  ASSERT_TRUE(!profiler_stream_json_for_this_process(w));
+}
+
 TEST(GeckoProfiler, PseudoStack)
 {
   uint32_t features = ProfilerFeature::StackWalk;
   const char* filters[] = { "GeckoMain" };
 
   PROFILER_LABEL("A", "B", js::ProfileEntry::Category::OTHER);
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);