v8/test/cctest/test-cpu-profiler.cc
yurys@chromium.org dc9b817667 Send SIGPROF signals on the profiler event processor thread
The patch is based on the previous one that was rolled out: https://code.google.com/p/v8/source/detail?r=12985

On Linux sampling for CPU profiler is initiated on the profiler event processor thread, other platforms to follow.

CPU profiler continues to use SamplingCircularQueue, we will replave it with a single sample buffer when Mac and Win ports support profiling on the event processing thread.

When --prof option is specified profiling is initiated either on the profiler event processor thread if CPU profiler is on or on the  SignalSender thread as it used to if no CPU profiles are being collected.

ProfilerEventsProcessor::ProcessEventsAndDoSample now waits in a tight loop, processing collected samples until sampling interval expires. To save CPU resources I'm planning to change that to use nanosleep as only one sample is expected in the queue at any point.

BUG=v8:2364

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13735 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2013-02-26 16:15:32 +00:00

403 lines
14 KiB
C++

// Copyright 2010 the V8 project authors. All rights reserved.
//
// Tests of profiles generator and utilities.
#include "v8.h"
#include "cpu-profiler-inl.h"
#include "cctest.h"
#include "../include/v8-profiler.h"
using i::CodeEntry;
using i::CpuProfile;
using i::CpuProfiler;
using i::CpuProfilesCollection;
using i::ProfileGenerator;
using i::ProfileNode;
using i::ProfilerEventsProcessor;
using i::TokenEnumerator;
TEST(StartStop) {
CpuProfilesCollection profiles;
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator, NULL, 100);
processor.Start();
processor.Stop();
processor.Join();
}
static v8::Persistent<v8::Context> env;
static void InitializeVM() {
if (env.IsEmpty()) env = v8::Context::New();
v8::HandleScope scope;
env->Enter();
}
static inline i::Address ToAddress(int n) {
return reinterpret_cast<i::Address>(n);
}
static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
i::Address frame1,
i::Address frame2 = NULL,
i::Address frame3 = NULL) {
i::TickSample* sample = proc->TickSampleEvent();
sample->pc = frame1;
sample->tos = frame1;
sample->frames_count = 0;
if (frame2 != NULL) {
sample->stack[0] = frame2;
sample->frames_count = 1;
}
if (frame3 != NULL) {
sample->stack[1] = frame3;
sample->frames_count = 2;
}
}
namespace {
class TestSetup {
public:
TestSetup()
: old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
i::FLAG_prof_browser_mode = false;
}
~TestSetup() {
i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
}
private:
bool old_flag_prof_browser_mode_;
};
} // namespace
TEST(CodeEvents) {
InitializeVM();
i::Isolate* isolate = i::Isolate::Current();
i::Heap* heap = isolate->heap();
i::Factory* factory = isolate->factory();
TestSetup test_setup;
CpuProfilesCollection profiles;
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator, NULL, 100);
processor.Start();
// 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));
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);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
processor.Stop();
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)));
}
template<typename T>
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);
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator, NULL, 100);
processor.Start();
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();
processor.Join();
CpuProfile* profile =
profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
// Check call trees.
const i::List<ProfileNode*>* top_down_root_children =
profile->top_down()->root()->children();
CHECK_EQ(1, top_down_root_children->length());
CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
const i::List<ProfileNode*>* top_down_bbb_children =
top_down_root_children->last()->children();
CHECK_EQ(1, top_down_bbb_children->length());
CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
const i::List<ProfileNode*>* top_down_stub_children =
top_down_bbb_children->last()->children();
CHECK_EQ(1, top_down_stub_children->length());
CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
const i::List<ProfileNode*>* top_down_ddd_children =
top_down_stub_children->last()->children();
CHECK_EQ(0, top_down_ddd_children->length());
const i::List<ProfileNode*>* bottom_up_root_children_unsorted =
profile->bottom_up()->root()->children();
CHECK_EQ(3, bottom_up_root_children_unsorted->length());
i::List<ProfileNode*> bottom_up_root_children(3);
bottom_up_root_children.AddAll(*bottom_up_root_children_unsorted);
bottom_up_root_children.Sort(&CompareProfileNodes);
CHECK_EQ("5", bottom_up_root_children[0]->entry()->name());
CHECK_EQ("bbb", bottom_up_root_children[1]->entry()->name());
CHECK_EQ("ddd", bottom_up_root_children[2]->entry()->name());
const i::List<ProfileNode*>* bottom_up_stub_children =
bottom_up_root_children[0]->children();
CHECK_EQ(1, bottom_up_stub_children->length());
CHECK_EQ("bbb", bottom_up_stub_children->last()->entry()->name());
const i::List<ProfileNode*>* bottom_up_bbb_children =
bottom_up_root_children[1]->children();
CHECK_EQ(0, bottom_up_bbb_children->length());
const i::List<ProfileNode*>* bottom_up_ddd_children =
bottom_up_root_children[2]->children();
CHECK_EQ(1, bottom_up_ddd_children->length());
CHECK_EQ("5", bottom_up_ddd_children->last()->entry()->name());
const i::List<ProfileNode*>* bottom_up_ddd_stub_children =
bottom_up_ddd_children->last()->children();
CHECK_EQ(1, bottom_up_ddd_stub_children->length());
CHECK_EQ("bbb", bottom_up_ddd_stub_children->last()->entry()->name());
}
// http://crbug/51594
// This test must not crash.
TEST(CrashIfStoppingLastNonExistentProfile) {
InitializeVM();
TestSetup test_setup;
CpuProfiler::SetUp();
CpuProfiler::StartProfiling("1");
CpuProfiler::StopProfiling("2");
CpuProfiler::StartProfiling("1");
CpuProfiler::StopProfiling("");
CpuProfiler::TearDown();
}
// http://code.google.com/p/v8/issues/detail?id=1398
// Long stacks (exceeding max frames limit) must not be erased.
TEST(Issue1398) {
TestSetup test_setup;
CpuProfilesCollection profiles;
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator, NULL, 100);
processor.Start();
processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
"bbb",
ToAddress(0x1200),
0x80);
i::TickSample* sample = processor.TickSampleEvent();
sample->pc = ToAddress(0x1200);
sample->tos = 0;
sample->frames_count = i::TickSample::kMaxFramesCount;
for (int i = 0; i < sample->frames_count; ++i) {
sample->stack[i] = ToAddress(0x1200);
}
processor.Stop();
processor.Join();
CpuProfile* profile =
profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
int actual_depth = 0;
const ProfileNode* node = profile->top_down()->root();
while (node->children()->length() > 0) {
node = node->children()->last();
++actual_depth;
}
CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
}
TEST(DeleteAllCpuProfiles) {
InitializeVM();
TestSetup test_setup;
CpuProfiler::SetUp();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CpuProfiler::DeleteAllProfiles();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CpuProfiler::StartProfiling("1");
CpuProfiler::StopProfiling("1");
CHECK_EQ(1, CpuProfiler::GetProfilesCount());
CpuProfiler::DeleteAllProfiles();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CpuProfiler::StartProfiling("1");
CpuProfiler::StartProfiling("2");
CpuProfiler::StopProfiling("2");
CpuProfiler::StopProfiling("1");
CHECK_EQ(2, CpuProfiler::GetProfilesCount());
CpuProfiler::DeleteAllProfiles();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
// Test profiling cancellation by the 'delete' command.
CpuProfiler::StartProfiling("1");
CpuProfiler::StartProfiling("2");
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CpuProfiler::DeleteAllProfiles();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CpuProfiler::TearDown();
}
TEST(DeleteCpuProfile) {
v8::HandleScope scope;
LocalContext env;
CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
v8::Local<v8::String> name1 = v8::String::New("1");
v8::CpuProfiler::StartProfiling(name1);
const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
CHECK_NE(NULL, p1);
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
unsigned uid1 = p1->GetUid();
CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
const_cast<v8::CpuProfile*>(p1)->Delete();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
v8::Local<v8::String> name2 = v8::String::New("2");
v8::CpuProfiler::StartProfiling(name2);
const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2);
CHECK_NE(NULL, p2);
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
unsigned uid2 = p2->GetUid();
CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2));
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
v8::Local<v8::String> name3 = v8::String::New("3");
v8::CpuProfiler::StartProfiling(name3);
const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
CHECK_NE(NULL, p3);
CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
unsigned uid3 = p3->GetUid();
CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
const_cast<v8::CpuProfile*>(p2)->Delete();
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
const_cast<v8::CpuProfile*>(p3)->Delete();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
}
TEST(DeleteCpuProfileDifferentTokens) {
v8::HandleScope scope;
LocalContext env;
CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
v8::Local<v8::String> name1 = v8::String::New("1");
v8::CpuProfiler::StartProfiling(name1);
const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
CHECK_NE(NULL, p1);
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
unsigned uid1 = p1->GetUid();
CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
v8::Local<v8::String> token1 = v8::String::New("token1");
const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1);
CHECK_NE(NULL, p1_t1);
CHECK_NE(p1, p1_t1);
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
const_cast<v8::CpuProfile*>(p1)->Delete();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1));
const_cast<v8::CpuProfile*>(p1_t1)->Delete();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
v8::Local<v8::String> name2 = v8::String::New("2");
v8::CpuProfiler::StartProfiling(name2);
v8::Local<v8::String> token2 = v8::String::New("token2");
const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2);
CHECK_NE(NULL, p2_t2);
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
unsigned uid2 = p2_t2->GetUid();
CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2);
CHECK_NE(p2_t2, p2);
v8::Local<v8::String> name3 = v8::String::New("3");
v8::CpuProfiler::StartProfiling(name3);
const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
CHECK_NE(NULL, p3);
CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
unsigned uid3 = p3->GetUid();
CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
const_cast<v8::CpuProfile*>(p2_t2)->Delete();
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
const_cast<v8::CpuProfile*>(p2)->Delete();
CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
const_cast<v8::CpuProfile*>(p3)->Delete();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
}