Add an ability to initiate GC through V8 API.

I'm planning to use it in DevTools heap profiler. It is a common scenario in debugging memory leaks to enforce GC, then perform an operation, then enforce GC again to check for non-collected (that is, leaked) objects. Using the existing GC extension isn't possible because it doesn't exposed in the normal operation mode of Chromium.

Review URL: http://codereview.chromium.org/159787

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2619 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f2faaa5c
...@@ -1971,12 +1971,15 @@ typedef Persistent<Context> (*ContextGenerator)(); ...@@ -1971,12 +1971,15 @@ typedef Persistent<Context> (*ContextGenerator)();
* *
* In V8, profiler consists of several modules: CPU profiler, and different * In V8, profiler consists of several modules: CPU profiler, and different
* kinds of heap profiling. Each can be turned on / off independently. * kinds of heap profiling. Each can be turned on / off independently.
* When PROFILER_MODULE_HEAP_SNAPSHOT flag is passed to ResumeProfilerEx,
* modules are enabled only temporarily for making a snapshot of the heap.
*/ */
enum ProfilerModules { enum ProfilerModules {
PROFILER_MODULE_NONE = 0, PROFILER_MODULE_NONE = 0,
PROFILER_MODULE_CPU = 1, PROFILER_MODULE_CPU = 1,
PROFILER_MODULE_HEAP_STATS = 1 << 1, PROFILER_MODULE_HEAP_STATS = 1 << 1,
PROFILER_MODULE_JS_CONSTRUCTORS = 1 << 2 PROFILER_MODULE_JS_CONSTRUCTORS = 1 << 2,
PROFILER_MODULE_HEAP_SNAPSHOT = 1 << 16
}; };
......
...@@ -3214,21 +3214,21 @@ void V8::SetGlobalGCEpilogueCallback(GCCallback callback) { ...@@ -3214,21 +3214,21 @@ void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
void V8::PauseProfiler() { void V8::PauseProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
i::Logger::PauseProfiler(); i::Logger::PauseProfiler(PROFILER_MODULE_CPU);
#endif #endif
} }
void V8::ResumeProfiler() { void V8::ResumeProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
i::Logger::ResumeProfiler(); i::Logger::ResumeProfiler(PROFILER_MODULE_CPU);
#endif #endif
} }
bool V8::IsProfilerPaused() { bool V8::IsProfilerPaused() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
return i::Logger::IsProfilerPaused(); return i::Logger::GetActiveProfilerModules() & PROFILER_MODULE_CPU;
#else #else
return true; return true;
#endif #endif
...@@ -3237,11 +3237,19 @@ bool V8::IsProfilerPaused() { ...@@ -3237,11 +3237,19 @@ bool V8::IsProfilerPaused() {
void V8::ResumeProfilerEx(int flags) { void V8::ResumeProfilerEx(int flags) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (flags & PROFILER_MODULE_CPU) { if (flags & PROFILER_MODULE_HEAP_SNAPSHOT) {
i::Logger::ResumeProfiler(); // Snapshot mode: resume modules, perform GC, then pause only
} // those modules which haven't been started prior to making a
if (flags & (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) { // snapshot.
i::FLAG_log_gc = true;
// Reset snapshot flag and CPU module flags.
flags &= ~(PROFILER_MODULE_HEAP_SNAPSHOT | PROFILER_MODULE_CPU);
const int current_flags = i::Logger::GetActiveProfilerModules();
i::Logger::ResumeProfiler(flags);
i::Heap::CollectAllGarbage();
i::Logger::PauseProfiler(~current_flags & flags);
} else {
i::Logger::ResumeProfiler(flags);
} }
#endif #endif
} }
...@@ -3249,26 +3257,14 @@ void V8::ResumeProfilerEx(int flags) { ...@@ -3249,26 +3257,14 @@ void V8::ResumeProfilerEx(int flags) {
void V8::PauseProfilerEx(int flags) { void V8::PauseProfilerEx(int flags) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (flags & PROFILER_MODULE_CPU) { i::Logger::PauseProfiler(flags);
i::Logger::PauseProfiler();
}
if (flags & (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
i::FLAG_log_gc = false;
}
#endif #endif
} }
int V8::GetActiveProfilerModules() { int V8::GetActiveProfilerModules() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
int result = PROFILER_MODULE_NONE; return i::Logger::GetActiveProfilerModules();
if (!i::Logger::IsProfilerPaused()) {
result |= PROFILER_MODULE_CPU;
}
if (i::FLAG_log_gc) {
result |= PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS;
}
return result;
#else #else
return PROFILER_MODULE_NONE; return PROFILER_MODULE_NONE;
#endif #endif
......
...@@ -957,38 +957,63 @@ void Logger::TickEvent(TickSample* sample, bool overflow) { ...@@ -957,38 +957,63 @@ void Logger::TickEvent(TickSample* sample, bool overflow) {
} }
bool Logger::IsProfilerPaused() { int Logger::GetActiveProfilerModules() {
return profiler_->paused(); int result = PROFILER_MODULE_NONE;
if (!profiler_->paused()) {
result |= PROFILER_MODULE_CPU;
}
if (FLAG_log_gc) {
result |= PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS;
}
return result;
} }
void Logger::PauseProfiler() { void Logger::PauseProfiler(int flags) {
if (profiler_->paused()) { if (!Log::IsEnabled()) return;
return; const int active_modules = GetActiveProfilerModules();
const int modules_to_disable = active_modules & flags;
if (modules_to_disable == PROFILER_MODULE_NONE) return;
if (modules_to_disable & PROFILER_MODULE_CPU) {
profiler_->pause();
if (FLAG_prof_lazy) {
if (!FLAG_sliding_state_window) ticker_->Stop();
FLAG_log_code = false;
// Must be the same message as Log::kDynamicBufferSeal.
LOG(UncheckedStringEvent("profiler", "pause"));
}
} }
profiler_->pause(); if (modules_to_disable &
if (FLAG_prof_lazy) { (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
if (!FLAG_sliding_state_window) ticker_->Stop(); FLAG_log_gc = false;
FLAG_log_code = false; }
// Must be the same message as Log::kDynamicBufferSeal. // Turn off logging if no active modules remain.
LOG(UncheckedStringEvent("profiler", "pause")); if (active_modules & ~flags == PROFILER_MODULE_NONE) {
is_logging_ = false;
} }
is_logging_ = false;
} }
void Logger::ResumeProfiler() { void Logger::ResumeProfiler(int flags) {
if (!profiler_->paused() || !Log::IsEnabled()) { if (!Log::IsEnabled()) return;
return; const int modules_to_enable = ~GetActiveProfilerModules() & flags;
if (modules_to_enable != PROFILER_MODULE_NONE) {
is_logging_ = true;
} }
is_logging_ = true; if (modules_to_enable & PROFILER_MODULE_CPU) {
if (FLAG_prof_lazy) { if (FLAG_prof_lazy) {
LOG(UncheckedStringEvent("profiler", "resume")); LOG(UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true; FLAG_log_code = true;
LogCompiledFunctions(); LogCompiledFunctions();
if (!FLAG_sliding_state_window) ticker_->Start(); if (!FLAG_sliding_state_window) ticker_->Start();
}
profiler_->resume();
}
if (modules_to_enable &
(PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
FLAG_log_gc = true;
} }
profiler_->resume();
} }
...@@ -996,7 +1021,7 @@ void Logger::ResumeProfiler() { ...@@ -996,7 +1021,7 @@ void Logger::ResumeProfiler() {
// either from main or Profiler's thread. // either from main or Profiler's thread.
void Logger::StopLoggingAndProfiling() { void Logger::StopLoggingAndProfiling() {
Log::stop(); Log::stop();
PauseProfiler(); PauseProfiler(PROFILER_MODULE_CPU);
} }
......
...@@ -249,11 +249,11 @@ class Logger { ...@@ -249,11 +249,11 @@ class Logger {
} }
// Pause/Resume collection of profiling data. // Pause/Resume collection of profiling data.
// When data collection is paused, Tick events are discarded until // When data collection is paused, CPU Tick events are discarded until
// data collection is Resumed. // data collection is Resumed.
static bool IsProfilerPaused(); static void PauseProfiler(int flags);
static void PauseProfiler(); static void ResumeProfiler(int flags);
static void ResumeProfiler(); static int GetActiveProfilerModules();
// If logging is performed into a memory buffer, allows to // If logging is performed into a memory buffer, allows to
// retrieve previously written messages. See v8.h. // retrieve previously written messages. See v8.h.
......
...@@ -166,7 +166,7 @@ static void SigProfSignalHandler(int signal, siginfo_t* info, void* context) { ...@@ -166,7 +166,7 @@ static void SigProfSignalHandler(int signal, siginfo_t* info, void* context) {
static int CheckThatProfilerWorks(int log_pos) { static int CheckThatProfilerWorks(int log_pos) {
Logger::ResumeProfiler(); Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU);
CHECK(LoggerTestHelper::IsSamplerActive()); CHECK(LoggerTestHelper::IsSamplerActive());
// Verify that the current map of compiled functions has been logged. // Verify that the current map of compiled functions has been logged.
...@@ -207,7 +207,7 @@ static int CheckThatProfilerWorks(int log_pos) { ...@@ -207,7 +207,7 @@ static int CheckThatProfilerWorks(int log_pos) {
i::OS::Sleep(1); i::OS::Sleep(1);
} }
Logger::PauseProfiler(); Logger::PauseProfiler(v8::PROFILER_MODULE_CPU);
CHECK(!LoggerTestHelper::IsSamplerActive()); CHECK(!LoggerTestHelper::IsSamplerActive());
// Wait 50 msecs to allow Profiler thread to process the last // Wait 50 msecs to allow Profiler thread to process the last
......
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