LCOV - code coverage report
Current view: top level - test/cctest - test-profile-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 463 483 95.9 %
Date: 2019-04-17 Functions: 23 24 95.8 %

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

Generated by: LCOV version 1.10