Bug 1466783 - Avoid copying while passing the profiler data with IPC r?mstange
MozReview-Commit-ID: HfskcLojToC
--- a/tools/profiler/core/ProfileJSONWriter.cpp
+++ b/tools/profiler/core/ProfileJSONWriter.cpp
@@ -32,33 +32,50 @@ ChunkedJSONWriteFunc::Write(const char*
}
memcpy(mChunkPtr, aStr, len);
*newPtr = '\0';
mChunkPtr = newPtr;
mChunkLengths.back() += len;
}
-mozilla::UniquePtr<char[]>
-ChunkedJSONWriteFunc::CopyData() const
+size_t
+ChunkedJSONWriteFunc::GetTotalLength() const
{
MOZ_ASSERT(mChunkLengths.length() == mChunkList.length());
size_t totalLen = 1;
for (size_t i = 0; i < mChunkLengths.length(); i++) {
MOZ_ASSERT(strlen(mChunkList[i].get()) == mChunkLengths[i]);
totalLen += mChunkLengths[i];
}
- mozilla::UniquePtr<char[]> c = mozilla::MakeUnique<char[]>(totalLen);
- char* ptr = c.get();
+ return totalLen;
+}
+
+void
+ChunkedJSONWriteFunc::CopyDataIntoLazilyAllocatedBuffer(
+ const std::function<char*(size_t)>& aAllocator) const
+{
+ size_t totalLen = GetTotalLength();
+ char* ptr = aAllocator(totalLen);
for (size_t i = 0; i < mChunkList.length(); i++) {
size_t len = mChunkLengths[i];
memcpy(ptr, mChunkList[i].get(), len);
ptr += len;
}
*ptr = '\0';
+}
+
+mozilla::UniquePtr<char[]>
+ChunkedJSONWriteFunc::CopyData() const
+{
+ mozilla::UniquePtr<char[]> c;
+ CopyDataIntoLazilyAllocatedBuffer([&](size_t allocationSize) {
+ c = mozilla::MakeUnique<char[]>(allocationSize);
+ return c.get();
+ });
return c;
}
void
ChunkedJSONWriteFunc::Take(ChunkedJSONWriteFunc&& aOther)
{
for (size_t i = 0; i < aOther.mChunkList.length(); i++) {
MOZ_ALWAYS_TRUE(mChunkLengths.append(aOther.mChunkLengths[i]));
--- a/tools/profiler/core/ProfileJSONWriter.h
+++ b/tools/profiler/core/ProfileJSONWriter.h
@@ -32,18 +32,23 @@ public:
bool IsEmpty() const {
MOZ_ASSERT_IF(!mChunkPtr, !mChunkEnd &&
mChunkList.length() == 0 &&
mChunkLengths.length() == 0);
return !mChunkPtr;
}
void Write(const char* aStr) override;
+ void CopyDataIntoLazilyAllocatedBuffer(
+ const std::function<char*(size_t)>& aAllocator) const;
mozilla::UniquePtr<char[]> CopyData() const;
void Take(ChunkedJSONWriteFunc&& aOther);
+ // Returns the byte length of the complete combined string, including the
+ // null terminator byte.
+ size_t GetTotalLength() const;
private:
void AllocChunk(size_t aChunkSize);
static const size_t kChunkSize = 4096 * 512;
// Pointer for writing inside the current chunk.
//
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2652,39 +2652,67 @@ profiler_shutdown()
// profiler_stop() explain why.
if (samplerThread) {
ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
delete samplerThread;
}
}
+static bool
+WriteProfileToJSONWriter(SpliceableChunkedJSONWriter& aWriter,
+ double aSinceTime,
+ bool aIsShuttingDown)
+{
+ LOG("WriteProfileToJSONWriter");
+
+ MOZ_RELEASE_ASSERT(CorePS::Exists());
+
+ aWriter.Start();
+ {
+ if (!profiler_stream_json_for_this_process(
+ aWriter, aSinceTime, aIsShuttingDown)) {
+ return false;
+ }
+
+ // Don't include profiles from other processes because this is a
+ // synchronous function.
+ aWriter.StartArrayProperty("processes");
+ aWriter.EndArray();
+ }
+ aWriter.End();
+ return true;
+}
+
UniquePtr<char[]>
profiler_get_profile(double aSinceTime, bool aIsShuttingDown)
{
LOG("profiler_get_profile");
- MOZ_RELEASE_ASSERT(CorePS::Exists());
+ SpliceableChunkedJSONWriter b;
+ if (!WriteProfileToJSONWriter(b, aSinceTime, aIsShuttingDown)) {
+ return nullptr;
+ }
+ return b.WriteFunc()->CopyData();
+}
+
+void
+profiler_get_profile_json_into_lazily_allocated_buffer(
+ const std::function<char*(size_t)>& aAllocator,
+ double aSinceTime,
+ bool aIsShuttingDown)
+{
+ LOG("profiler_get_profile_json_into_lazily_allocated_buffer");
SpliceableChunkedJSONWriter b;
- b.Start();
- {
- if (!profiler_stream_json_for_this_process(b, aSinceTime,
- aIsShuttingDown)) {
- return nullptr;
- }
-
- // Don't include profiles from other processes because this is a
- // synchronous function.
- b.StartArrayProperty("processes");
- b.EndArray();
+ if (!WriteProfileToJSONWriter(b, aSinceTime, aIsShuttingDown)) {
+ return;
}
- b.End();
-
- return b.WriteFunc()->CopyData();
+
+ b.WriteFunc()->CopyDataIntoLazilyAllocatedBuffer(aAllocator);
}
void
profiler_get_start_params(int* aEntries, double* aInterval, uint32_t* aFeatures,
Vector<const char*>* aFilters)
{
MOZ_RELEASE_ASSERT(CorePS::Exists());
--- a/tools/profiler/gecko/ProfilerChild.cpp
+++ b/tools/profiler/gecko/ProfilerChild.cpp
@@ -83,36 +83,32 @@ 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)
{
- nsCString profile = CollectProfileOrEmptyString(/* aIsShuttingDown */ false);
- aResolve(ConvertProfileStringToShmem(profile));
+ mozilla::ipc::Shmem shmem;
+ profiler_get_profile_json_into_lazily_allocated_buffer(
+ [&](size_t allocationSize) -> char* {
+ if (AllocShmem(allocationSize,
+ mozilla::ipc::Shmem::SharedMemory::TYPE_BASIC,
+ &shmem)) {
+ return shmem.get<char>();
+ }
+ return nullptr;
+ },
+ /* aSinceTime */ 0,
+ /* aIsShuttingDown */ false);
+ aResolve(std::move(shmem));
return IPC_OK();
}
void
ProfilerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
{
mDestroyed = true;
}
--- a/tools/profiler/public/ProfilerChild.h
+++ b/tools/profiler/public/ProfilerChild.h
@@ -39,17 +39,16 @@ 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