xref: /aosp_15_r20/external/cronet/base/profiler/sample_metadata.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_PROFILER_SAMPLE_METADATA_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_PROFILER_SAMPLE_METADATA_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <optional>
9*6777b538SAndroid Build Coastguard Worker #include <string_view>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/profiler/metadata_recorder.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
16*6777b538SAndroid Build Coastguard Worker // Usage documentation
17*6777b538SAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
18*6777b538SAndroid Build Coastguard Worker //
19*6777b538SAndroid Build Coastguard Worker // Overview:
20*6777b538SAndroid Build Coastguard Worker // These functions provide a means to control the metadata attached to samples
21*6777b538SAndroid Build Coastguard Worker // collected by the stack sampling profiler. SampleMetadataScope controls the
22*6777b538SAndroid Build Coastguard Worker // scope covered by the metadata (thread, process).
23*6777b538SAndroid Build Coastguard Worker //
24*6777b538SAndroid Build Coastguard Worker // Any samples collected by the sampling profiler will include the active
25*6777b538SAndroid Build Coastguard Worker // metadata. This enables us to later analyze targeted subsets of samples
26*6777b538SAndroid Build Coastguard Worker // (e.g. those collected during paint or layout).
27*6777b538SAndroid Build Coastguard Worker //
28*6777b538SAndroid Build Coastguard Worker // For example:
29*6777b538SAndroid Build Coastguard Worker //
30*6777b538SAndroid Build Coastguard Worker //   void DidStartLoad() {
31*6777b538SAndroid Build Coastguard Worker //     is_loading_metadata_.Set(1);
32*6777b538SAndroid Build Coastguard Worker //   }
33*6777b538SAndroid Build Coastguard Worker //
34*6777b538SAndroid Build Coastguard Worker //   void DidFinishLoad() {
35*6777b538SAndroid Build Coastguard Worker //     is_loading_metadata_.Remove();
36*6777b538SAndroid Build Coastguard Worker //   }
37*6777b538SAndroid Build Coastguard Worker //
38*6777b538SAndroid Build Coastguard Worker //   base::SampleMetadata is_loading_metadata_;
39*6777b538SAndroid Build Coastguard Worker //
40*6777b538SAndroid Build Coastguard Worker // Alternatively, ScopedSampleMetadata can be used to ensure that the metadata
41*6777b538SAndroid Build Coastguard Worker // is removed correctly.
42*6777b538SAndroid Build Coastguard Worker //
43*6777b538SAndroid Build Coastguard Worker // For example:
44*6777b538SAndroid Build Coastguard Worker //
45*6777b538SAndroid Build Coastguard Worker //   void DoExpensiveWork() {
46*6777b538SAndroid Build Coastguard Worker //     base::ScopedSampleMetadata metadata("xyz", 1);
47*6777b538SAndroid Build Coastguard Worker //     if (...) {
48*6777b538SAndroid Build Coastguard Worker //       ...
49*6777b538SAndroid Build Coastguard Worker //       if (...) {
50*6777b538SAndroid Build Coastguard Worker //         ...
51*6777b538SAndroid Build Coastguard Worker //         return;
52*6777b538SAndroid Build Coastguard Worker //       }
53*6777b538SAndroid Build Coastguard Worker //     }
54*6777b538SAndroid Build Coastguard Worker //     ...
55*6777b538SAndroid Build Coastguard Worker //   }
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker namespace base {
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker class TimeTicks;
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker enum class SampleMetadataScope {
62*6777b538SAndroid Build Coastguard Worker   // All threads in the current process will have the associated metadata
63*6777b538SAndroid Build Coastguard Worker   // attached to their samples.
64*6777b538SAndroid Build Coastguard Worker   kProcess,
65*6777b538SAndroid Build Coastguard Worker   // The metadata will only be attached to samples for the current thread.
66*6777b538SAndroid Build Coastguard Worker   kThread
67*6777b538SAndroid Build Coastguard Worker };
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT SampleMetadata {
70*6777b538SAndroid Build Coastguard Worker  public:
71*6777b538SAndroid Build Coastguard Worker   // Set the metadata value associated with |name| to be recorded for |scope|.
72*6777b538SAndroid Build Coastguard Worker   explicit SampleMetadata(std::string_view name, SampleMetadataScope scope);
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker   SampleMetadata(const SampleMetadata&) = default;
75*6777b538SAndroid Build Coastguard Worker   ~SampleMetadata() = default;
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker   SampleMetadata& operator=(const SampleMetadata&) = delete;
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker   // Set the metadata value associated with |name| in the process-global stack
80*6777b538SAndroid Build Coastguard Worker   // sampling profiler metadata, overwriting any previous value set for that
81*6777b538SAndroid Build Coastguard Worker   // |name|.
82*6777b538SAndroid Build Coastguard Worker   void Set(int64_t value);
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   // Set the metadata value associated with the pair (|name|, |key|) in the
85*6777b538SAndroid Build Coastguard Worker   // process-global stack sampling profiler metadata, overwriting any previous
86*6777b538SAndroid Build Coastguard Worker   // value set for that (|name|, |key|) pair. This constructor allows the
87*6777b538SAndroid Build Coastguard Worker   // metadata to be associated with an additional user-defined key. One might
88*6777b538SAndroid Build Coastguard Worker   // supply a key based on the frame id, for example, to distinguish execution
89*6777b538SAndroid Build Coastguard Worker   // in service of scrolling between different frames. Prefer the previous
90*6777b538SAndroid Build Coastguard Worker   // function if no user-defined metadata is required. Note: values specified
91*6777b538SAndroid Build Coastguard Worker   // for a name and key are stored separately from values specified with only a
92*6777b538SAndroid Build Coastguard Worker   // name.
93*6777b538SAndroid Build Coastguard Worker   void Set(int64_t key, int64_t value);
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   // Removes the metadata item with the specified name from the process-global
96*6777b538SAndroid Build Coastguard Worker   // stack sampling profiler metadata.
97*6777b538SAndroid Build Coastguard Worker   //
98*6777b538SAndroid Build Coastguard Worker   // If such an item doesn't exist, this has no effect.
99*6777b538SAndroid Build Coastguard Worker   void Remove();
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   // Removes the metadata item with the specified (|name|, |key|) pair from the
102*6777b538SAndroid Build Coastguard Worker   // process-global stack sampling profiler metadata. This function does not
103*6777b538SAndroid Build Coastguard Worker   // alter values set with the name |name| but no key.
104*6777b538SAndroid Build Coastguard Worker   //
105*6777b538SAndroid Build Coastguard Worker   // If such an item doesn't exist, this has no effect.
106*6777b538SAndroid Build Coastguard Worker   void Remove(int64_t key);
107*6777b538SAndroid Build Coastguard Worker 
108*6777b538SAndroid Build Coastguard Worker  private:
109*6777b538SAndroid Build Coastguard Worker   const uint64_t name_hash_;
110*6777b538SAndroid Build Coastguard Worker   // Scope is kept as-is instead of retrieving a PlatformThreadId in case
111*6777b538SAndroid Build Coastguard Worker   // Set()/Remove() is called on a thread different from where the object was
112*6777b538SAndroid Build Coastguard Worker   // constructed.
113*6777b538SAndroid Build Coastguard Worker   const SampleMetadataScope scope_;
114*6777b538SAndroid Build Coastguard Worker };
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT ScopedSampleMetadata {
117*6777b538SAndroid Build Coastguard Worker  public:
118*6777b538SAndroid Build Coastguard Worker   // Set the metadata value associated with |name| for |scope|.
119*6777b538SAndroid Build Coastguard Worker   ScopedSampleMetadata(std::string_view name,
120*6777b538SAndroid Build Coastguard Worker                        int64_t value,
121*6777b538SAndroid Build Coastguard Worker                        SampleMetadataScope scope);
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker   // Set the metadata value associated with the pair (|name|, |key|) for
124*6777b538SAndroid Build Coastguard Worker   // |scope|. This constructor allows the metadata to be associated with an
125*6777b538SAndroid Build Coastguard Worker   // additional user-defined key. One might supply a key based on the frame id,
126*6777b538SAndroid Build Coastguard Worker   // for example, to distinguish execution in service of scrolling between
127*6777b538SAndroid Build Coastguard Worker   // different frames. Prefer the previous constructor if no user-defined
128*6777b538SAndroid Build Coastguard Worker   // metadata is required. Note: values specified for a name and key are stored
129*6777b538SAndroid Build Coastguard Worker   // separately from values specified with only a name.
130*6777b538SAndroid Build Coastguard Worker   ScopedSampleMetadata(std::string_view name,
131*6777b538SAndroid Build Coastguard Worker                        int64_t key,
132*6777b538SAndroid Build Coastguard Worker                        int64_t value,
133*6777b538SAndroid Build Coastguard Worker                        SampleMetadataScope scope);
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker   ScopedSampleMetadata(const ScopedSampleMetadata&) = delete;
136*6777b538SAndroid Build Coastguard Worker   ~ScopedSampleMetadata();
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   ScopedSampleMetadata& operator=(const ScopedSampleMetadata&) = delete;
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker  private:
141*6777b538SAndroid Build Coastguard Worker   const uint64_t name_hash_;
142*6777b538SAndroid Build Coastguard Worker   std::optional<int64_t> key_;
143*6777b538SAndroid Build Coastguard Worker   std::optional<PlatformThreadId> thread_id_;
144*6777b538SAndroid Build Coastguard Worker };
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker // Applies the specified metadata to samples already recorded between
147*6777b538SAndroid Build Coastguard Worker // |period_start| and |period_end| in all thread's active profiles, subject to
148*6777b538SAndroid Build Coastguard Worker // the condition that the profile fully encompasses the period and the profile
149*6777b538SAndroid Build Coastguard Worker // has not already completed. The condition ensures that the metadata is applied
150*6777b538SAndroid Build Coastguard Worker // only if all execution during its scope was seen in the profile. This avoids
151*6777b538SAndroid Build Coastguard Worker // biasng the samples towards the 'middle' of the execution seen during the
152*6777b538SAndroid Build Coastguard Worker // metadata scope (i.e. because the start or end of execution was missed), at
153*6777b538SAndroid Build Coastguard Worker // the cost of missing execution that are longer than the profiling period, or
154*6777b538SAndroid Build Coastguard Worker // extend before or after it. |period_end| must be <= TimeTicks::Now().
155*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void ApplyMetadataToPastSamples(TimeTicks period_start,
156*6777b538SAndroid Build Coastguard Worker                                             TimeTicks period_end,
157*6777b538SAndroid Build Coastguard Worker                                             std::string_view name,
158*6777b538SAndroid Build Coastguard Worker                                             int64_t value,
159*6777b538SAndroid Build Coastguard Worker                                             SampleMetadataScope scope);
160*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void ApplyMetadataToPastSamples(TimeTicks period_start,
161*6777b538SAndroid Build Coastguard Worker                                             TimeTicks period_end,
162*6777b538SAndroid Build Coastguard Worker                                             std::string_view name,
163*6777b538SAndroid Build Coastguard Worker                                             int64_t key,
164*6777b538SAndroid Build Coastguard Worker                                             int64_t value,
165*6777b538SAndroid Build Coastguard Worker                                             SampleMetadataScope scope);
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker // Adds metadata as metadata global to the sampling profile. Has the effect of
168*6777b538SAndroid Build Coastguard Worker // applying the metadata to all samples in the profile, even ones collected
169*6777b538SAndroid Build Coastguard Worker // earlier in time. This is probably not what you want for most use cases;
170*6777b538SAndroid Build Coastguard Worker // prefer using SampleMetadata / ScopedSampleMetadata /
171*6777b538SAndroid Build Coastguard Worker // ApplyMetadataToPastSamples instead.
172*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void AddProfileMetadata(std::string_view name,
173*6777b538SAndroid Build Coastguard Worker                                     int64_t key,
174*6777b538SAndroid Build Coastguard Worker                                     int64_t value,
175*6777b538SAndroid Build Coastguard Worker                                     SampleMetadataScope scope);
176*6777b538SAndroid Build Coastguard Worker 
177*6777b538SAndroid Build Coastguard Worker // Returns the process-global metadata recorder instance used for tracking
178*6777b538SAndroid Build Coastguard Worker // sampling profiler metadata.
179*6777b538SAndroid Build Coastguard Worker //
180*6777b538SAndroid Build Coastguard Worker // This function should not be called by non-profiler related code.
181*6777b538SAndroid Build Coastguard Worker BASE_EXPORT MetadataRecorder* GetSampleMetadataRecorder();
182*6777b538SAndroid Build Coastguard Worker 
183*6777b538SAndroid Build Coastguard Worker }  // namespace base
184*6777b538SAndroid Build Coastguard Worker 
185*6777b538SAndroid Build Coastguard Worker #endif  // BASE_PROFILER_SAMPLE_METADATA_H_
186