Upstream version 7.36.152.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-cpu-profiler.cc
1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 // Tests of profiles generator and utilities.
29
30 #include "v8.h"
31 #include "cpu-profiler-inl.h"
32 #include "cctest.h"
33 #include "platform.h"
34 #include "profiler-extension.h"
35 #include "smart-pointers.h"
36 #include "utils.h"
37 #include "../include/v8-profiler.h"
38 using i::CodeEntry;
39 using i::CpuProfile;
40 using i::CpuProfiler;
41 using i::CpuProfilesCollection;
42 using i::Heap;
43 using i::ProfileGenerator;
44 using i::ProfileNode;
45 using i::ProfilerEventsProcessor;
46 using i::ScopedVector;
47 using i::SmartPointer;
48 using i::TimeDelta;
49 using i::Vector;
50
51
52 TEST(StartStop) {
53   i::Isolate* isolate = CcTest::i_isolate();
54   CpuProfilesCollection profiles(isolate->heap());
55   ProfileGenerator generator(&profiles);
56   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
57           &generator, NULL, TimeDelta::FromMicroseconds(100)));
58   processor->Start();
59   processor->StopSynchronously();
60 }
61
62
63 static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
64                                    i::Address frame1,
65                                    i::Address frame2 = NULL,
66                                    i::Address frame3 = NULL) {
67   i::TickSample* sample = proc->StartTickSample();
68   sample->pc = frame1;
69   sample->tos = frame1;
70   sample->frames_count = 0;
71   if (frame2 != NULL) {
72     sample->stack[0] = frame2;
73     sample->frames_count = 1;
74   }
75   if (frame3 != NULL) {
76     sample->stack[1] = frame3;
77     sample->frames_count = 2;
78   }
79   proc->FinishTickSample();
80 }
81
82 namespace {
83
84 class TestSetup {
85  public:
86   TestSetup()
87       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
88     i::FLAG_prof_browser_mode = false;
89   }
90
91   ~TestSetup() {
92     i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
93   }
94
95  private:
96   bool old_flag_prof_browser_mode_;
97 };
98
99 }  // namespace
100
101
102 i::Code* CreateCode(LocalContext* env) {
103   static int counter = 0;
104   i::EmbeddedVector<char, 256> script;
105   i::EmbeddedVector<char, 32> name;
106
107   i::OS::SNPrintF(name, "function_%d", ++counter);
108   const char* name_start = name.start();
109   i::OS::SNPrintF(script,
110       "function %s() {\n"
111            "var counter = 0;\n"
112            "for (var i = 0; i < %d; ++i) counter += i;\n"
113            "return '%s_' + counter;\n"
114        "}\n"
115        "%s();\n", name_start, counter, name_start, name_start);
116   CompileRun(script.start());
117   i::Handle<i::JSFunction> fun = v8::Utils::OpenHandle(
118       *v8::Local<v8::Function>::Cast(
119           (*env)->Global()->Get(v8_str(name_start))));
120   return fun->code();
121 }
122
123
124 TEST(CodeEvents) {
125   CcTest::InitializeVM();
126   LocalContext env;
127   i::Isolate* isolate = CcTest::i_isolate();
128   i::Factory* factory = isolate->factory();
129   TestSetup test_setup;
130
131   i::HandleScope scope(isolate);
132
133   i::Code* aaa_code = CreateCode(&env);
134   i::Code* comment_code = CreateCode(&env);
135   i::Code* args5_code = CreateCode(&env);
136   i::Code* comment2_code = CreateCode(&env);
137   i::Code* moved_code = CreateCode(&env);
138   i::Code* args3_code = CreateCode(&env);
139   i::Code* args4_code = CreateCode(&env);
140
141   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
142   profiles->StartProfiling("", false);
143   ProfileGenerator generator(profiles);
144   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
145           &generator, NULL, TimeDelta::FromMicroseconds(100)));
146   processor->Start();
147   CpuProfiler profiler(isolate, profiles, &generator, processor.get());
148
149   // Enqueue code creation events.
150   const char* aaa_str = "aaa";
151   i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str);
152   profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code, *aaa_name);
153   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code, "comment");
154   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5);
155   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code, "comment2");
156   profiler.CodeMoveEvent(comment2_code->address(), moved_code->address());
157   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3);
158   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4);
159
160   // Enqueue a tick event to enable code events processing.
161   EnqueueTickSampleEvent(processor.get(), aaa_code->address());
162
163   processor->StopSynchronously();
164
165   // Check the state of profile generator.
166   CodeEntry* aaa = generator.code_map()->FindEntry(aaa_code->address());
167   CHECK_NE(NULL, aaa);
168   CHECK_EQ(aaa_str, aaa->name());
169
170   CodeEntry* comment = generator.code_map()->FindEntry(comment_code->address());
171   CHECK_NE(NULL, comment);
172   CHECK_EQ("comment", comment->name());
173
174   CodeEntry* args5 = generator.code_map()->FindEntry(args5_code->address());
175   CHECK_NE(NULL, args5);
176   CHECK_EQ("5", args5->name());
177
178   CHECK_EQ(NULL, generator.code_map()->FindEntry(comment2_code->address()));
179
180   CodeEntry* comment2 = generator.code_map()->FindEntry(moved_code->address());
181   CHECK_NE(NULL, comment2);
182   CHECK_EQ("comment2", comment2->name());
183 }
184
185
186 template<typename T>
187 static int CompareProfileNodes(const T* p1, const T* p2) {
188   return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
189 }
190
191
192 TEST(TickEvents) {
193   TestSetup test_setup;
194   LocalContext env;
195   i::Isolate* isolate = CcTest::i_isolate();
196   i::HandleScope scope(isolate);
197
198   i::Code* frame1_code = CreateCode(&env);
199   i::Code* frame2_code = CreateCode(&env);
200   i::Code* frame3_code = CreateCode(&env);
201
202   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
203   profiles->StartProfiling("", false);
204   ProfileGenerator generator(profiles);
205   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
206           &generator, NULL, TimeDelta::FromMicroseconds(100)));
207   processor->Start();
208   CpuProfiler profiler(isolate, profiles, &generator, processor.get());
209
210   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
211   profiler.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5);
212   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
213
214   EnqueueTickSampleEvent(processor.get(), frame1_code->instruction_start());
215   EnqueueTickSampleEvent(
216       processor.get(),
217       frame2_code->instruction_start() + frame2_code->ExecutableSize() / 2,
218       frame1_code->instruction_start() + frame2_code->ExecutableSize() / 2);
219   EnqueueTickSampleEvent(
220       processor.get(),
221       frame3_code->instruction_end() - 1,
222       frame2_code->instruction_end() - 1,
223       frame1_code->instruction_end() - 1);
224
225   processor->StopSynchronously();
226   CpuProfile* profile = profiles->StopProfiling("");
227   CHECK_NE(NULL, profile);
228
229   // Check call trees.
230   const i::List<ProfileNode*>* top_down_root_children =
231       profile->top_down()->root()->children();
232   CHECK_EQ(1, top_down_root_children->length());
233   CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
234   const i::List<ProfileNode*>* top_down_bbb_children =
235       top_down_root_children->last()->children();
236   CHECK_EQ(1, top_down_bbb_children->length());
237   CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
238   const i::List<ProfileNode*>* top_down_stub_children =
239       top_down_bbb_children->last()->children();
240   CHECK_EQ(1, top_down_stub_children->length());
241   CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
242   const i::List<ProfileNode*>* top_down_ddd_children =
243       top_down_stub_children->last()->children();
244   CHECK_EQ(0, top_down_ddd_children->length());
245 }
246
247
248 // http://crbug/51594
249 // This test must not crash.
250 TEST(CrashIfStoppingLastNonExistentProfile) {
251   CcTest::InitializeVM();
252   TestSetup test_setup;
253   CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
254   profiler->StartProfiling("1");
255   profiler->StopProfiling("2");
256   profiler->StartProfiling("1");
257   profiler->StopProfiling("");
258 }
259
260
261 // http://code.google.com/p/v8/issues/detail?id=1398
262 // Long stacks (exceeding max frames limit) must not be erased.
263 TEST(Issue1398) {
264   TestSetup test_setup;
265   LocalContext env;
266   i::Isolate* isolate = CcTest::i_isolate();
267   i::HandleScope scope(isolate);
268
269   i::Code* code = CreateCode(&env);
270
271   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
272   profiles->StartProfiling("", false);
273   ProfileGenerator generator(profiles);
274   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
275           &generator, NULL, TimeDelta::FromMicroseconds(100)));
276   processor->Start();
277   CpuProfiler profiler(isolate, profiles, &generator, processor.get());
278
279   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
280
281   i::TickSample* sample = processor->StartTickSample();
282   sample->pc = code->address();
283   sample->tos = 0;
284   sample->frames_count = i::TickSample::kMaxFramesCount;
285   for (int i = 0; i < sample->frames_count; ++i) {
286     sample->stack[i] = code->address();
287   }
288   processor->FinishTickSample();
289
290   processor->StopSynchronously();
291   CpuProfile* profile = profiles->StopProfiling("");
292   CHECK_NE(NULL, profile);
293
294   int actual_depth = 0;
295   const ProfileNode* node = profile->top_down()->root();
296   while (node->children()->length() > 0) {
297     node = node->children()->last();
298     ++actual_depth;
299   }
300
301   CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth);  // +1 for PC.
302 }
303
304
305 TEST(DeleteAllCpuProfiles) {
306   CcTest::InitializeVM();
307   TestSetup test_setup;
308   CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
309   CHECK_EQ(0, profiler->GetProfilesCount());
310   profiler->DeleteAllProfiles();
311   CHECK_EQ(0, profiler->GetProfilesCount());
312
313   profiler->StartProfiling("1");
314   profiler->StopProfiling("1");
315   CHECK_EQ(1, profiler->GetProfilesCount());
316   profiler->DeleteAllProfiles();
317   CHECK_EQ(0, profiler->GetProfilesCount());
318   profiler->StartProfiling("1");
319   profiler->StartProfiling("2");
320   profiler->StopProfiling("2");
321   profiler->StopProfiling("1");
322   CHECK_EQ(2, profiler->GetProfilesCount());
323   profiler->DeleteAllProfiles();
324   CHECK_EQ(0, profiler->GetProfilesCount());
325
326   // Test profiling cancellation by the 'delete' command.
327   profiler->StartProfiling("1");
328   profiler->StartProfiling("2");
329   CHECK_EQ(0, profiler->GetProfilesCount());
330   profiler->DeleteAllProfiles();
331   CHECK_EQ(0, profiler->GetProfilesCount());
332 }
333
334
335 static bool FindCpuProfile(v8::CpuProfiler* v8profiler,
336                            const v8::CpuProfile* v8profile) {
337   i::CpuProfiler* profiler = reinterpret_cast<i::CpuProfiler*>(v8profiler);
338   const i::CpuProfile* profile =
339       reinterpret_cast<const i::CpuProfile*>(v8profile);
340   int length = profiler->GetProfilesCount();
341   for (int i = 0; i < length; i++) {
342     if (profile == profiler->GetProfile(i))
343       return true;
344   }
345   return false;
346 }
347
348
349 TEST(DeleteCpuProfile) {
350   LocalContext env;
351   v8::HandleScope scope(env->GetIsolate());
352   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
353   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(cpu_profiler);
354
355   CHECK_EQ(0, iprofiler->GetProfilesCount());
356   v8::Local<v8::String> name1 = v8::String::NewFromUtf8(env->GetIsolate(), "1");
357   cpu_profiler->StartProfiling(name1);
358   v8::CpuProfile* p1 = cpu_profiler->StopProfiling(name1);
359   CHECK_NE(NULL, p1);
360   CHECK_EQ(1, iprofiler->GetProfilesCount());
361   CHECK(FindCpuProfile(cpu_profiler, p1));
362   p1->Delete();
363   CHECK_EQ(0, iprofiler->GetProfilesCount());
364
365   v8::Local<v8::String> name2 = v8::String::NewFromUtf8(env->GetIsolate(), "2");
366   cpu_profiler->StartProfiling(name2);
367   v8::CpuProfile* p2 = cpu_profiler->StopProfiling(name2);
368   CHECK_NE(NULL, p2);
369   CHECK_EQ(1, iprofiler->GetProfilesCount());
370   CHECK(FindCpuProfile(cpu_profiler, p2));
371   v8::Local<v8::String> name3 = v8::String::NewFromUtf8(env->GetIsolate(), "3");
372   cpu_profiler->StartProfiling(name3);
373   v8::CpuProfile* p3 = cpu_profiler->StopProfiling(name3);
374   CHECK_NE(NULL, p3);
375   CHECK_EQ(2, iprofiler->GetProfilesCount());
376   CHECK_NE(p2, p3);
377   CHECK(FindCpuProfile(cpu_profiler, p3));
378   CHECK(FindCpuProfile(cpu_profiler, p2));
379   p2->Delete();
380   CHECK_EQ(1, iprofiler->GetProfilesCount());
381   CHECK(!FindCpuProfile(cpu_profiler, p2));
382   CHECK(FindCpuProfile(cpu_profiler, p3));
383   p3->Delete();
384   CHECK_EQ(0, iprofiler->GetProfilesCount());
385 }
386
387
388 TEST(ProfileStartEndTime) {
389   LocalContext env;
390   v8::HandleScope scope(env->GetIsolate());
391   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
392
393   v8::Local<v8::String> profile_name =
394       v8::String::NewFromUtf8(env->GetIsolate(), "test");
395   cpu_profiler->StartProfiling(profile_name);
396   const v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
397   CHECK(profile->GetStartTime() <= profile->GetEndTime());
398 }
399
400
401 static v8::CpuProfile* RunProfiler(
402     v8::Handle<v8::Context> env, v8::Handle<v8::Function> function,
403     v8::Handle<v8::Value> argv[], int argc,
404     unsigned min_js_samples, bool collect_samples = false) {
405   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
406   v8::Local<v8::String> profile_name =
407       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile");
408
409   cpu_profiler->StartProfiling(profile_name, collect_samples);
410
411   i::Sampler* sampler =
412       reinterpret_cast<i::Isolate*>(env->GetIsolate())->logger()->sampler();
413   sampler->StartCountingSamples();
414   do {
415     function->Call(env->Global(), argc, argv);
416   } while (sampler->js_and_external_sample_count() < min_js_samples);
417
418   v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
419
420   CHECK_NE(NULL, profile);
421   // Dump collected profile to have a better diagnostic in case of failure.
422   reinterpret_cast<i::CpuProfile*>(profile)->Print();
423
424   return profile;
425 }
426
427
428 static bool ContainsString(v8::Handle<v8::String> string,
429                            const Vector<v8::Handle<v8::String> >& vector) {
430   for (int i = 0; i < vector.length(); i++) {
431     if (string->Equals(vector[i]))
432       return true;
433   }
434   return false;
435 }
436
437
438 static void CheckChildrenNames(const v8::CpuProfileNode* node,
439                                const Vector<v8::Handle<v8::String> >& names) {
440   int count = node->GetChildrenCount();
441   for (int i = 0; i < count; i++) {
442     v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
443     CHECK(ContainsString(name, names));
444     // Check that there are no duplicates.
445     for (int j = 0; j < count; j++) {
446       if (j == i) continue;
447       CHECK_NE(name, node->GetChild(j)->GetFunctionName());
448     }
449   }
450 }
451
452
453 static const v8::CpuProfileNode* FindChild(v8::Isolate* isolate,
454                                            const v8::CpuProfileNode* node,
455                                            const char* name) {
456   int count = node->GetChildrenCount();
457   v8::Handle<v8::String> nameHandle = v8::String::NewFromUtf8(isolate, name);
458   for (int i = 0; i < count; i++) {
459     const v8::CpuProfileNode* child = node->GetChild(i);
460     if (nameHandle->Equals(child->GetFunctionName())) return child;
461   }
462   return NULL;
463 }
464
465
466 static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate,
467                                           const v8::CpuProfileNode* node,
468                                           const char* name) {
469   const v8::CpuProfileNode* result = FindChild(isolate, node, name);
470   if (!result) {
471     char buffer[100];
472     i::OS::SNPrintF(Vector<char>(buffer, ARRAY_SIZE(buffer)),
473                     "Failed to GetChild: %s", name);
474     FATAL(buffer);
475   }
476   return result;
477 }
478
479
480 static void CheckSimpleBranch(v8::Isolate* isolate,
481                               const v8::CpuProfileNode* node,
482                               const char* names[], int length) {
483   for (int i = 0; i < length; i++) {
484     const char* name = names[i];
485     node = GetChild(isolate, node, name);
486     int expectedChildrenCount = (i == length - 1) ? 0 : 1;
487     CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
488   }
489 }
490
491
492 static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
493 "  this.mmm = 0;\n"
494 "  var start = Date.now();\n"
495 "  while (Date.now() - start < timeout) {\n"
496 "    var n = 100*1000;\n"
497 "    while(n > 1) {\n"
498 "      n--;\n"
499 "      this.mmm += n * n * n;\n"
500 "    }\n"
501 "  }\n"
502 "}\n"
503 "function delay() { try { loop(10); } catch(e) { } }\n"
504 "function bar() { delay(); }\n"
505 "function baz() { delay(); }\n"
506 "function foo() {\n"
507 "    try {\n"
508 "       delay();\n"
509 "       bar();\n"
510 "       delay();\n"
511 "       baz();\n"
512 "    } catch (e) { }\n"
513 "}\n"
514 "function start(timeout) {\n"
515 "  var start = Date.now();\n"
516 "  do {\n"
517 "    foo();\n"
518 "    var duration = Date.now() - start;\n"
519 "  } while (duration < timeout);\n"
520 "  return duration;\n"
521 "}\n";
522
523
524 // Check that the profile tree for the script above will look like the
525 // following:
526 //
527 // [Top down]:
528 //  1062     0   (root) [-1]
529 //  1054     0    start [-1]
530 //  1054     1      foo [-1]
531 //   265     0        baz [-1]
532 //   265     1          delay [-1]
533 //   264   264            loop [-1]
534 //   525     3        delay [-1]
535 //   522   522          loop [-1]
536 //   263     0        bar [-1]
537 //   263     1          delay [-1]
538 //   262   262            loop [-1]
539 //     2     2    (program) [-1]
540 //     6     6    (garbage collector) [-1]
541 TEST(CollectCpuProfile) {
542   LocalContext env;
543   v8::HandleScope scope(env->GetIsolate());
544
545   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
546                                               cpu_profiler_test_source))->Run();
547   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
548       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
549
550   int32_t profiling_interval_ms = 200;
551   v8::Handle<v8::Value> args[] = {
552     v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
553   };
554   v8::CpuProfile* profile =
555       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
556   function->Call(env->Global(), ARRAY_SIZE(args), args);
557
558   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
559
560   ScopedVector<v8::Handle<v8::String> > names(3);
561   names[0] = v8::String::NewFromUtf8(
562       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
563   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
564                                      ProfileGenerator::kProgramEntryName);
565   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
566   CheckChildrenNames(root, names);
567
568   const v8::CpuProfileNode* startNode =
569       GetChild(env->GetIsolate(), root, "start");
570   CHECK_EQ(1, startNode->GetChildrenCount());
571
572   const v8::CpuProfileNode* fooNode =
573       GetChild(env->GetIsolate(), startNode, "foo");
574   CHECK_EQ(3, fooNode->GetChildrenCount());
575
576   const char* barBranch[] = { "bar", "delay", "loop" };
577   CheckSimpleBranch(env->GetIsolate(), fooNode, barBranch,
578                     ARRAY_SIZE(barBranch));
579   const char* bazBranch[] = { "baz", "delay", "loop" };
580   CheckSimpleBranch(env->GetIsolate(), fooNode, bazBranch,
581                     ARRAY_SIZE(bazBranch));
582   const char* delayBranch[] = { "delay", "loop" };
583   CheckSimpleBranch(env->GetIsolate(), fooNode, delayBranch,
584                     ARRAY_SIZE(delayBranch));
585
586   profile->Delete();
587 }
588
589
590 TEST(CollectCpuProfileSamples) {
591   LocalContext env;
592   v8::HandleScope scope(env->GetIsolate());
593
594   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
595                                               cpu_profiler_test_source))->Run();
596   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
597       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
598
599   int32_t profiling_interval_ms = 200;
600   v8::Handle<v8::Value> args[] = {
601     v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
602   };
603   v8::CpuProfile* profile =
604       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200, true);
605
606   CHECK_LE(200, profile->GetSamplesCount());
607   uint64_t end_time = profile->GetEndTime();
608   uint64_t current_time = profile->GetStartTime();
609   CHECK_LE(current_time, end_time);
610   for (int i = 0; i < profile->GetSamplesCount(); i++) {
611     CHECK_NE(NULL, profile->GetSample(i));
612     uint64_t timestamp = profile->GetSampleTimestamp(i);
613     CHECK_LE(current_time, timestamp);
614     CHECK_LE(timestamp, end_time);
615     current_time = timestamp;
616   }
617
618   profile->Delete();
619 }
620
621
622 static const char* cpu_profiler_test_source2 = "function loop() {}\n"
623 "function delay() { loop(); }\n"
624 "function start(count) {\n"
625 "  var k = 0;\n"
626 "  do {\n"
627 "    delay();\n"
628 "  } while (++k < count*100*1000);\n"
629 "}\n";
630
631 // Check that the profile tree doesn't contain unexpected traces:
632 //  - 'loop' can be called only by 'delay'
633 //  - 'delay' may be called only by 'start'
634 // The profile will look like the following:
635 //
636 // [Top down]:
637 //   135     0   (root) [-1] #1
638 //   121    72    start [-1] #3
639 //    49    33      delay [-1] #4
640 //    16    16        loop [-1] #5
641 //    14    14    (program) [-1] #2
642 TEST(SampleWhenFrameIsNotSetup) {
643   LocalContext env;
644   v8::HandleScope scope(env->GetIsolate());
645
646   v8::Script::Compile(v8::String::NewFromUtf8(
647                           env->GetIsolate(), cpu_profiler_test_source2))->Run();
648   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
649       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
650
651   int32_t repeat_count = 100;
652 #if defined(USE_SIMULATOR)
653   // Simulators are much slower.
654   repeat_count = 1;
655 #endif
656   v8::Handle<v8::Value> args[] = {
657     v8::Integer::New(env->GetIsolate(), repeat_count)
658   };
659   v8::CpuProfile* profile =
660       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
661
662   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
663
664   ScopedVector<v8::Handle<v8::String> > names(3);
665   names[0] = v8::String::NewFromUtf8(
666       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
667   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
668                                      ProfileGenerator::kProgramEntryName);
669   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
670   CheckChildrenNames(root, names);
671
672   const v8::CpuProfileNode* startNode =
673       FindChild(env->GetIsolate(), root, "start");
674   // On slow machines there may be no meaningfull samples at all, skip the
675   // check there.
676   if (startNode && startNode->GetChildrenCount() > 0) {
677     CHECK_EQ(1, startNode->GetChildrenCount());
678     const v8::CpuProfileNode* delayNode =
679         GetChild(env->GetIsolate(), startNode, "delay");
680     if (delayNode->GetChildrenCount() > 0) {
681       CHECK_EQ(1, delayNode->GetChildrenCount());
682       GetChild(env->GetIsolate(), delayNode, "loop");
683     }
684   }
685
686   profile->Delete();
687 }
688
689
690 static const char* native_accessor_test_source = "function start(count) {\n"
691 "  for (var i = 0; i < count; i++) {\n"
692 "    var o = instance.foo;\n"
693 "    instance.foo = o + 1;\n"
694 "  }\n"
695 "}\n";
696
697
698 class TestApiCallbacks {
699  public:
700   explicit TestApiCallbacks(int min_duration_ms)
701       : min_duration_ms_(min_duration_ms),
702         is_warming_up_(false) {}
703
704   static void Getter(v8::Local<v8::String> name,
705                      const v8::PropertyCallbackInfo<v8::Value>& info) {
706     TestApiCallbacks* data = fromInfo(info);
707     data->Wait();
708   }
709
710   static void Setter(v8::Local<v8::String> name,
711                      v8::Local<v8::Value> value,
712                      const v8::PropertyCallbackInfo<void>& info) {
713     TestApiCallbacks* data = fromInfo(info);
714     data->Wait();
715   }
716
717   static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
718     TestApiCallbacks* data = fromInfo(info);
719     data->Wait();
720   }
721
722   void set_warming_up(bool value) { is_warming_up_ = value; }
723
724  private:
725   void Wait() {
726     if (is_warming_up_) return;
727     double start = i::OS::TimeCurrentMillis();
728     double duration = 0;
729     while (duration < min_duration_ms_) {
730       i::OS::Sleep(1);
731       duration = i::OS::TimeCurrentMillis() - start;
732     }
733   }
734
735   template<typename T>
736   static TestApiCallbacks* fromInfo(const T& info) {
737     void* data = v8::External::Cast(*info.Data())->Value();
738     return reinterpret_cast<TestApiCallbacks*>(data);
739   }
740
741   int min_duration_ms_;
742   bool is_warming_up_;
743 };
744
745
746 // Test that native accessors are properly reported in the CPU profile.
747 // This test checks the case when the long-running accessors are called
748 // only once and the optimizer doesn't have chance to change the invocation
749 // code.
750 TEST(NativeAccessorUninitializedIC) {
751   LocalContext env;
752   v8::Isolate* isolate = env->GetIsolate();
753   v8::HandleScope scope(isolate);
754
755   v8::Local<v8::FunctionTemplate> func_template =
756       v8::FunctionTemplate::New(isolate);
757   v8::Local<v8::ObjectTemplate> instance_template =
758       func_template->InstanceTemplate();
759
760   TestApiCallbacks accessors(100);
761   v8::Local<v8::External> data =
762       v8::External::New(isolate, &accessors);
763   instance_template->SetAccessor(
764       v8::String::NewFromUtf8(isolate, "foo"),
765       &TestApiCallbacks::Getter, &TestApiCallbacks::Setter, data);
766   v8::Local<v8::Function> func = func_template->GetFunction();
767   v8::Local<v8::Object> instance = func->NewInstance();
768   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
769                      instance);
770
771   v8::Script::Compile(
772       v8::String::NewFromUtf8(isolate, native_accessor_test_source))
773       ->Run();
774   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
775       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
776
777   int32_t repeat_count = 1;
778   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
779   v8::CpuProfile* profile =
780       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 180);
781
782   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
783   const v8::CpuProfileNode* startNode =
784       GetChild(isolate, root, "start");
785   GetChild(isolate, startNode, "get foo");
786   GetChild(isolate, startNode, "set foo");
787
788   profile->Delete();
789 }
790
791
792 // Test that native accessors are properly reported in the CPU profile.
793 // This test makes sure that the accessors are called enough times to become
794 // hot and to trigger optimizations.
795 TEST(NativeAccessorMonomorphicIC) {
796   LocalContext env;
797   v8::Isolate* isolate = env->GetIsolate();
798   v8::HandleScope scope(isolate);
799
800   v8::Local<v8::FunctionTemplate> func_template =
801       v8::FunctionTemplate::New(isolate);
802   v8::Local<v8::ObjectTemplate> instance_template =
803       func_template->InstanceTemplate();
804
805   TestApiCallbacks accessors(1);
806   v8::Local<v8::External> data =
807       v8::External::New(isolate, &accessors);
808   instance_template->SetAccessor(
809       v8::String::NewFromUtf8(isolate, "foo"),
810       &TestApiCallbacks::Getter, &TestApiCallbacks::Setter, data);
811   v8::Local<v8::Function> func = func_template->GetFunction();
812   v8::Local<v8::Object> instance = func->NewInstance();
813   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
814                      instance);
815
816   v8::Script::Compile(
817       v8::String::NewFromUtf8(isolate, native_accessor_test_source))
818       ->Run();
819   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
820       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
821
822   {
823     // Make sure accessors ICs are in monomorphic state before starting
824     // profiling.
825     accessors.set_warming_up(true);
826     int32_t warm_up_iterations = 3;
827     v8::Handle<v8::Value> args[] = {
828       v8::Integer::New(isolate, warm_up_iterations)
829     };
830     function->Call(env->Global(), ARRAY_SIZE(args), args);
831     accessors.set_warming_up(false);
832   }
833
834   int32_t repeat_count = 100;
835   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
836   v8::CpuProfile* profile =
837       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
838
839   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
840   const v8::CpuProfileNode* startNode =
841       GetChild(isolate, root, "start");
842   GetChild(isolate, startNode, "get foo");
843   GetChild(isolate, startNode, "set foo");
844
845   profile->Delete();
846 }
847
848
849 static const char* native_method_test_source = "function start(count) {\n"
850 "  for (var i = 0; i < count; i++) {\n"
851 "    instance.fooMethod();\n"
852 "  }\n"
853 "}\n";
854
855
856 TEST(NativeMethodUninitializedIC) {
857   LocalContext env;
858   v8::Isolate* isolate = env->GetIsolate();
859   v8::HandleScope scope(isolate);
860
861   TestApiCallbacks callbacks(100);
862   v8::Local<v8::External> data =
863       v8::External::New(isolate, &callbacks);
864
865   v8::Local<v8::FunctionTemplate> func_template =
866       v8::FunctionTemplate::New(isolate);
867   func_template->SetClassName(
868       v8::String::NewFromUtf8(isolate, "Test_InstanceCostructor"));
869   v8::Local<v8::ObjectTemplate> proto_template =
870       func_template->PrototypeTemplate();
871   v8::Local<v8::Signature> signature =
872       v8::Signature::New(isolate, func_template);
873   proto_template->Set(v8::String::NewFromUtf8(isolate, "fooMethod"),
874                       v8::FunctionTemplate::New(isolate,
875                                                 &TestApiCallbacks::Callback,
876                                                 data, signature, 0));
877
878   v8::Local<v8::Function> func = func_template->GetFunction();
879   v8::Local<v8::Object> instance = func->NewInstance();
880   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
881                      instance);
882
883   v8::Script::Compile(v8::String::NewFromUtf8(
884                           isolate, native_method_test_source))->Run();
885   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
886       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
887
888   int32_t repeat_count = 1;
889   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
890   v8::CpuProfile* profile =
891       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
892
893   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
894   const v8::CpuProfileNode* startNode =
895       GetChild(isolate, root, "start");
896   GetChild(isolate, startNode, "fooMethod");
897
898   profile->Delete();
899 }
900
901
902 TEST(NativeMethodMonomorphicIC) {
903   LocalContext env;
904   v8::Isolate* isolate = env->GetIsolate();
905   v8::HandleScope scope(isolate);
906
907   TestApiCallbacks callbacks(1);
908   v8::Local<v8::External> data =
909       v8::External::New(isolate, &callbacks);
910
911   v8::Local<v8::FunctionTemplate> func_template =
912       v8::FunctionTemplate::New(isolate);
913   func_template->SetClassName(
914       v8::String::NewFromUtf8(isolate, "Test_InstanceCostructor"));
915   v8::Local<v8::ObjectTemplate> proto_template =
916       func_template->PrototypeTemplate();
917   v8::Local<v8::Signature> signature =
918       v8::Signature::New(isolate, func_template);
919   proto_template->Set(v8::String::NewFromUtf8(isolate, "fooMethod"),
920                       v8::FunctionTemplate::New(isolate,
921                                                 &TestApiCallbacks::Callback,
922                                                 data, signature, 0));
923
924   v8::Local<v8::Function> func = func_template->GetFunction();
925   v8::Local<v8::Object> instance = func->NewInstance();
926   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
927                      instance);
928
929   v8::Script::Compile(v8::String::NewFromUtf8(
930                           isolate, native_method_test_source))->Run();
931   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
932       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
933   {
934     // Make sure method ICs are in monomorphic state before starting
935     // profiling.
936     callbacks.set_warming_up(true);
937     int32_t warm_up_iterations = 3;
938     v8::Handle<v8::Value> args[] = {
939       v8::Integer::New(isolate, warm_up_iterations)
940     };
941     function->Call(env->Global(), ARRAY_SIZE(args), args);
942     callbacks.set_warming_up(false);
943   }
944
945   int32_t repeat_count = 100;
946   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
947   v8::CpuProfile* profile =
948       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
949
950   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
951   GetChild(isolate, root, "start");
952   const v8::CpuProfileNode* startNode =
953       GetChild(isolate, root, "start");
954   GetChild(isolate, startNode, "fooMethod");
955
956   profile->Delete();
957 }
958
959
960 static const char* bound_function_test_source = "function foo(iterations) {\n"
961 "  var r = 0;\n"
962 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
963 "  return r;\n"
964 "}\n"
965 "function start(duration) {\n"
966 "  var callback = foo.bind(this);\n"
967 "  var start = Date.now();\n"
968 "  while (Date.now() - start < duration) {\n"
969 "    callback(10 * 1000);\n"
970 "  }\n"
971 "}";
972
973
974 TEST(BoundFunctionCall) {
975   LocalContext env;
976   v8::HandleScope scope(env->GetIsolate());
977
978   v8::Script::Compile(
979       v8::String::NewFromUtf8(env->GetIsolate(), bound_function_test_source))
980       ->Run();
981   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
982       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
983
984   int32_t duration_ms = 100;
985   v8::Handle<v8::Value> args[] = {
986     v8::Integer::New(env->GetIsolate(), duration_ms)
987   };
988   v8::CpuProfile* profile =
989       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
990
991   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
992   ScopedVector<v8::Handle<v8::String> > names(3);
993   names[0] = v8::String::NewFromUtf8(
994       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
995   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
996                                      ProfileGenerator::kProgramEntryName);
997   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
998   // Don't allow |foo| node to be at the top level.
999   CheckChildrenNames(root, names);
1000
1001   const v8::CpuProfileNode* startNode =
1002       GetChild(env->GetIsolate(), root, "start");
1003   GetChild(env->GetIsolate(), startNode, "foo");
1004
1005   profile->Delete();
1006 }
1007
1008
1009 // Check that the profile tree for the script below will look like the
1010 // following:
1011 //
1012 // [Top down]:
1013 //  0  (root)0 #1
1014 //  15    start 20 #3 no reason
1015 //  3      foo 20 #4 TryCatchStatement
1016 //  121        bar 20 #5 TryCatchStatement
1017 //  223          loop 20 #6 no reason
1018 //
1019 // This tests checks distribution of the samples through the source lines.
1020 // The optimizing compiler is disabled for the hotest function to make
1021 // the test deterministic.
1022
1023 static int GetHitLineSampleCount(const v8::CpuProfileNode* node) {
1024   int sampleCount = 0;
1025   unsigned int lineCount = node->GetHitLineCount();
1026   if (lineCount) {
1027     v8::LineTick* entries = new v8::LineTick[lineCount];
1028     CHECK_EQ(true, node->GetLineTicks(entries, lineCount));
1029     for (unsigned int i = 0; i < lineCount; i++) {
1030       sampleCount += entries[i].ticks;
1031     }
1032     delete [] entries;
1033   }
1034   return sampleCount;
1035 }
1036
1037
1038 void CheckHitLine(unsigned int lineNo,
1039                   const v8::CpuProfileNode* node,
1040                   unsigned int sampleTotal,
1041                   unsigned int threshold) {
1042   bool found = false;
1043
1044   unsigned int lineCount = node->GetHitLineCount();
1045   CHECK_GT(lineCount, 0);
1046
1047   v8::LineTick* entries = new v8::LineTick[lineCount];
1048   CHECK_EQ(true, node->GetLineTicks(entries, lineCount));
1049
1050   unsigned int i = 0;
1051   for (i = 0; i < lineCount; i++) {
1052     if (entries[i].line == lineNo) {
1053       found = true;
1054       break;
1055     }
1056   }
1057
1058   CHECK_EQ(true, found);
1059   CHECK_GT(entries[i].ticks * 100 / sampleTotal, threshold);
1060
1061   delete[] entries;
1062 }
1063
1064
1065 static void CheckBranchWithTickLines(v8::Isolate* isolate,
1066                                      const v8::CpuProfile* profile) {
1067   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1068
1069   const v8::CpuProfileNode* startNode =
1070       GetChild(isolate, root, "start");
1071   CHECK_EQ(1, startNode->GetChildrenCount());
1072   CHECK_EQ(startNode->GetHitCount(), GetHitLineSampleCount(startNode));
1073
1074   const v8::CpuProfileNode* fooNode =
1075       GetChild(isolate, startNode, "foo");
1076   CHECK_EQ(1, fooNode->GetChildrenCount());
1077   CHECK_EQ(fooNode->GetHitCount(), GetHitLineSampleCount(fooNode));
1078
1079   const v8::CpuProfileNode* barNode =
1080       GetChild(isolate, fooNode, "bar");
1081   CHECK_EQ(1, barNode->GetChildrenCount());
1082   CHECK_EQ(barNode->GetHitCount(), GetHitLineSampleCount(barNode));
1083   // Check that line #14 collects at least 90% of the samples.
1084   CheckHitLine(14, barNode, barNode->GetHitCount(), 90);
1085
1086   const v8::CpuProfileNode* loopNode =
1087      GetChild(isolate, barNode, "loop");
1088   CHECK_EQ(0, loopNode->GetChildrenCount());
1089   CHECK_EQ(loopNode->GetHitCount(), GetHitLineSampleCount(loopNode));
1090
1091   // Check that line #8 collects at least 70% of the samples
1092   CheckHitLine(8, loopNode, loopNode->GetHitCount(), 70);
1093 }
1094
1095
1096 static const char* cpu_profiler_test_source3 = "function loop(timeout) {\n"
1097 "  with({}); // disable the optimizing compiler for this function"
1098 "  this.mmm = 0;\n"
1099 "  var start = Date.now();\n"
1100 "  while (Date.now() - start < timeout) {\n"
1101 "    var n = 100*1000;\n"
1102 "    while(n > 1) {\n"
1103 "      n--;\n"
1104 "      this.mmm += n * n * n;\n"
1105 "    }\n"
1106 "  }\n"
1107 "}\n"
1108 "function bar() {\n"
1109 "    try {\n"
1110 "       loop(10);\n"
1111 "    } catch(e) { }\n"
1112 "}\n"
1113 "function foo() {\n"
1114 "    try {\n"
1115 "       bar();\n"
1116 "    } catch (e) { }\n"
1117 "}\n"
1118 "function start(timeout) {\n"
1119 "  var start = Date.now();\n"
1120 "  do {\n"
1121 "    foo();\n"
1122 "    var duration = Date.now() - start;\n"
1123 "  } while (duration < timeout);\n"
1124 "  return duration;\n"
1125 "}\n";
1126
1127
1128 TEST(TickLines) {
1129   LocalContext env;
1130   v8::HandleScope scope(env->GetIsolate());
1131   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1132     cpu_profiler_test_source3))->Run();
1133   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
1134     env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
1135
1136   int32_t profiling_interval_ms = 200;
1137   v8::Handle<v8::Value> args[] = {
1138       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
1139   };
1140
1141   // The first run tests distribution of the samples through the source
1142   // line information taken from "relocation info" created during code
1143   // generation.
1144   v8::CpuProfile* profile =
1145       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
1146   function->Call(env->Global(), ARRAY_SIZE(args), args);
1147   CheckBranchWithTickLines(env->GetIsolate(), profile);
1148   profile->Delete();
1149
1150   // This is a case when the precompiled functions located on the heap
1151   // are profiled. The second run tests that same source lines collect
1152   // the expected number of samples.
1153   profile = RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
1154   function->Call(env->Global(), ARRAY_SIZE(args), args);
1155   CheckBranchWithTickLines(env->GetIsolate(), profile);
1156   profile->Delete();
1157 }
1158
1159
1160 static const char* call_function_test_source = "function bar(iterations) {\n"
1161 "}\n"
1162 "function start(duration) {\n"
1163 "  var start = Date.now();\n"
1164 "  while (Date.now() - start < duration) {\n"
1165 "    try {\n"
1166 "      bar.call(this, 10 * 1000);\n"
1167 "    } catch(e) {}\n"
1168 "  }\n"
1169 "}";
1170
1171
1172 // Test that if we sampled thread when it was inside FunctionCall buitin then
1173 // its caller frame will be '(unresolved function)' as we have no reliable way
1174 // to resolve it.
1175 //
1176 // [Top down]:
1177 //    96     0   (root) [-1] #1
1178 //     1     1    (garbage collector) [-1] #4
1179 //     5     0    (unresolved function) [-1] #5
1180 //     5     5      call [-1] #6
1181 //    71    70    start [-1] #3
1182 //     1     1      bar [-1] #7
1183 //    19    19    (program) [-1] #2
1184 TEST(FunctionCallSample) {
1185   LocalContext env;
1186   v8::HandleScope scope(env->GetIsolate());
1187
1188   // Collect garbage that might have be generated while installing extensions.
1189   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1190
1191   v8::Script::Compile(v8::String::NewFromUtf8(
1192                           env->GetIsolate(), call_function_test_source))->Run();
1193   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
1194       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
1195
1196   int32_t duration_ms = 100;
1197   v8::Handle<v8::Value> args[] = {
1198     v8::Integer::New(env->GetIsolate(), duration_ms)
1199   };
1200   v8::CpuProfile* profile =
1201       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
1202
1203   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1204   {
1205     ScopedVector<v8::Handle<v8::String> > names(4);
1206     names[0] = v8::String::NewFromUtf8(
1207         env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
1208     names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
1209                                        ProfileGenerator::kProgramEntryName);
1210     names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
1211     names[3] = v8::String::NewFromUtf8(
1212         env->GetIsolate(), i::ProfileGenerator::kUnresolvedFunctionName);
1213     // Don't allow |bar| and |call| nodes to be at the top level.
1214     CheckChildrenNames(root, names);
1215   }
1216
1217   // In case of GC stress tests all samples may be in GC phase and there
1218   // won't be |start| node in the profiles.
1219   bool is_gc_stress_testing =
1220       (i::FLAG_gc_interval != -1) || i::FLAG_stress_compaction;
1221   const v8::CpuProfileNode* startNode =
1222       FindChild(env->GetIsolate(), root, "start");
1223   CHECK(is_gc_stress_testing || startNode);
1224   if (startNode) {
1225     ScopedVector<v8::Handle<v8::String> > names(2);
1226     names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "bar");
1227     names[1] = v8::String::NewFromUtf8(env->GetIsolate(), "call");
1228     CheckChildrenNames(startNode, names);
1229   }
1230
1231   const v8::CpuProfileNode* unresolvedNode = FindChild(
1232       env->GetIsolate(), root, i::ProfileGenerator::kUnresolvedFunctionName);
1233   if (unresolvedNode) {
1234     ScopedVector<v8::Handle<v8::String> > names(1);
1235     names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "call");
1236     CheckChildrenNames(unresolvedNode, names);
1237   }
1238
1239   profile->Delete();
1240 }
1241
1242
1243 static const char* function_apply_test_source = "function bar(iterations) {\n"
1244 "}\n"
1245 "function test() {\n"
1246 "  bar.apply(this, [10 * 1000]);\n"
1247 "}\n"
1248 "function start(duration) {\n"
1249 "  var start = Date.now();\n"
1250 "  while (Date.now() - start < duration) {\n"
1251 "    try {\n"
1252 "      test();\n"
1253 "    } catch(e) {}\n"
1254 "  }\n"
1255 "}";
1256
1257
1258 // [Top down]:
1259 //    94     0   (root) [-1] #0 1
1260 //     2     2    (garbage collector) [-1] #0 7
1261 //    82    49    start [-1] #16 3
1262 //     1     0      (unresolved function) [-1] #0 8
1263 //     1     1        apply [-1] #0 9
1264 //    32    21      test [-1] #16 4
1265 //     2     2        bar [-1] #16 6
1266 //     9     9        apply [-1] #0 5
1267 //    10    10    (program) [-1] #0 2
1268 TEST(FunctionApplySample) {
1269   LocalContext env;
1270   v8::HandleScope scope(env->GetIsolate());
1271
1272   v8::Script::Compile(
1273       v8::String::NewFromUtf8(env->GetIsolate(), function_apply_test_source))
1274       ->Run();
1275   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
1276       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
1277
1278   int32_t duration_ms = 100;
1279   v8::Handle<v8::Value> args[] = {
1280     v8::Integer::New(env->GetIsolate(), duration_ms)
1281   };
1282
1283   v8::CpuProfile* profile =
1284       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
1285
1286   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1287   {
1288     ScopedVector<v8::Handle<v8::String> > names(3);
1289     names[0] = v8::String::NewFromUtf8(
1290         env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
1291     names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
1292                                        ProfileGenerator::kProgramEntryName);
1293     names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
1294     // Don't allow |test|, |bar| and |apply| nodes to be at the top level.
1295     CheckChildrenNames(root, names);
1296   }
1297
1298   const v8::CpuProfileNode* startNode =
1299       FindChild(env->GetIsolate(), root, "start");
1300   if (startNode) {
1301     {
1302       ScopedVector<v8::Handle<v8::String> > names(2);
1303       names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "test");
1304       names[1] = v8::String::NewFromUtf8(
1305           env->GetIsolate(), ProfileGenerator::kUnresolvedFunctionName);
1306       CheckChildrenNames(startNode, names);
1307     }
1308
1309     const v8::CpuProfileNode* testNode =
1310         FindChild(env->GetIsolate(), startNode, "test");
1311     if (testNode) {
1312       ScopedVector<v8::Handle<v8::String> > names(2);
1313       names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "bar");
1314       names[1] = v8::String::NewFromUtf8(env->GetIsolate(), "apply");
1315       CheckChildrenNames(testNode, names);
1316     }
1317
1318     if (const v8::CpuProfileNode* unresolvedNode =
1319             FindChild(env->GetIsolate(), startNode,
1320                       ProfileGenerator::kUnresolvedFunctionName)) {
1321       ScopedVector<v8::Handle<v8::String> > names(1);
1322       names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "apply");
1323       CheckChildrenNames(unresolvedNode, names);
1324       GetChild(env->GetIsolate(), unresolvedNode, "apply");
1325     }
1326   }
1327
1328   profile->Delete();
1329 }
1330
1331
1332 static const char* js_native_js_test_source =
1333 "var is_profiling = false;\n"
1334 "function foo(iterations) {\n"
1335 "  if (!is_profiling) {\n"
1336 "    is_profiling = true;\n"
1337 "    startProfiling('my_profile');\n"
1338 "  }\n"
1339 "  var r = 0;\n"
1340 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
1341 "  return r;\n"
1342 "}\n"
1343 "function bar(iterations) {\n"
1344 "  try { foo(iterations); } catch(e) {}\n"
1345 "}\n"
1346 "function start(duration) {\n"
1347 "  var start = Date.now();\n"
1348 "  while (Date.now() - start < duration) {\n"
1349 "    try {\n"
1350 "      CallJsFunction(bar, 10 * 1000);\n"
1351 "    } catch(e) {}\n"
1352 "  }\n"
1353 "}";
1354
1355 static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
1356   v8::Handle<v8::Function> function = info[0].As<v8::Function>();
1357   v8::Handle<v8::Value> argv[] = { info[1] };
1358   function->Call(info.This(), ARRAY_SIZE(argv), argv);
1359 }
1360
1361
1362 // [Top down]:
1363 //    58     0   (root) #0 1
1364 //     2     2    (program) #0 2
1365 //    56     1    start #16 3
1366 //    55     0      CallJsFunction #0 4
1367 //    55     1        bar #16 5
1368 //    54    54          foo #16 6
1369 TEST(JsNativeJsSample) {
1370   v8::HandleScope scope(CcTest::isolate());
1371   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1372   v8::Context::Scope context_scope(env);
1373
1374   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
1375       env->GetIsolate(), CallJsFunction);
1376   v8::Local<v8::Function> func = func_template->GetFunction();
1377   func->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"));
1378   env->Global()->Set(
1379       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"), func);
1380
1381   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1382                                               js_native_js_test_source))->Run();
1383   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
1384       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
1385
1386   int32_t duration_ms = 20;
1387   v8::Handle<v8::Value> args[] = {
1388     v8::Integer::New(env->GetIsolate(), duration_ms)
1389   };
1390   v8::CpuProfile* profile =
1391       RunProfiler(env, function, args, ARRAY_SIZE(args), 10);
1392
1393   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1394   {
1395     ScopedVector<v8::Handle<v8::String> > names(3);
1396     names[0] = v8::String::NewFromUtf8(
1397         env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
1398     names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
1399                                        ProfileGenerator::kProgramEntryName);
1400     names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
1401     CheckChildrenNames(root, names);
1402   }
1403
1404   const v8::CpuProfileNode* startNode =
1405       GetChild(env->GetIsolate(), root, "start");
1406   CHECK_EQ(1, startNode->GetChildrenCount());
1407   const v8::CpuProfileNode* nativeFunctionNode =
1408       GetChild(env->GetIsolate(), startNode, "CallJsFunction");
1409
1410   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
1411   const v8::CpuProfileNode* barNode =
1412       GetChild(env->GetIsolate(), nativeFunctionNode, "bar");
1413
1414   CHECK_EQ(1, barNode->GetChildrenCount());
1415   GetChild(env->GetIsolate(), barNode, "foo");
1416
1417   profile->Delete();
1418 }
1419
1420
1421 static const char* js_native_js_runtime_js_test_source =
1422 "var is_profiling = false;\n"
1423 "function foo(iterations) {\n"
1424 "  if (!is_profiling) {\n"
1425 "    is_profiling = true;\n"
1426 "    startProfiling('my_profile');\n"
1427 "  }\n"
1428 "  var r = 0;\n"
1429 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
1430 "  return r;\n"
1431 "}\n"
1432 "var bound = foo.bind(this);\n"
1433 "function bar(iterations) {\n"
1434 "  try { bound(iterations); } catch(e) {}\n"
1435 "}\n"
1436 "function start(duration) {\n"
1437 "  var start = Date.now();\n"
1438 "  while (Date.now() - start < duration) {\n"
1439 "    try {\n"
1440 "      CallJsFunction(bar, 10 * 1000);\n"
1441 "    } catch(e) {}\n"
1442 "  }\n"
1443 "}";
1444
1445
1446 // [Top down]:
1447 //    57     0   (root) #0 1
1448 //    55     1    start #16 3
1449 //    54     0      CallJsFunction #0 4
1450 //    54     3        bar #16 5
1451 //    51    51          foo #16 6
1452 //     2     2    (program) #0 2
1453 TEST(JsNativeJsRuntimeJsSample) {
1454   v8::HandleScope scope(CcTest::isolate());
1455   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1456   v8::Context::Scope context_scope(env);
1457
1458   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
1459       env->GetIsolate(), CallJsFunction);
1460   v8::Local<v8::Function> func = func_template->GetFunction();
1461   func->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"));
1462   env->Global()->Set(
1463       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"), func);
1464
1465   v8::Script::Compile(
1466       v8::String::NewFromUtf8(env->GetIsolate(),
1467                               js_native_js_runtime_js_test_source))->Run();
1468   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
1469       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
1470
1471   int32_t duration_ms = 20;
1472   v8::Handle<v8::Value> args[] = {
1473     v8::Integer::New(env->GetIsolate(), duration_ms)
1474   };
1475   v8::CpuProfile* profile =
1476       RunProfiler(env, function, args, ARRAY_SIZE(args), 10);
1477
1478   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1479   ScopedVector<v8::Handle<v8::String> > names(3);
1480   names[0] = v8::String::NewFromUtf8(
1481       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
1482   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
1483                                      ProfileGenerator::kProgramEntryName);
1484   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
1485   CheckChildrenNames(root, names);
1486
1487   const v8::CpuProfileNode* startNode =
1488       GetChild(env->GetIsolate(), root, "start");
1489   CHECK_EQ(1, startNode->GetChildrenCount());
1490   const v8::CpuProfileNode* nativeFunctionNode =
1491       GetChild(env->GetIsolate(), startNode, "CallJsFunction");
1492
1493   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
1494   const v8::CpuProfileNode* barNode =
1495       GetChild(env->GetIsolate(), nativeFunctionNode, "bar");
1496
1497   CHECK_EQ(1, barNode->GetChildrenCount());
1498   GetChild(env->GetIsolate(), barNode, "foo");
1499
1500   profile->Delete();
1501 }
1502
1503
1504 static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
1505   CallJsFunction(info);
1506 }
1507
1508
1509 static const char* js_native1_js_native2_js_test_source =
1510 "var is_profiling = false;\n"
1511 "function foo(iterations) {\n"
1512 "  if (!is_profiling) {\n"
1513 "    is_profiling = true;\n"
1514 "    startProfiling('my_profile');\n"
1515 "  }\n"
1516 "  var r = 0;\n"
1517 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
1518 "  return r;\n"
1519 "}\n"
1520 "function bar(iterations) {\n"
1521 "  CallJsFunction2(foo, iterations);\n"
1522 "}\n"
1523 "function start(duration) {\n"
1524 "  var start = Date.now();\n"
1525 "  while (Date.now() - start < duration) {\n"
1526 "    try {\n"
1527 "      CallJsFunction1(bar, 10 * 1000);\n"
1528 "    } catch(e) {}\n"
1529 "  }\n"
1530 "}";
1531
1532
1533 // [Top down]:
1534 //    57     0   (root) #0 1
1535 //    55     1    start #16 3
1536 //    54     0      CallJsFunction1 #0 4
1537 //    54     0        bar #16 5
1538 //    54     0          CallJsFunction2 #0 6
1539 //    54    54            foo #16 7
1540 //     2     2    (program) #0 2
1541 TEST(JsNative1JsNative2JsSample) {
1542   v8::HandleScope scope(CcTest::isolate());
1543   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1544   v8::Context::Scope context_scope(env);
1545
1546   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
1547       env->GetIsolate(), CallJsFunction);
1548   v8::Local<v8::Function> func1 = func_template->GetFunction();
1549   func1->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction1"));
1550   env->Global()->Set(
1551       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction1"), func1);
1552
1553   v8::Local<v8::Function> func2 = v8::FunctionTemplate::New(
1554       env->GetIsolate(), CallJsFunction2)->GetFunction();
1555   func2->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction2"));
1556   env->Global()->Set(
1557       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction2"), func2);
1558
1559   v8::Script::Compile(
1560       v8::String::NewFromUtf8(env->GetIsolate(),
1561                               js_native1_js_native2_js_test_source))->Run();
1562   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
1563       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
1564
1565   int32_t duration_ms = 20;
1566   v8::Handle<v8::Value> args[] = {
1567     v8::Integer::New(env->GetIsolate(), duration_ms)
1568   };
1569   v8::CpuProfile* profile =
1570       RunProfiler(env, function, args, ARRAY_SIZE(args), 10);
1571
1572   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1573   ScopedVector<v8::Handle<v8::String> > names(3);
1574   names[0] = v8::String::NewFromUtf8(
1575       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
1576   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
1577                                      ProfileGenerator::kProgramEntryName);
1578   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
1579   CheckChildrenNames(root, names);
1580
1581   const v8::CpuProfileNode* startNode =
1582       GetChild(env->GetIsolate(), root, "start");
1583   CHECK_EQ(1, startNode->GetChildrenCount());
1584   const v8::CpuProfileNode* nativeNode1 =
1585       GetChild(env->GetIsolate(), startNode, "CallJsFunction1");
1586
1587   CHECK_EQ(1, nativeNode1->GetChildrenCount());
1588   const v8::CpuProfileNode* barNode =
1589       GetChild(env->GetIsolate(), nativeNode1, "bar");
1590
1591   CHECK_EQ(1, barNode->GetChildrenCount());
1592   const v8::CpuProfileNode* nativeNode2 =
1593       GetChild(env->GetIsolate(), barNode, "CallJsFunction2");
1594
1595   CHECK_EQ(1, nativeNode2->GetChildrenCount());
1596   GetChild(env->GetIsolate(), nativeNode2, "foo");
1597
1598   profile->Delete();
1599 }
1600
1601
1602 // [Top down]:
1603 //     6     0   (root) #0 1
1604 //     3     3    (program) #0 2
1605 //     3     3    (idle) #0 3
1606 TEST(IdleTime) {
1607   LocalContext env;
1608   v8::HandleScope scope(env->GetIsolate());
1609   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
1610
1611   v8::Local<v8::String> profile_name =
1612       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile");
1613   cpu_profiler->StartProfiling(profile_name);
1614
1615   i::Isolate* isolate = CcTest::i_isolate();
1616   i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor();
1617   processor->AddCurrentStack(isolate);
1618
1619   cpu_profiler->SetIdle(true);
1620
1621   for (int i = 0; i < 3; i++) {
1622     processor->AddCurrentStack(isolate);
1623   }
1624
1625   cpu_profiler->SetIdle(false);
1626   processor->AddCurrentStack(isolate);
1627
1628
1629   v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
1630   CHECK_NE(NULL, profile);
1631   // Dump collected profile to have a better diagnostic in case of failure.
1632   reinterpret_cast<i::CpuProfile*>(profile)->Print();
1633
1634   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1635   ScopedVector<v8::Handle<v8::String> > names(3);
1636   names[0] = v8::String::NewFromUtf8(
1637       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
1638   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
1639                                      ProfileGenerator::kProgramEntryName);
1640   names[2] = v8::String::NewFromUtf8(env->GetIsolate(),
1641                                      ProfileGenerator::kIdleEntryName);
1642   CheckChildrenNames(root, names);
1643
1644   const v8::CpuProfileNode* programNode =
1645       GetChild(env->GetIsolate(), root, ProfileGenerator::kProgramEntryName);
1646   CHECK_EQ(0, programNode->GetChildrenCount());
1647   CHECK_GE(programNode->GetHitCount(), 3);
1648
1649   const v8::CpuProfileNode* idleNode =
1650       GetChild(env->GetIsolate(), root, ProfileGenerator::kIdleEntryName);
1651   CHECK_EQ(0, idleNode->GetChildrenCount());
1652   CHECK_GE(idleNode->GetHitCount(), 3);
1653
1654   profile->Delete();
1655 }
1656
1657
1658 static void CheckFunctionDetails(v8::Isolate* isolate,
1659                                  const v8::CpuProfileNode* node,
1660                                  const char* name, const char* script_name,
1661                                  int script_id, int line, int column) {
1662   CHECK_EQ(v8::String::NewFromUtf8(isolate, name),
1663            node->GetFunctionName());
1664   CHECK_EQ(v8::String::NewFromUtf8(isolate, script_name),
1665            node->GetScriptResourceName());
1666   CHECK_EQ(script_id, node->GetScriptId());
1667   CHECK_EQ(line, node->GetLineNumber());
1668   CHECK_EQ(column, node->GetColumnNumber());
1669 }
1670
1671
1672 TEST(FunctionDetails) {
1673   v8::HandleScope scope(CcTest::isolate());
1674   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1675   v8::Context::Scope context_scope(env);
1676
1677   v8::Handle<v8::Script> script_a = CompileWithOrigin(
1678           "    function foo\n() { try { bar(); } catch(e) {} }\n"
1679           " function bar() { startProfiling(); }\n",
1680           "script_a");
1681   script_a->Run();
1682   v8::Handle<v8::Script> script_b = CompileWithOrigin(
1683           "\n\n   function baz() { try { foo(); } catch(e) {} }\n"
1684           "\n\nbaz();\n"
1685           "stopProfiling();\n",
1686           "script_b");
1687   script_b->Run();
1688   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
1689   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
1690   reinterpret_cast<ProfileNode*>(
1691       const_cast<v8::CpuProfileNode*>(current))->Print(0);
1692   // The tree should look like this:
1693   //  0   (root) 0 #1
1694   //  0    (anonymous function) 19 #2 no reason script_b:1
1695   //  0      baz 19 #3 TryCatchStatement script_b:3
1696   //  0        foo 18 #4 TryCatchStatement script_a:2
1697   //  1          bar 18 #5 no reason script_a:3
1698   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1699   const v8::CpuProfileNode* script = GetChild(env->GetIsolate(), root,
1700       ProfileGenerator::kAnonymousFunctionName);
1701   CheckFunctionDetails(env->GetIsolate(), script,
1702                        ProfileGenerator::kAnonymousFunctionName, "script_b",
1703                        script_b->GetId(), 1, 1);
1704   const v8::CpuProfileNode* baz = GetChild(env->GetIsolate(), script, "baz");
1705   CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b",
1706                        script_b->GetId(), 3, 16);
1707   const v8::CpuProfileNode* foo = GetChild(env->GetIsolate(), baz, "foo");
1708   CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a",
1709                        script_a->GetId(), 2, 1);
1710   const v8::CpuProfileNode* bar = GetChild(env->GetIsolate(), foo, "bar");
1711   CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a",
1712                        script_a->GetId(), 3, 14);
1713 }
1714
1715
1716 TEST(DontStopOnFinishedProfileDelete) {
1717   v8::HandleScope scope(CcTest::isolate());
1718   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1719   v8::Context::Scope context_scope(env);
1720   v8::Isolate* isolate = env->GetIsolate();
1721
1722   v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
1723   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
1724
1725   CHECK_EQ(0, iprofiler->GetProfilesCount());
1726   v8::Handle<v8::String> outer = v8::String::NewFromUtf8(isolate, "outer");
1727   profiler->StartProfiling(outer);
1728   CHECK_EQ(0, iprofiler->GetProfilesCount());
1729
1730   v8::Handle<v8::String> inner = v8::String::NewFromUtf8(isolate, "inner");
1731   profiler->StartProfiling(inner);
1732   CHECK_EQ(0, iprofiler->GetProfilesCount());
1733
1734   v8::CpuProfile* inner_profile = profiler->StopProfiling(inner);
1735   CHECK(inner_profile);
1736   CHECK_EQ(1, iprofiler->GetProfilesCount());
1737   inner_profile->Delete();
1738   inner_profile = NULL;
1739   CHECK_EQ(0, iprofiler->GetProfilesCount());
1740
1741   v8::CpuProfile* outer_profile = profiler->StopProfiling(outer);
1742   CHECK(outer_profile);
1743   CHECK_EQ(1, iprofiler->GetProfilesCount());
1744   outer_profile->Delete();
1745   outer_profile = NULL;
1746   CHECK_EQ(0, iprofiler->GetProfilesCount());
1747 }