Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(730)

Unified Diff: runtime/vm/profiler_service.cc

Issue 1210333002: Make CPU profile models public and refactor model building code (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | runtime/vm/service.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/profiler_service.cc
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 188d7cd13218ad95f1ac0307cf94906fcb44923a..a75f8a20f41799c9c68c1ef545a95b202305318d 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -19,12 +19,6 @@ DECLARE_FLAG(int, profile_period);
DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler.");
-// Forward declarations.
-class CodeRegion;
-class ProfileFunction;
-class ProfileFunctionTable;
-
-
class DeoptimizedCodeSet : public ZoneAllocated {
public:
explicit DeoptimizedCodeSet(Isolate* isolate)
@@ -92,156 +86,351 @@ class DeoptimizedCodeSet : public ZoneAllocated {
const GrowableObjectArray& current_;
};
-class ProfileFunction : public ZoneAllocated {
- public:
- enum Kind {
- kDartFunction, // Dart function.
- kNativeFunction, // Synthetic function for Native (C/C++).
- kTagFunction, // Synthetic function for a VM or User tag.
- kStubFunction, // Synthetic function for stub code.
- kUnkownFunction, // A singleton function for unknown objects.
- };
- ProfileFunction(Kind kind,
+
+ProfileFunction::ProfileFunction(Kind kind,
const char* name,
const Function& function,
const intptr_t table_index)
- : kind_(kind),
- name_(name),
- function_(Function::ZoneHandle(function.raw())),
- table_index_(table_index),
- code_objects_(new ZoneGrowableArray<intptr_t>()),
- exclusive_ticks_(0),
- inclusive_ticks_(0),
- inclusive_tick_serial_(0) {
- ASSERT((kind_ != kDartFunction) || !function_.IsNull());
- ASSERT((kind_ != kDartFunction) || (table_index_ >= 0));
- ASSERT(code_objects_->length() == 0);
- }
+ : kind_(kind),
+ name_(name),
+ function_(Function::ZoneHandle(function.raw())),
+ table_index_(table_index),
+ profile_codes_(0),
+ exclusive_ticks_(0),
+ inclusive_ticks_(0) {
+ ASSERT((kind_ != kDartFunction) || !function_.IsNull());
+ ASSERT((kind_ != kDartFunction) || (table_index_ >= 0));
+ ASSERT(profile_codes_.length() == 0);
+}
- const char* name() const {
- ASSERT(name_ != NULL);
- return name_;
- }
- RawFunction* function() const {
- return function_.raw();
+void ProfileFunction::Tick(bool exclusive, intptr_t inclusive_serial) {
+ if (exclusive) {
+ exclusive_ticks_++;
+ } else {
+ if (inclusive_serial_ == inclusive_serial) {
+ // Already ticket.
+ return;
+ }
+ inclusive_serial_ = inclusive_serial;
+ inclusive_ticks_++;
}
+}
- intptr_t index() const {
- return table_index_;
- }
- Kind kind() const {
- return kind_;
+const char* ProfileFunction::KindToCString(Kind kind) {
+ switch (kind) {
+ case kDartFunction:
+ return "Dart";
+ case kNativeFunction:
+ return "Native";
+ case kTagFunction:
+ return "Tag";
+ case kStubFunction:
+ return "Stub";
+ case kUnknownFunction:
+ return "Collected";
+ default:
+ UNIMPLEMENTED();
+ return "";
}
+}
+
+
+void ProfileFunction::PrintToJSONObject(JSONObject* func) {
+ func->AddProperty("type", "@Function");
+ func->AddProperty("name", name());
+ func->AddProperty("_kind", KindToCString(kind()));
+}
+
- const char* KindToCString(Kind kind) {
- switch (kind) {
- case kDartFunction:
- return "Dart";
- case kNativeFunction:
- return "Native";
- case kTagFunction:
- return "Tag";
- case kStubFunction:
- return "Stub";
- case kUnkownFunction:
- return "Collected";
- default:
- UNIMPLEMENTED();
- return "";
+void ProfileFunction::PrintToJSONArray(JSONArray* functions) {
+ JSONObject obj(functions);
+ obj.AddProperty("kind", KindToCString(kind()));
+ obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
+ obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
+ if (kind() == kDartFunction) {
+ ASSERT(!function_.IsNull());
+ obj.AddProperty("function", function_);
+ } else {
+ JSONObject func(&obj, "function");
+ PrintToJSONObject(&func);
+ }
+ {
+ JSONArray codes(&obj, "codes");
+ for (intptr_t i = 0; i < profile_codes_.length(); i++) {
+ intptr_t code_index = profile_codes_[i];
+ codes.AddValue(code_index);
}
}
+}
+
- void Dump() {
- const char* n = (name_ == NULL) ? "<NULL>" : name_;
- const char* fn = "";
- if (!function_.IsNull()) {
- fn = function_.ToQualifiedCString();
+void ProfileFunction::AddProfileCode(intptr_t code_table_index) {
+ for (intptr_t i = 0; i < profile_codes_.length(); i++) {
+ if (profile_codes_[i] == code_table_index) {
+ return;
}
- OS::Print("%s %s [%s]", KindToCString(kind()), n, fn);
}
+ profile_codes_.Add(code_table_index);
+}
- void AddCodeObjectIndex(intptr_t index) {
- for (intptr_t i = 0; i < code_objects_->length(); i++) {
- if ((*code_objects_)[i] == index) {
- return;
- }
- }
- code_objects_->Add(index);
+
+ProfileCodeAddress::ProfileCodeAddress(uword pc)
+ : pc_(pc),
+ exclusive_ticks_(0),
+ inclusive_ticks_(0) {
+}
+
+
+void ProfileCodeAddress::Tick(bool exclusive) {
+ if (exclusive) {
+ exclusive_ticks_++;
+ } else {
+ inclusive_ticks_++;
}
+}
+
+
+ProfileCode::ProfileCode(Kind kind,
+ uword start,
+ uword end,
+ int64_t timestamp,
+ const Code& code)
+ : kind_(kind),
+ start_(start),
+ end_(end),
+ exclusive_ticks_(0),
+ inclusive_ticks_(0),
+ inclusive_serial_(-1),
+ code_(code),
+ name_(NULL),
+ compile_timestamp_(0),
+ function_(NULL),
+ code_table_index_(-1),
+ address_ticks_(0) {
+}
+
- intptr_t inclusive_ticks() const {
- return inclusive_ticks_;
+void ProfileCode::AdjustExtent(uword start, uword end) {
+ if (start < start_) {
+ start_ = start;
}
- void inc_inclusive_ticks() {
- inclusive_ticks_++;
+ if (end > end_) {
+ end_ = end;
+ }
+ ASSERT(start_ < end_);
+}
+
+
+bool ProfileCode::Overlaps(const ProfileCode* other) const {
+ ASSERT(other != NULL);
+ return other->Contains(start_) ||
+ other->Contains(end_ - 1) ||
+ Contains(other->start()) ||
+ Contains(other->end() - 1);
+}
+
+
+bool ProfileCode::IsOptimizedDart() const {
+ return !code_.IsNull() && code_.is_optimized();
+}
+
+
+void ProfileCode::SetName(const char* name) {
+ if (name == NULL) {
+ name_ = NULL;
}
- intptr_t exclusive_ticks() const {
- return exclusive_ticks_;
+ intptr_t len = strlen(name);
+ name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
+ strncpy(const_cast<char*>(name_), name, len);
+ const_cast<char*>(name_)[len] = '\0';
+}
+
+
+void ProfileCode::GenerateAndSetSymbolName(const char* prefix) {
+ const intptr_t kBuffSize = 512;
+ char buff[kBuffSize];
+ OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
+ prefix, start(), end());
+ SetName(buff);
+}
+
+
+void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) {
+ if (exclusive) {
+ exclusive_ticks_++;
+ } else {
+ if (inclusive_serial_ == serial) {
+ // Already ticked for this sample.
+ return;
+ }
+ inclusive_serial_ = serial;
+ inclusive_ticks_++;
}
+ TickAddress(pc, exclusive);
+}
+
- void Tick(bool exclusive, intptr_t serial) {
- // Assert that exclusive ticks are never passed a valid serial number.
- ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
- if (!exclusive && (inclusive_tick_serial_ == serial)) {
- // We've already given this object an inclusive tick for this sample.
+void ProfileCode::TickAddress(uword pc, bool exclusive) {
+ const intptr_t length = address_ticks_.length();
+
+ intptr_t i = 0;
+ for (; i < length; i++) {
+ ProfileCodeAddress& entry = address_ticks_[i];
+ if (entry.pc() == pc) {
+ // Tick the address entry.
+ entry.Tick(exclusive);
return;
}
- if (exclusive) {
- exclusive_ticks_++;
- } else {
- inclusive_ticks_++;
- // Mark the last serial we ticked the inclusive count.
- inclusive_tick_serial_ = serial;
+ if (entry.pc() > pc) {
+ break;
}
}
- void PrintToJSONObject(JSONObject* func) {
- func->AddProperty("type", "@Function");
- func->AddProperty("name", name());
- func->AddProperty("_kind", KindToCString(kind()));
+ // New address, add entry.
+ ProfileCodeAddress entry(pc);
+
+ entry.Tick(exclusive);
+
+ if (i < length) {
+ // Insert at i.
+ address_ticks_.InsertAt(i, entry);
+ } else {
+ // Add to end.
+ address_ticks_.Add(entry);
}
+}
- void PrintToJSONArray(JSONArray* functions) {
- JSONObject obj(functions);
- obj.AddProperty("kind", KindToCString(kind()));
- obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
- obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
- if (kind() == kDartFunction) {
- ASSERT(!function_.IsNull());
- obj.AddProperty("function", function_);
- } else {
- JSONObject func(&obj, "function");
- PrintToJSONObject(&func);
- }
- {
- JSONArray codes(&obj, "codes");
- for (intptr_t i = 0; i < code_objects_->length(); i++) {
- intptr_t code_index = (*code_objects_)[i];
- codes.AddValue(code_index);
- }
- }
+
+void ProfileCode::PrintNativeCode(JSONObject* profile_code_obj) {
+ ASSERT(kind() == kNativeCode);
+ JSONObject obj(profile_code_obj, "code");
+ obj.AddProperty("type", "@Code");
+ obj.AddProperty("kind", "Native");
+ obj.AddProperty("name", name());
+ obj.AddProperty("_optimized", false);
+ obj.AddPropertyF("start", "%" Px "", start());
+ obj.AddPropertyF("end", "%" Px "", end());
+ {
+ // Generate a fake function entry.
+ JSONObject func(&obj, "function");
+ ASSERT(function_ != NULL);
+ function_->PrintToJSONObject(&func);
}
+}
- private:
- const Kind kind_;
- const char* name_;
- const Function& function_;
- const intptr_t table_index_;
- ZoneGrowableArray<intptr_t>* code_objects_;
- intptr_t exclusive_ticks_;
- intptr_t inclusive_ticks_;
- intptr_t inclusive_tick_serial_;
-};
+
+void ProfileCode::PrintCollectedCode(JSONObject* profile_code_obj) {
+ ASSERT(kind() == kCollectedCode);
+ JSONObject obj(profile_code_obj, "code");
+ obj.AddProperty("type", "@Code");
+ obj.AddProperty("kind", "Collected");
+ obj.AddProperty("name", name());
+ obj.AddProperty("_optimized", false);
+ obj.AddPropertyF("start", "%" Px "", start());
+ obj.AddPropertyF("end", "%" Px "", end());
+ {
+ // Generate a fake function entry.
+ JSONObject func(&obj, "function");
+ ASSERT(function_ != NULL);
+ function_->PrintToJSONObject(&func);
+ }
+}
+
+
+void ProfileCode::PrintOverwrittenCode(JSONObject* profile_code_obj) {
+ ASSERT(kind() == kReusedCode);
+ JSONObject obj(profile_code_obj, "code");
+ obj.AddProperty("type", "@Code");
+ obj.AddProperty("kind", "Collected");
+ obj.AddProperty("name", name());
+ obj.AddProperty("_optimized", false);
+ obj.AddPropertyF("start", "%" Px "", start());
+ obj.AddPropertyF("end", "%" Px "", end());
+ {
+ // Generate a fake function entry.
+ JSONObject func(&obj, "function");
+ ASSERT(function_ != NULL);
+ function_->PrintToJSONObject(&func);
+ }
+}
+
+
+void ProfileCode::PrintTagCode(JSONObject* profile_code_obj) {
+ ASSERT(kind() == kTagCode);
+ JSONObject obj(profile_code_obj, "code");
+ obj.AddProperty("type", "@Code");
+ obj.AddProperty("kind", "Tag");
+ obj.AddProperty("name", name());
+ obj.AddPropertyF("start", "%" Px "", start());
+ obj.AddPropertyF("end", "%" Px "", end());
+ obj.AddProperty("_optimized", false);
+ {
+ // Generate a fake function entry.
+ JSONObject func(&obj, "function");
+ ASSERT(function_ != NULL);
+ function_->PrintToJSONObject(&func);
+ }
+}
+
+
+const char* ProfileCode::KindToCString(Kind kind) {
+ switch (kind) {
+ case kDartCode:
+ return "Dart";
+ case kCollectedCode:
+ return "Collected";
+ case kNativeCode:
+ return "Native";
+ case kReusedCode:
+ return "Overwritten";
+ case kTagCode:
+ return "Tag";
+ }
+ UNREACHABLE();
+ return NULL;
+}
+
+
+void ProfileCode::PrintToJSONArray(JSONArray* codes) {
+ JSONObject obj(codes);
+ obj.AddProperty("kind", ProfileCode::KindToCString(kind()));
+ obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
+ obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
+ if (kind() == kDartCode) {
+ ASSERT(!code_.IsNull());
+ obj.AddProperty("code", code_);
+ } else if (kind() == kCollectedCode) {
+ PrintCollectedCode(&obj);
+ } else if (kind() == kReusedCode) {
+ PrintOverwrittenCode(&obj);
+ } else if (kind() == kTagCode) {
+ PrintTagCode(&obj);
+ } else {
+ ASSERT(kind() == kNativeCode);
+ PrintNativeCode(&obj);
+ }
+ {
+ JSONArray ticks(&obj, "ticks");
+ for (intptr_t i = 0; i < address_ticks_.length(); i++) {
+ const ProfileCodeAddress& entry = address_ticks_[i];
+ ticks.AddValueF("%" Px "", entry.pc());
+ ticks.AddValueF("%" Pd "", entry.exclusive_ticks());
+ ticks.AddValueF("%" Pd "", entry.inclusive_ticks());
+ }
+ }
+}
-class ProfileFunctionTable : public ValueObject {
+class ProfileFunctionTable : public ZoneAllocated {
public:
ProfileFunctionTable()
: null_function_(Function::ZoneHandle()),
- table_(new ZoneGrowableArray<ProfileFunction*>()),
+ table_(8),
unknown_function_(NULL) {
+ unknown_function_ = Add(ProfileFunction::kUnknownFunction,
+ "<unknown Dart function>");
}
ProfileFunction* LookupOrAdd(const Function& function) {
@@ -255,8 +444,8 @@ class ProfileFunctionTable : public ValueObject {
intptr_t LookupIndex(const Function& function) {
ASSERT(!function.IsNull());
- for (intptr_t i = 0; i < table_->length(); i++) {
- ProfileFunction* profile_function = (*table_)[i];
+ for (intptr_t i = 0; i < table_.length(); i++) {
+ ProfileFunction* profile_function = table_[i];
if (profile_function->function() == function.raw()) {
return i;
}
@@ -265,11 +454,6 @@ class ProfileFunctionTable : public ValueObject {
}
ProfileFunction* GetUnknown() {
- if (unknown_function_ == NULL) {
- // Construct.
- unknown_function_ = Add(ProfileFunction::kUnkownFunction,
- "<unknown Dart function>");
- }
ASSERT(unknown_function_ != NULL);
return unknown_function_;
}
@@ -292,14 +476,14 @@ class ProfileFunctionTable : public ValueObject {
return Add(ProfileFunction::kStubFunction, name);
}
- intptr_t Length() const {
- return table_->length();
+ intptr_t length() const {
+ return table_.length();
}
ProfileFunction* At(intptr_t i) const {
ASSERT(i >= 0);
- ASSERT(i < Length());
- return (*table_)[i];
+ ASSERT(i < length());
+ return table_[i];
}
private:
@@ -310,8 +494,8 @@ class ProfileFunctionTable : public ValueObject {
new ProfileFunction(kind,
name,
null_function_,
- table_->length());
- table_->Add(profile_function);
+ table_.length());
+ table_.Add(profile_function);
return profile_function;
}
@@ -321,8 +505,8 @@ class ProfileFunctionTable : public ValueObject {
new ProfileFunction(ProfileFunction::kDartFunction,
NULL,
function,
- table_->length());
- table_->Add(profile_function);
+ table_.length());
+ table_.Add(profile_function);
return profile_function;
}
@@ -332,559 +516,189 @@ class ProfileFunctionTable : public ValueObject {
if (index == -1) {
return NULL;
}
- return (*table_)[index];
+ return table_[index];
}
const Function& null_function_;
- ZoneGrowableArray<ProfileFunction*>* table_;
-
+ ZoneGrowableArray<ProfileFunction*> table_;
ProfileFunction* unknown_function_;
};
-struct AddressEntry {
- uword pc;
- intptr_t exclusive_ticks;
- intptr_t inclusive_ticks;
-
- void tick(bool exclusive) {
- if (exclusive) {
- exclusive_ticks++;
+ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) {
+ ASSERT(function_ == NULL);
+
+ ProfileFunction* function = NULL;
+ if ((kind() == kReusedCode) || (kind() == kCollectedCode)) {
+ if (name() == NULL) {
+ // Lazily set generated name.
+ GenerateAndSetSymbolName("[Collected]");
+ }
+ // Map these to a canonical unknown function.
+ function = table->GetUnknown();
+ } else if (kind() == kDartCode) {
+ ASSERT(!code_.IsNull());
+ const Object& obj = Object::Handle(code_.owner());
+ if (obj.IsFunction()) {
+ const String& user_name = String::Handle(code_.PrettyName());
+ function = table->LookupOrAdd(Function::Cast(obj));
+ SetName(user_name.ToCString());
} else {
- inclusive_ticks++;
- }
- }
-};
-
-typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
-
-// A contiguous address region that holds code. Each CodeRegion has a "kind"
-// which describes the type of code contained inside the region. Each
-// region covers the following interval: [start, end).
-class CodeRegion : public ZoneAllocated {
- public:
- enum Kind {
- kDartCode, // Live Dart code.
- kCollectedCode, // Dead Dart code.
- kNativeCode, // Native code.
- kReusedCode, // Dead Dart code that has been reused by new kDartCode.
- kTagCode, // A special kind of code representing a tag.
- };
-
- CodeRegion(Kind kind,
- uword start,
- uword end,
- int64_t timestamp,
- const Code& code)
- : kind_(kind),
- start_(start),
- end_(end),
- inclusive_ticks_(0),
- exclusive_ticks_(0),
- inclusive_tick_serial_(0),
- name_(NULL),
- compile_timestamp_(timestamp),
- code_(Code::ZoneHandle(code.raw())),
- profile_function_(NULL),
- code_table_index_(-1) {
- ASSERT(start_ < end_);
- // Ensure all kDartCode have a valid code_ object.
- ASSERT((kind != kDartCode) || (!code_.IsNull()));
- }
-
- uword start() const { return start_; }
- void set_start(uword start) {
- start_ = start;
- }
-
- uword end() const { return end_; }
- void set_end(uword end) {
- end_ = end;
- }
-
- void AdjustExtent(uword start, uword end) {
- if (start < start_) {
- start_ = start;
- }
- if (end > end_) {
- end_ = end;
- }
- ASSERT(start_ < end_);
- }
-
- bool contains(uword pc) const {
- return (pc >= start_) && (pc < end_);
- }
-
- bool overlaps(const CodeRegion* other) const {
- ASSERT(other != NULL);
- return other->contains(start_) ||
- other->contains(end_ - 1) ||
- contains(other->start()) ||
- contains(other->end() - 1);
- }
-
- int64_t compile_timestamp() const { return compile_timestamp_; }
- void set_compile_timestamp(int64_t timestamp) {
- compile_timestamp_ = timestamp;
- }
-
- intptr_t inclusive_ticks() const { return inclusive_ticks_; }
- void set_inclusive_ticks(intptr_t inclusive_ticks) {
- inclusive_ticks_ = inclusive_ticks;
- }
- void inc_inclusive_ticks() {
- inclusive_ticks_++;
- }
-
- intptr_t exclusive_ticks() const { return exclusive_ticks_; }
- void set_exclusive_ticks(intptr_t exclusive_ticks) {
- exclusive_ticks_ = exclusive_ticks;
- }
-
- const char* name() const { return name_; }
- void SetName(const char* name) {
- if (name == NULL) {
- name_ = NULL;
- }
- intptr_t len = strlen(name);
- name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
- strncpy(const_cast<char*>(name_), name, len);
- const_cast<char*>(name_)[len] = '\0';
- }
-
- bool IsOptimizedDart() const {
- return !code_.IsNull() && code_.is_optimized();
- }
-
- RawCode* code() const {
- return code_.raw();
- }
-
- ProfileFunction* SetFunctionAndName(ProfileFunctionTable* table) {
- ASSERT(profile_function_ == NULL);
-
- ProfileFunction* function = NULL;
- if ((kind() == kReusedCode) || (kind() == kCollectedCode)) {
- if (name() == NULL) {
- // Lazily set generated name.
- GenerateAndSetSymbolName("[Collected]");
- }
- // Map these to a canonical unknown function.
- function = table->GetUnknown();
- } else if (kind() == kDartCode) {
- ASSERT(!code_.IsNull());
- const Object& obj = Object::Handle(code_.owner());
- if (obj.IsFunction()) {
- const String& user_name = String::Handle(code_.PrettyName());
- function = table->LookupOrAdd(Function::Cast(obj));
- SetName(user_name.ToCString());
+ // A stub.
+ const String& user_name = String::Handle(code_.PrettyName());
+ function = table->AddStub(start(), user_name.ToCString());
+ SetName(user_name.ToCString());
+ }
+ } else if (kind() == kNativeCode) {
+ if (name() == NULL) {
+ // Lazily set generated name.
+ GenerateAndSetSymbolName("[Native]");
+ }
+ function = table->AddNative(start(), name());
+ } else if (kind() == kTagCode) {
+ if (name() == NULL) {
+ if (UserTags::IsUserTag(start())) {
+ const char* tag_name = UserTags::TagName(start());
+ ASSERT(tag_name != NULL);
+ SetName(tag_name);
+ } else if (VMTag::IsVMTag(start()) ||
+ VMTag::IsRuntimeEntryTag(start()) ||
+ VMTag::IsNativeEntryTag(start())) {
+ const char* tag_name = VMTag::TagName(start());
+ ASSERT(tag_name != NULL);
+ SetName(tag_name);
} else {
- // A stub.
- const String& user_name = String::Handle(code_.PrettyName());
- function = table->AddStub(start(), user_name.ToCString());
- SetName(user_name.ToCString());
- }
- } else if (kind() == kNativeCode) {
- if (name() == NULL) {
- // Lazily set generated name.
- GenerateAndSetSymbolName("[Native]");
- }
- function = table->AddNative(start(), name());
- } else if (kind() == kTagCode) {
- if (name() == NULL) {
- if (UserTags::IsUserTag(start())) {
- const char* tag_name = UserTags::TagName(start());
- ASSERT(tag_name != NULL);
- SetName(tag_name);
- } else if (VMTag::IsVMTag(start()) ||
- VMTag::IsRuntimeEntryTag(start()) ||
- VMTag::IsNativeEntryTag(start())) {
- const char* tag_name = VMTag::TagName(start());
- ASSERT(tag_name != NULL);
- SetName(tag_name);
+ if (start() == VMTag::kRootTagId) {
+ SetName("Root");
} else {
- if (start() == VMTag::kRootTagId) {
- SetName("Root");
- } else {
- ASSERT(start() == VMTag::kTruncatedTagId);
- SetName("[Truncated]");
- }
+ ASSERT(start() == VMTag::kTruncatedTagId);
+ SetName("[Truncated]");
}
}
- function = table->AddTag(start(), name());
- } else {
- UNREACHABLE();
- }
- ASSERT(function != NULL);
- // Register this CodeRegion with this function.
- function->AddCodeObjectIndex(code_table_index());
- profile_function_ = function;
- return profile_function_;
- }
-
- ProfileFunction* function() const {
- ASSERT(profile_function_ != NULL);
- return profile_function_;
- }
-
- void set_code_table_index(intptr_t code_table_index) {
- ASSERT(code_table_index_ == -1);
- ASSERT(code_table_index != -1);
- code_table_index_ = code_table_index;
- }
- intptr_t code_table_index() const {
- ASSERT(code_table_index_ != -1);
- return code_table_index_;
- }
-
- Kind kind() const { return kind_; }
-
- static const char* KindToCString(Kind kind) {
- switch (kind) {
- case kDartCode:
- return "Dart";
- case kCollectedCode:
- return "Collected";
- case kNativeCode:
- return "Native";
- case kReusedCode:
- return "Overwritten";
- case kTagCode:
- return "Tag";
}
+ function = table->AddTag(start(), name());
+ } else {
UNREACHABLE();
- return NULL;
- }
-
- void DebugPrint() const {
- OS::Print("%s [%" Px ", %" Px ") %" Pd64 "\n",
- KindToCString(kind_),
- start(),
- end(),
- compile_timestamp_);
}
+ ASSERT(function != NULL);
- void Tick(uword pc, bool exclusive, intptr_t serial) {
- // Assert that exclusive ticks are never passed a valid serial number.
- ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
- if (!exclusive && (inclusive_tick_serial_ == serial)) {
- // We've already given this code object an inclusive tick for this sample.
- return;
- }
- // Tick the code object.
- if (exclusive) {
- exclusive_ticks_++;
- } else {
- inclusive_ticks_++;
- // Mark the last serial we ticked the inclusive count.
- inclusive_tick_serial_ = serial;
- }
- TickAddress(pc, exclusive);
- }
+ function->AddProfileCode(code_table_index());
- void PrintNativeCode(JSONObject* profile_code_obj) {
- ASSERT(kind() == kNativeCode);
- JSONObject obj(profile_code_obj, "code");
- obj.AddProperty("type", "@Code");
- obj.AddProperty("kind", "Native");
- obj.AddProperty("name", name());
- obj.AddProperty("_optimized", false);
- obj.AddPropertyF("start", "%" Px "", start());
- obj.AddPropertyF("end", "%" Px "", end());
- {
- // Generate a fake function entry.
- JSONObject func(&obj, "function");
- profile_function_->PrintToJSONObject(&func);
- }
- }
-
- void PrintCollectedCode(JSONObject* profile_code_obj) {
- ASSERT(kind() == kCollectedCode);
- JSONObject obj(profile_code_obj, "code");
- obj.AddProperty("type", "@Code");
- obj.AddProperty("kind", "Collected");
- obj.AddProperty("name", name());
- obj.AddProperty("_optimized", false);
- obj.AddPropertyF("start", "%" Px "", start());
- obj.AddPropertyF("end", "%" Px "", end());
- {
- // Generate a fake function entry.
- JSONObject func(&obj, "function");
- profile_function_->PrintToJSONObject(&func);
- }
- }
-
- void PrintOverwrittenCode(JSONObject* profile_code_obj) {
- ASSERT(kind() == kReusedCode);
- JSONObject obj(profile_code_obj, "code");
- obj.AddProperty("type", "@Code");
- obj.AddProperty("kind", "Collected");
- obj.AddProperty("name", name());
- obj.AddProperty("_optimized", false);
- obj.AddPropertyF("start", "%" Px "", start());
- obj.AddPropertyF("end", "%" Px "", end());
- {
- // Generate a fake function entry.
- JSONObject func(&obj, "function");
- ASSERT(profile_function_ != NULL);
- profile_function_->PrintToJSONObject(&func);
- }
- }
-
- void PrintTagCode(JSONObject* profile_code_obj) {
- ASSERT(kind() == kTagCode);
- JSONObject obj(profile_code_obj, "code");
- obj.AddProperty("type", "@Code");
- obj.AddProperty("kind", "Tag");
- obj.AddProperty("name", name());
- obj.AddPropertyF("start", "%" Px "", start());
- obj.AddPropertyF("end", "%" Px "", end());
- obj.AddProperty("_optimized", false);
- {
- // Generate a fake function entry.
- JSONObject func(&obj, "function");
- ASSERT(profile_function_ != NULL);
- profile_function_->PrintToJSONObject(&func);
- }
- }
-
- void PrintToJSONArray(JSONArray* codes) {
- JSONObject obj(codes);
- obj.AddProperty("kind", KindToCString(kind()));
- obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
- obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
- if (kind() == kDartCode) {
- ASSERT(!code_.IsNull());
- obj.AddProperty("code", code_);
- } else if (kind() == kCollectedCode) {
- PrintCollectedCode(&obj);
- } else if (kind() == kReusedCode) {
- PrintOverwrittenCode(&obj);
- } else if (kind() == kTagCode) {
- PrintTagCode(&obj);
- } else {
- ASSERT(kind() == kNativeCode);
- PrintNativeCode(&obj);
- }
- {
- JSONArray ticks(&obj, "ticks");
- for (intptr_t i = 0; i < address_table_.length(); i++) {
- const AddressEntry& entry = address_table_[i];
- ticks.AddValueF("%" Px "", entry.pc);
- ticks.AddValueF("%" Pd "", entry.exclusive_ticks);
- ticks.AddValueF("%" Pd "", entry.inclusive_ticks);
- }
- }
- }
+ function_ = function;
+ return function_;
+}
- private:
- void TickAddress(uword pc, bool exclusive) {
- const intptr_t length = address_table_.length();
- intptr_t i = 0;
- for (; i < length; i++) {
- AddressEntry& entry = address_table_[i];
- if (entry.pc == pc) {
- // Tick the address entry.
- entry.tick(exclusive);
- return;
- }
- if (entry.pc > pc) {
- break;
- }
- }
- // New address, add entry.
- AddressEntry entry;
- entry.pc = pc;
- entry.exclusive_ticks = 0;
- entry.inclusive_ticks = 0;
- entry.tick(exclusive);
- if (i < length) {
- // Insert at i.
- address_table_.InsertAt(i, entry);
- } else {
- // Add to end.
- address_table_.Add(entry);
- }
- }
-
- void GenerateAndSetSymbolName(const char* prefix) {
- const intptr_t kBuffSize = 512;
- char buff[kBuffSize];
- OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
- prefix, start(), end());
- SetName(buff);
- }
-
- // CodeRegion kind.
- const Kind kind_;
- // CodeRegion start address.
- uword start_;
- // CodeRegion end address.
- uword end_;
- // Inclusive ticks.
- intptr_t inclusive_ticks_;
- // Exclusive ticks.
- intptr_t exclusive_ticks_;
- // Inclusive tick serial number, ensures that each CodeRegion is only given
- // a single inclusive tick per sample.
- intptr_t inclusive_tick_serial_;
- // Name of code region.
- const char* name_;
- // The compilation timestamp associated with this code region.
- int64_t compile_timestamp_;
- // Dart code object (may be null).
- const Code& code_;
- // Pointer to ProfileFunction.
- ProfileFunction* profile_function_;
- // Final code table index.
- intptr_t code_table_index_;
- ZoneGrowableArray<AddressEntry> address_table_;
- DISALLOW_COPY_AND_ASSIGN(CodeRegion);
-};
+typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end);
-// A sorted table of CodeRegions. Does not allow for overlap.
-class CodeRegionTable : public ValueObject {
+class ProfileCodeTable : public ZoneAllocated {
public:
- enum TickResult {
- kTicked = 0, // CodeRegion found and ticked.
- kNotFound = -1, // No CodeRegion found.
- kNewerCode = -2, // CodeRegion found but it was compiled after sample.
- };
-
- CodeRegionTable() :
- code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
- }
-
- // Ticks the CodeRegion containing pc if it is alive at timestamp.
- TickResult Tick(uword pc,
- bool exclusive,
- intptr_t serial,
- int64_t timestamp) {
- intptr_t index = FindIndex(pc);
- if (index < 0) {
- // Not found.
- return kNotFound;
- }
- ASSERT(index < code_region_table_->length());
- CodeRegion* region = At(index);
- if (region->compile_timestamp() > timestamp) {
- // Compiled after tick.
- return kNewerCode;
- }
- region->Tick(pc, exclusive, serial);
- return kTicked;
+ ProfileCodeTable()
+ : table_(8) {
}
- // Table length.
- intptr_t Length() const { return code_region_table_->length(); }
+ intptr_t length() const { return table_.length(); }
- // Get the CodeRegion at index.
- CodeRegion* At(intptr_t index) const {
- return (*code_region_table_)[index];
+ ProfileCode* At(intptr_t index) const {
+ ASSERT(index >= 0);
+ ASSERT(index < length());
+ return table_[index];
}
- // Find the table index to the CodeRegion containing pc.
+ // Find the table index to the ProfileCode containing pc.
// Returns < 0 if not found.
- intptr_t FindIndex(uword pc) const {
- intptr_t index = FindRegionIndex(pc, &CompareLowerBound);
- const CodeRegion* code_region = NULL;
- if (index == code_region_table_->length()) {
+ intptr_t FindCodeIndexForPC(uword pc) const {
+ intptr_t index = FindCodeIndex(pc, &CompareLowerBound);
+ if (index == length()) {
+ // Not present.
+ return -1;
+ }
+ const ProfileCode* code = At(index);
+ if (!code->Contains(pc)) {
// Not present.
return -1;
}
- code_region = At(index);
- if (code_region->contains(pc)) {
- // Found at index.
- return index;
+ // Found at index.
+ return index;
+ }
+
+ ProfileCode* FindCodeForPC(uword pc) const {
+ intptr_t index = FindCodeIndexForPC(pc);
+ if (index < 0) {
+ return NULL;
}
- return -2;
+ return At(index);
}
- // Insert code_region into the table. Returns the table index where the
- // CodeRegion was inserted. Will merge with an overlapping CodeRegion if
- // one is present.
- intptr_t InsertCodeRegion(CodeRegion* code_region) {
- const uword start = code_region->start();
- const uword end = code_region->end();
- const intptr_t length = code_region_table_->length();
+ // Insert |new_code| into the table. Returns the table index where |new_code|
+ // was inserted. Will merge with an overlapping ProfileCode if one is present.
+ intptr_t InsertCode(ProfileCode* new_code) {
+ const uword start = new_code->start();
+ const uword end = new_code->end();
+ const intptr_t length = table_.length();
if (length == 0) {
- code_region_table_->Add(code_region);
+ table_.Add(new_code);
return length;
}
- // Determine the correct place to insert or merge code_region into table.
- intptr_t lo = FindRegionIndex(start, &CompareLowerBound);
- intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound);
+ // Determine the correct place to insert or merge |new_code| into table.
+ intptr_t lo = FindCodeIndex(start, &CompareLowerBound);
+ intptr_t hi = FindCodeIndex(end - 1, &CompareUpperBound);
// TODO(johnmccutchan): Simplify below logic.
if ((lo == length) && (hi == length)) {
lo = length - 1;
}
if (lo == length) {
- CodeRegion* region = At(hi);
- if (region->overlaps(code_region)) {
- HandleOverlap(region, code_region, start, end);
+ ProfileCode* code = At(hi);
+ if (code->Overlaps(new_code)) {
+ HandleOverlap(code, new_code, start, end);
return hi;
}
- code_region_table_->Add(code_region);
+ table_.Add(new_code);
return length;
} else if (hi == length) {
- CodeRegion* region = At(lo);
- if (region->overlaps(code_region)) {
- HandleOverlap(region, code_region, start, end);
+ ProfileCode* code = At(lo);
+ if (code->Overlaps(new_code)) {
+ HandleOverlap(code, new_code, start, end);
return lo;
}
- code_region_table_->Add(code_region);
+ table_.Add(new_code);
return length;
} else if (lo == hi) {
- CodeRegion* region = At(lo);
- if (region->overlaps(code_region)) {
- HandleOverlap(region, code_region, start, end);
+ ProfileCode* code = At(lo);
+ if (code->Overlaps(new_code)) {
+ HandleOverlap(code, new_code, start, end);
return lo;
}
- code_region_table_->InsertAt(lo, code_region);
+ table_.InsertAt(lo, new_code);
return lo;
} else {
- CodeRegion* region = At(lo);
- if (region->overlaps(code_region)) {
- HandleOverlap(region, code_region, start, end);
+ ProfileCode* code = At(lo);
+ if (code->Overlaps(new_code)) {
+ HandleOverlap(code, new_code, start, end);
return lo;
}
- region = At(hi);
- if (region->overlaps(code_region)) {
- HandleOverlap(region, code_region, start, end);
+ code = At(hi);
+ if (code->Overlaps(new_code)) {
+ HandleOverlap(code, new_code, start, end);
return hi;
}
- code_region_table_->InsertAt(hi, code_region);
+ table_.InsertAt(hi, new_code);
return hi;
}
UNREACHABLE();
}
- void Verify() {
- VerifyOrder();
- VerifyOverlap();
- }
-
- void DebugPrint() {
- OS::Print("Dumping CodeRegionTable:\n");
- for (intptr_t i = 0; i < code_region_table_->length(); i++) {
- CodeRegion* region = At(i);
- region->DebugPrint();
- }
- }
-
private:
- intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
+ intptr_t FindCodeIndex(uword pc, RangeCompare comparator) const {
ASSERT(comparator != NULL);
- intptr_t count = code_region_table_->length();
+ intptr_t count = table_.length();
intptr_t first = 0;
while (count > 0) {
intptr_t it = first;
intptr_t step = count / 2;
it += step;
- const CodeRegion* code_region = At(it);
- if (comparator(pc, code_region->start(), code_region->end())) {
+ const ProfileCode* code = At(it);
+ if (comparator(pc, code->start(), code->end())) {
first = ++it;
count -= (step + 1);
} else {
@@ -902,387 +716,126 @@ class CodeRegionTable : public ValueObject {
return end <= pc;
}
- void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
+ void HandleOverlap(ProfileCode* existing, ProfileCode* code,
uword start, uword end) {
// We should never see overlapping Dart code regions.
- ASSERT(region->kind() != CodeRegion::kDartCode);
+ ASSERT(existing->kind() != ProfileCode::kDartCode);
// We should never see overlapping Tag code regions.
- ASSERT(region->kind() != CodeRegion::kTagCode);
+ ASSERT(existing->kind() != ProfileCode::kTagCode);
// When code regions overlap, they should be of the same kind.
- ASSERT(region->kind() == code_region->kind());
- region->AdjustExtent(start, end);
+ ASSERT(existing->kind() == code->kind());
+ existing->AdjustExtent(start, end);
}
void VerifyOrder() {
- const intptr_t length = code_region_table_->length();
+ const intptr_t length = table_.length();
if (length == 0) {
return;
}
- uword last = (*code_region_table_)[0]->end();
+ uword last = table_[0]->end();
for (intptr_t i = 1; i < length; i++) {
- CodeRegion* a = (*code_region_table_)[i];
+ ProfileCode* a = table_[i];
ASSERT(last <= a->start());
last = a->end();
}
}
void VerifyOverlap() {
- const intptr_t length = code_region_table_->length();
+ const intptr_t length = table_.length();
for (intptr_t i = 0; i < length; i++) {
- CodeRegion* a = (*code_region_table_)[i];
+ ProfileCode* a = table_[i];
for (intptr_t j = i+1; j < length; j++) {
- CodeRegion* b = (*code_region_table_)[j];
- ASSERT(!a->contains(b->start()) &&
- !a->contains(b->end() - 1) &&
- !b->contains(a->start()) &&
- !b->contains(a->end() - 1));
+ ProfileCode* b = table_[j];
+ ASSERT(!a->Contains(b->start()) &&
+ !a->Contains(b->end() - 1) &&
+ !b->Contains(a->start()) &&
+ !b->Contains(a->end() - 1));
}
}
}
- ZoneGrowableArray<CodeRegion*>* code_region_table_;
+ ZoneGrowableArray<ProfileCode*> table_;
};
-class CodeRegionTableBuilder {
- public:
- CodeRegionTableBuilder(Isolate* isolate,
- CodeRegionTable* live_code_table,
- CodeRegionTable* dead_code_table,
- CodeRegionTable* tag_code_table,
- DeoptimizedCodeSet* deoptimized_code)
- : live_code_table_(live_code_table),
- dead_code_table_(dead_code_table),
- tag_code_table_(tag_code_table),
- isolate_(isolate),
- vm_isolate_(Dart::vm_isolate()),
- null_code_(Code::ZoneHandle()),
- deoptimized_code_(deoptimized_code) {
- ASSERT(live_code_table_ != NULL);
- ASSERT(dead_code_table_ != NULL);
- ASSERT(tag_code_table_ != NULL);
- ASSERT(isolate_ != NULL);
- ASSERT(vm_isolate_ != NULL);
- ASSERT(null_code_.IsNull());
- frames_ = 0;
- min_time_ = kMaxInt64;
- max_time_ = 0;
- }
+ProfileTrieNode::ProfileTrieNode(intptr_t table_index)
+ : table_index_(table_index),
+ count_(0),
+ children_(0) {
+ ASSERT(table_index_ >= 0);
+}
- void Build(ProcessedSampleBuffer* buffer) {
- for (intptr_t i = 0; i < buffer->length(); i++) {
- ProcessedSample* sample = buffer->At(i);
- VisitSample(i, sample);
- }
- }
- intptr_t frames() const { return frames_; }
+ProfileTrieNode::~ProfileTrieNode() {
+}
- intptr_t TimeDeltaMicros() const {
- return static_cast<intptr_t>(max_time_ - min_time_);
- }
- int64_t max_time() const { return max_time_; }
- private:
- void VisitSample(intptr_t serial, ProcessedSample* sample) {
- int64_t timestamp = sample->timestamp();
- if (timestamp > max_time_) {
- max_time_ = timestamp;
- }
- if (timestamp < min_time_) {
- min_time_ = timestamp;
- }
+void ProfileTrieNode::SortChildren() {
+ children_.Sort(ProfileTrieNodeCompare);
+ // Recurse.
+ for (intptr_t i = 0; i < children_.length(); i++) {
+ children_[i]->SortChildren();
+ }
+}
- // Make sure VM tag is created.
- if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
- CreateTag(VMTag::kNativeTagId);
- } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
- CreateTag(VMTag::kRuntimeTagId);
- }
- CreateTag(sample->vm_tag());
- // Make sure user tag is created.
- CreateUserTag(sample->user_tag());
+class ProfileCodeTrieNode : public ProfileTrieNode {
+ public:
+ explicit ProfileCodeTrieNode(intptr_t table_index)
+ : ProfileTrieNode(table_index) {
+ }
- // Exclusive tick for top frame if the first frame was executing.
- if (!sample->first_frame_executing()) {
- Tick(sample->At(0), true, serial, timestamp);
+ void PrintToJSONArray(JSONArray* array) const {
+ ASSERT(array != NULL);
+ // Write CodeRegion index.
+ array->AddValue(table_index());
+ // Write count.
+ array->AddValue(count());
+ // Write number of children.
+ intptr_t child_count = NumChildren();
+ array->AddValue(child_count);
+ // Recurse.
+ for (intptr_t i = 0; i < child_count; i++) {
+ children_[i]->PrintToJSONArray(array);
}
+ }
- // Inclusive tick for all frames.
- for (intptr_t i = 0; i < sample->length(); i++) {
- ASSERT(sample->At(i) != 0);
- frames_++;
- Tick(sample->At(i), false, serial, timestamp);
+ ProfileCodeTrieNode* GetChild(intptr_t child_table_index) {
+ const intptr_t length = NumChildren();
+ intptr_t i = 0;
+ while (i < length) {
+ ProfileCodeTrieNode* child =
+ reinterpret_cast<ProfileCodeTrieNode*>(children_[i]);
+ if (child->table_index() == child_table_index) {
+ return child;
+ }
+ if (child->table_index() > child_table_index) {
+ break;
+ }
+ i++;
+ }
+ ProfileCodeTrieNode* child = new ProfileCodeTrieNode(child_table_index);
+ if (i < length) {
+ // Insert at i.
+ children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
+ } else {
+ // Add to end.
+ children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
}
+ return child;
}
+};
- void CreateTag(uword tag) {
- intptr_t index = tag_code_table_->FindIndex(tag);
- if (index >= 0) {
- // Already created.
- return;
- }
- CodeRegion* region = new CodeRegion(CodeRegion::kTagCode,
- tag,
- tag + 1,
- 0,
- null_code_);
- index = tag_code_table_->InsertCodeRegion(region);
- ASSERT(index >= 0);
+
+class ProfileFunctionTrieNodeCode {
+ public:
+ explicit ProfileFunctionTrieNodeCode(intptr_t index)
+ : code_index_(index),
+ ticks_(0) {
}
- void CreateUserTag(uword tag) {
- if (tag == 0) {
- // None set.
- return;
- }
- return CreateTag(tag);
- }
-
- void Tick(uword pc, bool exclusive, intptr_t serial, int64_t timestamp) {
- CodeRegionTable::TickResult r;
- if (exclusive) {
- // Exclusive ticks do not have an associated serial.
- serial = -1;
- }
-
- r = live_code_table_->Tick(pc, exclusive, serial, timestamp);
- if (r == CodeRegionTable::kTicked) {
- // Live code found and ticked.
- return;
- }
-
- if (r == CodeRegionTable::kNewerCode) {
- // Code has been overwritten by newer code.
- // Update shadow table of dead code regions.
- r = dead_code_table_->Tick(pc, exclusive, serial, timestamp);
- ASSERT(r != CodeRegionTable::kNewerCode);
- if (r == CodeRegionTable::kTicked) {
- // Dead code found and ticked.
- return;
- }
- ASSERT(r == CodeRegionTable::kNotFound);
- CreateAndTickDeadCodeRegion(pc, exclusive, serial);
- return;
- }
-
- // Create new live CodeRegion.
- ASSERT(r == CodeRegionTable::kNotFound);
- CodeRegion* region = CreateCodeRegion(pc);
- intptr_t index = live_code_table_->InsertCodeRegion(region);
- ASSERT(index >= 0);
- region = live_code_table_->At(index);
- if (region->compile_timestamp() <= timestamp) {
- region->Tick(pc, exclusive, serial);
- return;
- }
-
- // We have created a new code region but it's for a CodeRegion
- // compiled after the sample.
- ASSERT(region->kind() == CodeRegion::kDartCode);
- CreateAndTickDeadCodeRegion(pc, exclusive, serial);
- }
-
- void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) {
- // Need to create dead code.
- CodeRegion* region = new CodeRegion(CodeRegion::kReusedCode,
- pc,
- pc + 1,
- 0,
- null_code_);
- intptr_t index = dead_code_table_->InsertCodeRegion(region);
- ASSERT(index >= 0);
- dead_code_table_->At(index)->Tick(pc, exclusive, serial);
- }
-
- CodeRegion* CreateCodeRegion(uword pc) {
- const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
- const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
- Code& code = Code::Handle(isolate_);
-
- // Check current isolate for pc.
- if (isolate_->heap()->CodeContains(pc)) {
- code ^= Code::LookupCode(pc);
- if (!code.IsNull()) {
- deoptimized_code_->Add(code);
- return new CodeRegion(CodeRegion::kDartCode,
- code.EntryPoint(),
- code.EntryPoint() + code.Size(),
- code.compile_timestamp(),
- code);
- }
- return new CodeRegion(CodeRegion::kCollectedCode,
- pc,
- (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
- 0,
- code);
- }
-
- // Check VM isolate for pc.
- if (vm_isolate_->heap()->CodeContains(pc)) {
- code ^= Code::LookupCodeInVmIsolate(pc);
- if (!code.IsNull()) {
- return new CodeRegion(CodeRegion::kDartCode,
- code.EntryPoint(),
- code.EntryPoint() + code.Size(),
- code.compile_timestamp(),
- code);
- }
- return new CodeRegion(CodeRegion::kCollectedCode,
- pc,
- (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
- 0,
- code);
- }
-
- // Check NativeSymbolResolver for pc.
- uintptr_t native_start = 0;
- char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
- &native_start);
- if (native_name == NULL) {
- // No native name found.
- return new CodeRegion(CodeRegion::kNativeCode,
- pc,
- pc + 1,
- 0,
- code);
- }
- ASSERT(pc >= native_start);
- CodeRegion* code_region =
- new CodeRegion(CodeRegion::kNativeCode,
- native_start,
- pc + 1,
- 0,
- code);
- code_region->SetName(native_name);
- free(native_name);
- return code_region;
- }
-
- intptr_t frames_;
- int64_t min_time_;
- int64_t max_time_;
- CodeRegionTable* live_code_table_;
- CodeRegionTable* dead_code_table_;
- CodeRegionTable* tag_code_table_;
- Isolate* isolate_;
- Isolate* vm_isolate_;
- const Code& null_code_;
- DeoptimizedCodeSet* deoptimized_code_;
-};
-
-
-class CodeRegionFunctionMapper : public ValueObject {
- public:
- CodeRegionFunctionMapper(Isolate* isolate,
- CodeRegionTable* live_code_table,
- CodeRegionTable* dead_code_table,
- CodeRegionTable* tag_code_table,
- ProfileFunctionTable* function_table)
- : isolate_(isolate),
- live_code_table_(live_code_table),
- dead_code_table_(dead_code_table),
- tag_code_table_(tag_code_table),
- function_table_(function_table) {
- ASSERT(isolate_ != NULL);
- ASSERT(live_code_table_ != NULL);
- ASSERT(dead_code_table_ != NULL);
- ASSERT(tag_code_table_ != NULL);
- dead_code_table_offset_ = live_code_table_->Length();
- tag_code_table_offset_ = dead_code_table_offset_ +
- dead_code_table_->Length();
-
- const Code& null_code = Code::ZoneHandle();
-
- // Create the truncated tag.
- intptr_t truncated_index =
- tag_code_table_->FindIndex(VMTag::kTruncatedTagId);
- ASSERT(truncated_index < 0);
- CodeRegion* truncated =
- new CodeRegion(CodeRegion::kTagCode,
- VMTag::kTruncatedTagId,
- VMTag::kTruncatedTagId + 1,
- 0,
- null_code);
- truncated_index = tag_code_table_->InsertCodeRegion(truncated);
- ASSERT(truncated_index >= 0);
-
- // Create the root tag.
- intptr_t root_index = tag_code_table_->FindIndex(VMTag::kRootTagId);
- ASSERT(root_index < 0);
- CodeRegion* root = new CodeRegion(CodeRegion::kTagCode,
- VMTag::kRootTagId,
- VMTag::kRootTagId + 1,
- 0,
- null_code);
- root_index = tag_code_table_->InsertCodeRegion(root);
- ASSERT(root_index >= 0);
- }
-
- void Map() {
- // Calculate final indexes in code table for each CodeRegion.
- for (intptr_t i = 0; i < live_code_table_->Length(); i++) {
- const intptr_t index = i;
- CodeRegion* region = live_code_table_->At(i);
- ASSERT(region != NULL);
- region->set_code_table_index(index);
- }
-
- for (intptr_t i = 0; i < dead_code_table_->Length(); i++) {
- const intptr_t index = dead_code_table_offset_ + i;
- CodeRegion* region = dead_code_table_->At(i);
- ASSERT(region != NULL);
- region->set_code_table_index(index);
- }
-
- for (intptr_t i = 0; i < tag_code_table_->Length(); i++) {
- const intptr_t index = tag_code_table_offset_ + i;
- CodeRegion* region = tag_code_table_->At(i);
- ASSERT(region != NULL);
- region->set_code_table_index(index);
- }
-
- // Associate a ProfileFunction with each CodeRegion.
- for (intptr_t i = 0; i < live_code_table_->Length(); i++) {
- CodeRegion* region = live_code_table_->At(i);
- ASSERT(region != NULL);
- region->SetFunctionAndName(function_table_);
- }
-
- for (intptr_t i = 0; i < dead_code_table_->Length(); i++) {
- CodeRegion* region = dead_code_table_->At(i);
- ASSERT(region != NULL);
- region->SetFunctionAndName(function_table_);
- }
-
- for (intptr_t i = 0; i < tag_code_table_->Length(); i++) {
- CodeRegion* region = tag_code_table_->At(i);
- ASSERT(region != NULL);
- region->SetFunctionAndName(function_table_);
- }
- }
-
- private:
- Isolate* isolate_;
- CodeRegionTable* live_code_table_;
- CodeRegionTable* dead_code_table_;
- CodeRegionTable* tag_code_table_;
- ProfileFunctionTable* function_table_;
- intptr_t dead_code_table_offset_;
- intptr_t tag_code_table_offset_;
-};
-
-
-class ProfileFunctionTrieNodeCode {
- public:
- explicit ProfileFunctionTrieNodeCode(intptr_t index)
- : code_index_(index),
- ticks_(0) {
- }
-
- intptr_t index() const {
- return code_index_;
+ intptr_t index() const {
+ return code_index_;
}
void Tick() {
@@ -1299,56 +852,65 @@ class ProfileFunctionTrieNodeCode {
};
-class ProfileFunctionTrieNode : public ZoneAllocated {
+class ProfileFunctionTrieNode : public ProfileTrieNode {
public:
- explicit ProfileFunctionTrieNode(intptr_t profile_function_table_index)
- : profile_function_table_index_(profile_function_table_index),
- count_(0),
- code_objects_(new ZoneGrowableArray<ProfileFunctionTrieNodeCode>()) {
+ explicit ProfileFunctionTrieNode(intptr_t table_index)
+ : ProfileTrieNode(table_index),
+ code_objects_(1) {
}
- void Tick() {
- count_++;
- }
-
- intptr_t count() const {
- return count_;
- }
-
- intptr_t profile_function_table_index() const {
- return profile_function_table_index_;
+ void PrintToJSONArray(JSONArray* array) const {
+ ASSERT(array != NULL);
+ // Write CodeRegion index.
+ array->AddValue(table_index());
+ // Write count.
+ array->AddValue(count());
+ // Write number of code objects.
+ intptr_t code_count = code_objects_.length();
+ array->AddValue(code_count);
+ // Write each code object index and ticks.
+ for (intptr_t i = 0; i < code_count; i++) {
+ array->AddValue(code_objects_[i].index());
+ array->AddValue(code_objects_[i].ticks());
+ }
+ // Write number of children.
+ intptr_t child_count = children_.length();
+ array->AddValue(child_count);
+ // Recurse.
+ for (intptr_t i = 0; i < child_count; i++) {
+ children_[i]->PrintToJSONArray(array);
+ }
}
-
- ProfileFunctionTrieNode* GetChild(intptr_t child_index) {
- const intptr_t length = children_.length();
+ ProfileFunctionTrieNode* GetChild(intptr_t child_table_index) {
+ const intptr_t length = NumChildren();
intptr_t i = 0;
while (i < length) {
- ProfileFunctionTrieNode* child = children_[i];
- if (child->profile_function_table_index() == child_index) {
+ ProfileFunctionTrieNode* child =
+ reinterpret_cast<ProfileFunctionTrieNode*>(children_[i]);
+ if (child->table_index() == child_table_index) {
return child;
}
- if (child->profile_function_table_index() > child_index) {
+ if (child->table_index() > child_table_index) {
break;
}
i++;
}
- // Add new ProfileFunctionTrieNode, sorted by index.
ProfileFunctionTrieNode* child =
- new ProfileFunctionTrieNode(child_index);
+ new ProfileFunctionTrieNode(child_table_index);
if (i < length) {
// Insert at i.
- children_.InsertAt(i, child);
+ children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
} else {
// Add to end.
- children_.Add(child);
+ children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
}
return child;
}
void AddCodeObjectIndex(intptr_t index) {
- for (intptr_t i = 0; i < code_objects_->length(); i++) {
- ProfileFunctionTrieNodeCode& code_object = (*code_objects_)[i];
+ for (intptr_t i = 0; i < code_objects_.length(); i++) {
+ ProfileFunctionTrieNodeCode& code_object = code_objects_[i];
if (code_object.index() == index) {
code_object.Tick();
return;
@@ -1356,414 +918,361 @@ class ProfileFunctionTrieNode : public ZoneAllocated {
}
ProfileFunctionTrieNodeCode code_object(index);
code_object.Tick();
- code_objects_->Add(code_object);
+ code_objects_.Add(code_object);
}
- // This should only be called after the trie is completely built.
- void SortByCount() {
- code_objects_->Sort(ProfileFunctionTrieNodeCodeCompare);
- children_.Sort(ProfileFunctionTrieNodeCompare);
- intptr_t child_count = children_.length();
- // Recurse.
- for (intptr_t i = 0; i < child_count; i++) {
- children_[i]->SortByCount();
- }
+ private:
+ ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_;
+};
+
+
+class ProfileBuilder : public ValueObject {
+ public:
+ ProfileBuilder(Isolate* isolate,
+ SampleFilter* filter,
+ Profile::TagOrder tag_order,
+ Profile* profile)
+ : isolate_(isolate),
+ vm_isolate_(Dart::vm_isolate()),
+ filter_(filter),
+ tag_order_(tag_order),
+ profile_(profile),
+ deoptimized_code_(new DeoptimizedCodeSet(isolate)),
+ null_code_(Code::ZoneHandle()),
+ null_function_(Function::ZoneHandle()),
+ tick_functions_(false),
+ samples_(NULL) {
+ ASSERT(profile_ != NULL);
}
- void PrintToJSONArray(JSONArray* array) const {
- ASSERT(array != NULL);
- // Write CodeRegion index.
- array->AddValue(profile_function_table_index_);
- // Write count.
- array->AddValue(count_);
- // Write number of code objects.
- intptr_t code_count = code_objects_->length();
- array->AddValue(code_count);
- // Write each code object index and ticks.
- for (intptr_t i = 0; i < code_count; i++) {
- array->AddValue((*code_objects_)[i].index());
- array->AddValue((*code_objects_)[i].ticks());
- }
- // Write number of children.
- intptr_t child_count = children_.length();
- array->AddValue(child_count);
- // Recurse.
- for (intptr_t i = 0; i < child_count; i++) {
- children_[i]->PrintToJSONArray(array);
- }
+ void Build() {
+ ScopeTimer sw("ProfileBuilder::Build", FLAG_trace_profiler);
+ FilterSamples();
+
+ Setup();
+ BuildCodeTable();
+ FinalizeCodeIndexes();
+ BuildFunctionTable();
+
+ BuildCodeTrie(Profile::kExclusiveCode);
+ BuildCodeTrie(Profile::kInclusiveCode);
+
+ BuildFunctionTrie(Profile::kExclusiveFunction);
+ BuildFunctionTrie(Profile::kInclusiveFunction);
}
private:
- static int ProfileFunctionTrieNodeCodeCompare(
- const ProfileFunctionTrieNodeCode* a,
- const ProfileFunctionTrieNodeCode* b) {
- ASSERT(a != NULL);
- ASSERT(b != NULL);
- return b->ticks() - a->ticks();
+ static bool IsInclusiveTrie(Profile::TrieKind kind) {
+ return (kind == Profile::kInclusiveFunction) ||
+ (kind == Profile::kInclusiveCode);
+ }
+
+ void Setup() {
+ profile_->live_code_ = new ProfileCodeTable();
+ profile_->dead_code_ = new ProfileCodeTable();
+ profile_->tag_code_ = new ProfileCodeTable();
+ profile_->functions_ = new ProfileFunctionTable();
+ // Register some synthetic tags.
+ RegisterProfileCodeTag(VMTag::kRootTagId);
+ RegisterProfileCodeTag(VMTag::kTruncatedTagId);
+ }
+
+ void FilterSamples() {
+ ScopeTimer sw("ProfileBuilder::FilterSamples", FLAG_trace_profiler);
+ MutexLocker profiler_data_lock(isolate_->profiler_data_mutex());
+ IsolateProfilerData* profiler_data = isolate_->profiler_data();
+ if (profiler_data == NULL) {
+ return;
+ }
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
+ }
+ samples_ = sample_buffer->BuildProcessedSampleBuffer(filter_);
+ profile_->sample_count_ = samples_->length();
}
- static int ProfileFunctionTrieNodeCompare(ProfileFunctionTrieNode* const* a,
- ProfileFunctionTrieNode* const* b) {
- ASSERT(a != NULL);
- ASSERT(b != NULL);
- return (*b)->count() - (*a)->count();
+ void UpdateMinMaxTimes(int64_t timestamp) {
+ profile_->min_time_ =
+ timestamp < profile_->min_time_ ? timestamp : profile_->min_time_;
+ profile_->max_time_ =
+ timestamp > profile_->max_time_ ? timestamp : profile_->max_time_;
}
- const intptr_t profile_function_table_index_;
- intptr_t count_;
- ZoneGrowableArray<ProfileFunctionTrieNode*> children_;
- ZoneGrowableArray<ProfileFunctionTrieNodeCode>* code_objects_;
-};
+ void BuildCodeTable() {
+ ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler);
+ for (intptr_t i = 0; i < samples_->length(); i++) {
+ ProcessedSample* sample = samples_->At(i);
+ const int64_t timestamp = sample->timestamp();
+ // This is our first pass over the sample buffer, use this as an
+ // opportunity to determine the min and max time ranges of this profile.
+ UpdateMinMaxTimes(timestamp);
-class TrieBuilder : public ValueObject {
- public:
- TrieBuilder(CodeRegionTable* live_code_table,
- CodeRegionTable* dead_code_table,
- CodeRegionTable* tag_code_table)
- : live_code_table_(live_code_table),
- dead_code_table_(dead_code_table),
- tag_code_table_(tag_code_table) {
- ASSERT(live_code_table_ != NULL);
- ASSERT(dead_code_table_ != NULL);
- ASSERT(tag_code_table_ != NULL);
- }
-
- ProfilerService::TagOrder tag_order() const {
- return tag_order_;
+ // Make sure VM tag exists.
+ if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
+ RegisterProfileCodeTag(VMTag::kNativeTagId);
+ } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
+ RegisterProfileCodeTag(VMTag::kRuntimeTagId);
+ }
+ RegisterProfileCodeTag(sample->vm_tag());
+ // Make sure user tag exists.
+ RegisterProfileCodeTag(sample->user_tag());
+
+ // Make sure that a ProfileCode objects exist for all pcs in the sample
+ // and tick each one.
+ for (intptr_t i = 0; i < sample->length(); i++) {
+ const uword pc = sample->At(i);
+ ASSERT(pc != 0);
+ ProfileCode* code = RegisterProfileCode(pc, timestamp);
+ ASSERT(code != NULL);
+ code->Tick(pc, (i == 0), i);
+ }
+ }
}
- void set_tag_order(ProfilerService::TagOrder tag_order) {
- tag_order_ = tag_order;
- }
+ void FinalizeCodeIndexes() {
+ ScopeTimer sw("ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler);
+ ProfileCodeTable* live_table = profile_->live_code_;
+ ProfileCodeTable* dead_table = profile_->dead_code_;
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ const intptr_t dead_code_index_offset = live_table->length();
+ const intptr_t tag_code_index_offset =
+ dead_table->length() + dead_code_index_offset;
- protected:
- intptr_t FindTagIndex(uword tag) const {
- if (tag == 0) {
- UNREACHABLE();
- return -1;
+ profile_->dead_code_index_offset_ = dead_code_index_offset;
+ profile_->tag_code_index_offset_ = tag_code_index_offset;
+
+ for (intptr_t i = 0; i < live_table->length(); i++) {
+ const intptr_t index = i;
+ ProfileCode* code = live_table->At(i);
+ ASSERT(code != NULL);
+ code->set_code_table_index(index);
}
- intptr_t index = tag_code_table_->FindIndex(tag);
- if (index < 0) {
- UNREACHABLE();
- return -1;
+
+ for (intptr_t i = 0; i < dead_table->length(); i++) {
+ const intptr_t index = dead_code_index_offset + i;
+ ProfileCode* code = dead_table->At(i);
+ ASSERT(code != NULL);
+ code->set_code_table_index(index);
}
- ASSERT(index >= 0);
- CodeRegion* region = tag_code_table_->At(index);
- ASSERT(region->contains(tag));
- return region->code_table_index();
- }
- intptr_t FindDeadIndex(uword pc, int64_t timestamp) const {
- intptr_t index = dead_code_table_->FindIndex(pc);
- if (index < 0) {
- OS::Print("%" Px " cannot be found\n", pc);
- return -1;
+ for (intptr_t i = 0; i < tag_table->length(); i++) {
+ const intptr_t index = tag_code_index_offset + i;
+ ProfileCode* code = tag_table->At(i);
+ ASSERT(code != NULL);
+ code->set_code_table_index(index);
}
- CodeRegion* region = dead_code_table_->At(index);
- ASSERT(region->contains(pc));
- ASSERT(region->compile_timestamp() <= timestamp);
- return region->code_table_index();
}
- intptr_t FindFinalIndex(uword pc, int64_t timestamp) const {
- intptr_t index = live_code_table_->FindIndex(pc);
- if (index < 0) {
- // Try dead code table.
- return FindDeadIndex(pc, timestamp);
+ void BuildFunctionTable() {
+ ScopeTimer sw("ProfileBuilder::BuildFunctionTable", FLAG_trace_profiler);
+ ProfileCodeTable* live_table = profile_->live_code_;
+ ProfileCodeTable* dead_table = profile_->dead_code_;
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ ProfileFunctionTable* function_table = profile_->functions_;
+ for (intptr_t i = 0; i < live_table->length(); i++) {
+ ProfileCode* code = live_table->At(i);
+ ASSERT(code != NULL);
+ code->SetFunctionAndName(function_table);
}
- CodeRegion* region = live_code_table_->At(index);
- ASSERT(region->contains(pc));
- if (region->compile_timestamp() > timestamp) {
- // Overwritten code, find in dead code table.
- return FindDeadIndex(pc, timestamp);
+
+ for (intptr_t i = 0; i < dead_table->length(); i++) {
+ ProfileCode* code = dead_table->At(i);
+ ASSERT(code != NULL);
+ code->SetFunctionAndName(function_table);
}
- ASSERT(region->compile_timestamp() <= timestamp);
- return region->code_table_index();
- }
- bool vm_tags_emitted() const {
- return (tag_order_ == ProfilerService::kUserVM) ||
- (tag_order_ == ProfilerService::kVMUser) ||
- (tag_order_ == ProfilerService::kVM);
+ for (intptr_t i = 0; i < tag_table->length(); i++) {
+ ProfileCode* code = tag_table->At(i);
+ ASSERT(code != NULL);
+ code->SetFunctionAndName(function_table);
+ }
}
- CodeRegion* FindCodeObject(uword pc, int64_t timestamp) const {
- intptr_t index = live_code_table_->FindIndex(pc);
- if (index < 0) {
- return NULL;
- }
- CodeRegion* region = live_code_table_->At(index);
- ASSERT(region->contains(pc));
- if (region->compile_timestamp() > timestamp) {
- // Overwritten code, find in dead code table.
- index = dead_code_table_->FindIndex(pc);
- if (index < 0) {
- return NULL;
- }
- region = dead_code_table_->At(index);
- ASSERT(region->contains(pc));
- ASSERT(region->compile_timestamp() <= timestamp);
- return region;
+ void BuildCodeTrie(Profile::TrieKind kind) {
+ ProfileCodeTrieNode* root =
+ new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId));
+ if (IsInclusiveTrie(kind)) {
+ BuildInclusiveCodeTrie(root);
+ } else {
+ BuildExclusiveCodeTrie(root);
}
- ASSERT(region->compile_timestamp() <= timestamp);
- return region;
+ root->SortChildren();
+ profile_->roots_[static_cast<intptr_t>(kind)] = root;
}
- CodeRegionTable* live_code_table_;
- CodeRegionTable* dead_code_table_;
- CodeRegionTable* tag_code_table_;
- ProfilerService::TagOrder tag_order_;
-};
+ void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) {
+ ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie",
+ FLAG_trace_profiler);
+ for (intptr_t i = 0; i < samples_->length(); i++) {
+ ProcessedSample* sample = samples_->At(i);
+ // Tick the root.
+ ProfileCodeTrieNode* current = root;
+ current->Tick();
-class ProfileFunctionTrieBuilder : public TrieBuilder {
- public:
- ProfileFunctionTrieBuilder(CodeRegionTable* live_code_table,
- CodeRegionTable* dead_code_table,
- CodeRegionTable* tag_code_table,
- ProfileFunctionTable* function_table)
- : TrieBuilder(live_code_table, dead_code_table, tag_code_table),
- function_table_(function_table),
- inclusive_tree_(false) {
- ASSERT(function_table_ != NULL);
- set_tag_order(ProfilerService::kUserVM);
-
- // Verify that the truncated tag exists.
- ASSERT(tag_code_table_->FindIndex(VMTag::kTruncatedTagId) >= 0);
-
- // Verify that the root tag exists.
- intptr_t root_index = tag_code_table_->FindIndex(VMTag::kRootTagId);
- ASSERT(root_index >= 0);
-
- // Setup root.
- CodeRegion* region = tag_code_table_->At(root_index);
- ASSERT(region != NULL);
- ProfileFunction* function = region->function();
- ASSERT(function != NULL);
-
- exclusive_root_ = new ProfileFunctionTrieNode(function->index());
- inclusive_root_ = new ProfileFunctionTrieNode(function->index());
- }
+ // VM & User tags.
+ current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
- void VisitSample(intptr_t sample_idx, ProcessedSample* sample) {
- inclusive_tree_ = false;
- ProcessSampleExclusive(sample_idx, sample);
- inclusive_tree_ = true;
- ProcessSampleInclusive(sample_idx, sample);
- }
+ // Truncated tag.
+ if (sample->truncated()) {
+ current = AppendTruncatedTag(current);
+ }
- void Build(ProcessedSampleBuffer* buffer) {
- for (intptr_t i = 0; i < buffer->length(); i++) {
- ProcessedSample* sample = buffer->At(i);
- VisitSample(i, sample);
+ // Walk the sampled PCs.
+ for (intptr_t j = sample->length() - 1; j >= 0; j--) {
+ ASSERT(sample->At(j) != 0);
+ intptr_t index =
+ GetProfileCodeIndex(sample->At(j), sample->timestamp());
+ ASSERT(index >= 0);
+ current = current->GetChild(index);
+ current->Tick();
+ }
}
}
- ProfileFunctionTrieNode* exclusive_root() const {
- return exclusive_root_;
- }
+ void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) {
+ ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie",
+ FLAG_trace_profiler);
+ for (intptr_t i = 0; i < samples_->length(); i++) {
+ ProcessedSample* sample = samples_->At(i);
- ProfileFunctionTrieNode* inclusive_root() const {
- return inclusive_root_;
- }
+ // Tick the root.
+ ProfileCodeTrieNode* current = root;
+ current->Tick();
- ProfilerService::TagOrder tag_order() const {
- return tag_order_;
- }
+ // VM & User tags.
+ current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
+
+ // Walk the sampled PCs.
+ for (intptr_t j = 0; j < sample->length(); j++) {
+ ASSERT(sample->At(j) != 0);
+ intptr_t index =
+ GetProfileCodeIndex(sample->At(j), sample->timestamp());
+ ASSERT(index >= 0);
+ current = current->GetChild(index);
+
+ if (j == 0) {
+ // Executing PC.
+ if (!sample->first_frame_executing() || vm_tags_emitted()) {
+ // Only tick if this isn't an exit frame or VM tags are emitted.
+ current->Tick();
+ }
+ } else {
+ // Caller PCs.
+ current->Tick();
+ }
- bool vm_tags_emitted() const {
- return (tag_order_ == ProfilerService::kUserVM) ||
- (tag_order_ == ProfilerService::kVMUser) ||
- (tag_order_ == ProfilerService::kVM);
- }
+ current->Tick();
+ }
- void set_tag_order(ProfilerService::TagOrder tag_order) {
- tag_order_ = tag_order;
+ // Truncated tag.
+ if (sample->truncated()) {
+ current = AppendTruncatedTag(current);
+ }
+ }
}
- private:
- void ProcessSampleInclusive(intptr_t sample_idx, ProcessedSample* sample) {
- // Give the root a tick.
- inclusive_root_->Tick();
- ProfileFunctionTrieNode* current = inclusive_root_;
- current = AppendTags(sample, current);
- if (sample->truncated()) {
- InclusiveTickTruncatedTag();
- current = AppendTruncatedTag(current);
- }
- // Walk the sampled PCs.
- for (intptr_t i = sample->length() - 1; i >= 0; i--) {
- ASSERT(sample->At(i) != 0);
- current = ProcessPC(sample->At(i),
- sample->timestamp(),
- current,
- sample_idx,
- (i == 0),
- !sample->first_frame_executing() && (i == 0));
- }
- }
-
- void ProcessSampleExclusive(intptr_t sample_idx, ProcessedSample* sample) {
- // Give the root a tick.
- exclusive_root_->Tick();
- ProfileFunctionTrieNode* current = exclusive_root_;
- current = AppendTags(sample, current);
- // Walk the sampled PCs.
- for (intptr_t i = 0; i < sample->length(); i++) {
- ASSERT(sample->At(i) != 0);
- current = ProcessPC(sample->At(i),
- sample->timestamp(),
- current,
- sample_idx,
- (i == 0),
- !sample->first_frame_executing() && (i == 0));
- }
- if (sample->truncated()) {
- current = AppendTruncatedTag(current);
- }
- }
-
- ProfileFunctionTrieNode* AppendUserTag(ProcessedSample* sample,
- ProfileFunctionTrieNode* current) {
- intptr_t user_tag_index = FindTagFunctionIndex(sample->user_tag());
- if (user_tag_index >= 0) {
- current = current->GetChild(user_tag_index);
- // Give the tag a tick.
- current->Tick();
+ void BuildFunctionTrie(Profile::TrieKind kind) {
+ ProfileFunctionTrieNode* root =
+ new ProfileFunctionTrieNode(
+ GetProfileFunctionTagIndex(VMTag::kRootTagId));
+ // We tick the functions while building the trie, but, we don't want to do
+ // it for both tries, just one.
+ tick_functions_ = IsInclusiveTrie(kind);
+ if (IsInclusiveTrie(kind)) {
+ BuildInclusiveFunctionTrie(root);
+ } else {
+ BuildExclusiveFunctionTrie(root);
}
- return current;
+ root->SortChildren();
+ profile_->roots_[static_cast<intptr_t>(kind)] = root;
}
+ void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
+ ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie",
+ FLAG_trace_profiler);
+ for (intptr_t i = 0; i < samples_->length(); i++) {
+ ProcessedSample* sample = samples_->At(i);
- ProfileFunctionTrieNode* AppendTruncatedTag(
- ProfileFunctionTrieNode* current) {
- intptr_t truncated_tag_index = FindTagFunctionIndex(VMTag::kTruncatedTagId);
- ASSERT(truncated_tag_index >= 0);
- current = current->GetChild(truncated_tag_index);
- current->Tick();
- return current;
- }
+ // Tick the root.
+ ProfileFunctionTrieNode* current = root;
+ current->Tick();
- void InclusiveTickTruncatedTag() {
- intptr_t index = tag_code_table_->FindIndex(VMTag::kTruncatedTagId);
- CodeRegion* region = tag_code_table_->At(index);
- ProfileFunction* function = region->function();
- function->inc_inclusive_ticks();
- }
+ // VM & User tags.
+ current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
- ProfileFunctionTrieNode* AppendVMTag(ProcessedSample* sample,
- ProfileFunctionTrieNode* current) {
- if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
- // Insert a dummy kNativeTagId node.
- intptr_t tag_index = FindTagFunctionIndex(VMTag::kNativeTagId);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick();
- } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
- // Insert a dummy kRuntimeTagId node.
- intptr_t tag_index = FindTagFunctionIndex(VMTag::kRuntimeTagId);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick();
- } else {
- intptr_t tag_index = FindTagFunctionIndex(sample->vm_tag());
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick();
- }
- return current;
- }
+ // Truncated tag.
+ if (sample->truncated()) {
+ current = AppendTruncatedTag(current);
+ InclusiveTickTruncatedTag();
+ }
- ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
- ProcessedSample* sample, ProfileFunctionTrieNode* current) {
- // Only Native and Runtime entries have a second VM tag.
- if (!VMTag::IsNativeEntryTag(sample->vm_tag()) &&
- !VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
- return current;
+ // Walk the sampled PCs.
+ for (intptr_t j = sample->length() - 1; j >= 0; j--) {
+ ASSERT(sample->At(j) != 0);
+ current = ProcessFunctionPC(
+ sample->At(j),
+ sample->timestamp(),
+ current,
+ i,
+ (j == 0),
+ sample->first_frame_executing(),
+ true);
+ }
}
- intptr_t tag_index = FindTagFunctionIndex(sample->vm_tag());
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick();
- return current;
}
- ProfileFunctionTrieNode* AppendVMTags(ProcessedSample* sample,
- ProfileFunctionTrieNode* current) {
- current = AppendVMTag(sample, current);
- current = AppendSpecificNativeRuntimeEntryVMTag(sample, current);
- return current;
- }
+ void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
+ ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie",
+ FLAG_trace_profiler);
+ for (intptr_t i = 0; i < samples_->length(); i++) {
+ ProcessedSample* sample = samples_->At(i);
- ProfileFunctionTrieNode* AppendTags(ProcessedSample* sample,
- ProfileFunctionTrieNode* current) {
- // None.
- if (tag_order() == ProfilerService::kNoTags) {
- return current;
- }
- // User first.
- if ((tag_order() == ProfilerService::kUserVM) ||
- (tag_order() == ProfilerService::kUser)) {
- current = AppendUserTag(sample, current);
- // Only user.
- if (tag_order() == ProfilerService::kUser) {
- return current;
+ // Tick the root.
+ ProfileFunctionTrieNode* current = root;
+ current->Tick();
+
+ // VM & User tags.
+ current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
+
+ // Walk the sampled PCs.
+ for (intptr_t j = 0; j < sample->length(); j++) {
+ ASSERT(sample->At(j) != 0);
+ current = ProcessFunctionPC(
+ sample->At(j),
+ sample->timestamp(),
+ current,
+ i,
+ (j == 0),
+ sample->first_frame_executing(),
+ false);
}
- return AppendVMTags(sample, current);
- }
- // VM first.
- ASSERT((tag_order() == ProfilerService::kVMUser) ||
- (tag_order() == ProfilerService::kVM));
- current = AppendVMTags(sample, current);
- // Only VM.
- if (tag_order() == ProfilerService::kVM) {
- return current;
- }
- return AppendUserTag(sample, current);
- }
- intptr_t FindTagFunctionIndex(uword tag) const {
- if (tag == 0) {
- UNREACHABLE();
- return -1;
- }
- intptr_t index = tag_code_table_->FindIndex(tag);
- if (index < 0) {
- UNREACHABLE();
- return -1;
+ // Truncated tag.
+ if (sample->truncated()) {
+ current = AppendTruncatedTag(current);
+ }
}
- ASSERT(index >= 0);
- CodeRegion* region = tag_code_table_->At(index);
- ASSERT(region->contains(tag));
- ProfileFunction* function = region->function();
- ASSERT(function != NULL);
- return function->index();
- }
-
- void Dump(ProfileFunctionTrieNode* current) {
- int current_index = current->profile_function_table_index();
- ProfileFunction* function = function_table_->At(current_index);
- function->Dump();
- OS::Print("\n");
}
- ProfileFunctionTrieNode* ProcessPC(uword pc,
- int64_t timestamp,
- ProfileFunctionTrieNode* current,
- intptr_t inclusive_serial,
- bool top_frame,
- bool exit_frame) {
- CodeRegion* region = FindCodeObject(pc, timestamp);
- if (region == NULL) {
- return current;
- }
- const char* region_name = region->name();
- if (region_name == NULL) {
- region_name = "";
- }
- intptr_t code_index = region->code_table_index();
- const Code& code = Code::ZoneHandle(region->code());
+ ProfileFunctionTrieNode* ProcessFunctionPC(
+ uword pc,
+ int64_t timestamp,
+ ProfileFunctionTrieNode* current,
+ intptr_t inclusive_serial,
+ bool top_frame,
+ bool top_frame_executing,
+ bool inclusive_tree) {
+ ProfileCode* profile_code = GetProfileCode(pc, timestamp);
+ ASSERT(profile_code != NULL);
+ const char* code_name = profile_code->name();
+ if (code_name == NULL) {
+ code_name = "";
+ }
+ intptr_t code_index = profile_code->code_table_index();
+ const Code& code = Code::ZoneHandle(profile_code->code());
GrowableArray<Function*> inlined_functions;
if (!code.IsNull()) {
intptr_t offset = pc - code.EntryPoint();
@@ -1771,18 +1280,18 @@ class ProfileFunctionTrieBuilder : public TrieBuilder {
}
if (code.IsNull() || (inlined_functions.length() == 0)) {
// No inlined functions.
- ProfileFunction* function = region->function();
+ ProfileFunction* function = profile_code->function();
ASSERT(function != NULL);
current = ProcessFunction(function,
current,
inclusive_serial,
top_frame,
- exit_frame,
+ top_frame_executing,
code_index);
return current;
}
- if (inclusive_tree_) {
+ if (inclusive_tree) {
for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) {
Function* inlined_function = inlined_functions[i];
ASSERT(inlined_function != NULL);
@@ -1791,7 +1300,7 @@ class ProfileFunctionTrieBuilder : public TrieBuilder {
current,
inclusive_serial,
top_frame,
- exit_frame,
+ top_frame_executing,
code_index);
top_frame = false;
}
@@ -1804,7 +1313,7 @@ class ProfileFunctionTrieBuilder : public TrieBuilder {
current,
inclusive_serial,
top_frame,
- exit_frame,
+ top_frame_executing,
code_index);
top_frame = false;
}
@@ -1818,16 +1327,16 @@ class ProfileFunctionTrieBuilder : public TrieBuilder {
ProfileFunctionTrieNode* current,
intptr_t inclusive_serial,
bool top_frame,
- bool exit_frame,
+ bool top_frame_executing,
intptr_t code_index) {
- ProfileFunction* function =
- function_table_->LookupOrAdd(*inlined_function);
+ ProfileFunctionTable* function_table = profile_->functions_;
+ ProfileFunction* function = function_table->LookupOrAdd(*inlined_function);
ASSERT(function != NULL);
return ProcessFunction(function,
current,
inclusive_serial,
top_frame,
- exit_frame,
+ top_frame_executing,
code_index);
}
@@ -1835,254 +1344,171 @@ class ProfileFunctionTrieBuilder : public TrieBuilder {
ProfileFunctionTrieNode* current,
intptr_t inclusive_serial,
bool top_frame,
- bool exit_frame,
- intptr_t code_index) {
- const bool exclusive = top_frame && !exit_frame;
- if (!inclusive_tree_) {
- // We process functions for the inclusive and exclusive trees.
- // Only tick the function for the exclusive tree.
- function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
- }
- function->AddCodeObjectIndex(code_index);
- current = current->GetChild(function->index());
- current->AddCodeObjectIndex(code_index);
- if (top_frame) {
- if (!exit_frame || vm_tags_emitted()) {
- // Only tick if this isn't an exit frame or VM tags are emitted.
- current->Tick();
- }
- } else {
- current->Tick();
- }
- return current;
- }
-
- ProfileFunctionTrieNode* exclusive_root_;
- ProfileFunctionTrieNode* inclusive_root_;
- ProfileFunctionTable* function_table_;
- bool inclusive_tree_;
-};
-
-
-class CodeRegionTrieNode : public ZoneAllocated {
- public:
- explicit CodeRegionTrieNode(intptr_t code_region_index)
- : code_region_index_(code_region_index),
- count_(0),
- children_(new ZoneGrowableArray<CodeRegionTrieNode*>()) {
- }
-
- void Tick() {
- ASSERT(code_region_index_ >= 0);
- count_++;
- }
-
- intptr_t count() const {
- ASSERT(code_region_index_ >= 0);
- return count_;
- }
-
- intptr_t code_region_index() const {
- return code_region_index_;
- }
-
- ZoneGrowableArray<CodeRegionTrieNode*>& children() const {
- return *children_;
- }
-
- CodeRegionTrieNode* GetChild(intptr_t child_code_region_index) {
- const intptr_t length = children_->length();
- intptr_t i = 0;
- while (i < length) {
- CodeRegionTrieNode* child = (*children_)[i];
- if (child->code_region_index() == child_code_region_index) {
- return child;
- }
- if (child->code_region_index() > child_code_region_index) {
- break;
- }
- i++;
- }
- // Add new CodeRegion, sorted by CodeRegionTable index.
- CodeRegionTrieNode* child = new CodeRegionTrieNode(child_code_region_index);
- if (i < length) {
- // Insert at i.
- children_->InsertAt(i, child);
- } else {
- // Add to end.
- children_->Add(child);
- }
- return child;
- }
-
- // This should only be called after the trie is completely built.
- void SortByCount() {
- children_->Sort(CodeRegionTrieNodeCompare);
- ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
- intptr_t child_count = kids.length();
- // Recurse.
- for (intptr_t i = 0; i < child_count; i++) {
- kids[i]->SortByCount();
- }
- }
-
- void PrintToJSONArray(JSONArray* array) const {
- ASSERT(array != NULL);
- // Write CodeRegion index.
- array->AddValue(code_region_index_);
- // Write count.
- array->AddValue(count_);
- // Write number of children.
- ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
- intptr_t child_count = kids.length();
- array->AddValue(child_count);
- // Recurse.
- for (intptr_t i = 0; i < child_count; i++) {
- kids[i]->PrintToJSONArray(array);
+ bool top_frame_executing,
+ intptr_t code_index) {
+ const bool exclusive = top_frame && top_frame_executing;
+ if (tick_functions_) {
+ function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
+ }
+ function->AddProfileCode(code_index);
+ current = current->GetChild(function->table_index());
+ current->AddCodeObjectIndex(code_index);
+ if (top_frame) {
+ if (top_frame_executing || vm_tags_emitted()) {
+ // Only tick if this function is using CPU time or VM tags are emitted.
+ current->Tick();
+ }
+ } else {
+ current->Tick();
}
+ return current;
}
- private:
- static int CodeRegionTrieNodeCompare(CodeRegionTrieNode* const* a,
- CodeRegionTrieNode* const* b) {
- ASSERT(a != NULL);
- ASSERT(b != NULL);
- return (*b)->count() - (*a)->count();
+ // Tick the truncated tag's inclusive tick count.
+ void InclusiveTickTruncatedTag() {
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ intptr_t index = tag_table->FindCodeIndexForPC(VMTag::kTruncatedTagId);
+ ASSERT(index >= 0);
+ ProfileCode* code = tag_table->At(index);
+ code->IncInclusiveTicks();
+ ASSERT(code != NULL);
+ ProfileFunction* function = code->function();
+ function->IncInclusiveTicks();
}
- const intptr_t code_region_index_;
- intptr_t count_;
- ZoneGrowableArray<CodeRegionTrieNode*>* children_;
-};
-
-
-class CodeRegionTrieBuilder : public TrieBuilder {
- public:
- CodeRegionTrieBuilder(Isolate* isolate,
- CodeRegionTable* live_code_table,
- CodeRegionTable* dead_code_table,
- CodeRegionTable* tag_code_table)
- : TrieBuilder(live_code_table, dead_code_table, tag_code_table) {
- set_tag_order(ProfilerService::kUserVM);
- // Verify that the truncated tag exists.
- ASSERT(tag_code_table_->FindIndex(VMTag::kTruncatedTagId) >= 0);
+ // Tag append functions are overloaded for |ProfileCodeTrieNode| and
+ // |ProfileFunctionTrieNode| types.
- // Verify that the root tag exists.
- intptr_t root_index = tag_code_table_->FindIndex(VMTag::kRootTagId);
- ASSERT(root_index >= 0);
- CodeRegion* region = tag_code_table_->At(root_index);
- ASSERT(region != NULL);
+ // ProfileCodeTrieNode
+ ProfileCodeTrieNode* AppendUserTag(uword user_tag,
+ ProfileCodeTrieNode* current) {
+ intptr_t user_tag_index = GetProfileCodeTagIndex(user_tag);
+ if (user_tag_index >= 0) {
+ current = current->GetChild(user_tag_index);
+ current->Tick();
+ }
+ return current;
+ }
- exclusive_root_ = new CodeRegionTrieNode(region->code_table_index());
- inclusive_root_ = new CodeRegionTrieNode(region->code_table_index());
+ ProfileCodeTrieNode* AppendTruncatedTag(ProfileCodeTrieNode* current) {
+ intptr_t truncated_tag_index =
+ GetProfileCodeTagIndex(VMTag::kTruncatedTagId);
+ ASSERT(truncated_tag_index >= 0);
+ current = current->GetChild(truncated_tag_index);
+ current->Tick();
+ return current;
}
- void Build(ProcessedSampleBuffer* buffer) {
- for (intptr_t i = 0; i < buffer->length(); i++) {
- ProcessedSample* sample = buffer->At(i);
- VisitSample(sample);
+ ProfileCodeTrieNode* AppendVMTag(uword vm_tag,
+ ProfileCodeTrieNode* current) {
+ if (VMTag::IsNativeEntryTag(vm_tag)) {
+ // Insert a dummy kNativeTagId node.
+ intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kNativeTagId);
+ current = current->GetChild(tag_index);
+ // Give the tag a tick.
+ current->Tick();
+ } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
+ // Insert a dummy kRuntimeTagId node.
+ intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kRuntimeTagId);
+ current = current->GetChild(tag_index);
+ // Give the tag a tick.
+ current->Tick();
+ } else {
+ intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
+ current = current->GetChild(tag_index);
+ // Give the tag a tick.
+ current->Tick();
}
+ return current;
}
- CodeRegionTrieNode* inclusive_root() const {
- return inclusive_root_;
+ ProfileCodeTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
+ uword vm_tag, ProfileCodeTrieNode* current) {
+ // Only Native and Runtime entries have a second VM tag.
+ if (!VMTag::IsNativeEntryTag(vm_tag) &&
+ !VMTag::IsRuntimeEntryTag(vm_tag)) {
+ return current;
+ }
+ intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
+ current = current->GetChild(tag_index);
+ // Give the tag a tick.
+ current->Tick();
+ return current;
}
- CodeRegionTrieNode* exclusive_root() const {
- return exclusive_root_;
+ ProfileCodeTrieNode* AppendVMTags(uword vm_tag,
+ ProfileCodeTrieNode* current) {
+ current = AppendVMTag(vm_tag, current);
+ current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
+ return current;
}
- private:
- void VisitSample(ProcessedSample* sample) {
- ProcessSampleExclusive(sample);
- ProcessSampleInclusive(sample);
- }
-
- void ProcessSampleInclusive(ProcessedSample* sample) {
- // Give the root a tick.
- inclusive_root_->Tick();
- CodeRegionTrieNode* current = inclusive_root_;
- current = AppendTags(sample, current);
- if (sample->truncated()) {
- current = AppendTruncatedTag(current);
- }
- // Walk the sampled PCs.
- for (intptr_t i = sample->length() - 1; i >= 0; i--) {
- ASSERT(sample->At(i) != 0);
- intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
- if (index < 0) {
- continue;
- }
- current = current->GetChild(index);
- current->Tick();
+ ProfileCodeTrieNode* AppendTags(uword vm_tag,
+ uword user_tag,
+ ProfileCodeTrieNode* current) {
+ // None.
+ if (tag_order() == Profile::kNoTags) {
+ return current;
}
- }
-
- void ProcessSampleExclusive(ProcessedSample* sample) {
- // Give the root a tick.
- exclusive_root_->Tick();
- CodeRegionTrieNode* current = exclusive_root_;
- current = AppendTags(sample, current);
- // Walk the sampled PCs.
- for (intptr_t i = 0; i < sample->length(); i++) {
- ASSERT(sample->At(i) != 0);
- intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
- if (index < 0) {
- continue;
- }
- current = current->GetChild(index);
- if (i == 0) {
- // Executing PC.
- if (!sample->first_frame_executing() || vm_tags_emitted()) {
- // Only tick if this isn't an exit frame or VM tags are emitted.
- current->Tick();
- }
- } else {
- // Caller PCs.
- current->Tick();
+ // User first.
+ if ((tag_order() == Profile::kUserVM) ||
+ (tag_order() == Profile::kUser)) {
+ current = AppendUserTag(user_tag, current);
+ // Only user.
+ if (tag_order() == Profile::kUser) {
+ return current;
}
+ return AppendVMTags(vm_tag, current);
}
- if (sample->truncated()) {
- current = AppendTruncatedTag(current);
+ // VM first.
+ ASSERT((tag_order() == Profile::kVMUser) ||
+ (tag_order() == Profile::kVM));
+ current = AppendVMTags(vm_tag, current);
+ // Only VM.
+ if (tag_order() == Profile::kVM) {
+ return current;
}
+ return AppendUserTag(user_tag, current);
}
- CodeRegionTrieNode* AppendUserTag(ProcessedSample* sample,
- CodeRegionTrieNode* current) {
- intptr_t user_tag_index = FindTagIndex(sample->user_tag());
+ // ProfileFunctionTrieNode
+ ProfileFunctionTrieNode* AppendUserTag(uword user_tag,
+ ProfileFunctionTrieNode* current) {
+ intptr_t user_tag_index = GetProfileFunctionTagIndex(user_tag);
if (user_tag_index >= 0) {
current = current->GetChild(user_tag_index);
- // Give the tag a tick.
current->Tick();
}
return current;
}
- CodeRegionTrieNode* AppendTruncatedTag(CodeRegionTrieNode* current) {
- intptr_t truncated_tag_index = FindTagIndex(VMTag::kTruncatedTagId);
+ ProfileFunctionTrieNode* AppendTruncatedTag(
+ ProfileFunctionTrieNode* current) {
+ intptr_t truncated_tag_index =
+ GetProfileFunctionTagIndex(VMTag::kTruncatedTagId);
ASSERT(truncated_tag_index >= 0);
current = current->GetChild(truncated_tag_index);
current->Tick();
return current;
}
- CodeRegionTrieNode* AppendVMTag(ProcessedSample* sample,
- CodeRegionTrieNode* current) {
- if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
+ ProfileFunctionTrieNode* AppendVMTag(uword vm_tag,
+ ProfileFunctionTrieNode* current) {
+ if (VMTag::IsNativeEntryTag(vm_tag)) {
// Insert a dummy kNativeTagId node.
- intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId);
+ intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId);
current = current->GetChild(tag_index);
// Give the tag a tick.
current->Tick();
- } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
+ } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
// Insert a dummy kRuntimeTagId node.
- intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId);
+ intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kRuntimeTagId);
current = current->GetChild(tag_index);
// Give the tag a tick.
current->Tick();
} else {
- intptr_t tag_index = FindTagIndex(sample->vm_tag());
+ intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
current = current->GetChild(tag_index);
// Give the tag a tick.
current->Tick();
@@ -2090,59 +1516,384 @@ class CodeRegionTrieBuilder : public TrieBuilder {
return current;
}
- CodeRegionTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
- ProcessedSample* sample, CodeRegionTrieNode* current) {
+ ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
+ uword vm_tag, ProfileFunctionTrieNode* current) {
// Only Native and Runtime entries have a second VM tag.
- if (!VMTag::IsNativeEntryTag(sample->vm_tag()) &&
- !VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
+ if (!VMTag::IsNativeEntryTag(vm_tag) &&
+ !VMTag::IsRuntimeEntryTag(vm_tag)) {
return current;
}
- intptr_t tag_index = FindTagIndex(sample->vm_tag());
+ intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
current = current->GetChild(tag_index);
// Give the tag a tick.
current->Tick();
return current;
}
- CodeRegionTrieNode* AppendVMTags(ProcessedSample* sample,
- CodeRegionTrieNode* current) {
- current = AppendVMTag(sample, current);
- current = AppendSpecificNativeRuntimeEntryVMTag(sample, current);
+ ProfileFunctionTrieNode* AppendVMTags(uword vm_tag,
+ ProfileFunctionTrieNode* current) {
+ current = AppendVMTag(vm_tag, current);
+ current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
return current;
}
- CodeRegionTrieNode* AppendTags(ProcessedSample* sample,
- CodeRegionTrieNode* current) {
+ ProfileFunctionTrieNode* AppendTags(uword vm_tag,
+ uword user_tag,
+ ProfileFunctionTrieNode* current) {
// None.
- if (tag_order() == ProfilerService::kNoTags) {
+ if (tag_order() == Profile::kNoTags) {
return current;
}
// User first.
- if ((tag_order() == ProfilerService::kUserVM) ||
- (tag_order() == ProfilerService::kUser)) {
- current = AppendUserTag(sample, current);
+ if ((tag_order() == Profile::kUserVM) ||
+ (tag_order() == Profile::kUser)) {
+ current = AppendUserTag(user_tag, current);
// Only user.
- if (tag_order() == ProfilerService::kUser) {
+ if (tag_order() == Profile::kUser) {
return current;
}
- return AppendVMTags(sample, current);
+ return AppendVMTags(vm_tag, current);
}
// VM first.
- ASSERT((tag_order() == ProfilerService::kVMUser) ||
- (tag_order() == ProfilerService::kVM));
- current = AppendVMTags(sample, current);
+ ASSERT((tag_order() == Profile::kVMUser) ||
+ (tag_order() == Profile::kVM));
+ current = AppendVMTags(vm_tag, current);
// Only VM.
- if (tag_order() == ProfilerService::kVM) {
+ if (tag_order() == Profile::kVM) {
return current;
}
- return AppendUserTag(sample, current);
+ return AppendUserTag(user_tag, current);
+ }
+
+ intptr_t GetProfileCodeTagIndex(uword tag) {
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ intptr_t index = tag_table->FindCodeIndexForPC(tag);
+ ASSERT(index >= 0);
+ ProfileCode* code = tag_table->At(index);
+ ASSERT(code != NULL);
+ return code->code_table_index();
+ }
+
+ intptr_t GetProfileFunctionTagIndex(uword tag) {
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ intptr_t index = tag_table->FindCodeIndexForPC(tag);
+ ASSERT(index >= 0);
+ ProfileCode* code = tag_table->At(index);
+ ASSERT(code != NULL);
+ ProfileFunction* function = code->function();
+ ASSERT(function != NULL);
+ return function->table_index();
+ }
+
+ intptr_t GetProfileCodeIndex(uword pc, int64_t timestamp) {
+ return GetProfileCode(pc, timestamp)->code_table_index();
+ }
+
+ ProfileCode* GetProfileCode(uword pc, int64_t timestamp) {
+ ProfileCodeTable* live_table = profile_->live_code_;
+ ProfileCodeTable* dead_table = profile_->dead_code_;
+
+ intptr_t index = live_table->FindCodeIndexForPC(pc);
+ ProfileCode* code = NULL;
+ if (index < 0) {
+ index = dead_table->FindCodeIndexForPC(pc);
+ ASSERT(index >= 0);
+ code = dead_table->At(index);
+ } else {
+ code = live_table->At(index);
+ ASSERT(code != NULL);
+ if (code->compile_timestamp() > timestamp) {
+ // Code is newer than sample. Fall back to dead code table.
+ index = dead_table->FindCodeIndexForPC(pc);
+ ASSERT(index >= 0);
+ code = dead_table->At(index);
+ }
+ }
+
+ ASSERT(code != NULL);
+ ASSERT(code->Contains(pc));
+ ASSERT(code->compile_timestamp() <= timestamp);
+ return code;
+ }
+
+ void RegisterProfileCodeTag(uword tag) {
+ if (tag == 0) {
+ // No tag.
+ return;
+ }
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ intptr_t index = tag_table->FindCodeIndexForPC(tag);
+ if (index >= 0) {
+ // Already created.
+ return;
+ }
+ ProfileCode* code = new ProfileCode(ProfileCode::kTagCode,
+ tag,
+ tag + 1,
+ 0,
+ null_code_);
+ index = tag_table->InsertCode(code);
+ ASSERT(index >= 0);
+ }
+
+ ProfileCode* CreateProfileCodeReused(uword pc) {
+ ProfileCode* code = new ProfileCode(ProfileCode::kReusedCode,
+ pc,
+ pc + 1,
+ 0,
+ null_code_);
+ return code;
+ }
+
+ ProfileCode* CreateProfileCode(uword pc) {
+ const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
+ const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
+ Code& code = Code::Handle(isolate_);
+
+ // Check current isolate for pc.
+ if (isolate_->heap()->CodeContains(pc)) {
+ code ^= Code::LookupCode(pc);
+ if (!code.IsNull()) {
+ deoptimized_code_->Add(code);
+ return new ProfileCode(ProfileCode::kDartCode,
+ code.EntryPoint(),
+ code.EntryPoint() + code.Size(),
+ code.compile_timestamp(),
+ code);
+ }
+ return new ProfileCode(ProfileCode::kCollectedCode,
+ pc,
+ (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
+ 0,
+ code);
+ }
+
+ // Check VM isolate for pc.
+ if (vm_isolate_->heap()->CodeContains(pc)) {
+ code ^= Code::LookupCodeInVmIsolate(pc);
+ if (!code.IsNull()) {
+ return new ProfileCode(ProfileCode::kDartCode,
+ code.EntryPoint(),
+ code.EntryPoint() + code.Size(),
+ code.compile_timestamp(),
+ code);
+ }
+ return new ProfileCode(ProfileCode::kCollectedCode,
+ pc,
+ (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
+ 0,
+ code);
+ }
+
+ // Check NativeSymbolResolver for pc.
+ uintptr_t native_start = 0;
+ char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
+ &native_start);
+ if (native_name == NULL) {
+ // No native name found.
+ return new ProfileCode(ProfileCode::kNativeCode,
+ pc,
+ pc + 1,
+ 0,
+ code);
+ }
+ ASSERT(pc >= native_start);
+ ProfileCode* profile_code =
+ new ProfileCode(ProfileCode::kNativeCode,
+ native_start,
+ pc + 1,
+ 0,
+ code);
+ profile_code->SetName(native_name);
+ free(native_name);
+ return profile_code;
+ }
+
+ ProfileCode* RegisterProfileCode(uword pc, int64_t timestamp) {
+ ProfileCodeTable* live_table = profile_->live_code_;
+ ProfileCodeTable* dead_table = profile_->dead_code_;
+
+ ProfileCode* code = live_table->FindCodeForPC(pc);
+ if (code == NULL) {
+ // Code not found.
+ intptr_t index = live_table->InsertCode(CreateProfileCode(pc));
+ ASSERT(index >= 0);
+ code = live_table->At(index);
+ if (code->compile_timestamp() <= timestamp) {
+ // Code was compiled before sample was taken.
+ return code;
+ }
+ // Code was compiled after the sample was taken. Insert code object into
+ // the dead code table.
+ index = dead_table->InsertCode(CreateProfileCodeReused(pc));
+ ASSERT(index >= 0);
+ return dead_table->At(index);
+ }
+ // Existing code found.
+ if (code->compile_timestamp() <= timestamp) {
+ // Code was compiled before sample was taken.
+ return code;
+ }
+ // Code was compiled after the sample was taken. Check if we have an entry
+ // in the dead code table.
+ code = dead_table->FindCodeForPC(pc);
+ if (code != NULL) {
+ return code;
+ }
+ // Create a new dead code entry.
+ intptr_t index = dead_table->InsertCode(CreateProfileCodeReused(pc));
+ ASSERT(index >= 0);
+ return dead_table->At(index);
+ }
+
+ Profile::TagOrder tag_order() const {
+ return tag_order_;
}
- CodeRegionTrieNode* exclusive_root_;
- CodeRegionTrieNode* inclusive_root_;
+ bool vm_tags_emitted() const {
+ return (tag_order_ == Profile::kUserVM) ||
+ (tag_order_ == Profile::kVMUser) ||
+ (tag_order_ == Profile::kVM);
+ }
+
+ Isolate* isolate_;
+ Isolate* vm_isolate_;
+ SampleFilter* filter_;
+ Profile::TagOrder tag_order_;
+ Profile* profile_;
+ DeoptimizedCodeSet* deoptimized_code_;
+ const Code& null_code_;
+ const Function& null_function_;
+ bool tick_functions_;
+
+ ProcessedSampleBuffer* samples_;
};
+Profile::Profile(Isolate* isolate)
+ : isolate_(isolate),
+ live_code_(NULL),
+ dead_code_(NULL),
+ tag_code_(NULL),
+ functions_(NULL),
+ dead_code_index_offset_(-1),
+ tag_code_index_offset_(-1),
+ min_time_(kMaxInt64),
+ max_time_(0) {
+ ASSERT(isolate_ != NULL);
+ for (intptr_t i = 0; i < kNumTrieKinds; i++) {
+ roots_[i] = NULL;
+ }
+}
+
+
+void Profile::Build(SampleFilter* filter, TagOrder tag_order) {
+ ProfileBuilder builder(isolate_, filter, tag_order, this);
+ builder.Build();
+}
+
+
+ProfileFunction* Profile::GetFunction(intptr_t index) {
+ ASSERT(functions_ != NULL);
+ return functions_->At(index);
+}
+
+
+ProfileCode* Profile::GetCode(intptr_t index) {
+ ASSERT(live_code_ != NULL);
+ ASSERT(dead_code_ != NULL);
+ ASSERT(tag_code_ != NULL);
+ ASSERT(dead_code_index_offset_ >= 0);
+ ASSERT(tag_code_index_offset_ >= 0);
+
+ // Code indexes span three arrays.
+ // 0 ... |live_code|
+ // |live_code| ... |dead_code|
+ // |dead_code| ... |tag_code|
+
+ if (index < dead_code_index_offset_) {
+ return live_code_->At(index);
+ }
+
+ if (index < tag_code_index_offset_) {
+ index -= dead_code_index_offset_;
+ return dead_code_->At(index);
+ }
+
+ index -= tag_code_index_offset_;
+ return tag_code_->At(index);
+}
+
+
+ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) {
+ return roots_[static_cast<intptr_t>(trie_kind)];
+}
+
+
+void Profile::PrintJSON(JSONStream* stream) {
+ ScopeTimer sw("Profile::PrintJSON", FLAG_trace_profiler);
+ JSONObject obj(stream);
+ obj.AddProperty("type", "_CpuProfile");
+ obj.AddProperty("samplePeriod",
+ static_cast<intptr_t>(FLAG_profile_period));
+ obj.AddProperty("stackDepth",
+ static_cast<intptr_t>(FLAG_profile_depth));
+ obj.AddProperty("sampleCount", sample_count());
+ obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan()));
+ {
+ JSONArray codes(&obj, "codes");
+ for (intptr_t i = 0; i < live_code_->length(); i++) {
+ ProfileCode* code = live_code_->At(i);
+ ASSERT(code != NULL);
+ code->PrintToJSONArray(&codes);
+ }
+ for (intptr_t i = 0; i < dead_code_->length(); i++) {
+ ProfileCode* code = dead_code_->At(i);
+ ASSERT(code != NULL);
+ code->PrintToJSONArray(&codes);
+ }
+ for (intptr_t i = 0; i < tag_code_->length(); i++) {
+ ProfileCode* code = tag_code_->At(i);
+ ASSERT(code != NULL);
+ code->PrintToJSONArray(&codes);
+ }
+ }
+
+ {
+ JSONArray functions(&obj, "functions");
+ for (intptr_t i = 0; i < functions_->length(); i++) {
+ ProfileFunction* function = functions_->At(i);
+ ASSERT(function != NULL);
+ function->PrintToJSONArray(&functions);
+ }
+ }
+ {
+ JSONArray code_trie(&obj, "exclusiveCodeTrie");
+ ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveCode)];
+ ASSERT(root != NULL);
+ root->PrintToJSONArray(&code_trie);
+ }
+ {
+ JSONArray code_trie(&obj, "inclusiveCodeTrie");
+ ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveCode)];
+ ASSERT(root != NULL);
+ root->PrintToJSONArray(&code_trie);
+ }
+ {
+ JSONArray function_trie(&obj, "exclusiveFunctionTrie");
+ ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveFunction)];
+ ASSERT(root != NULL);
+ root->PrintToJSONArray(&function_trie);
+ }
+ {
+ JSONArray function_trie(&obj, "inclusiveFunctionTrie");
+ ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveFunction)];
+ ASSERT(root != NULL);
+ root->PrintToJSONArray(&function_trie);
+ }
+}
+
+
class NoAllocationSampleFilter : public SampleFilter {
public:
explicit NoAllocationSampleFilter(Isolate* isolate)
@@ -2155,189 +1906,30 @@ class NoAllocationSampleFilter : public SampleFilter {
};
-void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) {
+void ProfilerService::PrintJSON(JSONStream* stream,
+ Profile::TagOrder tag_order) {
Isolate* isolate = Isolate::Current();
// Disable profile interrupts while processing the buffer.
Profiler::EndExecution(isolate);
- MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- stream->PrintError(kFeatureDisabled, NULL);
- return;
+
+ {
+ MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ stream->PrintError(kFeatureDisabled, NULL);
+ return;
+ }
}
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- ASSERT(sample_buffer != NULL);
- ScopeTimer sw("ProfilerService::PrintJSON", FLAG_trace_profiler);
+
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
-
- ProcessedSampleBuffer* processed_samples = NULL;
- {
- ScopeTimer sw("BuildProcessedSampleBuffer", FLAG_trace_profiler);
- NoAllocationSampleFilter filter(isolate);
- processed_samples = sample_buffer->BuildProcessedSampleBuffer(&filter);
- }
-
- {
- // Live code holds Dart, Native, and Collected CodeRegions.
- CodeRegionTable live_code_table;
- // Dead code holds Overwritten CodeRegions.
- CodeRegionTable dead_code_table;
- // Tag code holds Tag CodeRegions.
- CodeRegionTable tag_code_table;
- // Table holding all ProfileFunctions.
- ProfileFunctionTable function_table;
- // Set of deoptimized code still referenced by the profiler.
- DeoptimizedCodeSet* deoptimized_code = new DeoptimizedCodeSet(isolate);
-
- // Build CodeRegion tables.
- CodeRegionTableBuilder builder(isolate,
- &live_code_table,
- &dead_code_table,
- &tag_code_table,
- deoptimized_code);
- {
- ScopeTimer sw("CodeRegionTableBuilder::Build", FLAG_trace_profiler);
- builder.Build(processed_samples);
- }
- intptr_t samples = processed_samples->length();
- intptr_t frames = builder.frames();
- if (FLAG_trace_profiler) {
- intptr_t total_live_code_objects = live_code_table.Length();
- intptr_t total_dead_code_objects = dead_code_table.Length();
- intptr_t total_tag_code_objects = tag_code_table.Length();
- OS::Print(
- "Processed %" Pd " samples with %" Pd " frames\n", samples, frames);
- OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n",
- total_live_code_objects,
- total_dead_code_objects,
- total_tag_code_objects);
- }
-
- if (FLAG_trace_profiler) {
- ScopeTimer sw("CodeRegionTableVerify", FLAG_trace_profiler);
- live_code_table.Verify();
- dead_code_table.Verify();
- tag_code_table.Verify();
- }
-
- {
- ScopeTimer st("CodeRegionFunctionMapping", FLAG_trace_profiler);
- CodeRegionFunctionMapper mapper(isolate, &live_code_table,
- &dead_code_table,
- &tag_code_table,
- &function_table);
- mapper.Map();
- }
- if (FLAG_trace_profiler) {
- intptr_t total_functions = function_table.Length();
- OS::Print("FunctionTable: size=%" Pd "\n", total_functions);
- }
- CodeRegionTrieBuilder code_trie_builder(isolate,
- &live_code_table,
- &dead_code_table,
- &tag_code_table);
- code_trie_builder.set_tag_order(tag_order);
- {
- // Build CodeRegion trie.
- ScopeTimer sw("CodeRegionTrieBuilder::Build", FLAG_trace_profiler);
- code_trie_builder.Build(processed_samples);
- code_trie_builder.exclusive_root()->SortByCount();
- code_trie_builder.inclusive_root()->SortByCount();
- }
- if (FLAG_trace_profiler) {
- OS::Print("Code Trie Root Count: E: %" Pd " I: %" Pd "\n",
- code_trie_builder.exclusive_root()->count(),
- code_trie_builder.inclusive_root()->count());
- }
- ProfileFunctionTrieBuilder function_trie_builder(&live_code_table,
- &dead_code_table,
- &tag_code_table,
- &function_table);
- function_trie_builder.set_tag_order(tag_order);
- {
- // Build ProfileFunction trie.
- ScopeTimer sw("ProfileFunctionTrieBuilder::Build",
- FLAG_trace_profiler);
- function_trie_builder.Build(processed_samples);
- function_trie_builder.exclusive_root()->SortByCount();
- function_trie_builder.inclusive_root()->SortByCount();
- }
- if (FLAG_trace_profiler) {
- OS::Print("Function Trie Root Count: E: %" Pd " I: %" Pd "\n",
- function_trie_builder.exclusive_root()->count(),
- function_trie_builder.inclusive_root()->count());
- }
- {
- ScopeTimer sw("CpuProfileJSONStream", FLAG_trace_profiler);
- // Serialize to JSON.
- JSONObject obj(stream);
- obj.AddProperty("type", "_CpuProfile");
- obj.AddProperty("sampleCount", samples);
- obj.AddProperty("samplePeriod",
- static_cast<intptr_t>(FLAG_profile_period));
- obj.AddProperty("stackDepth",
- static_cast<intptr_t>(FLAG_profile_depth));
- obj.AddProperty("timeSpan",
- MicrosecondsToSeconds(builder.TimeDeltaMicros()));
- {
- JSONArray code_trie(&obj, "exclusiveCodeTrie");
- CodeRegionTrieNode* root = code_trie_builder.exclusive_root();
- ASSERT(root != NULL);
- root->PrintToJSONArray(&code_trie);
- }
- {
- JSONArray code_trie(&obj, "inclusiveCodeTrie");
- CodeRegionTrieNode* root = code_trie_builder.inclusive_root();
- ASSERT(root != NULL);
- root->PrintToJSONArray(&code_trie);
- }
- {
- JSONArray function_trie(&obj, "exclusiveFunctionTrie");
- ProfileFunctionTrieNode* root =
- function_trie_builder.exclusive_root();
- ASSERT(root != NULL);
- root->PrintToJSONArray(&function_trie);
- }
- {
- JSONArray function_trie(&obj, "inclusiveFunctionTrie");
- ProfileFunctionTrieNode* root =
- function_trie_builder.inclusive_root();
- ASSERT(root != NULL);
- root->PrintToJSONArray(&function_trie);
- }
- {
- JSONArray codes(&obj, "codes");
- for (intptr_t i = 0; i < live_code_table.Length(); i++) {
- CodeRegion* region = live_code_table.At(i);
- ASSERT(region != NULL);
- region->PrintToJSONArray(&codes);
- }
- for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
- CodeRegion* region = dead_code_table.At(i);
- ASSERT(region != NULL);
- region->PrintToJSONArray(&codes);
- }
- for (intptr_t i = 0; i < tag_code_table.Length(); i++) {
- CodeRegion* region = tag_code_table.At(i);
- ASSERT(region != NULL);
- region->PrintToJSONArray(&codes);
- }
- }
- {
- JSONArray functions(&obj, "functions");
- for (intptr_t i = 0; i < function_table.Length(); i++) {
- ProfileFunction* function = function_table.At(i);
- ASSERT(function != NULL);
- function->PrintToJSONArray(&functions);
- }
- }
- }
- // Update the isolates set of dead code.
- deoptimized_code->UpdateIsolate(isolate);
- }
+ Profile profile(isolate);
+ NoAllocationSampleFilter filter(isolate);
+ profile.Build(&filter, tag_order);
+ profile.PrintJSON(stream);
}
+
// Enable profile interrupts.
Profiler::BeginExecution(isolate);
}
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | runtime/vm/service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698