| 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/profiler_service.h" | 5 #include "vm/profiler_service.h" |
| 6 | 6 |
| 7 #include "vm/growable_array.h" | 7 #include "vm/growable_array.h" |
| 8 #include "vm/hash_map.h" | 8 #include "vm/hash_map.h" |
| 9 #include "vm/log.h" | 9 #include "vm/log.h" |
| 10 #include "vm/malloc_hooks.h" | 10 #include "vm/malloc_hooks.h" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 } | 84 } |
| 85 return size; | 85 return size; |
| 86 } | 86 } |
| 87 | 87 |
| 88 // Array holding code that is being kept around only for the profiler. | 88 // Array holding code that is being kept around only for the profiler. |
| 89 const GrowableObjectArray& previous_; | 89 const GrowableObjectArray& previous_; |
| 90 // Array holding code that should continue to be kept around for the profiler. | 90 // Array holding code that should continue to be kept around for the profiler. |
| 91 const GrowableObjectArray& current_; | 91 const GrowableObjectArray& current_; |
| 92 }; | 92 }; |
| 93 | 93 |
| 94 | |
| 95 ProfileFunctionSourcePosition::ProfileFunctionSourcePosition( | 94 ProfileFunctionSourcePosition::ProfileFunctionSourcePosition( |
| 96 TokenPosition token_pos) | 95 TokenPosition token_pos) |
| 97 : token_pos_(token_pos), exclusive_ticks_(0), inclusive_ticks_(0) {} | 96 : token_pos_(token_pos), exclusive_ticks_(0), inclusive_ticks_(0) {} |
| 98 | 97 |
| 99 | |
| 100 void ProfileFunctionSourcePosition::Tick(bool exclusive) { | 98 void ProfileFunctionSourcePosition::Tick(bool exclusive) { |
| 101 if (exclusive) { | 99 if (exclusive) { |
| 102 exclusive_ticks_++; | 100 exclusive_ticks_++; |
| 103 } else { | 101 } else { |
| 104 inclusive_ticks_++; | 102 inclusive_ticks_++; |
| 105 } | 103 } |
| 106 } | 104 } |
| 107 | 105 |
| 108 | |
| 109 ProfileFunction::ProfileFunction(Kind kind, | 106 ProfileFunction::ProfileFunction(Kind kind, |
| 110 const char* name, | 107 const char* name, |
| 111 const Function& function, | 108 const Function& function, |
| 112 const intptr_t table_index) | 109 const intptr_t table_index) |
| 113 : kind_(kind), | 110 : kind_(kind), |
| 114 name_(name), | 111 name_(name), |
| 115 function_(Function::ZoneHandle(function.raw())), | 112 function_(Function::ZoneHandle(function.raw())), |
| 116 table_index_(table_index), | 113 table_index_(table_index), |
| 117 profile_codes_(0), | 114 profile_codes_(0), |
| 118 source_position_ticks_(0), | 115 source_position_ticks_(0), |
| 119 exclusive_ticks_(0), | 116 exclusive_ticks_(0), |
| 120 inclusive_ticks_(0), | 117 inclusive_ticks_(0), |
| 121 inclusive_serial_(-1) { | 118 inclusive_serial_(-1) { |
| 122 ASSERT((kind_ != kDartFunction) || !function_.IsNull()); | 119 ASSERT((kind_ != kDartFunction) || !function_.IsNull()); |
| 123 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0)); | 120 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0)); |
| 124 ASSERT(profile_codes_.length() == 0); | 121 ASSERT(profile_codes_.length() == 0); |
| 125 } | 122 } |
| 126 | 123 |
| 127 | |
| 128 const char* ProfileFunction::Name() const { | 124 const char* ProfileFunction::Name() const { |
| 129 if (name_ != NULL) { | 125 if (name_ != NULL) { |
| 130 return name_; | 126 return name_; |
| 131 } | 127 } |
| 132 ASSERT(!function_.IsNull()); | 128 ASSERT(!function_.IsNull()); |
| 133 const String& func_name = | 129 const String& func_name = |
| 134 String::Handle(function_.QualifiedUserVisibleName()); | 130 String::Handle(function_.QualifiedUserVisibleName()); |
| 135 return func_name.ToCString(); | 131 return func_name.ToCString(); |
| 136 } | 132 } |
| 137 | 133 |
| 138 | |
| 139 bool ProfileFunction::is_visible() const { | 134 bool ProfileFunction::is_visible() const { |
| 140 if (function_.IsNull()) { | 135 if (function_.IsNull()) { |
| 141 // Some synthetic function. | 136 // Some synthetic function. |
| 142 return true; | 137 return true; |
| 143 } | 138 } |
| 144 return FLAG_show_invisible_frames || function_.is_visible(); | 139 return FLAG_show_invisible_frames || function_.is_visible(); |
| 145 } | 140 } |
| 146 | 141 |
| 147 | |
| 148 void ProfileFunction::Tick(bool exclusive, | 142 void ProfileFunction::Tick(bool exclusive, |
| 149 intptr_t inclusive_serial, | 143 intptr_t inclusive_serial, |
| 150 TokenPosition token_position) { | 144 TokenPosition token_position) { |
| 151 if (exclusive) { | 145 if (exclusive) { |
| 152 exclusive_ticks_++; | 146 exclusive_ticks_++; |
| 153 TickSourcePosition(token_position, exclusive); | 147 TickSourcePosition(token_position, exclusive); |
| 154 } | 148 } |
| 155 // Fall through and tick inclusive count too. | 149 // Fall through and tick inclusive count too. |
| 156 if (inclusive_serial_ == inclusive_serial) { | 150 if (inclusive_serial_ == inclusive_serial) { |
| 157 // Already ticked. | 151 // Already ticked. |
| 158 return; | 152 return; |
| 159 } | 153 } |
| 160 inclusive_serial_ = inclusive_serial; | 154 inclusive_serial_ = inclusive_serial; |
| 161 inclusive_ticks_++; | 155 inclusive_ticks_++; |
| 162 TickSourcePosition(token_position, false); | 156 TickSourcePosition(token_position, false); |
| 163 } | 157 } |
| 164 | 158 |
| 165 | |
| 166 void ProfileFunction::TickSourcePosition(TokenPosition token_position, | 159 void ProfileFunction::TickSourcePosition(TokenPosition token_position, |
| 167 bool exclusive) { | 160 bool exclusive) { |
| 168 intptr_t i = 0; | 161 intptr_t i = 0; |
| 169 for (; i < source_position_ticks_.length(); i++) { | 162 for (; i < source_position_ticks_.length(); i++) { |
| 170 ProfileFunctionSourcePosition& position = source_position_ticks_[i]; | 163 ProfileFunctionSourcePosition& position = source_position_ticks_[i]; |
| 171 if (position.token_pos().value() == token_position.value()) { | 164 if (position.token_pos().value() == token_position.value()) { |
| 172 if (FLAG_trace_profiler_verbose) { | 165 if (FLAG_trace_profiler_verbose) { |
| 173 OS::Print("Ticking source position %s %s\n", | 166 OS::Print("Ticking source position %s %s\n", |
| 174 exclusive ? "exclusive" : "inclusive", | 167 exclusive ? "exclusive" : "inclusive", |
| 175 token_position.ToCString()); | 168 token_position.ToCString()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 192 } | 185 } |
| 193 pfsp.Tick(exclusive); | 186 pfsp.Tick(exclusive); |
| 194 | 187 |
| 195 if (i < source_position_ticks_.length()) { | 188 if (i < source_position_ticks_.length()) { |
| 196 source_position_ticks_.InsertAt(i, pfsp); | 189 source_position_ticks_.InsertAt(i, pfsp); |
| 197 } else { | 190 } else { |
| 198 source_position_ticks_.Add(pfsp); | 191 source_position_ticks_.Add(pfsp); |
| 199 } | 192 } |
| 200 } | 193 } |
| 201 | 194 |
| 202 | |
| 203 const char* ProfileFunction::KindToCString(Kind kind) { | 195 const char* ProfileFunction::KindToCString(Kind kind) { |
| 204 switch (kind) { | 196 switch (kind) { |
| 205 case kDartFunction: | 197 case kDartFunction: |
| 206 return "Dart"; | 198 return "Dart"; |
| 207 case kNativeFunction: | 199 case kNativeFunction: |
| 208 return "Native"; | 200 return "Native"; |
| 209 case kTagFunction: | 201 case kTagFunction: |
| 210 return "Tag"; | 202 return "Tag"; |
| 211 case kStubFunction: | 203 case kStubFunction: |
| 212 return "Stub"; | 204 return "Stub"; |
| 213 case kUnknownFunction: | 205 case kUnknownFunction: |
| 214 return "Collected"; | 206 return "Collected"; |
| 215 default: | 207 default: |
| 216 UNIMPLEMENTED(); | 208 UNIMPLEMENTED(); |
| 217 return ""; | 209 return ""; |
| 218 } | 210 } |
| 219 } | 211 } |
| 220 | 212 |
| 221 | |
| 222 void ProfileFunction::PrintToJSONObject(JSONObject* func) { | 213 void ProfileFunction::PrintToJSONObject(JSONObject* func) { |
| 223 func->AddProperty("type", "@Function"); | 214 func->AddProperty("type", "@Function"); |
| 224 func->AddProperty("name", name()); | 215 func->AddProperty("name", name()); |
| 225 func->AddProperty("_kind", KindToCString(kind())); | 216 func->AddProperty("_kind", KindToCString(kind())); |
| 226 } | 217 } |
| 227 | 218 |
| 228 | |
| 229 void ProfileFunction::PrintToJSONArray(JSONArray* functions) { | 219 void ProfileFunction::PrintToJSONArray(JSONArray* functions) { |
| 230 JSONObject obj(functions); | 220 JSONObject obj(functions); |
| 231 obj.AddProperty("kind", KindToCString(kind())); | 221 obj.AddProperty("kind", KindToCString(kind())); |
| 232 obj.AddProperty("inclusiveTicks", inclusive_ticks()); | 222 obj.AddProperty("inclusiveTicks", inclusive_ticks()); |
| 233 obj.AddProperty("exclusiveTicks", exclusive_ticks()); | 223 obj.AddProperty("exclusiveTicks", exclusive_ticks()); |
| 234 if (kind() == kDartFunction) { | 224 if (kind() == kDartFunction) { |
| 235 ASSERT(!function_.IsNull()); | 225 ASSERT(!function_.IsNull()); |
| 236 obj.AddProperty("function", function_); | 226 obj.AddProperty("function", function_); |
| 237 } else { | 227 } else { |
| 238 JSONObject func(&obj, "function"); | 228 JSONObject func(&obj, "function"); |
| 239 PrintToJSONObject(&func); | 229 PrintToJSONObject(&func); |
| 240 } | 230 } |
| 241 { | 231 { |
| 242 JSONArray codes(&obj, "codes"); | 232 JSONArray codes(&obj, "codes"); |
| 243 for (intptr_t i = 0; i < profile_codes_.length(); i++) { | 233 for (intptr_t i = 0; i < profile_codes_.length(); i++) { |
| 244 intptr_t code_index = profile_codes_[i]; | 234 intptr_t code_index = profile_codes_[i]; |
| 245 codes.AddValue(code_index); | 235 codes.AddValue(code_index); |
| 246 } | 236 } |
| 247 } | 237 } |
| 248 } | 238 } |
| 249 | 239 |
| 250 | |
| 251 void ProfileFunction::AddProfileCode(intptr_t code_table_index) { | 240 void ProfileFunction::AddProfileCode(intptr_t code_table_index) { |
| 252 for (intptr_t i = 0; i < profile_codes_.length(); i++) { | 241 for (intptr_t i = 0; i < profile_codes_.length(); i++) { |
| 253 if (profile_codes_[i] == code_table_index) { | 242 if (profile_codes_[i] == code_table_index) { |
| 254 return; | 243 return; |
| 255 } | 244 } |
| 256 } | 245 } |
| 257 profile_codes_.Add(code_table_index); | 246 profile_codes_.Add(code_table_index); |
| 258 } | 247 } |
| 259 | 248 |
| 260 | |
| 261 bool ProfileFunction::GetSinglePosition(ProfileFunctionSourcePosition* pfsp) { | 249 bool ProfileFunction::GetSinglePosition(ProfileFunctionSourcePosition* pfsp) { |
| 262 if (pfsp == NULL) { | 250 if (pfsp == NULL) { |
| 263 return false; | 251 return false; |
| 264 } | 252 } |
| 265 if (source_position_ticks_.length() != 1) { | 253 if (source_position_ticks_.length() != 1) { |
| 266 return false; | 254 return false; |
| 267 } | 255 } |
| 268 *pfsp = source_position_ticks_[0]; | 256 *pfsp = source_position_ticks_[0]; |
| 269 return true; | 257 return true; |
| 270 } | 258 } |
| 271 | 259 |
| 272 | |
| 273 ProfileCodeAddress::ProfileCodeAddress(uword pc) | 260 ProfileCodeAddress::ProfileCodeAddress(uword pc) |
| 274 : pc_(pc), exclusive_ticks_(0), inclusive_ticks_(0) {} | 261 : pc_(pc), exclusive_ticks_(0), inclusive_ticks_(0) {} |
| 275 | 262 |
| 276 | |
| 277 void ProfileCodeAddress::Tick(bool exclusive) { | 263 void ProfileCodeAddress::Tick(bool exclusive) { |
| 278 if (exclusive) { | 264 if (exclusive) { |
| 279 exclusive_ticks_++; | 265 exclusive_ticks_++; |
| 280 } else { | 266 } else { |
| 281 inclusive_ticks_++; | 267 inclusive_ticks_++; |
| 282 } | 268 } |
| 283 } | 269 } |
| 284 | 270 |
| 285 | |
| 286 ProfileCode::ProfileCode(Kind kind, | 271 ProfileCode::ProfileCode(Kind kind, |
| 287 uword start, | 272 uword start, |
| 288 uword end, | 273 uword end, |
| 289 int64_t timestamp, | 274 int64_t timestamp, |
| 290 const Code& code) | 275 const Code& code) |
| 291 : kind_(kind), | 276 : kind_(kind), |
| 292 start_(start), | 277 start_(start), |
| 293 end_(end), | 278 end_(end), |
| 294 exclusive_ticks_(0), | 279 exclusive_ticks_(0), |
| 295 inclusive_ticks_(0), | 280 inclusive_ticks_(0), |
| 296 inclusive_serial_(-1), | 281 inclusive_serial_(-1), |
| 297 code_(code), | 282 code_(code), |
| 298 name_(NULL), | 283 name_(NULL), |
| 299 compile_timestamp_(0), | 284 compile_timestamp_(0), |
| 300 function_(NULL), | 285 function_(NULL), |
| 301 code_table_index_(-1), | 286 code_table_index_(-1), |
| 302 address_ticks_(0) {} | 287 address_ticks_(0) {} |
| 303 | 288 |
| 304 | |
| 305 void ProfileCode::TruncateLower(uword start) { | 289 void ProfileCode::TruncateLower(uword start) { |
| 306 if (start > start_) { | 290 if (start > start_) { |
| 307 start_ = start; | 291 start_ = start; |
| 308 } | 292 } |
| 309 ASSERT(start_ < end_); | 293 ASSERT(start_ < end_); |
| 310 } | 294 } |
| 311 | 295 |
| 312 | |
| 313 void ProfileCode::TruncateUpper(uword end) { | 296 void ProfileCode::TruncateUpper(uword end) { |
| 314 if (end < end_) { | 297 if (end < end_) { |
| 315 end_ = end; | 298 end_ = end; |
| 316 } | 299 } |
| 317 ASSERT(start_ < end_); | 300 ASSERT(start_ < end_); |
| 318 } | 301 } |
| 319 | 302 |
| 320 | |
| 321 void ProfileCode::ExpandLower(uword start) { | 303 void ProfileCode::ExpandLower(uword start) { |
| 322 if (start < start_) { | 304 if (start < start_) { |
| 323 start_ = start; | 305 start_ = start; |
| 324 } | 306 } |
| 325 ASSERT(start_ < end_); | 307 ASSERT(start_ < end_); |
| 326 } | 308 } |
| 327 | 309 |
| 328 | |
| 329 void ProfileCode::ExpandUpper(uword end) { | 310 void ProfileCode::ExpandUpper(uword end) { |
| 330 if (end > end_) { | 311 if (end > end_) { |
| 331 end_ = end; | 312 end_ = end; |
| 332 } | 313 } |
| 333 ASSERT(start_ < end_); | 314 ASSERT(start_ < end_); |
| 334 } | 315 } |
| 335 | 316 |
| 336 | |
| 337 bool ProfileCode::Overlaps(const ProfileCode* other) const { | 317 bool ProfileCode::Overlaps(const ProfileCode* other) const { |
| 338 ASSERT(other != NULL); | 318 ASSERT(other != NULL); |
| 339 return other->Contains(start_) || other->Contains(end_ - 1) || | 319 return other->Contains(start_) || other->Contains(end_ - 1) || |
| 340 Contains(other->start()) || Contains(other->end() - 1); | 320 Contains(other->start()) || Contains(other->end() - 1); |
| 341 } | 321 } |
| 342 | 322 |
| 343 | |
| 344 bool ProfileCode::IsOptimizedDart() const { | 323 bool ProfileCode::IsOptimizedDart() const { |
| 345 return !code_.IsNull() && code_.is_optimized(); | 324 return !code_.IsNull() && code_.is_optimized(); |
| 346 } | 325 } |
| 347 | 326 |
| 348 | |
| 349 void ProfileCode::SetName(const char* name) { | 327 void ProfileCode::SetName(const char* name) { |
| 350 if (name == NULL) { | 328 if (name == NULL) { |
| 351 name_ = NULL; | 329 name_ = NULL; |
| 352 } | 330 } |
| 353 intptr_t len = strlen(name); | 331 intptr_t len = strlen(name); |
| 354 name_ = Thread::Current()->zone()->Alloc<char>(len + 1); | 332 name_ = Thread::Current()->zone()->Alloc<char>(len + 1); |
| 355 strncpy(name_, name, len); | 333 strncpy(name_, name, len); |
| 356 name_[len] = '\0'; | 334 name_[len] = '\0'; |
| 357 } | 335 } |
| 358 | 336 |
| 359 | |
| 360 void ProfileCode::GenerateAndSetSymbolName(const char* prefix) { | 337 void ProfileCode::GenerateAndSetSymbolName(const char* prefix) { |
| 361 const intptr_t kBuffSize = 512; | 338 const intptr_t kBuffSize = 512; |
| 362 char buff[kBuffSize]; | 339 char buff[kBuffSize]; |
| 363 OS::SNPrint(&buff[0], kBuffSize - 1, "%s [%" Px ", %" Px ")", prefix, start(), | 340 OS::SNPrint(&buff[0], kBuffSize - 1, "%s [%" Px ", %" Px ")", prefix, start(), |
| 364 end()); | 341 end()); |
| 365 SetName(buff); | 342 SetName(buff); |
| 366 } | 343 } |
| 367 | 344 |
| 368 | |
| 369 void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) { | 345 void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) { |
| 370 // If exclusive is set, tick it. | 346 // If exclusive is set, tick it. |
| 371 if (exclusive) { | 347 if (exclusive) { |
| 372 exclusive_ticks_++; | 348 exclusive_ticks_++; |
| 373 TickAddress(pc, true); | 349 TickAddress(pc, true); |
| 374 } | 350 } |
| 375 // Fall through and tick inclusive count too. | 351 // Fall through and tick inclusive count too. |
| 376 if (inclusive_serial_ == serial) { | 352 if (inclusive_serial_ == serial) { |
| 377 // Already gave inclusive tick for this sample. | 353 // Already gave inclusive tick for this sample. |
| 378 return; | 354 return; |
| 379 } | 355 } |
| 380 inclusive_serial_ = serial; | 356 inclusive_serial_ = serial; |
| 381 inclusive_ticks_++; | 357 inclusive_ticks_++; |
| 382 TickAddress(pc, false); | 358 TickAddress(pc, false); |
| 383 } | 359 } |
| 384 | 360 |
| 385 | |
| 386 void ProfileCode::TickAddress(uword pc, bool exclusive) { | 361 void ProfileCode::TickAddress(uword pc, bool exclusive) { |
| 387 const intptr_t length = address_ticks_.length(); | 362 const intptr_t length = address_ticks_.length(); |
| 388 | 363 |
| 389 intptr_t i = 0; | 364 intptr_t i = 0; |
| 390 for (; i < length; i++) { | 365 for (; i < length; i++) { |
| 391 ProfileCodeAddress& entry = address_ticks_[i]; | 366 ProfileCodeAddress& entry = address_ticks_[i]; |
| 392 if (entry.pc() == pc) { | 367 if (entry.pc() == pc) { |
| 393 // Tick the address entry. | 368 // Tick the address entry. |
| 394 entry.Tick(exclusive); | 369 entry.Tick(exclusive); |
| 395 return; | 370 return; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 406 | 381 |
| 407 if (i < length) { | 382 if (i < length) { |
| 408 // Insert at i. | 383 // Insert at i. |
| 409 address_ticks_.InsertAt(i, entry); | 384 address_ticks_.InsertAt(i, entry); |
| 410 } else { | 385 } else { |
| 411 // Add to end. | 386 // Add to end. |
| 412 address_ticks_.Add(entry); | 387 address_ticks_.Add(entry); |
| 413 } | 388 } |
| 414 } | 389 } |
| 415 | 390 |
| 416 | |
| 417 void ProfileCode::PrintNativeCode(JSONObject* profile_code_obj) { | 391 void ProfileCode::PrintNativeCode(JSONObject* profile_code_obj) { |
| 418 ASSERT(kind() == kNativeCode); | 392 ASSERT(kind() == kNativeCode); |
| 419 JSONObject obj(profile_code_obj, "code"); | 393 JSONObject obj(profile_code_obj, "code"); |
| 420 obj.AddProperty("type", "@Code"); | 394 obj.AddProperty("type", "@Code"); |
| 421 obj.AddProperty("kind", "Native"); | 395 obj.AddProperty("kind", "Native"); |
| 422 obj.AddProperty("name", name()); | 396 obj.AddProperty("name", name()); |
| 423 obj.AddProperty("_optimized", false); | 397 obj.AddProperty("_optimized", false); |
| 424 obj.AddPropertyF("start", "%" Px "", start()); | 398 obj.AddPropertyF("start", "%" Px "", start()); |
| 425 obj.AddPropertyF("end", "%" Px "", end()); | 399 obj.AddPropertyF("end", "%" Px "", end()); |
| 426 { | 400 { |
| 427 // Generate a fake function entry. | 401 // Generate a fake function entry. |
| 428 JSONObject func(&obj, "function"); | 402 JSONObject func(&obj, "function"); |
| 429 ASSERT(function_ != NULL); | 403 ASSERT(function_ != NULL); |
| 430 function_->PrintToJSONObject(&func); | 404 function_->PrintToJSONObject(&func); |
| 431 } | 405 } |
| 432 } | 406 } |
| 433 | 407 |
| 434 | |
| 435 void ProfileCode::PrintCollectedCode(JSONObject* profile_code_obj) { | 408 void ProfileCode::PrintCollectedCode(JSONObject* profile_code_obj) { |
| 436 ASSERT(kind() == kCollectedCode); | 409 ASSERT(kind() == kCollectedCode); |
| 437 JSONObject obj(profile_code_obj, "code"); | 410 JSONObject obj(profile_code_obj, "code"); |
| 438 obj.AddProperty("type", "@Code"); | 411 obj.AddProperty("type", "@Code"); |
| 439 obj.AddProperty("kind", "Collected"); | 412 obj.AddProperty("kind", "Collected"); |
| 440 obj.AddProperty("name", name()); | 413 obj.AddProperty("name", name()); |
| 441 obj.AddProperty("_optimized", false); | 414 obj.AddProperty("_optimized", false); |
| 442 obj.AddPropertyF("start", "%" Px "", start()); | 415 obj.AddPropertyF("start", "%" Px "", start()); |
| 443 obj.AddPropertyF("end", "%" Px "", end()); | 416 obj.AddPropertyF("end", "%" Px "", end()); |
| 444 { | 417 { |
| 445 // Generate a fake function entry. | 418 // Generate a fake function entry. |
| 446 JSONObject func(&obj, "function"); | 419 JSONObject func(&obj, "function"); |
| 447 ASSERT(function_ != NULL); | 420 ASSERT(function_ != NULL); |
| 448 function_->PrintToJSONObject(&func); | 421 function_->PrintToJSONObject(&func); |
| 449 } | 422 } |
| 450 } | 423 } |
| 451 | 424 |
| 452 | |
| 453 void ProfileCode::PrintOverwrittenCode(JSONObject* profile_code_obj) { | 425 void ProfileCode::PrintOverwrittenCode(JSONObject* profile_code_obj) { |
| 454 ASSERT(kind() == kReusedCode); | 426 ASSERT(kind() == kReusedCode); |
| 455 JSONObject obj(profile_code_obj, "code"); | 427 JSONObject obj(profile_code_obj, "code"); |
| 456 obj.AddProperty("type", "@Code"); | 428 obj.AddProperty("type", "@Code"); |
| 457 obj.AddProperty("kind", "Collected"); | 429 obj.AddProperty("kind", "Collected"); |
| 458 obj.AddProperty("name", name()); | 430 obj.AddProperty("name", name()); |
| 459 obj.AddProperty("_optimized", false); | 431 obj.AddProperty("_optimized", false); |
| 460 obj.AddPropertyF("start", "%" Px "", start()); | 432 obj.AddPropertyF("start", "%" Px "", start()); |
| 461 obj.AddPropertyF("end", "%" Px "", end()); | 433 obj.AddPropertyF("end", "%" Px "", end()); |
| 462 { | 434 { |
| 463 // Generate a fake function entry. | 435 // Generate a fake function entry. |
| 464 JSONObject func(&obj, "function"); | 436 JSONObject func(&obj, "function"); |
| 465 ASSERT(function_ != NULL); | 437 ASSERT(function_ != NULL); |
| 466 function_->PrintToJSONObject(&func); | 438 function_->PrintToJSONObject(&func); |
| 467 } | 439 } |
| 468 } | 440 } |
| 469 | 441 |
| 470 | |
| 471 void ProfileCode::PrintTagCode(JSONObject* profile_code_obj) { | 442 void ProfileCode::PrintTagCode(JSONObject* profile_code_obj) { |
| 472 ASSERT(kind() == kTagCode); | 443 ASSERT(kind() == kTagCode); |
| 473 JSONObject obj(profile_code_obj, "code"); | 444 JSONObject obj(profile_code_obj, "code"); |
| 474 obj.AddProperty("type", "@Code"); | 445 obj.AddProperty("type", "@Code"); |
| 475 obj.AddProperty("kind", "Tag"); | 446 obj.AddProperty("kind", "Tag"); |
| 476 obj.AddProperty("name", name()); | 447 obj.AddProperty("name", name()); |
| 477 obj.AddPropertyF("start", "%" Px "", start()); | 448 obj.AddPropertyF("start", "%" Px "", start()); |
| 478 obj.AddPropertyF("end", "%" Px "", end()); | 449 obj.AddPropertyF("end", "%" Px "", end()); |
| 479 obj.AddProperty("_optimized", false); | 450 obj.AddProperty("_optimized", false); |
| 480 { | 451 { |
| 481 // Generate a fake function entry. | 452 // Generate a fake function entry. |
| 482 JSONObject func(&obj, "function"); | 453 JSONObject func(&obj, "function"); |
| 483 ASSERT(function_ != NULL); | 454 ASSERT(function_ != NULL); |
| 484 function_->PrintToJSONObject(&func); | 455 function_->PrintToJSONObject(&func); |
| 485 } | 456 } |
| 486 } | 457 } |
| 487 | 458 |
| 488 | |
| 489 const char* ProfileCode::KindToCString(Kind kind) { | 459 const char* ProfileCode::KindToCString(Kind kind) { |
| 490 switch (kind) { | 460 switch (kind) { |
| 491 case kDartCode: | 461 case kDartCode: |
| 492 return "Dart"; | 462 return "Dart"; |
| 493 case kCollectedCode: | 463 case kCollectedCode: |
| 494 return "Collected"; | 464 return "Collected"; |
| 495 case kNativeCode: | 465 case kNativeCode: |
| 496 return "Native"; | 466 return "Native"; |
| 497 case kReusedCode: | 467 case kReusedCode: |
| 498 return "Overwritten"; | 468 return "Overwritten"; |
| 499 case kTagCode: | 469 case kTagCode: |
| 500 return "Tag"; | 470 return "Tag"; |
| 501 } | 471 } |
| 502 UNREACHABLE(); | 472 UNREACHABLE(); |
| 503 return NULL; | 473 return NULL; |
| 504 } | 474 } |
| 505 | 475 |
| 506 | |
| 507 void ProfileCode::PrintToJSONArray(JSONArray* codes) { | 476 void ProfileCode::PrintToJSONArray(JSONArray* codes) { |
| 508 JSONObject obj(codes); | 477 JSONObject obj(codes); |
| 509 obj.AddProperty("kind", ProfileCode::KindToCString(kind())); | 478 obj.AddProperty("kind", ProfileCode::KindToCString(kind())); |
| 510 obj.AddProperty("inclusiveTicks", inclusive_ticks()); | 479 obj.AddProperty("inclusiveTicks", inclusive_ticks()); |
| 511 obj.AddProperty("exclusiveTicks", exclusive_ticks()); | 480 obj.AddProperty("exclusiveTicks", exclusive_ticks()); |
| 512 if (kind() == kDartCode) { | 481 if (kind() == kDartCode) { |
| 513 ASSERT(!code_.IsNull()); | 482 ASSERT(!code_.IsNull()); |
| 514 obj.AddProperty("code", code_); | 483 obj.AddProperty("code", code_); |
| 515 } else if (kind() == kCollectedCode) { | 484 } else if (kind() == kCollectedCode) { |
| 516 PrintCollectedCode(&obj); | 485 PrintCollectedCode(&obj); |
| 517 } else if (kind() == kReusedCode) { | 486 } else if (kind() == kReusedCode) { |
| 518 PrintOverwrittenCode(&obj); | 487 PrintOverwrittenCode(&obj); |
| 519 } else if (kind() == kTagCode) { | 488 } else if (kind() == kTagCode) { |
| 520 PrintTagCode(&obj); | 489 PrintTagCode(&obj); |
| 521 } else { | 490 } else { |
| 522 ASSERT(kind() == kNativeCode); | 491 ASSERT(kind() == kNativeCode); |
| 523 PrintNativeCode(&obj); | 492 PrintNativeCode(&obj); |
| 524 } | 493 } |
| 525 { | 494 { |
| 526 JSONArray ticks(&obj, "ticks"); | 495 JSONArray ticks(&obj, "ticks"); |
| 527 for (intptr_t i = 0; i < address_ticks_.length(); i++) { | 496 for (intptr_t i = 0; i < address_ticks_.length(); i++) { |
| 528 const ProfileCodeAddress& entry = address_ticks_[i]; | 497 const ProfileCodeAddress& entry = address_ticks_[i]; |
| 529 ticks.AddValueF("%" Px "", entry.pc()); | 498 ticks.AddValueF("%" Px "", entry.pc()); |
| 530 ticks.AddValue(entry.exclusive_ticks()); | 499 ticks.AddValue(entry.exclusive_ticks()); |
| 531 ticks.AddValue(entry.inclusive_ticks()); | 500 ticks.AddValue(entry.inclusive_ticks()); |
| 532 } | 501 } |
| 533 } | 502 } |
| 534 } | 503 } |
| 535 | 504 |
| 536 | |
| 537 class ProfileFunctionTable : public ZoneAllocated { | 505 class ProfileFunctionTable : public ZoneAllocated { |
| 538 public: | 506 public: |
| 539 ProfileFunctionTable() | 507 ProfileFunctionTable() |
| 540 : null_function_(Function::ZoneHandle()), | 508 : null_function_(Function::ZoneHandle()), |
| 541 unknown_function_(NULL), | 509 unknown_function_(NULL), |
| 542 table_(8) { | 510 table_(8) { |
| 543 unknown_function_ = | 511 unknown_function_ = |
| 544 Add(ProfileFunction::kUnknownFunction, "<unknown Dart function>"); | 512 Add(ProfileFunction::kUnknownFunction, "<unknown Dart function>"); |
| 545 } | 513 } |
| 546 | 514 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 return kv->function()->raw() == key->raw(); | 592 return kv->function()->raw() == key->raw(); |
| 625 } | 593 } |
| 626 }; | 594 }; |
| 627 | 595 |
| 628 const Function& null_function_; | 596 const Function& null_function_; |
| 629 ProfileFunction* unknown_function_; | 597 ProfileFunction* unknown_function_; |
| 630 ZoneGrowableArray<ProfileFunction*> table_; | 598 ZoneGrowableArray<ProfileFunction*> table_; |
| 631 DirectChainedHashMap<ProfileFunctionTableTrait> function_hash_; | 599 DirectChainedHashMap<ProfileFunctionTableTrait> function_hash_; |
| 632 }; | 600 }; |
| 633 | 601 |
| 634 | |
| 635 ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) { | 602 ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) { |
| 636 ASSERT(function_ == NULL); | 603 ASSERT(function_ == NULL); |
| 637 | 604 |
| 638 ProfileFunction* function = NULL; | 605 ProfileFunction* function = NULL; |
| 639 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) { | 606 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) { |
| 640 if (name() == NULL) { | 607 if (name() == NULL) { |
| 641 // Lazily set generated name. | 608 // Lazily set generated name. |
| 642 GenerateAndSetSymbolName("[Collected]"); | 609 GenerateAndSetSymbolName("[Collected]"); |
| 643 } | 610 } |
| 644 // Map these to a canonical unknown function. | 611 // Map these to a canonical unknown function. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 UNREACHABLE(); | 675 UNREACHABLE(); |
| 709 } | 676 } |
| 710 ASSERT(function != NULL); | 677 ASSERT(function != NULL); |
| 711 | 678 |
| 712 function->AddProfileCode(code_table_index()); | 679 function->AddProfileCode(code_table_index()); |
| 713 | 680 |
| 714 function_ = function; | 681 function_ = function; |
| 715 return function_; | 682 return function_; |
| 716 } | 683 } |
| 717 | 684 |
| 718 | |
| 719 intptr_t ProfileCodeTable::FindCodeIndexForPC(uword pc) const { | 685 intptr_t ProfileCodeTable::FindCodeIndexForPC(uword pc) const { |
| 720 intptr_t length = table_.length(); | 686 intptr_t length = table_.length(); |
| 721 if (length == 0) { | 687 if (length == 0) { |
| 722 return -1; // Not found. | 688 return -1; // Not found. |
| 723 } | 689 } |
| 724 intptr_t lo = 0; | 690 intptr_t lo = 0; |
| 725 intptr_t hi = length - 1; | 691 intptr_t hi = length - 1; |
| 726 while (lo <= hi) { | 692 while (lo <= hi) { |
| 727 intptr_t mid = (hi - lo + 1) / 2 + lo; | 693 intptr_t mid = (hi - lo + 1) / 2 + lo; |
| 728 ASSERT(mid >= lo); | 694 ASSERT(mid >= lo); |
| 729 ASSERT(mid <= hi); | 695 ASSERT(mid <= hi); |
| 730 ProfileCode* code = At(mid); | 696 ProfileCode* code = At(mid); |
| 731 if (code->Contains(pc)) { | 697 if (code->Contains(pc)) { |
| 732 return mid; | 698 return mid; |
| 733 } else if (pc < code->start()) { | 699 } else if (pc < code->start()) { |
| 734 hi = mid - 1; | 700 hi = mid - 1; |
| 735 } else { | 701 } else { |
| 736 lo = mid + 1; | 702 lo = mid + 1; |
| 737 } | 703 } |
| 738 } | 704 } |
| 739 return -1; | 705 return -1; |
| 740 } | 706 } |
| 741 | 707 |
| 742 | |
| 743 intptr_t ProfileCodeTable::InsertCode(ProfileCode* new_code) { | 708 intptr_t ProfileCodeTable::InsertCode(ProfileCode* new_code) { |
| 744 const intptr_t length = table_.length(); | 709 const intptr_t length = table_.length(); |
| 745 if (length == 0) { | 710 if (length == 0) { |
| 746 table_.Add(new_code); | 711 table_.Add(new_code); |
| 747 return length; | 712 return length; |
| 748 } | 713 } |
| 749 | 714 |
| 750 // Determine the correct place to insert or merge |new_code| into table. | 715 // Determine the correct place to insert or merge |new_code| into table. |
| 751 intptr_t lo = -1; | 716 intptr_t lo = -1; |
| 752 intptr_t hi = -1; | 717 intptr_t hi = -1; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 792 insert = 0; | 757 insert = 0; |
| 793 } else if (hi == -1) { | 758 } else if (hi == -1) { |
| 794 insert = length; | 759 insert = length; |
| 795 } else { | 760 } else { |
| 796 insert = lo + 1; | 761 insert = lo + 1; |
| 797 } | 762 } |
| 798 table_.InsertAt(insert, new_code); | 763 table_.InsertAt(insert, new_code); |
| 799 return insert; | 764 return insert; |
| 800 } | 765 } |
| 801 | 766 |
| 802 | |
| 803 void ProfileCodeTable::FindNeighbors(uword pc, | 767 void ProfileCodeTable::FindNeighbors(uword pc, |
| 804 intptr_t* lo, | 768 intptr_t* lo, |
| 805 intptr_t* hi, | 769 intptr_t* hi, |
| 806 ProfileCode** lo_code, | 770 ProfileCode** lo_code, |
| 807 ProfileCode** hi_code) const { | 771 ProfileCode** hi_code) const { |
| 808 ASSERT(table_.length() >= 1); | 772 ASSERT(table_.length() >= 1); |
| 809 | 773 |
| 810 intptr_t length = table_.length(); | 774 intptr_t length = table_.length(); |
| 811 | 775 |
| 812 if (pc < At(0)->start()) { | 776 if (pc < At(0)->start()) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 841 *lo = mid; | 805 *lo = mid; |
| 842 *lo_code = code; | 806 *lo_code = code; |
| 843 } | 807 } |
| 844 if (pc < code->end()) { | 808 if (pc < code->end()) { |
| 845 *hi = mid; | 809 *hi = mid; |
| 846 *hi_code = code; | 810 *hi_code = code; |
| 847 } | 811 } |
| 848 } | 812 } |
| 849 } | 813 } |
| 850 | 814 |
| 851 | |
| 852 void ProfileCodeTable::VerifyOrder() { | 815 void ProfileCodeTable::VerifyOrder() { |
| 853 const intptr_t length = table_.length(); | 816 const intptr_t length = table_.length(); |
| 854 if (length == 0) { | 817 if (length == 0) { |
| 855 return; | 818 return; |
| 856 } | 819 } |
| 857 uword last = table_[0]->end(); | 820 uword last = table_[0]->end(); |
| 858 for (intptr_t i = 1; i < length; i++) { | 821 for (intptr_t i = 1; i < length; i++) { |
| 859 ProfileCode* a = table_[i]; | 822 ProfileCode* a = table_[i]; |
| 860 ASSERT(last <= a->start()); | 823 ASSERT(last <= a->start()); |
| 861 last = a->end(); | 824 last = a->end(); |
| 862 } | 825 } |
| 863 } | 826 } |
| 864 | 827 |
| 865 void ProfileCodeTable::VerifyOverlap() { | 828 void ProfileCodeTable::VerifyOverlap() { |
| 866 const intptr_t length = table_.length(); | 829 const intptr_t length = table_.length(); |
| 867 for (intptr_t i = 0; i < length; i++) { | 830 for (intptr_t i = 0; i < length; i++) { |
| 868 ProfileCode* a = table_[i]; | 831 ProfileCode* a = table_[i]; |
| 869 for (intptr_t j = i + 1; j < length; j++) { | 832 for (intptr_t j = i + 1; j < length; j++) { |
| 870 ProfileCode* b = table_[j]; | 833 ProfileCode* b = table_[j]; |
| 871 ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && | 834 ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && |
| 872 !b->Contains(a->start()) && !b->Contains(a->end() - 1)); | 835 !b->Contains(a->start()) && !b->Contains(a->end() - 1)); |
| 873 } | 836 } |
| 874 } | 837 } |
| 875 } | 838 } |
| 876 | 839 |
| 877 | |
| 878 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) | 840 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) |
| 879 : table_index_(table_index), | 841 : table_index_(table_index), |
| 880 count_(0), | 842 count_(0), |
| 881 exclusive_allocations_(0), | 843 exclusive_allocations_(0), |
| 882 inclusive_allocations_(0), | 844 inclusive_allocations_(0), |
| 883 children_(0), | 845 children_(0), |
| 884 frame_id_(-1) { | 846 frame_id_(-1) { |
| 885 ASSERT(table_index_ >= 0); | 847 ASSERT(table_index_ >= 0); |
| 886 } | 848 } |
| 887 | 849 |
| 888 | |
| 889 ProfileTrieNode::~ProfileTrieNode() {} | 850 ProfileTrieNode::~ProfileTrieNode() {} |
| 890 | 851 |
| 891 | |
| 892 void ProfileTrieNode::Tick(ProcessedSample* sample, bool exclusive) { | 852 void ProfileTrieNode::Tick(ProcessedSample* sample, bool exclusive) { |
| 893 count_++; | 853 count_++; |
| 894 IncrementAllocation(sample->native_allocation_size_bytes(), exclusive); | 854 IncrementAllocation(sample->native_allocation_size_bytes(), exclusive); |
| 895 } | 855 } |
| 896 | 856 |
| 897 | |
| 898 void ProfileTrieNode::SortChildren() { | 857 void ProfileTrieNode::SortChildren() { |
| 899 children_.Sort(ProfileTrieNodeCompare); | 858 children_.Sort(ProfileTrieNodeCompare); |
| 900 // Recurse. | 859 // Recurse. |
| 901 for (intptr_t i = 0; i < children_.length(); i++) { | 860 for (intptr_t i = 0; i < children_.length(); i++) { |
| 902 children_[i]->SortChildren(); | 861 children_[i]->SortChildren(); |
| 903 } | 862 } |
| 904 } | 863 } |
| 905 | 864 |
| 906 | |
| 907 intptr_t ProfileTrieNode::IndexOf(ProfileTrieNode* node) { | 865 intptr_t ProfileTrieNode::IndexOf(ProfileTrieNode* node) { |
| 908 for (intptr_t i = 0; i < children_.length(); i++) { | 866 for (intptr_t i = 0; i < children_.length(); i++) { |
| 909 if (children_[i] == node) { | 867 if (children_[i] == node) { |
| 910 return i; | 868 return i; |
| 911 } | 869 } |
| 912 } | 870 } |
| 913 return -1; | 871 return -1; |
| 914 } | 872 } |
| 915 | 873 |
| 916 | |
| 917 class ProfileCodeTrieNode : public ProfileTrieNode { | 874 class ProfileCodeTrieNode : public ProfileTrieNode { |
| 918 public: | 875 public: |
| 919 explicit ProfileCodeTrieNode(intptr_t table_index) | 876 explicit ProfileCodeTrieNode(intptr_t table_index) |
| 920 : ProfileTrieNode(table_index) {} | 877 : ProfileTrieNode(table_index) {} |
| 921 | 878 |
| 922 void PrintToJSONArray(JSONArray* array) const { | 879 void PrintToJSONArray(JSONArray* array) const { |
| 923 ASSERT(array != NULL); | 880 ASSERT(array != NULL); |
| 924 // Write CodeRegion index. | 881 // Write CodeRegion index. |
| 925 array->AddValue(table_index()); | 882 array->AddValue(table_index()); |
| 926 // Write count. | 883 // Write count. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 957 // Insert at i. | 914 // Insert at i. |
| 958 children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child)); | 915 children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child)); |
| 959 } else { | 916 } else { |
| 960 // Add to end. | 917 // Add to end. |
| 961 children_.Add(reinterpret_cast<ProfileTrieNode*>(child)); | 918 children_.Add(reinterpret_cast<ProfileTrieNode*>(child)); |
| 962 } | 919 } |
| 963 return child; | 920 return child; |
| 964 } | 921 } |
| 965 }; | 922 }; |
| 966 | 923 |
| 967 | |
| 968 class ProfileFunctionTrieNodeCode { | 924 class ProfileFunctionTrieNodeCode { |
| 969 public: | 925 public: |
| 970 explicit ProfileFunctionTrieNodeCode(intptr_t index) | 926 explicit ProfileFunctionTrieNodeCode(intptr_t index) |
| 971 : code_index_(index), ticks_(0) {} | 927 : code_index_(index), ticks_(0) {} |
| 972 | 928 |
| 973 intptr_t index() const { return code_index_; } | 929 intptr_t index() const { return code_index_; } |
| 974 | 930 |
| 975 void Tick() { ticks_++; } | 931 void Tick() { ticks_++; } |
| 976 | 932 |
| 977 intptr_t ticks() const { return ticks_; } | 933 intptr_t ticks() const { return ticks_; } |
| 978 | 934 |
| 979 private: | 935 private: |
| 980 intptr_t code_index_; | 936 intptr_t code_index_; |
| 981 intptr_t ticks_; | 937 intptr_t ticks_; |
| 982 }; | 938 }; |
| 983 | 939 |
| 984 | |
| 985 class ProfileFunctionTrieNode : public ProfileTrieNode { | 940 class ProfileFunctionTrieNode : public ProfileTrieNode { |
| 986 public: | 941 public: |
| 987 explicit ProfileFunctionTrieNode(intptr_t table_index) | 942 explicit ProfileFunctionTrieNode(intptr_t table_index) |
| 988 : ProfileTrieNode(table_index), code_objects_(1) {} | 943 : ProfileTrieNode(table_index), code_objects_(1) {} |
| 989 | 944 |
| 990 void PrintToJSONArray(JSONArray* array) const { | 945 void PrintToJSONArray(JSONArray* array) const { |
| 991 ASSERT(array != NULL); | 946 ASSERT(array != NULL); |
| 992 // Write CodeRegion index. | 947 // Write CodeRegion index. |
| 993 array->AddValue(table_index()); | 948 array->AddValue(table_index()); |
| 994 // Write count. | 949 // Write count. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 } | 1005 } |
| 1051 ProfileFunctionTrieNodeCode code_object(index); | 1006 ProfileFunctionTrieNodeCode code_object(index); |
| 1052 code_object.Tick(); | 1007 code_object.Tick(); |
| 1053 code_objects_.Add(code_object); | 1008 code_objects_.Add(code_object); |
| 1054 } | 1009 } |
| 1055 | 1010 |
| 1056 private: | 1011 private: |
| 1057 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_; | 1012 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_; |
| 1058 }; | 1013 }; |
| 1059 | 1014 |
| 1060 | |
| 1061 class ProfileCodeInlinedFunctionsCache : public ValueObject { | 1015 class ProfileCodeInlinedFunctionsCache : public ValueObject { |
| 1062 public: | 1016 public: |
| 1063 ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) { | 1017 ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) { |
| 1064 for (intptr_t i = 0; i < kCacheSize; i++) { | 1018 for (intptr_t i = 0; i < kCacheSize; i++) { |
| 1065 cache_[i].Reset(); | 1019 cache_[i].Reset(); |
| 1066 } | 1020 } |
| 1067 cache_hit_ = 0; | 1021 cache_hit_ = 0; |
| 1068 cache_miss_ = 0; | 1022 cache_miss_ = 0; |
| 1069 } | 1023 } |
| 1070 | 1024 |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1195 }; | 1149 }; |
| 1196 | 1150 |
| 1197 static const intptr_t kCacheSize = 128; | 1151 static const intptr_t kCacheSize = 128; |
| 1198 intptr_t cache_cursor_; | 1152 intptr_t cache_cursor_; |
| 1199 intptr_t last_hit_; | 1153 intptr_t last_hit_; |
| 1200 CacheEntry cache_[kCacheSize]; | 1154 CacheEntry cache_[kCacheSize]; |
| 1201 intptr_t cache_miss_; | 1155 intptr_t cache_miss_; |
| 1202 intptr_t cache_hit_; | 1156 intptr_t cache_hit_; |
| 1203 }; | 1157 }; |
| 1204 | 1158 |
| 1205 | |
| 1206 class ProfileBuilder : public ValueObject { | 1159 class ProfileBuilder : public ValueObject { |
| 1207 public: | 1160 public: |
| 1208 enum ProfileInfoKind { | 1161 enum ProfileInfoKind { |
| 1209 kNone, | 1162 kNone, |
| 1210 kOptimized, | 1163 kOptimized, |
| 1211 kUnoptimized, | 1164 kUnoptimized, |
| 1212 kNative, | 1165 kNative, |
| 1213 kInlineStart, | 1166 kInlineStart, |
| 1214 kInlineFinish, | 1167 kInlineFinish, |
| 1215 kNumProfileInfoKind, | 1168 kNumProfileInfoKind, |
| (...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1771 ProfileCodeTable* tag_table = profile_->tag_code_; | 1724 ProfileCodeTable* tag_table = profile_->tag_code_; |
| 1772 intptr_t index = tag_table->FindCodeIndexForPC(VMTag::kTruncatedTagId); | 1725 intptr_t index = tag_table->FindCodeIndexForPC(VMTag::kTruncatedTagId); |
| 1773 ASSERT(index >= 0); | 1726 ASSERT(index >= 0); |
| 1774 ProfileCode* code = tag_table->At(index); | 1727 ProfileCode* code = tag_table->At(index); |
| 1775 code->IncInclusiveTicks(); | 1728 code->IncInclusiveTicks(); |
| 1776 ASSERT(code != NULL); | 1729 ASSERT(code != NULL); |
| 1777 ProfileFunction* function = code->function(); | 1730 ProfileFunction* function = code->function(); |
| 1778 function->IncInclusiveTicks(); | 1731 function->IncInclusiveTicks(); |
| 1779 } | 1732 } |
| 1780 | 1733 |
| 1781 | |
| 1782 // Tag append functions are overloaded for |ProfileCodeTrieNode| and | 1734 // Tag append functions are overloaded for |ProfileCodeTrieNode| and |
| 1783 // |ProfileFunctionTrieNode| types. | 1735 // |ProfileFunctionTrieNode| types. |
| 1784 | 1736 |
| 1785 // ProfileCodeTrieNode | 1737 // ProfileCodeTrieNode |
| 1786 ProfileCodeTrieNode* AppendUserTag(uword user_tag, | 1738 ProfileCodeTrieNode* AppendUserTag(uword user_tag, |
| 1787 ProfileCodeTrieNode* current, | 1739 ProfileCodeTrieNode* current, |
| 1788 ProcessedSample* sample) { | 1740 ProcessedSample* sample) { |
| 1789 intptr_t user_tag_index = GetProfileCodeTagIndex(user_tag); | 1741 intptr_t user_tag_index = GetProfileCodeTagIndex(user_tag); |
| 1790 if (user_tag_index >= 0) { | 1742 if (user_tag_index >= 0) { |
| 1791 current = current->GetChild(user_tag_index); | 1743 current = current->GetChild(user_tag_index); |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2218 ProfileCode* code = | 2170 ProfileCode* code = |
| 2219 new ProfileCode(ProfileCode::kReusedCode, pc, pc + 1, 0, null_code_); | 2171 new ProfileCode(ProfileCode::kReusedCode, pc, pc + 1, 0, null_code_); |
| 2220 return code; | 2172 return code; |
| 2221 } | 2173 } |
| 2222 | 2174 |
| 2223 bool IsPCInDartHeap(uword pc) { | 2175 bool IsPCInDartHeap(uword pc) { |
| 2224 return vm_isolate_->heap()->CodeContains(pc) || | 2176 return vm_isolate_->heap()->CodeContains(pc) || |
| 2225 thread_->isolate()->heap()->CodeContains(pc); | 2177 thread_->isolate()->heap()->CodeContains(pc); |
| 2226 } | 2178 } |
| 2227 | 2179 |
| 2228 | |
| 2229 ProfileCode* FindOrRegisterNativeProfileCode(uword pc) { | 2180 ProfileCode* FindOrRegisterNativeProfileCode(uword pc) { |
| 2230 // Check if |pc| is already known in the live code table. | 2181 // Check if |pc| is already known in the live code table. |
| 2231 ProfileCodeTable* live_table = profile_->live_code_; | 2182 ProfileCodeTable* live_table = profile_->live_code_; |
| 2232 ProfileCode* profile_code = live_table->FindCodeForPC(pc); | 2183 ProfileCode* profile_code = live_table->FindCodeForPC(pc); |
| 2233 if (profile_code != NULL) { | 2184 if (profile_code != NULL) { |
| 2234 return profile_code; | 2185 return profile_code; |
| 2235 } | 2186 } |
| 2236 | 2187 |
| 2237 // We haven't seen this pc yet. | 2188 // We haven't seen this pc yet. |
| 2238 Code& code = Code::Handle(thread_->zone()); | 2189 Code& code = Code::Handle(thread_->zone()); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2338 DeoptimizedCodeSet* deoptimized_code_; | 2289 DeoptimizedCodeSet* deoptimized_code_; |
| 2339 const Code& null_code_; | 2290 const Code& null_code_; |
| 2340 const Function& null_function_; | 2291 const Function& null_function_; |
| 2341 bool tick_functions_; | 2292 bool tick_functions_; |
| 2342 bool inclusive_tree_; | 2293 bool inclusive_tree_; |
| 2343 ProfileCodeInlinedFunctionsCache inlined_functions_cache_; | 2294 ProfileCodeInlinedFunctionsCache inlined_functions_cache_; |
| 2344 ProcessedSampleBuffer* samples_; | 2295 ProcessedSampleBuffer* samples_; |
| 2345 ProfileInfoKind info_kind_; | 2296 ProfileInfoKind info_kind_; |
| 2346 }; // ProfileBuilder. | 2297 }; // ProfileBuilder. |
| 2347 | 2298 |
| 2348 | |
| 2349 Profile::Profile(Isolate* isolate) | 2299 Profile::Profile(Isolate* isolate) |
| 2350 : isolate_(isolate), | 2300 : isolate_(isolate), |
| 2351 zone_(Thread::Current()->zone()), | 2301 zone_(Thread::Current()->zone()), |
| 2352 samples_(NULL), | 2302 samples_(NULL), |
| 2353 live_code_(NULL), | 2303 live_code_(NULL), |
| 2354 dead_code_(NULL), | 2304 dead_code_(NULL), |
| 2355 tag_code_(NULL), | 2305 tag_code_(NULL), |
| 2356 functions_(NULL), | 2306 functions_(NULL), |
| 2357 dead_code_index_offset_(-1), | 2307 dead_code_index_offset_(-1), |
| 2358 tag_code_index_offset_(-1), | 2308 tag_code_index_offset_(-1), |
| 2359 min_time_(kMaxInt64), | 2309 min_time_(kMaxInt64), |
| 2360 max_time_(0) { | 2310 max_time_(0) { |
| 2361 ASSERT(isolate_ != NULL); | 2311 ASSERT(isolate_ != NULL); |
| 2362 for (intptr_t i = 0; i < kNumTrieKinds; i++) { | 2312 for (intptr_t i = 0; i < kNumTrieKinds; i++) { |
| 2363 roots_[i] = NULL; | 2313 roots_[i] = NULL; |
| 2364 } | 2314 } |
| 2365 } | 2315 } |
| 2366 | 2316 |
| 2367 | |
| 2368 void Profile::Build(Thread* thread, | 2317 void Profile::Build(Thread* thread, |
| 2369 SampleFilter* filter, | 2318 SampleFilter* filter, |
| 2370 SampleBuffer* sample_buffer, | 2319 SampleBuffer* sample_buffer, |
| 2371 TagOrder tag_order, | 2320 TagOrder tag_order, |
| 2372 intptr_t extra_tags) { | 2321 intptr_t extra_tags) { |
| 2373 ProfileBuilder builder(thread, filter, sample_buffer, tag_order, extra_tags, | 2322 ProfileBuilder builder(thread, filter, sample_buffer, tag_order, extra_tags, |
| 2374 this); | 2323 this); |
| 2375 builder.Build(); | 2324 builder.Build(); |
| 2376 } | 2325 } |
| 2377 | 2326 |
| 2378 | |
| 2379 intptr_t Profile::NumFunctions() const { | 2327 intptr_t Profile::NumFunctions() const { |
| 2380 return functions_->length(); | 2328 return functions_->length(); |
| 2381 } | 2329 } |
| 2382 | 2330 |
| 2383 ProfileFunction* Profile::GetFunction(intptr_t index) { | 2331 ProfileFunction* Profile::GetFunction(intptr_t index) { |
| 2384 ASSERT(functions_ != NULL); | 2332 ASSERT(functions_ != NULL); |
| 2385 return functions_->At(index); | 2333 return functions_->At(index); |
| 2386 } | 2334 } |
| 2387 | 2335 |
| 2388 | |
| 2389 ProfileCode* Profile::GetCode(intptr_t index) { | 2336 ProfileCode* Profile::GetCode(intptr_t index) { |
| 2390 ASSERT(live_code_ != NULL); | 2337 ASSERT(live_code_ != NULL); |
| 2391 ASSERT(dead_code_ != NULL); | 2338 ASSERT(dead_code_ != NULL); |
| 2392 ASSERT(tag_code_ != NULL); | 2339 ASSERT(tag_code_ != NULL); |
| 2393 ASSERT(dead_code_index_offset_ >= 0); | 2340 ASSERT(dead_code_index_offset_ >= 0); |
| 2394 ASSERT(tag_code_index_offset_ >= 0); | 2341 ASSERT(tag_code_index_offset_ >= 0); |
| 2395 | 2342 |
| 2396 // Code indexes span three arrays. | 2343 // Code indexes span three arrays. |
| 2397 // 0 ... |live_code| | 2344 // 0 ... |live_code| |
| 2398 // |live_code| ... |dead_code| | 2345 // |live_code| ... |dead_code| |
| 2399 // |dead_code| ... |tag_code| | 2346 // |dead_code| ... |tag_code| |
| 2400 | 2347 |
| 2401 if (index < dead_code_index_offset_) { | 2348 if (index < dead_code_index_offset_) { |
| 2402 return live_code_->At(index); | 2349 return live_code_->At(index); |
| 2403 } | 2350 } |
| 2404 | 2351 |
| 2405 if (index < tag_code_index_offset_) { | 2352 if (index < tag_code_index_offset_) { |
| 2406 index -= dead_code_index_offset_; | 2353 index -= dead_code_index_offset_; |
| 2407 return dead_code_->At(index); | 2354 return dead_code_->At(index); |
| 2408 } | 2355 } |
| 2409 | 2356 |
| 2410 index -= tag_code_index_offset_; | 2357 index -= tag_code_index_offset_; |
| 2411 return tag_code_->At(index); | 2358 return tag_code_->At(index); |
| 2412 } | 2359 } |
| 2413 | 2360 |
| 2414 | |
| 2415 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { | 2361 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { |
| 2416 return roots_[static_cast<intptr_t>(trie_kind)]; | 2362 return roots_[static_cast<intptr_t>(trie_kind)]; |
| 2417 } | 2363 } |
| 2418 | 2364 |
| 2419 | |
| 2420 void Profile::PrintHeaderJSON(JSONObject* obj) { | 2365 void Profile::PrintHeaderJSON(JSONObject* obj) { |
| 2421 obj->AddProperty("samplePeriod", static_cast<intptr_t>(FLAG_profile_period)); | 2366 obj->AddProperty("samplePeriod", static_cast<intptr_t>(FLAG_profile_period)); |
| 2422 obj->AddProperty("stackDepth", static_cast<intptr_t>(FLAG_max_profile_depth)); | 2367 obj->AddProperty("stackDepth", static_cast<intptr_t>(FLAG_max_profile_depth)); |
| 2423 obj->AddProperty("sampleCount", sample_count()); | 2368 obj->AddProperty("sampleCount", sample_count()); |
| 2424 obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); | 2369 obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); |
| 2425 obj->AddPropertyTimeMicros("timeOriginMicros", min_time()); | 2370 obj->AddPropertyTimeMicros("timeOriginMicros", min_time()); |
| 2426 obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan()); | 2371 obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan()); |
| 2427 | 2372 |
| 2428 ProfilerCounters counters = Profiler::counters(); | 2373 ProfilerCounters counters = Profiler::counters(); |
| 2429 { | 2374 { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2442 "single_frame_sample_get_and_validate_stack_bounds", | 2387 "single_frame_sample_get_and_validate_stack_bounds", |
| 2443 counters.single_frame_sample_get_and_validate_stack_bounds); | 2388 counters.single_frame_sample_get_and_validate_stack_bounds); |
| 2444 counts.AddProperty64("stack_walker_native", counters.stack_walker_native); | 2389 counts.AddProperty64("stack_walker_native", counters.stack_walker_native); |
| 2445 counts.AddProperty64("stack_walker_dart_exit", | 2390 counts.AddProperty64("stack_walker_dart_exit", |
| 2446 counters.stack_walker_dart_exit); | 2391 counters.stack_walker_dart_exit); |
| 2447 counts.AddProperty64("stack_walker_dart", counters.stack_walker_dart); | 2392 counts.AddProperty64("stack_walker_dart", counters.stack_walker_dart); |
| 2448 counts.AddProperty64("stack_walker_none", counters.stack_walker_none); | 2393 counts.AddProperty64("stack_walker_none", counters.stack_walker_none); |
| 2449 } | 2394 } |
| 2450 } | 2395 } |
| 2451 | 2396 |
| 2452 | |
| 2453 void Profile::PrintTimelineFrameJSON(JSONObject* frames, | 2397 void Profile::PrintTimelineFrameJSON(JSONObject* frames, |
| 2454 ProfileTrieNode* current, | 2398 ProfileTrieNode* current, |
| 2455 ProfileTrieNode* parent, | 2399 ProfileTrieNode* parent, |
| 2456 intptr_t* next_id) { | 2400 intptr_t* next_id) { |
| 2457 ASSERT(current->frame_id() == -1); | 2401 ASSERT(current->frame_id() == -1); |
| 2458 const intptr_t id = *next_id; | 2402 const intptr_t id = *next_id; |
| 2459 *next_id = id + 1; | 2403 *next_id = id + 1; |
| 2460 current->set_frame_id(id); | 2404 current->set_frame_id(id); |
| 2461 ASSERT(current->frame_id() != -1); | 2405 ASSERT(current->frame_id() != -1); |
| 2462 | 2406 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2476 parent->frame_id()); | 2420 parent->frame_id()); |
| 2477 } | 2421 } |
| 2478 } | 2422 } |
| 2479 | 2423 |
| 2480 for (intptr_t i = 0; i < current->NumChildren(); i++) { | 2424 for (intptr_t i = 0; i < current->NumChildren(); i++) { |
| 2481 ProfileTrieNode* child = current->At(i); | 2425 ProfileTrieNode* child = current->At(i); |
| 2482 PrintTimelineFrameJSON(frames, child, current, next_id); | 2426 PrintTimelineFrameJSON(frames, child, current, next_id); |
| 2483 } | 2427 } |
| 2484 } | 2428 } |
| 2485 | 2429 |
| 2486 | |
| 2487 void Profile::PrintTimelineJSON(JSONStream* stream) { | 2430 void Profile::PrintTimelineJSON(JSONStream* stream) { |
| 2488 ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); | 2431 ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); |
| 2489 JSONObject obj(stream); | 2432 JSONObject obj(stream); |
| 2490 obj.AddProperty("type", "_CpuProfileTimeline"); | 2433 obj.AddProperty("type", "_CpuProfileTimeline"); |
| 2491 PrintHeaderJSON(&obj); | 2434 PrintHeaderJSON(&obj); |
| 2492 { | 2435 { |
| 2493 JSONObject frames(&obj, "stackFrames"); | 2436 JSONObject frames(&obj, "stackFrames"); |
| 2494 ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); | 2437 ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); |
| 2495 intptr_t next_id = 0; | 2438 intptr_t next_id = 0; |
| 2496 PrintTimelineFrameJSON(&frames, root, NULL, &next_id); | 2439 PrintTimelineFrameJSON(&frames, root, NULL, &next_id); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2511 event.AddPropertyTimeMicros("ts", sample->timestamp()); | 2454 event.AddPropertyTimeMicros("ts", sample->timestamp()); |
| 2512 event.AddProperty("cat", "Dart"); | 2455 event.AddProperty("cat", "Dart"); |
| 2513 | 2456 |
| 2514 ProfileTrieNode* trie = sample->timeline_trie(); | 2457 ProfileTrieNode* trie = sample->timeline_trie(); |
| 2515 ASSERT(trie->frame_id() != -1); | 2458 ASSERT(trie->frame_id() != -1); |
| 2516 event.AddPropertyF("sf", "%" Pd "-%" Pd, isolate_id, trie->frame_id()); | 2459 event.AddPropertyF("sf", "%" Pd "-%" Pd, isolate_id, trie->frame_id()); |
| 2517 } | 2460 } |
| 2518 } | 2461 } |
| 2519 } | 2462 } |
| 2520 | 2463 |
| 2521 | |
| 2522 ProfileFunction* Profile::FindFunction(const Function& function) { | 2464 ProfileFunction* Profile::FindFunction(const Function& function) { |
| 2523 return (functions_ != NULL) ? functions_->Lookup(function) : NULL; | 2465 return (functions_ != NULL) ? functions_->Lookup(function) : NULL; |
| 2524 } | 2466 } |
| 2525 | 2467 |
| 2526 | |
| 2527 void Profile::PrintProfileJSON(JSONStream* stream) { | 2468 void Profile::PrintProfileJSON(JSONStream* stream) { |
| 2528 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); | 2469 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); |
| 2529 JSONObject obj(stream); | 2470 JSONObject obj(stream); |
| 2530 obj.AddProperty("type", "_CpuProfile"); | 2471 obj.AddProperty("type", "_CpuProfile"); |
| 2531 PrintHeaderJSON(&obj); | 2472 PrintHeaderJSON(&obj); |
| 2532 { | 2473 { |
| 2533 JSONArray codes(&obj, "codes"); | 2474 JSONArray codes(&obj, "codes"); |
| 2534 for (intptr_t i = 0; i < live_code_->length(); i++) { | 2475 for (intptr_t i = 0; i < live_code_->length(); i++) { |
| 2535 ProfileCode* code = live_code_->At(i); | 2476 ProfileCode* code = live_code_->At(i); |
| 2536 ASSERT(code != NULL); | 2477 ASSERT(code != NULL); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2575 root->PrintToJSONArray(&function_trie); | 2516 root->PrintToJSONArray(&function_trie); |
| 2576 } | 2517 } |
| 2577 { | 2518 { |
| 2578 JSONArray function_trie(&obj, "inclusiveFunctionTrie"); | 2519 JSONArray function_trie(&obj, "inclusiveFunctionTrie"); |
| 2579 ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveFunction)]; | 2520 ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveFunction)]; |
| 2580 ASSERT(root != NULL); | 2521 ASSERT(root != NULL); |
| 2581 root->PrintToJSONArray(&function_trie); | 2522 root->PrintToJSONArray(&function_trie); |
| 2582 } | 2523 } |
| 2583 } | 2524 } |
| 2584 | 2525 |
| 2585 | |
| 2586 void ProfileTrieWalker::Reset(Profile::TrieKind trie_kind) { | 2526 void ProfileTrieWalker::Reset(Profile::TrieKind trie_kind) { |
| 2587 code_trie_ = Profile::IsCodeTrie(trie_kind); | 2527 code_trie_ = Profile::IsCodeTrie(trie_kind); |
| 2588 parent_ = NULL; | 2528 parent_ = NULL; |
| 2589 current_ = profile_->GetTrieRoot(trie_kind); | 2529 current_ = profile_->GetTrieRoot(trie_kind); |
| 2590 ASSERT(current_ != NULL); | 2530 ASSERT(current_ != NULL); |
| 2591 } | 2531 } |
| 2592 | 2532 |
| 2593 | |
| 2594 const char* ProfileTrieWalker::CurrentName() { | 2533 const char* ProfileTrieWalker::CurrentName() { |
| 2595 if (current_ == NULL) { | 2534 if (current_ == NULL) { |
| 2596 return NULL; | 2535 return NULL; |
| 2597 } | 2536 } |
| 2598 if (code_trie_) { | 2537 if (code_trie_) { |
| 2599 ProfileCode* code = profile_->GetCode(current_->table_index()); | 2538 ProfileCode* code = profile_->GetCode(current_->table_index()); |
| 2600 return code->name(); | 2539 return code->name(); |
| 2601 } else { | 2540 } else { |
| 2602 ProfileFunction* func = profile_->GetFunction(current_->table_index()); | 2541 ProfileFunction* func = profile_->GetFunction(current_->table_index()); |
| 2603 return func->Name(); | 2542 return func->Name(); |
| 2604 } | 2543 } |
| 2605 UNREACHABLE(); | 2544 UNREACHABLE(); |
| 2606 return NULL; | 2545 return NULL; |
| 2607 } | 2546 } |
| 2608 | 2547 |
| 2609 | |
| 2610 intptr_t ProfileTrieWalker::CurrentNodeTickCount() { | 2548 intptr_t ProfileTrieWalker::CurrentNodeTickCount() { |
| 2611 if (current_ == NULL) { | 2549 if (current_ == NULL) { |
| 2612 return -1; | 2550 return -1; |
| 2613 } | 2551 } |
| 2614 return current_->count(); | 2552 return current_->count(); |
| 2615 } | 2553 } |
| 2616 | 2554 |
| 2617 | |
| 2618 intptr_t ProfileTrieWalker::CurrentInclusiveTicks() { | 2555 intptr_t ProfileTrieWalker::CurrentInclusiveTicks() { |
| 2619 if (current_ == NULL) { | 2556 if (current_ == NULL) { |
| 2620 return -1; | 2557 return -1; |
| 2621 } | 2558 } |
| 2622 if (code_trie_) { | 2559 if (code_trie_) { |
| 2623 ProfileCode* code = profile_->GetCode(current_->table_index()); | 2560 ProfileCode* code = profile_->GetCode(current_->table_index()); |
| 2624 return code->inclusive_ticks(); | 2561 return code->inclusive_ticks(); |
| 2625 } else { | 2562 } else { |
| 2626 ProfileFunction* func = profile_->GetFunction(current_->table_index()); | 2563 ProfileFunction* func = profile_->GetFunction(current_->table_index()); |
| 2627 return func->inclusive_ticks(); | 2564 return func->inclusive_ticks(); |
| 2628 } | 2565 } |
| 2629 UNREACHABLE(); | 2566 UNREACHABLE(); |
| 2630 return -1; | 2567 return -1; |
| 2631 } | 2568 } |
| 2632 | 2569 |
| 2633 | |
| 2634 intptr_t ProfileTrieWalker::CurrentExclusiveTicks() { | 2570 intptr_t ProfileTrieWalker::CurrentExclusiveTicks() { |
| 2635 if (current_ == NULL) { | 2571 if (current_ == NULL) { |
| 2636 return -1; | 2572 return -1; |
| 2637 } | 2573 } |
| 2638 if (code_trie_) { | 2574 if (code_trie_) { |
| 2639 ProfileCode* code = profile_->GetCode(current_->table_index()); | 2575 ProfileCode* code = profile_->GetCode(current_->table_index()); |
| 2640 return code->exclusive_ticks(); | 2576 return code->exclusive_ticks(); |
| 2641 } else { | 2577 } else { |
| 2642 ProfileFunction* func = profile_->GetFunction(current_->table_index()); | 2578 ProfileFunction* func = profile_->GetFunction(current_->table_index()); |
| 2643 return func->exclusive_ticks(); | 2579 return func->exclusive_ticks(); |
| 2644 } | 2580 } |
| 2645 UNREACHABLE(); | 2581 UNREACHABLE(); |
| 2646 return -1; | 2582 return -1; |
| 2647 } | 2583 } |
| 2648 | 2584 |
| 2649 | |
| 2650 intptr_t ProfileTrieWalker::CurrentInclusiveAllocations() { | 2585 intptr_t ProfileTrieWalker::CurrentInclusiveAllocations() { |
| 2651 if (current_ == NULL) { | 2586 if (current_ == NULL) { |
| 2652 return -1; | 2587 return -1; |
| 2653 } | 2588 } |
| 2654 return current_->inclusive_allocations(); | 2589 return current_->inclusive_allocations(); |
| 2655 } | 2590 } |
| 2656 | 2591 |
| 2657 | |
| 2658 intptr_t ProfileTrieWalker::CurrentExclusiveAllocations() { | 2592 intptr_t ProfileTrieWalker::CurrentExclusiveAllocations() { |
| 2659 if (current_ == NULL) { | 2593 if (current_ == NULL) { |
| 2660 return -1; | 2594 return -1; |
| 2661 } | 2595 } |
| 2662 return current_->exclusive_allocations(); | 2596 return current_->exclusive_allocations(); |
| 2663 } | 2597 } |
| 2664 | 2598 |
| 2665 | |
| 2666 const char* ProfileTrieWalker::CurrentToken() { | 2599 const char* ProfileTrieWalker::CurrentToken() { |
| 2667 if (current_ == NULL) { | 2600 if (current_ == NULL) { |
| 2668 return NULL; | 2601 return NULL; |
| 2669 } | 2602 } |
| 2670 if (code_trie_) { | 2603 if (code_trie_) { |
| 2671 return NULL; | 2604 return NULL; |
| 2672 } | 2605 } |
| 2673 ProfileFunction* func = profile_->GetFunction(current_->table_index()); | 2606 ProfileFunction* func = profile_->GetFunction(current_->table_index()); |
| 2674 const Function& function = *(func->function()); | 2607 const Function& function = *(func->function()); |
| 2675 if (function.IsNull()) { | 2608 if (function.IsNull()) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2716 | 2649 |
| 2717 bool ProfileTrieWalker::Down() { | 2650 bool ProfileTrieWalker::Down() { |
| 2718 if ((current_ == NULL) || (current_->NumChildren() == 0)) { | 2651 if ((current_ == NULL) || (current_->NumChildren() == 0)) { |
| 2719 return false; | 2652 return false; |
| 2720 } | 2653 } |
| 2721 parent_ = current_; | 2654 parent_ = current_; |
| 2722 current_ = current_->At(0); | 2655 current_ = current_->At(0); |
| 2723 return true; | 2656 return true; |
| 2724 } | 2657 } |
| 2725 | 2658 |
| 2726 | |
| 2727 bool ProfileTrieWalker::NextSibling() { | 2659 bool ProfileTrieWalker::NextSibling() { |
| 2728 if (parent_ == NULL) { | 2660 if (parent_ == NULL) { |
| 2729 return false; | 2661 return false; |
| 2730 } | 2662 } |
| 2731 intptr_t current_index = parent_->IndexOf(current_); | 2663 intptr_t current_index = parent_->IndexOf(current_); |
| 2732 if (current_index < 0) { | 2664 if (current_index < 0) { |
| 2733 return false; | 2665 return false; |
| 2734 } | 2666 } |
| 2735 current_index++; | 2667 current_index++; |
| 2736 if (current_index >= parent_->NumChildren()) { | 2668 if (current_index >= parent_->NumChildren()) { |
| 2737 return false; | 2669 return false; |
| 2738 } | 2670 } |
| 2739 current_ = parent_->At(current_index); | 2671 current_ = parent_->At(current_index); |
| 2740 return true; | 2672 return true; |
| 2741 } | 2673 } |
| 2742 | 2674 |
| 2743 | |
| 2744 intptr_t ProfileTrieWalker::SiblingCount() { | 2675 intptr_t ProfileTrieWalker::SiblingCount() { |
| 2745 ASSERT(parent_ != NULL); | 2676 ASSERT(parent_ != NULL); |
| 2746 return parent_->NumChildren(); | 2677 return parent_->NumChildren(); |
| 2747 } | 2678 } |
| 2748 | 2679 |
| 2749 | |
| 2750 void ProfilerService::PrintJSONImpl(Thread* thread, | 2680 void ProfilerService::PrintJSONImpl(Thread* thread, |
| 2751 JSONStream* stream, | 2681 JSONStream* stream, |
| 2752 Profile::TagOrder tag_order, | 2682 Profile::TagOrder tag_order, |
| 2753 intptr_t extra_tags, | 2683 intptr_t extra_tags, |
| 2754 SampleFilter* filter, | 2684 SampleFilter* filter, |
| 2755 SampleBuffer* sample_buffer, | 2685 SampleBuffer* sample_buffer, |
| 2756 bool as_timeline) { | 2686 bool as_timeline) { |
| 2757 Isolate* isolate = thread->isolate(); | 2687 Isolate* isolate = thread->isolate(); |
| 2758 // Disable thread interrupts while processing the buffer. | 2688 // Disable thread interrupts while processing the buffer. |
| 2759 DisableThreadInterruptsScope dtis(thread); | 2689 DisableThreadInterruptsScope dtis(thread); |
| 2760 | 2690 |
| 2761 if (sample_buffer == NULL) { | 2691 if (sample_buffer == NULL) { |
| 2762 stream->PrintError(kFeatureDisabled, NULL); | 2692 stream->PrintError(kFeatureDisabled, NULL); |
| 2763 return; | 2693 return; |
| 2764 } | 2694 } |
| 2765 | 2695 |
| 2766 { | 2696 { |
| 2767 StackZone zone(thread); | 2697 StackZone zone(thread); |
| 2768 HANDLESCOPE(thread); | 2698 HANDLESCOPE(thread); |
| 2769 Profile profile(isolate); | 2699 Profile profile(isolate); |
| 2770 profile.Build(thread, filter, sample_buffer, tag_order, extra_tags); | 2700 profile.Build(thread, filter, sample_buffer, tag_order, extra_tags); |
| 2771 if (as_timeline) { | 2701 if (as_timeline) { |
| 2772 profile.PrintTimelineJSON(stream); | 2702 profile.PrintTimelineJSON(stream); |
| 2773 } else { | 2703 } else { |
| 2774 profile.PrintProfileJSON(stream); | 2704 profile.PrintProfileJSON(stream); |
| 2775 } | 2705 } |
| 2776 } | 2706 } |
| 2777 } | 2707 } |
| 2778 | 2708 |
| 2779 | |
| 2780 class NoAllocationSampleFilter : public SampleFilter { | 2709 class NoAllocationSampleFilter : public SampleFilter { |
| 2781 public: | 2710 public: |
| 2782 NoAllocationSampleFilter(Dart_Port port, | 2711 NoAllocationSampleFilter(Dart_Port port, |
| 2783 intptr_t thread_task_mask, | 2712 intptr_t thread_task_mask, |
| 2784 int64_t time_origin_micros, | 2713 int64_t time_origin_micros, |
| 2785 int64_t time_extent_micros) | 2714 int64_t time_extent_micros) |
| 2786 : SampleFilter(port, | 2715 : SampleFilter(port, |
| 2787 thread_task_mask, | 2716 thread_task_mask, |
| 2788 time_origin_micros, | 2717 time_origin_micros, |
| 2789 time_extent_micros) {} | 2718 time_extent_micros) {} |
| 2790 | 2719 |
| 2791 bool FilterSample(Sample* sample) { return !sample->is_allocation_sample(); } | 2720 bool FilterSample(Sample* sample) { return !sample->is_allocation_sample(); } |
| 2792 }; | 2721 }; |
| 2793 | 2722 |
| 2794 | |
| 2795 void ProfilerService::PrintJSON(JSONStream* stream, | 2723 void ProfilerService::PrintJSON(JSONStream* stream, |
| 2796 Profile::TagOrder tag_order, | 2724 Profile::TagOrder tag_order, |
| 2797 intptr_t extra_tags, | 2725 intptr_t extra_tags, |
| 2798 int64_t time_origin_micros, | 2726 int64_t time_origin_micros, |
| 2799 int64_t time_extent_micros) { | 2727 int64_t time_extent_micros) { |
| 2800 Thread* thread = Thread::Current(); | 2728 Thread* thread = Thread::Current(); |
| 2801 Isolate* isolate = thread->isolate(); | 2729 Isolate* isolate = thread->isolate(); |
| 2802 NoAllocationSampleFilter filter(isolate->main_port(), Thread::kMutatorTask, | 2730 NoAllocationSampleFilter filter(isolate->main_port(), Thread::kMutatorTask, |
| 2803 time_origin_micros, time_extent_micros); | 2731 time_origin_micros, time_extent_micros); |
| 2804 const bool as_timeline = false; | 2732 const bool as_timeline = false; |
| 2805 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, | 2733 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, |
| 2806 Profiler::sample_buffer(), as_timeline); | 2734 Profiler::sample_buffer(), as_timeline); |
| 2807 } | 2735 } |
| 2808 | 2736 |
| 2809 | |
| 2810 class ClassAllocationSampleFilter : public SampleFilter { | 2737 class ClassAllocationSampleFilter : public SampleFilter { |
| 2811 public: | 2738 public: |
| 2812 ClassAllocationSampleFilter(Dart_Port port, | 2739 ClassAllocationSampleFilter(Dart_Port port, |
| 2813 const Class& cls, | 2740 const Class& cls, |
| 2814 intptr_t thread_task_mask, | 2741 intptr_t thread_task_mask, |
| 2815 int64_t time_origin_micros, | 2742 int64_t time_origin_micros, |
| 2816 int64_t time_extent_micros) | 2743 int64_t time_extent_micros) |
| 2817 : SampleFilter(port, | 2744 : SampleFilter(port, |
| 2818 thread_task_mask, | 2745 thread_task_mask, |
| 2819 time_origin_micros, | 2746 time_origin_micros, |
| 2820 time_extent_micros), | 2747 time_extent_micros), |
| 2821 cls_(Class::Handle(cls.raw())) { | 2748 cls_(Class::Handle(cls.raw())) { |
| 2822 ASSERT(!cls_.IsNull()); | 2749 ASSERT(!cls_.IsNull()); |
| 2823 } | 2750 } |
| 2824 | 2751 |
| 2825 bool FilterSample(Sample* sample) { | 2752 bool FilterSample(Sample* sample) { |
| 2826 return sample->is_allocation_sample() && | 2753 return sample->is_allocation_sample() && |
| 2827 (sample->allocation_cid() == cls_.id()); | 2754 (sample->allocation_cid() == cls_.id()); |
| 2828 } | 2755 } |
| 2829 | 2756 |
| 2830 private: | 2757 private: |
| 2831 const Class& cls_; | 2758 const Class& cls_; |
| 2832 }; | 2759 }; |
| 2833 | 2760 |
| 2834 | |
| 2835 void ProfilerService::PrintAllocationJSON(JSONStream* stream, | 2761 void ProfilerService::PrintAllocationJSON(JSONStream* stream, |
| 2836 Profile::TagOrder tag_order, | 2762 Profile::TagOrder tag_order, |
| 2837 const Class& cls, | 2763 const Class& cls, |
| 2838 int64_t time_origin_micros, | 2764 int64_t time_origin_micros, |
| 2839 int64_t time_extent_micros) { | 2765 int64_t time_extent_micros) { |
| 2840 Thread* thread = Thread::Current(); | 2766 Thread* thread = Thread::Current(); |
| 2841 Isolate* isolate = thread->isolate(); | 2767 Isolate* isolate = thread->isolate(); |
| 2842 ClassAllocationSampleFilter filter(isolate->main_port(), cls, | 2768 ClassAllocationSampleFilter filter(isolate->main_port(), cls, |
| 2843 Thread::kMutatorTask, time_origin_micros, | 2769 Thread::kMutatorTask, time_origin_micros, |
| 2844 time_extent_micros); | 2770 time_extent_micros); |
| 2845 const bool as_timeline = false; | 2771 const bool as_timeline = false; |
| 2846 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, | 2772 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, |
| 2847 Profiler::sample_buffer(), as_timeline); | 2773 Profiler::sample_buffer(), as_timeline); |
| 2848 } | 2774 } |
| 2849 | 2775 |
| 2850 | |
| 2851 void ProfilerService::PrintNativeAllocationJSON(JSONStream* stream, | 2776 void ProfilerService::PrintNativeAllocationJSON(JSONStream* stream, |
| 2852 Profile::TagOrder tag_order, | 2777 Profile::TagOrder tag_order, |
| 2853 int64_t time_origin_micros, | 2778 int64_t time_origin_micros, |
| 2854 int64_t time_extent_micros) { | 2779 int64_t time_extent_micros) { |
| 2855 Thread* thread = Thread::Current(); | 2780 Thread* thread = Thread::Current(); |
| 2856 NativeAllocationSampleFilter filter(time_origin_micros, time_extent_micros); | 2781 NativeAllocationSampleFilter filter(time_origin_micros, time_extent_micros); |
| 2857 const bool as_timeline = false; | 2782 const bool as_timeline = false; |
| 2858 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, | 2783 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, |
| 2859 Profiler::allocation_sample_buffer(), as_timeline); | 2784 Profiler::allocation_sample_buffer(), as_timeline); |
| 2860 } | 2785 } |
| 2861 | 2786 |
| 2862 | |
| 2863 void ProfilerService::PrintTimelineJSON(JSONStream* stream, | 2787 void ProfilerService::PrintTimelineJSON(JSONStream* stream, |
| 2864 Profile::TagOrder tag_order, | 2788 Profile::TagOrder tag_order, |
| 2865 int64_t time_origin_micros, | 2789 int64_t time_origin_micros, |
| 2866 int64_t time_extent_micros) { | 2790 int64_t time_extent_micros) { |
| 2867 Thread* thread = Thread::Current(); | 2791 Thread* thread = Thread::Current(); |
| 2868 Isolate* isolate = thread->isolate(); | 2792 Isolate* isolate = thread->isolate(); |
| 2869 const intptr_t thread_task_mask = Thread::kMutatorTask | | 2793 const intptr_t thread_task_mask = Thread::kMutatorTask | |
| 2870 Thread::kCompilerTask | | 2794 Thread::kCompilerTask | |
| 2871 Thread::kSweeperTask | Thread::kMarkerTask; | 2795 Thread::kSweeperTask | Thread::kMarkerTask; |
| 2872 NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask, | 2796 NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask, |
| 2873 time_origin_micros, time_extent_micros); | 2797 time_origin_micros, time_extent_micros); |
| 2874 const bool as_timeline = true; | 2798 const bool as_timeline = true; |
| 2875 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, | 2799 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, |
| 2876 Profiler::sample_buffer(), as_timeline); | 2800 Profiler::sample_buffer(), as_timeline); |
| 2877 } | 2801 } |
| 2878 | 2802 |
| 2879 | |
| 2880 void ProfilerService::ClearSamples() { | 2803 void ProfilerService::ClearSamples() { |
| 2881 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 2804 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
| 2882 if (sample_buffer == NULL) { | 2805 if (sample_buffer == NULL) { |
| 2883 return; | 2806 return; |
| 2884 } | 2807 } |
| 2885 | 2808 |
| 2886 Thread* thread = Thread::Current(); | 2809 Thread* thread = Thread::Current(); |
| 2887 Isolate* isolate = thread->isolate(); | 2810 Isolate* isolate = thread->isolate(); |
| 2888 | 2811 |
| 2889 // Disable thread interrupts while processing the buffer. | 2812 // Disable thread interrupts while processing the buffer. |
| 2890 DisableThreadInterruptsScope dtis(thread); | 2813 DisableThreadInterruptsScope dtis(thread); |
| 2891 | 2814 |
| 2892 ClearProfileVisitor clear_profile(isolate); | 2815 ClearProfileVisitor clear_profile(isolate); |
| 2893 sample_buffer->VisitSamples(&clear_profile); | 2816 sample_buffer->VisitSamples(&clear_profile); |
| 2894 } | 2817 } |
| 2895 | 2818 |
| 2896 #endif // !PRODUCT | 2819 #endif // !PRODUCT |
| 2897 | 2820 |
| 2898 } // namespace dart | 2821 } // namespace dart |
| OLD | NEW |