Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 "vm/timeline_analysis.h" | 5 #include "vm/timeline_analysis.h" |
| 6 | 6 |
| 7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
| 8 #include "vm/log.h" | 8 #include "vm/log.h" |
| 9 #include "vm/os_thread.h" | 9 #include "vm/os_thread.h" |
| 10 | 10 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 ASSERT(a != NULL); | 31 ASSERT(a != NULL); |
| 32 ASSERT(*a != NULL); | 32 ASSERT(*a != NULL); |
| 33 ASSERT(b != NULL); | 33 ASSERT(b != NULL); |
| 34 ASSERT(*b != NULL); | 34 ASSERT(*b != NULL); |
| 35 return (*a)->LowerTimeBound() - (*b)->LowerTimeBound(); | 35 return (*a)->LowerTimeBound() - (*b)->LowerTimeBound(); |
| 36 } | 36 } |
| 37 | 37 |
| 38 | 38 |
| 39 void TimelineAnalysisThread::Finalize() { | 39 void TimelineAnalysisThread::Finalize() { |
| 40 blocks_.Sort(CompareBlocksLowerTimeBound); | 40 blocks_.Sort(CompareBlocksLowerTimeBound); |
| 41 ISL_Print("Thread %" Px " has %" Pd " blocks\n", | 41 if (FLAG_trace_timeline_analysis) { |
| 42 OSThread::ThreadIdToIntPtr(id_), | 42 ISL_Print("Thread %" Px " has %" Pd " blocks\n", |
| 43 blocks_.length()); | 43 OSThread::ThreadIdToIntPtr(id_), |
| 44 blocks_.length()); | |
| 45 } | |
| 44 } | 46 } |
| 45 | 47 |
| 46 | 48 |
| 47 TimelineAnalysisThreadEventIterator::TimelineAnalysisThreadEventIterator( | 49 TimelineAnalysisThreadEventIterator::TimelineAnalysisThreadEventIterator( |
| 48 TimelineAnalysisThread* thread) { | 50 TimelineAnalysisThread* thread) { |
| 49 Reset(thread); | 51 Reset(thread); |
| 50 } | 52 } |
| 51 | 53 |
| 52 | 54 |
| 53 TimelineAnalysisThreadEventIterator::~TimelineAnalysisThreadEventIterator() { | 55 TimelineAnalysisThreadEventIterator::~TimelineAnalysisThreadEventIterator() { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 va_start(args, format); | 194 va_start(args, format); |
| 193 error_msg_ = zone_->VPrint(format, args); | 195 error_msg_ = zone_->VPrint(format, args); |
| 194 ASSERT(error_msg_ != NULL); | 196 ASSERT(error_msg_ != NULL); |
| 195 } | 197 } |
| 196 | 198 |
| 197 | 199 |
| 198 TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name) | 200 TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name) |
| 199 : name_(name), | 201 : name_(name), |
| 200 inclusive_micros_(0), | 202 inclusive_micros_(0), |
| 201 exclusive_micros_(0), | 203 exclusive_micros_(0), |
| 202 max_duration_micros_(0) { | 204 max_inclusive_micros_(0), |
| 205 max_exclusive_micros_(0) { | |
| 203 ASSERT(name_ != NULL); | 206 ASSERT(name_ != NULL); |
| 204 } | 207 } |
| 205 | 208 |
| 206 | 209 |
| 207 void TimelineLabelPauseInfo::OnPush(int64_t micros) { | 210 void TimelineLabelPauseInfo::OnPush(int64_t micros, bool already_on_stack) { |
| 208 add_inclusive_micros(micros); | 211 if (!already_on_stack) { |
| 209 add_exclusive_micros(micros); | 212 // Only adjust inclusive counts if we aren't already on the stack. |
| 210 if (micros > max_duration_micros_) { | 213 add_inclusive_micros(micros); |
| 211 max_duration_micros_ = micros; | 214 if (micros > max_inclusive_micros_) { |
| 215 max_inclusive_micros_ = micros; | |
| 216 } | |
| 212 } | 217 } |
| 213 } | 218 } |
| 214 | 219 |
| 215 | 220 |
| 216 void TimelineLabelPauseInfo::OnChildPush(int64_t micros) { | 221 void TimelineLabelPauseInfo::OnPop(int64_t exclusive_micros) { |
| 217 ASSERT(micros >= 0); | 222 add_exclusive_micros(exclusive_micros); |
| 218 add_exclusive_micros(-micros); | 223 if (exclusive_micros > max_exclusive_micros_) { |
| 224 max_exclusive_micros_ = exclusive_micros; | |
| 225 } | |
| 219 } | 226 } |
| 220 | 227 |
| 221 | 228 |
| 222 TimelinePauses::TimelinePauses(Zone* zone, | 229 TimelinePauses::TimelinePauses(Zone* zone, |
| 223 Isolate* isolate, | 230 Isolate* isolate, |
| 224 TimelineEventRecorder* recorder) | 231 TimelineEventRecorder* recorder) |
| 225 : TimelineAnalysis(zone, isolate, recorder) { | 232 : TimelineAnalysis(zone, isolate, recorder) { |
| 226 } | 233 } |
| 227 | 234 |
| 228 | 235 |
| 229 void TimelinePauses::Setup() { | 236 void TimelinePauses::Setup() { |
| 230 BuildThreads(); | 237 BuildThreads(); |
| 231 } | 238 } |
| 232 | 239 |
| 233 | 240 |
| 234 void TimelinePauses::CalculatePauseTimesForThread(ThreadId tid) { | 241 void TimelinePauses::CalculatePauseTimesForThread(ThreadId tid) { |
| 235 if (has_error()) { | 242 if (has_error()) { |
| 236 return; | 243 return; |
| 237 } | 244 } |
| 238 TimelineAnalysisThread* thread = GetThread(tid); | 245 TimelineAnalysisThread* thread = GetThread(tid); |
| 239 if (thread == NULL) { | 246 if (thread == NULL) { |
| 240 SetError("Thread %" Px " does not exist.", OSThread::ThreadIdToIntPtr(tid)); | 247 SetError("Thread %" Px " does not exist.", OSThread::ThreadIdToIntPtr(tid)); |
| 241 return; | 248 return; |
| 242 } | 249 } |
| 243 ProcessThread(thread); | 250 ProcessThread(thread); |
| 244 } | 251 } |
| 245 | 252 |
| 246 | 253 |
| 247 TimelineLabelPauseInfo* TimelinePauses::GetLabel(const char* name) const { | 254 TimelineLabelPauseInfo* TimelinePauses::GetLabelPauseInfo( |
| 255 const char* name) const { | |
| 248 ASSERT(name != NULL); | 256 ASSERT(name != NULL); |
| 249 // Linear lookup because we expect N (# of labels in an isolate) to be small. | 257 // Linear lookup because we expect N (# of labels in an isolate) to be small. |
| 250 for (intptr_t i = 0; i < labels_.length(); i++) { | 258 for (intptr_t i = 0; i < labels_.length(); i++) { |
| 251 TimelineLabelPauseInfo* label = labels_.At(i); | 259 TimelineLabelPauseInfo* label = labels_.At(i); |
| 252 if (strcmp(label->name(), name) == 0) { | 260 if (strcmp(label->name(), name) == 0) { |
| 253 return label; | 261 return label; |
| 254 } | 262 } |
| 255 } | 263 } |
| 256 return NULL; | 264 return NULL; |
| 257 } | 265 } |
| 258 | 266 |
| 259 | 267 |
| 260 int64_t TimelinePauses::InclusiveTime(const char* name) const { | 268 int64_t TimelinePauses::InclusiveTime(const char* name) const { |
| 261 TimelineLabelPauseInfo* pause_info = GetLabel(name); | 269 TimelineLabelPauseInfo* pause_info = GetLabelPauseInfo(name); |
| 262 ASSERT(pause_info != NULL); | 270 ASSERT(pause_info != NULL); |
| 263 return pause_info->inclusive_micros(); | 271 return pause_info->inclusive_micros(); |
| 264 } | 272 } |
| 265 | 273 |
| 266 | 274 |
| 267 int64_t TimelinePauses::ExclusiveTime(const char* name) const { | 275 int64_t TimelinePauses::ExclusiveTime(const char* name) const { |
| 268 TimelineLabelPauseInfo* pause_info = GetLabel(name); | 276 TimelineLabelPauseInfo* pause_info = GetLabelPauseInfo(name); |
| 269 ASSERT(pause_info != NULL); | 277 ASSERT(pause_info != NULL); |
| 270 return pause_info->exclusive_micros(); | 278 return pause_info->exclusive_micros(); |
| 271 } | 279 } |
| 272 | 280 |
| 273 | 281 |
| 274 int64_t TimelinePauses::MaxDurationTime(const char* name) const { | 282 int64_t TimelinePauses::MaxInclusiveTime(const char* name) const { |
| 275 TimelineLabelPauseInfo* pause_info = GetLabel(name); | 283 TimelineLabelPauseInfo* pause_info = GetLabelPauseInfo(name); |
| 276 ASSERT(pause_info != NULL); | 284 ASSERT(pause_info != NULL); |
| 277 return pause_info->max_duration_micros(); | 285 return pause_info->max_inclusive_micros(); |
| 278 } | 286 } |
| 279 | 287 |
| 280 | 288 |
| 289 int64_t TimelinePauses::MaxExclusiveTime(const char* name) const { | |
| 290 TimelineLabelPauseInfo* pause_info = GetLabelPauseInfo(name); | |
| 291 ASSERT(pause_info != NULL); | |
| 292 return pause_info->max_exclusive_micros(); | |
| 293 } | |
| 294 | |
| 295 | |
| 281 void TimelinePauses::ProcessThread(TimelineAnalysisThread* thread) { | 296 void TimelinePauses::ProcessThread(TimelineAnalysisThread* thread) { |
| 282 ASSERT(thread != NULL); | 297 ASSERT(thread != NULL); |
| 283 stack_.Clear(); | 298 stack_.Clear(); |
| 284 labels_.Clear(); | 299 labels_.Clear(); |
| 285 | 300 |
| 286 TimelineAnalysisThreadEventIterator it(thread); | 301 TimelineAnalysisThreadEventIterator it(thread); |
| 287 if (FLAG_trace_timeline_analysis) { | 302 if (FLAG_trace_timeline_analysis) { |
| 288 ISL_Print(">>> TimelinePauses::ProcessThread %" Px "\n", | 303 ISL_Print(">>> TimelinePauses::ProcessThread %" Px "\n", |
| 289 OSThread::ThreadIdToIntPtr(thread->id())); | 304 OSThread::ThreadIdToIntPtr(thread->id())); |
| 290 } | 305 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 311 OSThread::ThreadIdToIntPtr(thread->id()), | 326 OSThread::ThreadIdToIntPtr(thread->id()), |
| 312 event_count); | 327 event_count); |
| 313 } | 328 } |
| 314 } | 329 } |
| 315 | 330 |
| 316 | 331 |
| 317 // Verify that |event| is contained within all parent events on the stack. | 332 // Verify that |event| is contained within all parent events on the stack. |
| 318 bool TimelinePauses::CheckStack(TimelineEvent* event) { | 333 bool TimelinePauses::CheckStack(TimelineEvent* event) { |
| 319 ASSERT(event != NULL); | 334 ASSERT(event != NULL); |
| 320 for (intptr_t i = 0; i < stack_.length(); i++) { | 335 for (intptr_t i = 0; i < stack_.length(); i++) { |
| 321 TimelineEvent* slot = stack_.At(i); | 336 const StackItem& slot = stack_.At(i); |
| 322 if (!slot->DurationContains(event)) { | 337 if (!slot.event->DurationContains(event)) { |
| 323 return false; | 338 return false; |
| 324 } | 339 } |
| 325 } | 340 } |
| 326 return true; | 341 return true; |
| 327 } | 342 } |
| 328 | 343 |
| 329 | 344 |
| 330 void TimelinePauses::PopFinished(int64_t start) { | 345 void TimelinePauses::PopFinished(int64_t start) { |
| 331 while (stack_.length() > 0) { | 346 while (stack_.length() > 0) { |
| 332 TimelineEvent* top = stack_.Last(); | 347 const StackItem& top = stack_.Last(); |
| 333 if (top->DurationFinishedBefore(start)) { | 348 if (top.event->DurationFinishedBefore(start)) { |
| 349 top.pause_info->OnPop(top.exclusive_micros); | |
| 334 // Top of stack completes before |start|. | 350 // Top of stack completes before |start|. |
| 335 stack_.RemoveLast(); | 351 stack_.RemoveLast(); |
| 336 if (FLAG_trace_timeline_analysis) { | 352 if (FLAG_trace_timeline_analysis) { |
| 337 ISL_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n", | 353 ISL_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n", |
| 338 top->label(), | 354 top.event->label(), |
| 339 top->TimeEnd(), | 355 top.event->TimeEnd(), |
| 340 start); | 356 start); |
| 341 } | 357 } |
| 342 } else { | 358 } else { |
| 343 return; | 359 return; |
| 344 } | 360 } |
| 345 } | 361 } |
| 346 } | 362 } |
| 347 | 363 |
| 348 | 364 |
| 349 void TimelinePauses::Push(TimelineEvent* event) { | 365 void TimelinePauses::Push(TimelineEvent* event) { |
| 350 TimelineLabelPauseInfo* pause_info = GetOrAddLabel(event->label()); | 366 TimelineLabelPauseInfo* pause_info = GetOrAddLabelPauseInfo(event->label()); |
| 351 ASSERT(pause_info != NULL); | 367 ASSERT(pause_info != NULL); |
| 352 // |pause_info| will be running for |event->TimeDuration()|. | 368 // |pause_info| will be running for |event->TimeDuration()|. |
| 353 if (FLAG_trace_timeline_analysis) { | 369 if (FLAG_trace_timeline_analysis) { |
| 354 ISL_Print("Pushing %s %" Pd64 " us\n", | 370 ISL_Print("Pushing %s %" Pd64 " us\n", |
| 355 pause_info->name(), | 371 pause_info->name(), |
| 356 event->TimeDuration()); | 372 event->TimeDuration()); |
| 357 } | 373 } |
| 358 pause_info->OnPush(event->TimeDuration()); | 374 pause_info->OnPush(event->TimeDuration(), IsLabelOnStack(event->label())); |
|
srdjan
2015/08/17 17:37:11
Is it better to do:
if (!isLabelOnStack(..)) {
p
Cutch
2015/08/17 17:51:12
At one point we needed the extra argument, right n
| |
| 359 TimelineLabelPauseInfo* top_pause_info = GetTopLabel(); | 375 if (StackDepth() > 0) { |
| 360 if (top_pause_info != NULL) { | 376 StackItem& top = GetStackTop(); |
| 361 // |top_pause_info| is under |event|'s shadow, adjust the exclusive micros. | 377 // |top| is under |event|'s shadow, adjust the exclusive micros. |
| 362 if (FLAG_trace_timeline_analysis) { | 378 top.exclusive_micros -= event->TimeDuration(); |
| 363 ISL_Print("Adjusting %s by %" Pd64 " us\n", | |
| 364 top_pause_info->name(), | |
| 365 event->TimeDuration()); | |
| 366 } | |
| 367 top_pause_info->OnChildPush(event->TimeDuration()); | |
| 368 } | 379 } |
| 369 // Push onto the stack. | 380 // Push onto the stack. |
| 370 stack_.Add(event); | 381 StackItem item; |
| 382 item.event = event; | |
| 383 item.pause_info = pause_info; | |
| 384 item.exclusive_micros = event->TimeDuration(); | |
| 385 stack_.Add(item); | |
| 371 } | 386 } |
| 372 | 387 |
| 373 | 388 |
| 374 TimelineLabelPauseInfo* TimelinePauses::GetTopLabel() { | 389 bool TimelinePauses::IsLabelOnStack(const char* label) { |
|
srdjan
2015/08/17 17:37:11
const
Cutch
2015/08/17 17:51:12
Done (in a CL I'm working on now).
| |
| 375 if (stack_.length() == 0) { | 390 ASSERT(label != NULL); |
| 376 return NULL; | 391 for (intptr_t i = 0; i < stack_.length(); i++) { |
| 392 const StackItem& slot = stack_.At(i); | |
| 393 if (strcmp(slot.event->label(), label) == 0) { | |
| 394 return true; | |
| 395 } | |
| 377 } | 396 } |
| 378 TimelineEvent* event = stack_.Last(); | 397 return false; |
| 379 return GetLabel(event->label()); | |
| 380 } | 398 } |
| 381 | 399 |
| 382 | 400 |
| 383 TimelineLabelPauseInfo* TimelinePauses::GetOrAddLabel(const char* name) { | 401 intptr_t TimelinePauses::StackDepth() const { |
| 402 return stack_.length(); | |
| 403 } | |
| 404 | |
| 405 | |
| 406 TimelinePauses::StackItem& TimelinePauses::GetStackTop() { | |
|
srdjan
2015/08/17 17:37:11
const
Cutch
2015/08/17 17:51:12
Cannot be done because StackItem& is modified by t
| |
| 407 ASSERT(stack_.length() > 0); | |
| 408 return stack_.Last(); | |
| 409 } | |
| 410 | |
| 411 | |
| 412 TimelineLabelPauseInfo* TimelinePauses::GetOrAddLabelPauseInfo( | |
| 413 const char* name) { | |
| 384 ASSERT(name != NULL); | 414 ASSERT(name != NULL); |
| 385 TimelineLabelPauseInfo* label = GetLabel(name); | 415 TimelineLabelPauseInfo* pause_info = GetLabelPauseInfo(name); |
| 386 if (label != NULL) { | 416 if (pause_info != NULL) { |
| 387 return label; | 417 return pause_info; |
| 388 } | 418 } |
| 389 // New label. | 419 // New label. |
| 390 label = new TimelineLabelPauseInfo(name); | 420 pause_info = new TimelineLabelPauseInfo(name); |
| 391 labels_.Add(label); | 421 labels_.Add(pause_info); |
| 392 return label; | 422 return pause_info; |
| 393 } | 423 } |
| 394 | 424 |
| 395 } // namespace dart | 425 } // namespace dart |
| OLD | NEW |