| Index: src/heap-profiler.h
|
| diff --git a/src/heap-profiler.h b/src/heap-profiler.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..32a424f347e2b03cb887b731c99d318fad444b2c
|
| --- /dev/null
|
| +++ b/src/heap-profiler.h
|
| @@ -0,0 +1,259 @@
|
| +// Copyright 2009 the V8 project authors. All rights reserved.
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following
|
| +// disclaimer in the documentation and/or other materials provided
|
| +// with the distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived
|
| +// from this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#ifndef V8_HEAP_PROFILER_H_
|
| +#define V8_HEAP_PROFILER_H_
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +#ifdef ENABLE_LOGGING_AND_PROFILING
|
| +
|
| +// The HeapProfiler writes data to the log files, which can be postprocessed
|
| +// to generate .hp files for use by the GHC/Valgrind tool hp2ps.
|
| +class HeapProfiler {
|
| + public:
|
| + // Write a single heap sample to the log file.
|
| + static void WriteSample();
|
| +
|
| + private:
|
| + // Update the array info with stats from obj.
|
| + static void CollectStats(HeapObject* obj, HistogramInfo* info);
|
| +};
|
| +
|
| +
|
| +// 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();
|
| + // Used by ZoneSplayTree::ForEach. Made virtual to allow overriding in tests.
|
| + virtual void Call(String* name, const NumberAndSizeInfo& number_and_size);
|
| +
|
| + private:
|
| + struct TreeConfig {
|
| + typedef String* Key;
|
| + typedef NumberAndSizeInfo Value;
|
| + static const Key kNoKey;
|
| + static const Value kNoValue;
|
| + static int Compare(const Key& a, const Key& b) {
|
| + // Strings are unique, so it is sufficient to compare their pointers.
|
| + return a == b ? 0 : (a < b ? -1 : 1);
|
| + }
|
| + };
|
| + typedef ZoneSplayTree<TreeConfig> JSObjectsInfoTree;
|
| +
|
| + ZoneScope zscope_;
|
| + JSObjectsInfoTree js_objects_info_tree_;
|
| +};
|
| +
|
| +
|
| +// JSObjectsCluster describes a group of JS objects that are
|
| +// considered equivalent in terms of retainer profile.
|
| +class JSObjectsCluster BASE_EMBEDDED {
|
| + public:
|
| + enum SpecialCase {
|
| + ROOTS = 1,
|
| + GLOBAL_PROPERTY = 2
|
| + };
|
| +
|
| + 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;
|
| + }
|
| +
|
| + bool is_null() const { return constructor_ == NULL; }
|
| + bool can_be_coarsed() const { return instance_ != NULL; }
|
| +
|
| + 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();
|
| + default:
|
| + UNREACHABLE();
|
| + return NULL;
|
| + }
|
| + }
|
| +
|
| + String* constructor_;
|
| + Object* instance_;
|
| +};
|
| +
|
| +
|
| +struct JSObjectsClusterTreeConfig;
|
| +typedef ZoneSplayTree<JSObjectsClusterTreeConfig> JSObjectsClusterTree;
|
| +
|
| +// JSObjectsClusterTree is used to represent retainer graphs using
|
| +// adjacency list form. That is, the first level maps JS object
|
| +// clusters to adjacency lists, which in their turn are degenerate
|
| +// JSObjectsClusterTrees (their values are NULLs.)
|
| +struct JSObjectsClusterTreeConfig {
|
| + 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);
|
| + }
|
| +};
|
| +
|
| +
|
| +class ClustersCoarser BASE_EMBEDDED {
|
| + public:
|
| + ClustersCoarser();
|
| +
|
| + // Processes a given retainer graph.
|
| + void Process(JSObjectsClusterTree* 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 ZoneSplayTree::ForEach.
|
| + void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
|
| +
|
| + 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);
|
| +
|
| + 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(JSObjectsClusterTree* tree);
|
| + int FillEqualityTree();
|
| +
|
| + static const int INITIAL_BACKREFS_LIST_CAPACITY = 2;
|
| + static const int INITIAL_SIMILARITY_LIST_CAPACITY = 2000;
|
| + // Number of passes for finding equivalents. Limits the length of paths
|
| + // that can be considered equivalent.
|
| + static const int MAX_PASSES_COUNT = 10;
|
| +
|
| + ZoneScope zscope_;
|
| + SimilarityList simList_;
|
| + EqualityTree eqTree_;
|
| + ClusterBackRefs* currentPair_;
|
| + JSObjectsClusterTree* currentSet_;
|
| +};
|
| +
|
| +
|
| +// 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 RetainerHeapProfile BASE_EMBEDDED {
|
| + public:
|
| + class Printer {
|
| + public:
|
| + virtual ~Printer() {}
|
| + virtual void PrintRetainers(const StringStream& retainers) = 0;
|
| + };
|
| +
|
| + RetainerHeapProfile();
|
| + void CollectStats(HeapObject* obj);
|
| + void PrintStats();
|
| + void DebugPrintStats(Printer* printer);
|
| + void StoreReference(const JSObjectsCluster& cluster, Object* ref);
|
| +
|
| + private:
|
| + JSObjectsCluster Clusterize(Object* obj);
|
| +
|
| + // Limit on the number of retainers to be printed per cluster.
|
| + static const int MAX_RETAINERS_TO_PRINT = 50;
|
| + ZoneScope zscope_;
|
| + JSObjectsClusterTree retainers_tree_;
|
| + ClustersCoarser coarser_;
|
| + // TODO(mnaganov): Use some helper class to hold these state variables.
|
| + JSObjectsClusterTree* coarse_cluster_tree_;
|
| + int retainers_printed_;
|
| + Printer* current_printer_;
|
| + StringStream* current_stream_;
|
| + public:
|
| + // Used by JSObjectsClusterTree::ForEach.
|
| + void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
|
| +};
|
| +
|
| +
|
| +#endif // ENABLE_LOGGING_AND_PROFILING
|
| +
|
| +} } // namespace v8::internal
|
| +
|
| +#endif // V8_HEAP_PROFILER_H_
|
|
|