// Copyright 2018 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_METRICS_CALL_STACKS_CALL_STACK_PROFILE_BUILDER_H_ #define COMPONENTS_METRICS_CALL_STACKS_CALL_STACK_PROFILE_BUILDER_H_ #include #include #include #include #include #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/profiler/metadata_recorder.h" #include "base/profiler/module_cache.h" #include "base/profiler/profile_builder.h" #include "base/time/time.h" #include "components/metrics/call_stacks/call_stack_profile_metadata.h" #include "components/metrics/call_stacks/child_call_stack_profile_collector.h" #include "components/sampling_profiler/call_stack_profile_params.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "third_party/metrics_proto/sampled_profile.pb.h" namespace metrics { // Interface that allows the CallStackProfileBuilder to provide ids for distinct // work items. Samples with the same id are tagged as coming from the same work // item in the recorded samples. class WorkIdRecorder { public: WorkIdRecorder() = default; virtual ~WorkIdRecorder() = default; // This function is invoked on the profiler thread while the target thread is // suspended so must not take any locks, including indirectly through use of // heap allocation, LOG, CHECK, or DCHECK. virtual unsigned int RecordWorkId() const = 0; WorkIdRecorder(const WorkIdRecorder&) = delete; WorkIdRecorder& operator=(const WorkIdRecorder&) = delete; }; // An instance of the class is meant to be passed to base::StackSamplingProfiler // to collect profiles. The profiles collected are uploaded via the metrics log. // // This uses the new StackSample encoding rather than the legacy Sample // encoding. class CallStackProfileBuilder : public base::ProfileBuilder { public: // |completed_callback| is made when sampling a profile completes. Other // threads, including the UI thread, may block on callback completion so this // should run as quickly as possible. // // IMPORTANT NOTE: The callback is invoked on a thread the profiler // constructs, rather than on the thread used to construct the profiler, and // thus the callback must be callable on any thread. explicit CallStackProfileBuilder( const sampling_profiler::CallStackProfileParams& profile_params, const WorkIdRecorder* work_id_recorder = nullptr, base::OnceClosure completed_callback = base::OnceClosure()); CallStackProfileBuilder(const CallStackProfileBuilder&) = delete; CallStackProfileBuilder& operator=(const CallStackProfileBuilder&) = delete; ~CallStackProfileBuilder() override; // Both weight and count are used by the heap profiler only. void OnSampleCompleted(std::vector frames, base::TimeTicks sample_timestamp, size_t weight, size_t count); // base::ProfileBuilder: base::ModuleCache* GetModuleCache() override; void RecordMetadata(const base::MetadataRecorder::MetadataProvider& metadata_provider) override; void ApplyMetadataRetrospectively( base::TimeTicks period_start, base::TimeTicks period_end, const base::MetadataRecorder::Item& item) override; void AddProfileMetadata(const base::MetadataRecorder::Item& item) override; void OnSampleCompleted(std::vector frames, base::TimeTicks sample_timestamp) override; void OnProfileCompleted(base::TimeDelta profile_duration, base::TimeDelta sampling_period) override; // Sets the callback to use for reporting browser process profiles. This // indirection is required to avoid a dependency on unnecessary metrics code // in child processes. static void SetBrowserProcessReceiverCallback( const base::RepeatingCallback& callback); // Sets the CallStackProfileCollector interface from |browser_interface|. // This function must be called within child processes, and must only be // called once. static void SetParentProfileCollectorForChildProcess( mojo::PendingRemote browser_interface); // Resets the ChildCallStackProfileCollector to its default state. This will // discard all collected profiles, remove any CallStackProfileCollector // interface set through SetParentProfileCollectorForChildProcess, and allow // SetParentProfileCollectorForChildProcess to be called multiple times during // tests. static void ResetChildCallStackProfileCollectorForTesting(); protected: // Test seam. virtual void PassProfilesToMetricsProvider(base::TimeTicks profile_start_time, SampledProfile sampled_profile); private: // The functor for Stack comparison. struct StackComparer { bool operator()(const CallStackProfile::Stack* stack1, const CallStackProfile::Stack* stack2) const; }; // The module cache to use for the duration the sampling associated with this // ProfileBuilder. base::ModuleCache module_cache_; unsigned int last_work_id_ = std::numeric_limits::max(); bool is_continued_work_ = false; raw_ptr work_id_recorder_; // The SampledProfile protobuf message which contains the collected stack // samples. SampledProfile sampled_profile_; // The indexes of stacks, indexed by stack's address. std::map stack_index_; // The indexes of modules in the modules_ vector below.. std::unordered_map module_index_; // The distinct modules in the current profile. std::vector> modules_; // Timestamps recording when each sample was taken. std::vector sample_timestamps_; // Callback made when sampling a profile completes. base::OnceClosure completed_callback_; // The start time of a profile collection. base::TimeTicks profile_start_time_; // Maintains the current metadata to apply to samples. CallStackProfileMetadata metadata_; }; } // namespace metrics #endif // COMPONENTS_METRICS_CALL_STACKS_CALL_STACK_PROFILE_BUILDER_H_