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 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
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 #ifdef ENABLE_LOGGING_AND_PROFILING | 28 #ifdef ENABLE_LOGGING_AND_PROFILING |
29 | 29 |
30 #include "v8.h" | 30 #include "v8.h" |
| 31 #include "global-handles.h" |
31 | 32 |
32 #include "profile-generator-inl.h" | 33 #include "profile-generator-inl.h" |
33 | 34 |
34 #include "../include/v8-profiler.h" | 35 #include "../include/v8-profiler.h" |
35 | 36 |
36 namespace v8 { | 37 namespace v8 { |
37 namespace internal { | 38 namespace internal { |
38 | 39 |
39 | 40 |
| 41 TokenEnumerator::TokenEnumerator() |
| 42 : token_locations_(4), |
| 43 token_removed_(4) { |
| 44 } |
| 45 |
| 46 |
| 47 TokenEnumerator::~TokenEnumerator() { |
| 48 for (int i = 0; i < token_locations_.length(); ++i) { |
| 49 if (!token_removed_[i]) { |
| 50 GlobalHandles::ClearWeakness(token_locations_[i]); |
| 51 GlobalHandles::Destroy(token_locations_[i]); |
| 52 } |
| 53 } |
| 54 } |
| 55 |
| 56 |
| 57 int TokenEnumerator::GetTokenId(Object* token) { |
| 58 if (token == NULL) return CodeEntry::kNoSecurityToken; |
| 59 for (int i = 0; i < token_locations_.length(); ++i) { |
| 60 if (*token_locations_[i] == token && !token_removed_[i]) return i; |
| 61 } |
| 62 Handle<Object> handle = GlobalHandles::Create(token); |
| 63 // handle.location() points to a memory cell holding a pointer |
| 64 // to a token object in the V8's heap. |
| 65 GlobalHandles::MakeWeak(handle.location(), this, TokenRemovedCallback); |
| 66 token_locations_.Add(handle.location()); |
| 67 token_removed_.Add(false); |
| 68 return token_locations_.length() - 1; |
| 69 } |
| 70 |
| 71 |
| 72 void TokenEnumerator::TokenRemovedCallback(v8::Persistent<v8::Value> handle, |
| 73 void* parameter) { |
| 74 reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved( |
| 75 Utils::OpenHandle(*handle).location()); |
| 76 } |
| 77 |
| 78 |
| 79 void TokenEnumerator::TokenRemoved(Object** token_location) { |
| 80 for (int i = 0; i < token_locations_.length(); ++i) { |
| 81 if (token_locations_[i] == token_location && !token_removed_[i]) { |
| 82 token_removed_[i] = true; |
| 83 return; |
| 84 } |
| 85 } |
| 86 } |
| 87 |
| 88 |
40 const char* CodeEntry::kEmptyNamePrefix = ""; | 89 const char* CodeEntry::kEmptyNamePrefix = ""; |
41 unsigned CodeEntry::next_call_uid_ = 1; | 90 unsigned CodeEntry::next_call_uid_ = 1; |
42 | 91 |
43 | 92 |
| 93 void CodeEntry::CopyData(const CodeEntry& source) { |
| 94 call_uid_ = source.call_uid_; |
| 95 tag_ = source.tag_; |
| 96 name_prefix_ = source.name_prefix_; |
| 97 name_ = source.name_; |
| 98 resource_name_ = source.resource_name_; |
| 99 line_number_ = source.line_number_; |
| 100 } |
| 101 |
| 102 |
44 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 103 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
45 HashMap::Entry* map_entry = | 104 HashMap::Entry* map_entry = |
46 children_.Lookup(entry, CodeEntryHash(entry), false); | 105 children_.Lookup(entry, CodeEntryHash(entry), false); |
47 return map_entry != NULL ? | 106 return map_entry != NULL ? |
48 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 107 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
49 } | 108 } |
50 | 109 |
51 | 110 |
52 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 111 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
53 HashMap::Entry* map_entry = | 112 HashMap::Entry* map_entry = |
(...skipping 12 matching lines...) Expand all Loading... |
66 return tree_->TicksToMillis(self_ticks_); | 125 return tree_->TicksToMillis(self_ticks_); |
67 } | 126 } |
68 | 127 |
69 | 128 |
70 double ProfileNode::GetTotalMillis() const { | 129 double ProfileNode::GetTotalMillis() const { |
71 return tree_->TicksToMillis(total_ticks_); | 130 return tree_->TicksToMillis(total_ticks_); |
72 } | 131 } |
73 | 132 |
74 | 133 |
75 void ProfileNode::Print(int indent) { | 134 void ProfileNode::Print(int indent) { |
76 OS::Print("%5u %5u %*c %s%s", | 135 OS::Print("%5u %5u %*c %s%s [%d]", |
77 total_ticks_, self_ticks_, | 136 total_ticks_, self_ticks_, |
78 indent, ' ', | 137 indent, ' ', |
79 entry_->name_prefix(), | 138 entry_->name_prefix(), |
80 entry_->name()); | 139 entry_->name(), |
| 140 entry_->security_token_id()); |
81 if (entry_->resource_name()[0] != '\0') | 141 if (entry_->resource_name()[0] != '\0') |
82 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); | 142 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); |
83 OS::Print("\n"); | 143 OS::Print("\n"); |
84 for (HashMap::Entry* p = children_.Start(); | 144 for (HashMap::Entry* p = children_.Start(); |
85 p != NULL; | 145 p != NULL; |
86 p = children_.Next(p)) { | 146 p = children_.Next(p)) { |
87 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); | 147 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); |
88 } | 148 } |
89 } | 149 } |
90 | 150 |
91 | 151 |
92 namespace { | 152 namespace { |
93 | 153 |
94 class DeleteNodesCallback { | 154 class DeleteNodesCallback { |
95 public: | 155 public: |
| 156 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
| 157 |
96 void AfterAllChildrenTraversed(ProfileNode* node) { | 158 void AfterAllChildrenTraversed(ProfileNode* node) { |
97 delete node; | 159 delete node; |
98 } | 160 } |
99 | 161 |
100 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } | 162 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
101 }; | 163 }; |
102 | 164 |
103 } // namespace | 165 } // namespace |
104 | 166 |
105 | 167 |
106 ProfileTree::ProfileTree() | 168 ProfileTree::ProfileTree() |
107 : root_entry_(Logger::FUNCTION_TAG, "", "(root)", "", 0), | 169 : root_entry_(Logger::FUNCTION_TAG, |
| 170 "", |
| 171 "(root)", |
| 172 "", |
| 173 0, |
| 174 CodeEntry::kNoSecurityToken), |
108 root_(new ProfileNode(this, &root_entry_)) { | 175 root_(new ProfileNode(this, &root_entry_)) { |
109 } | 176 } |
110 | 177 |
111 | 178 |
112 ProfileTree::~ProfileTree() { | 179 ProfileTree::~ProfileTree() { |
113 DeleteNodesCallback cb; | 180 DeleteNodesCallback cb; |
114 TraverseDepthFirstPostOrder(&cb); | 181 TraverseDepthFirst(&cb); |
115 } | 182 } |
116 | 183 |
117 | 184 |
118 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { | 185 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { |
119 ProfileNode* node = root_; | 186 ProfileNode* node = root_; |
120 for (CodeEntry** entry = path.start() + path.length() - 1; | 187 for (CodeEntry** entry = path.start() + path.length() - 1; |
121 entry != path.start() - 1; | 188 entry != path.start() - 1; |
122 --entry) { | 189 --entry) { |
123 if (*entry != NULL) { | 190 if (*entry != NULL) { |
124 node = node->FindOrAddChild(*entry); | 191 node = node->FindOrAddChild(*entry); |
125 } | 192 } |
126 } | 193 } |
127 node->IncrementSelfTicks(); | 194 node->IncrementSelfTicks(); |
128 } | 195 } |
129 | 196 |
130 | 197 |
131 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { | 198 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { |
132 ProfileNode* node = root_; | 199 ProfileNode* node = root_; |
133 for (CodeEntry** entry = path.start(); | 200 for (CodeEntry** entry = path.start(); |
134 entry != path.start() + path.length(); | 201 entry != path.start() + path.length(); |
135 ++entry) { | 202 ++entry) { |
136 if (*entry != NULL) { | 203 if (*entry != NULL) { |
137 node = node->FindOrAddChild(*entry); | 204 node = node->FindOrAddChild(*entry); |
138 } | 205 } |
139 } | 206 } |
140 node->IncrementSelfTicks(); | 207 node->IncrementSelfTicks(); |
141 } | 208 } |
142 | 209 |
143 | 210 |
| 211 namespace { |
| 212 |
| 213 struct NodesPair { |
| 214 NodesPair(ProfileNode* src, ProfileNode* dst) |
| 215 : src(src), dst(dst) { } |
| 216 ProfileNode* src; |
| 217 ProfileNode* dst; |
| 218 }; |
| 219 |
| 220 |
| 221 class FilteredCloneCallback { |
| 222 public: |
| 223 explicit FilteredCloneCallback(ProfileNode* dst_root, int security_token_id) |
| 224 : stack_(10), |
| 225 security_token_id_(security_token_id) { |
| 226 stack_.Add(NodesPair(NULL, dst_root)); |
| 227 } |
| 228 |
| 229 void BeforeTraversingChild(ProfileNode* parent, ProfileNode* child) { |
| 230 if (IsTokenAcceptable(child->entry()->security_token_id(), |
| 231 parent->entry()->security_token_id())) { |
| 232 ProfileNode* clone = stack_.last().dst->FindOrAddChild(child->entry()); |
| 233 clone->IncreaseSelfTicks(child->self_ticks()); |
| 234 stack_.Add(NodesPair(child, clone)); |
| 235 } else { |
| 236 // Attribute ticks to parent node. |
| 237 stack_.last().dst->IncreaseSelfTicks(child->self_ticks()); |
| 238 } |
| 239 } |
| 240 |
| 241 void AfterAllChildrenTraversed(ProfileNode* parent) { } |
| 242 |
| 243 void AfterChildTraversed(ProfileNode*, ProfileNode* child) { |
| 244 if (stack_.last().src == child) { |
| 245 stack_.RemoveLast(); |
| 246 } |
| 247 } |
| 248 |
| 249 private: |
| 250 bool IsTokenAcceptable(int token, int parent_token) { |
| 251 if (token == CodeEntry::kNoSecurityToken |
| 252 || token == security_token_id_) return true; |
| 253 if (token == CodeEntry::kInheritsSecurityToken) { |
| 254 ASSERT(parent_token != CodeEntry::kInheritsSecurityToken); |
| 255 return parent_token == CodeEntry::kNoSecurityToken |
| 256 || parent_token == security_token_id_; |
| 257 } |
| 258 return false; |
| 259 } |
| 260 |
| 261 List<NodesPair> stack_; |
| 262 int security_token_id_; |
| 263 }; |
| 264 |
| 265 } // namespace |
| 266 |
| 267 void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) { |
| 268 ms_to_ticks_scale_ = src->ms_to_ticks_scale_; |
| 269 FilteredCloneCallback cb(root_, security_token_id); |
| 270 src->TraverseDepthFirst(&cb); |
| 271 CalculateTotalTicks(); |
| 272 } |
| 273 |
| 274 |
144 void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { | 275 void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { |
145 ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0; | 276 ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0; |
146 } | 277 } |
147 | 278 |
148 | 279 |
149 namespace { | 280 namespace { |
150 | 281 |
151 class Position { | 282 class Position { |
152 public: | 283 public: |
153 explicit Position(ProfileNode* node) | 284 explicit Position(ProfileNode* node) |
154 : node(node), child_idx_(0) { } | 285 : node(node), child_idx_(0) { } |
155 INLINE(ProfileNode* current_child()) { | 286 INLINE(ProfileNode* current_child()) { |
156 return node->children()->at(child_idx_); | 287 return node->children()->at(child_idx_); |
157 } | 288 } |
158 INLINE(bool has_current_child()) { | 289 INLINE(bool has_current_child()) { |
159 return child_idx_ < node->children()->length(); | 290 return child_idx_ < node->children()->length(); |
160 } | 291 } |
161 INLINE(void next_child()) { ++child_idx_; } | 292 INLINE(void next_child()) { ++child_idx_; } |
162 | 293 |
163 ProfileNode* node; | 294 ProfileNode* node; |
164 private: | 295 private: |
165 int child_idx_; | 296 int child_idx_; |
166 }; | 297 }; |
167 | 298 |
168 } // namespace | 299 } // namespace |
169 | 300 |
170 | 301 |
171 // Non-recursive implementation of a depth-first post-order tree traversal. | 302 // Non-recursive implementation of a depth-first post-order tree traversal. |
172 template <typename Callback> | 303 template <typename Callback> |
173 void ProfileTree::TraverseDepthFirstPostOrder(Callback* callback) { | 304 void ProfileTree::TraverseDepthFirst(Callback* callback) { |
174 List<Position> stack(10); | 305 List<Position> stack(10); |
175 stack.Add(Position(root_)); | 306 stack.Add(Position(root_)); |
176 do { | 307 while (stack.length() > 0) { |
177 Position& current = stack.last(); | 308 Position& current = stack.last(); |
178 if (current.has_current_child()) { | 309 if (current.has_current_child()) { |
| 310 callback->BeforeTraversingChild(current.node, current.current_child()); |
179 stack.Add(Position(current.current_child())); | 311 stack.Add(Position(current.current_child())); |
180 } else { | 312 } else { |
181 callback->AfterAllChildrenTraversed(current.node); | 313 callback->AfterAllChildrenTraversed(current.node); |
182 if (stack.length() > 1) { | 314 if (stack.length() > 1) { |
183 Position& parent = stack[stack.length() - 2]; | 315 Position& parent = stack[stack.length() - 2]; |
184 callback->AfterChildTraversed(parent.node, current.node); | 316 callback->AfterChildTraversed(parent.node, current.node); |
185 parent.next_child(); | 317 parent.next_child(); |
186 // Remove child from the stack. | |
187 stack.RemoveLast(); | |
188 } | 318 } |
| 319 // Remove child from the stack. |
| 320 stack.RemoveLast(); |
189 } | 321 } |
190 } while (stack.length() > 1 || stack.last().has_current_child()); | 322 } |
191 } | 323 } |
192 | 324 |
193 | 325 |
194 namespace { | 326 namespace { |
195 | 327 |
196 class CalculateTotalTicksCallback { | 328 class CalculateTotalTicksCallback { |
197 public: | 329 public: |
| 330 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
| 331 |
198 void AfterAllChildrenTraversed(ProfileNode* node) { | 332 void AfterAllChildrenTraversed(ProfileNode* node) { |
199 node->IncreaseTotalTicks(node->self_ticks()); | 333 node->IncreaseTotalTicks(node->self_ticks()); |
200 } | 334 } |
201 | 335 |
202 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { | 336 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { |
203 parent->IncreaseTotalTicks(child->total_ticks()); | 337 parent->IncreaseTotalTicks(child->total_ticks()); |
204 } | 338 } |
205 }; | 339 }; |
206 | 340 |
207 } // namespace | 341 } // namespace |
208 | 342 |
209 | 343 |
210 void ProfileTree::CalculateTotalTicks() { | 344 void ProfileTree::CalculateTotalTicks() { |
211 CalculateTotalTicksCallback cb; | 345 CalculateTotalTicksCallback cb; |
212 TraverseDepthFirstPostOrder(&cb); | 346 TraverseDepthFirst(&cb); |
213 } | 347 } |
214 | 348 |
215 | 349 |
216 void ProfileTree::ShortPrint() { | 350 void ProfileTree::ShortPrint() { |
217 OS::Print("root: %u %u %.2fms %.2fms\n", | 351 OS::Print("root: %u %u %.2fms %.2fms\n", |
218 root_->total_ticks(), root_->self_ticks(), | 352 root_->total_ticks(), root_->self_ticks(), |
219 root_->GetTotalMillis(), root_->GetSelfMillis()); | 353 root_->GetTotalMillis(), root_->GetSelfMillis()); |
220 } | 354 } |
221 | 355 |
222 | 356 |
223 void CpuProfile::AddPath(const Vector<CodeEntry*>& path) { | 357 void CpuProfile::AddPath(const Vector<CodeEntry*>& path) { |
224 top_down_.AddPathFromEnd(path); | 358 top_down_.AddPathFromEnd(path); |
225 bottom_up_.AddPathFromStart(path); | 359 bottom_up_.AddPathFromStart(path); |
226 } | 360 } |
227 | 361 |
228 | 362 |
229 void CpuProfile::CalculateTotalTicks() { | 363 void CpuProfile::CalculateTotalTicks() { |
230 top_down_.CalculateTotalTicks(); | 364 top_down_.CalculateTotalTicks(); |
231 bottom_up_.CalculateTotalTicks(); | 365 bottom_up_.CalculateTotalTicks(); |
232 } | 366 } |
233 | 367 |
234 | 368 |
235 void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) { | 369 void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) { |
236 top_down_.SetTickRatePerMs(actual_sampling_rate); | 370 top_down_.SetTickRatePerMs(actual_sampling_rate); |
237 bottom_up_.SetTickRatePerMs(actual_sampling_rate); | 371 bottom_up_.SetTickRatePerMs(actual_sampling_rate); |
238 } | 372 } |
239 | 373 |
240 | 374 |
| 375 CpuProfile* CpuProfile::FilteredClone(int security_token_id) { |
| 376 ASSERT(security_token_id != CodeEntry::kNoSecurityToken); |
| 377 CpuProfile* clone = new CpuProfile(title_, uid_); |
| 378 clone->top_down_.FilteredClone(&top_down_, security_token_id); |
| 379 clone->bottom_up_.FilteredClone(&bottom_up_, security_token_id); |
| 380 return clone; |
| 381 } |
| 382 |
| 383 |
241 void CpuProfile::ShortPrint() { | 384 void CpuProfile::ShortPrint() { |
242 OS::Print("top down "); | 385 OS::Print("top down "); |
243 top_down_.ShortPrint(); | 386 top_down_.ShortPrint(); |
244 OS::Print("bottom up "); | 387 OS::Print("bottom up "); |
245 bottom_up_.ShortPrint(); | 388 bottom_up_.ShortPrint(); |
246 } | 389 } |
247 | 390 |
248 | 391 |
249 void CpuProfile::Print() { | 392 void CpuProfile::Print() { |
250 OS::Print("[Top down]:\n"); | 393 OS::Print("[Top down]:\n"); |
251 top_down_.Print(); | 394 top_down_.Print(); |
252 OS::Print("[Bottom up]:\n"); | 395 OS::Print("[Bottom up]:\n"); |
253 bottom_up_.Print(); | 396 bottom_up_.Print(); |
254 } | 397 } |
255 | 398 |
256 | 399 |
257 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; | 400 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; |
258 const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = | 401 const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = |
259 CodeMap::CodeEntryInfo(NULL, 0); | 402 CodeMap::CodeEntryInfo(NULL, 0); |
260 | 403 |
261 | 404 |
262 void CodeMap::AddAlias(Address alias, Address addr) { | 405 void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) { |
263 CodeTree::Locator locator; | 406 CodeTree::Locator locator; |
264 if (tree_.Find(addr, &locator)) { | 407 if (tree_.Find(code_start, &locator)) { |
265 const CodeEntryInfo& entry_info = locator.value(); | 408 const CodeEntryInfo& code_info = locator.value(); |
266 tree_.Insert(alias, &locator); | 409 entry->CopyData(*code_info.entry); |
267 locator.set_value(entry_info); | 410 tree_.Insert(start, &locator); |
| 411 locator.set_value(CodeEntryInfo(entry, code_info.size)); |
268 } | 412 } |
269 } | 413 } |
270 | 414 |
271 | 415 |
272 CodeEntry* CodeMap::FindEntry(Address addr) { | 416 CodeEntry* CodeMap::FindEntry(Address addr) { |
273 CodeTree::Locator locator; | 417 CodeTree::Locator locator; |
274 if (tree_.FindGreatestLessThan(addr, &locator)) { | 418 if (tree_.FindGreatestLessThan(addr, &locator)) { |
275 // locator.key() <= addr. Need to check that addr is within entry. | 419 // locator.key() <= addr. Need to check that addr is within entry. |
276 const CodeEntryInfo& entry = locator.value(); | 420 const CodeEntryInfo& entry = locator.value(); |
277 if (addr < (locator.key() + entry.size)) | 421 if (addr < (locator.key() + entry.size)) |
(...skipping 10 matching lines...) Expand all Loading... |
288 | 432 |
289 | 433 |
290 void CodeMap::Print() { | 434 void CodeMap::Print() { |
291 CodeTreePrinter printer; | 435 CodeTreePrinter printer; |
292 tree_.ForEach(&printer); | 436 tree_.ForEach(&printer); |
293 } | 437 } |
294 | 438 |
295 | 439 |
296 CpuProfilesCollection::CpuProfilesCollection() | 440 CpuProfilesCollection::CpuProfilesCollection() |
297 : function_and_resource_names_(StringsMatch), | 441 : function_and_resource_names_(StringsMatch), |
298 profiles_uids_(CpuProfilesMatch), | 442 profiles_uids_(UidsMatch), |
299 current_profiles_semaphore_(OS::CreateSemaphore(1)) { | 443 current_profiles_semaphore_(OS::CreateSemaphore(1)) { |
| 444 // Create list of unabridged profiles. |
| 445 profiles_by_token_.Add(new List<CpuProfile*>()); |
300 } | 446 } |
301 | 447 |
302 | 448 |
303 static void DeleteArgsCountName(char** name_ptr) { | 449 static void DeleteArgsCountName(char** name_ptr) { |
304 DeleteArray(*name_ptr); | 450 DeleteArray(*name_ptr); |
305 } | 451 } |
306 | 452 |
307 | 453 |
308 static void DeleteCodeEntry(CodeEntry** entry_ptr) { | 454 static void DeleteCodeEntry(CodeEntry** entry_ptr) { |
309 delete *entry_ptr; | 455 delete *entry_ptr; |
310 } | 456 } |
311 | 457 |
312 static void DeleteCpuProfile(CpuProfile** profile_ptr) { | 458 static void DeleteCpuProfile(CpuProfile** profile_ptr) { |
313 delete *profile_ptr; | 459 delete *profile_ptr; |
314 } | 460 } |
315 | 461 |
| 462 static void DeleteProfilesList(List<CpuProfile*>** list_ptr) { |
| 463 (*list_ptr)->Iterate(DeleteCpuProfile); |
| 464 delete *list_ptr; |
| 465 } |
316 | 466 |
317 CpuProfilesCollection::~CpuProfilesCollection() { | 467 CpuProfilesCollection::~CpuProfilesCollection() { |
318 delete current_profiles_semaphore_; | 468 delete current_profiles_semaphore_; |
319 current_profiles_.Iterate(DeleteCpuProfile); | 469 current_profiles_.Iterate(DeleteCpuProfile); |
320 profiles_.Iterate(DeleteCpuProfile); | 470 profiles_by_token_.Iterate(DeleteProfilesList); |
321 code_entries_.Iterate(DeleteCodeEntry); | 471 code_entries_.Iterate(DeleteCodeEntry); |
322 args_count_names_.Iterate(DeleteArgsCountName); | 472 args_count_names_.Iterate(DeleteArgsCountName); |
323 for (HashMap::Entry* p = function_and_resource_names_.Start(); | 473 for (HashMap::Entry* p = function_and_resource_names_.Start(); |
324 p != NULL; | 474 p != NULL; |
325 p = function_and_resource_names_.Next(p)) { | 475 p = function_and_resource_names_.Next(p)) { |
326 DeleteArray(reinterpret_cast<const char*>(p->value)); | 476 DeleteArray(reinterpret_cast<const char*>(p->value)); |
327 } | 477 } |
328 } | 478 } |
329 | 479 |
330 | 480 |
(...skipping 11 matching lines...) Expand all Loading... |
342 current_profiles_semaphore_->Signal(); | 492 current_profiles_semaphore_->Signal(); |
343 return true; | 493 return true; |
344 } | 494 } |
345 | 495 |
346 | 496 |
347 bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) { | 497 bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) { |
348 return StartProfiling(GetName(title), uid); | 498 return StartProfiling(GetName(title), uid); |
349 } | 499 } |
350 | 500 |
351 | 501 |
352 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title, | 502 CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id, |
| 503 const char* title, |
353 double actual_sampling_rate) { | 504 double actual_sampling_rate) { |
354 const int title_len = StrLength(title); | 505 const int title_len = StrLength(title); |
355 CpuProfile* profile = NULL; | 506 CpuProfile* profile = NULL; |
356 current_profiles_semaphore_->Wait(); | 507 current_profiles_semaphore_->Wait(); |
357 for (int i = current_profiles_.length() - 1; i >= 0; --i) { | 508 for (int i = current_profiles_.length() - 1; i >= 0; --i) { |
358 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { | 509 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) { |
359 profile = current_profiles_.Remove(i); | 510 profile = current_profiles_.Remove(i); |
360 break; | 511 break; |
361 } | 512 } |
362 } | 513 } |
363 current_profiles_semaphore_->Signal(); | 514 current_profiles_semaphore_->Signal(); |
364 | 515 |
365 if (profile != NULL) { | 516 if (profile != NULL) { |
366 profile->CalculateTotalTicks(); | 517 profile->CalculateTotalTicks(); |
367 profile->SetActualSamplingRate(actual_sampling_rate); | 518 profile->SetActualSamplingRate(actual_sampling_rate); |
368 profiles_.Add(profile); | 519 List<CpuProfile*>* unabridged_list = |
| 520 profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
| 521 unabridged_list->Add(profile); |
369 HashMap::Entry* entry = | 522 HashMap::Entry* entry = |
370 profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()), | 523 profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()), |
371 static_cast<uint32_t>(profile->uid()), | 524 static_cast<uint32_t>(profile->uid()), |
372 true); | 525 true); |
373 ASSERT(entry->value == NULL); | 526 ASSERT(entry->value == NULL); |
374 entry->value = profile; | 527 entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1); |
| 528 return GetProfile(security_token_id, profile->uid()); |
375 } | 529 } |
376 return profile; | 530 return NULL; |
377 } | 531 } |
378 | 532 |
379 | 533 |
380 CpuProfile* CpuProfilesCollection::StopProfiling(String* title, | 534 CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id, |
| 535 String* title, |
381 double actual_sampling_rate) { | 536 double actual_sampling_rate) { |
382 return StopProfiling(GetName(title), actual_sampling_rate); | 537 return StopProfiling(security_token_id, GetName(title), actual_sampling_rate); |
383 } | 538 } |
384 | 539 |
385 | 540 |
386 CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) { | 541 CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id, |
| 542 unsigned uid) { |
387 HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid), | 543 HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid), |
388 static_cast<uint32_t>(uid), | 544 static_cast<uint32_t>(uid), |
389 false); | 545 false); |
390 return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; | 546 int index; |
| 547 if (entry != NULL) { |
| 548 index = reinterpret_cast<int>(entry->value); |
| 549 } else { |
| 550 return NULL; |
| 551 } |
| 552 List<CpuProfile*>* unabridged_list = |
| 553 profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
| 554 if (security_token_id == CodeEntry::kNoSecurityToken) { |
| 555 return unabridged_list->at(index); |
| 556 } |
| 557 List<CpuProfile*>* list = GetProfilesList(security_token_id); |
| 558 if (list->at(index) == NULL) { |
| 559 list->at(index) = |
| 560 unabridged_list->at(index)->FilteredClone(security_token_id); |
| 561 } |
| 562 return list->at(index); |
391 } | 563 } |
392 | 564 |
393 | 565 |
| 566 int CpuProfilesCollection::TokenToIndex(int security_token_id) { |
| 567 ASSERT(CodeEntry::kNoSecurityToken == -1); |
| 568 return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ... |
| 569 } |
| 570 |
| 571 |
| 572 List<CpuProfile*>* CpuProfilesCollection::GetProfilesList( |
| 573 int security_token_id) { |
| 574 const int index = TokenToIndex(security_token_id); |
| 575 profiles_by_token_.AddBlock(NULL, profiles_by_token_.length() - index + 1); |
| 576 List<CpuProfile*>* unabridged_list = |
| 577 profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
| 578 const int current_count = unabridged_list->length(); |
| 579 if (profiles_by_token_[index] == NULL) { |
| 580 profiles_by_token_[index] = new List<CpuProfile*>(current_count); |
| 581 } |
| 582 List<CpuProfile*>* list = profiles_by_token_[index]; |
| 583 list->AddBlock(NULL, current_count - list->length()); |
| 584 return list; |
| 585 } |
| 586 |
| 587 |
| 588 List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) { |
| 589 List<CpuProfile*>* unabridged_list = |
| 590 profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
| 591 if (security_token_id == CodeEntry::kNoSecurityToken) { |
| 592 return unabridged_list; |
| 593 } |
| 594 List<CpuProfile*>* list = GetProfilesList(security_token_id); |
| 595 const int current_count = unabridged_list->length(); |
| 596 for (int i = 0; i < current_count; ++i) { |
| 597 if (list->at(i) == NULL) { |
| 598 list->at(i) = unabridged_list->at(i)->FilteredClone(security_token_id); |
| 599 } |
| 600 } |
| 601 return list; |
| 602 } |
| 603 |
| 604 |
394 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 605 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
395 String* name, | 606 String* name, |
396 String* resource_name, | 607 String* resource_name, |
397 int line_number) { | 608 int line_number) { |
398 CodeEntry* entry = new CodeEntry(tag, | 609 CodeEntry* entry = new CodeEntry(tag, |
399 CodeEntry::kEmptyNamePrefix, | 610 CodeEntry::kEmptyNamePrefix, |
400 GetFunctionName(name), | 611 GetFunctionName(name), |
401 GetName(resource_name), | 612 GetName(resource_name), |
402 line_number); | 613 line_number, |
| 614 CodeEntry::kNoSecurityToken); |
403 code_entries_.Add(entry); | 615 code_entries_.Add(entry); |
404 return entry; | 616 return entry; |
405 } | 617 } |
406 | 618 |
407 | 619 |
408 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 620 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
409 const char* name) { | 621 const char* name) { |
410 CodeEntry* entry = new CodeEntry(tag, | 622 CodeEntry* entry = new CodeEntry(tag, |
411 CodeEntry::kEmptyNamePrefix, | 623 CodeEntry::kEmptyNamePrefix, |
412 GetFunctionName(name), | 624 GetFunctionName(name), |
413 "", | 625 "", |
414 v8::CpuProfileNode::kNoLineNumberInfo); | 626 v8::CpuProfileNode::kNoLineNumberInfo, |
| 627 CodeEntry::kNoSecurityToken); |
415 code_entries_.Add(entry); | 628 code_entries_.Add(entry); |
416 return entry; | 629 return entry; |
417 } | 630 } |
418 | 631 |
419 | 632 |
420 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 633 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
421 const char* name_prefix, | 634 const char* name_prefix, |
422 String* name) { | 635 String* name) { |
423 CodeEntry* entry = new CodeEntry(tag, | 636 CodeEntry* entry = new CodeEntry(tag, |
424 name_prefix, | 637 name_prefix, |
425 GetName(name), | 638 GetName(name), |
426 "", | 639 "", |
427 v8::CpuProfileNode::kNoLineNumberInfo); | 640 v8::CpuProfileNode::kNoLineNumberInfo, |
| 641 CodeEntry::kInheritsSecurityToken); |
428 code_entries_.Add(entry); | 642 code_entries_.Add(entry); |
429 return entry; | 643 return entry; |
430 } | 644 } |
431 | 645 |
432 | 646 |
433 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, | 647 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
434 int args_count) { | 648 int args_count) { |
435 CodeEntry* entry = new CodeEntry(tag, | 649 CodeEntry* entry = new CodeEntry(tag, |
436 "args_count: ", | 650 "args_count: ", |
437 GetName(args_count), | 651 GetName(args_count), |
438 "", | 652 "", |
439 v8::CpuProfileNode::kNoLineNumberInfo); | 653 v8::CpuProfileNode::kNoLineNumberInfo, |
| 654 CodeEntry::kInheritsSecurityToken); |
440 code_entries_.Add(entry); | 655 code_entries_.Add(entry); |
441 return entry; | 656 return entry; |
442 } | 657 } |
| 658 |
| 659 |
| 660 CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) { |
| 661 CodeEntry* entry = new CodeEntry(security_token_id); |
| 662 code_entries_.Add(entry); |
| 663 return entry; |
| 664 } |
443 | 665 |
444 | 666 |
445 const char* CpuProfilesCollection::GetName(String* name) { | 667 const char* CpuProfilesCollection::GetName(String* name) { |
446 if (name->IsString()) { | 668 if (name->IsString()) { |
447 char* c_name = | 669 char* c_name = |
448 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); | 670 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); |
449 HashMap::Entry* cache_entry = | 671 HashMap::Entry* cache_entry = |
450 function_and_resource_names_.Lookup(c_name, | 672 function_and_resource_names_.Lookup(c_name, |
451 name->Hash(), | 673 name->Hash(), |
452 true); | 674 true); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 memset(entry, 0, entries.length() * sizeof(*entry)); | 762 memset(entry, 0, entries.length() * sizeof(*entry)); |
541 if (sample.pc != NULL) { | 763 if (sample.pc != NULL) { |
542 *entry++ = code_map_.FindEntry(sample.pc); | 764 *entry++ = code_map_.FindEntry(sample.pc); |
543 | 765 |
544 if (sample.function != NULL) { | 766 if (sample.function != NULL) { |
545 *entry = code_map_.FindEntry(sample.function); | 767 *entry = code_map_.FindEntry(sample.function); |
546 if (*entry != NULL && !(*entry)->is_js_function()) { | 768 if (*entry != NULL && !(*entry)->is_js_function()) { |
547 *entry = NULL; | 769 *entry = NULL; |
548 } else { | 770 } else { |
549 CodeEntry* pc_entry = *entries.start(); | 771 CodeEntry* pc_entry = *entries.start(); |
550 if (pc_entry == NULL || pc_entry->is_js_function()) | 772 if (pc_entry == NULL) { |
551 *entry = NULL; | 773 *entry = NULL; |
| 774 } else if (pc_entry->is_js_function()) { |
| 775 // Use function entry in favor of pc entry, as function |
| 776 // entry has security token. |
| 777 *entries.start() = NULL; |
| 778 } |
552 } | 779 } |
553 entry++; | 780 entry++; |
554 } | 781 } |
555 | 782 |
556 for (const Address *stack_pos = sample.stack, | 783 for (const Address *stack_pos = sample.stack, |
557 *stack_end = stack_pos + sample.frames_count; | 784 *stack_end = stack_pos + sample.frames_count; |
558 stack_pos != stack_end; | 785 stack_pos != stack_end; |
559 ++stack_pos) { | 786 ++stack_pos) { |
560 *entry++ = code_map_.FindEntry(*stack_pos); | 787 *entry++ = code_map_.FindEntry(*stack_pos); |
561 } | 788 } |
(...skipping 12 matching lines...) Expand all Loading... |
574 *entry++ = EntryForVMState(sample.state); | 801 *entry++ = EntryForVMState(sample.state); |
575 } | 802 } |
576 } | 803 } |
577 | 804 |
578 profiles_->AddPathToCurrentProfiles(entries); | 805 profiles_->AddPathToCurrentProfiles(entries); |
579 } | 806 } |
580 | 807 |
581 } } // namespace v8::internal | 808 } } // namespace v8::internal |
582 | 809 |
583 #endif // ENABLE_LOGGING_AND_PROFILING | 810 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |