Introduce first approximation of constructor heap profile for JS objects.

It is activated with '--log-gc' flag.

JS object size is calculated as its size + size of 'properties' and 'elements' arrays, if they are non-empty. This doesn't take maps, strings, heap numbers, and other shared objects into account.

As Soeren suggested, I've moved ZoneSplayTree from jsregexp to zone, and removed now empty jsregexp-inl header file.

Review URL: http://codereview.chromium.org/159504

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2570 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 87f51556
......@@ -3411,6 +3411,100 @@ void HeapIterator::reset() {
}
#ifdef ENABLE_LOGGING_AND_PROFILING
namespace {
// JSConstructorProfile is responsible for gathering and logging
// "constructor profile" of JS object allocated on heap.
// It is run during garbage collection cycle, thus it doesn't need
// to use handles.
class JSConstructorProfile BASE_EMBEDDED {
public:
JSConstructorProfile() : zscope_(DELETE_ON_EXIT) {}
void CollectStats(JSObject* obj);
void PrintStats();
// Used by ZoneSplayTree::ForEach.
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;
// Strings are unique, so it is sufficient to compare their pointers.
static int Compare(const Key& a, const Key& b) {
return a == b ? 0 : (a < b ? -1 : 1);
}
};
typedef ZoneSplayTree<TreeConfig> JSObjectsInfoTree;
static int CalculateJSObjectNetworkSize(JSObject* obj);
ZoneScope zscope_;
JSObjectsInfoTree js_objects_info_tree_;
};
const JSConstructorProfile::TreeConfig::Key
JSConstructorProfile::TreeConfig::kNoKey = NULL;
const JSConstructorProfile::TreeConfig::Value
JSConstructorProfile::TreeConfig::kNoValue;
int JSConstructorProfile::CalculateJSObjectNetworkSize(JSObject* obj) {
int size = obj->Size();
// If 'properties' and 'elements' are non-empty (thus, non-shared),
// take their size into account.
if (FixedArray::cast(obj->properties())->length() != 0) {
size += obj->properties()->Size();
}
if (FixedArray::cast(obj->elements())->length() != 0) {
size += obj->elements()->Size();
}
return size;
}
void JSConstructorProfile::Call(String* name,
const NumberAndSizeInfo& number_and_size) {
SmartPointer<char> s_name;
if (name != NULL) {
s_name = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
}
LOG(HeapSampleJSConstructorEvent(*s_name,
number_and_size.number(),
number_and_size.bytes()));
}
void JSConstructorProfile::CollectStats(JSObject* obj) {
String* constructor_func = NULL;
if (obj->map()->constructor()->IsJSFunction()) {
JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
SharedFunctionInfo* sfi = constructor->shared();
String* name = String::cast(sfi->name());
constructor_func = name->length() > 0 ? name : sfi->inferred_name();
} else if (obj->IsJSFunction()) {
constructor_func = Heap::function_class_symbol();
}
JSObjectsInfoTree::Locator loc;
if (!js_objects_info_tree_.Find(constructor_func, &loc)) {
js_objects_info_tree_.Insert(constructor_func, &loc);
}
NumberAndSizeInfo number_and_size = loc.value();
number_and_size.increment_number(1);
number_and_size.increment_bytes(CalculateJSObjectNetworkSize(obj));
loc.set_value(number_and_size);
}
void JSConstructorProfile::PrintStats() {
js_objects_info_tree_.ForEach(this);
}
} // namespace
#endif
//
// HeapProfiler class implementation.
//
......@@ -3435,9 +3529,14 @@ void HeapProfiler::WriteSample() {
INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
#undef DEF_TYPE_NAME
JSConstructorProfile js_cons_profile;
HeapIterator iterator;
while (iterator.has_next()) {
CollectStats(iterator.next(), info);
HeapObject* obj = iterator.next();
CollectStats(obj, info);
if (obj->IsJSObject()) {
js_cons_profile.CollectStats(JSObject::cast(obj));
}
}
// Lump all the string types together.
......@@ -3459,6 +3558,8 @@ void HeapProfiler::WriteSample() {
}
}
js_cons_profile.PrintStats();
LOG(HeapSampleEndEvent("Heap", "allocated"));
}
......
// Copyright 2008 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_JSREGEXP_INL_H_
#define V8_JSREGEXP_INL_H_
#include "jsregexp.h"
#include "regexp-macro-assembler.h"
namespace v8 {
namespace internal {
template <typename C>
bool ZoneSplayTree<C>::Insert(const Key& key, Locator* locator) {
if (is_empty()) {
// If the tree is empty, insert the new node.
root_ = new Node(key, C::kNoValue);
} else {
// Splay on the key to move the last node on the search path
// for the key to the root of the tree.
Splay(key);
// Ignore repeated insertions with the same key.
int cmp = C::Compare(key, root_->key_);
if (cmp == 0) {
locator->bind(root_);
return false;
}
// Insert the new node.
Node* node = new Node(key, C::kNoValue);
if (cmp > 0) {
node->left_ = root_;
node->right_ = root_->right_;
root_->right_ = NULL;
} else {
node->right_ = root_;
node->left_ = root_->left_;
root_->left_ = NULL;
}
root_ = node;
}
locator->bind(root_);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::Find(const Key& key, Locator* locator) {
if (is_empty())
return false;
Splay(key);
if (C::Compare(key, root_->key_) == 0) {
locator->bind(root_);
return true;
} else {
return false;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindGreatestLessThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the greatest node in
// the left subtree.
int cmp = C::Compare(root_->key_, key);
if (cmp <= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->left_;
bool result = FindGreatest(locator);
root_ = temp;
return result;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindLeastGreaterThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the least node in
// the right subtree.
int cmp = C::Compare(root_->key_, key);
if (cmp >= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->right_;
bool result = FindLeast(locator);
root_ = temp;
return result;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindGreatest(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->right_ != NULL)
current = current->right_;
locator->bind(current);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::FindLeast(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->left_ != NULL)
current = current->left_;
locator->bind(current);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::Remove(const Key& key) {
// Bail if the tree is empty
if (is_empty())
return false;
// Splay on the key to move the node with the given key to the top.
Splay(key);
// Bail if the key is not in the tree
if (C::Compare(key, root_->key_) != 0)
return false;
if (root_->left_ == NULL) {
// No left child, so the new tree is just the right child.
root_ = root_->right_;
} else {
// Left child exists.
Node* right = root_->right_;
// Make the original left child the new root.
root_ = root_->left_;
// Splay to make sure that the new root has an empty right child.
Splay(key);
// Insert the original right child as the right child of the new
// root.
root_->right_ = right;
}
return true;
}
template <typename C>
void ZoneSplayTree<C>::Splay(const Key& key) {
if (is_empty())
return;
Node dummy_node(C::kNoKey, C::kNoValue);
// Create a dummy node. The use of the dummy node is a bit
// counter-intuitive: The right child of the dummy node will hold
// the L tree of the algorithm. The left child of the dummy node
// will hold the R tree of the algorithm. Using a dummy node, left
// and right will always be nodes and we avoid special cases.
Node* dummy = &dummy_node;
Node* left = dummy;
Node* right = dummy;
Node* current = root_;
while (true) {
int cmp = C::Compare(key, current->key_);
if (cmp < 0) {
if (current->left_ == NULL)
break;
if (C::Compare(key, current->left_->key_) < 0) {
// Rotate right.
Node* temp = current->left_;
current->left_ = temp->right_;
temp->right_ = current;
current = temp;
if (current->left_ == NULL)
break;
}
// Link right.
right->left_ = current;
right = current;
current = current->left_;
} else if (cmp > 0) {
if (current->right_ == NULL)
break;
if (C::Compare(key, current->right_->key_) > 0) {
// Rotate left.
Node* temp = current->right_;
current->right_ = temp->left_;
temp->left_ = current;
current = temp;
if (current->right_ == NULL)
break;
}
// Link left.
left->right_ = current;
left = current;
current = current->right_;
} else {
break;
}
}
// Assemble.
left->right_ = current->left_;
right->left_ = current->right_;
current->left_ = dummy->right_;
current->right_ = dummy->left_;
root_ = current;
}
template <typename Node, class Callback>
static void DoForEach(Node* node, Callback* callback) {
if (node == NULL) return;
DoForEach<Node, Callback>(node->left(), callback);
callback->Call(node->key(), node->value());
DoForEach<Node, Callback>(node->right(), callback);
}
}} // namespace v8::internal
#endif // V8_JSREGEXP_INL_H_
......@@ -31,7 +31,7 @@
#include "compiler.h"
#include "execution.h"
#include "factory.h"
#include "jsregexp-inl.h"
#include "jsregexp.h"
#include "platform.h"
#include "runtime.h"
#include "top.h"
......
......@@ -214,108 +214,6 @@ class CharacterRange {
};
template <typename Node, class Callback>
static void DoForEach(Node* node, Callback* callback);
// A zone splay tree. The config type parameter encapsulates the
// different configurations of a concrete splay tree:
//
// typedef Key: the key type
// typedef Value: the value type
// static const kNoKey: the dummy key used when no key is set
// static const kNoValue: the dummy value used to initialize nodes
// int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
//
template <typename Config>
class ZoneSplayTree : public ZoneObject {
public:
typedef typename Config::Key Key;
typedef typename Config::Value Value;
class Locator;
ZoneSplayTree() : root_(NULL) { }
// Inserts the given key in this tree with the given value. Returns
// true if a node was inserted, otherwise false. If found the locator
// is enabled and provides access to the mapping for the key.
bool Insert(const Key& key, Locator* locator);
// Looks up the key in this tree and returns true if it was found,
// otherwise false. If the node is found the locator is enabled and
// provides access to the mapping for the key.
bool Find(const Key& key, Locator* locator);
// Finds the mapping with the greatest key less than or equal to the
// given key.
bool FindGreatestLessThan(const Key& key, Locator* locator);
// Find the mapping with the greatest key in this tree.
bool FindGreatest(Locator* locator);
// Finds the mapping with the least key greater than or equal to the
// given key.
bool FindLeastGreaterThan(const Key& key, Locator* locator);
// Find the mapping with the least key in this tree.
bool FindLeast(Locator* locator);
// Remove the node with the given key from the tree.
bool Remove(const Key& key);
bool is_empty() { return root_ == NULL; }
// Perform the splay operation for the given key. Moves the node with
// the given key to the top of the tree. If no node has the given
// key, the last node on the search path is moved to the top of the
// tree.
void Splay(const Key& key);
class Node : public ZoneObject {
public:
Node(const Key& key, const Value& value)
: key_(key),
value_(value),
left_(NULL),
right_(NULL) { }
Key key() { return key_; }
Value value() { return value_; }
Node* left() { return left_; }
Node* right() { return right_; }
private:
friend class ZoneSplayTree;
friend class Locator;
Key key_;
Value value_;
Node* left_;
Node* right_;
};
// A locator provides access to a node in the tree without actually
// exposing the node.
class Locator {
public:
explicit Locator(Node* node) : node_(node) { }
Locator() : node_(NULL) { }
const Key& key() { return node_->key_; }
Value& value() { return node_->value_; }
void set_value(const Value& value) { node_->value_ = value; }
inline void bind(Node* node) { node_ = node; }
private:
Node* node_;
};
template <class Callback>
void ForEach(Callback* c) {
DoForEach<typename ZoneSplayTree<Config>::Node, Callback>(root_, c);
}
private:
Node* root_;
};
// A set of unsigned integers that behaves especially well on small
// integers (< 32). May do zone-allocation.
class OutSet: public ZoneObject {
......
......@@ -884,6 +884,21 @@ void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
}
void Logger::HeapSampleJSConstructorEvent(const char* constructor,
int number, int bytes) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_gc) return;
LogMessageBuilder msg;
msg.Append("heap-js-cons-item,%s,%d,%d\n",
constructor != NULL ?
(constructor[0] != '\0' ? constructor : "(anonymous)") :
"(no_constructor)",
number, bytes);
msg.WriteToLogFile();
#endif
}
void Logger::DebugTag(const char* call_site_tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log) return;
......
......@@ -219,6 +219,8 @@ class Logger {
static void HeapSampleBeginEvent(const char* space, const char* kind);
static void HeapSampleEndEvent(const char* space, const char* kind);
static void HeapSampleItemEvent(const char* type, int number, int bytes);
static void HeapSampleJSConstructorEvent(const char* constructor,
int number, int bytes);
static void HeapSampleStats(const char* space, const char* kind,
int capacity, int used);
......
......@@ -931,34 +931,41 @@ class PagedSpace : public Space {
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
// HistogramInfo class for recording a single "bar" of a histogram. This
// class is used for collecting statistics to print to stdout (when compiled
// with DEBUG) or to the log file (when compiled with
// ENABLE_LOGGING_AND_PROFILING).
class HistogramInfo BASE_EMBEDDED {
class NumberAndSizeInfo BASE_EMBEDDED {
public:
HistogramInfo() : number_(0), bytes_(0) {}
NumberAndSizeInfo() : number_(0), bytes_(0) {}
const char* name() { return name_; }
void set_name(const char* name) { name_ = name; }
int number() { return number_; }
int number() const { return number_; }
void increment_number(int num) { number_ += num; }
int bytes() { return bytes_; }
int bytes() const { return bytes_; }
void increment_bytes(int size) { bytes_ += size; }
// Clear the number of objects and size fields, but not the name.
void clear() {
number_ = 0;
bytes_ = 0;
}
private:
const char* name_;
int number_;
int bytes_;
};
// HistogramInfo class for recording a single "bar" of a histogram. This
// class is used for collecting statistics to print to stdout (when compiled
// with DEBUG) or to the log file (when compiled with
// ENABLE_LOGGING_AND_PROFILING).
class HistogramInfo: public NumberAndSizeInfo {
public:
HistogramInfo() : NumberAndSizeInfo() {}
const char* name() { return name_; }
void set_name(const char* name) { name_ = name; }
private:
const char* name_;
};
#endif
......
......@@ -68,6 +68,223 @@ void Zone::adjust_segment_bytes_allocated(int delta) {
}
template <typename C>
bool ZoneSplayTree<C>::Insert(const Key& key, Locator* locator) {
if (is_empty()) {
// If the tree is empty, insert the new node.
root_ = new Node(key, C::kNoValue);
} else {
// Splay on the key to move the last node on the search path
// for the key to the root of the tree.
Splay(key);
// Ignore repeated insertions with the same key.
int cmp = C::Compare(key, root_->key_);
if (cmp == 0) {
locator->bind(root_);
return false;
}
// Insert the new node.
Node* node = new Node(key, C::kNoValue);
if (cmp > 0) {
node->left_ = root_;
node->right_ = root_->right_;
root_->right_ = NULL;
} else {
node->right_ = root_;
node->left_ = root_->left_;
root_->left_ = NULL;
}
root_ = node;
}
locator->bind(root_);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::Find(const Key& key, Locator* locator) {
if (is_empty())
return false;
Splay(key);
if (C::Compare(key, root_->key_) == 0) {
locator->bind(root_);
return true;
} else {
return false;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindGreatestLessThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the greatest node in
// the left subtree.
int cmp = C::Compare(root_->key_, key);
if (cmp <= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->left_;
bool result = FindGreatest(locator);
root_ = temp;
return result;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindLeastGreaterThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the least node in
// the right subtree.
int cmp = C::Compare(root_->key_, key);
if (cmp >= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->right_;
bool result = FindLeast(locator);
root_ = temp;
return result;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindGreatest(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->right_ != NULL)
current = current->right_;
locator->bind(current);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::FindLeast(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->left_ != NULL)
current = current->left_;
locator->bind(current);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::Remove(const Key& key) {
// Bail if the tree is empty
if (is_empty())
return false;
// Splay on the key to move the node with the given key to the top.
Splay(key);
// Bail if the key is not in the tree
if (C::Compare(key, root_->key_) != 0)
return false;
if (root_->left_ == NULL) {
// No left child, so the new tree is just the right child.
root_ = root_->right_;
} else {
// Left child exists.
Node* right = root_->right_;
// Make the original left child the new root.
root_ = root_->left_;
// Splay to make sure that the new root has an empty right child.
Splay(key);
// Insert the original right child as the right child of the new
// root.
root_->right_ = right;
}
return true;
}
template <typename C>
void ZoneSplayTree<C>::Splay(const Key& key) {
if (is_empty())
return;
Node dummy_node(C::kNoKey, C::kNoValue);
// Create a dummy node. The use of the dummy node is a bit
// counter-intuitive: The right child of the dummy node will hold
// the L tree of the algorithm. The left child of the dummy node
// will hold the R tree of the algorithm. Using a dummy node, left
// and right will always be nodes and we avoid special cases.
Node* dummy = &dummy_node;
Node* left = dummy;
Node* right = dummy;
Node* current = root_;
while (true) {
int cmp = C::Compare(key, current->key_);
if (cmp < 0) {
if (current->left_ == NULL)
break;
if (C::Compare(key, current->left_->key_) < 0) {
// Rotate right.
Node* temp = current->left_;
current->left_ = temp->right_;
temp->right_ = current;
current = temp;
if (current->left_ == NULL)
break;
}
// Link right.
right->left_ = current;
right = current;
current = current->left_;
} else if (cmp > 0) {
if (current->right_ == NULL)
break;
if (C::Compare(key, current->right_->key_) > 0) {
// Rotate left.
Node* temp = current->right_;
current->right_ = temp->left_;
temp->left_ = current;
current = temp;
if (current->right_ == NULL)
break;
}
// Link left.
left->right_ = current;
left = current;
current = current->right_;
} else {
break;
}
}
// Assemble.
left->right_ = current->left_;
right->left_ = current->right_;
current->left_ = dummy->right_;
current->right_ = dummy->left_;
root_ = current;
}
template <typename Node, class Callback>
static void DoForEach(Node* node, Callback* callback) {
if (node == NULL) return;
DoForEach<Node, Callback>(node->left(), callback);
callback->Call(node->key(), node->value());
DoForEach<Node, Callback>(node->right(), callback);
}
} } // namespace v8::internal
#endif // V8_ZONE_INL_H_
......@@ -204,6 +204,108 @@ class ZoneScope BASE_EMBEDDED {
};
template <typename Node, class Callback>
static void DoForEach(Node* node, Callback* callback);
// A zone splay tree. The config type parameter encapsulates the
// different configurations of a concrete splay tree:
//
// typedef Key: the key type
// typedef Value: the value type
// static const kNoKey: the dummy key used when no key is set
// static const kNoValue: the dummy value used to initialize nodes
// int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
//
template <typename Config>
class ZoneSplayTree : public ZoneObject {
public:
typedef typename Config::Key Key;
typedef typename Config::Value Value;
class Locator;
ZoneSplayTree() : root_(NULL) { }
// Inserts the given key in this tree with the given value. Returns
// true if a node was inserted, otherwise false. If found the locator
// is enabled and provides access to the mapping for the key.
bool Insert(const Key& key, Locator* locator);
// Looks up the key in this tree and returns true if it was found,
// otherwise false. If the node is found the locator is enabled and
// provides access to the mapping for the key.
bool Find(const Key& key, Locator* locator);
// Finds the mapping with the greatest key less than or equal to the
// given key.
bool FindGreatestLessThan(const Key& key, Locator* locator);
// Find the mapping with the greatest key in this tree.
bool FindGreatest(Locator* locator);
// Finds the mapping with the least key greater than or equal to the
// given key.
bool FindLeastGreaterThan(const Key& key, Locator* locator);
// Find the mapping with the least key in this tree.
bool FindLeast(Locator* locator);
// Remove the node with the given key from the tree.
bool Remove(const Key& key);
bool is_empty() { return root_ == NULL; }
// Perform the splay operation for the given key. Moves the node with
// the given key to the top of the tree. If no node has the given
// key, the last node on the search path is moved to the top of the
// tree.
void Splay(const Key& key);
class Node : public ZoneObject {
public:
Node(const Key& key, const Value& value)
: key_(key),
value_(value),
left_(NULL),
right_(NULL) { }
Key key() { return key_; }
Value value() { return value_; }
Node* left() { return left_; }
Node* right() { return right_; }
private:
friend class ZoneSplayTree;
friend class Locator;
Key key_;
Value value_;
Node* left_;
Node* right_;
};
// A locator provides access to a node in the tree without actually
// exposing the node.
class Locator {
public:
explicit Locator(Node* node) : node_(node) { }
Locator() : node_(NULL) { }
const Key& key() { return node_->key_; }
Value& value() { return node_->value_; }
void set_value(const Value& value) { node_->value_ = value; }
inline void bind(Node* node) { node_ = node; }
private:
Node* node_;
};
template <class Callback>
void ForEach(Callback* c) {
DoForEach<typename ZoneSplayTree<Config>::Node, Callback>(root_, c);
}
private:
Node* root_;
};
} } // namespace v8::internal
#endif // V8_ZONE_H_
......@@ -35,7 +35,7 @@
#include "zone-inl.h"
#include "parser.h"
#include "ast.h"
#include "jsregexp-inl.h"
#include "jsregexp.h"
#include "regexp-macro-assembler.h"
#include "regexp-macro-assembler-irregexp.h"
#ifdef V8_TARGET_ARCH_ARM
......
......@@ -35,10 +35,14 @@
# $ ./shell --log-gc script.js
# $ tools/process-heap-prof.py v8.log | hp2ps -c > script-heap-graph.ps
# ('-c' enables color, see hp2ps manual page for more options)
# or
# $ tools/process-heap-prof.py --js-cons-profile v8.log | hp2ps -c > script-heap-graph.ps
# to get JS constructor profile
import csv, sys, time
def process_logfile(filename):
def process_logfile(filename, itemname):
first_call_time = None
sample_time = 0.0
sampling = False
......@@ -63,11 +67,14 @@ def process_logfile(filename):
elif row[0] == 'heap-sample-end' and row[1] == 'Heap':
print('END_SAMPLE %.2f' % sample_time)
sampling = False
elif row[0] == 'heap-sample-item' and sampling:
elif row[0] == itemname and sampling:
print('%s %d' % (row[1], int(row[3])))
finally:
logfile.close()
except:
sys.exit('can\'t open %s' % filename)
process_logfile(sys.argv[1])
if sys.argv[1] == '--js-cons-profile':
process_logfile(sys.argv[2], 'heap-js-cons-item')
else:
process_logfile(sys.argv[1], 'heap-sample-item')
......@@ -520,10 +520,6 @@
RelativePath="..\..\src\ia32\jump-target-ia32.cc"
>
</File>
<File
RelativePath="..\..\src\jsregexp-inl.h"
>
</File>
<File
RelativePath="..\..\src\jsregexp.cc"
>
......
......@@ -520,10 +520,6 @@
RelativePath="..\..\src\arm\jump-target-arm.cc"
>
</File>
<File
RelativePath="..\..\src\jsregexp-inl.h"
>
</File>
<File
RelativePath="..\..\src\jsregexp.cc"
>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment