Home | History | Annotate | Download | only in cctest
      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 "utils.h"
     35 #include "../include/v8-profiler.h"
     36 using i::CodeEntry;
     37 using i::CpuProfile;
     38 using i::CpuProfiler;
     39 using i::CpuProfilesCollection;
     40 using i::Heap;
     41 using i::ProfileGenerator;
     42 using i::ProfileNode;
     43 using i::ProfilerEventsProcessor;
     44 using i::ScopedVector;
     45 using i::Vector;
     46 
     47 
     48 TEST(StartStop) {
     49   CpuProfilesCollection profiles;
     50   ProfileGenerator generator(&profiles);
     51   ProfilerEventsProcessor processor(&generator);
     52   processor.Start();
     53   processor.StopSynchronously();
     54   processor.Join();
     55 }
     56 
     57 
     58 static inline i::Address ToAddress(int n) {
     59   return reinterpret_cast<i::Address>(n);
     60 }
     61 
     62 static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
     63                                    i::Address frame1,
     64                                    i::Address frame2 = NULL,
     65                                    i::Address frame3 = NULL) {
     66   i::TickSample* sample = proc->TickSampleEvent();
     67   sample->pc = frame1;
     68   sample->tos = frame1;
     69   sample->frames_count = 0;
     70   if (frame2 != NULL) {
     71     sample->stack[0] = frame2;
     72     sample->frames_count = 1;
     73   }
     74   if (frame3 != NULL) {
     75     sample->stack[1] = frame3;
     76     sample->frames_count = 2;
     77   }
     78 }
     79 
     80 namespace {
     81 
     82 class TestSetup {
     83  public:
     84   TestSetup()
     85       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
     86     i::FLAG_prof_browser_mode = false;
     87   }
     88 
     89   ~TestSetup() {
     90     i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
     91   }
     92 
     93  private:
     94   bool old_flag_prof_browser_mode_;
     95 };
     96 
     97 }  // namespace
     98 
     99 
    100 i::Code* CreateCode(LocalContext* env) {
    101   static int counter = 0;
    102   i::EmbeddedVector<char, 256> script;
    103   i::EmbeddedVector<char, 32> name;
    104 
    105   i::OS::SNPrintF(name, "function_%d", ++counter);
    106   const char* name_start = name.start();
    107   i::OS::SNPrintF(script,
    108       "function %s() {\n"
    109            "var counter = 0;\n"
    110            "for (var i = 0; i < %d; ++i) counter += i;\n"
    111            "return '%s_' + counter;\n"
    112        "}\n"
    113        "%s();\n", name_start, counter, name_start, name_start);
    114   CompileRun(script.start());
    115   i::Handle<i::JSFunction> fun = v8::Utils::OpenHandle(
    116       *v8::Local<v8::Function>::Cast(
    117           (*env)->Global()->Get(v8_str(name_start))));
    118   return fun->code();
    119 }
    120 
    121 
    122 TEST(CodeEvents) {
    123   CcTest::InitializeVM();
    124   LocalContext env;
    125   i::Isolate* isolate = i::Isolate::Current();
    126   i::Factory* factory = isolate->factory();
    127   TestSetup test_setup;
    128 
    129   i::HandleScope scope(isolate);
    130 
    131   i::Code* aaa_code = CreateCode(&env);
    132   i::Code* comment_code = CreateCode(&env);
    133   i::Code* args5_code = CreateCode(&env);
    134   i::Code* comment2_code = CreateCode(&env);
    135   i::Code* moved_code = CreateCode(&env);
    136   i::Code* args3_code = CreateCode(&env);
    137   i::Code* args4_code = CreateCode(&env);
    138 
    139   CpuProfilesCollection* profiles = new CpuProfilesCollection;
    140   profiles->StartProfiling("", 1, false);
    141   ProfileGenerator generator(profiles);
    142   ProfilerEventsProcessor processor(&generator);
    143   processor.Start();
    144   CpuProfiler profiler(isolate, profiles, &generator, &processor);
    145 
    146   // Enqueue code creation events.
    147   const char* aaa_str = "aaa";
    148   i::Handle<i::String> aaa_name = factory->NewStringFromAscii(
    149       i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
    150   profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code, *aaa_name);
    151   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code, "comment");
    152   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5);
    153   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code, "comment2");
    154   profiler.CodeMoveEvent(comment2_code->address(), moved_code->address());
    155   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3);
    156   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4);
    157 
    158   // Enqueue a tick event to enable code events processing.
    159   EnqueueTickSampleEvent(&processor, aaa_code->address());
    160 
    161   processor.StopSynchronously();
    162   processor.Join();
    163 
    164   // Check the state of profile generator.
    165   CodeEntry* aaa = generator.code_map()->FindEntry(aaa_code->address());
    166   CHECK_NE(NULL, aaa);
    167   CHECK_EQ(aaa_str, aaa->name());
    168 
    169   CodeEntry* comment = generator.code_map()->FindEntry(comment_code->address());
    170   CHECK_NE(NULL, comment);
    171   CHECK_EQ("comment", comment->name());
    172 
    173   CodeEntry* args5 = generator.code_map()->FindEntry(args5_code->address());
    174   CHECK_NE(NULL, args5);
    175   CHECK_EQ("5", args5->name());
    176 
    177   CHECK_EQ(NULL, generator.code_map()->FindEntry(comment2_code->address()));
    178 
    179   CodeEntry* comment2 = generator.code_map()->FindEntry(moved_code->address());
    180   CHECK_NE(NULL, comment2);
    181   CHECK_EQ("comment2", comment2->name());
    182 }
    183 
    184 
    185 template<typename T>
    186 static int CompareProfileNodes(const T* p1, const T* p2) {
    187   return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
    188 }
    189 
    190 
    191 TEST(TickEvents) {
    192   TestSetup test_setup;
    193   LocalContext env;
    194   i::Isolate* isolate = i::Isolate::Current();
    195   i::HandleScope scope(isolate);
    196 
    197   i::Code* frame1_code = CreateCode(&env);
    198   i::Code* frame2_code = CreateCode(&env);
    199   i::Code* frame3_code = CreateCode(&env);
    200 
    201   CpuProfilesCollection* profiles = new CpuProfilesCollection;
    202   profiles->StartProfiling("", 1, false);
    203   ProfileGenerator generator(profiles);
    204   ProfilerEventsProcessor processor(&generator);
    205   processor.Start();
    206   CpuProfiler profiler(isolate, profiles, &generator, &processor);
    207 
    208   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
    209   profiler.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5);
    210   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
    211 
    212   EnqueueTickSampleEvent(&processor, frame1_code->instruction_start());
    213   EnqueueTickSampleEvent(
    214       &processor,
    215       frame2_code->instruction_start() + frame2_code->ExecutableSize() / 2,
    216       frame1_code->instruction_start() + frame2_code->ExecutableSize() / 2);
    217   EnqueueTickSampleEvent(
    218       &processor,
    219       frame3_code->instruction_end() - 1,
    220       frame2_code->instruction_end() - 1,
    221       frame1_code->instruction_end() - 1);
    222 
    223   processor.StopSynchronously();
    224   processor.Join();
    225   CpuProfile* profile = profiles->StopProfiling("");
    226   CHECK_NE(NULL, profile);
    227 
    228   // Check call trees.
    229   const i::List<ProfileNode*>* top_down_root_children =
    230       profile->top_down()->root()->children();
    231   CHECK_EQ(1, top_down_root_children->length());
    232   CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
    233   const i::List<ProfileNode*>* top_down_bbb_children =
    234       top_down_root_children->last()->children();
    235   CHECK_EQ(1, top_down_bbb_children->length());
    236   CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
    237   const i::List<ProfileNode*>* top_down_stub_children =
    238       top_down_bbb_children->last()->children();
    239   CHECK_EQ(1, top_down_stub_children->length());
    240   CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
    241   const i::List<ProfileNode*>* top_down_ddd_children =
    242       top_down_stub_children->last()->children();
    243   CHECK_EQ(0, top_down_ddd_children->length());
    244 }
    245 
    246 
    247 // http://crbug/51594
    248 // This test must not crash.
    249 TEST(CrashIfStoppingLastNonExistentProfile) {
    250   CcTest::InitializeVM();
    251   TestSetup test_setup;
    252   CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
    253   profiler->StartProfiling("1");
    254   profiler->StopProfiling("2");
    255   profiler->StartProfiling("1");
    256   profiler->StopProfiling("");
    257 }
    258 
    259 
    260 // http://code.google.com/p/v8/issues/detail?id=1398
    261 // Long stacks (exceeding max frames limit) must not be erased.
    262 TEST(Issue1398) {
    263   TestSetup test_setup;
    264   LocalContext env;
    265   i::Isolate* isolate = i::Isolate::Current();
    266   i::HandleScope scope(isolate);
    267 
    268   i::Code* code = CreateCode(&env);
    269 
    270   CpuProfilesCollection* profiles = new CpuProfilesCollection;
    271   profiles->StartProfiling("", 1, false);
    272   ProfileGenerator generator(profiles);
    273   ProfilerEventsProcessor processor(&generator);
    274   processor.Start();
    275   CpuProfiler profiler(isolate, profiles, &generator, &processor);
    276 
    277   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
    278 
    279   i::TickSample* sample = processor.TickSampleEvent();
    280   sample->pc = code->address();
    281   sample->tos = 0;
    282   sample->frames_count = i::TickSample::kMaxFramesCount;
    283   for (int i = 0; i < sample->frames_count; ++i) {
    284     sample->stack[i] = code->address();
    285   }
    286 
    287   processor.StopSynchronously();
    288   processor.Join();
    289   CpuProfile* profile = profiles->StopProfiling("");
    290   CHECK_NE(NULL, profile);
    291 
    292   int actual_depth = 0;
    293   const ProfileNode* node = profile->top_down()->root();
    294   while (node->children()->length() > 0) {
    295     node = node->children()->last();
    296     ++actual_depth;
    297   }
    298 
    299   CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth);  // +1 for PC.
    300 }
    301 
    302 
    303 TEST(DeleteAllCpuProfiles) {
    304   CcTest::InitializeVM();
    305   TestSetup test_setup;
    306   CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
    307   CHECK_EQ(0, profiler->GetProfilesCount());
    308   profiler->DeleteAllProfiles();
    309   CHECK_EQ(0, profiler->GetProfilesCount());
    310 
    311   profiler->StartProfiling("1");
    312   profiler->StopProfiling("1");
    313   CHECK_EQ(1, profiler->GetProfilesCount());
    314   profiler->DeleteAllProfiles();
    315   CHECK_EQ(0, profiler->GetProfilesCount());
    316   profiler->StartProfiling("1");
    317   profiler->StartProfiling("2");
    318   profiler->StopProfiling("2");
    319   profiler->StopProfiling("1");
    320   CHECK_EQ(2, profiler->GetProfilesCount());
    321   profiler->DeleteAllProfiles();
    322   CHECK_EQ(0, profiler->GetProfilesCount());
    323 
    324   // Test profiling cancellation by the 'delete' command.
    325   profiler->StartProfiling("1");
    326   profiler->StartProfiling("2");
    327   CHECK_EQ(0, profiler->GetProfilesCount());
    328   profiler->DeleteAllProfiles();
    329   CHECK_EQ(0, profiler->GetProfilesCount());
    330 }
    331 
    332 
    333 static const v8::CpuProfile* FindCpuProfile(v8::CpuProfiler* profiler,
    334                                             unsigned uid) {
    335   int length = profiler->GetProfileCount();
    336   for (int i = 0; i < length; i++) {
    337     const v8::CpuProfile* profile = profiler->GetCpuProfile(i);
    338     if (profile->GetUid() == uid) {
    339       return profile;
    340     }
    341   }
    342   return NULL;
    343 }
    344 
    345 
    346 TEST(DeleteCpuProfile) {
    347   LocalContext env;
    348   v8::HandleScope scope(env->GetIsolate());
    349   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    350 
    351   CHECK_EQ(0, cpu_profiler->GetProfileCount());
    352   v8::Local<v8::String> name1 = v8::String::New("1");
    353   cpu_profiler->StartCpuProfiling(name1);
    354   const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1);
    355   CHECK_NE(NULL, p1);
    356   CHECK_EQ(1, cpu_profiler->GetProfileCount());
    357   unsigned uid1 = p1->GetUid();
    358   CHECK_EQ(p1, FindCpuProfile(cpu_profiler, uid1));
    359   const_cast<v8::CpuProfile*>(p1)->Delete();
    360   CHECK_EQ(0, cpu_profiler->GetProfileCount());
    361   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid1));
    362 
    363   v8::Local<v8::String> name2 = v8::String::New("2");
    364   cpu_profiler->StartCpuProfiling(name2);
    365   const v8::CpuProfile* p2 = cpu_profiler->StopCpuProfiling(name2);
    366   CHECK_NE(NULL, p2);
    367   CHECK_EQ(1, cpu_profiler->GetProfileCount());
    368   unsigned uid2 = p2->GetUid();
    369   CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
    370   CHECK_EQ(p2, FindCpuProfile(cpu_profiler, uid2));
    371   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid1));
    372   v8::Local<v8::String> name3 = v8::String::New("3");
    373   cpu_profiler->StartCpuProfiling(name3);
    374   const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3);
    375   CHECK_NE(NULL, p3);
    376   CHECK_EQ(2, cpu_profiler->GetProfileCount());
    377   unsigned uid3 = p3->GetUid();
    378   CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
    379   CHECK_EQ(p3, FindCpuProfile(cpu_profiler, uid3));
    380   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid1));
    381   const_cast<v8::CpuProfile*>(p2)->Delete();
    382   CHECK_EQ(1, cpu_profiler->GetProfileCount());
    383   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid2));
    384   CHECK_EQ(p3, FindCpuProfile(cpu_profiler, uid3));
    385   const_cast<v8::CpuProfile*>(p3)->Delete();
    386   CHECK_EQ(0, cpu_profiler->GetProfileCount());
    387   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid3));
    388   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid2));
    389   CHECK_EQ(NULL, FindCpuProfile(cpu_profiler, uid1));
    390 }
    391 
    392 
    393 TEST(GetProfilerWhenIsolateIsNotInitialized) {
    394   v8::Isolate* isolate = v8::Isolate::GetCurrent();
    395   CHECK(i::Isolate::Current()->IsDefaultIsolate());
    396   CHECK(!i::Isolate::Current()->IsInitialized());
    397   CHECK_EQ(NULL, isolate->GetCpuProfiler());
    398   {
    399     v8::Isolate::Scope isolateScope(isolate);
    400     LocalContext env;
    401     v8::HandleScope scope(isolate);
    402     CHECK_NE(NULL, isolate->GetCpuProfiler());
    403     isolate->GetCpuProfiler()->StartCpuProfiling(v8::String::New("Test"));
    404     isolate->GetCpuProfiler()->StopCpuProfiling(v8::String::New("Test"));
    405   }
    406   CHECK(i::Isolate::Current()->IsInitialized());
    407   CHECK_NE(NULL, isolate->GetCpuProfiler());
    408   isolate->Dispose();
    409   CHECK_EQ(NULL, isolate->GetCpuProfiler());
    410 }
    411 
    412 
    413 TEST(ProfileStartEndTime) {
    414   LocalContext env;
    415   v8::HandleScope scope(env->GetIsolate());
    416   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    417 
    418   int64_t time_before_profiling = i::OS::Ticks();
    419   v8::Local<v8::String> profile_name = v8::String::New("test");
    420   cpu_profiler->StartCpuProfiling(profile_name);
    421   const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
    422   CHECK(time_before_profiling <= profile->GetStartTime());
    423   CHECK(profile->GetStartTime() <= profile->GetEndTime());
    424   CHECK(profile->GetEndTime() <= i::OS::Ticks());
    425 }
    426 
    427 
    428 static const v8::CpuProfile* RunProfiler(
    429     LocalContext& env, v8::Handle<v8::Function> function,
    430     v8::Handle<v8::Value> argv[], int argc,
    431     unsigned min_js_samples) {
    432   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    433   v8::Local<v8::String> profile_name = v8::String::New("my_profile");
    434 
    435   cpu_profiler->StartCpuProfiling(profile_name);
    436 
    437   i::Sampler* sampler =
    438       reinterpret_cast<i::Isolate*>(env->GetIsolate())->logger()->sampler();
    439   sampler->StartCountingSamples();
    440   do {
    441     function->Call(env->Global(), argc, argv);
    442   } while (sampler->js_and_external_sample_count() < min_js_samples);
    443 
    444   const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
    445 
    446   CHECK_NE(NULL, profile);
    447   // Dump collected profile to have a better diagnostic in case of failure.
    448   reinterpret_cast<i::CpuProfile*>(
    449       const_cast<v8::CpuProfile*>(profile))->Print();
    450 
    451   return profile;
    452 }
    453 
    454 
    455 static bool ContainsString(v8::Handle<v8::String> string,
    456                            const Vector<v8::Handle<v8::String> >& vector) {
    457   for (int i = 0; i < vector.length(); i++) {
    458     if (string->Equals(vector[i]))
    459       return true;
    460   }
    461   return false;
    462 }
    463 
    464 
    465 static void CheckChildrenNames(const v8::CpuProfileNode* node,
    466                                const Vector<v8::Handle<v8::String> >& names) {
    467   int count = node->GetChildrenCount();
    468   for (int i = 0; i < count; i++) {
    469     v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
    470     CHECK(ContainsString(name, names));
    471     // Check that there are no duplicates.
    472     for (int j = 0; j < count; j++) {
    473       if (j == i) continue;
    474       CHECK_NE(name, node->GetChild(j)->GetFunctionName());
    475     }
    476   }
    477 }
    478 
    479 
    480 static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
    481                                            const char* name) {
    482   int count = node->GetChildrenCount();
    483   v8::Handle<v8::String> nameHandle = v8::String::New(name);
    484   for (int i = 0; i < count; i++) {
    485     const v8::CpuProfileNode* child = node->GetChild(i);
    486     if (nameHandle->Equals(child->GetFunctionName())) return child;
    487   }
    488   return NULL;
    489 }
    490 
    491 
    492 static const v8::CpuProfileNode* GetChild(const v8::CpuProfileNode* node,
    493                                           const char* name) {
    494   const v8::CpuProfileNode* result = FindChild(node, name);
    495   CHECK(result);
    496   return result;
    497 }
    498 
    499 
    500 static void CheckSimpleBranch(const v8::CpuProfileNode* node,
    501                               const char* names[], int length) {
    502   for (int i = 0; i < length; i++) {
    503     const char* name = names[i];
    504     node = GetChild(node, name);
    505     int expectedChildrenCount = (i == length - 1) ? 0 : 1;
    506     CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
    507   }
    508 }
    509 
    510 
    511 static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
    512 "  this.mmm = 0;\n"
    513 "  var start = Date.now();\n"
    514 "  while (Date.now() - start < timeout) {\n"
    515 "    var n = 100*1000;\n"
    516 "    while(n > 1) {\n"
    517 "      n--;\n"
    518 "      this.mmm += n * n * n;\n"
    519 "    }\n"
    520 "  }\n"
    521 "}\n"
    522 "function delay() { try { loop(10); } catch(e) { } }\n"
    523 "function bar() { delay(); }\n"
    524 "function baz() { delay(); }\n"
    525 "function foo() {\n"
    526 "    try {\n"
    527 "       delay();\n"
    528 "       bar();\n"
    529 "       delay();\n"
    530 "       baz();\n"
    531 "    } catch (e) { }\n"
    532 "}\n"
    533 "function start(timeout) {\n"
    534 "  var start = Date.now();\n"
    535 "  do {\n"
    536 "    foo();\n"
    537 "    var duration = Date.now() - start;\n"
    538 "  } while (duration < timeout);\n"
    539 "  return duration;\n"
    540 "}\n";
    541 
    542 
    543 // Check that the profile tree for the script above will look like the
    544 // following:
    545 //
    546 // [Top down]:
    547 //  1062     0   (root) [-1]
    548 //  1054     0    start [-1]
    549 //  1054     1      foo [-1]
    550 //   265     0        baz [-1]
    551 //   265     1          delay [-1]
    552 //   264   264            loop [-1]
    553 //   525     3        delay [-1]
    554 //   522   522          loop [-1]
    555 //   263     0        bar [-1]
    556 //   263     1          delay [-1]
    557 //   262   262            loop [-1]
    558 //     2     2    (program) [-1]
    559 //     6     6    (garbage collector) [-1]
    560 TEST(CollectCpuProfile) {
    561   LocalContext env;
    562   v8::HandleScope scope(env->GetIsolate());
    563 
    564   v8::Script::Compile(v8::String::New(cpu_profiler_test_source))->Run();
    565   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    566       env->Global()->Get(v8::String::New("start")));
    567 
    568   int32_t profiling_interval_ms = 200;
    569   v8::Handle<v8::Value> args[] = { v8::Integer::New(profiling_interval_ms) };
    570   const v8::CpuProfile* profile =
    571       RunProfiler(env, function, args, ARRAY_SIZE(args), 200);
    572   function->Call(env->Global(), ARRAY_SIZE(args), args);
    573 
    574   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    575 
    576   ScopedVector<v8::Handle<v8::String> > names(3);
    577   names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
    578   names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
    579   names[2] = v8::String::New("start");
    580   CheckChildrenNames(root, names);
    581 
    582   const v8::CpuProfileNode* startNode = GetChild(root, "start");
    583   CHECK_EQ(1, startNode->GetChildrenCount());
    584 
    585   const v8::CpuProfileNode* fooNode = GetChild(startNode, "foo");
    586   CHECK_EQ(3, fooNode->GetChildrenCount());
    587 
    588   const char* barBranch[] = { "bar", "delay", "loop" };
    589   CheckSimpleBranch(fooNode, barBranch, ARRAY_SIZE(barBranch));
    590   const char* bazBranch[] = { "baz", "delay", "loop" };
    591   CheckSimpleBranch(fooNode, bazBranch, ARRAY_SIZE(bazBranch));
    592   const char* delayBranch[] = { "delay", "loop" };
    593   CheckSimpleBranch(fooNode, delayBranch, ARRAY_SIZE(delayBranch));
    594 
    595   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    596   cpu_profiler->DeleteAllCpuProfiles();
    597 }
    598 
    599 
    600 
    601 static const char* cpu_profiler_test_source2 = "function loop() {}\n"
    602 "function delay() { loop(); }\n"
    603 "function start(count) {\n"
    604 "  var k = 0;\n"
    605 "  do {\n"
    606 "    delay();\n"
    607 "  } while (++k < count*100*1000);\n"
    608 "}\n";
    609 
    610 // Check that the profile tree doesn't contain unexpecte traces:
    611 //  - 'loop' can be called only by 'delay'
    612 //  - 'delay' may be called only by 'start'
    613 // The profile will look like the following:
    614 //
    615 // [Top down]:
    616 //   135     0   (root) [-1] #1
    617 //   121    72    start [-1] #3
    618 //    49    33      delay [-1] #4
    619 //    16    16        loop [-1] #5
    620 //    14    14    (program) [-1] #2
    621 TEST(SampleWhenFrameIsNotSetup) {
    622   LocalContext env;
    623   v8::HandleScope scope(env->GetIsolate());
    624 
    625   v8::Script::Compile(v8::String::New(cpu_profiler_test_source2))->Run();
    626   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    627       env->Global()->Get(v8::String::New("start")));
    628 
    629   int32_t repeat_count = 100;
    630 #if defined(USE_SIMULATOR)
    631   // Simulators are much slower.
    632   repeat_count = 1;
    633 #endif
    634   v8::Handle<v8::Value> args[] = { v8::Integer::New(repeat_count) };
    635   const v8::CpuProfile* profile =
    636       RunProfiler(env, function, args, ARRAY_SIZE(args), 100);
    637 
    638   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    639 
    640   ScopedVector<v8::Handle<v8::String> > names(3);
    641   names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
    642   names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
    643   names[2] = v8::String::New("start");
    644   CheckChildrenNames(root, names);
    645 
    646   const v8::CpuProfileNode* startNode = FindChild(root, "start");
    647   // On slow machines there may be no meaningfull samples at all, skip the
    648   // check there.
    649   if (startNode && startNode->GetChildrenCount() > 0) {
    650     CHECK_EQ(1, startNode->GetChildrenCount());
    651     const v8::CpuProfileNode* delayNode = GetChild(startNode, "delay");
    652     if (delayNode->GetChildrenCount() > 0) {
    653       CHECK_EQ(1, delayNode->GetChildrenCount());
    654       GetChild(delayNode, "loop");
    655     }
    656   }
    657 
    658   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    659   cpu_profiler->DeleteAllCpuProfiles();
    660 }
    661 
    662 
    663 static const char* native_accessor_test_source = "function start(count) {\n"
    664 "  for (var i = 0; i < count; i++) {\n"
    665 "    var o = instance.foo;\n"
    666 "    instance.foo = o + 1;\n"
    667 "  }\n"
    668 "}\n";
    669 
    670 
    671 class TestApiCallbacks {
    672  public:
    673   explicit TestApiCallbacks(int min_duration_ms)
    674       : min_duration_ms_(min_duration_ms),
    675         is_warming_up_(false) {}
    676 
    677   static void Getter(v8::Local<v8::String> name,
    678                      const v8::PropertyCallbackInfo<v8::Value>& info) {
    679     TestApiCallbacks* data = fromInfo(info);
    680     data->Wait();
    681   }
    682 
    683   static void Setter(v8::Local<v8::String> name,
    684                      v8::Local<v8::Value> value,
    685                      const v8::PropertyCallbackInfo<void>& info) {
    686     TestApiCallbacks* data = fromInfo(info);
    687     data->Wait();
    688   }
    689 
    690   static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
    691     TestApiCallbacks* data = fromInfo(info);
    692     data->Wait();
    693   }
    694 
    695   void set_warming_up(bool value) { is_warming_up_ = value; }
    696 
    697  private:
    698   void Wait() {
    699     if (is_warming_up_) return;
    700     double start = i::OS::TimeCurrentMillis();
    701     double duration = 0;
    702     while (duration < min_duration_ms_) {
    703       i::OS::Sleep(1);
    704       duration = i::OS::TimeCurrentMillis() - start;
    705     }
    706   }
    707 
    708   template<typename T>
    709   static TestApiCallbacks* fromInfo(const T& info) {
    710     void* data = v8::External::Cast(*info.Data())->Value();
    711     return reinterpret_cast<TestApiCallbacks*>(data);
    712   }
    713 
    714   int min_duration_ms_;
    715   bool is_warming_up_;
    716 };
    717 
    718 
    719 // Test that native accessors are properly reported in the CPU profile.
    720 // This test checks the case when the long-running accessors are called
    721 // only once and the optimizer doesn't have chance to change the invocation
    722 // code.
    723 TEST(NativeAccessorUninitializedIC) {
    724   LocalContext env;
    725   v8::HandleScope scope(env->GetIsolate());
    726 
    727 
    728   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
    729   v8::Local<v8::ObjectTemplate> instance_template =
    730       func_template->InstanceTemplate();
    731 
    732   TestApiCallbacks accessors(100);
    733   v8::Local<v8::External> data = v8::External::New(&accessors);
    734   instance_template->SetAccessor(
    735       v8::String::New("foo"), &TestApiCallbacks::Getter,
    736       &TestApiCallbacks::Setter, data);
    737   v8::Local<v8::Function> func = func_template->GetFunction();
    738   v8::Local<v8::Object> instance = func->NewInstance();
    739   env->Global()->Set(v8::String::New("instance"), instance);
    740 
    741   v8::Script::Compile(v8::String::New(native_accessor_test_source))->Run();
    742   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    743       env->Global()->Get(v8::String::New("start")));
    744 
    745   int32_t repeat_count = 1;
    746   v8::Handle<v8::Value> args[] = { v8::Integer::New(repeat_count) };
    747   const v8::CpuProfile* profile =
    748       RunProfiler(env, function, args, ARRAY_SIZE(args), 180);
    749 
    750   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    751   const v8::CpuProfileNode* startNode = GetChild(root, "start");
    752   GetChild(startNode, "get foo");
    753   GetChild(startNode, "set foo");
    754 
    755   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    756   cpu_profiler->DeleteAllCpuProfiles();
    757 }
    758 
    759 
    760 // Test that native accessors are properly reported in the CPU profile.
    761 // This test makes sure that the accessors are called enough times to become
    762 // hot and to trigger optimizations.
    763 TEST(NativeAccessorMonomorphicIC) {
    764   LocalContext env;
    765   v8::HandleScope scope(env->GetIsolate());
    766 
    767 
    768   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
    769   v8::Local<v8::ObjectTemplate> instance_template =
    770       func_template->InstanceTemplate();
    771 
    772   TestApiCallbacks accessors(1);
    773   v8::Local<v8::External> data = v8::External::New(&accessors);
    774   instance_template->SetAccessor(
    775       v8::String::New("foo"), &TestApiCallbacks::Getter,
    776       &TestApiCallbacks::Setter, data);
    777   v8::Local<v8::Function> func = func_template->GetFunction();
    778   v8::Local<v8::Object> instance = func->NewInstance();
    779   env->Global()->Set(v8::String::New("instance"), instance);
    780 
    781   v8::Script::Compile(v8::String::New(native_accessor_test_source))->Run();
    782   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    783       env->Global()->Get(v8::String::New("start")));
    784 
    785   {
    786     // Make sure accessors ICs are in monomorphic state before starting
    787     // profiling.
    788     accessors.set_warming_up(true);
    789     int32_t warm_up_iterations = 3;
    790     v8::Handle<v8::Value> args[] = { v8::Integer::New(warm_up_iterations) };
    791     function->Call(env->Global(), ARRAY_SIZE(args), args);
    792     accessors.set_warming_up(false);
    793   }
    794 
    795   int32_t repeat_count = 100;
    796   v8::Handle<v8::Value> args[] = { v8::Integer::New(repeat_count) };
    797   const v8::CpuProfile* profile =
    798       RunProfiler(env, function, args, ARRAY_SIZE(args), 200);
    799 
    800   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    801   const v8::CpuProfileNode* startNode = GetChild(root, "start");
    802   GetChild(startNode, "get foo");
    803   GetChild(startNode, "set foo");
    804 
    805   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    806   cpu_profiler->DeleteAllCpuProfiles();
    807 }
    808 
    809 
    810 static const char* native_method_test_source = "function start(count) {\n"
    811 "  for (var i = 0; i < count; i++) {\n"
    812 "    instance.fooMethod();\n"
    813 "  }\n"
    814 "}\n";
    815 
    816 
    817 TEST(NativeMethodUninitializedIC) {
    818   LocalContext env;
    819   v8::HandleScope scope(env->GetIsolate());
    820 
    821   TestApiCallbacks callbacks(100);
    822   v8::Local<v8::External> data = v8::External::New(&callbacks);
    823 
    824   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
    825   func_template->SetClassName(v8::String::New("Test_InstanceCostructor"));
    826   v8::Local<v8::ObjectTemplate> proto_template =
    827       func_template->PrototypeTemplate();
    828   v8::Local<v8::Signature> signature = v8::Signature::New(func_template);
    829   proto_template->Set(v8::String::New("fooMethod"), v8::FunctionTemplate::New(
    830       &TestApiCallbacks::Callback, data, signature, 0));
    831 
    832   v8::Local<v8::Function> func = func_template->GetFunction();
    833   v8::Local<v8::Object> instance = func->NewInstance();
    834   env->Global()->Set(v8::String::New("instance"), instance);
    835 
    836   v8::Script::Compile(v8::String::New(native_method_test_source))->Run();
    837   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    838       env->Global()->Get(v8::String::New("start")));
    839 
    840   int32_t repeat_count = 1;
    841   v8::Handle<v8::Value> args[] = { v8::Integer::New(repeat_count) };
    842   const v8::CpuProfile* profile =
    843       RunProfiler(env, function, args, ARRAY_SIZE(args), 100);
    844 
    845   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    846   const v8::CpuProfileNode* startNode = GetChild(root, "start");
    847   GetChild(startNode, "fooMethod");
    848 
    849   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    850   cpu_profiler->DeleteAllCpuProfiles();
    851 }
    852 
    853 
    854 TEST(NativeMethodMonomorphicIC) {
    855   LocalContext env;
    856   v8::HandleScope scope(env->GetIsolate());
    857 
    858   TestApiCallbacks callbacks(1);
    859   v8::Local<v8::External> data = v8::External::New(&callbacks);
    860 
    861   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
    862   func_template->SetClassName(v8::String::New("Test_InstanceCostructor"));
    863   v8::Local<v8::ObjectTemplate> proto_template =
    864       func_template->PrototypeTemplate();
    865   v8::Local<v8::Signature> signature = v8::Signature::New(func_template);
    866   proto_template->Set(v8::String::New("fooMethod"), v8::FunctionTemplate::New(
    867       &TestApiCallbacks::Callback, data, signature, 0));
    868 
    869   v8::Local<v8::Function> func = func_template->GetFunction();
    870   v8::Local<v8::Object> instance = func->NewInstance();
    871   env->Global()->Set(v8::String::New("instance"), instance);
    872 
    873   v8::Script::Compile(v8::String::New(native_method_test_source))->Run();
    874   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    875       env->Global()->Get(v8::String::New("start")));
    876   {
    877     // Make sure method ICs are in monomorphic state before starting
    878     // profiling.
    879     callbacks.set_warming_up(true);
    880     int32_t warm_up_iterations = 3;
    881     v8::Handle<v8::Value> args[] = { v8::Integer::New(warm_up_iterations) };
    882     function->Call(env->Global(), ARRAY_SIZE(args), args);
    883     callbacks.set_warming_up(false);
    884   }
    885 
    886   int32_t repeat_count = 100;
    887   v8::Handle<v8::Value> args[] = { v8::Integer::New(repeat_count) };
    888   const v8::CpuProfile* profile =
    889       RunProfiler(env, function, args, ARRAY_SIZE(args), 100);
    890 
    891   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    892   GetChild(root, "start");
    893   const v8::CpuProfileNode* startNode = GetChild(root, "start");
    894   GetChild(startNode, "fooMethod");
    895 
    896   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    897   cpu_profiler->DeleteAllCpuProfiles();
    898 }
    899 
    900 
    901 static const char* bound_function_test_source = "function foo(iterations) {\n"
    902 "  var r = 0;\n"
    903 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
    904 "  return r;\n"
    905 "}\n"
    906 "function start(duration) {\n"
    907 "  var callback = foo.bind(this);\n"
    908 "  var start = Date.now();\n"
    909 "  while (Date.now() - start < duration) {\n"
    910 "    callback(10 * 1000);\n"
    911 "  }\n"
    912 "}";
    913 
    914 
    915 TEST(BoundFunctionCall) {
    916   LocalContext env;
    917   v8::HandleScope scope(env->GetIsolate());
    918 
    919   v8::Script::Compile(v8::String::New(bound_function_test_source))->Run();
    920   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    921       env->Global()->Get(v8::String::New("start")));
    922 
    923   int32_t duration_ms = 100;
    924   v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
    925   const v8::CpuProfile* profile =
    926       RunProfiler(env, function, args, ARRAY_SIZE(args), 100);
    927 
    928   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    929   ScopedVector<v8::Handle<v8::String> > names(3);
    930   names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
    931   names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
    932   names[2] = v8::String::New("start");
    933   // Don't allow |foo| node to be at the top level.
    934   CheckChildrenNames(root, names);
    935 
    936   const v8::CpuProfileNode* startNode = GetChild(root, "start");
    937   GetChild(startNode, "foo");
    938 
    939   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    940   cpu_profiler->DeleteAllCpuProfiles();
    941 }
    942 
    943 
    944 static const char* call_function_test_source = "function bar(iterations) {\n"
    945 "}\n"
    946 "function start(duration) {\n"
    947 "  var start = Date.now();\n"
    948 "  while (Date.now() - start < duration) {\n"
    949 "    try {\n"
    950 "      bar.call(this, 10 * 1000);\n"
    951 "    } catch(e) {}\n"
    952 "  }\n"
    953 "}";
    954 
    955 
    956 // Test that if we sampled thread when it was inside FunctionCall buitin then
    957 // its caller frame will be '(unresolved function)' as we have no reliable way
    958 // to resolve it.
    959 //
    960 // [Top down]:
    961 //    96     0   (root) [-1] #1
    962 //     1     1    (garbage collector) [-1] #4
    963 //     5     0    (unresolved function) [-1] #5
    964 //     5     5      call [-1] #6
    965 //    71    70    start [-1] #3
    966 //     1     1      bar [-1] #7
    967 //    19    19    (program) [-1] #2
    968 TEST(FunctionCallSample) {
    969   LocalContext env;
    970   v8::HandleScope scope(env->GetIsolate());
    971 
    972   // Collect garbage that might have be generated while installing extensions.
    973   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
    974 
    975   v8::Script::Compile(v8::String::New(call_function_test_source))->Run();
    976   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    977       env->Global()->Get(v8::String::New("start")));
    978 
    979   int32_t duration_ms = 100;
    980   v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
    981   const v8::CpuProfile* profile =
    982       RunProfiler(env, function, args, ARRAY_SIZE(args), 100);
    983 
    984   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    985   {
    986     ScopedVector<v8::Handle<v8::String> > names(4);
    987     names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
    988     names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
    989     names[2] = v8::String::New("start");
    990     names[3] = v8::String::New(i::ProfileGenerator::kUnresolvedFunctionName);
    991     // Don't allow |bar| and |call| nodes to be at the top level.
    992     CheckChildrenNames(root, names);
    993   }
    994 
    995   // In case of GC stress tests all samples may be in GC phase and there
    996   // won't be |start| node in the profiles.
    997   bool is_gc_stress_testing =
    998       (i::FLAG_gc_interval != -1) || i::FLAG_stress_compaction;
    999   const v8::CpuProfileNode* startNode = FindChild(root, "start");
   1000   CHECK(is_gc_stress_testing || startNode);
   1001   if (startNode) {
   1002     ScopedVector<v8::Handle<v8::String> > names(2);
   1003     names[0] = v8::String::New("bar");
   1004     names[1] = v8::String::New("call");
   1005     CheckChildrenNames(startNode, names);
   1006   }
   1007 
   1008   const v8::CpuProfileNode* unresolvedNode =
   1009       FindChild(root, i::ProfileGenerator::kUnresolvedFunctionName);
   1010   if (unresolvedNode) {
   1011     ScopedVector<v8::Handle<v8::String> > names(1);
   1012     names[0] = v8::String::New("call");
   1013     CheckChildrenNames(unresolvedNode, names);
   1014   }
   1015 
   1016   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1017   cpu_profiler->DeleteAllCpuProfiles();
   1018 }
   1019 
   1020 
   1021 static const char* function_apply_test_source = "function bar(iterations) {\n"
   1022 "}\n"
   1023 "function test() {\n"
   1024 "  bar.apply(this, [10 * 1000]);\n"
   1025 "}\n"
   1026 "function start(duration) {\n"
   1027 "  var start = Date.now();\n"
   1028 "  while (Date.now() - start < duration) {\n"
   1029 "    try {\n"
   1030 "      test();\n"
   1031 "    } catch(e) {}\n"
   1032 "  }\n"
   1033 "}";
   1034 
   1035 
   1036 // [Top down]:
   1037 //    94     0   (root) [-1] #0 1
   1038 //     2     2    (garbage collector) [-1] #0 7
   1039 //    82    49    start [-1] #16 3
   1040 //     1     0      (unresolved function) [-1] #0 8
   1041 //     1     1        apply [-1] #0 9
   1042 //    32    21      test [-1] #16 4
   1043 //     2     2        bar [-1] #16 6
   1044 //     9     9        apply [-1] #0 5
   1045 //    10    10    (program) [-1] #0 2
   1046 TEST(FunctionApplySample) {
   1047   LocalContext env;
   1048   v8::HandleScope scope(env->GetIsolate());
   1049 
   1050   v8::Script::Compile(v8::String::New(function_apply_test_source))->Run();
   1051   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1052       env->Global()->Get(v8::String::New("start")));
   1053 
   1054   int32_t duration_ms = 100;
   1055   v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
   1056 
   1057   const v8::CpuProfile* profile =
   1058       RunProfiler(env, function, args, ARRAY_SIZE(args), 100);
   1059 
   1060   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1061   {
   1062     ScopedVector<v8::Handle<v8::String> > names(3);
   1063     names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
   1064     names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
   1065     names[2] = v8::String::New("start");
   1066     // Don't allow |test|, |bar| and |apply| nodes to be at the top level.
   1067     CheckChildrenNames(root, names);
   1068   }
   1069 
   1070   const v8::CpuProfileNode* startNode = FindChild(root, "start");
   1071   if (startNode) {
   1072     {
   1073       ScopedVector<v8::Handle<v8::String> > names(2);
   1074       names[0] = v8::String::New("test");
   1075       names[1] = v8::String::New(ProfileGenerator::kUnresolvedFunctionName);
   1076       CheckChildrenNames(startNode, names);
   1077     }
   1078 
   1079     const v8::CpuProfileNode* testNode = FindChild(startNode, "test");
   1080     if (testNode) {
   1081       ScopedVector<v8::Handle<v8::String> > names(2);
   1082       names[0] = v8::String::New("bar");
   1083       names[1] = v8::String::New("apply");
   1084       CheckChildrenNames(testNode, names);
   1085     }
   1086 
   1087     if (const v8::CpuProfileNode* unresolvedNode =
   1088             FindChild(startNode, ProfileGenerator::kUnresolvedFunctionName)) {
   1089       ScopedVector<v8::Handle<v8::String> > names(1);
   1090       names[0] = v8::String::New("apply");
   1091       CheckChildrenNames(unresolvedNode, names);
   1092       GetChild(unresolvedNode, "apply");
   1093     }
   1094   }
   1095 
   1096   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1097   cpu_profiler->DeleteAllCpuProfiles();
   1098 }
   1099 
   1100 
   1101 static const char* js_native_js_test_source = "function foo(iterations) {\n"
   1102 "  var r = 0;\n"
   1103 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1104 "  return r;\n"
   1105 "}\n"
   1106 "function bar(iterations) {\n"
   1107 "  try { foo(iterations); } catch(e) {}\n"
   1108 "}\n"
   1109 "function start(duration) {\n"
   1110 "  var start = Date.now();\n"
   1111 "  while (Date.now() - start < duration) {\n"
   1112 "    try {\n"
   1113 "      CallJsFunction(bar, 10 * 1000);\n"
   1114 "    } catch(e) {}\n"
   1115 "  }\n"
   1116 "}";
   1117 
   1118 static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1119   v8::Handle<v8::Function> function = info[0].As<v8::Function>();
   1120   v8::Handle<v8::Value> argv[] = { info[1] };
   1121   function->Call(info.This(), ARRAY_SIZE(argv), argv);
   1122 }
   1123 
   1124 
   1125 // [Top down]:
   1126 //    58     0   (root) #0 1
   1127 //     2     2    (program) #0 2
   1128 //    56     1    start #16 3
   1129 //    55     0      CallJsFunction #0 4
   1130 //    55     1        bar #16 5
   1131 //    54    54          foo #16 6
   1132 TEST(JsNativeJsSample) {
   1133   LocalContext env;
   1134   v8::HandleScope scope(env->GetIsolate());
   1135 
   1136   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
   1137       CallJsFunction);
   1138   v8::Local<v8::Function> func = func_template->GetFunction();
   1139   func->SetName(v8::String::New("CallJsFunction"));
   1140   env->Global()->Set(v8::String::New("CallJsFunction"), func);
   1141 
   1142   v8::Script::Compile(v8::String::New(js_native_js_test_source))->Run();
   1143   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1144       env->Global()->Get(v8::String::New("start")));
   1145 
   1146   int32_t duration_ms = 20;
   1147   v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
   1148   const v8::CpuProfile* profile =
   1149       RunProfiler(env, function, args, ARRAY_SIZE(args), 50);
   1150 
   1151   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1152   {
   1153     ScopedVector<v8::Handle<v8::String> > names(3);
   1154     names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
   1155     names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
   1156     names[2] = v8::String::New("start");
   1157     CheckChildrenNames(root, names);
   1158   }
   1159 
   1160   const v8::CpuProfileNode* startNode = GetChild(root, "start");
   1161   CHECK_EQ(1, startNode->GetChildrenCount());
   1162   const v8::CpuProfileNode* nativeFunctionNode =
   1163       GetChild(startNode, "CallJsFunction");
   1164 
   1165   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
   1166   const v8::CpuProfileNode* barNode = GetChild(nativeFunctionNode, "bar");
   1167 
   1168   CHECK_EQ(1, barNode->GetChildrenCount());
   1169   GetChild(barNode, "foo");
   1170 
   1171   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1172   cpu_profiler->DeleteAllCpuProfiles();
   1173 }
   1174 
   1175 
   1176 static const char* js_native_js_runtime_js_test_source =
   1177 "function foo(iterations) {\n"
   1178 "  var r = 0;\n"
   1179 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1180 "  return r;\n"
   1181 "}\n"
   1182 "var bound = foo.bind(this);\n"
   1183 "function bar(iterations) {\n"
   1184 "  try { bound(iterations); } catch(e) {}\n"
   1185 "}\n"
   1186 "function start(duration) {\n"
   1187 "  var start = Date.now();\n"
   1188 "  while (Date.now() - start < duration) {\n"
   1189 "    try {\n"
   1190 "      CallJsFunction(bar, 10 * 1000);\n"
   1191 "    } catch(e) {}\n"
   1192 "  }\n"
   1193 "}";
   1194 
   1195 
   1196 // [Top down]:
   1197 //    57     0   (root) #0 1
   1198 //    55     1    start #16 3
   1199 //    54     0      CallJsFunction #0 4
   1200 //    54     3        bar #16 5
   1201 //    51    51          foo #16 6
   1202 //     2     2    (program) #0 2
   1203 TEST(JsNativeJsRuntimeJsSample) {
   1204   LocalContext env;
   1205   v8::HandleScope scope(env->GetIsolate());
   1206 
   1207   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
   1208       CallJsFunction);
   1209   v8::Local<v8::Function> func = func_template->GetFunction();
   1210   func->SetName(v8::String::New("CallJsFunction"));
   1211   env->Global()->Set(v8::String::New("CallJsFunction"), func);
   1212 
   1213   v8::Script::Compile(v8::String::New(js_native_js_runtime_js_test_source))->
   1214       Run();
   1215   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1216       env->Global()->Get(v8::String::New("start")));
   1217 
   1218   int32_t duration_ms = 20;
   1219   v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
   1220   const v8::CpuProfile* profile =
   1221       RunProfiler(env, function, args, ARRAY_SIZE(args), 50);
   1222 
   1223   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1224   ScopedVector<v8::Handle<v8::String> > names(3);
   1225   names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
   1226   names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
   1227   names[2] = v8::String::New("start");
   1228   CheckChildrenNames(root, names);
   1229 
   1230   const v8::CpuProfileNode* startNode = GetChild(root, "start");
   1231   CHECK_EQ(1, startNode->GetChildrenCount());
   1232   const v8::CpuProfileNode* nativeFunctionNode =
   1233       GetChild(startNode, "CallJsFunction");
   1234 
   1235   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
   1236   const v8::CpuProfileNode* barNode = GetChild(nativeFunctionNode, "bar");
   1237 
   1238   CHECK_EQ(1, barNode->GetChildrenCount());
   1239   GetChild(barNode, "foo");
   1240 
   1241   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1242   cpu_profiler->DeleteAllCpuProfiles();
   1243 }
   1244 
   1245 
   1246 static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1247   CallJsFunction(info);
   1248 }
   1249 
   1250 
   1251 static const char* js_native1_js_native2_js_test_source =
   1252 "function foo(iterations) {\n"
   1253 "  var r = 0;\n"
   1254 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1255 "  return r;\n"
   1256 "}\n"
   1257 "function bar(iterations) {\n"
   1258 "  CallJsFunction2(foo, iterations);\n"
   1259 "}\n"
   1260 "function start(duration) {\n"
   1261 "  var start = Date.now();\n"
   1262 "  while (Date.now() - start < duration) {\n"
   1263 "    try {\n"
   1264 "      CallJsFunction1(bar, 10 * 1000);\n"
   1265 "    } catch(e) {}\n"
   1266 "  }\n"
   1267 "}";
   1268 
   1269 
   1270 // [Top down]:
   1271 //    57     0   (root) #0 1
   1272 //    55     1    start #16 3
   1273 //    54     0      CallJsFunction1 #0 4
   1274 //    54     0        bar #16 5
   1275 //    54     0          CallJsFunction2 #0 6
   1276 //    54    54            foo #16 7
   1277 //     2     2    (program) #0 2
   1278 TEST(JsNative1JsNative2JsSample) {
   1279   LocalContext env;
   1280   v8::HandleScope scope(env->GetIsolate());
   1281 
   1282   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
   1283       CallJsFunction);
   1284   v8::Local<v8::Function> func1 = func_template->GetFunction();
   1285   func1->SetName(v8::String::New("CallJsFunction1"));
   1286   env->Global()->Set(v8::String::New("CallJsFunction1"), func1);
   1287 
   1288   v8::Local<v8::Function> func2 = v8::FunctionTemplate::New(
   1289       CallJsFunction2)->GetFunction();
   1290   func2->SetName(v8::String::New("CallJsFunction2"));
   1291   env->Global()->Set(v8::String::New("CallJsFunction2"), func2);
   1292 
   1293   v8::Script::Compile(v8::String::New(js_native1_js_native2_js_test_source))->
   1294       Run();
   1295   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1296       env->Global()->Get(v8::String::New("start")));
   1297 
   1298   int32_t duration_ms = 20;
   1299   v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
   1300   const v8::CpuProfile* profile =
   1301       RunProfiler(env, function, args, ARRAY_SIZE(args), 50);
   1302 
   1303   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1304   ScopedVector<v8::Handle<v8::String> > names(3);
   1305   names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
   1306   names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
   1307   names[2] = v8::String::New("start");
   1308   CheckChildrenNames(root, names);
   1309 
   1310   const v8::CpuProfileNode* startNode = GetChild(root, "start");
   1311   CHECK_EQ(1, startNode->GetChildrenCount());
   1312   const v8::CpuProfileNode* nativeNode1 =
   1313       GetChild(startNode, "CallJsFunction1");
   1314 
   1315   CHECK_EQ(1, nativeNode1->GetChildrenCount());
   1316   const v8::CpuProfileNode* barNode = GetChild(nativeNode1, "bar");
   1317 
   1318   CHECK_EQ(1, barNode->GetChildrenCount());
   1319   const v8::CpuProfileNode* nativeNode2 = GetChild(barNode, "CallJsFunction2");
   1320 
   1321   CHECK_EQ(1, nativeNode2->GetChildrenCount());
   1322   GetChild(nativeNode2, "foo");
   1323 
   1324   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1325   cpu_profiler->DeleteAllCpuProfiles();
   1326 }
   1327 
   1328 
   1329 // [Top down]:
   1330 //     6     0   (root) #0 1
   1331 //     3     3    (program) #0 2
   1332 //     3     3    (idle) #0 3
   1333 TEST(IdleTime) {
   1334   LocalContext env;
   1335   v8::HandleScope scope(env->GetIsolate());
   1336   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1337 
   1338   v8::Local<v8::String> profile_name = v8::String::New("my_profile");
   1339   cpu_profiler->StartCpuProfiling(profile_name);
   1340 
   1341   i::Isolate* isolate = i::Isolate::Current();
   1342   i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor();
   1343   processor->AddCurrentStack(isolate);
   1344 
   1345   cpu_profiler->SetIdle(true);
   1346 
   1347   for (int i = 0; i < 3; i++) {
   1348     processor->AddCurrentStack(isolate);
   1349   }
   1350 
   1351   cpu_profiler->SetIdle(false);
   1352   processor->AddCurrentStack(isolate);
   1353 
   1354 
   1355   const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
   1356   CHECK_NE(NULL, profile);
   1357   // Dump collected profile to have a better diagnostic in case of failure.
   1358   reinterpret_cast<i::CpuProfile*>(
   1359       const_cast<v8::CpuProfile*>(profile))->Print();
   1360 
   1361   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1362   ScopedVector<v8::Handle<v8::String> > names(3);
   1363   names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
   1364   names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
   1365   names[2] = v8::String::New(ProfileGenerator::kIdleEntryName);
   1366   CheckChildrenNames(root, names);
   1367 
   1368   const v8::CpuProfileNode* programNode =
   1369       GetChild(root, ProfileGenerator::kProgramEntryName);
   1370   CHECK_EQ(0, programNode->GetChildrenCount());
   1371   CHECK_GE(programNode->GetSelfSamplesCount(), 3);
   1372   CHECK_GE(programNode->GetHitCount(), 3);
   1373 
   1374   const v8::CpuProfileNode* idleNode =
   1375       GetChild(root, ProfileGenerator::kIdleEntryName);
   1376   CHECK_EQ(0, idleNode->GetChildrenCount());
   1377   CHECK_GE(idleNode->GetSelfSamplesCount(), 3);
   1378   CHECK_GE(idleNode->GetHitCount(), 3);
   1379 
   1380   cpu_profiler->DeleteAllCpuProfiles();
   1381 }
   1382