Bug 1927515 - [FxMS Docs] Updates Spotlight UI template documentation in source doc...
[gecko.git] / tools / profiler / core / ProfileBuffer.h
blob4004ad10bbd4e7cacd7b596891e4a7a97941f887
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 "GeckoProfiler.h"
10 #include "ProfileBufferEntry.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/PowerOfTwo.h"
14 #include "mozilla/ProfileBufferChunkManagerSingle.h"
15 #include "mozilla/ProfileChunkedBuffer.h"
17 class ProcessStreamingContext;
18 class RunningTimes;
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(mozilla::ProfileChunkedBuffer& aBuffer);
31 mozilla::ProfileChunkedBuffer& UnderlyingChunkedBuffer() const {
32 return mEntries;
35 bool IsThreadSafe() const { return mEntries.IsThreadSafe(); }
37 // Add |aEntry| to the buffer, ignoring what kind of entry it is.
38 uint64_t AddEntry(const ProfileBufferEntry& aEntry);
40 // Add to the buffer a sample start (ThreadId) entry for aThreadId.
41 // Returns the position of the entry.
42 uint64_t AddThreadIdEntry(ProfilerThreadId aThreadId);
44 void CollectCodeLocation(
45 const char* aLabel, const char* aStr, uint32_t aFrameFlags,
46 uint64_t aInnerWindowID, const mozilla::Maybe<uint32_t>& aLineNumber,
47 const mozilla::Maybe<uint32_t>& aColumnNumber,
48 const mozilla::Maybe<JS::ProfilingCategoryPair>& aCategoryPair);
50 // Maximum size of a frameKey string that we'll handle.
51 static const size_t kMaxFrameKeyLength = 512;
53 // Add JIT frame information to aJITFrameInfo for any JitReturnAddr entries
54 // that are currently in the buffer at or after aRangeStart, in samples
55 // for the given thread.
56 void AddJITInfoForRange(uint64_t aRangeStart, ProfilerThreadId aThreadId,
57 JSContext* aContext, JITFrameInfo& aJITFrameInfo,
58 mozilla::ProgressLogger aProgressLogger) const;
60 // Stream JSON for samples in the buffer to aWriter, using the supplied
61 // UniqueStacks object.
62 // Only streams samples for the given thread ID and which were taken at or
63 // after aSinceTime. If ID is 0, ignore the stored thread ID; this should only
64 // be used when the buffer contains only one sample.
65 // aUniqueStacks needs to contain information about any JIT frames that we
66 // might encounter in the buffer, before this method is called. In other
67 // words, you need to have called AddJITInfoForRange for every range that
68 // might contain JIT frame information before calling this method.
69 // Return the thread ID of the streamed sample(s), or 0.
70 ProfilerThreadId StreamSamplesToJSON(
71 SpliceableJSONWriter& aWriter, ProfilerThreadId aThreadId,
72 double aSinceTime, UniqueStacks& aUniqueStacks,
73 mozilla::ProgressLogger aProgressLogger) const;
75 void StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
76 ProfilerThreadId aThreadId,
77 const mozilla::TimeStamp& aProcessStartTime,
78 double aSinceTime, UniqueStacks& aUniqueStacks,
79 mozilla::ProgressLogger aProgressLogger) const;
81 // Stream samples and markers from all threads that `aProcessStreamingContext`
82 // accepts.
83 void StreamSamplesAndMarkersToJSON(
84 ProcessStreamingContext& aProcessStreamingContext,
85 mozilla::ProgressLogger aProgressLogger) const;
87 void StreamPausedRangesToJSON(SpliceableJSONWriter& aWriter,
88 double aSinceTime,
89 mozilla::ProgressLogger aProgressLogger) const;
90 void StreamProfilerOverheadToJSON(
91 SpliceableJSONWriter& aWriter,
92 const mozilla::TimeStamp& aProcessStartTime, double aSinceTime,
93 mozilla::ProgressLogger aProgressLogger) const;
94 void StreamCountersToJSON(SpliceableJSONWriter& aWriter,
95 const mozilla::TimeStamp& aProcessStartTime,
96 double aSinceTime,
97 mozilla::ProgressLogger aProgressLogger) const;
99 // Find (via |aLastSample|) the most recent sample for the thread denoted by
100 // |aThreadId| and clone it, patching in the current time as appropriate.
101 // Mutate |aLastSample| to point to the newly inserted sample.
102 // Returns whether duplication was successful.
103 bool DuplicateLastSample(ProfilerThreadId aThreadId, double aSampleTimeMs,
104 mozilla::Maybe<uint64_t>& aLastSample,
105 const RunningTimes& aRunningTimes);
107 void DiscardSamplesBeforeTime(double aTime);
109 // Read an entry in the buffer.
110 ProfileBufferEntry GetEntry(uint64_t aPosition) const {
111 return mEntries.ReadAt(
112 mozilla::ProfileBufferBlockIndex::CreateFromProfileBufferIndex(
113 aPosition),
114 [&](mozilla::Maybe<mozilla::ProfileBufferEntryReader>&& aMER) {
115 ProfileBufferEntry entry;
116 if (aMER.isSome()) {
117 if (aMER->CurrentBlockIndex().ConvertToProfileBufferIndex() ==
118 aPosition) {
119 // If we're here, it means `aPosition` pointed at a valid block.
120 MOZ_RELEASE_ASSERT(aMER->RemainingBytes() <= sizeof(entry));
121 aMER->ReadBytes(&entry, aMER->RemainingBytes());
122 } else {
123 // EntryReader at the wrong position, pretend to have read
124 // everything.
125 aMER->SetRemainingBytes(0);
128 return entry;
132 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
133 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
135 void CollectOverheadStats(double aSamplingTimeMs,
136 mozilla::TimeDuration aLocking,
137 mozilla::TimeDuration aCleaning,
138 mozilla::TimeDuration aCounters,
139 mozilla::TimeDuration aThreads);
141 ProfilerBufferInfo GetProfilerBufferInfo() const;
143 private:
144 // Add |aEntry| to the provided ProfileChunkedBuffer.
145 // `static` because it may be used to add an entry to a `ProfileChunkedBuffer`
146 // that is not attached to a `ProfileBuffer`.
147 static mozilla::ProfileBufferBlockIndex AddEntry(
148 mozilla::ProfileChunkedBuffer& aProfileChunkedBuffer,
149 const ProfileBufferEntry& aEntry);
151 // Add a sample start (ThreadId) entry for aThreadId to the provided
152 // ProfileChunkedBuffer. Returns the position of the entry.
153 // `static` because it may be used to add an entry to a `ProfileChunkedBuffer`
154 // that is not attached to a `ProfileBuffer`.
155 static mozilla::ProfileBufferBlockIndex AddThreadIdEntry(
156 mozilla::ProfileChunkedBuffer& aProfileChunkedBuffer,
157 ProfilerThreadId aThreadId);
159 // The storage in which this ProfileBuffer stores its entries.
160 mozilla::ProfileChunkedBuffer& mEntries;
162 public:
163 // `BufferRangeStart()` and `BufferRangeEnd()` return `uint64_t` values
164 // corresponding to the first entry and past the last entry stored in
165 // `mEntries`.
167 // The returned values are not guaranteed to be stable, because other threads
168 // may also be accessing the buffer concurrently. But they will always
169 // increase, and can therefore give an indication of how far these values have
170 // *at least* reached. In particular:
171 // - Entries whose index is strictly less that `BufferRangeStart()` have been
172 // discarded by now, so any related data may also be safely discarded.
173 // - It is safe to try and read entries at any index strictly less than
174 // `BufferRangeEnd()` -- but note that these reads may fail by the time you
175 // request them, as old entries get overwritten by new ones.
176 uint64_t BufferRangeStart() const { return mEntries.GetState().mRangeStart; }
177 uint64_t BufferRangeEnd() const { return mEntries.GetState().mRangeEnd; }
179 private:
180 // Single pre-allocated chunk (to avoid spurious mallocs), used when:
181 // - Duplicating sleeping stacks (hence scExpectedMaximumStackSize).
182 // - Adding JIT info.
183 // - Streaming stacks to JSON.
184 // Mutable because it's accessed from non-multithreaded const methods.
185 mutable mozilla::Maybe<mozilla::ProfileBufferChunkManagerSingle>
186 mMaybeWorkerChunkManager;
187 mozilla::ProfileBufferChunkManagerSingle& WorkerChunkManager() const {
188 if (mMaybeWorkerChunkManager.isNothing()) {
189 // Only actually allocate it on first use. (Some ProfileBuffers are
190 // temporary and don't actually need this.)
191 mMaybeWorkerChunkManager.emplace(
192 mozilla::ProfileBufferChunk::SizeofChunkMetadata() +
193 mozilla::ProfileBufferChunkManager::scExpectedMaximumStackSize);
195 return *mMaybeWorkerChunkManager;
198 #ifdef MOZ_EXECUTION_TRACING
199 template <typename GetStreamingParametersForThreadCallback>
200 void MaybeStreamExecutionTraceToJSON(
201 GetStreamingParametersForThreadCallback&&
202 aGetStreamingParametersForThreadCallback,
203 double aSinceTime) const;
204 #endif
206 // GetStreamingParametersForThreadCallback:
207 // (ProfilerThreadId) -> Maybe<StreamingParametersForThread>
208 template <typename GetStreamingParametersForThreadCallback>
209 ProfilerThreadId DoStreamSamplesAndMarkersToJSON(
210 mozilla::FailureLatch& aFailureLatch,
211 GetStreamingParametersForThreadCallback&&
212 aGetStreamingParametersForThreadCallback,
213 double aSinceTime, ProcessStreamingContext* aStreamingContextForMarkers,
214 mozilla::ProgressLogger aProgressLogger) const;
216 double mFirstSamplingTimeUs = 0.0;
217 double mLastSamplingTimeUs = 0.0;
218 ProfilerStats mIntervalsUs;
219 ProfilerStats mOverheadsUs;
220 ProfilerStats mLockingsUs;
221 ProfilerStats mCleaningsUs;
222 ProfilerStats mCountersUs;
223 ProfilerStats mThreadsUs;
227 * Helper type used to implement ProfilerStackCollector. This type is used as
228 * the collector for MergeStacks by ProfileBuffer. It holds a reference to the
229 * buffer, as well as additional feature flags which are needed to control the
230 * data collection strategy
232 class ProfileBufferCollector final : public ProfilerStackCollector {
233 public:
234 ProfileBufferCollector(ProfileBuffer& aBuf, uint64_t aSamplePos,
235 uint64_t aBufferRangeStart)
236 : mBuf(aBuf),
237 mSamplePositionInBuffer(aSamplePos),
238 mBufferRangeStart(aBufferRangeStart) {
239 MOZ_ASSERT(
240 mSamplePositionInBuffer >= mBufferRangeStart,
241 "The sample position should always be after the buffer range start");
244 // Position at which the sample starts in the profiler buffer (which may be
245 // different from the buffer in which the sample data is collected here).
246 mozilla::Maybe<uint64_t> SamplePositionInBuffer() override {
247 return mozilla::Some(mSamplePositionInBuffer);
250 // Profiler buffer's range start (which may be different from the buffer in
251 // which the sample data is collected here).
252 mozilla::Maybe<uint64_t> BufferRangeStart() override {
253 return mozilla::Some(mBufferRangeStart);
256 virtual void CollectNativeLeafAddr(void* aAddr) override;
257 virtual void CollectJitReturnAddr(void* aAddr) override;
258 virtual void CollectWasmFrame(JS::ProfilingCategoryPair aCategory,
259 const char* aLabel) override;
260 virtual void CollectProfilingStackFrame(
261 const js::ProfilingStackFrame& aFrame) override;
263 private:
264 ProfileBuffer& mBuf;
265 uint64_t mSamplePositionInBuffer;
266 uint64_t mBufferRangeStart;
269 #endif