Home | History | Annotate | Download | only in cctest
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 //
     28 // Tests of profiles generator and utilities.
     29 
     30 #include "src/v8.h"
     31 
     32 #include "include/v8-profiler.h"
     33 #include "src/cpu-profiler.h"
     34 #include "src/profile-generator-inl.h"
     35 #include "test/cctest/cctest.h"
     36 #include "test/cctest/profiler-extension.h"
     37 
     38 using i::CodeEntry;
     39 using i::CodeMap;
     40 using i::CpuProfile;
     41 using i::CpuProfiler;
     42 using i::CpuProfilesCollection;
     43 using i::ProfileNode;
     44 using i::ProfileTree;
     45 using i::ProfileGenerator;
     46 using i::TickSample;
     47 using i::Vector;
     48 
     49 
     50 TEST(ProfileNodeFindOrAddChild) {
     51   ProfileTree tree;
     52   ProfileNode* node = tree.root();
     53   CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
     54   ProfileNode* childNode1 = node->FindOrAddChild(&entry1);
     55   CHECK_NE(NULL, childNode1);
     56   CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
     57   CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
     58   ProfileNode* childNode2 = node->FindOrAddChild(&entry2);
     59   CHECK_NE(NULL, childNode2);
     60   CHECK_NE(childNode1, childNode2);
     61   CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
     62   CHECK_EQ(childNode2, node->FindOrAddChild(&entry2));
     63   CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
     64   ProfileNode* childNode3 = node->FindOrAddChild(&entry3);
     65   CHECK_NE(NULL, childNode3);
     66   CHECK_NE(childNode1, childNode3);
     67   CHECK_NE(childNode2, childNode3);
     68   CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
     69   CHECK_EQ(childNode2, node->FindOrAddChild(&entry2));
     70   CHECK_EQ(childNode3, node->FindOrAddChild(&entry3));
     71 }
     72 
     73 
     74 TEST(ProfileNodeFindOrAddChildForSameFunction) {
     75   const char* aaa = "aaa";
     76   ProfileTree tree;
     77   ProfileNode* node = tree.root();
     78   CodeEntry entry1(i::Logger::FUNCTION_TAG, aaa);
     79   ProfileNode* childNode1 = node->FindOrAddChild(&entry1);
     80   CHECK_NE(NULL, childNode1);
     81   CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
     82   // The same function again.
     83   CodeEntry entry2(i::Logger::FUNCTION_TAG, aaa);
     84   CHECK_EQ(childNode1, node->FindOrAddChild(&entry2));
     85   // Now with a different security token.
     86   CodeEntry entry3(i::Logger::FUNCTION_TAG, aaa);
     87   CHECK_EQ(childNode1, node->FindOrAddChild(&entry3));
     88 }
     89 
     90 
     91 namespace {
     92 
     93 class ProfileTreeTestHelper {
     94  public:
     95   explicit ProfileTreeTestHelper(const ProfileTree* tree)
     96       : tree_(tree) { }
     97 
     98   ProfileNode* Walk(CodeEntry* entry1,
     99                     CodeEntry* entry2 = NULL,
    100                     CodeEntry* entry3 = NULL) {
    101     ProfileNode* node = tree_->root();
    102     node = node->FindChild(entry1);
    103     if (node == NULL) return NULL;
    104     if (entry2 != NULL) {
    105       node = node->FindChild(entry2);
    106       if (node == NULL) return NULL;
    107     }
    108     if (entry3 != NULL) {
    109       node = node->FindChild(entry3);
    110     }
    111     return node;
    112   }
    113 
    114  private:
    115   const ProfileTree* tree_;
    116 };
    117 
    118 }  // namespace
    119 
    120 TEST(ProfileTreeAddPathFromStart) {
    121   CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
    122   CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
    123   CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
    124   ProfileTree tree;
    125   ProfileTreeTestHelper helper(&tree);
    126   CHECK_EQ(NULL, helper.Walk(&entry1));
    127   CHECK_EQ(NULL, helper.Walk(&entry2));
    128   CHECK_EQ(NULL, helper.Walk(&entry3));
    129 
    130   CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
    131   Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
    132   tree.AddPathFromStart(path_vec);
    133   CHECK_EQ(NULL, helper.Walk(&entry2));
    134   CHECK_EQ(NULL, helper.Walk(&entry3));
    135   ProfileNode* node1 = helper.Walk(&entry1);
    136   CHECK_NE(NULL, node1);
    137   CHECK_EQ(0, node1->self_ticks());
    138   CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
    139   CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
    140   ProfileNode* node2 = helper.Walk(&entry1, &entry2);
    141   CHECK_NE(NULL, node2);
    142   CHECK_NE(node1, node2);
    143   CHECK_EQ(0, node2->self_ticks());
    144   CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
    145   CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
    146   ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
    147   CHECK_NE(NULL, node3);
    148   CHECK_NE(node1, node3);
    149   CHECK_NE(node2, node3);
    150   CHECK_EQ(1, node3->self_ticks());
    151 
    152   tree.AddPathFromStart(path_vec);
    153   CHECK_EQ(node1, helper.Walk(&entry1));
    154   CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
    155   CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
    156   CHECK_EQ(0, node1->self_ticks());
    157   CHECK_EQ(0, node2->self_ticks());
    158   CHECK_EQ(2, node3->self_ticks());
    159 
    160   CodeEntry* path2[] = {&entry1, &entry2, &entry2};
    161   Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
    162   tree.AddPathFromStart(path2_vec);
    163   CHECK_EQ(NULL, helper.Walk(&entry2));
    164   CHECK_EQ(NULL, helper.Walk(&entry3));
    165   CHECK_EQ(node1, helper.Walk(&entry1));
    166   CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
    167   CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
    168   CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
    169   CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
    170   CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
    171   CHECK_EQ(2, node3->self_ticks());
    172   ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
    173   CHECK_NE(NULL, node4);
    174   CHECK_NE(node3, node4);
    175   CHECK_EQ(1, node4->self_ticks());
    176 }
    177 
    178 
    179 TEST(ProfileTreeAddPathFromEnd) {
    180   CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
    181   CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
    182   CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
    183   ProfileTree tree;
    184   ProfileTreeTestHelper helper(&tree);
    185   CHECK_EQ(NULL, helper.Walk(&entry1));
    186   CHECK_EQ(NULL, helper.Walk(&entry2));
    187   CHECK_EQ(NULL, helper.Walk(&entry3));
    188 
    189   CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
    190   Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
    191   tree.AddPathFromEnd(path_vec);
    192   CHECK_EQ(NULL, helper.Walk(&entry2));
    193   CHECK_EQ(NULL, helper.Walk(&entry3));
    194   ProfileNode* node1 = helper.Walk(&entry1);
    195   CHECK_NE(NULL, node1);
    196   CHECK_EQ(0, node1->self_ticks());
    197   CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
    198   CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
    199   ProfileNode* node2 = helper.Walk(&entry1, &entry2);
    200   CHECK_NE(NULL, node2);
    201   CHECK_NE(node1, node2);
    202   CHECK_EQ(0, node2->self_ticks());
    203   CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
    204   CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
    205   ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
    206   CHECK_NE(NULL, node3);
    207   CHECK_NE(node1, node3);
    208   CHECK_NE(node2, node3);
    209   CHECK_EQ(1, node3->self_ticks());
    210 
    211   tree.AddPathFromEnd(path_vec);
    212   CHECK_EQ(node1, helper.Walk(&entry1));
    213   CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
    214   CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
    215   CHECK_EQ(0, node1->self_ticks());
    216   CHECK_EQ(0, node2->self_ticks());
    217   CHECK_EQ(2, node3->self_ticks());
    218 
    219   CodeEntry* path2[] = {&entry2, &entry2, &entry1};
    220   Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
    221   tree.AddPathFromEnd(path2_vec);
    222   CHECK_EQ(NULL, helper.Walk(&entry2));
    223   CHECK_EQ(NULL, helper.Walk(&entry3));
    224   CHECK_EQ(node1, helper.Walk(&entry1));
    225   CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
    226   CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
    227   CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
    228   CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
    229   CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
    230   CHECK_EQ(2, node3->self_ticks());
    231   ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
    232   CHECK_NE(NULL, node4);
    233   CHECK_NE(node3, node4);
    234   CHECK_EQ(1, node4->self_ticks());
    235 }
    236 
    237 
    238 TEST(ProfileTreeCalculateTotalTicks) {
    239   ProfileTree empty_tree;
    240   CHECK_EQ(0, empty_tree.root()->self_ticks());
    241   empty_tree.root()->IncrementSelfTicks();
    242   CHECK_EQ(1, empty_tree.root()->self_ticks());
    243 
    244   CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
    245   CodeEntry* e1_path[] = {&entry1};
    246   Vector<CodeEntry*> e1_path_vec(
    247       e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
    248 
    249   ProfileTree single_child_tree;
    250   single_child_tree.AddPathFromStart(e1_path_vec);
    251   single_child_tree.root()->IncrementSelfTicks();
    252   CHECK_EQ(1, single_child_tree.root()->self_ticks());
    253   ProfileTreeTestHelper single_child_helper(&single_child_tree);
    254   ProfileNode* node1 = single_child_helper.Walk(&entry1);
    255   CHECK_NE(NULL, node1);
    256   CHECK_EQ(1, single_child_tree.root()->self_ticks());
    257   CHECK_EQ(1, node1->self_ticks());
    258 
    259   CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
    260   CodeEntry* e1_e2_path[] = {&entry1, &entry2};
    261   Vector<CodeEntry*> e1_e2_path_vec(
    262       e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
    263 
    264   ProfileTree flat_tree;
    265   ProfileTreeTestHelper flat_helper(&flat_tree);
    266   flat_tree.AddPathFromStart(e1_path_vec);
    267   flat_tree.AddPathFromStart(e1_path_vec);
    268   flat_tree.AddPathFromStart(e1_e2_path_vec);
    269   flat_tree.AddPathFromStart(e1_e2_path_vec);
    270   flat_tree.AddPathFromStart(e1_e2_path_vec);
    271   // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
    272   CHECK_EQ(0, flat_tree.root()->self_ticks());
    273   node1 = flat_helper.Walk(&entry1);
    274   CHECK_NE(NULL, node1);
    275   CHECK_EQ(2, node1->self_ticks());
    276   ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
    277   CHECK_NE(NULL, node2);
    278   CHECK_EQ(3, node2->self_ticks());
    279   // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
    280   CHECK_EQ(0, flat_tree.root()->self_ticks());
    281   CHECK_EQ(2, node1->self_ticks());
    282 
    283   CodeEntry* e2_path[] = {&entry2};
    284   Vector<CodeEntry*> e2_path_vec(
    285       e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
    286   CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
    287   CodeEntry* e3_path[] = {&entry3};
    288   Vector<CodeEntry*> e3_path_vec(
    289       e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
    290 
    291   ProfileTree wide_tree;
    292   ProfileTreeTestHelper wide_helper(&wide_tree);
    293   wide_tree.AddPathFromStart(e1_path_vec);
    294   wide_tree.AddPathFromStart(e1_path_vec);
    295   wide_tree.AddPathFromStart(e1_e2_path_vec);
    296   wide_tree.AddPathFromStart(e2_path_vec);
    297   wide_tree.AddPathFromStart(e2_path_vec);
    298   wide_tree.AddPathFromStart(e2_path_vec);
    299   wide_tree.AddPathFromStart(e3_path_vec);
    300   wide_tree.AddPathFromStart(e3_path_vec);
    301   wide_tree.AddPathFromStart(e3_path_vec);
    302   wide_tree.AddPathFromStart(e3_path_vec);
    303   // Results in            -> {entry1,0,2} -> {entry2,0,1}
    304   //            {root,0,0} -> {entry2,0,3}
    305   //                       -> {entry3,0,4}
    306   CHECK_EQ(0, wide_tree.root()->self_ticks());
    307   node1 = wide_helper.Walk(&entry1);
    308   CHECK_NE(NULL, node1);
    309   CHECK_EQ(2, node1->self_ticks());
    310   ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
    311   CHECK_NE(NULL, node1_2);
    312   CHECK_EQ(1, node1_2->self_ticks());
    313   node2 = wide_helper.Walk(&entry2);
    314   CHECK_NE(NULL, node2);
    315   CHECK_EQ(3, node2->self_ticks());
    316   ProfileNode* node3 = wide_helper.Walk(&entry3);
    317   CHECK_NE(NULL, node3);
    318   CHECK_EQ(4, node3->self_ticks());
    319   // Calculates             -> {entry1,3,2} -> {entry2,1,1}
    320   //            {root,10,0} -> {entry2,3,3}
    321   //                        -> {entry3,4,4}
    322   CHECK_EQ(0, wide_tree.root()->self_ticks());
    323   CHECK_EQ(2, node1->self_ticks());
    324   CHECK_EQ(1, node1_2->self_ticks());
    325   CHECK_EQ(3, node2->self_ticks());
    326   CHECK_EQ(4, node3->self_ticks());
    327 }
    328 
    329 
    330 static inline i::Address ToAddress(int n) {
    331   return reinterpret_cast<i::Address>(n);
    332 }
    333 
    334 
    335 TEST(CodeMapAddCode) {
    336   CodeMap code_map;
    337   CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
    338   CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
    339   CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
    340   CodeEntry entry4(i::Logger::FUNCTION_TAG, "ddd");
    341   code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
    342   code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
    343   code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
    344   code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
    345   CHECK_EQ(NULL, code_map.FindEntry(0));
    346   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
    347   CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
    348   CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
    349   CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
    350   CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
    351   CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
    352   CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
    353   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
    354   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
    355   CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
    356   CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
    357   CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
    358   CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
    359   CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
    360   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
    361   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
    362 }
    363 
    364 
    365 TEST(CodeMapMoveAndDeleteCode) {
    366   CodeMap code_map;
    367   CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
    368   CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
    369   code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
    370   code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
    371   CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
    372   CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
    373   code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700));  // Deprecate bbb.
    374   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
    375   CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
    376   CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
    377   code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
    378   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
    379   CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
    380 }
    381 
    382 
    383 namespace {
    384 
    385 class TestSetup {
    386  public:
    387   TestSetup()
    388       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
    389     i::FLAG_prof_browser_mode = false;
    390   }
    391 
    392   ~TestSetup() {
    393     i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
    394   }
    395 
    396  private:
    397   bool old_flag_prof_browser_mode_;
    398 };
    399 
    400 }  // namespace
    401 
    402 TEST(RecordTickSample) {
    403   TestSetup test_setup;
    404   CpuProfilesCollection profiles(CcTest::heap());
    405   profiles.StartProfiling("", false);
    406   ProfileGenerator generator(&profiles);
    407   CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
    408   CodeEntry* entry2 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
    409   CodeEntry* entry3 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
    410   generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
    411   generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
    412   generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
    413 
    414   // We are building the following calls tree:
    415   //      -> aaa         - sample1
    416   //  aaa -> bbb -> ccc  - sample2
    417   //      -> ccc -> aaa  - sample3
    418   TickSample sample1;
    419   sample1.pc = ToAddress(0x1600);
    420   sample1.tos = ToAddress(0x1500);
    421   sample1.stack[0] = ToAddress(0x1510);
    422   sample1.frames_count = 1;
    423   generator.RecordTickSample(sample1);
    424   TickSample sample2;
    425   sample2.pc = ToAddress(0x1925);
    426   sample2.tos = ToAddress(0x1900);
    427   sample2.stack[0] = ToAddress(0x1780);
    428   sample2.stack[1] = ToAddress(0x10000);  // non-existent.
    429   sample2.stack[2] = ToAddress(0x1620);
    430   sample2.frames_count = 3;
    431   generator.RecordTickSample(sample2);
    432   TickSample sample3;
    433   sample3.pc = ToAddress(0x1510);
    434   sample3.tos = ToAddress(0x1500);
    435   sample3.stack[0] = ToAddress(0x1910);
    436   sample3.stack[1] = ToAddress(0x1610);
    437   sample3.frames_count = 2;
    438   generator.RecordTickSample(sample3);
    439 
    440   CpuProfile* profile = profiles.StopProfiling("");
    441   CHECK_NE(NULL, profile);
    442   ProfileTreeTestHelper top_down_test_helper(profile->top_down());
    443   CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
    444   CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
    445   ProfileNode* node1 = top_down_test_helper.Walk(entry1);
    446   CHECK_NE(NULL, node1);
    447   CHECK_EQ(entry1, node1->entry());
    448   ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
    449   CHECK_NE(NULL, node2);
    450   CHECK_EQ(entry1, node2->entry());
    451   ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
    452   CHECK_NE(NULL, node3);
    453   CHECK_EQ(entry3, node3->entry());
    454   ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
    455   CHECK_NE(NULL, node4);
    456   CHECK_EQ(entry1, node4->entry());
    457 }
    458 
    459 
    460 static void CheckNodeIds(ProfileNode* node, int* expectedId) {
    461   CHECK_EQ((*expectedId)++, node->id());
    462   for (int i = 0; i < node->children()->length(); i++) {
    463     CheckNodeIds(node->children()->at(i), expectedId);
    464   }
    465 }
    466 
    467 
    468 TEST(SampleIds) {
    469   TestSetup test_setup;
    470   CpuProfilesCollection profiles(CcTest::heap());
    471   profiles.StartProfiling("", true);
    472   ProfileGenerator generator(&profiles);
    473   CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
    474   CodeEntry* entry2 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
    475   CodeEntry* entry3 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
    476   generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
    477   generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
    478   generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
    479 
    480   // We are building the following calls tree:
    481   //                    -> aaa #3           - sample1
    482   // (root)#1 -> aaa #2 -> bbb #4 -> ccc #5 - sample2
    483   //                    -> ccc #6 -> aaa #7 - sample3
    484   TickSample sample1;
    485   sample1.pc = ToAddress(0x1600);
    486   sample1.stack[0] = ToAddress(0x1510);
    487   sample1.frames_count = 1;
    488   generator.RecordTickSample(sample1);
    489   TickSample sample2;
    490   sample2.pc = ToAddress(0x1925);
    491   sample2.stack[0] = ToAddress(0x1780);
    492   sample2.stack[1] = ToAddress(0x10000);  // non-existent.
    493   sample2.stack[2] = ToAddress(0x1620);
    494   sample2.frames_count = 3;
    495   generator.RecordTickSample(sample2);
    496   TickSample sample3;
    497   sample3.pc = ToAddress(0x1510);
    498   sample3.stack[0] = ToAddress(0x1910);
    499   sample3.stack[1] = ToAddress(0x1610);
    500   sample3.frames_count = 2;
    501   generator.RecordTickSample(sample3);
    502 
    503   CpuProfile* profile = profiles.StopProfiling("");
    504   int nodeId = 1;
    505   CheckNodeIds(profile->top_down()->root(), &nodeId);
    506   CHECK_EQ(7, nodeId - 1);
    507 
    508   CHECK_EQ(3, profile->samples_count());
    509   int expected_id[] = {3, 5, 7};
    510   for (int i = 0; i < 3; i++) {
    511     CHECK_EQ(expected_id[i], profile->sample(i)->id());
    512   }
    513 }
    514 
    515 
    516 TEST(NoSamples) {
    517   TestSetup test_setup;
    518   CpuProfilesCollection profiles(CcTest::heap());
    519   profiles.StartProfiling("", false);
    520   ProfileGenerator generator(&profiles);
    521   CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
    522   generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
    523 
    524   // We are building the following calls tree:
    525   // (root)#1 -> aaa #2 -> aaa #3 - sample1
    526   TickSample sample1;
    527   sample1.pc = ToAddress(0x1600);
    528   sample1.stack[0] = ToAddress(0x1510);
    529   sample1.frames_count = 1;
    530   generator.RecordTickSample(sample1);
    531 
    532   CpuProfile* profile = profiles.StopProfiling("");
    533   int nodeId = 1;
    534   CheckNodeIds(profile->top_down()->root(), &nodeId);
    535   CHECK_EQ(3, nodeId - 1);
    536 
    537   CHECK_EQ(0, profile->samples_count());
    538 }
    539 
    540 
    541 static const ProfileNode* PickChild(const ProfileNode* parent,
    542                                     const char* name) {
    543   for (int i = 0; i < parent->children()->length(); ++i) {
    544     const ProfileNode* child = parent->children()->at(i);
    545     if (strcmp(child->entry()->name(), name) == 0) return child;
    546   }
    547   return NULL;
    548 }
    549 
    550 
    551 TEST(RecordStackTraceAtStartProfiling) {
    552   // This test does not pass with inlining enabled since inlined functions
    553   // don't appear in the stack trace.
    554   i::FLAG_use_inlining = false;
    555 
    556   v8::HandleScope scope(CcTest::isolate());
    557   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    558   v8::Context::Scope context_scope(env);
    559 
    560   CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
    561   CHECK_EQ(0, profiler->GetProfilesCount());
    562   CompileRun(
    563       "function c() { startProfiling(); }\n"
    564       "function b() { c(); }\n"
    565       "function a() { b(); }\n"
    566       "a();\n"
    567       "stopProfiling();");
    568   CHECK_EQ(1, profiler->GetProfilesCount());
    569   CpuProfile* profile = profiler->GetProfile(0);
    570   const ProfileTree* topDown = profile->top_down();
    571   const ProfileNode* current = topDown->root();
    572   const_cast<ProfileNode*>(current)->Print(0);
    573   // The tree should look like this:
    574   //  (root)
    575   //   ""
    576   //     a
    577   //       b
    578   //         c
    579   // There can also be:
    580   //           startProfiling
    581   // if the sampler managed to get a tick.
    582   current = PickChild(current, "");
    583   CHECK_NE(NULL, const_cast<ProfileNode*>(current));
    584   current = PickChild(current, "a");
    585   CHECK_NE(NULL, const_cast<ProfileNode*>(current));
    586   current = PickChild(current, "b");
    587   CHECK_NE(NULL, const_cast<ProfileNode*>(current));
    588   current = PickChild(current, "c");
    589   CHECK_NE(NULL, const_cast<ProfileNode*>(current));
    590   CHECK(current->children()->length() == 0 ||
    591         current->children()->length() == 1);
    592   if (current->children()->length() == 1) {
    593     current = PickChild(current, "startProfiling");
    594     CHECK_EQ(0, current->children()->length());
    595   }
    596 }
    597 
    598 
    599 TEST(Issue51919) {
    600   CpuProfilesCollection collection(CcTest::heap());
    601   i::EmbeddedVector<char*,
    602       CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
    603   for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
    604     i::Vector<char> title = i::Vector<char>::New(16);
    605     i::SNPrintF(title, "%d", i);
    606     CHECK(collection.StartProfiling(title.start(), false));
    607     titles[i] = title.start();
    608   }
    609   CHECK(!collection.StartProfiling("maximum", false));
    610   for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
    611     i::DeleteArray(titles[i]);
    612 }
    613 
    614 
    615 static const v8::CpuProfileNode* PickChild(const v8::CpuProfileNode* parent,
    616                                            const char* name) {
    617   for (int i = 0; i < parent->GetChildrenCount(); ++i) {
    618     const v8::CpuProfileNode* child = parent->GetChild(i);
    619     v8::String::Utf8Value function_name(child->GetFunctionName());
    620     if (strcmp(*function_name, name) == 0) return child;
    621   }
    622   return NULL;
    623 }
    624 
    625 
    626 TEST(ProfileNodeScriptId) {
    627   // This test does not pass with inlining enabled since inlined functions
    628   // don't appear in the stack trace.
    629   i::FLAG_use_inlining = false;
    630 
    631   v8::HandleScope scope(CcTest::isolate());
    632   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    633   v8::Context::Scope context_scope(env);
    634 
    635   v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
    636   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
    637   CHECK_EQ(0, iprofiler->GetProfilesCount());
    638   v8::Handle<v8::Script> script_a = v8::Script::Compile(v8::String::NewFromUtf8(
    639       env->GetIsolate(), "function a() { startProfiling(); }\n"));
    640   script_a->Run();
    641   v8::Handle<v8::Script> script_b =
    642       v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
    643                                                   "function b() { a(); }\n"
    644                                                   "b();\n"
    645                                                   "stopProfiling();\n"));
    646   script_b->Run();
    647   CHECK_EQ(1, iprofiler->GetProfilesCount());
    648   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
    649   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
    650   reinterpret_cast<ProfileNode*>(
    651       const_cast<v8::CpuProfileNode*>(current))->Print(0);
    652   // The tree should look like this:
    653   //  (root)
    654   //   ""
    655   //     b
    656   //       a
    657   // There can also be:
    658   //         startProfiling
    659   // if the sampler managed to get a tick.
    660   current = PickChild(current, "");
    661   CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
    662 
    663   current = PickChild(current, "b");
    664   CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
    665   CHECK_EQ(script_b->GetUnboundScript()->GetId(), current->GetScriptId());
    666 
    667   current = PickChild(current, "a");
    668   CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
    669   CHECK_EQ(script_a->GetUnboundScript()->GetId(), current->GetScriptId());
    670 }
    671 
    672 
    673 
    674 
    675 static const char* line_number_test_source_existing_functions =
    676 "function foo_at_the_first_line() {\n"
    677 "}\n"
    678 "foo_at_the_first_line();\n"
    679 "function lazy_func_at_forth_line() {}\n";
    680 
    681 
    682 static const char* line_number_test_source_profile_time_functions =
    683 "// Empty first line\n"
    684 "function bar_at_the_second_line() {\n"
    685 "  foo_at_the_first_line();\n"
    686 "}\n"
    687 "bar_at_the_second_line();\n"
    688 "function lazy_func_at_6th_line() {}";
    689 
    690 int GetFunctionLineNumber(LocalContext* env, const char* name) {
    691   CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
    692   CodeMap* code_map = profiler->generator()->code_map();
    693   i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
    694       *v8::Local<v8::Function>::Cast(
    695           (*(*env))->Global()->Get(v8_str(name))));
    696   CodeEntry* func_entry = code_map->FindEntry(func->code()->address());
    697   if (!func_entry)
    698     FATAL(name);
    699   return func_entry->line_number();
    700 }
    701 
    702 
    703 TEST(LineNumber) {
    704   i::FLAG_use_inlining = false;
    705 
    706   CcTest::InitializeVM();
    707   LocalContext env;
    708   i::Isolate* isolate = CcTest::i_isolate();
    709   TestSetup test_setup;
    710 
    711   i::HandleScope scope(isolate);
    712 
    713   CompileRun(line_number_test_source_existing_functions);
    714 
    715   CpuProfiler* profiler = isolate->cpu_profiler();
    716   profiler->StartProfiling("LineNumber");
    717 
    718   CompileRun(line_number_test_source_profile_time_functions);
    719 
    720   profiler->processor()->StopSynchronously();
    721 
    722   CHECK_EQ(1, GetFunctionLineNumber(&env, "foo_at_the_first_line"));
    723   CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_forth_line"));
    724   CHECK_EQ(2, GetFunctionLineNumber(&env, "bar_at_the_second_line"));
    725   CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_6th_line"));
    726 
    727   profiler->StopProfiling("LineNumber");
    728 }
    729 
    730 
    731 
    732 TEST(BailoutReason) {
    733   v8::HandleScope scope(CcTest::isolate());
    734   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    735   v8::Context::Scope context_scope(env);
    736 
    737   v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
    738   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
    739   CHECK_EQ(0, iprofiler->GetProfilesCount());
    740   v8::Handle<v8::Script> script =
    741       v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
    742                                                   "function TryCatch() {\n"
    743                                                   "  try {\n"
    744                                                   "    startProfiling();\n"
    745                                                   "  } catch (e) { };\n"
    746                                                   "}\n"
    747                                                   "function TryFinally() {\n"
    748                                                   "  try {\n"
    749                                                   "    TryCatch();\n"
    750                                                   "  } finally { };\n"
    751                                                   "}\n"
    752                                                   "TryFinally();\n"
    753                                                   "stopProfiling();"));
    754   script->Run();
    755   CHECK_EQ(1, iprofiler->GetProfilesCount());
    756   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
    757   CHECK(profile);
    758   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
    759   reinterpret_cast<ProfileNode*>(
    760       const_cast<v8::CpuProfileNode*>(current))->Print(0);
    761   // The tree should look like this:
    762   //  (root)
    763   //   ""
    764   //     kTryFinally
    765   //       kTryCatch
    766   current = PickChild(current, "");
    767   CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
    768 
    769   current = PickChild(current, "TryFinally");
    770   CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
    771   CHECK(!strcmp("TryFinallyStatement", current->GetBailoutReason()));
    772 
    773   current = PickChild(current, "TryCatch");
    774   CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
    775   CHECK(!strcmp("TryCatchStatement", current->GetBailoutReason()));
    776 }
    777