Bug 1721939 - ProfilerThreadRegistrationInfo - r=canaltinova

`ProfilerThreadRegistrationInfo` will replace `ThreadInfo`, and contains thread-specific information that may be kept after that thread has ended, to identify recorded profiling data about that thread.
It is public and not ref-counted because it will be included as value into the thread registration data (to avoid a separate allocation).

Differential Revision: https://phabricator.services.mozilla.com/D120813
This commit is contained in:
Gerald Squelart 2021-08-12 01:12:29 +00:00
Родитель 9b4a2add9f
Коммит 779c0c93b1
3 изменённых файлов: 124 добавлений и 1 удалений

Просмотреть файл

@ -154,6 +154,7 @@ EXPORTS.mozilla += [
"public/ProfilerMarkersPrerequisites.h",
"public/ProfilerMarkerTypes.h",
"public/ProfilerState.h",
"public/ProfilerThreadRegistrationInfo.h",
"public/ProfilerUtils.h",
]

Просмотреть файл

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ProfilerThreadRegistrationInfo_h
#define ProfilerThreadRegistrationInfo_h
#include "mozilla/ProfilerUtils.h"
#include "mozilla/TimeStamp.h"
#include <string>
namespace mozilla::profiler {
// This class contains immutable information about a thread which needs to be
// stored across restarts of the profiler and which can be useful even after the
// thread has stopped running.
class ThreadRegistrationInfo {
public:
// Construct on the thread.
explicit ThreadRegistrationInfo(const char* aName) : mName(aName) {}
// Construct for a foreign thread (e.g., Java).
ThreadRegistrationInfo(const char* aName, ProfilerThreadId aThreadId,
bool aIsMainThread, const TimeStamp& aRegisterTime)
: mName(aName),
mRegisterTime(aRegisterTime),
mThreadId(aThreadId),
mIsMainThread(aIsMainThread) {}
// Only allow move construction, for extraction when the thread ends.
ThreadRegistrationInfo(ThreadRegistrationInfo&&) = default;
// Other copies/moves disallowed.
ThreadRegistrationInfo(const ThreadRegistrationInfo&) = delete;
ThreadRegistrationInfo& operator=(const ThreadRegistrationInfo&) = delete;
ThreadRegistrationInfo& operator=(ThreadRegistrationInfo&&) = delete;
[[nodiscard]] const char* Name() const { return mName.c_str(); }
[[nodiscard]] const TimeStamp& RegisterTime() const { return mRegisterTime; }
[[nodiscard]] ProfilerThreadId ThreadId() const { return mThreadId; }
[[nodiscard]] bool IsMainThread() const { return mIsMainThread; }
private:
const std::string mName;
const TimeStamp mRegisterTime = TimeStamp::Now();
const ProfilerThreadId mThreadId = profiler_current_thread_id();
const bool mIsMainThread = profiler_is_main_thread();
};
} // namespace mozilla::profiler
#endif // ProfilerThreadRegistrationInfo_h

Просмотреть файл

@ -9,7 +9,9 @@
// happens when calling these functions. They don't do much inspection of
// profiler internals.
#include "mozilla/ProfilerThreadRegistrationInfo.h"
#include "mozilla/ProfilerUtils.h"
#include "mozilla/UniquePtrExtensions.h"
#include "gtest/gtest.h"
@ -34,7 +36,6 @@
# include "mozilla/ProfileBufferEntrySerializationGeckoExtensions.h"
# include "mozilla/ProfileJSONWriter.h"
# include "mozilla/ScopeExit.h"
# include "mozilla/UniquePtrExtensions.h"
# include "mozilla/net/HttpBaseChannel.h"
# include "nsIChannelEventSink.h"
# include "nsIThread.h"
@ -98,6 +99,72 @@ TEST(GeckoProfiler, ProfilerUtils)
testThread.join();
}
TEST(GeckoProfiler, ThreadRegistrationInfo)
{
profiler_init_main_thread_id();
TimeStamp ts = TimeStamp::Now();
{
profiler::ThreadRegistrationInfo trInfo{
"name", ProfilerThreadId::FromNumber(123), false, ts};
EXPECT_STREQ(trInfo.Name(), "name");
EXPECT_NE(trInfo.Name(), "name")
<< "ThreadRegistrationInfo should keep its own copy of the name";
EXPECT_EQ(trInfo.RegisterTime(), ts);
EXPECT_EQ(trInfo.ThreadId(), ProfilerThreadId::FromNumber(123));
EXPECT_EQ(trInfo.IsMainThread(), false);
}
// Make sure the next timestamp will be different from `ts`.
while (TimeStamp::Now() == ts) {
}
{
profiler::ThreadRegistrationInfo trInfoHere{"Here"};
EXPECT_STREQ(trInfoHere.Name(), "Here");
EXPECT_NE(trInfoHere.Name(), "Here")
<< "ThreadRegistrationInfo should keep its own copy of the name";
EXPECT_GT(trInfoHere.RegisterTime(), ts);
EXPECT_EQ(trInfoHere.ThreadId(), profiler_current_thread_id());
EXPECT_EQ(trInfoHere.ThreadId(), profiler_main_thread_id())
<< "Gtests are assumed to run on the main thread";
EXPECT_EQ(trInfoHere.IsMainThread(), true)
<< "Gtests are assumed to run on the main thread";
}
{
// Sub-thread test.
// These will receive sub-thread data (to test move at thread end).
TimeStamp tsThread;
ProfilerThreadId threadThreadId;
UniquePtr<profiler::ThreadRegistrationInfo> trInfoThreadPtr;
std::thread testThread([&]() {
profiler::ThreadRegistrationInfo trInfoThread{"Thread"};
EXPECT_STREQ(trInfoThread.Name(), "Thread");
EXPECT_NE(trInfoThread.Name(), "Thread")
<< "ThreadRegistrationInfo should keep its own copy of the name";
EXPECT_GT(trInfoThread.RegisterTime(), ts);
EXPECT_EQ(trInfoThread.ThreadId(), profiler_current_thread_id());
EXPECT_NE(trInfoThread.ThreadId(), profiler_main_thread_id());
EXPECT_EQ(trInfoThread.IsMainThread(), false);
tsThread = trInfoThread.RegisterTime();
threadThreadId = trInfoThread.ThreadId();
trInfoThreadPtr =
MakeUnique<profiler::ThreadRegistrationInfo>(std::move(trInfoThread));
});
testThread.join();
ASSERT_NE(trInfoThreadPtr, nullptr);
EXPECT_STREQ(trInfoThreadPtr->Name(), "Thread");
EXPECT_EQ(trInfoThreadPtr->RegisterTime(), tsThread);
EXPECT_EQ(trInfoThreadPtr->ThreadId(), threadThreadId);
EXPECT_EQ(trInfoThreadPtr->IsMainThread(), false)
<< "Gtests are assumed to run on the main thread";
}
}
#ifdef MOZ_GECKO_PROFILER
TEST(BaseProfiler, BlocksRingBuffer)