Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3004)

Unified Diff: base/debug/activity_tracker.h

Issue 1980743002: Track thread activities in order to diagnose hangs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@readwrite-mmf
Patch Set: addressed review comments Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/base.gypi ('k') | base/debug/activity_tracker.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/debug/activity_tracker.h
diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h
new file mode 100644
index 0000000000000000000000000000000000000000..7eff069acc2f956daa7e3cd5ae4298ea5a710cbd
--- /dev/null
+++ b/base/debug/activity_tracker.h
@@ -0,0 +1,270 @@
+// 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_METRICS_ACTIVITY_TRACKER_H_
+#define BASE_METRICS_ACTIVITY_TRACKER_H_
+
+#include <atomic>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+
+struct PendingTask;
+
+class Lock;
+class MemoryMappedFile;
+
+namespace debug {
+
+class ThreadActivityAnalyzer;
+
+
+// Enables the global activity tracker according to a field trial setting.
+BASE_EXPORT void SetupGlobalActivityTrackerFieldTrial();
+
+
+// This class manages tracking a stack of activities for a single thread in
+// a persistent manner. However, in order to support an operational mode where
+// another thread is analyzing this data in real-time, atomic operations are
+// used where necessary to guarantee a consistent view from the outside.
+class BASE_EXPORT ThreadActivityTracker {
+ public:
+ enum ActivityType : uint8_t {
+ ACT_TASK,
+ ACT_LOCK,
+ ACT_EVENT,
+ };
+
+ struct StackEntry {
+ int64_t time_ticks;
+ uint8_t activity_type;
+ intptr_t source_address;
+ intptr_t method_address;
+ uint64_t sequence_id;
+ };
+
+ class BASE_EXPORT ScopedActivity {
+ public:
+ ScopedActivity(ThreadActivityTracker* tracker,
+ const void* source,
+ ActivityType activity,
+ intptr_t method,
+ uint64_t sequence)
+ : tracker_(tracker), source_(source) {
+ if (tracker_)
+ tracker_->PushActivity(source, activity, method, sequence);
+ }
+ ~ScopedActivity() {
+ if (tracker_)
+ tracker_->PopActivity(source_);
+ }
+
+ private:
+ ThreadActivityTracker* const tracker_;
+ const void* const source_;
+ };
+
+ // A ThreadActivityTracker runs on top of memory that is managed externally.
+ // It must be large enough for the internal header and a few StackEntry
+ // blocks. See SizeForStackDepth().
+ ThreadActivityTracker(void* base, size_t size);
+ virtual ~ThreadActivityTracker();
+
+ // Indicate that a method of the given (arbitrary) identifier has started.
+ void PushActivity(const void* source,
+ ActivityType activity,
+ intptr_t method,
+ uint64_t sequence);
+
+ // Indicate that a method of the given (arbitrary) identifier has finished.
+ void PopActivity(const void* source);
+
+ // Returns whether the current data is valid or not. It is not valid if
+ // corruption is detected in the header or other data structures. Fetching
+ // a copy of the stack will return nothing if the data is not valid.
+ bool is_valid() { return valid_; }
+
+ // Creates an "analysis" object for this thread tracker. The operation of
+ // the returned object is only valid as long as the tracker from which it
+ // was created continues to live.
+ std::unique_ptr<ThreadActivityAnalyzer> CreateAnalyzer();
manzagop (departed) 2016/05/20 20:24:22 I'm not sure we need this, as I don't think tracke
bcwhite 2016/05/20 20:41:18 They do for testing. :-) It could be CreateAnaly
Sigurður Ásgeirsson 2016/05/24 14:11:50 You generally want to start with the MVI - minimum
bcwhite 2016/05/26 15:35:39 Done.
+
+ // Calculates the memory size required for a given stack depth, including
+ // the internal header structure for the stack.
+ static size_t SizeForStackDepth(int stack_depth);
+
+ protected:
+ struct Header;
+
+ // Gets the header structure so derived classes can do analysis on it.
+ Header* header() { return header_; }
+
+ // Gets the stack so derived classes can do analysis on it.
+ StackEntry* stack() { return stack_; }
+
+ // Gets the number of slots in the stack.
+ uint32_t stack_slots() { return stack_slots_; }
+
+ private:
+ friend class ActivityTrackerTest;
+
+ Header* const header_;
+ StackEntry* const stack_;
+ const uint32_t stack_slots_;
+
+ bool valid_ = false;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker);
+};
+
+
+// Be sure not to create multiple Analyzers for given tracker data as parallel
+// operation could lead to inconsistencies from concurrent synchronization with
+// an active tracker.
+class BASE_EXPORT ThreadActivityAnalyzer : private ThreadActivityTracker {
manzagop (departed) 2016/05/20 20:24:22 Would it be cleaner for the analyzer not to derive
bcwhite 2016/05/20 20:41:18 Perhaps. This re-uses the initialization and vali
Sigurður Ásgeirsson 2016/05/24 14:11:50 no private inheritance in C++: https://google.gith
Sigurður Ásgeirsson 2016/05/24 14:11:50 Private inheritance is verboten in Chromium and Go
bcwhite 2016/05/26 15:35:39 Acknowledged.
+ public:
+ ThreadActivityAnalyzer(void* base, size_t size);
+ ~ThreadActivityAnalyzer() override;
+
+ // Gets a copy of the current stack contents. The return value is the current
+ // depth of the stack which may be greater than the number of StackEntry
+ // records returned. If so, the returned stack has the "base" of the stack
+ // with later entries omitted.
+ uint32_t SnapshotStack(std::vector<StackEntry>* snapshot);
+};
+
+
+class BASE_EXPORT GlobalActivityTracker {
+ public:
+ class BASE_EXPORT ScopedThreadActivity
+ : public ThreadActivityTracker::ScopedActivity {
+ public:
+ ScopedThreadActivity(const void* source,
+ ThreadActivityTracker::ActivityType activity,
+ intptr_t method,
+ uint64_t sequence)
+ : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(),
+ source,
+ activity,
+ method,
+ sequence) {}
+
+ private:
+ static ThreadActivityTracker* GetOrCreateTracker() {
+ GlobalActivityTracker* global_tracker = Get();
+ if (!global_tracker)
+ return nullptr;
+ return global_tracker->GetOrCreateTrackerForCurrentThread();
+ }
+ };
+
+ ~GlobalActivityTracker();
+
+ static void CreateWithAllocator(
+ std::unique_ptr<PersistentMemoryAllocator> allocator,
+ int stack_depth);
+
+ static void CreateWithLocalMemory(size_t size,
+ uint64_t id,
+ StringPiece name,
+ int stack_depth);
+
+ static void CreateWithFile(const FilePath& file_path,
+ size_t size,
+ uint64_t id,
+ StringPiece name,
+ int stack_depth);
+
+ // Gets the global activity-tracker or null if none exists.
+ static GlobalActivityTracker* Get() { return g_tracker_; }
+
+ // Gets the persistent-memory-allocator in which data is stored. Callers
+ // can store additional records here to pass additional information to
+ // the analysis process.
+ PersistentMemoryAllocator* allocator() { return allocator_.get(); }
+
+ // Gets the thread's activity-tracker, assuming it already exists. This
+ // is inline for performance reasons. Ownership remains with the global
+ // tracker.
+ ThreadActivityTracker* GetTrackerForCurrentThread() {
+ void* tracker = this_thread_tracker_.Get();
+ DCHECK(tracker);
+ return reinterpret_cast<ThreadActivityTracker*>(tracker);
+ }
+
+ // Gets the thread's activity-tracker or creates one if none exists. This
+ // is inline for performance reasons. Ownership remains with the global
+ // tracker.
+ ThreadActivityTracker* GetOrCreateTrackerForCurrentThread() {
+ void* tracker = this_thread_tracker_.Get();
+ if (tracker)
+ return reinterpret_cast<ThreadActivityTracker*>(tracker);
+ return CreateTrackerForCurrentThread();
+ }
+
+ // Creates an activity-tracker for the current thread.
+ ThreadActivityTracker* CreateTrackerForCurrentThread();
+
+ // Releases the activity-tracker for the current thread (for testing only).
+ void ReleaseTrackerForCurrentThreadForTesting();
+
+ private:
+ friend class ActivityTrackerTest;
+
+ class ManagedActivityTracker : public ThreadActivityTracker {
+ public:
+ ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference,
+ void* base,
+ size_t size);
+ ~ManagedActivityTracker() override;
+
+ private:
+ const PersistentMemoryAllocator::Reference mem_reference_;
+ void* const mem_base_;
+ };
+
+ GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator,
+ int stack_depth);
+
+ // Returns the memory used by an activity-tracker managed by this class.
+ void ReturnTrackerMemory(ManagedActivityTracker* tracker,
+ PersistentMemoryAllocator::Reference mem_reference,
+ void* mem_base);
+
+ static void OnTLSDestroy(void* value);
+
+ std::unique_ptr<PersistentMemoryAllocator> allocator_;
+ const size_t stack_memory_;
+
+ base::ThreadLocalStorage::Slot this_thread_tracker_;
+
+ Lock lock_;
+ std::set<ManagedActivityTracker*> thread_trackers_;
+ std::vector<PersistentMemoryAllocator::Reference> available_memories_;
+
+ static GlobalActivityTracker* g_tracker_;
+};
+
+class BASE_EXPORT ScopedTaskActivity
+ : public GlobalActivityTracker::ScopedThreadActivity {
+ public:
+ ScopedTaskActivity(const base::PendingTask& task);
+};
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_METRICS_ACTIVITY_TRACKER_H_
« no previous file with comments | « base/base.gypi ('k') | base/debug/activity_tracker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698