--- 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);