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