forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactivity_analyzer.h
262 lines (203 loc) · 9.44 KB
/
activity_analyzer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// 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"
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)
// 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);
// 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 // BASE_DEBUG_ACTIVITY_ANALYZER_H_