blob: 17611acbf91409a796146dca528c85cf23d53da2 [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 "cpu-profiler-inl.h"
9#include "cctest.h"
Steve Block44f0eee2011-05-26 01:26:41 +010010#include "../include/v8-profiler.h"
Steve Block6ded16b2010-05-10 14:33:55 +010011
12namespace i = v8::internal;
13
14using i::CodeEntry;
15using i::CpuProfile;
Iain Merrick75681382010-08-19 15:07:18 +010016using i::CpuProfiler;
Steve Block6ded16b2010-05-10 14:33:55 +010017using i::CpuProfilesCollection;
18using i::ProfileGenerator;
19using i::ProfileNode;
20using i::ProfilerEventsProcessor;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010021using i::TokenEnumerator;
Steve Block6ded16b2010-05-10 14:33:55 +010022
23
24TEST(StartStop) {
25 CpuProfilesCollection profiles;
26 ProfileGenerator generator(&profiles);
Steve Block44f0eee2011-05-26 01:26:41 +010027 ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
Steve Block6ded16b2010-05-10 14:33:55 +010028 processor.Start();
29 while (!processor.running()) {
30 i::Thread::YieldCPU();
31 }
32 processor.Stop();
33 processor.Join();
34}
35
36static v8::Persistent<v8::Context> env;
37
38static void InitializeVM() {
39 if (env.IsEmpty()) env = v8::Context::New();
40 v8::HandleScope scope;
41 env->Enter();
42}
43
44static inline i::Address ToAddress(int n) {
45 return reinterpret_cast<i::Address>(n);
46}
47
48static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
49 i::Address frame1,
50 i::Address frame2 = NULL,
51 i::Address frame3 = NULL) {
52 i::TickSample* sample = proc->TickSampleEvent();
53 sample->pc = frame1;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010054 sample->tos = frame1;
Steve Block6ded16b2010-05-10 14:33:55 +010055 sample->frames_count = 0;
56 if (frame2 != NULL) {
57 sample->stack[0] = frame2;
58 sample->frames_count = 1;
59 }
60 if (frame3 != NULL) {
61 sample->stack[1] = frame3;
62 sample->frames_count = 2;
63 }
64}
65
66namespace {
67
68class TestSetup {
69 public:
70 TestSetup()
71 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
72 i::FLAG_prof_browser_mode = false;
73 }
74
75 ~TestSetup() {
76 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
77 }
78
79 private:
80 bool old_flag_prof_browser_mode_;
81};
82
83} // namespace
84
85TEST(CodeEvents) {
86 InitializeVM();
87 TestSetup test_setup;
88 CpuProfilesCollection profiles;
89 profiles.StartProfiling("", 1);
90 ProfileGenerator generator(&profiles);
Steve Block44f0eee2011-05-26 01:26:41 +010091 ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
Steve Block6ded16b2010-05-10 14:33:55 +010092 processor.Start();
93 while (!processor.running()) {
94 i::Thread::YieldCPU();
95 }
96
97 // Enqueue code creation events.
98 i::HandleScope scope;
99 const char* aaa_str = "aaa";
Steve Block44f0eee2011-05-26 01:26:41 +0100100 i::Handle<i::String> aaa_name = FACTORY->NewStringFromAscii(
Steve Block6ded16b2010-05-10 14:33:55 +0100101 i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
102 processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
103 *aaa_name,
Steve Block44f0eee2011-05-26 01:26:41 +0100104 HEAP->empty_string(),
Steve Block6ded16b2010-05-10 14:33:55 +0100105 0,
106 ToAddress(0x1000),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100107 0x100,
108 ToAddress(0x10000));
Steve Block6ded16b2010-05-10 14:33:55 +0100109 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
110 "bbb",
111 ToAddress(0x1200),
112 0x80);
113 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
114 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
115 "ddd",
116 ToAddress(0x1400),
117 0x80);
118 processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
119 processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
120 processor.CodeDeleteEvent(ToAddress(0x1600));
Steve Block6ded16b2010-05-10 14:33:55 +0100121 // Enqueue a tick event to enable code events processing.
122 EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
123
124 processor.Stop();
125 processor.Join();
126
127 // Check the state of profile generator.
128 CodeEntry* entry1 = generator.code_map()->FindEntry(ToAddress(0x1000));
129 CHECK_NE(NULL, entry1);
130 CHECK_EQ(aaa_str, entry1->name());
131 CodeEntry* entry2 = generator.code_map()->FindEntry(ToAddress(0x1200));
132 CHECK_NE(NULL, entry2);
133 CHECK_EQ("bbb", entry2->name());
134 CodeEntry* entry3 = generator.code_map()->FindEntry(ToAddress(0x1300));
135 CHECK_NE(NULL, entry3);
136 CHECK_EQ("5", entry3->name());
137 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1400)));
138 CodeEntry* entry4 = generator.code_map()->FindEntry(ToAddress(0x1500));
139 CHECK_NE(NULL, entry4);
140 CHECK_EQ("ddd", entry4->name());
141 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
Steve Block6ded16b2010-05-10 14:33:55 +0100142}
143
144
145template<typename T>
146static int CompareProfileNodes(const T* p1, const T* p2) {
147 return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
148}
149
150TEST(TickEvents) {
151 TestSetup test_setup;
152 CpuProfilesCollection profiles;
153 profiles.StartProfiling("", 1);
154 ProfileGenerator generator(&profiles);
Steve Block44f0eee2011-05-26 01:26:41 +0100155 ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
Steve Block6ded16b2010-05-10 14:33:55 +0100156 processor.Start();
157 while (!processor.running()) {
158 i::Thread::YieldCPU();
159 }
160
161 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
162 "bbb",
163 ToAddress(0x1200),
164 0x80);
165 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
166 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
167 "ddd",
168 ToAddress(0x1400),
169 0x80);
170 EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
171 EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
172 EnqueueTickSampleEvent(&processor,
173 ToAddress(0x1404),
174 ToAddress(0x1305),
175 ToAddress(0x1230));
176
177 processor.Stop();
178 processor.Join();
Leon Clarkef7060e22010-06-03 12:02:55 +0100179 CpuProfile* profile =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100180 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100181 CHECK_NE(NULL, profile);
182
183 // Check call trees.
184 const i::List<ProfileNode*>* top_down_root_children =
185 profile->top_down()->root()->children();
186 CHECK_EQ(1, top_down_root_children->length());
187 CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
188 const i::List<ProfileNode*>* top_down_bbb_children =
189 top_down_root_children->last()->children();
190 CHECK_EQ(1, top_down_bbb_children->length());
191 CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
192 const i::List<ProfileNode*>* top_down_stub_children =
193 top_down_bbb_children->last()->children();
194 CHECK_EQ(1, top_down_stub_children->length());
195 CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
196 const i::List<ProfileNode*>* top_down_ddd_children =
197 top_down_stub_children->last()->children();
198 CHECK_EQ(0, top_down_ddd_children->length());
199
200 const i::List<ProfileNode*>* bottom_up_root_children_unsorted =
201 profile->bottom_up()->root()->children();
202 CHECK_EQ(3, bottom_up_root_children_unsorted->length());
203 i::List<ProfileNode*> bottom_up_root_children(3);
204 bottom_up_root_children.AddAll(*bottom_up_root_children_unsorted);
205 bottom_up_root_children.Sort(&CompareProfileNodes);
206 CHECK_EQ("5", bottom_up_root_children[0]->entry()->name());
207 CHECK_EQ("bbb", bottom_up_root_children[1]->entry()->name());
208 CHECK_EQ("ddd", bottom_up_root_children[2]->entry()->name());
209 const i::List<ProfileNode*>* bottom_up_stub_children =
210 bottom_up_root_children[0]->children();
211 CHECK_EQ(1, bottom_up_stub_children->length());
212 CHECK_EQ("bbb", bottom_up_stub_children->last()->entry()->name());
213 const i::List<ProfileNode*>* bottom_up_bbb_children =
214 bottom_up_root_children[1]->children();
215 CHECK_EQ(0, bottom_up_bbb_children->length());
216 const i::List<ProfileNode*>* bottom_up_ddd_children =
217 bottom_up_root_children[2]->children();
218 CHECK_EQ(1, bottom_up_ddd_children->length());
219 CHECK_EQ("5", bottom_up_ddd_children->last()->entry()->name());
220 const i::List<ProfileNode*>* bottom_up_ddd_stub_children =
221 bottom_up_ddd_children->last()->children();
222 CHECK_EQ(1, bottom_up_ddd_stub_children->length());
223 CHECK_EQ("bbb", bottom_up_ddd_stub_children->last()->entry()->name());
224}
225
Iain Merrick75681382010-08-19 15:07:18 +0100226
227// http://crbug/51594
228// This test must not crash.
229TEST(CrashIfStoppingLastNonExistentProfile) {
230 InitializeVM();
231 TestSetup test_setup;
232 CpuProfiler::Setup();
233 CpuProfiler::StartProfiling("1");
234 CpuProfiler::StopProfiling("2");
235 CpuProfiler::StartProfiling("1");
236 CpuProfiler::StopProfiling("");
237 CpuProfiler::TearDown();
238}
239
Steve Block44f0eee2011-05-26 01:26:41 +0100240
Steve Block053d10c2011-06-13 19:13:29 +0100241// http://code.google.com/p/v8/issues/detail?id=1398
242// Long stacks (exceeding max frames limit) must not be erased.
243TEST(Issue1398) {
244 TestSetup test_setup;
245 CpuProfilesCollection profiles;
246 profiles.StartProfiling("", 1);
247 ProfileGenerator generator(&profiles);
248 ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
249 processor.Start();
250 while (!processor.running()) {
251 i::Thread::YieldCPU();
252 }
253
254 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
255 "bbb",
256 ToAddress(0x1200),
257 0x80);
258
259 i::TickSample* sample = processor.TickSampleEvent();
260 sample->pc = ToAddress(0x1200);
261 sample->tos = 0;
262 sample->frames_count = i::TickSample::kMaxFramesCount;
263 for (int i = 0; i < sample->frames_count; ++i) {
264 sample->stack[i] = ToAddress(0x1200);
265 }
266
267 processor.Stop();
268 processor.Join();
269 CpuProfile* profile =
270 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
271 CHECK_NE(NULL, profile);
272
273 int actual_depth = 0;
274 const ProfileNode* node = profile->top_down()->root();
275 while (node->children()->length() > 0) {
276 node = node->children()->last();
277 ++actual_depth;
278 }
279
280 CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
281}
282
283
Steve Block44f0eee2011-05-26 01:26:41 +0100284TEST(DeleteAllCpuProfiles) {
285 InitializeVM();
286 TestSetup test_setup;
287 CpuProfiler::Setup();
288 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
289 CpuProfiler::DeleteAllProfiles();
290 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
291
292 CpuProfiler::StartProfiling("1");
293 CpuProfiler::StopProfiling("1");
294 CHECK_EQ(1, CpuProfiler::GetProfilesCount());
295 CpuProfiler::DeleteAllProfiles();
296 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
297 CpuProfiler::StartProfiling("1");
298 CpuProfiler::StartProfiling("2");
299 CpuProfiler::StopProfiling("2");
300 CpuProfiler::StopProfiling("1");
301 CHECK_EQ(2, CpuProfiler::GetProfilesCount());
302 CpuProfiler::DeleteAllProfiles();
303 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
304
305 // Test profiling cancellation by the 'delete' command.
306 CpuProfiler::StartProfiling("1");
307 CpuProfiler::StartProfiling("2");
308 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
309 CpuProfiler::DeleteAllProfiles();
310 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
311
312 CpuProfiler::TearDown();
313}
314
315
316TEST(DeleteCpuProfile) {
317 v8::HandleScope scope;
318 LocalContext env;
319
320 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
321 v8::Local<v8::String> name1 = v8::String::New("1");
322 v8::CpuProfiler::StartProfiling(name1);
323 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
324 CHECK_NE(NULL, p1);
325 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
326 unsigned uid1 = p1->GetUid();
327 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
328 const_cast<v8::CpuProfile*>(p1)->Delete();
329 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
330 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
331
332 v8::Local<v8::String> name2 = v8::String::New("2");
333 v8::CpuProfiler::StartProfiling(name2);
334 const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2);
335 CHECK_NE(NULL, p2);
336 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
337 unsigned uid2 = p2->GetUid();
338 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
339 CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2));
340 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
341 v8::Local<v8::String> name3 = v8::String::New("3");
342 v8::CpuProfiler::StartProfiling(name3);
343 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
344 CHECK_NE(NULL, p3);
345 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
346 unsigned uid3 = p3->GetUid();
347 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
348 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
349 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
350 const_cast<v8::CpuProfile*>(p2)->Delete();
351 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
352 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
353 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
354 const_cast<v8::CpuProfile*>(p3)->Delete();
355 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
356 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
357 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
358 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
359}
360
361
362TEST(DeleteCpuProfileDifferentTokens) {
363 v8::HandleScope scope;
364 LocalContext env;
365
366 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
367 v8::Local<v8::String> name1 = v8::String::New("1");
368 v8::CpuProfiler::StartProfiling(name1);
369 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
370 CHECK_NE(NULL, p1);
371 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
372 unsigned uid1 = p1->GetUid();
373 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
374 v8::Local<v8::String> token1 = v8::String::New("token1");
375 const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1);
376 CHECK_NE(NULL, p1_t1);
377 CHECK_NE(p1, p1_t1);
378 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
379 const_cast<v8::CpuProfile*>(p1)->Delete();
380 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
381 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
382 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1));
383 const_cast<v8::CpuProfile*>(p1_t1)->Delete();
384 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
385
386 v8::Local<v8::String> name2 = v8::String::New("2");
387 v8::CpuProfiler::StartProfiling(name2);
388 v8::Local<v8::String> token2 = v8::String::New("token2");
389 const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2);
390 CHECK_NE(NULL, p2_t2);
391 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
392 unsigned uid2 = p2_t2->GetUid();
393 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
394 const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2);
395 CHECK_NE(p2_t2, p2);
396 v8::Local<v8::String> name3 = v8::String::New("3");
397 v8::CpuProfiler::StartProfiling(name3);
398 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
399 CHECK_NE(NULL, p3);
400 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
401 unsigned uid3 = p3->GetUid();
402 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
403 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
404 const_cast<v8::CpuProfile*>(p2_t2)->Delete();
405 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
406 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
407 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
408 const_cast<v8::CpuProfile*>(p2)->Delete();
409 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
410 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
411 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
412 const_cast<v8::CpuProfile*>(p3)->Delete();
413 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
414 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
415}
416
Steve Block6ded16b2010-05-10 14:33:55 +0100417#endif // ENABLE_LOGGING_AND_PROFILING