activity_analyzer.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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. #include "base/debug/activity_analyzer.h"
  5. #include <utility>
  6. #include "base/check_op.h"
  7. #include "base/containers/contains.h"
  8. #include "base/files/file.h"
  9. #include "base/files/file_path.h"
  10. #include "base/files/memory_mapped_file.h"
  11. #include "base/metrics/histogram_functions.h"
  12. #include "base/metrics/histogram_macros.h"
  13. #include "base/no_destructor.h"
  14. #include "base/ranges/algorithm.h"
  15. #include "base/strings/string_util.h"
  16. #include "build/build_config.h"
  17. namespace base {
  18. namespace debug {
  19. namespace {
  20. const ActivityUserData::Snapshot& GetEmptyUserDataSnapshot() {
  21. // An empty snapshot that can be returned when there otherwise is none.
  22. static const NoDestructor<ActivityUserData::Snapshot> empty_snapshot;
  23. return *empty_snapshot;
  24. }
  25. // DO NOT CHANGE VALUES. This is logged persistently in a histogram.
  26. enum AnalyzerCreationError {
  27. kInvalidMemoryMappedFile,
  28. kPmaBadFile,
  29. kPmaUninitialized,
  30. kPmaDeleted,
  31. kPmaCorrupt,
  32. kAnalyzerCreationErrorMax // Keep this last.
  33. };
  34. void LogAnalyzerCreationError(AnalyzerCreationError error) {
  35. UmaHistogramEnumeration("ActivityTracker.Collect.AnalyzerCreationError",
  36. error, kAnalyzerCreationErrorMax);
  37. }
  38. } // namespace
  39. ThreadActivityAnalyzer::Snapshot::Snapshot() = default;
  40. ThreadActivityAnalyzer::Snapshot::~Snapshot() = default;
  41. ThreadActivityAnalyzer::ThreadActivityAnalyzer(
  42. const ThreadActivityTracker& tracker)
  43. : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {}
  44. ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size)
  45. : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {}
  46. ThreadActivityAnalyzer::ThreadActivityAnalyzer(
  47. PersistentMemoryAllocator* allocator,
  48. PersistentMemoryAllocator::Reference reference)
  49. : ThreadActivityAnalyzer(allocator->GetAsArray<char>(
  50. reference,
  51. GlobalActivityTracker::kTypeIdActivityTracker,
  52. PersistentMemoryAllocator::kSizeAny),
  53. allocator->GetAllocSize(reference)) {}
  54. ThreadActivityAnalyzer::~ThreadActivityAnalyzer() = default;
  55. void ThreadActivityAnalyzer::AddGlobalInformation(
  56. GlobalActivityAnalyzer* global) {
  57. if (!IsValid())
  58. return;
  59. // User-data is held at the global scope even though it's referenced at the
  60. // thread scope.
  61. activity_snapshot_.user_data_stack.clear();
  62. for (auto& activity : activity_snapshot_.activity_stack) {
  63. // The global GetUserDataSnapshot will return an empty snapshot if the ref
  64. // or id is not valid.
  65. activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot(
  66. activity_snapshot_.process_id, activity.user_data_ref,
  67. activity.user_data_id));
  68. }
  69. }
  70. GlobalActivityAnalyzer::GlobalActivityAnalyzer(
  71. std::unique_ptr<PersistentMemoryAllocator> allocator)
  72. : allocator_(std::move(allocator)),
  73. analysis_stamp_(0LL),
  74. allocator_iterator_(allocator_.get()) {
  75. DCHECK(allocator_);
  76. }
  77. GlobalActivityAnalyzer::~GlobalActivityAnalyzer() = default;
  78. // static
  79. std::unique_ptr<GlobalActivityAnalyzer>
  80. GlobalActivityAnalyzer::CreateWithAllocator(
  81. std::unique_ptr<PersistentMemoryAllocator> allocator) {
  82. if (allocator->GetMemoryState() ==
  83. PersistentMemoryAllocator::MEMORY_UNINITIALIZED) {
  84. LogAnalyzerCreationError(kPmaUninitialized);
  85. return nullptr;
  86. }
  87. if (allocator->GetMemoryState() ==
  88. PersistentMemoryAllocator::MEMORY_DELETED) {
  89. LogAnalyzerCreationError(kPmaDeleted);
  90. return nullptr;
  91. }
  92. if (allocator->IsCorrupt()) {
  93. LogAnalyzerCreationError(kPmaCorrupt);
  94. return nullptr;
  95. }
  96. return std::make_unique<GlobalActivityAnalyzer>(std::move(allocator));
  97. }
  98. #if !BUILDFLAG(IS_NACL)
  99. // static
  100. std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile(
  101. const FilePath& file_path) {
  102. // Map the file read-write so it can guarantee consistency between
  103. // the analyzer and any trackers that my still be active.
  104. std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
  105. if (!mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE)) {
  106. LogAnalyzerCreationError(kInvalidMemoryMappedFile);
  107. return nullptr;
  108. }
  109. if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) {
  110. LogAnalyzerCreationError(kPmaBadFile);
  111. return nullptr;
  112. }
  113. return CreateWithAllocator(std::make_unique<FilePersistentMemoryAllocator>(
  114. std::move(mmfile), 0, 0, StringPiece(), /*readonly=*/true));
  115. }
  116. #endif // !BUILDFLAG(IS_NACL)
  117. // static
  118. std::unique_ptr<GlobalActivityAnalyzer>
  119. GlobalActivityAnalyzer::CreateWithSharedMemory(
  120. base::ReadOnlySharedMemoryMapping mapping) {
  121. if (!mapping.IsValid() ||
  122. !ReadOnlySharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(
  123. mapping)) {
  124. return nullptr;
  125. }
  126. return CreateWithAllocator(
  127. std::make_unique<ReadOnlySharedPersistentMemoryAllocator>(
  128. std::move(mapping), 0, StringPiece()));
  129. }
  130. ProcessId GlobalActivityAnalyzer::GetFirstProcess() {
  131. PrepareAllAnalyzers();
  132. return GetNextProcess();
  133. }
  134. ProcessId GlobalActivityAnalyzer::GetNextProcess() {
  135. if (process_ids_.empty())
  136. return 0;
  137. ProcessId pid = process_ids_.back();
  138. process_ids_.pop_back();
  139. return pid;
  140. }
  141. ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(
  142. ProcessId pid) {
  143. analyzers_iterator_ = analyzers_.begin();
  144. analyzers_iterator_pid_ = pid;
  145. if (analyzers_iterator_ == analyzers_.end())
  146. return nullptr;
  147. int64_t create_stamp;
  148. if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
  149. create_stamp <= analysis_stamp_) {
  150. return analyzers_iterator_->second.get();
  151. }
  152. return GetNextAnalyzer();
  153. }
  154. ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
  155. DCHECK(analyzers_iterator_ != analyzers_.end());
  156. int64_t create_stamp;
  157. do {
  158. ++analyzers_iterator_;
  159. if (analyzers_iterator_ == analyzers_.end())
  160. return nullptr;
  161. } while (analyzers_iterator_->second->GetProcessId(&create_stamp) !=
  162. analyzers_iterator_pid_ ||
  163. create_stamp > analysis_stamp_);
  164. return analyzers_iterator_->second.get();
  165. }
  166. ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
  167. const ThreadKey& key) {
  168. auto found = analyzers_.find(key);
  169. if (found == analyzers_.end())
  170. return nullptr;
  171. return found->second.get();
  172. }
  173. ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
  174. ProcessId pid,
  175. uint32_t ref,
  176. uint32_t id) {
  177. ActivityUserData::Snapshot snapshot;
  178. void* memory = allocator_->GetAsArray<char>(
  179. ref, GlobalActivityTracker::kTypeIdUserDataRecord,
  180. PersistentMemoryAllocator::kSizeAny);
  181. if (memory) {
  182. size_t size = allocator_->GetAllocSize(ref);
  183. const ActivityUserData user_data(memory, size);
  184. user_data.CreateSnapshot(&snapshot);
  185. ProcessId process_id;
  186. int64_t create_stamp;
  187. if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
  188. &create_stamp) ||
  189. process_id != pid || user_data.id() != id) {
  190. // This allocation has been overwritten since it was created. Return an
  191. // empty snapshot because whatever was captured is incorrect.
  192. snapshot.clear();
  193. }
  194. }
  195. return snapshot;
  196. }
  197. const ActivityUserData::Snapshot&
  198. GlobalActivityAnalyzer::GetProcessDataSnapshot(ProcessId pid) {
  199. auto iter = process_data_.find(pid);
  200. if (iter == process_data_.end())
  201. return GetEmptyUserDataSnapshot();
  202. if (iter->second.create_stamp > analysis_stamp_)
  203. return GetEmptyUserDataSnapshot();
  204. DCHECK_EQ(pid, iter->second.process_id);
  205. return iter->second.data;
  206. }
  207. std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
  208. std::vector<std::string> messages;
  209. PersistentMemoryAllocator::Reference ref;
  210. PersistentMemoryAllocator::Iterator iter(allocator_.get());
  211. while ((ref = iter.GetNextOfType(
  212. GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) {
  213. const char* message = allocator_->GetAsArray<char>(
  214. ref, GlobalActivityTracker::kTypeIdGlobalLogMessage,
  215. PersistentMemoryAllocator::kSizeAny);
  216. if (message)
  217. messages.push_back(message);
  218. }
  219. return messages;
  220. }
  221. std::vector<GlobalActivityTracker::ModuleInfo>
  222. GlobalActivityAnalyzer::GetModules(ProcessId pid) {
  223. std::vector<GlobalActivityTracker::ModuleInfo> modules;
  224. PersistentMemoryAllocator::Iterator iter(allocator_.get());
  225. const GlobalActivityTracker::ModuleInfoRecord* record;
  226. while (
  227. (record =
  228. iter.GetNextOfObject<GlobalActivityTracker::ModuleInfoRecord>()) !=
  229. nullptr) {
  230. ProcessId process_id;
  231. int64_t create_stamp;
  232. if (!OwningProcess::GetOwningProcessId(&record->owner, &process_id,
  233. &create_stamp) ||
  234. pid != process_id || create_stamp > analysis_stamp_) {
  235. continue;
  236. }
  237. GlobalActivityTracker::ModuleInfo info;
  238. if (record->DecodeTo(&info, allocator_->GetAllocSize(
  239. allocator_->GetAsReference(record)))) {
  240. modules.push_back(std::move(info));
  241. }
  242. }
  243. return modules;
  244. }
  245. GlobalActivityAnalyzer::ProgramLocation
  246. GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
  247. // This should be implemented but it's never been a priority.
  248. return { 0, 0 };
  249. }
  250. bool GlobalActivityAnalyzer::IsDataComplete() const {
  251. DCHECK(allocator_);
  252. return !allocator_->IsFull();
  253. }
  254. GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() = default;
  255. GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
  256. const UserDataSnapshot& rhs) = default;
  257. GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
  258. UserDataSnapshot&& rhs) = default;
  259. GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() = default;
  260. void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
  261. // Record the time when analysis started.
  262. analysis_stamp_ = base::Time::Now().ToInternalValue();
  263. // Fetch all the records. This will retrieve only ones created since the
  264. // last run since the PMA iterator will continue from where it left off.
  265. uint32_t type;
  266. PersistentMemoryAllocator::Reference ref;
  267. while ((ref = allocator_iterator_.GetNext(&type)) != 0) {
  268. switch (type) {
  269. case GlobalActivityTracker::kTypeIdActivityTracker:
  270. case GlobalActivityTracker::kTypeIdActivityTrackerFree:
  271. case GlobalActivityTracker::kTypeIdProcessDataRecord:
  272. case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
  273. case PersistentMemoryAllocator::kTypeIdTransitioning:
  274. // Active, free, or transitioning: add it to the list of references
  275. // for later analysis.
  276. memory_references_.insert(ref);
  277. break;
  278. }
  279. }
  280. // Clear out any old information.
  281. analyzers_.clear();
  282. process_data_.clear();
  283. process_ids_.clear();
  284. std::set<ProcessId> seen_pids;
  285. // Go through all the known references and create objects for them with
  286. // snapshots of the current state.
  287. for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
  288. // Get the actual data segment for the tracker. Any type will do since it
  289. // is checked below.
  290. void* const base = allocator_->GetAsArray<char>(
  291. memory_ref, PersistentMemoryAllocator::kTypeIdAny,
  292. PersistentMemoryAllocator::kSizeAny);
  293. const size_t size = allocator_->GetAllocSize(memory_ref);
  294. if (!base)
  295. continue;
  296. switch (allocator_->GetType(memory_ref)) {
  297. case GlobalActivityTracker::kTypeIdActivityTracker: {
  298. // Create the analyzer on the data. This will capture a snapshot of the
  299. // tracker state. This can fail if the tracker is somehow corrupted or
  300. // is in the process of shutting down.
  301. std::unique_ptr<ThreadActivityAnalyzer> analyzer(
  302. new ThreadActivityAnalyzer(base, size));
  303. if (!analyzer->IsValid())
  304. continue;
  305. analyzer->AddGlobalInformation(this);
  306. // Track PIDs.
  307. ProcessId pid = analyzer->GetProcessId();
  308. if (seen_pids.find(pid) == seen_pids.end()) {
  309. process_ids_.push_back(pid);
  310. seen_pids.insert(pid);
  311. }
  312. // Add this analyzer to the map of known ones, indexed by a unique
  313. // thread
  314. // identifier.
  315. DCHECK(!base::Contains(analyzers_, analyzer->GetThreadKey()));
  316. analyzer->allocator_reference_ = ref;
  317. analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
  318. } break;
  319. case GlobalActivityTracker::kTypeIdProcessDataRecord: {
  320. // Get the PID associated with this data record.
  321. ProcessId process_id;
  322. int64_t create_stamp;
  323. ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
  324. DCHECK(!base::Contains(process_data_, process_id));
  325. // Create a snapshot of the data. This can fail if the data is somehow
  326. // corrupted or the process shutdown and the memory being released.
  327. UserDataSnapshot& snapshot = process_data_[process_id];
  328. snapshot.process_id = process_id;
  329. snapshot.create_stamp = create_stamp;
  330. const ActivityUserData process_data(base, size);
  331. if (!process_data.CreateSnapshot(&snapshot.data))
  332. break;
  333. // Check that nothing changed. If it did, forget what was recorded.
  334. ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
  335. if (process_id != snapshot.process_id ||
  336. create_stamp != snapshot.create_stamp) {
  337. process_data_.erase(process_id);
  338. break;
  339. }
  340. // Track PIDs.
  341. if (seen_pids.find(process_id) == seen_pids.end()) {
  342. process_ids_.push_back(process_id);
  343. seen_pids.insert(process_id);
  344. }
  345. } break;
  346. }
  347. }
  348. // Reverse the list of PIDs so that they get popped in the order found.
  349. ranges::reverse(process_ids_);
  350. }
  351. } // namespace debug
  352. } // namespace base