1 // Copyright 2018 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 COMPONENTS_METRICS_CALL_STACKS_CALL_STACK_PROFILE_BUILDER_H_ 6 #define COMPONENTS_METRICS_CALL_STACKS_CALL_STACK_PROFILE_BUILDER_H_ 7 8 #include <limits> 9 #include <map> 10 #include <unordered_map> 11 #include <utility> 12 #include <vector> 13 14 #include "base/functional/callback.h" 15 #include "base/memory/raw_ptr.h" 16 #include "base/profiler/metadata_recorder.h" 17 #include "base/profiler/module_cache.h" 18 #include "base/profiler/profile_builder.h" 19 #include "base/time/time.h" 20 #include "components/metrics/call_stacks/call_stack_profile_metadata.h" 21 #include "components/metrics/call_stacks/call_stack_profile_params.h" 22 #include "components/metrics/call_stacks/child_call_stack_profile_collector.h" 23 #include "mojo/public/cpp/bindings/pending_remote.h" 24 #include "third_party/metrics_proto/sampled_profile.pb.h" 25 26 namespace metrics { 27 28 // Interface that allows the CallStackProfileBuilder to provide ids for distinct 29 // work items. Samples with the same id are tagged as coming from the same work 30 // item in the recorded samples. 31 class WorkIdRecorder { 32 public: 33 WorkIdRecorder() = default; 34 virtual ~WorkIdRecorder() = default; 35 36 // This function is invoked on the profiler thread while the target thread is 37 // suspended so must not take any locks, including indirectly through use of 38 // heap allocation, LOG, CHECK, or DCHECK. 39 virtual unsigned int RecordWorkId() const = 0; 40 41 WorkIdRecorder(const WorkIdRecorder&) = delete; 42 WorkIdRecorder& operator=(const WorkIdRecorder&) = delete; 43 }; 44 45 // An instance of the class is meant to be passed to base::StackSamplingProfiler 46 // to collect profiles. The profiles collected are uploaded via the metrics log. 47 // 48 // This uses the new StackSample encoding rather than the legacy Sample 49 // encoding. 50 class CallStackProfileBuilder : public base::ProfileBuilder { 51 public: 52 // |completed_callback| is made when sampling a profile completes. Other 53 // threads, including the UI thread, may block on callback completion so this 54 // should run as quickly as possible. 55 // 56 // IMPORTANT NOTE: The callback is invoked on a thread the profiler 57 // constructs, rather than on the thread used to construct the profiler, and 58 // thus the callback must be callable on any thread. 59 explicit CallStackProfileBuilder( 60 const CallStackProfileParams& profile_params, 61 const WorkIdRecorder* work_id_recorder = nullptr, 62 base::OnceClosure completed_callback = base::OnceClosure()); 63 64 CallStackProfileBuilder(const CallStackProfileBuilder&) = delete; 65 CallStackProfileBuilder& operator=(const CallStackProfileBuilder&) = delete; 66 67 ~CallStackProfileBuilder() override; 68 69 // Both weight and count are used by the heap profiler only. 70 void OnSampleCompleted(std::vector<base::Frame> frames, 71 base::TimeTicks sample_timestamp, 72 size_t weight, 73 size_t count); 74 75 // base::ProfileBuilder: 76 base::ModuleCache* GetModuleCache() override; 77 void RecordMetadata(const base::MetadataRecorder::MetadataProvider& 78 metadata_provider) override; 79 void ApplyMetadataRetrospectively( 80 base::TimeTicks period_start, 81 base::TimeTicks period_end, 82 const base::MetadataRecorder::Item& item) override; 83 void AddProfileMetadata(const base::MetadataRecorder::Item& item) override; 84 void OnSampleCompleted(std::vector<base::Frame> frames, 85 base::TimeTicks sample_timestamp) override; 86 void OnProfileCompleted(base::TimeDelta profile_duration, 87 base::TimeDelta sampling_period) override; 88 89 // Sets the callback to use for reporting browser process profiles. This 90 // indirection is required to avoid a dependency on unnecessary metrics code 91 // in child processes. 92 static void SetBrowserProcessReceiverCallback( 93 const base::RepeatingCallback<void(base::TimeTicks, SampledProfile)>& 94 callback); 95 96 // Sets the CallStackProfileCollector interface from |browser_interface|. 97 // This function must be called within child processes, and must only be 98 // called once. 99 static void SetParentProfileCollectorForChildProcess( 100 mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> 101 browser_interface); 102 103 // Resets the ChildCallStackProfileCollector to its default state. This will 104 // discard all collected profiles, remove any CallStackProfileCollector 105 // interface set through SetParentProfileCollectorForChildProcess, and allow 106 // SetParentProfileCollectorForChildProcess to be called multiple times during 107 // tests. 108 static void ResetChildCallStackProfileCollectorForTesting(); 109 110 protected: 111 // Test seam. 112 virtual void PassProfilesToMetricsProvider(base::TimeTicks profile_start_time, 113 SampledProfile sampled_profile); 114 115 private: 116 // The functor for Stack comparison. 117 struct StackComparer { 118 bool operator()(const CallStackProfile::Stack* stack1, 119 const CallStackProfile::Stack* stack2) const; 120 }; 121 122 // The module cache to use for the duration the sampling associated with this 123 // ProfileBuilder. 124 base::ModuleCache module_cache_; 125 126 unsigned int last_work_id_ = std::numeric_limits<unsigned int>::max(); 127 bool is_continued_work_ = false; 128 const raw_ptr<const WorkIdRecorder> work_id_recorder_; 129 130 // The SampledProfile protobuf message which contains the collected stack 131 // samples. 132 SampledProfile sampled_profile_; 133 134 // The indexes of stacks, indexed by stack's address. 135 std::map<const CallStackProfile::Stack*, int, StackComparer> stack_index_; 136 137 // The indexes of modules in the modules_ vector below.. 138 std::unordered_map<const base::ModuleCache::Module*, size_t> module_index_; 139 140 // The distinct modules in the current profile. 141 std::vector<raw_ptr<const base::ModuleCache::Module, VectorExperimental>> 142 modules_; 143 144 // Timestamps recording when each sample was taken. 145 std::vector<base::TimeTicks> sample_timestamps_; 146 147 // Callback made when sampling a profile completes. 148 base::OnceClosure completed_callback_; 149 150 // The start time of a profile collection. 151 base::TimeTicks profile_start_time_; 152 153 // Maintains the current metadata to apply to samples. 154 CallStackProfileMetadata metadata_; 155 }; 156 157 } // namespace metrics 158 159 #endif // COMPONENTS_METRICS_CALL_STACKS_CALL_STACK_PROFILE_BUILDER_H_ 160