1// Copyright 2010 the V8 project authors. All rights reserved.
2//
3// Tests of profiles generator and utilities.
4
5#ifdef ENABLE_LOGGING_AND_PROFILING
6
7#include "v8.h"
8#include "profile-generator-inl.h"
9#include "cctest.h"
10#include "../include/v8-profiler.h"
11
12namespace i = v8::internal;
13
14using i::CodeEntry;
15using i::CodeMap;
16using i::CpuProfile;
17using i::CpuProfiler;
18using i::CpuProfilesCollection;
19using i::ProfileNode;
20using i::ProfileTree;
21using i::ProfileGenerator;
22using i::SampleRateCalculator;
23using i::TickSample;
24using i::TokenEnumerator;
25using i::Vector;
26
27
28namespace v8 {
29namespace internal {
30
31class TokenEnumeratorTester {
32 public:
33  static i::List<bool>* token_removed(TokenEnumerator* te) {
34    return &te->token_removed_;
35  }
36};
37
38} }  // namespace v8::internal
39
40TEST(TokenEnumerator) {
41  TokenEnumerator te;
42  CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
43  v8::HandleScope hs;
44  v8::Local<v8::String> token1(v8::String::New("1"));
45  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
46  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
47  v8::Local<v8::String> token2(v8::String::New("2"));
48  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
49  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
50  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
51  {
52    v8::HandleScope hs;
53    v8::Local<v8::String> token3(v8::String::New("3"));
54    CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
55    CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
56    CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
57  }
58  CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
59  HEAP->CollectAllGarbage(false);
60  CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
61  CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
62  CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
63}
64
65
66TEST(ProfileNodeFindOrAddChild) {
67  ProfileNode node(NULL, NULL);
68  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
69                   TokenEnumerator::kNoSecurityToken);
70  ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
71  CHECK_NE(NULL, childNode1);
72  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
73  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
74                   TokenEnumerator::kNoSecurityToken);
75  ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
76  CHECK_NE(NULL, childNode2);
77  CHECK_NE(childNode1, childNode2);
78  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
79  CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
80  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
81                   TokenEnumerator::kNoSecurityToken);
82  ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
83  CHECK_NE(NULL, childNode3);
84  CHECK_NE(childNode1, childNode3);
85  CHECK_NE(childNode2, childNode3);
86  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
87  CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
88  CHECK_EQ(childNode3, node.FindOrAddChild(&entry3));
89}
90
91
92TEST(ProfileNodeFindOrAddChildForSameFunction) {
93  const char* empty = "";
94  const char* aaa = "aaa";
95  ProfileNode node(NULL, NULL);
96  CodeEntry entry1(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
97                     TokenEnumerator::kNoSecurityToken);
98  ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
99  CHECK_NE(NULL, childNode1);
100  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
101  // The same function again.
102  CodeEntry entry2(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
103                   TokenEnumerator::kNoSecurityToken);
104  CHECK_EQ(childNode1, node.FindOrAddChild(&entry2));
105  // Now with a different security token.
106  CodeEntry entry3(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
107                   TokenEnumerator::kNoSecurityToken + 1);
108  CHECK_EQ(childNode1, node.FindOrAddChild(&entry3));
109}
110
111
112namespace {
113
114class ProfileTreeTestHelper {
115 public:
116  explicit ProfileTreeTestHelper(const ProfileTree* tree)
117      : tree_(tree) { }
118
119  ProfileNode* Walk(CodeEntry* entry1,
120                    CodeEntry* entry2 = NULL,
121                    CodeEntry* entry3 = NULL) {
122    ProfileNode* node = tree_->root();
123    node = node->FindChild(entry1);
124    if (node == NULL) return NULL;
125    if (entry2 != NULL) {
126      node = node->FindChild(entry2);
127      if (node == NULL) return NULL;
128    }
129    if (entry3 != NULL) {
130      node = node->FindChild(entry3);
131    }
132    return node;
133  }
134
135 private:
136  const ProfileTree* tree_;
137};
138
139}  // namespace
140
141TEST(ProfileTreeAddPathFromStart) {
142  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
143                   TokenEnumerator::kNoSecurityToken);
144  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
145                   TokenEnumerator::kNoSecurityToken);
146  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
147                   TokenEnumerator::kNoSecurityToken);
148  ProfileTree tree;
149  ProfileTreeTestHelper helper(&tree);
150  CHECK_EQ(NULL, helper.Walk(&entry1));
151  CHECK_EQ(NULL, helper.Walk(&entry2));
152  CHECK_EQ(NULL, helper.Walk(&entry3));
153
154  CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
155  Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
156  tree.AddPathFromStart(path_vec);
157  CHECK_EQ(NULL, helper.Walk(&entry2));
158  CHECK_EQ(NULL, helper.Walk(&entry3));
159  ProfileNode* node1 = helper.Walk(&entry1);
160  CHECK_NE(NULL, node1);
161  CHECK_EQ(0, node1->total_ticks());
162  CHECK_EQ(0, node1->self_ticks());
163  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
164  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
165  ProfileNode* node2 = helper.Walk(&entry1, &entry2);
166  CHECK_NE(NULL, node2);
167  CHECK_NE(node1, node2);
168  CHECK_EQ(0, node2->total_ticks());
169  CHECK_EQ(0, node2->self_ticks());
170  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
171  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
172  ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
173  CHECK_NE(NULL, node3);
174  CHECK_NE(node1, node3);
175  CHECK_NE(node2, node3);
176  CHECK_EQ(0, node3->total_ticks());
177  CHECK_EQ(1, node3->self_ticks());
178
179  tree.AddPathFromStart(path_vec);
180  CHECK_EQ(node1, helper.Walk(&entry1));
181  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
182  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
183  CHECK_EQ(0, node1->total_ticks());
184  CHECK_EQ(0, node1->self_ticks());
185  CHECK_EQ(0, node2->total_ticks());
186  CHECK_EQ(0, node2->self_ticks());
187  CHECK_EQ(0, node3->total_ticks());
188  CHECK_EQ(2, node3->self_ticks());
189
190  CodeEntry* path2[] = {&entry1, &entry2, &entry2};
191  Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
192  tree.AddPathFromStart(path2_vec);
193  CHECK_EQ(NULL, helper.Walk(&entry2));
194  CHECK_EQ(NULL, helper.Walk(&entry3));
195  CHECK_EQ(node1, helper.Walk(&entry1));
196  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
197  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
198  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
199  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
200  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
201  CHECK_EQ(0, node3->total_ticks());
202  CHECK_EQ(2, node3->self_ticks());
203  ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
204  CHECK_NE(NULL, node4);
205  CHECK_NE(node3, node4);
206  CHECK_EQ(0, node4->total_ticks());
207  CHECK_EQ(1, node4->self_ticks());
208}
209
210
211TEST(ProfileTreeAddPathFromEnd) {
212  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
213                   TokenEnumerator::kNoSecurityToken);
214  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
215                   TokenEnumerator::kNoSecurityToken);
216  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
217                   TokenEnumerator::kNoSecurityToken);
218  ProfileTree tree;
219  ProfileTreeTestHelper helper(&tree);
220  CHECK_EQ(NULL, helper.Walk(&entry1));
221  CHECK_EQ(NULL, helper.Walk(&entry2));
222  CHECK_EQ(NULL, helper.Walk(&entry3));
223
224  CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
225  Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
226  tree.AddPathFromEnd(path_vec);
227  CHECK_EQ(NULL, helper.Walk(&entry2));
228  CHECK_EQ(NULL, helper.Walk(&entry3));
229  ProfileNode* node1 = helper.Walk(&entry1);
230  CHECK_NE(NULL, node1);
231  CHECK_EQ(0, node1->total_ticks());
232  CHECK_EQ(0, node1->self_ticks());
233  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
234  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
235  ProfileNode* node2 = helper.Walk(&entry1, &entry2);
236  CHECK_NE(NULL, node2);
237  CHECK_NE(node1, node2);
238  CHECK_EQ(0, node2->total_ticks());
239  CHECK_EQ(0, node2->self_ticks());
240  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
241  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
242  ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
243  CHECK_NE(NULL, node3);
244  CHECK_NE(node1, node3);
245  CHECK_NE(node2, node3);
246  CHECK_EQ(0, node3->total_ticks());
247  CHECK_EQ(1, node3->self_ticks());
248
249  tree.AddPathFromEnd(path_vec);
250  CHECK_EQ(node1, helper.Walk(&entry1));
251  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
252  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
253  CHECK_EQ(0, node1->total_ticks());
254  CHECK_EQ(0, node1->self_ticks());
255  CHECK_EQ(0, node2->total_ticks());
256  CHECK_EQ(0, node2->self_ticks());
257  CHECK_EQ(0, node3->total_ticks());
258  CHECK_EQ(2, node3->self_ticks());
259
260  CodeEntry* path2[] = {&entry2, &entry2, &entry1};
261  Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
262  tree.AddPathFromEnd(path2_vec);
263  CHECK_EQ(NULL, helper.Walk(&entry2));
264  CHECK_EQ(NULL, helper.Walk(&entry3));
265  CHECK_EQ(node1, helper.Walk(&entry1));
266  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
267  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
268  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
269  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
270  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
271  CHECK_EQ(0, node3->total_ticks());
272  CHECK_EQ(2, node3->self_ticks());
273  ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
274  CHECK_NE(NULL, node4);
275  CHECK_NE(node3, node4);
276  CHECK_EQ(0, node4->total_ticks());
277  CHECK_EQ(1, node4->self_ticks());
278}
279
280
281TEST(ProfileTreeCalculateTotalTicks) {
282  ProfileTree empty_tree;
283  CHECK_EQ(0, empty_tree.root()->total_ticks());
284  CHECK_EQ(0, empty_tree.root()->self_ticks());
285  empty_tree.CalculateTotalTicks();
286  CHECK_EQ(0, empty_tree.root()->total_ticks());
287  CHECK_EQ(0, empty_tree.root()->self_ticks());
288  empty_tree.root()->IncrementSelfTicks();
289  CHECK_EQ(0, empty_tree.root()->total_ticks());
290  CHECK_EQ(1, empty_tree.root()->self_ticks());
291  empty_tree.CalculateTotalTicks();
292  CHECK_EQ(1, empty_tree.root()->total_ticks());
293  CHECK_EQ(1, empty_tree.root()->self_ticks());
294
295  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
296                   TokenEnumerator::kNoSecurityToken);
297  CodeEntry* e1_path[] = {&entry1};
298  Vector<CodeEntry*> e1_path_vec(
299      e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
300
301  ProfileTree single_child_tree;
302  single_child_tree.AddPathFromStart(e1_path_vec);
303  single_child_tree.root()->IncrementSelfTicks();
304  CHECK_EQ(0, single_child_tree.root()->total_ticks());
305  CHECK_EQ(1, single_child_tree.root()->self_ticks());
306  ProfileTreeTestHelper single_child_helper(&single_child_tree);
307  ProfileNode* node1 = single_child_helper.Walk(&entry1);
308  CHECK_NE(NULL, node1);
309  CHECK_EQ(0, node1->total_ticks());
310  CHECK_EQ(1, node1->self_ticks());
311  single_child_tree.CalculateTotalTicks();
312  CHECK_EQ(2, single_child_tree.root()->total_ticks());
313  CHECK_EQ(1, single_child_tree.root()->self_ticks());
314  CHECK_EQ(1, node1->total_ticks());
315  CHECK_EQ(1, node1->self_ticks());
316
317  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
318                   TokenEnumerator::kNoSecurityToken);
319  CodeEntry* e1_e2_path[] = {&entry1, &entry2};
320  Vector<CodeEntry*> e1_e2_path_vec(
321      e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
322
323  ProfileTree flat_tree;
324  ProfileTreeTestHelper flat_helper(&flat_tree);
325  flat_tree.AddPathFromStart(e1_path_vec);
326  flat_tree.AddPathFromStart(e1_path_vec);
327  flat_tree.AddPathFromStart(e1_e2_path_vec);
328  flat_tree.AddPathFromStart(e1_e2_path_vec);
329  flat_tree.AddPathFromStart(e1_e2_path_vec);
330  // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
331  CHECK_EQ(0, flat_tree.root()->total_ticks());
332  CHECK_EQ(0, flat_tree.root()->self_ticks());
333  node1 = flat_helper.Walk(&entry1);
334  CHECK_NE(NULL, node1);
335  CHECK_EQ(0, node1->total_ticks());
336  CHECK_EQ(2, node1->self_ticks());
337  ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
338  CHECK_NE(NULL, node2);
339  CHECK_EQ(0, node2->total_ticks());
340  CHECK_EQ(3, node2->self_ticks());
341  flat_tree.CalculateTotalTicks();
342  // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
343  CHECK_EQ(5, flat_tree.root()->total_ticks());
344  CHECK_EQ(0, flat_tree.root()->self_ticks());
345  CHECK_EQ(5, node1->total_ticks());
346  CHECK_EQ(2, node1->self_ticks());
347  CHECK_EQ(3, node2->total_ticks());
348  CHECK_EQ(3, node2->self_ticks());
349
350  CodeEntry* e2_path[] = {&entry2};
351  Vector<CodeEntry*> e2_path_vec(
352      e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
353  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
354                   TokenEnumerator::kNoSecurityToken);
355  CodeEntry* e3_path[] = {&entry3};
356  Vector<CodeEntry*> e3_path_vec(
357      e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
358
359  ProfileTree wide_tree;
360  ProfileTreeTestHelper wide_helper(&wide_tree);
361  wide_tree.AddPathFromStart(e1_path_vec);
362  wide_tree.AddPathFromStart(e1_path_vec);
363  wide_tree.AddPathFromStart(e1_e2_path_vec);
364  wide_tree.AddPathFromStart(e2_path_vec);
365  wide_tree.AddPathFromStart(e2_path_vec);
366  wide_tree.AddPathFromStart(e2_path_vec);
367  wide_tree.AddPathFromStart(e3_path_vec);
368  wide_tree.AddPathFromStart(e3_path_vec);
369  wide_tree.AddPathFromStart(e3_path_vec);
370  wide_tree.AddPathFromStart(e3_path_vec);
371  // Results in            -> {entry1,0,2} -> {entry2,0,1}
372  //            {root,0,0} -> {entry2,0,3}
373  //                       -> {entry3,0,4}
374  CHECK_EQ(0, wide_tree.root()->total_ticks());
375  CHECK_EQ(0, wide_tree.root()->self_ticks());
376  node1 = wide_helper.Walk(&entry1);
377  CHECK_NE(NULL, node1);
378  CHECK_EQ(0, node1->total_ticks());
379  CHECK_EQ(2, node1->self_ticks());
380  ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
381  CHECK_NE(NULL, node1_2);
382  CHECK_EQ(0, node1_2->total_ticks());
383  CHECK_EQ(1, node1_2->self_ticks());
384  node2 = wide_helper.Walk(&entry2);
385  CHECK_NE(NULL, node2);
386  CHECK_EQ(0, node2->total_ticks());
387  CHECK_EQ(3, node2->self_ticks());
388  ProfileNode* node3 = wide_helper.Walk(&entry3);
389  CHECK_NE(NULL, node3);
390  CHECK_EQ(0, node3->total_ticks());
391  CHECK_EQ(4, node3->self_ticks());
392  wide_tree.CalculateTotalTicks();
393  // Calculates             -> {entry1,3,2} -> {entry2,1,1}
394  //            {root,10,0} -> {entry2,3,3}
395  //                        -> {entry3,4,4}
396  CHECK_EQ(10, wide_tree.root()->total_ticks());
397  CHECK_EQ(0, wide_tree.root()->self_ticks());
398  CHECK_EQ(3, node1->total_ticks());
399  CHECK_EQ(2, node1->self_ticks());
400  CHECK_EQ(1, node1_2->total_ticks());
401  CHECK_EQ(1, node1_2->self_ticks());
402  CHECK_EQ(3, node2->total_ticks());
403  CHECK_EQ(3, node2->self_ticks());
404  CHECK_EQ(4, node3->total_ticks());
405  CHECK_EQ(4, node3->self_ticks());
406}
407
408
409TEST(ProfileTreeFilteredClone) {
410  ProfileTree source_tree;
411  const int token0 = 0, token1 = 1, token2 = 2;
412  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
413  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
414  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
415  CodeEntry entry4(
416      i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
417      TokenEnumerator::kInheritsSecurityToken);
418
419  {
420    CodeEntry* e1_e2_path[] = {&entry1, &entry2};
421    Vector<CodeEntry*> e1_e2_path_vec(
422        e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
423    source_tree.AddPathFromStart(e1_e2_path_vec);
424    CodeEntry* e2_e4_path[] = {&entry2, &entry4};
425    Vector<CodeEntry*> e2_e4_path_vec(
426        e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
427    source_tree.AddPathFromStart(e2_e4_path_vec);
428    CodeEntry* e3_e1_path[] = {&entry3, &entry1};
429    Vector<CodeEntry*> e3_e1_path_vec(
430        e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
431    source_tree.AddPathFromStart(e3_e1_path_vec);
432    CodeEntry* e3_e2_path[] = {&entry3, &entry2};
433    Vector<CodeEntry*> e3_e2_path_vec(
434        e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
435    source_tree.AddPathFromStart(e3_e2_path_vec);
436    source_tree.CalculateTotalTicks();
437    // Results in               -> {entry1,0,1,0} -> {entry2,1,1,1}
438    //            {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
439    //                          -> {entry3,0,2,0} -> {entry1,1,1,0}
440    //                                            -> {entry2,1,1,1}
441    CHECK_EQ(4, source_tree.root()->total_ticks());
442    CHECK_EQ(0, source_tree.root()->self_ticks());
443  }
444
445  {
446    ProfileTree token0_tree;
447    token0_tree.FilteredClone(&source_tree, token0);
448    // Should be                -> {entry1,1,1,0}
449    //            {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
450    // [self ticks from filtered nodes are attributed to their parents]
451    CHECK_EQ(4, token0_tree.root()->total_ticks());
452    CHECK_EQ(1, token0_tree.root()->self_ticks());
453    ProfileTreeTestHelper token0_helper(&token0_tree);
454    ProfileNode* node1 = token0_helper.Walk(&entry1);
455    CHECK_NE(NULL, node1);
456    CHECK_EQ(1, node1->total_ticks());
457    CHECK_EQ(1, node1->self_ticks());
458    CHECK_EQ(NULL, token0_helper.Walk(&entry2));
459    ProfileNode* node3 = token0_helper.Walk(&entry3);
460    CHECK_NE(NULL, node3);
461    CHECK_EQ(2, node3->total_ticks());
462    CHECK_EQ(1, node3->self_ticks());
463    ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
464    CHECK_NE(NULL, node3_1);
465    CHECK_EQ(1, node3_1->total_ticks());
466    CHECK_EQ(1, node3_1->self_ticks());
467    CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
468  }
469
470  {
471    ProfileTree token1_tree;
472    token1_tree.FilteredClone(&source_tree, token1);
473    // Should be
474    //            {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
475    // [child nodes referring to the same entry get merged and
476    //  their self times summed up]
477    CHECK_EQ(4, token1_tree.root()->total_ticks());
478    CHECK_EQ(1, token1_tree.root()->self_ticks());
479    ProfileTreeTestHelper token1_helper(&token1_tree);
480    CHECK_EQ(NULL, token1_helper.Walk(&entry1));
481    CHECK_EQ(NULL, token1_helper.Walk(&entry3));
482    ProfileNode* node2 = token1_helper.Walk(&entry2);
483    CHECK_NE(NULL, node2);
484    CHECK_EQ(3, node2->total_ticks());
485    CHECK_EQ(2, node2->self_ticks());
486    ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
487    CHECK_NE(NULL, node2_4);
488    CHECK_EQ(1, node2_4->total_ticks());
489    CHECK_EQ(1, node2_4->self_ticks());
490  }
491
492  {
493    ProfileTree token2_tree;
494    token2_tree.FilteredClone(&source_tree, token2);
495    // Should be
496    //            {root,4,4,-1}
497    // [no nodes, all ticks get migrated into root node]
498    CHECK_EQ(4, token2_tree.root()->total_ticks());
499    CHECK_EQ(4, token2_tree.root()->self_ticks());
500    ProfileTreeTestHelper token2_helper(&token2_tree);
501    CHECK_EQ(NULL, token2_helper.Walk(&entry1));
502    CHECK_EQ(NULL, token2_helper.Walk(&entry2));
503    CHECK_EQ(NULL, token2_helper.Walk(&entry3));
504  }
505}
506
507
508static inline i::Address ToAddress(int n) {
509  return reinterpret_cast<i::Address>(n);
510}
511
512TEST(CodeMapAddCode) {
513  CodeMap code_map;
514  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
515                   TokenEnumerator::kNoSecurityToken);
516  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
517                   TokenEnumerator::kNoSecurityToken);
518  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
519                   TokenEnumerator::kNoSecurityToken);
520  CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
521                   TokenEnumerator::kNoSecurityToken);
522  code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
523  code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
524  code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
525  code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
526  CHECK_EQ(NULL, code_map.FindEntry(0));
527  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
528  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
529  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
530  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
531  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
532  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
533  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
534  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
535  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
536  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
537  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
538  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
539  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
540  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
541  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
542  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
543}
544
545
546TEST(CodeMapMoveAndDeleteCode) {
547  CodeMap code_map;
548  CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
549                   TokenEnumerator::kNoSecurityToken);
550  CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
551                   TokenEnumerator::kNoSecurityToken);
552  code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
553  code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
554  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
555  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
556  code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800));
557  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
558  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
559  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
560  code_map.DeleteCode(ToAddress(0x1700));
561  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
562  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
563}
564
565
566namespace {
567
568class TestSetup {
569 public:
570  TestSetup()
571      : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
572    i::FLAG_prof_browser_mode = false;
573  }
574
575  ~TestSetup() {
576    i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
577  }
578
579 private:
580  bool old_flag_prof_browser_mode_;
581};
582
583}  // namespace
584
585TEST(RecordTickSample) {
586  TestSetup test_setup;
587  CpuProfilesCollection profiles;
588  profiles.StartProfiling("", 1);
589  ProfileGenerator generator(&profiles);
590  CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
591  CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
592  CodeEntry* entry3 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
593  generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
594  generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
595  generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
596
597  // We are building the following calls tree:
598  //      -> aaa         - sample1
599  //  aaa -> bbb -> ccc  - sample2
600  //      -> ccc -> aaa  - sample3
601  TickSample sample1;
602  sample1.pc = ToAddress(0x1600);
603  sample1.tos = ToAddress(0x1500);
604  sample1.stack[0] = ToAddress(0x1510);
605  sample1.frames_count = 1;
606  generator.RecordTickSample(sample1);
607  TickSample sample2;
608  sample2.pc = ToAddress(0x1925);
609  sample2.tos = ToAddress(0x1900);
610  sample2.stack[0] = ToAddress(0x1780);
611  sample2.stack[1] = ToAddress(0x10000);  // non-existent.
612  sample2.stack[2] = ToAddress(0x1620);
613  sample2.frames_count = 3;
614  generator.RecordTickSample(sample2);
615  TickSample sample3;
616  sample3.pc = ToAddress(0x1510);
617  sample3.tos = ToAddress(0x1500);
618  sample3.stack[0] = ToAddress(0x1910);
619  sample3.stack[1] = ToAddress(0x1610);
620  sample3.frames_count = 2;
621  generator.RecordTickSample(sample3);
622
623  CpuProfile* profile =
624      profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
625  CHECK_NE(NULL, profile);
626  ProfileTreeTestHelper top_down_test_helper(profile->top_down());
627  CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
628  CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
629  ProfileNode* node1 = top_down_test_helper.Walk(entry1);
630  CHECK_NE(NULL, node1);
631  CHECK_EQ(entry1, node1->entry());
632  ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
633  CHECK_NE(NULL, node2);
634  CHECK_EQ(entry1, node2->entry());
635  ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
636  CHECK_NE(NULL, node3);
637  CHECK_EQ(entry3, node3->entry());
638  ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
639  CHECK_NE(NULL, node4);
640  CHECK_EQ(entry1, node4->entry());
641}
642
643
644TEST(SampleRateCalculator) {
645  const double kSamplingIntervalMs = i::Logger::kSamplingIntervalMs;
646
647  // Verify that ticking exactly in query intervals results in the
648  // initial sampling interval.
649  double time = 0.0;
650  SampleRateCalculator calc1;
651  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
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  time += SampleRateCalculator::kWallTimeQueryIntervalMs;
661  calc1.UpdateMeasurements(time);
662  CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
663
664  SampleRateCalculator calc2;
665  time = 0.0;
666  CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
667  calc2.UpdateMeasurements(time);
668  CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
669  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.5;
670  calc2.UpdateMeasurements(time);
671  // (1.0 + 2.0) / 2
672  CHECK_EQ(kSamplingIntervalMs * 1.5, calc2.ticks_per_ms());
673  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.75;
674  calc2.UpdateMeasurements(time);
675  // (1.0 + 2.0 + 2.0) / 3
676  CHECK_EQ(kSamplingIntervalMs * 5.0, floor(calc2.ticks_per_ms() * 3.0 + 0.5));
677
678  SampleRateCalculator calc3;
679  time = 0.0;
680  CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
681  calc3.UpdateMeasurements(time);
682  CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
683  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 2;
684  calc3.UpdateMeasurements(time);
685  // (1.0 + 0.5) / 2
686  CHECK_EQ(kSamplingIntervalMs * 0.75, calc3.ticks_per_ms());
687  time += SampleRateCalculator::kWallTimeQueryIntervalMs * 1.5;
688  calc3.UpdateMeasurements(time);
689  // (1.0 + 0.5 + 0.5) / 3
690  CHECK_EQ(kSamplingIntervalMs * 2.0, floor(calc3.ticks_per_ms() * 3.0 + 0.5));
691}
692
693
694// --- P r o f i l e r   E x t e n s i o n ---
695
696class ProfilerExtension : public v8::Extension {
697 public:
698  ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
699  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
700      v8::Handle<v8::String> name);
701  static v8::Handle<v8::Value> StartProfiling(const v8::Arguments& args);
702  static v8::Handle<v8::Value> StopProfiling(const v8::Arguments& args);
703 private:
704  static const char* kSource;
705};
706
707
708const char* ProfilerExtension::kSource =
709    "native function startProfiling();"
710    "native function stopProfiling();";
711
712v8::Handle<v8::FunctionTemplate> ProfilerExtension::GetNativeFunction(
713    v8::Handle<v8::String> name) {
714  if (name->Equals(v8::String::New("startProfiling"))) {
715    return v8::FunctionTemplate::New(ProfilerExtension::StartProfiling);
716  } else if (name->Equals(v8::String::New("stopProfiling"))) {
717    return v8::FunctionTemplate::New(ProfilerExtension::StopProfiling);
718  } else {
719    CHECK(false);
720    return v8::Handle<v8::FunctionTemplate>();
721  }
722}
723
724
725v8::Handle<v8::Value> ProfilerExtension::StartProfiling(
726    const v8::Arguments& args) {
727  if (args.Length() > 0)
728    v8::CpuProfiler::StartProfiling(args[0].As<v8::String>());
729  else
730    v8::CpuProfiler::StartProfiling(v8::String::New(""));
731  return v8::Undefined();
732}
733
734
735v8::Handle<v8::Value> ProfilerExtension::StopProfiling(
736    const v8::Arguments& args) {
737  if (args.Length() > 0)
738    v8::CpuProfiler::StopProfiling(args[0].As<v8::String>());
739  else
740    v8::CpuProfiler::StopProfiling(v8::String::New(""));
741  return v8::Undefined();
742}
743
744
745static ProfilerExtension kProfilerExtension;
746v8::DeclareExtension kProfilerExtensionDeclaration(&kProfilerExtension);
747static v8::Persistent<v8::Context> env;
748
749static const ProfileNode* PickChild(const ProfileNode* parent,
750                                    const char* name) {
751  for (int i = 0; i < parent->children()->length(); ++i) {
752    const ProfileNode* child = parent->children()->at(i);
753    if (strcmp(child->entry()->name(), name) == 0) return child;
754  }
755  return NULL;
756}
757
758
759TEST(RecordStackTraceAtStartProfiling) {
760  // This test does not pass with inlining enabled since inlined functions
761  // don't appear in the stack trace.
762  i::FLAG_use_inlining = false;
763
764  if (env.IsEmpty()) {
765    v8::HandleScope scope;
766    const char* extensions[] = { "v8/profiler" };
767    v8::ExtensionConfiguration config(1, extensions);
768    env = v8::Context::New(&config);
769  }
770  v8::HandleScope scope;
771  env->Enter();
772
773  CHECK_EQ(0, CpuProfiler::GetProfilesCount());
774  CompileRun(
775      "function c() { startProfiling(); }\n"
776      "function b() { c(); }\n"
777      "function a() { b(); }\n"
778      "a();\n"
779      "stopProfiling();");
780  CHECK_EQ(1, CpuProfiler::GetProfilesCount());
781  CpuProfile* profile =
782      CpuProfiler::GetProfile(NULL, 0);
783  const ProfileTree* topDown = profile->top_down();
784  const ProfileNode* current = topDown->root();
785  const_cast<ProfileNode*>(current)->Print(0);
786  // The tree should look like this:
787  //  (root)
788  //   (anonymous function)
789  //     a
790  //       b
791  //         c
792  // There can also be:
793  //           startProfiling
794  // if the sampler managed to get a tick.
795  current = PickChild(current, "(anonymous function)");
796  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
797  current = PickChild(current, "a");
798  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
799  current = PickChild(current, "b");
800  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
801  current = PickChild(current, "c");
802  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
803  CHECK(current->children()->length() == 0 ||
804        current->children()->length() == 1);
805  if (current->children()->length() == 1) {
806    current = PickChild(current, "startProfiling");
807    CHECK_EQ(0, current->children()->length());
808  }
809}
810
811
812TEST(Issue51919) {
813  CpuProfilesCollection collection;
814  i::EmbeddedVector<char*,
815      CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
816  for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
817    i::Vector<char> title = i::Vector<char>::New(16);
818    i::OS::SNPrintF(title, "%d", i);
819    CHECK(collection.StartProfiling(title.start(), i + 1));  // UID must be > 0.
820    titles[i] = title.start();
821  }
822  CHECK(!collection.StartProfiling(
823      "maximum", CpuProfilesCollection::kMaxSimultaneousProfiles + 1));
824  for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
825    i::DeleteArray(titles[i]);
826}
827
828#endif  // ENABLE_LOGGING_AND_PROFILING
829