Bug 1458246 - Use Shmem to pass the profiler data to be able to send large profiler data r?mstange draft
authorNazım Can Altınova <canaltinova@gmail.com>
Fri, 01 Jun 2018 19:28:32 +0200
changeset 803985 f646388b2f2db50e9747013d828d8cf28f674680
parent 801916 3931f461c8e8668a264d52b51a4524aac39a7a16
push id112257
push userbmo:canaltinova@gmail.com
push dateTue, 05 Jun 2018 09:07:08 +0000
reviewersmstange
bugs1458246
milestone62.0a1
Bug 1458246 - Use Shmem to pass the profiler data to be able to send large profiler data r?mstange We were using nsCString to pass the profiler data between processes. But it was failing to send because there is a ~256MB limit for the string data. So we changed it to use Shmem instead. Shmem creates a shared memory and passes the weak reference. With it, we can send larger data without having a problem. MozReview-Commit-ID: 1kj57fZDXVF
tools/profiler/gecko/PProfiler.ipdl
tools/profiler/gecko/ProfilerChild.cpp
tools/profiler/gecko/nsProfiler.cpp
tools/profiler/public/ProfilerChild.h
tools/profiler/public/ProfilerParent.h
--- a/tools/profiler/gecko/PProfiler.ipdl
+++ b/tools/profiler/gecko/PProfiler.ipdl
@@ -18,13 +18,13 @@ async protocol PProfiler
 {
 child:
   async Start(ProfilerInitParams params);
   async EnsureStarted(ProfilerInitParams params);
   async Stop();
   async Pause();
   async Resume();
 
-  async GatherProfile() returns (nsCString profile);
+  async GatherProfile() returns (Shmem profile);
 };
 
 } // namespace mozilla
 
--- a/tools/profiler/gecko/ProfilerChild.cpp
+++ b/tools/profiler/gecko/ProfilerChild.cpp
@@ -83,20 +83,36 @@ CollectProfileOrEmptyString(bool aIsShut
   if (profile) {
     profileCString = nsCString(profile.get(), strlen(profile.get()));
   } else {
     profileCString = EmptyCString();
   }
   return profileCString;
 }
 
+Shmem
+ProfilerChild::ConvertProfileStringToShmem(const nsCString& aProfileCString) {
+  Shmem shmem;
+  if (!AllocShmem(aProfileCString.Length(),
+                  SharedMemory::TYPE_BASIC,
+                  &shmem)) {
+    return shmem;
+  }
+
+  PodCopy(shmem.get<char>(),
+          aProfileCString.BeginReading(),
+          aProfileCString.Length());
+  return shmem;
+}
+
 mozilla::ipc::IPCResult
 ProfilerChild::RecvGatherProfile(GatherProfileResolver&& aResolve)
 {
-  aResolve(CollectProfileOrEmptyString(/* aIsShuttingDown */ false));
+  nsCString profile = CollectProfileOrEmptyString(/* aIsShuttingDown */ false);
+  aResolve(ConvertProfileStringToShmem(profile));
   return IPC_OK();
 }
 
 void
 ProfilerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
 {
   mDestroyed = true;
 }
--- a/tools/profiler/gecko/nsProfiler.cpp
+++ b/tools/profiler/gecko/nsProfiler.cpp
@@ -613,18 +613,20 @@ nsProfiler::StartGathering(double aSince
   // until FinishGathering() is called. As profiles from the other processes
   // come in, they will be inserted and end up in the right spot.
   // FinishGathering() will close the array and the root object.
 
   mPendingProfiles = profiles.Length();
   RefPtr<nsProfiler> self = this;
   for (auto profile : profiles) {
     profile->Then(GetMainThreadSerialEventTarget(), __func__,
-      [self](const nsCString& aResult) {
-        self->GatheredOOPProfile(aResult);
+      [self](const mozilla::ipc::Shmem& aResult) {
+        const nsDependentCString profileString(aResult.get<char>(),
+                                               aResult.Size<char>());
+        self->GatheredOOPProfile(profileString);
       },
       [self](ipc::ResponseRejectReason aReason) {
         self->GatheredOOPProfile(NS_LITERAL_CSTRING(""));
       });
   }
   if (!mPendingProfiles) {
     FinishGathering();
   }
--- a/tools/profiler/public/ProfilerChild.h
+++ b/tools/profiler/public/ProfilerChild.h
@@ -13,17 +13,18 @@
 class nsIThread;
 
 namespace mozilla {
 
 // The ProfilerChild actor is created in all processes except for the main
 // process. The corresponding ProfilerParent actor is created in the main
 // process, and it will notify us about profiler state changes and request
 // profiles from us.
-class ProfilerChild final : public PProfilerChild
+class ProfilerChild final : public PProfilerChild,
+                            public mozilla::ipc::IShmemAllocator
 {
   NS_INLINE_DECL_REFCOUNTING(ProfilerChild)
 
   ProfilerChild();
 
   // Collects and returns a profile.
   // 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
@@ -38,16 +39,19 @@ private:
   mozilla::ipc::IPCResult RecvStart(const ProfilerInitParams& params) override;
   mozilla::ipc::IPCResult RecvEnsureStarted(const ProfilerInitParams& params) override;
   mozilla::ipc::IPCResult RecvStop() override;
   mozilla::ipc::IPCResult RecvPause() override;
   mozilla::ipc::IPCResult RecvResume() override;
   mozilla::ipc::IPCResult RecvGatherProfile(GatherProfileResolver&& aResolve) override;
 
   void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
+  Shmem ConvertProfileStringToShmem(const nsCString& profile);
+
+  FORWARD_SHMEM_ALLOCATOR_TO(PProfilerChild)
 
   nsCOMPtr<nsIThread> mThread;
   bool mDestroyed;
 };
 
 } // namespace mozilla
 
 #endif  // ProfilerChild_h
--- a/tools/profiler/public/ProfilerParent.h
+++ b/tools/profiler/public/ProfilerParent.h
@@ -30,17 +30,17 @@ class ProfilerParentTracker;
 // and handles shutdown.
 class ProfilerParent final : public PProfilerParent
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(ProfilerParent)
 
   static mozilla::ipc::Endpoint<PProfilerChild> CreateForProcess(base::ProcessId aOtherPid);
 
-  typedef MozPromise<nsCString, ResponseRejectReason, false> SingleProcessProfilePromise;
+  typedef MozPromise<Shmem, ResponseRejectReason, true> SingleProcessProfilePromise;
 
   // The following static methods can be called on any thread, but they are
   // no-ops on anything other than the main thread.
   // If called on the main thread, the call will be broadcast to all
   // registered processes (all processes for which we have a ProfilerParent
   // object).
   // At the moment, the main process always calls these methods on the main
   // thread, and that's the only process in which we need to forward these