OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 return map_entry != NULL ? | 47 return map_entry != NULL ? |
48 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 48 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
49 } | 49 } |
50 | 50 |
51 | 51 |
52 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 52 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
53 HashMap::Entry* map_entry = | 53 HashMap::Entry* map_entry = |
54 children_.Lookup(entry, CodeEntryHash(entry), true); | 54 children_.Lookup(entry, CodeEntryHash(entry), true); |
55 if (map_entry->value == NULL) { | 55 if (map_entry->value == NULL) { |
56 // New node added. | 56 // New node added. |
57 ProfileNode* new_node = new ProfileNode(entry); | 57 ProfileNode* new_node = new ProfileNode(tree_, entry); |
58 map_entry->value = new_node; | 58 map_entry->value = new_node; |
59 children_list_.Add(new_node); | 59 children_list_.Add(new_node); |
60 } | 60 } |
61 return reinterpret_cast<ProfileNode*>(map_entry->value); | 61 return reinterpret_cast<ProfileNode*>(map_entry->value); |
62 } | 62 } |
63 | 63 |
64 | 64 |
| 65 double ProfileNode::GetSelfMillis() const { |
| 66 return tree_->TicksToMillis(self_ticks_); |
| 67 } |
| 68 |
| 69 |
| 70 double ProfileNode::GetTotalMillis() const { |
| 71 return tree_->TicksToMillis(total_ticks_); |
| 72 } |
| 73 |
| 74 |
65 void ProfileNode::Print(int indent) { | 75 void ProfileNode::Print(int indent) { |
66 OS::Print("%5u %5u %*c %s%s", | 76 OS::Print("%5u %5u %*c %s%s", |
67 total_ticks_, self_ticks_, | 77 total_ticks_, self_ticks_, |
68 indent, ' ', | 78 indent, ' ', |
69 entry_->name_prefix(), | 79 entry_->name_prefix(), |
70 entry_->name()); | 80 entry_->name()); |
71 if (entry_->resource_name()[0] != '\0') | 81 if (entry_->resource_name()[0] != '\0') |
72 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); | 82 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); |
73 OS::Print("\n"); | 83 OS::Print("\n"); |
74 for (HashMap::Entry* p = children_.Start(); | 84 for (HashMap::Entry* p = children_.Start(); |
(...skipping 13 matching lines...) Expand all Loading... |
88 } | 98 } |
89 | 99 |
90 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } | 100 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
91 }; | 101 }; |
92 | 102 |
93 } // namespace | 103 } // namespace |
94 | 104 |
95 | 105 |
96 ProfileTree::ProfileTree() | 106 ProfileTree::ProfileTree() |
97 : root_entry_(Logger::FUNCTION_TAG, "", "(root)", "", 0), | 107 : root_entry_(Logger::FUNCTION_TAG, "", "(root)", "", 0), |
98 root_(new ProfileNode(&root_entry_)) { | 108 root_(new ProfileNode(this, &root_entry_)) { |
99 } | 109 } |
100 | 110 |
101 | 111 |
102 ProfileTree::~ProfileTree() { | 112 ProfileTree::~ProfileTree() { |
103 DeleteNodesCallback cb; | 113 DeleteNodesCallback cb; |
104 TraverseBreadthFirstPostOrder(&cb); | 114 TraverseDepthFirstPostOrder(&cb); |
105 } | 115 } |
106 | 116 |
107 | 117 |
108 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { | 118 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { |
109 ProfileNode* node = root_; | 119 ProfileNode* node = root_; |
110 for (CodeEntry** entry = path.start() + path.length() - 1; | 120 for (CodeEntry** entry = path.start() + path.length() - 1; |
111 entry != path.start() - 1; | 121 entry != path.start() - 1; |
112 --entry) { | 122 --entry) { |
113 if (*entry != NULL) { | 123 if (*entry != NULL) { |
114 node = node->FindOrAddChild(*entry); | 124 node = node->FindOrAddChild(*entry); |
115 } | 125 } |
116 } | 126 } |
117 node->IncrementSelfTicks(); | 127 node->IncrementSelfTicks(); |
118 } | 128 } |
119 | 129 |
120 | 130 |
121 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { | 131 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { |
122 ProfileNode* node = root_; | 132 ProfileNode* node = root_; |
123 for (CodeEntry** entry = path.start(); | 133 for (CodeEntry** entry = path.start(); |
124 entry != path.start() + path.length(); | 134 entry != path.start() + path.length(); |
125 ++entry) { | 135 ++entry) { |
126 if (*entry != NULL) { | 136 if (*entry != NULL) { |
127 node = node->FindOrAddChild(*entry); | 137 node = node->FindOrAddChild(*entry); |
128 } | 138 } |
129 } | 139 } |
130 node->IncrementSelfTicks(); | 140 node->IncrementSelfTicks(); |
131 } | 141 } |
132 | 142 |
133 | 143 |
| 144 void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { |
| 145 ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0; |
| 146 } |
| 147 |
| 148 |
134 namespace { | 149 namespace { |
135 | 150 |
136 class Position { | 151 class Position { |
137 public: | 152 public: |
138 explicit Position(ProfileNode* node) | 153 explicit Position(ProfileNode* node) |
139 : node(node), child_idx_(0) { } | 154 : node(node), child_idx_(0) { } |
140 INLINE(ProfileNode* current_child()) { | 155 INLINE(ProfileNode* current_child()) { |
141 return node->children()->at(child_idx_); | 156 return node->children()->at(child_idx_); |
142 } | 157 } |
143 INLINE(bool has_current_child()) { | 158 INLINE(bool has_current_child()) { |
144 return child_idx_ < node->children()->length(); | 159 return child_idx_ < node->children()->length(); |
145 } | 160 } |
146 INLINE(void next_child()) { ++child_idx_; } | 161 INLINE(void next_child()) { ++child_idx_; } |
147 | 162 |
148 ProfileNode* node; | 163 ProfileNode* node; |
149 private: | 164 private: |
150 int child_idx_; | 165 int child_idx_; |
151 }; | 166 }; |
152 | 167 |
153 } // namespace | 168 } // namespace |
154 | 169 |
155 | 170 |
156 // Non-recursive implementation of breadth-first post-order tree traversal. | 171 // Non-recursive implementation of a depth-first post-order tree traversal. |
157 template <typename Callback> | 172 template <typename Callback> |
158 void ProfileTree::TraverseBreadthFirstPostOrder(Callback* callback) { | 173 void ProfileTree::TraverseDepthFirstPostOrder(Callback* callback) { |
159 List<Position> stack(10); | 174 List<Position> stack(10); |
160 stack.Add(Position(root_)); | 175 stack.Add(Position(root_)); |
161 do { | 176 do { |
162 Position& current = stack.last(); | 177 Position& current = stack.last(); |
163 if (current.has_current_child()) { | 178 if (current.has_current_child()) { |
164 stack.Add(Position(current.current_child())); | 179 stack.Add(Position(current.current_child())); |
165 } else { | 180 } else { |
166 callback->AfterAllChildrenTraversed(current.node); | 181 callback->AfterAllChildrenTraversed(current.node); |
167 if (stack.length() > 1) { | 182 if (stack.length() > 1) { |
168 Position& parent = stack[stack.length() - 2]; | 183 Position& parent = stack[stack.length() - 2]; |
(...skipping 18 matching lines...) Expand all Loading... |
187 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { | 202 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { |
188 parent->IncreaseTotalTicks(child->total_ticks()); | 203 parent->IncreaseTotalTicks(child->total_ticks()); |
189 } | 204 } |
190 }; | 205 }; |
191 | 206 |
192 } // namespace | 207 } // namespace |
193 | 208 |
194 | 209 |
195 void ProfileTree::CalculateTotalTicks() { | 210 void ProfileTree::CalculateTotalTicks() { |
196 CalculateTotalTicksCallback cb; | 211 CalculateTotalTicksCallback cb; |
197 TraverseBreadthFirstPostOrder(&cb); | 212 TraverseDepthFirstPostOrder(&cb); |
198 } | 213 } |
199 | 214 |
200 | 215 |
201 void ProfileTree::ShortPrint() { | 216 void ProfileTree::ShortPrint() { |
202 OS::Print("root: %u %u\n", root_->total_ticks(), root_->self_ticks()); | 217 OS::Print("root: %u %u %.2fms %.2fms\n", |
| 218 root_->total_ticks(), root_->self_ticks(), |
| 219 root_->GetTotalMillis(), root_->GetSelfMillis()); |
203 } | 220 } |
204 | 221 |
205 | 222 |
206 void CpuProfile::AddPath(const Vector<CodeEntry*>& path) { | 223 void CpuProfile::AddPath(const Vector<CodeEntry*>& path) { |
207 top_down_.AddPathFromEnd(path); | 224 top_down_.AddPathFromEnd(path); |
208 bottom_up_.AddPathFromStart(path); | 225 bottom_up_.AddPathFromStart(path); |
209 } | 226 } |
210 | 227 |
211 | 228 |
212 void CpuProfile::CalculateTotalTicks() { | 229 void CpuProfile::CalculateTotalTicks() { |
213 top_down_.CalculateTotalTicks(); | 230 top_down_.CalculateTotalTicks(); |
214 bottom_up_.CalculateTotalTicks(); | 231 bottom_up_.CalculateTotalTicks(); |
215 } | 232 } |
216 | 233 |
217 | 234 |
| 235 void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) { |
| 236 top_down_.SetTickRatePerMs(actual_sampling_rate); |
| 237 bottom_up_.SetTickRatePerMs(actual_sampling_rate); |
| 238 } |
| 239 |
| 240 |
218 void CpuProfile::ShortPrint() { | 241 void CpuProfile::ShortPrint() { |
219 OS::Print("top down "); | 242 OS::Print("top down "); |
220 top_down_.ShortPrint(); | 243 top_down_.ShortPrint(); |
221 OS::Print("bottom up "); | 244 OS::Print("bottom up "); |
222 bottom_up_.ShortPrint(); | 245 bottom_up_.ShortPrint(); |
223 } | 246 } |
224 | 247 |
225 | 248 |
226 void CpuProfile::Print() { | 249 void CpuProfile::Print() { |
227 OS::Print("[Top down]:\n"); | 250 OS::Print("[Top down]:\n"); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 current_profiles_semaphore_->Signal(); | 342 current_profiles_semaphore_->Signal(); |
320 return true; | 343 return true; |
321 } | 344 } |
322 | 345 |
323 | 346 |
324 bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) { | 347 bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) { |
325 return StartProfiling(GetName(title), uid); | 348 return StartProfiling(GetName(title), uid); |
326 } | 349 } |
327 | 350 |
328 | 351 |
329 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) { | 352 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title, |
| 353 double actual_sampling_rate) { |
330 const int title_len = StrLength(title); | 354 const int title_len = StrLength(title); |
331 CpuProfile* profile = NULL; | 355 CpuProfile* profile = NULL; |
332 current_profiles_semaphore_->Wait(); | 356 current_profiles_semaphore_->Wait(); |
333 for (int i = current_profiles_.length() - 1; i >= 0; --i) { | 357 for (int i = current_profiles_.length() - 1; i >= 0; --i) { |
334 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { | 358 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { |
335 profile = current_profiles_.Remove(i); | 359 profile = current_profiles_.Remove(i); |
336 break; | 360 break; |
337 } | 361 } |
338 } | 362 } |
339 current_profiles_semaphore_->Signal(); | 363 current_profiles_semaphore_->Signal(); |
340 | 364 |
341 if (profile != NULL) { | 365 if (profile != NULL) { |
342 profile->CalculateTotalTicks(); | 366 profile->CalculateTotalTicks(); |
| 367 profile->SetActualSamplingRate(actual_sampling_rate); |
343 profiles_.Add(profile); | 368 profiles_.Add(profile); |
344 HashMap::Entry* entry = | 369 HashMap::Entry* entry = |
345 profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()), | 370 profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()), |
346 static_cast<uint32_t>(profile->uid()), | 371 static_cast<uint32_t>(profile->uid()), |
347 true); | 372 true); |
348 ASSERT(entry->value == NULL); | 373 ASSERT(entry->value == NULL); |
349 entry->value = profile; | 374 entry->value = profile; |
350 } | 375 } |
351 return profile; | 376 return profile; |
352 } | 377 } |
353 | 378 |
354 | 379 |
355 CpuProfile* CpuProfilesCollection::StopProfiling(String* title) { | 380 CpuProfile* CpuProfilesCollection::StopProfiling(String* title, |
356 return StopProfiling(GetName(title)); | 381 double actual_sampling_rate) { |
| 382 return StopProfiling(GetName(title), actual_sampling_rate); |
357 } | 383 } |
358 | 384 |
359 | 385 |
360 CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) { | 386 CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) { |
361 HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid), | 387 HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid), |
362 static_cast<uint32_t>(uid), | 388 static_cast<uint32_t>(uid), |
363 false); | 389 false); |
364 return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; | 390 return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; |
365 } | 391 } |
366 | 392 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 // method, we don't bother minimizing the duration of lock holding, | 485 // method, we don't bother minimizing the duration of lock holding, |
460 // e.g. copying contents of the list to a local vector. | 486 // e.g. copying contents of the list to a local vector. |
461 current_profiles_semaphore_->Wait(); | 487 current_profiles_semaphore_->Wait(); |
462 for (int i = 0; i < current_profiles_.length(); ++i) { | 488 for (int i = 0; i < current_profiles_.length(); ++i) { |
463 current_profiles_[i]->AddPath(path); | 489 current_profiles_[i]->AddPath(path); |
464 } | 490 } |
465 current_profiles_semaphore_->Signal(); | 491 current_profiles_semaphore_->Signal(); |
466 } | 492 } |
467 | 493 |
468 | 494 |
| 495 void SampleRateCalculator::Tick() { |
| 496 if (--wall_time_query_countdown_ == 0) |
| 497 UpdateMeasurements(OS::TimeCurrentMillis()); |
| 498 } |
| 499 |
| 500 |
| 501 void SampleRateCalculator::UpdateMeasurements(double current_time) { |
| 502 if (measurements_count_++ != 0) { |
| 503 const double measured_ticks_per_ms = |
| 504 (kWallTimeQueryIntervalMs * ticks_per_ms_) / |
| 505 (current_time - last_wall_time_); |
| 506 // Update the average value. |
| 507 ticks_per_ms_ += |
| 508 (measured_ticks_per_ms - ticks_per_ms_) / measurements_count_; |
| 509 // Update the externally accessible result. |
| 510 result_ = static_cast<AtomicWord>(ticks_per_ms_ * kResultScale); |
| 511 } |
| 512 last_wall_time_ = current_time; |
| 513 wall_time_query_countdown_ = |
| 514 static_cast<unsigned>(kWallTimeQueryIntervalMs * ticks_per_ms_); |
| 515 } |
| 516 |
| 517 |
469 const char* ProfileGenerator::kAnonymousFunctionName = "(anonymous function)"; | 518 const char* ProfileGenerator::kAnonymousFunctionName = "(anonymous function)"; |
470 const char* ProfileGenerator::kProgramEntryName = "(program)"; | 519 const char* ProfileGenerator::kProgramEntryName = "(program)"; |
471 const char* ProfileGenerator::kGarbageCollectorEntryName = | 520 const char* ProfileGenerator::kGarbageCollectorEntryName = |
472 "(garbage collector)"; | 521 "(garbage collector)"; |
473 | 522 |
474 | 523 |
475 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 524 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |
476 : profiles_(profiles), | 525 : profiles_(profiles), |
477 program_entry_( | 526 program_entry_( |
478 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)), | 527 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)), |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 // Put VM state as the topmost entry. | 565 // Put VM state as the topmost entry. |
517 *entry++ = EntryForVMState(sample.state); | 566 *entry++ = EntryForVMState(sample.state); |
518 } | 567 } |
519 | 568 |
520 profiles_->AddPathToCurrentProfiles(entries); | 569 profiles_->AddPathToCurrentProfiles(entries); |
521 } | 570 } |
522 | 571 |
523 } } // namespace v8::internal | 572 } } // namespace v8::internal |
524 | 573 |
525 #endif // ENABLE_LOGGING_AND_PROFILING | 574 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |