Bug 1166492 - Return UniquePtr<char[]> from profiler_get_profile to avoid double copying. (r=mstange)
authorShu-yu Guo <shu@rfrn.org>
Tue, 26 May 2015 22:58:40 -0700
changeset 268020 588c920f963c444724feb1e575b8ff1af2ead106
parent 268019 7eb1c387ca5f019a8f7d416f7733e567ffac9d67
child 268021 1118d069545209d920f317f508195e675ec4cfb4
push id2294
push userbsmedberg@mozilla.com
push dateWed, 27 May 2015 15:05:10 +0000
reviewersmstange
bugs1166492
milestone41.0a1
Bug 1166492 - Return UniquePtr<char[]> from profiler_get_profile to avoid double copying. (r=mstange)
dom/ipc/ContentChild.cpp
dom/plugins/ipc/PluginModuleChild.cpp
tools/profiler/GeckoProfiler.h
tools/profiler/GeckoProfilerFunc.h
tools/profiler/GeckoProfilerImpl.h
tools/profiler/TableTicker.cpp
tools/profiler/TableTicker.h
tools/profiler/nsProfiler.cpp
tools/profiler/platform.cpp
widget/android/AndroidJNI.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2650,20 +2650,19 @@ ContentChild::RecvStopProfiler()
 {
     profiler_stop();
     return true;
 }
 
 bool
 ContentChild::RecvGetProfile(nsCString* aProfile)
 {
-    char* profile = profiler_get_profile();
+    UniquePtr<char[]> profile = profiler_get_profile();
     if (profile) {
-        *aProfile = nsCString(profile, strlen(profile));
-        free(profile);
+        *aProfile = nsCString(profile.get(), strlen(profile.get()));
     } else {
         *aProfile = EmptyCString();
     }
     return true;
 }
 
 bool
 ContentChild::RecvLoadPluginResult(const uint32_t& aPluginId, const bool& aResult)
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -2561,17 +2561,16 @@ PluginModuleChild::RecvStopProfiler()
 {
     profiler_stop();
     return true;
 }
 
 bool
 PluginModuleChild::AnswerGetProfile(nsCString* aProfile)
 {
-    char* profile = profiler_get_profile();
+    UniquePtr<char[]> profile = profiler_get_profile();
     if (profile != nullptr) {
-        *aProfile = nsCString(profile, strlen(profile));
-        free(profile);
+        *aProfile = nsCString(profile.get(), strlen(profile.get()));
     } else {
         *aProfile = nsCString("", 0);
     }
     return true;
 }
--- a/tools/profiler/GeckoProfiler.h
+++ b/tools/profiler/GeckoProfiler.h
@@ -45,16 +45,17 @@
  * 't' - Elapse time since recording started.
  *
  */
 
 #ifndef SAMPLER_H
 #define SAMPLER_H
 
 #include "js/TypeDecls.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 class TimeStamp;
 }
 
 enum TracingMetadata {
   TRACING_DEFAULT,
   TRACING_INTERVAL_START,
@@ -154,17 +155,19 @@ static inline bool profiler_feature_acti
 
 // Internal-only. Used by the event tracer.
 static inline void profiler_responsiveness(const mozilla::TimeStamp& aTime) {}
 
 // Internal-only.
 static inline void profiler_set_frame_number(int frameNumber) {}
 
 // Get the profile encoded as a JSON string.
-static inline char* profiler_get_profile(float aSinceTime = 0) { return nullptr; }
+static inline mozilla::UniquePtr<char[]> profiler_get_profile(float aSinceTime = 0) {
+  return nullptr;
+}
 
 // Get the profile encoded as a JSON object.
 static inline JSObject* profiler_get_profile_jsobject(JSContext* aCx,
                                                       float aSinceTime = 0) {
   return nullptr;
 }
 
 // Get the profile and write it into a file
--- a/tools/profiler/GeckoProfilerFunc.h
+++ b/tools/profiler/GeckoProfilerFunc.h
@@ -3,16 +3,17 @@
  * 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 PROFILER_FUNCS_H
 #define PROFILER_FUNCS_H
 
 #include "js/TypeDecls.h"
 #include "js/ProfilingStack.h"
+#include "mozilla/UniquePtr.h"
 #include <stdint.h>
 
 namespace mozilla {
 class TimeStamp;
 }
 
 class ProfilerBacktrace;
 class ProfilerMarkerPayload;
@@ -48,17 +49,17 @@ bool mozilla_sampler_feature_active(cons
 void mozilla_sampler_responsiveness(const mozilla::TimeStamp& time);
 
 void mozilla_sampler_frame_number(int frameNumber);
 
 const double* mozilla_sampler_get_responsiveness();
 
 void mozilla_sampler_save();
 
-char* mozilla_sampler_get_profile(float aSinceTime);
+mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(float aSinceTime);
 
 JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime);
 
 // Make this function easily callable from a debugger in a build without
 // debugging information (work around http://llvm.org/bugs/show_bug.cgi?id=22211)
 extern "C" {
   void mozilla_sampler_save_profile_to_file(const char* aFilename);
 }
--- a/tools/profiler/GeckoProfilerImpl.h
+++ b/tools/profiler/GeckoProfilerImpl.h
@@ -139,17 +139,17 @@ void profiler_responsiveness(const mozil
 
 static inline
 void profiler_set_frame_number(int frameNumber)
 {
   return mozilla_sampler_frame_number(frameNumber);
 }
 
 static inline
-char* profiler_get_profile(float aSinceTime = 0)
+mozilla::UniquePtr<char[]> profiler_get_profile(float aSinceTime = 0)
 {
   return mozilla_sampler_get_profile(aSinceTime);
 }
 
 static inline
 JSObject* profiler_get_profile_jsobject(JSContext* aCx, float aSinceTime = 0)
 {
   return mozilla_sampler_get_profile_data(aCx, aSinceTime);
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -213,26 +213,31 @@ void TableTicker::ToStreamAsJSON(std::os
   SpliceableJSONWriter b(mozilla::MakeUnique<OStreamJSONWriteFunc>(stream));
   StreamJSON(b, aSinceTime);
 }
 
 JSObject* TableTicker::ToJSObject(JSContext *aCx, float aSinceTime)
 {
   JS::RootedValue val(aCx);
   {
-    SpliceableChunkedJSONWriter b;
-    StreamJSON(b, aSinceTime);
-    UniquePtr<char[]> buf = b.WriteFunc()->CopyData();
+    UniquePtr<char[]> buf = ToJSON(aSinceTime);
     NS_ConvertUTF8toUTF16 js_string(nsDependentCString(buf.get()));
     MOZ_ALWAYS_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()),
                                  js_string.Length(), &val));
   }
   return &val.toObject();
 }
 
+UniquePtr<char[]> TableTicker::ToJSON(float aSinceTime)
+{
+  SpliceableChunkedJSONWriter b;
+  StreamJSON(b, aSinceTime);
+  return b.WriteFunc()->CopyData();
+}
+
 struct SubprocessClosure {
   explicit SubprocessClosure(SpliceableJSONWriter *aWriter)
     : mWriter(aWriter)
   {}
 
   SpliceableJSONWriter* mWriter;
 };
 
--- a/tools/profiler/TableTicker.h
+++ b/tools/profiler/TableTicker.h
@@ -189,16 +189,17 @@ class TableTicker: public Sampler {
       }
     }
 
     return mPrimaryThreadProfile;
   }
 
   void ToStreamAsJSON(std::ostream& stream, float aSinceTime = 0);
   virtual JSObject *ToJSObject(JSContext *aCx, float aSinceTime = 0);
+  mozilla::UniquePtr<char[]> ToJSON(float aSinceTime = 0);
   void StreamMetaJSCustomObject(SpliceableJSONWriter& aWriter);
   void StreamTaskTracer(SpliceableJSONWriter& aWriter);
   void FlushOnJSShutdown(JSRuntime* aRuntime);
   bool ProfileJS() const { return mProfileJS; }
   bool ProfileJava() const { return mProfileJava; }
   bool ProfileGPU() const { return mProfileGPU; }
   bool ProfilePower() const { return mProfilePower; }
   bool ProfileThreads() const override { return mProfileThreads; }
--- a/tools/profiler/nsProfiler.cpp
+++ b/tools/profiler/nsProfiler.cpp
@@ -114,24 +114,23 @@ nsProfiler::AddMarker(const char *aMarke
 {
   PROFILER_MARKER(aMarker);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsProfiler::GetProfile(float aSinceTime, char **aProfile)
 {
-  char *profile = profiler_get_profile(aSinceTime);
+  mozilla::UniquePtr<char[]> profile = profiler_get_profile(aSinceTime);
   if (profile) {
-    size_t len = strlen(profile);
+    size_t len = strlen(profile.get());
     char *profileStr = static_cast<char *>
-                         (nsMemory::Clone(profile, (len + 1) * sizeof(char)));
+                         (nsMemory::Clone(profile.get(), (len + 1) * sizeof(char)));
     profileStr[len] = '\0';
     *aProfile = profileStr;
-    free(profile);
   }
   return NS_OK;
 }
 
 static void
 AddSharedLibraryInfoToStream(std::ostream& aStream, const SharedLibrary& aLib)
 {
   aStream << "{";
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -556,27 +556,24 @@ void mozilla_sampler_save()
   }
 
   t->RequestSave();
   // We're on the main thread already so we don't
   // have to wait to handle the save request.
   t->HandleSaveRequest();
 }
 
-char* mozilla_sampler_get_profile(float aSinceTime)
+mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(float aSinceTime)
 {
   TableTicker *t = tlsTicker.get();
   if (!t) {
     return nullptr;
   }
 
-  std::stringstream stream;
-  t->ToStreamAsJSON(stream, aSinceTime);
-  char* profile = strdup(stream.str().c_str());
-  return profile;
+  return t->ToJSON(aSinceTime);
 }
 
 JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime)
 {
   TableTicker *t = tlsTicker.get();
   if (!t) {
     return nullptr;
   }
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -1007,19 +1007,18 @@ Java_org_mozilla_gecko_ANRReporter_getNa
         // Maybe profiler support is disabled?
         return nullptr;
     }
 
     // Timeout if we don't get a profiler sample after 5 seconds.
     const PRIntervalTime timeout = PR_SecondsToInterval(5);
     const PRIntervalTime startTime = PR_IntervalNow();
 
-    typedef struct { void operator()(void* p) { free(p); } } ProfilePtrPolicy;
     // Pointer to a profile JSON string
-    typedef mozilla::UniquePtr<char, ProfilePtrPolicy> ProfilePtr;
+    typedef mozilla::UniquePtr<char[]> ProfilePtr;
 
     ProfilePtr profile(profiler_get_profile());
 
     while (profile && !strstr(profile.get(), "\"samples\":[{")) {
         // no sample yet?
         if (PR_IntervalNow() - startTime >= timeout) {
             return nullptr;
         }