diff options
Diffstat (limited to 'chromium/base/profiler/stack_sampling_profiler.h')
-rw-r--r-- | chromium/base/profiler/stack_sampling_profiler.h | 205 |
1 files changed, 114 insertions, 91 deletions
diff --git a/chromium/base/profiler/stack_sampling_profiler.h b/chromium/base/profiler/stack_sampling_profiler.h index 2f9ade55eea..e43349a8fe0 100644 --- a/chromium/base/profiler/stack_sampling_profiler.h +++ b/chromium/base/profiler/stack_sampling_profiler.h @@ -7,13 +7,12 @@ #include <stddef.h> +#include <map> #include <memory> #include <string> #include <vector> -#include "base/atomicops.h" #include "base/base_export.h" -#include "base/callback.h" #include "base/files/file_path.h" #include "base/macros.h" #include "base/strings/string16.h" @@ -23,7 +22,9 @@ namespace base { -class NativeStackSampler; +// Identifies an unknown module. +BASE_EXPORT extern const size_t kUnknownModuleIndex; + class NativeStackSamplerTestDelegate; // StackSamplingProfiler periodically stops a thread to sample its stack, for @@ -35,34 +36,24 @@ class NativeStackSamplerTestDelegate; // // // Create and customize params as desired. // base::StackStackSamplingProfiler::SamplingParams params; -// // Any thread's ID may be passed as the target. -// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()), -// params); // -// // Or, to process the profiles within Chrome rather than via UMA, use a -// // custom completed callback: -// base::StackStackSamplingProfiler::CompletedCallback -// thread_safe_callback = ...; +// // To process the profiles, use a custom ProfileBuilder subclass: +// class SubProfileBuilder : +// public base::StackSamplingProfiler::ProfileBuilder{...} // base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()), -// params, thread_safe_callback); +// params, std::make_unique<SubProfileBuilder>(...)); // // profiler.Start(); // // ... work being done on the target thread here ... // profiler.Stop(); // optional, stops collection before complete per params // -// The default SamplingParams causes stacks to be recorded in a single burst at -// a 10Hz interval for a total of 30 seconds. All of these parameters may be +// The default SamplingParams causes stacks to be recorded in a single profile +// at a 10Hz interval for a total of 30 seconds. All of these parameters may be // altered as desired. // -// When all call stack profiles are complete, or the profiler is stopped, the -// completed callback is called from a thread created by the profiler with the -// collected profiles. -// -// The results of the profiling are passed to the completed callback and consist -// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a -// burst as specified in SamplingParams and contains a set of Samples and -// Modules. One Sample corresponds to a single recorded stack, and the Modules -// record those modules associated with the recorded stack frames. +// When a call stack profile is complete, or the profiler is stopped, +// ProfileBuilder's OnProfileCompleted function is called from a thread created +// by the profiler. class BASE_EXPORT StackSamplingProfiler { public: // Module represents the module (DLL or exe) corresponding to a stack frame. @@ -89,11 +80,39 @@ class BASE_EXPORT StackSamplingProfiler { FilePath filename; }; + // InternalModule represents the module (DLL or exe) and its validness state. + // Different from Module, it has an additional field "is_valid". + // + // This struct is only used for sampling data transfer from NativeStackSampler + // to ProfileBuilder. + struct BASE_EXPORT InternalModule { + InternalModule(); + InternalModule(uintptr_t base_address, + const std::string& id, + const FilePath& filename); + ~InternalModule(); + + // Points to the base address of the module. + uintptr_t base_address; + + // An opaque binary string that uniquely identifies a particular program + // version with high probability. This is parsed from headers of the loaded + // module. + // For binaries generated by GNU tools: + // Contents of the .note.gnu.build-id field. + // On Windows: + // GUID + AGE in the debug image headers of a module. + std::string id; + + // The filename of the module. + FilePath filename; + + // The validness of the module. + bool is_valid; + }; + // Frame represents an individual sampled stack frame with module information. struct BASE_EXPORT Frame { - // Identifies an unknown module. - static const size_t kUnknownModuleIndex = static_cast<size_t>(-1); - Frame(uintptr_t instruction_pointer, size_t module_index); ~Frame(); @@ -108,6 +127,23 @@ class BASE_EXPORT StackSamplingProfiler { size_t module_index; }; + // InternalFrame represents an individual sampled stack frame with full module + // information. This is different from Frame which only contains module index. + // + // This struct is only used for sampling data transfer from NativeStackSampler + // to ProfileBuilder. + struct BASE_EXPORT InternalFrame { + InternalFrame(uintptr_t instruction_pointer, + InternalModule internal_module); + ~InternalFrame(); + + // The sampled instruction pointer within the function. + uintptr_t instruction_pointer; + + // The module information. + InternalModule internal_module; + }; + // Sample represents a set of stack frames with some extra information. struct BASE_EXPORT Sample { Sample(); @@ -157,24 +193,15 @@ class BASE_EXPORT StackSamplingProfiler { DISALLOW_ASSIGN(CallStackProfile); }; - using CallStackProfiles = std::vector<CallStackProfile>; - // Represents parameters that configure the sampling. struct BASE_EXPORT SamplingParams { // Time to delay before first samples are taken. TimeDelta initial_delay = TimeDelta::FromMilliseconds(0); - // Number of sampling bursts to perform. - int bursts = 1; - - // Interval between sampling bursts. This is the desired duration from the - // start of one burst to the start of the next burst. - TimeDelta burst_interval = TimeDelta::FromSeconds(10); - - // Number of samples to record per burst. - int samples_per_burst = 300; + // Number of samples to record per profile. + int samples_per_profile = 300; - // Interval between samples during a sampling burst. This is the desired + // Interval between samples during a sampling profile. This is the desired // duration from the start of one sample to the start of the next sample. TimeDelta sampling_interval = TimeDelta::FromMilliseconds(100); }; @@ -189,9 +216,6 @@ class BASE_EXPORT StackSamplingProfiler { // so that tests don't inherit state from previous tests. static void Reset(); - // Resets internal annotations (like process phase) to initial values. - static void ResetAnnotations(); - // Returns whether the sampling thread is currently running or not. static bool IsSamplingThreadRunning(); @@ -211,41 +235,58 @@ class BASE_EXPORT StackSamplingProfiler { bool simulate_intervening_start); }; - // The callback type used to collect completed profiles. The passed |profiles| - // are move-only. 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 - // set the callback, and thus the callback must be callable on any thread. For - // threads with message loops that create StackSamplingProfilers, posting a - // task to the message loop with the moved (i.e. std::move) profiles is the - // thread-safe callback implementation. - using CompletedCallback = Callback<void(CallStackProfiles)>; - - // Creates a profiler for the CURRENT thread that sends completed profiles - // to |callback|. An optional |test_delegate| can be supplied by tests. - // The caller must ensure that this object gets destroyed before the current - // thread exits. + // The ProfileBuilder interface allows the user to record profile information + // on the fly in whatever format is desired. Functions are invoked by the + // profiler on its own thread so must not block or perform expensive + // operations. + class BASE_EXPORT ProfileBuilder { + public: + ProfileBuilder() = default; + virtual ~ProfileBuilder() = default; + + // Metadata associated with the sample to be saved off. + // The code implementing this method must not do anything that could acquire + // a mutex, including allocating memory (which includes LOG messages) + // because that mutex could be held by a stopped thread, thus resulting in + // deadlock. + virtual void RecordAnnotations() = 0; + + // Records a new set of internal frames. Invoked when sampling a sample + // completes. + virtual void OnSampleCompleted( + std::vector<InternalFrame> internal_frames) = 0; + + // Finishes the profile construction with |profile_duration| and + // |sampling_period|. Invoked when sampling a profile completes. + virtual void OnProfileCompleted(TimeDelta profile_duration, + TimeDelta sampling_period) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(ProfileBuilder); + }; + + // Creates a profiler for the CURRENT thread. An optional |test_delegate| can + // be supplied by tests. The caller must ensure that this object gets + // destroyed before the current thread exits. StackSamplingProfiler( const SamplingParams& params, - const CompletedCallback& callback, + std::unique_ptr<ProfileBuilder> profile_builder, NativeStackSamplerTestDelegate* test_delegate = nullptr); - // Creates a profiler for ANOTHER thread that sends completed profiles to - // |callback|. An optional |test_delegate| can be supplied by tests. + // Creates a profiler for ANOTHER thread. An optional |test_delegate| can be + // supplied by tests. // // IMPORTANT: The caller must ensure that the thread being sampled does not // exit before this object gets destructed or Bad Things(tm) may occur. StackSamplingProfiler( PlatformThreadId thread_id, const SamplingParams& params, - const CompletedCallback& callback, + std::unique_ptr<ProfileBuilder> profile_builder, NativeStackSamplerTestDelegate* test_delegate = nullptr); // Stops any profiling currently taking place before destroying the profiler. - // This will block until the callback has been run if profiling has started - // but not already finished. + // This will block until profile_builder_'s OnProfileCompleted function has + // executed if profiling has started but not already finished. ~StackSamplingProfiler(); // Initializes the profiler and starts sampling. Might block on a @@ -254,21 +295,13 @@ class BASE_EXPORT StackSamplingProfiler { void Start(); // Stops the profiler and any ongoing sampling. This method will return - // immediately with the callback being run asynchronously. At most one - // more stack sample will be taken after this method returns. Calling this - // function is optional; if not invoked profiling terminates when all the - // profiling bursts specified in the SamplingParams are completed or the - // profiler object is destroyed, whichever occurs first. + // immediately with the profile_builder_'s OnProfileCompleted function being + // run asynchronously. At most one more stack sample will be taken after this + // method returns. Calling this function is optional; if not invoked profiling + // terminates when all the profiling samples specified in the SamplingParams + // are completed or the profiler object is destroyed, whichever occurs first. void Stop(); - // Set the current system state that is recorded with each captured stack - // frame. This is thread-safe so can be called from anywhere. The parameter - // value should be from an enumeration of the appropriate type with values - // ranging from 0 to 31, inclusive. This sets bits within Sample field of - // |process_milestones|. The actual meanings of these bits are defined - // (globally) by the caller(s). - static void SetProcessMilestone(int milestone); - private: friend class TestAPI; @@ -276,31 +309,21 @@ class BASE_EXPORT StackSamplingProfiler { // the target thread. class SamplingThread; - // Adds annotations to a Sample. - static void RecordAnnotations(Sample* sample); - - // This global variables holds the current system state and is recorded with - // every captured sample, done on a separate thread which is why updates to - // this must be atomic. A PostTask to move the the updates to that thread - // would skew the timing and a lock could result in deadlock if the thread - // making a change was also being profiled and got stopped. - static subtle::Atomic32 process_milestones_; - // The thread whose stack will be sampled. PlatformThreadId thread_id_; const SamplingParams params_; - const CompletedCallback completed_callback_; + // Receives the sampling data and builds a CallStackProfile. The ownership of + // this object will be transferred to the sampling thread when thread sampling + // starts. + std::unique_ptr<ProfileBuilder> profile_builder_; // This starts "signaled", is reset when sampling begins, and is signaled - // when that sampling is complete and the callback done. + // when that sampling is complete and the profile_builder_'s + // OnProfileCompleted function has executed. WaitableEvent profiling_inactive_; - // Object that does the native sampling. This is created during construction - // and later passed to the sampling thread when profiling is started. - std::unique_ptr<NativeStackSampler> native_sampler_; - // An ID uniquely identifying this profiler to the sampling thread. This // will be an internal "null" value when no collection has been started. int profiler_id_; |