ll_prof: Reduce profiling hooks overhead from >400% to 25%.
Switched to using binary low-level log instead of the textual log used by the ticks processor. The binary log contains code-related events, code object names, and their bodies. When writing to the log we ask glibc to use a larger buffer. To avoid complex processing of the snapshot log (which is still textual) the serializer emits final snapshot position to code name mappings that can be quickly be read without replaying the snapshot log. (This might be useful for the ticks processor.) Review URL: http://codereview.chromium.org/6904127 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7729 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
796ac25a4f
commit
a9ea3f98b0
@ -818,7 +818,7 @@ bool Isolate::Init(Deserializer* des) {
|
||||
|
||||
// If we are deserializing, log non-function code objects and compiled
|
||||
// functions found in the snapshot.
|
||||
if (des != NULL && FLAG_log_code) {
|
||||
if (des != NULL && (FLAG_log_code || FLAG_ll_prof)) {
|
||||
HandleScope scope;
|
||||
LOG(this, LogCodeObjects());
|
||||
LOG(this, LogCompiledFunctions());
|
||||
|
@ -126,7 +126,7 @@ Log::Log(Logger* logger)
|
||||
: write_to_file_(false),
|
||||
is_stopped_(false),
|
||||
output_handle_(NULL),
|
||||
output_code_handle_(NULL),
|
||||
ll_output_handle_(NULL),
|
||||
output_buffer_(NULL),
|
||||
mutex_(NULL),
|
||||
message_buffer_(NULL),
|
||||
@ -168,7 +168,7 @@ void Log::Initialize() {
|
||||
|
||||
bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
|
||||
|| FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
|
||||
|| FLAG_log_regexp || FLAG_log_state_changes;
|
||||
|| FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof;
|
||||
|
||||
bool open_log_file = start_logging || FLAG_prof_lazy;
|
||||
|
||||
@ -233,7 +233,12 @@ void Log::OpenStdout() {
|
||||
}
|
||||
|
||||
|
||||
static const char kCodeLogExt[] = ".code";
|
||||
// Extension added to V8 log file name to get the low-level log name.
|
||||
static const char kLowLevelLogExt[] = ".ll";
|
||||
|
||||
// File buffer size of the low-level log. We don't use the default to
|
||||
// minimize the associated overhead.
|
||||
static const int kLowLevelLogBufferSize = 2 * MB;
|
||||
|
||||
|
||||
void Log::OpenFile(const char* name) {
|
||||
@ -241,14 +246,13 @@ void Log::OpenFile(const char* name) {
|
||||
output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
|
||||
write_to_file_ = true;
|
||||
if (FLAG_ll_prof) {
|
||||
// Open a file for logging the contents of code objects so that
|
||||
// they can be disassembled later.
|
||||
size_t name_len = strlen(name);
|
||||
ScopedVector<char> code_name(
|
||||
static_cast<int>(name_len + sizeof(kCodeLogExt)));
|
||||
memcpy(code_name.start(), name, name_len);
|
||||
memcpy(code_name.start() + name_len, kCodeLogExt, sizeof(kCodeLogExt));
|
||||
output_code_handle_ = OS::FOpen(code_name.start(), OS::LogFileOpenMode);
|
||||
// Open the low-level log file.
|
||||
size_t len = strlen(name);
|
||||
ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLowLevelLogExt)));
|
||||
memcpy(ll_name.start(), name, len);
|
||||
memcpy(ll_name.start() + len, kLowLevelLogExt, sizeof(kLowLevelLogExt));
|
||||
ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
|
||||
setvbuf(ll_output_handle_, NULL, _IOFBF, kLowLevelLogBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,8 +270,8 @@ void Log::Close() {
|
||||
if (write_to_file_) {
|
||||
if (output_handle_ != NULL) fclose(output_handle_);
|
||||
output_handle_ = NULL;
|
||||
if (output_code_handle_ != NULL) fclose(output_code_handle_);
|
||||
output_code_handle_ = NULL;
|
||||
if (ll_output_handle_ != NULL) fclose(ll_output_handle_);
|
||||
ll_output_handle_ = NULL;
|
||||
} else {
|
||||
delete output_buffer_;
|
||||
output_buffer_ = NULL;
|
||||
@ -361,6 +365,7 @@ void LogMessageBuilder::AppendAddress(Address addr) {
|
||||
|
||||
|
||||
void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
|
||||
if (str == NULL) return;
|
||||
AssertNoAllocation no_heap_allocation; // Ensure string stay valid.
|
||||
int len = str->length();
|
||||
if (len > 0x1000)
|
||||
|
@ -154,8 +154,8 @@ class Log {
|
||||
// mutex_ should be acquired before using output_handle_ or output_buffer_.
|
||||
FILE* output_handle_;
|
||||
|
||||
// Used when low-level profiling is active to save code object contents.
|
||||
FILE* output_code_handle_;
|
||||
// Used when low-level profiling is active.
|
||||
FILE* ll_output_handle_;
|
||||
|
||||
LogDynamicBuffer* output_buffer_;
|
||||
|
||||
|
403
src/log.cc
403
src/log.cc
@ -334,10 +334,187 @@ void Profiler::Run() {
|
||||
}
|
||||
|
||||
|
||||
// Low-level profiling event structures.
|
||||
|
||||
struct LowLevelCodeCreateStruct {
|
||||
static const char kTag = 'C';
|
||||
|
||||
int32_t name_size;
|
||||
Address code_address;
|
||||
int32_t code_size;
|
||||
};
|
||||
|
||||
|
||||
struct LowLevelCodeMoveStruct {
|
||||
static const char kTag = 'M';
|
||||
|
||||
Address from_address;
|
||||
Address to_address;
|
||||
};
|
||||
|
||||
|
||||
struct LowLevelCodeDeleteStruct {
|
||||
static const char kTag = 'D';
|
||||
|
||||
Address address;
|
||||
};
|
||||
|
||||
|
||||
struct LowLevelSnapshotPositionStruct {
|
||||
static const char kTag = 'P';
|
||||
|
||||
Address address;
|
||||
int32_t position;
|
||||
};
|
||||
|
||||
|
||||
static const char kCodeMovingGCTag = 'G';
|
||||
|
||||
|
||||
//
|
||||
// Logger class implementation.
|
||||
//
|
||||
|
||||
class Logger::NameMap {
|
||||
public:
|
||||
NameMap() : impl_(&PointerEquals) {}
|
||||
|
||||
~NameMap() {
|
||||
for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) {
|
||||
DeleteArray(static_cast<const char*>(p->value));
|
||||
}
|
||||
}
|
||||
|
||||
void Insert(Address code_address, const char* name, int name_size) {
|
||||
HashMap::Entry* entry = FindOrCreateEntry(code_address);
|
||||
if (entry->value == NULL) {
|
||||
entry->value = CopyName(name, name_size);
|
||||
}
|
||||
}
|
||||
|
||||
const char* Lookup(Address code_address) {
|
||||
HashMap::Entry* entry = FindEntry(code_address);
|
||||
return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
|
||||
}
|
||||
|
||||
void Remove(Address code_address) {
|
||||
HashMap::Entry* entry = FindEntry(code_address);
|
||||
if (entry != NULL) DeleteArray(static_cast<const char*>(entry->value));
|
||||
RemoveEntry(entry);
|
||||
}
|
||||
|
||||
void Move(Address from, Address to) {
|
||||
if (from == to) return;
|
||||
HashMap::Entry* from_entry = FindEntry(from);
|
||||
ASSERT(from_entry != NULL);
|
||||
void* value = from_entry->value;
|
||||
RemoveEntry(from_entry);
|
||||
HashMap::Entry* to_entry = FindOrCreateEntry(to);
|
||||
ASSERT(to_entry->value == NULL);
|
||||
to_entry->value = value;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool PointerEquals(void* lhs, void* rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static char* CopyName(const char* name, int name_size) {
|
||||
char* result = NewArray<char>(name_size + 1);
|
||||
for (int i = 0; i < name_size; ++i) {
|
||||
char c = name[i];
|
||||
if (c == '\0') c = ' ';
|
||||
result[i] = c;
|
||||
}
|
||||
result[name_size] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
HashMap::Entry* FindOrCreateEntry(Address code_address) {
|
||||
return impl_.Lookup(code_address, ComputePointerHash(code_address), true);
|
||||
}
|
||||
|
||||
HashMap::Entry* FindEntry(Address code_address) {
|
||||
return impl_.Lookup(code_address, ComputePointerHash(code_address), false);
|
||||
}
|
||||
|
||||
void RemoveEntry(HashMap::Entry* entry) {
|
||||
impl_.Remove(entry->key, entry->hash);
|
||||
}
|
||||
|
||||
HashMap impl_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NameMap);
|
||||
};
|
||||
|
||||
|
||||
class Logger::NameBuffer {
|
||||
public:
|
||||
NameBuffer() { Reset(); }
|
||||
|
||||
void Reset() {
|
||||
utf8_pos_ = 0;
|
||||
}
|
||||
|
||||
void AppendString(String* str) {
|
||||
if (str == NULL) return;
|
||||
if (str->HasOnlyAsciiChars()) {
|
||||
int utf8_length = Min(str->length(), kUtf8BufferSize - utf8_pos_);
|
||||
String::WriteToFlat(str, utf8_buffer_ + utf8_pos_, 0, utf8_length);
|
||||
utf8_pos_ += utf8_length;
|
||||
return;
|
||||
}
|
||||
int uc16_length = Min(str->length(), kUc16BufferSize);
|
||||
String::WriteToFlat(str, uc16_buffer_, 0, uc16_length);
|
||||
for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
|
||||
uc16 c = uc16_buffer_[i];
|
||||
if (c <= String::kMaxAsciiCharCodeU) {
|
||||
utf8_buffer_[utf8_pos_++] = c;
|
||||
} else {
|
||||
int char_length = unibrow::Utf8::Length(c);
|
||||
if (utf8_pos_ + char_length > kUtf8BufferSize) break;
|
||||
unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c);
|
||||
utf8_pos_ += char_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppendBytes(const char* bytes, int size) {
|
||||
size = Min(size, kUtf8BufferSize - utf8_pos_);
|
||||
memcpy(utf8_buffer_ + utf8_pos_, bytes, size);
|
||||
utf8_pos_ += size;
|
||||
}
|
||||
|
||||
void AppendBytes(const char* bytes) {
|
||||
AppendBytes(bytes, StrLength(bytes));
|
||||
}
|
||||
|
||||
void AppendByte(char c) {
|
||||
if (utf8_pos_ >= kUtf8BufferSize) return;
|
||||
utf8_buffer_[utf8_pos_++] = c;
|
||||
}
|
||||
|
||||
void AppendInt(int n) {
|
||||
Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
|
||||
int size = OS::SNPrintF(buffer, "%d", n);
|
||||
if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
|
||||
utf8_pos_ += size;
|
||||
}
|
||||
}
|
||||
|
||||
const char* get() { return utf8_buffer_; }
|
||||
int size() const { return utf8_pos_; }
|
||||
|
||||
private:
|
||||
static const int kUtf8BufferSize = 512;
|
||||
static const int kUc16BufferSize = 128;
|
||||
|
||||
int utf8_pos_;
|
||||
char utf8_buffer_[kUtf8BufferSize];
|
||||
uc16 uc16_buffer_[kUc16BufferSize];
|
||||
};
|
||||
|
||||
|
||||
Logger::Logger()
|
||||
: ticker_(NULL),
|
||||
profiler_(NULL),
|
||||
@ -347,6 +524,8 @@ Logger::Logger()
|
||||
cpu_profiler_nesting_(0),
|
||||
heap_profiler_nesting_(0),
|
||||
log_(new Log(this)),
|
||||
name_buffer_(new NameBuffer),
|
||||
address_to_name_map_(NULL),
|
||||
is_initialized_(false),
|
||||
last_address_(NULL),
|
||||
prev_sp_(NULL),
|
||||
@ -355,10 +534,14 @@ Logger::Logger()
|
||||
prev_code_(NULL) {
|
||||
}
|
||||
|
||||
|
||||
Logger::~Logger() {
|
||||
delete address_to_name_map_;
|
||||
delete name_buffer_;
|
||||
delete log_;
|
||||
}
|
||||
|
||||
|
||||
#define DECLARE_EVENT(ignore1, name) name,
|
||||
static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
|
||||
LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
|
||||
@ -735,7 +918,20 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
const char* comment) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled()) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendBytes(comment);
|
||||
}
|
||||
if (FLAG_ll_prof) {
|
||||
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (Serializer::enabled()) {
|
||||
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (!FLAG_log_code) return;
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s,%s,",
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
@ -749,7 +945,6 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
msg.Append(*p);
|
||||
}
|
||||
msg.Append('"');
|
||||
LowLevelCodeCreateEvent(code, &msg);
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
#endif
|
||||
@ -760,13 +955,30 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
String* name) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (name != NULL) {
|
||||
SmartPointer<char> str =
|
||||
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
CodeCreateEvent(tag, code, *str);
|
||||
} else {
|
||||
CodeCreateEvent(tag, code, "");
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled()) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendString(name);
|
||||
}
|
||||
if (FLAG_ll_prof) {
|
||||
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (Serializer::enabled()) {
|
||||
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (!FLAG_log_code) return;
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s,%s,",
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
kLogEventsNames[tag]);
|
||||
msg.AppendAddress(code->address());
|
||||
msg.Append(",%d,\"", code->ExecutableSize());
|
||||
msg.AppendDetailed(name, false);
|
||||
msg.Append('"');
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -788,7 +1000,20 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
SharedFunctionInfo* shared,
|
||||
String* name) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled()) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendString(name);
|
||||
}
|
||||
if (FLAG_ll_prof) {
|
||||
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (Serializer::enabled()) {
|
||||
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (!FLAG_log_code) return;
|
||||
if (code == Isolate::Current()->builtins()->builtin(
|
||||
Builtins::kLazyCompile))
|
||||
return;
|
||||
@ -803,7 +1028,6 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
|
||||
msg.AppendAddress(shared->address());
|
||||
msg.Append(",%s", ComputeMarker(code));
|
||||
LowLevelCodeCreateEvent(code, &msg);
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
#endif
|
||||
@ -818,7 +1042,24 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
SharedFunctionInfo* shared,
|
||||
String* source, int line) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled()) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendString(shared->DebugName());
|
||||
name_buffer_->AppendByte(' ');
|
||||
name_buffer_->AppendString(source);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendInt(line);
|
||||
}
|
||||
if (FLAG_ll_prof) {
|
||||
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (Serializer::enabled()) {
|
||||
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (!FLAG_log_code) return;
|
||||
LogMessageBuilder msg(this);
|
||||
SmartPointer<char> name =
|
||||
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
@ -835,7 +1076,6 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
line);
|
||||
msg.AppendAddress(shared->address());
|
||||
msg.Append(",%s", ComputeMarker(code));
|
||||
LowLevelCodeCreateEvent(code, &msg);
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
#endif
|
||||
@ -844,14 +1084,26 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
|
||||
void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled()) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendInt(args_count);
|
||||
}
|
||||
if (FLAG_ll_prof) {
|
||||
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (Serializer::enabled()) {
|
||||
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (!FLAG_log_code) return;
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s,%s,",
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
kLogEventsNames[tag]);
|
||||
msg.AppendAddress(code->address());
|
||||
msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
|
||||
LowLevelCodeCreateEvent(code, &msg);
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
#endif
|
||||
@ -860,10 +1112,8 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
|
||||
|
||||
void Logger::CodeMovingGCEvent() {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s\n", kLogEventsNames[CODE_MOVING_GC]);
|
||||
msg.WriteToLogFile();
|
||||
if (!log_->IsEnabled() || !FLAG_ll_prof) return;
|
||||
LowLevelLogWriteBytes(&kCodeMovingGCTag, sizeof(kCodeMovingGCTag));
|
||||
OS::SignalCodeMovingGC();
|
||||
#endif
|
||||
}
|
||||
@ -871,7 +1121,20 @@ void Logger::CodeMovingGCEvent() {
|
||||
|
||||
void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled()) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[REG_EXP_TAG]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendString(source);
|
||||
}
|
||||
if (FLAG_ll_prof) {
|
||||
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (Serializer::enabled()) {
|
||||
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
||||
}
|
||||
if (!FLAG_log_code) return;
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s,%s,",
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
@ -880,7 +1143,6 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
|
||||
msg.Append(",%d,\"", code->ExecutableSize());
|
||||
msg.AppendDetailed(source, false);
|
||||
msg.Append('\"');
|
||||
LowLevelCodeCreateEvent(code, &msg);
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
#endif
|
||||
@ -889,6 +1151,11 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
|
||||
|
||||
void Logger::CodeMoveEvent(Address from, Address to) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof) LowLevelCodeMoveEvent(from, to);
|
||||
if (Serializer::enabled() && address_to_name_map_ != NULL) {
|
||||
address_to_name_map_->Move(from, to);
|
||||
}
|
||||
MoveEventInternal(CODE_MOVE_EVENT, from, to);
|
||||
#endif
|
||||
}
|
||||
@ -896,6 +1163,11 @@ void Logger::CodeMoveEvent(Address from, Address to) {
|
||||
|
||||
void Logger::CodeDeleteEvent(Address from) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof) LowLevelCodeDeleteEvent(from);
|
||||
if (Serializer::enabled() && address_to_name_map_ != NULL) {
|
||||
address_to_name_map_->Remove(from);
|
||||
}
|
||||
DeleteEventInternal(CODE_DELETE_EVENT, from);
|
||||
#endif
|
||||
}
|
||||
@ -903,7 +1175,21 @@ void Logger::CodeDeleteEvent(Address from) {
|
||||
|
||||
void Logger::SnapshotPositionEvent(Address addr, int pos) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_snapshot_positions) return;
|
||||
if (!log_->IsEnabled()) return;
|
||||
if (FLAG_ll_prof) LowLevelSnapshotPositionEvent(addr, pos);
|
||||
if (Serializer::enabled() && address_to_name_map_ != NULL) {
|
||||
const char* code_name = address_to_name_map_->Lookup(addr);
|
||||
if (code_name == NULL) return; // Not a code object.
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s,%d,\"", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
|
||||
for (const char* p = code_name; *p != '\0'; ++p) {
|
||||
if (*p == '"') msg.Append('\\');
|
||||
msg.Append(*p);
|
||||
}
|
||||
msg.Append("\"\n");
|
||||
msg.WriteToLogFile();
|
||||
}
|
||||
if (!FLAG_log_snapshot_positions) return;
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
|
||||
msg.AppendAddress(addr);
|
||||
@ -1308,7 +1594,7 @@ static int EnumerateCompiledFunctions(Handle<SharedFunctionInfo>* sfis,
|
||||
|
||||
|
||||
void Logger::LogCodeObject(Object* object) {
|
||||
if (FLAG_log_code) {
|
||||
if (FLAG_log_code || FLAG_ll_prof) {
|
||||
Code* code_object = Code::cast(object);
|
||||
LogEventsAndTags tag = Logger::STUB_TAG;
|
||||
const char* description = "Unknown code from the snapshot";
|
||||
@ -1370,7 +1656,7 @@ void Logger::LogCodeObject(Object* object) {
|
||||
|
||||
void Logger::LogCodeInfo() {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (!log_->IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
|
||||
if (!log_->IsEnabled() || !FLAG_ll_prof) return;
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
const char arch[] = "ia32";
|
||||
#elif V8_TARGET_ARCH_X64
|
||||
@ -1380,21 +1666,69 @@ void Logger::LogCodeInfo() {
|
||||
#else
|
||||
const char arch[] = "unknown";
|
||||
#endif
|
||||
LogMessageBuilder msg(this);
|
||||
msg.Append("code-info,%s,%d\n", arch, Code::kHeaderSize);
|
||||
msg.WriteToLogFile();
|
||||
LowLevelLogWriteBytes(arch, sizeof(arch));
|
||||
#endif // ENABLE_LOGGING_AND_PROFILING
|
||||
}
|
||||
|
||||
|
||||
void Logger::LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg) {
|
||||
if (!FLAG_ll_prof || log_->output_code_handle_ == NULL) return;
|
||||
int pos = static_cast<int>(ftell(log_->output_code_handle_));
|
||||
size_t rv = fwrite(code->instruction_start(), 1, code->instruction_size(),
|
||||
log_->output_code_handle_);
|
||||
ASSERT(static_cast<size_t>(code->instruction_size()) == rv);
|
||||
void Logger::RegisterSnapshotCodeName(Code* code,
|
||||
const char* name,
|
||||
int name_size) {
|
||||
ASSERT(Serializer::enabled());
|
||||
if (address_to_name_map_ == NULL) {
|
||||
address_to_name_map_ = new NameMap;
|
||||
}
|
||||
address_to_name_map_->Insert(code->address(), name, name_size);
|
||||
}
|
||||
|
||||
|
||||
void Logger::LowLevelCodeCreateEvent(Code* code,
|
||||
const char* name,
|
||||
int name_size) {
|
||||
if (log_->ll_output_handle_ == NULL) return;
|
||||
LowLevelCodeCreateStruct event;
|
||||
event.name_size = name_size;
|
||||
event.code_address = code->instruction_start();
|
||||
ASSERT(event.code_address == code->address() + Code::kHeaderSize);
|
||||
event.code_size = code->instruction_size();
|
||||
LowLevelLogWriteStruct(event);
|
||||
LowLevelLogWriteBytes(name, name_size);
|
||||
LowLevelLogWriteBytes(
|
||||
reinterpret_cast<const char*>(code->instruction_start()),
|
||||
code->instruction_size());
|
||||
}
|
||||
|
||||
|
||||
void Logger::LowLevelCodeMoveEvent(Address from, Address to) {
|
||||
if (log_->ll_output_handle_ == NULL) return;
|
||||
LowLevelCodeMoveStruct event;
|
||||
event.from_address = from + Code::kHeaderSize;
|
||||
event.to_address = to + Code::kHeaderSize;
|
||||
LowLevelLogWriteStruct(event);
|
||||
}
|
||||
|
||||
|
||||
void Logger::LowLevelCodeDeleteEvent(Address from) {
|
||||
if (log_->ll_output_handle_ == NULL) return;
|
||||
LowLevelCodeDeleteStruct event;
|
||||
event.address = from + Code::kHeaderSize;
|
||||
LowLevelLogWriteStruct(event);
|
||||
}
|
||||
|
||||
|
||||
void Logger::LowLevelSnapshotPositionEvent(Address addr, int pos) {
|
||||
if (log_->ll_output_handle_ == NULL) return;
|
||||
LowLevelSnapshotPositionStruct event;
|
||||
event.address = addr + Code::kHeaderSize;
|
||||
event.position = pos;
|
||||
LowLevelLogWriteStruct(event);
|
||||
}
|
||||
|
||||
|
||||
void Logger::LowLevelLogWriteBytes(const char* bytes, int size) {
|
||||
size_t rv = fwrite(bytes, 1, size, log_->ll_output_handle_);
|
||||
ASSERT(static_cast<size_t>(size) == rv);
|
||||
USE(rv);
|
||||
msg->Append(",%d", pos);
|
||||
}
|
||||
|
||||
|
||||
@ -1497,7 +1831,6 @@ bool Logger::Setup() {
|
||||
|
||||
// --ll-prof implies --log-code and --log-snapshot-positions.
|
||||
if (FLAG_ll_prof) {
|
||||
FLAG_log_code = true;
|
||||
FLAG_log_snapshot_positions = true;
|
||||
}
|
||||
|
||||
@ -1524,7 +1857,7 @@ bool Logger::Setup() {
|
||||
|
||||
bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
|
||||
|| FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
|
||||
|| FLAG_log_regexp || FLAG_log_state_changes;
|
||||
|| FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof;
|
||||
|
||||
if (start_logging) {
|
||||
logging_nesting_ = 1;
|
||||
|
35
src/log.h
35
src/log.h
@ -69,11 +69,12 @@ namespace internal {
|
||||
// tick profiler requires code events, so --prof implies --log-code.
|
||||
|
||||
// Forward declarations.
|
||||
class Ticker;
|
||||
class HashMap;
|
||||
class LogMessageBuilder;
|
||||
class Profiler;
|
||||
class Semaphore;
|
||||
class SlidingStateWindow;
|
||||
class LogMessageBuilder;
|
||||
class Ticker;
|
||||
|
||||
#undef LOG
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
@ -95,6 +96,7 @@ class LogMessageBuilder;
|
||||
V(CODE_MOVING_GC, "code-moving-gc") \
|
||||
V(SHARED_FUNC_MOVE_EVENT, "sfi-move") \
|
||||
V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \
|
||||
V(SNAPSHOT_CODE_NAME_EVENT, "snapshot-code-name") \
|
||||
V(TICK_EVENT, "tick") \
|
||||
V(REPEAT_META_EVENT, "repeat") \
|
||||
V(BUILTIN_TAG, "Builtin") \
|
||||
@ -300,6 +302,9 @@ class Logger {
|
||||
void LogFailure();
|
||||
|
||||
private:
|
||||
class NameBuffer;
|
||||
class NameMap;
|
||||
|
||||
Logger();
|
||||
~Logger();
|
||||
|
||||
@ -326,8 +331,26 @@ class Logger {
|
||||
// Emits general information about generated code.
|
||||
void LogCodeInfo();
|
||||
|
||||
// Handles code creation when low-level profiling is active.
|
||||
void LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg);
|
||||
void RegisterSnapshotCodeName(Code* code, const char* name, int name_size);
|
||||
|
||||
// Low-level logging support.
|
||||
|
||||
void LowLevelCodeCreateEvent(Code* code, const char* name, int name_size);
|
||||
|
||||
void LowLevelCodeMoveEvent(Address from, Address to);
|
||||
|
||||
void LowLevelCodeDeleteEvent(Address from);
|
||||
|
||||
void LowLevelSnapshotPositionEvent(Address addr, int pos);
|
||||
|
||||
void LowLevelLogWriteBytes(const char* bytes, int size);
|
||||
|
||||
template <typename T>
|
||||
void LowLevelLogWriteStruct(const T& s) {
|
||||
char tag = T::kTag;
|
||||
LowLevelLogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
|
||||
LowLevelLogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
|
||||
}
|
||||
|
||||
// Emits a profiler tick event. Used by the profiler thread.
|
||||
void TickEvent(TickSample* sample, bool overflow);
|
||||
@ -379,6 +402,10 @@ class Logger {
|
||||
|
||||
Log* log_;
|
||||
|
||||
NameBuffer* name_buffer_;
|
||||
|
||||
NameMap* address_to_name_map_;
|
||||
|
||||
// Guards against multiple calls to TearDown() that can happen in some tests.
|
||||
// 'true' between Setup() and TearDown().
|
||||
bool is_initialized_;
|
||||
|
@ -251,6 +251,12 @@ static inline uint32_t ComputeIntegerHash(uint32_t key) {
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t ComputePointerHash(void* ptr) {
|
||||
return ComputeIntegerHash(
|
||||
static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)));
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Miscellaneous
|
||||
|
||||
|
236
tools/ll_prof.py
236
tools/ll_prof.py
@ -124,7 +124,7 @@ class Code(object):
|
||||
self.callee_ticks = collections.defaultdict(lambda: 0)
|
||||
self.callee_ticks[callee] += 1
|
||||
|
||||
def PrintAnnotated(self, code_info, options):
|
||||
def PrintAnnotated(self, arch, options):
|
||||
if self.self_ticks_map is None:
|
||||
ticks_map = []
|
||||
else:
|
||||
@ -135,7 +135,7 @@ class Code(object):
|
||||
ticks_offsets = [t[0] for t in ticks_map]
|
||||
ticks_counts = [t[1] for t in ticks_map]
|
||||
# Get a list of disassembled lines and their addresses.
|
||||
lines = self._GetDisasmLines(code_info, options)
|
||||
lines = self._GetDisasmLines(arch, options)
|
||||
if len(lines) == 0:
|
||||
return
|
||||
# Print annotated lines.
|
||||
@ -174,17 +174,17 @@ class Code(object):
|
||||
self.end_address - self.start_address,
|
||||
self.origin)
|
||||
|
||||
def _GetDisasmLines(self, code_info, options):
|
||||
def _GetDisasmLines(self, arch, options):
|
||||
if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN:
|
||||
inplace = False
|
||||
filename = options.log + ".code"
|
||||
filename = options.log + ".ll"
|
||||
else:
|
||||
inplace = True
|
||||
filename = self.origin
|
||||
return disasm.GetDisasmLines(filename,
|
||||
self.origin_offset,
|
||||
self.end_address - self.start_address,
|
||||
code_info.arch,
|
||||
arch,
|
||||
inplace)
|
||||
|
||||
|
||||
@ -304,76 +304,102 @@ class CodeInfo(object):
|
||||
self.header_size = header_size
|
||||
|
||||
|
||||
class CodeLogReader(object):
|
||||
"""V8 code event log reader."""
|
||||
class SnapshotLogReader(object):
|
||||
"""V8 snapshot log reader."""
|
||||
|
||||
_CODE_INFO_RE = re.compile(
|
||||
r"code-info,([^,]+),(\d+)")
|
||||
_SNAPSHOT_CODE_NAME_RE = re.compile(
|
||||
r"snapshot-code-name,(\d+),\"(.*)\"")
|
||||
|
||||
_CODE_CREATE_RE = re.compile(
|
||||
r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(0x[a-f0-9]+),([~*])?)?(?:,(\d+))?")
|
||||
def __init__(self, log_name):
|
||||
self.log_name = log_name
|
||||
|
||||
_CODE_MOVE_RE = re.compile(
|
||||
r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)")
|
||||
def ReadNameMap(self):
|
||||
log = open(self.log_name, "r")
|
||||
try:
|
||||
snapshot_pos_to_name = {}
|
||||
for line in log:
|
||||
match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line)
|
||||
if match:
|
||||
pos = int(match.group(1))
|
||||
name = match.group(2)
|
||||
snapshot_pos_to_name[pos] = name
|
||||
finally:
|
||||
log.close()
|
||||
return snapshot_pos_to_name
|
||||
|
||||
_CODE_DELETE_RE = re.compile(
|
||||
r"code-delete,(0x[a-f0-9]+)")
|
||||
|
||||
_SNAPSHOT_POS_RE = re.compile(
|
||||
r"snapshot-pos,(0x[a-f0-9]+),(\d+)")
|
||||
class LogReader(object):
|
||||
"""V8 low-level (binary) log reader."""
|
||||
|
||||
_CODE_MOVING_GC = "code-moving-gc"
|
||||
_ARCH_TO_POINTER_TYPE_MAP = {
|
||||
"ia32": ctypes.c_uint32,
|
||||
"arm": ctypes.c_uint32,
|
||||
"x64": ctypes.c_uint64
|
||||
}
|
||||
|
||||
def __init__(self, log_name, code_map, is_snapshot, snapshot_pos_to_name):
|
||||
self.log = open(log_name, "r")
|
||||
_CODE_CREATE_TAG = "C"
|
||||
_CODE_MOVE_TAG = "M"
|
||||
_CODE_DELETE_TAG = "D"
|
||||
_SNAPSHOT_POSITION_TAG = "P"
|
||||
_CODE_MOVING_GC_TAG = "G"
|
||||
|
||||
def __init__(self, log_name, code_map, snapshot_pos_to_name):
|
||||
self.log_file = open(log_name, "r")
|
||||
self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
|
||||
self.log_pos = 0
|
||||
self.code_map = code_map
|
||||
self.is_snapshot = is_snapshot
|
||||
self.snapshot_pos_to_name = snapshot_pos_to_name
|
||||
self.address_to_snapshot_name = {}
|
||||
|
||||
def ReadCodeInfo(self):
|
||||
line = self.log.readline() or ""
|
||||
match = CodeLogReader._CODE_INFO_RE.match(line)
|
||||
assert match, "No code info in log"
|
||||
return CodeInfo(arch=match.group(1), header_size=int(match.group(2)))
|
||||
self.arch = self.log[:self.log.find("\0")]
|
||||
self.log_pos += len(self.arch) + 1
|
||||
assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
|
||||
"Unsupported architecture %s" % self.arch
|
||||
pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
|
||||
|
||||
def ReadUpToGC(self, code_info):
|
||||
made_progress = False
|
||||
code_header_size = code_info.header_size
|
||||
while True:
|
||||
line = self.log.readline()
|
||||
if not line:
|
||||
return made_progress
|
||||
made_progress = True
|
||||
self.code_create_struct = LogReader._DefineStruct([
|
||||
("name_size", ctypes.c_int32),
|
||||
("code_address", pointer_type),
|
||||
("code_size", ctypes.c_int32)])
|
||||
|
||||
if line.startswith(CodeLogReader._CODE_MOVING_GC):
|
||||
self.code_move_struct = LogReader._DefineStruct([
|
||||
("from_address", pointer_type),
|
||||
("to_address", pointer_type)])
|
||||
|
||||
self.code_delete_struct = LogReader._DefineStruct([
|
||||
("address", pointer_type)])
|
||||
|
||||
self.snapshot_position_struct = LogReader._DefineStruct([
|
||||
("address", pointer_type),
|
||||
("position", ctypes.c_int32)])
|
||||
|
||||
def ReadUpToGC(self):
|
||||
while self.log_pos < self.log.size():
|
||||
tag = self.log[self.log_pos]
|
||||
self.log_pos += 1
|
||||
|
||||
if tag == LogReader._CODE_MOVING_GC_TAG:
|
||||
self.address_to_snapshot_name.clear()
|
||||
return made_progress
|
||||
return
|
||||
|
||||
match = CodeLogReader._CODE_CREATE_RE.match(line)
|
||||
if match:
|
||||
start_address = int(match.group(2), 16) + code_header_size
|
||||
end_address = start_address + int(match.group(3)) - code_header_size
|
||||
if tag == LogReader._CODE_CREATE_TAG:
|
||||
event = self.code_create_struct.from_buffer(self.log, self.log_pos)
|
||||
self.log_pos += ctypes.sizeof(event)
|
||||
start_address = event.code_address
|
||||
end_address = start_address + event.code_size
|
||||
if start_address in self.address_to_snapshot_name:
|
||||
name = self.address_to_snapshot_name[start_address]
|
||||
origin = JS_SNAPSHOT_ORIGIN
|
||||
else:
|
||||
tag = match.group(1)
|
||||
optimization_status = match.group(6)
|
||||
func_name = match.group(4)
|
||||
if optimization_status:
|
||||
name = "%s:%s%s" % (tag, optimization_status, func_name)
|
||||
else:
|
||||
name = "%s:%s" % (tag, func_name)
|
||||
name = self.log[self.log_pos:self.log_pos + event.name_size]
|
||||
origin = JS_ORIGIN
|
||||
if self.is_snapshot:
|
||||
origin_offset = 0
|
||||
else:
|
||||
origin_offset = int(match.group(7))
|
||||
self.log_pos += event.name_size
|
||||
origin_offset = self.log_pos
|
||||
self.log_pos += event.code_size
|
||||
code = Code(name, start_address, end_address, origin, origin_offset)
|
||||
conficting_code = self.code_map.Find(start_address)
|
||||
if conficting_code:
|
||||
CodeLogReader._HandleCodeConflict(conficting_code, code)
|
||||
LogReader._HandleCodeConflict(conficting_code, code)
|
||||
# TODO(vitalyr): this warning is too noisy because of our
|
||||
# attempts to reconstruct code log from the snapshot.
|
||||
# print >>sys.stderr, \
|
||||
@ -382,10 +408,11 @@ class CodeLogReader(object):
|
||||
self.code_map.Add(code)
|
||||
continue
|
||||
|
||||
match = CodeLogReader._CODE_MOVE_RE.match(line)
|
||||
if match:
|
||||
old_start_address = int(match.group(1), 16) + code_header_size
|
||||
new_start_address = int(match.group(2), 16) + code_header_size
|
||||
if tag == LogReader._CODE_MOVE_TAG:
|
||||
event = self.code_move_struct.from_buffer(self.log, self.log_pos)
|
||||
self.log_pos += ctypes.sizeof(event)
|
||||
old_start_address = event.from_address
|
||||
new_start_address = event.to_address
|
||||
if old_start_address == new_start_address:
|
||||
# Skip useless code move entries.
|
||||
continue
|
||||
@ -402,9 +429,10 @@ class CodeLogReader(object):
|
||||
self.code_map.Add(code)
|
||||
continue
|
||||
|
||||
match = CodeLogReader._CODE_DELETE_RE.match(line)
|
||||
if match:
|
||||
old_start_address = int(match.group(1), 16) + code_header_size
|
||||
if tag == LogReader._CODE_DELETE_TAG:
|
||||
event = self.code_delete_struct.from_buffer(self.log, self.log_pos)
|
||||
self.log_pos += ctypes.sizeof(event)
|
||||
old_start_address = event.address
|
||||
code = self.code_map.Find(old_start_address)
|
||||
if not code:
|
||||
print >>sys.stderr, "Warning: Not found %x" % old_start_address
|
||||
@ -414,40 +442,36 @@ class CodeLogReader(object):
|
||||
self.code_map.Remove(code)
|
||||
continue
|
||||
|
||||
match = CodeLogReader._SNAPSHOT_POS_RE.match(line)
|
||||
if match:
|
||||
start_address = int(match.group(1), 16) + code_header_size
|
||||
snapshot_pos = int(match.group(2))
|
||||
if self.is_snapshot:
|
||||
code = self.code_map.Find(start_address)
|
||||
if code:
|
||||
assert code.start_address == start_address, \
|
||||
"Inexact snapshot address %x for %s" % (start_address, code)
|
||||
self.snapshot_pos_to_name[snapshot_pos] = code.name
|
||||
else:
|
||||
if snapshot_pos in self.snapshot_pos_to_name:
|
||||
self.address_to_snapshot_name[start_address] = \
|
||||
self.snapshot_pos_to_name[snapshot_pos]
|
||||
if tag == LogReader._SNAPSHOT_POSITION_TAG:
|
||||
event = self.snapshot_position_struct.from_buffer(self.log,
|
||||
self.log_pos)
|
||||
self.log_pos += ctypes.sizeof(event)
|
||||
start_address = event.address
|
||||
snapshot_pos = event.position
|
||||
if snapshot_pos in self.snapshot_pos_to_name:
|
||||
self.address_to_snapshot_name[start_address] = \
|
||||
self.snapshot_pos_to_name[snapshot_pos]
|
||||
continue
|
||||
|
||||
assert False, "Unknown tag %s" % tag
|
||||
|
||||
def Dispose(self):
|
||||
self.log.close()
|
||||
self.log_file.close()
|
||||
|
||||
@staticmethod
|
||||
def _DefineStruct(fields):
|
||||
class Struct(ctypes.Structure):
|
||||
_fields_ = fields
|
||||
return Struct
|
||||
|
||||
@staticmethod
|
||||
def _HandleCodeConflict(old_code, new_code):
|
||||
assert (old_code.start_address == new_code.start_address and
|
||||
old_code.end_address == new_code.end_address), \
|
||||
"Conficting code log entries %s and %s" % (old_code, new_code)
|
||||
CodeLogReader._UpdateNames(old_code, new_code)
|
||||
|
||||
@staticmethod
|
||||
def _UpdateNames(old_code, new_code):
|
||||
if old_code.name == new_code.name:
|
||||
return
|
||||
# Kludge: there are code objects with custom names that don't
|
||||
# match their flags.
|
||||
misnamed_code = set(["Builtin:CpuFeatures::Probe"])
|
||||
if old_code.name in misnamed_code:
|
||||
return
|
||||
# Code object may be shared by a few functions. Collect the full
|
||||
# set of names.
|
||||
old_code.AddName(new_code.name)
|
||||
@ -756,14 +780,14 @@ class LibraryRepo(object):
|
||||
return True
|
||||
|
||||
|
||||
def PrintReport(code_map, library_repo, code_info, options):
|
||||
def PrintReport(code_map, library_repo, arch, options):
|
||||
print "Ticks per symbol:"
|
||||
used_code = [code for code in code_map.UsedCode()]
|
||||
used_code.sort(key=lambda x: x.self_ticks, reverse=True)
|
||||
for i, code in enumerate(used_code):
|
||||
print "%10d %s [%s]" % (code.self_ticks, code.FullName(), code.origin)
|
||||
if options.disasm_all or i < options.disasm_top:
|
||||
code.PrintAnnotated(code_info, options)
|
||||
code.PrintAnnotated(arch, options)
|
||||
print
|
||||
print "Ticks per library:"
|
||||
mmap_infos = [m for m in library_repo.infos]
|
||||
@ -825,11 +849,11 @@ if __name__ == "__main__":
|
||||
|
||||
if not options.quiet:
|
||||
if options.snapshot:
|
||||
print "V8 logs: %s, %s, %s.code" % (options.snapshot_log,
|
||||
options.log,
|
||||
options.log)
|
||||
print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log,
|
||||
options.log,
|
||||
options.log)
|
||||
else:
|
||||
print "V8 log: %s, %s.code (no snapshot)" % (options.log, options.log)
|
||||
print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log)
|
||||
print "Perf trace file: %s" % options.trace
|
||||
|
||||
# Stats.
|
||||
@ -840,30 +864,24 @@ if __name__ == "__main__":
|
||||
mmap_time = 0
|
||||
sample_time = 0
|
||||
|
||||
# Initialize the log reader and get the code info.
|
||||
code_map = CodeMap()
|
||||
snapshot_name_map = {}
|
||||
log_reader = CodeLogReader(log_name=options.log,
|
||||
code_map=code_map,
|
||||
is_snapshot=False,
|
||||
snapshot_pos_to_name=snapshot_name_map)
|
||||
code_info = log_reader.ReadCodeInfo()
|
||||
if not options.quiet:
|
||||
print "Generated code architecture: %s" % code_info.arch
|
||||
print
|
||||
|
||||
# Process the snapshot log to fill the snapshot name map.
|
||||
snapshot_name_map = {}
|
||||
if options.snapshot:
|
||||
snapshot_log_reader = CodeLogReader(log_name=options.snapshot_log,
|
||||
code_map=CodeMap(),
|
||||
is_snapshot=True,
|
||||
snapshot_pos_to_name=snapshot_name_map)
|
||||
while snapshot_log_reader.ReadUpToGC(code_info):
|
||||
pass
|
||||
snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log)
|
||||
snapshot_name_map = snapshot_log_reader.ReadNameMap()
|
||||
|
||||
# Initialize the log reader.
|
||||
code_map = CodeMap()
|
||||
log_reader = LogReader(log_name=options.log + ".ll",
|
||||
code_map=code_map,
|
||||
snapshot_pos_to_name=snapshot_name_map)
|
||||
if not options.quiet:
|
||||
print "Generated code architecture: %s" % log_reader.arch
|
||||
print
|
||||
|
||||
# Process the code and trace logs.
|
||||
library_repo = LibraryRepo()
|
||||
log_reader.ReadUpToGC(code_info)
|
||||
log_reader.ReadUpToGC()
|
||||
trace_reader = TraceReader(options.trace)
|
||||
while True:
|
||||
header, offset = trace_reader.ReadEventHeader()
|
||||
@ -874,7 +892,7 @@ if __name__ == "__main__":
|
||||
start = time.time()
|
||||
mmap_info = trace_reader.ReadMmap(header, offset)
|
||||
if mmap_info.filename == V8_GC_FAKE_MMAP:
|
||||
log_reader.ReadUpToGC(code_info)
|
||||
log_reader.ReadUpToGC()
|
||||
else:
|
||||
library_repo.Load(mmap_info, code_map, options)
|
||||
mmap_time += time.time() - start
|
||||
@ -901,7 +919,7 @@ if __name__ == "__main__":
|
||||
if options.dot:
|
||||
PrintDot(code_map, options)
|
||||
else:
|
||||
PrintReport(code_map, library_repo, code_info, options)
|
||||
PrintReport(code_map, library_repo, log_reader.arch, options)
|
||||
|
||||
if not options.quiet:
|
||||
print
|
||||
|
Loading…
Reference in New Issue
Block a user