Bug 1776694 - Make GrabShutdownProfile return the additional information as well r=mstange

Depends on D170502

Differential Revision: https://phabricator.services.mozilla.com/D170783
This commit is contained in:
Julien Wajsberg 2023-03-15 18:19:29 +00:00
Родитель 1f69fa0f99
Коммит a4cea1aea6
8 изменённых файлов: 97 добавлений и 41 удалений

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

@ -3075,7 +3075,7 @@ void ContentChild::ShutdownInternal() {
CrashReporter::Annotation::ProfilerChildShutdownPhase,
isProfiling ? "Profiling - GrabShutdownProfileAndShutdown"_ns
: "Not profiling - GrabShutdownProfileAndShutdown"_ns);
nsCString shutdownProfile =
ProfileAndAdditionalInformation shutdownProfileAndAdditionalInformation =
mProfilerController->GrabShutdownProfileAndShutdown();
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::ProfilerChildShutdownPhase,
@ -3086,16 +3086,17 @@ void ContentChild::ShutdownInternal() {
CrashReporter::Annotation::ProfilerChildShutdownPhase,
isProfiling ? "Profiling - SendShutdownProfile (sending)"_ns
: "Not profiling - SendShutdownProfile (sending)"_ns);
if (const size_t len = shutdownProfile.Length();
if (const size_t len = shutdownProfileAndAdditionalInformation.SizeOf();
len >= size_t(IPC::Channel::kMaximumMessageSize)) {
shutdownProfile = nsPrintfCString(
shutdownProfileAndAdditionalInformation.mProfile = nsPrintfCString(
"*Profile from pid %u bigger (%zu) than IPC max (%zu)",
unsigned(profiler_current_process_id().ToNumber()), len,
size_t(IPC::Channel::kMaximumMessageSize));
}
// Send the shutdown profile to the parent process through our own
// message channel, which we know will survive for long enough.
bool sent = SendShutdownProfile(shutdownProfile);
bool sent =
SendShutdownProfile(shutdownProfileAndAdditionalInformation.mProfile);
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::ProfilerChildShutdownPhase,
sent ? (isProfiling ? "Profiling - SendShutdownProfile (sent)"_ns

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

@ -53,10 +53,11 @@ void ChildProfilerController::Init(Endpoint<PProfilerChild>&& aEndpoint) {
}
}
nsCString ChildProfilerController::GrabShutdownProfileAndShutdown() {
nsCString shutdownProfile;
ShutdownAndMaybeGrabShutdownProfileFirst(&shutdownProfile);
return shutdownProfile;
ProfileAndAdditionalInformation
ChildProfilerController::GrabShutdownProfileAndShutdown() {
ProfileAndAdditionalInformation profileAndAdditionalInformation;
ShutdownAndMaybeGrabShutdownProfileFirst(&profileAndAdditionalInformation);
return profileAndAdditionalInformation;
}
void ChildProfilerController::Shutdown() {
@ -64,7 +65,7 @@ void ChildProfilerController::Shutdown() {
}
void ChildProfilerController::ShutdownAndMaybeGrabShutdownProfileFirst(
nsCString* aOutShutdownProfile) {
ProfileAndAdditionalInformation* aOutShutdownProfileInformation) {
// First, get the owning reference out of mThread, so it cannot be used in
// ChildProfilerController after this (including re-entrantly during the
// profilerChildThread->Shutdown() inner event loop below).
@ -80,10 +81,10 @@ void ChildProfilerController::ShutdownAndMaybeGrabShutdownProfileFirst(
CrashReporter::Annotation::ProfilerChildShutdownPhase,
"Profiling - Dispatching ShutdownProfilerChild"_ns);
profilerChildThread->Dispatch(
NewRunnableMethod<nsCString*>(
NewRunnableMethod<ProfileAndAdditionalInformation*>(
"ChildProfilerController::ShutdownProfilerChild", this,
&ChildProfilerController::ShutdownProfilerChild,
aOutShutdownProfile),
aOutShutdownProfileInformation),
NS_DISPATCH_NORMAL);
// Shut down the thread. This call will spin until all runnables
// (including the ShutdownProfilerChild runnable) have been processed.
@ -96,7 +97,7 @@ void ChildProfilerController::ShutdownAndMaybeGrabShutdownProfileFirst(
// done synchronously. This avoids having to manually shutdown the thread,
// which runs a risky inner event loop, see bug 1613798.
profilerChildThread->Dispatch(
NewRunnableMethod<nsCString*>(
NewRunnableMethod<ProfileAndAdditionalInformation*>(
"ChildProfilerController::ShutdownProfilerChild SYNC", this,
&ChildProfilerController::ShutdownProfilerChild, nullptr),
NS_DISPATCH_SYNC);
@ -143,14 +144,14 @@ void ChildProfilerController::SetupProfilerChild(
}
void ChildProfilerController::ShutdownProfilerChild(
nsCString* aOutShutdownProfile) {
ProfileAndAdditionalInformation* aOutShutdownProfileInformation) {
const bool isProfiling = profiler_is_active();
if (aOutShutdownProfile) {
if (aOutShutdownProfileInformation) {
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::ProfilerChildShutdownPhase,
isProfiling ? "Profiling - GrabShutdownProfile"_ns
: "Not profiling - GrabShutdownProfile"_ns);
*aOutShutdownProfile = mProfilerChild->GrabShutdownProfile();
*aOutShutdownProfileInformation = mProfilerChild->GrabShutdownProfile();
}
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::ProfilerChildShutdownPhase,

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

@ -485,7 +485,7 @@ void ProfilerChild::Destroy() {
}
}
nsCString ProfilerChild::GrabShutdownProfile() {
ProfileAndAdditionalInformation ProfilerChild::GrabShutdownProfile() {
LOG("GrabShutdownProfile");
UniquePtr<ProfilerCodeAddressService> service =
@ -498,32 +498,36 @@ nsCString ProfilerChild::GrabShutdownProfile() {
/* aIsShuttingDown */ true, service.get(), ProgressLogger{});
if (rv.isErr()) {
const char* failure = writer.GetFailure();
return nsPrintfCString("*Profile unavailable for pid %u%s%s",
unsigned(profiler_current_process_id().ToNumber()),
failure ? ", failure: " : "",
failure ? failure : "");
return ProfileAndAdditionalInformation(
nsPrintfCString("*Profile unavailable for pid %u%s%s",
unsigned(profiler_current_process_id().ToNumber()),
failure ? ", failure: " : "", failure ? failure : ""));
}
auto additionalInfo = rv.unwrap();
writer.StartArrayProperty("processes");
writer.EndArray();
writer.End();
const size_t len = writer.ChunkedWriteFunc().Length();
// This string is destined to be sent as a shutdown profile, which is limited
// by the maximum IPC message size.
// This string and information are destined to be sent as a shutdown profile,
// which is limited by the maximum IPC message size.
// TODO: IPC to change to shmem (bug 1780330), raising this limit to
// JS::MaxStringLength.
if (len >= size_t(IPC::Channel::kMaximumMessageSize)) {
return nsPrintfCString(
"*Profile from pid %u bigger (%zu) than IPC max (%zu)",
unsigned(profiler_current_process_id().ToNumber()), len,
size_t(IPC::Channel::kMaximumMessageSize));
if (len + additionalInfo.SizeOf() >=
size_t(IPC::Channel::kMaximumMessageSize)) {
return ProfileAndAdditionalInformation(
nsPrintfCString("*Profile from pid %u bigger (%zu) than IPC max (%zu)",
unsigned(profiler_current_process_id().ToNumber()), len,
size_t(IPC::Channel::kMaximumMessageSize)));
}
nsCString profileCString;
if (!profileCString.SetLength(len, fallible)) {
return nsPrintfCString(
return ProfileAndAdditionalInformation(nsPrintfCString(
"*Could not allocate %zu bytes for profile from pid %u", len,
unsigned(profiler_current_process_id().ToNumber()));
unsigned(profiler_current_process_id().ToNumber())));
}
MOZ_ASSERT(*(profileCString.Data() + len) == '\0',
"We expected a null at the end of the string buffer, to be "
@ -531,8 +535,9 @@ nsCString ProfilerChild::GrabShutdownProfile() {
char* const profileBeginWriting = profileCString.BeginWriting();
if (!profileBeginWriting) {
return nsPrintfCString("*Could not write profile from pid %u",
unsigned(profiler_current_process_id().ToNumber()));
return ProfileAndAdditionalInformation(
nsPrintfCString("*Could not write profile from pid %u",
unsigned(profiler_current_process_id().ToNumber())));
}
// Here, we have enough space reserved in `profileCString`, starting at
@ -542,13 +547,15 @@ nsCString ProfilerChild::GrabShutdownProfile() {
MOZ_RELEASE_ASSERT(aBufferLen == len + 1);
return profileBeginWriting;
})) {
return nsPrintfCString("*Could not copy profile from pid %u",
unsigned(profiler_current_process_id().ToNumber()));
return ProfileAndAdditionalInformation(
nsPrintfCString("*Could not copy profile from pid %u",
unsigned(profiler_current_process_id().ToNumber())));
}
MOZ_ASSERT(*(profileCString.Data() + len) == '\0',
"We still expected a null at the end of the string buffer");
return profileCString;
return ProfileAndAdditionalInformation{std::move(profileCString),
std::move(additionalInfo)};
}
} // namespace mozilla

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

@ -13,6 +13,7 @@
#include "mozilla/RefPtr.h"
#include "nsISupportsImpl.h"
#include "nsStringFwd.h"
#include "ProfileAdditionalInformation.h"
namespace mozilla {
@ -31,18 +32,21 @@ class ChildProfilerController final {
static already_AddRefed<ChildProfilerController> Create(
mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint);
[[nodiscard]] nsCString GrabShutdownProfileAndShutdown();
[[nodiscard]] ProfileAndAdditionalInformation
GrabShutdownProfileAndShutdown();
void Shutdown();
private:
ChildProfilerController();
~ChildProfilerController();
void Init(mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint);
void ShutdownAndMaybeGrabShutdownProfileFirst(nsCString* aOutShutdownProfile);
void ShutdownAndMaybeGrabShutdownProfileFirst(
ProfileAndAdditionalInformation* aOutShutdownProfileInformation);
// Called on mThread:
void SetupProfilerChild(mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint);
void ShutdownProfilerChild(nsCString* aOutShutdownProfile);
void ShutdownProfilerChild(
ProfileAndAdditionalInformation* aOutShutdownProfileInformation);
RefPtr<ProfilerChild> mProfilerChild; // only accessed on mThread
DataMutex<RefPtr<nsIThread>> mThread;

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

@ -381,7 +381,7 @@ mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0,
// Write the profile for this process (excluding subprocesses) into aWriter.
// Returns a failed result if the profiler is inactive.
ProfilerResult<ProfileGenerationAdditionalInformation>
ProfilerResult<mozilla::ProfileGenerationAdditionalInformation>
profiler_stream_json_for_this_process(
mozilla::baseprofiler::SpliceableJSONWriter& aWriter, double aSinceTime = 0,
bool aIsShuttingDown = false,

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

@ -16,10 +16,36 @@
#include "shared-libraries.h"
namespace mozilla {
// This structure contains additional information gathered while generating the
// profile json and iterating the buffer.
struct ProfileGenerationAdditionalInformation {
SharedLibraryInfo sharedLibraries;
size_t SizeOf() const { return mSharedLibraries.SizeOf(); }
SharedLibraryInfo mSharedLibraries;
};
#endif
struct ProfileAndAdditionalInformation {
ProfileAndAdditionalInformation() = default;
explicit ProfileAndAdditionalInformation(const nsCString&& aProfile)
: mProfile(aProfile) {}
ProfileAndAdditionalInformation(
const nsCString&& aProfile,
const ProfileGenerationAdditionalInformation&& aAdditionalInformation)
: mProfile(aProfile),
mAdditionalInformation(Some(aAdditionalInformation)) {}
size_t SizeOf() const {
size_t size = mProfile.Length();
if (mAdditionalInformation.isSome()) {
size += mAdditionalInformation->SizeOf();
}
return size;
}
nsCString mProfile;
Maybe<ProfileGenerationAdditionalInformation> mAdditionalInformation;
};
} // namespace mozilla
#endif // ProfileAdditionalInformation_h

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

@ -13,6 +13,7 @@
#include "mozilla/ProfileBufferControlledChunkManager.h"
#include "mozilla/ProgressLogger.h"
#include "mozilla/RefPtr.h"
#include "ProfileAdditionalInformation.h"
class nsIThread;
struct PRThread;
@ -33,7 +34,7 @@ class ProfilerChild final : public PProfilerChild,
// This method can be used to grab a profile just before PProfiler is torn
// down. The collected profile should then be sent through a different
// message channel that is guaranteed to stay open long enough.
nsCString GrabShutdownProfile();
ProfileAndAdditionalInformation GrabShutdownProfile();
void Destroy();

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

@ -68,6 +68,12 @@ class SharedLibrary {
const nsString& GetDebugPath() const { return mDebugPath; }
const nsCString& GetVersion() const { return mVersion; }
const std::string& GetArch() const { return mArch; }
size_t SizeOf() const {
return sizeof *this + mBreakpadId.Length() + mCodeId.Length() +
mModuleName.Length() * 2 + mModulePath.Length() * 2 +
mDebugName.Length() * 2 + mDebugPath.Length() * 2 +
mVersion.Length() + mArch.size();
}
private:
SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {}
@ -130,6 +136,16 @@ class SharedLibraryInfo {
void Clear() { mEntries.clear(); }
size_t SizeOf() const {
size_t size = 0;
for (const auto& item : mEntries) {
size += item.SizeOf();
}
return size;
}
private:
std::vector<SharedLibrary> mEntries;
};