| Index: src/profiler/sampling-heap-profiler.cc
|
| diff --git a/src/profiler/sampling-heap-profiler.cc b/src/profiler/sampling-heap-profiler.cc
|
| index 7b924e729007e187f59db9d2cfa2a5e45c11dbe2..e65279ab8f9c1b2d85cbd5c633a4f0574038b21c 100644
|
| --- a/src/profiler/sampling-heap-profiler.cc
|
| +++ b/src/profiler/sampling-heap-profiler.cc
|
| @@ -42,7 +42,6 @@
|
| other_spaces_observer_(new SamplingAllocationObserver(
|
| heap_, rate, rate, this, heap->isolate()->random_number_generator())),
|
| names_(names),
|
| - profile_root_("(root)", v8::UnboundScript::kNoScriptId, 0),
|
| samples_(),
|
| stack_depth_(stack_depth) {
|
| heap->new_space()->AddAllocationObserver(new_space_observer_.get());
|
| @@ -64,10 +63,12 @@
|
| }
|
| }
|
|
|
| - for (auto sample : samples_) {
|
| - delete sample;
|
| - }
|
| - std::set<Sample*> empty;
|
| + // Clear samples and drop all the weak references we are keeping.
|
| + std::set<SampledAllocation*>::iterator it;
|
| + for (it = samples_.begin(); it != samples_.end(); ++it) {
|
| + delete *it;
|
| + }
|
| + std::set<SampledAllocation*> empty;
|
| samples_.swap(empty);
|
| }
|
|
|
| @@ -85,48 +86,51 @@
|
|
|
| Local<v8::Value> loc = v8::Utils::ToLocal(obj);
|
|
|
| - AllocationNode* node = AddStack();
|
| - node->allocations_[size]++;
|
| - Sample* sample = new Sample(size, node, loc, this);
|
| + SampledAllocation* sample =
|
| + new SampledAllocation(this, isolate_, loc, size, stack_depth_);
|
| samples_.insert(sample);
|
| - sample->global.SetWeak(sample, OnWeakCallback, WeakCallbackType::kParameter);
|
| -}
|
| -
|
| -void SamplingHeapProfiler::OnWeakCallback(
|
| - const WeakCallbackInfo<Sample>& data) {
|
| - Sample* sample = data.GetParameter();
|
| - AllocationNode* node = sample->owner;
|
| - DCHECK(node->allocations_[sample->size] > 0);
|
| - node->allocations_[sample->size]--;
|
| - sample->profiler->samples_.erase(sample);
|
| +}
|
| +
|
| +
|
| +void SamplingHeapProfiler::SampledAllocation::OnWeakCallback(
|
| + const WeakCallbackInfo<SampledAllocation>& data) {
|
| + SampledAllocation* sample = data.GetParameter();
|
| + sample->sampling_heap_profiler_->samples_.erase(sample);
|
| delete sample;
|
| }
|
|
|
| -SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::FindOrAddChildNode(
|
| - AllocationNode* parent, const char* name, int script_id,
|
| - int start_position) {
|
| - for (AllocationNode* child : parent->children_) {
|
| - if (child->script_id_ == script_id &&
|
| - child->script_position_ == start_position &&
|
| - strcmp(child->name_, name) == 0) {
|
| - return child;
|
| - }
|
| - }
|
| - AllocationNode* child = new AllocationNode(name, script_id, start_position);
|
| - parent->children_.push_back(child);
|
| - return child;
|
| -}
|
| -
|
| -SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() {
|
| - AllocationNode* node = &profile_root_;
|
| -
|
| - std::vector<SharedFunctionInfo*> stack;
|
| - StackTraceFrameIterator it(isolate_);
|
| +
|
| +SamplingHeapProfiler::FunctionInfo::FunctionInfo(SharedFunctionInfo* shared,
|
| + StringsStorage* names)
|
| + : name_(names->GetFunctionName(shared->DebugName())),
|
| + script_name_(""),
|
| + script_id_(v8::UnboundScript::kNoScriptId),
|
| + start_position_(shared->start_position()) {
|
| + if (shared->script()->IsScript()) {
|
| + Script* script = Script::cast(shared->script());
|
| + script_id_ = script->id();
|
| + if (script->name()->IsName()) {
|
| + Name* name = Name::cast(script->name());
|
| + script_name_ = names->GetName(name);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +SamplingHeapProfiler::SampledAllocation::SampledAllocation(
|
| + SamplingHeapProfiler* sampling_heap_profiler, Isolate* isolate,
|
| + Local<Value> local, size_t size, int max_frames)
|
| + : sampling_heap_profiler_(sampling_heap_profiler),
|
| + global_(reinterpret_cast<v8::Isolate*>(isolate), local),
|
| + size_(size) {
|
| + global_.SetWeak(this, OnWeakCallback, WeakCallbackType::kParameter);
|
| +
|
| + StackTraceFrameIterator it(isolate);
|
| int frames_captured = 0;
|
| - while (!it.done() && frames_captured < stack_depth_) {
|
| + while (!it.done() && frames_captured < max_frames) {
|
| JavaScriptFrame* frame = it.frame();
|
| SharedFunctionInfo* shared = frame->function()->shared();
|
| - stack.push_back(shared);
|
| + stack_.push_back(new FunctionInfo(shared, sampling_heap_profiler->names()));
|
|
|
| frames_captured++;
|
| it.Advance();
|
| @@ -134,7 +138,7 @@
|
|
|
| if (frames_captured == 0) {
|
| const char* name = nullptr;
|
| - switch (isolate_->current_vm_state()) {
|
| + switch (isolate->current_vm_state()) {
|
| case GC:
|
| name = "(GC)";
|
| break;
|
| @@ -154,62 +158,70 @@
|
| name = "(JS)";
|
| break;
|
| }
|
| - return FindOrAddChildNode(node, name, v8::UnboundScript::kNoScriptId, 0);
|
| - }
|
| + stack_.push_back(new FunctionInfo(name));
|
| + }
|
| +}
|
| +
|
| +v8::AllocationProfile::Node* SamplingHeapProfiler::AllocateNode(
|
| + AllocationProfile* profile, const std::map<int, Script*>& scripts,
|
| + FunctionInfo* function_info) {
|
| + DCHECK(function_info->get_name());
|
| + DCHECK(function_info->get_script_name());
|
| +
|
| + int line = v8::AllocationProfile::kNoLineNumberInfo;
|
| + int column = v8::AllocationProfile::kNoColumnNumberInfo;
|
| +
|
| + if (function_info->get_script_id() != v8::UnboundScript::kNoScriptId) {
|
| + // Cannot use std::map<T>::at because it is not available on android.
|
| + auto non_const_scripts = const_cast<std::map<int, Script*>&>(scripts);
|
| + Handle<Script> script(non_const_scripts[function_info->get_script_id()]);
|
| +
|
| + line =
|
| + 1 + Script::GetLineNumber(script, function_info->get_start_position());
|
| + column = 1 + Script::GetColumnNumber(script,
|
| + function_info->get_start_position());
|
| + }
|
| +
|
| + profile->nodes().push_back(v8::AllocationProfile::Node(
|
| + {ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(
|
| + function_info->get_name())),
|
| + ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(
|
| + function_info->get_script_name())),
|
| + function_info->get_script_id(), function_info->get_start_position(),
|
| + line, column, std::vector<v8::AllocationProfile::Node*>(),
|
| + std::vector<v8::AllocationProfile::Allocation>()}));
|
| +
|
| + return &profile->nodes().back();
|
| +}
|
| +
|
| +v8::AllocationProfile::Node* SamplingHeapProfiler::FindOrAddChildNode(
|
| + AllocationProfile* profile, const std::map<int, Script*>& scripts,
|
| + v8::AllocationProfile::Node* parent, FunctionInfo* function_info) {
|
| + for (v8::AllocationProfile::Node* child : parent->children) {
|
| + if (child->script_id == function_info->get_script_id() &&
|
| + child->start_position == function_info->get_start_position())
|
| + return child;
|
| + }
|
| + v8::AllocationProfile::Node* child =
|
| + AllocateNode(profile, scripts, function_info);
|
| + parent->children.push_back(child);
|
| + return child;
|
| +}
|
| +
|
| +v8::AllocationProfile::Node* SamplingHeapProfiler::AddStack(
|
| + AllocationProfile* profile, const std::map<int, Script*>& scripts,
|
| + const std::vector<FunctionInfo*>& stack) {
|
| + v8::AllocationProfile::Node* node = profile->GetRootNode();
|
|
|
| // We need to process the stack in reverse order as the top of the stack is
|
| // the first element in the list.
|
| for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
|
| - SharedFunctionInfo* shared = *it;
|
| - const char* name = this->names()->GetFunctionName(shared->DebugName());
|
| - int script_id = v8::UnboundScript::kNoScriptId;
|
| - if (shared->script()->IsScript()) {
|
| - Script* script = Script::cast(shared->script());
|
| - script_id = script->id();
|
| - }
|
| - node = FindOrAddChildNode(node, name, script_id, shared->start_position());
|
| + FunctionInfo* function_info = *it;
|
| + node = FindOrAddChildNode(profile, scripts, node, function_info);
|
| }
|
| return node;
|
| }
|
|
|
| -v8::AllocationProfile::Node* SamplingHeapProfiler::TranslateAllocationNode(
|
| - AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
|
| - const std::map<int, Script*>& scripts) {
|
| - Local<v8::String> script_name =
|
| - ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(""));
|
| - int line = v8::AllocationProfile::kNoLineNumberInfo;
|
| - int column = v8::AllocationProfile::kNoColumnNumberInfo;
|
| - std::vector<v8::AllocationProfile::Allocation> allocations;
|
| - if (node->script_id_ != v8::UnboundScript::kNoScriptId) {
|
| - // Cannot use std::map<T>::at because it is not available on android.
|
| - auto non_const_scripts = const_cast<std::map<int, Script*>&>(scripts);
|
| - Script* script = non_const_scripts[node->script_id_];
|
| - if (script->name()->IsName()) {
|
| - Name* name = Name::cast(script->name());
|
| - script_name = ToApiHandle<v8::String>(
|
| - isolate_->factory()->InternalizeUtf8String(names_->GetName(name)));
|
| - }
|
| - Handle<Script> script_handle(script);
|
| -
|
| - line = 1 + Script::GetLineNumber(script_handle, node->script_position_);
|
| - column = 1 + Script::GetColumnNumber(script_handle, node->script_position_);
|
| - for (auto alloc : node->allocations_) {
|
| - allocations.push_back({alloc.first, alloc.second});
|
| - }
|
| - }
|
| -
|
| - profile->nodes().push_back(v8::AllocationProfile::Node(
|
| - {ToApiHandle<v8::String>(
|
| - isolate_->factory()->InternalizeUtf8String(node->name_)),
|
| - script_name, node->script_id_, node->script_position_, line, column,
|
| - std::vector<v8::AllocationProfile::Node*>(), allocations}));
|
| - v8::AllocationProfile::Node* current = &profile->nodes().back();
|
| - for (auto child : node->children_) {
|
| - current->children.push_back(
|
| - TranslateAllocationNode(profile, child, scripts));
|
| - }
|
| - return current;
|
| -}
|
|
|
| v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() {
|
| // To resolve positions to line/column numbers, we will need to look up
|
| @@ -225,7 +237,15 @@
|
|
|
| auto profile = new v8::internal::AllocationProfile();
|
|
|
| - TranslateAllocationNode(profile, &profile_root_, scripts);
|
| + // Create the root node.
|
| + FunctionInfo function_info("(root)");
|
| + AllocateNode(profile, scripts, &function_info);
|
| +
|
| + for (SampledAllocation* allocation : samples_) {
|
| + v8::AllocationProfile::Node* node =
|
| + AddStack(profile, scripts, allocation->get_stack());
|
| + node->allocations.push_back({allocation->get_size(), 1});
|
| + }
|
|
|
| return profile;
|
| }
|
|
|