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