Home | History | Annotate | Download | only in cctest
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 //
      3 // Tests of profiles generator and utilities.
      4 
      5 #include "v8.h"
      6 #include "profile-generator-inl.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;
     14 using i::CpuProfilesCollection;
     15 using i::ProfileNode;
     16 using i::ProfileTree;
     17 using i::ProfileGenerator;
     18 using i::SampleRateCalculator;
     19 using i::TickSample;
     20 using i::TokenEnumerator;
     21 using i::Vector;
     22 
     23 
     24 namespace v8 {
     25 namespace internal {
     26 
     27 class TokenEnumeratorTester {
     28  public:
     29   static i::List<bool>* token_removed(TokenEnumerator* te) {
     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));
     39   v8::HandleScope hs;
     40   v8::Local<v8::String> token1(v8::String::New("1x"));
     41   CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
     42   CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
     43   v8::Local<v8::String> token2(v8::String::New("2x"));
     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   {
     48     v8::HandleScope hs;
     49     v8::Local<v8::String> token3(v8::String::New("3x"));
     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   }
     54   CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
     55   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
     56   CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
     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 
    693 class ProfilerExtension : public v8::Extension {
    694  public:
    695   ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
    696   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
    697       v8::Handle<v8::String> name);
    698   static v8::Handle<v8::Value> StartProfiling(const v8::Arguments& args);
    699   static v8::Handle<v8::Value> StopProfiling(const v8::Arguments& args);
    700  private:
    701   static const char* kSource;
    702 };
    703 
    704 
    705 const char* ProfilerExtension::kSource =
    706     "native function startProfiling();"
    707     "native function stopProfiling();";
    708 
    709 v8::Handle<v8::FunctionTemplate> ProfilerExtension::GetNativeFunction(
    710     v8::Handle<v8::String> name) {
    711   if (name->Equals(v8::String::New("startProfiling"))) {
    712     return v8::FunctionTemplate::New(ProfilerExtension::StartProfiling);
    713   } else if (name->Equals(v8::String::New("stopProfiling"))) {
    714     return v8::FunctionTemplate::New(ProfilerExtension::StopProfiling);
    715   } else {
    716     CHECK(false);
    717     return v8::Handle<v8::FunctionTemplate>();
    718   }
    719 }
    720 
    721 
    722 v8::Handle<v8::Value> ProfilerExtension::StartProfiling(
    723     const v8::Arguments& args) {
    724   if (args.Length() > 0)
    725     v8::CpuProfiler::StartProfiling(args[0].As<v8::String>());
    726   else
    727     v8::CpuProfiler::StartProfiling(v8::String::New(""));
    728   return v8::Undefined();
    729 }
    730 
    731 
    732 v8::Handle<v8::Value> ProfilerExtension::StopProfiling(
    733     const v8::Arguments& args) {
    734   if (args.Length() > 0)
    735     v8::CpuProfiler::StopProfiling(args[0].As<v8::String>());
    736   else
    737     v8::CpuProfiler::StopProfiling(v8::String::New(""));
    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) {
    814     i::Vector<char> title = i::Vector<char>::New(16);
    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 }
    824