📄 log.cc.svn-base
字号:
// Copyright 2006-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include <stdarg.h>#include "v8.h"#include "log.h"#include "platform.h"namespace v8 { namespace internal {#ifdef ENABLE_LOGGING_AND_PROFILING//// Sliding state window. Updates counters to keep track of the last// window of kBufferSize states. This is useful to track where we// spent our time.//class SlidingStateWindow { public: SlidingStateWindow(); ~SlidingStateWindow(); void AddState(StateTag state); private: static const int kBufferSize = 256; int current_index_; bool is_full_; byte buffer_[kBufferSize]; void IncrementStateCounter(StateTag state) { Counters::state_counters[state].Increment(); } void DecrementStateCounter(StateTag state) { Counters::state_counters[state].Decrement(); }};//// The Profiler samples pc and sp values for the main thread.// Each sample is appended to a circular buffer.// An independent thread removes data and writes it to the log.// This design minimizes the time spent in the sampler.//class Profiler: public Thread { public: Profiler(); void Engage(); void Disengage(); // Inserts collected profiling data into buffer. void Insert(TickSample* sample) { if (Succ(head_) == tail_) { overflow_ = true; } else { buffer_[head_] = *sample; head_ = Succ(head_); buffer_semaphore_->Signal(); // Tell we have an element. } } // Waits for a signal and removes profiling data. bool Remove(TickSample* sample) { buffer_semaphore_->Wait(); // Wait for an element. *sample = buffer_[tail_]; bool result = overflow_; tail_ = Succ(tail_); overflow_ = false; return result; } void Run(); private: // Returns the next index in the cyclic buffer. int Succ(int index) { return (index + 1) % kBufferSize; } // Cyclic buffer for communicating profiling samples // between the signal handler and the worker thread. static const int kBufferSize = 128; TickSample buffer_[kBufferSize]; // Buffer storage. int head_; // Index to the buffer head. int tail_; // Index to the buffer tail. bool overflow_; // Tell whether a buffer overflow has occurred. Semaphore* buffer_semaphore_; // Sempahore used for buffer synchronization. // Tells whether worker thread should continue running. bool running_;};//// Ticker used to provide ticks to the profiler and the sliding state// window.//class Ticker: public Sampler { public: explicit Ticker(int interval): Sampler(interval, FLAG_prof), window_(NULL), profiler_(NULL) {} ~Ticker() { if (IsActive()) Stop(); } void Tick(TickSample* sample) { if (profiler_) profiler_->Insert(sample); if (window_) window_->AddState(sample->state); } void SetWindow(SlidingStateWindow* window) { window_ = window; if (!IsActive()) Start(); } void ClearWindow() { window_ = NULL; if (!profiler_ && IsActive()) Stop(); } void SetProfiler(Profiler* profiler) { profiler_ = profiler; if (!IsActive()) Start(); } void ClearProfiler() { profiler_ = NULL; if (!window_ && IsActive()) Stop(); } private: SlidingStateWindow* window_; Profiler* profiler_;};//// SlidingStateWindow implementation.//SlidingStateWindow::SlidingStateWindow(): current_index_(0), is_full_(false) { for (int i = 0; i < kBufferSize; i++) { buffer_[i] = static_cast<byte>(OTHER); } Logger::ticker_->SetWindow(this);}SlidingStateWindow::~SlidingStateWindow() { Logger::ticker_->ClearWindow();}void SlidingStateWindow::AddState(StateTag state) { if (is_full_) { DecrementStateCounter(static_cast<StateTag>(buffer_[current_index_])); } else if (current_index_ == kBufferSize - 1) { is_full_ = true; } buffer_[current_index_] = static_cast<byte>(state); IncrementStateCounter(state); ASSERT(IsPowerOf2(kBufferSize)); current_index_ = (current_index_ + 1) & (kBufferSize - 1);}//// Profiler implementation.//Profiler::Profiler() { buffer_semaphore_ = OS::CreateSemaphore(0); head_ = 0; tail_ = 0; overflow_ = false; running_ = false;}void Profiler::Engage() { OS::LogSharedLibraryAddresses(); // Start thread processing the profiler buffer. running_ = true; Start(); // Register to get ticks. Logger::ticker_->SetProfiler(this); LOG(StringEvent("profiler", "begin"));}void Profiler::Disengage() { // Stop receiving ticks. Logger::ticker_->ClearProfiler(); // Terminate the worker thread by setting running_ to false, // inserting a fake element in the queue and then wait for // the thread to terminate. running_ = false; TickSample sample; sample.pc = 0; sample.sp = 0; sample.state = OTHER; Insert(&sample); Join(); LOG(StringEvent("profiler", "end"));}void Profiler::Run() { TickSample sample; bool overflow = Logger::profiler_->Remove(&sample); while (running_) { LOG(TickEvent(&sample, overflow)); overflow = Logger::profiler_->Remove(&sample); }}//// Logger class implementation.//Ticker* Logger::ticker_ = NULL;FILE* Logger::logfile_ = NULL;Profiler* Logger::profiler_ = NULL;Mutex* Logger::mutex_ = NULL;VMState* Logger::current_state_ = NULL;SlidingStateWindow* Logger::sliding_state_window_ = NULL;#endif // ENABLE_LOGGING_AND_PROFILINGvoid Logger::Preamble(const char* content) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s", content);#endif}void Logger::StringEvent(const char* name, const char* value) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s,\"%s\"\n", name, value);#endif}void Logger::IntEvent(const char* name, int value) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s,%d\n", name, value);#endif}void Logger::HandleEvent(const char* name, Object** location) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL || !FLAG_log_handles) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s,0x%x\n", name, reinterpret_cast<unsigned int>(location));#endif}#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// FLAG_log_api is true.void Logger::ApiEvent(const char* format, ...) { ASSERT(logfile_ != NULL && FLAG_log_api); ScopedLock sl(mutex_); va_list ap; va_start(ap, format); vfprintf(logfile_, format, ap);}#endifvoid Logger::ApiNamedSecurityCheck(Object* key) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL || !FLAG_log_api) return; if (key->IsString()) { SmartPointer<char> str = String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); ApiEvent("api,check-security,\"%s\"\n", *str); } else if (key->IsUndefined()) { ApiEvent("api,check-security,undefined\n"); } else { ApiEvent("api,check-security,['no-name']\n"); }#endif}void Logger::SharedLibraryEvent(const char* library_path, unsigned start, unsigned end) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL || !FLAG_prof) return; ScopedLock sl(mutex_); fprintf(logfile_, "shared-library,\"%s\",0x%08x,0x%08x\n", library_path, start, end);#endif}void Logger::SharedLibraryEvent(const wchar_t* library_path, unsigned start, unsigned end) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL || !FLAG_prof) return; ScopedLock sl(mutex_); fprintf(logfile_, "shared-library,\"%ls\",0x%08x,0x%08x\n", library_path, start, end);#endif}#ifdef ENABLE_LOGGING_AND_PROFILINGvoid Logger::LogRegExpSource(Handle<JSRegExp> regexp) { // Prints "/" + re.source + "/" + // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"") Handle<Object> source = GetProperty(regexp, "source"); if (!source->IsString()) { fprintf(logfile_, "no source"); return; } Handle<String> source_string = Handle<String>::cast(source); SmartPointer<uc16> cstring = source_string->ToWideCString(); fprintf(logfile_, "/"); for (int i = 0, n = source_string->length(); i < n; i++) { uc16 c = cstring[i]; if (c < 32 || (c > 126 && c <= 255)) { fprintf(logfile_, "\\x%02x", c); } else if (c > 255) { fprintf(logfile_, "\\u%04x", c); } else { fprintf(logfile_, "%lc", c); } } fprintf(logfile_, "/"); // global flag Handle<Object> global = GetProperty(regexp, "global"); if (global->IsTrue()) { fprintf(logfile_, "g"); } // ignorecase flag Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase"); if (ignorecase->IsTrue()) { fprintf(logfile_, "i"); } // multiline flag Handle<Object> multiline = GetProperty(regexp, "multiline"); if (multiline->IsTrue()) { fprintf(logfile_, "m"); }}#endif // ENABLE_LOGGING_AND_PROFILINGvoid Logger::RegExpCompileEvent(Handle<JSRegExp> regexp) {#ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL || !FLAG_log_regexp) return; ScopedLock sl(mutex_); fprintf(logfile_, "regexp-compile,"); LogRegExpSource(regexp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -