| Index: test/cctest/test-cpu-profiler.cc
|
| diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
|
| index 9a2496a72a96a77154be1003aab35b150300be8a..e880d17f1b79574dd5af8ad407658e3d0b0ea261 100644
|
| --- a/test/cctest/test-cpu-profiler.cc
|
| +++ b/test/cctest/test-cpu-profiler.cc
|
| @@ -31,6 +31,7 @@
|
| #include "v8.h"
|
| #include "cpu-profiler-inl.h"
|
| #include "cctest.h"
|
| +#include "platform.h"
|
| #include "utils.h"
|
| #include "../include/v8-profiler.h"
|
| #undef V8_DISABLE_DEPRECATIONS
|
| @@ -43,19 +44,19 @@ using i::ProfileGenerator;
|
| using i::ProfileNode;
|
| using i::ProfilerEventsProcessor;
|
| using i::ScopedVector;
|
| -using i::TokenEnumerator;
|
| using i::Vector;
|
|
|
|
|
| TEST(StartStop) {
|
| CpuProfilesCollection profiles;
|
| ProfileGenerator generator(&profiles);
|
| - ProfilerEventsProcessor processor(&generator, &profiles);
|
| + ProfilerEventsProcessor processor(&generator);
|
| processor.Start();
|
| - processor.Stop();
|
| + processor.StopSynchronously();
|
| processor.Join();
|
| }
|
|
|
| +
|
| static inline i::Address ToAddress(int n) {
|
| return reinterpret_cast<i::Address>(n);
|
| }
|
| @@ -97,64 +98,89 @@ class TestSetup {
|
|
|
| } // namespace
|
|
|
| +
|
| +i::Code* CreateCode(LocalContext* env) {
|
| + static int counter = 0;
|
| + i::EmbeddedVector<char, 256> script;
|
| + i::EmbeddedVector<char, 32> name;
|
| +
|
| + i::OS::SNPrintF(name, "function_%d", ++counter);
|
| + const char* name_start = name.start();
|
| + i::OS::SNPrintF(script,
|
| + "function %s() {\n"
|
| + "var counter = 0;\n"
|
| + "for (var i = 0; i < %d; ++i) counter += i;\n"
|
| + "return '%s_' + counter;\n"
|
| + "}\n"
|
| + "%s();\n", name_start, counter, name_start, name_start);
|
| + CompileRun(script.start());
|
| + i::Handle<i::JSFunction> fun = v8::Utils::OpenHandle(
|
| + *v8::Local<v8::Function>::Cast(
|
| + (*env)->Global()->Get(v8_str(name_start))));
|
| + return fun->code();
|
| +}
|
| +
|
| +
|
| TEST(CodeEvents) {
|
| CcTest::InitializeVM();
|
| + LocalContext env;
|
| i::Isolate* isolate = i::Isolate::Current();
|
| - i::Heap* heap = isolate->heap();
|
| i::Factory* factory = isolate->factory();
|
| TestSetup test_setup;
|
| - CpuProfilesCollection profiles;
|
| - profiles.StartProfiling("", 1, false);
|
| - ProfileGenerator generator(&profiles);
|
| - ProfilerEventsProcessor processor(&generator, &profiles);
|
| +
|
| + i::HandleScope scope(isolate);
|
| +
|
| + i::Code* aaa_code = CreateCode(&env);
|
| + i::Code* comment_code = CreateCode(&env);
|
| + i::Code* args5_code = CreateCode(&env);
|
| + i::Code* comment2_code = CreateCode(&env);
|
| + i::Code* moved_code = CreateCode(&env);
|
| + i::Code* args3_code = CreateCode(&env);
|
| + i::Code* args4_code = CreateCode(&env);
|
| +
|
| + CpuProfilesCollection* profiles = new CpuProfilesCollection;
|
| + profiles->StartProfiling("", 1, false);
|
| + ProfileGenerator generator(profiles);
|
| + ProfilerEventsProcessor processor(&generator);
|
| processor.Start();
|
| + CpuProfiler profiler(isolate, profiles, &generator, &processor);
|
|
|
| // Enqueue code creation events.
|
| - i::HandleScope scope(isolate);
|
| const char* aaa_str = "aaa";
|
| i::Handle<i::String> aaa_name = factory->NewStringFromAscii(
|
| i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
|
| - processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
|
| - *aaa_name,
|
| - heap->empty_string(),
|
| - 0,
|
| - ToAddress(0x1000),
|
| - 0x100,
|
| - ToAddress(0x10000),
|
| - NULL);
|
| - processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
|
| - "bbb",
|
| - ToAddress(0x1200),
|
| - 0x80);
|
| - processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
|
| - processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
|
| - "ddd",
|
| - ToAddress(0x1400),
|
| - 0x80);
|
| - processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
|
| - processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
|
| - processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
|
| + profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code, *aaa_name);
|
| + profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code, "comment");
|
| + profiler.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5);
|
| + profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code, "comment2");
|
| + profiler.CodeMoveEvent(comment2_code->address(), moved_code->address());
|
| + profiler.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3);
|
| + profiler.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4);
|
| +
|
| // Enqueue a tick event to enable code events processing.
|
| - EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
|
| + EnqueueTickSampleEvent(&processor, aaa_code->address());
|
|
|
| - processor.Stop();
|
| + processor.StopSynchronously();
|
| processor.Join();
|
|
|
| // Check the state of profile generator.
|
| - CodeEntry* entry1 = generator.code_map()->FindEntry(ToAddress(0x1000));
|
| - CHECK_NE(NULL, entry1);
|
| - CHECK_EQ(aaa_str, entry1->name());
|
| - CodeEntry* entry2 = generator.code_map()->FindEntry(ToAddress(0x1200));
|
| - CHECK_NE(NULL, entry2);
|
| - CHECK_EQ("bbb", entry2->name());
|
| - CodeEntry* entry3 = generator.code_map()->FindEntry(ToAddress(0x1300));
|
| - CHECK_NE(NULL, entry3);
|
| - CHECK_EQ("5", entry3->name());
|
| - CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1400)));
|
| - CodeEntry* entry4 = generator.code_map()->FindEntry(ToAddress(0x1500));
|
| - CHECK_NE(NULL, entry4);
|
| - CHECK_EQ("ddd", entry4->name());
|
| - CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
|
| + CodeEntry* aaa = generator.code_map()->FindEntry(aaa_code->address());
|
| + CHECK_NE(NULL, aaa);
|
| + CHECK_EQ(aaa_str, aaa->name());
|
| +
|
| + CodeEntry* comment = generator.code_map()->FindEntry(comment_code->address());
|
| + CHECK_NE(NULL, comment);
|
| + CHECK_EQ("comment", comment->name());
|
| +
|
| + CodeEntry* args5 = generator.code_map()->FindEntry(args5_code->address());
|
| + CHECK_NE(NULL, args5);
|
| + CHECK_EQ("5", args5->name());
|
| +
|
| + CHECK_EQ(NULL, generator.code_map()->FindEntry(comment2_code->address()));
|
| +
|
| + CodeEntry* comment2 = generator.code_map()->FindEntry(moved_code->address());
|
| + CHECK_NE(NULL, comment2);
|
| + CHECK_EQ("comment2", comment2->name());
|
| }
|
|
|
|
|
| @@ -163,34 +189,42 @@ static int CompareProfileNodes(const T* p1, const T* p2) {
|
| return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
|
| }
|
|
|
| +
|
| TEST(TickEvents) {
|
| TestSetup test_setup;
|
| - CpuProfilesCollection profiles;
|
| - profiles.StartProfiling("", 1, false);
|
| - ProfileGenerator generator(&profiles);
|
| - ProfilerEventsProcessor processor(&generator, &profiles);
|
| - processor.Start();
|
| + LocalContext env;
|
| + i::Isolate* isolate = i::Isolate::Current();
|
| + i::HandleScope scope(isolate);
|
|
|
| - processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
|
| - "bbb",
|
| - ToAddress(0x1200),
|
| - 0x80);
|
| - processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
|
| - processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
|
| - "ddd",
|
| - ToAddress(0x1400),
|
| - 0x80);
|
| - EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
|
| - EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
|
| - EnqueueTickSampleEvent(&processor,
|
| - ToAddress(0x1404),
|
| - ToAddress(0x1305),
|
| - ToAddress(0x1230));
|
| -
|
| - processor.Stop();
|
| + i::Code* frame1_code = CreateCode(&env);
|
| + i::Code* frame2_code = CreateCode(&env);
|
| + i::Code* frame3_code = CreateCode(&env);
|
| +
|
| + CpuProfilesCollection* profiles = new CpuProfilesCollection;
|
| + profiles->StartProfiling("", 1, false);
|
| + ProfileGenerator generator(profiles);
|
| + ProfilerEventsProcessor processor(&generator);
|
| + processor.Start();
|
| + CpuProfiler profiler(isolate, profiles, &generator, &processor);
|
| +
|
| + profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
|
| + profiler.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5);
|
| + profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
|
| +
|
| + EnqueueTickSampleEvent(&processor, frame1_code->instruction_start());
|
| + EnqueueTickSampleEvent(
|
| + &processor,
|
| + frame2_code->instruction_start() + frame2_code->ExecutableSize() / 2,
|
| + frame1_code->instruction_start() + frame2_code->ExecutableSize() / 2);
|
| + EnqueueTickSampleEvent(
|
| + &processor,
|
| + frame3_code->instruction_end() - 1,
|
| + frame2_code->instruction_end() - 1,
|
| + frame1_code->instruction_end() - 1);
|
| +
|
| + processor.StopSynchronously();
|
| processor.Join();
|
| - CpuProfile* profile =
|
| - profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
|
| + CpuProfile* profile = profiles->StopProfiling("", 1);
|
| CHECK_NE(NULL, profile);
|
|
|
| // Check call trees.
|
| @@ -229,29 +263,32 @@ TEST(CrashIfStoppingLastNonExistentProfile) {
|
| // Long stacks (exceeding max frames limit) must not be erased.
|
| TEST(Issue1398) {
|
| TestSetup test_setup;
|
| - CpuProfilesCollection profiles;
|
| - profiles.StartProfiling("", 1, false);
|
| - ProfileGenerator generator(&profiles);
|
| - ProfilerEventsProcessor processor(&generator, &profiles);
|
| + LocalContext env;
|
| + i::Isolate* isolate = i::Isolate::Current();
|
| + i::HandleScope scope(isolate);
|
| +
|
| + i::Code* code = CreateCode(&env);
|
| +
|
| + CpuProfilesCollection* profiles = new CpuProfilesCollection;
|
| + profiles->StartProfiling("", 1, false);
|
| + ProfileGenerator generator(profiles);
|
| + ProfilerEventsProcessor processor(&generator);
|
| processor.Start();
|
| + CpuProfiler profiler(isolate, profiles, &generator, &processor);
|
|
|
| - processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
|
| - "bbb",
|
| - ToAddress(0x1200),
|
| - 0x80);
|
| + profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
|
|
|
| i::TickSample* sample = processor.TickSampleEvent();
|
| - sample->pc = ToAddress(0x1200);
|
| + sample->pc = code->address();
|
| sample->tos = 0;
|
| sample->frames_count = i::TickSample::kMaxFramesCount;
|
| for (int i = 0; i < sample->frames_count; ++i) {
|
| - sample->stack[i] = ToAddress(0x1200);
|
| + sample->stack[i] = code->address();
|
| }
|
|
|
| - processor.Stop();
|
| + processor.StopSynchronously();
|
| processor.Join();
|
| - CpuProfile* profile =
|
| - profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
|
| + CpuProfile* profile = profiles->StopProfiling("", 1);
|
| CHECK_NE(NULL, profile);
|
|
|
| int actual_depth = 0;
|
| @@ -355,60 +392,23 @@ TEST(DeleteCpuProfile) {
|
| }
|
|
|
|
|
| -TEST(DeleteCpuProfileDifferentTokens) {
|
| - LocalContext env;
|
| - v8::HandleScope scope(env->GetIsolate());
|
| - v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
|
| -
|
| - CHECK_EQ(0, cpu_profiler->GetProfileCount());
|
| - v8::Local<v8::String> name1 = v8::String::New("1");
|
| - cpu_profiler->StartCpuProfiling(name1);
|
| - const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1);
|
| - CHECK_NE(NULL, p1);
|
| - CHECK_EQ(1, cpu_profiler->GetProfileCount());
|
| - unsigned uid1 = p1->GetUid();
|
| - CHECK_EQ(p1, cpu_profiler->FindCpuProfile(uid1));
|
| - v8::Local<v8::String> token1 = v8::String::New("token1");
|
| - const v8::CpuProfile* p1_t1 = cpu_profiler->FindCpuProfile(uid1, token1);
|
| - CHECK_NE(NULL, p1_t1);
|
| - CHECK_NE(p1, p1_t1);
|
| - CHECK_EQ(1, cpu_profiler->GetProfileCount());
|
| - const_cast<v8::CpuProfile*>(p1)->Delete();
|
| - CHECK_EQ(0, cpu_profiler->GetProfileCount());
|
| - CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
|
| - CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1, token1));
|
| - const_cast<v8::CpuProfile*>(p1_t1)->Delete();
|
| - CHECK_EQ(0, cpu_profiler->GetProfileCount());
|
| -
|
| - v8::Local<v8::String> name2 = v8::String::New("2");
|
| - cpu_profiler->StartCpuProfiling(name2);
|
| - v8::Local<v8::String> token2 = v8::String::New("token2");
|
| - const v8::CpuProfile* p2_t2 = cpu_profiler->StopCpuProfiling(name2, token2);
|
| - CHECK_NE(NULL, p2_t2);
|
| - CHECK_EQ(1, cpu_profiler->GetProfileCount());
|
| - unsigned uid2 = p2_t2->GetUid();
|
| - CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
|
| - const v8::CpuProfile* p2 = cpu_profiler->FindCpuProfile(uid2);
|
| - CHECK_NE(p2_t2, p2);
|
| - v8::Local<v8::String> name3 = v8::String::New("3");
|
| - cpu_profiler->StartCpuProfiling(name3);
|
| - const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3);
|
| - CHECK_NE(NULL, p3);
|
| - CHECK_EQ(2, cpu_profiler->GetProfileCount());
|
| - unsigned uid3 = p3->GetUid();
|
| - CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
|
| - CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
|
| - const_cast<v8::CpuProfile*>(p2_t2)->Delete();
|
| - CHECK_EQ(1, cpu_profiler->GetProfileCount());
|
| - CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
|
| - CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
|
| - const_cast<v8::CpuProfile*>(p2)->Delete();
|
| - CHECK_EQ(1, cpu_profiler->GetProfileCount());
|
| - CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
|
| - CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
|
| - const_cast<v8::CpuProfile*>(p3)->Delete();
|
| - CHECK_EQ(0, cpu_profiler->GetProfileCount());
|
| - CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3));
|
| +TEST(GetProfilerWhenIsolateIsNotInitialized) {
|
| + v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
| + CHECK(i::Isolate::Current()->IsDefaultIsolate());
|
| + CHECK(!i::Isolate::Current()->IsInitialized());
|
| + CHECK_EQ(NULL, isolate->GetCpuProfiler());
|
| + {
|
| + v8::Isolate::Scope isolateScope(isolate);
|
| + LocalContext env;
|
| + v8::HandleScope scope(isolate);
|
| + CHECK_NE(NULL, isolate->GetCpuProfiler());
|
| + isolate->GetCpuProfiler()->StartCpuProfiling(v8::String::New("Test"));
|
| + isolate->GetCpuProfiler()->StopCpuProfiling(v8::String::New("Test"));
|
| + }
|
| + CHECK(i::Isolate::Current()->IsInitialized());
|
| + CHECK_NE(NULL, isolate->GetCpuProfiler());
|
| + isolate->Dispose();
|
| + CHECK_EQ(NULL, isolate->GetCpuProfiler());
|
| }
|
|
|
|
|
| @@ -965,3 +965,182 @@ TEST(BoundFunctionCall) {
|
|
|
| cpu_profiler->DeleteAllCpuProfiles();
|
| }
|
| +
|
| +
|
| +static const char* call_function_test_source = "function bar(iterations) {\n"
|
| +"}\n"
|
| +"function start(duration) {\n"
|
| +" var start = Date.now();\n"
|
| +" while (Date.now() - start < duration) {\n"
|
| +" try {\n"
|
| +" bar.call(this, 10 * 1000);\n"
|
| +" } catch(e) {}\n"
|
| +" }\n"
|
| +"}";
|
| +
|
| +
|
| +// Test that if we sampled thread when it was inside FunctionCall buitin then
|
| +// its caller frame will be '(unresolved function)' as we have no reliable way
|
| +// to resolve it.
|
| +//
|
| +// [Top down]:
|
| +// 96 0 (root) [-1] #1
|
| +// 1 1 (garbage collector) [-1] #4
|
| +// 5 0 (unresolved function) [-1] #5
|
| +// 5 5 call [-1] #6
|
| +// 71 70 start [-1] #3
|
| +// 1 1 bar [-1] #7
|
| +// 19 19 (program) [-1] #2
|
| +TEST(FunctionCallSample) {
|
| + LocalContext env;
|
| + v8::HandleScope scope(env->GetIsolate());
|
| +
|
| + v8::Script::Compile(v8::String::New(call_function_test_source))->Run();
|
| + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(v8::String::New("start")));
|
| +
|
| + v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
|
| + v8::Local<v8::String> profile_name = v8::String::New("my_profile");
|
| +
|
| + cpu_profiler->StartCpuProfiling(profile_name);
|
| + int32_t duration_ms = 100;
|
| +#if defined(_WIN32) || defined(_WIN64)
|
| + // 100ms is not enough on Windows. See
|
| + // https://code.google.com/p/v8/issues/detail?id=2628
|
| + duration_ms = 400;
|
| +#endif
|
| + v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
|
| + function->Call(env->Global(), ARRAY_SIZE(args), args);
|
| + const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
|
| +
|
| + CHECK_NE(NULL, profile);
|
| + // Dump collected profile to have a better diagnostic in case of failure.
|
| + reinterpret_cast<i::CpuProfile*>(
|
| + const_cast<v8::CpuProfile*>(profile))->Print();
|
| +
|
| + const v8::CpuProfileNode* root = profile->GetTopDownRoot();
|
| + {
|
| + ScopedVector<v8::Handle<v8::String> > names(4);
|
| + names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
|
| + names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
|
| + names[2] = v8::String::New("start");
|
| + names[3] = v8::String::New(i::ProfileGenerator::kUnresolvedFunctionName);
|
| + // Don't allow |bar| and |call| nodes to be at the top level.
|
| + CheckChildrenNames(root, names);
|
| + }
|
| +
|
| + // In case of GC stress tests all samples may be in GC phase and there
|
| + // won't be |start| node in the profiles.
|
| + bool is_gc_stress_testing =
|
| + (i::FLAG_gc_interval != -1) || i::FLAG_stress_compaction;
|
| + const v8::CpuProfileNode* startNode = FindChild(root, "start");
|
| + CHECK(is_gc_stress_testing || startNode);
|
| + if (startNode) {
|
| + ScopedVector<v8::Handle<v8::String> > names(2);
|
| + names[0] = v8::String::New("bar");
|
| + names[1] = v8::String::New("call");
|
| + CheckChildrenNames(startNode, names);
|
| + }
|
| +
|
| + const v8::CpuProfileNode* unresolvedNode =
|
| + FindChild(root, i::ProfileGenerator::kUnresolvedFunctionName);
|
| + if (unresolvedNode) {
|
| + ScopedVector<v8::Handle<v8::String> > names(1);
|
| + names[0] = v8::String::New("call");
|
| + CheckChildrenNames(unresolvedNode, names);
|
| + }
|
| +
|
| + cpu_profiler->DeleteAllCpuProfiles();
|
| +}
|
| +
|
| +
|
| +static const char* function_apply_test_source = "function bar(iterations) {\n"
|
| +"}\n"
|
| +"function test() {\n"
|
| +" bar.apply(this, [10 * 1000]);\n"
|
| +"}\n"
|
| +"function start(duration) {\n"
|
| +" var start = Date.now();\n"
|
| +" while (Date.now() - start < duration) {\n"
|
| +" try {\n"
|
| +" test();\n"
|
| +" } catch(e) {}\n"
|
| +" }\n"
|
| +"}";
|
| +
|
| +
|
| +// [Top down]:
|
| +// 94 0 (root) [-1] #0 1
|
| +// 2 2 (garbage collector) [-1] #0 7
|
| +// 82 49 start [-1] #16 3
|
| +// 1 0 (unresolved function) [-1] #0 8
|
| +// 1 1 apply [-1] #0 9
|
| +// 32 21 test [-1] #16 4
|
| +// 2 2 bar [-1] #16 6
|
| +// 9 9 apply [-1] #0 5
|
| +// 10 10 (program) [-1] #0 2
|
| +TEST(FunctionApplySample) {
|
| + LocalContext env;
|
| + v8::HandleScope scope(env->GetIsolate());
|
| +
|
| + v8::Script::Compile(v8::String::New(function_apply_test_source))->Run();
|
| + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(v8::String::New("start")));
|
| +
|
| + v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
|
| + v8::Local<v8::String> profile_name = v8::String::New("my_profile");
|
| +
|
| + cpu_profiler->StartCpuProfiling(profile_name);
|
| + int32_t duration_ms = 100;
|
| +#if defined(_WIN32) || defined(_WIN64)
|
| + // 100ms is not enough on Windows. See
|
| + // https://code.google.com/p/v8/issues/detail?id=2628
|
| + duration_ms = 400;
|
| +#endif
|
| + v8::Handle<v8::Value> args[] = { v8::Integer::New(duration_ms) };
|
| + function->Call(env->Global(), ARRAY_SIZE(args), args);
|
| + const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
|
| +
|
| + CHECK_NE(NULL, profile);
|
| + // Dump collected profile to have a better diagnostic in case of failure.
|
| + reinterpret_cast<i::CpuProfile*>(
|
| + const_cast<v8::CpuProfile*>(profile))->Print();
|
| +
|
| + const v8::CpuProfileNode* root = profile->GetTopDownRoot();
|
| + {
|
| + ScopedVector<v8::Handle<v8::String> > names(3);
|
| + names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
|
| + names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
|
| + names[2] = v8::String::New("start");
|
| + // Don't allow |test|, |bar| and |apply| nodes to be at the top level.
|
| + CheckChildrenNames(root, names);
|
| + }
|
| +
|
| + const v8::CpuProfileNode* startNode = FindChild(root, "start");
|
| + if (startNode) {
|
| + {
|
| + ScopedVector<v8::Handle<v8::String> > names(2);
|
| + names[0] = v8::String::New("test");
|
| + names[1] = v8::String::New(ProfileGenerator::kUnresolvedFunctionName);
|
| + CheckChildrenNames(startNode, names);
|
| + }
|
| +
|
| + const v8::CpuProfileNode* testNode = FindChild(startNode, "test");
|
| + if (testNode) {
|
| + ScopedVector<v8::Handle<v8::String> > names(2);
|
| + names[0] = v8::String::New("bar");
|
| + names[1] = v8::String::New("apply");
|
| + CheckChildrenNames(testNode, names);
|
| + }
|
| +
|
| + if (const v8::CpuProfileNode* unresolvedNode =
|
| + FindChild(startNode, ProfileGenerator::kUnresolvedFunctionName)) {
|
| + ScopedVector<v8::Handle<v8::String> > names(1);
|
| + names[0] = v8::String::New("apply");
|
| + CheckChildrenNames(unresolvedNode, names);
|
| + GetChild(unresolvedNode, "apply");
|
| + }
|
| + }
|
| +
|
| + cpu_profiler->DeleteAllCpuProfiles();
|
| +}
|
|
|