LCOV - code coverage report
Current view: top level - test/cctest - test-profile-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 430 432 99.5 %
Date: 2017-10-20 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.10