Introducing phased profiling framework.

TrackingSynchronizer can send a "phase completed" message to all processes. Their ThreadData's make a snapshot of task deaths and store it in a static map, associating with the number of the completed phase. They also clean the death data.

When requested to return a tasks snapshot, ThreadData returns that saved map, adding a snapshot of current task deaths as a separate "current" phase.

The rest of code was transformed to work with the map of snapshots instead of a single snapshot.

BUG=456354

Review URL: https://codereview.chromium.org/985773002

Cr-Commit-Position: refs/heads/master@{#323151}


CrOS-Libchrome-Original-Commit: 379d7fe794b4a200e08ac3f23c69184edef085f7
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 5359d89..32ec75c 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -390,23 +390,9 @@
 }
 
 // static
-void ThreadData::Snapshot(ProcessDataSnapshot* process_data) {
-  // Add births that have run to completion to |collected_data|.
-  // |birth_counts| tracks the total number of births recorded at each location
-  // for which we have not seen a death count.
-  BirthCountMap birth_counts;
-  ThreadData::SnapshotAllExecutedTasks(process_data, &birth_counts);
-
-  // Add births that are still active -- i.e. objects that have tallied a birth,
-  // but have not yet tallied a matching death, and hence must be either
-  // running, queued up, or being held in limbo for future posting.
-  for (BirthCountMap::const_iterator it = birth_counts.begin();
-       it != birth_counts.end(); ++it) {
-    if (it->second > 0) {
-      process_data->tasks.push_back(
-          TaskSnapshot(*it->first, DeathData(it->second), "Still_Alive"));
-    }
-  }
+void ThreadData::Snapshot(ProcessDataSnapshot* process_data_snapshot) {
+  ThreadData::SnapshotCurrentPhase(
+      &process_data_snapshot->phased_process_data_snapshots[0]);
 }
 
 Births* ThreadData::TallyABirth(const Location& location) {
@@ -578,8 +564,9 @@
 }
 
 // static
-void ThreadData::SnapshotAllExecutedTasks(ProcessDataSnapshot* process_data,
-                                          BirthCountMap* birth_counts) {
+void ThreadData::SnapshotAllExecutedTasks(
+    ProcessDataPhaseSnapshot* process_data_phase,
+    BirthCountMap* birth_counts) {
   if (!kTrackAllTaskObjects)
     return;  // Not compiled in.
 
@@ -595,12 +582,33 @@
   for (ThreadData* thread_data = my_list;
        thread_data;
        thread_data = thread_data->next()) {
-    thread_data->SnapshotExecutedTasks(process_data, birth_counts);
+    thread_data->SnapshotExecutedTasks(process_data_phase, birth_counts);
   }
 }
 
-void ThreadData::SnapshotExecutedTasks(ProcessDataSnapshot* process_data,
-                                       BirthCountMap* birth_counts) {
+// static
+void ThreadData::SnapshotCurrentPhase(
+    ProcessDataPhaseSnapshot* process_data_phase) {
+  // Add births that have run to completion to |collected_data|.
+  // |birth_counts| tracks the total number of births recorded at each location
+  // for which we have not seen a death count.
+  BirthCountMap birth_counts;
+  ThreadData::SnapshotAllExecutedTasks(process_data_phase, &birth_counts);
+
+  // Add births that are still active -- i.e. objects that have tallied a birth,
+  // but have not yet tallied a matching death, and hence must be either
+  // running, queued up, or being held in limbo for future posting.
+  for (const auto& birth_count : birth_counts) {
+    if (birth_count.second > 0) {
+      process_data_phase->tasks.push_back(TaskSnapshot(
+          *birth_count.first, DeathData(birth_count.second), "Still_Alive"));
+    }
+  }
+}
+
+void ThreadData::SnapshotExecutedTasks(
+    ProcessDataPhaseSnapshot* process_data_phase,
+    BirthCountMap* birth_counts) {
   // Get copy of data, so that the data will not change during the iterations
   // and processing.
   ThreadData::BirthMap birth_map;
@@ -608,24 +616,22 @@
   ThreadData::ParentChildSet parent_child_set;
   SnapshotMaps(&birth_map, &death_map, &parent_child_set);
 
-  for (ThreadData::DeathMap::const_iterator it = death_map.begin();
-       it != death_map.end(); ++it) {
-    process_data->tasks.push_back(
-        TaskSnapshot(*it->first, it->second, thread_name()));
-    (*birth_counts)[it->first] -= it->first->birth_count();
+  for (const auto& death : death_map) {
+    process_data_phase->tasks.push_back(
+        TaskSnapshot(*death.first, death.second, thread_name()));
+    (*birth_counts)[death.first] -= death.first->birth_count();
   }
 
-  for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
-       it != birth_map.end(); ++it) {
-    (*birth_counts)[it->second] += it->second->birth_count();
+  for (const auto& birth : birth_map) {
+    (*birth_counts)[birth.second] += birth.second->birth_count();
   }
 
   if (!kTrackParentChildLinks)
     return;
 
-  for (ThreadData::ParentChildSet::const_iterator it = parent_child_set.begin();
-       it != parent_child_set.end(); ++it) {
-    process_data->descendants.push_back(ParentChildPairSnapshot(*it));
+  for (const auto& parent_child : parent_child_set) {
+    process_data_phase->descendants.push_back(
+        ParentChildPairSnapshot(parent_child));
   }
 }
 
@@ -634,20 +640,16 @@
                               DeathMap* death_map,
                               ParentChildSet* parent_child_set) {
   base::AutoLock lock(map_lock_);
-  for (BirthMap::const_iterator it = birth_map_.begin();
-       it != birth_map_.end(); ++it)
-    (*birth_map)[it->first] = it->second;
-  for (DeathMap::iterator it = death_map_.begin();
-       it != death_map_.end(); ++it) {
-    (*death_map)[it->first] = it->second;
-  }
+  for (const auto& birth : birth_map_)
+    (*birth_map)[birth.first] = birth.second;
+  for (const auto& death : death_map_)
+    (*death_map)[death.first] = death.second;
 
   if (!kTrackParentChildLinks)
     return;
 
-  for (ParentChildSet::iterator it = parent_child_set_.begin();
-       it != parent_child_set_.end(); ++it)
-    parent_child_set->insert(*it);
+  for (const auto& parent_child : parent_child_set_)
+    parent_child_set->insert(parent_child);
 }
 
 static void OptionallyInitializeAlternateTimer() {
@@ -959,13 +961,22 @@
 }
 
 //------------------------------------------------------------------------------
-// ProcessDataSnapshot
+// ProcessDataPhaseSnapshot
+
+ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
+}
+
+ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataPhaseSnapshot
 
 ProcessDataSnapshot::ProcessDataSnapshot()
 #if !defined(OS_NACL)
     : process_id(base::GetCurrentProcId()) {
 #else
-    : process_id(0) {
+    : process_id(base::kNullProcessId) {
 #endif
 }
 
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 34c3667..9643265 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -18,6 +18,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
+#include "base/process/process_handle.h"
 #include "base/profiler/alternate_timer.h"
 #include "base/profiler/tracked_time.h"
 #include "base/synchronization/lock.h"
@@ -147,10 +148,14 @@
 // TaskSnapshot instances, so that such instances can be sorted and
 // aggregated (and remain frozen during our processing).
 //
-// The ProcessDataSnapshot struct is a serialized representation of the list
-// of ThreadData objects for a process.  It holds a set of TaskSnapshots
-// and tracks parent/child relationships for the executed tasks.  The statistics
-// in a snapshot are gathered asynhcronously relative to their ongoing updates.
+// Profiling consists of phases. The concrete phase in the sequence of phases is
+// identified by its 0-based index.
+//
+// The ProcessDataPhaseSnapshot struct is a serialized representation of the
+// list of ThreadData objects for a process for a concrete profiling phase. It
+// holds a set of TaskSnapshots and tracks parent/child relationships for the
+// executed tasks. The statistics in a snapshot are gathered asynhcronously
+// relative to their ongoing updates.
 // It is possible, though highly unlikely, that stats could be incorrectly
 // recorded by this process (all data is held in 32 bit ints, but we are not
 // atomically collecting all data, so we could have count that does not, for
@@ -342,9 +347,15 @@
 // We also have a linked list of ThreadData instances, and that list is used to
 // harvest data from all existing instances.
 
+struct ProcessDataPhaseSnapshot;
 struct ProcessDataSnapshot;
 class BASE_EXPORT TaskStopwatch;
 
+// Map from profiling phase number to the process-wide snapshotted
+// representation of the list of ThreadData objects that died during the given
+// phase.
+typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap;
+
 class BASE_EXPORT ThreadData {
  public:
   // Current allowable states of the tracking system.  The states can vary
@@ -376,8 +387,9 @@
   // This may return NULL if the system is disabled for any reason.
   static ThreadData* Get();
 
-  // Fills |process_data| with all the recursive results in our process.
-  static void Snapshot(ProcessDataSnapshot* process_data);
+  // Fills |process_data_snapshot| with phased snapshots of all profiling
+  // phases, including the current one.
+  static void Snapshot(ProcessDataSnapshot* process_data_snapshot);
 
   // Finds (or creates) a place to count births from the given location in this
   // thread, and increment that tally.
@@ -403,16 +415,14 @@
   // the task.
   // The |end_of_run| was just obtained by a call to Now() (just after the task
   // finished).
-  static void TallyRunOnWorkerThreadIfTracking(
-      const Births* birth,
-      const TrackedTime& time_posted,
-      const TaskStopwatch& stopwatch);
+  static void TallyRunOnWorkerThreadIfTracking(const Births* birth,
+                                               const TrackedTime& time_posted,
+                                               const TaskStopwatch& stopwatch);
 
   // Record the end of execution in region, generally corresponding to a scope
   // being exited.
-  static void TallyRunInAScopedRegionIfTracking(
-      const Births* birth,
-      const TaskStopwatch& stopwatch);
+  static void TallyRunInAScopedRegionIfTracking(const Births* birth,
+                                                const TaskStopwatch& stopwatch);
 
   const std::string& thread_name() const { return thread_name_; }
 
@@ -514,16 +524,21 @@
   // Snapshot (under a lock) the profiled data for the tasks in each ThreadData
   // instance.  Also updates the |birth_counts| tally for each task to keep
   // track of the number of living instances of the task.
-  static void SnapshotAllExecutedTasks(ProcessDataSnapshot* process_data,
-                                       BirthCountMap* birth_counts);
+  static void SnapshotAllExecutedTasks(
+      ProcessDataPhaseSnapshot* process_data_phase,
+      BirthCountMap* birth_counts);
+
+  // Fills |process_data_phase| with all the recursive results in our process.
+  static void SnapshotCurrentPhase(
+      ProcessDataPhaseSnapshot* process_data_phase);
 
   // Snapshots (under a lock) the profiled data for the tasks for this thread
   // and writes all of the executed tasks' data -- i.e. the data for the tasks
-  // with with entries in the death_map_ -- into |process_data|.  Also updates
-  // the |birth_counts| tally for each task to keep track of the number of
-  // living instances of the task -- that is, each task maps to the number of
+  // with with entries in the death_map_ -- into |process_data_phase|.  Also
+  // updates the |birth_counts| tally for each task to keep track of the number
+  // of living instances of the task -- that is, each task maps to the number of
   // births for the task that have not yet been balanced by a death.
-  void SnapshotExecutedTasks(ProcessDataSnapshot* process_data,
+  void SnapshotExecutedTasks(ProcessDataPhaseSnapshot* process_data_phase,
                              BirthCountMap* birth_counts);
 
   // Using our lock, make a copy of the specified maps.  This call may be made
@@ -747,16 +762,29 @@
 };
 
 //------------------------------------------------------------------------------
-// A snapshotted representation of the list of ThreadData objects for a process.
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for a single profiling phase.
+
+struct BASE_EXPORT ProcessDataPhaseSnapshot {
+ public:
+  ProcessDataPhaseSnapshot();
+  ~ProcessDataPhaseSnapshot();
+
+  std::vector<TaskSnapshot> tasks;
+  std::vector<ParentChildPairSnapshot> descendants;
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for all profiling phases, including the current one.
 
 struct BASE_EXPORT ProcessDataSnapshot {
  public:
   ProcessDataSnapshot();
   ~ProcessDataSnapshot();
 
-  std::vector<TaskSnapshot> tasks;
-  std::vector<ParentChildPairSnapshot> descendants;
-  int process_id;
+  PhasedProcessDataSnapshotMap phased_process_data_snapshots;
+  base::ProcessId process_id;
 };
 
 }  // namespace tracked_objects
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
index 7713091..5455fef 100644
--- a/base/tracked_objects_unittest.cc
+++ b/base/tracked_objects_unittest.cc
@@ -71,28 +71,37 @@
                                int count,
                                int run_ms,
                                int queue_ms) {
-    ASSERT_EQ(1u, process_data.tasks.size());
+    ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+    auto it = process_data.phased_process_data_snapshots.find(0);
+    ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+    const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
-    EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
+    ASSERT_EQ(1u, process_data_phase.tasks.size());
+
+    EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
     EXPECT_EQ(function_name,
-              process_data.tasks[0].birth.location.function_name);
-    EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
+              process_data_phase.tasks[0].birth.location.function_name);
+    EXPECT_EQ(kLineNumber,
+              process_data_phase.tasks[0].birth.location.line_number);
 
-    EXPECT_EQ(birth_thread, process_data.tasks[0].birth.thread_name);
+    EXPECT_EQ(birth_thread, process_data_phase.tasks[0].birth.thread_name);
 
-    EXPECT_EQ(count, process_data.tasks[0].death_data.count);
+    EXPECT_EQ(count, process_data_phase.tasks[0].death_data.count);
     EXPECT_EQ(count * run_ms,
-              process_data.tasks[0].death_data.run_duration_sum);
-    EXPECT_EQ(run_ms, process_data.tasks[0].death_data.run_duration_max);
-    EXPECT_EQ(run_ms, process_data.tasks[0].death_data.run_duration_sample);
+              process_data_phase.tasks[0].death_data.run_duration_sum);
+    EXPECT_EQ(run_ms, process_data_phase.tasks[0].death_data.run_duration_max);
+    EXPECT_EQ(run_ms,
+              process_data_phase.tasks[0].death_data.run_duration_sample);
     EXPECT_EQ(count * queue_ms,
-              process_data.tasks[0].death_data.queue_duration_sum);
-    EXPECT_EQ(queue_ms, process_data.tasks[0].death_data.queue_duration_max);
-    EXPECT_EQ(queue_ms, process_data.tasks[0].death_data.queue_duration_sample);
+              process_data_phase.tasks[0].death_data.queue_duration_sum);
+    EXPECT_EQ(queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_max);
+    EXPECT_EQ(queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_sample);
 
-    EXPECT_EQ(death_thread, process_data.tasks[0].death_thread_name);
+    EXPECT_EQ(death_thread, process_data_phase.tasks[0].death_thread_name);
 
-    EXPECT_EQ(0u, process_data.descendants.size());
+    EXPECT_EQ(0u, process_data_phase.descendants.size());
 
     EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
   }
@@ -230,37 +239,49 @@
   ProcessDataSnapshot process_data;
   ThreadData::Snapshot(&process_data);
 
-  ASSERT_EQ(1u, process_data.tasks.size());
-  EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
-  EXPECT_EQ(kFunction, process_data.tasks[0].birth.location.function_name);
-  EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
-  EXPECT_EQ(kWorkerThreadName, process_data.tasks[0].birth.thread_name);
-  EXPECT_EQ(1, process_data.tasks[0].death_data.count);
-  EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_sum);
-  EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_max);
-  EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_sample);
-  EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_sum);
-  EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_max);
-  EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_sample);
-  EXPECT_EQ(kWorkerThreadName, process_data.tasks[0].death_thread_name);
+  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+  auto it = process_data.phased_process_data_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+  ASSERT_EQ(1u, process_data_phase.tasks.size());
+  EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].death_thread_name);
 
   if (ThreadData::TrackingParentChildStatus()) {
-    ASSERT_EQ(1u, process_data.descendants.size());
-    EXPECT_EQ(kFile, process_data.descendants[0].parent.location.file_name);
+    ASSERT_EQ(1u, process_data_phase.descendants.size());
+    EXPECT_EQ(kFile,
+              process_data_phase.descendants[0].parent.location.file_name);
     EXPECT_EQ(kFunction,
-              process_data.descendants[0].parent.location.function_name);
+              process_data_phase.descendants[0].parent.location.function_name);
     EXPECT_EQ(kLineNumber,
-              process_data.descendants[0].parent.location.line_number);
+              process_data_phase.descendants[0].parent.location.line_number);
     EXPECT_EQ(kWorkerThreadName,
-              process_data.descendants[0].parent.thread_name);
-    EXPECT_EQ(kFile, process_data.descendants[0].child.location.file_name);
+              process_data_phase.descendants[0].parent.thread_name);
+    EXPECT_EQ(kFile,
+              process_data_phase.descendants[0].child.location.file_name);
     EXPECT_EQ(kFunction,
-              process_data.descendants[0].child.location.function_name);
+              process_data_phase.descendants[0].child.location.function_name);
     EXPECT_EQ(kLineNumber,
-              process_data.descendants[0].child.location.line_number);
-    EXPECT_EQ(kWorkerThreadName, process_data.descendants[0].child.thread_name);
+              process_data_phase.descendants[0].child.location.line_number);
+    EXPECT_EQ(kWorkerThreadName,
+              process_data_phase.descendants[0].child.thread_name);
   } else {
-    EXPECT_EQ(0u, process_data.descendants.size());
+    EXPECT_EQ(0u, process_data_phase.descendants.size());
   }
 }
 
@@ -318,8 +339,14 @@
 
   ProcessDataSnapshot process_data;
   ThreadData::Snapshot(&process_data);
-  EXPECT_EQ(0u, process_data.tasks.size());
-  EXPECT_EQ(0u, process_data.descendants.size());
+
+  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+  auto it = process_data.phased_process_data_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  EXPECT_EQ(0u, process_data_phase.tasks.size());
+  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
@@ -335,8 +362,14 @@
 
   ProcessDataSnapshot process_data;
   ThreadData::Snapshot(&process_data);
-  EXPECT_EQ(0u, process_data.tasks.size());
-  EXPECT_EQ(0u, process_data.descendants.size());
+
+  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+  auto it = process_data.phased_process_data_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  EXPECT_EQ(0u, process_data_phase.tasks.size());
+  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
@@ -425,8 +458,8 @@
   pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
 
   // Turn off tracking now that we have births.
-  EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
-      ThreadData::DEACTIVATED));
+  EXPECT_TRUE(
+      ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED));
 
   const unsigned int kStartOfRun = 5;
   const unsigned int kEndOfRun = 7;
@@ -474,8 +507,14 @@
 
   ProcessDataSnapshot process_data;
   ThreadData::Snapshot(&process_data);
-  EXPECT_EQ(0u, process_data.tasks.size());
-  EXPECT_EQ(0u, process_data.descendants.size());
+
+  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+  auto it = process_data.phased_process_data_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  EXPECT_EQ(0u, process_data_phase.tasks.size());
+  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
@@ -558,34 +597,43 @@
 
   ProcessDataSnapshot process_data;
   ThreadData::Snapshot(&process_data);
-  ASSERT_EQ(2u, process_data.tasks.size());
 
-  EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
-  EXPECT_EQ(kFunction, process_data.tasks[0].birth.location.function_name);
-  EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[0].birth.thread_name);
-  EXPECT_EQ(1, process_data.tasks[0].death_data.count);
-  EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_sum);
-  EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_max);
-  EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_sample);
-  EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_sum);
-  EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_max);
-  EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_sample);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[0].death_thread_name);
-  EXPECT_EQ(kFile, process_data.tasks[1].birth.location.file_name);
-  EXPECT_EQ(kFunction, process_data.tasks[1].birth.location.function_name);
+  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+  auto it = process_data.phased_process_data_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(2u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].death_thread_name);
+  EXPECT_EQ(kFile, process_data_phase.tasks[1].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[1].birth.location.function_name);
   EXPECT_EQ(kSecondFakeLineNumber,
-            process_data.tasks[1].birth.location.line_number);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[1].birth.thread_name);
-  EXPECT_EQ(1, process_data.tasks[1].death_data.count);
-  EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_sum);
-  EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_max);
-  EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_sample);
-  EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_sum);
-  EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_max);
-  EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_sample);
-  EXPECT_EQ(kStillAlive, process_data.tasks[1].death_thread_name);
-  EXPECT_EQ(0u, process_data.descendants.size());
+            process_data_phase.tasks[1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[1].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[1].death_data.count);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sample);
+  EXPECT_EQ(kStillAlive, process_data_phase.tasks[1].death_thread_name);
+  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
@@ -719,38 +767,48 @@
   ProcessDataSnapshot process_data;
   ThreadData::Snapshot(&process_data);
 
+  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
+  auto it = process_data.phased_process_data_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
   // The order in which the two task follow is platform-dependent.
-  int t0 = (process_data.tasks[0].birth.location.line_number == kLineNumber) ?
-      0 : 1;
+  int t0 =
+      (process_data_phase.tasks[0].birth.location.line_number == kLineNumber)
+          ? 0
+          : 1;
   int t1 = 1 - t0;
 
-  ASSERT_EQ(2u, process_data.tasks.size());
-  EXPECT_EQ(kFile, process_data.tasks[t0].birth.location.file_name);
-  EXPECT_EQ(kFunction, process_data.tasks[t0].birth.location.function_name);
-  EXPECT_EQ(kLineNumber, process_data.tasks[t0].birth.location.line_number);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[t0].birth.thread_name);
-  EXPECT_EQ(1, process_data.tasks[t0].death_data.count);
-  EXPECT_EQ(6, process_data.tasks[t0].death_data.run_duration_sum);
-  EXPECT_EQ(6, process_data.tasks[t0].death_data.run_duration_max);
-  EXPECT_EQ(6, process_data.tasks[t0].death_data.run_duration_sample);
-  EXPECT_EQ(4, process_data.tasks[t0].death_data.queue_duration_sum);
-  EXPECT_EQ(4, process_data.tasks[t0].death_data.queue_duration_max);
-  EXPECT_EQ(4, process_data.tasks[t0].death_data.queue_duration_sample);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[t0].death_thread_name);
-  EXPECT_EQ(kFile, process_data.tasks[t1].birth.location.file_name);
-  EXPECT_EQ(kFunction, process_data.tasks[t1].birth.location.function_name);
+  ASSERT_EQ(2u, process_data_phase.tasks.size());
+  EXPECT_EQ(kFile, process_data_phase.tasks[t0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[t0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[t0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[t0].death_data.count);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sum);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_max);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].death_thread_name);
+  EXPECT_EQ(kFile, process_data_phase.tasks[t1].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[t1].birth.location.function_name);
   EXPECT_EQ(kSecondFakeLineNumber,
-            process_data.tasks[t1].birth.location.line_number);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[t1].birth.thread_name);
-  EXPECT_EQ(1, process_data.tasks[t1].death_data.count);
-  EXPECT_EQ(2, process_data.tasks[t1].death_data.run_duration_sum);
-  EXPECT_EQ(2, process_data.tasks[t1].death_data.run_duration_max);
-  EXPECT_EQ(2, process_data.tasks[t1].death_data.run_duration_sample);
-  EXPECT_EQ(1, process_data.tasks[t1].death_data.queue_duration_sum);
-  EXPECT_EQ(1, process_data.tasks[t1].death_data.queue_duration_max);
-  EXPECT_EQ(1, process_data.tasks[t1].death_data.queue_duration_sample);
-  EXPECT_EQ(kMainThreadName, process_data.tasks[t1].death_thread_name);
-  EXPECT_EQ(0u, process_data.descendants.size());
+            process_data_phase.tasks[t1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.count);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sample);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sum);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_max);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].death_thread_name);
+  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }