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

Unified Diff: runtime/vm/profiler.cc

Issue 100103011: Changes to support dprof and Observatory profiler UIs (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years 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
Index: runtime/vm/profiler.cc
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d2545208bf45d2c164446119a59f562de67be46a..51eb1769f7a4a09cb2474058fa3ef458046e28c9 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -6,7 +6,9 @@
#include "platform/utils.h"
+#include "vm/allocation.h"
#include "vm/atomic.h"
+#include "vm/code_patcher.h"
#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/native_symbol.h"
@@ -218,124 +220,304 @@ void Profiler::RecordSampleInterruptCallback(
}
-void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
- ASSERT(isolate == Isolate::Current());
- UNIMPLEMENTED();
-}
+class SymbolLookupCache {
+ public:
+ explicit SymbolLookupCache(const intptr_t cache_size = 32) {
+ cache_index_ = 0;
+ cache_size_ = cache_size;
+ pcs_ = reinterpret_cast<uintptr_t*>(
+ calloc(cache_size, sizeof(uintptr_t))); // NOLINT
+ names_ = reinterpret_cast<const char**>(
+ calloc(cache_size, sizeof(const char*))); // NOLINT
+ }
+
+ virtual ~SymbolLookupCache() {
+ for (intptr_t i = 0; i < cache_size_; i++) {
+ ClearCacheIndex(i);
+ }
+ free(pcs_);
+ free(names_);
+ }
+
+ const char* Lookup(uintptr_t pc) {
+ const char* symbol = LookupInCache(pc);
+ if (symbol != NULL) {
+ return symbol;
+ }
+ symbol = QuerySource(pc);
+ if (symbol != NULL) {
+ InsertIntoCache(pc, symbol);
+ }
+ return symbol;
+ }
+
+ virtual const char* QuerySource(uintptr_t pc) const = 0;
+ protected:
+ const char* GenerateSymbolName(const char* prefix, uintptr_t pc) const {
+ // Generate a name by binning into buckets by PC.
+ const intptr_t kBucketSize = 256;
+ const intptr_t kBucketMask = ~(kBucketSize - 1);
+ pc &= kBucketMask;
+ const intptr_t kBuffSize = 256;
+ char buff[kBuffSize];
+ OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
+ prefix, pc, pc + kBucketSize);
+ return strdup(buff);
+ }
-static const char* FindSymbolName(uintptr_t pc, bool* symbol_name_allocated) {
- // TODO(johnmccutchan): Differentiate between symbols which can't be found
- // and symbols which were GCed. (Heap::CodeContains).
- ASSERT(symbol_name_allocated != NULL);
- const char* symbol_name = "Unknown";
- *symbol_name_allocated = false;
- if (pc == 0) {
- return const_cast<char*>(Sample::kNoFrame);
- }
- const Code& code = Code::Handle(Code::LookupCode(pc));
- if (!code.IsNull()) {
- const Function& function = Function::Handle(code.function());
- if (!function.IsNull()) {
- const String& name = String::Handle(function.QualifiedUserVisibleName());
- if (!name.IsNull()) {
- symbol_name = name.ToCString();
- return symbol_name;
+ private:
+ const char* LookupInCache(uintptr_t pc) {
+ for (intptr_t i = 0; i < cache_size_; i++) {
+ if (pcs_[i] == pc) {
+ ASSERT(names_[i] != NULL);
+ return names_[i];
}
}
- } else {
- // Possibly a native symbol.
+ return NULL;
+ }
+
+ intptr_t GetCacheIndex(uintptr_t pc) {
+ cache_index_ = (cache_index_ + 1) % cache_size_;
+ return cache_index_;
+ }
+
+ void InsertIntoCache(uintptr_t pc, const char* name) {
+ intptr_t index = GetCacheIndex(pc);
+ ClearCacheIndex(index);
+ pcs_[index] = pc;
+ names_[index] = name;
+ }
+
+ void ClearCacheIndex(intptr_t index) {
+ free(const_cast<char*>(names_[index]));
+ names_[index] = NULL;
+ pcs_[index] = 0;
+ }
+
+ intptr_t cache_index_;
+ intptr_t cache_size_;
+ uintptr_t* pcs_;
+ const char** names_;
+};
+
+
+class NativeSymbolLookup : public SymbolLookupCache {
+ public:
+ NativeSymbolLookup() : SymbolLookupCache(32) {
+ }
+
+ const char* QuerySource(uintptr_t pc) const {
char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
- if (native_name != NULL) {
- symbol_name = native_name;
- *symbol_name_allocated = true;
- return symbol_name;
+ if (native_name == NULL) {
+ return GenerateSymbolName("Unknown", pc);
}
+ return native_name;
}
- const intptr_t kBucketSize = 256;
- const intptr_t kBucketMask = ~(kBucketSize - 1);
- // Not a Dart symbol or a native symbol. Bin into buckets by PC.
- pc &= kBucketMask;
+};
+
+
+class DartSymbolLookup : public SymbolLookupCache {
+ public:
+ explicit DartSymbolLookup(Isolate* isolate) : SymbolLookupCache(32),
+ isolate_(isolate),
+ heap_(isolate_->heap()) {
+ }
+
+ bool InDartCodeSpace(uintptr_t pc) {
+ ASSERT(heap_ != NULL);
+ return heap_->CodeContains(pc);
+ }
+
+ const char* QuerySource(uintptr_t pc) const {
+ const Code& code = Code::Handle(isolate_, Code::LookupCode(pc));
+ if (!code.IsNull()) {
+ const Function& function = Function::Handle(isolate_, code.function());
+ if (!function.IsNull()) {
+ const String& name =
+ String::Handle(isolate_, function.QualifiedUserVisibleName());
+ if (!name.IsNull()) {
+ return strdup(name.ToCString());
+ }
+ } else {
+ return GenerateSymbolName("Detached", pc);
+ }
+ }
+ return GenerateSymbolName("Collected", pc);
+ }
+
+ private:
+ Isolate* isolate_;
+ Heap* heap_;
+};
+
+
+class DartCodeTable {
+ public:
+ explicit DartCodeTable(Isolate* isolate) :
+ heap_(isolate->heap()),
+ code_table_(GrowableObjectArray::Handle(isolate)) {
+ code_table_ ^= GrowableObjectArray::New();
+ ASSERT(!code_table_.IsNull());
+ }
+
+ ~DartCodeTable() {
+ }
+
+ bool Contains(const Code& code) {
+ intptr_t length = code_table_.Length();
+ Code& table_code = Code::Handle();
+ for (intptr_t i = 0; i < length; i++) {
+ table_code ^= code_table_.At(i);
+ if (table_code.IsNull()) {
+ return false;
+ }
+ ASSERT(!table_code.IsNull());
+ if (table_code.raw() == code.raw()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void Add(const Code& code) {
+ ASSERT(!Contains(code));
+ code_table_.Add(code);
+ }
+
+ private:
+ Heap* heap_;
+ GrowableObjectArray& code_table_;
+};
+
+
+class ProfilerSymbolHelper {
+ public:
+ explicit ProfilerSymbolHelper(Isolate* isolate) :
+ dart_symbol_(isolate),
+ code_table_(isolate) {
+ }
+
+ ~ProfilerSymbolHelper() {
+ }
+
+
+ const char* GetSymbol(uintptr_t pc) {
+ if (pc == 0) {
+ return "<no frame>";
+ }
+ if (dart_symbol_.InDartCodeSpace(pc)) {
Ivan Posva 2013/12/30 23:06:09 Restructuring this as discussed will avoid iterati
+ return dart_symbol_.Lookup(pc);
+ } else {
+ return native_symbol_.Lookup(pc);
+ }
+ }
+
+
+ RawCode* GetNewCode(uintptr_t pc) {
+ Code& new_code = Code::Handle();
+ new_code ^= Code::LookupCode(pc);
Ivan Posva 2013/12/30 23:06:09 Here you are walking through the heap again. Looki
+ if (!new_code.IsNull()) {
+ Function& function = Function::Handle(new_code.function());
+ if (function.IsNull()) {
+ // If code no longer has a function, ignore it.
+ new_code ^= Code::null();
+ } else if (code_table_.Contains(new_code)) {
+ // If code has been serialized, ignore it.
+ new_code ^= Code::null();
+ } else {
+ // Add code to code table.
+ code_table_.Add(new_code);
+ }
+ }
+ return new_code.raw();
+ }
+
+ private:
+ DartSymbolLookup dart_symbol_;
+ DartCodeTable code_table_;
+ NativeSymbolLookup native_symbol_;
+};
+
+
+void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
+ ASSERT(isolate == Isolate::Current());
+ // Disable profile interrupts while processing the buffer.
+ EndExecution(isolate);
+ 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();
+ ASSERT(sample_buffer != NULL);
+ ProfilerSymbolHelper symbol_helper(isolate);
{
- const intptr_t kBuffSize = 256;
- char buff[kBuffSize];
- OS::SNPrint(&buff[0], kBuffSize-1, "Unknown [%" Px ", %" Px ")",
- pc, pc + kBucketSize);
- symbol_name = strdup(buff);
- *symbol_name_allocated = true;
+ JSONArray events(stream);
+ for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
+ Sample sample = sample_buffer->GetSample(i);
+ if (sample.isolate != isolate) {
+ continue;
+ }
+ if (sample.timestamp == 0) {
+ continue;
+ }
+ WriteSample(isolate, &symbol_helper, &sample, events);
+ }
}
- return symbol_name;
+ // Enable profile interrupts.
+ BeginExecution(isolate);
}
-void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid,
- Sample* sample, JSONArray& events) {
+void Profiler::WriteSample(Isolate* isolate,
+ ProfilerSymbolHelper* symbol_helper,
+ Sample* sample, JSONArray& events) {
+ StackZone zone(isolate);
+ Code& new_code = Code::Handle(isolate);
Sample::SampleType type = sample->type;
- intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid);
+ if (type != Sample::kIsolateSample) {
+ return;
+ }
double timestamp = static_cast<double>(sample->timestamp);
- const char* isolate_name = isolate->name();
- switch (type) {
- case Sample::kIsolateStart: {
- JSONObject begin(&events);
- begin.AddProperty("ph", "B");
- begin.AddProperty("tid", tid);
- begin.AddProperty("pid", pid);
- begin.AddProperty("name", isolate_name);
- begin.AddProperty("ts", timestamp);
+ bool any = false;
+ for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
+ if (sample->pcs[i] == 0) {
+ continue;
}
- break;
- case Sample::kIsolateStop: {
- JSONObject begin(&events);
- begin.AddProperty("ph", "E");
- begin.AddProperty("tid", tid);
- begin.AddProperty("pid", pid);
- begin.AddProperty("name", isolate_name);
- begin.AddProperty("ts", timestamp);
- }
- break;
- case Sample::kIsolateSample:
- // Write "B" events.
+ any = true;
+ }
+ if (!any) {
+ // No frames in this sample.
+ return;
+ }
+ {
+ JSONObject sample_event(&events);
+ sample_event.AddProperty("ts", timestamp);
+ {
+ JSONArray frames(&sample_event, "f");
for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
- bool symbol_name_allocated = false;
- const char* symbol_name = FindSymbolName(sample->pcs[i],
- &symbol_name_allocated);
- {
- JSONObject begin(&events);
- begin.AddProperty("ph", "B");
- begin.AddProperty("tid", tid);
- begin.AddProperty("pid", pid);
- begin.AddProperty("name", symbol_name);
- begin.AddProperty("ts", timestamp);
+ if (sample->pcs[i] == 0) {
+ continue;
}
- if (symbol_name_allocated) {
- free(const_cast<char*>(symbol_name));
+ const char* symbol_name = symbol_helper->GetSymbol(sample->pcs[i]);
+ new_code ^= symbol_helper->GetNewCode(sample->pcs[i]);
+ if (!new_code.IsNull()) {
+ // Dump code.
+ frames.AddValue(new_code, false);
}
- }
- // Write "E" events.
- for (int i = 0; i < Sample::kNumStackFrames; i++) {
- bool symbol_name_allocated = false;
- const char* symbol_name = FindSymbolName(sample->pcs[i],
- &symbol_name_allocated);
{
- JSONObject begin(&events);
- begin.AddProperty("ph", "E");
- begin.AddProperty("tid", tid);
- begin.AddProperty("pid", pid);
- begin.AddProperty("name", symbol_name);
- begin.AddProperty("ts", timestamp);
- }
- if (symbol_name_allocated) {
- free(const_cast<char*>(symbol_name));
+ JSONObject tick(&frames);
+ tick.AddProperty("s", symbol_name);
+ tick.AddPropertyF("pc", "%" Px "", sample->pcs[i]);
}
}
- break;
- default:
- UNIMPLEMENTED();
+ }
}
}
-void Profiler::WriteTracing(Isolate* isolate) {
+void Profiler::WriteSamples(Isolate* isolate) {
if (isolate == NULL) {
return;
}
@@ -354,41 +536,10 @@ void Profiler::WriteTracing(Isolate* isolate) {
return;
}
// We will be looking up code objects within the isolate.
- ASSERT(Isolate::Current() != NULL);
- // We do not want to be interrupted while processing the buffer.
- EndExecution(isolate);
- 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();
- ASSERT(sample_buffer != NULL);
+ ASSERT(Isolate::Current() == isolate);
JSONStream stream(10 * MB);
intptr_t pid = OS::ProcessId();
- {
- JSONArray events(&stream);
- {
- JSONObject process_name(&events);
- process_name.AddProperty("name", "process_name");
- process_name.AddProperty("ph", "M");
- process_name.AddProperty("pid", pid);
- {
- JSONObject args(&process_name, "args");
- args.AddProperty("name", "Dart VM");
- }
- }
- for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
- Sample* sample = sample_buffer->GetSample(i);
- if (sample->isolate != isolate) {
- continue;
- }
- if (sample->timestamp == 0) {
- continue;
- }
- WriteTracingSample(isolate, pid, sample, events);
- }
- }
+ PrintToJSONStream(isolate, &stream);
const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json";
intptr_t len = OS::SNPrint(NULL, 0, format,
FLAG_profile_dir, pid, isolate->main_port());
@@ -404,7 +555,6 @@ void Profiler::WriteTracing(Isolate* isolate) {
ASSERT(buffer != NULL);
file_write(buffer->buf(), buffer->length(), f);
file_close(f);
- BeginExecution(isolate);
}

Powered by Google App Engine
This is Rietveld 408576698