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