Bug 1557789 - Expose subcategory information in the profile JSON. r=njn
authorMarkus Stange <mstange@themasta.com>
Tue, 02 Jul 2019 17:27:13 +0000
changeset 540654 1f407c83db16381332d82bcfa992eea1022284ac
parent 540653 6525ac41c35455512bc1b681df331a5b74cb75cc
child 540655 dd501b160508c7dedf613941135707435b2e42c1
push id11529
push userarchaeopteryx@coole-files.de
push dateThu, 04 Jul 2019 15:22:33 +0000
treeherdermozilla-beta@ebb510a784b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1557789, 1500692
milestone69.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 1557789 - Expose subcategory information in the profile JSON. r=njn This was reviewed before in bug 1500692. Differential Revision: https://phabricator.services.mozilla.com/D11338
mozglue/baseprofiler/core/ProfileBufferEntry.cpp
mozglue/baseprofiler/core/ProfileBufferEntry.h
mozglue/baseprofiler/core/ProfiledThreadData.cpp
mozglue/baseprofiler/core/platform.cpp
tools/profiler/core/ProfileBufferEntry.cpp
tools/profiler/core/ProfileBufferEntry.h
tools/profiler/core/ProfiledThreadData.cpp
tools/profiler/core/platform.cpp
--- a/mozglue/baseprofiler/core/ProfileBufferEntry.cpp
+++ b/mozglue/baseprofiler/core/ProfileBufferEntry.cpp
@@ -321,17 +321,18 @@ void UniqueStacks::StreamNonJITFrame(con
 
   enum Schema : uint32_t {
     LOCATION = 0,
     RELEVANT_FOR_JS = 1,
     IMPLEMENTATION = 2,
     OPTIMIZATIONS = 3,
     LINE = 4,
     COLUMN = 5,
-    CATEGORY = 6
+    CATEGORY = 6,
+    SUBCATEGORY = 7
   };
 
   AutoArraySchemaWriter writer(mFrameTableWriter, *mUniqueStrings);
 
   const NormalFrameData& data = aFrame.mData.as<NormalFrameData>();
   writer.StringElement(LOCATION, data.mLocation.c_str());
   writer.BoolElement(RELEVANT_FOR_JS, data.mRelevantForJS);
   if (data.mLine.isSome()) {
@@ -339,16 +340,17 @@ void UniqueStacks::StreamNonJITFrame(con
   }
   if (data.mColumn.isSome()) {
     writer.IntElement(COLUMN, *data.mColumn);
   }
   if (data.mCategoryPair.isSome()) {
     const ProfilingCategoryPairInfo& info =
         GetProfilingCategoryPairInfo(*data.mCategoryPair);
     writer.IntElement(CATEGORY, uint32_t(info.mCategory));
+    writer.IntElement(SUBCATEGORY, info.mSubcategoryIndex);
   }
 }
 
 struct CStringWriteFunc : public JSONWriteFunc {
   std::string& mBuffer;  // The struct must not outlive this buffer
   explicit CStringWriteFunc(std::string& aBuffer) : mBuffer(aBuffer) {}
 
   void Write(const char* aStr) override { mBuffer += aStr; }
--- a/mozglue/baseprofiler/core/ProfileBufferEntry.h
+++ b/mozglue/baseprofiler/core/ProfileBufferEntry.h
@@ -339,21 +339,24 @@ class UniqueStacks {
 //     ]
 //   },
 //
 //   "frameTable":
 //   {
 //     "schema":
 //     {
 //       "location": 0,       /* index into stringTable */
-//       "implementation": 1, /* index into stringTable */
-//       "optimizations": 2,  /* arbitrary JSON */
-//       "line": 3,           /* number */
-//       "column": 4,         /* number */
-//       "category": 5        /* number */
+//       "relevantForJS": 1,  /* bool */
+//       "implementation": 2, /* index into stringTable */
+//       "optimizations": 3,  /* arbitrary JSON */
+//       "line": 4,           /* number */
+//       "column": 5,         /* number */
+//       "category": 6        /* index into profile.meta.categories */
+//       "subcategory": 7     /* index into
+//       profile.meta.categories[category].subcategories */
 //     },
 //     "data":
 //     [
 //       [ 0 ],               /* { location: '(root)' } */
 //       [ 1, 2 ]             /* { location: 'foo.js',
 //                                 implementation: 'baseline' } */
 //     ]
 //   },
--- a/mozglue/baseprofiler/core/ProfiledThreadData.cpp
+++ b/mozglue/baseprofiler/core/ProfiledThreadData.cpp
@@ -59,16 +59,17 @@ void ProfiledThreadData::StreamJSON(cons
         JSONSchemaWriter schema(aWriter);
         schema.WriteField("location");
         schema.WriteField("relevantForJS");
         schema.WriteField("implementation");
         schema.WriteField("optimizations");
         schema.WriteField("line");
         schema.WriteField("column");
         schema.WriteField("category");
+        schema.WriteField("subcategory");
       }
 
       aWriter.StartArrayProperty("data");
       { uniqueStacks.SpliceFrameTableElements(aWriter); }
       aWriter.EndArray();
     }
     aWriter.EndObject();
 
--- a/mozglue/baseprofiler/core/platform.cpp
+++ b/mozglue/baseprofiler/core/platform.cpp
@@ -1492,24 +1492,45 @@ void AppendSharedLibraries(JSONWriter& a
   SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf();
   info.SortByAddress();
   for (size_t i = 0; i < info.GetSize(); i++) {
     AddSharedLibraryInfoToStream(aWriter, info.GetEntry(i));
   }
 }
 
 static void StreamCategories(SpliceableJSONWriter& aWriter) {
-  // Same order as ProfilingCategory.
+  // Same order as ProfilingCategory. Format:
+  // [
+  //   {
+  //     name: "Idle",
+  //     color: "transparent",
+  //     subcategories: ["Other"],
+  //   },
+  //   {
+  //     name: "Other",
+  //     color: "grey",
+  //     subcategories: [
+  //       "JSM loading",
+  //       "Subprocess launching",
+  //       "DLL loading"
+  //     ]
+  //   },
+  //   ...
+  // ]
 
 #  define CATEGORY_JSON_BEGIN_CATEGORY(name, labelAsString, color) \
     aWriter.Start();                                               \
     aWriter.StringProperty("name", labelAsString);                 \
-    aWriter.StringProperty("color", color);
-#  define CATEGORY_JSON_SUBCATEGORY(category, name, labelAsString)
-#  define CATEGORY_JSON_END_CATEGORY aWriter.EndObject();
+    aWriter.StringProperty("color", color);                        \
+    aWriter.StartArrayProperty("subcategories");
+#  define CATEGORY_JSON_SUBCATEGORY(supercategory, name, labelAsString) \
+    aWriter.StringElement(labelAsString);
+#  define CATEGORY_JSON_END_CATEGORY \
+    aWriter.EndArray();              \
+    aWriter.EndObject();
 
   BASE_PROFILING_CATEGORY_LIST(CATEGORY_JSON_BEGIN_CATEGORY,
                                CATEGORY_JSON_SUBCATEGORY,
                                CATEGORY_JSON_END_CATEGORY)
 
 #  undef CATEGORY_JSON_BEGIN_CATEGORY
 #  undef CATEGORY_JSON_SUBCATEGORY
 #  undef CATEGORY_JSON_END_CATEGORY
@@ -1517,17 +1538,17 @@ static void StreamCategories(SpliceableJ
 
 static int64_t MicrosecondsSince1970();
 
 static void StreamMetaJSCustomObject(PSLockRef aLock,
                                      SpliceableJSONWriter& aWriter,
                                      bool aIsShuttingDown) {
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
-  aWriter.IntProperty("version", 15);
+  aWriter.IntProperty("version", 16);
 
   // The "startTime" field holds the number of milliseconds since midnight
   // January 1, 1970 GMT. This grotty code computes (Now - (Now -
   // ProcessStartTime)) to convert CorePS::ProcessStartTime() into that form.
   TimeDuration delta = TimeStamp::NowUnfuzzed() - CorePS::ProcessStartTime();
   aWriter.DoubleProperty(
       "startTime", MicrosecondsSince1970() / 1000.0 - delta.ToMilliseconds());
 
--- a/tools/profiler/core/ProfileBufferEntry.cpp
+++ b/tools/profiler/core/ProfileBufferEntry.cpp
@@ -479,17 +479,18 @@ void UniqueStacks::StreamNonJITFrame(con
 
   enum Schema : uint32_t {
     LOCATION = 0,
     RELEVANT_FOR_JS = 1,
     IMPLEMENTATION = 2,
     OPTIMIZATIONS = 3,
     LINE = 4,
     COLUMN = 5,
-    CATEGORY = 6
+    CATEGORY = 6,
+    SUBCATEGORY = 7
   };
 
   AutoArraySchemaWriter writer(mFrameTableWriter, *mUniqueStrings);
 
   const NormalFrameData& data = aFrame.mData.as<NormalFrameData>();
   writer.StringElement(LOCATION, data.mLocation.get());
   writer.BoolElement(RELEVANT_FOR_JS, data.mRelevantForJS);
   if (data.mLine.isSome()) {
@@ -497,16 +498,17 @@ void UniqueStacks::StreamNonJITFrame(con
   }
   if (data.mColumn.isSome()) {
     writer.IntElement(COLUMN, *data.mColumn);
   }
   if (data.mCategoryPair.isSome()) {
     const JS::ProfilingCategoryPairInfo& info =
         JS::GetProfilingCategoryPairInfo(*data.mCategoryPair);
     writer.IntElement(CATEGORY, uint32_t(info.mCategory));
+    writer.IntElement(SUBCATEGORY, info.mSubcategoryIndex);
   }
 }
 
 static void StreamJITFrameOptimizations(
     SpliceableJSONWriter& aWriter, UniqueJSONStrings& aUniqueStrings,
     JSContext* aContext, const JS::ProfiledFrameHandle& aJITFrame) {
   aWriter.StartObjectElement();
   {
@@ -598,17 +600,18 @@ static void StreamJITFrame(JSContext* aC
                            const JS::ProfiledFrameHandle& aJITFrame) {
   enum Schema : uint32_t {
     LOCATION = 0,
     RELEVANT_FOR_JS = 1,
     IMPLEMENTATION = 2,
     OPTIMIZATIONS = 3,
     LINE = 4,
     COLUMN = 5,
-    CATEGORY = 6
+    CATEGORY = 6,
+    SUBCATEGORY = 7
   };
 
   AutoArraySchemaWriter writer(aWriter, aUniqueStrings);
 
   writer.StringElement(LOCATION, aJITFrame.label());
   writer.BoolElement(RELEVANT_FOR_JS, false);
 
   JS::ProfilingFrameIterator::FrameKind frameKind = aJITFrame.frameKind();
@@ -621,16 +624,21 @@ static void StreamJITFrame(JSContext* aC
   if (aJITFrame.hasTrackedOptimizations()) {
     writer.FreeFormElement(
         OPTIMIZATIONS,
         [&](SpliceableJSONWriter& aWriter, UniqueJSONStrings& aUniqueStrings) {
           StreamJITFrameOptimizations(aWriter, aUniqueStrings, aContext,
                                       aJITFrame);
         });
   }
+
+  const JS::ProfilingCategoryPairInfo& info =
+      JS::GetProfilingCategoryPairInfo(JS::ProfilingCategoryPair::JS);
+  writer.IntElement(CATEGORY, uint32_t(info.mCategory));
+  writer.IntElement(SUBCATEGORY, info.mSubcategoryIndex);
 }
 
 struct CStringWriteFunc : public JSONWriteFunc {
   nsACString& mBuffer;  // The struct must not outlive this buffer
   explicit CStringWriteFunc(nsACString& aBuffer) : mBuffer(aBuffer) {}
 
   void Write(const char* aStr) override { mBuffer.Append(aStr); }
 };
--- a/tools/profiler/core/ProfileBufferEntry.h
+++ b/tools/profiler/core/ProfileBufferEntry.h
@@ -464,21 +464,24 @@ class UniqueStacks {
 //     ]
 //   },
 //
 //   "frameTable":
 //   {
 //     "schema":
 //     {
 //       "location": 0,       /* index into stringTable */
-//       "implementation": 1, /* index into stringTable */
-//       "optimizations": 2,  /* arbitrary JSON */
-//       "line": 3,           /* number */
-//       "column": 4,         /* number */
-//       "category": 5        /* number */
+//       "relevantForJS": 1,  /* bool */
+//       "implementation": 2, /* index into stringTable */
+//       "optimizations": 3,  /* arbitrary JSON */
+//       "line": 4,           /* number */
+//       "column": 5,         /* number */
+//       "category": 6        /* index into profile.meta.categories */
+//       "subcategory": 7     /* index into
+//       profile.meta.categories[category].subcategories */
 //     },
 //     "data":
 //     [
 //       [ 0 ],               /* { location: '(root)' } */
 //       [ 1, 2 ]             /* { location: 'foo.js',
 //                                 implementation: 'baseline' } */
 //     ]
 //   },
--- a/tools/profiler/core/ProfiledThreadData.cpp
+++ b/tools/profiler/core/ProfiledThreadData.cpp
@@ -82,16 +82,17 @@ void ProfiledThreadData::StreamJSON(cons
         JSONSchemaWriter schema(aWriter);
         schema.WriteField("location");
         schema.WriteField("relevantForJS");
         schema.WriteField("implementation");
         schema.WriteField("optimizations");
         schema.WriteField("line");
         schema.WriteField("column");
         schema.WriteField("category");
+        schema.WriteField("subcategory");
       }
 
       aWriter.StartArrayProperty("data");
       { uniqueStacks.SpliceFrameTableElements(aWriter); }
       aWriter.EndArray();
     }
     aWriter.EndObject();
 
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -1837,39 +1837,60 @@ static void StreamTaskTracer(PSLockRef a
   aWriter.EndArray();
 
   aWriter.DoubleProperty("start",
                          static_cast<double>(tasktracer::GetStartTime()));
 #endif
 }
 
 static void StreamCategories(SpliceableJSONWriter& aWriter) {
-  // Same order as ProfilingCategory.
+  // Same order as ProfilingCategory. Format:
+  // [
+  //   {
+  //     name: "Idle",
+  //     color: "transparent",
+  //     subcategories: ["Other"],
+  //   },
+  //   {
+  //     name: "Other",
+  //     color: "grey",
+  //     subcategories: [
+  //       "JSM loading",
+  //       "Subprocess launching",
+  //       "DLL loading"
+  //     ]
+  //   },
+  //   ...
+  // ]
 
 #define CATEGORY_JSON_BEGIN_CATEGORY(name, labelAsString, color) \
   aWriter.Start();                                               \
   aWriter.StringProperty("name", labelAsString);                 \
-  aWriter.StringProperty("color", color);
-#define CATEGORY_JSON_SUBCATEGORY(category, name, labelAsString)
-#define CATEGORY_JSON_END_CATEGORY aWriter.EndObject();
+  aWriter.StringProperty("color", color);                        \
+  aWriter.StartArrayProperty("subcategories");
+#define CATEGORY_JSON_SUBCATEGORY(supercategory, name, labelAsString) \
+  aWriter.StringElement(labelAsString);
+#define CATEGORY_JSON_END_CATEGORY \
+  aWriter.EndArray();              \
+  aWriter.EndObject();
 
   PROFILING_CATEGORY_LIST(CATEGORY_JSON_BEGIN_CATEGORY,
                           CATEGORY_JSON_SUBCATEGORY, CATEGORY_JSON_END_CATEGORY)
 
 #undef CATEGORY_JSON_BEGIN_CATEGORY
 #undef CATEGORY_JSON_SUBCATEGORY
 #undef CATEGORY_JSON_END_CATEGORY
 }
 
 static void StreamMetaJSCustomObject(PSLockRef aLock,
                                      SpliceableJSONWriter& aWriter,
                                      bool aIsShuttingDown) {
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
-  aWriter.IntProperty("version", 15);
+  aWriter.IntProperty("version", 16);
 
   // The "startTime" field holds the number of milliseconds since midnight
   // January 1, 1970 GMT. This grotty code computes (Now - (Now -
   // ProcessStartTime)) to convert CorePS::ProcessStartTime() into that form.
   TimeDuration delta = TimeStamp::NowUnfuzzed() - CorePS::ProcessStartTime();
   aWriter.DoubleProperty(
       "startTime",
       static_cast<double>(PR_Now() / 1000.0 - delta.ToMilliseconds()));