| Index: test/cctest/test-cpu-profiler.cc
|
| diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
|
| index 0bf80003f86e0dbbc3fbb053965a38d953b89a5b..7d24fec89f8bb7a79c06b7d96be3f22434a4b4e7 100644
|
| --- a/test/cctest/test-cpu-profiler.cc
|
| +++ b/test/cctest/test-cpu-profiler.cc
|
| @@ -30,6 +30,7 @@
|
| #include "v8.h"
|
| #include "cpu-profiler-inl.h"
|
| #include "cctest.h"
|
| +#include "utils.h"
|
| #include "../include/v8-profiler.h"
|
|
|
| using i::CodeEntry;
|
| @@ -39,7 +40,9 @@ using i::CpuProfilesCollection;
|
| using i::ProfileGenerator;
|
| using i::ProfileNode;
|
| using i::ProfilerEventsProcessor;
|
| +using i::ScopedVector;
|
| using i::TokenEnumerator;
|
| +using i::Vector;
|
|
|
|
|
| TEST(StartStop) {
|
| @@ -399,3 +402,145 @@ TEST(DeleteCpuProfileDifferentTokens) {
|
| CHECK_EQ(0, cpu_profiler->GetProfileCount());
|
| CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3));
|
| }
|
| +
|
| +
|
| +static bool ContainsString(v8::Handle<v8::String> string,
|
| + const Vector<v8::Handle<v8::String> >& vector) {
|
| + for (int i = 0; i < vector.length(); i++) {
|
| + if (string->Equals(vector[i]))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| +static void CheckChildrenNames(const v8::CpuProfileNode* node,
|
| + const Vector<v8::Handle<v8::String> >& names) {
|
| + int count = node->GetChildrenCount();
|
| + for (int i = 0; i < count; i++) {
|
| + v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
|
| + CHECK(ContainsString(name, names));
|
| + // Check that there are no duplicates.
|
| + for (int j = 0; j < count; j++) {
|
| + if (j == i) continue;
|
| + CHECK_NE(name, node->GetChild(j)->GetFunctionName());
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
|
| + const char* name) {
|
| + int count = node->GetChildrenCount();
|
| + v8::Handle<v8::String> nameHandle = v8::String::New(name);
|
| + for (int i = 0; i < count; i++) {
|
| + const v8::CpuProfileNode* child = node->GetChild(i);
|
| + if (nameHandle->Equals(child->GetFunctionName())) return child;
|
| + }
|
| + CHECK(false);
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +static void CheckSimpleBranch(const v8::CpuProfileNode* node,
|
| + const char* names[], int length) {
|
| + for (int i = 0; i < length; i++) {
|
| + const char* name = names[i];
|
| + node = FindChild(node, name);
|
| + CHECK(node);
|
| + int expectedChildrenCount = (i == length - 1) ? 0 : 1;
|
| + CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
|
| + }
|
| +}
|
| +
|
| +
|
| +static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
|
| +" this.mmm = 0;\n"
|
| +" var start = Date.now();\n"
|
| +" while (Date.now() - start < timeout) {\n"
|
| +" var n = 100*1000;\n"
|
| +" while(n > 1) {\n"
|
| +" n--;\n"
|
| +" this.mmm += n * n * n;\n"
|
| +" }\n"
|
| +" }\n"
|
| +"}\n"
|
| +"function delay() { try { loop(10); } catch(e) { } }\n"
|
| +"function bar() { delay(); }\n"
|
| +"function baz() { delay(); }\n"
|
| +"function foo() {\n"
|
| +" try {\n"
|
| +" delay();\n"
|
| +" bar();\n"
|
| +" delay();\n"
|
| +" baz();\n"
|
| +" } catch (e) { }\n"
|
| +"}\n"
|
| +"function start() {\n"
|
| +" var start = Date.now();\n"
|
| +" do {\n"
|
| +" foo();\n"
|
| +" var duration = Date.now() - start;\n"
|
| +" } while (duration < 200);\n"
|
| +" return duration;\n"
|
| +"}\n";
|
| +
|
| +
|
| +// Check that the profile tree for the script above will look like the
|
| +// following:
|
| +//
|
| +// [Top down]:
|
| +// 1062 0 (root) [-1]
|
| +// 1054 0 start [-1]
|
| +// 1054 1 foo [-1]
|
| +// 265 0 baz [-1]
|
| +// 265 1 delay [-1]
|
| +// 264 264 loop [-1]
|
| +// 525 3 delay [-1]
|
| +// 522 522 loop [-1]
|
| +// 263 0 bar [-1]
|
| +// 263 1 delay [-1]
|
| +// 262 262 loop [-1]
|
| +// 2 2 (program) [-1]
|
| +// 6 6 (garbage collector) [-1]
|
| +TEST(CollectCpuProfile) {
|
| + LocalContext env;
|
| + v8::HandleScope scope(env->GetIsolate());
|
| +
|
| + v8::Script::Compile(v8::String::New(cpu_profiler_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);
|
| + function->Call(env->Global(), 0, 0);
|
| + 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");
|
| + CheckChildrenNames(root, names);
|
| +
|
| + const v8::CpuProfileNode* startNode = FindChild(root, "start");
|
| + CHECK_EQ(1, startNode->GetChildrenCount());
|
| +
|
| + const v8::CpuProfileNode* fooNode = FindChild(startNode, "foo");
|
| + CHECK_EQ(3, fooNode->GetChildrenCount());
|
| +
|
| + const char* barBranch[] = { "bar", "delay", "loop" };
|
| + CheckSimpleBranch(fooNode, barBranch, ARRAY_SIZE(barBranch));
|
| + const char* bazBranch[] = { "baz", "delay", "loop" };
|
| + CheckSimpleBranch(fooNode, bazBranch, ARRAY_SIZE(bazBranch));
|
| + const char* delayBranch[] = { "delay", "loop" };
|
| + CheckSimpleBranch(fooNode, delayBranch, ARRAY_SIZE(delayBranch));
|
| +}
|
|
|