1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/disk_cache/blockfile/trace.h" 6 7#include <stdio.h> 8#if defined(OS_WIN) 9#include <windows.h> 10#endif 11 12#include "base/lazy_instance.h" 13#include "base/logging.h" 14#include "base/synchronization/lock.h" 15#include "net/disk_cache/blockfile/stress_support.h" 16 17// Change this value to 1 to enable tracing on a release build. By default, 18// tracing is enabled only on debug builds. 19#define ENABLE_TRACING 0 20 21#ifndef NDEBUG 22#undef ENABLE_TRACING 23#define ENABLE_TRACING 1 24#endif 25 26namespace { 27 28const int kEntrySize = 12 * sizeof(size_t); 29#if defined(NET_BUILD_STRESS_CACHE) 30const int kNumberOfEntries = 500000; 31#else 32const int kNumberOfEntries = 5000; // 240 KB on 32bit, 480 KB on 64bit 33#endif 34 35bool s_trace_enabled = false; 36base::LazyInstance<base::Lock>::Leaky s_lock = LAZY_INSTANCE_INITIALIZER; 37 38struct TraceBuffer { 39 int num_traces; 40 int current; 41 char buffer[kNumberOfEntries][kEntrySize]; 42}; 43 44#if ENABLE_TRACING 45void DebugOutput(const char* msg) { 46#if defined(OS_WIN) 47 OutputDebugStringA(msg); 48#else 49 NOTIMPLEMENTED(); 50#endif 51} 52#endif // ENABLE_TRACING 53 54} // namespace 55 56namespace disk_cache { 57 58// s_trace_buffer and s_trace_object are not singletons because I want the 59// buffer to be destroyed and re-created when the last user goes away, and it 60// must be straightforward to access the buffer from the debugger. 61static TraceObject* s_trace_object = NULL; 62 63// Static. 64TraceObject* TraceObject::GetTraceObject() { 65 base::AutoLock lock(s_lock.Get()); 66 67 if (s_trace_object) 68 return s_trace_object; 69 70 s_trace_object = new TraceObject(); 71 return s_trace_object; 72} 73 74TraceObject::TraceObject() { 75 InitTrace(); 76} 77 78TraceObject::~TraceObject() { 79 DestroyTrace(); 80} 81 82void TraceObject::EnableTracing(bool enable) { 83 base::AutoLock lock(s_lock.Get()); 84 s_trace_enabled = enable; 85} 86 87#if ENABLE_TRACING 88 89static TraceBuffer* s_trace_buffer = NULL; 90 91void InitTrace(void) { 92 s_trace_enabled = true; 93 if (s_trace_buffer) 94 return; 95 96 s_trace_buffer = new TraceBuffer; 97 memset(s_trace_buffer, 0, sizeof(*s_trace_buffer)); 98} 99 100void DestroyTrace(void) { 101 base::AutoLock lock(s_lock.Get()); 102 103 delete s_trace_buffer; 104 s_trace_buffer = NULL; 105 s_trace_object = NULL; 106} 107 108void Trace(const char* format, ...) { 109 if (!s_trace_buffer || !s_trace_enabled) 110 return; 111 112 va_list ap; 113 va_start(ap, format); 114 char line[kEntrySize + 2]; 115 116#if defined(OS_WIN) 117 vsprintf_s(line, format, ap); 118#else 119 vsnprintf(line, kEntrySize, format, ap); 120#endif 121 122#if defined(DISK_CACHE_TRACE_TO_LOG) 123 line[kEntrySize] = '\0'; 124 LOG(INFO) << line; 125#endif 126 127 va_end(ap); 128 129 { 130 base::AutoLock lock(s_lock.Get()); 131 if (!s_trace_buffer || !s_trace_enabled) 132 return; 133 134 memcpy(s_trace_buffer->buffer[s_trace_buffer->current], line, kEntrySize); 135 136 s_trace_buffer->num_traces++; 137 s_trace_buffer->current++; 138 if (s_trace_buffer->current == kNumberOfEntries) 139 s_trace_buffer->current = 0; 140 } 141} 142 143// Writes the last num_traces to the debugger output. 144void DumpTrace(int num_traces) { 145 DCHECK(s_trace_buffer); 146 DebugOutput("Last traces:\n"); 147 148 if (num_traces > kNumberOfEntries || num_traces < 0) 149 num_traces = kNumberOfEntries; 150 151 if (s_trace_buffer->num_traces) { 152 char line[kEntrySize + 2]; 153 154 int current = s_trace_buffer->current - num_traces; 155 if (current < 0) 156 current += kNumberOfEntries; 157 158 for (int i = 0; i < num_traces; i++) { 159 memcpy(line, s_trace_buffer->buffer[current], kEntrySize); 160 line[kEntrySize] = '\0'; 161 size_t length = strlen(line); 162 if (length) { 163 line[length] = '\n'; 164 line[length + 1] = '\0'; 165 DebugOutput(line); 166 } 167 168 current++; 169 if (current == kNumberOfEntries) 170 current = 0; 171 } 172 } 173 174 DebugOutput("End of Traces\n"); 175} 176 177#else // ENABLE_TRACING 178 179void InitTrace(void) { 180 return; 181} 182 183void DestroyTrace(void) { 184 s_trace_object = NULL; 185} 186 187void Trace(const char* format, ...) { 188} 189 190#endif // ENABLE_TRACING 191 192} // namespace disk_cache 193