blob: 7578b35fbdc7e94eb5367e87cee8cb5589c5c321 [file] [log] [blame]
Steve Block6ded16b2010-05-10 14:33:55 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// 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.
Steve Block6ded16b2010-05-10 14:33:55 +010027//
28// Tests of profiles generator and utilities.
29
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include "src/v8.h"
31
32#include "include/v8-profiler.h"
33#include "src/cpu-profiler.h"
34#include "src/profile-generator-inl.h"
35#include "test/cctest/cctest.h"
36#include "test/cctest/profiler-extension.h"
Steve Block6ded16b2010-05-10 14:33:55 +010037
Steve Block6ded16b2010-05-10 14:33:55 +010038using i::CodeEntry;
39using i::CodeMap;
40using i::CpuProfile;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010041using i::CpuProfiler;
Steve Block6ded16b2010-05-10 14:33:55 +010042using i::CpuProfilesCollection;
43using i::ProfileNode;
44using i::ProfileTree;
45using i::ProfileGenerator;
Steve Block6ded16b2010-05-10 14:33:55 +010046using i::TickSample;
47using i::Vector;
48
49
50TEST(ProfileNodeFindOrAddChild) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 ProfileTree tree;
52 ProfileNode* node = tree.root();
53 CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
54 ProfileNode* childNode1 = node->FindOrAddChild(&entry1);
Steve Block6ded16b2010-05-10 14:33:55 +010055 CHECK_NE(NULL, childNode1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056 CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
57 CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
58 ProfileNode* childNode2 = node->FindOrAddChild(&entry2);
Steve Block6ded16b2010-05-10 14:33:55 +010059 CHECK_NE(NULL, childNode2);
60 CHECK_NE(childNode1, childNode2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
62 CHECK_EQ(childNode2, node->FindOrAddChild(&entry2));
63 CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
64 ProfileNode* childNode3 = node->FindOrAddChild(&entry3);
Steve Block6ded16b2010-05-10 14:33:55 +010065 CHECK_NE(NULL, childNode3);
66 CHECK_NE(childNode1, childNode3);
67 CHECK_NE(childNode2, childNode3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
69 CHECK_EQ(childNode2, node->FindOrAddChild(&entry2));
70 CHECK_EQ(childNode3, node->FindOrAddChild(&entry3));
Steve Block6ded16b2010-05-10 14:33:55 +010071}
72
73
Kristian Monsen0d5e1162010-09-30 15:31:59 +010074TEST(ProfileNodeFindOrAddChildForSameFunction) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010075 const char* aaa = "aaa";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076 ProfileTree tree;
77 ProfileNode* node = tree.root();
78 CodeEntry entry1(i::Logger::FUNCTION_TAG, aaa);
79 ProfileNode* childNode1 = node->FindOrAddChild(&entry1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010080 CHECK_NE(NULL, childNode1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 CHECK_EQ(childNode1, node->FindOrAddChild(&entry1));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010082 // The same function again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 CodeEntry entry2(i::Logger::FUNCTION_TAG, aaa);
84 CHECK_EQ(childNode1, node->FindOrAddChild(&entry2));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010085 // Now with a different security token.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 CodeEntry entry3(i::Logger::FUNCTION_TAG, aaa);
87 CHECK_EQ(childNode1, node->FindOrAddChild(&entry3));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010088}
89
90
Steve Block6ded16b2010-05-10 14:33:55 +010091namespace {
92
93class ProfileTreeTestHelper {
94 public:
95 explicit ProfileTreeTestHelper(const ProfileTree* tree)
96 : tree_(tree) { }
97
98 ProfileNode* Walk(CodeEntry* entry1,
99 CodeEntry* entry2 = NULL,
100 CodeEntry* entry3 = NULL) {
101 ProfileNode* node = tree_->root();
102 node = node->FindChild(entry1);
103 if (node == NULL) return NULL;
104 if (entry2 != NULL) {
105 node = node->FindChild(entry2);
106 if (node == NULL) return NULL;
107 }
108 if (entry3 != NULL) {
109 node = node->FindChild(entry3);
110 }
111 return node;
112 }
113
114 private:
115 const ProfileTree* tree_;
116};
117
118} // namespace
119
120TEST(ProfileTreeAddPathFromStart) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
122 CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
123 CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
Steve Block6ded16b2010-05-10 14:33:55 +0100124 ProfileTree tree;
125 ProfileTreeTestHelper helper(&tree);
126 CHECK_EQ(NULL, helper.Walk(&entry1));
127 CHECK_EQ(NULL, helper.Walk(&entry2));
128 CHECK_EQ(NULL, helper.Walk(&entry3));
129
130 CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
131 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
132 tree.AddPathFromStart(path_vec);
133 CHECK_EQ(NULL, helper.Walk(&entry2));
134 CHECK_EQ(NULL, helper.Walk(&entry3));
135 ProfileNode* node1 = helper.Walk(&entry1);
136 CHECK_NE(NULL, node1);
Steve Block6ded16b2010-05-10 14:33:55 +0100137 CHECK_EQ(0, node1->self_ticks());
138 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
139 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
140 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
141 CHECK_NE(NULL, node2);
142 CHECK_NE(node1, node2);
Steve Block6ded16b2010-05-10 14:33:55 +0100143 CHECK_EQ(0, node2->self_ticks());
144 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
145 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
146 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
147 CHECK_NE(NULL, node3);
148 CHECK_NE(node1, node3);
149 CHECK_NE(node2, node3);
Steve Block6ded16b2010-05-10 14:33:55 +0100150 CHECK_EQ(1, node3->self_ticks());
151
152 tree.AddPathFromStart(path_vec);
153 CHECK_EQ(node1, helper.Walk(&entry1));
154 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
155 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
Steve Block6ded16b2010-05-10 14:33:55 +0100156 CHECK_EQ(0, node1->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100157 CHECK_EQ(0, node2->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100158 CHECK_EQ(2, node3->self_ticks());
159
160 CodeEntry* path2[] = {&entry1, &entry2, &entry2};
161 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
162 tree.AddPathFromStart(path2_vec);
163 CHECK_EQ(NULL, helper.Walk(&entry2));
164 CHECK_EQ(NULL, helper.Walk(&entry3));
165 CHECK_EQ(node1, helper.Walk(&entry1));
166 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
167 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
168 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
169 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
170 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
Steve Block6ded16b2010-05-10 14:33:55 +0100171 CHECK_EQ(2, node3->self_ticks());
172 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
173 CHECK_NE(NULL, node4);
174 CHECK_NE(node3, node4);
Steve Block6ded16b2010-05-10 14:33:55 +0100175 CHECK_EQ(1, node4->self_ticks());
176}
177
178
179TEST(ProfileTreeAddPathFromEnd) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
181 CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
182 CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
Steve Block6ded16b2010-05-10 14:33:55 +0100183 ProfileTree tree;
184 ProfileTreeTestHelper helper(&tree);
185 CHECK_EQ(NULL, helper.Walk(&entry1));
186 CHECK_EQ(NULL, helper.Walk(&entry2));
187 CHECK_EQ(NULL, helper.Walk(&entry3));
188
189 CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
190 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
191 tree.AddPathFromEnd(path_vec);
192 CHECK_EQ(NULL, helper.Walk(&entry2));
193 CHECK_EQ(NULL, helper.Walk(&entry3));
194 ProfileNode* node1 = helper.Walk(&entry1);
195 CHECK_NE(NULL, node1);
Steve Block6ded16b2010-05-10 14:33:55 +0100196 CHECK_EQ(0, node1->self_ticks());
197 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
198 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
199 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
200 CHECK_NE(NULL, node2);
201 CHECK_NE(node1, node2);
Steve Block6ded16b2010-05-10 14:33:55 +0100202 CHECK_EQ(0, node2->self_ticks());
203 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
204 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
205 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
206 CHECK_NE(NULL, node3);
207 CHECK_NE(node1, node3);
208 CHECK_NE(node2, node3);
Steve Block6ded16b2010-05-10 14:33:55 +0100209 CHECK_EQ(1, node3->self_ticks());
210
211 tree.AddPathFromEnd(path_vec);
212 CHECK_EQ(node1, helper.Walk(&entry1));
213 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
214 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
Steve Block6ded16b2010-05-10 14:33:55 +0100215 CHECK_EQ(0, node1->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100216 CHECK_EQ(0, node2->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100217 CHECK_EQ(2, node3->self_ticks());
218
219 CodeEntry* path2[] = {&entry2, &entry2, &entry1};
220 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
221 tree.AddPathFromEnd(path2_vec);
222 CHECK_EQ(NULL, helper.Walk(&entry2));
223 CHECK_EQ(NULL, helper.Walk(&entry3));
224 CHECK_EQ(node1, helper.Walk(&entry1));
225 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
226 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
227 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
228 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
229 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
Steve Block6ded16b2010-05-10 14:33:55 +0100230 CHECK_EQ(2, node3->self_ticks());
231 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
232 CHECK_NE(NULL, node4);
233 CHECK_NE(node3, node4);
Steve Block6ded16b2010-05-10 14:33:55 +0100234 CHECK_EQ(1, node4->self_ticks());
235}
236
237
238TEST(ProfileTreeCalculateTotalTicks) {
239 ProfileTree empty_tree;
Steve Block6ded16b2010-05-10 14:33:55 +0100240 CHECK_EQ(0, empty_tree.root()->self_ticks());
241 empty_tree.root()->IncrementSelfTicks();
Steve Block6ded16b2010-05-10 14:33:55 +0100242 CHECK_EQ(1, empty_tree.root()->self_ticks());
243
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
Steve Block6ded16b2010-05-10 14:33:55 +0100245 CodeEntry* e1_path[] = {&entry1};
246 Vector<CodeEntry*> e1_path_vec(
247 e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
Leon Clarkef7060e22010-06-03 12:02:55 +0100248
249 ProfileTree single_child_tree;
250 single_child_tree.AddPathFromStart(e1_path_vec);
251 single_child_tree.root()->IncrementSelfTicks();
Leon Clarkef7060e22010-06-03 12:02:55 +0100252 CHECK_EQ(1, single_child_tree.root()->self_ticks());
253 ProfileTreeTestHelper single_child_helper(&single_child_tree);
254 ProfileNode* node1 = single_child_helper.Walk(&entry1);
255 CHECK_NE(NULL, node1);
Leon Clarkef7060e22010-06-03 12:02:55 +0100256 CHECK_EQ(1, single_child_tree.root()->self_ticks());
Leon Clarkef7060e22010-06-03 12:02:55 +0100257 CHECK_EQ(1, node1->self_ticks());
258
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
Steve Block6ded16b2010-05-10 14:33:55 +0100260 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
261 Vector<CodeEntry*> e1_e2_path_vec(
262 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
263
264 ProfileTree flat_tree;
265 ProfileTreeTestHelper flat_helper(&flat_tree);
266 flat_tree.AddPathFromStart(e1_path_vec);
267 flat_tree.AddPathFromStart(e1_path_vec);
268 flat_tree.AddPathFromStart(e1_e2_path_vec);
269 flat_tree.AddPathFromStart(e1_e2_path_vec);
270 flat_tree.AddPathFromStart(e1_e2_path_vec);
271 // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
Steve Block6ded16b2010-05-10 14:33:55 +0100272 CHECK_EQ(0, flat_tree.root()->self_ticks());
Leon Clarkef7060e22010-06-03 12:02:55 +0100273 node1 = flat_helper.Walk(&entry1);
Steve Block6ded16b2010-05-10 14:33:55 +0100274 CHECK_NE(NULL, node1);
Steve Block6ded16b2010-05-10 14:33:55 +0100275 CHECK_EQ(2, node1->self_ticks());
276 ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
277 CHECK_NE(NULL, node2);
Steve Block6ded16b2010-05-10 14:33:55 +0100278 CHECK_EQ(3, node2->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100279 // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
Steve Block6ded16b2010-05-10 14:33:55 +0100280 CHECK_EQ(0, flat_tree.root()->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100281 CHECK_EQ(2, node1->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100282
283 CodeEntry* e2_path[] = {&entry2};
284 Vector<CodeEntry*> e2_path_vec(
285 e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
Steve Block6ded16b2010-05-10 14:33:55 +0100287 CodeEntry* e3_path[] = {&entry3};
288 Vector<CodeEntry*> e3_path_vec(
289 e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
290
291 ProfileTree wide_tree;
292 ProfileTreeTestHelper wide_helper(&wide_tree);
293 wide_tree.AddPathFromStart(e1_path_vec);
294 wide_tree.AddPathFromStart(e1_path_vec);
295 wide_tree.AddPathFromStart(e1_e2_path_vec);
296 wide_tree.AddPathFromStart(e2_path_vec);
297 wide_tree.AddPathFromStart(e2_path_vec);
298 wide_tree.AddPathFromStart(e2_path_vec);
299 wide_tree.AddPathFromStart(e3_path_vec);
300 wide_tree.AddPathFromStart(e3_path_vec);
301 wide_tree.AddPathFromStart(e3_path_vec);
302 wide_tree.AddPathFromStart(e3_path_vec);
303 // Results in -> {entry1,0,2} -> {entry2,0,1}
304 // {root,0,0} -> {entry2,0,3}
305 // -> {entry3,0,4}
Steve Block6ded16b2010-05-10 14:33:55 +0100306 CHECK_EQ(0, wide_tree.root()->self_ticks());
307 node1 = wide_helper.Walk(&entry1);
308 CHECK_NE(NULL, node1);
Steve Block6ded16b2010-05-10 14:33:55 +0100309 CHECK_EQ(2, node1->self_ticks());
310 ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
311 CHECK_NE(NULL, node1_2);
Steve Block6ded16b2010-05-10 14:33:55 +0100312 CHECK_EQ(1, node1_2->self_ticks());
313 node2 = wide_helper.Walk(&entry2);
314 CHECK_NE(NULL, node2);
Steve Block6ded16b2010-05-10 14:33:55 +0100315 CHECK_EQ(3, node2->self_ticks());
316 ProfileNode* node3 = wide_helper.Walk(&entry3);
317 CHECK_NE(NULL, node3);
Steve Block6ded16b2010-05-10 14:33:55 +0100318 CHECK_EQ(4, node3->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100319 // Calculates -> {entry1,3,2} -> {entry2,1,1}
320 // {root,10,0} -> {entry2,3,3}
321 // -> {entry3,4,4}
Steve Block6ded16b2010-05-10 14:33:55 +0100322 CHECK_EQ(0, wide_tree.root()->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100323 CHECK_EQ(2, node1->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100324 CHECK_EQ(1, node1_2->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100325 CHECK_EQ(3, node2->self_ticks());
Steve Block6ded16b2010-05-10 14:33:55 +0100326 CHECK_EQ(4, node3->self_ticks());
327}
328
329
330static inline i::Address ToAddress(int n) {
331 return reinterpret_cast<i::Address>(n);
332}
333
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334
Steve Block6ded16b2010-05-10 14:33:55 +0100335TEST(CodeMapAddCode) {
336 CodeMap code_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
338 CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
339 CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
340 CodeEntry entry4(i::Logger::FUNCTION_TAG, "ddd");
Steve Block6ded16b2010-05-10 14:33:55 +0100341 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
342 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
343 code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
344 code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
345 CHECK_EQ(NULL, code_map.FindEntry(0));
346 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
347 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
348 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
349 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
350 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
351 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
352 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
353 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
354 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
355 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
356 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
357 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
358 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
359 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
360 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
361 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
362}
363
364
365TEST(CodeMapMoveAndDeleteCode) {
366 CodeMap code_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367 CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
368 CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
Steve Block6ded16b2010-05-10 14:33:55 +0100369 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
370 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
371 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
372 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
Ben Murdoch589d6972011-11-30 16:04:58 +0000373 code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700)); // Deprecate bbb.
Steve Block6ded16b2010-05-10 14:33:55 +0100374 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
Ben Murdoch589d6972011-11-30 16:04:58 +0000375 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
Ben Murdoch589d6972011-11-30 16:04:58 +0000377 code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
Steve Block6ded16b2010-05-10 14:33:55 +0100378 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
Ben Murdoch589d6972011-11-30 16:04:58 +0000379 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
Steve Block6ded16b2010-05-10 14:33:55 +0100380}
381
382
383namespace {
384
385class TestSetup {
386 public:
387 TestSetup()
388 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
389 i::FLAG_prof_browser_mode = false;
390 }
391
392 ~TestSetup() {
393 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
394 }
395
396 private:
397 bool old_flag_prof_browser_mode_;
398};
399
400} // namespace
401
402TEST(RecordTickSample) {
403 TestSetup test_setup;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 CpuProfilesCollection profiles(CcTest::heap());
405 profiles.StartProfiling("", false);
Steve Block6ded16b2010-05-10 14:33:55 +0100406 ProfileGenerator generator(&profiles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000407 CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
408 CodeEntry* entry2 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
409 CodeEntry* entry3 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
Steve Block6ded16b2010-05-10 14:33:55 +0100410 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
411 generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
412 generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
413
414 // We are building the following calls tree:
415 // -> aaa - sample1
416 // aaa -> bbb -> ccc - sample2
417 // -> ccc -> aaa - sample3
418 TickSample sample1;
419 sample1.pc = ToAddress(0x1600);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100420 sample1.tos = ToAddress(0x1500);
Steve Block6ded16b2010-05-10 14:33:55 +0100421 sample1.stack[0] = ToAddress(0x1510);
422 sample1.frames_count = 1;
423 generator.RecordTickSample(sample1);
424 TickSample sample2;
425 sample2.pc = ToAddress(0x1925);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100426 sample2.tos = ToAddress(0x1900);
Steve Block6ded16b2010-05-10 14:33:55 +0100427 sample2.stack[0] = ToAddress(0x1780);
428 sample2.stack[1] = ToAddress(0x10000); // non-existent.
429 sample2.stack[2] = ToAddress(0x1620);
430 sample2.frames_count = 3;
431 generator.RecordTickSample(sample2);
432 TickSample sample3;
433 sample3.pc = ToAddress(0x1510);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100434 sample3.tos = ToAddress(0x1500);
Steve Block6ded16b2010-05-10 14:33:55 +0100435 sample3.stack[0] = ToAddress(0x1910);
436 sample3.stack[1] = ToAddress(0x1610);
437 sample3.frames_count = 2;
438 generator.RecordTickSample(sample3);
439
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 CpuProfile* profile = profiles.StopProfiling("");
Steve Block6ded16b2010-05-10 14:33:55 +0100441 CHECK_NE(NULL, profile);
442 ProfileTreeTestHelper top_down_test_helper(profile->top_down());
443 CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
444 CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
445 ProfileNode* node1 = top_down_test_helper.Walk(entry1);
446 CHECK_NE(NULL, node1);
447 CHECK_EQ(entry1, node1->entry());
448 ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
449 CHECK_NE(NULL, node2);
450 CHECK_EQ(entry1, node2->entry());
451 ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
452 CHECK_NE(NULL, node3);
453 CHECK_EQ(entry3, node3->entry());
454 ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
455 CHECK_NE(NULL, node4);
456 CHECK_EQ(entry1, node4->entry());
457}
458
459
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000460static void CheckNodeIds(ProfileNode* node, int* expectedId) {
461 CHECK_EQ((*expectedId)++, node->id());
462 for (int i = 0; i < node->children()->length(); i++) {
463 CheckNodeIds(node->children()->at(i), expectedId);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100464 }
465}
466
467
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468TEST(SampleIds) {
469 TestSetup test_setup;
470 CpuProfilesCollection profiles(CcTest::heap());
471 profiles.StartProfiling("", true);
472 ProfileGenerator generator(&profiles);
473 CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
474 CodeEntry* entry2 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
475 CodeEntry* entry3 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
476 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
477 generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
478 generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
479
480 // We are building the following calls tree:
481 // -> aaa #3 - sample1
482 // (root)#1 -> aaa #2 -> bbb #4 -> ccc #5 - sample2
483 // -> ccc #6 -> aaa #7 - sample3
484 TickSample sample1;
485 sample1.pc = ToAddress(0x1600);
486 sample1.stack[0] = ToAddress(0x1510);
487 sample1.frames_count = 1;
488 generator.RecordTickSample(sample1);
489 TickSample sample2;
490 sample2.pc = ToAddress(0x1925);
491 sample2.stack[0] = ToAddress(0x1780);
492 sample2.stack[1] = ToAddress(0x10000); // non-existent.
493 sample2.stack[2] = ToAddress(0x1620);
494 sample2.frames_count = 3;
495 generator.RecordTickSample(sample2);
496 TickSample sample3;
497 sample3.pc = ToAddress(0x1510);
498 sample3.stack[0] = ToAddress(0x1910);
499 sample3.stack[1] = ToAddress(0x1610);
500 sample3.frames_count = 2;
501 generator.RecordTickSample(sample3);
502
503 CpuProfile* profile = profiles.StopProfiling("");
504 int nodeId = 1;
505 CheckNodeIds(profile->top_down()->root(), &nodeId);
506 CHECK_EQ(7, nodeId - 1);
507
508 CHECK_EQ(3, profile->samples_count());
509 int expected_id[] = {3, 5, 7};
510 for (int i = 0; i < 3; i++) {
511 CHECK_EQ(expected_id[i], profile->sample(i)->id());
512 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100513}
514
515
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516TEST(NoSamples) {
517 TestSetup test_setup;
518 CpuProfilesCollection profiles(CcTest::heap());
519 profiles.StartProfiling("", false);
520 ProfileGenerator generator(&profiles);
521 CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
522 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
523
524 // We are building the following calls tree:
525 // (root)#1 -> aaa #2 -> aaa #3 - sample1
526 TickSample sample1;
527 sample1.pc = ToAddress(0x1600);
528 sample1.stack[0] = ToAddress(0x1510);
529 sample1.frames_count = 1;
530 generator.RecordTickSample(sample1);
531
532 CpuProfile* profile = profiles.StopProfiling("");
533 int nodeId = 1;
534 CheckNodeIds(profile->top_down()->root(), &nodeId);
535 CHECK_EQ(3, nodeId - 1);
536
537 CHECK_EQ(0, profile->samples_count());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100538}
539
540
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100541static const ProfileNode* PickChild(const ProfileNode* parent,
542 const char* name) {
543 for (int i = 0; i < parent->children()->length(); ++i) {
544 const ProfileNode* child = parent->children()->at(i);
545 if (strcmp(child->entry()->name(), name) == 0) return child;
546 }
547 return NULL;
548}
549
550
551TEST(RecordStackTraceAtStartProfiling) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100552 // This test does not pass with inlining enabled since inlined functions
553 // don't appear in the stack trace.
554 i::FLAG_use_inlining = false;
555
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556 v8::HandleScope scope(CcTest::isolate());
557 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
558 v8::Context::Scope context_scope(env);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100559
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
561 CHECK_EQ(0, profiler->GetProfilesCount());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100562 CompileRun(
563 "function c() { startProfiling(); }\n"
564 "function b() { c(); }\n"
565 "function a() { b(); }\n"
566 "a();\n"
567 "stopProfiling();");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000568 CHECK_EQ(1, profiler->GetProfilesCount());
569 CpuProfile* profile = profiler->GetProfile(0);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100570 const ProfileTree* topDown = profile->top_down();
571 const ProfileNode* current = topDown->root();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100572 const_cast<ProfileNode*>(current)->Print(0);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100573 // The tree should look like this:
574 // (root)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 // ""
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100576 // a
577 // b
578 // c
Ben Murdochb0fe1622011-05-05 13:52:32 +0100579 // There can also be:
580 // startProfiling
581 // if the sampler managed to get a tick.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 current = PickChild(current, "");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100583 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
584 current = PickChild(current, "a");
585 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
586 current = PickChild(current, "b");
587 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
588 current = PickChild(current, "c");
589 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100590 CHECK(current->children()->length() == 0 ||
591 current->children()->length() == 1);
592 if (current->children()->length() == 1) {
593 current = PickChild(current, "startProfiling");
594 CHECK_EQ(0, current->children()->length());
595 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100596}
597
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100598
599TEST(Issue51919) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 CpuProfilesCollection collection(CcTest::heap());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100601 i::EmbeddedVector<char*,
602 CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
603 for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
604 i::Vector<char> title = i::Vector<char>::New(16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 i::SNPrintF(title, "%d", i);
606 CHECK(collection.StartProfiling(title.start(), false));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100607 titles[i] = title.start();
608 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 CHECK(!collection.StartProfiling("maximum", false));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100610 for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
611 i::DeleteArray(titles[i]);
612}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613
614
615static const v8::CpuProfileNode* PickChild(const v8::CpuProfileNode* parent,
616 const char* name) {
617 for (int i = 0; i < parent->GetChildrenCount(); ++i) {
618 const v8::CpuProfileNode* child = parent->GetChild(i);
619 v8::String::Utf8Value function_name(child->GetFunctionName());
620 if (strcmp(*function_name, name) == 0) return child;
621 }
622 return NULL;
623}
624
625
626TEST(ProfileNodeScriptId) {
627 // This test does not pass with inlining enabled since inlined functions
628 // don't appear in the stack trace.
629 i::FLAG_use_inlining = false;
630
631 v8::HandleScope scope(CcTest::isolate());
632 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
633 v8::Context::Scope context_scope(env);
634
635 v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
636 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
637 CHECK_EQ(0, iprofiler->GetProfilesCount());
638 v8::Handle<v8::Script> script_a = v8::Script::Compile(v8::String::NewFromUtf8(
639 env->GetIsolate(), "function a() { startProfiling(); }\n"));
640 script_a->Run();
641 v8::Handle<v8::Script> script_b =
642 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
643 "function b() { a(); }\n"
644 "b();\n"
645 "stopProfiling();\n"));
646 script_b->Run();
647 CHECK_EQ(1, iprofiler->GetProfilesCount());
648 const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
649 const v8::CpuProfileNode* current = profile->GetTopDownRoot();
650 reinterpret_cast<ProfileNode*>(
651 const_cast<v8::CpuProfileNode*>(current))->Print(0);
652 // The tree should look like this:
653 // (root)
654 // ""
655 // b
656 // a
657 // There can also be:
658 // startProfiling
659 // if the sampler managed to get a tick.
660 current = PickChild(current, "");
661 CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
662
663 current = PickChild(current, "b");
664 CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
665 CHECK_EQ(script_b->GetUnboundScript()->GetId(), current->GetScriptId());
666
667 current = PickChild(current, "a");
668 CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
669 CHECK_EQ(script_a->GetUnboundScript()->GetId(), current->GetScriptId());
670}
671
672
673
674
675static const char* line_number_test_source_existing_functions =
676"function foo_at_the_first_line() {\n"
677"}\n"
678"foo_at_the_first_line();\n"
679"function lazy_func_at_forth_line() {}\n";
680
681
682static const char* line_number_test_source_profile_time_functions =
683"// Empty first line\n"
684"function bar_at_the_second_line() {\n"
685" foo_at_the_first_line();\n"
686"}\n"
687"bar_at_the_second_line();\n"
688"function lazy_func_at_6th_line() {}";
689
690int GetFunctionLineNumber(LocalContext* env, const char* name) {
691 CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
692 CodeMap* code_map = profiler->generator()->code_map();
693 i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
694 *v8::Local<v8::Function>::Cast(
695 (*(*env))->Global()->Get(v8_str(name))));
696 CodeEntry* func_entry = code_map->FindEntry(func->code()->address());
697 if (!func_entry)
698 FATAL(name);
699 return func_entry->line_number();
700}
701
702
703TEST(LineNumber) {
704 i::FLAG_use_inlining = false;
705
706 CcTest::InitializeVM();
707 LocalContext env;
708 i::Isolate* isolate = CcTest::i_isolate();
709 TestSetup test_setup;
710
711 i::HandleScope scope(isolate);
712
713 CompileRun(line_number_test_source_existing_functions);
714
715 CpuProfiler* profiler = isolate->cpu_profiler();
716 profiler->StartProfiling("LineNumber");
717
718 CompileRun(line_number_test_source_profile_time_functions);
719
720 profiler->processor()->StopSynchronously();
721
722 CHECK_EQ(1, GetFunctionLineNumber(&env, "foo_at_the_first_line"));
723 CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_forth_line"));
724 CHECK_EQ(2, GetFunctionLineNumber(&env, "bar_at_the_second_line"));
725 CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_6th_line"));
726
727 profiler->StopProfiling("LineNumber");
728}
729
730
731
732TEST(BailoutReason) {
733 v8::HandleScope scope(CcTest::isolate());
734 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
735 v8::Context::Scope context_scope(env);
736
737 v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
738 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
739 CHECK_EQ(0, iprofiler->GetProfilesCount());
740 v8::Handle<v8::Script> script =
741 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
742 "function TryCatch() {\n"
743 " try {\n"
744 " startProfiling();\n"
745 " } catch (e) { };\n"
746 "}\n"
747 "function TryFinally() {\n"
748 " try {\n"
749 " TryCatch();\n"
750 " } finally { };\n"
751 "}\n"
752 "TryFinally();\n"
753 "stopProfiling();"));
754 script->Run();
755 CHECK_EQ(1, iprofiler->GetProfilesCount());
756 const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
757 CHECK(profile);
758 const v8::CpuProfileNode* current = profile->GetTopDownRoot();
759 reinterpret_cast<ProfileNode*>(
760 const_cast<v8::CpuProfileNode*>(current))->Print(0);
761 // The tree should look like this:
762 // (root)
763 // ""
764 // kTryFinally
765 // kTryCatch
766 current = PickChild(current, "");
767 CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
768
769 current = PickChild(current, "TryFinally");
770 CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
771 CHECK(!strcmp("TryFinallyStatement", current->GetBailoutReason()));
772
773 current = PickChild(current, "TryCatch");
774 CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
775 CHECK(!strcmp("TryCatchStatement", current->GetBailoutReason()));
776}