tor-browser

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

ProfilerBacktrace.cpp (5032B)


      1 /* -*- Mode: C++; tab-width: 8; 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 "ProfilerBacktrace.h"
      8 
      9 #include "ProfileBuffer.h"
     10 #include "ProfiledThreadData.h"
     11 #include "ThreadInfo.h"
     12 
     13 #include "mozilla/BaseProfiler.h"
     14 #include "mozilla/BaseProfileJSONWriter.h"
     15 
     16 namespace mozilla {
     17 namespace baseprofiler {
     18 
     19 ProfilerBacktrace::ProfilerBacktrace(
     20    const char* aName,
     21    UniquePtr<ProfileChunkedBuffer> aProfileChunkedBufferStorage,
     22    UniquePtr<ProfileBuffer> aProfileBufferStorageOrNull /* = nullptr */)
     23    : mName(aName),
     24      mOptionalProfileChunkedBufferStorage(
     25          std::move(aProfileChunkedBufferStorage)),
     26      mProfileChunkedBuffer(mOptionalProfileChunkedBufferStorage.get()),
     27      mOptionalProfileBufferStorage(std::move(aProfileBufferStorageOrNull)),
     28      mProfileBuffer(mOptionalProfileBufferStorage.get()) {
     29  if (mProfileBuffer) {
     30    MOZ_RELEASE_ASSERT(mProfileChunkedBuffer,
     31                       "If we take ownership of a ProfileBuffer, we must also "
     32                       "receive ownership of a ProfileChunkedBuffer");
     33    MOZ_RELEASE_ASSERT(
     34        mProfileChunkedBuffer == &mProfileBuffer->UnderlyingChunkedBuffer(),
     35        "If we take ownership of a ProfileBuffer, we must also receive "
     36        "ownership of its ProfileChunkedBuffer");
     37  }
     38  MOZ_ASSERT(
     39      !mProfileChunkedBuffer || !mProfileChunkedBuffer->IsThreadSafe(),
     40      "ProfilerBacktrace only takes a non-thread-safe ProfileChunkedBuffer");
     41 }
     42 
     43 ProfilerBacktrace::ProfilerBacktrace(
     44    const char* aName,
     45    ProfileChunkedBuffer* aExternalProfileChunkedBufferOrNull /* = nullptr */,
     46    ProfileBuffer* aExternalProfileBufferOrNull /* = nullptr */)
     47    : mName(aName),
     48      mProfileChunkedBuffer(aExternalProfileChunkedBufferOrNull),
     49      mProfileBuffer(aExternalProfileBufferOrNull) {
     50  if (!mProfileChunkedBuffer) {
     51    if (mProfileBuffer) {
     52      // We don't have a ProfileChunkedBuffer but we have a ProfileBuffer, use
     53      // the latter's ProfileChunkedBuffer.
     54      mProfileChunkedBuffer = &mProfileBuffer->UnderlyingChunkedBuffer();
     55      MOZ_ASSERT(!mProfileChunkedBuffer->IsThreadSafe(),
     56                 "ProfilerBacktrace only takes a non-thread-safe "
     57                 "ProfileChunkedBuffer");
     58    }
     59  } else {
     60    if (mProfileBuffer) {
     61      MOZ_RELEASE_ASSERT(
     62          mProfileChunkedBuffer == &mProfileBuffer->UnderlyingChunkedBuffer(),
     63          "If we reference both ProfileChunkedBuffer and ProfileBuffer, they "
     64          "must already be connected");
     65    }
     66    MOZ_ASSERT(!mProfileChunkedBuffer->IsThreadSafe(),
     67               "ProfilerBacktrace only takes a non-thread-safe "
     68               "ProfileChunkedBuffer");
     69  }
     70 }
     71 
     72 ProfilerBacktrace::~ProfilerBacktrace() {}
     73 
     74 BaseProfilerThreadId ProfilerBacktrace::StreamJSON(
     75    SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime,
     76    UniqueStacks& aUniqueStacks) {
     77  BaseProfilerThreadId processedThreadId;
     78 
     79  // Unlike ProfiledThreadData::StreamJSON, we don't need to call
     80  // ProfileBuffer::AddJITInfoForRange because ProfileBuffer does not contain
     81  // any JitReturnAddr entries. For synchronous samples, JIT frames get expanded
     82  // at sample time.
     83  if (mProfileBuffer) {
     84    processedThreadId = StreamSamplesAndMarkers(
     85        mName.c_str(), BaseProfilerThreadId{}, *mProfileBuffer, aWriter, "", "",
     86        aProcessStartTime,
     87        /* aRegisterTime */ TimeStamp(),
     88        /* aUnregisterTime */ TimeStamp(),
     89        /* aSinceTime */ 0, aUniqueStacks);
     90  } else if (mProfileChunkedBuffer) {
     91    ProfileBuffer profileBuffer(*mProfileChunkedBuffer);
     92    processedThreadId = StreamSamplesAndMarkers(
     93        mName.c_str(), BaseProfilerThreadId{}, profileBuffer, aWriter, "", "",
     94        aProcessStartTime,
     95        /* aRegisterTime */ TimeStamp(),
     96        /* aUnregisterTime */ TimeStamp(),
     97        /* aSinceTime */ 0, aUniqueStacks);
     98  }
     99  // If there are no buffers, the backtrace is empty and nothing is streamed.
    100 
    101  return processedThreadId;
    102 }
    103 
    104 }  // namespace baseprofiler
    105 
    106 // static
    107 template <typename Destructor>
    108 UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>
    109 ProfileBufferEntryReader::
    110    Deserializer<UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>>::Read(
    111        ProfileBufferEntryReader& aER) {
    112  auto profileChunkedBuffer = aER.ReadObject<UniquePtr<ProfileChunkedBuffer>>();
    113  if (!profileChunkedBuffer) {
    114    return nullptr;
    115  }
    116  MOZ_ASSERT(
    117      !profileChunkedBuffer->IsThreadSafe(),
    118      "ProfilerBacktrace only stores non-thread-safe ProfileChunkedBuffers");
    119  std::string name = aER.ReadObject<std::string>();
    120  return UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>{
    121      new baseprofiler::ProfilerBacktrace(name.c_str(),
    122                                          std::move(profileChunkedBuffer))};
    123 };
    124 
    125 }  // namespace mozilla