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
10using i::CodeEntry;
11using i::CpuProfile;
12using i::CpuProfiler;
13using i::CpuProfilesCollection;
14using i::ProfileGenerator;
15using i::ProfileNode;
16using i::ProfilerEventsProcessor;
17using i::TokenEnumerator;
18
19
20TEST(StartStop) {
21  CpuProfilesCollection profiles;
22  ProfileGenerator generator(&profiles);
23  ProfilerEventsProcessor processor(&generator);
24  processor.Start();
25  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;
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
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);
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
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);
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.
216TEST(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.
230TEST(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
268TEST(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
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}
400