Commit 1b6265ef authored by alph's avatar alph Committed by Commit bot

Unflake CPU profiler tests.

Do not rely on elapsed time to collect enough samples.
Use CollectSample API function instead.

Remove checks for extra functions present in a profile, as
there in fact can be lots of native support functions.

BUG=v8:2999
LOG=N

Review URL: https://codereview.chromium.org/1665303004

Cr-Commit-Position: refs/heads/master@{#33822}
parent fe581185
......@@ -71,20 +71,9 @@
# This tests API threading, no point in running several variants.
'test-api/Threading*': [PASS, NO_VARIANTS],
# The cpu profiler tests are notoriously flaky.
# BUG(2999). (test/cpu-profiler/CollectCpuProfile)
# BUG(3287). (test-cpu-profiler/SampleWhenFrameIsNotSetup)
'test-cpu-profiler/CollectCpuProfile': [SKIP],
'test-cpu-profiler/CollectCpuProfileSamples': [SKIP],
'test-cpu-profiler/FunctionApplySample': [SKIP],
'test-cpu-profiler/FunctionCallSample': [SKIP],
'test-cpu-profiler/SampleWhenFrameIsNotSetup': [SKIP],
'test-cpu-profiler/HotDeoptNoFrameEntry': [SKIP],
'test-cpu-profiler/BoundFunctionCall': [SKIP],
# BUG(2999). The cpu profiler tests are notoriously flaky.
'test-cpu-profiler/CpuProfileDeepStack': [SKIP],
'test-cpu-profiler/JsNativeJsSample': [SKIP],
'test-cpu-profiler/JsNativeJsRuntimeJsSample': [SKIP],
'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP],
'test-cpu-profiler/HotDeoptNoFrameEntry': [SKIP],
# BUG(3525). Test crashes flakily.
'test-debug/RecursiveBreakpoints': [PASS, FLAKY],
......@@ -605,13 +594,23 @@
# TODO(rmcilroy,4680): Test assert errors.
'test-cpu-profiler/CodeEvents': [FAIL],
'test-cpu-profiler/TickEvents': [FAIL],
'test-cpu-profiler/BoundFunctionCall': [FAIL],
'test-cpu-profiler/CollectCpuProfile': [FAIL],
'test-cpu-profiler/CollectSampleAPI': [FAIL],
'test-cpu-profiler/CpuProfileDeepStack': [FAIL],
'test-cpu-profiler/FunctionApplySample': [FAIL],
'test-cpu-profiler/FunctionCallSample': [FAIL],
'test-cpu-profiler/FunctionDetails': [FAIL],
'test-cpu-profiler/HotDeoptNoFrameEntry': [FAIL],
'test-cpu-profiler/JsNative1JsNative2JsSample': [FAIL],
'test-cpu-profiler/JsNativeJsRuntimeJsSample': [FAIL],
'test-cpu-profiler/JsNativeJsRuntimeJsSampleMultiple': [FAIL],
'test-cpu-profiler/JsNativeJsSample': [FAIL],
'test-cpu-profiler/NativeMethodUninitializedIC': [FAIL],
'test-cpu-profiler/NativeMethodMonomorphicIC': [FAIL],
'test-cpu-profiler/NativeAccessorUninitializedIC': [FAIL],
'test-cpu-profiler/NativeAccessorMonomorphicIC': [FAIL],
'test-cpu-profiler/SampleWhenFrameIsNotSetup': [FAIL],
'test-sampler-api/StackFramesConsistent': [FAIL],
'test-profile-generator/LineNumber': [FAIL],
'test-profile-generator/ProfileNodeScriptId': [FAIL],
......
......@@ -27,41 +27,35 @@
//
// Tests of profiles generator and utilities.
#include "src/base/logging.h"
#include "test/cctest/profiler-extension.h"
#include "test/cctest/cctest.h"
namespace v8 {
namespace internal {
v8::CpuProfile* ProfilerExtension::last_profile = NULL;
const char* ProfilerExtension::kSource =
"native function startProfiling();"
"native function stopProfiling();";
"native function stopProfiling();"
"native function collectSample();";
v8::Local<v8::FunctionTemplate> ProfilerExtension::GetNativeFunctionTemplate(
v8::Isolate* isolate, v8::Local<v8::String> name) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (name->Equals(context, v8::String::NewFromUtf8(isolate, "startProfiling",
v8::NewStringType::kNormal)
.ToLocalChecked())
.FromJust()) {
if (name->Equals(context, v8_str(isolate, "startProfiling")).FromJust()) {
return v8::FunctionTemplate::New(isolate,
ProfilerExtension::StartProfiling);
} else if (name->Equals(context,
v8::String::NewFromUtf8(isolate, "stopProfiling",
v8::NewStringType::kNormal)
.ToLocalChecked())
.FromJust()) {
return v8::FunctionTemplate::New(isolate,
ProfilerExtension::StopProfiling);
} else {
CHECK(false);
return v8::Local<v8::FunctionTemplate>();
}
if (name->Equals(context, v8_str(isolate, "stopProfiling")).FromJust()) {
return v8::FunctionTemplate::New(isolate, ProfilerExtension::StopProfiling);
}
if (name->Equals(context, v8_str(isolate, "collectSample")).FromJust()) {
return v8::FunctionTemplate::New(isolate, ProfilerExtension::CollectSample);
}
CHECK(false);
return v8::Local<v8::FunctionTemplate>();
}
void ProfilerExtension::StartProfiling(
const v8::FunctionCallbackInfo<v8::Value>& args) {
last_profile = NULL;
......@@ -71,7 +65,6 @@ void ProfilerExtension::StartProfiling(
: v8::String::Empty(args.GetIsolate()));
}
void ProfilerExtension::StopProfiling(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler();
......@@ -80,5 +73,10 @@ void ProfilerExtension::StopProfiling(
: v8::String::Empty(args.GetIsolate()));
}
void ProfilerExtension::CollectSample(
const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetIsolate()->GetCpuProfiler()->CollectSample();
}
} // namespace internal
} // namespace v8
......@@ -40,10 +40,13 @@ class ProfilerExtension : public v8::Extension {
ProfilerExtension() : v8::Extension("v8/profiler", kSource) { }
virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
v8::Isolate* isolate, v8::Local<v8::String> name);
static void StartProfiling(const v8::FunctionCallbackInfo<v8::Value>& args);
static void StopProfiling(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::CpuProfile* last_profile;
private:
static void StartProfiling(const v8::FunctionCallbackInfo<v8::Value>& args);
static void StopProfiling(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args);
static const char* kSource;
};
......
......@@ -75,7 +75,7 @@ TEST(StartStop) {
CpuProfilesCollection profiles(isolate->heap());
ProfileGenerator generator(&profiles);
SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
&generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
&generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
processor->Start();
processor->StopSynchronously();
}
......@@ -446,55 +446,14 @@ static v8::CpuProfile* RunProfiler(v8::Local<v8::Context> env,
}
static bool ContainsString(v8::Local<v8::Context> context,
v8::Local<v8::String> string,
const Vector<v8::Local<v8::String> >& vector) {
for (int i = 0; i < vector.length(); i++) {
if (string->Equals(context, vector[i]).FromJust()) return true;
}
return false;
}
static void CheckChildrenNames(v8::Local<v8::Context> context,
const v8::CpuProfileNode* node,
const Vector<v8::Local<v8::String> >& names) {
int count = node->GetChildrenCount();
for (int i = 0; i < count; i++) {
v8::Local<v8::String> name = node->GetChild(i)->GetFunctionName();
if (!ContainsString(context, name, names)) {
char buffer[100];
i::SNPrintF(Vector<char>(buffer, arraysize(buffer)),
"Unexpected child '%s' found in '%s'",
*v8::String::Utf8Value(name),
*v8::String::Utf8Value(node->GetFunctionName()));
FATAL(buffer);
}
// Check that there are no duplicates.
for (int j = 0; j < count; j++) {
if (j == i) continue;
if (name->Equals(context, node->GetChild(j)->GetFunctionName())
.FromJust()) {
char buffer[100];
i::SNPrintF(Vector<char>(buffer, arraysize(buffer)),
"Second child with the same name '%s' found in '%s'",
*v8::String::Utf8Value(name),
*v8::String::Utf8Value(node->GetFunctionName()));
FATAL(buffer);
}
}
}
}
static const v8::CpuProfileNode* FindChild(v8::Local<v8::Context> context,
const v8::CpuProfileNode* node,
const char* name) {
int count = node->GetChildrenCount();
v8::Local<v8::String> nameHandle = v8_str(name);
v8::Local<v8::String> name_handle = v8_str(name);
for (int i = 0; i < count; i++) {
const v8::CpuProfileNode* child = node->GetChild(i);
if (nameHandle->Equals(context, child->GetFunctionName()).FromJust()) {
if (name_handle->Equals(context, child->GetFunctionName()).FromJust()) {
return child;
}
}
......@@ -522,8 +481,6 @@ static void CheckSimpleBranch(v8::Local<v8::Context> context,
for (int i = 0; i < length; i++) {
const char* name = names[i];
node = GetChild(context, node, name);
int expectedChildrenCount = (i == length - 1) ? 0 : 1;
CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
}
}
......@@ -542,37 +499,39 @@ static void CallCollectSample(const v8::FunctionCallbackInfo<v8::Value>& info) {
info.GetIsolate()->GetCpuProfiler()->CollectSample();
}
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(timeout) {\n"
" var start = Date.now();\n"
" do {\n"
" foo();\n"
" var duration = Date.now() - start;\n"
" } while (duration < timeout);\n"
" return duration;\n"
"}\n";
static const char* cpu_profiler_test_source =
"%NeverOptimizeFunction(loop);\n"
"%NeverOptimizeFunction(delay);\n"
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(baz);\n"
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(start);\n"
"function loop(timeout) {\n"
" this.mmm = 0;\n"
" var start = Date.now();\n"
" do {\n"
" var n = 1000;\n"
" while(n > 1) {\n"
" n--;\n"
" this.mmm += n * n * n;\n"
" }\n"
" } while (Date.now() - start < timeout);\n"
"}\n"
"function delay() { loop(10); }\n"
"function bar() { delay(); }\n"
"function baz() { delay(); }\n"
"function foo() {\n"
" delay();\n"
" bar();\n"
" delay();\n"
" baz();\n"
"}\n"
"function start(duration) {\n"
" var start = Date.now();\n"
" do {\n"
" foo();\n"
" } while (Date.now() - start < duration);\n"
"}\n";
// Check that the profile tree for the script above will look like the
// following:
......@@ -592,6 +551,7 @@ static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
// 2 2 (program) [-1]
// 6 6 (garbage collector) [-1]
TEST(CollectCpuProfile) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
......@@ -602,49 +562,37 @@ TEST(CollectCpuProfile) {
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
v8::CpuProfile* profile =
RunProfiler(env.local(), function, args, arraysize(args), 200);
function->Call(env.local(), env->Global(), arraysize(args), args)
.ToLocalChecked();
RunProfiler(env.local(), function, args, arraysize(args), 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
const v8::CpuProfileNode* foo_node = GetChild(env.local(), start_node, "foo");
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env.local(), root, names);
const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start");
CHECK_EQ(1, startNode->GetChildrenCount());
const v8::CpuProfileNode* fooNode = GetChild(env.local(), startNode, "foo");
CHECK_EQ(3, fooNode->GetChildrenCount());
const char* barBranch[] = { "bar", "delay", "loop" };
CheckSimpleBranch(env.local(), fooNode, barBranch, arraysize(barBranch));
const char* bazBranch[] = { "baz", "delay", "loop" };
CheckSimpleBranch(env.local(), fooNode, bazBranch, arraysize(bazBranch));
const char* delayBranch[] = { "delay", "loop" };
CheckSimpleBranch(env.local(), fooNode, delayBranch, arraysize(delayBranch));
const char* bar_branch[] = {"bar", "delay", "loop"};
CheckSimpleBranch(env.local(), foo_node, bar_branch, arraysize(bar_branch));
const char* baz_branch[] = {"baz", "delay", "loop"};
CheckSimpleBranch(env.local(), foo_node, baz_branch, arraysize(baz_branch));
const char* delay_branch[] = {"delay", "loop"};
CheckSimpleBranch(env.local(), foo_node, delay_branch,
arraysize(delay_branch));
profile->Delete();
}
static const char* hot_deopt_no_frame_entry_test_source =
"function foo(a, b) {\n"
" try {\n"
" return a + b;\n"
" } catch (e) { }\n"
"}\n"
"function start(timeout) {\n"
" var start = Date.now();\n"
" do {\n"
" for (var i = 1; i < 1000; ++i) foo(1, i);\n"
" var duration = Date.now() - start;\n"
" } while (duration < timeout);\n"
" return duration;\n"
"}\n";
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(start);\n"
"function foo(a, b) {\n"
" return a + b;\n"
"}\n"
"function start(timeout) {\n"
" var start = Date.now();\n"
" do {\n"
" for (var i = 1; i < 1000; ++i) foo(1, i);\n"
" var duration = Date.now() - start;\n"
" } while (duration < timeout);\n"
" return duration;\n"
"}\n";
// Check that the profile tree for the script above will look like the
// following:
......@@ -660,6 +608,7 @@ static const char* hot_deopt_no_frame_entry_test_source =
// If 'foo' has no ranges the samples falling into the prologue will miss the
// 'start' function on the stack, so 'foo' will be attached to the (root).
TEST(HotDeoptNoFrameEntry) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
......@@ -670,28 +619,19 @@ TEST(HotDeoptNoFrameEntry) {
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
v8::CpuProfile* profile =
RunProfiler(env.local(), function, args, arraysize(args), 200);
RunProfiler(env.local(), function, args, arraysize(args), 1000);
function->Call(env.local(), env->Global(), arraysize(args), args)
.ToLocalChecked();
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env.local(), root, names);
const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start");
CHECK_EQ(1, startNode->GetChildrenCount());
GetChild(env.local(), startNode, "foo");
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "foo");
profile->Delete();
}
TEST(CollectCpuProfileSamples) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
......@@ -702,7 +642,7 @@ TEST(CollectCpuProfileSamples) {
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
v8::CpuProfile* profile =
RunProfiler(env.local(), function, args, arraysize(args), 200, true);
RunProfiler(env.local(), function, args, arraysize(args), 1000, true);
CHECK_LE(200, profile->GetSamplesCount());
uint64_t end_time = profile->GetEndTime();
......@@ -719,15 +659,18 @@ TEST(CollectCpuProfileSamples) {
profile->Delete();
}
static const char* cpu_profiler_test_source2 = "function loop() {}\n"
"function delay() { loop(); }\n"
"function start(count) {\n"
" var k = 0;\n"
" do {\n"
" delay();\n"
" } while (++k < count*100*1000);\n"
"}\n";
static const char* cpu_profiler_test_source2 =
"%NeverOptimizeFunction(loop);\n"
"%NeverOptimizeFunction(delay);\n"
"%NeverOptimizeFunction(start);\n"
"function loop() {}\n"
"function delay() { loop(); }\n"
"function start(duration) {\n"
" var start = Date.now();\n"
" do {\n"
" for (var i = 0; i < 10000; ++i) delay();\n"
" } while (Date.now() - start < duration);\n"
"}";
// Check that the profile tree doesn't contain unexpected traces:
// - 'loop' can be called only by 'delay'
......@@ -741,47 +684,28 @@ static const char* cpu_profiler_test_source2 = "function loop() {}\n"
// 16 16 loop [-1] #5
// 14 14 (program) [-1] #2
TEST(SampleWhenFrameIsNotSetup) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
CompileRun(cpu_profiler_test_source2);
v8::Local<v8::Function> function = GetFunction(env.local(), "start");
int32_t repeat_count = 100;
#if defined(USE_SIMULATOR)
// Simulators are much slower.
repeat_count = 1;
#endif
int32_t duration_ms = 100;
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), repeat_count)};
v8::Integer::New(env->GetIsolate(), duration_ms)};
v8::CpuProfile* profile =
RunProfiler(env.local(), function, args, arraysize(args), 100);
RunProfiler(env.local(), function, args, arraysize(args), 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env.local(), root, names);
const v8::CpuProfileNode* startNode = FindChild(env.local(), root, "start");
// On slow machines there may be no meaningfull samples at all, skip the
// check there.
if (startNode && startNode->GetChildrenCount() > 0) {
CHECK_EQ(1, startNode->GetChildrenCount());
const v8::CpuProfileNode* delayNode =
GetChild(env.local(), startNode, "delay");
if (delayNode->GetChildrenCount() > 0) {
CHECK_EQ(1, delayNode->GetChildrenCount());
GetChild(env.local(), delayNode, "loop");
}
}
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
const v8::CpuProfileNode* delay_node =
GetChild(env.local(), start_node, "delay");
GetChild(env.local(), delay_node, "loop");
profile->Delete();
}
static const char* native_accessor_test_source = "function start(count) {\n"
" for (var i = 0; i < count; i++) {\n"
" var o = instance.foo;\n"
......@@ -789,7 +713,6 @@ static const char* native_accessor_test_source = "function start(count) {\n"
" }\n"
"}\n";
class TestApiCallbacks {
public:
explicit TestApiCallbacks(int min_duration_ms)
......@@ -798,19 +721,19 @@ class TestApiCallbacks {
static void Getter(v8::Local<v8::String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
TestApiCallbacks* data = fromInfo(info);
TestApiCallbacks* data = FromInfo(info);
data->Wait();
}
static void Setter(v8::Local<v8::String> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
TestApiCallbacks* data = fromInfo(info);
TestApiCallbacks* data = FromInfo(info);
data->Wait();
}
static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
TestApiCallbacks* data = fromInfo(info);
TestApiCallbacks* data = FromInfo(info);
data->Wait();
}
......@@ -827,8 +750,8 @@ class TestApiCallbacks {
}
}
template<typename T>
static TestApiCallbacks* fromInfo(const T& info) {
template <typename T>
static TestApiCallbacks* FromInfo(const T& info) {
void* data = v8::External::Cast(*info.Data())->Value();
return reinterpret_cast<TestApiCallbacks*>(data);
}
......@@ -872,9 +795,9 @@ TEST(NativeAccessorUninitializedIC) {
RunProfiler(env.local(), function, args, arraysize(args), 180);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start");
GetChild(env.local(), startNode, "get foo");
GetChild(env.local(), startNode, "set foo");
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "get foo");
GetChild(env.local(), start_node, "set foo");
profile->Delete();
}
......@@ -925,9 +848,9 @@ TEST(NativeAccessorMonomorphicIC) {
RunProfiler(env.local(), function, args, arraysize(args), 200);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start");
GetChild(env.local(), startNode, "get foo");
GetChild(env.local(), startNode, "set foo");
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "get foo");
GetChild(env.local(), start_node, "set foo");
profile->Delete();
}
......@@ -976,8 +899,8 @@ TEST(NativeMethodUninitializedIC) {
RunProfiler(env.local(), function, args, arraysize(args), 100);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start");
GetChild(env.local(), startNode, "fooMethod");
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "fooMethod");
profile->Delete();
}
......@@ -1031,8 +954,8 @@ TEST(NativeMethodMonomorphicIC) {
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
GetChild(env.local(), root, "start");
const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start");
GetChild(env.local(), startNode, "fooMethod");
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "fooMethod");
profile->Delete();
}
......@@ -1059,15 +982,9 @@ TEST(BoundFunctionCall) {
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
// Don't allow |foo| node to be at the top level.
CheckChildrenNames(env, root, names);
const v8::CpuProfileNode* startNode = GetChild(env, root, "start");
GetChild(env, startNode, "foo");
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
GetChild(env, start_node, "foo");
profile->Delete();
}
......@@ -1170,18 +1087,21 @@ TEST(TickLines) {
CHECK_EQ(hit_count, value);
}
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"
"}";
static const char* call_function_test_source =
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(start);\n"
"function bar(n) {\n"
" var s = 0;\n"
" for (var i = 0; i < n; i++) s += i * i * i;\n"
" return s;\n"
"}\n"
"function start(duration) {\n"
" var start = Date.now();\n"
" do {\n"
" for (var i = 0; i < 100; ++i)\n"
" bar.call(this, 1000);\n"
" } while (Date.now() - start < duration);\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
......@@ -1196,6 +1116,7 @@ static const char* call_function_test_source = "function bar(iterations) {\n"
// 1 1 bar [-1] #7
// 19 19 (program) [-1] #2
TEST(FunctionCallSample) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
......@@ -1210,60 +1131,38 @@ TEST(FunctionCallSample) {
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), duration_ms)};
v8::CpuProfile* profile =
RunProfiler(env.local(), function, args, arraysize(args), 100);
RunProfiler(env.local(), function, args, arraysize(args), 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
{
ScopedVector<v8::Local<v8::String> > names(4);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
names[3] = v8_str(i::ProfileGenerator::kUnresolvedFunctionName);
// Don't allow |bar| and |call| nodes to be at the top level.
CheckChildrenNames(env.local(), root, names);
}
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "bar");
// 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(env.local(), root, "start");
CHECK(is_gc_stress_testing || startNode);
if (startNode) {
ScopedVector<v8::Local<v8::String> > names(2);
names[0] = v8_str("bar");
names[1] = v8_str("call");
CheckChildrenNames(env.local(), startNode, names);
}
const v8::CpuProfileNode* unresolvedNode = FindChild(
const v8::CpuProfileNode* unresolved_node = FindChild(
env.local(), root, i::ProfileGenerator::kUnresolvedFunctionName);
if (unresolvedNode) {
ScopedVector<v8::Local<v8::String> > names(1);
names[0] = v8_str("call");
CheckChildrenNames(env.local(), unresolvedNode, names);
}
CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call"));
profile->Delete();
}
static const char* function_apply_test_source =
"function bar(iterations) {\n"
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(test);\n"
"%NeverOptimizeFunction(start);\n"
"function bar(n) {\n"
" var s = 0;\n"
" for (var i = 0; i < n; i++) s += i * i * i;\n"
" return s;\n"
"}\n"
"function test() {\n"
" bar.apply(this, [10 * 1000]);\n"
" bar.apply(this, [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"
" do {\n"
" for (var i = 0; i < 100; ++i) test();\n"
" } while (Date.now() - start < duration);\n"
"}";
// [Top down]:
// 94 0 (root) [-1] #0 1
// 2 2 (garbage collector) [-1] #0 7
......@@ -1272,9 +1171,9 @@ static const char* function_apply_test_source =
// 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) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
......@@ -1286,64 +1185,32 @@ TEST(FunctionApplySample) {
v8::Integer::New(env->GetIsolate(), duration_ms)};
v8::CpuProfile* profile =
RunProfiler(env.local(), function, args, arraysize(args), 100);
RunProfiler(env.local(), function, args, arraysize(args), 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
{
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
// Don't allow |test|, |bar| and |apply| nodes to be at the top level.
CheckChildrenNames(env.local(), root, names);
}
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
const v8::CpuProfileNode* test_node =
GetChild(env.local(), start_node, "test");
GetChild(env.local(), test_node, "bar");
const v8::CpuProfileNode* startNode = FindChild(env.local(), root, "start");
if (startNode) {
{
ScopedVector<v8::Local<v8::String> > names(2);
names[0] = v8_str("test");
names[1] = v8_str(ProfileGenerator::kUnresolvedFunctionName);
CheckChildrenNames(env.local(), startNode, names);
}
const v8::CpuProfileNode* testNode =
FindChild(env.local(), startNode, "test");
if (testNode) {
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str("bar");
names[1] = v8_str("apply");
// apply calls "get length" before invoking the function itself
// and we may get hit into it.
names[2] = v8_str("get length");
CheckChildrenNames(env.local(), testNode, names);
}
if (const v8::CpuProfileNode* unresolvedNode =
FindChild(env.local(), startNode,
ProfileGenerator::kUnresolvedFunctionName)) {
ScopedVector<v8::Local<v8::String> > names(1);
names[0] = v8_str("apply");
CheckChildrenNames(env.local(), unresolvedNode, names);
GetChild(env.local(), unresolvedNode, "apply");
}
}
const v8::CpuProfileNode* unresolved_node = FindChild(
env.local(), start_node, ProfileGenerator::kUnresolvedFunctionName);
CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply"));
profile->Delete();
}
static const char* cpu_profiler_deep_stack_test_source =
"function foo(n) {\n"
" if (n)\n"
" foo(n - 1);\n"
" else\n"
" startProfiling('my_profile');\n"
"}\n"
"function start() {\n"
" foo(250);\n"
"}\n";
"function foo(n) {\n"
" if (n)\n"
" foo(n - 1);\n"
" else\n"
" collectSample();\n"
"}\n"
"function start() {\n"
" startProfiling('my_profile');\n"
" foo(250);\n"
"}\n";
// Check a deep stack
//
......@@ -1354,8 +1221,7 @@ static const char* cpu_profiler_deep_stack_test_source =
// 0 foo 21 #4 no reason
// 0 foo 21 #5 no reason
// ....
// 0 foo 21 #253 no reason
// 1 startProfiling 0 #254
// 0 foo 21 #254 no reason
TEST(CpuProfileDeepStack) {
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
......@@ -1373,37 +1239,29 @@ TEST(CpuProfileDeepStack) {
reinterpret_cast<i::CpuProfile*>(profile)->Print();
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
{
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env, root, names);
}
const v8::CpuProfileNode* node = GetChild(env, root, "start");
for (int i = 0; i < 250; ++i) {
for (int i = 0; i <= 250; ++i) {
node = GetChild(env, node, "foo");
}
// TODO(alph):
// In theory there must be one more 'foo' and a 'startProfiling' nodes,
// but due to unstable top frame extraction these might be missing.
CHECK(!FindChild(env, node, "foo"));
profile->Delete();
}
static const char* js_native_js_test_source =
"function foo() {\n"
" startProfiling('my_profile');\n"
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(start);\n"
"function foo(n) {\n"
" var s = 0;\n"
" for (var i = 0; i < n; i++) s += i * i * i;\n"
" return s;\n"
"}\n"
"function bar() {\n"
" try { foo(); } catch(e) {}\n"
" foo(1000);\n"
"}\n"
"function start() {\n"
" try {\n"
" CallJsFunction(bar);\n"
" } catch(e) {}\n"
" CallJsFunction(bar);\n"
"}";
static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
......@@ -1414,7 +1272,6 @@ static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
.ToLocalChecked();
}
// [Top down]:
// 58 0 (root) #0 1
// 2 2 (program) #0 2
......@@ -1423,6 +1280,7 @@ static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
// 55 1 bar #16 5
// 54 54 foo #16 6
TEST(JsNativeJsSample) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
v8::Context::Scope context_scope(env);
......@@ -1437,47 +1295,35 @@ TEST(JsNativeJsSample) {
CompileRun(js_native_js_test_source);
v8::Local<v8::Function> function = GetFunction(env, "start");
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0);
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
{
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env, root, names);
}
const v8::CpuProfileNode* startNode = GetChild(env, root, "start");
CHECK_EQ(1, startNode->GetChildrenCount());
const v8::CpuProfileNode* nativeFunctionNode =
GetChild(env, startNode, "CallJsFunction");
CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
const v8::CpuProfileNode* barNode = GetChild(env, nativeFunctionNode, "bar");
CHECK_EQ(1, barNode->GetChildrenCount());
GetChild(env, barNode, "foo");
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
const v8::CpuProfileNode* native_node =
GetChild(env, start_node, "CallJsFunction");
const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
GetChild(env, bar_node, "foo");
profile->Delete();
}
static const char* js_native_js_runtime_js_test_source =
"function foo() {\n"
" startProfiling('my_profile');\n"
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(start);\n"
"function foo(n) {\n"
" var s = 0;\n"
" for (var i = 0; i < n; i++) s += i * i * i;\n"
" return s;\n"
"}\n"
"var bound = foo.bind(this);\n"
"function bar() {\n"
" try { bound(); } catch(e) {}\n"
" bound(1000);\n"
"}\n"
"function start() {\n"
" try {\n"
" CallJsFunction(bar);\n"
" } catch(e) {}\n"
" CallJsFunction(bar);\n"
"}";
// [Top down]:
// 57 0 (root) #0 1
// 55 1 start #16 3
......@@ -1486,6 +1332,7 @@ static const char* js_native_js_runtime_js_test_source =
// 51 51 foo #16 6
// 2 2 (program) #0 2
TEST(JsNativeJsRuntimeJsSample) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
v8::Context::Scope context_scope(env);
......@@ -1499,57 +1346,39 @@ TEST(JsNativeJsRuntimeJsSample) {
CompileRun(js_native_js_runtime_js_test_source);
v8::Local<v8::Function> function = GetFunction(env, "start");
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0);
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env, root, names);
const v8::CpuProfileNode* startNode = GetChild(env, root, "start");
CHECK_EQ(1, startNode->GetChildrenCount());
const v8::CpuProfileNode* nativeFunctionNode =
GetChild(env, startNode, "CallJsFunction");
CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
const v8::CpuProfileNode* barNode = GetChild(env, nativeFunctionNode, "bar");
// The child is in fact a bound foo.
// A bound function has a wrapper that may make calls to
// other functions e.g. "get length".
CHECK_LE(1, barNode->GetChildrenCount());
CHECK_GE(2, barNode->GetChildrenCount());
GetChild(env, barNode, "foo");
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
const v8::CpuProfileNode* native_node =
GetChild(env, start_node, "CallJsFunction");
const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
GetChild(env, bar_node, "foo");
profile->Delete();
}
static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::base::OS::Print("In CallJsFunction2\n");
CallJsFunction(info);
}
static const char* js_native1_js_native2_js_test_source =
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(start);\n"
"function foo() {\n"
" try {\n"
" startProfiling('my_profile');\n"
" } catch(e) {}\n"
" var s = 0;\n"
" for (var i = 0; i < 1000; i++) s += i * i * i;\n"
" return s;\n"
"}\n"
"function bar() {\n"
" CallJsFunction2(foo);\n"
"}\n"
"function start() {\n"
" try {\n"
" CallJsFunction1(bar);\n"
" } catch(e) {}\n"
" CallJsFunction1(bar);\n"
"}";
// [Top down]:
// 57 0 (root) #0 1
// 55 1 start #16 3
......@@ -1559,14 +1388,15 @@ static const char* js_native1_js_native2_js_test_source =
// 54 54 foo #16 7
// 2 2 (program) #0 2
TEST(JsNative1JsNative2JsSample) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
v8::Context::Scope context_scope(env);
v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
env->GetIsolate(), CallJsFunction);
v8::Local<v8::Function> func1 =
func_template->GetFunction(env).ToLocalChecked();
v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction)
->GetFunction(env)
.ToLocalChecked();
func1->SetName(v8_str("CallJsFunction1"));
env->Global()->Set(env, v8_str("CallJsFunction1"), func1).FromJust();
......@@ -1580,29 +1410,16 @@ TEST(JsNative1JsNative2JsSample) {
CompileRun(js_native1_js_native2_js_test_source);
v8::Local<v8::Function> function = GetFunction(env, "start");
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0);
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str("start");
CheckChildrenNames(env, root, names);
const v8::CpuProfileNode* startNode = GetChild(env, root, "start");
CHECK_EQ(1, startNode->GetChildrenCount());
const v8::CpuProfileNode* nativeNode1 =
GetChild(env, startNode, "CallJsFunction1");
CHECK_EQ(1, nativeNode1->GetChildrenCount());
const v8::CpuProfileNode* barNode = GetChild(env, nativeNode1, "bar");
CHECK_EQ(1, barNode->GetChildrenCount());
const v8::CpuProfileNode* nativeNode2 =
GetChild(env, barNode, "CallJsFunction2");
CHECK_EQ(1, nativeNode2->GetChildrenCount());
GetChild(env, nativeNode2, "foo");
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
const v8::CpuProfileNode* native_node1 =
GetChild(env, start_node, "CallJsFunction1");
const v8::CpuProfileNode* bar_node = GetChild(env, native_node1, "bar");
const v8::CpuProfileNode* native_node2 =
GetChild(env, bar_node, "CallJsFunction2");
GetChild(env, native_node2, "foo");
profile->Delete();
}
......@@ -1626,34 +1443,33 @@ TEST(CollectSampleAPI) {
CompileRun(js_force_collect_sample_source);
v8::Local<v8::Function> function = GetFunction(env, "start");
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* startNode = GetChild(env, root, "start");
CHECK_LE(1, startNode->GetChildrenCount());
GetChild(env, startNode, "CallCollectSample");
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
CHECK_LE(1, start_node->GetChildrenCount());
GetChild(env, start_node, "CallCollectSample");
profile->Delete();
}
static const char* js_native_js_runtime_multiple_test_source =
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(bar);\n"
"%NeverOptimizeFunction(start);\n"
"function foo() {\n"
" CallCollectSample();"
" return Math.sin(Math.random());\n"
"}\n"
"var bound = foo.bind(this);\n"
"function bar() {\n"
" try { return bound(); } catch(e) {}\n"
" return bound();\n"
"}\n"
"function start() {\n"
" try {\n"
" startProfiling('my_profile');\n"
" var startTime = Date.now();\n"
" do {\n"
" CallJsFunction(bar);\n"
" } while (Date.now() - startTime < 200);\n"
" } catch(e) {}\n"
" startProfiling('my_profile');\n"
" var startTime = Date.now();\n"
" do {\n"
" CallJsFunction(bar);\n"
" } while (Date.now() - startTime < 200);\n"
"}";
// The test check multiple entrances/exits between JS and native code.
......@@ -1664,9 +1480,9 @@ static const char* js_native_js_runtime_multiple_test_source =
// CallJsFunction #0 4
// bar #16 5
// foo #16 6
// CallCollectSample
// (program) #0 2
TEST(JsNativeJsRuntimeJsSampleMultiple) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
v8::Context::Scope context_scope(env);
......@@ -1678,25 +1494,17 @@ TEST(JsNativeJsRuntimeJsSampleMultiple) {
func->SetName(v8_str("CallJsFunction"));
env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
func_template =
v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample);
func = func_template->GetFunction(env).ToLocalChecked();
func->SetName(v8_str("CallCollectSample"));
env->Global()->Set(env, v8_str("CallCollectSample"), func).FromJust();
CompileRun(js_native_js_runtime_multiple_test_source);
v8::Local<v8::Function> function = GetFunction(env, "start");
v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* startNode = GetChild(env, root, "start");
const v8::CpuProfileNode* nativeFunctionNode =
GetChild(env, startNode, "CallJsFunction");
const v8::CpuProfileNode* barNode = GetChild(env, nativeFunctionNode, "bar");
const v8::CpuProfileNode* fooNode = GetChild(env, barNode, "foo");
GetChild(env, fooNode, "CallCollectSample");
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
const v8::CpuProfileNode* native_node =
GetChild(env, start_node, "CallJsFunction");
const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
GetChild(env, bar_node, "foo");
profile->Delete();
}
......@@ -1715,14 +1523,12 @@ TEST(IdleTime) {
i::Isolate* isolate = CcTest::i_isolate();
i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor();
processor->AddCurrentStack(isolate, true);
processor->AddCurrentStack(isolate, true);
cpu_profiler->SetIdle(true);
for (int i = 0; i < 3; i++) {
processor->AddCurrentStack(isolate, true);
}
cpu_profiler->SetIdle(false);
processor->AddCurrentStack(isolate, true);
......@@ -1732,26 +1538,19 @@ TEST(IdleTime) {
reinterpret_cast<i::CpuProfile*>(profile)->Print();
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Local<v8::String> > names(3);
names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8_str(ProfileGenerator::kProgramEntryName);
names[2] = v8_str(ProfileGenerator::kIdleEntryName);
CheckChildrenNames(env.local(), root, names);
const v8::CpuProfileNode* programNode =
const v8::CpuProfileNode* program_node =
GetChild(env.local(), root, ProfileGenerator::kProgramEntryName);
CHECK_EQ(0, programNode->GetChildrenCount());
CHECK_GE(programNode->GetHitCount(), 2u);
CHECK_EQ(0, program_node->GetChildrenCount());
CHECK_GE(program_node->GetHitCount(), 2u);
const v8::CpuProfileNode* idleNode =
const v8::CpuProfileNode* idle_node =
GetChild(env.local(), root, ProfileGenerator::kIdleEntryName);
CHECK_EQ(0, idleNode->GetChildrenCount());
CHECK_GE(idleNode->GetHitCount(), 3u);
CHECK_EQ(0, idle_node->GetChildrenCount());
CHECK_GE(idle_node->GetHitCount(), 3u);
profile->Delete();
}
static void CheckFunctionDetails(v8::Isolate* isolate,
const v8::CpuProfileNode* node,
const char* name, const char* script_name,
......@@ -1768,17 +1567,21 @@ static void CheckFunctionDetails(v8::Isolate* isolate,
TEST(FunctionDetails) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
v8::Context::Scope context_scope(env);
v8::Local<v8::Script> script_a = CompileWithOrigin(
" function foo\n() { try { bar(); } catch(e) {} }\n"
"%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(bar);\n"
" function foo\n() { bar(); }\n"
" function bar() { startProfiling(); }\n",
"script_a");
script_a->Run(env).ToLocalChecked();
v8::Local<v8::Script> script_b = CompileWithOrigin(
"\n\n function baz() { try { foo(); } catch(e) {} }\n"
"%NeverOptimizeFunction(baz);"
"\n\n function baz() { foo(); }\n"
"\n\nbaz();\n"
"stopProfiling();\n",
"script_b");
......@@ -1802,10 +1605,10 @@ TEST(FunctionDetails) {
script_b->GetUnboundScript()->GetId(), 3, 16);
const v8::CpuProfileNode* foo = GetChild(env, baz, "foo");
CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a",
script_a->GetUnboundScript()->GetId(), 2, 1);
script_a->GetUnboundScript()->GetId(), 4, 1);
const v8::CpuProfileNode* bar = GetChild(env, foo, "bar");
CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a",
script_a->GetUnboundScript()->GetId(), 3, 14);
script_a->GetUnboundScript()->GetId(), 5, 14);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment