|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_DEBUG_ACTIVITY_ANALYZER_H_ | 
|  | #define BASE_DEBUG_ACTIVITY_ANALYZER_H_ | 
|  |  | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/base_export.h" | 
|  | #include "base/debug/activity_tracker.h" | 
|  |  | 
|  | #if defined(STARBOARD) | 
|  |  | 
|  | namespace base { | 
|  | namespace debug { | 
|  |  | 
|  | class GlobalActivityAnalyzer; | 
|  |  | 
|  | // This class provides analysis of data captured from a ThreadActivityTracker. | 
|  | // When created, it takes a snapshot of the data held by the tracker and | 
|  | // makes that information available to other code. | 
|  | class BASE_EXPORT ThreadActivityAnalyzer { | 
|  | public: | 
|  | struct BASE_EXPORT Snapshot : ThreadActivityTracker::Snapshot { | 
|  | Snapshot(); | 
|  | ~Snapshot(); | 
|  |  | 
|  | // The user-data snapshot for an activity, matching the |activity_stack| | 
|  | // of ThreadActivityTracker::Snapshot, if any. | 
|  | std::vector<ActivityUserData::Snapshot> user_data_stack; | 
|  | }; | 
|  |  | 
|  | // This class provides keys that uniquely identify a thread, even across | 
|  | // multiple processes. | 
|  | class ThreadKey { | 
|  | public: | 
|  | ThreadKey(int64_t pid, int64_t tid) : pid_(pid), tid_(tid) {} | 
|  |  | 
|  | bool operator<(const ThreadKey& rhs) const { | 
|  | if (pid_ != rhs.pid_) | 
|  | return pid_ < rhs.pid_; | 
|  | return tid_ < rhs.tid_; | 
|  | } | 
|  |  | 
|  | bool operator==(const ThreadKey& rhs) const { | 
|  | return (pid_ == rhs.pid_ && tid_ == rhs.tid_); | 
|  | } | 
|  |  | 
|  | private: | 
|  | int64_t pid_; | 
|  | int64_t tid_; | 
|  | }; | 
|  |  | 
|  | // Creates an analyzer for an existing activity |tracker|. A snapshot is taken | 
|  | // immediately and the tracker is not referenced again. | 
|  | explicit ThreadActivityAnalyzer(const ThreadActivityTracker& tracker); | 
|  |  | 
|  | // Creates an analyzer for a block of memory currently or previously in-use | 
|  | // by an activity-tracker. A snapshot is taken immediately and the memory | 
|  | // is not referenced again. | 
|  | ThreadActivityAnalyzer(void* base, size_t size); | 
|  |  | 
|  | // Creates an analyzer for a block of memory held within a persistent-memory | 
|  | // |allocator| at the given |reference|. A snapshot is taken immediately and | 
|  | // the memory is not referenced again. | 
|  | ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator, | 
|  | PersistentMemoryAllocator::Reference reference); | 
|  |  | 
|  | ~ThreadActivityAnalyzer(); | 
|  |  | 
|  | // Adds information from the global analyzer. | 
|  | void AddGlobalInformation(GlobalActivityAnalyzer* global); | 
|  |  | 
|  | // Returns true iff the contained data is valid. Results from all other | 
|  | // methods are undefined if this returns false. | 
|  | bool IsValid() { return activity_snapshot_valid_; } | 
|  |  | 
|  | // Gets the process id and its creation stamp. | 
|  | int64_t GetProcessId(int64_t* out_stamp = nullptr) { | 
|  | if (out_stamp) | 
|  | *out_stamp = activity_snapshot_.create_stamp; | 
|  | return activity_snapshot_.process_id; | 
|  | } | 
|  |  | 
|  | // Gets the name of the thread. | 
|  | const std::string& GetThreadName() { | 
|  | return activity_snapshot_.thread_name; | 
|  | } | 
|  |  | 
|  | // Gets the TheadKey for this thread. | 
|  | ThreadKey GetThreadKey() { | 
|  | return ThreadKey(activity_snapshot_.process_id, | 
|  | activity_snapshot_.thread_id); | 
|  | } | 
|  |  | 
|  | const Snapshot& activity_snapshot() { return activity_snapshot_; } | 
|  |  | 
|  | private: | 
|  | friend class GlobalActivityAnalyzer; | 
|  |  | 
|  | // The snapshot of the activity tracker taken at the moment of construction. | 
|  | Snapshot activity_snapshot_; | 
|  |  | 
|  | // Flag indicating if the snapshot data is valid. | 
|  | bool activity_snapshot_valid_; | 
|  |  | 
|  | // A reference into a persistent memory allocator, used by the global | 
|  | // analyzer to know where this tracker came from. | 
|  | PersistentMemoryAllocator::Reference allocator_reference_ = 0; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer); | 
|  | }; | 
|  |  | 
|  |  | 
|  | // This class manages analyzers for all known processes and threads as stored | 
|  | // in a persistent memory allocator. It supports retrieval of them through | 
|  | // iteration and directly using a ThreadKey, which allows for cross-references | 
|  | // to be resolved. | 
|  | // Note that though atomic snapshots are used and everything has its snapshot | 
|  | // taken at the same time, the multi-snapshot itself is not atomic and thus may | 
|  | // show small inconsistencies between threads if attempted on a live system. | 
|  | class BASE_EXPORT GlobalActivityAnalyzer { | 
|  | public: | 
|  | struct ProgramLocation { | 
|  | int module; | 
|  | uintptr_t offset; | 
|  | }; | 
|  |  | 
|  | using ThreadKey = ThreadActivityAnalyzer::ThreadKey; | 
|  |  | 
|  | // Creates a global analyzer from a persistent memory allocator. | 
|  | explicit GlobalActivityAnalyzer( | 
|  | std::unique_ptr<PersistentMemoryAllocator> allocator); | 
|  |  | 
|  | ~GlobalActivityAnalyzer(); | 
|  |  | 
|  | // Creates a global analyzer using a given persistent-memory |allocator|. | 
|  | static std::unique_ptr<GlobalActivityAnalyzer> CreateWithAllocator( | 
|  | std::unique_ptr<PersistentMemoryAllocator> allocator); | 
|  |  | 
|  | #if !defined(OS_NACL) | 
|  | // Creates a global analyzer using the contents of a file given in | 
|  | // |file_path|. | 
|  | static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile( | 
|  | const FilePath& file_path); | 
|  | #endif  // !defined(OS_NACL) | 
|  |  | 
|  | #if !defined(STARBOARD) | 
|  | // Like above but accesses an allocator in a mapped shared-memory segment. | 
|  | static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemory( | 
|  | std::unique_ptr<SharedMemory> shm); | 
|  |  | 
|  | // Like above but takes a handle to an existing shared memory segment and | 
|  | // maps it before creating the tracker. | 
|  | static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemoryHandle( | 
|  | const SharedMemoryHandle& handle, | 
|  | size_t size); | 
|  | #endif  // !defined(STARBOARD) | 
|  |  | 
|  | // Iterates over all known valid processes and returns their PIDs or zero | 
|  | // if there are no more. Calls to GetFirstProcess() will perform a global | 
|  | // snapshot in order to provide a relatively consistent state across the | 
|  | // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are | 
|  | // returned in the order they're found meaning that a first-launched | 
|  | // controlling process will be found first. Note, however, that space | 
|  | // freed by an exiting process may be re-used by a later process. | 
|  | int64_t GetFirstProcess(); | 
|  | int64_t GetNextProcess(); | 
|  |  | 
|  | // Iterates over all known valid analyzers for the a given process or returns | 
|  | // null if there are no more. | 
|  | // | 
|  | // GetFirstProcess() must be called first in order to capture a global | 
|  | // snapshot! Ownership stays with the global analyzer object and all existing | 
|  | // analyzer pointers are invalidated when GetFirstProcess() is called. | 
|  | ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid); | 
|  | ThreadActivityAnalyzer* GetNextAnalyzer(); | 
|  |  | 
|  | // Gets the analyzer for a specific thread or null if there is none. | 
|  | // Ownership stays with the global analyzer object. | 
|  | ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key); | 
|  |  | 
|  | // Extract user data based on a reference and its identifier. | 
|  | ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid, | 
|  | uint32_t ref, | 
|  | uint32_t id); | 
|  |  | 
|  | // Extract the data for a specific process. An empty snapshot will be | 
|  | // returned if the process is not known. | 
|  | const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid); | 
|  |  | 
|  | // Gets all log messages stored within. | 
|  | std::vector<std::string> GetLogMessages(); | 
|  |  | 
|  | // Gets modules corresponding to a pid. This pid must come from a call to | 
|  | // GetFirst/NextProcess. Only modules that were first registered prior to | 
|  | // GetFirstProcess's snapshot are returned. | 
|  | std::vector<GlobalActivityTracker::ModuleInfo> GetModules(int64_t pid); | 
|  |  | 
|  | // Gets the corresponding "program location" for a given "program counter". | 
|  | // This will return {0,0} if no mapping could be found. | 
|  | ProgramLocation GetProgramLocationFromAddress(uint64_t address); | 
|  |  | 
|  | // Returns whether the data is complete. Data can be incomplete if the | 
|  | // recording size quota is hit. | 
|  | bool IsDataComplete() const; | 
|  |  | 
|  | private: | 
|  | using AnalyzerMap = | 
|  | std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>; | 
|  |  | 
|  | struct UserDataSnapshot { | 
|  | // Complex class needs out-of-line ctor/dtor. | 
|  | UserDataSnapshot(); | 
|  | UserDataSnapshot(const UserDataSnapshot& rhs); | 
|  | UserDataSnapshot(UserDataSnapshot&& rhs); | 
|  | ~UserDataSnapshot(); | 
|  |  | 
|  | int64_t process_id; | 
|  | int64_t create_stamp; | 
|  | ActivityUserData::Snapshot data; | 
|  | }; | 
|  |  | 
|  | // Finds, creates, and indexes analyzers for all known processes and threads. | 
|  | void PrepareAllAnalyzers(); | 
|  |  | 
|  | // The persistent memory allocator holding all tracking data. | 
|  | std::unique_ptr<PersistentMemoryAllocator> allocator_; | 
|  |  | 
|  | // The time stamp when analysis began. This is used to prevent looking into | 
|  | // process IDs that get reused when analyzing a live system. | 
|  | int64_t analysis_stamp_; | 
|  |  | 
|  | // The iterator for finding tracking information in the allocator. | 
|  | PersistentMemoryAllocator::Iterator allocator_iterator_; | 
|  |  | 
|  | // A set of all interesting memory references found within the allocator. | 
|  | std::set<PersistentMemoryAllocator::Reference> memory_references_; | 
|  |  | 
|  | // A set of all process-data memory references found within the allocator. | 
|  | std::map<int64_t, UserDataSnapshot> process_data_; | 
|  |  | 
|  | // A set of all process IDs collected during PrepareAllAnalyzers. These are | 
|  | // popped and returned one-by-one with calls to GetFirst/NextProcess(). | 
|  | std::vector<int64_t> process_ids_; | 
|  |  | 
|  | // A map, keyed by ThreadKey, of all valid activity analyzers. | 
|  | AnalyzerMap analyzers_; | 
|  |  | 
|  | // The iterator within the analyzers_ map for returning analyzers through | 
|  | // first/next iteration. | 
|  | AnalyzerMap::iterator analyzers_iterator_; | 
|  | int64_t analyzers_iterator_pid_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer); | 
|  | }; | 
|  |  | 
|  | }  // namespace debug | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // !defined(STARBOARD) | 
|  |  | 
|  | #endif  // BASE_DEBUG_ACTIVITY_ANALYZER_H_ |