bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors. All rights reserved. |
| 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 BASE_DEBUG_ACTIVITY_ANALYZER_H_ |
| 6 | #define BASE_DEBUG_ACTIVITY_ANALYZER_H_ |
| 7 | |
| 8 | #include <map> |
| 9 | #include <memory> |
| 10 | #include <set> |
manzagop | 54b190f | 2016-11-10 00:44:25 +0900 | [diff] [blame] | 11 | #include <string> |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 12 | #include <vector> |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 13 | |
| 14 | #include "base/base_export.h" |
| 15 | #include "base/debug/activity_tracker.h" |
| 16 | |
| 17 | namespace base { |
| 18 | namespace debug { |
| 19 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 20 | class GlobalActivityAnalyzer; |
| 21 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 22 | // This class provides analysis of data captured from a ThreadActivityTracker. |
| 23 | // When created, it takes a snapshot of the data held by the tracker and |
| 24 | // makes that information available to other code. |
| 25 | class BASE_EXPORT ThreadActivityAnalyzer { |
| 26 | public: |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 27 | struct BASE_EXPORT Snapshot : ThreadActivityTracker::Snapshot { |
| 28 | Snapshot(); |
| 29 | ~Snapshot(); |
| 30 | |
| 31 | // The user-data snapshot for an activity, matching the |activity_stack| |
| 32 | // of ThreadActivityTracker::Snapshot, if any. |
| 33 | std::vector<ActivityUserData::Snapshot> user_data_stack; |
| 34 | }; |
| 35 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 36 | // This class provides keys that uniquely identify a thread, even across |
| 37 | // multiple processes. |
| 38 | class ThreadKey { |
| 39 | public: |
| 40 | ThreadKey(int64_t pid, int64_t tid) : pid_(pid), tid_(tid) {} |
| 41 | |
| 42 | bool operator<(const ThreadKey& rhs) const { |
| 43 | if (pid_ != rhs.pid_) |
| 44 | return pid_ < rhs.pid_; |
| 45 | return tid_ < rhs.tid_; |
| 46 | } |
| 47 | |
| 48 | bool operator==(const ThreadKey& rhs) const { |
| 49 | return (pid_ == rhs.pid_ && tid_ == rhs.tid_); |
| 50 | } |
| 51 | |
| 52 | private: |
| 53 | int64_t pid_; |
| 54 | int64_t tid_; |
| 55 | }; |
| 56 | |
| 57 | // Creates an analyzer for an existing activity |tracker|. A snapshot is taken |
| 58 | // immediately and the tracker is not referenced again. |
| 59 | explicit ThreadActivityAnalyzer(const ThreadActivityTracker& tracker); |
| 60 | |
| 61 | // Creates an analyzer for a block of memory currently or previously in-use |
| 62 | // by an activity-tracker. A snapshot is taken immediately and the memory |
| 63 | // is not referenced again. |
| 64 | ThreadActivityAnalyzer(void* base, size_t size); |
| 65 | |
| 66 | // Creates an analyzer for a block of memory held within a persistent-memory |
| 67 | // |allocator| at the given |reference|. A snapshot is taken immediately and |
| 68 | // the memory is not referenced again. |
| 69 | ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator, |
| 70 | PersistentMemoryAllocator::Reference reference); |
| 71 | |
| 72 | ~ThreadActivityAnalyzer(); |
| 73 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 74 | // Adds information from the global analyzer. |
| 75 | void AddGlobalInformation(GlobalActivityAnalyzer* global); |
| 76 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 77 | // Returns true iff the contained data is valid. Results from all other |
| 78 | // methods are undefined if this returns false. |
| 79 | bool IsValid() { return activity_snapshot_valid_; } |
| 80 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 81 | // Gets the process id and its creation stamp. |
| 82 | int64_t GetProcessId(int64_t* out_stamp = nullptr) { |
| 83 | if (out_stamp) |
| 84 | *out_stamp = activity_snapshot_.create_stamp; |
| 85 | return activity_snapshot_.process_id; |
| 86 | } |
| 87 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 88 | // Gets the name of the thread. |
| 89 | const std::string& GetThreadName() { |
| 90 | return activity_snapshot_.thread_name; |
| 91 | } |
| 92 | |
| 93 | // Gets the TheadKey for this thread. |
| 94 | ThreadKey GetThreadKey() { |
| 95 | return ThreadKey(activity_snapshot_.process_id, |
| 96 | activity_snapshot_.thread_id); |
| 97 | } |
| 98 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 99 | const Snapshot& activity_snapshot() { return activity_snapshot_; } |
manzagop | 54b190f | 2016-11-10 00:44:25 +0900 | [diff] [blame] | 100 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 101 | private: |
| 102 | friend class GlobalActivityAnalyzer; |
| 103 | |
| 104 | // The snapshot of the activity tracker taken at the moment of construction. |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 105 | Snapshot activity_snapshot_; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 106 | |
| 107 | // Flag indicating if the snapshot data is valid. |
| 108 | bool activity_snapshot_valid_; |
| 109 | |
| 110 | // A reference into a persistent memory allocator, used by the global |
| 111 | // analyzer to know where this tracker came from. |
| 112 | PersistentMemoryAllocator::Reference allocator_reference_ = 0; |
| 113 | |
| 114 | DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer); |
| 115 | }; |
| 116 | |
| 117 | |
| 118 | // This class manages analyzers for all known processes and threads as stored |
| 119 | // in a persistent memory allocator. It supports retrieval of them through |
| 120 | // iteration and directly using a ThreadKey, which allows for cross-references |
| 121 | // to be resolved. |
| 122 | // Note that though atomic snapshots are used and everything has its snapshot |
| 123 | // taken at the same time, the multi-snapshot itself is not atomic and thus may |
| 124 | // show small inconsistencies between threads if attempted on a live system. |
| 125 | class BASE_EXPORT GlobalActivityAnalyzer { |
| 126 | public: |
bcwhite | 60a440f | 2016-11-11 00:46:45 +0900 | [diff] [blame] | 127 | struct ProgramLocation { |
| 128 | int module; |
| 129 | uintptr_t offset; |
| 130 | }; |
| 131 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 132 | using ThreadKey = ThreadActivityAnalyzer::ThreadKey; |
| 133 | |
| 134 | // Creates a global analyzer from a persistent memory allocator. |
| 135 | explicit GlobalActivityAnalyzer( |
| 136 | std::unique_ptr<PersistentMemoryAllocator> allocator); |
| 137 | |
| 138 | ~GlobalActivityAnalyzer(); |
| 139 | |
| 140 | #if !defined(OS_NACL) |
| 141 | // Creates a global analyzer using the contents of a file given in |
| 142 | // |file_path|. |
| 143 | static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile( |
| 144 | const FilePath& file_path); |
| 145 | #endif // !defined(OS_NACL) |
| 146 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 147 | // Iterates over all known valid processes and returns their PIDs or zero |
| 148 | // if there are no more. Calls to GetFirstProcess() will perform a global |
| 149 | // snapshot in order to provide a relatively consistent state across the |
| 150 | // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are |
| 151 | // returned in the order they're found meaning that a first-launched |
| 152 | // controlling process will be found first. Note, however, that space |
| 153 | // freed by an exiting process may be re-used by a later process. |
| 154 | int64_t GetFirstProcess(); |
| 155 | int64_t GetNextProcess(); |
| 156 | |
| 157 | // Iterates over all known valid analyzers for the a given process or returns |
| 158 | // null if there are no more. |
| 159 | // |
| 160 | // GetFirstProcess() must be called first in order to capture a global |
| 161 | // snapshot! Ownership stays with the global analyzer object and all existing |
| 162 | // analyzer pointers are invalidated when GetFirstProcess() is called. |
| 163 | ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 164 | ThreadActivityAnalyzer* GetNextAnalyzer(); |
| 165 | |
| 166 | // Gets the analyzer for a specific thread or null if there is none. |
| 167 | // Ownership stays with the global analyzer object. |
| 168 | ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key); |
| 169 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 170 | // Extract user data based on a reference and its identifier. |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 171 | ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid, |
| 172 | uint32_t ref, |
| 173 | uint32_t id); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 174 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 175 | // Extract the data for a specific process. An empty snapshot will be |
| 176 | // returned if the process is not known. |
| 177 | const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid); |
| 178 | |
bcwhite | 2d4c331 | 2016-12-03 06:23:40 +0900 | [diff] [blame] | 179 | // Gets all log messages stored within. |
| 180 | std::vector<std::string> GetLogMessages(); |
| 181 | |
bcwhite | 8f3021d | 2017-01-27 03:28:18 +0900 | [diff] [blame] | 182 | // Gets all the known modules. |
| 183 | std::vector<GlobalActivityTracker::ModuleInfo> GetModules(); |
| 184 | |
bcwhite | 60a440f | 2016-11-11 00:46:45 +0900 | [diff] [blame] | 185 | // Gets the corresponding "program location" for a given "program counter". |
| 186 | // This will return {0,0} if no mapping could be found. |
| 187 | ProgramLocation GetProgramLocationFromAddress(uint64_t address); |
| 188 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 189 | private: |
| 190 | using AnalyzerMap = |
| 191 | std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>; |
| 192 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 193 | struct UserDataSnapshot { |
| 194 | // Complex class needs out-of-line ctor/dtor. |
| 195 | UserDataSnapshot(); |
| 196 | UserDataSnapshot(const UserDataSnapshot& rhs); |
| 197 | UserDataSnapshot(UserDataSnapshot&& rhs); |
| 198 | ~UserDataSnapshot(); |
| 199 | |
| 200 | int64_t process_id; |
| 201 | int64_t create_stamp; |
| 202 | ActivityUserData::Snapshot data; |
| 203 | }; |
| 204 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 205 | // Finds, creates, and indexes analyzers for all known processes and threads. |
| 206 | void PrepareAllAnalyzers(); |
| 207 | |
| 208 | // The persistent memory allocator holding all tracking data. |
| 209 | std::unique_ptr<PersistentMemoryAllocator> allocator_; |
| 210 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 211 | // The time stamp when analysis began. This is used to prevent looking into |
| 212 | // process IDs that get reused when analyzing a live system. |
| 213 | int64_t analysis_stamp_; |
| 214 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 215 | // The iterator for finding tracking information in the allocator. |
| 216 | PersistentMemoryAllocator::Iterator allocator_iterator_; |
| 217 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 218 | // A set of all interesting memory references found within the allocator. |
| 219 | std::set<PersistentMemoryAllocator::Reference> memory_references_; |
| 220 | |
| 221 | // A set of all process-data memory references found within the allocator. |
| 222 | std::map<int64_t, UserDataSnapshot> process_data_; |
| 223 | |
| 224 | // A set of all process IDs collected during PrepareAllAnalyzers. These are |
| 225 | // popped and returned one-by-one with calls to GetFirst/NextProcess(). |
| 226 | std::vector<int64_t> process_ids_; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 227 | |
| 228 | // A map, keyed by ThreadKey, of all valid activity analyzers. |
| 229 | AnalyzerMap analyzers_; |
| 230 | |
| 231 | // The iterator within the analyzers_ map for returning analyzers through |
| 232 | // first/next iteration. |
| 233 | AnalyzerMap::iterator analyzers_iterator_; |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 234 | int64_t analyzers_iterator_pid_; |
| 235 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 236 | DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer); |
| 237 | }; |
| 238 | |
| 239 | } // namespace debug |
| 240 | } // namespace base |
| 241 | |
| 242 | #endif // BASE_DEBUG_ACTIVITY_ANALYZER_H_ |