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

Unified Diff: runtime/vm/profiler.cc

Issue 109803002: Profiler Take 2 (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
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_android.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 8de6d12d59a7f87dfdecde35bbfd7d5cc1fb6b45..b08b2cd2a1e25a5b3198c3bbfa8078c1d4eb3b08 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -6,6 +6,7 @@
#include "platform/utils.h"
+#include "vm/atomic.h"
#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/native_symbol.h"
@@ -13,346 +14,206 @@
#include "vm/os.h"
#include "vm/profiler.h"
#include "vm/signal_handler.h"
+#include "vm/simulator.h"
namespace dart {
-// Notes on locking and signal handling:
-//
-// The ProfilerManager has a single monitor (monitor_). This monitor guards
-// access to the schedule list of isolates (isolates_, isolates_size_, etc).
-//
-// Each isolate has a mutex (profiler_data_mutex_) which protects access
-// to the isolate's profiler data.
-//
-// Locks can be taken in this order:
-// 1. ProfilerManager::monitor_
-// 2. isolate->profiler_data_mutex_
-// In other words, it is not acceptable to take ProfilerManager::monitor_
-// after grabbing isolate->profiler_data_mutex_.
-//
-// ProfileManager::monitor_ taking entry points:
-// InitOnce, Shutdown
-// ProfilerManager::monitor_
-// ScheduleIsolate, DescheduleIsolate.
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-// ThreadMain
-// isolate->profiler_data_mutex_ taking entry points:
-// SetupIsolateForProfiling, FreeIsolateForProfiling.
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-// ScheduleIsolate, DescheduleIsolate.
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-// ProfileSignalAction
-// isolate->profiler_data_mutex_
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-//
-// Signal handling and locking:
-// On OSes with pthreads (Android, Linux, and Mac) we use signal delivery
-// to interrupt the isolate running thread for sampling. After a thread
-// is sent the SIGPROF, it is removed from the scheduled isolate list.
-// Inside the signal handler, after the sample is taken, the isolate is
-// added to the scheduled isolate list again. The side effect of this is
-// that the signal handler must be able to acquire the isolate profiler data
-// mutex and the profile manager monitor. When an isolate running thread
-// (potential signal target) calls into an entry point which acquires
-// ProfileManager::monitor_ signal delivery must be blocked. An example is
-// ProfileManager::ScheduleIsolate which blocks signal delivery while removing
-// the scheduling the isolate.
-//
// Notes on stack frame walking:
//
// The sampling profiler will collect up to Sample::kNumStackFrames stack frames
// The stack frame walking code uses the frame pointer to traverse the stack.
// If the VM is compiled without frame pointers (which is the default on
-// recent GCC versions with optimizing enabled) the stack walking code will
+// recent GCC versions with optimizing enabled) the stack walking code may
// fail (sometimes leading to a crash).
//
-DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
+#if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
+ defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID)
+ DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
+#else
+ DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
+#endif
DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
+DEFINE_FLAG(charp, profile_dir, NULL,
+ "Enable writing profile data into specified directory.");
-bool ProfilerManager::initialized_ = false;
-bool ProfilerManager::shutdown_ = false;
-bool ProfilerManager::thread_running_ = false;
-Monitor* ProfilerManager::monitor_ = NULL;
-Monitor* ProfilerManager::start_stop_monitor_ = NULL;
-Isolate** ProfilerManager::isolates_ = NULL;
-intptr_t ProfilerManager::isolates_capacity_ = 0;
-intptr_t ProfilerManager::isolates_size_ = 0;
-
+bool Profiler::initialized_ = false;
+Monitor* Profiler::monitor_ = NULL;
+SampleBuffer* Profiler::sample_buffer_ = NULL;
-void ProfilerManager::InitOnce() {
-#if defined(USING_SIMULATOR)
- // Force disable of profiling on simulator.
- FLAG_profile = false;
-#endif
-#if defined(TARGET_OS_WINDOWS)
- // Force disable of profiling on Windows.
- FLAG_profile = false;
-#endif
+void Profiler::InitOnce() {
if (!FLAG_profile) {
return;
}
- NativeSymbolResolver::InitOnce();
ASSERT(!initialized_);
- monitor_ = new Monitor();
- start_stop_monitor_ = new Monitor();
initialized_ = true;
- ResizeIsolates(16);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager starting up.\n");
- }
- {
- ScopedMonitor startup_lock(start_stop_monitor_);
- Thread::Start(ThreadMain, 0);
- while (!thread_running_) {
- // Wait until profiler thread has started up.
- startup_lock.Wait();
- }
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager running.\n");
- }
+ monitor_ = new Monitor();
+ sample_buffer_ = new SampleBuffer();
+ NativeSymbolResolver::InitOnce();
+ ThreadInterrupter::InitOnce();
}
-void ProfilerManager::Shutdown() {
+void Profiler::Shutdown() {
if (!FLAG_profile) {
return;
}
ASSERT(initialized_);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager shutting down.\n");
- }
- intptr_t size_at_shutdown = 0;
- {
- ScopedSignalBlocker ssb;
- {
- ScopedMonitor lock(monitor_);
- shutdown_ = true;
- size_at_shutdown = isolates_size_;
- isolates_size_ = 0;
- free(isolates_);
- isolates_ = NULL;
- lock.Notify();
- }
- }
+ ThreadInterrupter::Shutdown();
NativeSymbolResolver::ShutdownOnce();
- {
- ScopedMonitor shutdown_lock(start_stop_monitor_);
- while (thread_running_) {
- // Wait until profiler thread has exited.
- shutdown_lock.Wait();
- }
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager shut down (%" Pd ").\n", size_at_shutdown);
- }
}
-void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) {
+void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
if (!FLAG_profile) {
return;
}
ASSERT(isolate != NULL);
+ ASSERT(sample_buffer_ != NULL);
+ MonitorLocker ml(monitor_);
{
- ScopedSignalBlocker ssb;
- {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- SampleBuffer* sample_buffer = new SampleBuffer();
- ASSERT(sample_buffer != NULL);
- IsolateProfilerData* profiler_data =
- new IsolateProfilerData(isolate, sample_buffer);
- ASSERT(profiler_data != NULL);
- profiler_data->set_sample_interval_micros(1000);
- isolate->set_profiler_data(profiler_data);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Setup Isolate %p %s %p\n",
- isolate,
- isolate->name(),
- reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
- }
+ MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
+ SampleBuffer* sample_buffer = sample_buffer_;
+ if (!shared_buffer) {
+ sample_buffer = new SampleBuffer();
+ }
+ IsolateProfilerData* profiler_data =
+ new IsolateProfilerData(sample_buffer, !shared_buffer);
+ ASSERT(profiler_data != NULL);
+ isolate->set_profiler_data(profiler_data);
+ if (FLAG_trace_profiled_isolates) {
+ OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
}
}
}
-void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- // Already freed.
- return;
- }
- isolate->set_profiler_data(NULL);
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- ASSERT(sample_buffer != NULL);
- profiler_data->set_sample_buffer(NULL);
- delete sample_buffer;
- delete profiler_data;
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Shutdown Isolate %p %s %p\n",
- isolate,
- isolate->name(),
- reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
- }
-}
-
-
-void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) {
+void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
ASSERT(isolate != NULL);
if (!FLAG_profile) {
return;
}
+ // We do not have a current isolate.
+ ASSERT(Isolate::Current() == NULL);
+ MonitorLocker ml(monitor_);
{
- ScopedSignalBlocker ssb;
- FreeIsolateProfilingData(isolate);
- }
-}
-
-
-void ProfilerManager::ScheduleIsolateHelper(Isolate* isolate) {
- ScopedMonitor lock(monitor_);
- {
- if (shutdown_) {
- // Shutdown.
- return;
- }
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
+ MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
IsolateProfilerData* profiler_data = isolate->profiler_data();
if (profiler_data == NULL) {
+ // Already freed.
return;
}
- profiler_data->Scheduled(OS::GetCurrentTimeMicros(),
- Thread::GetCurrentThreadId());
- }
- intptr_t i = FindIsolate(isolate);
- if (i >= 0) {
- // Already scheduled.
- return;
+ isolate->set_profiler_data(NULL);
+ profiler_data->set_sample_buffer(NULL);
+ delete profiler_data;
+ if (FLAG_trace_profiled_isolates) {
+ OS::Print("Profiler Shutdown %p %s\n", isolate, isolate->name());
+ }
}
- AddIsolate(isolate);
- lock.Notify();
}
-void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) {
+void Profiler::BeginExecution(Isolate* isolate) {
+ if (isolate == NULL) {
+ return;
+ }
if (!FLAG_profile) {
return;
}
ASSERT(initialized_);
- ASSERT(isolate != NULL);
- if (!inside_signal) {
- ScopedSignalBlocker ssb;
- {
- ScheduleIsolateHelper(isolate);
- }
- } else {
- // Do not need a signal blocker inside a signal handler.
- {
- ScheduleIsolateHelper(isolate);
- }
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
+ }
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
}
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateStart, isolate, OS::GetCurrentTimeMicros(),
+ Thread::GetCurrentThreadId());
+ ThreadInterrupter::Register(RecordSampleInterruptCallback, isolate);
}
-void ProfilerManager::DescheduleIsolate(Isolate* isolate) {
+void Profiler::EndExecution(Isolate* isolate) {
+ if (isolate == NULL) {
+ return;
+ }
if (!FLAG_profile) {
return;
}
ASSERT(initialized_);
- ASSERT(isolate != NULL);
- {
- ScopedSignalBlocker ssb;
- {
- ScopedMonitor lock(monitor_);
- if (shutdown_) {
- // Shutdown.
- return;
- }
- intptr_t i = FindIsolate(isolate);
- if (i < 0) {
- // Not scheduled.
- return;
- }
- {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data != NULL) {
- profiler_data->Descheduled();
- }
- }
- RemoveIsolate(i);
- lock.Notify();
- }
+ ThreadInterrupter::Unregister();
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
}
-}
-
-
-void PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
- ASSERT(isolate == Isolate::Current());
- {
- // We can't get signals here.
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
}
- UNIMPLEMENTED();
-}
-
-
-void ProfilerManager::ResizeIsolates(intptr_t new_capacity) {
- ASSERT(new_capacity < kMaxProfiledIsolates);
- ASSERT(new_capacity > isolates_capacity_);
- Isolate* isolate = NULL;
- isolates_ = reinterpret_cast<Isolate**>(
- realloc(isolates_, sizeof(isolate) * new_capacity));
- isolates_capacity_ = new_capacity;
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateStop, isolate, OS::GetCurrentTimeMicros(),
+ Thread::GetCurrentThreadId());
}
-void ProfilerManager::AddIsolate(Isolate* isolate) {
- // Must be called with monitor_ locked.
- if (isolates_ == NULL) {
- // We are shutting down.
+void Profiler::RecordTickInterruptCallback(const InterruptedThreadState& state,
+ void* data) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(data);
+ if (isolate == NULL) {
return;
}
- if (isolates_size_ == isolates_capacity_) {
- ResizeIsolates(isolates_capacity_ == 0 ? 16 : isolates_capacity_ * 2);
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
}
- isolates_[isolates_size_] = isolate;
- isolates_size_++;
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
+ }
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
+ state.tid);
}
-intptr_t ProfilerManager::FindIsolate(Isolate* isolate) {
- // Must be called with monitor_ locked.
- if (isolates_ == NULL) {
- // We are shutting down.
- return -1;
+void Profiler::RecordSampleInterruptCallback(
+ const InterruptedThreadState& state,
+ void* data) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(data);
+ if (isolate == NULL) {
+ return;
}
- for (intptr_t i = 0; i < isolates_size_; i++) {
- if (isolates_[i] == isolate) {
- return i;
- }
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
}
- return -1;
-}
-
-
-void ProfilerManager::RemoveIsolate(intptr_t i) {
- // Must be called with monitor_ locked.
- if (isolates_ == NULL) {
- // We are shutting down.
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
return;
}
- ASSERT(i < isolates_size_);
- intptr_t last = isolates_size_ - 1;
- if (i != last) {
- isolates_[i] = isolates_[last];
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
+ state.tid);
+ uintptr_t stack_lower = 0;
+ uintptr_t stack_upper = 0;
+ isolate->GetStackBounds(&stack_lower, &stack_upper);
+ if ((stack_lower == 0) || (stack_upper == 0)) {
+ stack_lower = 0;
+ stack_upper = 0;
}
- // Mark last as NULL.
- isolates_[last] = NULL;
- // Pop.
- isolates_size_--;
+ ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
+ state.pc, state.fp, state.sp);
+ stackWalker.walk();
+}
+
+
+void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
+ ASSERT(isolate == Isolate::Current());
+ UNIMPLEMENTED();
}
@@ -362,6 +223,9 @@ static char* FindSymbolName(uintptr_t pc, bool* native_symbol) {
ASSERT(native_symbol != NULL);
const char* symbol_name = "Unknown";
*native_symbol = false;
+ if (pc == 0) {
+ return const_cast<char*>(Sample::kNoFrame);
+ }
const Code& code = Code::Handle(Code::LookupCode(pc));
if (code.IsNull()) {
// Possibly a native symbol.
@@ -383,203 +247,181 @@ static char* FindSymbolName(uintptr_t pc, bool* native_symbol) {
}
-void ProfilerManager::WriteTracing(Isolate* isolate, const char* name,
- Dart_Port port) {
- ASSERT(isolate == Isolate::Current());
- {
- ScopedSignalBlocker ssb;
- {
- ScopedMutex 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);
- JSONStream stream(10 * MB);
- intptr_t tid = reinterpret_cast<intptr_t>(sample_buffer);
- intptr_t pid = 1;
- {
- JSONArray events(&stream);
+void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid,
+ Sample* sample, JSONArray& events) {
+ Sample::SampleType type = sample->type;
+ intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid);
+ 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);
+ }
+ 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.
+ for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
+ bool native_symbol = false;
+ char* symbol_name = FindSymbolName(sample->pcs[i], &native_symbol);
{
- JSONObject thread_name(&events);
- thread_name.AddProperty("name", "thread_name");
- thread_name.AddProperty("ph", "M");
- thread_name.AddProperty("tid", tid);
- thread_name.AddProperty("pid", pid);
- {
- JSONObject args(&thread_name, "args");
- args.AddProperty("name", name);
- }
+ 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 (native_symbol) {
+ NativeSymbolResolver::FreeSymbolName(symbol_name);
}
+ }
+ // Write "E" events.
+ for (int i = 0; i < Sample::kNumStackFrames; i++) {
+ bool native_symbol = false;
+ char* symbol_name = FindSymbolName(sample->pcs[i], &native_symbol);
{
- JSONObject process_name(&events);
- process_name.AddProperty("name", "process_name");
- process_name.AddProperty("ph", "M");
- process_name.AddProperty("tid", tid);
- process_name.AddProperty("pid", pid);
- {
- JSONObject args(&process_name, "args");
- args.AddProperty("name", "Dart VM");
- }
+ JSONObject begin(&events);
+ begin.AddProperty("ph", "E");
+ begin.AddProperty("tid", tid);
+ begin.AddProperty("pid", pid);
+ begin.AddProperty("name", symbol_name);
+ begin.AddProperty("ts", timestamp);
}
- uint64_t last_time = 0;
- for (Sample* i = sample_buffer->FirstSample();
- i != sample_buffer->LastSample();
- i = sample_buffer->NextSample(i)) {
- if (last_time == 0) {
- last_time = i->timestamp;
- }
- intptr_t delta = i->timestamp - last_time;
- {
- double percentage = static_cast<double>(i->cpu_usage) /
- static_cast<double>(delta) * 100.0;
- if (percentage != percentage) {
- percentage = 0.0;
- }
- percentage = percentage < 0.0 ? 0.0 : percentage;
- percentage = percentage > 100.0 ? 100.0 : percentage;
- {
- JSONObject cpu_usage(&events);
- cpu_usage.AddProperty("name", "CPU Usage");
- cpu_usage.AddProperty("ph", "C");
- cpu_usage.AddProperty("tid", tid);
- cpu_usage.AddProperty("pid", pid);
- cpu_usage.AddProperty("ts", static_cast<double>(last_time));
- {
- JSONObject args(&cpu_usage, "args");
- args.AddProperty("CPU", percentage);
- }
- }
- {
- JSONObject cpu_usage(&events);
- cpu_usage.AddProperty("name", "CPU Usage");
- cpu_usage.AddProperty("ph", "C");
- cpu_usage.AddProperty("tid", tid);
- cpu_usage.AddProperty("pid", pid);
- cpu_usage.AddProperty("ts", static_cast<double>(i->timestamp));
- {
- JSONObject args(&cpu_usage, "args");
- args.AddProperty("CPU", percentage);
- }
- }
- }
- for (int j = 0; j < Sample::kNumStackFrames; j++) {
- if (i->pcs[j] == 0) {
- continue;
- }
- bool native_symbol = false;
- char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol);
- {
- JSONObject begin(&events);
- begin.AddProperty("ph", "B");
- begin.AddProperty("tid", tid);
- begin.AddProperty("pid", pid);
- begin.AddProperty("name", symbol_name);
- begin.AddProperty("ts", static_cast<double>(last_time));
- }
- if (native_symbol) {
- NativeSymbolResolver::FreeSymbolName(symbol_name);
- }
- }
- for (int j = Sample::kNumStackFrames-1; j >= 0; j--) {
- if (i->pcs[j] == 0) {
- continue;
- }
- bool native_symbol = false;
- char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol);
- {
- JSONObject end(&events);
- end.AddProperty("ph", "E");
- end.AddProperty("tid", tid);
- end.AddProperty("pid", pid);
- end.AddProperty("name", symbol_name);
- end.AddProperty("ts", static_cast<double>(i->timestamp));
- }
- if (native_symbol) {
- NativeSymbolResolver::FreeSymbolName(symbol_name);
- }
- }
- last_time = i->timestamp;
+ if (native_symbol) {
+ NativeSymbolResolver::FreeSymbolName(symbol_name);
}
}
- char fname[1024];
- #if defined(TARGET_OS_WINDOWS)
- snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d.prof",
- static_cast<int>(port));
- #else
- snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d.prof",
- static_cast<int>(port));
- #endif
- printf("%s\n", fname);
- FILE* f = fopen(fname, "wb");
- ASSERT(f != NULL);
- fputs(stream.ToCString(), f);
- fclose(f);
- }
+ break;
+ default:
+ UNIMPLEMENTED();
}
}
-IsolateProfilerData::IsolateProfilerData(Isolate* isolate,
- SampleBuffer* sample_buffer) {
- isolate_ = isolate;
- sample_buffer_ = sample_buffer;
- timer_expiration_micros_ = kNoExpirationTime;
- last_sampled_micros_ = 0;
- thread_id_ = 0;
-}
-
-
-IsolateProfilerData::~IsolateProfilerData() {
-}
-
-
-void IsolateProfilerData::SampledAt(int64_t current_time) {
- last_sampled_micros_ = current_time;
+void Profiler::WriteTracing(Isolate* isolate) {
+ if (isolate == NULL) {
+ return;
+ }
+ if (!FLAG_profile) {
+ return;
+ }
+ ASSERT(initialized_);
+ if (FLAG_profile_dir == NULL) {
+ return;
+ }
+ Dart_FileOpenCallback file_open = Isolate::file_open_callback();
+ Dart_FileCloseCallback file_close = Isolate::file_close_callback();
+ Dart_FileWriteCallback file_write = Isolate::file_write_callback();
+ if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) {
+ // Embedder has not provided necessary callbacks.
+ 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);
+ 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);
+ }
+ }
+ const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json";
+ intptr_t len = OS::SNPrint(NULL, 0, format,
+ FLAG_profile_dir, pid, isolate->main_port());
+ char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(filename, len + 1, format,
+ FLAG_profile_dir, pid, isolate->main_port());
+ void* f = file_open(filename, true);
+ if (f == NULL) {
+ // Cannot write.
+ return;
+ }
+ TextBuffer* buffer = stream.buffer();
+ ASSERT(buffer != NULL);
+ file_write(buffer->buf(), buffer->length(), f);
+ file_close(f);
+ BeginExecution(isolate);
}
-void IsolateProfilerData::Scheduled(int64_t current_time, ThreadId thread_id) {
- timer_expiration_micros_ = current_time + sample_interval_micros_;
- thread_id_ = thread_id;
- Thread::GetThreadCpuUsage(thread_id_, &cpu_usage_);
+IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
+ bool own_sample_buffer) {
+ sample_buffer_ = sample_buffer;
+ own_sample_buffer_ = own_sample_buffer;
}
-void IsolateProfilerData::Descheduled() {
- // TODO(johnmccutchan): Track when we ran for a fraction of our sample
- // interval and incorporate the time difference when scheduling the
- // isolate again.
- cpu_usage_ = kDescheduledCpuUsage;
- timer_expiration_micros_ = kNoExpirationTime;
- Sample* sample = sample_buffer_->ReserveSample();
- ASSERT(sample != NULL);
- sample->timestamp = OS::GetCurrentTimeMicros();
- sample->cpu_usage = 0;
- sample->vm_tags = Sample::kIdle;
+IsolateProfilerData::~IsolateProfilerData() {
+ if (own_sample_buffer_) {
+ delete sample_buffer_;
+ sample_buffer_ = NULL;
+ own_sample_buffer_ = false;
+ }
}
const char* Sample::kLookupSymbol = "Symbol Not Looked Up";
const char* Sample::kNoSymbol = "No Symbol Found";
-
-Sample::Sample() {
- timestamp = 0;
- cpu_usage = 0;
- for (int i = 0; i < kNumStackFrames; i++) {
+const char* Sample::kNoFrame = "<no frame>";
+
+void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp,
+ ThreadId tid) {
+ this->timestamp = timestamp;
+ this->tid = tid;
+ this->isolate = isolate;
+ for (intptr_t i = 0; i < kNumStackFrames; i++) {
pcs[i] = 0;
}
- vm_tags = kIdle;
+ this->type = type;
+ vm_tags = 0;
runtime_tags = 0;
}
-
SampleBuffer::SampleBuffer(intptr_t capacity) {
- start_ = 0;
- end_ = 0;
capacity_ = capacity;
samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample)));
+ cursor_ = 0;
}
@@ -587,8 +429,7 @@ SampleBuffer::~SampleBuffer() {
if (samples_ != NULL) {
free(samples_);
samples_ = NULL;
- start_ = 0;
- end_ = 0;
+ cursor_ = 0;
capacity_ = 0;
}
}
@@ -596,40 +437,10 @@ SampleBuffer::~SampleBuffer() {
Sample* SampleBuffer::ReserveSample() {
ASSERT(samples_ != NULL);
- intptr_t index = end_;
- end_ = WrapIncrement(end_);
- if (end_ == start_) {
- start_ = WrapIncrement(start_);
- }
- ASSERT(index >= 0);
- ASSERT(index < capacity_);
- // Reset.
- samples_[index] = Sample();
- return &samples_[index];
-}
-
-
-Sample* SampleBuffer::FirstSample() const {
- return &samples_[start_];
-}
-
-
-Sample* SampleBuffer::NextSample(Sample* sample) const {
- ASSERT(sample >= &samples_[0]);
- ASSERT(sample < &samples_[capacity_]);
- intptr_t index = sample - samples_;
- index = WrapIncrement(index);
- return &samples_[index];
-}
-
-
-Sample* SampleBuffer::LastSample() const {
- return &samples_[end_];
-}
-
-
-intptr_t SampleBuffer::WrapIncrement(intptr_t i) const {
- return (i + 1) % capacity_;
+ uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
+ // Map back into sample buffer range.
+ cursor = cursor % capacity_;
+ return &samples_[cursor];
}
@@ -652,6 +463,7 @@ ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample,
int ProfilerSampleStackWalker::walk() {
uword* pc = reinterpret_cast<uword*>(original_pc_);
+#define WALK_STACK
#if defined(WALK_STACK)
uword* fp = reinterpret_cast<uword*>(original_fp_);
uword* previous_fp = fp;
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_android.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698