Bug 1779367 - If a shmem cannot be created for a child profile, send a message instead - r=florian
authorGerald Squelart <gsquelart@mozilla.com>
Wed, 20 Jul 2022 12:53:00 +0000
changeset 624511 70cacc19a882ebf0f7545b5eaa071662b670e6b2
parent 624510 a58be620f788efee642fb80f45240ef571d275ad
child 624512 9c7fdc02ddaa82de714f769ec9afab8a45bdcb68
push id40007
push usersmolnar@mozilla.com
push dateWed, 20 Jul 2022 21:52:02 +0000
treeherdermozilla-central@16a4302fb1a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs1779367
milestone104.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1779367 - If a shmem cannot be created for a child profile, send a message instead - r=florian Instead of trying to create a too-big shmem, or if the shmem creation fails, send a short message starting with '*', which the parent can put into the profileGatheringLog. Differential Revision: https://phabricator.services.mozilla.com/D152028
tools/profiler/gecko/PProfiler.ipdl
tools/profiler/gecko/ProfilerChild.cpp
tools/profiler/gecko/nsProfiler.cpp
--- a/tools/profiler/gecko/PProfiler.ipdl
+++ b/tools/profiler/gecko/PProfiler.ipdl
@@ -27,16 +27,18 @@ child:
   async PauseSampling() returns (bool unused);
   async ResumeSampling() returns (bool unused);
 
   async WaitOnePeriodicSampling() returns (bool sampled);
 
   async AwaitNextChunkManagerUpdate() returns (ProfileBufferChunkManagerUpdate update);
   async DestroyReleasedChunksAtOrBefore(TimeStamp timeStamp);
 
+  // The returned shmem may contain an empty string (unavailable), an error
+  // message starting with '*', or a profile as a stringified JSON object.
   async GatherProfile() returns (Shmem profile);
   async GetGatherProfileProgress() returns (GatherProfileProgress progress);
 
   async ClearAllPages();
 };
 
 } // namespace mozilla
 
--- a/tools/profiler/gecko/ProfilerChild.cpp
+++ b/tools/profiler/gecko/ProfilerChild.cpp
@@ -360,24 +360,52 @@ void ProfilerChild::GatherProfileThreadF
                   // The ProfilerChild progress is still the one we know.
                   parameters->profilerChild->mGatherProfileProgress = nullptr;
                 }
 
                 // Shmem allocation and promise resolution must be made on the
                 // ProfilerChild thread, that's why this task was needed here.
                 mozilla::ipc::Shmem shmem;
                 if (writer) {
-                  writer->ChunkedWriteFunc().CopyDataIntoLazilyAllocatedBuffer(
-                      [&](size_t allocationSize) -> char* {
-                        if (parameters->profilerChild->AllocShmem(
-                                allocationSize, &shmem)) {
-                          return shmem.get<char>();
-                        }
-                        return nullptr;
-                      });
+                  if (const size_t len = writer->ChunkedWriteFunc().Length();
+                      len < UINT32_MAX) {
+                    bool success = false;
+                    writer->ChunkedWriteFunc()
+                        .CopyDataIntoLazilyAllocatedBuffer(
+                            [&](size_t allocationSize) -> char* {
+                              MOZ_ASSERT(allocationSize == len + 1);
+                              if (parameters->profilerChild->AllocShmem(
+                                      allocationSize, &shmem)) {
+                                success = true;
+                                return shmem.get<char>();
+                              }
+                              return nullptr;
+                            });
+                    if (!success) {
+                      const nsPrintfCString message(
+                          "*Could not create shmem for profile from pid %u "
+                          "(%zu B)",
+                          unsigned(profiler_current_process_id().ToNumber()),
+                          len);
+                      if (parameters->profilerChild->AllocShmem(
+                              message.Length() + 1, &shmem)) {
+                        strcpy(shmem.get<char>(), message.Data());
+                      }
+                    }
+                  } else {
+                    const nsPrintfCString message(
+                        "*Profile from pid %u bigger (%zu) than shmem max "
+                        "(%zu)",
+                        unsigned(profiler_current_process_id().ToNumber()), len,
+                        size_t(UINT32_MAX));
+                    if (parameters->profilerChild->AllocShmem(
+                            message.Length() + 1, &shmem)) {
+                      strcpy(shmem.get<char>(), message.Data());
+                    }
+                  }
                   writer = nullptr;
                 } else {
                   // No profile, send an empty string.
                   if (parameters->profilerChild->AllocShmem(1, &shmem)) {
                     shmem.get<char>()[0] = '\0';
                   }
                 }
 
--- a/tools/profiler/gecko/nsProfiler.cpp
+++ b/tools/profiler/gecko/nsProfiler.cpp
@@ -1251,17 +1251,27 @@ RefPtr<nsProfiler::GatheringPromise> nsP
               self->LogEvent([&](Json::Value& aEvent) {
                 aEvent.append(
                     Json::StaticString{"Got profile from pid, with size:"});
                 aEvent.append(Json::Value::UInt64(childPid));
                 aEvent.append(Json::Value::UInt64{aResult.Size<char>()});
               });
               const nsDependentCSubstring profileString(
                   aResult.get<char>(), aResult.Size<char>() - 1);
-              self->GatheredOOPProfile(childPid, profileString);
+              if (profileString.IsEmpty() || profileString[0] != '*') {
+                self->GatheredOOPProfile(childPid, profileString);
+              } else {
+                self->LogEvent([&](Json::Value& aEvent) {
+                  aEvent.append(Json::StaticString{
+                      "Child non-profile from pid, with error message:"});
+                  aEvent.append(Json::Value::UInt64(childPid));
+                  aEvent.append(profileString.Data() + 1);
+                });
+                self->GatheredOOPProfile(childPid, ""_ns);
+              }
             } else {
               // This can happen if the child failed to allocate
               // the Shmem (or maliciously sent an invalid Shmem).
               self->LogEvent([&](Json::Value& aEvent) {
                 aEvent.append(Json::StaticString{"Got failure from pid:"});
                 aEvent.append(Json::Value::UInt64(childPid));
               });
               self->GatheredOOPProfile(childPid, ""_ns);