diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-07-05 14:40:13 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-07-05 14:51:29 -0700 |
commit | 149562555c9bf56457dee9a1ad70c53ed670a776 (patch) | |
tree | f6217cf3c54ddbee03f37247a3c7c75203f868fd /deps/v8/src/heap-profiler.h | |
parent | f08720606757577d95bd09b48697c7decbf17f00 (diff) | |
download | node-new-149562555c9bf56457dee9a1ad70c53ed670a776.tar.gz |
Downgrade V8 to 3.1.8.25
There are serious performance regressions both in V8 and our own legacy
networking stack. Until we correct our own problems we are going back to the
old V8.
Diffstat (limited to 'deps/v8/src/heap-profiler.h')
-rw-r--r-- | deps/v8/src/heap-profiler.h | 317 |
1 files changed, 298 insertions, 19 deletions
diff --git a/deps/v8/src/heap-profiler.h b/deps/v8/src/heap-profiler.h index c32f4c425f..20ba457c5b 100644 --- a/deps/v8/src/heap-profiler.h +++ b/deps/v8/src/heap-profiler.h @@ -28,7 +28,7 @@ #ifndef V8_HEAP_PROFILER_H_ #define V8_HEAP_PROFILER_H_ -#include "isolate.h" +#include "zone-inl.h" namespace v8 { namespace internal { @@ -38,15 +38,14 @@ namespace internal { class HeapSnapshot; class HeapSnapshotsCollection; -#define HEAP_PROFILE(heap, call) \ - do { \ - v8::internal::HeapProfiler* profiler = heap->isolate()->heap_profiler(); \ - if (profiler != NULL && profiler->is_profiling()) { \ - profiler->call; \ - } \ +#define HEAP_PROFILE(Call) \ + do { \ + if (v8::internal::HeapProfiler::is_profiling()) { \ + v8::internal::HeapProfiler::Call; \ + } \ } while (false) #else -#define HEAP_PROFILE(heap, call) ((void) 0) +#define HEAP_PROFILE(Call) ((void) 0) #endif // ENABLE_LOGGING_AND_PROFILING // The HeapProfiler writes data to the log files, which can be postprocessed @@ -66,19 +65,17 @@ class HeapProfiler { static int GetSnapshotsCount(); static HeapSnapshot* GetSnapshot(int index); static HeapSnapshot* FindSnapshot(unsigned uid); - static void DeleteAllSnapshots(); - void ObjectMoveEvent(Address from, Address to); + static void ObjectMoveEvent(Address from, Address to); - void DefineWrapperClass( - uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback); - - v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id, - Object** wrapper); - INLINE(bool is_profiling()) { - return snapshots_->is_tracking_objects(); + static INLINE(bool is_profiling()) { + return singleton_ != NULL && singleton_->snapshots_->is_tracking_objects(); } + // Obsolete interface. + // Write a single heap sample to the log file. + static void WriteSample(); + private: HeapProfiler(); ~HeapProfiler(); @@ -88,15 +85,297 @@ class HeapProfiler { HeapSnapshot* TakeSnapshotImpl(String* name, int type, v8::ActivityControl* control); - void ResetSnapshots(); HeapSnapshotsCollection* snapshots_; unsigned next_snapshot_uid_; - List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_; + static HeapProfiler* singleton_; #endif // ENABLE_LOGGING_AND_PROFILING }; + +#ifdef ENABLE_LOGGING_AND_PROFILING + +// JSObjectsCluster describes a group of JS objects that are +// considered equivalent in terms of a particular profile. +class JSObjectsCluster BASE_EMBEDDED { + public: + // These special cases are used in retainer profile. + enum SpecialCase { + ROOTS = 1, + GLOBAL_PROPERTY = 2, + CODE = 3, + SELF = 100 // This case is used in ClustersCoarser only. + }; + + JSObjectsCluster() : constructor_(NULL), instance_(NULL) {} + explicit JSObjectsCluster(String* constructor) + : constructor_(constructor), instance_(NULL) {} + explicit JSObjectsCluster(SpecialCase special) + : constructor_(FromSpecialCase(special)), instance_(NULL) {} + JSObjectsCluster(String* constructor, Object* instance) + : constructor_(constructor), instance_(instance) {} + + static int CompareConstructors(const JSObjectsCluster& a, + const JSObjectsCluster& b) { + // Strings are unique, so it is sufficient to compare their pointers. + return a.constructor_ == b.constructor_ ? 0 + : (a.constructor_ < b.constructor_ ? -1 : 1); + } + static int Compare(const JSObjectsCluster& a, const JSObjectsCluster& b) { + // Strings are unique, so it is sufficient to compare their pointers. + const int cons_cmp = CompareConstructors(a, b); + return cons_cmp == 0 ? + (a.instance_ == b.instance_ ? 0 : (a.instance_ < b.instance_ ? -1 : 1)) + : cons_cmp; + } + static int Compare(const JSObjectsCluster* a, const JSObjectsCluster* b) { + return Compare(*a, *b); + } + + bool is_null() const { return constructor_ == NULL; } + bool can_be_coarsed() const { return instance_ != NULL; } + String* constructor() const { return constructor_; } + Object* instance() const { return instance_; } + + const char* GetSpecialCaseName() const; + void Print(StringStream* accumulator) const; + // Allows null clusters to be printed. + void DebugPrint(StringStream* accumulator) const; + + private: + static String* FromSpecialCase(SpecialCase special) { + // We use symbols that are illegal JS identifiers to identify special cases. + // Their actual value is irrelevant for us. + switch (special) { + case ROOTS: return Heap::result_symbol(); + case GLOBAL_PROPERTY: return Heap::code_symbol(); + case CODE: return Heap::arguments_shadow_symbol(); + case SELF: return Heap::catch_var_symbol(); + default: + UNREACHABLE(); + return NULL; + } + } + + String* constructor_; + Object* instance_; +}; + + +struct JSObjectsClusterTreeConfig { + typedef JSObjectsCluster Key; + typedef NumberAndSizeInfo Value; + static const Key kNoKey; + static const Value kNoValue; + static int Compare(const Key& a, const Key& b) { + return Key::Compare(a, b); + } +}; +typedef ZoneSplayTree<JSObjectsClusterTreeConfig> JSObjectsClusterTree; + + +// ConstructorHeapProfile is responsible for gathering and logging +// "constructor profile" of JS objects allocated on heap. +// It is run during garbage collection cycle, thus it doesn't need +// to use handles. +class ConstructorHeapProfile BASE_EMBEDDED { + public: + ConstructorHeapProfile(); + virtual ~ConstructorHeapProfile() {} + void CollectStats(HeapObject* obj); + void PrintStats(); + + template<class Callback> + void ForEach(Callback* callback) { js_objects_info_tree_.ForEach(callback); } + // Used by ZoneSplayTree::ForEach. Made virtual to allow overriding in tests. + virtual void Call(const JSObjectsCluster& cluster, + const NumberAndSizeInfo& number_and_size); + + private: + ZoneScope zscope_; + JSObjectsClusterTree js_objects_info_tree_; +}; + + +// JSObjectsRetainerTree is used to represent retainer graphs using +// adjacency list form: +// +// Cluster -> (Cluster -> NumberAndSizeInfo) +// +// Subordinate splay trees are stored by pointer. They are zone-allocated, +// so it isn't needed to manage their lifetime. +// +struct JSObjectsRetainerTreeConfig { + typedef JSObjectsCluster Key; + typedef JSObjectsClusterTree* Value; + static const Key kNoKey; + static const Value kNoValue; + static int Compare(const Key& a, const Key& b) { + return Key::Compare(a, b); + } +}; +typedef ZoneSplayTree<JSObjectsRetainerTreeConfig> JSObjectsRetainerTree; + + +class ClustersCoarser BASE_EMBEDDED { + public: + ClustersCoarser(); + + // Processes a given retainer graph. + void Process(JSObjectsRetainerTree* tree); + + // Returns an equivalent cluster (can be the cluster itself). + // If the given cluster doesn't have an equivalent, returns null cluster. + JSObjectsCluster GetCoarseEquivalent(const JSObjectsCluster& cluster); + // Returns whether a cluster can be substitued with an equivalent and thus, + // skipped in some cases. + bool HasAnEquivalent(const JSObjectsCluster& cluster); + + // Used by JSObjectsRetainerTree::ForEach. + void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree); + void Call(const JSObjectsCluster& cluster, + const NumberAndSizeInfo& number_and_size); + + private: + // Stores a list of back references for a cluster. + struct ClusterBackRefs { + explicit ClusterBackRefs(const JSObjectsCluster& cluster_); + ClusterBackRefs(const ClusterBackRefs& src); + ClusterBackRefs& operator=(const ClusterBackRefs& src); + + static int Compare(const ClusterBackRefs& a, const ClusterBackRefs& b); + void SortRefs() { refs.Sort(JSObjectsCluster::Compare); } + static void SortRefsIterator(ClusterBackRefs* ref) { ref->SortRefs(); } + + JSObjectsCluster cluster; + ZoneList<JSObjectsCluster> refs; + }; + typedef ZoneList<ClusterBackRefs> SimilarityList; + + // A tree for storing a list of equivalents for a cluster. + struct ClusterEqualityConfig { + typedef JSObjectsCluster Key; + typedef JSObjectsCluster Value; + static const Key kNoKey; + static const Value kNoValue; + static int Compare(const Key& a, const Key& b) { + return Key::Compare(a, b); + } + }; + typedef ZoneSplayTree<ClusterEqualityConfig> EqualityTree; + + static int ClusterBackRefsCmp(const ClusterBackRefs* a, + const ClusterBackRefs* b) { + return ClusterBackRefs::Compare(*a, *b); + } + int DoProcess(JSObjectsRetainerTree* tree); + int FillEqualityTree(); + + static const int kInitialBackrefsListCapacity = 2; + static const int kInitialSimilarityListCapacity = 2000; + // Number of passes for finding equivalents. Limits the length of paths + // that can be considered equivalent. + static const int kMaxPassesCount = 10; + + ZoneScope zscope_; + SimilarityList sim_list_; + EqualityTree eq_tree_; + ClusterBackRefs* current_pair_; + JSObjectsRetainerTree* current_set_; + const JSObjectsCluster* self_; +}; + + +// RetainerHeapProfile is responsible for gathering and logging +// "retainer profile" of JS objects allocated on heap. +// It is run during garbage collection cycle, thus it doesn't need +// to use handles. +class RetainerTreeAggregator; + +class RetainerHeapProfile BASE_EMBEDDED { + public: + class Printer { + public: + virtual ~Printer() {} + virtual void PrintRetainers(const JSObjectsCluster& cluster, + const StringStream& retainers) = 0; + }; + + RetainerHeapProfile(); + ~RetainerHeapProfile(); + + RetainerTreeAggregator* aggregator() { return aggregator_; } + ClustersCoarser* coarser() { return &coarser_; } + JSObjectsRetainerTree* retainers_tree() { return &retainers_tree_; } + + void CollectStats(HeapObject* obj); + void CoarseAndAggregate(); + void PrintStats(); + void DebugPrintStats(Printer* printer); + void StoreReference(const JSObjectsCluster& cluster, HeapObject* ref); + + private: + ZoneScope zscope_; + JSObjectsRetainerTree retainers_tree_; + ClustersCoarser coarser_; + RetainerTreeAggregator* aggregator_; +}; + + +class AggregatedHeapSnapshot { + public: + AggregatedHeapSnapshot(); + ~AggregatedHeapSnapshot(); + + HistogramInfo* info() { return info_; } + ConstructorHeapProfile* js_cons_profile() { return &js_cons_profile_; } + RetainerHeapProfile* js_retainer_profile() { return &js_retainer_profile_; } + + private: + HistogramInfo* info_; + ConstructorHeapProfile js_cons_profile_; + RetainerHeapProfile js_retainer_profile_; +}; + + +class HeapEntriesMap; +class HeapEntriesAllocator; +class HeapSnapshot; + +class AggregatedHeapSnapshotGenerator { + public: + explicit AggregatedHeapSnapshotGenerator(AggregatedHeapSnapshot* snapshot); + void GenerateSnapshot(); + void FillHeapSnapshot(HeapSnapshot* snapshot); + + static const int kAllStringsType = LAST_TYPE + 1; + + private: + void CalculateStringsStats(); + void CollectStats(HeapObject* obj); + template<class Iterator> + void IterateRetainers( + HeapEntriesAllocator* allocator, HeapEntriesMap* entries_map); + + AggregatedHeapSnapshot* agg_snapshot_; +}; + + +class ProducerHeapProfile : public AllStatic { + public: + static void Setup(); + static void RecordJSObjectAllocation(Object* obj) { + if (FLAG_log_producers) DoRecordJSObjectAllocation(obj); + } + + private: + static void DoRecordJSObjectAllocation(Object* obj); + static bool can_log_; +}; + +#endif // ENABLE_LOGGING_AND_PROFILING + } } // namespace v8::internal #endif // V8_HEAP_PROFILER_H_ |