[test][d8] Add d8.log.getAndStop helper
The new helper function allows us to write tests for log parsing without the need to first generating a log file. This makes it easier to spot errors when the log format changes. - Add d8 global variable - Add file_name accessor to Logger and Log classes - Change OS::LogFileOpenMode to w+ / wb+ - Use separate Log::WriteLogHeader method - Remove unused logger_ instance variable from Log Bug: v8:10644 Change-Id: Ifc7e35aa4e91b3f01f0847843263946e085944c3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2387563 Commit-Queue: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#69715}
This commit is contained in:
parent
c1d06eb3d3
commit
95aa697b2f
@ -679,9 +679,7 @@ FILE* OS::OpenTemporaryFile() {
|
||||
return tmpfile();
|
||||
}
|
||||
|
||||
|
||||
const char* const OS::LogFileOpenMode = "w";
|
||||
|
||||
const char* const OS::LogFileOpenMode = "w+";
|
||||
|
||||
void OS::Print(const char* format, ...) {
|
||||
va_list args;
|
||||
|
@ -603,8 +603,7 @@ FILE* OS::OpenTemporaryFile() {
|
||||
|
||||
|
||||
// Open log file in binary mode to avoid /n -> /r/n conversion.
|
||||
const char* const OS::LogFileOpenMode = "wb";
|
||||
|
||||
const char* const OS::LogFileOpenMode = "wb+";
|
||||
|
||||
// Print (debug) message to console.
|
||||
void OS::Print(const char* format, ...) {
|
||||
|
212
src/d8/d8.cc
212
src/d8/d8.cc
@ -43,6 +43,7 @@
|
||||
#include "src/init/v8.h"
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "src/logging/counters.h"
|
||||
#include "src/logging/log-utils.h"
|
||||
#include "src/objects/managed.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/objects.h"
|
||||
@ -1503,6 +1504,41 @@ void Shell::RealmSharedSet(Local<String> property, Local<Value> value,
|
||||
data->realm_shared_.Reset(isolate, value);
|
||||
}
|
||||
|
||||
void Shell::LogGetAndStop(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
std::string file_name = i_isolate->logger()->file_name();
|
||||
if (i::Log::IsLoggingToConsole(file_name)) {
|
||||
Throw(isolate, "Logging to console instead of file.");
|
||||
return;
|
||||
}
|
||||
if (!i_isolate->logger()->is_logging()) {
|
||||
Throw(isolate, "Logging not enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string raw_log;
|
||||
FILE* log_file = i_isolate->logger()->TearDownAndGetLogFile();
|
||||
CHECK_NOT_NULL(log_file);
|
||||
|
||||
bool exists = false;
|
||||
raw_log = i::ReadFile(log_file, &exists, true);
|
||||
fclose(log_file);
|
||||
|
||||
if (!exists) {
|
||||
Throw(isolate, "Unable to read log file.");
|
||||
return;
|
||||
}
|
||||
Local<String> result =
|
||||
String::NewFromUtf8(isolate, raw_log.c_str(), NewStringType::kNormal,
|
||||
static_cast<int>(raw_log.size()))
|
||||
.ToLocalChecked();
|
||||
|
||||
args.GetReturnValue().Set(result);
|
||||
}
|
||||
|
||||
// async_hooks.createHook() registers functions to be called for different
|
||||
// lifetime events of each async operation.
|
||||
void Shell::AsyncHooksCreateHook(
|
||||
@ -2071,6 +2107,11 @@ Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
|
||||
|
||||
Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
|
||||
Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
|
||||
global_template->Set(Symbol::GetToStringTag(isolate),
|
||||
String::NewFromUtf8Literal(isolate, "global"));
|
||||
global_template->Set(isolate, "version",
|
||||
FunctionTemplate::New(isolate, Version));
|
||||
|
||||
global_template->Set(isolate, "print", FunctionTemplate::New(isolate, Print));
|
||||
global_template->Set(isolate, "printErr",
|
||||
FunctionTemplate::New(isolate, PrintErr));
|
||||
@ -2089,57 +2130,37 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
|
||||
if (!options.omit_quit) {
|
||||
global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
|
||||
}
|
||||
Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
|
||||
global_template->Set(isolate, "testRunner", test_template);
|
||||
test_template->Set(isolate, "notifyDone",
|
||||
FunctionTemplate::New(isolate, NotifyDone));
|
||||
test_template->Set(isolate, "waitUntilDone",
|
||||
FunctionTemplate::New(isolate, WaitUntilDone));
|
||||
// Reliable access to quit functionality. The "quit" method function
|
||||
// installed on the global object can be hidden with the --omit-quit flag
|
||||
// (e.g. on asan bots).
|
||||
test_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
|
||||
global_template->Set(isolate, "testRunner",
|
||||
Shell::CreateTestRunnerTemplate(isolate));
|
||||
global_template->Set(isolate, "Realm", Shell::CreateRealmTemplate(isolate));
|
||||
global_template->Set(isolate, "performance",
|
||||
Shell::CreatePerformanceTemplate(isolate));
|
||||
global_template->Set(isolate, "Worker", Shell::CreateWorkerTemplate(isolate));
|
||||
global_template->Set(isolate, "os", Shell::CreateOSTemplate(isolate));
|
||||
global_template->Set(isolate, "d8", Shell::CreateD8Template(isolate));
|
||||
|
||||
global_template->Set(isolate, "version",
|
||||
FunctionTemplate::New(isolate, Version));
|
||||
global_template->Set(Symbol::GetToStringTag(isolate),
|
||||
String::NewFromUtf8Literal(isolate, "global"));
|
||||
#ifdef V8_FUZZILLI
|
||||
global_template->Set(
|
||||
String::NewFromUtf8(isolate, "fuzzilli", NewStringType::kNormal)
|
||||
.ToLocalChecked(),
|
||||
FunctionTemplate::New(isolate, Fuzzilli), PropertyAttribute::DontEnum);
|
||||
#endif // V8_FUZZILLI
|
||||
|
||||
// Bind the Realm object.
|
||||
Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
|
||||
realm_template->Set(isolate, "current",
|
||||
FunctionTemplate::New(isolate, RealmCurrent));
|
||||
realm_template->Set(isolate, "owner",
|
||||
FunctionTemplate::New(isolate, RealmOwner));
|
||||
realm_template->Set(isolate, "global",
|
||||
FunctionTemplate::New(isolate, RealmGlobal));
|
||||
realm_template->Set(isolate, "create",
|
||||
FunctionTemplate::New(isolate, RealmCreate));
|
||||
realm_template->Set(
|
||||
isolate, "createAllowCrossRealmAccess",
|
||||
FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
|
||||
realm_template->Set(isolate, "navigate",
|
||||
FunctionTemplate::New(isolate, RealmNavigate));
|
||||
realm_template->Set(isolate, "detachGlobal",
|
||||
FunctionTemplate::New(isolate, RealmDetachGlobal));
|
||||
realm_template->Set(isolate, "dispose",
|
||||
FunctionTemplate::New(isolate, RealmDispose));
|
||||
realm_template->Set(isolate, "switch",
|
||||
FunctionTemplate::New(isolate, RealmSwitch));
|
||||
realm_template->Set(isolate, "eval",
|
||||
FunctionTemplate::New(isolate, RealmEval));
|
||||
realm_template->SetAccessor(String::NewFromUtf8Literal(isolate, "shared"),
|
||||
RealmSharedGet, RealmSharedSet);
|
||||
global_template->Set(isolate, "Realm", realm_template);
|
||||
if (i::FLAG_expose_async_hooks) {
|
||||
global_template->Set(isolate, "async_hooks",
|
||||
Shell::CreateAsyncHookTemplate(isolate));
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
|
||||
performance_template->Set(isolate, "now",
|
||||
FunctionTemplate::New(isolate, PerformanceNow));
|
||||
performance_template->Set(
|
||||
isolate, "measureMemory",
|
||||
FunctionTemplate::New(isolate, PerformanceMeasureMemory));
|
||||
global_template->Set(isolate, "performance", performance_template);
|
||||
return global_template;
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> Shell::CreateOSTemplate(Isolate* isolate) {
|
||||
Local<ObjectTemplate> os_template = ObjectTemplate::New(isolate);
|
||||
AddOSMethods(isolate, os_template);
|
||||
return os_template;
|
||||
}
|
||||
|
||||
Local<FunctionTemplate> Shell::CreateWorkerTemplate(Isolate* isolate) {
|
||||
Local<FunctionTemplate> worker_fun_template =
|
||||
FunctionTemplate::New(isolate, WorkerNew);
|
||||
Local<Signature> worker_signature =
|
||||
@ -2164,34 +2185,83 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
|
||||
FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
|
||||
worker_signature));
|
||||
worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
global_template->Set(isolate, "Worker", worker_fun_template);
|
||||
return worker_fun_template;
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
|
||||
AddOSMethods(isolate, os_templ);
|
||||
global_template->Set(isolate, "os", os_templ);
|
||||
Local<ObjectTemplate> Shell::CreateAsyncHookTemplate(Isolate* isolate) {
|
||||
Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
|
||||
async_hooks_templ->Set(isolate, "createHook",
|
||||
FunctionTemplate::New(isolate, AsyncHooksCreateHook));
|
||||
async_hooks_templ->Set(
|
||||
isolate, "executionAsyncId",
|
||||
FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
|
||||
async_hooks_templ->Set(
|
||||
isolate, "triggerAsyncId",
|
||||
FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
|
||||
return async_hooks_templ;
|
||||
}
|
||||
|
||||
#ifdef V8_FUZZILLI
|
||||
global_template->Set(
|
||||
String::NewFromUtf8(isolate, "fuzzilli", NewStringType::kNormal)
|
||||
.ToLocalChecked(),
|
||||
FunctionTemplate::New(isolate, Fuzzilli), PropertyAttribute::DontEnum);
|
||||
#endif // V8_FUZZILLI
|
||||
Local<ObjectTemplate> Shell::CreateTestRunnerTemplate(Isolate* isolate) {
|
||||
Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
|
||||
test_template->Set(isolate, "notifyDone",
|
||||
FunctionTemplate::New(isolate, NotifyDone));
|
||||
test_template->Set(isolate, "waitUntilDone",
|
||||
FunctionTemplate::New(isolate, WaitUntilDone));
|
||||
// Reliable access to quit functionality. The "quit" method function
|
||||
// installed on the global object can be hidden with the --omit-quit flag
|
||||
// (e.g. on asan bots).
|
||||
test_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit));
|
||||
return test_template;
|
||||
}
|
||||
|
||||
if (i::FLAG_expose_async_hooks) {
|
||||
Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
|
||||
async_hooks_templ->Set(
|
||||
isolate, "createHook",
|
||||
FunctionTemplate::New(isolate, AsyncHooksCreateHook));
|
||||
async_hooks_templ->Set(
|
||||
isolate, "executionAsyncId",
|
||||
FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
|
||||
async_hooks_templ->Set(
|
||||
isolate, "triggerAsyncId",
|
||||
FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
|
||||
global_template->Set(isolate, "async_hooks", async_hooks_templ);
|
||||
Local<ObjectTemplate> Shell::CreatePerformanceTemplate(Isolate* isolate) {
|
||||
Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
|
||||
performance_template->Set(isolate, "now",
|
||||
FunctionTemplate::New(isolate, PerformanceNow));
|
||||
performance_template->Set(
|
||||
isolate, "measureMemory",
|
||||
FunctionTemplate::New(isolate, PerformanceMeasureMemory));
|
||||
return performance_template;
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> Shell::CreateRealmTemplate(Isolate* isolate) {
|
||||
Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
|
||||
realm_template->Set(isolate, "current",
|
||||
FunctionTemplate::New(isolate, RealmCurrent));
|
||||
realm_template->Set(isolate, "owner",
|
||||
FunctionTemplate::New(isolate, RealmOwner));
|
||||
realm_template->Set(isolate, "global",
|
||||
FunctionTemplate::New(isolate, RealmGlobal));
|
||||
realm_template->Set(isolate, "create",
|
||||
FunctionTemplate::New(isolate, RealmCreate));
|
||||
realm_template->Set(
|
||||
isolate, "createAllowCrossRealmAccess",
|
||||
FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
|
||||
realm_template->Set(isolate, "navigate",
|
||||
FunctionTemplate::New(isolate, RealmNavigate));
|
||||
realm_template->Set(isolate, "detachGlobal",
|
||||
FunctionTemplate::New(isolate, RealmDetachGlobal));
|
||||
realm_template->Set(isolate, "dispose",
|
||||
FunctionTemplate::New(isolate, RealmDispose));
|
||||
realm_template->Set(isolate, "switch",
|
||||
FunctionTemplate::New(isolate, RealmSwitch));
|
||||
realm_template->Set(isolate, "eval",
|
||||
FunctionTemplate::New(isolate, RealmEval));
|
||||
realm_template->SetAccessor(String::NewFromUtf8Literal(isolate, "shared"),
|
||||
RealmSharedGet, RealmSharedSet);
|
||||
return realm_template;
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) {
|
||||
Local<ObjectTemplate> d8_template = ObjectTemplate::New(isolate);
|
||||
{
|
||||
Local<ObjectTemplate> log_template = ObjectTemplate::New(isolate);
|
||||
log_template->Set(isolate, "getAndStop",
|
||||
FunctionTemplate::New(isolate, LogGetAndStop));
|
||||
|
||||
d8_template->Set(isolate, "log", log_template);
|
||||
}
|
||||
|
||||
return global_template;
|
||||
return d8_template;
|
||||
}
|
||||
|
||||
static void PrintMessageCallback(Local<Message> message, Local<Value> error) {
|
||||
|
11
src/d8/d8.h
11
src/d8/d8.h
@ -401,6 +401,8 @@ class Shell : public i::AllStatic {
|
||||
static void RealmSharedSet(Local<String> property, Local<Value> value,
|
||||
const PropertyCallbackInfo<void>& info);
|
||||
|
||||
static void LogGetAndStop(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
static void AsyncHooksCreateHook(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void AsyncHooksExecutionAsyncId(
|
||||
@ -539,7 +541,16 @@ class Shell : public i::AllStatic {
|
||||
static Local<String> Stringify(Isolate* isolate, Local<Value> value);
|
||||
static void RunShell(Isolate* isolate);
|
||||
static bool SetOptions(int argc, char* argv[]);
|
||||
|
||||
static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreateOSTemplate(Isolate* isolate);
|
||||
static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreateAsyncHookTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreateTestRunnerTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreatePerformanceTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreateRealmTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreateD8Template(Isolate* isolate);
|
||||
|
||||
static MaybeLocal<Context> CreateRealm(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args, int index,
|
||||
v8::MaybeLocal<Value> global_object);
|
||||
|
@ -3077,7 +3077,8 @@ void Isolate::Deinit() {
|
||||
cancelable_task_manager()->CancelAndWait();
|
||||
|
||||
heap_.TearDown();
|
||||
logger_->TearDown();
|
||||
FILE* logfile = logger_->TearDownAndGetLogFile();
|
||||
if (logfile != nullptr) fclose(logfile);
|
||||
|
||||
if (wasm_engine_) {
|
||||
wasm_engine_->RemoveIsolate(this);
|
||||
|
@ -23,25 +23,35 @@ const char* const Log::kLogToTemporaryFile = "&";
|
||||
const char* const Log::kLogToConsole = "-";
|
||||
|
||||
// static
|
||||
FILE* Log::CreateOutputHandle(const char* file_name) {
|
||||
FILE* Log::CreateOutputHandle(std::string file_name) {
|
||||
// If we're logging anything, we need to open the log file.
|
||||
if (!Log::InitLogAtStart()) {
|
||||
return nullptr;
|
||||
} else if (strcmp(file_name, kLogToConsole) == 0) {
|
||||
} else if (Log::IsLoggingToConsole(file_name)) {
|
||||
return stdout;
|
||||
} else if (strcmp(file_name, kLogToTemporaryFile) == 0) {
|
||||
} else if (Log::IsLoggingToTemporaryFile(file_name)) {
|
||||
return base::OS::OpenTemporaryFile();
|
||||
} else {
|
||||
return base::OS::FOpen(file_name, base::OS::LogFileOpenMode);
|
||||
return base::OS::FOpen(file_name.c_str(), base::OS::LogFileOpenMode);
|
||||
}
|
||||
}
|
||||
|
||||
Log::Log(Logger* logger, const char* file_name)
|
||||
: output_handle_(Log::CreateOutputHandle(file_name)),
|
||||
// static
|
||||
bool Log::IsLoggingToConsole(std::string file_name) {
|
||||
return file_name.compare(Log::kLogToConsole) == 0;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Log::IsLoggingToTemporaryFile(std::string file_name) {
|
||||
return file_name.compare(Log::kLogToTemporaryFile) == 0;
|
||||
}
|
||||
|
||||
Log::Log(std::string file_name)
|
||||
: file_name_(file_name),
|
||||
output_handle_(Log::CreateOutputHandle(file_name)),
|
||||
os_(output_handle_ == nullptr ? stdout : output_handle_),
|
||||
is_enabled_(output_handle_ != nullptr),
|
||||
format_buffer_(NewArray<char>(kMessageBufferSize)),
|
||||
logger_(logger) {
|
||||
format_buffer_(NewArray<char>(kMessageBufferSize)) {
|
||||
// --log-all enables all the log flags.
|
||||
if (FLAG_log_all) {
|
||||
FLAG_log_api = true;
|
||||
@ -56,7 +66,13 @@ Log::Log(Logger* logger, const char* file_name)
|
||||
if (FLAG_prof) FLAG_log_code = true;
|
||||
|
||||
if (output_handle_ == nullptr) return;
|
||||
Log::MessageBuilder msg(this);
|
||||
WriteLogHeader();
|
||||
}
|
||||
|
||||
void Log::WriteLogHeader() {
|
||||
std::unique_ptr<Log::MessageBuilder> msg_ptr = NewMessageBuilder();
|
||||
if (!msg_ptr) return;
|
||||
Log::MessageBuilder& msg = *msg_ptr.get();
|
||||
LogSeparator kNext = LogSeparator::kSeparator;
|
||||
msg << "v8-version" << kNext << Version::GetMajor() << kNext
|
||||
<< Version::GetMinor() << kNext << Version::GetBuild() << kNext
|
||||
@ -83,20 +99,17 @@ FILE* Log::Close() {
|
||||
base::MutexGuard guard(&mutex_);
|
||||
FILE* result = nullptr;
|
||||
if (output_handle_ != nullptr) {
|
||||
if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
|
||||
fclose(output_handle_);
|
||||
} else {
|
||||
result = output_handle_;
|
||||
}
|
||||
fflush(output_handle_);
|
||||
result = output_handle_;
|
||||
}
|
||||
output_handle_ = nullptr;
|
||||
|
||||
format_buffer_.reset();
|
||||
|
||||
is_enabled_.store(false, std::memory_order_relaxed);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Log::file_name() const { return file_name_; }
|
||||
|
||||
Log::MessageBuilder::MessageBuilder(Log* log)
|
||||
: log_(log), lock_guard_(&log_->mutex_) {
|
||||
DCHECK_NOT_NULL(log_->format_buffer_.get());
|
||||
|
@ -30,22 +30,27 @@ enum class LogSeparator { kSeparator };
|
||||
// Functions and data for performing output of log messages.
|
||||
class Log {
|
||||
public:
|
||||
Log(Logger* log, const char* log_file_name);
|
||||
explicit Log(std::string log_file_name);
|
||||
|
||||
static bool InitLogAtStart() {
|
||||
return FLAG_log || FLAG_log_api || FLAG_log_code || FLAG_log_handles ||
|
||||
FLAG_log_suspect || FLAG_ll_prof || FLAG_perf_basic_prof ||
|
||||
FLAG_perf_prof || FLAG_log_source_code || FLAG_gdbjit ||
|
||||
FLAG_log_internal_timer_events || FLAG_prof_cpp || FLAG_trace_ic ||
|
||||
FLAG_log_function_events || FLAG_trace_zone_stats ||
|
||||
return FLAG_log || FLAG_log_all || FLAG_log_api || FLAG_log_code ||
|
||||
FLAG_log_handles || FLAG_log_suspect || FLAG_ll_prof ||
|
||||
FLAG_perf_basic_prof || FLAG_perf_prof || FLAG_log_source_code ||
|
||||
FLAG_gdbjit || FLAG_log_internal_timer_events || FLAG_prof_cpp ||
|
||||
FLAG_trace_ic || FLAG_log_function_events || FLAG_trace_zone_stats ||
|
||||
FLAG_turbo_profiling_log_builtins;
|
||||
}
|
||||
|
||||
V8_EXPORT_PRIVATE static bool IsLoggingToConsole(std::string file_name);
|
||||
V8_EXPORT_PRIVATE static bool IsLoggingToTemporaryFile(std::string file_name);
|
||||
|
||||
// Frees all resources acquired in Initialize and Open... functions.
|
||||
// When a temporary file is used for the log, returns its stream descriptor,
|
||||
// leaving the file open.
|
||||
FILE* Close();
|
||||
|
||||
std::string file_name() const;
|
||||
|
||||
// Returns whether logging is enabled.
|
||||
bool IsEnabled() { return is_enabled_.load(std::memory_order_relaxed); }
|
||||
|
||||
@ -109,19 +114,15 @@ class Log {
|
||||
std::unique_ptr<Log::MessageBuilder> NewMessageBuilder();
|
||||
|
||||
private:
|
||||
static FILE* CreateOutputHandle(const char* file_name);
|
||||
static FILE* CreateOutputHandle(std::string file_name);
|
||||
|
||||
// Implementation of writing to a log file.
|
||||
int WriteToFile(const char* msg, int length) {
|
||||
DCHECK_NOT_NULL(output_handle_);
|
||||
os_.write(msg, length);
|
||||
DCHECK(!os_.bad());
|
||||
return length;
|
||||
}
|
||||
void WriteLogHeader();
|
||||
|
||||
std::string file_name_;
|
||||
// When logging is active output_handle_ is used to store a pointer to log
|
||||
// destination. mutex_ should be acquired before using output_handle_.
|
||||
FILE* output_handle_;
|
||||
|
||||
OFStream os_;
|
||||
|
||||
// Stores whether logging is enabled.
|
||||
@ -134,10 +135,6 @@ class Log {
|
||||
// Buffer used for formatting log messages. This is a singleton buffer and
|
||||
// mutex_ should be acquired before using it.
|
||||
std::unique_ptr<char[]> format_buffer_;
|
||||
|
||||
Logger* logger_;
|
||||
|
||||
friend class Logger;
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -1974,16 +1974,13 @@ void Logger::LogAllMaps() {
|
||||
}
|
||||
}
|
||||
|
||||
static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT
|
||||
Isolate* isolate) {
|
||||
if (FLAG_logfile_per_isolate) {
|
||||
os << "isolate-" << isolate << "-" << base::OS::GetCurrentProcessId()
|
||||
<< "-";
|
||||
}
|
||||
static void AddIsolateIdIfNeeded(std::ostream& os, Isolate* isolate) {
|
||||
if (!FLAG_logfile_per_isolate) return;
|
||||
os << "isolate-" << isolate << "-" << base::OS::GetCurrentProcessId() << "-";
|
||||
}
|
||||
|
||||
static void PrepareLogFileName(std::ostream& os, // NOLINT
|
||||
Isolate* isolate, const char* file_name) {
|
||||
static void PrepareLogFileName(std::ostream& os, Isolate* isolate,
|
||||
const char* file_name) {
|
||||
int dir_separator_count = 0;
|
||||
for (const char* p = file_name; *p; p++) {
|
||||
if (base::OS::isDirectorySeparator(*p)) dir_separator_count++;
|
||||
@ -2032,9 +2029,8 @@ bool Logger::SetUp(Isolate* isolate) {
|
||||
is_initialized_ = true;
|
||||
|
||||
std::ostringstream log_file_name;
|
||||
std::ostringstream source_log_file_name;
|
||||
PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
|
||||
log_ = std::make_unique<Log>(this, log_file_name.str().c_str());
|
||||
log_ = std::make_unique<Log>(log_file_name.str());
|
||||
|
||||
#if V8_OS_LINUX
|
||||
if (FLAG_perf_basic_prof) {
|
||||
@ -2063,9 +2059,7 @@ bool Logger::SetUp(Isolate* isolate) {
|
||||
|
||||
ticker_ = std::make_unique<Ticker>(isolate, FLAG_prof_sampling_interval);
|
||||
|
||||
if (Log::InitLogAtStart()) {
|
||||
is_logging_ = true;
|
||||
}
|
||||
if (Log::InitLogAtStart()) is_logging_ = true;
|
||||
|
||||
timer_.Start();
|
||||
|
||||
@ -2075,9 +2069,7 @@ bool Logger::SetUp(Isolate* isolate) {
|
||||
profiler_->Engage();
|
||||
}
|
||||
|
||||
if (is_logging_) {
|
||||
AddCodeEventListener(this);
|
||||
}
|
||||
if (is_logging_) AddCodeEventListener(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2104,6 +2096,7 @@ void Logger::SetCodeEventHandler(uint32_t options,
|
||||
}
|
||||
|
||||
sampler::Sampler* Logger::sampler() { return ticker_.get(); }
|
||||
std::string Logger::file_name() const { return log_.get()->file_name(); }
|
||||
|
||||
void Logger::StopProfilerThread() {
|
||||
if (profiler_ != nullptr) {
|
||||
@ -2112,14 +2105,16 @@ void Logger::StopProfilerThread() {
|
||||
}
|
||||
}
|
||||
|
||||
FILE* Logger::TearDown() {
|
||||
FILE* Logger::TearDownAndGetLogFile() {
|
||||
if (!is_initialized_) return nullptr;
|
||||
is_initialized_ = false;
|
||||
is_logging_ = false;
|
||||
|
||||
// Stop the profiler thread before closing the file.
|
||||
StopProfilerThread();
|
||||
|
||||
ticker_.reset();
|
||||
timer_.Stop();
|
||||
|
||||
#if V8_OS_LINUX
|
||||
if (perf_basic_logger_) {
|
||||
|
@ -126,18 +126,19 @@ class Logger : public CodeEventListener {
|
||||
// Acquires resources for logging if the right flags are set.
|
||||
bool SetUp(Isolate* isolate);
|
||||
|
||||
// Frees resources acquired in SetUp.
|
||||
// When a temporary file is used for the log, returns its stream descriptor,
|
||||
// leaving the file open.
|
||||
V8_EXPORT_PRIVATE FILE* TearDownAndGetLogFile();
|
||||
|
||||
// Sets the current code event handler.
|
||||
void SetCodeEventHandler(uint32_t options, JitCodeEventHandler event_handler);
|
||||
|
||||
sampler::Sampler* sampler();
|
||||
V8_EXPORT_PRIVATE std::string file_name() const;
|
||||
|
||||
V8_EXPORT_PRIVATE void StopProfilerThread();
|
||||
|
||||
// Frees resources acquired in SetUp.
|
||||
// When a temporary file is used for the log, returns its stream descriptor,
|
||||
// leaving the file open.
|
||||
V8_EXPORT_PRIVATE FILE* TearDown();
|
||||
|
||||
// Emits an event with a string value -> (name, value).
|
||||
V8_EXPORT_PRIVATE void StringEvent(const char* name, const char* value);
|
||||
|
||||
|
@ -83,8 +83,8 @@ class ScopedLoggerInitializer {
|
||||
|
||||
~ScopedLoggerInitializer() {
|
||||
env_->Exit();
|
||||
logger_->TearDown();
|
||||
if (temp_file_ != nullptr) fclose(temp_file_);
|
||||
FILE* log_file = logger_->TearDownAndGetLogFile();
|
||||
if (log_file != nullptr) fclose(log_file);
|
||||
i::FLAG_prof = saved_prof_;
|
||||
i::FLAG_log = saved_log_;
|
||||
}
|
||||
@ -203,9 +203,8 @@ class ScopedLoggerInitializer {
|
||||
|
||||
private:
|
||||
FILE* StopLoggingGetTempFile() {
|
||||
temp_file_ = logger_->TearDown();
|
||||
temp_file_ = logger_->TearDownAndGetLogFile();
|
||||
CHECK(temp_file_);
|
||||
fflush(temp_file_);
|
||||
rewind(temp_file_);
|
||||
return temp_file_;
|
||||
}
|
||||
|
25
test/mjsunit/tools/log.js
Normal file
25
test/mjsunit/tools/log.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --log-all --log --no-stress-opt
|
||||
|
||||
function testFunctionWithFunnyName(o) {
|
||||
return o.a;
|
||||
}
|
||||
|
||||
(function testLoopWithFunnyName() {
|
||||
const o = {a:1};
|
||||
let result = 0;
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
result += testFunctionWithFunnyName(o);
|
||||
}
|
||||
})();
|
||||
|
||||
const log = d8.log.getAndStop();
|
||||
|
||||
// Check that we have a minimally working log file.
|
||||
assertTrue(log.length > 0);
|
||||
assertTrue(log.indexOf('v8-version') == 0);
|
||||
assertTrue(log.indexOf('testFunctionWithFunnyName') >= 10);
|
||||
assertTrue(log.indexOf('testLoopWithFunnyName') >= 10);
|
Loading…
Reference in New Issue
Block a user