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
This commit is contained in:
mikhail.naganov@gmail.com 2009-08-04 14:14:01 +00:00
parent f2faaa5c34
commit 5470f9b132
5 changed files with 76 additions and 52 deletions

View File

@ -1971,12 +1971,15 @@ typedef Persistent<Context> (*ContextGenerator)();
*
* In V8, profiler consists of several modules: CPU profiler, and different
* 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 {
PROFILER_MODULE_NONE = 0,
PROFILER_MODULE_CPU = 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
};

View File

@ -3214,21 +3214,21 @@ void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
void V8::PauseProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING
i::Logger::PauseProfiler();
i::Logger::PauseProfiler(PROFILER_MODULE_CPU);
#endif
}
void V8::ResumeProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING
i::Logger::ResumeProfiler();
i::Logger::ResumeProfiler(PROFILER_MODULE_CPU);
#endif
}
bool V8::IsProfilerPaused() {
#ifdef ENABLE_LOGGING_AND_PROFILING
return i::Logger::IsProfilerPaused();
return i::Logger::GetActiveProfilerModules() & PROFILER_MODULE_CPU;
#else
return true;
#endif
@ -3237,11 +3237,19 @@ bool V8::IsProfilerPaused() {
void V8::ResumeProfilerEx(int flags) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (flags & PROFILER_MODULE_CPU) {
i::Logger::ResumeProfiler();
}
if (flags & (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
i::FLAG_log_gc = true;
if (flags & PROFILER_MODULE_HEAP_SNAPSHOT) {
// Snapshot mode: resume modules, perform GC, then pause only
// those modules which haven't been started prior to making a
// snapshot.
// 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
}
@ -3249,26 +3257,14 @@ void V8::ResumeProfilerEx(int flags) {
void V8::PauseProfilerEx(int flags) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (flags & PROFILER_MODULE_CPU) {
i::Logger::PauseProfiler();
}
if (flags & (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
i::FLAG_log_gc = false;
}
i::Logger::PauseProfiler(flags);
#endif
}
int V8::GetActiveProfilerModules() {
#ifdef ENABLE_LOGGING_AND_PROFILING
int result = PROFILER_MODULE_NONE;
if (!i::Logger::IsProfilerPaused()) {
result |= PROFILER_MODULE_CPU;
}
if (i::FLAG_log_gc) {
result |= PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS;
}
return result;
return i::Logger::GetActiveProfilerModules();
#else
return PROFILER_MODULE_NONE;
#endif

View File

@ -957,38 +957,63 @@ void Logger::TickEvent(TickSample* sample, bool overflow) {
}
bool Logger::IsProfilerPaused() {
return profiler_->paused();
int Logger::GetActiveProfilerModules() {
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() {
if (profiler_->paused()) {
return;
void Logger::PauseProfiler(int flags) {
if (!Log::IsEnabled()) 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 (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"));
if (modules_to_disable &
(PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
FLAG_log_gc = false;
}
// Turn off logging if no active modules remain.
if (active_modules & ~flags == PROFILER_MODULE_NONE) {
is_logging_ = false;
}
is_logging_ = false;
}
void Logger::ResumeProfiler() {
if (!profiler_->paused() || !Log::IsEnabled()) {
return;
void Logger::ResumeProfiler(int flags) {
if (!Log::IsEnabled()) return;
const int modules_to_enable = ~GetActiveProfilerModules() & flags;
if (modules_to_enable != PROFILER_MODULE_NONE) {
is_logging_ = true;
}
is_logging_ = true;
if (FLAG_prof_lazy) {
LOG(UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true;
LogCompiledFunctions();
if (!FLAG_sliding_state_window) ticker_->Start();
if (modules_to_enable & PROFILER_MODULE_CPU) {
if (FLAG_prof_lazy) {
LOG(UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true;
LogCompiledFunctions();
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() {
// either from main or Profiler's thread.
void Logger::StopLoggingAndProfiling() {
Log::stop();
PauseProfiler();
PauseProfiler(PROFILER_MODULE_CPU);
}

View File

@ -249,11 +249,11 @@ class Logger {
}
// 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.
static bool IsProfilerPaused();
static void PauseProfiler();
static void ResumeProfiler();
static void PauseProfiler(int flags);
static void ResumeProfiler(int flags);
static int GetActiveProfilerModules();
// If logging is performed into a memory buffer, allows to
// retrieve previously written messages. See v8.h.

View File

@ -166,7 +166,7 @@ static void SigProfSignalHandler(int signal, siginfo_t* info, void* context) {
static int CheckThatProfilerWorks(int log_pos) {
Logger::ResumeProfiler();
Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU);
CHECK(LoggerTestHelper::IsSamplerActive());
// Verify that the current map of compiled functions has been logged.
@ -207,7 +207,7 @@ static int CheckThatProfilerWorks(int log_pos) {
i::OS::Sleep(1);
}
Logger::PauseProfiler();
Logger::PauseProfiler(v8::PROFILER_MODULE_CPU);
CHECK(!LoggerTestHelper::IsSamplerActive());
// Wait 50 msecs to allow Profiler thread to process the last