tor-browser

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

ProfileBuffer.cpp (7765B)


      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 "ProfileBuffer.h"
      8 
      9 #include "mozilla/BaseProfiler.h"
     10 
     11 namespace mozilla {
     12 namespace baseprofiler {
     13 
     14 ProfileBuffer::ProfileBuffer(ProfileChunkedBuffer& aBuffer)
     15    : mEntries(aBuffer) {
     16  // Assume the given buffer is in-session.
     17  MOZ_ASSERT(mEntries.IsInSession());
     18 }
     19 
     20 /* static */
     21 ProfileBufferBlockIndex ProfileBuffer::AddEntry(
     22    ProfileChunkedBuffer& aProfileChunkedBuffer,
     23    const ProfileBufferEntry& aEntry) {
     24  switch (aEntry.GetKind()) {
     25 #define SWITCH_KIND(KIND, TYPE, SIZE)                          \
     26  case ProfileBufferEntry::Kind::KIND: {                       \
     27    return aProfileChunkedBuffer.PutFrom(&aEntry, 1 + (SIZE)); \
     28    break;                                                     \
     29  }
     30 
     31    FOR_EACH_PROFILE_BUFFER_ENTRY_KIND(SWITCH_KIND)
     32 
     33 #undef SWITCH_KIND
     34    default:
     35      MOZ_ASSERT(false, "Unhandled baseprofiler::ProfilerBuffer entry KIND");
     36      return ProfileBufferBlockIndex{};
     37  }
     38 }
     39 
     40 // Called from signal, call only reentrant functions
     41 uint64_t ProfileBuffer::AddEntry(const ProfileBufferEntry& aEntry) {
     42  return AddEntry(mEntries, aEntry).ConvertToProfileBufferIndex();
     43 }
     44 
     45 /* static */
     46 ProfileBufferBlockIndex ProfileBuffer::AddThreadIdEntry(
     47    ProfileChunkedBuffer& aProfileChunkedBuffer,
     48    BaseProfilerThreadId aThreadId) {
     49  return AddEntry(aProfileChunkedBuffer,
     50                  ProfileBufferEntry::ThreadId(aThreadId));
     51 }
     52 
     53 uint64_t ProfileBuffer::AddThreadIdEntry(BaseProfilerThreadId aThreadId) {
     54  return AddThreadIdEntry(mEntries, aThreadId).ConvertToProfileBufferIndex();
     55 }
     56 
     57 void ProfileBuffer::CollectCodeLocation(
     58    const char* aLabel, const char* aStr, uint32_t aFrameFlags,
     59    uint64_t aInnerWindowID, uint32_t aSourceId,
     60    const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
     61    const Maybe<ProfilingCategoryPair>& aCategoryPair) {
     62  AddEntry(ProfileBufferEntry::Label(aLabel));
     63  AddEntry(ProfileBufferEntry::FrameFlags(uint64_t(aFrameFlags)));
     64 
     65  if (aStr) {
     66    // Store the string using one or more DynamicStringFragment entries.
     67    size_t strLen = strlen(aStr) + 1;  // +1 for the null terminator
     68    // If larger than the prescribed limit, we will cut the string and end it
     69    // with an ellipsis.
     70    const bool tooBig = strLen > kMaxFrameKeyLength;
     71    if (tooBig) {
     72      strLen = kMaxFrameKeyLength;
     73    }
     74    char chars[ProfileBufferEntry::kNumChars];
     75    for (size_t j = 0;; j += ProfileBufferEntry::kNumChars) {
     76      // Store up to kNumChars characters in the entry.
     77      size_t len = ProfileBufferEntry::kNumChars;
     78      const bool last = j + len >= strLen;
     79      if (last) {
     80        // Only the last entry may be smaller than kNumChars.
     81        len = strLen - j;
     82        if (tooBig) {
     83          // That last entry is part of a too-big string, replace the end
     84          // characters with an ellipsis "...".
     85          len = std::max(len, size_t(4));
     86          chars[len - 4] = '.';
     87          chars[len - 3] = '.';
     88          chars[len - 2] = '.';
     89          chars[len - 1] = '\0';
     90          // Make sure the memcpy will not overwrite our ellipsis!
     91          len -= 4;
     92        }
     93      }
     94      memcpy(chars, &aStr[j], len);
     95      AddEntry(ProfileBufferEntry::DynamicStringFragment(chars));
     96      if (last) {
     97        break;
     98      }
     99    }
    100  }
    101 
    102  if (aInnerWindowID) {
    103    AddEntry(ProfileBufferEntry::InnerWindowID(aInnerWindowID));
    104  }
    105 
    106  if (aSourceId) {
    107    AddEntry(ProfileBufferEntry::SourceId(aSourceId));
    108  }
    109 
    110  if (aLineNumber) {
    111    AddEntry(ProfileBufferEntry::LineNumber(*aLineNumber));
    112  }
    113 
    114  if (aColumnNumber) {
    115    AddEntry(ProfileBufferEntry::ColumnNumber(*aColumnNumber));
    116  }
    117 
    118  if (aCategoryPair.isSome()) {
    119    AddEntry(ProfileBufferEntry::CategoryPair(int(*aCategoryPair)));
    120  }
    121 }
    122 
    123 size_t ProfileBuffer::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    124  // Measurement of the following members may be added later if DMD finds it
    125  // is worthwhile:
    126  // - memory pointed to by the elements within mEntries
    127  return mEntries.SizeOfExcludingThis(aMallocSizeOf);
    128 }
    129 
    130 size_t ProfileBuffer::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    131  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    132 }
    133 
    134 void ProfileBuffer::CollectOverheadStats(TimeDuration aSamplingTime,
    135                                         TimeDuration aLocking,
    136                                         TimeDuration aCleaning,
    137                                         TimeDuration aCounters,
    138                                         TimeDuration aThreads) {
    139  double timeUs = aSamplingTime.ToMilliseconds() * 1000.0;
    140  if (mFirstSamplingTimeUs == 0.0) {
    141    mFirstSamplingTimeUs = timeUs;
    142  } else {
    143    // Note that we'll have 1 fewer interval than other numbers (because
    144    // we need both ends of an interval to know its duration). The final
    145    // difference should be insignificant over the expected many thousands
    146    // of iterations.
    147    mIntervalsUs.Count(timeUs - mLastSamplingTimeUs);
    148  }
    149  mLastSamplingTimeUs = timeUs;
    150  // Time to take the lock before sampling.
    151  double lockingUs = aLocking.ToMilliseconds() * 1000.0;
    152  // Time to discard expired data.
    153  double cleaningUs = aCleaning.ToMilliseconds() * 1000.0;
    154  // Time to gather all counters.
    155  double countersUs = aCounters.ToMilliseconds() * 1000.0;
    156  // Time to sample all threads.
    157  double threadsUs = aThreads.ToMilliseconds() * 1000.0;
    158 
    159  // Add to our gathered stats.
    160  mOverheadsUs.Count(lockingUs + cleaningUs + countersUs + threadsUs);
    161  mLockingsUs.Count(lockingUs);
    162  mCleaningsUs.Count(cleaningUs);
    163  mCountersUs.Count(countersUs);
    164  mThreadsUs.Count(threadsUs);
    165 
    166  // Record details in buffer, if requested.
    167  static const bool sRecordSamplingOverhead = []() {
    168    const char* recordOverheads = getenv("MOZ_PROFILER_RECORD_OVERHEADS");
    169    return recordOverheads && recordOverheads[0] != '\0';
    170  }();
    171  if (sRecordSamplingOverhead) {
    172    AddEntry(ProfileBufferEntry::ProfilerOverheadTime(timeUs));
    173    AddEntry(ProfileBufferEntry::ProfilerOverheadDuration(lockingUs));
    174    AddEntry(ProfileBufferEntry::ProfilerOverheadDuration(cleaningUs));
    175    AddEntry(ProfileBufferEntry::ProfilerOverheadDuration(countersUs));
    176    AddEntry(ProfileBufferEntry::ProfilerOverheadDuration(threadsUs));
    177  }
    178 }
    179 
    180 ProfilerBufferInfo ProfileBuffer::GetProfilerBufferInfo() const {
    181  return {BufferRangeStart(),
    182          BufferRangeEnd(),
    183          static_cast<uint32_t>(*mEntries.BufferLength() /
    184                                8),  // 8 bytes per entry.
    185          mIntervalsUs,
    186          mOverheadsUs,
    187          mLockingsUs,
    188          mCleaningsUs,
    189          mCountersUs,
    190          mThreadsUs};
    191 }
    192 
    193 /* ProfileBufferCollector */
    194 
    195 void ProfileBufferCollector::CollectNativeLeafAddr(void* aAddr) {
    196  mBuf.AddEntry(ProfileBufferEntry::NativeLeafAddr(aAddr));
    197 }
    198 
    199 void ProfileBufferCollector::CollectProfilingStackFrame(
    200    const ProfilingStackFrame& aFrame) {
    201  // WARNING: this function runs within the profiler's "critical section".
    202 
    203  MOZ_ASSERT(aFrame.isLabelFrame() ||
    204             (aFrame.isJsFrame() && !aFrame.isOSRFrame()));
    205 
    206  const char* label = aFrame.label();
    207  const char* dynamicString = aFrame.dynamicString();
    208  Maybe<uint32_t> line;
    209  Maybe<uint32_t> column;
    210 
    211  MOZ_ASSERT(aFrame.isLabelFrame());
    212 
    213  mBuf.CollectCodeLocation(label, dynamicString, aFrame.flags(),
    214                           aFrame.realmID(), 0, line, column,
    215                           Some(aFrame.categoryPair()));
    216 }
    217 
    218 }  // namespace baseprofiler
    219 }  // namespace mozilla