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