Index: base/debug/activity_tracker.h |
diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h |
index a3a9419c7ab1eb01a6edc0f9f4bab0bb72db5b7c..258b54fa0fc8bf6db78ad68ed40b9b2ee825cb52 100644 |
--- a/base/debug/activity_tracker.h |
+++ b/base/debug/activity_tracker.h |
@@ -155,6 +155,18 @@ class ActivityTrackerMemoryAllocator { |
// Returns an object to the "free" pool. |
void ReleaseObjectReference(Reference ref); |
+ // Helper function to access an object allocated using this instance. |
+ template <typename T> |
+ T* GetAsObject(Reference ref) { |
+ return allocator_->GetAsObject<T>(ref, object_type_); |
+ } |
+ |
+ // Similar to GetAsObject() but converts references to arrays of objects. |
+ template <typename T> |
+ T* GetAsArray(Reference ref, size_t count) { |
+ return allocator_->GetAsArray<T>(ref, object_type_, count); |
+ } |
+ |
// The current "used size" of the internal cache, visible for testing. |
size_t cache_used() const { return cache_used_; } |
@@ -244,8 +256,10 @@ struct Activity { |
// enabled. |
uint64_t call_stack[kActivityCallStackSize]; |
- // Reference to arbitrary user data within the persistent memory segment. |
- uint32_t user_data; |
+ // Reference to arbitrary user data within the persistent memory segment |
+ // and a unique identifier for it. |
+ uint32_t user_data_ref; |
+ uint32_t user_data_id; |
// The (enumerated) type of the activity. This defines what fields of the |
// |data| record are valid. |
@@ -254,7 +268,7 @@ struct Activity { |
// Padding to ensure that the next member begins on a 64-bit boundary |
// even on 32-bit builds which ensures inter-operability between CPU |
// architectures. New fields can be taken from this space. |
- uint8_t padding[3]; |
+ uint8_t padding[7]; |
// Information specific to the |activity_type|. |
ActivityData data; |
@@ -266,40 +280,12 @@ struct Activity { |
const ActivityData& data); |
}; |
-// This structure holds a copy of all the internal data at the moment the |
-// "snapshot" operation is done. It is disconnected from the live tracker |
-// so that continued operation of the thread will not cause changes here. |
-struct BASE_EXPORT ActivitySnapshot { |
- // Explicit constructor/destructor are needed because of complex types |
- // with non-trivial default constructors and destructors. |
- ActivitySnapshot(); |
- ~ActivitySnapshot(); |
- |
- // The name of the thread as set when it was created. The name may be |
- // truncated due to internal length limitations. |
- std::string thread_name; |
- |
- // The process and thread IDs. These values have no meaning other than |
- // they uniquely identify a running process and a running thread within |
- // that process. Thread-IDs can be re-used across different processes |
- // and both can be re-used after the process/thread exits. |
- int64_t process_id = 0; |
- int64_t thread_id = 0; |
- |
- // The current stack of activities that are underway for this thread. It |
- // is limited in its maximum size with later entries being left off. |
- std::vector<Activity> activity_stack; |
- |
- // The current total depth of the activity stack, including those later |
- // entries not recorded in the |activity_stack| vector. |
- uint32_t activity_stack_depth = 0; |
-}; |
- |
// This class manages arbitrary user data that can be associated with activities |
// done by a thread by supporting key/value pairs of any type. This can provide |
// additional information during debugging. It is also used to store arbitrary |
// global data. All updates must be done from the same thread. |
class BASE_EXPORT ActivityUserData { |
+ public: |
// List of known value type. REFERENCE types must immediately follow the non- |
// external types. |
enum ValueType : uint8_t { |
@@ -309,14 +295,53 @@ class BASE_EXPORT ActivityUserData { |
STRING_VALUE, |
STRING_VALUE_REFERENCE, |
CHAR_VALUE, |
+ BOOL_VALUE, |
SIGNED_VALUE, |
UNSIGNED_VALUE, |
}; |
- public: |
+ class BASE_EXPORT TypedValue { |
+ public: |
+ TypedValue(); |
+ TypedValue(const TypedValue& other); |
+ ~TypedValue(); |
+ |
+ // These methods return the extracted value in the correct format. |
+ StringPiece Get() const; |
+ StringPiece GetString() const; |
+ bool GetBool() const; |
+ char GetChar() const; |
+ int64_t GetInt() const; |
+ uint64_t GetUint() const; |
+ |
+ // These methods return references to process memory as originally provided |
+ // to correpsonding Set calls. USE WITH CAUTION! There is no guarantee that |
manzagop (departed)
2016/12/02 22:13:32
typo: correpsonding
bcwhite
2016/12/08 21:30:56
Done.
|
+ // the referenced memory is accessible or still contains the information |
manzagop (departed)
2016/12/02 22:13:32
Also mention it might be from a different process?
bcwhite
2016/12/08 21:30:56
Done.
|
+ // that was originally considered important. |
+ StringPiece GetReference() const; |
+ StringPiece GetStringReference() const; |
+ |
+ private: |
+ friend class ActivityUserData; |
+ |
+ ValueType type; |
+ uint64_t short_value; // Used to hold copy of numbers, etc. |
+ std::string long_value; // Used to hold copy of raw/string data. |
+ StringPiece ref_value; // Used to hold reference to external data. |
+ }; |
+ |
+ using Snapshot = std::map<std::string, TypedValue>; |
+ |
ActivityUserData(void* memory, size_t size); |
~ActivityUserData(); |
+ // Gets the unique ID number for this user data. If this changes then the |
+ // contents have been overwritten by another thread. The return value is |
+ // always non-zero unless it's actually just a data "sink". |
+ uint32_t id() const { |
+ return memory_ ? id_->load(std::memory_order_relaxed) : 0; |
+ } |
+ |
// Writes a |value| (as part of a key/value pair) that will be included with |
// the activity in any reports. The same |name| can be written multiple times |
// with each successive call overwriting the previously stored |value|. For |
@@ -332,6 +357,10 @@ class BASE_EXPORT ActivityUserData { |
void SetString(StringPiece name, StringPiece value) { |
Set(name, STRING_VALUE, value.data(), value.length()); |
} |
+ void SetBool(StringPiece name, bool value) { |
+ char cvalue = value ? 1 : 0; |
+ Set(name, BOOL_VALUE, &cvalue, sizeof(cvalue)); |
+ } |
void SetChar(StringPiece name, char value) { |
Set(name, CHAR_VALUE, &value, sizeof(value)); |
} |
@@ -353,6 +382,16 @@ class BASE_EXPORT ActivityUserData { |
SetReference(name, STRING_VALUE_REFERENCE, value.data(), value.length()); |
} |
+ // Creates a snapshot of the key/value pairs contained within. The returned |
+ // data will be fixed, independent of whatever changes afterward. There is |
+ // protection against concurrent modification of the values but no protection |
+ // against a complete overwrite of the contents; the caller must ensure that |
+ // the memory segment is not going to be re-initialized while this runs. |
+ bool CreateSnapshot(Snapshot* output_snapshot) const; |
+ |
+ // Gets the base memory address used for storing data. |
+ const void* GetBaseAddress(); |
+ |
private: |
FRIEND_TEST_ALL_PREFIXES(ActivityTrackerTest, UserDataTest); |
@@ -392,18 +431,62 @@ class BASE_EXPORT ActivityUserData { |
const void* memory, |
size_t size); |
- // TODO(bcwhite): Add Get() methods for Analyzer to use. |
+ // Loads any data already in the memory segment. This allows for accessing |
+ // records created previously. |
+ void ImportExistingData() const; |
+ |
+ // A map of all the values within the memory block, keyed by name for quick |
+ // updates of the values. This is "mutable" because it changes on "const" |
+ // objects even when the actual data values can't change. |
+ mutable std::map<StringPiece, ValueInfo> values_; |
- std::map<StringPiece, ValueInfo> values_; |
+ // Information about the memory block in which new data can be stored. These |
+ // are "mutable" because they change even on "const" objects that are just |
+ // skipping already set values. |
+ mutable char* memory_; |
+ mutable size_t available_; |
- char* memory_; |
- size_t available_; |
+ // A pointer to the unique ID for this instance. |
+ std::atomic<uint32_t>* const id_; |
base::ThreadChecker thread_checker_; |
+ // This ID is used to create unique indentifiers for user data so that it's |
+ // possible to tell if the information has been overwritten. |
+ static std::atomic<uint32_t> next_id_; |
+ |
DISALLOW_COPY_AND_ASSIGN(ActivityUserData); |
}; |
+// This structure holds a copy of all the internal data at the moment the |
+// "snapshot" operation is done. It is disconnected from the live tracker |
+// so that continued operation of the thread will not cause changes here. |
+struct BASE_EXPORT ActivitySnapshot { |
+ // Explicit constructor/destructor are needed because of complex types |
+ // with non-trivial default constructors and destructors. |
+ ActivitySnapshot(); |
+ ~ActivitySnapshot(); |
+ |
+ // The name of the thread as set when it was created. The name may be |
+ // truncated due to internal length limitations. |
+ std::string thread_name; |
+ |
+ // The process and thread IDs. These values have no meaning other than |
+ // they uniquely identify a running process and a running thread within |
+ // that process. Thread-IDs can be re-used across different processes |
+ // and both can be re-used after the process/thread exits. |
+ int64_t process_id = 0; |
+ int64_t thread_id = 0; |
+ |
+ // The current stack of activities that are underway for this thread. It |
+ // is limited in its maximum size with later entries being left off. |
+ std::vector<Activity> activity_stack; |
+ |
+ // The current total depth of the activity stack, including those later |
+ // entries not recorded in the |activity_stack| vector. |
+ uint32_t activity_stack_depth = 0; |
+}; |
+ |
// This class manages tracking a stack of activities for a single thread in |
// a persistent manner, implementing a bounded-size stack in a fixed-size |
// memory allocation. In order to support an operational mode where another |
@@ -438,10 +521,7 @@ class BASE_EXPORT ThreadActivityTracker { |
// Changes some basic metadata about the activity. |
void ChangeTypeAndData(Activity::Type type, const ActivityData& data); |
- // Returns an object for manipulating user data. |
- ActivityUserData& user_data(); |
- |
- private: |
+ protected: |
// The thread tracker to which this object reports. It can be null if |
// activity tracking is not (yet) enabled. |
ThreadActivityTracker* const tracker_; |
@@ -449,9 +529,6 @@ class BASE_EXPORT ThreadActivityTracker { |
// An identifier that indicates a specific activity on the stack. |
ActivityId activity_id_; |
- // An object that manages additional user data, created only upon request. |
- std::unique_ptr<ActivityUserData> user_data_; |
- |
DISALLOW_COPY_AND_ASSIGN(ScopedActivity); |
}; |
@@ -495,8 +572,18 @@ class BASE_EXPORT ThreadActivityTracker { |
// Indicates that an activity has completed. |
void PopActivity(ActivityId id); |
- // Returns an object capable of storing arbitrary user data. |
- std::unique_ptr<ActivityUserData> GetUserData(ActivityId id); |
+ // Sets the user-data information for an activity. |
+ std::unique_ptr<ActivityUserData> GetUserData( |
+ ActivityId id, |
+ ActivityTrackerMemoryAllocator* allocator); |
+ |
+ // Returns if there is true use-data associated with a given ActivityId since |
+ // it's possible than any returned object is just a sink. |
+ bool HasUserData(ActivityId id); |
+ |
+ // Release the user-data information for an activity. |
+ void ReleaseUserData(ActivityId id, |
+ ActivityTrackerMemoryAllocator* allocator); |
// Returns whether the current data is valid or not. It is not valid if |
// corruption has been detected in the header or other data structures. |
@@ -506,7 +593,7 @@ class BASE_EXPORT ThreadActivityTracker { |
// snapshot was not possible, perhaps because the data is not valid; the |
// contents of |output_snapshot| are undefined in that case. The current |
// implementation does not support concurrent snapshot operations. |
- bool Snapshot(ActivitySnapshot* output_snapshot) const; |
+ bool CreateSnapshot(ActivitySnapshot* output_snapshot) const; |
// Calculates the memory size required for a given stack depth, including |
// the internal header structure for the stack. |
@@ -539,9 +626,9 @@ class BASE_EXPORT GlobalActivityTracker { |
// will be safely ignored. These are public so that an external process |
// can recognize records of this type within an allocator. |
enum : uint32_t { |
- kTypeIdActivityTracker = 0x5D7381AF + 3, // SHA1(ActivityTracker) v3 |
- kTypeIdUserDataRecord = 0x615EDDD7 + 1, // SHA1(UserDataRecord) v1 |
- kTypeIdGlobalDataRecord = 0xAFE61ABE + 1, // SHA1(GlobalDataRecord) v1 |
+ kTypeIdActivityTracker = 0x5D7381AF + 3, // SHA1(ActivityTracker) v3 |
+ kTypeIdUserDataRecord = 0x615EDDD7 + 2, // SHA1(UserDataRecord) v2 |
+ kTypeIdGlobalDataRecord = kTypeIdUserDataRecord + 0x5F1184F7, // Global |
kTypeIdActivityTrackerFree = ~kTypeIdActivityTracker, |
kTypeIdUserDataRecordFree = ~kTypeIdUserDataRecord, |
@@ -558,13 +645,11 @@ class BASE_EXPORT GlobalActivityTracker { |
const void* origin, |
Activity::Type type, |
const ActivityData& data, |
- bool lock_allowed) |
- : ThreadActivityTracker::ScopedActivity( |
- GetOrCreateTracker(lock_allowed), |
- program_counter, |
- origin, |
- type, |
- data) {} |
+ bool lock_allowed); |
+ ~ScopedThreadActivity(); |
+ |
+ // Returns an object for manipulating user data. |
+ ActivityUserData& user_data(); |
private: |
// Gets (or creates) a tracker for the current thread. If locking is not |
@@ -582,6 +667,9 @@ class BASE_EXPORT GlobalActivityTracker { |
return global_tracker->GetTrackerForCurrentThread(); |
} |
+ // An object that manages additional user data, created only upon request. |
+ std::unique_ptr<ActivityUserData> user_data_; |
+ |
DISALLOW_COPY_AND_ASSIGN(ScopedThreadActivity); |
}; |
@@ -645,18 +733,11 @@ class BASE_EXPORT GlobalActivityTracker { |
// Releases the activity-tracker for the current thread (for testing only). |
void ReleaseTrackerForCurrentThreadForTesting(); |
- // Gets a reference to memory for holding user-defined activity data. If |
- // the reference is valid, it's memory will be returned. If not, then a |
- // new reference will be created (and stored) and that memory returned. |
- void* GetUserDataMemory(PersistentMemoryAllocator::Reference* reference); |
- |
- // Releases memory for user-defined activity data. |
- void ReleaseUserDataMemory(PersistentMemoryAllocator::Reference* reference); |
- |
// Accesses the global data record for storing arbitrary key/value pairs. |
ActivityUserData& user_data() { return user_data_; } |
private: |
+ friend class ScopedThreadActivity; |
friend class ActivityTrackerTest; |
enum : int { |