tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ProfiledThreadData.cpp (6077B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ProfiledThreadData.h"
      8 
      9 #include "ProfileBuffer.h"
     10 
     11 #include "mozilla/BaseProfiler.h"
     12 #include "mozilla/BaseProfileJSONWriter.h"
     13 
     14 #if defined(GP_OS_darwin)
     15 #  include <pthread.h>
     16 #endif
     17 
     18 namespace mozilla {
     19 namespace baseprofiler {
     20 
     21 ProfiledThreadData::ProfiledThreadData(ThreadInfo* aThreadInfo)
     22    : mThreadInfo(aThreadInfo) {}
     23 
     24 ProfiledThreadData::~ProfiledThreadData() {}
     25 
     26 void ProfiledThreadData::StreamJSON(const ProfileBuffer& aBuffer,
     27                                    SpliceableJSONWriter& aWriter,
     28                                    const std::string& aProcessName,
     29                                    const std::string& aETLDplus1,
     30                                    const TimeStamp& aProcessStartTime,
     31                                    double aSinceTime) {
     32  UniqueStacks uniqueStacks;
     33 
     34  aWriter.SetUniqueStrings(uniqueStacks.UniqueStrings());
     35 
     36  aWriter.Start();
     37  {
     38    StreamSamplesAndMarkers(mThreadInfo->Name(), mThreadInfo->ThreadId(),
     39                            aBuffer, aWriter, aProcessName, aETLDplus1,
     40                            aProcessStartTime, mThreadInfo->RegisterTime(),
     41                            mUnregisterTime, aSinceTime, uniqueStacks);
     42 
     43    aWriter.StartObjectProperty("stackTable");
     44    {
     45      {
     46        JSONSchemaWriter schema(aWriter);
     47        schema.WriteField("prefix");
     48        schema.WriteField("frame");
     49      }
     50 
     51      aWriter.StartArrayProperty("data");
     52      {
     53        uniqueStacks.SpliceStackTableElements(aWriter);
     54      }
     55      aWriter.EndArray();
     56    }
     57    aWriter.EndObject();
     58 
     59    aWriter.StartObjectProperty("frameTable");
     60    {
     61      {
     62        JSONSchemaWriter schema(aWriter);
     63        schema.WriteField("location");
     64        schema.WriteField("relevantForJS");
     65        schema.WriteField("innerWindowID");
     66        schema.WriteField("implementation");
     67        schema.WriteField("line");
     68        schema.WriteField("column");
     69        schema.WriteField("category");
     70        schema.WriteField("subcategory");
     71      }
     72 
     73      aWriter.StartArrayProperty("data");
     74      {
     75        uniqueStacks.SpliceFrameTableElements(aWriter);
     76      }
     77      aWriter.EndArray();
     78    }
     79    aWriter.EndObject();
     80 
     81    aWriter.StartArrayProperty("stringTable");
     82    {
     83      std::move(uniqueStacks.UniqueStrings())
     84          .SpliceStringTableElements(aWriter);
     85    }
     86    aWriter.EndArray();
     87  }
     88  aWriter.End();
     89 
     90  aWriter.ResetUniqueStrings();
     91 }
     92 
     93 BaseProfilerThreadId StreamSamplesAndMarkers(
     94    const char* aName, BaseProfilerThreadId aThreadId,
     95    const ProfileBuffer& aBuffer, SpliceableJSONWriter& aWriter,
     96    const std::string& aProcessName, const std::string& aETLDplus1,
     97    const TimeStamp& aProcessStartTime, const TimeStamp& aRegisterTime,
     98    const TimeStamp& aUnregisterTime, double aSinceTime,
     99    UniqueStacks& aUniqueStacks) {
    100  BaseProfilerThreadId processedThreadId;
    101 
    102  aWriter.StringProperty(
    103      "processType",
    104      "(unknown)" /* XRE_GeckoProcessTypeToString(XRE_GetProcessType()) */);
    105 
    106  {
    107    std::string name = aName;
    108    // We currently need to distinguish threads output by Base Profiler from
    109    // those in Gecko Profiler, as the frontend could get confused and lose
    110    // tracks with the same name.
    111    // TODO: As part of the profilers de-duplication, thread data from both
    112    // profilers should end up in the same track, at which point this won't be
    113    // necessary anymore. See meta bug 1557566.
    114    name += " (pre-xul)";
    115    aWriter.StringProperty("name", name);
    116  }
    117 
    118  // Use given process name (if any).
    119  if (!aProcessName.empty()) {
    120    aWriter.StringProperty("processName", aProcessName);
    121  }
    122  if (!aETLDplus1.empty()) {
    123    aWriter.StringProperty("eTLD+1", aETLDplus1);
    124  }
    125 
    126  if (aRegisterTime) {
    127    aWriter.DoubleProperty(
    128        "registerTime", (aRegisterTime - aProcessStartTime).ToMilliseconds());
    129  } else {
    130    aWriter.NullProperty("registerTime");
    131  }
    132 
    133  if (aUnregisterTime) {
    134    aWriter.DoubleProperty(
    135        "unregisterTime",
    136        (aUnregisterTime - aProcessStartTime).ToMilliseconds());
    137  } else {
    138    aWriter.NullProperty("unregisterTime");
    139  }
    140 
    141  aWriter.StartObjectProperty("samples");
    142  {
    143    {
    144      JSONSchemaWriter schema(aWriter);
    145      schema.WriteField("stack");
    146      schema.WriteField("time");
    147      schema.WriteField("eventDelay");
    148    }
    149 
    150    aWriter.StartArrayProperty("data");
    151    {
    152      processedThreadId = aBuffer.StreamSamplesToJSON(
    153          aWriter, aThreadId, aSinceTime, aUniqueStacks);
    154    }
    155    aWriter.EndArray();
    156  }
    157  aWriter.EndObject();
    158 
    159  aWriter.StartObjectProperty("markers");
    160  {
    161    {
    162      JSONSchemaWriter schema(aWriter);
    163      schema.WriteField("name");
    164      schema.WriteField("startTime");
    165      schema.WriteField("endTime");
    166      schema.WriteField("phase");
    167      schema.WriteField("category");
    168      schema.WriteField("data");
    169    }
    170 
    171    aWriter.StartArrayProperty("data");
    172    {
    173      aBuffer.StreamMarkersToJSON(aWriter, aThreadId, aProcessStartTime,
    174                                  aSinceTime, aUniqueStacks);
    175    }
    176    aWriter.EndArray();
    177  }
    178  aWriter.EndObject();
    179 
    180  // Tech note: If `ToNumber()` returns a uint64_t, the conversion to int64_t is
    181  // "implementation-defined" before C++20. This is acceptable here, because
    182  // this is a one-way conversion to a unique identifier that's used to visually
    183  // separate data by thread on the front-end.
    184  aWriter.IntProperty(
    185      "pid", static_cast<int64_t>(profiler_current_process_id().ToNumber()));
    186  aWriter.IntProperty("tid",
    187                      static_cast<int64_t>(aThreadId.IsSpecified()
    188                                               ? aThreadId.ToNumber()
    189                                               : processedThreadId.ToNumber()));
    190 
    191  return processedThreadId;
    192 }
    193 
    194 }  // namespace baseprofiler
    195 }  // namespace mozilla