| // 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_ |