Author: [email protected]
Date: Tue May 5 08:57:47 2009
New Revision: 1870
Added:
branches/bleeding_edge/test/cctest/test-log.cc
Modified:
branches/bleeding_edge/include/v8.h
branches/bleeding_edge/src/api.cc
branches/bleeding_edge/src/log.cc
branches/bleeding_edge/src/log.h
branches/bleeding_edge/test/cctest/SConscript
branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj
branches/bleeding_edge/tools/visual_studio/v8_cctest_arm.vcproj
Log:
Introduce internal Log class that handles writing log messages, enable
logging to memory buffer.
This will enable reading profiler log in Chrome. The current implementation
of memory buffer is trivial (fixed size buffer, no memory recycling) but
enough to start end-to-end DevTools Profiler implementation. Later it will
be enhanced.
Review URL: http://codereview.chromium.org/108011
Modified: branches/bleeding_edge/include/v8.h
==============================================================================
--- branches/bleeding_edge/include/v8.h (original)
+++ branches/bleeding_edge/include/v8.h Tue May 5 08:57:47 2009
@@ -1126,9 +1126,9 @@
/**
* Returns the identity hash for this object. The current implemenation
uses
- * a hidden property on the object to store the identity hash.
+ * a hidden property on the object to store the identity hash.
*
- * The return value will never be 0. Also, it is not guaranteed to be
+ * The return value will never be 0. Also, it is not guaranteed to be
* unique.
*/
int GetIdentityHash();
@@ -2078,6 +2078,24 @@
* See also PauseProfiler().
*/
static void ResumeProfiler();
+
+ /**
+ * If logging is performed into a memory buffer (via --logfile=*),
allows to
+ * retrieve previously written messages. This can be used for retrieving
+ * profiler log data in the application. This function is thread-safe.
+ *
+ * Caller provides a destination buffer that must exist during
GetLogLines
+ * call. Only whole log lines are copied into the buffer.
+ *
+ * \param from_pos specified a point in a buffer to read from, 0 is the
+ * beginning of a buffer. It is assumed that caller updates its current
+ * position using returned size value from the previous call.
+ * \param dest_buf destination buffer for log data.
+ * \param max_size size of the destination buffer.
+ * \returns actual size of log data copied into buffer.
+ */
+ static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+
/**
* Releases any resources used by v8 and stops any utility threads
Modified: branches/bleeding_edge/src/api.cc
==============================================================================
--- branches/bleeding_edge/src/api.cc (original)
+++ branches/bleeding_edge/src/api.cc Tue May 5 08:57:47 2009
@@ -3112,6 +3112,11 @@
#endif
}
+int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ return i::Logger::GetLogLines(from_pos, dest_buf, max_size);
+#endif
+}
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
Modified: branches/bleeding_edge/src/log.cc
==============================================================================
--- branches/bleeding_edge/src/log.cc (original)
+++ branches/bleeding_edge/src/log.cc Tue May 5 08:57:47 2009
@@ -285,8 +285,178 @@
#ifdef ENABLE_LOGGING_AND_PROFILING
+
+// Functions and data for performing output of log messages.
+class Log : public AllStatic {
+ public:
+ // Opens stdout for logging.
+ static void OpenStdout();
+
+ // Opens file for logging.
+ static void OpenFile(const char* name);
+
+ // Opens memory buffer for logging.
+ static void OpenMemoryBuffer();
+
+ // Frees all resources acquired in Open... functions.
+ static void Close();
+
+ // See description in v8.h.
+ static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+
+ static bool is_enabled() { return output_.handle != NULL; }
+
+ typedef int (*WritePtr)(const char* msg, int length);
+ private:
+ static void Init();
+
+ // Write functions assume that mutex_ is acquired by the caller.
+ static WritePtr Write;
+
+ static int WriteToFile(const char* msg, int length) {
+ ASSERT(output_.handle != NULL);
+ int rv = fwrite(msg, 1, length, output_.handle);
+ ASSERT(length == rv);
+ return rv;
+ }
+
+ static int WriteToMemory(const char* msg, int length) {
+ ASSERT(output_.buffer != NULL);
+ ASSERT(output_buffer_write_pos_ >= output_.buffer);
+ if (output_buffer_write_pos_ + length
+ <= output_.buffer + kOutputBufferSize) {
+ memcpy(output_buffer_write_pos_, msg, length);
+ output_buffer_write_pos_ += length;
+ return length;
+ } else {
+ // Memory buffer is full, ignore write.
+ return 0;
+ }
+ }
+
+ // When logging is active, output_ refers the file or memory buffer
+ // events are written to.
+ // mutex_ should be acquired before using output_.
+ union Output {
+ FILE* handle;
+ char* buffer;
+ };
+ static Output output_;
+
+ // mutex_ is a Mutex used for enforcing exclusive
+ // access to the formatting buffer and the log file or log memory buffer.
+ static Mutex* mutex_;
+
+ // Size of buffer used for memory logging.
+ static const int kOutputBufferSize = 2 * 1024 * 1024;
+
+ // Writing position in a memory buffer.
+ static char* output_buffer_write_pos_;
+
+ // Size of buffer used for formatting log messages.
+ static const int kMessageBufferSize = 2048;
+
+ // Buffer used for formatting log messages. This is a singleton buffer
and
+ // mutex_ should be acquired before using it.
+ static char* message_buffer_;
+
+ friend class LogMessageBuilder;
+};
+
+
+Log::WritePtr Log::Write = NULL;
+Log::Output Log::output_ = {NULL};
+Mutex* Log::mutex_ = NULL;
+char* Log::output_buffer_write_pos_ = NULL;
+char* Log::message_buffer_ = NULL;
+
+
+void Log::Init() {
+ mutex_ = OS::CreateMutex();
+ message_buffer_ = NewArray<char>(kMessageBufferSize);
+}
+
+
+void Log::OpenStdout() {
+ ASSERT(output_.handle == NULL);
+ output_.handle = stdout;
+ Write = WriteToFile;
+ Init();
+}
+
+
+void Log::OpenFile(const char* name) {
+ ASSERT(output_.handle == NULL);
+ output_.handle = OS::FOpen(name, OS::LogFileOpenMode);
+ Write = WriteToFile;
+ Init();
+}
+
+
+void Log::OpenMemoryBuffer() {
+ ASSERT(output_.buffer == NULL);
+ output_.buffer = NewArray<char>(kOutputBufferSize);
+ output_buffer_write_pos_ = output_.buffer;
+ Write = WriteToMemory;
+ Init();
+}
+
+
+void Log::Close() {
+ if (Write == WriteToFile) {
+ fclose(output_.handle);
+ output_.handle = NULL;
+ } else if (Write == WriteToMemory) {
+ DeleteArray(output_.buffer);
+ output_.buffer = NULL;
+ } else {
+ ASSERT(Write == NULL);
+ }
+ Write = NULL;
+
+ delete mutex_;
+ mutex_ = NULL;
+
+ DeleteArray(message_buffer_);
+ message_buffer_ = NULL;
+}
+
+
+int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) {
+ ASSERT(output_.buffer != NULL);
+ ASSERT(output_buffer_write_pos_ >= output_.buffer);
+ ASSERT(from_pos >= 0);
+ ASSERT(max_size >= 0);
+ int actual_size = max_size;
+ char* buffer_read_pos = output_.buffer + from_pos;
+ ScopedLock sl(mutex_);
+ if (actual_size == 0
+ || output_buffer_write_pos_ == output_.buffer
+ || buffer_read_pos >= output_buffer_write_pos_) {
+ // No data requested or can be returned.
+ return 0;
+ }
+ if (buffer_read_pos + actual_size > output_buffer_write_pos_) {
+ // Requested size overlaps with current writing position and
+ // needs to be truncated.
+ actual_size = output_buffer_write_pos_ - buffer_read_pos;
+ ASSERT(actual_size == 0 || buffer_read_pos[actual_size - 1] == '\n');
+ } else {
+ // Find previous log line boundary.
+ char* end_pos = buffer_read_pos + actual_size - 1;
+ while (end_pos >= buffer_read_pos && *end_pos != '\n') --end_pos;
+ actual_size = end_pos - buffer_read_pos + 1;
+ }
+ ASSERT(actual_size <= max_size);
+ if (actual_size > 0) {
+ memcpy(dest_buf, buffer_read_pos, actual_size);
+ }
+ return actual_size;
+}
+
+
// Utility class for formatting log messages. It fills the message into the
-// static buffer in Logger.
+// static buffer in Log.
class LogMessageBuilder BASE_EMBEDDED {
public:
explicit LogMessageBuilder();
@@ -309,45 +479,45 @@
// Create a message builder starting from position 0. This acquires the
mutex
// in the logger as well.
-LogMessageBuilder::LogMessageBuilder(): sl(Logger::mutex_), pos_(0) {
- ASSERT(Logger::message_buffer_ != NULL);
+LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) {
+ ASSERT(Log::message_buffer_ != NULL);
}
// Append string data to the log message.
void LogMessageBuilder::Append(const char* format, ...) {
- Vector<char> buf(Logger::message_buffer_ + pos_,
- Logger::kMessageBufferSize - pos_);
+ Vector<char> buf(Log::message_buffer_ + pos_,
+ Log::kMessageBufferSize - pos_);
va_list args;
va_start(args, format);
Append(format, args);
va_end(args);
- ASSERT(pos_ <= Logger::kMessageBufferSize);
+ ASSERT(pos_ <= Log::kMessageBufferSize);
}
// Append string data to the log message.
void LogMessageBuilder::Append(const char* format, va_list args) {
- Vector<char> buf(Logger::message_buffer_ + pos_,
- Logger::kMessageBufferSize - pos_);
+ Vector<char> buf(Log::message_buffer_ + pos_,
+ Log::kMessageBufferSize - pos_);
int result = v8::internal::OS::VSNPrintF(buf, format, args);
// Result is -1 if output was truncated.
if (result >= 0) {
pos_ += result;
} else {
- pos_ = Logger::kMessageBufferSize;
+ pos_ = Log::kMessageBufferSize;
}
- ASSERT(pos_ <= Logger::kMessageBufferSize);
+ ASSERT(pos_ <= Log::kMessageBufferSize);
}
// Append a character to the log message.
void LogMessageBuilder::Append(const char c) {
- if (pos_ < Logger::kMessageBufferSize) {
- Logger::message_buffer_[pos_++] = c;
+ if (pos_ < Log::kMessageBufferSize) {
+ Log::message_buffer_[pos_++] = c;
}
- ASSERT(pos_ <= Logger::kMessageBufferSize);
+ ASSERT(pos_ <= Log::kMessageBufferSize);
}
@@ -391,18 +561,14 @@
// Write the log message to the log file currently opened.
void LogMessageBuilder::WriteToLogFile() {
- ASSERT(pos_ <= Logger::kMessageBufferSize);
- size_t rv = fwrite(Logger::message_buffer_, 1, pos_, Logger::logfile_);
- ASSERT(rv == static_cast<size_t>(pos_));
- USE(rv);
+ ASSERT(pos_ <= Log::kMessageBufferSize);
+ Log::Write(Log::message_buffer_, pos_);
}
// Write a null-terminated string to to the log file currently opened.
void LogMessageBuilder::WriteCStringToLogFile(const char* str) {
- size_t len = strlen(str);
- size_t rv = fwrite(str, 1, len, Logger::logfile_);
- ASSERT(rv == len);
- USE(rv);
+ int len = strlen(str);
+ Log::Write(str, len);
}
#endif
@@ -411,20 +577,22 @@
// Logger class implementation.
//
Ticker* Logger::ticker_ = NULL;
-char* Logger::message_buffer_ = NULL;
-FILE* Logger::logfile_ = NULL;
Profiler* Logger::profiler_ = NULL;
-Mutex* Logger::mutex_ = NULL;
VMState* Logger::current_state_ = NULL;
VMState Logger::bottom_state_(EXTERNAL);
SlidingStateWindow* Logger::sliding_state_window_ = NULL;
+
+bool Logger::is_enabled() {
+ return Log::is_enabled();
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
void Logger::Preamble(const char* content) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.WriteCStringToLogFile(content);
#endif
@@ -440,7 +608,7 @@
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::UncheckedStringEvent(const char* name, const char* value) {
- if (logfile_ == NULL) return;
+ if (!Log::is_enabled()) return;
LogMessageBuilder msg;
msg.Append("%s,\"%s\"\n", name, value);
msg.WriteToLogFile();
@@ -450,7 +618,7 @@
void Logger::IntEvent(const char* name, int value) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log) return;
+ if (!Log::is_enabled() || !FLAG_log) return;
LogMessageBuilder msg;
msg.Append("%s,%d\n", name, value);
msg.WriteToLogFile();
@@ -460,7 +628,7 @@
void Logger::HandleEvent(const char* name, Object** location) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_handles) return;
+ if (!Log::is_enabled() || !FLAG_log_handles) return;
LogMessageBuilder msg;
msg.Append("%s,0x%x\n", name,
reinterpret_cast<unsigned int>(location));
@@ -471,10 +639,10 @@
#ifdef ENABLE_LOGGING_AND_PROFILING
// ApiEvent is private so all the calls come from the Logger class. It is
the
-// caller's responsibility to ensure that logfile_ is not NULL and that
+// caller's responsibility to ensure that log is enabled and that
// FLAG_log_api is true.
void Logger::ApiEvent(const char* format, ...) {
- ASSERT(logfile_ != NULL && FLAG_log_api);
+ ASSERT(Log::is_enabled() && FLAG_log_api);
LogMessageBuilder msg;
va_list ap;
va_start(ap, format);
@@ -487,7 +655,7 @@
void Logger::ApiNamedSecurityCheck(Object* key) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_api) return;
+ if (!Log::is_enabled() || !FLAG_log_api) return;
if (key->IsString()) {
SmartPointer<char> str =
String::cast(key)->ToCString(DISALLOW_NULLS,
ROBUST_STRING_TRAVERSAL);
@@ -505,7 +673,7 @@
unsigned start,
unsigned end) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_prof) return;
+ if (!Log::is_enabled() || !FLAG_prof) return;
LogMessageBuilder msg;
msg.Append("shared-library,\"%s\",0x%08x,0x%08x\n", library_path,
start, end);
@@ -518,7 +686,7 @@
unsigned start,
unsigned end) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_prof) return;
+ if (!Log::is_enabled() || !FLAG_prof) return;
LogMessageBuilder msg;
msg.Append("shared-library,\"%ls\",0x%08x,0x%08x\n", library_path,
start, end);
@@ -573,7 +741,7 @@
void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_regexp) return;
+ if (!Log::is_enabled() || !FLAG_log_regexp) return;
LogMessageBuilder msg;
msg.Append("regexp-compile,");
LogRegExpSource(regexp);
@@ -585,7 +753,7 @@
void Logger::LogRuntime(Vector<const char> format, JSArray* args) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_runtime) return;
+ if (!Log::is_enabled() || !FLAG_log_runtime) return;
HandleScope scope;
LogMessageBuilder msg;
for (int i = 0; i < format.length(); i++) {
@@ -626,7 +794,7 @@
void Logger::ApiIndexedSecurityCheck(uint32_t index) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_api) return;
+ if (!Log::is_enabled() || !FLAG_log_api) return;
ApiEvent("api,check-security,%u\n", index);
#endif
}
@@ -637,7 +805,7 @@
Object* name) {
#ifdef ENABLE_LOGGING_AND_PROFILING
ASSERT(name->IsString());
- if (logfile_ == NULL || !FLAG_log_api) return;
+ if (!Log::is_enabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
SmartPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -651,7 +819,7 @@
JSObject* holder,
uint32_t index) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_api) return;
+ if (!Log::is_enabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
SmartPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -661,7 +829,7 @@
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_api) return;
+ if (!Log::is_enabled() || !FLAG_log_api) return;
String* class_name_obj = object->class_name();
SmartPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -672,7 +840,7 @@
void Logger::ApiEntryCall(const char* name) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_api) return;
+ if (!Log::is_enabled() || !FLAG_log_api) return;
Logger::ApiEvent("api,%s\n", name);
#endif
}
@@ -680,7 +848,7 @@
void Logger::NewEvent(const char* name, void* object, size_t size) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log) return;
+ if (!Log::is_enabled() || !FLAG_log) return;
LogMessageBuilder msg;
msg.Append("new,%s,0x%x,%u\n", name,
reinterpret_cast<unsigned int>(object),
@@ -692,7 +860,7 @@
void Logger::DeleteEvent(const char* name, void* object) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log) return;
+ if (!Log::is_enabled() || !FLAG_log) return;
LogMessageBuilder msg;
msg.Append("delete,%s,0x%x\n", name,
reinterpret_cast<unsigned int>(object));
@@ -703,7 +871,7 @@
void Logger::CodeCreateEvent(const char* tag, Code* code, const char*
comment) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("code-creation,%s,0x%x,%d,\"", tag,
reinterpret_cast<unsigned int>(code->address()),
@@ -723,7 +891,7 @@
void Logger::CodeCreateEvent(const char* tag, Code* code, String* name) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -738,7 +906,7 @@
void Logger::CodeCreateEvent(const char* tag, Code* code, String* name,
String* source, int line) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -755,7 +923,7 @@
void Logger::CodeCreateEvent(const char* tag, Code* code, int args_count) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("code-creation,%s,0x%x,%d,\"args_count: %d\"\n", tag,
reinterpret_cast<unsigned int>(code->address()),
@@ -768,7 +936,7 @@
void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("code-creation,%s,0x%x,%d,\"", "RegExp",
reinterpret_cast<unsigned int>(code->address()),
@@ -782,7 +950,7 @@
void Logger::CodeAllocateEvent(Code* code, Assembler* assem) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("code-allocate,0x%x,0x%x\n",
reinterpret_cast<unsigned int>(code->address()),
@@ -794,7 +962,7 @@
void Logger::CodeMoveEvent(Address from, Address to) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("code-move,0x%x,0x%x\n",
reinterpret_cast<unsigned int>(from),
@@ -806,7 +974,7 @@
void Logger::CodeDeleteEvent(Address from) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
+ if (!Log::is_enabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("code-delete,0x%x\n", reinterpret_cast<unsigned int>(from));
msg.WriteToLogFile();
@@ -816,7 +984,7 @@
void Logger::ResourceEvent(const char* name, const char* tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log) return;
+ if (!Log::is_enabled() || !FLAG_log) return;
LogMessageBuilder msg;
msg.Append("%s,%s,", name, tag);
@@ -834,12 +1002,11 @@
void Logger::SuspectReadEvent(String* name, Object* obj) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_suspect) return;
+ if (!Log::is_enabled() || !FLAG_log_suspect) return;
LogMessageBuilder msg;
String* class_name = obj->IsJSObject()
? JSObject::cast(obj)->class_name()
: Heap::empty_string();
- ScopedLock sl(mutex_);
msg.Append("suspect-read,");
msg.Append(class_name);
msg.Append(',');
@@ -854,7 +1021,7 @@
void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_gc) return;
+ if (!Log::is_enabled() || !FLAG_log_gc) return;
LogMessageBuilder msg;
msg.Append("heap-sample-begin,\"%s\",\"%s\"\n", space, kind);
msg.WriteToLogFile();
@@ -864,7 +1031,7 @@
void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_gc) return;
+ if (!Log::is_enabled() || !FLAG_log_gc) return;
LogMessageBuilder msg;
msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
msg.WriteToLogFile();
@@ -874,7 +1041,7 @@
void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_gc) return;
+ if (!Log::is_enabled() || !FLAG_log_gc) return;
LogMessageBuilder msg;
msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
msg.WriteToLogFile();
@@ -884,7 +1051,7 @@
void Logger::DebugTag(const char* call_site_tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log) return;
+ if (!Log::is_enabled() || !FLAG_log) return;
LogMessageBuilder msg;
msg.Append("debug-tag,%s\n", call_site_tag);
msg.WriteToLogFile();
@@ -894,7 +1061,7 @@
void Logger::DebugEvent(const char* event_type, Vector<uint16_t>
parameter) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log) return;
+ if (!Log::is_enabled() || !FLAG_log) return;
StringBuilder s(parameter.length() + 1);
for (int i = 0; i < parameter.length(); ++i) {
s.AddCharacter(static_cast<char>(parameter[i]));
@@ -913,7 +1080,7 @@
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::TickEvent(TickSample* sample, bool overflow) {
- if (logfile_ == NULL || !FLAG_prof) return;
+ if (!Log::is_enabled() || !FLAG_prof) return;
LogMessageBuilder msg;
msg.Append("tick,0x%x,0x%x,%d", sample->pc, sample->sp,
static_cast<int>(sample->state));
@@ -941,6 +1108,12 @@
void Logger::ResumeProfiler() {
profiler_->resume();
}
+
+
+int Logger::GetLogLines(int from_pos, char* dest_buf, int max_size) {
+ return Log::GetLogLines(from_pos, dest_buf, max_size);
+}
+
#endif
@@ -967,7 +1140,9 @@
// If we're logging anything, we need to open the log file.
if (open_log_file) {
if (strcmp(FLAG_logfile, "-") == 0) {
- logfile_ = stdout;
+ Log::OpenStdout();
+ } else if (strcmp(FLAG_logfile, "*") == 0) {
+ Log::OpenMemoryBuffer();
} else if (strchr(FLAG_logfile, '%') != NULL) {
// If there's a '%' in the log file name we have to expand
// placeholders.
@@ -1003,12 +1178,10 @@
}
}
SmartPointer<const char> expanded = stream.ToCString();
- logfile_ = OS::FOpen(*expanded, OS::LogFileOpenMode);
+ Log::OpenFile(*expanded);
} else {
- logfile_ = OS::FOpen(FLAG_logfile, OS::LogFileOpenMode);
+ Log::OpenFile(FLAG_logfile);
}
- message_buffer_ = NewArray<char>(kMessageBufferSize);
- mutex_ = OS::CreateMutex();
}
current_state_ = &bottom_state_;
@@ -1050,13 +1223,7 @@
delete ticker_;
- if (logfile_ != NULL) {
- fclose(logfile_);
- logfile_ = NULL;
- delete mutex_;
- mutex_ = NULL;
- DeleteArray(message_buffer_);
- }
+ Log::Close();
#endif
}
Modified: branches/bleeding_edge/src/log.h
==============================================================================
--- branches/bleeding_edge/src/log.h (original)
+++ branches/bleeding_edge/src/log.h Tue May 5 08:57:47 2009
@@ -103,10 +103,10 @@
class Logger {
public:
- // Opens the file for logging if the right flags are set.
+ // Acquires resources for logging if the right flags are set.
static bool Setup();
- // Closes file opened in Setup.
+ // Frees resources acquired in Setup.
static void TearDown();
// Enable the computation of a sliding window of states.
@@ -201,7 +201,7 @@
return current_state_ ? current_state_->state() : OTHER;
}
- static bool is_enabled() { return logfile_ != NULL; }
+ static bool is_enabled();
// Pause/Resume collection of profiling data.
// When data collection is paused, Tick events are discarded until
@@ -210,6 +210,10 @@
static void PauseProfiler();
static void ResumeProfiler();
+ // If logging is performed into a memory buffer, allows to
+ // retrieve previously written messages. See v8.h.
+ static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+
private:
// Emits the source code of a regexp. Used by regexp events.
@@ -223,17 +227,6 @@
// Logs a StringEvent regardless of whether FLAG_log is true.
static void UncheckedStringEvent(const char* name, const char* value);
- // Size of buffer used for formatting log messages.
- static const int kMessageBufferSize = 2048;
-
- // Buffer used for formatting log messages. This is a singleton buffer
and
- // mutex_ should be acquired before using it.
- static char* message_buffer_;
-
- // When logging is active, logfile_ refers the file events are written
to.
- // mutex_ should be acquired before using logfile_.
- static FILE* logfile_;
-
// The sampler used by the profiler and the sliding state window.
static Ticker* ticker_;
@@ -242,10 +235,6 @@
// of samples.
static Profiler* profiler_;
- // mutex_ is a Mutex used for enforcing exclusive
- // access to the formatting buffer and the log file.
- static Mutex* mutex_;
-
// A stack of VM states.
static VMState* current_state_;
@@ -258,7 +247,6 @@
// Internal implementation classes with access to
// private members.
- friend class LogMessageBuilder;
friend class EventLog;
friend class TimeLog;
friend class Profiler;
Modified: branches/bleeding_edge/test/cctest/SConscript
==============================================================================
--- branches/bleeding_edge/test/cctest/SConscript (original)
+++ branches/bleeding_edge/test/cctest/SConscript Tue May 5 08:57:47 2009
@@ -47,6 +47,7 @@
'test-heap.cc',
'test-list.cc',
'test-lock.cc',
+ 'test-log.cc',
'test-mark-compact.cc',
'test-regexp.cc',
'test-serialize.cc',
Added: branches/bleeding_edge/test/cctest/test-log.cc
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/cctest/test-log.cc Tue May 5 08:57:47 2009
@@ -0,0 +1,102 @@
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+//
+// Tests of logging functions from log.h
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+#include "v8.h"
+
+#include "log.h"
+
+#include "cctest.h"
+
+using v8::internal::Logger;
+
+static void SetUp() {
+ // Log to memory buffer.
+ v8::internal::FLAG_logfile = "*";
+ v8::internal::FLAG_log = true;
+ Logger::Setup();
+}
+
+static void TearDown() {
+ Logger::TearDown();
+}
+
+TEST(EmptyLog) {
+ SetUp();
+ CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0));
+ CHECK_EQ(0, Logger::GetLogLines(100, NULL, 0));
+ CHECK_EQ(0, Logger::GetLogLines(0, NULL, 100));
+ CHECK_EQ(0, Logger::GetLogLines(100, NULL, 100));
+ TearDown();
+}
+
+
+TEST(GetMessages) {
+ SetUp();
+ Logger::StringEvent("aaa", "bbb");
+ Logger::StringEvent("cccc", "dddd");
+ CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0));
+ char log_lines[100];
+ memset(log_lines, 0, sizeof(log_lines));
+ // Requesting data size which is smaller than first log message length.
+ CHECK_EQ(0, Logger::GetLogLines(0, log_lines, 3));
+ // See Logger::StringEvent.
+ const char* line_1 = "aaa,\"bbb\"\n";
+ const int line_1_len = strlen(line_1);
+ // Still smaller than log message length.
+ CHECK_EQ(0, Logger::GetLogLines(0, log_lines, line_1_len - 1));
+ // The exact size.
+ CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len));
+ CHECK_EQ(line_1, log_lines);
+ memset(log_lines, 0, sizeof(log_lines));
+ // A bit more than the first line length.
+ CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len + 3));
+ CHECK_EQ(line_1, log_lines);
+ memset(log_lines, 0, sizeof(log_lines));
+ const char* line_2 = "cccc,\"dddd\"\n";
+ const int line_2_len = strlen(line_2);
+ // Now start with line_2 beginning.
+ CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, 0));
+ CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, 3));
+ CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, line_2_len - 1));
+ CHECK_EQ(line_2_len, Logger::GetLogLines(line_1_len, log_lines,
line_2_len));
+ CHECK_EQ(line_2, log_lines);
+ memset(log_lines, 0, sizeof(log_lines));
+ CHECK_EQ(line_2_len,
+ Logger::GetLogLines(line_1_len, log_lines, line_2_len + 3));
+ CHECK_EQ(line_2, log_lines);
+ memset(log_lines, 0, sizeof(log_lines));
+ // Now get entire buffer contents.
+ const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n";
+ const int all_lines_len = strlen(all_lines);
+ CHECK_EQ(all_lines_len, Logger::GetLogLines(0, log_lines,
all_lines_len));
+ CHECK_EQ(all_lines, log_lines);
+ memset(log_lines, 0, sizeof(log_lines));
+ CHECK_EQ(all_lines_len, Logger::GetLogLines(0, log_lines, all_lines_len
+ 3));
+ CHECK_EQ(all_lines, log_lines);
+ memset(log_lines, 0, sizeof(log_lines));
+ TearDown();
+}
+
+
+TEST(BeyondWritePosition) {
+ SetUp();
+ Logger::StringEvent("aaa", "bbb");
+ Logger::StringEvent("cccc", "dddd");
+ // See Logger::StringEvent.
+ const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n";
+ const int all_lines_len = strlen(all_lines);
+ CHECK_EQ(0, Logger::GetLogLines(all_lines_len, NULL, 1));
+ CHECK_EQ(0, Logger::GetLogLines(all_lines_len, NULL, 100));
+ CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 1, NULL, 1));
+ CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 1, NULL, 100));
+ CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 100, NULL, 1));
+ CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 100, NULL, 100));
+ CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, NULL, 1));
+ CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, NULL, 100));
+ TearDown();
+}
+
+#endif // ENABLE_LOGGING_AND_PROFILING
Modified: branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj
==============================================================================
--- branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj (original)
+++ branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj Tue May 5
08:57:47 2009
@@ -202,6 +202,10 @@
>
</File>
<File
+ RelativePath="..\..\test\cctest\test-log.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\test\cctest\test-log-ia32.cc"
>
</File>
Modified: branches/bleeding_edge/tools/visual_studio/v8_cctest_arm.vcproj
==============================================================================
--- branches/bleeding_edge/tools/visual_studio/v8_cctest_arm.vcproj
(original)
+++ branches/bleeding_edge/tools/visual_studio/v8_cctest_arm.vcproj Tue
May 5 08:57:47 2009
@@ -196,6 +196,10 @@
>
</File>
<File
+ RelativePath="..\..\test\cctest\test-log.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\test\cctest\test-mark-compact.cc"
>
</File>
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---