blob: 9ff2a171a3d9baafe18d59b8514d7b44fbf37267 [file] [log] [blame]
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001// Copyright 2010 the V8 project authors. All rights reserved.
2//
3// Tests of profiles generator and utilities.
4
5#include "v8.h"
6#include "cpu-profiler-inl.h"
7#include "cctest.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008#include "../include/v8-profiler.h"
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00009
10namespace i = v8::internal;
11
12using i::CodeEntry;
lrn@chromium.org25156de2010-04-06 13:10:27 +000013using i::CpuProfile;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000014using i::CpuProfiler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000015using i::CpuProfilesCollection;
16using i::ProfileGenerator;
17using i::ProfileNode;
18using i::ProfilerEventsProcessor;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000019using i::TokenEnumerator;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000020
21
22TEST(StartStop) {
23 CpuProfilesCollection profiles;
24 ProfileGenerator generator(&profiles);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000025 ProfilerEventsProcessor processor(&generator);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000026 processor.Start();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000027 processor.Stop();
28 processor.Join();
29}
30
31static v8::Persistent<v8::Context> env;
32
33static void InitializeVM() {
34 if (env.IsEmpty()) env = v8::Context::New();
35 v8::HandleScope scope;
36 env->Enter();
37}
38
39static inline i::Address ToAddress(int n) {
40 return reinterpret_cast<i::Address>(n);
41}
42
43static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
44 i::Address frame1,
45 i::Address frame2 = NULL,
46 i::Address frame3 = NULL) {
47 i::TickSample* sample = proc->TickSampleEvent();
48 sample->pc = frame1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000049 sample->tos = frame1;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000050 sample->frames_count = 0;
51 if (frame2 != NULL) {
52 sample->stack[0] = frame2;
53 sample->frames_count = 1;
54 }
55 if (frame3 != NULL) {
56 sample->stack[1] = frame3;
57 sample->frames_count = 2;
58 }
59}
60
ager@chromium.org357bf652010-04-12 11:30:10 +000061namespace {
62
63class TestSetup {
64 public:
65 TestSetup()
66 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
67 i::FLAG_prof_browser_mode = false;
68 }
69
70 ~TestSetup() {
71 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
72 }
73
74 private:
75 bool old_flag_prof_browser_mode_;
76};
77
78} // namespace
79
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000080TEST(CodeEvents) {
81 InitializeVM();
ager@chromium.org357bf652010-04-12 11:30:10 +000082 TestSetup test_setup;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000083 CpuProfilesCollection profiles;
lrn@chromium.org25156de2010-04-06 13:10:27 +000084 profiles.StartProfiling("", 1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000085 ProfileGenerator generator(&profiles);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000086 ProfilerEventsProcessor processor(&generator);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000087 processor.Start();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000088
89 // Enqueue code creation events.
90 i::HandleScope scope;
91 const char* aaa_str = "aaa";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092 i::Handle<i::String> aaa_name = FACTORY->NewStringFromAscii(
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000093 i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000094 processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
95 *aaa_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000096 HEAP->empty_string(),
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000097 0,
98 ToAddress(0x1000),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000099 0x100,
100 ToAddress(0x10000));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000101 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
102 "bbb",
103 ToAddress(0x1200),
104 0x80);
105 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
106 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
107 "ddd",
108 ToAddress(0x1400),
109 0x80);
110 processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
111 processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
112 processor.CodeDeleteEvent(ToAddress(0x1600));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000113 // Enqueue a tick event to enable code events processing.
114 EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
115
116 processor.Stop();
117 processor.Join();
118
119 // Check the state of profile generator.
120 CodeEntry* entry1 = generator.code_map()->FindEntry(ToAddress(0x1000));
121 CHECK_NE(NULL, entry1);
122 CHECK_EQ(aaa_str, entry1->name());
123 CodeEntry* entry2 = generator.code_map()->FindEntry(ToAddress(0x1200));
124 CHECK_NE(NULL, entry2);
125 CHECK_EQ("bbb", entry2->name());
126 CodeEntry* entry3 = generator.code_map()->FindEntry(ToAddress(0x1300));
127 CHECK_NE(NULL, entry3);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000128 CHECK_EQ("5", entry3->name());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000129 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1400)));
130 CodeEntry* entry4 = generator.code_map()->FindEntry(ToAddress(0x1500));
131 CHECK_NE(NULL, entry4);
132 CHECK_EQ("ddd", entry4->name());
133 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000134}
135
136
137template<typename T>
138static int CompareProfileNodes(const T* p1, const T* p2) {
139 return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
140}
141
142TEST(TickEvents) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000143 TestSetup test_setup;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000144 CpuProfilesCollection profiles;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000145 profiles.StartProfiling("", 1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000146 ProfileGenerator generator(&profiles);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000147 ProfilerEventsProcessor processor(&generator);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000148 processor.Start();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000149
150 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
151 "bbb",
152 ToAddress(0x1200),
153 0x80);
154 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
155 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
156 "ddd",
157 ToAddress(0x1400),
158 0x80);
159 EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
160 EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
161 EnqueueTickSampleEvent(&processor,
162 ToAddress(0x1404),
163 ToAddress(0x1305),
164 ToAddress(0x1230));
165
166 processor.Stop();
167 processor.Join();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000168 CpuProfile* profile =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000169 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000170 CHECK_NE(NULL, profile);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000171
172 // Check call trees.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000173 const i::List<ProfileNode*>* top_down_root_children =
174 profile->top_down()->root()->children();
175 CHECK_EQ(1, top_down_root_children->length());
176 CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
177 const i::List<ProfileNode*>* top_down_bbb_children =
178 top_down_root_children->last()->children();
179 CHECK_EQ(1, top_down_bbb_children->length());
180 CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
181 const i::List<ProfileNode*>* top_down_stub_children =
182 top_down_bbb_children->last()->children();
183 CHECK_EQ(1, top_down_stub_children->length());
184 CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
185 const i::List<ProfileNode*>* top_down_ddd_children =
186 top_down_stub_children->last()->children();
187 CHECK_EQ(0, top_down_ddd_children->length());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000188
lrn@chromium.org25156de2010-04-06 13:10:27 +0000189 const i::List<ProfileNode*>* bottom_up_root_children_unsorted =
190 profile->bottom_up()->root()->children();
191 CHECK_EQ(3, bottom_up_root_children_unsorted->length());
192 i::List<ProfileNode*> bottom_up_root_children(3);
193 bottom_up_root_children.AddAll(*bottom_up_root_children_unsorted);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000194 bottom_up_root_children.Sort(&CompareProfileNodes);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000195 CHECK_EQ("5", bottom_up_root_children[0]->entry()->name());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000196 CHECK_EQ("bbb", bottom_up_root_children[1]->entry()->name());
197 CHECK_EQ("ddd", bottom_up_root_children[2]->entry()->name());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000198 const i::List<ProfileNode*>* bottom_up_stub_children =
199 bottom_up_root_children[0]->children();
200 CHECK_EQ(1, bottom_up_stub_children->length());
201 CHECK_EQ("bbb", bottom_up_stub_children->last()->entry()->name());
202 const i::List<ProfileNode*>* bottom_up_bbb_children =
203 bottom_up_root_children[1]->children();
204 CHECK_EQ(0, bottom_up_bbb_children->length());
205 const i::List<ProfileNode*>* bottom_up_ddd_children =
206 bottom_up_root_children[2]->children();
207 CHECK_EQ(1, bottom_up_ddd_children->length());
208 CHECK_EQ("5", bottom_up_ddd_children->last()->entry()->name());
209 const i::List<ProfileNode*>* bottom_up_ddd_stub_children =
210 bottom_up_ddd_children->last()->children();
211 CHECK_EQ(1, bottom_up_ddd_stub_children->length());
212 CHECK_EQ("bbb", bottom_up_ddd_stub_children->last()->entry()->name());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000213}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000214
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000215
216// http://crbug/51594
217// This test must not crash.
218TEST(CrashIfStoppingLastNonExistentProfile) {
219 InitializeVM();
220 TestSetup test_setup;
221 CpuProfiler::Setup();
222 CpuProfiler::StartProfiling("1");
223 CpuProfiler::StopProfiling("2");
224 CpuProfiler::StartProfiling("1");
225 CpuProfiler::StopProfiling("");
226 CpuProfiler::TearDown();
227}
228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000230// http://code.google.com/p/v8/issues/detail?id=1398
231// Long stacks (exceeding max frames limit) must not be erased.
232TEST(Issue1398) {
233 TestSetup test_setup;
234 CpuProfilesCollection profiles;
235 profiles.StartProfiling("", 1);
236 ProfileGenerator generator(&profiles);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000237 ProfilerEventsProcessor processor(&generator);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000238 processor.Start();
239
240 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
241 "bbb",
242 ToAddress(0x1200),
243 0x80);
244
245 i::TickSample* sample = processor.TickSampleEvent();
246 sample->pc = ToAddress(0x1200);
247 sample->tos = 0;
248 sample->frames_count = i::TickSample::kMaxFramesCount;
249 for (int i = 0; i < sample->frames_count; ++i) {
250 sample->stack[i] = ToAddress(0x1200);
251 }
252
253 processor.Stop();
254 processor.Join();
255 CpuProfile* profile =
256 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
257 CHECK_NE(NULL, profile);
258
259 int actual_depth = 0;
260 const ProfileNode* node = profile->top_down()->root();
261 while (node->children()->length() > 0) {
262 node = node->children()->last();
263 ++actual_depth;
264 }
265
266 CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
267}
268
269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270TEST(DeleteAllCpuProfiles) {
271 InitializeVM();
272 TestSetup test_setup;
273 CpuProfiler::Setup();
274 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
275 CpuProfiler::DeleteAllProfiles();
276 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
277
278 CpuProfiler::StartProfiling("1");
279 CpuProfiler::StopProfiling("1");
280 CHECK_EQ(1, CpuProfiler::GetProfilesCount());
281 CpuProfiler::DeleteAllProfiles();
282 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
283 CpuProfiler::StartProfiling("1");
284 CpuProfiler::StartProfiling("2");
285 CpuProfiler::StopProfiling("2");
286 CpuProfiler::StopProfiling("1");
287 CHECK_EQ(2, CpuProfiler::GetProfilesCount());
288 CpuProfiler::DeleteAllProfiles();
289 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
290
291 // Test profiling cancellation by the 'delete' command.
292 CpuProfiler::StartProfiling("1");
293 CpuProfiler::StartProfiling("2");
294 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
295 CpuProfiler::DeleteAllProfiles();
296 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
297
298 CpuProfiler::TearDown();
299}
300
301
302TEST(DeleteCpuProfile) {
303 v8::HandleScope scope;
304 LocalContext env;
305
306 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
307 v8::Local<v8::String> name1 = v8::String::New("1");
308 v8::CpuProfiler::StartProfiling(name1);
309 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
310 CHECK_NE(NULL, p1);
311 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
312 unsigned uid1 = p1->GetUid();
313 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
314 const_cast<v8::CpuProfile*>(p1)->Delete();
315 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
316 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
317
318 v8::Local<v8::String> name2 = v8::String::New("2");
319 v8::CpuProfiler::StartProfiling(name2);
320 const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2);
321 CHECK_NE(NULL, p2);
322 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
323 unsigned uid2 = p2->GetUid();
324 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
325 CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2));
326 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
327 v8::Local<v8::String> name3 = v8::String::New("3");
328 v8::CpuProfiler::StartProfiling(name3);
329 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
330 CHECK_NE(NULL, p3);
331 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
332 unsigned uid3 = p3->GetUid();
333 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
334 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
335 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
336 const_cast<v8::CpuProfile*>(p2)->Delete();
337 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
338 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
339 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
340 const_cast<v8::CpuProfile*>(p3)->Delete();
341 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
342 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
343 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
344 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
345}
346
347
348TEST(DeleteCpuProfileDifferentTokens) {
349 v8::HandleScope scope;
350 LocalContext env;
351
352 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
353 v8::Local<v8::String> name1 = v8::String::New("1");
354 v8::CpuProfiler::StartProfiling(name1);
355 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
356 CHECK_NE(NULL, p1);
357 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
358 unsigned uid1 = p1->GetUid();
359 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
360 v8::Local<v8::String> token1 = v8::String::New("token1");
361 const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1);
362 CHECK_NE(NULL, p1_t1);
363 CHECK_NE(p1, p1_t1);
364 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
365 const_cast<v8::CpuProfile*>(p1)->Delete();
366 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
367 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
368 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1));
369 const_cast<v8::CpuProfile*>(p1_t1)->Delete();
370 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
371
372 v8::Local<v8::String> name2 = v8::String::New("2");
373 v8::CpuProfiler::StartProfiling(name2);
374 v8::Local<v8::String> token2 = v8::String::New("token2");
375 const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2);
376 CHECK_NE(NULL, p2_t2);
377 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
378 unsigned uid2 = p2_t2->GetUid();
379 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
380 const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2);
381 CHECK_NE(p2_t2, p2);
382 v8::Local<v8::String> name3 = v8::String::New("3");
383 v8::CpuProfiler::StartProfiling(name3);
384 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
385 CHECK_NE(NULL, p3);
386 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
387 unsigned uid3 = p3->GetUid();
388 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
389 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
390 const_cast<v8::CpuProfile*>(p2_t2)->Delete();
391 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
392 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
393 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
394 const_cast<v8::CpuProfile*>(p2)->Delete();
395 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
396 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
397 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
398 const_cast<v8::CpuProfile*>(p3)->Delete();
399 CHECK_EQ(0, CpuProfiler::GetProfilesCount());
400 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
401}