michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "base/trace_event.h" michael@0: michael@0: #include "base/file_path.h" michael@0: #include "base/file_util.h" michael@0: #include "base/path_service.h" michael@0: #include "base/platform_thread.h" michael@0: #include "base/process_util.h" michael@0: #include "base/string_util.h" michael@0: #include "base/time.h" michael@0: michael@0: #define USE_UNRELIABLE_NOW michael@0: michael@0: namespace base { michael@0: michael@0: static const char* kEventTypeNames[] = { michael@0: "BEGIN", michael@0: "END", michael@0: "INSTANT" michael@0: }; michael@0: michael@0: static const FilePath::CharType* kLogFileName = michael@0: FILE_PATH_LITERAL("trace_%d.log"); michael@0: michael@0: TraceLog::TraceLog() : enabled_(false), log_file_(NULL) { michael@0: base::ProcessHandle proc = base::GetCurrentProcessHandle(); michael@0: process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc)); michael@0: } michael@0: michael@0: TraceLog::~TraceLog() { michael@0: Stop(); michael@0: } michael@0: michael@0: // static michael@0: bool TraceLog::IsTracing() { michael@0: TraceLog* trace = Singleton::get(); michael@0: return trace->enabled_; michael@0: } michael@0: michael@0: // static michael@0: bool TraceLog::StartTracing() { michael@0: TraceLog* trace = Singleton::get(); michael@0: return trace->Start(); michael@0: } michael@0: michael@0: bool TraceLog::Start() { michael@0: if (enabled_) michael@0: return true; michael@0: enabled_ = OpenLogFile(); michael@0: if (enabled_) { michael@0: Log("var raw_trace_events = [\n"); michael@0: trace_start_time_ = TimeTicks::Now(); michael@0: timer_.Start(TimeDelta::FromMilliseconds(250), this, &TraceLog::Heartbeat); michael@0: } michael@0: return enabled_; michael@0: } michael@0: michael@0: // static michael@0: void TraceLog::StopTracing() { michael@0: TraceLog* trace = Singleton::get(); michael@0: return trace->Stop(); michael@0: } michael@0: michael@0: void TraceLog::Stop() { michael@0: if (enabled_) { michael@0: enabled_ = false; michael@0: Log("];\n"); michael@0: CloseLogFile(); michael@0: timer_.Stop(); michael@0: } michael@0: } michael@0: michael@0: void TraceLog::Heartbeat() { michael@0: std::string cpu = StringPrintf("%d", process_metrics_->GetCPUUsage()); michael@0: TRACE_EVENT_INSTANT("heartbeat.cpu", 0, cpu); michael@0: } michael@0: michael@0: void TraceLog::CloseLogFile() { michael@0: if (log_file_) { michael@0: file_util::CloseFile(log_file_); michael@0: } michael@0: } michael@0: michael@0: bool TraceLog::OpenLogFile() { michael@0: FilePath::StringType pid_filename = michael@0: StringPrintf(kLogFileName, base::GetCurrentProcId()); michael@0: FilePath log_file_path; michael@0: if (!PathService::Get(base::DIR_EXE, &log_file_path)) michael@0: return false; michael@0: log_file_path = log_file_path.Append(pid_filename); michael@0: log_file_ = file_util::OpenFile(log_file_path, "a"); michael@0: if (!log_file_) { michael@0: // try the current directory michael@0: log_file_ = file_util::OpenFile(FilePath(pid_filename), "a"); michael@0: if (!log_file_) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void TraceLog::Trace(const std::string& name, michael@0: EventType type, michael@0: const void* id, michael@0: const std::wstring& extra, michael@0: const char* file, michael@0: int line) { michael@0: if (!enabled_) michael@0: return; michael@0: Trace(name, type, id, WideToUTF8(extra), file, line); michael@0: } michael@0: michael@0: void TraceLog::Trace(const std::string& name, michael@0: EventType type, michael@0: const void* id, michael@0: const std::string& extra, michael@0: const char* file, michael@0: int line) { michael@0: if (!enabled_) michael@0: return; michael@0: michael@0: #ifdef USE_UNRELIABLE_NOW michael@0: TimeTicks tick = TimeTicks::HighResNow(); michael@0: #else michael@0: TimeTicks tick = TimeTicks::Now(); michael@0: #endif michael@0: TimeDelta delta = tick - trace_start_time_; michael@0: int64_t usec = delta.InMicroseconds(); michael@0: std::string msg = michael@0: StringPrintf("{'pid':'0x%lx', 'tid':'0x%lx', 'type':'%s', " michael@0: "'name':'%s', 'id':'0x%lx', 'extra':'%s', 'file':'%s', " michael@0: "'line_number':'%d', 'usec_begin': %I64d},\n", michael@0: base::GetCurrentProcId(), michael@0: PlatformThread::CurrentId(), michael@0: kEventTypeNames[type], michael@0: name.c_str(), michael@0: id, michael@0: extra.c_str(), michael@0: file, michael@0: line, michael@0: usec); michael@0: michael@0: Log(msg); michael@0: } michael@0: michael@0: void TraceLog::Log(const std::string& msg) { michael@0: AutoLock lock(file_lock_); michael@0: michael@0: fprintf(log_file_, "%s", msg.c_str()); michael@0: } michael@0: michael@0: } // namespace base