• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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"
8 #include "../include/v8-profiler.h"
9 
10 using i::CodeEntry;
11 using i::CpuProfile;
12 using i::CpuProfiler;
13 using i::CpuProfilesCollection;
14 using i::ProfileGenerator;
15 using i::ProfileNode;
16 using i::ProfilerEventsProcessor;
17 using i::TokenEnumerator;
18 
19 
TEST(StartStop)20 TEST(StartStop) {
21   CpuProfilesCollection profiles;
22   ProfileGenerator generator(&profiles);
23   ProfilerEventsProcessor processor(&generator);
24   processor.Start();
25   processor.Stop();
26   processor.Join();
27 }
28 
29 static v8::Persistent<v8::Context> env;
30 
InitializeVM()31 static void InitializeVM() {
32   if (env.IsEmpty()) env = v8::Context::New();
33   v8::HandleScope scope;
34   env->Enter();
35 }
36 
ToAddress(int n)37 static inline i::Address ToAddress(int n) {
38   return reinterpret_cast<i::Address>(n);
39 }
40 
EnqueueTickSampleEvent(ProfilerEventsProcessor * proc,i::Address frame1,i::Address frame2=NULL,i::Address frame3=NULL)41 static 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;
47   sample->tos = frame1;
48   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 
59 namespace {
60 
61 class TestSetup {
62  public:
TestSetup()63   TestSetup()
64       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
65     i::FLAG_prof_browser_mode = false;
66   }
67 
~TestSetup()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 
TEST(CodeEvents)78 TEST(CodeEvents) {
79   InitializeVM();
80   TestSetup test_setup;
81   CpuProfilesCollection profiles;
82   profiles.StartProfiling("", 1);
83   ProfileGenerator generator(&profiles);
84   ProfilerEventsProcessor processor(&generator);
85   processor.Start();
86 
87   // Enqueue code creation events.
88   i::HandleScope scope;
89   const char* aaa_str = "aaa";
90   i::Handle<i::String> aaa_name = FACTORY->NewStringFromAscii(
91       i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
92   processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
93                             *aaa_name,
94                             HEAP->empty_string(),
95                             0,
96                             ToAddress(0x1000),
97                             0x100,
98                             ToAddress(0x10000));
99   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);
110   processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
111   // 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)));
132 }
133 
134 
135 template<typename T>
CompareProfileNodes(const T * p1,const T * p2)136 static int CompareProfileNodes(const T* p1, const T* p2) {
137   return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
138 }
139 
TEST(TickEvents)140 TEST(TickEvents) {
141   TestSetup test_setup;
142   CpuProfilesCollection profiles;
143   profiles.StartProfiling("", 1);
144   ProfileGenerator generator(&profiles);
145   ProfilerEventsProcessor processor(&generator);
146   processor.Start();
147 
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();
166   CpuProfile* profile =
167       profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
168   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 
213 
214 // http://crbug/51594
215 // This test must not crash.
TEST(CrashIfStoppingLastNonExistentProfile)216 TEST(CrashIfStoppingLastNonExistentProfile) {
217   InitializeVM();
218   TestSetup test_setup;
219   CpuProfiler::SetUp();
220   CpuProfiler::StartProfiling("1");
221   CpuProfiler::StopProfiling("2");
222   CpuProfiler::StartProfiling("1");
223   CpuProfiler::StopProfiling("");
224   CpuProfiler::TearDown();
225 }
226 
227 
228 // http://code.google.com/p/v8/issues/detail?id=1398
229 // Long stacks (exceeding max frames limit) must not be erased.
TEST(Issue1398)230 TEST(Issue1398) {
231   TestSetup test_setup;
232   CpuProfilesCollection profiles;
233   profiles.StartProfiling("", 1);
234   ProfileGenerator generator(&profiles);
235   ProfilerEventsProcessor processor(&generator);
236   processor.Start();
237 
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 
TEST(DeleteAllCpuProfiles)268 TEST(DeleteAllCpuProfiles) {
269   InitializeVM();
270   TestSetup test_setup;
271   CpuProfiler::SetUp();
272   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 
TEST(DeleteCpuProfile)300 TEST(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 
TEST(DeleteCpuProfileDifferentTokens)346 TEST(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 }
400