tor-browser

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

ProfileBuffer.h (9271B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef MOZ_PROFILE_BUFFER_H
      7 #define MOZ_PROFILE_BUFFER_H
      8 
      9 #include "ProfileBufferEntry.h"
     10 
     11 #include "mozilla/BaseProfiler.h"
     12 #include "mozilla/Maybe.h"
     13 #include "mozilla/PowerOfTwo.h"
     14 #include "mozilla/ProfileBufferChunkManagerSingle.h"
     15 #include "mozilla/ProfileChunkedBuffer.h"
     16 
     17 namespace mozilla {
     18 namespace baseprofiler {
     19 
     20 // Class storing most profiling data in a ProfileChunkedBuffer.
     21 //
     22 // This class is used as a queue of entries which, after construction, never
     23 // allocates. This makes it safe to use in the profiler's "critical section".
     24 class ProfileBuffer final {
     25 public:
     26  // ProfileBuffer constructor
     27  // @param aBuffer The in-session ProfileChunkedBuffer to use as buffer
     28  // manager.
     29  explicit ProfileBuffer(ProfileChunkedBuffer& aBuffer);
     30 
     31  ProfileChunkedBuffer& UnderlyingChunkedBuffer() const { return mEntries; }
     32 
     33  bool IsThreadSafe() const { return mEntries.IsThreadSafe(); }
     34 
     35  // Add |aEntry| to the buffer, ignoring what kind of entry it is.
     36  // Returns the position of the entry.
     37  uint64_t AddEntry(const ProfileBufferEntry& aEntry);
     38 
     39  // Add to the buffer a sample start (ThreadId) entry for aThreadId.
     40  // Returns the position of the entry.
     41  uint64_t AddThreadIdEntry(BaseProfilerThreadId aThreadId);
     42 
     43  void CollectCodeLocation(const char* aLabel, const char* aStr,
     44                           uint32_t aFrameFlags, uint64_t aInnerWindowID,
     45                           uint32_t aSourceId,
     46                           const Maybe<uint32_t>& aLineNumber,
     47                           const Maybe<uint32_t>& aColumnNumber,
     48                           const Maybe<ProfilingCategoryPair>& aCategoryPair);
     49 
     50  // Maximum size of a frameKey string that we'll handle.
     51  static constexpr size_t kMaxFrameKeyLength = 512;
     52 
     53  // Stream JSON for samples in the buffer to aWriter, using the supplied
     54  // UniqueStacks object.
     55  // Only streams samples for the given thread ID and which were taken at or
     56  // after aSinceTime. If ID is 0, ignore the stored thread ID; this should only
     57  // be used when the buffer contains only one sample.
     58  // Return the thread ID of the streamed sample(s), or 0.
     59  BaseProfilerThreadId StreamSamplesToJSON(SpliceableJSONWriter& aWriter,
     60                                           BaseProfilerThreadId aThreadId,
     61                                           double aSinceTime,
     62                                           UniqueStacks& aUniqueStacks) const;
     63 
     64  void StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
     65                           BaseProfilerThreadId aThreadId,
     66                           const TimeStamp& aProcessStartTime,
     67                           double aSinceTime,
     68                           UniqueStacks& aUniqueStacks) const;
     69  void StreamPausedRangesToJSON(SpliceableJSONWriter& aWriter,
     70                                double aSinceTime) const;
     71  void StreamProfilerOverheadToJSON(SpliceableJSONWriter& aWriter,
     72                                    const TimeStamp& aProcessStartTime,
     73                                    double aSinceTime) const;
     74  void StreamCountersToJSON(SpliceableJSONWriter& aWriter,
     75                            const TimeStamp& aProcessStartTime,
     76                            double aSinceTime) const;
     77 
     78  // Find (via |aLastSample|) the most recent sample for the thread denoted by
     79  // |aThreadId| and clone it, patching in the current time as appropriate.
     80  // Mutate |aLastSample| to point to the newly inserted sample.
     81  // Returns whether duplication was successful.
     82  bool DuplicateLastSample(BaseProfilerThreadId aThreadId,
     83                           const TimeStamp& aProcessStartTime,
     84                           Maybe<uint64_t>& aLastSample);
     85 
     86  void DiscardSamplesBeforeTime(double aTime);
     87 
     88  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
     89  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
     90 
     91  void CollectOverheadStats(TimeDuration aSamplingTime, TimeDuration aLocking,
     92                            TimeDuration aCleaning, TimeDuration aCounters,
     93                            TimeDuration aThreads);
     94 
     95  ProfilerBufferInfo GetProfilerBufferInfo() const;
     96 
     97 private:
     98  // Add |aEntry| to the provider ProfileChunkedBuffer.
     99  // `static` because it may be used to add an entry to a `ProfileChunkedBuffer`
    100  // that is not attached to a `ProfileBuffer`.
    101  static ProfileBufferBlockIndex AddEntry(
    102      ProfileChunkedBuffer& aProfileChunkedBuffer,
    103      const ProfileBufferEntry& aEntry);
    104 
    105  // Add a sample start (ThreadId) entry for aThreadId to the provided
    106  // ProfileChunkedBuffer. Returns the position of the entry.
    107  // `static` because it may be used to add an entry to a `ProfileChunkedBuffer`
    108  // that is not attached to a `ProfileBuffer`.
    109  static ProfileBufferBlockIndex AddThreadIdEntry(
    110      ProfileChunkedBuffer& aProfileChunkedBuffer,
    111      BaseProfilerThreadId aThreadId);
    112 
    113  // The storage in which this ProfileBuffer stores its entries.
    114  ProfileChunkedBuffer& mEntries;
    115 
    116 public:
    117  // `BufferRangeStart()` and `BufferRangeEnd()` return `uint64_t` values
    118  // corresponding to the first entry and past the last entry stored in
    119  // `mEntries`.
    120  //
    121  // The returned values are not guaranteed to be stable, because other threads
    122  // may also be accessing the buffer concurrently. But they will always
    123  // increase, and can therefore give an indication of how far these values have
    124  // *at least* reached. In particular:
    125  // - Entries whose index is strictly less that `BufferRangeStart()` have been
    126  //   discarded by now, so any related data may also be safely discarded.
    127  // - It is safe to try and read entries at any index strictly less than
    128  //   `BufferRangeEnd()` -- but note that these reads may fail by the time you
    129  //   request them, as old entries get overwritten by new ones.
    130  uint64_t BufferRangeStart() const { return mEntries.GetState().mRangeStart; }
    131  uint64_t BufferRangeEnd() const { return mEntries.GetState().mRangeEnd; }
    132 
    133 private:
    134  // Single pre-allocated chunk (to avoid spurious mallocs), used when:
    135  // - Duplicating sleeping stacks (hence scExpectedMaximumStackSize).
    136  // - Adding JIT info.
    137  // - Streaming stacks to JSON.
    138  // Mutable because it's accessed from non-multithreaded const methods.
    139  mutable Maybe<ProfileBufferChunkManagerSingle> mMaybeWorkerChunkManager;
    140  ProfileBufferChunkManagerSingle& WorkerChunkManager() const {
    141    if (mMaybeWorkerChunkManager.isNothing()) {
    142      // Only actually allocate it on first use. (Some ProfileBuffers are
    143      // temporary and don't actually need this.)
    144      mMaybeWorkerChunkManager.emplace(
    145          ProfileBufferChunk::SizeofChunkMetadata() +
    146          ProfileBufferChunkManager::scExpectedMaximumStackSize);
    147    }
    148    return *mMaybeWorkerChunkManager;
    149  }
    150 
    151  // Time from launch (us) when first sampling was recorded.
    152  double mFirstSamplingTimeUs = 0.0;
    153  // Time from launch (us) when last sampling was recorded.
    154  double mLastSamplingTimeUs = 0.0;
    155  // Sampling stats: Interval (us) between successive samplings.
    156  ProfilerStats mIntervalsUs;
    157  // Sampling stats: Total duration (us) of each sampling. (Split detail below.)
    158  ProfilerStats mOverheadsUs;
    159  // Sampling stats: Time (us) to acquire the lock before sampling.
    160  ProfilerStats mLockingsUs;
    161  // Sampling stats: Time (us) to discard expired data.
    162  ProfilerStats mCleaningsUs;
    163  // Sampling stats: Time (us) to collect counter data.
    164  ProfilerStats mCountersUs;
    165  // Sampling stats: Time (us) to sample thread stacks.
    166  ProfilerStats mThreadsUs;
    167 };
    168 
    169 /**
    170 * Helper type used to implement ProfilerStackCollector. This type is used as
    171 * the collector for MergeStacks by ProfileBuffer. It holds a reference to the
    172 * buffer, as well as additional feature flags which are needed to control the
    173 * data collection strategy
    174 */
    175 class ProfileBufferCollector final : public ProfilerStackCollector {
    176 public:
    177  ProfileBufferCollector(ProfileBuffer& aBuf, uint64_t aSamplePos,
    178                         uint64_t aBufferRangeStart)
    179      : mBuf(aBuf),
    180        mSamplePositionInBuffer(aSamplePos),
    181        mBufferRangeStart(aBufferRangeStart) {
    182    MOZ_ASSERT(
    183        mSamplePositionInBuffer >= mBufferRangeStart,
    184        "The sample position should always be after the buffer range start");
    185  }
    186 
    187  // Position at which the sample starts in the profiler buffer (which may be
    188  // different from the buffer in which the sample data is collected here).
    189  Maybe<uint64_t> SamplePositionInBuffer() override {
    190    return Some(mSamplePositionInBuffer);
    191  }
    192 
    193  // Profiler buffer's range start (which may be different from the buffer in
    194  // which the sample data is collected here).
    195  Maybe<uint64_t> BufferRangeStart() override {
    196    return Some(mBufferRangeStart);
    197  }
    198 
    199  virtual void CollectNativeLeafAddr(void* aAddr) override;
    200  virtual void CollectProfilingStackFrame(
    201      const ProfilingStackFrame& aFrame) override;
    202 
    203 private:
    204  ProfileBuffer& mBuf;
    205  uint64_t mSamplePositionInBuffer;
    206  uint64_t mBufferRangeStart;
    207 };
    208 
    209 }  // namespace baseprofiler
    210 }  // namespace mozilla
    211 
    212 #endif