v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-profile-generator.cc
Go to the documentation of this file.
1 // Copyright 2010 the V8 project authors. All rights reserved.
2 //
3 // Tests of profiles generator and utilities.
4 
5 #include "v8.h"
7 #include "cctest.h"
8 #include "../include/v8-profiler.h"
9 
10 using i::CodeEntry;
11 using i::CodeMap;
12 using i::CpuProfile;
13 using i::CpuProfiler;
15 using i::ProfileNode;
16 using i::ProfileTree;
19 using i::TickSample;
20 using i::TokenEnumerator;
21 using i::Vector;
22 
23 
24 namespace v8 {
25 namespace internal {
26 
28  public:
30  return &te->token_removed_;
31  }
32 };
33 
34 } } // namespace v8::internal
35 
36 TEST(TokenEnumerator) {
37  TokenEnumerator te;
38  CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
41  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
42  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
44  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
45  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
46  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
47  {
50  CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
51  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
52  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
53  }
55  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
57  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
58  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
59 }
60 
61 
62 TEST(ProfileNodeFindOrAddChild) {
63  ProfileNode node(NULL, NULL);
64  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
65  TokenEnumerator::kNoSecurityToken);
66  ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
67  CHECK_NE(NULL, childNode1);
68  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
69  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
70  TokenEnumerator::kNoSecurityToken);
71  ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
72  CHECK_NE(NULL, childNode2);
73  CHECK_NE(childNode1, childNode2);
74  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
75  CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
76  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
77  TokenEnumerator::kNoSecurityToken);
78  ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
79  CHECK_NE(NULL, childNode3);
80  CHECK_NE(childNode1, childNode3);
81  CHECK_NE(childNode2, childNode3);
82  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
83  CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
84  CHECK_EQ(childNode3, node.FindOrAddChild(&entry3));
85 }
86 
87 
88 TEST(ProfileNodeFindOrAddChildForSameFunction) {
89  const char* empty = "";
90  const char* aaa = "aaa";
91  ProfileNode node(NULL, NULL);
92  CodeEntry entry1(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
93  TokenEnumerator::kNoSecurityToken);
94  ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
95  CHECK_NE(NULL, childNode1);
96  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
97  // The same function again.
98  CodeEntry entry2(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
99  TokenEnumerator::kNoSecurityToken);
100  CHECK_EQ(childNode1, node.FindOrAddChild(&entry2));
101  // Now with a different security token.
102  CodeEntry entry3(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
103  TokenEnumerator::kNoSecurityToken + 1);
104  CHECK_EQ(childNode1, node.FindOrAddChild(&entry3));
105 }
106 
107 
108 namespace {
109 
110 class ProfileTreeTestHelper {
111  public:
112  explicit ProfileTreeTestHelper(const ProfileTree* tree)
113  : tree_(tree) { }
114 
115  ProfileNode* Walk(CodeEntry* entry1,
116  CodeEntry* entry2 = NULL,
117  CodeEntry* entry3 = NULL) {
118  ProfileNode* node = tree_->root();
119  node = node->FindChild(entry1);
120  if (node == NULL) return NULL;
121  if (entry2 != NULL) {
122  node = node->FindChild(entry2);
123  if (node == NULL) return NULL;
124  }
125  if (entry3 != NULL) {
126  node = node->FindChild(entry3);
127  }
128  return node;
129  }
130 
131  private:
132  const ProfileTree* tree_;
133 };
134 
135 } // namespace
136 
137 TEST(ProfileTreeAddPathFromStart) {
138  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
139  TokenEnumerator::kNoSecurityToken);
140  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
141  TokenEnumerator::kNoSecurityToken);
142  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
143  TokenEnumerator::kNoSecurityToken);
144  ProfileTree tree;
145  ProfileTreeTestHelper helper(&tree);
146  CHECK_EQ(NULL, helper.Walk(&entry1));
147  CHECK_EQ(NULL, helper.Walk(&entry2));
148  CHECK_EQ(NULL, helper.Walk(&entry3));
149 
150  CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
151  Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
152  tree.AddPathFromStart(path_vec);
153  CHECK_EQ(NULL, helper.Walk(&entry2));
154  CHECK_EQ(NULL, helper.Walk(&entry3));
155  ProfileNode* node1 = helper.Walk(&entry1);
156  CHECK_NE(NULL, node1);
157  CHECK_EQ(0, node1->total_ticks());
158  CHECK_EQ(0, node1->self_ticks());
159  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
160  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
161  ProfileNode* node2 = helper.Walk(&entry1, &entry2);
162  CHECK_NE(NULL, node2);
163  CHECK_NE(node1, node2);
164  CHECK_EQ(0, node2->total_ticks());
165  CHECK_EQ(0, node2->self_ticks());
166  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
167  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
168  ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
169  CHECK_NE(NULL, node3);
170  CHECK_NE(node1, node3);
171  CHECK_NE(node2, node3);
172  CHECK_EQ(0, node3->total_ticks());
173  CHECK_EQ(1, node3->self_ticks());
174 
175  tree.AddPathFromStart(path_vec);
176  CHECK_EQ(node1, helper.Walk(&entry1));
177  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
178  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
179  CHECK_EQ(0, node1->total_ticks());
180  CHECK_EQ(0, node1->self_ticks());
181  CHECK_EQ(0, node2->total_ticks());
182  CHECK_EQ(0, node2->self_ticks());
183  CHECK_EQ(0, node3->total_ticks());
184  CHECK_EQ(2, node3->self_ticks());
185 
186  CodeEntry* path2[] = {&entry1, &entry2, &entry2};
187  Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
188  tree.AddPathFromStart(path2_vec);
189  CHECK_EQ(NULL, helper.Walk(&entry2));
190  CHECK_EQ(NULL, helper.Walk(&entry3));
191  CHECK_EQ(node1, helper.Walk(&entry1));
192  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
193  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
194  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
195  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
196  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
197  CHECK_EQ(0, node3->total_ticks());
198  CHECK_EQ(2, node3->self_ticks());
199  ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
200  CHECK_NE(NULL, node4);
201  CHECK_NE(node3, node4);
202  CHECK_EQ(0, node4->total_ticks());
203  CHECK_EQ(1, node4->self_ticks());
204 }
205 
206 
207 TEST(ProfileTreeAddPathFromEnd) {
208  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
209  TokenEnumerator::kNoSecurityToken);
210  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
211  TokenEnumerator::kNoSecurityToken);
212  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
213  TokenEnumerator::kNoSecurityToken);
214  ProfileTree tree;
215  ProfileTreeTestHelper helper(&tree);
216  CHECK_EQ(NULL, helper.Walk(&entry1));
217  CHECK_EQ(NULL, helper.Walk(&entry2));
218  CHECK_EQ(NULL, helper.Walk(&entry3));
219 
220  CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
221  Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
222  tree.AddPathFromEnd(path_vec);
223  CHECK_EQ(NULL, helper.Walk(&entry2));
224  CHECK_EQ(NULL, helper.Walk(&entry3));
225  ProfileNode* node1 = helper.Walk(&entry1);
226  CHECK_NE(NULL, node1);
227  CHECK_EQ(0, node1->total_ticks());
228  CHECK_EQ(0, node1->self_ticks());
229  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
230  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
231  ProfileNode* node2 = helper.Walk(&entry1, &entry2);
232  CHECK_NE(NULL, node2);
233  CHECK_NE(node1, node2);
234  CHECK_EQ(0, node2->total_ticks());
235  CHECK_EQ(0, node2->self_ticks());
236  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
237  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
238  ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
239  CHECK_NE(NULL, node3);
240  CHECK_NE(node1, node3);
241  CHECK_NE(node2, node3);
242  CHECK_EQ(0, node3->total_ticks());
243  CHECK_EQ(1, node3->self_ticks());
244 
245  tree.AddPathFromEnd(path_vec);
246  CHECK_EQ(node1, helper.Walk(&entry1));
247  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
248  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
249  CHECK_EQ(0, node1->total_ticks());
250  CHECK_EQ(0, node1->self_ticks());
251  CHECK_EQ(0, node2->total_ticks());
252  CHECK_EQ(0, node2->self_ticks());
253  CHECK_EQ(0, node3->total_ticks());
254  CHECK_EQ(2, node3->self_ticks());
255 
256  CodeEntry* path2[] = {&entry2, &entry2, &entry1};
257  Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
258  tree.AddPathFromEnd(path2_vec);
259  CHECK_EQ(NULL, helper.Walk(&entry2));
260  CHECK_EQ(NULL, helper.Walk(&entry3));
261  CHECK_EQ(node1, helper.Walk(&entry1));
262  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
263  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
264  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
265  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
266  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
267  CHECK_EQ(0, node3->total_ticks());
268  CHECK_EQ(2, node3->self_ticks());
269  ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
270  CHECK_NE(NULL, node4);
271  CHECK_NE(node3, node4);
272  CHECK_EQ(0, node4->total_ticks());
273  CHECK_EQ(1, node4->self_ticks());
274 }
275 
276 
277 TEST(ProfileTreeCalculateTotalTicks) {
278  ProfileTree empty_tree;
279  CHECK_EQ(0, empty_tree.root()->total_ticks());
280  CHECK_EQ(0, empty_tree.root()->self_ticks());
281  empty_tree.CalculateTotalTicks();
282  CHECK_EQ(0, empty_tree.root()->total_ticks());
283  CHECK_EQ(0, empty_tree.root()->self_ticks());
284  empty_tree.root()->IncrementSelfTicks();
285  CHECK_EQ(0, empty_tree.root()->total_ticks());
286  CHECK_EQ(1, empty_tree.root()->self_ticks());
287  empty_tree.CalculateTotalTicks();
288  CHECK_EQ(1, empty_tree.root()->total_ticks());
289  CHECK_EQ(1, empty_tree.root()->self_ticks());
290 
291  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
292  TokenEnumerator::kNoSecurityToken);
293  CodeEntry* e1_path[] = {&entry1};
294  Vector<CodeEntry*> e1_path_vec(
295  e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
296 
297  ProfileTree single_child_tree;
298  single_child_tree.AddPathFromStart(e1_path_vec);
299  single_child_tree.root()->IncrementSelfTicks();
300  CHECK_EQ(0, single_child_tree.root()->total_ticks());
301  CHECK_EQ(1, single_child_tree.root()->self_ticks());
302  ProfileTreeTestHelper single_child_helper(&single_child_tree);
303  ProfileNode* node1 = single_child_helper.Walk(&entry1);
304  CHECK_NE(NULL, node1);
305  CHECK_EQ(0, node1->total_ticks());
306  CHECK_EQ(1, node1->self_ticks());
307  single_child_tree.CalculateTotalTicks();
308  CHECK_EQ(2, single_child_tree.root()->total_ticks());
309  CHECK_EQ(1, single_child_tree.root()->self_ticks());
310  CHECK_EQ(1, node1->total_ticks());
311  CHECK_EQ(1, node1->self_ticks());
312 
313  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
314  TokenEnumerator::kNoSecurityToken);
315  CodeEntry* e1_e2_path[] = {&entry1, &entry2};
316  Vector<CodeEntry*> e1_e2_path_vec(
317  e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
318 
319  ProfileTree flat_tree;
320  ProfileTreeTestHelper flat_helper(&flat_tree);
321  flat_tree.AddPathFromStart(e1_path_vec);
322  flat_tree.AddPathFromStart(e1_path_vec);
323  flat_tree.AddPathFromStart(e1_e2_path_vec);
324  flat_tree.AddPathFromStart(e1_e2_path_vec);
325  flat_tree.AddPathFromStart(e1_e2_path_vec);
326  // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
327  CHECK_EQ(0, flat_tree.root()->total_ticks());
328  CHECK_EQ(0, flat_tree.root()->self_ticks());
329  node1 = flat_helper.Walk(&entry1);
330  CHECK_NE(NULL, node1);
331  CHECK_EQ(0, node1->total_ticks());
332  CHECK_EQ(2, node1->self_ticks());
333  ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
334  CHECK_NE(NULL, node2);
335  CHECK_EQ(0, node2->total_ticks());
336  CHECK_EQ(3, node2->self_ticks());
337  flat_tree.CalculateTotalTicks();
338  // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
339  CHECK_EQ(5, flat_tree.root()->total_ticks());
340  CHECK_EQ(0, flat_tree.root()->self_ticks());
341  CHECK_EQ(5, node1->total_ticks());
342  CHECK_EQ(2, node1->self_ticks());
343  CHECK_EQ(3, node2->total_ticks());
344  CHECK_EQ(3, node2->self_ticks());
345 
346  CodeEntry* e2_path[] = {&entry2};
347  Vector<CodeEntry*> e2_path_vec(
348  e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
349  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
350  TokenEnumerator::kNoSecurityToken);
351  CodeEntry* e3_path[] = {&entry3};
352  Vector<CodeEntry*> e3_path_vec(
353  e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
354 
355  ProfileTree wide_tree;
356  ProfileTreeTestHelper wide_helper(&wide_tree);
357  wide_tree.AddPathFromStart(e1_path_vec);
358  wide_tree.AddPathFromStart(e1_path_vec);
359  wide_tree.AddPathFromStart(e1_e2_path_vec);
360  wide_tree.AddPathFromStart(e2_path_vec);
361  wide_tree.AddPathFromStart(e2_path_vec);
362  wide_tree.AddPathFromStart(e2_path_vec);
363  wide_tree.AddPathFromStart(e3_path_vec);
364  wide_tree.AddPathFromStart(e3_path_vec);
365  wide_tree.AddPathFromStart(e3_path_vec);
366  wide_tree.AddPathFromStart(e3_path_vec);
367  // Results in -> {entry1,0,2} -> {entry2,0,1}
368  // {root,0,0} -> {entry2,0,3}
369  // -> {entry3,0,4}
370  CHECK_EQ(0, wide_tree.root()->total_ticks());
371  CHECK_EQ(0, wide_tree.root()->self_ticks());
372  node1 = wide_helper.Walk(&entry1);
373  CHECK_NE(NULL, node1);
374  CHECK_EQ(0, node1->total_ticks());
375  CHECK_EQ(2, node1->self_ticks());
376  ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
377  CHECK_NE(NULL, node1_2);
378  CHECK_EQ(0, node1_2->total_ticks());
379  CHECK_EQ(1, node1_2->self_ticks());
380  node2 = wide_helper.Walk(&entry2);
381  CHECK_NE(NULL, node2);
382  CHECK_EQ(0, node2->total_ticks());
383  CHECK_EQ(3, node2->self_ticks());
384  ProfileNode* node3 = wide_helper.Walk(&entry3);
385  CHECK_NE(NULL, node3);
386  CHECK_EQ(0, node3->total_ticks());
387  CHECK_EQ(4, node3->self_ticks());
388  wide_tree.CalculateTotalTicks();
389  // Calculates -> {entry1,3,2} -> {entry2,1,1}
390  // {root,10,0} -> {entry2,3,3}
391  // -> {entry3,4,4}
392  CHECK_EQ(10, wide_tree.root()->total_ticks());
393  CHECK_EQ(0, wide_tree.root()->self_ticks());
394  CHECK_EQ(3, node1->total_ticks());
395  CHECK_EQ(2, node1->self_ticks());
396  CHECK_EQ(1, node1_2->total_ticks());
397  CHECK_EQ(1, node1_2->self_ticks());
398  CHECK_EQ(3, node2->total_ticks());
399  CHECK_EQ(3, node2->self_ticks());
400  CHECK_EQ(4, node3->total_ticks());
401  CHECK_EQ(4, node3->self_ticks());
402 }
403 
404 
405 TEST(ProfileTreeFilteredClone) {
406  ProfileTree source_tree;
407  const int token0 = 0, token1 = 1, token2 = 2;
408  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
409  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
410  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
411  CodeEntry entry4(
412  i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
413  TokenEnumerator::kInheritsSecurityToken);
414 
415  {
416  CodeEntry* e1_e2_path[] = {&entry1, &entry2};
417  Vector<CodeEntry*> e1_e2_path_vec(
418  e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
419  source_tree.AddPathFromStart(e1_e2_path_vec);
420  CodeEntry* e2_e4_path[] = {&entry2, &entry4};
421  Vector<CodeEntry*> e2_e4_path_vec(
422  e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
423  source_tree.AddPathFromStart(e2_e4_path_vec);
424  CodeEntry* e3_e1_path[] = {&entry3, &entry1};
425  Vector<CodeEntry*> e3_e1_path_vec(
426  e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
427  source_tree.AddPathFromStart(e3_e1_path_vec);
428  CodeEntry* e3_e2_path[] = {&entry3, &entry2};
429  Vector<CodeEntry*> e3_e2_path_vec(
430  e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
431  source_tree.AddPathFromStart(e3_e2_path_vec);
432  source_tree.CalculateTotalTicks();
433  // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
434  // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
435  // -> {entry3,0,2,0} -> {entry1,1,1,0}
436  // -> {entry2,1,1,1}
437  CHECK_EQ(4, source_tree.root()->total_ticks());
438  CHECK_EQ(0, source_tree.root()->self_ticks());
439  }
440 
441  {
442  ProfileTree token0_tree;
443  token0_tree.FilteredClone(&source_tree, token0);
444  // Should be -> {entry1,1,1,0}
445  // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
446  // [self ticks from filtered nodes are attributed to their parents]
447  CHECK_EQ(4, token0_tree.root()->total_ticks());
448  CHECK_EQ(1, token0_tree.root()->self_ticks());
449  ProfileTreeTestHelper token0_helper(&token0_tree);
450  ProfileNode* node1 = token0_helper.Walk(&entry1);
451  CHECK_NE(NULL, node1);
452  CHECK_EQ(1, node1->total_ticks());
453  CHECK_EQ(1, node1->self_ticks());
454  CHECK_EQ(NULL, token0_helper.Walk(&entry2));
455  ProfileNode* node3 = token0_helper.Walk(&entry3);
456  CHECK_NE(NULL, node3);
457  CHECK_EQ(2, node3->total_ticks());
458  CHECK_EQ(1, node3->self_ticks());
459  ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
460  CHECK_NE(NULL, node3_1);
461  CHECK_EQ(1, node3_1->total_ticks());
462  CHECK_EQ(1, node3_1->self_ticks());
463  CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
464  }
465 
466  {
467  ProfileTree token1_tree;
468  token1_tree.FilteredClone(&source_tree, token1);
469  // Should be
470  // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
471  // [child nodes referring to the same entry get merged and
472  // their self times summed up]
473  CHECK_EQ(4, token1_tree.root()->total_ticks());
474  CHECK_EQ(1, token1_tree.root()->self_ticks());
475  ProfileTreeTestHelper token1_helper(&token1_tree);
476  CHECK_EQ(NULL, token1_helper.Walk(&entry1));
477  CHECK_EQ(NULL, token1_helper.Walk(&entry3));
478  ProfileNode* node2 = token1_helper.Walk(&entry2);
479  CHECK_NE(NULL, node2);
480  CHECK_EQ(3, node2->total_ticks());
481  CHECK_EQ(2, node2->self_ticks());
482  ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
483  CHECK_NE(NULL, node2_4);
484  CHECK_EQ(1, node2_4->total_ticks());
485  CHECK_EQ(1, node2_4->self_ticks());
486  }
487 
488  {
489  ProfileTree token2_tree;
490  token2_tree.FilteredClone(&source_tree, token2);
491  // Should be
492  // {root,4,4,-1}
493  // [no nodes, all ticks get migrated into root node]
494  CHECK_EQ(4, token2_tree.root()->total_ticks());
495  CHECK_EQ(4, token2_tree.root()->self_ticks());
496  ProfileTreeTestHelper token2_helper(&token2_tree);
497  CHECK_EQ(NULL, token2_helper.Walk(&entry1));
498  CHECK_EQ(NULL, token2_helper.Walk(&entry2));
499  CHECK_EQ(NULL, token2_helper.Walk(&entry3));
500  }
501 }
502 
503 
504 static inline i::Address ToAddress(int n) {
505  return reinterpret_cast<i::Address>(n);
506 }
507 
508 TEST(CodeMapAddCode) {
509  CodeMap code_map;
510  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
511  TokenEnumerator::kNoSecurityToken);
512  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
513  TokenEnumerator::kNoSecurityToken);
514  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
515  TokenEnumerator::kNoSecurityToken);
516  CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
517  TokenEnumerator::kNoSecurityToken);
518  code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
519  code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
520  code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
521  code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
522  CHECK_EQ(NULL, code_map.FindEntry(0));
523  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
524  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
525  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
526  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
527  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
528  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
529  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
530  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
531  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
532  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
533  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
534  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
535  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
536  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
537  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
538  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
539 }
540 
541 
542 TEST(CodeMapMoveAndDeleteCode) {
543  CodeMap code_map;
544  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
545  TokenEnumerator::kNoSecurityToken);
546  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
547  TokenEnumerator::kNoSecurityToken);
548  code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
549  code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
550  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
551  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
552  code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700)); // Deprecate bbb.
553  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
554  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
555  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
556  TokenEnumerator::kNoSecurityToken);
557  code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
558  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
559  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
560 }
561 
562 
563 namespace {
564 
565 class TestSetup {
566  public:
567  TestSetup()
568  : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
569  i::FLAG_prof_browser_mode = false;
570  }
571 
572  ~TestSetup() {
573  i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
574  }
575 
576  private:
577  bool old_flag_prof_browser_mode_;
578 };
579 
580 } // namespace
581 
582 TEST(RecordTickSample) {
583  TestSetup test_setup;
584  CpuProfilesCollection profiles;
585  profiles.StartProfiling("", 1);
586  ProfileGenerator generator(&profiles);
587  CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
588  CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
589  CodeEntry* entry3 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
590  generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
591  generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
592  generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
593 
594  // We are building the following calls tree:
595  // -> aaa - sample1
596  // aaa -> bbb -> ccc - sample2
597  // -> ccc -> aaa - sample3
598  TickSample sample1;
599  sample1.pc = ToAddress(0x1600);
600  sample1.tos = ToAddress(0x1500);
601  sample1.stack[0] = ToAddress(0x1510);
602  sample1.frames_count = 1;
603  generator.RecordTickSample(sample1);
604  TickSample sample2;
605  sample2.pc = ToAddress(0x1925);
606  sample2.tos = ToAddress(0x1900);
607  sample2.stack[0] = ToAddress(0x1780);
608  sample2.stack[1] = ToAddress(0x10000); // non-existent.
609  sample2.stack[2] = ToAddress(0x1620);
610  sample2.frames_count = 3;
611  generator.RecordTickSample(sample2);
612  TickSample sample3;
613  sample3.pc = ToAddress(0x1510);
614  sample3.tos = ToAddress(0x1500);
615  sample3.stack[0] = ToAddress(0x1910);
616  sample3.stack[1] = ToAddress(0x1610);
617  sample3.frames_count = 2;
618  generator.RecordTickSample(sample3);
619 
620  CpuProfile* profile =
621  profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
622  CHECK_NE(NULL, profile);
623  ProfileTreeTestHelper top_down_test_helper(profile->top_down());
624  CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
625  CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
626  ProfileNode* node1 = top_down_test_helper.Walk(entry1);
627  CHECK_NE(NULL, node1);
628  CHECK_EQ(entry1, node1->entry());
629  ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
630  CHECK_NE(NULL, node2);
631  CHECK_EQ(entry1, node2->entry());
632  ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
633  CHECK_NE(NULL, node3);
634  CHECK_EQ(entry3, node3->entry());
635  ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
636  CHECK_NE(NULL, node4);
637  CHECK_EQ(entry1, node4->entry());
638 }
639 
640 
641 TEST(SampleRateCalculator) {
642  const double kSamplingIntervalMs = i::Logger::kSamplingIntervalMs;
643 
644  // Verify that ticking exactly in query intervals results in the
645  // initial sampling interval.
646  double time = 0.0;
647  SampleRateCalculator calc1;
648  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
649  calc1.UpdateMeasurements(time);
650  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
651  time += SampleRateCalculator::kWallTimeQueryIntervalMs;
652  calc1.UpdateMeasurements(time);
653  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
654  time += SampleRateCalculator::kWallTimeQueryIntervalMs;
655  calc1.UpdateMeasurements(time);
656  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
657  time += SampleRateCalculator::kWallTimeQueryIntervalMs;
658  calc1.UpdateMeasurements(time);
659  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
660 
661  SampleRateCalculator calc2;
662  time = 0.0;
663  CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
664  calc2.UpdateMeasurements(time);
665  CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
666  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.5;
667  calc2.UpdateMeasurements(time);
668  // (1.0 + 2.0) / 2
669  CHECK_EQ(kSamplingIntervalMs * 1.5, calc2.ticks_per_ms());
670  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.75;
671  calc2.UpdateMeasurements(time);
672  // (1.0 + 2.0 + 2.0) / 3
673  CHECK_EQ(kSamplingIntervalMs * 5.0, floor(calc2.ticks_per_ms() * 3.0 + 0.5));
674 
675  SampleRateCalculator calc3;
676  time = 0.0;
677  CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
678  calc3.UpdateMeasurements(time);
679  CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
680  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 2;
681  calc3.UpdateMeasurements(time);
682  // (1.0 + 0.5) / 2
683  CHECK_EQ(kSamplingIntervalMs * 0.75, calc3.ticks_per_ms());
684  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 1.5;
685  calc3.UpdateMeasurements(time);
686  // (1.0 + 0.5 + 0.5) / 3
687  CHECK_EQ(kSamplingIntervalMs * 2.0, floor(calc3.ticks_per_ms() * 3.0 + 0.5));
688 }
689 
690 
691 // --- P r o f i l e r E x t e n s i o n ---
692 
694  public:
695  ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
700  private:
701  static const char* kSource;
702 };
703 
704 
705 const char* ProfilerExtension::kSource =
706  "native function startProfiling();"
707  "native function stopProfiling();";
708 
710  v8::Handle<v8::String> name) {
711  if (name->Equals(v8::String::New("startProfiling"))) {
713  } else if (name->Equals(v8::String::New("stopProfiling"))) {
715  } else {
716  CHECK(false);
718  }
719 }
720 
721 
723  const v8::Arguments& args) {
724  if (args.Length() > 0)
725  v8::CpuProfiler::StartProfiling(args[0].As<v8::String>());
726  else
728  return v8::Undefined();
729 }
730 
731 
733  const v8::Arguments& args) {
734  if (args.Length() > 0)
735  v8::CpuProfiler::StopProfiling(args[0].As<v8::String>());
736  else
738  return v8::Undefined();
739 }
740 
741 
742 static ProfilerExtension kProfilerExtension;
743 v8::DeclareExtension kProfilerExtensionDeclaration(&kProfilerExtension);
744 static v8::Persistent<v8::Context> env;
745 
746 static const ProfileNode* PickChild(const ProfileNode* parent,
747  const char* name) {
748  for (int i = 0; i < parent->children()->length(); ++i) {
749  const ProfileNode* child = parent->children()->at(i);
750  if (strcmp(child->entry()->name(), name) == 0) return child;
751  }
752  return NULL;
753 }
754 
755 
756 TEST(RecordStackTraceAtStartProfiling) {
757  // This test does not pass with inlining enabled since inlined functions
758  // don't appear in the stack trace.
759  i::FLAG_use_inlining = false;
760 
761  if (env.IsEmpty()) {
762  v8::HandleScope scope;
763  const char* extensions[] = { "v8/profiler" };
764  v8::ExtensionConfiguration config(1, extensions);
765  env = v8::Context::New(&config);
766  }
767  v8::HandleScope scope;
768  env->Enter();
769 
770  CHECK_EQ(0, CpuProfiler::GetProfilesCount());
771  CompileRun(
772  "function c() { startProfiling(); }\n"
773  "function b() { c(); }\n"
774  "function a() { b(); }\n"
775  "a();\n"
776  "stopProfiling();");
777  CHECK_EQ(1, CpuProfiler::GetProfilesCount());
778  CpuProfile* profile =
779  CpuProfiler::GetProfile(NULL, 0);
780  const ProfileTree* topDown = profile->top_down();
781  const ProfileNode* current = topDown->root();
782  const_cast<ProfileNode*>(current)->Print(0);
783  // The tree should look like this:
784  // (root)
785  // (anonymous function)
786  // a
787  // b
788  // c
789  // There can also be:
790  // startProfiling
791  // if the sampler managed to get a tick.
792  current = PickChild(current, "(anonymous function)");
793  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
794  current = PickChild(current, "a");
795  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
796  current = PickChild(current, "b");
797  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
798  current = PickChild(current, "c");
799  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
800  CHECK(current->children()->length() == 0 ||
801  current->children()->length() == 1);
802  if (current->children()->length() == 1) {
803  current = PickChild(current, "startProfiling");
804  CHECK_EQ(0, current->children()->length());
805  }
806 }
807 
808 
809 TEST(Issue51919) {
810  CpuProfilesCollection collection;
811  i::EmbeddedVector<char*,
812  CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
813  for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
815  i::OS::SNPrintF(title, "%d", i);
816  CHECK(collection.StartProfiling(title.start(), i + 1)); // UID must be > 0.
817  titles[i] = title.start();
818  }
819  CHECK(!collection.StartProfiling(
820  "maximum", CpuProfilesCollection::kMaxSimultaneousProfiles + 1));
821  for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
822  i::DeleteArray(titles[i]);
823 }
byte * Address
Definition: globals.h:157
#define CHECK_EQ(expected, value)
Definition: checks.h:219
static Local< FunctionTemplate > New(InvocationCallback callback=0, Handle< Value > data=Handle< Value >(), Handle< Signature > signature=Handle< Signature >())
Definition: api.cc:951
static i::List< bool > * token_removed(TokenEnumerator *te)
Extension(const char *name, const char *source=0, int dep_count=0, const char **deps=0, int source_length=-1)
Definition: api.cc:532
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4779
v8::Handle< v8::Value > Print(const v8::Arguments &args)
#define CHECK(condition)
Definition: checks.h:56
V8EXPORT bool Equals(Handle< Value > that) const
Definition: api.cc:2684
T * start() const
Definition: utils.h:390
static void StartProfiling(Handle< String > title)
Definition: api.cc:6109
static const int kNoGCFlags
Definition: heap.h:1081
int Length() const
Definition: v8.h:4318
const char * name() const
Definition: v8.h:2574
Definition: v8.h:105
static Vector< T > New(int length)
Definition: utils.h:370
#define CHECK_NE(unexpected, value)
Definition: checks.h:223
TEST(TokenEnumerator)
static int SNPrintF(Vector< char > str, const char *format,...)
static v8::Handle< v8::Value > StopProfiling(const v8::Arguments &args)
static v8::Handle< v8::Value > StartProfiling(const v8::Arguments &args)
virtual v8::Handle< v8::FunctionTemplate > GetNativeFunction(v8::Handle< v8::String > name)
#define HEAP
Definition: isolate.h:1433
static const int kSamplingIntervalMs
Definition: log.h:319
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Handle< Primitive > V8EXPORT Undefined()
Definition: api.cc:549
bool IsEmpty() const
Definition: v8.h:209
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4411
static const CpuProfile * StopProfiling(Handle< String > title, Handle< Value > security_token=Handle< Value >())
Definition: api.cc:6116
void DeleteArray(T *array)
Definition: allocation.h:91
Definition: v8.h:106
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random generator(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer