blob: 56b1788a85132140bfeb0d7bea36479f0f0deb36 [file] [log] [blame]
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001// Copyright 2010 the V8 project authors. All rights reserved.
ulan@chromium.org750145a2013-03-07 15:14:13 +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.
fschneider@chromium.org086aac62010-03-17 13:18:24 +000027//
28// Tests of profiles generator and utilities.
29
30#include "v8.h"
31#include "profile-generator-inl.h"
32#include "cctest.h"
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000033#include "../include/v8-profiler.h"
fschneider@chromium.org086aac62010-03-17 13:18:24 +000034
fschneider@chromium.org086aac62010-03-17 13:18:24 +000035using i::CodeEntry;
36using i::CodeMap;
lrn@chromium.org25156de2010-04-06 13:10:27 +000037using i::CpuProfile;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000038using i::CpuProfiler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000039using i::CpuProfilesCollection;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000040using i::ProfileNode;
41using i::ProfileTree;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000042using i::ProfileGenerator;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000043using i::SampleRateCalculator;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000044using i::TickSample;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000045using i::TokenEnumerator;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000046using i::Vector;
47
48
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000049namespace v8 {
50namespace internal {
51
52class TokenEnumeratorTester {
53 public:
54 static i::List<bool>* token_removed(TokenEnumerator* te) {
55 return &te->token_removed_;
56 }
57};
58
59} } // namespace v8::internal
60
61TEST(TokenEnumerator) {
62 TokenEnumerator te;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000063 CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000064 v8::HandleScope hs(v8::Isolate::GetCurrent());
ricow@chromium.org55ee8072011-09-08 16:33:10 +000065 v8::Local<v8::String> token1(v8::String::New("1x"));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000066 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
67 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
ricow@chromium.org55ee8072011-09-08 16:33:10 +000068 v8::Local<v8::String> token2(v8::String::New("2x"));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000069 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
70 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
71 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
72 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000073 v8::HandleScope hs(v8::Isolate::GetCurrent());
ricow@chromium.org55ee8072011-09-08 16:33:10 +000074 v8::Local<v8::String> token3(v8::String::New("3x"));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000075 CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
76 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
77 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
78 }
79 CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000080 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000081 CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
82 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
83 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
84}
85
86
fschneider@chromium.org086aac62010-03-17 13:18:24 +000087TEST(ProfileNodeFindOrAddChild) {
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +000088 ProfileTree tree;
89 ProfileNode node(&tree, NULL);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000090 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
91 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000092 ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
93 CHECK_NE(NULL, childNode1);
94 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000095 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
96 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000097 ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
98 CHECK_NE(NULL, childNode2);
99 CHECK_NE(childNode1, childNode2);
100 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
101 CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000102 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
103 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000104 ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
105 CHECK_NE(NULL, childNode3);
106 CHECK_NE(childNode1, childNode3);
107 CHECK_NE(childNode2, childNode3);
108 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
109 CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
110 CHECK_EQ(childNode3, node.FindOrAddChild(&entry3));
111}
112
113
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000114TEST(ProfileNodeFindOrAddChildForSameFunction) {
115 const char* empty = "";
116 const char* aaa = "aaa";
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000117 ProfileTree tree;
118 ProfileNode node(&tree, NULL);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000119 CodeEntry entry1(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
120 TokenEnumerator::kNoSecurityToken);
121 ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
122 CHECK_NE(NULL, childNode1);
123 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
124 // The same function again.
125 CodeEntry entry2(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
126 TokenEnumerator::kNoSecurityToken);
127 CHECK_EQ(childNode1, node.FindOrAddChild(&entry2));
128 // Now with a different security token.
129 CodeEntry entry3(i::Logger::FUNCTION_TAG, empty, aaa, empty, 0,
130 TokenEnumerator::kNoSecurityToken + 1);
131 CHECK_EQ(childNode1, node.FindOrAddChild(&entry3));
132}
133
134
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000135namespace {
136
137class ProfileTreeTestHelper {
138 public:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000139 explicit ProfileTreeTestHelper(const ProfileTree* tree)
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000140 : tree_(tree) { }
141
142 ProfileNode* Walk(CodeEntry* entry1,
143 CodeEntry* entry2 = NULL,
144 CodeEntry* entry3 = NULL) {
145 ProfileNode* node = tree_->root();
146 node = node->FindChild(entry1);
147 if (node == NULL) return NULL;
148 if (entry2 != NULL) {
149 node = node->FindChild(entry2);
150 if (node == NULL) return NULL;
151 }
152 if (entry3 != NULL) {
153 node = node->FindChild(entry3);
154 }
155 return node;
156 }
157
158 private:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000159 const ProfileTree* tree_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000160};
161
162} // namespace
163
164TEST(ProfileTreeAddPathFromStart) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000165 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
166 TokenEnumerator::kNoSecurityToken);
167 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
168 TokenEnumerator::kNoSecurityToken);
169 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
170 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000171 ProfileTree tree;
172 ProfileTreeTestHelper helper(&tree);
173 CHECK_EQ(NULL, helper.Walk(&entry1));
174 CHECK_EQ(NULL, helper.Walk(&entry2));
175 CHECK_EQ(NULL, helper.Walk(&entry3));
176
177 CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
178 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
179 tree.AddPathFromStart(path_vec);
180 CHECK_EQ(NULL, helper.Walk(&entry2));
181 CHECK_EQ(NULL, helper.Walk(&entry3));
182 ProfileNode* node1 = helper.Walk(&entry1);
183 CHECK_NE(NULL, node1);
184 CHECK_EQ(0, node1->total_ticks());
185 CHECK_EQ(0, node1->self_ticks());
186 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
187 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
188 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
189 CHECK_NE(NULL, node2);
190 CHECK_NE(node1, node2);
191 CHECK_EQ(0, node2->total_ticks());
192 CHECK_EQ(0, node2->self_ticks());
193 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
194 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
195 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
196 CHECK_NE(NULL, node3);
197 CHECK_NE(node1, node3);
198 CHECK_NE(node2, node3);
199 CHECK_EQ(0, node3->total_ticks());
200 CHECK_EQ(1, node3->self_ticks());
201
202 tree.AddPathFromStart(path_vec);
203 CHECK_EQ(node1, helper.Walk(&entry1));
204 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
205 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
206 CHECK_EQ(0, node1->total_ticks());
207 CHECK_EQ(0, node1->self_ticks());
208 CHECK_EQ(0, node2->total_ticks());
209 CHECK_EQ(0, node2->self_ticks());
210 CHECK_EQ(0, node3->total_ticks());
211 CHECK_EQ(2, node3->self_ticks());
212
213 CodeEntry* path2[] = {&entry1, &entry2, &entry2};
214 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
215 tree.AddPathFromStart(path2_vec);
216 CHECK_EQ(NULL, helper.Walk(&entry2));
217 CHECK_EQ(NULL, helper.Walk(&entry3));
218 CHECK_EQ(node1, helper.Walk(&entry1));
219 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
220 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
221 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
222 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
223 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
224 CHECK_EQ(0, node3->total_ticks());
225 CHECK_EQ(2, node3->self_ticks());
226 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
227 CHECK_NE(NULL, node4);
228 CHECK_NE(node3, node4);
229 CHECK_EQ(0, node4->total_ticks());
230 CHECK_EQ(1, node4->self_ticks());
231}
232
233
234TEST(ProfileTreeAddPathFromEnd) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000235 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
236 TokenEnumerator::kNoSecurityToken);
237 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
238 TokenEnumerator::kNoSecurityToken);
239 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
240 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000241 ProfileTree tree;
242 ProfileTreeTestHelper helper(&tree);
243 CHECK_EQ(NULL, helper.Walk(&entry1));
244 CHECK_EQ(NULL, helper.Walk(&entry2));
245 CHECK_EQ(NULL, helper.Walk(&entry3));
246
247 CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
248 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
249 tree.AddPathFromEnd(path_vec);
250 CHECK_EQ(NULL, helper.Walk(&entry2));
251 CHECK_EQ(NULL, helper.Walk(&entry3));
252 ProfileNode* node1 = helper.Walk(&entry1);
253 CHECK_NE(NULL, node1);
254 CHECK_EQ(0, node1->total_ticks());
255 CHECK_EQ(0, node1->self_ticks());
256 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
257 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
258 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
259 CHECK_NE(NULL, node2);
260 CHECK_NE(node1, node2);
261 CHECK_EQ(0, node2->total_ticks());
262 CHECK_EQ(0, node2->self_ticks());
263 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
264 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
265 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
266 CHECK_NE(NULL, node3);
267 CHECK_NE(node1, node3);
268 CHECK_NE(node2, node3);
269 CHECK_EQ(0, node3->total_ticks());
270 CHECK_EQ(1, node3->self_ticks());
271
272 tree.AddPathFromEnd(path_vec);
273 CHECK_EQ(node1, helper.Walk(&entry1));
274 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
275 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
276 CHECK_EQ(0, node1->total_ticks());
277 CHECK_EQ(0, node1->self_ticks());
278 CHECK_EQ(0, node2->total_ticks());
279 CHECK_EQ(0, node2->self_ticks());
280 CHECK_EQ(0, node3->total_ticks());
281 CHECK_EQ(2, node3->self_ticks());
282
283 CodeEntry* path2[] = {&entry2, &entry2, &entry1};
284 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
285 tree.AddPathFromEnd(path2_vec);
286 CHECK_EQ(NULL, helper.Walk(&entry2));
287 CHECK_EQ(NULL, helper.Walk(&entry3));
288 CHECK_EQ(node1, helper.Walk(&entry1));
289 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
290 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
291 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
292 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
293 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
294 CHECK_EQ(0, node3->total_ticks());
295 CHECK_EQ(2, node3->self_ticks());
296 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
297 CHECK_NE(NULL, node4);
298 CHECK_NE(node3, node4);
299 CHECK_EQ(0, node4->total_ticks());
300 CHECK_EQ(1, node4->self_ticks());
301}
302
303
304TEST(ProfileTreeCalculateTotalTicks) {
305 ProfileTree empty_tree;
306 CHECK_EQ(0, empty_tree.root()->total_ticks());
307 CHECK_EQ(0, empty_tree.root()->self_ticks());
308 empty_tree.CalculateTotalTicks();
309 CHECK_EQ(0, empty_tree.root()->total_ticks());
310 CHECK_EQ(0, empty_tree.root()->self_ticks());
311 empty_tree.root()->IncrementSelfTicks();
312 CHECK_EQ(0, empty_tree.root()->total_ticks());
313 CHECK_EQ(1, empty_tree.root()->self_ticks());
314 empty_tree.CalculateTotalTicks();
315 CHECK_EQ(1, empty_tree.root()->total_ticks());
316 CHECK_EQ(1, empty_tree.root()->self_ticks());
317
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000318 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
319 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000320 CodeEntry* e1_path[] = {&entry1};
321 Vector<CodeEntry*> e1_path_vec(
322 e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000323
324 ProfileTree single_child_tree;
325 single_child_tree.AddPathFromStart(e1_path_vec);
326 single_child_tree.root()->IncrementSelfTicks();
327 CHECK_EQ(0, single_child_tree.root()->total_ticks());
328 CHECK_EQ(1, single_child_tree.root()->self_ticks());
329 ProfileTreeTestHelper single_child_helper(&single_child_tree);
330 ProfileNode* node1 = single_child_helper.Walk(&entry1);
331 CHECK_NE(NULL, node1);
332 CHECK_EQ(0, node1->total_ticks());
333 CHECK_EQ(1, node1->self_ticks());
334 single_child_tree.CalculateTotalTicks();
335 CHECK_EQ(2, single_child_tree.root()->total_ticks());
336 CHECK_EQ(1, single_child_tree.root()->self_ticks());
337 CHECK_EQ(1, node1->total_ticks());
338 CHECK_EQ(1, node1->self_ticks());
339
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000340 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
341 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000342 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
343 Vector<CodeEntry*> e1_e2_path_vec(
344 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
345
346 ProfileTree flat_tree;
347 ProfileTreeTestHelper flat_helper(&flat_tree);
348 flat_tree.AddPathFromStart(e1_path_vec);
349 flat_tree.AddPathFromStart(e1_path_vec);
350 flat_tree.AddPathFromStart(e1_e2_path_vec);
351 flat_tree.AddPathFromStart(e1_e2_path_vec);
352 flat_tree.AddPathFromStart(e1_e2_path_vec);
353 // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
354 CHECK_EQ(0, flat_tree.root()->total_ticks());
355 CHECK_EQ(0, flat_tree.root()->self_ticks());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000356 node1 = flat_helper.Walk(&entry1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000357 CHECK_NE(NULL, node1);
358 CHECK_EQ(0, node1->total_ticks());
359 CHECK_EQ(2, node1->self_ticks());
360 ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
361 CHECK_NE(NULL, node2);
362 CHECK_EQ(0, node2->total_ticks());
363 CHECK_EQ(3, node2->self_ticks());
364 flat_tree.CalculateTotalTicks();
365 // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
366 CHECK_EQ(5, flat_tree.root()->total_ticks());
367 CHECK_EQ(0, flat_tree.root()->self_ticks());
368 CHECK_EQ(5, node1->total_ticks());
369 CHECK_EQ(2, node1->self_ticks());
370 CHECK_EQ(3, node2->total_ticks());
371 CHECK_EQ(3, node2->self_ticks());
372
373 CodeEntry* e2_path[] = {&entry2};
374 Vector<CodeEntry*> e2_path_vec(
375 e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000376 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
377 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000378 CodeEntry* e3_path[] = {&entry3};
379 Vector<CodeEntry*> e3_path_vec(
380 e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
381
382 ProfileTree wide_tree;
383 ProfileTreeTestHelper wide_helper(&wide_tree);
384 wide_tree.AddPathFromStart(e1_path_vec);
385 wide_tree.AddPathFromStart(e1_path_vec);
386 wide_tree.AddPathFromStart(e1_e2_path_vec);
387 wide_tree.AddPathFromStart(e2_path_vec);
388 wide_tree.AddPathFromStart(e2_path_vec);
389 wide_tree.AddPathFromStart(e2_path_vec);
390 wide_tree.AddPathFromStart(e3_path_vec);
391 wide_tree.AddPathFromStart(e3_path_vec);
392 wide_tree.AddPathFromStart(e3_path_vec);
393 wide_tree.AddPathFromStart(e3_path_vec);
394 // Results in -> {entry1,0,2} -> {entry2,0,1}
395 // {root,0,0} -> {entry2,0,3}
396 // -> {entry3,0,4}
397 CHECK_EQ(0, wide_tree.root()->total_ticks());
398 CHECK_EQ(0, wide_tree.root()->self_ticks());
399 node1 = wide_helper.Walk(&entry1);
400 CHECK_NE(NULL, node1);
401 CHECK_EQ(0, node1->total_ticks());
402 CHECK_EQ(2, node1->self_ticks());
403 ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
404 CHECK_NE(NULL, node1_2);
405 CHECK_EQ(0, node1_2->total_ticks());
406 CHECK_EQ(1, node1_2->self_ticks());
407 node2 = wide_helper.Walk(&entry2);
408 CHECK_NE(NULL, node2);
409 CHECK_EQ(0, node2->total_ticks());
410 CHECK_EQ(3, node2->self_ticks());
411 ProfileNode* node3 = wide_helper.Walk(&entry3);
412 CHECK_NE(NULL, node3);
413 CHECK_EQ(0, node3->total_ticks());
414 CHECK_EQ(4, node3->self_ticks());
415 wide_tree.CalculateTotalTicks();
416 // Calculates -> {entry1,3,2} -> {entry2,1,1}
417 // {root,10,0} -> {entry2,3,3}
418 // -> {entry3,4,4}
419 CHECK_EQ(10, wide_tree.root()->total_ticks());
420 CHECK_EQ(0, wide_tree.root()->self_ticks());
421 CHECK_EQ(3, node1->total_ticks());
422 CHECK_EQ(2, node1->self_ticks());
423 CHECK_EQ(1, node1_2->total_ticks());
424 CHECK_EQ(1, node1_2->self_ticks());
425 CHECK_EQ(3, node2->total_ticks());
426 CHECK_EQ(3, node2->self_ticks());
427 CHECK_EQ(4, node3->total_ticks());
428 CHECK_EQ(4, node3->self_ticks());
429}
430
431
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000432TEST(ProfileTreeFilteredClone) {
433 ProfileTree source_tree;
434 const int token0 = 0, token1 = 1, token2 = 2;
435 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
436 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
437 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
438 CodeEntry entry4(
439 i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000440 TokenEnumerator::kInheritsSecurityToken);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000441
442 {
443 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
444 Vector<CodeEntry*> e1_e2_path_vec(
445 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
446 source_tree.AddPathFromStart(e1_e2_path_vec);
447 CodeEntry* e2_e4_path[] = {&entry2, &entry4};
448 Vector<CodeEntry*> e2_e4_path_vec(
449 e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
450 source_tree.AddPathFromStart(e2_e4_path_vec);
451 CodeEntry* e3_e1_path[] = {&entry3, &entry1};
452 Vector<CodeEntry*> e3_e1_path_vec(
453 e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
454 source_tree.AddPathFromStart(e3_e1_path_vec);
455 CodeEntry* e3_e2_path[] = {&entry3, &entry2};
456 Vector<CodeEntry*> e3_e2_path_vec(
457 e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
458 source_tree.AddPathFromStart(e3_e2_path_vec);
459 source_tree.CalculateTotalTicks();
460 // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
461 // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
462 // -> {entry3,0,2,0} -> {entry1,1,1,0}
463 // -> {entry2,1,1,1}
464 CHECK_EQ(4, source_tree.root()->total_ticks());
465 CHECK_EQ(0, source_tree.root()->self_ticks());
466 }
467
468 {
469 ProfileTree token0_tree;
470 token0_tree.FilteredClone(&source_tree, token0);
471 // Should be -> {entry1,1,1,0}
472 // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
473 // [self ticks from filtered nodes are attributed to their parents]
474 CHECK_EQ(4, token0_tree.root()->total_ticks());
475 CHECK_EQ(1, token0_tree.root()->self_ticks());
476 ProfileTreeTestHelper token0_helper(&token0_tree);
477 ProfileNode* node1 = token0_helper.Walk(&entry1);
478 CHECK_NE(NULL, node1);
479 CHECK_EQ(1, node1->total_ticks());
480 CHECK_EQ(1, node1->self_ticks());
481 CHECK_EQ(NULL, token0_helper.Walk(&entry2));
482 ProfileNode* node3 = token0_helper.Walk(&entry3);
483 CHECK_NE(NULL, node3);
484 CHECK_EQ(2, node3->total_ticks());
485 CHECK_EQ(1, node3->self_ticks());
486 ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
487 CHECK_NE(NULL, node3_1);
488 CHECK_EQ(1, node3_1->total_ticks());
489 CHECK_EQ(1, node3_1->self_ticks());
490 CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
491 }
492
493 {
494 ProfileTree token1_tree;
495 token1_tree.FilteredClone(&source_tree, token1);
496 // Should be
497 // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
498 // [child nodes referring to the same entry get merged and
499 // their self times summed up]
500 CHECK_EQ(4, token1_tree.root()->total_ticks());
501 CHECK_EQ(1, token1_tree.root()->self_ticks());
502 ProfileTreeTestHelper token1_helper(&token1_tree);
503 CHECK_EQ(NULL, token1_helper.Walk(&entry1));
504 CHECK_EQ(NULL, token1_helper.Walk(&entry3));
505 ProfileNode* node2 = token1_helper.Walk(&entry2);
506 CHECK_NE(NULL, node2);
507 CHECK_EQ(3, node2->total_ticks());
508 CHECK_EQ(2, node2->self_ticks());
509 ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
510 CHECK_NE(NULL, node2_4);
511 CHECK_EQ(1, node2_4->total_ticks());
512 CHECK_EQ(1, node2_4->self_ticks());
513 }
514
515 {
516 ProfileTree token2_tree;
517 token2_tree.FilteredClone(&source_tree, token2);
518 // Should be
519 // {root,4,4,-1}
520 // [no nodes, all ticks get migrated into root node]
521 CHECK_EQ(4, token2_tree.root()->total_ticks());
522 CHECK_EQ(4, token2_tree.root()->self_ticks());
523 ProfileTreeTestHelper token2_helper(&token2_tree);
524 CHECK_EQ(NULL, token2_helper.Walk(&entry1));
525 CHECK_EQ(NULL, token2_helper.Walk(&entry2));
526 CHECK_EQ(NULL, token2_helper.Walk(&entry3));
527 }
528}
529
530
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000531static inline i::Address ToAddress(int n) {
532 return reinterpret_cast<i::Address>(n);
533}
534
535TEST(CodeMapAddCode) {
536 CodeMap code_map;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000537 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
538 TokenEnumerator::kNoSecurityToken);
539 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
540 TokenEnumerator::kNoSecurityToken);
541 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
542 TokenEnumerator::kNoSecurityToken);
543 CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
544 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000545 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
546 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
547 code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
548 code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
549 CHECK_EQ(NULL, code_map.FindEntry(0));
550 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
551 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
552 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
553 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
554 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
555 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
556 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
557 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
558 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
559 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
560 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
561 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
562 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
563 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
564 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
565 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
566}
567
568
569TEST(CodeMapMoveAndDeleteCode) {
570 CodeMap code_map;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000571 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
572 TokenEnumerator::kNoSecurityToken);
573 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
574 TokenEnumerator::kNoSecurityToken);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000575 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
576 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
577 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
578 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000579 code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700)); // Deprecate bbb.
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000580 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000581 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
582 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
583 TokenEnumerator::kNoSecurityToken);
584 code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000585 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000586 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000587}
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000588
589
ager@chromium.org357bf652010-04-12 11:30:10 +0000590namespace {
591
592class TestSetup {
593 public:
594 TestSetup()
595 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
596 i::FLAG_prof_browser_mode = false;
597 }
598
599 ~TestSetup() {
600 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
601 }
602
603 private:
604 bool old_flag_prof_browser_mode_;
605};
606
607} // namespace
608
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000609TEST(RecordTickSample) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000610 TestSetup test_setup;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000611 CpuProfilesCollection profiles;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000612 profiles.StartProfiling("", 1, false);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000613 ProfileGenerator generator(&profiles);
614 CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
615 CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
616 CodeEntry* entry3 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
617 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
618 generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
619 generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
620
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000621 // We are building the following calls tree:
622 // -> aaa - sample1
623 // aaa -> bbb -> ccc - sample2
624 // -> ccc -> aaa - sample3
625 TickSample sample1;
626 sample1.pc = ToAddress(0x1600);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000627 sample1.tos = ToAddress(0x1500);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000628 sample1.stack[0] = ToAddress(0x1510);
629 sample1.frames_count = 1;
630 generator.RecordTickSample(sample1);
631 TickSample sample2;
632 sample2.pc = ToAddress(0x1925);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000633 sample2.tos = ToAddress(0x1900);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000634 sample2.stack[0] = ToAddress(0x1780);
635 sample2.stack[1] = ToAddress(0x10000); // non-existent.
636 sample2.stack[2] = ToAddress(0x1620);
637 sample2.frames_count = 3;
638 generator.RecordTickSample(sample2);
639 TickSample sample3;
640 sample3.pc = ToAddress(0x1510);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000641 sample3.tos = ToAddress(0x1500);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000642 sample3.stack[0] = ToAddress(0x1910);
643 sample3.stack[1] = ToAddress(0x1610);
644 sample3.frames_count = 2;
645 generator.RecordTickSample(sample3);
646
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000647 CpuProfile* profile =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000648 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000649 CHECK_NE(NULL, profile);
650 ProfileTreeTestHelper top_down_test_helper(profile->top_down());
651 CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
652 CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000653 ProfileNode* node1 = top_down_test_helper.Walk(entry1);
654 CHECK_NE(NULL, node1);
655 CHECK_EQ(entry1, node1->entry());
656 ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
657 CHECK_NE(NULL, node2);
658 CHECK_EQ(entry1, node2->entry());
659 ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
660 CHECK_NE(NULL, node3);
661 CHECK_EQ(entry3, node3->entry());
662 ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
663 CHECK_NE(NULL, node4);
664 CHECK_EQ(entry1, node4->entry());
665}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000666
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000667
668TEST(SampleRateCalculator) {
669 const double kSamplingIntervalMs = i::Logger::kSamplingIntervalMs;
670
671 // Verify that ticking exactly in query intervals results in the
672 // initial sampling interval.
673 double time = 0.0;
674 SampleRateCalculator calc1;
675 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
676 calc1.UpdateMeasurements(time);
677 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
678 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
679 calc1.UpdateMeasurements(time);
680 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
681 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
682 calc1.UpdateMeasurements(time);
683 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
684 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
685 calc1.UpdateMeasurements(time);
686 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
687
688 SampleRateCalculator calc2;
689 time = 0.0;
690 CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
691 calc2.UpdateMeasurements(time);
692 CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
693 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.5;
694 calc2.UpdateMeasurements(time);
695 // (1.0 + 2.0) / 2
696 CHECK_EQ(kSamplingIntervalMs * 1.5, calc2.ticks_per_ms());
697 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.75;
698 calc2.UpdateMeasurements(time);
699 // (1.0 + 2.0 + 2.0) / 3
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000700 CHECK_EQ(kSamplingIntervalMs * 5.0, floor(calc2.ticks_per_ms() * 3.0 + 0.5));
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000701
702 SampleRateCalculator calc3;
703 time = 0.0;
704 CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
705 calc3.UpdateMeasurements(time);
706 CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
707 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 2;
708 calc3.UpdateMeasurements(time);
709 // (1.0 + 0.5) / 2
710 CHECK_EQ(kSamplingIntervalMs * 0.75, calc3.ticks_per_ms());
711 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 1.5;
712 calc3.UpdateMeasurements(time);
713 // (1.0 + 0.5 + 0.5) / 3
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000714 CHECK_EQ(kSamplingIntervalMs * 2.0, floor(calc3.ticks_per_ms() * 3.0 + 0.5));
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000715}
716
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000717
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000718static void CheckNodeIds(ProfileNode* node, int* expectedId) {
719 CHECK_EQ((*expectedId)++, node->id());
720 for (int i = 0; i < node->children()->length(); i++) {
721 CheckNodeIds(node->children()->at(i), expectedId);
722 }
723}
724
725TEST(SampleIds) {
726 TestSetup test_setup;
727 CpuProfilesCollection profiles;
728 profiles.StartProfiling("", 1, true);
729 ProfileGenerator generator(&profiles);
730 CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
731 CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
732 CodeEntry* entry3 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
733 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
734 generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
735 generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
736
737 // We are building the following calls tree:
738 // -> aaa #3 - sample1
739 // (root)#1 -> aaa #2 -> bbb #4 -> ccc #5 - sample2
740 // -> ccc #6 -> aaa #7 - sample3
741 TickSample sample1;
742 sample1.pc = ToAddress(0x1600);
743 sample1.stack[0] = ToAddress(0x1510);
744 sample1.frames_count = 1;
745 generator.RecordTickSample(sample1);
746 TickSample sample2;
747 sample2.pc = ToAddress(0x1925);
748 sample2.stack[0] = ToAddress(0x1780);
749 sample2.stack[1] = ToAddress(0x10000); // non-existent.
750 sample2.stack[2] = ToAddress(0x1620);
751 sample2.frames_count = 3;
752 generator.RecordTickSample(sample2);
753 TickSample sample3;
754 sample3.pc = ToAddress(0x1510);
755 sample3.stack[0] = ToAddress(0x1910);
756 sample3.stack[1] = ToAddress(0x1610);
757 sample3.frames_count = 2;
758 generator.RecordTickSample(sample3);
759
760 CpuProfile* profile =
761 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
762 int nodeId = 1;
763 CheckNodeIds(profile->top_down()->root(), &nodeId);
764 CHECK_EQ(7, nodeId - 1);
765
766 CHECK_EQ(3, profile->samples_count());
767 int expected_id[] = {3, 5, 7};
768 for (int i = 0; i < 3; i++) {
769 CHECK_EQ(expected_id[i], profile->sample(i)->id());
770 }
771}
772
773
774TEST(NoSamples) {
775 TestSetup test_setup;
776 CpuProfilesCollection profiles;
777 profiles.StartProfiling("", 1, false);
778 ProfileGenerator generator(&profiles);
779 CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
780 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
781
782 // We are building the following calls tree:
783 // (root)#1 -> aaa #2 -> aaa #3 - sample1
784 TickSample sample1;
785 sample1.pc = ToAddress(0x1600);
786 sample1.stack[0] = ToAddress(0x1510);
787 sample1.frames_count = 1;
788 generator.RecordTickSample(sample1);
789
790 CpuProfile* profile =
791 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
792 int nodeId = 1;
793 CheckNodeIds(profile->top_down()->root(), &nodeId);
794 CHECK_EQ(3, nodeId - 1);
795
796 CHECK_EQ(0, profile->samples_count());
797}
798
799
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000800// --- P r o f i l e r E x t e n s i o n ---
801
802class ProfilerExtension : public v8::Extension {
803 public:
804 ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
805 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
806 v8::Handle<v8::String> name);
807 static v8::Handle<v8::Value> StartProfiling(const v8::Arguments& args);
808 static v8::Handle<v8::Value> StopProfiling(const v8::Arguments& args);
809 private:
810 static const char* kSource;
811};
812
813
814const char* ProfilerExtension::kSource =
815 "native function startProfiling();"
816 "native function stopProfiling();";
817
818v8::Handle<v8::FunctionTemplate> ProfilerExtension::GetNativeFunction(
819 v8::Handle<v8::String> name) {
820 if (name->Equals(v8::String::New("startProfiling"))) {
821 return v8::FunctionTemplate::New(ProfilerExtension::StartProfiling);
822 } else if (name->Equals(v8::String::New("stopProfiling"))) {
823 return v8::FunctionTemplate::New(ProfilerExtension::StopProfiling);
824 } else {
825 CHECK(false);
826 return v8::Handle<v8::FunctionTemplate>();
827 }
828}
829
830
831v8::Handle<v8::Value> ProfilerExtension::StartProfiling(
832 const v8::Arguments& args) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000833 v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler();
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000834 if (args.Length() > 0)
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000835 cpu_profiler->StartCpuProfiling(args[0].As<v8::String>());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000836 else
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000837 cpu_profiler->StartCpuProfiling(v8::String::New(""));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000838 return v8::Undefined();
839}
840
841
842v8::Handle<v8::Value> ProfilerExtension::StopProfiling(
843 const v8::Arguments& args) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000844 v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler();
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000845 if (args.Length() > 0)
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000846 cpu_profiler->StopCpuProfiling(args[0].As<v8::String>());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000847 else
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000848 cpu_profiler->StopCpuProfiling(v8::String::New(""));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000849 return v8::Undefined();
850}
851
852
853static ProfilerExtension kProfilerExtension;
854v8::DeclareExtension kProfilerExtensionDeclaration(&kProfilerExtension);
855static v8::Persistent<v8::Context> env;
856
857static const ProfileNode* PickChild(const ProfileNode* parent,
858 const char* name) {
859 for (int i = 0; i < parent->children()->length(); ++i) {
860 const ProfileNode* child = parent->children()->at(i);
861 if (strcmp(child->entry()->name(), name) == 0) return child;
862 }
863 return NULL;
864}
865
866
867TEST(RecordStackTraceAtStartProfiling) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000868 // This test does not pass with inlining enabled since inlined functions
869 // don't appear in the stack trace.
870 i::FLAG_use_inlining = false;
871
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000872 if (env.IsEmpty()) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000873 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000874 const char* extensions[] = { "v8/profiler" };
875 v8::ExtensionConfiguration config(1, extensions);
876 env = v8::Context::New(&config);
877 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000878 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000879 env->Enter();
880
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000881 CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
882 CHECK_EQ(0, profiler->GetProfilesCount());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000883 CompileRun(
884 "function c() { startProfiling(); }\n"
885 "function b() { c(); }\n"
886 "function a() { b(); }\n"
887 "a();\n"
888 "stopProfiling();");
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000889 CHECK_EQ(1, profiler->GetProfilesCount());
890 CpuProfile* profile = profiler->GetProfile(NULL, 0);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000891 const ProfileTree* topDown = profile->top_down();
892 const ProfileNode* current = topDown->root();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000893 const_cast<ProfileNode*>(current)->Print(0);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000894 // The tree should look like this:
895 // (root)
896 // (anonymous function)
897 // a
898 // b
899 // c
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000900 // There can also be:
901 // startProfiling
902 // if the sampler managed to get a tick.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000903 current = PickChild(current, "(anonymous function)");
904 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
905 current = PickChild(current, "a");
906 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
907 current = PickChild(current, "b");
908 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
909 current = PickChild(current, "c");
910 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000911 CHECK(current->children()->length() == 0 ||
912 current->children()->length() == 1);
913 if (current->children()->length() == 1) {
914 current = PickChild(current, "startProfiling");
915 CHECK_EQ(0, current->children()->length());
916 }
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000917}
918
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000919
920TEST(Issue51919) {
921 CpuProfilesCollection collection;
922 i::EmbeddedVector<char*,
923 CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
924 for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
925 i::Vector<char> title = i::Vector<char>::New(16);
926 i::OS::SNPrintF(title, "%d", i);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000927 // UID must be > 0.
928 CHECK(collection.StartProfiling(title.start(), i + 1, false));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000929 titles[i] = title.start();
930 }
931 CHECK(!collection.StartProfiling(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000932 "maximum", CpuProfilesCollection::kMaxSimultaneousProfiles + 1, false));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000933 for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
934 i::DeleteArray(titles[i]);
935}