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