Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include <cstdio> | 5 #include <cstdio> |
| 6 | 6 |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 | 8 |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/json_stream.h" | 10 #include "vm/json_stream.h" |
| 11 #include "vm/native_symbol.h" | 11 #include "vm/native_symbol.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/os.h" | 13 #include "vm/os.h" |
| 14 #include "vm/profiler.h" | 14 #include "vm/profiler.h" |
| 15 #include "vm/signal_handler.h" | |
| 15 | 16 |
| 16 namespace dart { | 17 namespace dart { |
| 17 | 18 |
| 18 // Notes on locking and signal handling: | 19 // Notes on locking and signal handling: |
| 19 // | 20 // |
| 20 // The ProfilerManager has a single monitor (monitor_). This monitor guards | 21 // The ProfilerManager has a single monitor (monitor_). This monitor guards |
| 21 // access to the schedule list of isolates (isolates_, isolates_size_, etc). | 22 // access to the schedule list of isolates (isolates_, isolates_size_, etc). |
| 22 // | 23 // |
| 23 // Each isolate has a mutex (profiler_data_mutex_) which protects access | 24 // Each isolate has a mutex (profiler_data_mutex_) which protects access |
| 24 // to the isolate's profiler data. | 25 // to the isolate's profiler data. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 47 // Signal handling and locking: | 48 // Signal handling and locking: |
| 48 // On OSes with pthreads (Android, Linux, and Mac) we use signal delivery | 49 // On OSes with pthreads (Android, Linux, and Mac) we use signal delivery |
| 49 // to interrupt the isolate running thread for sampling. After a thread | 50 // to interrupt the isolate running thread for sampling. After a thread |
| 50 // is sent the SIGPROF, it is removed from the scheduled isolate list. | 51 // is sent the SIGPROF, it is removed from the scheduled isolate list. |
| 51 // Inside the signal handler, after the sample is taken, the isolate is | 52 // Inside the signal handler, after the sample is taken, the isolate is |
| 52 // added to the scheduled isolate list again. The side effect of this is | 53 // added to the scheduled isolate list again. The side effect of this is |
| 53 // that the signal handler must be able to acquire the isolate profiler data | 54 // that the signal handler must be able to acquire the isolate profiler data |
| 54 // mutex and the profile manager monitor. When an isolate running thread | 55 // mutex and the profile manager monitor. When an isolate running thread |
| 55 // (potential signal target) calls into an entry point which acquires | 56 // (potential signal target) calls into an entry point which acquires |
| 56 // ProfileManager::monitor_ signal delivery must be blocked. An example is | 57 // ProfileManager::monitor_ signal delivery must be blocked. An example is |
| 57 // Isolate::SetCurrent which blocks signal delivery while removing the old | 58 // ProfileManager::ScheduleIsolate which blocks signal delivery while removing |
| 58 // current isolate from the scheduled list and adding the new current isolate | 59 // the scheduling the isolate. |
| 59 // to the scheduled list. | |
| 60 // | 60 // |
| 61 | 61 |
| 62 // Notes on stack frame walking: | 62 // Notes on stack frame walking: |
| 63 // | 63 // |
| 64 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames | 64 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames |
| 65 // The stack frame walking code uses the frame pointer to traverse the stack. | 65 // The stack frame walking code uses the frame pointer to traverse the stack. |
| 66 // If the VM is compiled without frame pointers (which is the default on | 66 // If the VM is compiled without frame pointers (which is the default on |
| 67 // recent GCC versions with optimizing enabled) the stack walking code will | 67 // recent GCC versions with optimizing enabled) the stack walking code will |
| 68 // fail (sometimes leading to a crash). | 68 // fail (sometimes leading to a crash). |
| 69 // | 69 // |
| 70 | 70 |
| 71 | 71 |
| 72 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); | 72 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); |
| 73 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); | |
| 73 | 74 |
| 74 bool ProfilerManager::initialized_ = false; | 75 bool ProfilerManager::initialized_ = false; |
| 75 bool ProfilerManager::shutdown_ = false; | 76 bool ProfilerManager::shutdown_ = false; |
| 76 Monitor* ProfilerManager::monitor_ = NULL; | 77 Monitor* ProfilerManager::monitor_ = NULL; |
| 77 Isolate** ProfilerManager::isolates_ = NULL; | 78 Isolate** ProfilerManager::isolates_ = NULL; |
| 78 intptr_t ProfilerManager::isolates_capacity_ = 0; | 79 intptr_t ProfilerManager::isolates_capacity_ = 0; |
| 79 intptr_t ProfilerManager::isolates_size_ = 0; | 80 intptr_t ProfilerManager::isolates_size_ = 0; |
| 80 | 81 |
| 81 | 82 |
| 82 void ProfilerManager::InitOnce() { | 83 void ProfilerManager::InitOnce() { |
| 83 if (!FLAG_profile) { | 84 if (!FLAG_profile) { |
| 84 return; | 85 return; |
| 85 } | 86 } |
| 86 NativeSymbolResolver::InitOnce(); | 87 NativeSymbolResolver::InitOnce(); |
| 87 ASSERT(!initialized_); | 88 ASSERT(!initialized_); |
| 88 monitor_ = new Monitor(); | 89 monitor_ = new Monitor(); |
| 89 initialized_ = true; | 90 initialized_ = true; |
| 90 ResizeIsolates(16); | 91 ResizeIsolates(16); |
| 91 Thread::Start(ThreadMain, 0); | 92 Thread::Start(ThreadMain, 0); |
| 92 } | 93 } |
| 93 | 94 |
| 94 | 95 |
| 95 void ProfilerManager::Shutdown() { | 96 void ProfilerManager::Shutdown() { |
| 96 if (!FLAG_profile) { | 97 if (!FLAG_profile) { |
| 97 return; | 98 return; |
| 98 } | 99 } |
| 99 ASSERT(initialized_); | 100 ASSERT(initialized_); |
| 100 ScopedMonitor lock(monitor_); | 101 { |
| 101 shutdown_ = true; | 102 ScopedSignalBlocker ssb; |
| 102 for (intptr_t i = 0; i < isolates_size_; i++) { | 103 { |
| 103 Isolate* isolate = isolates_[i]; | 104 ScopedMonitor lock(monitor_); |
| 104 ASSERT(isolate != NULL); | 105 shutdown_ = true; |
| 105 FreeIsolateProfilingData(isolate); | 106 for (intptr_t i = 0; i < isolates_size_; i++) { |
| 107 Isolate* isolate = isolates_[i]; | |
| 108 ASSERT(isolate != NULL); | |
| 109 FreeIsolateProfilingData(isolate); | |
| 110 } | |
| 111 isolates_size_ = 0; | |
| 112 free(isolates_); | |
| 113 isolates_ = NULL; | |
| 114 lock.Notify(); | |
| 115 } | |
| 106 } | 116 } |
| 107 isolates_size_ = 0; | |
| 108 free(isolates_); | |
| 109 isolates_ = NULL; | |
| 110 lock.Notify(); | |
| 111 NativeSymbolResolver::ShutdownOnce(); | 117 NativeSymbolResolver::ShutdownOnce(); |
| 112 } | 118 } |
| 113 | 119 |
| 114 | 120 |
| 115 void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) { | 121 void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) { |
| 116 if (!FLAG_profile) { | 122 if (!FLAG_profile) { |
| 117 return; | 123 return; |
| 118 } | 124 } |
| 119 ASSERT(isolate != NULL); | 125 ASSERT(isolate != NULL); |
| 120 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | 126 { |
| 121 SampleBuffer* sample_buffer = new SampleBuffer(); | 127 ScopedSignalBlocker ssb; |
| 122 IsolateProfilerData* profiler_data = | 128 { |
| 123 new IsolateProfilerData(isolate, sample_buffer); | 129 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); |
| 124 profiler_data->set_sample_interval_micros(1000); | 130 SampleBuffer* sample_buffer = new SampleBuffer(); |
| 125 isolate->set_profiler_data(profiler_data); | 131 IsolateProfilerData* profiler_data = |
| 132 new IsolateProfilerData(isolate, sample_buffer); | |
| 133 profiler_data->set_sample_interval_micros(1000); | |
| 134 isolate->set_profiler_data(profiler_data); | |
| 135 if (FLAG_trace_profiled_isolates) { | |
| 136 OS::Print("PROF SETUP %p %s %p\n", | |
| 137 isolate, | |
| 138 isolate->name(), | |
| 139 reinterpret_cast<void*>(Thread::GetCurrentThreadId())); | |
| 140 } | |
| 141 } | |
| 142 } | |
| 126 } | 143 } |
| 127 | 144 |
| 128 | 145 |
| 129 void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) { | 146 void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) { |
| 130 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | 147 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); |
| 131 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 148 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 132 if (profiler_data == NULL) { | 149 if (profiler_data == NULL) { |
| 133 // Already freed. | 150 // Already freed. |
| 134 return; | 151 return; |
| 135 } | 152 } |
| 136 isolate->set_profiler_data(NULL); | 153 isolate->set_profiler_data(NULL); |
| 137 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 154 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 138 ASSERT(sample_buffer != NULL); | 155 ASSERT(sample_buffer != NULL); |
| 139 delete sample_buffer; | 156 delete sample_buffer; |
| 140 delete profiler_data; | 157 delete profiler_data; |
| 158 if (FLAG_trace_profiled_isolates) { | |
| 159 OS::Print("PROF SHUTDOWN %p %s %p\n", isolate, | |
| 160 isolate->name(), reinterpret_cast<void*>(Thread::GetCurrentThreadId())); | |
| 161 } | |
| 141 } | 162 } |
| 142 | 163 |
| 143 | 164 |
| 144 void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) { | 165 void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) { |
| 145 ASSERT(isolate != NULL); | 166 ASSERT(isolate != NULL); |
| 146 if (!FLAG_profile) { | 167 if (!FLAG_profile) { |
| 147 return; | 168 return; |
| 148 } | 169 } |
| 149 FreeIsolateProfilingData(isolate); | 170 { |
| 171 ScopedSignalBlocker ssb; | |
| 172 FreeIsolateProfilingData(isolate); | |
| 173 } | |
| 150 } | 174 } |
| 151 | 175 |
| 152 | 176 |
| 153 void ProfilerManager::ScheduleIsolate(Isolate* isolate) { | 177 void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) { |
| 154 if (!FLAG_profile) { | 178 if (!FLAG_profile) { |
| 155 return; | 179 return; |
| 156 } | 180 } |
| 157 ASSERT(initialized_); | 181 ASSERT(initialized_); |
| 158 ASSERT(isolate != NULL); | 182 ASSERT(isolate != NULL); |
| 159 ScopedMonitor lock(monitor_); | 183 { |
| 160 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | 184 ScopedSignalBlocker ssb; |
| 161 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 185 { |
| 162 if (profiler_data == NULL) { | 186 ScopedMonitor lock(monitor_); |
| 163 return; | 187 { |
| 188 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | |
| 189 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
| 190 if (profiler_data == NULL) { | |
| 191 return; | |
| 192 } | |
| 193 profiler_data->Scheduled(OS::GetCurrentTimeMicros(), | |
| 194 Thread::GetCurrentThreadId()); | |
| 195 AddIsolate(isolate); | |
| 196 lock.Notify(); | |
| 197 } | |
| 198 } | |
| 164 } | 199 } |
| 165 profiler_data->Scheduled(OS::GetCurrentTimeMicros(), | |
| 166 Thread::GetCurrentThreadId()); | |
| 167 AddIsolate(isolate); | |
| 168 lock.Notify(); | |
| 169 } | 200 } |
| 170 | 201 |
| 171 | 202 |
| 172 void ProfilerManager::DescheduleIsolate(Isolate* isolate) { | 203 void ProfilerManager::DescheduleIsolate(Isolate* isolate) { |
| 173 if (!FLAG_profile) { | 204 if (!FLAG_profile) { |
| 174 return; | 205 return; |
| 175 } | 206 } |
| 176 ASSERT(initialized_); | 207 ASSERT(initialized_); |
| 177 ASSERT(isolate != NULL); | 208 ASSERT(isolate != NULL); |
| 178 ScopedMonitor lock(monitor_); | 209 { |
| 179 intptr_t i = FindIsolate(isolate); | 210 ScopedSignalBlocker ssb; |
| 180 if (i < 0) { | 211 { |
| 181 // Not scheduled. | 212 ScopedMonitor lock(monitor_); |
| 182 return; | 213 intptr_t i = FindIsolate(isolate); |
| 214 if (i < 0) { | |
| 215 // Not scheduled. | |
| 216 return; | |
| 217 } | |
| 218 { | |
| 219 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | |
| 220 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
| 221 if (profiler_data != NULL) { | |
| 222 profiler_data->Descheduled(); | |
| 223 } | |
| 224 } | |
| 225 RemoveIsolate(i); | |
| 226 lock.Notify(); | |
| 227 } | |
| 183 } | 228 } |
| 184 { | |
| 185 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | |
| 186 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
| 187 ASSERT(profiler_data != NULL); | |
| 188 profiler_data->Descheduled(); | |
| 189 } | |
| 190 RemoveIsolate(i); | |
| 191 lock.Notify(); | |
| 192 } | 229 } |
| 193 | 230 |
| 194 | 231 |
| 195 void PrintToJSONStream(Isolate* isolate, JSONStream* stream) { | 232 void PrintToJSONStream(Isolate* isolate, JSONStream* stream) { |
| 196 ASSERT(isolate == Isolate::Current()); | 233 ASSERT(isolate == Isolate::Current()); |
| 197 { | 234 { |
| 198 // We can't get signals here. | 235 // We can't get signals here. |
| 199 } | 236 } |
| 200 UNIMPLEMENTED(); | 237 UNIMPLEMENTED(); |
| 201 } | 238 } |
| 202 | 239 |
| 203 | 240 |
| 204 void ProfilerManager::ResizeIsolates(intptr_t new_capacity) { | 241 void ProfilerManager::ResizeIsolates(intptr_t new_capacity) { |
| 205 ASSERT(new_capacity < kMaxProfiledIsolates); | 242 ASSERT(new_capacity < kMaxProfiledIsolates); |
| 206 ASSERT(new_capacity > isolates_capacity_); | 243 ASSERT(new_capacity > isolates_capacity_); |
| 207 Isolate* isolate = NULL; | 244 Isolate* isolate = NULL; |
| 208 isolates_ = reinterpret_cast<Isolate**>( | 245 isolates_ = reinterpret_cast<Isolate**>( |
| 209 realloc(isolates_, sizeof(isolate) * new_capacity)); | 246 realloc(isolates_, sizeof(isolate) * new_capacity)); |
| 210 isolates_capacity_ = new_capacity; | 247 isolates_capacity_ = new_capacity; |
| 211 } | 248 } |
| 212 | 249 |
| 213 | 250 |
| 214 void ProfilerManager::AddIsolate(Isolate* isolate) { | 251 void ProfilerManager::AddIsolate(Isolate* isolate) { |
| 252 // Must be called with monitor_ locked. | |
| 215 if (isolates_ == NULL) { | 253 if (isolates_ == NULL) { |
| 216 // We are shutting down. | 254 // We are shutting down. |
| 217 return; | 255 return; |
| 218 } | 256 } |
| 219 // Must be called with monitor_ locked. | |
| 220 if (isolates_size_ == isolates_capacity_) { | 257 if (isolates_size_ == isolates_capacity_) { |
| 221 ResizeIsolates(isolates_capacity_ == 0 ? 16 : isolates_capacity_ * 2); | 258 ResizeIsolates(isolates_capacity_ == 0 ? 16 : isolates_capacity_ * 2); |
| 222 } | 259 } |
| 223 isolates_[isolates_size_] = isolate; | 260 isolates_[isolates_size_] = isolate; |
| 224 isolates_size_++; | 261 isolates_size_++; |
| 225 } | 262 } |
| 226 | 263 |
| 227 | 264 |
| 228 intptr_t ProfilerManager::FindIsolate(Isolate* isolate) { | 265 intptr_t ProfilerManager::FindIsolate(Isolate* isolate) { |
| 229 // Must be called with monitor_ locked. | 266 // Must be called with monitor_ locked. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 } | 310 } |
| 274 } | 311 } |
| 275 } | 312 } |
| 276 return const_cast<char*>(symbol_name); | 313 return const_cast<char*>(symbol_name); |
| 277 } | 314 } |
| 278 | 315 |
| 279 | 316 |
| 280 void ProfilerManager::WriteTracing(Isolate* isolate, const char* name, | 317 void ProfilerManager::WriteTracing(Isolate* isolate, const char* name, |
| 281 Dart_Port port) { | 318 Dart_Port port) { |
| 282 ASSERT(isolate == Isolate::Current()); | 319 ASSERT(isolate == Isolate::Current()); |
| 283 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); | |
| 284 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
| 285 if (profiler_data == NULL) { | |
| 286 return; | |
| 287 } | |
| 288 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
| 289 ASSERT(sample_buffer != NULL); | |
| 290 JSONStream stream(10 * MB); | |
| 291 intptr_t tid = reinterpret_cast<intptr_t>(sample_buffer); | |
| 292 intptr_t pid = 1; | |
| 293 { | 320 { |
| 294 JSONArray events(&stream); | 321 ScopedSignalBlocker ssb; |
|
Cutch
2013/11/22 23:30:18
NOTE: This function was not changed aside from exp
| |
| 295 { | 322 { |
| 296 JSONObject thread_name(&events); | 323 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); |
| 297 thread_name.AddProperty("name", "thread_name"); | 324 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 298 thread_name.AddProperty("ph", "M"); | 325 if (profiler_data == NULL) { |
| 299 thread_name.AddProperty("tid", tid); | 326 return; |
| 300 thread_name.AddProperty("pid", pid); | 327 } |
| 328 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
| 329 ASSERT(sample_buffer != NULL); | |
| 330 JSONStream stream(10 * MB); | |
| 331 intptr_t tid = reinterpret_cast<intptr_t>(sample_buffer); | |
| 332 intptr_t pid = 1; | |
| 301 { | 333 { |
| 302 JSONObject args(&thread_name, "args"); | 334 JSONArray events(&stream); |
| 303 args.AddProperty("name", name); | |
| 304 } | |
| 305 } | |
| 306 { | |
| 307 JSONObject process_name(&events); | |
| 308 process_name.AddProperty("name", "process_name"); | |
| 309 process_name.AddProperty("ph", "M"); | |
| 310 process_name.AddProperty("tid", tid); | |
| 311 process_name.AddProperty("pid", pid); | |
| 312 { | |
| 313 JSONObject args(&process_name, "args"); | |
| 314 args.AddProperty("name", "Dart VM"); | |
| 315 } | |
| 316 } | |
| 317 uint64_t last_time = 0; | |
| 318 for (Sample* i = sample_buffer->FirstSample(); | |
| 319 i != sample_buffer->LastSample(); | |
| 320 i = sample_buffer->NextSample(i)) { | |
| 321 if (last_time == 0) { | |
| 322 last_time = i->timestamp; | |
| 323 } | |
| 324 intptr_t delta = i->timestamp - last_time; | |
| 325 { | |
| 326 double percentage = static_cast<double>(i->cpu_usage) / | |
| 327 static_cast<double>(delta) * 100.0; | |
| 328 if (percentage != percentage) { | |
| 329 percentage = 0.0; | |
| 330 } | |
| 331 percentage = percentage < 0.0 ? 0.0 : percentage; | |
| 332 percentage = percentage > 100.0 ? 100.0 : percentage; | |
| 333 { | 335 { |
| 334 JSONObject cpu_usage(&events); | 336 JSONObject thread_name(&events); |
| 335 cpu_usage.AddProperty("name", "CPU Usage"); | 337 thread_name.AddProperty("name", "thread_name"); |
| 336 cpu_usage.AddProperty("ph", "C"); | 338 thread_name.AddProperty("ph", "M"); |
| 337 cpu_usage.AddProperty("tid", tid); | 339 thread_name.AddProperty("tid", tid); |
| 338 cpu_usage.AddProperty("pid", pid); | 340 thread_name.AddProperty("pid", pid); |
| 339 cpu_usage.AddProperty("ts", static_cast<double>(last_time)); | |
| 340 { | 341 { |
| 341 JSONObject args(&cpu_usage, "args"); | 342 JSONObject args(&thread_name, "args"); |
| 342 args.AddProperty("CPU", percentage); | 343 args.AddProperty("name", name); |
| 343 } | 344 } |
| 344 } | 345 } |
| 345 { | 346 { |
| 346 JSONObject cpu_usage(&events); | 347 JSONObject process_name(&events); |
| 347 cpu_usage.AddProperty("name", "CPU Usage"); | 348 process_name.AddProperty("name", "process_name"); |
| 348 cpu_usage.AddProperty("ph", "C"); | 349 process_name.AddProperty("ph", "M"); |
| 349 cpu_usage.AddProperty("tid", tid); | 350 process_name.AddProperty("tid", tid); |
| 350 cpu_usage.AddProperty("pid", pid); | 351 process_name.AddProperty("pid", pid); |
| 351 cpu_usage.AddProperty("ts", static_cast<double>(i->timestamp)); | |
| 352 { | 352 { |
| 353 JSONObject args(&cpu_usage, "args"); | 353 JSONObject args(&process_name, "args"); |
| 354 args.AddProperty("CPU", percentage); | 354 args.AddProperty("name", "Dart VM"); |
| 355 } | 355 } |
| 356 } | 356 } |
| 357 } | 357 uint64_t last_time = 0; |
| 358 for (int j = 0; j < Sample::kNumStackFrames; j++) { | 358 for (Sample* i = sample_buffer->FirstSample(); |
| 359 if (i->pcs[j] == 0) { | 359 i != sample_buffer->LastSample(); |
| 360 continue; | 360 i = sample_buffer->NextSample(i)) { |
| 361 } | 361 if (last_time == 0) { |
| 362 bool native_symbol = false; | 362 last_time = i->timestamp; |
| 363 char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol); | 363 } |
| 364 { | 364 intptr_t delta = i->timestamp - last_time; |
| 365 JSONObject begin(&events); | 365 { |
| 366 begin.AddProperty("ph", "B"); | 366 double percentage = static_cast<double>(i->cpu_usage) / |
| 367 begin.AddProperty("tid", tid); | 367 static_cast<double>(delta) * 100.0; |
| 368 begin.AddProperty("pid", pid); | 368 if (percentage != percentage) { |
| 369 begin.AddProperty("name", symbol_name); | 369 percentage = 0.0; |
| 370 begin.AddProperty("ts", static_cast<double>(last_time)); | 370 } |
| 371 } | 371 percentage = percentage < 0.0 ? 0.0 : percentage; |
| 372 if (native_symbol) { | 372 percentage = percentage > 100.0 ? 100.0 : percentage; |
| 373 NativeSymbolResolver::FreeSymbolName(symbol_name); | 373 { |
| 374 JSONObject cpu_usage(&events); | |
| 375 cpu_usage.AddProperty("name", "CPU Usage"); | |
| 376 cpu_usage.AddProperty("ph", "C"); | |
| 377 cpu_usage.AddProperty("tid", tid); | |
| 378 cpu_usage.AddProperty("pid", pid); | |
| 379 cpu_usage.AddProperty("ts", static_cast<double>(last_time)); | |
| 380 { | |
| 381 JSONObject args(&cpu_usage, "args"); | |
| 382 args.AddProperty("CPU", percentage); | |
| 383 } | |
| 384 } | |
| 385 { | |
| 386 JSONObject cpu_usage(&events); | |
| 387 cpu_usage.AddProperty("name", "CPU Usage"); | |
| 388 cpu_usage.AddProperty("ph", "C"); | |
| 389 cpu_usage.AddProperty("tid", tid); | |
| 390 cpu_usage.AddProperty("pid", pid); | |
| 391 cpu_usage.AddProperty("ts", static_cast<double>(i->timestamp)); | |
| 392 { | |
| 393 JSONObject args(&cpu_usage, "args"); | |
| 394 args.AddProperty("CPU", percentage); | |
| 395 } | |
| 396 } | |
| 397 } | |
| 398 for (int j = 0; j < Sample::kNumStackFrames; j++) { | |
| 399 if (i->pcs[j] == 0) { | |
| 400 continue; | |
| 401 } | |
| 402 bool native_symbol = false; | |
| 403 char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol); | |
| 404 { | |
| 405 JSONObject begin(&events); | |
| 406 begin.AddProperty("ph", "B"); | |
| 407 begin.AddProperty("tid", tid); | |
| 408 begin.AddProperty("pid", pid); | |
| 409 begin.AddProperty("name", symbol_name); | |
| 410 begin.AddProperty("ts", static_cast<double>(last_time)); | |
| 411 } | |
| 412 if (native_symbol) { | |
| 413 NativeSymbolResolver::FreeSymbolName(symbol_name); | |
| 414 } | |
| 415 } | |
| 416 for (int j = Sample::kNumStackFrames-1; j >= 0; j--) { | |
| 417 if (i->pcs[j] == 0) { | |
| 418 continue; | |
| 419 } | |
| 420 bool native_symbol = false; | |
| 421 char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol); | |
| 422 { | |
| 423 JSONObject end(&events); | |
| 424 end.AddProperty("ph", "E"); | |
| 425 end.AddProperty("tid", tid); | |
| 426 end.AddProperty("pid", pid); | |
| 427 end.AddProperty("name", symbol_name); | |
| 428 end.AddProperty("ts", static_cast<double>(i->timestamp)); | |
| 429 } | |
| 430 if (native_symbol) { | |
| 431 NativeSymbolResolver::FreeSymbolName(symbol_name); | |
| 432 } | |
| 433 } | |
| 434 last_time = i->timestamp; | |
| 374 } | 435 } |
| 375 } | 436 } |
| 376 for (int j = Sample::kNumStackFrames-1; j >= 0; j--) { | 437 char fname[1024]; |
| 377 if (i->pcs[j] == 0) { | 438 #if defined(TARGET_OS_WINDOWS) |
| 378 continue; | 439 snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d.prof", |
| 379 } | 440 static_cast<int>(port)); |
| 380 bool native_symbol = false; | 441 #else |
| 381 char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol); | 442 snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d.prof", |
| 382 { | 443 static_cast<int>(port)); |
| 383 JSONObject end(&events); | 444 #endif |
| 384 end.AddProperty("ph", "E"); | 445 printf("%s\n", fname); |
| 385 end.AddProperty("tid", tid); | 446 FILE* f = fopen(fname, "wb"); |
| 386 end.AddProperty("pid", pid); | 447 ASSERT(f != NULL); |
| 387 end.AddProperty("name", symbol_name); | 448 fputs(stream.ToCString(), f); |
| 388 end.AddProperty("ts", static_cast<double>(i->timestamp)); | 449 fclose(f); |
| 389 } | |
| 390 if (native_symbol) { | |
| 391 NativeSymbolResolver::FreeSymbolName(symbol_name); | |
| 392 } | |
| 393 } | |
| 394 last_time = i->timestamp; | |
| 395 } | 450 } |
| 396 } | 451 } |
| 397 char fname[1024]; | |
| 398 #if defined(TARGET_OS_WINDOWS) | |
| 399 snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d.prof", | |
| 400 static_cast<int>(port)); | |
| 401 #else | |
| 402 snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d.prof", | |
| 403 static_cast<int>(port)); | |
| 404 #endif | |
| 405 printf("%s\n", fname); | |
| 406 FILE* f = fopen(fname, "wb"); | |
| 407 ASSERT(f != NULL); | |
| 408 fputs(stream.ToCString(), f); | |
| 409 fclose(f); | |
| 410 } | 452 } |
| 411 | 453 |
| 412 | 454 |
| 413 | |
| 414 | |
| 415 | |
| 416 IsolateProfilerData::IsolateProfilerData(Isolate* isolate, | 455 IsolateProfilerData::IsolateProfilerData(Isolate* isolate, |
| 417 SampleBuffer* sample_buffer) { | 456 SampleBuffer* sample_buffer) { |
| 418 isolate_ = isolate; | 457 isolate_ = isolate; |
| 419 sample_buffer_ = sample_buffer; | 458 sample_buffer_ = sample_buffer; |
| 420 timer_expiration_micros_ = kNoExpirationTime; | 459 timer_expiration_micros_ = kNoExpirationTime; |
| 421 last_sampled_micros_ = 0; | 460 last_sampled_micros_ = 0; |
| 422 thread_id_ = 0; | 461 thread_id_ = 0; |
| 423 } | 462 } |
| 424 | 463 |
| 425 | 464 |
| 426 IsolateProfilerData::~IsolateProfilerData() { | 465 IsolateProfilerData::~IsolateProfilerData() { |
| 427 } | 466 } |
| 428 | 467 |
| 429 | 468 |
| 430 void IsolateProfilerData::SampledAt(int64_t current_time) { | 469 void IsolateProfilerData::SampledAt(int64_t current_time) { |
| 431 last_sampled_micros_ = current_time; | 470 last_sampled_micros_ = current_time; |
| 432 } | 471 } |
| 433 | 472 |
| 434 | 473 |
| 435 void IsolateProfilerData::Scheduled(int64_t current_time, ThreadId thread_id) { | 474 void IsolateProfilerData::Scheduled(int64_t current_time, ThreadId thread_id) { |
| 436 timer_expiration_micros_ = current_time + sample_interval_micros_; | 475 timer_expiration_micros_ = current_time + sample_interval_micros_; |
| 437 Thread::GetThreadCpuUsage(thread_id, &cpu_usage_); | |
| 438 thread_id_ = thread_id; | 476 thread_id_ = thread_id; |
| 477 Thread::GetThreadCpuUsage(thread_id_, &cpu_usage_); | |
| 439 } | 478 } |
| 440 | 479 |
| 441 | 480 |
| 442 void IsolateProfilerData::Descheduled() { | 481 void IsolateProfilerData::Descheduled() { |
| 443 // TODO(johnmccutchan): Track when we ran for a fraction of our sample | 482 // TODO(johnmccutchan): Track when we ran for a fraction of our sample |
| 444 // interval and incorporate the time difference when scheduling the | 483 // interval and incorporate the time difference when scheduling the |
| 445 // isolate again. | 484 // isolate again. |
| 446 cpu_usage_ = kDescheduledCpuUsage; | 485 cpu_usage_ = kDescheduledCpuUsage; |
| 447 timer_expiration_micros_ = kNoExpirationTime; | 486 timer_expiration_micros_ = kNoExpirationTime; |
| 448 thread_id_ = 0; | |
|
Cutch
2013/11/22 23:30:18
Only update the thread_id when scheduled.
| |
| 449 Sample* sample = sample_buffer_->ReserveSample(); | 487 Sample* sample = sample_buffer_->ReserveSample(); |
| 450 ASSERT(sample != NULL); | 488 ASSERT(sample != NULL); |
| 451 sample->timestamp = OS::GetCurrentTimeMicros(); | 489 sample->timestamp = OS::GetCurrentTimeMicros(); |
| 452 sample->cpu_usage = 0; | 490 sample->cpu_usage = 0; |
| 453 sample->vm_tags = Sample::kIdle; | 491 sample->vm_tags = Sample::kIdle; |
| 454 } | 492 } |
| 455 | 493 |
| 456 | 494 |
| 457 const char* Sample::kLookupSymbol = "Symbol Not Looked Up"; | 495 const char* Sample::kLookupSymbol = "Symbol Not Looked Up"; |
| 458 const char* Sample::kNoSymbol = "No Symbol Found"; | 496 const char* Sample::kNoSymbol = "No Symbol Found"; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 583 return false; | 621 return false; |
| 584 } | 622 } |
| 585 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); | 623 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
| 586 cursor += sizeof(fp); | 624 cursor += sizeof(fp); |
| 587 bool r = cursor >= lower_bound_ && cursor < stack_upper_; | 625 bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
| 588 return r; | 626 return r; |
| 589 } | 627 } |
| 590 | 628 |
| 591 | 629 |
| 592 } // namespace dart | 630 } // namespace dart |
| OLD | NEW |