Bug 1735697 - profiler_is_being_profiled checks for pauses, and can check another thread - r=florian

If the profiler is paused, then really, threads are not *being* profiled.

profiler_is_active_and_unpaused() was added, to help with non-MOZ_GECKO_PROFILER builds.

(Note: baseprofiler::profiler_thread_is_being_profiled(ProfilerThreadId) is not possible to implement, but it's not needed anyway.)

Differential Revision: https://phabricator.services.mozilla.com/D128707
This commit is contained in:
Gerald Squelart 2021-10-18 23:11:29 +00:00
parent a685378366
commit 8bf5fd4b34
5 changed files with 219 additions and 8 deletions

View File

@ -31,6 +31,7 @@
namespace mozilla::baseprofiler {
[[nodiscard]] inline bool profiler_is_active() { return false; }
[[nodiscard]] inline bool profiler_is_active_and_unpaused() { return false; }
} // namespace mozilla::baseprofiler
@ -309,6 +310,11 @@ MFBT_API bool IsThreadBeingProfiled();
return baseprofiler::detail::RacyFeatures::IsActive();
}
// Same as profiler_is_active(), but also checks if the profiler is not paused.
[[nodiscard]] inline bool profiler_is_active_and_unpaused() {
return baseprofiler::detail::RacyFeatures::IsActiveAndUnpaused();
}
// Same as profiler_is_active(), but with the same extra checks that determine
// if the profiler would currently store markers. So this should be used before
// doing some potentially-expensive work that's used in a marker. E.g.:
@ -320,10 +326,11 @@ MFBT_API bool IsThreadBeingProfiled();
return baseprofiler::detail::RacyFeatures::IsActiveAndUnpaused();
}
// Is the profiler active, and is the current thread being profiled?
// (Same caveats and recommented usage as profiler_is_active().)
// Is the profiler active and unpaused, and is the current thread being
// profiled? (Same caveats and recommented usage as profiler_is_active().)
[[nodiscard]] inline bool profiler_thread_is_being_profiled() {
return profiler_is_active() && baseprofiler::detail::IsThreadBeingProfiled();
return baseprofiler::detail::RacyFeatures::IsActiveAndUnpaused() &&
baseprofiler::detail::IsThreadBeingProfiled();
}
// Is the profiler active and paused? Returns false if the profiler is inactive.

View File

@ -4082,6 +4082,8 @@ void TestProfiler() {
printf("baseprofiler_pause()...\n");
baseprofiler::profiler_pause();
MOZ_RELEASE_ASSERT(!baseprofiler::profiler_thread_is_being_profiled());
Maybe<baseprofiler::ProfilerBufferInfo> info =
baseprofiler::profiler_get_buffer_info();
MOZ_RELEASE_ASSERT(info.isSome());

View File

@ -163,6 +163,7 @@ using ProfilingStateChangeCallback = std::function<void(ProfilingState)>;
#ifndef MOZ_GECKO_PROFILER
[[nodiscard]] inline bool profiler_is_active() { return false; }
[[nodiscard]] inline bool profiler_is_active_and_unpaused() { return false; }
[[nodiscard]] inline bool profiler_can_accept_markers() { return false; }
[[nodiscard]] inline bool profiler_feature_active(uint32_t aFeature) {
return false;
@ -301,6 +302,11 @@ class RacyFeatures {
return mozilla::profiler::detail::RacyFeatures::IsActive();
}
// Same as profiler_is_active(), but also checks if the profiler is not paused.
[[nodiscard]] inline bool profiler_is_active_and_unpaused() {
return mozilla::profiler::detail::RacyFeatures::IsActiveAndUnpaused();
}
// Same as profiler_is_active(), but with the same extra checks that determine
// if the profiler would currently store markers. So this should be used before
// doing some potentially-expensive work that's used in a marker. E.g.:

View File

@ -22,17 +22,45 @@
mozilla::profiler::ThreadRegistration::IsRegistered();
}
// Is the profiler active, and is the current thread being profiled?
// (Same caveats and recommented usage as profiler_is_active().)
// Is the profiler active and unpaused, and is the current thread being
// profiled? (Same caveats and recommented usage as profiler_is_active().)
[[nodiscard]] inline bool profiler_thread_is_being_profiled() {
return profiler_is_active() &&
return profiler_is_active_and_unpaused() &&
mozilla::profiler::ThreadRegistration::WithOnThreadRefOr(
[](mozilla::profiler::ThreadRegistration::OnThreadRef aTR) {
return aTR.UnlockedConstReaderAndAtomicRWCRef()
.IsBeingProfiled();
},
false);
;
}
// Is the profiler active and unpaused, and is the given thread being profiled?
// (Same caveats and recommented usage as profiler_is_active().)
// Safe to use with the current thread id, or unspecified ProfilerThreadId (same
// as current thread id).
[[nodiscard]] inline bool profiler_thread_is_being_profiled(
const ProfilerThreadId& aThreadId) {
if (!profiler_is_active_and_unpaused()) {
return false;
}
if (!aThreadId.IsSpecified() || aThreadId == profiler_current_thread_id()) {
// For the current thread id, use the ThreadRegistration directly, it is
// more efficient.
return mozilla::profiler::ThreadRegistration::WithOnThreadRefOr(
[](mozilla::profiler::ThreadRegistration::OnThreadRef aTR) {
return aTR.UnlockedConstReaderAndAtomicRWCRef().IsBeingProfiled();
},
false);
}
// For other threads, go through the ThreadRegistry.
return mozilla::profiler::ThreadRegistry::WithOffThreadRefOr(
aThreadId,
[](mozilla::profiler::ThreadRegistry::OffThreadRef aTR) {
return aTR.UnlockedConstReaderAndAtomicRWCRef().IsBeingProfiled();
},
false);
}
// Is the current thread registered and sleeping?

View File

@ -1754,17 +1754,87 @@ TEST(GeckoProfiler, GetBacktrace)
TEST(GeckoProfiler, Pause)
{
profiler_init_main_thread_id();
ASSERT_TRUE(profiler_is_main_thread())
<< "This test must run on the main thread";
uint32_t features = ProfilerFeature::StackWalk;
const char* filters[] = {"GeckoMain"};
const char* filters[] = {"GeckoMain", "Profiled GeckoProfiler.Pause"};
ASSERT_TRUE(!profiler_is_paused());
ASSERT_TRUE(!profiler_can_accept_markers());
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(!profiler_thread_is_being_profiled(profiler_main_thread_id()));
std::thread{[&]() {
{
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Ignored GeckoProfiler.Pause - before start");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Profiled GeckoProfiler.Pause - before start");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
}}.join();
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL, features,
filters, MOZ_ARRAY_LENGTH(filters), 0);
ASSERT_TRUE(!profiler_is_paused());
ASSERT_TRUE(profiler_can_accept_markers());
ASSERT_TRUE(profiler_thread_is_being_profiled());
ASSERT_TRUE(profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_current_thread_id()));
std::thread{[&]() {
{
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Ignored GeckoProfiler.Pause - after start");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Profiled GeckoProfiler.Pause - after start");
ASSERT_TRUE(profiler_thread_is_being_profiled());
ASSERT_TRUE(profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
}}.join();
// Check that we are writing samples while not paused.
Maybe<ProfilerBufferInfo> info1 = profiler_get_buffer_info();
@ -1782,6 +1852,40 @@ TEST(GeckoProfiler, Pause)
ASSERT_TRUE(profiler_is_paused());
ASSERT_TRUE(!profiler_can_accept_markers());
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(!profiler_thread_is_being_profiled(profiler_current_thread_id()));
std::thread{[&]() {
{
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Ignored GeckoProfiler.Pause - after pause");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Profiled GeckoProfiler.Pause - after pause");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
}}.join();
// Check that we are not writing samples while paused.
info1 = profiler_get_buffer_info();
@ -1802,11 +1906,75 @@ TEST(GeckoProfiler, Pause)
ASSERT_TRUE(!profiler_is_paused());
ASSERT_TRUE(profiler_can_accept_markers());
ASSERT_TRUE(profiler_thread_is_being_profiled());
ASSERT_TRUE(profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_current_thread_id()));
std::thread{[&]() {
{
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Ignored GeckoProfiler.Pause - after resume");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Profiled GeckoProfiler.Pause - after resume");
ASSERT_TRUE(profiler_thread_is_being_profiled());
ASSERT_TRUE(profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
}}.join();
profiler_stop();
ASSERT_TRUE(!profiler_is_paused());
ASSERT_TRUE(!profiler_can_accept_markers());
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(!profiler_thread_is_being_profiled(profiler_current_thread_id()));
std::thread{[&]() {
{
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD("Ignored GeckoProfiler.Pause - after stop");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
{
AUTO_PROFILER_REGISTER_THREAD(
"Profiled GeckoProfiler.Pause - after stop");
ASSERT_TRUE(!profiler_thread_is_being_profiled());
ASSERT_TRUE(!profiler_thread_is_being_profiled(ProfilerThreadId{}));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_current_thread_id()));
ASSERT_TRUE(
!profiler_thread_is_being_profiled(profiler_main_thread_id()));
}
}}.join();
}
TEST(GeckoProfiler, Markers)