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 11 matching lines...) Expand all Loading... |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "profile-generator-inl.h" | 30 #include "profile-generator-inl.h" |
31 | 31 |
32 | |
33 namespace v8 { | 32 namespace v8 { |
34 namespace internal { | 33 namespace internal { |
35 | 34 |
| 35 #ifdef ENABLE_CPP_PROFILES_PROCESSOR |
36 | 36 |
37 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 37 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
38 HashMap::Entry* map_entry = | 38 HashMap::Entry* map_entry = |
39 children_.Lookup(entry, CodeEntryHash(entry), false); | 39 children_.Lookup(entry, CodeEntryHash(entry), false); |
40 return map_entry != NULL ? | 40 return map_entry != NULL ? |
41 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 41 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
42 } | 42 } |
43 | 43 |
44 | 44 |
45 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 45 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
46 HashMap::Entry* map_entry = | 46 HashMap::Entry* map_entry = |
47 children_.Lookup(entry, CodeEntryHash(entry), true); | 47 children_.Lookup(entry, CodeEntryHash(entry), true); |
48 if (map_entry->value == NULL) { | 48 if (map_entry->value == NULL) { |
49 // New node added. | 49 // New node added. |
50 map_entry->value = new ProfileNode(entry); | 50 ProfileNode* new_node = new ProfileNode(entry); |
| 51 map_entry->value = new_node; |
| 52 children_list_.Add(new_node); |
51 } | 53 } |
52 return reinterpret_cast<ProfileNode*>(map_entry->value); | 54 return reinterpret_cast<ProfileNode*>(map_entry->value); |
53 } | 55 } |
54 | 56 |
55 | 57 |
56 void ProfileNode::GetChildren(List<ProfileNode*>* children) { | |
57 for (HashMap::Entry* p = children_.Start(); | |
58 p != NULL; | |
59 p = children_.Next(p)) { | |
60 children->Add(reinterpret_cast<ProfileNode*>(p->value)); | |
61 } | |
62 } | |
63 | |
64 | |
65 void ProfileNode::Print(int indent) { | 58 void ProfileNode::Print(int indent) { |
66 OS::Print("%4u %4u %*c %s\n", | 59 OS::Print("%5u %5u %*c %s\n", |
67 total_ticks_, self_ticks_, | 60 total_ticks_, self_ticks_, |
68 indent, ' ', | 61 indent, ' ', |
69 entry_ != NULL ? entry_->name() : ""); | 62 entry_ != NULL ? entry_->name() : ""); |
70 for (HashMap::Entry* p = children_.Start(); | 63 for (HashMap::Entry* p = children_.Start(); |
71 p != NULL; | 64 p != NULL; |
72 p = children_.Next(p)) { | 65 p = children_.Next(p)) { |
73 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); | 66 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); |
74 } | 67 } |
75 } | 68 } |
76 | 69 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 if (*entry != NULL) { | 109 if (*entry != NULL) { |
117 node = node->FindOrAddChild(*entry); | 110 node = node->FindOrAddChild(*entry); |
118 } | 111 } |
119 } | 112 } |
120 node->IncrementSelfTicks(); | 113 node->IncrementSelfTicks(); |
121 } | 114 } |
122 | 115 |
123 | 116 |
124 namespace { | 117 namespace { |
125 | 118 |
126 struct Position { | 119 class Position { |
127 Position(ProfileNode* a_node, HashMap::Entry* a_p) | 120 public: |
128 : node(a_node), p(a_p) { } | 121 explicit Position(ProfileNode* node) |
| 122 : node(node), child_idx_(0) { } |
129 INLINE(ProfileNode* current_child()) { | 123 INLINE(ProfileNode* current_child()) { |
130 return reinterpret_cast<ProfileNode*>(p->value); | 124 return node->children()->at(child_idx_); |
131 } | 125 } |
| 126 INLINE(bool has_current_child()) { |
| 127 return child_idx_ < node->children()->length(); |
| 128 } |
| 129 INLINE(void next_child()) { ++child_idx_; } |
| 130 |
132 ProfileNode* node; | 131 ProfileNode* node; |
133 HashMap::Entry* p; | 132 private: |
| 133 int child_idx_; |
134 }; | 134 }; |
135 | 135 |
136 } // namespace | 136 } // namespace |
137 | 137 |
138 | 138 |
| 139 // Non-recursive implementation of breadth-first post-order tree traversal. |
139 template <typename Callback> | 140 template <typename Callback> |
140 void ProfileTree::TraverseBreadthFirstPostOrder(Callback* callback) { | 141 void ProfileTree::TraverseBreadthFirstPostOrder(Callback* callback) { |
141 List<Position> stack(10); | 142 List<Position> stack(10); |
142 stack.Add(Position(root_, root_->children_.Start())); | 143 stack.Add(Position(root_)); |
143 do { | 144 do { |
144 Position& current = stack.last(); | 145 Position& current = stack.last(); |
145 if (current.p != NULL) { | 146 if (current.has_current_child()) { |
146 stack.Add(Position(current.current_child(), | 147 stack.Add(Position(current.current_child())); |
147 current.current_child()->children_.Start())); | |
148 } else { | 148 } else { |
149 callback->AfterAllChildrenTraversed(current.node); | 149 callback->AfterAllChildrenTraversed(current.node); |
150 if (stack.length() > 1) { | 150 if (stack.length() > 1) { |
151 Position& parent = stack[stack.length() - 2]; | 151 Position& parent = stack[stack.length() - 2]; |
152 callback->AfterChildTraversed(parent.node, current.node); | 152 callback->AfterChildTraversed(parent.node, current.node); |
153 parent.p = parent.node->children_.Next(parent.p); | 153 parent.next_child(); |
154 // Remove child from the stack. | 154 // Remove child from the stack. |
155 stack.RemoveLast(); | 155 stack.RemoveLast(); |
156 } | 156 } |
157 } | 157 } |
158 } while (stack.length() > 1 || stack.last().p != NULL); | 158 } while (stack.length() > 1 || stack.last().has_current_child()); |
159 } | 159 } |
160 | 160 |
161 | 161 |
162 namespace { | 162 namespace { |
163 | 163 |
164 class CalculateTotalTicksCallback { | 164 class CalculateTotalTicksCallback { |
165 public: | 165 public: |
166 void AfterAllChildrenTraversed(ProfileNode* node) { | 166 void AfterAllChildrenTraversed(ProfileNode* node) { |
167 node->IncreaseTotalTicks(node->self_ticks()); | 167 node->IncreaseTotalTicks(node->self_ticks()); |
168 } | 168 } |
169 | 169 |
170 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { | 170 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { |
171 parent->IncreaseTotalTicks(child->total_ticks()); | 171 parent->IncreaseTotalTicks(child->total_ticks()); |
172 } | 172 } |
173 }; | 173 }; |
174 | 174 |
175 } // namespace | 175 } // namespace |
176 | 176 |
177 | 177 |
178 // Non-recursive implementation of breadth-first tree traversal. | |
179 void ProfileTree::CalculateTotalTicks() { | 178 void ProfileTree::CalculateTotalTicks() { |
180 CalculateTotalTicksCallback cb; | 179 CalculateTotalTicksCallback cb; |
181 TraverseBreadthFirstPostOrder(&cb); | 180 TraverseBreadthFirstPostOrder(&cb); |
182 } | 181 } |
183 | 182 |
184 | 183 |
185 void ProfileTree::ShortPrint() { | 184 void ProfileTree::ShortPrint() { |
186 OS::Print("root: %u %u\n", root_->total_ticks(), root_->self_ticks()); | 185 OS::Print("root: %u %u\n", root_->total_ticks(), root_->self_ticks()); |
187 } | 186 } |
188 | 187 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 if (tree_.FindGreatestLessThan(addr, &locator)) { | 234 if (tree_.FindGreatestLessThan(addr, &locator)) { |
236 // locator.key() <= addr. Need to check that addr is within entry. | 235 // locator.key() <= addr. Need to check that addr is within entry. |
237 const CodeEntryInfo& entry = locator.value(); | 236 const CodeEntryInfo& entry = locator.value(); |
238 if (addr < (locator.key() + entry.size)) | 237 if (addr < (locator.key() + entry.size)) |
239 return entry.entry; | 238 return entry.entry; |
240 } | 239 } |
241 return NULL; | 240 return NULL; |
242 } | 241 } |
243 | 242 |
244 | 243 |
| 244 void CodeMap::CodeTreePrinter::Call( |
| 245 const Address& key, const CodeMap::CodeEntryInfo& value) { |
| 246 OS::Print("%p %5d %s\n", key, value.size, value.entry->name()); |
| 247 } |
| 248 |
| 249 |
| 250 void CodeMap::Print() { |
| 251 CodeTreePrinter printer; |
| 252 tree_.ForEach(&printer); |
| 253 } |
| 254 |
| 255 |
245 CpuProfilesCollection::CpuProfilesCollection() | 256 CpuProfilesCollection::CpuProfilesCollection() |
246 : function_and_resource_names_(StringsMatch) { | 257 : function_and_resource_names_(StringsMatch), |
| 258 profiles_uids_(CpuProfilesMatch), |
| 259 current_profiles_semaphore_(OS::CreateSemaphore(1)) { |
247 } | 260 } |
248 | 261 |
249 | 262 |
250 static void DeleteArgsCountName(char** name_ptr) { | 263 static void DeleteArgsCountName(char** name_ptr) { |
251 DeleteArray(*name_ptr); | 264 DeleteArray(*name_ptr); |
252 } | 265 } |
253 | 266 |
254 | 267 |
255 static void DeleteCodeEntry(CodeEntry** entry_ptr) { | 268 static void DeleteCodeEntry(CodeEntry** entry_ptr) { |
256 delete *entry_ptr; | 269 delete *entry_ptr; |
257 } | 270 } |
258 | 271 |
259 static void DeleteCpuProfile(CpuProfile** profile_ptr) { | 272 static void DeleteCpuProfile(CpuProfile** profile_ptr) { |
260 delete *profile_ptr; | 273 delete *profile_ptr; |
261 } | 274 } |
262 | 275 |
263 | 276 |
264 CpuProfilesCollection::~CpuProfilesCollection() { | 277 CpuProfilesCollection::~CpuProfilesCollection() { |
| 278 delete current_profiles_semaphore_; |
| 279 current_profiles_.Iterate(DeleteCpuProfile); |
265 profiles_.Iterate(DeleteCpuProfile); | 280 profiles_.Iterate(DeleteCpuProfile); |
266 code_entries_.Iterate(DeleteCodeEntry); | 281 code_entries_.Iterate(DeleteCodeEntry); |
267 args_count_names_.Iterate(DeleteArgsCountName); | 282 args_count_names_.Iterate(DeleteArgsCountName); |
268 for (HashMap::Entry* p = function_and_resource_names_.Start(); | 283 for (HashMap::Entry* p = function_and_resource_names_.Start(); |
269 p != NULL; | 284 p != NULL; |
270 p = function_and_resource_names_.Next(p)) { | 285 p = function_and_resource_names_.Next(p)) { |
271 DeleteArray(reinterpret_cast<const char*>(p->value)); | 286 DeleteArray(reinterpret_cast<const char*>(p->value)); |
272 } | 287 } |
273 } | 288 } |
274 | 289 |
275 | 290 |
276 void CpuProfilesCollection::AddProfile(unsigned uid) { | 291 bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid) { |
277 profiles_.Add(new CpuProfile()); | 292 ASSERT(uid > 0); |
| 293 current_profiles_semaphore_->Wait(); |
| 294 for (int i = 0; i < current_profiles_.length(); ++i) { |
| 295 if (strcmp(current_profiles_[i]->title(), title) == 0) { |
| 296 // Ignore attempts to start profile with the same title. |
| 297 current_profiles_semaphore_->Signal(); |
| 298 return false; |
| 299 } |
| 300 } |
| 301 current_profiles_.Add(new CpuProfile(title, uid)); |
| 302 current_profiles_semaphore_->Signal(); |
| 303 return true; |
278 } | 304 } |
279 | 305 |
280 | 306 |
| 307 bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) { |
| 308 return StartProfiling(GetName(title), uid); |
| 309 } |
| 310 |
| 311 |
| 312 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) { |
| 313 const int title_len = strlen(title); |
| 314 CpuProfile* profile = NULL; |
| 315 current_profiles_semaphore_->Wait(); |
| 316 for (int i = current_profiles_.length() - 1; i >= 0; --i) { |
| 317 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { |
| 318 profile = current_profiles_.Remove(i); |
| 319 break; |
| 320 } |
| 321 } |
| 322 current_profiles_semaphore_->Signal(); |
| 323 |
| 324 if (profile != NULL) { |
| 325 profile->CalculateTotalTicks(); |
| 326 profiles_.Add(profile); |
| 327 HashMap::Entry* entry = |
| 328 profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()), |
| 329 static_cast<uint32_t>(profile->uid()), |
| 330 true); |
| 331 ASSERT(entry->value == NULL); |
| 332 entry->value = profile; |
| 333 } |
| 334 return profile; |
| 335 } |
| 336 |
| 337 |
| 338 CpuProfile* CpuProfilesCollection::StopProfiling(String* title) { |
| 339 return StopProfiling(GetName(title)); |
| 340 } |
| 341 |
| 342 |
| 343 CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) { |
| 344 HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid), |
| 345 static_cast<uint32_t>(uid), |
| 346 false); |
| 347 return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; |
| 348 } |
| 349 |
| 350 |
281 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 351 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
282 String* name, | 352 String* name, |
283 String* resource_name, | 353 String* resource_name, |
284 int line_number) { | 354 int line_number) { |
285 CodeEntry* entry = new CodeEntry(tag, | 355 CodeEntry* entry = new CodeEntry(tag, |
286 GetName(name), | 356 GetName(name), |
287 GetName(resource_name), | 357 GetName(resource_name), |
288 line_number); | 358 line_number); |
289 code_entries_.Add(entry); | 359 code_entries_.Add(entry); |
290 return entry; | 360 return entry; |
291 } | 361 } |
292 | 362 |
293 | 363 |
294 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 364 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
295 const char* name) { | 365 const char* name) { |
296 CodeEntry* entry = new CodeEntry(tag, name, "", 0); | 366 CodeEntry* entry = new CodeEntry(tag, |
| 367 name, |
| 368 "", |
| 369 kNoLineNumberInfo); |
297 code_entries_.Add(entry); | 370 code_entries_.Add(entry); |
298 return entry; | 371 return entry; |
299 } | 372 } |
300 | 373 |
301 | 374 |
302 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 375 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
303 int args_count) { | 376 int args_count) { |
304 CodeEntry* entry = new CodeEntry(tag, GetName(args_count), "", 0); | 377 CodeEntry* entry = new CodeEntry(tag, |
| 378 GetName(args_count), |
| 379 "", |
| 380 kNoLineNumberInfo); |
305 code_entries_.Add(entry); | 381 code_entries_.Add(entry); |
306 return entry; | 382 return entry; |
307 } | 383 } |
308 | 384 |
309 | 385 |
310 const char* CpuProfilesCollection::GetName(String* name) { | 386 const char* CpuProfilesCollection::GetName(String* name) { |
311 if (name->IsString()) { | 387 if (name->IsString()) { |
312 char* c_name = | 388 char* c_name = |
313 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); | 389 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); |
314 HashMap::Entry* cache_entry = | 390 HashMap::Entry* cache_entry = |
(...skipping 23 matching lines...) Expand all Loading... |
338 const int kMaximumNameLength = 32; | 414 const int kMaximumNameLength = 32; |
339 char* name = NewArray<char>(kMaximumNameLength); | 415 char* name = NewArray<char>(kMaximumNameLength); |
340 OS::SNPrintF(Vector<char>(name, kMaximumNameLength), | 416 OS::SNPrintF(Vector<char>(name, kMaximumNameLength), |
341 "args_count: %d", args_count); | 417 "args_count: %d", args_count); |
342 args_count_names_[args_count] = name; | 418 args_count_names_[args_count] = name; |
343 } | 419 } |
344 return args_count_names_[args_count]; | 420 return args_count_names_[args_count]; |
345 } | 421 } |
346 | 422 |
347 | 423 |
| 424 void CpuProfilesCollection::AddPathToCurrentProfiles( |
| 425 const Vector<CodeEntry*>& path) { |
| 426 // As starting / stopping profiles is rare relatively to this |
| 427 // method, we don't bother minimizing the duration of lock holding, |
| 428 // e.g. copying contents of the list to a local vector. |
| 429 current_profiles_semaphore_->Wait(); |
| 430 for (int i = 0; i < current_profiles_.length(); ++i) { |
| 431 current_profiles_[i]->AddPath(path); |
| 432 } |
| 433 current_profiles_semaphore_->Signal(); |
| 434 } |
| 435 |
| 436 |
348 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 437 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |
349 : profiles_(profiles) { | 438 : profiles_(profiles) { |
350 } | 439 } |
351 | 440 |
352 | 441 |
353 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 442 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
354 // Allocate space for stack frames + pc + function. | 443 // Allocate space for stack frames + pc + function. |
355 ScopedVector<CodeEntry*> entries(sample.frames_count + 2); | 444 ScopedVector<CodeEntry*> entries(sample.frames_count + 2); |
356 CodeEntry** entry = entries.start(); | 445 CodeEntry** entry = entries.start(); |
357 *entry++ = code_map_.FindEntry(sample.pc); | 446 *entry++ = code_map_.FindEntry(sample.pc); |
(...skipping 12 matching lines...) Expand all Loading... |
370 *entry++ = NULL; | 459 *entry++ = NULL; |
371 } | 460 } |
372 | 461 |
373 for (const Address *stack_pos = sample.stack, | 462 for (const Address *stack_pos = sample.stack, |
374 *stack_end = stack_pos + sample.frames_count; | 463 *stack_end = stack_pos + sample.frames_count; |
375 stack_pos != stack_end; | 464 stack_pos != stack_end; |
376 ++stack_pos) { | 465 ++stack_pos) { |
377 *entry++ = code_map_.FindEntry(*stack_pos); | 466 *entry++ = code_map_.FindEntry(*stack_pos); |
378 } | 467 } |
379 | 468 |
380 profile()->AddPath(entries); | 469 profiles_->AddPathToCurrentProfiles(entries); |
381 } | 470 } |
382 | 471 |
| 472 #endif // ENABLE_CPP_PROFILES_PROCESSOR |
383 | 473 |
384 } } // namespace v8::internal | 474 } } // namespace v8::internal |
OLD | NEW |