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/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/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 26 namespace { 27 28 const int kEntrySize = 12 * sizeof(size_t); 29 #if defined(NET_BUILD_STRESS_CACHE) 30 const int kNumberOfEntries = 500000; 31 #else 32 const int kNumberOfEntries = 5000; // 240 KB on 32bit, 480 KB on 64bit 33 #endif 34 35 bool s_trace_enabled = false; 36 base::LazyInstance<base::Lock>::Leaky s_lock = LAZY_INSTANCE_INITIALIZER; 37 38 struct TraceBuffer { 39 int num_traces; 40 int current; 41 char buffer[kNumberOfEntries][kEntrySize]; 42 }; 43 44 #if ENABLE_TRACING 45 void 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 56 namespace 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. 61 static TraceObject* s_trace_object = NULL; 62 63 // Static. 64 TraceObject* 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 74 TraceObject::TraceObject() { 75 InitTrace(); 76 } 77 78 TraceObject::~TraceObject() { 79 DestroyTrace(); 80 } 81 82 void TraceObject::EnableTracing(bool enable) { 83 base::AutoLock lock(s_lock.Get()); 84 s_trace_enabled = enable; 85 } 86 87 #if ENABLE_TRACING 88 89 static TraceBuffer* s_trace_buffer = NULL; 90 91 void 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 100 void 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 108 void 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. 144 void 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 179 void InitTrace(void) { 180 return; 181 } 182 183 void DestroyTrace(void) { 184 s_trace_object = NULL; 185 } 186 187 void Trace(const char* format, ...) { 188 } 189 190 #endif // ENABLE_TRACING 191 192 } // namespace disk_cache 193