blob: b438d252e0a8dd45f12153c1f930e73f2d803b16 [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"
10
11namespace i = v8::internal;
12
13using i::CodeEntry;
14using i::CodeMap;
15using i::CpuProfile;
16using i::CpuProfilesCollection;
17using i::ProfileNode;
18using i::ProfileTree;
19using i::ProfileGenerator;
20using i::SampleRateCalculator;
21using i::TickSample;
Leon Clarkef7060e22010-06-03 12:02:55 +010022using i::TokenEnumerator;
Steve Block6ded16b2010-05-10 14:33:55 +010023using i::Vector;
24
25
Leon Clarkef7060e22010-06-03 12:02:55 +010026namespace v8 {
27namespace internal {
28
29class TokenEnumeratorTester {
30 public:
31 static i::List<bool>* token_removed(TokenEnumerator* te) {
32 return &te->token_removed_;
33 }
34};
35
36} } // namespace v8::internal
37
38TEST(TokenEnumerator) {
39 TokenEnumerator te;
40 CHECK_EQ(CodeEntry::kNoSecurityToken, te.GetTokenId(NULL));
41 v8::HandleScope hs;
42 v8::Local<v8::String> token1(v8::String::New("1"));
43 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
44 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
45 v8::Local<v8::String> token2(v8::String::New("2"));
46 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
47 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
48 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
49 {
50 v8::HandleScope hs;
51 v8::Local<v8::String> token3(v8::String::New("3"));
52 CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
53 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
54 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
55 }
56 CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
57 i::Heap::CollectAllGarbage(false);
58 CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
59 CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
60 CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
61}
62
63
Steve Block6ded16b2010-05-10 14:33:55 +010064TEST(ProfileNodeFindOrAddChild) {
65 ProfileNode node(NULL, NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +010066 CodeEntry entry1(
67 i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +010068 ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
69 CHECK_NE(NULL, childNode1);
70 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
Leon Clarkef7060e22010-06-03 12:02:55 +010071 CodeEntry entry2(
72 i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +010073 ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
74 CHECK_NE(NULL, childNode2);
75 CHECK_NE(childNode1, childNode2);
76 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
77 CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
Leon Clarkef7060e22010-06-03 12:02:55 +010078 CodeEntry entry3(
79 i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +010080 ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
81 CHECK_NE(NULL, childNode3);
82 CHECK_NE(childNode1, childNode3);
83 CHECK_NE(childNode2, childNode3);
84 CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
85 CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
86 CHECK_EQ(childNode3, node.FindOrAddChild(&entry3));
87}
88
89
90namespace {
91
92class ProfileTreeTestHelper {
93 public:
94 explicit ProfileTreeTestHelper(const ProfileTree* tree)
95 : tree_(tree) { }
96
97 ProfileNode* Walk(CodeEntry* entry1,
98 CodeEntry* entry2 = NULL,
99 CodeEntry* entry3 = NULL) {
100 ProfileNode* node = tree_->root();
101 node = node->FindChild(entry1);
102 if (node == NULL) return NULL;
103 if (entry2 != NULL) {
104 node = node->FindChild(entry2);
105 if (node == NULL) return NULL;
106 }
107 if (entry3 != NULL) {
108 node = node->FindChild(entry3);
109 }
110 return node;
111 }
112
113 private:
114 const ProfileTree* tree_;
115};
116
117} // namespace
118
119TEST(ProfileTreeAddPathFromStart) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100120 CodeEntry entry1(
121 i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
122 CodeEntry entry2(
123 i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
124 CodeEntry entry3(
125 i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100126 ProfileTree tree;
127 ProfileTreeTestHelper helper(&tree);
128 CHECK_EQ(NULL, helper.Walk(&entry1));
129 CHECK_EQ(NULL, helper.Walk(&entry2));
130 CHECK_EQ(NULL, helper.Walk(&entry3));
131
132 CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL};
133 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
134 tree.AddPathFromStart(path_vec);
135 CHECK_EQ(NULL, helper.Walk(&entry2));
136 CHECK_EQ(NULL, helper.Walk(&entry3));
137 ProfileNode* node1 = helper.Walk(&entry1);
138 CHECK_NE(NULL, node1);
139 CHECK_EQ(0, node1->total_ticks());
140 CHECK_EQ(0, node1->self_ticks());
141 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
142 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
143 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
144 CHECK_NE(NULL, node2);
145 CHECK_NE(node1, node2);
146 CHECK_EQ(0, node2->total_ticks());
147 CHECK_EQ(0, node2->self_ticks());
148 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
149 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
150 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
151 CHECK_NE(NULL, node3);
152 CHECK_NE(node1, node3);
153 CHECK_NE(node2, node3);
154 CHECK_EQ(0, node3->total_ticks());
155 CHECK_EQ(1, node3->self_ticks());
156
157 tree.AddPathFromStart(path_vec);
158 CHECK_EQ(node1, helper.Walk(&entry1));
159 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
160 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
161 CHECK_EQ(0, node1->total_ticks());
162 CHECK_EQ(0, node1->self_ticks());
163 CHECK_EQ(0, node2->total_ticks());
164 CHECK_EQ(0, node2->self_ticks());
165 CHECK_EQ(0, node3->total_ticks());
166 CHECK_EQ(2, node3->self_ticks());
167
168 CodeEntry* path2[] = {&entry1, &entry2, &entry2};
169 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
170 tree.AddPathFromStart(path2_vec);
171 CHECK_EQ(NULL, helper.Walk(&entry2));
172 CHECK_EQ(NULL, helper.Walk(&entry3));
173 CHECK_EQ(node1, helper.Walk(&entry1));
174 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
175 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
176 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
177 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
178 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
179 CHECK_EQ(0, node3->total_ticks());
180 CHECK_EQ(2, node3->self_ticks());
181 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
182 CHECK_NE(NULL, node4);
183 CHECK_NE(node3, node4);
184 CHECK_EQ(0, node4->total_ticks());
185 CHECK_EQ(1, node4->self_ticks());
186}
187
188
189TEST(ProfileTreeAddPathFromEnd) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100190 CodeEntry entry1(
191 i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
192 CodeEntry entry2(
193 i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
194 CodeEntry entry3(
195 i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100196 ProfileTree tree;
197 ProfileTreeTestHelper helper(&tree);
198 CHECK_EQ(NULL, helper.Walk(&entry1));
199 CHECK_EQ(NULL, helper.Walk(&entry2));
200 CHECK_EQ(NULL, helper.Walk(&entry3));
201
202 CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL};
203 Vector<CodeEntry*> path_vec(path, sizeof(path) / sizeof(path[0]));
204 tree.AddPathFromEnd(path_vec);
205 CHECK_EQ(NULL, helper.Walk(&entry2));
206 CHECK_EQ(NULL, helper.Walk(&entry3));
207 ProfileNode* node1 = helper.Walk(&entry1);
208 CHECK_NE(NULL, node1);
209 CHECK_EQ(0, node1->total_ticks());
210 CHECK_EQ(0, node1->self_ticks());
211 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
212 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
213 ProfileNode* node2 = helper.Walk(&entry1, &entry2);
214 CHECK_NE(NULL, node2);
215 CHECK_NE(node1, node2);
216 CHECK_EQ(0, node2->total_ticks());
217 CHECK_EQ(0, node2->self_ticks());
218 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
219 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2));
220 ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3);
221 CHECK_NE(NULL, node3);
222 CHECK_NE(node1, node3);
223 CHECK_NE(node2, node3);
224 CHECK_EQ(0, node3->total_ticks());
225 CHECK_EQ(1, node3->self_ticks());
226
227 tree.AddPathFromEnd(path_vec);
228 CHECK_EQ(node1, helper.Walk(&entry1));
229 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
230 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
231 CHECK_EQ(0, node1->total_ticks());
232 CHECK_EQ(0, node1->self_ticks());
233 CHECK_EQ(0, node2->total_ticks());
234 CHECK_EQ(0, node2->self_ticks());
235 CHECK_EQ(0, node3->total_ticks());
236 CHECK_EQ(2, node3->self_ticks());
237
238 CodeEntry* path2[] = {&entry2, &entry2, &entry1};
239 Vector<CodeEntry*> path2_vec(path2, sizeof(path2) / sizeof(path2[0]));
240 tree.AddPathFromEnd(path2_vec);
241 CHECK_EQ(NULL, helper.Walk(&entry2));
242 CHECK_EQ(NULL, helper.Walk(&entry3));
243 CHECK_EQ(node1, helper.Walk(&entry1));
244 CHECK_EQ(NULL, helper.Walk(&entry1, &entry1));
245 CHECK_EQ(NULL, helper.Walk(&entry1, &entry3));
246 CHECK_EQ(node2, helper.Walk(&entry1, &entry2));
247 CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1));
248 CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3));
249 CHECK_EQ(0, node3->total_ticks());
250 CHECK_EQ(2, node3->self_ticks());
251 ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2);
252 CHECK_NE(NULL, node4);
253 CHECK_NE(node3, node4);
254 CHECK_EQ(0, node4->total_ticks());
255 CHECK_EQ(1, node4->self_ticks());
256}
257
258
259TEST(ProfileTreeCalculateTotalTicks) {
260 ProfileTree empty_tree;
261 CHECK_EQ(0, empty_tree.root()->total_ticks());
262 CHECK_EQ(0, empty_tree.root()->self_ticks());
263 empty_tree.CalculateTotalTicks();
264 CHECK_EQ(0, empty_tree.root()->total_ticks());
265 CHECK_EQ(0, empty_tree.root()->self_ticks());
266 empty_tree.root()->IncrementSelfTicks();
267 CHECK_EQ(0, empty_tree.root()->total_ticks());
268 CHECK_EQ(1, empty_tree.root()->self_ticks());
269 empty_tree.CalculateTotalTicks();
270 CHECK_EQ(1, empty_tree.root()->total_ticks());
271 CHECK_EQ(1, empty_tree.root()->self_ticks());
272
Leon Clarkef7060e22010-06-03 12:02:55 +0100273 CodeEntry entry1(
274 i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100275 CodeEntry* e1_path[] = {&entry1};
276 Vector<CodeEntry*> e1_path_vec(
277 e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
Leon Clarkef7060e22010-06-03 12:02:55 +0100278
279 ProfileTree single_child_tree;
280 single_child_tree.AddPathFromStart(e1_path_vec);
281 single_child_tree.root()->IncrementSelfTicks();
282 CHECK_EQ(0, single_child_tree.root()->total_ticks());
283 CHECK_EQ(1, single_child_tree.root()->self_ticks());
284 ProfileTreeTestHelper single_child_helper(&single_child_tree);
285 ProfileNode* node1 = single_child_helper.Walk(&entry1);
286 CHECK_NE(NULL, node1);
287 CHECK_EQ(0, node1->total_ticks());
288 CHECK_EQ(1, node1->self_ticks());
289 single_child_tree.CalculateTotalTicks();
290 CHECK_EQ(2, single_child_tree.root()->total_ticks());
291 CHECK_EQ(1, single_child_tree.root()->self_ticks());
292 CHECK_EQ(1, node1->total_ticks());
293 CHECK_EQ(1, node1->self_ticks());
294
295 CodeEntry entry2(
296 i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100297 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
298 Vector<CodeEntry*> e1_e2_path_vec(
299 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
300
301 ProfileTree flat_tree;
302 ProfileTreeTestHelper flat_helper(&flat_tree);
303 flat_tree.AddPathFromStart(e1_path_vec);
304 flat_tree.AddPathFromStart(e1_path_vec);
305 flat_tree.AddPathFromStart(e1_e2_path_vec);
306 flat_tree.AddPathFromStart(e1_e2_path_vec);
307 flat_tree.AddPathFromStart(e1_e2_path_vec);
308 // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
309 CHECK_EQ(0, flat_tree.root()->total_ticks());
310 CHECK_EQ(0, flat_tree.root()->self_ticks());
Leon Clarkef7060e22010-06-03 12:02:55 +0100311 node1 = flat_helper.Walk(&entry1);
Steve Block6ded16b2010-05-10 14:33:55 +0100312 CHECK_NE(NULL, node1);
313 CHECK_EQ(0, node1->total_ticks());
314 CHECK_EQ(2, node1->self_ticks());
315 ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2);
316 CHECK_NE(NULL, node2);
317 CHECK_EQ(0, node2->total_ticks());
318 CHECK_EQ(3, node2->self_ticks());
319 flat_tree.CalculateTotalTicks();
320 // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3}
321 CHECK_EQ(5, flat_tree.root()->total_ticks());
322 CHECK_EQ(0, flat_tree.root()->self_ticks());
323 CHECK_EQ(5, node1->total_ticks());
324 CHECK_EQ(2, node1->self_ticks());
325 CHECK_EQ(3, node2->total_ticks());
326 CHECK_EQ(3, node2->self_ticks());
327
328 CodeEntry* e2_path[] = {&entry2};
329 Vector<CodeEntry*> e2_path_vec(
330 e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
Leon Clarkef7060e22010-06-03 12:02:55 +0100331 CodeEntry entry3(
332 i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100333 CodeEntry* e3_path[] = {&entry3};
334 Vector<CodeEntry*> e3_path_vec(
335 e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
336
337 ProfileTree wide_tree;
338 ProfileTreeTestHelper wide_helper(&wide_tree);
339 wide_tree.AddPathFromStart(e1_path_vec);
340 wide_tree.AddPathFromStart(e1_path_vec);
341 wide_tree.AddPathFromStart(e1_e2_path_vec);
342 wide_tree.AddPathFromStart(e2_path_vec);
343 wide_tree.AddPathFromStart(e2_path_vec);
344 wide_tree.AddPathFromStart(e2_path_vec);
345 wide_tree.AddPathFromStart(e3_path_vec);
346 wide_tree.AddPathFromStart(e3_path_vec);
347 wide_tree.AddPathFromStart(e3_path_vec);
348 wide_tree.AddPathFromStart(e3_path_vec);
349 // Results in -> {entry1,0,2} -> {entry2,0,1}
350 // {root,0,0} -> {entry2,0,3}
351 // -> {entry3,0,4}
352 CHECK_EQ(0, wide_tree.root()->total_ticks());
353 CHECK_EQ(0, wide_tree.root()->self_ticks());
354 node1 = wide_helper.Walk(&entry1);
355 CHECK_NE(NULL, node1);
356 CHECK_EQ(0, node1->total_ticks());
357 CHECK_EQ(2, node1->self_ticks());
358 ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2);
359 CHECK_NE(NULL, node1_2);
360 CHECK_EQ(0, node1_2->total_ticks());
361 CHECK_EQ(1, node1_2->self_ticks());
362 node2 = wide_helper.Walk(&entry2);
363 CHECK_NE(NULL, node2);
364 CHECK_EQ(0, node2->total_ticks());
365 CHECK_EQ(3, node2->self_ticks());
366 ProfileNode* node3 = wide_helper.Walk(&entry3);
367 CHECK_NE(NULL, node3);
368 CHECK_EQ(0, node3->total_ticks());
369 CHECK_EQ(4, node3->self_ticks());
370 wide_tree.CalculateTotalTicks();
371 // Calculates -> {entry1,3,2} -> {entry2,1,1}
372 // {root,10,0} -> {entry2,3,3}
373 // -> {entry3,4,4}
374 CHECK_EQ(10, wide_tree.root()->total_ticks());
375 CHECK_EQ(0, wide_tree.root()->self_ticks());
376 CHECK_EQ(3, node1->total_ticks());
377 CHECK_EQ(2, node1->self_ticks());
378 CHECK_EQ(1, node1_2->total_ticks());
379 CHECK_EQ(1, node1_2->self_ticks());
380 CHECK_EQ(3, node2->total_ticks());
381 CHECK_EQ(3, node2->self_ticks());
382 CHECK_EQ(4, node3->total_ticks());
383 CHECK_EQ(4, node3->self_ticks());
384}
385
386
Leon Clarkef7060e22010-06-03 12:02:55 +0100387TEST(ProfileTreeFilteredClone) {
388 ProfileTree source_tree;
389 const int token0 = 0, token1 = 1, token2 = 2;
390 CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
391 CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
392 CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
393 CodeEntry entry4(
394 i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
395 CodeEntry::kInheritsSecurityToken);
396
397 {
398 CodeEntry* e1_e2_path[] = {&entry1, &entry2};
399 Vector<CodeEntry*> e1_e2_path_vec(
400 e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
401 source_tree.AddPathFromStart(e1_e2_path_vec);
402 CodeEntry* e2_e4_path[] = {&entry2, &entry4};
403 Vector<CodeEntry*> e2_e4_path_vec(
404 e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
405 source_tree.AddPathFromStart(e2_e4_path_vec);
406 CodeEntry* e3_e1_path[] = {&entry3, &entry1};
407 Vector<CodeEntry*> e3_e1_path_vec(
408 e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
409 source_tree.AddPathFromStart(e3_e1_path_vec);
410 CodeEntry* e3_e2_path[] = {&entry3, &entry2};
411 Vector<CodeEntry*> e3_e2_path_vec(
412 e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
413 source_tree.AddPathFromStart(e3_e2_path_vec);
414 source_tree.CalculateTotalTicks();
415 // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
416 // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
417 // -> {entry3,0,2,0} -> {entry1,1,1,0}
418 // -> {entry2,1,1,1}
419 CHECK_EQ(4, source_tree.root()->total_ticks());
420 CHECK_EQ(0, source_tree.root()->self_ticks());
421 }
422
423 {
424 ProfileTree token0_tree;
425 token0_tree.FilteredClone(&source_tree, token0);
426 // Should be -> {entry1,1,1,0}
427 // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
428 // [self ticks from filtered nodes are attributed to their parents]
429 CHECK_EQ(4, token0_tree.root()->total_ticks());
430 CHECK_EQ(1, token0_tree.root()->self_ticks());
431 ProfileTreeTestHelper token0_helper(&token0_tree);
432 ProfileNode* node1 = token0_helper.Walk(&entry1);
433 CHECK_NE(NULL, node1);
434 CHECK_EQ(1, node1->total_ticks());
435 CHECK_EQ(1, node1->self_ticks());
436 CHECK_EQ(NULL, token0_helper.Walk(&entry2));
437 ProfileNode* node3 = token0_helper.Walk(&entry3);
438 CHECK_NE(NULL, node3);
439 CHECK_EQ(2, node3->total_ticks());
440 CHECK_EQ(1, node3->self_ticks());
441 ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
442 CHECK_NE(NULL, node3_1);
443 CHECK_EQ(1, node3_1->total_ticks());
444 CHECK_EQ(1, node3_1->self_ticks());
445 CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
446 }
447
448 {
449 ProfileTree token1_tree;
450 token1_tree.FilteredClone(&source_tree, token1);
451 // Should be
452 // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
453 // [child nodes referring to the same entry get merged and
454 // their self times summed up]
455 CHECK_EQ(4, token1_tree.root()->total_ticks());
456 CHECK_EQ(1, token1_tree.root()->self_ticks());
457 ProfileTreeTestHelper token1_helper(&token1_tree);
458 CHECK_EQ(NULL, token1_helper.Walk(&entry1));
459 CHECK_EQ(NULL, token1_helper.Walk(&entry3));
460 ProfileNode* node2 = token1_helper.Walk(&entry2);
461 CHECK_NE(NULL, node2);
462 CHECK_EQ(3, node2->total_ticks());
463 CHECK_EQ(2, node2->self_ticks());
464 ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
465 CHECK_NE(NULL, node2_4);
466 CHECK_EQ(1, node2_4->total_ticks());
467 CHECK_EQ(1, node2_4->self_ticks());
468 }
469
470 {
471 ProfileTree token2_tree;
472 token2_tree.FilteredClone(&source_tree, token2);
473 // Should be
474 // {root,4,4,-1}
475 // [no nodes, all ticks get migrated into root node]
476 CHECK_EQ(4, token2_tree.root()->total_ticks());
477 CHECK_EQ(4, token2_tree.root()->self_ticks());
478 ProfileTreeTestHelper token2_helper(&token2_tree);
479 CHECK_EQ(NULL, token2_helper.Walk(&entry1));
480 CHECK_EQ(NULL, token2_helper.Walk(&entry2));
481 CHECK_EQ(NULL, token2_helper.Walk(&entry3));
482 }
483}
484
485
Steve Block6ded16b2010-05-10 14:33:55 +0100486static inline i::Address ToAddress(int n) {
487 return reinterpret_cast<i::Address>(n);
488}
489
490TEST(CodeMapAddCode) {
491 CodeMap code_map;
Leon Clarkef7060e22010-06-03 12:02:55 +0100492 CodeEntry entry1(
493 i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
494 CodeEntry entry2(
495 i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
496 CodeEntry entry3(
497 i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
498 CodeEntry entry4(
499 i::Logger::FUNCTION_TAG, "", "ddd", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100500 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
501 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
502 code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
503 code_map.AddCode(ToAddress(0x1950), &entry4, 0x10);
504 CHECK_EQ(NULL, code_map.FindEntry(0));
505 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1)));
506 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
507 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100)));
508 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1)));
509 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
510 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50)));
511 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1)));
512 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100)));
513 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1)));
514 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900)));
515 CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28)));
516 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950)));
517 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7)));
518 CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1)));
519 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10)));
520 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF)));
521}
522
523
524TEST(CodeMapMoveAndDeleteCode) {
525 CodeMap code_map;
Leon Clarkef7060e22010-06-03 12:02:55 +0100526 CodeEntry entry1(
527 i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
528 CodeEntry entry2(
529 i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
Steve Block6ded16b2010-05-10 14:33:55 +0100530 code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
531 code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
532 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
533 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
534 code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800));
535 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
536 CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
537 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
538 code_map.DeleteCode(ToAddress(0x1700));
539 CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
540 CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
541}
542
543
544namespace {
545
546class TestSetup {
547 public:
548 TestSetup()
549 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
550 i::FLAG_prof_browser_mode = false;
551 }
552
553 ~TestSetup() {
554 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
555 }
556
557 private:
558 bool old_flag_prof_browser_mode_;
559};
560
561} // namespace
562
563TEST(RecordTickSample) {
564 TestSetup test_setup;
565 CpuProfilesCollection profiles;
566 profiles.StartProfiling("", 1);
567 ProfileGenerator generator(&profiles);
568 CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
569 CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
570 CodeEntry* entry3 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "ccc");
571 generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
572 generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
573 generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
574
575 // We are building the following calls tree:
576 // -> aaa - sample1
577 // aaa -> bbb -> ccc - sample2
578 // -> ccc -> aaa - sample3
579 TickSample sample1;
580 sample1.pc = ToAddress(0x1600);
581 sample1.function = ToAddress(0x1500);
582 sample1.stack[0] = ToAddress(0x1510);
583 sample1.frames_count = 1;
584 generator.RecordTickSample(sample1);
585 TickSample sample2;
586 sample2.pc = ToAddress(0x1925);
587 sample2.function = ToAddress(0x1900);
588 sample2.stack[0] = ToAddress(0x1780);
589 sample2.stack[1] = ToAddress(0x10000); // non-existent.
590 sample2.stack[2] = ToAddress(0x1620);
591 sample2.frames_count = 3;
592 generator.RecordTickSample(sample2);
593 TickSample sample3;
594 sample3.pc = ToAddress(0x1510);
595 sample3.function = ToAddress(0x1500);
596 sample3.stack[0] = ToAddress(0x1910);
597 sample3.stack[1] = ToAddress(0x1610);
598 sample3.frames_count = 2;
599 generator.RecordTickSample(sample3);
600
Leon Clarkef7060e22010-06-03 12:02:55 +0100601 CpuProfile* profile =
602 profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100603 CHECK_NE(NULL, profile);
604 ProfileTreeTestHelper top_down_test_helper(profile->top_down());
605 CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
606 CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
607 ProfileNode* node1 = top_down_test_helper.Walk(entry1);
608 CHECK_NE(NULL, node1);
609 CHECK_EQ(entry1, node1->entry());
610 ProfileNode* node2 = top_down_test_helper.Walk(entry1, entry1);
611 CHECK_NE(NULL, node2);
612 CHECK_EQ(entry1, node2->entry());
613 ProfileNode* node3 = top_down_test_helper.Walk(entry1, entry2, entry3);
614 CHECK_NE(NULL, node3);
615 CHECK_EQ(entry3, node3->entry());
616 ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
617 CHECK_NE(NULL, node4);
618 CHECK_EQ(entry1, node4->entry());
619}
620
621
622TEST(SampleRateCalculator) {
623 const double kSamplingIntervalMs = i::Logger::kSamplingIntervalMs;
624
625 // Verify that ticking exactly in query intervals results in the
626 // initial sampling interval.
627 double time = 0.0;
628 SampleRateCalculator calc1;
629 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
630 calc1.UpdateMeasurements(time);
631 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
632 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
633 calc1.UpdateMeasurements(time);
634 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
635 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
636 calc1.UpdateMeasurements(time);
637 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
638 time += SampleRateCalculator::kWallTimeQueryIntervalMs;
639 calc1.UpdateMeasurements(time);
640 CHECK_EQ(kSamplingIntervalMs, calc1.ticks_per_ms());
641
642 SampleRateCalculator calc2;
643 time = 0.0;
644 CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
645 calc2.UpdateMeasurements(time);
646 CHECK_EQ(kSamplingIntervalMs, calc2.ticks_per_ms());
647 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.5;
648 calc2.UpdateMeasurements(time);
649 // (1.0 + 2.0) / 2
650 CHECK_EQ(kSamplingIntervalMs * 1.5, calc2.ticks_per_ms());
651 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 0.75;
652 calc2.UpdateMeasurements(time);
653 // (1.0 + 2.0 + 2.0) / 3
654 CHECK_EQ(kSamplingIntervalMs * 1.66666, calc2.ticks_per_ms());
655
656 SampleRateCalculator calc3;
657 time = 0.0;
658 CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
659 calc3.UpdateMeasurements(time);
660 CHECK_EQ(kSamplingIntervalMs, calc3.ticks_per_ms());
661 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 2;
662 calc3.UpdateMeasurements(time);
663 // (1.0 + 0.5) / 2
664 CHECK_EQ(kSamplingIntervalMs * 0.75, calc3.ticks_per_ms());
665 time += SampleRateCalculator::kWallTimeQueryIntervalMs * 1.5;
666 calc3.UpdateMeasurements(time);
667 // (1.0 + 0.5 + 0.5) / 3
668 CHECK_EQ(kSamplingIntervalMs * 0.66666, calc3.ticks_per_ms());
669}
670
671#endif // ENABLE_LOGGING_AND_PROFILING