Save heap object tracking data in heap snapshot
authoryurys <yurys@chromium.org>
Tue, 24 Mar 2015 05:49:54 +0000 (22:49 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 24 Mar 2015 05:50:04 +0000 (05:50 +0000)
Every time embedder calls v8::HeapProfiler::GetHeapStats we store next unuassigned heap object id and timestamp of the request. This patch serializes all that data into heap snapshot so that embedder can restore allocation timeline.

BUG=chromium:467222
LOG=Y

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

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

src/heap-snapshot-generator.cc
src/heap-snapshot-generator.h

index 5864ad9..9290644 100644 (file)
@@ -2743,6 +2743,11 @@ void HeapSnapshotJSONSerializer::SerializeImpl() {
   if (writer_->aborted()) return;
   writer_->AddString("],\n");
 
+  writer_->AddString("\"samples\":[");
+  SerializeSamples();
+  if (writer_->aborted()) return;
+  writer_->AddString("],\n");
+
   writer_->AddString("\"strings\":[");
   SerializeStrings();
   if (writer_->aborted()) return;
@@ -2939,7 +2944,10 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
         JSON_S("function_info_index") ","
         JSON_S("count") ","
         JSON_S("size") ","
-        JSON_S("children"))));
+        JSON_S("children")) ","
+    JSON_S("sample_fields") ":" JSON_A(
+        JSON_S("timestamp_us") ","
+        JSON_S("last_assigned_id"))));
 #undef JSON_S
 #undef JSON_O
 #undef JSON_A
@@ -3028,13 +3036,10 @@ void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
   EmbeddedVector<char, kBufferSize> buffer;
   const List<AllocationTracker::FunctionInfo*>& list =
       tracker->function_info_list();
-  bool first_entry = true;
   for (int i = 0; i < list.length(); i++) {
     AllocationTracker::FunctionInfo* info = list[i];
     int buffer_pos = 0;
-    if (first_entry) {
-      first_entry = false;
-    } else {
+    if (i > 0) {
       buffer[buffer_pos++] = ',';
     }
     buffer_pos = utoa(info->function_id, buffer, buffer_pos);
@@ -3057,6 +3062,34 @@ void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
 }
 
 
+void HeapSnapshotJSONSerializer::SerializeSamples() {
+  const List<HeapObjectsMap::TimeInterval>& samples =
+      snapshot_->profiler()->heap_object_map()->samples();
+  if (samples.is_empty()) return;
+  base::TimeTicks start_time = samples[0].timestamp;
+  // The buffer needs space for 2 unsigned ints, 2 commas, \n and \0
+  const int kBufferSize = MaxDecimalDigitsIn<sizeof(
+                              base::TimeDelta().InMicroseconds())>::kUnsigned +
+                          MaxDecimalDigitsIn<sizeof(samples[0].id)>::kUnsigned +
+                          2 + 1 + 1;
+  EmbeddedVector<char, kBufferSize> buffer;
+  for (int i = 0; i < samples.length(); i++) {
+    HeapObjectsMap::TimeInterval& sample = samples[i];
+    int buffer_pos = 0;
+    if (i > 0) {
+      buffer[buffer_pos++] = ',';
+    }
+    base::TimeDelta time_delta = sample.timestamp - start_time;
+    buffer_pos = utoa(time_delta.InMicroseconds(), buffer, buffer_pos);
+    buffer[buffer_pos++] = ',';
+    buffer_pos = utoa(sample.last_assigned_id(), buffer, buffer_pos);
+    buffer[buffer_pos++] = '\n';
+    buffer[buffer_pos++] = '\0';
+    writer_->AddString(buffer.start());
+  }
+}
+
+
 void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
   writer_->AddCharacter('\n');
   writer_->AddCharacter('\"');
index 55d36ce..ef71ce6 100644 (file)
@@ -194,6 +194,16 @@ class HeapSnapshot {
 
 class HeapObjectsMap {
  public:
+  struct TimeInterval {
+    explicit TimeInterval(SnapshotObjectId id)
+        : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
+    SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
+    SnapshotObjectId id;
+    uint32_t size;
+    uint32_t count;
+    base::TimeTicks timestamp;
+  };
+
   explicit HeapObjectsMap(Heap* heap);
 
   Heap* heap() const { return heap_; }
@@ -210,6 +220,7 @@ class HeapObjectsMap {
 
   void StopHeapObjectsTracking();
   SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
+  const List<TimeInterval>& samples() const { return time_intervals_; }
   size_t GetUsedMemorySize() const;
 
   SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
@@ -236,12 +247,6 @@ class HeapObjectsMap {
     unsigned int size;
     bool accessed;
   };
-  struct TimeInterval {
-    explicit TimeInterval(SnapshotObjectId id) : id(id), size(0), count(0) { }
-    SnapshotObjectId id;
-    uint32_t size;
-    uint32_t count;
-  };
 
   SnapshotObjectId next_id_;
   HashMap entries_map_;
@@ -584,6 +589,7 @@ class HeapSnapshotJSONSerializer {
   void SerializeTraceTree();
   void SerializeTraceNode(AllocationTraceNode* node);
   void SerializeTraceNodeInfos();
+  void SerializeSamples();
   void SerializeString(const unsigned char* s);
   void SerializeStrings();