The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-profile-generator.cc @ f230a1cf

History | View | Annotate | Download (29.4 KB)

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 "v8.h"
31
#include "profile-generator-inl.h"
32
#include "cctest.h"
33
#include "cpu-profiler.h"
34
#include "../include/v8-profiler.h"
35

    
36
using i::CodeEntry;
37
using i::CodeMap;
38
using i::CpuProfile;
39
using i::CpuProfiler;
40
using i::CpuProfilesCollection;
41
using i::ProfileNode;
42
using i::ProfileTree;
43
using i::ProfileGenerator;
44
using i::TickSample;
45
using i::Vector;
46

    
47

    
48
TEST(ProfileNodeFindOrAddChild) {
49
  ProfileTree tree;
50
  ProfileNode node(&tree, NULL);
51
  CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
52
  ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
53
  CHECK_NE(NULL, childNode1);
54
  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
55
  CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
56
  ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
57
  CHECK_NE(NULL, childNode2);
58
  CHECK_NE(childNode1, childNode2);
59
  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
60
  CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
61
  CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
62
  ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
63
  CHECK_NE(NULL, childNode3);
64
  CHECK_NE(childNode1, childNode3);
65
  CHECK_NE(childNode2, childNode3);
66
  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
67
  CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
68
  CHECK_EQ(childNode3, node.FindOrAddChild(&entry3));
69
}
70

    
71

    
72
TEST(ProfileNodeFindOrAddChildForSameFunction) {
73
  const char* aaa = "aaa";
74
  ProfileTree tree;
75
  ProfileNode node(&tree, NULL);
76
  CodeEntry entry1(i::Logger::FUNCTION_TAG, aaa);
77
  ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
78
  CHECK_NE(NULL, childNode1);
79
  CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
80
  // The same function again.
81
  CodeEntry entry2(i::Logger::FUNCTION_TAG, aaa);
82
  CHECK_EQ(childNode1, node.FindOrAddChild(&entry2));
83
  // Now with a different security token.
84
  CodeEntry entry3(i::Logger::FUNCTION_TAG, aaa);
85
  CHECK_EQ(childNode1, node.FindOrAddChild(&entry3));
86
}
87

    
88

    
89
namespace {
90

    
91
class ProfileTreeTestHelper {
92
 public:
93
  explicit ProfileTreeTestHelper(const ProfileTree* tree)
94
      : tree_(tree) { }
95

    
96
  ProfileNode* Walk(CodeEntry* entry1,
97
                    CodeEntry* entry2 = NULL,
98
                    CodeEntry* entry3 = NULL) {
99
    ProfileNode* node = tree_->root();
100
    node = node->FindChild(entry1);
101
    if (node == NULL) return NULL;
102
    if (entry2 != NULL) {
103
      node = node->FindChild(entry2);
104
      if (node == NULL) return NULL;
105
    }
106
    if (entry3 != NULL) {
107
      node = node->FindChild(entry3);
108
    }
109
    return node;
110
  }
111

    
112
 private:
113
  const ProfileTree* tree_;
114
};
115

    
116
}  // namespace
117

    
118
TEST(ProfileTreeAddPathFromStart) {
119
  CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
120
  CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
121
  CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
122
  ProfileTree tree;
123
  ProfileTreeTestHelper helper(&tree);
124
  CHECK_EQ(NULL, helper.Walk(&entry1));
125
  CHECK_EQ(NULL, helper.Walk(&entry2));
126
  CHECK_EQ(NULL, helper.Walk(&entry3));
127

    
128
  CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
129
  Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
130
  tree.AddPathFromStart(path_vec);
131
  CHECK_EQ(NULL, helper.Walk(&entry2));
132
  CHECK_EQ(NULL, helper.Walk(&entry3));
133
  ProfileNode* node1 = helper.Walk(&entry1);
134
  CHECK_NE(NULL, node1);
135
  CHECK_EQ(0, node1->self_ticks());
136
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
137
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
138
  ProfileNode* node2 = helper.Walk(&entry1, &entry2);
139
  CHECK_NE(NULL, node2);
140
  CHECK_NE(node1, node2);
141
  CHECK_EQ(0, node2->self_ticks());
142
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
143
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
144
  ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
145
  CHECK_NE(NULL, node3);
146
  CHECK_NE(node1, node3);
147
  CHECK_NE(node2, node3);
148
  CHECK_EQ(1, node3->self_ticks());
149

    
150
  tree.AddPathFromStart(path_vec);
151
  CHECK_EQ(node1, helper.Walk(&entry1));
152
  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
153
  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
154
  CHECK_EQ(0, node1->self_ticks());
155
  CHECK_EQ(0, node2->self_ticks());
156
  CHECK_EQ(2, node3->self_ticks());
157

    
158
  CodeEntry* path2[] = {&entry1, &entry2, &entry2};
159
  Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
160
  tree.AddPathFromStart(path2_vec);
161
  CHECK_EQ(NULL, helper.Walk(&entry2));
162
  CHECK_EQ(NULL, helper.Walk(&entry3));
163
  CHECK_EQ(node1, helper.Walk(&entry1));
164
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
165
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
166
  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
167
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
168
  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
169
  CHECK_EQ(2, node3->self_ticks());
170
  ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
171
  CHECK_NE(NULL, node4);
172
  CHECK_NE(node3, node4);
173
  CHECK_EQ(1, node4->self_ticks());
174
}
175

    
176

    
177
TEST(ProfileTreeAddPathFromEnd) {
178
  CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
179
  CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
180
  CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
181
  ProfileTree tree;
182
  ProfileTreeTestHelper helper(&tree);
183
  CHECK_EQ(NULL, helper.Walk(&entry1));
184
  CHECK_EQ(NULL, helper.Walk(&entry2));
185
  CHECK_EQ(NULL, helper.Walk(&entry3));
186

    
187
  CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
188
  Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
189
  tree.AddPathFromEnd(path_vec);
190
  CHECK_EQ(NULL, helper.Walk(&entry2));
191
  CHECK_EQ(NULL, helper.Walk(&entry3));
192
  ProfileNode* node1 = helper.Walk(&entry1);
193
  CHECK_NE(NULL, node1);
194
  CHECK_EQ(0, node1->self_ticks());
195
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
196
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
197
  ProfileNode* node2 = helper.Walk(&entry1, &entry2);
198
  CHECK_NE(NULL, node2);
199
  CHECK_NE(node1, node2);
200
  CHECK_EQ(0, node2->self_ticks());
201
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
202
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
203
  ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
204
  CHECK_NE(NULL, node3);
205
  CHECK_NE(node1, node3);
206
  CHECK_NE(node2, node3);
207
  CHECK_EQ(1, node3->self_ticks());
208

    
209
  tree.AddPathFromEnd(path_vec);
210
  CHECK_EQ(node1, helper.Walk(&entry1));
211
  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
212
  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
213
  CHECK_EQ(0, node1->self_ticks());
214
  CHECK_EQ(0, node2->self_ticks());
215
  CHECK_EQ(2, node3->self_ticks());
216

    
217
  CodeEntry* path2[] = {&entry2, &entry2, &entry1};
218
  Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
219
  tree.AddPathFromEnd(path2_vec);
220
  CHECK_EQ(NULL, helper.Walk(&entry2));
221
  CHECK_EQ(NULL, helper.Walk(&entry3));
222
  CHECK_EQ(node1, helper.Walk(&entry1));
223
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
224
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
225
  CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
226
  CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
227
  CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
228
  CHECK_EQ(2, node3->self_ticks());
229
  ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
230
  CHECK_NE(NULL, node4);
231
  CHECK_NE(node3, node4);
232
  CHECK_EQ(1, node4->self_ticks());
233
}
234

    
235

    
236
TEST(ProfileTreeCalculateTotalTicks) {
237
  ProfileTree empty_tree;
238
  CHECK_EQ(0, empty_tree.root()->self_ticks());
239
  empty_tree.root()->IncrementSelfTicks();
240
  CHECK_EQ(1, empty_tree.root()->self_ticks());
241

    
242
  CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
243
  CodeEntry* e1_path[] = {&entry1};
244
  Vector<CodeEntry*> e1_path_vec(
245
      e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
246

    
247
  ProfileTree single_child_tree;
248
  single_child_tree.AddPathFromStart(e1_path_vec);
249
  single_child_tree.root()->IncrementSelfTicks();
250
  CHECK_EQ(1, single_child_tree.root()->self_ticks());
251
  ProfileTreeTestHelper single_child_helper(&single_child_tree);
252
  ProfileNode* node1 = single_child_helper.Walk(&entry1);
253
  CHECK_NE(NULL, node1);
254
  CHECK_EQ(1, single_child_tree.root()->self_ticks());
255
  CHECK_EQ(1, node1->self_ticks());
256

    
257
  CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
258
  CodeEntry* e1_e2_path[] = {&entry1, &entry2};
259
  Vector<CodeEntry*> e1_e2_path_vec(
260
      e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
261

    
262
  ProfileTree flat_tree;
263
  ProfileTreeTestHelper flat_helper(&flat_tree);
264
  flat_tree.AddPathFromStart(e1_path_vec);
265
  flat_tree.AddPathFromStart(e1_path_vec);
266
  flat_tree.AddPathFromStart(e1_e2_path_vec);
267
  flat_tree.AddPathFromStart(e1_e2_path_vec);
268
  flat_tree.AddPathFromStart(e1_e2_path_vec);
269
  // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
270
  CHECK_EQ(0, flat_tree.root()->self_ticks());
271
  node1 = flat_helper.Walk(&entry1);
272
  CHECK_NE(NULL, node1);
273
  CHECK_EQ(2, node1->self_ticks());
274
  ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
275
  CHECK_NE(NULL, node2);
276
  CHECK_EQ(3, node2->self_ticks());
277
  // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
278
  CHECK_EQ(0, flat_tree.root()->self_ticks());
279
  CHECK_EQ(2, node1->self_ticks());
280

    
281
  CodeEntry* e2_path[] = {&entry2};
282
  Vector<CodeEntry*> e2_path_vec(
283
      e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
284
  CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
285
  CodeEntry* e3_path[] = {&entry3};
286
  Vector<CodeEntry*> e3_path_vec(
287
      e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
288

    
289
  ProfileTree wide_tree;
290
  ProfileTreeTestHelper wide_helper(&wide_tree);
291
  wide_tree.AddPathFromStart(e1_path_vec);
292
  wide_tree.AddPathFromStart(e1_path_vec);
293
  wide_tree.AddPathFromStart(e1_e2_path_vec);
294
  wide_tree.AddPathFromStart(e2_path_vec);
295
  wide_tree.AddPathFromStart(e2_path_vec);
296
  wide_tree.AddPathFromStart(e2_path_vec);
297
  wide_tree.AddPathFromStart(e3_path_vec);
298
  wide_tree.AddPathFromStart(e3_path_vec);
299
  wide_tree.AddPathFromStart(e3_path_vec);
300
  wide_tree.AddPathFromStart(e3_path_vec);
301
  // Results in            -> {entry1,0,2} -> {entry2,0,1}
302
  //            {root,0,0} -> {entry2,0,3}
303
  //                       -> {entry3,0,4}
304
  CHECK_EQ(0, wide_tree.root()->self_ticks());
305
  node1 = wide_helper.Walk(&entry1);
306
  CHECK_NE(NULL, node1);
307
  CHECK_EQ(2, node1->self_ticks());
308
  ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
309
  CHECK_NE(NULL, node1_2);
310
  CHECK_EQ(1, node1_2->self_ticks());
311
  node2 = wide_helper.Walk(&entry2);
312
  CHECK_NE(NULL, node2);
313
  CHECK_EQ(3, node2->self_ticks());
314
  ProfileNode* node3 = wide_helper.Walk(&entry3);
315
  CHECK_NE(NULL, node3);
316
  CHECK_EQ(4, node3->self_ticks());
317
  // Calculates             -> {entry1,3,2} -> {entry2,1,1}
318
  //            {root,10,0} -> {entry2,3,3}
319
  //                        -> {entry3,4,4}
320
  CHECK_EQ(0, wide_tree.root()->self_ticks());
321
  CHECK_EQ(2, node1->self_ticks());
322
  CHECK_EQ(1, node1_2->self_ticks());
323
  CHECK_EQ(3, node2->self_ticks());
324
  CHECK_EQ(4, node3->self_ticks());
325
}
326

    
327

    
328
static inline i::Address ToAddress(int n) {
329
  return reinterpret_cast<i::Address>(n);
330
}
331

    
332

    
333
TEST(CodeMapAddCode) {
334
  CodeMap code_map;
335
  CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
336
  CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
337
  CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
338
  CodeEntry entry4(i::Logger::FUNCTION_TAG, "ddd");
339
  code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
340
  code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
341
  code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
342
  code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
343
  CHECK_EQ(NULL, code_map.FindEntry(0));
344
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
345
  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
346
  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
347
  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
348
  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
349
  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
350
  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
351
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
352
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
353
  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
354
  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
355
  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
356
  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
357
  CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
358
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
359
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
360
}
361

    
362

    
363
TEST(CodeMapMoveAndDeleteCode) {
364
  CodeMap code_map;
365
  CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
366
  CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb");
367
  code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
368
  code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
369
  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
370
  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
371
  code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700));  // Deprecate bbb.
372
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
373
  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
374
  CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
375
  code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
376
  CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
377
  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
378
}
379

    
380

    
381
namespace {
382

    
383
class TestSetup {
384
 public:
385
  TestSetup()
386
      : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
387
    i::FLAG_prof_browser_mode = false;
388
  }
389

    
390
  ~TestSetup() {
391
    i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
392
  }
393

    
394
 private:
395
  bool old_flag_prof_browser_mode_;
396
};
397

    
398
}  // namespace
399

    
400
TEST(RecordTickSample) {
401
  TestSetup test_setup;
402
  CpuProfilesCollection profiles(CcTest::heap());
403
  profiles.StartProfiling("", 1, false);
404
  ProfileGenerator generator(&profiles);
405
  CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
406
  CodeEntry* entry2 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
407
  CodeEntry* entry3 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
408
  generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
409
  generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
410
  generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
411

    
412
  // We are building the following calls tree:
413
  //      -> aaa         - sample1
414
  //  aaa -> bbb -> ccc  - sample2
415
  //      -> ccc -> aaa  - sample3
416
  TickSample sample1;
417
  sample1.pc = ToAddress(0x1600);
418
  sample1.tos = ToAddress(0x1500);
419
  sample1.stack[0] = ToAddress(0x1510);
420
  sample1.frames_count = 1;
421
  generator.RecordTickSample(sample1);
422
  TickSample sample2;
423
  sample2.pc = ToAddress(0x1925);
424
  sample2.tos = ToAddress(0x1900);
425
  sample2.stack[0] = ToAddress(0x1780);
426
  sample2.stack[1] = ToAddress(0x10000);  // non-existent.
427
  sample2.stack[2] = ToAddress(0x1620);
428
  sample2.frames_count = 3;
429
  generator.RecordTickSample(sample2);
430
  TickSample sample3;
431
  sample3.pc = ToAddress(0x1510);
432
  sample3.tos = ToAddress(0x1500);
433
  sample3.stack[0] = ToAddress(0x1910);
434
  sample3.stack[1] = ToAddress(0x1610);
435
  sample3.frames_count = 2;
436
  generator.RecordTickSample(sample3);
437

    
438
  CpuProfile* profile = profiles.StopProfiling("");
439
  CHECK_NE(NULL, profile);
440
  ProfileTreeTestHelper top_down_test_helper(profile->top_down());
441
  CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
442
  CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
443
  ProfileNode* node1 = top_down_test_helper.Walk(entry1);
444
  CHECK_NE(NULL, node1);
445
  CHECK_EQ(entry1, node1->entry());
446
  ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
447
  CHECK_NE(NULL, node2);
448
  CHECK_EQ(entry1, node2->entry());
449
  ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
450
  CHECK_NE(NULL, node3);
451
  CHECK_EQ(entry3, node3->entry());
452
  ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
453
  CHECK_NE(NULL, node4);
454
  CHECK_EQ(entry1, node4->entry());
455
}
456

    
457

    
458
static void CheckNodeIds(ProfileNode* node, int* expectedId) {
459
  CHECK_EQ((*expectedId)++, node->id());
460
  for (int i = 0; i < node->children()->length(); i++) {
461
    CheckNodeIds(node->children()->at(i), expectedId);
462
  }
463
}
464

    
465

    
466
TEST(SampleIds) {
467
  TestSetup test_setup;
468
  CpuProfilesCollection profiles(CcTest::heap());
469
  profiles.StartProfiling("", 1, true);
470
  ProfileGenerator generator(&profiles);
471
  CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
472
  CodeEntry* entry2 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
473
  CodeEntry* entry3 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
474
  generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
475
  generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
476
  generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
477

    
478
  // We are building the following calls tree:
479
  //                    -> aaa #3           - sample1
480
  // (root)#1 -> aaa #2 -> bbb #4 -> ccc #5 - sample2
481
  //                    -> ccc #6 -> aaa #7 - sample3
482
  TickSample sample1;
483
  sample1.pc = ToAddress(0x1600);
484
  sample1.stack[0] = ToAddress(0x1510);
485
  sample1.frames_count = 1;
486
  generator.RecordTickSample(sample1);
487
  TickSample sample2;
488
  sample2.pc = ToAddress(0x1925);
489
  sample2.stack[0] = ToAddress(0x1780);
490
  sample2.stack[1] = ToAddress(0x10000);  // non-existent.
491
  sample2.stack[2] = ToAddress(0x1620);
492
  sample2.frames_count = 3;
493
  generator.RecordTickSample(sample2);
494
  TickSample sample3;
495
  sample3.pc = ToAddress(0x1510);
496
  sample3.stack[0] = ToAddress(0x1910);
497
  sample3.stack[1] = ToAddress(0x1610);
498
  sample3.frames_count = 2;
499
  generator.RecordTickSample(sample3);
500

    
501
  CpuProfile* profile = profiles.StopProfiling("");
502
  int nodeId = 1;
503
  CheckNodeIds(profile->top_down()->root(), &nodeId);
504
  CHECK_EQ(7, nodeId - 1);
505

    
506
  CHECK_EQ(3, profile->samples_count());
507
  int expected_id[] = {3, 5, 7};
508
  for (int i = 0; i < 3; i++) {
509
    CHECK_EQ(expected_id[i], profile->sample(i)->id());
510
  }
511
}
512

    
513

    
514
TEST(NoSamples) {
515
  TestSetup test_setup;
516
  CpuProfilesCollection profiles(CcTest::heap());
517
  profiles.StartProfiling("", 1, false);
518
  ProfileGenerator generator(&profiles);
519
  CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
520
  generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
521

    
522
  // We are building the following calls tree:
523
  // (root)#1 -> aaa #2 -> aaa #3 - sample1
524
  TickSample sample1;
525
  sample1.pc = ToAddress(0x1600);
526
  sample1.stack[0] = ToAddress(0x1510);
527
  sample1.frames_count = 1;
528
  generator.RecordTickSample(sample1);
529

    
530
  CpuProfile* profile = profiles.StopProfiling("");
531
  int nodeId = 1;
532
  CheckNodeIds(profile->top_down()->root(), &nodeId);
533
  CHECK_EQ(3, nodeId - 1);
534

    
535
  CHECK_EQ(0, profile->samples_count());
536
}
537

    
538

    
539
// --- P r o f i l e r   E x t e n s i o n ---
540

    
541
class ProfilerExtension : public v8::Extension {
542
 public:
543
  ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
544
  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
545
      v8::Handle<v8::String> name);
546
  static void StartProfiling(const v8::FunctionCallbackInfo<v8::Value>& args);
547
  static void StopProfiling(const v8::FunctionCallbackInfo<v8::Value>& args);
548
 private:
549
  static const char* kSource;
550
};
551

    
552

    
553
const char* ProfilerExtension::kSource =
554
    "native function startProfiling();"
555
    "native function stopProfiling();";
556

    
557
v8::Handle<v8::FunctionTemplate> ProfilerExtension::GetNativeFunction(
558
    v8::Handle<v8::String> name) {
559
  if (name->Equals(v8::String::New("startProfiling"))) {
560
    return v8::FunctionTemplate::New(ProfilerExtension::StartProfiling);
561
  } else if (name->Equals(v8::String::New("stopProfiling"))) {
562
    return v8::FunctionTemplate::New(ProfilerExtension::StopProfiling);
563
  } else {
564
    CHECK(false);
565
    return v8::Handle<v8::FunctionTemplate>();
566
  }
567
}
568

    
569

    
570
void ProfilerExtension::StartProfiling(
571
    const v8::FunctionCallbackInfo<v8::Value>& args) {
572
  v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler();
573
  if (args.Length() > 0)
574
    cpu_profiler->StartCpuProfiling(args[0].As<v8::String>());
575
  else
576
    cpu_profiler->StartCpuProfiling(v8::String::New(""));
577
}
578

    
579

    
580
void ProfilerExtension::StopProfiling(
581
    const v8::FunctionCallbackInfo<v8::Value>& args) {
582
  v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler();
583
  if (args.Length() > 0)
584
    cpu_profiler->StopCpuProfiling(args[0].As<v8::String>());
585
  else
586
    cpu_profiler->StopCpuProfiling(v8::String::New(""));
587
}
588

    
589

    
590
static ProfilerExtension kProfilerExtension;
591
v8::DeclareExtension kProfilerExtensionDeclaration(&kProfilerExtension);
592

    
593
static const ProfileNode* PickChild(const ProfileNode* parent,
594
                                    const char* name) {
595
  for (int i = 0; i < parent->children()->length(); ++i) {
596
    const ProfileNode* child = parent->children()->at(i);
597
    if (strcmp(child->entry()->name(), name) == 0) return child;
598
  }
599
  return NULL;
600
}
601

    
602

    
603
TEST(RecordStackTraceAtStartProfiling) {
604
  // This test does not pass with inlining enabled since inlined functions
605
  // don't appear in the stack trace.
606
  i::FLAG_use_inlining = false;
607

    
608
  v8::Isolate* isolate = CcTest::isolate();
609
  v8::HandleScope scope(isolate);
610
  const char* extensions[] = { "v8/profiler" };
611
  v8::ExtensionConfiguration config(1, extensions);
612
  v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
613
  context->Enter();
614

    
615
  CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
616
  CHECK_EQ(0, profiler->GetProfilesCount());
617
  CompileRun(
618
      "function c() { startProfiling(); }\n"
619
      "function b() { c(); }\n"
620
      "function a() { b(); }\n"
621
      "a();\n"
622
      "stopProfiling();");
623
  CHECK_EQ(1, profiler->GetProfilesCount());
624
  CpuProfile* profile = profiler->GetProfile(0);
625
  const ProfileTree* topDown = profile->top_down();
626
  const ProfileNode* current = topDown->root();
627
  const_cast<ProfileNode*>(current)->Print(0);
628
  // The tree should look like this:
629
  //  (root)
630
  //   (anonymous function)
631
  //     a
632
  //       b
633
  //         c
634
  // There can also be:
635
  //           startProfiling
636
  // if the sampler managed to get a tick.
637
  current = PickChild(current, "(anonymous function)");
638
  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
639
  current = PickChild(current, "a");
640
  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
641
  current = PickChild(current, "b");
642
  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
643
  current = PickChild(current, "c");
644
  CHECK_NE(NULL, const_cast<ProfileNode*>(current));
645
  CHECK(current->children()->length() == 0 ||
646
        current->children()->length() == 1);
647
  if (current->children()->length() == 1) {
648
    current = PickChild(current, "startProfiling");
649
    CHECK_EQ(0, current->children()->length());
650
  }
651
}
652

    
653

    
654
TEST(Issue51919) {
655
  CpuProfilesCollection collection(CcTest::heap());
656
  i::EmbeddedVector<char*,
657
      CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
658
  for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
659
    i::Vector<char> title = i::Vector<char>::New(16);
660
    i::OS::SNPrintF(title, "%d", i);
661
    // UID must be > 0.
662
    CHECK(collection.StartProfiling(title.start(), i + 1, false));
663
    titles[i] = title.start();
664
  }
665
  CHECK(!collection.StartProfiling(
666
      "maximum", CpuProfilesCollection::kMaxSimultaneousProfiles + 1, false));
667
  for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
668
    i::DeleteArray(titles[i]);
669
}
670

    
671

    
672
static const v8::CpuProfileNode* PickChild(const v8::CpuProfileNode* parent,
673
                                           const char* name) {
674
  for (int i = 0; i < parent->GetChildrenCount(); ++i) {
675
    const v8::CpuProfileNode* child = parent->GetChild(i);
676
    v8::String::AsciiValue function_name(child->GetFunctionName());
677
    if (strcmp(*function_name, name) == 0) return child;
678
  }
679
  return NULL;
680
}
681

    
682

    
683
TEST(ProfileNodeScriptId) {
684
  // This test does not pass with inlining enabled since inlined functions
685
  // don't appear in the stack trace.
686
  i::FLAG_use_inlining = false;
687

    
688
  const char* extensions[] = { "v8/profiler" };
689
  v8::ExtensionConfiguration config(1, extensions);
690
  LocalContext env(&config);
691
  v8::HandleScope hs(env->GetIsolate());
692

    
693
  v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
694
  CHECK_EQ(0, profiler->GetProfileCount());
695
  v8::Handle<v8::Script> script_a = v8::Script::Compile(v8::String::New(
696
      "function a() { startProfiling(); }\n"));
697
  script_a->Run();
698
  v8::Handle<v8::Script> script_b = v8::Script::Compile(v8::String::New(
699
      "function b() { a(); }\n"
700
      "b();\n"
701
      "stopProfiling();\n"));
702
  script_b->Run();
703
  CHECK_EQ(1, profiler->GetProfileCount());
704
  const v8::CpuProfile* profile = profiler->GetCpuProfile(0);
705
  const v8::CpuProfileNode* current = profile->GetTopDownRoot();
706
  reinterpret_cast<ProfileNode*>(
707
      const_cast<v8::CpuProfileNode*>(current))->Print(0);
708
  // The tree should look like this:
709
  //  (root)
710
  //   (anonymous function)
711
  //     b
712
  //       a
713
  // There can also be:
714
  //         startProfiling
715
  // if the sampler managed to get a tick.
716
  current = PickChild(current, i::ProfileGenerator::kAnonymousFunctionName);
717
  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
718

    
719
  current = PickChild(current, "b");
720
  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
721
  CHECK_EQ(script_b->GetId(), current->GetScriptId());
722

    
723
  current = PickChild(current, "a");
724
  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
725
  CHECK_EQ(script_a->GetId(), current->GetScriptId());
726
}
727

    
728

    
729

    
730

    
731
static const char* line_number_test_source_existing_functions =
732
"function foo_at_the_first_line() {\n"
733
"}\n"
734
"foo_at_the_first_line();\n"
735
"function lazy_func_at_forth_line() {}\n";
736

    
737

    
738
static const char* line_number_test_source_profile_time_functions =
739
"// Empty first line\n"
740
"function bar_at_the_second_line() {\n"
741
"  foo_at_the_first_line();\n"
742
"}\n"
743
"bar_at_the_second_line();\n"
744
"function lazy_func_at_6th_line() {}";
745

    
746
int GetFunctionLineNumber(LocalContext* env, const char* name) {
747
  CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
748
  CodeMap* code_map = profiler->generator()->code_map();
749
  i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
750
      *v8::Local<v8::Function>::Cast(
751
          (*(*env))->Global()->Get(v8_str(name))));
752
  CodeEntry* func_entry = code_map->FindEntry(func->code()->address());
753
  if (!func_entry)
754
    FATAL(name);
755
  return func_entry->line_number();
756
}
757

    
758

    
759
TEST(LineNumber) {
760
  i::FLAG_use_inlining = false;
761

    
762
  CcTest::InitializeVM();
763
  LocalContext env;
764
  i::Isolate* isolate = CcTest::i_isolate();
765
  TestSetup test_setup;
766

    
767
  i::HandleScope scope(isolate);
768

    
769
  CompileRun(line_number_test_source_existing_functions);
770

    
771
  CpuProfiler* profiler = isolate->cpu_profiler();
772
  profiler->StartProfiling("LineNumber");
773

    
774
  CompileRun(line_number_test_source_profile_time_functions);
775

    
776
  profiler->processor()->StopSynchronously();
777

    
778
  CHECK_EQ(1, GetFunctionLineNumber(&env, "foo_at_the_first_line"));
779
  CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_forth_line"));
780
  CHECK_EQ(2, GetFunctionLineNumber(&env, "bar_at_the_second_line"));
781
  CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_6th_line"));
782

    
783
  profiler->StopProfiling("LineNumber");
784
}
785

    
786

    
787

    
788
TEST(BailoutReason) {
789
  const char* extensions[] = { "v8/profiler" };
790
  v8::ExtensionConfiguration config(1, extensions);
791
  LocalContext env(&config);
792
  v8::HandleScope hs(env->GetIsolate());
793

    
794
  v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
795
  CHECK_EQ(0, profiler->GetProfileCount());
796
  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
797
      "function TryCatch() {\n"
798
      "  try {\n"
799
      "    startProfiling();\n"
800
      "  } catch (e) { };\n"
801
      "}\n"
802
      "function TryFinally() {\n"
803
      "  try {\n"
804
      "    TryCatch();\n"
805
      "  } finally { };\n"
806
      "}\n"
807
      "TryFinally();\n"
808
      "stopProfiling();"));
809
  script->Run();
810
  CHECK_EQ(1, profiler->GetProfileCount());
811
  const v8::CpuProfile* profile = profiler->GetCpuProfile(0);
812
  const v8::CpuProfileNode* current = profile->GetTopDownRoot();
813
  reinterpret_cast<ProfileNode*>(
814
      const_cast<v8::CpuProfileNode*>(current))->Print(0);
815
  // The tree should look like this:
816
  //  (root)
817
  //   (anonymous function)
818
  //     kTryFinally
819
  //       kTryCatch
820
  current = PickChild(current, i::ProfileGenerator::kAnonymousFunctionName);
821
  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
822

    
823
  current = PickChild(current, "TryFinally");
824
  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
825
  CHECK(!strcmp("TryFinallyStatement", current->GetBailoutReason()));
826

    
827
  current = PickChild(current, "TryCatch");
828
  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
829
  CHECK(!strcmp("TryCatchStatement", current->GetBailoutReason()));
830
}