Index: base/tracked_objects.h |
diff --git a/base/tracked_objects.h b/base/tracked_objects.h |
index 7ef0317c39bb1712873d9a78856b5c32220aa1fd..ca518636ea7f728ade6bbd868e79f75b87474b6a 100644 |
--- a/base/tracked_objects.h |
+++ b/base/tracked_objects.h |
@@ -14,9 +14,12 @@ |
#include <utility> |
#include <vector> |
+#include "base/allocator/features.h" |
#include "base/atomicops.h" |
#include "base/base_export.h" |
#include "base/containers/hash_tables.h" |
+#include "base/debug/debugging_flags.h" |
+#include "base/debug/thread_heap_usage_tracker.h" |
#include "base/gtest_prod_util.h" |
#include "base/lazy_instance.h" |
#include "base/location.h" |
@@ -248,6 +251,8 @@ class BASE_EXPORT Births: public BirthOnThread { |
DISALLOW_COPY_AND_ASSIGN(Births); |
}; |
+class DeathData; |
+ |
//------------------------------------------------------------------------------ |
// A "snapshotted" representation of the DeathData class. |
@@ -265,7 +270,15 @@ struct BASE_EXPORT DeathDataSnapshot { |
int32_t run_duration_sample, |
int32_t queue_duration_sum, |
int32_t queue_duration_max, |
- int32_t queue_duration_sample); |
+ int32_t queue_duration_sample, |
+ int32_t alloc_ops, |
+ int32_t free_ops, |
+ int32_t allocated_bytes, |
+ int32_t freed_bytes, |
+ int32_t alloc_overhead_bytes, |
+ int32_t max_allocated_bytes); |
+ DeathDataSnapshot(const DeathData& death_data); |
+ DeathDataSnapshot(const DeathDataSnapshot& other); |
~DeathDataSnapshot(); |
// Calculates and returns the delta between this snapshot and an earlier |
@@ -279,6 +292,13 @@ struct BASE_EXPORT DeathDataSnapshot { |
int32_t queue_duration_sum; |
int32_t queue_duration_max; |
int32_t queue_duration_sample; |
+ |
+ int32_t alloc_ops; |
+ int32_t free_ops; |
+ int32_t allocated_bytes; |
+ int32_t freed_bytes; |
+ int32_t alloc_overhead_bytes; |
+ int32_t max_allocated_bytes; |
}; |
//------------------------------------------------------------------------------ |
@@ -287,13 +307,7 @@ struct BASE_EXPORT DeathDataSnapshot { |
struct DeathDataPhaseSnapshot { |
DeathDataPhaseSnapshot(int profiling_phase, |
- int count, |
- int32_t run_duration_sum, |
- int32_t run_duration_max, |
- int32_t run_duration_sample, |
- int32_t queue_duration_sum, |
- int32_t queue_duration_max, |
- int32_t queue_duration_sample, |
+ const DeathData& death_data, |
const DeathDataPhaseSnapshot* prev); |
// Profiling phase at which completion this snapshot was taken. |
@@ -326,9 +340,26 @@ class BASE_EXPORT DeathData { |
// Update stats for a task destruction (death) that had a Run() time of |
// |duration|, and has had a queueing delay of |queue_duration|. |
- void RecordDeath(const int32_t queue_duration, |
- const int32_t run_duration, |
- const uint32_t random_number); |
+ void RecordDurations(const int32_t queue_duration, |
+ const int32_t run_duration, |
+ const uint32_t random_number); |
+ |
+ // Update stats for a task destruction that performed |alloc_ops| |
+ // allocations, |free_ops| frees, allocated |allocated_bytes| bytes, freed |
+ // |freed_bytes|, where an estimated |alloc_overhead_bytes| went to heap |
+ // overhead, and where at most |max_allocated_bytes| were outstanding at any |
+ // one time. |
+ // Note that |alloc_overhead_bytes|/|alloc_ops| yields the average estimated |
+ // heap overhead of allocations in the task, and |allocated_bytes|/|alloc_ops| |
+ // yields the average size of allocation. |
+ // Note also that |allocated_bytes|-|freed_bytes| yields the net heap memory |
+ // usage of the task, which can be negative. |
+ void RecordAllocations(const uint32_t alloc_ops, |
+ const uint32_t free_ops, |
+ const uint32_t allocated_bytes, |
+ const uint32_t freed_bytes, |
+ const uint32_t alloc_overhead_bytes, |
+ const uint32_t max_allocated_bytes); |
// Metrics and past snapshots accessors, used only for serialization and in |
// tests. |
@@ -351,6 +382,22 @@ class BASE_EXPORT DeathData { |
int32_t queue_duration_sample() const { |
return base::subtle::NoBarrier_Load(&queue_duration_sample_); |
} |
+ int32_t alloc_ops() const { |
+ return base::subtle::NoBarrier_Load(&alloc_ops_); |
+ } |
+ int32_t free_ops() const { return base::subtle::NoBarrier_Load(&free_ops_); } |
+ int32_t allocated_bytes() const { |
+ return base::subtle::NoBarrier_Load(&allocated_bytes_); |
+ } |
+ int32_t freed_bytes() const { |
+ return base::subtle::NoBarrier_Load(&freed_bytes_); |
+ } |
+ int32_t alloc_overhead_bytes() const { |
+ return base::subtle::NoBarrier_Load(&alloc_overhead_bytes_); |
+ } |
+ int32_t max_allocated_bytes() const { |
+ return base::subtle::NoBarrier_Load(&max_allocated_bytes_); |
+ } |
const DeathDataPhaseSnapshot* last_phase_snapshot() const { |
return last_phase_snapshot_; |
} |
@@ -361,6 +408,12 @@ class BASE_EXPORT DeathData { |
void OnProfilingPhaseCompleted(int profiling_phase); |
private: |
+ // A saturating addition operation for member variables. This elides the |
+ // use of atomic-primitive reads for members that are only written on the |
+ // owning thread. |
+ static void SaturatingMemberAdd(const uint32_t addend, |
+ base::subtle::Atomic32* sum); |
+ |
// Members are ordered from most regularly read and updated, to least |
// frequently used. This might help a bit with cache lines. |
// Number of runs seen (divisor for calculating averages). |
@@ -383,6 +436,24 @@ class BASE_EXPORT DeathData { |
// snapshot thread. |
base::subtle::Atomic32 run_duration_max_; |
base::subtle::Atomic32 queue_duration_max_; |
+ |
+ // The cumulative number of allocation and free operations. |
+ base::subtle::Atomic32 alloc_ops_; |
+ base::subtle::Atomic32 free_ops_; |
+ |
+ // The number of bytes allocated by the task. |
+ base::subtle::Atomic32 allocated_bytes_; |
+ |
+ // The number of bytes freed by the task. |
+ base::subtle::Atomic32 freed_bytes_; |
+ |
+ // The cumulative number of overhead bytes. Where available this yields an |
+ // estimate of the heap overhead for allocations. |
+ base::subtle::Atomic32 alloc_overhead_bytes_; |
+ |
+ // The high-watermark for the number of outstanding heap allocated bytes. |
+ base::subtle::Atomic32 max_allocated_bytes_; |
+ |
// Samples, used by crowd sourcing gatherers. These are almost never read, |
// and rarely updated. They can be modified only on the death thread. |
base::subtle::Atomic32 run_duration_sample_; |
@@ -755,6 +826,13 @@ class BASE_EXPORT TaskStopwatch { |
// this thread during that period. |
int32_t RunDurationMs() const; |
+#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER) |
+ const base::debug::ThreadHeapUsageTracker& heap_usage() const { |
+ return heap_usage_; |
+ } |
+ bool heap_tracking_enabled() const { return heap_tracking_enabled_; } |
+#endif |
+ |
// Returns tracking info for the current thread. |
ThreadData* GetThreadData() const; |
@@ -762,6 +840,11 @@ class BASE_EXPORT TaskStopwatch { |
// Time when the stopwatch was started. |
TrackedTime start_time_; |
+#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER) |
+ base::debug::ThreadHeapUsageTracker heap_usage_; |
+ bool heap_tracking_enabled_; |
+#endif |
+ |
// Wallclock duration of the task. |
int32_t wallclock_duration_ms_; |