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