blob: b36220284f29279c909c7498b2afa267ca267d30 [file] [log] [blame]
Steve Block6ded16b2010-05-10 14:33:55 +01001// Copyright 2010 the V8 project authors. All rights reserved.
2//
3// Tests of profiles generator and utilities.
4
5#ifdef ENABLE_LOGGING_AND_PROFILING
6
7#include "v8.h"
8#include "profile-generator-inl.h"
9#include "cctest.h"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010#include "../include/v8-profiler.h"
Steve Block6ded16b2010-05-10 14:33:55 +010011
12namespace i = v8::internal;
13
14using i::CodeEntry;
15using i::CodeMap;
16using i::CpuProfile;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010017using i::CpuProfiler;
Steve Block6ded16b2010-05-10 14:33:55 +010018using i::CpuProfilesCollection;
19using i::ProfileNode;
20using i::ProfileTree;
21using i::ProfileGenerator;
22using i::SampleRateCalculator;
23using i::TickSample;
Leon Clarkef7060e22010-06-03 12:02:55 +010024using i::TokenEnumerator;
Steve Block6ded16b2010-05-10 14:33:55 +010025using i::Vector;
26
27
Leon Clarkef7060e22010-06-03 12:02:55 +010028namespace v8 {
29namespace internal {
30
31class TokenEnumeratorTester {
32 public:
33 static i::List<bool>* token_removed(TokenEnumerator* te) {
34 return &te->token_removed_;
35 }
36};
37
38} } // namespace v8::internal
39
40TEST(TokenEnumerator) {
41 TokenEnumerator te;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010042 CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
Leon Clarkef7060e22010-06-03 12:02:55 +010043 v8::HandleScope hs;
44 v8::Local<v8::String> token1(v8::String::New("1"));
45 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
46 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
47 v8::Local<v8::String> token2(v8::String::New("2"));
48 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
49 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
50 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
51 {
52 v8::HandleScope hs;
53 v8::Local<v8::String> token3(v8::String::New("3"));
54 CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
55 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
56 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
57 }
58 CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
59 i::Heap::CollectAllGarbage(false);
60 CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
61 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
62 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
63}
64
65
Steve Block6ded16b2010-05-10 14:33:55 +010066TEST(ProfileNodeFindOrAddChild) {
67 ProfileNode node(NULL, NULL);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010068 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
69 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +010070 ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
71 CHECK_NE(NULL, childNode1);
72 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010073 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
74 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +010075 ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
76 CHECK_NE(NULL, childNode2);
77 CHECK_NE(childNode1, childNode2);
78 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
79 CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010080 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
81 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +010082 ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
83 CHECK_NE(NULL, childNode3);
84 CHECK_NE(childNode1, childNode3);
85 CHECK_NE(childNode2, childNode3);
86 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
87 CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
88 CHECK_EQ(childNode3, node.FindOrAddChild(&entry3));
89}
90
91
92namespace {
93
94class ProfileTreeTestHelper {
95 public:
96 explicit ProfileTreeTestHelper(const ProfileTree* tree)
97 : tree_(tree) { }
98
99 ProfileNode* Walk(CodeEntry* entry1,
100 CodeEntry* entry2 = NULL,
101 CodeEntry* entry3 = NULL) {
102 ProfileNode* node = tree_->root();
103 node = node->FindChild(entry1);
104 if (node == NULL) return NULL;
105 if (entry2 != NULL) {
106 node = node->FindChild(entry2);
107 if (node == NULL) return NULL;
108 }
109 if (entry3 != NULL) {
110 node = node->FindChild(entry3);
111 }
112 return node;
113 }
114
115 private:
116 const ProfileTree* tree_;
117};
118
119} // namespace
120
121TEST(ProfileTreeAddPathFromStart) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100122 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
123 TokenEnumerator::kNoSecurityToken);
124 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
125 TokenEnumerator::kNoSecurityToken);
126 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
127 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100128 ProfileTree tree;
129 ProfileTreeTestHelper helper(&tree);
130 CHECK_EQ(NULL, helper.Walk(&entry1));
131 CHECK_EQ(NULL, helper.Walk(&entry2));
132 CHECK_EQ(NULL, helper.Walk(&entry3));
133
134 CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
135 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
136 tree.AddPathFromStart(path_vec);
137 CHECK_EQ(NULL, helper.Walk(&entry2));
138 CHECK_EQ(NULL, helper.Walk(&entry3));
139 ProfileNode* node1 = helper.Walk(&entry1);
140 CHECK_NE(NULL, node1);
141 CHECK_EQ(0, node1->total_ticks());
142 CHECK_EQ(0, node1->self_ticks());
143 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
144 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
145 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
146 CHECK_NE(NULL, node2);
147 CHECK_NE(node1, node2);
148 CHECK_EQ(0, node2->total_ticks());
149 CHECK_EQ(0, node2->self_ticks());
150 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
151 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
152 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
153 CHECK_NE(NULL, node3);
154 CHECK_NE(node1, node3);
155 CHECK_NE(node2, node3);
156 CHECK_EQ(0, node3->total_ticks());
157 CHECK_EQ(1, node3->self_ticks());
158
159 tree.AddPathFromStart(path_vec);
160 CHECK_EQ(node1, helper.Walk(&entry1));
161 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
162 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
163 CHECK_EQ(0, node1->total_ticks());
164 CHECK_EQ(0, node1->self_ticks());
165 CHECK_EQ(0, node2->total_ticks());
166 CHECK_EQ(0, node2->self_ticks());
167 CHECK_EQ(0, node3->total_ticks());
168 CHECK_EQ(2, node3->self_ticks());
169
170 CodeEntry* path2[] = {&entry1, &entry2, &entry2};
171 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
172 tree.AddPathFromStart(path2_vec);
173 CHECK_EQ(NULL, helper.Walk(&entry2));
174 CHECK_EQ(NULL, helper.Walk(&entry3));
175 CHECK_EQ(node1, helper.Walk(&entry1));
176 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
177 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
178 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
179 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
180 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
181 CHECK_EQ(0, node3->total_ticks());
182 CHECK_EQ(2, node3->self_ticks());
183 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
184 CHECK_NE(NULL, node4);
185 CHECK_NE(node3, node4);
186 CHECK_EQ(0, node4->total_ticks());
187 CHECK_EQ(1, node4->self_ticks());
188}
189
190
191TEST(ProfileTreeAddPathFromEnd) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100192 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
193 TokenEnumerator::kNoSecurityToken);
194 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
195 TokenEnumerator::kNoSecurityToken);
196 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
197 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100198 ProfileTree tree;
199 ProfileTreeTestHelper helper(&tree);
200 CHECK_EQ(NULL, helper.Walk(&entry1));
201 CHECK_EQ(NULL, helper.Walk(&entry2));
202 CHECK_EQ(NULL, helper.Walk(&entry3));
203
204 CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
205 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
206 tree.AddPathFromEnd(path_vec);
207 CHECK_EQ(NULL, helper.Walk(&entry2));
208 CHECK_EQ(NULL, helper.Walk(&entry3));
209 ProfileNode* node1 = helper.Walk(&entry1);
210 CHECK_NE(NULL, node1);
211 CHECK_EQ(0, node1->total_ticks());
212 CHECK_EQ(0, node1->self_ticks());
213 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
214 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
215 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
216 CHECK_NE(NULL, node2);
217 CHECK_NE(node1, node2);
218 CHECK_EQ(0, node2->total_ticks());
219 CHECK_EQ(0, node2->self_ticks());
220 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
221 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
222 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
223 CHECK_NE(NULL, node3);
224 CHECK_NE(node1, node3);
225 CHECK_NE(node2, node3);
226 CHECK_EQ(0, node3->total_ticks());
227 CHECK_EQ(1, node3->self_ticks());
228
229 tree.AddPathFromEnd(path_vec);
230 CHECK_EQ(node1, helper.Walk(&entry1));
231 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
232 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
233 CHECK_EQ(0, node1->total_ticks());
234 CHECK_EQ(0, node1->self_ticks());
235 CHECK_EQ(0, node2->total_ticks());
236 CHECK_EQ(0, node2->self_ticks());
237 CHECK_EQ(0, node3->total_ticks());
238 CHECK_EQ(2, node3->self_ticks());
239
240 CodeEntry* path2[] = {&entry2, &entry2, &entry1};
241 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
242 tree.AddPathFromEnd(path2_vec);
243 CHECK_EQ(NULL, helper.Walk(&entry2));
244 CHECK_EQ(NULL, helper.Walk(&entry3));
245 CHECK_EQ(node1, helper.Walk(&entry1));
246 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
247 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
248 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
249 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
250 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
251 CHECK_EQ(0, node3->total_ticks());
252 CHECK_EQ(2, node3->self_ticks());
253 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
254 CHECK_NE(NULL, node4);
255 CHECK_NE(node3, node4);
256 CHECK_EQ(0, node4->total_ticks());
257 CHECK_EQ(1, node4->self_ticks());
258}
259
260
261TEST(ProfileTreeCalculateTotalTicks) {
262 ProfileTree empty_tree;
263 CHECK_EQ(0, empty_tree.root()->total_ticks());
264 CHECK_EQ(0, empty_tree.root()->self_ticks());
265 empty_tree.CalculateTotalTicks();
266 CHECK_EQ(0, empty_tree.root()->total_ticks());
267 CHECK_EQ(0, empty_tree.root()->self_ticks());
268 empty_tree.root()->IncrementSelfTicks();
269 CHECK_EQ(0, empty_tree.root()->total_ticks());
270 CHECK_EQ(1, empty_tree.root()->self_ticks());
271 empty_tree.CalculateTotalTicks();
272 CHECK_EQ(1, empty_tree.root()->total_ticks());
273 CHECK_EQ(1, empty_tree.root()->self_ticks());
274
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100275 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
276 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100277 CodeEntry* e1_path[] = {&entry1};
278 Vector<CodeEntry*> e1_path_vec(
279 e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
Leon Clarkef7060e22010-06-03 12:02:55 +0100280
281 ProfileTree single_child_tree;
282 single_child_tree.AddPathFromStart(e1_path_vec);
283 single_child_tree.root()->IncrementSelfTicks();
284 CHECK_EQ(0, single_child_tree.root()->total_ticks());
285 CHECK_EQ(1, single_child_tree.root()->self_ticks());
286 ProfileTreeTestHelper single_child_helper(&single_child_tree);
287 ProfileNode* node1 = single_child_helper.Walk(&entry1);
288 CHECK_NE(NULL, node1);
289 CHECK_EQ(0, node1->total_ticks());
290 CHECK_EQ(1, node1->self_ticks());
291 single_child_tree.CalculateTotalTicks();
292 CHECK_EQ(2, single_child_tree.root()->total_ticks());
293 CHECK_EQ(1, single_child_tree.root()->self_ticks());
294 CHECK_EQ(1, node1->total_ticks());
295 CHECK_EQ(1, node1->self_ticks());
296
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100297 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
298 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100299 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
300 Vector<CodeEntry*> e1_e2_path_vec(
301 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
302
303 ProfileTree flat_tree;
304 ProfileTreeTestHelper flat_helper(&flat_tree);
305 flat_tree.AddPathFromStart(e1_path_vec);
306 flat_tree.AddPathFromStart(e1_path_vec);
307 flat_tree.AddPathFromStart(e1_e2_path_vec);
308 flat_tree.AddPathFromStart(e1_e2_path_vec);
309 flat_tree.AddPathFromStart(e1_e2_path_vec);
310 // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
311 CHECK_EQ(0, flat_tree.root()->total_ticks());
312 CHECK_EQ(0, flat_tree.root()->self_ticks());
Leon Clarkef7060e22010-06-03 12:02:55 +0100313 node1 = flat_helper.Walk(&entry1);
Steve Block6ded16b2010-05-10 14:33:55 +0100314 CHECK_NE(NULL, node1);
315 CHECK_EQ(0, node1->total_ticks());
316 CHECK_EQ(2, node1->self_ticks());
317 ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
318 CHECK_NE(NULL, node2);
319 CHECK_EQ(0, node2->total_ticks());
320 CHECK_EQ(3, node2->self_ticks());
321 flat_tree.CalculateTotalTicks();
322 // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
323 CHECK_EQ(5, flat_tree.root()->total_ticks());
324 CHECK_EQ(0, flat_tree.root()->self_ticks());
325 CHECK_EQ(5, node1->total_ticks());
326 CHECK_EQ(2, node1->self_ticks());
327 CHECK_EQ(3, node2->total_ticks());
328 CHECK_EQ(3, node2->self_ticks());
329
330 CodeEntry* e2_path[] = {&entry2};
331 Vector<CodeEntry*> e2_path_vec(
332 e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100333 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
334 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100335 CodeEntry* e3_path[] = {&entry3};
336 Vector<CodeEntry*> e3_path_vec(
337 e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
338
339 ProfileTree wide_tree;
340 ProfileTreeTestHelper wide_helper(&wide_tree);
341 wide_tree.AddPathFromStart(e1_path_vec);
342 wide_tree.AddPathFromStart(e1_path_vec);
343 wide_tree.AddPathFromStart(e1_e2_path_vec);
344 wide_tree.AddPathFromStart(e2_path_vec);
345 wide_tree.AddPathFromStart(e2_path_vec);
346 wide_tree.AddPathFromStart(e2_path_vec);
347 wide_tree.AddPathFromStart(e3_path_vec);
348 wide_tree.AddPathFromStart(e3_path_vec);
349 wide_tree.AddPathFromStart(e3_path_vec);
350 wide_tree.AddPathFromStart(e3_path_vec);
351 // Results in -> {entry1,0,2} -> {entry2,0,1}
352 // {root,0,0} -> {entry2,0,3}
353 // -> {entry3,0,4}
354 CHECK_EQ(0, wide_tree.root()->total_ticks());
355 CHECK_EQ(0, wide_tree.root()->self_ticks());
356 node1 = wide_helper.Walk(&entry1);
357 CHECK_NE(NULL, node1);
358 CHECK_EQ(0, node1->total_ticks());
359 CHECK_EQ(2, node1->self_ticks());
360 ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
361 CHECK_NE(NULL, node1_2);
362 CHECK_EQ(0, node1_2->total_ticks());
363 CHECK_EQ(1, node1_2->self_ticks());
364 node2 = wide_helper.Walk(&entry2);
365 CHECK_NE(NULL, node2);
366 CHECK_EQ(0, node2->total_ticks());
367 CHECK_EQ(3, node2->self_ticks());
368 ProfileNode* node3 = wide_helper.Walk(&entry3);
369 CHECK_NE(NULL, node3);
370 CHECK_EQ(0, node3->total_ticks());
371 CHECK_EQ(4, node3->self_ticks());
372 wide_tree.CalculateTotalTicks();
373 // Calculates -> {entry1,3,2} -> {entry2,1,1}
374 // {root,10,0} -> {entry2,3,3}
375 // -> {entry3,4,4}
376 CHECK_EQ(10, wide_tree.root()->total_ticks());
377 CHECK_EQ(0, wide_tree.root()->self_ticks());
378 CHECK_EQ(3, node1->total_ticks());
379 CHECK_EQ(2, node1->self_ticks());
380 CHECK_EQ(1, node1_2->total_ticks());
381 CHECK_EQ(1, node1_2->self_ticks());
382 CHECK_EQ(3, node2->total_ticks());
383 CHECK_EQ(3, node2->self_ticks());
384 CHECK_EQ(4, node3->total_ticks());
385 CHECK_EQ(4, node3->self_ticks());
386}
387
388
Leon Clarkef7060e22010-06-03 12:02:55 +0100389TEST(ProfileTreeFilteredClone) {
390 ProfileTree source_tree;
391 const int token0 = 0, token1 = 1, token2 = 2;
392 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
393 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
394 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
395 CodeEntry entry4(
396 i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100397 TokenEnumerator::kInheritsSecurityToken);
Leon Clarkef7060e22010-06-03 12:02:55 +0100398
399 {
400 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
401 Vector<CodeEntry*> e1_e2_path_vec(
402 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
403 source_tree.AddPathFromStart(e1_e2_path_vec);
404 CodeEntry* e2_e4_path[] = {&entry2, &entry4};
405 Vector<CodeEntry*> e2_e4_path_vec(
406 e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
407 source_tree.AddPathFromStart(e2_e4_path_vec);
408 CodeEntry* e3_e1_path[] = {&entry3, &entry1};
409 Vector<CodeEntry*> e3_e1_path_vec(
410 e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
411 source_tree.AddPathFromStart(e3_e1_path_vec);
412 CodeEntry* e3_e2_path[] = {&entry3, &entry2};
413 Vector<CodeEntry*> e3_e2_path_vec(
414 e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
415 source_tree.AddPathFromStart(e3_e2_path_vec);
416 source_tree.CalculateTotalTicks();
417 // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
418 // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
419 // -> {entry3,0,2,0} -> {entry1,1,1,0}
420 // -> {entry2,1,1,1}
421 CHECK_EQ(4, source_tree.root()->total_ticks());
422 CHECK_EQ(0, source_tree.root()->self_ticks());
423 }
424
425 {
426 ProfileTree token0_tree;
427 token0_tree.FilteredClone(&source_tree, token0);
428 // Should be -> {entry1,1,1,0}
429 // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
430 // [self ticks from filtered nodes are attributed to their parents]
431 CHECK_EQ(4, token0_tree.root()->total_ticks());
432 CHECK_EQ(1, token0_tree.root()->self_ticks());
433 ProfileTreeTestHelper token0_helper(&token0_tree);
434 ProfileNode* node1 = token0_helper.Walk(&entry1);
435 CHECK_NE(NULL, node1);
436 CHECK_EQ(1, node1->total_ticks());
437 CHECK_EQ(1, node1->self_ticks());
438 CHECK_EQ(NULL, token0_helper.Walk(&entry2));
439 ProfileNode* node3 = token0_helper.Walk(&entry3);
440 CHECK_NE(NULL, node3);
441 CHECK_EQ(2, node3->total_ticks());
442 CHECK_EQ(1, node3->self_ticks());
443 ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
444 CHECK_NE(NULL, node3_1);
445 CHECK_EQ(1, node3_1->total_ticks());
446 CHECK_EQ(1, node3_1->self_ticks());
447 CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
448 }
449
450 {
451 ProfileTree token1_tree;
452 token1_tree.FilteredClone(&source_tree, token1);
453 // Should be
454 // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
455 // [child nodes referring to the same entry get merged and
456 // their self times summed up]
457 CHECK_EQ(4, token1_tree.root()->total_ticks());
458 CHECK_EQ(1, token1_tree.root()->self_ticks());
459 ProfileTreeTestHelper token1_helper(&token1_tree);
460 CHECK_EQ(NULL, token1_helper.Walk(&entry1));
461 CHECK_EQ(NULL, token1_helper.Walk(&entry3));
462 ProfileNode* node2 = token1_helper.Walk(&entry2);
463 CHECK_NE(NULL, node2);
464 CHECK_EQ(3, node2->total_ticks());
465 CHECK_EQ(2, node2->self_ticks());
466 ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
467 CHECK_NE(NULL, node2_4);
468 CHECK_EQ(1, node2_4->total_ticks());
469 CHECK_EQ(1, node2_4->self_ticks());
470 }
471
472 {
473 ProfileTree token2_tree;
474 token2_tree.FilteredClone(&source_tree, token2);
475 // Should be
476 // {root,4,4,-1}
477 // [no nodes, all ticks get migrated into root node]
478 CHECK_EQ(4, token2_tree.root()->total_ticks());
479 CHECK_EQ(4, token2_tree.root()->self_ticks());
480 ProfileTreeTestHelper token2_helper(&token2_tree);
481 CHECK_EQ(NULL, token2_helper.Walk(&entry1));
482 CHECK_EQ(NULL, token2_helper.Walk(&entry2));
483 CHECK_EQ(NULL, token2_helper.Walk(&entry3));
484 }
485}
486
487
Steve Block6ded16b2010-05-10 14:33:55 +0100488static inline i::Address ToAddress(int n) {
489 return reinterpret_cast<i::Address>(n);
490}
491
492TEST(CodeMapAddCode) {
493 CodeMap code_map;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100494 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
495 TokenEnumerator::kNoSecurityToken);
496 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
497 TokenEnumerator::kNoSecurityToken);
498 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
499 TokenEnumerator::kNoSecurityToken);
500 CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
501 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100502 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
503 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
504 code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
505 code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
506 CHECK_EQ(NULL, code_map.FindEntry(0));
507 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
508 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
509 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
510 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
511 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
512 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
513 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
514 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
515 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
516 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
517 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
518 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
519 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
520 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
521 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
522 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
523}
524
525
526TEST(CodeMapMoveAndDeleteCode) {
527 CodeMap code_map;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100528 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
529 TokenEnumerator::kNoSecurityToken);
530 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
531 TokenEnumerator::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100532 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
533 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
534 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
535 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
536 code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800));
537 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
538 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
539 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
540 code_map.DeleteCode(ToAddress(0x1700));
541 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
542 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
543}
544
545
546namespace {
547
548class TestSetup {
549 public:
550 TestSetup()
551 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
552 i::FLAG_prof_browser_mode = false;
553 }
554
555 ~TestSetup() {
556 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
557 }
558
559 private:
560 bool old_flag_prof_browser_mode_;
561};
562
563} // namespace
564
565TEST(RecordTickSample) {
566 TestSetup test_setup;
567 CpuProfilesCollection profiles;
568 profiles.StartProfiling("", 1);
569 ProfileGenerator generator(&profiles);
570 CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
571 CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
572 CodeEntry* entry3 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
573 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
574 generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
575 generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
576
577 // We are building the following calls tree:
578 // -> aaa - sample1
579 // aaa -> bbb -> ccc - sample2
580 // -> ccc -> aaa - sample3
581 TickSample sample1;
582 sample1.pc = ToAddress(0x1600);
583 sample1.function = ToAddress(0x1500);
584 sample1.stack[0] = ToAddress(0x1510);
585 sample1.frames_count = 1;
586 generator.RecordTickSample(sample1);
587 TickSample sample2;
588 sample2.pc = ToAddress(0x1925);
589 sample2.function = ToAddress(0x1900);
590 sample2.stack[0] = ToAddress(0x1780);
591 sample2.stack[1] = ToAddress(0x10000); // non-existent.
592 sample2.stack[2] = ToAddress(0x1620);
593 sample2.frames_count = 3;
594 generator.RecordTickSample(sample2);
595 TickSample sample3;
596 sample3.pc = ToAddress(0x1510);
597 sample3.function = ToAddress(0x1500);
598 sample3.stack[0] = ToAddress(0x1910);
599 sample3.stack[1] = ToAddress(0x1610);
600 sample3.frames_count = 2;
601 generator.RecordTickSample(sample3);
602
Leon Clarkef7060e22010-06-03 12:02:55 +0100603 CpuProfile* profile =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100604 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100605 CHECK_NE(NULL, profile);
606 ProfileTreeTestHelper top_down_test_helper(profile->top_down());
607 CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
608 CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
609 ProfileNode* node1 = top_down_test_helper.Walk(entry1);
610 CHECK_NE(NULL, node1);
611 CHECK_EQ(entry1, node1->entry());
612 ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
613 CHECK_NE(NULL, node2);
614 CHECK_EQ(entry1, node2->entry());
615 ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
616 CHECK_NE(NULL, node3);
617 CHECK_EQ(entry3, node3->entry());
618 ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
619 CHECK_NE(NULL, node4);
620 CHECK_EQ(entry1, node4->entry());
621}
622
623
624TEST(SampleRateCalculator) {
625 const double kSamplingIntervalMs = i::Logger::kSamplingIntervalMs;
626
627 // Verify that ticking exactly in query intervals results in the
628 // initial sampling interval.
629 double time = 0.0;
630 SampleRateCalculator calc1;
631 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
632 calc1.UpdateMeasurements(time);
633 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
634 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
635 calc1.UpdateMeasurements(time);
636 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
637 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
638 calc1.UpdateMeasurements(time);
639 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
640 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
641 calc1.UpdateMeasurements(time);
642 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
643
644 SampleRateCalculator calc2;
645 time = 0.0;
646 CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
647 calc2.UpdateMeasurements(time);
648 CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
649 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.5;
650 calc2.UpdateMeasurements(time);
651 // (1.0 + 2.0) / 2
652 CHECK_EQ(kSamplingIntervalMs * 1.5, calc2.ticks_per_ms());
653 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.75;
654 calc2.UpdateMeasurements(time);
655 // (1.0 + 2.0 + 2.0) / 3
Steve Block8defd9f2010-07-08 12:39:36 +0100656 CHECK_EQ(kSamplingIntervalMs * 5.0, floor(calc2.ticks_per_ms() * 3.0 + 0.5));
Steve Block6ded16b2010-05-10 14:33:55 +0100657
658 SampleRateCalculator calc3;
659 time = 0.0;
660 CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
661 calc3.UpdateMeasurements(time);
662 CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
663 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 2;
664 calc3.UpdateMeasurements(time);
665 // (1.0 + 0.5) / 2
666 CHECK_EQ(kSamplingIntervalMs * 0.75, calc3.ticks_per_ms());
667 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 1.5;
668 calc3.UpdateMeasurements(time);
669 // (1.0 + 0.5 + 0.5) / 3
Steve Block8defd9f2010-07-08 12:39:36 +0100670 CHECK_EQ(kSamplingIntervalMs * 2.0, floor(calc3.ticks_per_ms() * 3.0 + 0.5));
Steve Block6ded16b2010-05-10 14:33:55 +0100671}
672
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100673
674// --- P r o f i l e r E x t e n s i o n ---
675
676class ProfilerExtension : public v8::Extension {
677 public:
678 ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
679 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
680 v8::Handle<v8::String> name);
681 static v8::Handle<v8::Value> StartProfiling(const v8::Arguments& args);
682 static v8::Handle<v8::Value> StopProfiling(const v8::Arguments& args);
683 private:
684 static const char* kSource;
685};
686
687
688const char* ProfilerExtension::kSource =
689 "native function startProfiling();"
690 "native function stopProfiling();";
691
692v8::Handle<v8::FunctionTemplate> ProfilerExtension::GetNativeFunction(
693 v8::Handle<v8::String> name) {
694 if (name->Equals(v8::String::New("startProfiling"))) {
695 return v8::FunctionTemplate::New(ProfilerExtension::StartProfiling);
696 } else if (name->Equals(v8::String::New("stopProfiling"))) {
697 return v8::FunctionTemplate::New(ProfilerExtension::StopProfiling);
698 } else {
699 CHECK(false);
700 return v8::Handle<v8::FunctionTemplate>();
701 }
702}
703
704
705v8::Handle<v8::Value> ProfilerExtension::StartProfiling(
706 const v8::Arguments& args) {
707 if (args.Length() > 0)
708 v8::CpuProfiler::StartProfiling(args[0].As<v8::String>());
709 else
710 v8::CpuProfiler::StartProfiling(v8::String::New(""));
711 return v8::Undefined();
712}
713
714
715v8::Handle<v8::Value> ProfilerExtension::StopProfiling(
716 const v8::Arguments& args) {
717 if (args.Length() > 0)
718 v8::CpuProfiler::StopProfiling(args[0].As<v8::String>());
719 else
720 v8::CpuProfiler::StopProfiling(v8::String::New(""));
721 return v8::Undefined();
722}
723
724
725static ProfilerExtension kProfilerExtension;
726v8::DeclareExtension kProfilerExtensionDeclaration(&kProfilerExtension);
727static v8::Persistent<v8::Context> env;
728
729static const ProfileNode* PickChild(const ProfileNode* parent,
730 const char* name) {
731 for (int i = 0; i < parent->children()->length(); ++i) {
732 const ProfileNode* child = parent->children()->at(i);
733 if (strcmp(child->entry()->name(), name) == 0) return child;
734 }
735 return NULL;
736}
737
738
739TEST(RecordStackTraceAtStartProfiling) {
740 if (env.IsEmpty()) {
741 v8::HandleScope scope;
742 const char* extensions[] = { "v8/profiler" };
743 v8::ExtensionConfiguration config(1, extensions);
744 env = v8::Context::New(&config);
745 }
746 v8::HandleScope scope;
747 env->Enter();
748
749 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
750 CompileRun(
751 "function c() { startProfiling(); }\n"
752 "function b() { c(); }\n"
753 "function a() { b(); }\n"
754 "a();\n"
755 "stopProfiling();");
756 CHECK_EQ(1, CpuProfiler::GetProfilesCount());
757 CpuProfile* profile =
758 CpuProfiler::GetProfile(NULL, 0);
759 const ProfileTree* topDown = profile->top_down();
760 const ProfileNode* current = topDown->root();
761 // The tree should look like this:
762 // (root)
763 // (anonymous function)
764 // a
765 // b
766 // c
767 current = PickChild(current, "(anonymous function)");
768 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
769 current = PickChild(current, "a");
770 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
771 current = PickChild(current, "b");
772 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
773 current = PickChild(current, "c");
774 CHECK_NE(NULL, const_cast<ProfileNode*>(current));
775 CHECK_EQ(0, current->children()->length());
776}
777
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100778
779TEST(Issue51919) {
780 CpuProfilesCollection collection;
781 i::EmbeddedVector<char*,
782 CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
783 for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
784 i::Vector<char> title = i::Vector<char>::New(16);
785 i::OS::SNPrintF(title, "%d", i);
786 CHECK(collection.StartProfiling(title.start(), i + 1)); // UID must be > 0.
787 titles[i] = title.start();
788 }
789 CHECK(!collection.StartProfiling(
790 "maximum", CpuProfilesCollection::kMaxSimultaneousProfiles + 1));
791 for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
792 i::DeleteArray(titles[i]);
793}
794
Steve Block6ded16b2010-05-10 14:33:55 +0100795#endif // ENABLE_LOGGING_AND_PROFILING