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