| Index: src/profiler/profile-generator.cc
|
| diff --git a/src/profiler/profile-generator.cc b/src/profiler/profile-generator.cc
|
| index 583ef0f4e381e17f4c06452e4401ba6be0f8f82c..a670729b794961da40ef3668a326cb11cf851f90 100644
|
| --- a/src/profiler/profile-generator.cc
|
| +++ b/src/profiler/profile-generator.cc
|
| @@ -10,6 +10,8 @@
|
| #include "src/global-handles.h"
|
| #include "src/profiler/cpu-profiler.h"
|
| #include "src/profiler/profile-generator-inl.h"
|
| +#include "src/tracing/trace-event.h"
|
| +#include "src/tracing/traced-value.h"
|
| #include "src/unicode.h"
|
|
|
| namespace v8 {
|
| @@ -214,9 +216,8 @@ ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
|
| base::HashMap::Entry* map_entry =
|
| children_.LookupOrInsert(entry, CodeEntryHash(entry));
|
| ProfileNode* node = reinterpret_cast<ProfileNode*>(map_entry->value);
|
| - if (node == NULL) {
|
| - // New node added.
|
| - node = new ProfileNode(tree_, entry);
|
| + if (!node) {
|
| + node = new ProfileNode(tree_, entry, this);
|
| map_entry->value = node;
|
| children_list_.Add(node);
|
| }
|
| @@ -305,7 +306,7 @@ class DeleteNodesCallback {
|
| ProfileTree::ProfileTree(Isolate* isolate)
|
| : root_entry_(CodeEventListener::FUNCTION_TAG, "(root)"),
|
| next_node_id_(1),
|
| - root_(new ProfileNode(this, &root_entry_)),
|
| + root_(new ProfileNode(this, &root_entry_, nullptr)),
|
| isolate_(isolate),
|
| next_function_id_(1),
|
| function_ids_(ProfileNode::CodeEntriesMatch) {}
|
| @@ -397,13 +398,22 @@ void ProfileTree::TraverseDepthFirst(Callback* callback) {
|
| }
|
| }
|
|
|
| +using v8::tracing::TracedValue;
|
| +
|
| CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
|
| bool record_samples)
|
| : title_(title),
|
| record_samples_(record_samples),
|
| start_time_(base::TimeTicks::HighResolutionNow()),
|
| top_down_(profiler->isolate()),
|
| - profiler_(profiler) {}
|
| + profiler_(profiler),
|
| + streaming_next_sample_(0) {
|
| + auto value = TracedValue::Create();
|
| + value->SetDouble("startTime",
|
| + (start_time_ - base::TimeTicks()).InMicroseconds());
|
| + TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
|
| + "CpuProfile", this, "data", std::move(value));
|
| +}
|
|
|
| void CpuProfile::AddPath(base::TimeTicks timestamp,
|
| const std::vector<CodeEntry*>& path, int src_line,
|
| @@ -414,10 +424,91 @@ void CpuProfile::AddPath(base::TimeTicks timestamp,
|
| timestamps_.Add(timestamp);
|
| samples_.Add(top_frame_node);
|
| }
|
| + const int kSamplesFlushCount = 100;
|
| + const int kNodesFlushCount = 10;
|
| + if (samples_.length() - streaming_next_sample_ >= kSamplesFlushCount ||
|
| + top_down_.pending_nodes_count() >= kNodesFlushCount) {
|
| + StreamPendingTraceEvents();
|
| + }
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +void BuildNodeValue(const ProfileNode* node, TracedValue* value) {
|
| + const CodeEntry* entry = node->entry();
|
| + value->BeginDictionary("callFrame");
|
| + value->SetString("functionName", entry->name());
|
| + if (*entry->resource_name()) {
|
| + value->SetString("url", entry->resource_name());
|
| + }
|
| + value->SetInteger("scriptId", entry->script_id());
|
| + if (entry->line_number()) {
|
| + value->SetInteger("lineNumber", entry->line_number() - 1);
|
| + }
|
| + if (entry->column_number()) {
|
| + value->SetInteger("columnNumber", entry->column_number() - 1);
|
| + }
|
| + value->EndDictionary();
|
| + value->SetInteger("id", node->id());
|
| + if (node->parent()) {
|
| + value->SetInteger("parent", node->parent()->id());
|
| + }
|
| + const char* deopt_reason = entry->bailout_reason();
|
| + if (deopt_reason && deopt_reason[0] && strcmp(deopt_reason, "no reason")) {
|
| + value->SetString("deoptReason", deopt_reason);
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void CpuProfile::StreamPendingTraceEvents() {
|
| + std::vector<const ProfileNode*> pending_nodes = top_down_.TakePendingNodes();
|
| + if (pending_nodes.empty() && !samples_.length()) return;
|
| + auto value = TracedValue::Create();
|
| +
|
| + if (!pending_nodes.empty()) {
|
| + value->BeginArray("nodes");
|
| + for (auto node : pending_nodes) {
|
| + value->BeginDictionary();
|
| + BuildNodeValue(node, value.get());
|
| + value->EndDictionary();
|
| + }
|
| + value->EndArray();
|
| + }
|
| +
|
| + if (streaming_next_sample_ != samples_.length()) {
|
| + value->BeginArray("samples");
|
| + for (int i = streaming_next_sample_; i < samples_.length(); ++i) {
|
| + value->AppendInteger(samples_[i]->id());
|
| + }
|
| + value->EndArray();
|
| + value->BeginArray("timeDeltas");
|
| + base::TimeTicks lastTimestamp =
|
| + streaming_next_sample_ ? timestamps_[streaming_next_sample_ - 1]
|
| + : start_time();
|
| + for (int i = streaming_next_sample_; i < timestamps_.length(); ++i) {
|
| + value->AppendInteger(
|
| + static_cast<int>((timestamps_[i] - lastTimestamp).InMicroseconds()));
|
| + lastTimestamp = timestamps_[i];
|
| + }
|
| + value->EndArray();
|
| + DCHECK(samples_.length() == timestamps_.length());
|
| + streaming_next_sample_ = samples_.length();
|
| + }
|
| +
|
| + TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
|
| + "CpuProfileChunk", this, "data",
|
| + std::move(value));
|
| }
|
|
|
| -void CpuProfile::CalculateTotalTicksAndSamplingRate() {
|
| +void CpuProfile::FinishProfile() {
|
| end_time_ = base::TimeTicks::HighResolutionNow();
|
| + StreamPendingTraceEvents();
|
| + auto value = TracedValue::Create();
|
| + value->SetDouble("endTime", (end_time_ - base::TimeTicks()).InMicroseconds());
|
| + TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
|
| + "CpuProfileChunk", this, "data",
|
| + std::move(value));
|
| }
|
|
|
| void CpuProfile::Print() {
|
| @@ -504,7 +595,7 @@ bool CpuProfilesCollection::StartProfiling(const char* title,
|
|
|
| CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
|
| const int title_len = StrLength(title);
|
| - CpuProfile* profile = NULL;
|
| + CpuProfile* profile = nullptr;
|
| current_profiles_semaphore_.Wait();
|
| for (int i = current_profiles_.length() - 1; i >= 0; --i) {
|
| if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) {
|
| @@ -514,8 +605,8 @@ CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
|
| }
|
| current_profiles_semaphore_.Signal();
|
|
|
| - if (profile == NULL) return NULL;
|
| - profile->CalculateTotalTicksAndSamplingRate();
|
| + if (!profile) return nullptr;
|
| + profile->FinishProfile();
|
| finished_profiles_.Add(profile);
|
| return profile;
|
| }
|
|
|