| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/disk_cache/blockfile/trace.h" |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #if defined(OS_WIN) |
| #include <windows.h> |
| #endif |
| |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/synchronization/lock.h" |
| #include "net/disk_cache/blockfile/stress_support.h" |
| #include "starboard/common/string.h" |
| #include "starboard/memory.h" |
| #include "starboard/types.h" |
| |
| // Change this value to 1 to enable tracing on a release build. By default, |
| // tracing is enabled only on debug builds. |
| #define ENABLE_TRACING 0 |
| |
| #ifndef NDEBUG |
| #undef ENABLE_TRACING |
| #define ENABLE_TRACING 1 |
| #endif |
| |
| namespace { |
| |
| const int kEntrySize = 12 * sizeof(size_t); |
| #if defined(NET_BUILD_STRESS_CACHE) |
| const int kNumberOfEntries = 500000; |
| #else |
| const int kNumberOfEntries = 5000; // 240 KB on 32bit, 480 KB on 64bit |
| #endif |
| |
| bool s_trace_enabled = false; |
| base::LazyInstance<base::Lock>::Leaky s_lock = LAZY_INSTANCE_INITIALIZER; |
| |
| struct TraceBuffer { |
| int num_traces; |
| int current; |
| char buffer[kNumberOfEntries][kEntrySize]; |
| }; |
| |
| #if ENABLE_TRACING |
| void DebugOutput(const char* msg) { |
| #if defined(OS_WIN) |
| OutputDebugStringA(msg); |
| #else |
| NOTIMPLEMENTED(); |
| #endif |
| } |
| #endif // ENABLE_TRACING |
| |
| } // namespace |
| |
| namespace disk_cache { |
| |
| // s_trace_buffer and s_trace_object are not singletons because I want the |
| // buffer to be destroyed and re-created when the last user goes away, and it |
| // must be straightforward to access the buffer from the debugger. |
| static TraceObject* s_trace_object = NULL; |
| |
| // Static. |
| TraceObject* TraceObject::GetTraceObject() { |
| base::AutoLock lock(s_lock.Get()); |
| |
| if (s_trace_object) |
| return s_trace_object; |
| |
| s_trace_object = new TraceObject(); |
| return s_trace_object; |
| } |
| |
| TraceObject::TraceObject() { |
| InitTrace(); |
| } |
| |
| TraceObject::~TraceObject() { |
| DestroyTrace(); |
| } |
| |
| void TraceObject::EnableTracing(bool enable) { |
| base::AutoLock lock(s_lock.Get()); |
| s_trace_enabled = enable; |
| } |
| |
| #if ENABLE_TRACING |
| |
| static TraceBuffer* s_trace_buffer = NULL; |
| |
| void InitTrace(void) { |
| s_trace_enabled = true; |
| if (s_trace_buffer) |
| return; |
| |
| s_trace_buffer = new TraceBuffer; |
| SbMemorySet(s_trace_buffer, 0, sizeof(*s_trace_buffer)); |
| } |
| |
| void DestroyTrace(void) { |
| base::AutoLock lock(s_lock.Get()); |
| |
| delete s_trace_buffer; |
| s_trace_buffer = NULL; |
| s_trace_object = NULL; |
| } |
| |
| void Trace(const char* format, ...) { |
| if (!s_trace_buffer || !s_trace_enabled) |
| return; |
| |
| va_list ap; |
| va_start(ap, format); |
| char line[kEntrySize + 2]; |
| |
| #if defined(OS_WIN) |
| vsprintf_s(line, format, ap); |
| #else |
| vsnprintf(line, kEntrySize, format, ap); |
| #endif |
| |
| #if defined(DISK_CACHE_TRACE_TO_LOG) |
| line[kEntrySize] = '\0'; |
| LOG(INFO) << line; |
| #endif |
| |
| va_end(ap); |
| |
| { |
| base::AutoLock lock(s_lock.Get()); |
| if (!s_trace_buffer || !s_trace_enabled) |
| return; |
| |
| SbMemoryCopy(s_trace_buffer->buffer[s_trace_buffer->current], line, |
| kEntrySize); |
| |
| s_trace_buffer->num_traces++; |
| s_trace_buffer->current++; |
| if (s_trace_buffer->current == kNumberOfEntries) |
| s_trace_buffer->current = 0; |
| } |
| } |
| |
| // Writes the last num_traces to the debugger output. |
| void DumpTrace(int num_traces) { |
| DCHECK(s_trace_buffer); |
| DebugOutput("Last traces:\n"); |
| |
| if (num_traces > kNumberOfEntries || num_traces < 0) |
| num_traces = kNumberOfEntries; |
| |
| if (s_trace_buffer->num_traces) { |
| char line[kEntrySize + 2]; |
| |
| int current = s_trace_buffer->current - num_traces; |
| if (current < 0) |
| current += kNumberOfEntries; |
| |
| for (int i = 0; i < num_traces; i++) { |
| SbMemoryCopy(line, s_trace_buffer->buffer[current], kEntrySize); |
| line[kEntrySize] = '\0'; |
| size_t length = SbStringGetLength(line); |
| if (length) { |
| line[length] = '\n'; |
| line[length + 1] = '\0'; |
| DebugOutput(line); |
| } |
| |
| current++; |
| if (current == kNumberOfEntries) |
| current = 0; |
| } |
| } |
| |
| DebugOutput("End of Traces\n"); |
| } |
| |
| #else // ENABLE_TRACING |
| |
| void InitTrace(void) { |
| return; |
| } |
| |
| void DestroyTrace(void) { |
| s_trace_object = NULL; |
| } |
| |
| void Trace(const char* format, ...) { |
| } |
| |
| #endif // ENABLE_TRACING |
| |
| } // namespace disk_cache |