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