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

Unified Diff: runtime/vm/profiler.cc

Issue 197803004: Add dead CodeRegionTable for tracking overwritten Dart code (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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/object.cc ('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.cc
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 9eb125e0ed3d05c0beca8b121758f3219cb13ee6..48f4648a0a9627e32c8b17f22093b42a3e8be15b 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -162,6 +162,31 @@ void Profiler::EndExecution(Isolate* isolate) {
}
+class ScopeStopwatch : public ValueObject {
+ public:
+ explicit ScopeStopwatch(const char* name) : name_(name) {
+ start_ = FLAG_trace_profiled_isolates ? OS::GetCurrentTimeMillis() : 0;
+ }
+
+ intptr_t GetElapsed() const {
+ intptr_t end = OS::GetCurrentTimeMillis();
+ ASSERT(end >= start_);
+ return end - start_;
+ }
+
+ ~ScopeStopwatch() {
+ if (FLAG_trace_profiled_isolates) {
+ intptr_t elapsed = GetElapsed();
+ OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
+ }
+ }
+
+ private:
+ const char* name_;
+ intptr_t start_;
+};
+
+
struct AddressEntry {
uword pc;
intptr_t exclusive_ticks;
@@ -183,16 +208,20 @@ struct CallEntry {
typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
-// A region of code. Each region is a kind of code (Dart, Collected, or Native).
+// 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,
- kCollectedCode,
- kNativeCode
+ 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) :
+ CodeRegion(Kind kind, uword start, uword end, int64_t timestamp) :
kind_(kind),
start_(start),
end_(end),
@@ -200,14 +229,14 @@ class CodeRegion : public ZoneAllocated {
exclusive_ticks_(0),
inclusive_tick_serial_(0),
name_(NULL),
+ compile_timestamp_(timestamp),
+ creation_serial_(0),
address_table_(new ZoneGrowableArray<AddressEntry>()),
callers_table_(new ZoneGrowableArray<CallEntry>()),
callees_table_(new ZoneGrowableArray<CallEntry>()) {
ASSERT(start_ < end_);
}
- ~CodeRegion() {
- }
uword start() const { return start_; }
void set_start(uword start) {
@@ -241,6 +270,15 @@ class CodeRegion : public ZoneAllocated {
contains(other->end() - 1);
}
+ intptr_t creation_serial() const { return creation_serial_; }
+ void set_creation_serial(intptr_t serial) {
+ creation_serial_ = serial;
+ }
+ 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;
@@ -272,17 +310,25 @@ class CodeRegion : public ZoneAllocated {
return "Collected";
case kNativeCode:
return "Native";
+ case kReusedCode:
+ return "Overwritten";
+ case kTagCode:
+ return "Tag";
}
UNREACHABLE();
return NULL;
}
void DebugPrint() const {
- printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(),
- name_);
+ OS::Print("%s [%" Px ", %" Px ") %"Pd" %"Pd64"\n",
+ KindToCString(kind_),
+ start(),
+ end(),
+ creation_serial_,
+ compile_timestamp_);
}
- void AddTickAtAddress(uword pc, bool exclusive, intptr_t serial) {
+ 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)) {
@@ -293,35 +339,11 @@ class CodeRegion : public ZoneAllocated {
if (exclusive) {
exclusive_ticks_++;
} else {
+ inclusive_ticks_++;
// Mark the last serial we ticked the inclusive count.
inclusive_tick_serial_ = serial;
- inclusive_ticks_++;
- }
- // Tick the address entry.
- const intptr_t length = address_table_->length();
- intptr_t i = 0;
- for (; i < length; i++) {
- AddressEntry& entry = (*address_table_)[i];
- if (entry.pc == pc) {
- entry.tick(exclusive);
- return;
- }
- if (entry.pc > pc) {
- break;
- }
- }
- 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);
}
+ TickAddress(pc, exclusive);
}
void AddCaller(intptr_t index) {
@@ -341,12 +363,12 @@ class CodeRegion : public ZoneAllocated {
obj.AddProperty("user_name", name());
obj.AddPropertyF("start", "%" Px "", start());
obj.AddPropertyF("end", "%" Px "", end());
- obj.AddPropertyF("id", "code/native/%" Px "", start());
+ obj.AddPropertyF("id", "code/native-%" Px "", start());
{
// Generate a fake function entry.
JSONObject func(&obj, "function");
func.AddProperty("type", "@Function");
- func.AddPropertyF("id", "native/functions/%" Pd "", start());
+ func.AddPropertyF("id", "functions/native-%" Px "", start());
func.AddProperty("name", name());
func.AddProperty("user_name", name());
func.AddProperty("kind", "Native");
@@ -362,27 +384,48 @@ class CodeRegion : public ZoneAllocated {
obj.AddProperty("user_name", name());
obj.AddPropertyF("start", "%" Px "", start());
obj.AddPropertyF("end", "%" Px "", end());
- obj.AddPropertyF("id", "code/collected/%" Px "", start());
+ obj.AddPropertyF("id", "code/collected-%" Px "", start());
{
// Generate a fake function entry.
JSONObject func(&obj, "function");
func.AddProperty("type", "@Function");
- func.AddPropertyF("id", "collected/functions/%" Pd "", start());
+ obj.AddPropertyF("id", "functions/collected-%" Px "", start());
func.AddProperty("name", name());
func.AddProperty("user_name", name());
func.AddProperty("kind", "Collected");
}
}
+ void PrintOverwrittenCode(JSONObject* profile_code_obj) {
+ ASSERT(kind() == kReusedCode);
+ JSONObject obj(profile_code_obj, "code");
+ obj.AddProperty("type", "@Code");
+ obj.AddProperty("kind", "Reused");
+ obj.AddProperty("name", name());
+ obj.AddProperty("user_name", name());
+ obj.AddPropertyF("start", "%" Px "", start());
+ obj.AddPropertyF("end", "%" Px "", end());
+ obj.AddPropertyF("id", "code/reused-%" Px "", start());
+ {
+ // Generate a fake function entry.
+ JSONObject func(&obj, "function");
+ func.AddProperty("type", "@Function");
+ obj.AddPropertyF("id", "functions/reused-%" Px "", start());
+ func.AddProperty("name", name());
+ func.AddProperty("user_name", name());
+ func.AddProperty("kind", "Reused");
+ }
+ }
+
void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) {
JSONObject obj(events);
- obj.AddProperty("type", "ProfileCode");
+ obj.AddProperty("type", "CodeRegion");
obj.AddProperty("kind", KindToCString(kind()));
obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks());
obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks());
if (kind() == kDartCode) {
// Look up code in Dart heap.
- Code& code = Code::Handle();
+ Code& code = Code::Handle(isolate);
code ^= Code::LookupCode(start());
if (code.IsNull()) {
// Code is a stub in the Vm isolate.
@@ -393,14 +436,20 @@ class CodeRegion : public ZoneAllocated {
} else if (kind() == kCollectedCode) {
if (name() == NULL) {
// Lazily set generated name.
- GenerateAndSetSymbolName("Collected");
+ GenerateAndSetSymbolName("[Collected]");
}
PrintCollectedCode(&obj);
+ } else if (kind() == kReusedCode) {
+ if (name() == NULL) {
+ // Lazily set generated name.
+ GenerateAndSetSymbolName("[Reused]");
+ }
+ PrintOverwrittenCode(&obj);
} else {
ASSERT(kind() == kNativeCode);
if (name() == NULL) {
// Lazily set generated name.
- GenerateAndSetSymbolName("Native");
+ GenerateAndSetSymbolName("[Native]");
}
PrintNativeCode(&obj);
}
@@ -432,6 +481,36 @@ class CodeRegion : public ZoneAllocated {
}
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 AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) {
const intptr_t length = table->length();
intptr_t i = 0;
@@ -463,77 +542,72 @@ class CodeRegion : public ZoneAllocated {
SetName(buff);
}
- Kind kind_;
+ // 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_;
+ // Serial number at which this CodeRegion was created.
+ intptr_t creation_serial_;
ZoneGrowableArray<AddressEntry>* address_table_;
ZoneGrowableArray<CallEntry>* callers_table_;
ZoneGrowableArray<CallEntry>* callees_table_;
DISALLOW_COPY_AND_ASSIGN(CodeRegion);
};
-
-class ScopeStopwatch : public ValueObject {
+// A sorted table of CodeRegions. Does not allow for overlap.
+class CodeRegionTable : public ValueObject {
public:
- explicit ScopeStopwatch(const char* name) : name_(name) {
- start_ = OS::GetCurrentTimeMillis();
- }
-
- intptr_t GetElapsed() const {
- intptr_t end = OS::GetCurrentTimeMillis();
- ASSERT(end >= start_);
- return end - start_;
- }
-
- ~ScopeStopwatch() {
- if (FLAG_trace_profiled_isolates) {
- intptr_t elapsed = GetElapsed();
- OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
- }
- }
-
- private:
- const char* name_;
- intptr_t start_;
-};
-
+ enum TickResult {
+ kTicked = 0, // CodeRegion found and ticked.
+ kNotFound = -1, // No CodeRegion found.
+ kNewerCode = -2, // CodeRegion found but it was compiled after sample.
+ };
-// All code regions. Code region tables are built on demand when a profile
-// is requested (through the service or on isolate shutdown).
-class ProfilerCodeRegionTable : public ValueObject {
- public:
- explicit ProfilerCodeRegionTable(Isolate* isolate) :
- heap_(isolate->heap()),
+ CodeRegionTable() :
code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
}
- ~ProfilerCodeRegionTable() {
- }
-
- void AddTick(uword pc, bool exclusive, intptr_t serial) {
+ // 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) {
- CodeRegion* code_region = CreateCodeRegion(pc);
- ASSERT(code_region != NULL);
- index = InsertCodeRegion(code_region);
+ // Not found.
+ return kNotFound;
}
- ASSERT(index >= 0);
ASSERT(index < code_region_table_->length());
-
- // Update code object counters.
- (*code_region_table_)[index]->AddTickAtAddress(pc, exclusive, serial);
+ CodeRegion* region = At(index);
+ if (region->compile_timestamp() > timestamp) {
+ // Compiled after tick.
+ return kNewerCode;
+ }
+ region->Tick(pc, exclusive, serial);
+ return kTicked;
}
+ // Table length.
intptr_t Length() const { return code_region_table_->length(); }
- CodeRegion* At(intptr_t idx) {
- return (*code_region_table_)[idx];
+ // Get the CodeRegion at index.
+ CodeRegion* At(intptr_t index) const {
+ return (*code_region_table_)[index];
}
+ // Find the table index to the CodeRegion containing pc.
+ // Returns < 0 if not found.
intptr_t FindIndex(uword pc) const {
intptr_t index = FindRegionIndex(pc, &CompareLowerBound);
const CodeRegion* code_region = NULL;
@@ -541,90 +615,17 @@ class ProfilerCodeRegionTable : public ValueObject {
// Not present.
return -1;
}
- code_region = (*code_region_table_)[index];
+ code_region = At(index);
if (code_region->contains(pc)) {
// Found at index.
return index;
}
- return -1;
- }
-
-#if defined(DEBUG)
- void Verify() {
- VerifyOrder();
- VerifyOverlap();
- }
-#endif
-
- private:
- intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
- ASSERT(comparator != NULL);
- intptr_t count = code_region_table_->length();
- intptr_t first = 0;
- while (count > 0) {
- intptr_t it = first;
- intptr_t step = count / 2;
- it += step;
- const CodeRegion* code_region = (*code_region_table_)[it];
- if (comparator(pc, code_region->start(), code_region->end())) {
- first = ++it;
- count -= (step + 1);
- } else {
- count = step;
- }
- }
- return first;
- }
-
- static bool CompareUpperBound(uword pc, uword start, uword end) {
- return pc >= end;
- }
-
- static bool CompareLowerBound(uword pc, uword start, uword end) {
- return end <= pc;
- }
-
- CodeRegion* CreateCodeRegion(uword pc) {
- Code& code = Code::Handle();
- code ^= Code::LookupCode(pc);
- if (!code.IsNull()) {
- return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
- code.EntryPoint() + code.Size());
- }
- code ^= Code::LookupCodeInVmIsolate(pc);
- if (!code.IsNull()) {
- return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
- code.EntryPoint() + code.Size());
- }
- if (heap_->CodeContains(pc)) {
- const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
- const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
- return new CodeRegion(CodeRegion::kCollectedCode, pc,
- (pc & kDartCodeAlignmentMask) + kDartCodeAlignment);
- }
- uintptr_t native_start = 0;
- char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
- &native_start);
- if (native_name == NULL) {
- return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1);
- }
- ASSERT(pc >= native_start);
- CodeRegion* code_region =
- new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1);
- code_region->SetName(native_name);
- free(native_name);
- return code_region;
- }
-
- void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
- uword start, uword end) {
- // We should never see overlapping Dart code regions.
- ASSERT(region->kind() != CodeRegion::kDartCode);
- // When code regions overlap, they should be of the same kind.
- ASSERT(region->kind() == code_region->kind());
- region->AdjustExtent(start, end);
+ return -2;
}
+ // 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();
@@ -636,11 +637,12 @@ class ProfilerCodeRegionTable : public ValueObject {
// 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);
+ // TODO(johnmccutchan): Simplify below logic.
if ((lo == length) && (hi == length)) {
lo = length - 1;
}
if (lo == length) {
- CodeRegion* region = (*code_region_table_)[hi];
+ CodeRegion* region = At(hi);
if (region->overlaps(code_region)) {
HandleOverlap(region, code_region, start, end);
return hi;
@@ -648,7 +650,7 @@ class ProfilerCodeRegionTable : public ValueObject {
code_region_table_->Add(code_region);
return length;
} else if (hi == length) {
- CodeRegion* region = (*code_region_table_)[lo];
+ CodeRegion* region = At(lo);
if (region->overlaps(code_region)) {
HandleOverlap(region, code_region, start, end);
return lo;
@@ -656,7 +658,7 @@ class ProfilerCodeRegionTable : public ValueObject {
code_region_table_->Add(code_region);
return length;
} else if (lo == hi) {
- CodeRegion* region = (*code_region_table_)[lo];
+ CodeRegion* region = At(lo);
if (region->overlaps(code_region)) {
HandleOverlap(region, code_region, start, end);
return lo;
@@ -664,12 +666,12 @@ class ProfilerCodeRegionTable : public ValueObject {
code_region_table_->InsertAt(lo, code_region);
return lo;
} else {
- CodeRegion* region = (*code_region_table_)[lo];
+ CodeRegion* region = At(lo);
if (region->overlaps(code_region)) {
HandleOverlap(region, code_region, start, end);
return lo;
}
- region = (*code_region_table_)[hi];
+ region = At(hi);
if (region->overlaps(code_region)) {
HandleOverlap(region, code_region, start, end);
return hi;
@@ -681,6 +683,58 @@ class ProfilerCodeRegionTable : public ValueObject {
}
#if defined(DEBUG)
+ void Verify() {
+ VerifyOrder();
+ VerifyOverlap();
+ }
+#endif
+
+ 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 {
+ ASSERT(comparator != NULL);
+ intptr_t count = code_region_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())) {
+ first = ++it;
+ count -= (step + 1);
+ } else {
+ count = step;
+ }
+ }
+ return first;
+ }
+
+ static bool CompareUpperBound(uword pc, uword start, uword end) {
+ return pc >= end;
+ }
+
+ static bool CompareLowerBound(uword pc, uword start, uword end) {
+ return end <= pc;
+ }
+
+ void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
+ uword start, uword end) {
+ // We should never see overlapping Dart code regions.
+ ASSERT(region->kind() != CodeRegion::kDartCode);
+ // When code regions overlap, they should be of the same kind.
+ ASSERT(region->kind() == code_region->kind());
+ region->AdjustExtent(start, end);
+ }
+
+#if defined(DEBUG)
void VerifyOrder() {
const intptr_t length = code_region_table_->length();
if (length == 0) {
@@ -709,7 +763,6 @@ class ProfilerCodeRegionTable : public ValueObject {
}
#endif
- Heap* heap_;
ZoneGrowableArray<CodeRegion*>* code_region_table_;
};
@@ -717,11 +770,20 @@ class ProfilerCodeRegionTable : public ValueObject {
class CodeRegionTableBuilder : public SampleVisitor {
public:
CodeRegionTableBuilder(Isolate* isolate,
- ProfilerCodeRegionTable* code_region_table)
- : SampleVisitor(isolate), code_region_table_(code_region_table) {
+ CodeRegionTable* live_code_table,
+ CodeRegionTable* dead_code_table)
+ : SampleVisitor(isolate),
+ live_code_table_(live_code_table),
+ dead_code_table_(dead_code_table),
+ isolate_(isolate),
+ vm_isolate_(Dart::vm_isolate()) {
+ ASSERT(live_code_table_ != NULL);
+ ASSERT(dead_code_table_ != NULL);
frames_ = 0;
min_time_ = kMaxInt64;
max_time_ = 0;
+ ASSERT(isolate_ != NULL);
+ ASSERT(vm_isolate_ != NULL);
}
void VisitSample(Sample* sample) {
@@ -732,44 +794,148 @@ class CodeRegionTableBuilder : public SampleVisitor {
if (timestamp < min_time_) {
min_time_ = timestamp;
}
- // Give the bottom frame an exclusive tick.
- code_region_table_->AddTick(sample->At(0), true, -1);
- // Give all frames (including the bottom) an inclusive tick.
+ // Exclusive tick for bottom frame.
+ Tick(sample->At(0), true, timestamp);
+ // Inclusive tick for all frames.
for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
if (sample->At(i) == 0) {
break;
}
frames_++;
- code_region_table_->AddTick(sample->At(i), false, visited());
+ Tick(sample->At(i), false, timestamp);
}
}
intptr_t frames() const { return frames_; }
+
intptr_t TimeDeltaMicros() const {
return static_cast<intptr_t>(max_time_ - min_time_);
}
int64_t max_time() const { return max_time_; }
private:
+ void Tick(uword pc, bool exclusive, int64_t timestamp) {
+ CodeRegionTable::TickResult r;
+ intptr_t serial = exclusive ? -1 : visited();
+ 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);
+ region->set_creation_serial(visited());
+ 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);
+ intptr_t index = dead_code_table_->InsertCodeRegion(region);
+ region->set_creation_serial(visited());
+ 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()) {
+ return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
+ code.EntryPoint() + code.Size(),
+ code.compile_timestamp());
+ }
+ return new CodeRegion(CodeRegion::kCollectedCode, pc,
+ (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
+ 0);
+ }
+ // 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());
+ }
+ return new CodeRegion(CodeRegion::kCollectedCode, pc,
+ (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
+ 0);
+ }
+ // 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);
+ }
+ ASSERT(pc >= native_start);
+ CodeRegion* code_region =
+ new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1, 0);
+ code_region->SetName(native_name);
+ free(native_name);
+ return code_region;
+ }
+
intptr_t frames_;
int64_t min_time_;
int64_t max_time_;
- ProfilerCodeRegionTable* code_region_table_;
+ CodeRegionTable* live_code_table_;
+ CodeRegionTable* dead_code_table_;
+ Isolate* isolate_;
+ Isolate* vm_isolate_;
};
class CodeRegionTableCallersBuilder : public SampleVisitor {
public:
CodeRegionTableCallersBuilder(Isolate* isolate,
- ProfilerCodeRegionTable* code_region_table)
- : SampleVisitor(isolate), code_region_table_(code_region_table) {
- ASSERT(code_region_table_ != NULL);
+ CodeRegionTable* live_code_table,
+ CodeRegionTable* dead_code_table)
+ : SampleVisitor(isolate),
+ live_code_table_(live_code_table),
+ dead_code_table_(dead_code_table) {
+ ASSERT(live_code_table_ != NULL);
+ ASSERT(dead_code_table_ != NULL);
+ dead_code_table_offset_ = live_code_table_->Length();
}
void VisitSample(Sample* sample) {
- intptr_t current_index = code_region_table_->FindIndex(sample->At(0));
- ASSERT(current_index != -1);
- CodeRegion* current = code_region_table_->At(current_index);
+ int64_t timestamp = sample->timestamp();
+ intptr_t current_index = FindFinalIndex(sample->At(0), timestamp);
+ ASSERT(current_index >= 0);
+ CodeRegion* current = At(current_index);
intptr_t caller_index = -1;
CodeRegion* caller = NULL;
intptr_t callee_index = -1;
@@ -778,9 +944,9 @@ class CodeRegionTableCallersBuilder : public SampleVisitor {
if (sample->At(i) == 0) {
break;
}
- caller_index = code_region_table_->FindIndex(sample->At(i));
- ASSERT(caller_index != -1);
- caller = code_region_table_->At(caller_index);
+ caller_index = FindFinalIndex(sample->At(i), timestamp);
+ ASSERT(caller_index >= 0);
+ caller = At(caller_index);
current->AddCaller(caller_index);
if (callee != NULL) {
current->AddCallee(callee_index);
@@ -794,7 +960,36 @@ class CodeRegionTableCallersBuilder : public SampleVisitor {
}
private:
- ProfilerCodeRegionTable* code_region_table_;
+ intptr_t FindFinalIndex(uword pc, int64_t timestamp) const {
+ intptr_t index = live_code_table_->FindIndex(pc);
+ ASSERT(index >= 0);
+ 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);
+ ASSERT(index >= 0);
+ region = dead_code_table_->At(index);
+ ASSERT(region->contains(pc));
+ ASSERT(region->compile_timestamp() <= timestamp);
+ return index + dead_code_table_offset_;
+ }
+ ASSERT(region->compile_timestamp() <= timestamp);
+ return index;
+ }
+
+ CodeRegion* At(intptr_t final_index) {
+ ASSERT(final_index >= 0);
+ if (final_index < dead_code_table_offset_) {
+ return live_code_table_->At(final_index);
+ } else {
+ return dead_code_table_->At(final_index - dead_code_table_offset_);
+ }
+ }
+
+ CodeRegionTable* live_code_table_;
+ CodeRegionTable* dead_code_table_;
+ intptr_t dead_code_table_offset_;
};
void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream,
@@ -815,28 +1010,43 @@ void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream,
{
StackZone zone(isolate);
{
- // Build code region table.
- ProfilerCodeRegionTable code_region_table(isolate);
- CodeRegionTableBuilder builder(isolate, &code_region_table);
- CodeRegionTableCallersBuilder build_callers(isolate, &code_region_table);
+ // Live code holds Dart, Native, and Collected CodeRegions.
+ CodeRegionTable live_code_table;
+ // Dead code holds Overwritten CodeRegions.
+ CodeRegionTable dead_code_table;
+ CodeRegionTableBuilder builder(isolate,
+ &live_code_table,
+ &dead_code_table);
{
+ // Build CodeRegion tables.
ScopeStopwatch sw("CodeTableBuild");
sample_buffer->VisitSamples(&builder);
}
+ intptr_t samples = builder.visited();
+ intptr_t frames = builder.frames();
+ if (FLAG_trace_profiled_isolates) {
+ intptr_t total_live_code_objects = live_code_table.Length();
+ intptr_t total_dead_code_objects = dead_code_table.Length();
+ OS::Print("Processed %" Pd " frames\n", frames);
+ OS::Print("CodeTables: live=%" Pd " dead=%" Pd "\n",
+ total_live_code_objects,
+ total_dead_code_objects);
+ }
#if defined(DEBUG)
- code_region_table.Verify();
+ live_code_table.Verify();
+ dead_code_table.Verify();
+ if (FLAG_trace_profiled_isolates) {
+ OS::Print("CodeRegionTables verified to be ordered and not overlap.\n");
+ }
#endif
+ CodeRegionTableCallersBuilder build_callers(isolate,
+ &live_code_table,
+ &dead_code_table);
{
+ // Build CodeRegion callers.
ScopeStopwatch sw("CodeTableCallersBuild");
sample_buffer->VisitSamples(&build_callers);
}
- // Number of samples we processed.
- intptr_t samples = builder.visited();
- intptr_t frames = builder.frames();
- if (FLAG_trace_profiled_isolates) {
- OS::Print("%" Pd " frames produced %" Pd " code objects.\n",
- frames, code_region_table.Length());
- }
{
ScopeStopwatch sw("CodeTableStream");
// Serialize to JSON.
@@ -846,8 +1056,13 @@ void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream,
obj.AddProperty("samples", samples);
obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros());
JSONArray codes(&obj, "codes");
- for (intptr_t i = 0; i < code_region_table.Length(); i++) {
- CodeRegion* region = code_region_table.At(i);
+ for (intptr_t i = 0; i < live_code_table.Length(); i++) {
+ CodeRegion* region = live_code_table.At(i);
+ ASSERT(region != NULL);
+ region->PrintToJSONArray(isolate, &codes, full);
+ }
+ for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
+ CodeRegion* region = dead_code_table.At(i);
ASSERT(region != NULL);
region->PrintToJSONArray(isolate, &codes, full);
}
« no previous file with comments | « runtime/vm/object.cc ('k') | runtime/vm/service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698