| OLD | NEW | 
|---|
| 1 // Copyright 2009-2010 the V8 project authors. All rights reserved. | 1 // Copyright 2009-2010 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 //     * Redistributions of source code must retain the above copyright | 6 //     * Redistributions of source code must retain the above copyright | 
| 7 //       notice, this list of conditions and the following disclaimer. | 7 //       notice, this list of conditions and the following disclaimer. | 
| 8 //     * Redistributions in binary form must reproduce the above | 8 //     * Redistributions in binary form must reproduce the above | 
| 9 //       copyright notice, this list of conditions and the following | 9 //       copyright notice, this list of conditions and the following | 
| 10 //       disclaimer in the documentation and/or other materials provided | 10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 27 | 27 | 
| 28 #ifndef V8_HEAP_PROFILER_H_ | 28 #ifndef V8_HEAP_PROFILER_H_ | 
| 29 #define V8_HEAP_PROFILER_H_ | 29 #define V8_HEAP_PROFILER_H_ | 
| 30 | 30 | 
| 31 #include "allocation.h" |  | 
| 32 #include "isolate.h" | 31 #include "isolate.h" | 
| 33 #include "zone-inl.h" |  | 
| 34 | 32 | 
| 35 namespace v8 { | 33 namespace v8 { | 
| 36 namespace internal { | 34 namespace internal { | 
| 37 | 35 | 
| 38 #ifdef ENABLE_LOGGING_AND_PROFILING | 36 #ifdef ENABLE_LOGGING_AND_PROFILING | 
| 39 | 37 | 
| 40 class HeapSnapshot; | 38 class HeapSnapshot; | 
| 41 class HeapSnapshotsCollection; | 39 class HeapSnapshotsCollection; | 
| 42 | 40 | 
| 43 #define HEAP_PROFILE(heap, call)                                             \ | 41 #define HEAP_PROFILE(heap, call)                                             \ | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 74 | 72 | 
| 75   void DefineWrapperClass( | 73   void DefineWrapperClass( | 
| 76       uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback); | 74       uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback); | 
| 77 | 75 | 
| 78   v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id, | 76   v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id, | 
| 79                                                       Object** wrapper); | 77                                                       Object** wrapper); | 
| 80   INLINE(bool is_profiling()) { | 78   INLINE(bool is_profiling()) { | 
| 81     return snapshots_->is_tracking_objects(); | 79     return snapshots_->is_tracking_objects(); | 
| 82   } | 80   } | 
| 83 | 81 | 
| 84   // Obsolete interface. |  | 
| 85   // Write a single heap sample to the log file. |  | 
| 86   static void WriteSample(); |  | 
| 87 |  | 
| 88  private: | 82  private: | 
| 89   HeapProfiler(); | 83   HeapProfiler(); | 
| 90   ~HeapProfiler(); | 84   ~HeapProfiler(); | 
| 91   HeapSnapshot* TakeSnapshotImpl(const char* name, | 85   HeapSnapshot* TakeSnapshotImpl(const char* name, | 
| 92                                  int type, | 86                                  int type, | 
| 93                                  v8::ActivityControl* control); | 87                                  v8::ActivityControl* control); | 
| 94   HeapSnapshot* TakeSnapshotImpl(String* name, | 88   HeapSnapshot* TakeSnapshotImpl(String* name, | 
| 95                                  int type, | 89                                  int type, | 
| 96                                  v8::ActivityControl* control); | 90                                  v8::ActivityControl* control); | 
| 97   void ResetSnapshots(); | 91   void ResetSnapshots(); | 
| 98 | 92 | 
| 99   HeapSnapshotsCollection* snapshots_; | 93   HeapSnapshotsCollection* snapshots_; | 
| 100   unsigned next_snapshot_uid_; | 94   unsigned next_snapshot_uid_; | 
| 101   List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_; | 95   List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_; | 
| 102 | 96 | 
| 103 #endif  // ENABLE_LOGGING_AND_PROFILING | 97 #endif  // ENABLE_LOGGING_AND_PROFILING | 
| 104 }; | 98 }; | 
| 105 | 99 | 
| 106 |  | 
| 107 #ifdef ENABLE_LOGGING_AND_PROFILING |  | 
| 108 |  | 
| 109 // JSObjectsCluster describes a group of JS objects that are |  | 
| 110 // considered equivalent in terms of a particular profile. |  | 
| 111 class JSObjectsCluster BASE_EMBEDDED { |  | 
| 112  public: |  | 
| 113   // These special cases are used in retainer profile. |  | 
| 114   enum SpecialCase { |  | 
| 115     ROOTS = 1, |  | 
| 116     GLOBAL_PROPERTY = 2, |  | 
| 117     CODE = 3, |  | 
| 118     SELF = 100  // This case is used in ClustersCoarser only. |  | 
| 119   }; |  | 
| 120 |  | 
| 121   JSObjectsCluster() : constructor_(NULL), instance_(NULL) {} |  | 
| 122   explicit JSObjectsCluster(String* constructor) |  | 
| 123       : constructor_(constructor), instance_(NULL) {} |  | 
| 124   explicit JSObjectsCluster(SpecialCase special) |  | 
| 125       : constructor_(FromSpecialCase(special)), instance_(NULL) {} |  | 
| 126   JSObjectsCluster(String* constructor, Object* instance) |  | 
| 127       : constructor_(constructor), instance_(instance) {} |  | 
| 128 |  | 
| 129   static int CompareConstructors(const JSObjectsCluster& a, |  | 
| 130                                  const JSObjectsCluster& b) { |  | 
| 131     // Strings are unique, so it is sufficient to compare their pointers. |  | 
| 132     return a.constructor_ == b.constructor_ ? 0 |  | 
| 133         : (a.constructor_ < b.constructor_ ? -1 : 1); |  | 
| 134   } |  | 
| 135   static int Compare(const JSObjectsCluster& a, const JSObjectsCluster& b) { |  | 
| 136     // Strings are unique, so it is sufficient to compare their pointers. |  | 
| 137     const int cons_cmp = CompareConstructors(a, b); |  | 
| 138     return cons_cmp == 0 ? |  | 
| 139         (a.instance_ == b.instance_ ? 0 : (a.instance_ < b.instance_ ? -1 : 1)) |  | 
| 140         : cons_cmp; |  | 
| 141   } |  | 
| 142   static int Compare(const JSObjectsCluster* a, const JSObjectsCluster* b) { |  | 
| 143     return Compare(*a, *b); |  | 
| 144   } |  | 
| 145 |  | 
| 146   bool is_null() const { return constructor_ == NULL; } |  | 
| 147   bool can_be_coarsed() const { return instance_ != NULL; } |  | 
| 148   String* constructor() const { return constructor_; } |  | 
| 149   Object* instance() const { return instance_; } |  | 
| 150 |  | 
| 151   const char* GetSpecialCaseName() const; |  | 
| 152   void Print(StringStream* accumulator) const; |  | 
| 153   // Allows null clusters to be printed. |  | 
| 154   void DebugPrint(StringStream* accumulator) const; |  | 
| 155 |  | 
| 156  private: |  | 
| 157   static String* FromSpecialCase(SpecialCase special) { |  | 
| 158     // We use symbols that are illegal JS identifiers to identify special cases. |  | 
| 159     // Their actual value is irrelevant for us. |  | 
| 160     switch (special) { |  | 
| 161       case ROOTS: return HEAP->result_symbol(); |  | 
| 162       case GLOBAL_PROPERTY: return HEAP->catch_var_symbol(); |  | 
| 163       case CODE: return HEAP->code_symbol(); |  | 
| 164       case SELF: return HEAP->this_symbol(); |  | 
| 165       default: |  | 
| 166         UNREACHABLE(); |  | 
| 167         return NULL; |  | 
| 168     } |  | 
| 169   } |  | 
| 170 |  | 
| 171   String* constructor_; |  | 
| 172   Object* instance_; |  | 
| 173 }; |  | 
| 174 |  | 
| 175 |  | 
| 176 struct JSObjectsClusterTreeConfig { |  | 
| 177   typedef JSObjectsCluster Key; |  | 
| 178   typedef NumberAndSizeInfo Value; |  | 
| 179   static const Key kNoKey; |  | 
| 180   static const Value kNoValue; |  | 
| 181   static int Compare(const Key& a, const Key& b) { |  | 
| 182     return Key::Compare(a, b); |  | 
| 183   } |  | 
| 184 }; |  | 
| 185 typedef ZoneSplayTree<JSObjectsClusterTreeConfig> JSObjectsClusterTree; |  | 
| 186 |  | 
| 187 |  | 
| 188 // ConstructorHeapProfile is responsible for gathering and logging |  | 
| 189 // "constructor profile" of JS objects allocated on heap. |  | 
| 190 // It is run during garbage collection cycle, thus it doesn't need |  | 
| 191 // to use handles. |  | 
| 192 class ConstructorHeapProfile BASE_EMBEDDED { |  | 
| 193  public: |  | 
| 194   ConstructorHeapProfile(); |  | 
| 195   virtual ~ConstructorHeapProfile() {} |  | 
| 196   void CollectStats(HeapObject* obj); |  | 
| 197   void PrintStats(); |  | 
| 198 |  | 
| 199   template<class Callback> |  | 
| 200   void ForEach(Callback* callback) { js_objects_info_tree_.ForEach(callback); } |  | 
| 201   // Used by ZoneSplayTree::ForEach. Made virtual to allow overriding in tests. |  | 
| 202   virtual void Call(const JSObjectsCluster& cluster, |  | 
| 203                     const NumberAndSizeInfo& number_and_size); |  | 
| 204 |  | 
| 205  private: |  | 
| 206   ZoneScope zscope_; |  | 
| 207   JSObjectsClusterTree js_objects_info_tree_; |  | 
| 208 }; |  | 
| 209 |  | 
| 210 |  | 
| 211 // JSObjectsRetainerTree is used to represent retainer graphs using |  | 
| 212 // adjacency list form: |  | 
| 213 // |  | 
| 214 //   Cluster -> (Cluster -> NumberAndSizeInfo) |  | 
| 215 // |  | 
| 216 // Subordinate splay trees are stored by pointer. They are zone-allocated, |  | 
| 217 // so it isn't needed to manage their lifetime. |  | 
| 218 // |  | 
| 219 struct JSObjectsRetainerTreeConfig { |  | 
| 220   typedef JSObjectsCluster Key; |  | 
| 221   typedef JSObjectsClusterTree* Value; |  | 
| 222   static const Key kNoKey; |  | 
| 223   static const Value kNoValue; |  | 
| 224   static int Compare(const Key& a, const Key& b) { |  | 
| 225     return Key::Compare(a, b); |  | 
| 226   } |  | 
| 227 }; |  | 
| 228 typedef ZoneSplayTree<JSObjectsRetainerTreeConfig> JSObjectsRetainerTree; |  | 
| 229 |  | 
| 230 |  | 
| 231 class ClustersCoarser BASE_EMBEDDED { |  | 
| 232  public: |  | 
| 233   ClustersCoarser(); |  | 
| 234 |  | 
| 235   // Processes a given retainer graph. |  | 
| 236   void Process(JSObjectsRetainerTree* tree); |  | 
| 237 |  | 
| 238   // Returns an equivalent cluster (can be the cluster itself). |  | 
| 239   // If the given cluster doesn't have an equivalent, returns null cluster. |  | 
| 240   JSObjectsCluster GetCoarseEquivalent(const JSObjectsCluster& cluster); |  | 
| 241   // Returns whether a cluster can be substitued with an equivalent and thus, |  | 
| 242   // skipped in some cases. |  | 
| 243   bool HasAnEquivalent(const JSObjectsCluster& cluster); |  | 
| 244 |  | 
| 245   // Used by JSObjectsRetainerTree::ForEach. |  | 
| 246   void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree); |  | 
| 247   void Call(const JSObjectsCluster& cluster, |  | 
| 248             const NumberAndSizeInfo& number_and_size); |  | 
| 249 |  | 
| 250  private: |  | 
| 251   // Stores a list of back references for a cluster. |  | 
| 252   struct ClusterBackRefs { |  | 
| 253     explicit ClusterBackRefs(const JSObjectsCluster& cluster_); |  | 
| 254     ClusterBackRefs(const ClusterBackRefs& src); |  | 
| 255     ClusterBackRefs& operator=(const ClusterBackRefs& src); |  | 
| 256 |  | 
| 257     static int Compare(const ClusterBackRefs& a, const ClusterBackRefs& b); |  | 
| 258     void SortRefs() { refs.Sort(JSObjectsCluster::Compare); } |  | 
| 259     static void SortRefsIterator(ClusterBackRefs* ref) { ref->SortRefs(); } |  | 
| 260 |  | 
| 261     JSObjectsCluster cluster; |  | 
| 262     ZoneList<JSObjectsCluster> refs; |  | 
| 263   }; |  | 
| 264   typedef ZoneList<ClusterBackRefs> SimilarityList; |  | 
| 265 |  | 
| 266   // A tree for storing a list of equivalents for a cluster. |  | 
| 267   struct ClusterEqualityConfig { |  | 
| 268     typedef JSObjectsCluster Key; |  | 
| 269     typedef JSObjectsCluster Value; |  | 
| 270     static const Key kNoKey; |  | 
| 271     static const Value kNoValue; |  | 
| 272     static int Compare(const Key& a, const Key& b) { |  | 
| 273       return Key::Compare(a, b); |  | 
| 274     } |  | 
| 275   }; |  | 
| 276   typedef ZoneSplayTree<ClusterEqualityConfig> EqualityTree; |  | 
| 277 |  | 
| 278   static int ClusterBackRefsCmp(const ClusterBackRefs* a, |  | 
| 279                                 const ClusterBackRefs* b) { |  | 
| 280     return ClusterBackRefs::Compare(*a, *b); |  | 
| 281   } |  | 
| 282   int DoProcess(JSObjectsRetainerTree* tree); |  | 
| 283   int FillEqualityTree(); |  | 
| 284 |  | 
| 285   static const int kInitialBackrefsListCapacity = 2; |  | 
| 286   static const int kInitialSimilarityListCapacity = 2000; |  | 
| 287   // Number of passes for finding equivalents. Limits the length of paths |  | 
| 288   // that can be considered equivalent. |  | 
| 289   static const int kMaxPassesCount = 10; |  | 
| 290 |  | 
| 291   ZoneScope zscope_; |  | 
| 292   SimilarityList sim_list_; |  | 
| 293   EqualityTree eq_tree_; |  | 
| 294   ClusterBackRefs* current_pair_; |  | 
| 295   JSObjectsRetainerTree* current_set_; |  | 
| 296   const JSObjectsCluster* self_; |  | 
| 297 }; |  | 
| 298 |  | 
| 299 |  | 
| 300 // RetainerHeapProfile is responsible for gathering and logging |  | 
| 301 // "retainer profile" of JS objects allocated on heap. |  | 
| 302 // It is run during garbage collection cycle, thus it doesn't need |  | 
| 303 // to use handles. |  | 
| 304 class RetainerTreeAggregator; |  | 
| 305 |  | 
| 306 class RetainerHeapProfile BASE_EMBEDDED { |  | 
| 307  public: |  | 
| 308   class Printer { |  | 
| 309    public: |  | 
| 310     virtual ~Printer() {} |  | 
| 311     virtual void PrintRetainers(const JSObjectsCluster& cluster, |  | 
| 312                                 const StringStream& retainers) = 0; |  | 
| 313   }; |  | 
| 314 |  | 
| 315   RetainerHeapProfile(); |  | 
| 316   ~RetainerHeapProfile(); |  | 
| 317 |  | 
| 318   RetainerTreeAggregator* aggregator() { return aggregator_; } |  | 
| 319   ClustersCoarser* coarser() { return &coarser_; } |  | 
| 320   JSObjectsRetainerTree* retainers_tree() { return &retainers_tree_; } |  | 
| 321 |  | 
| 322   void CollectStats(HeapObject* obj); |  | 
| 323   void CoarseAndAggregate(); |  | 
| 324   void PrintStats(); |  | 
| 325   void DebugPrintStats(Printer* printer); |  | 
| 326   void StoreReference(const JSObjectsCluster& cluster, HeapObject* ref); |  | 
| 327 |  | 
| 328  private: |  | 
| 329   ZoneScope zscope_; |  | 
| 330   JSObjectsRetainerTree retainers_tree_; |  | 
| 331   ClustersCoarser coarser_; |  | 
| 332   RetainerTreeAggregator* aggregator_; |  | 
| 333 }; |  | 
| 334 |  | 
| 335 |  | 
| 336 class AggregatedHeapSnapshot { |  | 
| 337  public: |  | 
| 338   AggregatedHeapSnapshot(); |  | 
| 339   ~AggregatedHeapSnapshot(); |  | 
| 340 |  | 
| 341   HistogramInfo* info() { return info_; } |  | 
| 342   ConstructorHeapProfile* js_cons_profile() { return &js_cons_profile_; } |  | 
| 343   RetainerHeapProfile* js_retainer_profile() { return &js_retainer_profile_; } |  | 
| 344 |  | 
| 345  private: |  | 
| 346   HistogramInfo* info_; |  | 
| 347   ConstructorHeapProfile js_cons_profile_; |  | 
| 348   RetainerHeapProfile js_retainer_profile_; |  | 
| 349 }; |  | 
| 350 |  | 
| 351 |  | 
| 352 class HeapEntriesMap; |  | 
| 353 class HeapEntriesAllocator; |  | 
| 354 |  | 
| 355 class AggregatedHeapSnapshotGenerator { |  | 
| 356  public: |  | 
| 357   explicit AggregatedHeapSnapshotGenerator(AggregatedHeapSnapshot* snapshot); |  | 
| 358   void GenerateSnapshot(); |  | 
| 359   void FillHeapSnapshot(HeapSnapshot* snapshot); |  | 
| 360 |  | 
| 361   static const int kAllStringsType = LAST_TYPE + 1; |  | 
| 362 |  | 
| 363  private: |  | 
| 364   void CalculateStringsStats(); |  | 
| 365   void CollectStats(HeapObject* obj); |  | 
| 366   template<class Iterator> |  | 
| 367   void IterateRetainers( |  | 
| 368       HeapEntriesAllocator* allocator, HeapEntriesMap* entries_map); |  | 
| 369 |  | 
| 370   AggregatedHeapSnapshot* agg_snapshot_; |  | 
| 371 }; |  | 
| 372 |  | 
| 373 |  | 
| 374 class ProducerHeapProfile { |  | 
| 375  public: |  | 
| 376   void Setup(); |  | 
| 377   void RecordJSObjectAllocation(Object* obj) { |  | 
| 378     if (FLAG_log_producers) DoRecordJSObjectAllocation(obj); |  | 
| 379   } |  | 
| 380 |  | 
| 381  private: |  | 
| 382   ProducerHeapProfile() : can_log_(false) { } |  | 
| 383 |  | 
| 384   void DoRecordJSObjectAllocation(Object* obj); |  | 
| 385   Isolate* isolate_; |  | 
| 386   bool can_log_; |  | 
| 387 |  | 
| 388   friend class Isolate; |  | 
| 389 |  | 
| 390   DISALLOW_COPY_AND_ASSIGN(ProducerHeapProfile); |  | 
| 391 }; |  | 
| 392 |  | 
| 393 #endif  // ENABLE_LOGGING_AND_PROFILING |  | 
| 394 |  | 
| 395 } }  // namespace v8::internal | 100 } }  // namespace v8::internal | 
| 396 | 101 | 
| 397 #endif  // V8_HEAP_PROFILER_H_ | 102 #endif  // V8_HEAP_PROFILER_H_ | 
| OLD | NEW | 
|---|