blob: b10e6889ec8f9bd6f7d283a3d2f4eff049b7ba7a [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
Steve Block6ded16b2010-05-10 14:33:55 +01005#include "v8.h"
6#include "cpu-profiler-inl.h"
7#include "cctest.h"
Steve Block44f0eee2011-05-26 01:26:41 +01008#include "../include/v8-profiler.h"
Steve Block6ded16b2010-05-10 14:33:55 +01009
Steve Block6ded16b2010-05-10 14:33:55 +010010using i::CodeEntry;
11using i::CpuProfile;
Iain Merrick75681382010-08-19 15:07:18 +010012using i::CpuProfiler;
Steve Block6ded16b2010-05-10 14:33:55 +010013using i::CpuProfilesCollection;
14using i::ProfileGenerator;
15using i::ProfileNode;
16using i::ProfilerEventsProcessor;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010017using i::TokenEnumerator;
Steve Block6ded16b2010-05-10 14:33:55 +010018
19
20TEST(StartStop) {
21 CpuProfilesCollection profiles;
22 ProfileGenerator generator(&profiles);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000023 ProfilerEventsProcessor processor(&generator);
Steve Block6ded16b2010-05-10 14:33:55 +010024 processor.Start();
Steve Block6ded16b2010-05-10 14:33:55 +010025 processor.Stop();
26 processor.Join();
27}
28
29static v8::Persistent<v8::Context> env;
30
31static void InitializeVM() {
32 if (env.IsEmpty()) env = v8::Context::New();
33 v8::HandleScope scope;
34 env->Enter();
35}
36
37static inline i::Address ToAddress(int n) {
38 return reinterpret_cast<i::Address>(n);
39}
40
41static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
42 i::Address frame1,
43 i::Address frame2 = NULL,
44 i::Address frame3 = NULL) {
45 i::TickSample* sample = proc->TickSampleEvent();
46 sample->pc = frame1;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010047 sample->tos = frame1;
Steve Block6ded16b2010-05-10 14:33:55 +010048 sample->frames_count = 0;
49 if (frame2 != NULL) {
50 sample->stack[0] = frame2;
51 sample->frames_count = 1;
52 }
53 if (frame3 != NULL) {
54 sample->stack[1] = frame3;
55 sample->frames_count = 2;
56 }
57}
58
59namespace {
60
61class TestSetup {
62 public:
63 TestSetup()
64 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
65 i::FLAG_prof_browser_mode = false;
66 }
67
68 ~TestSetup() {
69 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
70 }
71
72 private:
73 bool old_flag_prof_browser_mode_;
74};
75
76} // namespace
77
78TEST(CodeEvents) {
79 InitializeVM();
80 TestSetup test_setup;
81 CpuProfilesCollection profiles;
82 profiles.StartProfiling("", 1);
83 ProfileGenerator generator(&profiles);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000084 ProfilerEventsProcessor processor(&generator);
Steve Block6ded16b2010-05-10 14:33:55 +010085 processor.Start();
Steve Block6ded16b2010-05-10 14:33:55 +010086
87 // Enqueue code creation events.
88 i::HandleScope scope;
89 const char* aaa_str = "aaa";
Steve Block44f0eee2011-05-26 01:26:41 +010090 i::Handle<i::String> aaa_name = FACTORY->NewStringFromAscii(
Steve Block6ded16b2010-05-10 14:33:55 +010091 i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
92 processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
93 *aaa_name,
Steve Block44f0eee2011-05-26 01:26:41 +010094 HEAP->empty_string(),
Steve Block6ded16b2010-05-10 14:33:55 +010095 0,
96 ToAddress(0x1000),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010097 0x100,
98 ToAddress(0x10000));
Steve Block6ded16b2010-05-10 14:33:55 +010099 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
100 "bbb",
101 ToAddress(0x1200),
102 0x80);
103 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
104 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
105 "ddd",
106 ToAddress(0x1400),
107 0x80);
108 processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
109 processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
Ben Murdoch589d6972011-11-30 16:04:58 +0000110 processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
Steve Block6ded16b2010-05-10 14:33:55 +0100111 // Enqueue a tick event to enable code events processing.
112 EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
113
114 processor.Stop();
115 processor.Join();
116
117 // Check the state of profile generator.
118 CodeEntry* entry1 = generator.code_map()->FindEntry(ToAddress(0x1000));
119 CHECK_NE(NULL, entry1);
120 CHECK_EQ(aaa_str, entry1->name());
121 CodeEntry* entry2 = generator.code_map()->FindEntry(ToAddress(0x1200));
122 CHECK_NE(NULL, entry2);
123 CHECK_EQ("bbb", entry2->name());
124 CodeEntry* entry3 = generator.code_map()->FindEntry(ToAddress(0x1300));
125 CHECK_NE(NULL, entry3);
126 CHECK_EQ("5", entry3->name());
127 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1400)));
128 CodeEntry* entry4 = generator.code_map()->FindEntry(ToAddress(0x1500));
129 CHECK_NE(NULL, entry4);
130 CHECK_EQ("ddd", entry4->name());
131 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
Steve Block6ded16b2010-05-10 14:33:55 +0100132}
133
134
135template<typename T>
136static int CompareProfileNodes(const T* p1, const T* p2) {
137 return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
138}
139
140TEST(TickEvents) {
141 TestSetup test_setup;
142 CpuProfilesCollection profiles;
143 profiles.StartProfiling("", 1);
144 ProfileGenerator generator(&profiles);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000145 ProfilerEventsProcessor processor(&generator);
Steve Block6ded16b2010-05-10 14:33:55 +0100146 processor.Start();
Steve Block6ded16b2010-05-10 14:33:55 +0100147
148 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
149 "bbb",
150 ToAddress(0x1200),
151 0x80);
152 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
153 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
154 "ddd",
155 ToAddress(0x1400),
156 0x80);
157 EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
158 EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
159 EnqueueTickSampleEvent(&processor,
160 ToAddress(0x1404),
161 ToAddress(0x1305),
162 ToAddress(0x1230));
163
164 processor.Stop();
165 processor.Join();
Leon Clarkef7060e22010-06-03 12:02:55 +0100166 CpuProfile* profile =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100167 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100168 CHECK_NE(NULL, profile);
169
170 // Check call trees.
171 const i::List<ProfileNode*>* top_down_root_children =
172 profile->top_down()->root()->children();
173 CHECK_EQ(1, top_down_root_children->length());
174 CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
175 const i::List<ProfileNode*>* top_down_bbb_children =
176 top_down_root_children->last()->children();
177 CHECK_EQ(1, top_down_bbb_children->length());
178 CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
179 const i::List<ProfileNode*>* top_down_stub_children =
180 top_down_bbb_children->last()->children();
181 CHECK_EQ(1, top_down_stub_children->length());
182 CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
183 const i::List<ProfileNode*>* top_down_ddd_children =
184 top_down_stub_children->last()->children();
185 CHECK_EQ(0, top_down_ddd_children->length());
186
187 const i::List<ProfileNode*>* bottom_up_root_children_unsorted =
188 profile->bottom_up()->root()->children();
189 CHECK_EQ(3, bottom_up_root_children_unsorted->length());
190 i::List<ProfileNode*> bottom_up_root_children(3);
191 bottom_up_root_children.AddAll(*bottom_up_root_children_unsorted);
192 bottom_up_root_children.Sort(&CompareProfileNodes);
193 CHECK_EQ("5", bottom_up_root_children[0]->entry()->name());
194 CHECK_EQ("bbb", bottom_up_root_children[1]->entry()->name());
195 CHECK_EQ("ddd", bottom_up_root_children[2]->entry()->name());
196 const i::List<ProfileNode*>* bottom_up_stub_children =
197 bottom_up_root_children[0]->children();
198 CHECK_EQ(1, bottom_up_stub_children->length());
199 CHECK_EQ("bbb", bottom_up_stub_children->last()->entry()->name());
200 const i::List<ProfileNode*>* bottom_up_bbb_children =
201 bottom_up_root_children[1]->children();
202 CHECK_EQ(0, bottom_up_bbb_children->length());
203 const i::List<ProfileNode*>* bottom_up_ddd_children =
204 bottom_up_root_children[2]->children();
205 CHECK_EQ(1, bottom_up_ddd_children->length());
206 CHECK_EQ("5", bottom_up_ddd_children->last()->entry()->name());
207 const i::List<ProfileNode*>* bottom_up_ddd_stub_children =
208 bottom_up_ddd_children->last()->children();
209 CHECK_EQ(1, bottom_up_ddd_stub_children->length());
210 CHECK_EQ("bbb", bottom_up_ddd_stub_children->last()->entry()->name());
211}
212
Iain Merrick75681382010-08-19 15:07:18 +0100213
214// http://crbug/51594
215// This test must not crash.
216TEST(CrashIfStoppingLastNonExistentProfile) {
217 InitializeVM();
218 TestSetup test_setup;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100219 CpuProfiler::SetUp();
Iain Merrick75681382010-08-19 15:07:18 +0100220 CpuProfiler::StartProfiling("1");
221 CpuProfiler::StopProfiling("2");
222 CpuProfiler::StartProfiling("1");
223 CpuProfiler::StopProfiling("");
224 CpuProfiler::TearDown();
225}
226
Steve Block44f0eee2011-05-26 01:26:41 +0100227
Steve Block053d10c2011-06-13 19:13:29 +0100228// http://code.google.com/p/v8/issues/detail?id=1398
229// Long stacks (exceeding max frames limit) must not be erased.
230TEST(Issue1398) {
231 TestSetup test_setup;
232 CpuProfilesCollection profiles;
233 profiles.StartProfiling("", 1);
234 ProfileGenerator generator(&profiles);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000235 ProfilerEventsProcessor processor(&generator);
Steve Block053d10c2011-06-13 19:13:29 +0100236 processor.Start();
Steve Block053d10c2011-06-13 19:13:29 +0100237
238 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
239 "bbb",
240 ToAddress(0x1200),
241 0x80);
242
243 i::TickSample* sample = processor.TickSampleEvent();
244 sample->pc = ToAddress(0x1200);
245 sample->tos = 0;
246 sample->frames_count = i::TickSample::kMaxFramesCount;
247 for (int i = 0; i < sample->frames_count; ++i) {
248 sample->stack[i] = ToAddress(0x1200);
249 }
250
251 processor.Stop();
252 processor.Join();
253 CpuProfile* profile =
254 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
255 CHECK_NE(NULL, profile);
256
257 int actual_depth = 0;
258 const ProfileNode* node = profile->top_down()->root();
259 while (node->children()->length() > 0) {
260 node = node->children()->last();
261 ++actual_depth;
262 }
263
264 CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
265}
266
267
Steve Block44f0eee2011-05-26 01:26:41 +0100268TEST(DeleteAllCpuProfiles) {
269 InitializeVM();
270 TestSetup test_setup;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100271 CpuProfiler::SetUp();
Steve Block44f0eee2011-05-26 01:26:41 +0100272 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
273 CpuProfiler::DeleteAllProfiles();
274 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
275
276 CpuProfiler::StartProfiling("1");
277 CpuProfiler::StopProfiling("1");
278 CHECK_EQ(1, CpuProfiler::GetProfilesCount());
279 CpuProfiler::DeleteAllProfiles();
280 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
281 CpuProfiler::StartProfiling("1");
282 CpuProfiler::StartProfiling("2");
283 CpuProfiler::StopProfiling("2");
284 CpuProfiler::StopProfiling("1");
285 CHECK_EQ(2, CpuProfiler::GetProfilesCount());
286 CpuProfiler::DeleteAllProfiles();
287 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
288
289 // Test profiling cancellation by the 'delete' command.
290 CpuProfiler::StartProfiling("1");
291 CpuProfiler::StartProfiling("2");
292 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
293 CpuProfiler::DeleteAllProfiles();
294 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
295
296 CpuProfiler::TearDown();
297}
298
299
300TEST(DeleteCpuProfile) {
301 v8::HandleScope scope;
302 LocalContext env;
303
304 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
305 v8::Local<v8::String> name1 = v8::String::New("1");
306 v8::CpuProfiler::StartProfiling(name1);
307 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
308 CHECK_NE(NULL, p1);
309 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
310 unsigned uid1 = p1->GetUid();
311 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
312 const_cast<v8::CpuProfile*>(p1)->Delete();
313 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
314 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
315
316 v8::Local<v8::String> name2 = v8::String::New("2");
317 v8::CpuProfiler::StartProfiling(name2);
318 const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2);
319 CHECK_NE(NULL, p2);
320 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
321 unsigned uid2 = p2->GetUid();
322 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
323 CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2));
324 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
325 v8::Local<v8::String> name3 = v8::String::New("3");
326 v8::CpuProfiler::StartProfiling(name3);
327 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
328 CHECK_NE(NULL, p3);
329 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
330 unsigned uid3 = p3->GetUid();
331 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
332 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
333 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
334 const_cast<v8::CpuProfile*>(p2)->Delete();
335 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
336 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
337 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
338 const_cast<v8::CpuProfile*>(p3)->Delete();
339 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
340 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
341 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
342 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
343}
344
345
346TEST(DeleteCpuProfileDifferentTokens) {
347 v8::HandleScope scope;
348 LocalContext env;
349
350 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
351 v8::Local<v8::String> name1 = v8::String::New("1");
352 v8::CpuProfiler::StartProfiling(name1);
353 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
354 CHECK_NE(NULL, p1);
355 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
356 unsigned uid1 = p1->GetUid();
357 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
358 v8::Local<v8::String> token1 = v8::String::New("token1");
359 const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1);
360 CHECK_NE(NULL, p1_t1);
361 CHECK_NE(p1, p1_t1);
362 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
363 const_cast<v8::CpuProfile*>(p1)->Delete();
364 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
365 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
366 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1));
367 const_cast<v8::CpuProfile*>(p1_t1)->Delete();
368 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
369
370 v8::Local<v8::String> name2 = v8::String::New("2");
371 v8::CpuProfiler::StartProfiling(name2);
372 v8::Local<v8::String> token2 = v8::String::New("token2");
373 const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2);
374 CHECK_NE(NULL, p2_t2);
375 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
376 unsigned uid2 = p2_t2->GetUid();
377 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
378 const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2);
379 CHECK_NE(p2_t2, p2);
380 v8::Local<v8::String> name3 = v8::String::New("3");
381 v8::CpuProfiler::StartProfiling(name3);
382 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
383 CHECK_NE(NULL, p3);
384 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
385 unsigned uid3 = p3->GetUid();
386 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
387 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
388 const_cast<v8::CpuProfile*>(p2_t2)->Delete();
389 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
390 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
391 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
392 const_cast<v8::CpuProfile*>(p2)->Delete();
393 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
394 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
395 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
396 const_cast<v8::CpuProfile*>(p3)->Delete();
397 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
398 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
399}