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>
11 #include <string>
12 #include <vector>
13 
14 #include "base/base_export.h"
15 #include "base/debug/activity_tracker.h"
16 
17 namespace base {
18 namespace debug {
19 
20 class GlobalActivityAnalyzer;
21 
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:
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 
36   // This class provides keys that uniquely identify a thread, even across
37   // multiple processes.
38   class ThreadKey {
39    public:
ThreadKey(int64_t pid,int64_t tid)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 
74   // Adds information from the global analyzer.
75   void AddGlobalInformation(GlobalActivityAnalyzer* global);
76 
77   // Returns true iff the contained data is valid. Results from all other
78   // methods are undefined if this returns false.
IsValid()79   bool IsValid() { return activity_snapshot_valid_; }
80 
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 
88   // Gets the name of the thread.
GetThreadName()89   const std::string& GetThreadName() {
90     return activity_snapshot_.thread_name;
91   }
92 
93   // Gets the TheadKey for this thread.
GetThreadKey()94   ThreadKey GetThreadKey() {
95     return ThreadKey(activity_snapshot_.process_id,
96                      activity_snapshot_.thread_id);
97   }
98 
activity_snapshot()99   const Snapshot& activity_snapshot() { return activity_snapshot_; }
100 
101  private:
102   friend class GlobalActivityAnalyzer;
103 
104   // The snapshot of the activity tracker taken at the moment of construction.
105   Snapshot activity_snapshot_;
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:
127   struct ProgramLocation {
128     int module;
129     uintptr_t offset;
130   };
131 
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   // Creates a global analyzer using a given persistent-memory |allocator|.
141   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithAllocator(
142       std::unique_ptr<PersistentMemoryAllocator> allocator);
143 
144 #if !defined(OS_NACL)
145   // Creates a global analyzer using the contents of a file given in
146   // |file_path|.
147   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile(
148       const FilePath& file_path);
149 #endif  // !defined(OS_NACL)
150 
151   // Like above but accesses an allocator in a mapped shared-memory segment.
152   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemory(
153       std::unique_ptr<SharedMemory> shm);
154 
155   // Like above but takes a handle to an existing shared memory segment and
156   // maps it before creating the tracker.
157   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemoryHandle(
158       const SharedMemoryHandle& handle,
159       size_t size);
160 
161   // Iterates over all known valid processes and returns their PIDs or zero
162   // if there are no more. Calls to GetFirstProcess() will perform a global
163   // snapshot in order to provide a relatively consistent state across the
164   // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are
165   // returned in the order they're found meaning that a first-launched
166   // controlling process will be found first. Note, however, that space
167   // freed by an exiting process may be re-used by a later process.
168   int64_t GetFirstProcess();
169   int64_t GetNextProcess();
170 
171   // Iterates over all known valid analyzers for the a given process or returns
172   // null if there are no more.
173   //
174   // GetFirstProcess() must be called first in order to capture a global
175   // snapshot! Ownership stays with the global analyzer object and all existing
176   // analyzer pointers are invalidated when GetFirstProcess() is called.
177   ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid);
178   ThreadActivityAnalyzer* GetNextAnalyzer();
179 
180   // Gets the analyzer for a specific thread or null if there is none.
181   // Ownership stays with the global analyzer object.
182   ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key);
183 
184   // Extract user data based on a reference and its identifier.
185   ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid,
186                                                  uint32_t ref,
187                                                  uint32_t id);
188 
189   // Extract the data for a specific process. An empty snapshot will be
190   // returned if the process is not known.
191   const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid);
192 
193   // Gets all log messages stored within.
194   std::vector<std::string> GetLogMessages();
195 
196   // Gets modules corresponding to a pid. This pid must come from a call to
197   // GetFirst/NextProcess. Only modules that were first registered prior to
198   // GetFirstProcess's snapshot are returned.
199   std::vector<GlobalActivityTracker::ModuleInfo> GetModules(int64_t pid);
200 
201   // Gets the corresponding "program location" for a given "program counter".
202   // This will return {0,0} if no mapping could be found.
203   ProgramLocation GetProgramLocationFromAddress(uint64_t address);
204 
205   // Returns whether the data is complete. Data can be incomplete if the
206   // recording size quota is hit.
207   bool IsDataComplete() const;
208 
209  private:
210   using AnalyzerMap =
211       std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>;
212 
213   struct UserDataSnapshot {
214     // Complex class needs out-of-line ctor/dtor.
215     UserDataSnapshot();
216     UserDataSnapshot(const UserDataSnapshot& rhs);
217     UserDataSnapshot(UserDataSnapshot&& rhs);
218     ~UserDataSnapshot();
219 
220     int64_t process_id;
221     int64_t create_stamp;
222     ActivityUserData::Snapshot data;
223   };
224 
225   // Finds, creates, and indexes analyzers for all known processes and threads.
226   void PrepareAllAnalyzers();
227 
228   // The persistent memory allocator holding all tracking data.
229   std::unique_ptr<PersistentMemoryAllocator> allocator_;
230 
231   // The time stamp when analysis began. This is used to prevent looking into
232   // process IDs that get reused when analyzing a live system.
233   int64_t analysis_stamp_;
234 
235   // The iterator for finding tracking information in the allocator.
236   PersistentMemoryAllocator::Iterator allocator_iterator_;
237 
238   // A set of all interesting memory references found within the allocator.
239   std::set<PersistentMemoryAllocator::Reference> memory_references_;
240 
241   // A set of all process-data memory references found within the allocator.
242   std::map<int64_t, UserDataSnapshot> process_data_;
243 
244   // A set of all process IDs collected during PrepareAllAnalyzers. These are
245   // popped and returned one-by-one with calls to GetFirst/NextProcess().
246   std::vector<int64_t> process_ids_;
247 
248   // A map, keyed by ThreadKey, of all valid activity analyzers.
249   AnalyzerMap analyzers_;
250 
251   // The iterator within the analyzers_ map for returning analyzers through
252   // first/next iteration.
253   AnalyzerMap::iterator analyzers_iterator_;
254   int64_t analyzers_iterator_pid_;
255 
256   DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer);
257 };
258 
259 }  // namespace debug
260 }  // namespace base
261 
262 #endif  // BASE_DEBUG_ACTIVITY_ANALYZER_H_
263