Revision f230a1cf deps/v8/src/heap-snapshot-generator.cc

View differences:

deps/v8/src/heap-snapshot-generator.cc
29 29

  
30 30
#include "heap-snapshot-generator-inl.h"
31 31

  
32
#include "allocation-tracker.h"
32 33
#include "heap-profiler.h"
33 34
#include "debug.h"
34 35
#include "types.h"
......
397 398
}
398 399

  
399 400

  
400
void HeapObjectsMap::MoveObject(Address from, Address to) {
401
void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
401 402
  ASSERT(to != NULL);
402 403
  ASSERT(from != NULL);
403 404
  if (from == to) return;
......
428 429
    int from_entry_info_index =
429 430
        static_cast<int>(reinterpret_cast<intptr_t>(from_value));
430 431
    entries_.at(from_entry_info_index).addr = to;
432
    // Size of an object can change during its life, so to keep information
433
    // about the object in entries_ consistent, we have to adjust size when the
434
    // object is migrated.
435
    if (FLAG_heap_profiler_trace_objects) {
436
      PrintF("Move object from %p to %p old size %6d new size %6d\n",
437
             from,
438
             to,
439
             entries_.at(from_entry_info_index).size,
440
             object_size);
441
    }
442
    entries_.at(from_entry_info_index).size = object_size;
431 443
    to_entry->value = from_value;
432 444
  }
433 445
}
434 446

  
435 447

  
448
void HeapObjectsMap::NewObject(Address addr, int size) {
449
  if (FLAG_heap_profiler_trace_objects) {
450
    PrintF("New object         : %p %6d. Next address is %p\n",
451
           addr,
452
           size,
453
           addr + size);
454
  }
455
  ASSERT(addr != NULL);
456
  FindOrAddEntry(addr, size, false);
457
}
458

  
459

  
460
void HeapObjectsMap::UpdateObjectSize(Address addr, int size) {
461
  FindOrAddEntry(addr, size, false);
462
}
463

  
464

  
436 465
SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
437 466
  HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr),
438 467
                                              false);
......
445 474

  
446 475

  
447 476
SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
448
                                                unsigned int size) {
477
                                                unsigned int size,
478
                                                bool accessed) {
449 479
  ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
450 480
  HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr),
451 481
                                              true);
......
453 483
    int entry_index =
454 484
        static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
455 485
    EntryInfo& entry_info = entries_.at(entry_index);
456
    entry_info.accessed = true;
486
    entry_info.accessed = accessed;
487
    if (FLAG_heap_profiler_trace_objects) {
488
      PrintF("Update object size : %p with old size %d and new size %d\n",
489
             addr,
490
             entry_info.size,
491
             size);
492
    }
457 493
    entry_info.size = size;
458 494
    return entry_info.id;
459 495
  }
460 496
  entry->value = reinterpret_cast<void*>(entries_.length());
461 497
  SnapshotObjectId id = next_id_;
462 498
  next_id_ += kObjectIdStep;
463
  entries_.Add(EntryInfo(id, addr, size));
499
  entries_.Add(EntryInfo(id, addr, size, accessed));
464 500
  ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
465 501
  return id;
466 502
}
......
472 508

  
473 509

  
474 510
void HeapObjectsMap::UpdateHeapObjectsMap() {
511
  if (FLAG_heap_profiler_trace_objects) {
512
    PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
513
           entries_map_.occupancy());
514
  }
475 515
  heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask,
476 516
                          "HeapSnapshotsCollection::UpdateHeapObjectsMap");
477 517
  HeapIterator iterator(heap_);
......
479 519
       obj != NULL;
480 520
       obj = iterator.next()) {
481 521
    FindOrAddEntry(obj->address(), obj->Size());
522
    if (FLAG_heap_profiler_trace_objects) {
523
      PrintF("Update object      : %p %6d. Next address is %p\n",
524
             obj->address(),
525
             obj->Size(),
526
             obj->address() + obj->Size());
527
    }
482 528
  }
483 529
  RemoveDeadEntries();
530
  if (FLAG_heap_profiler_trace_objects) {
531
    PrintF("End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
532
           entries_map_.occupancy());
533
  }
534
}
535

  
536

  
537
namespace {
538

  
539

  
540
struct HeapObjectInfo {
541
  HeapObjectInfo(HeapObject* obj, int expected_size)
542
    : obj(obj),
543
      expected_size(expected_size) {
544
  }
545

  
546
  HeapObject* obj;
547
  int expected_size;
548

  
549
  bool IsValid() const { return expected_size == obj->Size(); }
550

  
551
  void Print() const {
552
    if (expected_size == 0) {
553
      PrintF("Untracked object   : %p %6d. Next address is %p\n",
554
             obj->address(),
555
             obj->Size(),
556
             obj->address() + obj->Size());
557
    } else if (obj->Size() != expected_size) {
558
      PrintF("Wrong size %6d: %p %6d. Next address is %p\n",
559
             expected_size,
560
             obj->address(),
561
             obj->Size(),
562
             obj->address() + obj->Size());
563
    } else {
564
      PrintF("Good object      : %p %6d. Next address is %p\n",
565
             obj->address(),
566
             expected_size,
567
             obj->address() + obj->Size());
568
    }
569
  }
570
};
571

  
572

  
573
static int comparator(const HeapObjectInfo* a, const HeapObjectInfo* b) {
574
  if (a->obj < b->obj) return -1;
575
  if (a->obj > b->obj) return 1;
576
  return 0;
577
}
578

  
579

  
580
}  // namespace
581

  
582

  
583
int HeapObjectsMap::FindUntrackedObjects() {
584
  List<HeapObjectInfo> heap_objects(1000);
585

  
586
  HeapIterator iterator(heap_);
587
  int untracked = 0;
588
  for (HeapObject* obj = iterator.next();
589
       obj != NULL;
590
       obj = iterator.next()) {
591
    HashMap::Entry* entry = entries_map_.Lookup(
592
      obj->address(), ComputePointerHash(obj->address()), false);
593
    if (entry == NULL) {
594
      ++untracked;
595
      if (FLAG_heap_profiler_trace_objects) {
596
        heap_objects.Add(HeapObjectInfo(obj, 0));
597
      }
598
    } else {
599
      int entry_index = static_cast<int>(
600
          reinterpret_cast<intptr_t>(entry->value));
601
      EntryInfo& entry_info = entries_.at(entry_index);
602
      if (FLAG_heap_profiler_trace_objects) {
603
        heap_objects.Add(HeapObjectInfo(obj,
604
                         static_cast<int>(entry_info.size)));
605
        if (obj->Size() != static_cast<int>(entry_info.size))
606
          ++untracked;
607
      } else {
608
        CHECK_EQ(obj->Size(), static_cast<int>(entry_info.size));
609
      }
610
    }
611
  }
612
  if (FLAG_heap_profiler_trace_objects) {
613
    PrintF("\nBegin HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n",
614
           entries_map_.occupancy());
615
    heap_objects.Sort(comparator);
616
    int last_printed_object = -1;
617
    bool print_next_object = false;
618
    for (int i = 0; i < heap_objects.length(); ++i) {
619
      const HeapObjectInfo& object_info = heap_objects[i];
620
      if (!object_info.IsValid()) {
621
        ++untracked;
622
        if (last_printed_object != i - 1) {
623
          if (i > 0) {
624
            PrintF("%d objects were skipped\n", i - 1 - last_printed_object);
625
            heap_objects[i - 1].Print();
626
          }
627
        }
628
        object_info.Print();
629
        last_printed_object = i;
630
        print_next_object = true;
631
      } else if (print_next_object) {
632
        object_info.Print();
633
        print_next_object = false;
634
        last_printed_object = i;
635
      }
636
    }
637
    if (last_printed_object < heap_objects.length() - 1) {
638
      PrintF("Last %d objects were skipped\n",
639
             heap_objects.length() - 1 - last_printed_object);
640
    }
641
    PrintF("End HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n\n",
642
           entries_map_.occupancy());
643
  }
644
  return untracked;
484 645
}
485 646

  
486 647

  
......
587 748
HeapSnapshotsCollection::HeapSnapshotsCollection(Heap* heap)
588 749
    : is_tracking_objects_(false),
589 750
      names_(heap),
590
      ids_(heap) {
751
      ids_(heap),
752
      allocation_tracker_(NULL) {
591 753
}
592 754

  
593 755

  
......
597 759

  
598 760

  
599 761
HeapSnapshotsCollection::~HeapSnapshotsCollection() {
762
  delete allocation_tracker_;
600 763
  snapshots_.Iterate(DeleteHeapSnapshot);
601 764
}
602 765

  
603 766

  
767
void HeapSnapshotsCollection::StartHeapObjectsTracking() {
768
  ids_.UpdateHeapObjectsMap();
769
  if (allocation_tracker_ == NULL) {
770
    allocation_tracker_ = new AllocationTracker(&ids_, names());
771
  }
772
  is_tracking_objects_ = true;
773
}
774

  
775

  
776
void HeapSnapshotsCollection::StopHeapObjectsTracking() {
777
  ids_.StopHeapObjectsTracking();
778
  if (allocation_tracker_ != NULL) {
779
    delete allocation_tracker_;
780
    allocation_tracker_ = NULL;
781
  }
782
}
783

  
784

  
604 785
HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name,
605 786
                                                   unsigned uid) {
606 787
  is_tracking_objects_ = true;  // Start watching for heap objects moves.
......
644 825
}
645 826

  
646 827

  
828
void HeapSnapshotsCollection::NewObjectEvent(Address addr, int size) {
829
  DisallowHeapAllocation no_allocation;
830
  ids_.NewObject(addr, size);
831
  if (allocation_tracker_ != NULL) {
832
    allocation_tracker_->NewObjectEvent(addr, size);
833
  }
834
}
835

  
836

  
647 837
size_t HeapSnapshotsCollection::GetUsedMemorySize() const {
648 838
  size_t size = sizeof(*this);
649 839
  size += names_.GetUsedMemorySize();
......
1301 1491
                                                     AllocationSite* site) {
1302 1492
  SetInternalReference(site, entry, "transition_info", site->transition_info(),
1303 1493
                       AllocationSite::kTransitionInfoOffset);
1494
  SetInternalReference(site, entry, "nested_site", site->nested_site(),
1495
                       AllocationSite::kNestedSiteOffset);
1496
  SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
1497
                       AllocationSite::kDependentCodeOffset);
1304 1498
}
1305 1499

  
1306 1500

  
......
2438 2632
const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5;
2439 2633

  
2440 2634
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
2635
  if (AllocationTracker* allocation_tracker =
2636
      snapshot_->collection()->allocation_tracker()) {
2637
    allocation_tracker->PrepareForSerialization();
2638
  }
2441 2639
  ASSERT(writer_ == NULL);
2442 2640
  writer_ = new OutputStreamWriter(stream);
2443 2641
  SerializeImpl();
......
2461 2659
  SerializeEdges();
2462 2660
  if (writer_->aborted()) return;
2463 2661
  writer_->AddString("],\n");
2662

  
2663
  writer_->AddString("\"trace_function_infos\":[");
2664
  SerializeTraceNodeInfos();
2665
  if (writer_->aborted()) return;
2666
  writer_->AddString("],\n");
2667
  writer_->AddString("\"trace_tree\":[");
2668
  SerializeTraceTree();
2669
  if (writer_->aborted()) return;
2670
  writer_->AddString("],\n");
2671

  
2464 2672
  writer_->AddString("\"strings\":[");
2465 2673
  SerializeStrings();
2466 2674
  if (writer_->aborted()) return;
......
2472 2680

  
2473 2681
int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
2474 2682
  HashMap::Entry* cache_entry = strings_.Lookup(
2475
      const_cast<char*>(s), ObjectHash(s), true);
2683
      const_cast<char*>(s), StringHash(s), true);
2476 2684
  if (cache_entry->value == NULL) {
2477 2685
    cache_entry->value = reinterpret_cast<void*>(next_string_id_++);
2478 2686
  }
......
2621 2829
            JSON_S("shortcut") ","
2622 2830
            JSON_S("weak")) ","
2623 2831
        JSON_S("string_or_number") ","
2624
        JSON_S("node"))));
2832
        JSON_S("node")) ","
2833
    JSON_S("trace_function_info_fields") ":" JSON_A(
2834
        JSON_S("function_id") ","
2835
        JSON_S("name") ","
2836
        JSON_S("script_name") ","
2837
        JSON_S("script_id") ","
2838
        JSON_S("line") ","
2839
        JSON_S("column")) ","
2840
    JSON_S("trace_node_fields") ":" JSON_A(
2841
        JSON_S("id") ","
2842
        JSON_S("function_id") ","
2843
        JSON_S("count") ","
2844
        JSON_S("size") ","
2845
        JSON_S("children"))));
2625 2846
#undef JSON_S
2626 2847
#undef JSON_O
2627 2848
#undef JSON_A
......
2629 2850
  writer_->AddNumber(snapshot_->entries().length());
2630 2851
  writer_->AddString(",\"edge_count\":");
2631 2852
  writer_->AddNumber(snapshot_->edges().length());
2853
  writer_->AddString(",\"trace_function_count\":");
2854
  uint32_t count = 0;
2855
  AllocationTracker* tracker = snapshot_->collection()->allocation_tracker();
2856
  if (tracker) {
2857
    count = tracker->id_to_function_info()->occupancy();
2858
  }
2859
  writer_->AddNumber(count);
2632 2860
}
2633 2861

  
2634 2862

  
......
2642 2870
}
2643 2871

  
2644 2872

  
2873
void HeapSnapshotJSONSerializer::SerializeTraceTree() {
2874
  AllocationTracker* tracker = snapshot_->collection()->allocation_tracker();
2875
  if (!tracker) return;
2876
  AllocationTraceTree* traces = tracker->trace_tree();
2877
  SerializeTraceNode(traces->root());
2878
}
2879

  
2880

  
2881
void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) {
2882
  // The buffer needs space for 4 unsigned ints, 4 commas, [ and \0
2883
  const int kBufferSize =
2884
      4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
2885
      + 4 + 1 + 1;
2886
  EmbeddedVector<char, kBufferSize> buffer;
2887
  int buffer_pos = 0;
2888
  buffer_pos = utoa(node->id(), buffer, buffer_pos);
2889
  buffer[buffer_pos++] = ',';
2890
  buffer_pos = utoa(node->function_id(), buffer, buffer_pos);
2891
  buffer[buffer_pos++] = ',';
2892
  buffer_pos = utoa(node->allocation_count(), buffer, buffer_pos);
2893
  buffer[buffer_pos++] = ',';
2894
  buffer_pos = utoa(node->allocation_size(), buffer, buffer_pos);
2895
  buffer[buffer_pos++] = ',';
2896
  buffer[buffer_pos++] = '[';
2897
  buffer[buffer_pos++] = '\0';
2898
  writer_->AddString(buffer.start());
2899

  
2900
  Vector<AllocationTraceNode*> children = node->children();
2901
  for (int i = 0; i < children.length(); i++) {
2902
    if (i > 0) {
2903
      writer_->AddCharacter(',');
2904
    }
2905
    SerializeTraceNode(children[i]);
2906
  }
2907
  writer_->AddCharacter(']');
2908
}
2909

  
2910

  
2911
// 0-based position is converted to 1-based during the serialization.
2912
static int SerializePosition(int position, const Vector<char>& buffer,
2913
                             int buffer_pos) {
2914
  if (position == -1) {
2915
    buffer[buffer_pos++] = '0';
2916
  } else {
2917
    ASSERT(position >= 0);
2918
    buffer_pos = utoa(static_cast<unsigned>(position + 1), buffer, buffer_pos);
2919
  }
2920
  return buffer_pos;
2921
}
2922

  
2923

  
2924
void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
2925
  AllocationTracker* tracker = snapshot_->collection()->allocation_tracker();
2926
  if (!tracker) return;
2927
  // The buffer needs space for 6 unsigned ints, 6 commas, \n and \0
2928
  const int kBufferSize =
2929
      6 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
2930
      + 6 + 1 + 1;
2931
  EmbeddedVector<char, kBufferSize> buffer;
2932
  HashMap* id_to_function_info = tracker->id_to_function_info();
2933
  bool first_entry = true;
2934
  for (HashMap::Entry* p = id_to_function_info->Start();
2935
       p != NULL;
2936
       p = id_to_function_info->Next(p)) {
2937
    SnapshotObjectId id =
2938
        static_cast<SnapshotObjectId>(reinterpret_cast<intptr_t>(p->key));
2939
    AllocationTracker::FunctionInfo* info =
2940
        reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
2941
    int buffer_pos = 0;
2942
    if (first_entry) {
2943
      first_entry = false;
2944
    } else {
2945
      buffer[buffer_pos++] = ',';
2946
    }
2947
    buffer_pos = utoa(id, buffer, buffer_pos);
2948
    buffer[buffer_pos++] = ',';
2949
    buffer_pos = utoa(GetStringId(info->name), buffer, buffer_pos);
2950
    buffer[buffer_pos++] = ',';
2951
    buffer_pos = utoa(GetStringId(info->script_name), buffer, buffer_pos);
2952
    buffer[buffer_pos++] = ',';
2953
    // The cast is safe because script id is a non-negative Smi.
2954
    buffer_pos = utoa(static_cast<unsigned>(info->script_id), buffer,
2955
        buffer_pos);
2956
    buffer[buffer_pos++] = ',';
2957
    buffer_pos = SerializePosition(info->line, buffer, buffer_pos);
2958
    buffer[buffer_pos++] = ',';
2959
    buffer_pos = SerializePosition(info->column, buffer, buffer_pos);
2960
    buffer[buffer_pos++] = '\n';
2961
    buffer[buffer_pos++] = '\0';
2962
    writer_->AddString(buffer.start());
2963
  }
2964
}
2965

  
2966

  
2645 2967
void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
2646 2968
  writer_->AddCharacter('\n');
2647 2969
  writer_->AddCharacter('\"');
......
2693 3015

  
2694 3016

  
2695 3017
void HeapSnapshotJSONSerializer::SerializeStrings() {
2696
  List<HashMap::Entry*> sorted_strings;
2697
  SortHashMap(&strings_, &sorted_strings);
3018
  ScopedVector<const unsigned char*> sorted_strings(
3019
      strings_.occupancy() + 1);
3020
  for (HashMap::Entry* entry = strings_.Start();
3021
       entry != NULL;
3022
       entry = strings_.Next(entry)) {
3023
    int index = static_cast<int>(reinterpret_cast<uintptr_t>(entry->value));
3024
    sorted_strings[index] = reinterpret_cast<const unsigned char*>(entry->key);
3025
  }
2698 3026
  writer_->AddString("\"<dummy>\"");
2699
  for (int i = 0; i < sorted_strings.length(); ++i) {
3027
  for (int i = 1; i < sorted_strings.length(); ++i) {
2700 3028
    writer_->AddCharacter(',');
2701
    SerializeString(
2702
        reinterpret_cast<const unsigned char*>(sorted_strings[i]->key));
3029
    SerializeString(sorted_strings[i]);
2703 3030
    if (writer_->aborted()) return;
2704 3031
  }
2705 3032
}
2706 3033

  
2707 3034

  
2708
template<typename T>
2709
inline static int SortUsingEntryValue(const T* x, const T* y) {
2710
  uintptr_t x_uint = reinterpret_cast<uintptr_t>((*x)->value);
2711
  uintptr_t y_uint = reinterpret_cast<uintptr_t>((*y)->value);
2712
  if (x_uint > y_uint) {
2713
    return 1;
2714
  } else if (x_uint == y_uint) {
2715
    return 0;
2716
  } else {
2717
    return -1;
2718
  }
2719
}
2720

  
2721

  
2722
void HeapSnapshotJSONSerializer::SortHashMap(
2723
    HashMap* map, List<HashMap::Entry*>* sorted_entries) {
2724
  for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p))
2725
    sorted_entries->Add(p);
2726
  sorted_entries->Sort(SortUsingEntryValue);
2727
}
2728

  
2729 3035
} }  // namespace v8::internal

Also available in: Unified diff