OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "log-utils.h" | 30 #include "log-utils.h" |
| 31 #include "string-stream.h" |
31 | 32 |
32 namespace v8 { | 33 namespace v8 { |
33 namespace internal { | 34 namespace internal { |
34 | 35 |
35 #ifdef ENABLE_LOGGING_AND_PROFILING | 36 #ifdef ENABLE_LOGGING_AND_PROFILING |
36 | 37 |
37 LogDynamicBuffer::LogDynamicBuffer( | 38 LogDynamicBuffer::LogDynamicBuffer( |
38 int block_size, int max_size, const char* seal, int seal_size) | 39 int block_size, int max_size, const char* seal, int seal_size) |
39 : block_size_(block_size), | 40 : block_size_(block_size), |
40 max_size_(max_size - (max_size % block_size_)), | 41 max_size_(max_size - (max_size % block_size_)), |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 data_pos += write_size; | 112 data_pos += write_size; |
112 if (block_write_pos_ == block_size_) { | 113 if (block_write_pos_ == block_size_) { |
113 block_write_pos_ = 0; | 114 block_write_pos_ = 0; |
114 AllocateBlock(++block_index_); | 115 AllocateBlock(++block_index_); |
115 } | 116 } |
116 } | 117 } |
117 write_pos_ += data_size; | 118 write_pos_ += data_size; |
118 return data_size; | 119 return data_size; |
119 } | 120 } |
120 | 121 |
| 122 // Must be the same message as in Logger::PauseProfiler. |
| 123 const char* const Log::kDynamicBufferSeal = "profiler,\"pause\"\n"; |
121 | 124 |
122 bool Log::is_stopped_ = false; | 125 Log::Log(Logger* logger) |
123 Log::WritePtr Log::Write = NULL; | 126 : write_to_file_(false), |
124 FILE* Log::output_handle_ = NULL; | 127 is_stopped_(false), |
125 FILE* Log::output_code_handle_ = NULL; | 128 output_handle_(NULL), |
126 LogDynamicBuffer* Log::output_buffer_ = NULL; | 129 output_code_handle_(NULL), |
127 // Must be the same message as in Logger::PauseProfiler. | 130 output_buffer_(NULL), |
128 const char* Log::kDynamicBufferSeal = "profiler,\"pause\"\n"; | 131 mutex_(NULL), |
129 Mutex* Log::mutex_ = NULL; | 132 message_buffer_(NULL), |
130 char* Log::message_buffer_ = NULL; | 133 logger_(logger) { |
| 134 } |
131 | 135 |
132 | 136 |
133 void Log::Init() { | 137 static void AddIsolateIdIfNeeded(StringStream* stream) { |
| 138 Isolate* isolate = Isolate::Current(); |
| 139 if (isolate->IsDefaultIsolate()) return; |
| 140 stream->Add("isolate-%p-", isolate); |
| 141 } |
| 142 |
| 143 |
| 144 void Log::Initialize() { |
| 145 #ifdef ENABLE_LOGGING_AND_PROFILING |
134 mutex_ = OS::CreateMutex(); | 146 mutex_ = OS::CreateMutex(); |
135 message_buffer_ = NewArray<char>(kMessageBufferSize); | 147 message_buffer_ = NewArray<char>(kMessageBufferSize); |
| 148 |
| 149 // --log-all enables all the log flags. |
| 150 if (FLAG_log_all) { |
| 151 FLAG_log_runtime = true; |
| 152 FLAG_log_api = true; |
| 153 FLAG_log_code = true; |
| 154 FLAG_log_gc = true; |
| 155 FLAG_log_suspect = true; |
| 156 FLAG_log_handles = true; |
| 157 FLAG_log_regexp = true; |
| 158 } |
| 159 |
| 160 // --prof implies --log-code. |
| 161 if (FLAG_prof) FLAG_log_code = true; |
| 162 |
| 163 // --prof_lazy controls --log-code, implies --noprof_auto. |
| 164 if (FLAG_prof_lazy) { |
| 165 FLAG_log_code = false; |
| 166 FLAG_prof_auto = false; |
| 167 } |
| 168 |
| 169 bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api |
| 170 || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect |
| 171 || FLAG_log_regexp || FLAG_log_state_changes; |
| 172 |
| 173 bool open_log_file = start_logging || FLAG_prof_lazy; |
| 174 |
| 175 // If we're logging anything, we need to open the log file. |
| 176 if (open_log_file) { |
| 177 if (strcmp(FLAG_logfile, "-") == 0) { |
| 178 OpenStdout(); |
| 179 } else if (strcmp(FLAG_logfile, "*") == 0) { |
| 180 OpenMemoryBuffer(); |
| 181 } else { |
| 182 if (strchr(FLAG_logfile, '%') != NULL || |
| 183 !Isolate::Current()->IsDefaultIsolate()) { |
| 184 // If there's a '%' in the log file name we have to expand |
| 185 // placeholders. |
| 186 HeapStringAllocator allocator; |
| 187 StringStream stream(&allocator); |
| 188 AddIsolateIdIfNeeded(&stream); |
| 189 for (const char* p = FLAG_logfile; *p; p++) { |
| 190 if (*p == '%') { |
| 191 p++; |
| 192 switch (*p) { |
| 193 case '\0': |
| 194 // If there's a % at the end of the string we back up |
| 195 // one character so we can escape the loop properly. |
| 196 p--; |
| 197 break; |
| 198 case 't': { |
| 199 // %t expands to the current time in milliseconds. |
| 200 double time = OS::TimeCurrentMillis(); |
| 201 stream.Add("%.0f", FmtElm(time)); |
| 202 break; |
| 203 } |
| 204 case '%': |
| 205 // %% expands (contracts really) to %. |
| 206 stream.Put('%'); |
| 207 break; |
| 208 default: |
| 209 // All other %'s expand to themselves. |
| 210 stream.Put('%'); |
| 211 stream.Put(*p); |
| 212 break; |
| 213 } |
| 214 } else { |
| 215 stream.Put(*p); |
| 216 } |
| 217 } |
| 218 SmartPointer<const char> expanded = stream.ToCString(); |
| 219 OpenFile(*expanded); |
| 220 } else { |
| 221 OpenFile(FLAG_logfile); |
| 222 } |
| 223 } |
| 224 } |
| 225 #endif |
136 } | 226 } |
137 | 227 |
138 | 228 |
139 void Log::OpenStdout() { | 229 void Log::OpenStdout() { |
140 ASSERT(!IsEnabled()); | 230 ASSERT(!IsEnabled()); |
141 output_handle_ = stdout; | 231 output_handle_ = stdout; |
142 Write = WriteToFile; | 232 write_to_file_ = true; |
143 Init(); | |
144 } | 233 } |
145 | 234 |
146 | 235 |
147 static const char kCodeLogExt[] = ".code"; | 236 static const char kCodeLogExt[] = ".code"; |
148 | 237 |
149 | 238 |
150 void Log::OpenFile(const char* name) { | 239 void Log::OpenFile(const char* name) { |
151 ASSERT(!IsEnabled()); | 240 ASSERT(!IsEnabled()); |
152 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); | 241 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); |
| 242 write_to_file_ = true; |
153 if (FLAG_ll_prof) { | 243 if (FLAG_ll_prof) { |
154 // Open a file for logging the contents of code objects so that | 244 // Open a file for logging the contents of code objects so that |
155 // they can be disassembled later. | 245 // they can be disassembled later. |
156 size_t name_len = strlen(name); | 246 size_t name_len = strlen(name); |
157 ScopedVector<char> code_name( | 247 ScopedVector<char> code_name( |
158 static_cast<int>(name_len + sizeof(kCodeLogExt))); | 248 static_cast<int>(name_len + sizeof(kCodeLogExt))); |
159 memcpy(code_name.start(), name, name_len); | 249 memcpy(code_name.start(), name, name_len); |
160 memcpy(code_name.start() + name_len, kCodeLogExt, sizeof(kCodeLogExt)); | 250 memcpy(code_name.start() + name_len, kCodeLogExt, sizeof(kCodeLogExt)); |
161 output_code_handle_ = OS::FOpen(code_name.start(), OS::LogFileOpenMode); | 251 output_code_handle_ = OS::FOpen(code_name.start(), OS::LogFileOpenMode); |
162 } | 252 } |
163 Write = WriteToFile; | |
164 Init(); | |
165 } | 253 } |
166 | 254 |
167 | 255 |
168 void Log::OpenMemoryBuffer() { | 256 void Log::OpenMemoryBuffer() { |
169 ASSERT(!IsEnabled()); | 257 ASSERT(!IsEnabled()); |
170 output_buffer_ = new LogDynamicBuffer( | 258 output_buffer_ = new LogDynamicBuffer( |
171 kDynamicBufferBlockSize, kMaxDynamicBufferSize, | 259 kDynamicBufferBlockSize, kMaxDynamicBufferSize, |
172 kDynamicBufferSeal, StrLength(kDynamicBufferSeal)); | 260 kDynamicBufferSeal, StrLength(kDynamicBufferSeal)); |
173 Write = WriteToMemory; | 261 write_to_file_ = false; |
174 Init(); | |
175 } | 262 } |
176 | 263 |
177 | 264 |
178 void Log::Close() { | 265 void Log::Close() { |
179 if (Write == WriteToFile) { | 266 if (write_to_file_) { |
180 if (output_handle_ != NULL) fclose(output_handle_); | 267 if (output_handle_ != NULL) fclose(output_handle_); |
181 output_handle_ = NULL; | 268 output_handle_ = NULL; |
182 if (output_code_handle_ != NULL) fclose(output_code_handle_); | 269 if (output_code_handle_ != NULL) fclose(output_code_handle_); |
183 output_code_handle_ = NULL; | 270 output_code_handle_ = NULL; |
184 } else if (Write == WriteToMemory) { | 271 } else { |
185 delete output_buffer_; | 272 delete output_buffer_; |
186 output_buffer_ = NULL; | 273 output_buffer_ = NULL; |
187 } else { | |
188 ASSERT(Write == NULL); | |
189 } | 274 } |
190 Write = NULL; | |
191 | 275 |
192 DeleteArray(message_buffer_); | 276 DeleteArray(message_buffer_); |
193 message_buffer_ = NULL; | 277 message_buffer_ = NULL; |
194 | 278 |
195 delete mutex_; | 279 delete mutex_; |
196 mutex_ = NULL; | 280 mutex_ = NULL; |
197 | 281 |
198 is_stopped_ = false; | 282 is_stopped_ = false; |
199 } | 283 } |
200 | 284 |
201 | 285 |
202 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { | 286 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { |
203 if (Write != WriteToMemory) return 0; | 287 if (write_to_file_) return 0; |
204 ASSERT(output_buffer_ != NULL); | 288 ASSERT(output_buffer_ != NULL); |
205 ASSERT(from_pos >= 0); | 289 ASSERT(from_pos >= 0); |
206 ASSERT(max_size >= 0); | 290 ASSERT(max_size >= 0); |
207 int actual_size = output_buffer_->Read(from_pos, dest_buf, max_size); | 291 int actual_size = output_buffer_->Read(from_pos, dest_buf, max_size); |
208 ASSERT(actual_size <= max_size); | 292 ASSERT(actual_size <= max_size); |
209 if (actual_size == 0) return 0; | 293 if (actual_size == 0) return 0; |
210 | 294 |
211 // Find previous log line boundary. | 295 // Find previous log line boundary. |
212 char* end_pos = dest_buf + actual_size - 1; | 296 char* end_pos = dest_buf + actual_size - 1; |
213 while (end_pos >= dest_buf && *end_pos != '\n') --end_pos; | 297 while (end_pos >= dest_buf && *end_pos != '\n') --end_pos; |
214 actual_size = static_cast<int>(end_pos - dest_buf + 1); | 298 actual_size = static_cast<int>(end_pos - dest_buf + 1); |
215 // If the assertion below is hit, it means that there was no line end | 299 // If the assertion below is hit, it means that there was no line end |
216 // found --- something wrong has happened. | 300 // found --- something wrong has happened. |
217 ASSERT(actual_size > 0); | 301 ASSERT(actual_size > 0); |
218 ASSERT(actual_size <= max_size); | 302 ASSERT(actual_size <= max_size); |
219 return actual_size; | 303 return actual_size; |
220 } | 304 } |
221 | 305 |
222 | 306 |
223 LogMessageBuilder::WriteFailureHandler | 307 LogMessageBuilder::LogMessageBuilder(Logger* logger) |
224 LogMessageBuilder::write_failure_handler = NULL; | 308 : log_(logger->log_), |
225 | 309 sl(log_->mutex_), |
226 | 310 pos_(0) { |
227 LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) { | 311 ASSERT(log_->message_buffer_ != NULL); |
228 ASSERT(Log::message_buffer_ != NULL); | |
229 } | 312 } |
230 | 313 |
231 | 314 |
232 void LogMessageBuilder::Append(const char* format, ...) { | 315 void LogMessageBuilder::Append(const char* format, ...) { |
233 Vector<char> buf(Log::message_buffer_ + pos_, | 316 Vector<char> buf(log_->message_buffer_ + pos_, |
234 Log::kMessageBufferSize - pos_); | 317 Log::kMessageBufferSize - pos_); |
235 va_list args; | 318 va_list args; |
236 va_start(args, format); | 319 va_start(args, format); |
237 AppendVA(format, args); | 320 AppendVA(format, args); |
238 va_end(args); | 321 va_end(args); |
239 ASSERT(pos_ <= Log::kMessageBufferSize); | 322 ASSERT(pos_ <= Log::kMessageBufferSize); |
240 } | 323 } |
241 | 324 |
242 | 325 |
243 void LogMessageBuilder::AppendVA(const char* format, va_list args) { | 326 void LogMessageBuilder::AppendVA(const char* format, va_list args) { |
244 Vector<char> buf(Log::message_buffer_ + pos_, | 327 Vector<char> buf(log_->message_buffer_ + pos_, |
245 Log::kMessageBufferSize - pos_); | 328 Log::kMessageBufferSize - pos_); |
246 int result = v8::internal::OS::VSNPrintF(buf, format, args); | 329 int result = v8::internal::OS::VSNPrintF(buf, format, args); |
247 | 330 |
248 // Result is -1 if output was truncated. | 331 // Result is -1 if output was truncated. |
249 if (result >= 0) { | 332 if (result >= 0) { |
250 pos_ += result; | 333 pos_ += result; |
251 } else { | 334 } else { |
252 pos_ = Log::kMessageBufferSize; | 335 pos_ = Log::kMessageBufferSize; |
253 } | 336 } |
254 ASSERT(pos_ <= Log::kMessageBufferSize); | 337 ASSERT(pos_ <= Log::kMessageBufferSize); |
255 } | 338 } |
256 | 339 |
257 | 340 |
258 void LogMessageBuilder::Append(const char c) { | 341 void LogMessageBuilder::Append(const char c) { |
259 if (pos_ < Log::kMessageBufferSize) { | 342 if (pos_ < Log::kMessageBufferSize) { |
260 Log::message_buffer_[pos_++] = c; | 343 log_->message_buffer_[pos_++] = c; |
261 } | 344 } |
262 ASSERT(pos_ <= Log::kMessageBufferSize); | 345 ASSERT(pos_ <= Log::kMessageBufferSize); |
263 } | 346 } |
264 | 347 |
265 | 348 |
266 void LogMessageBuilder::Append(String* str) { | 349 void LogMessageBuilder::Append(String* str) { |
267 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | 350 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. |
268 int length = str->length(); | 351 int length = str->length(); |
269 for (int i = 0; i < length; i++) { | 352 for (int i = 0; i < length; i++) { |
270 Append(static_cast<char>(str->Get(i))); | 353 Append(static_cast<char>(str->Get(i))); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 } | 391 } |
309 } | 392 } |
310 | 393 |
311 | 394 |
312 void LogMessageBuilder::AppendStringPart(const char* str, int len) { | 395 void LogMessageBuilder::AppendStringPart(const char* str, int len) { |
313 if (pos_ + len > Log::kMessageBufferSize) { | 396 if (pos_ + len > Log::kMessageBufferSize) { |
314 len = Log::kMessageBufferSize - pos_; | 397 len = Log::kMessageBufferSize - pos_; |
315 ASSERT(len >= 0); | 398 ASSERT(len >= 0); |
316 if (len == 0) return; | 399 if (len == 0) return; |
317 } | 400 } |
318 Vector<char> buf(Log::message_buffer_ + pos_, | 401 Vector<char> buf(log_->message_buffer_ + pos_, |
319 Log::kMessageBufferSize - pos_); | 402 Log::kMessageBufferSize - pos_); |
320 OS::StrNCpy(buf, str, len); | 403 OS::StrNCpy(buf, str, len); |
321 pos_ += len; | 404 pos_ += len; |
322 ASSERT(pos_ <= Log::kMessageBufferSize); | 405 ASSERT(pos_ <= Log::kMessageBufferSize); |
323 } | 406 } |
324 | 407 |
325 | 408 |
326 void LogMessageBuilder::WriteToLogFile() { | 409 void LogMessageBuilder::WriteToLogFile() { |
327 ASSERT(pos_ <= Log::kMessageBufferSize); | 410 ASSERT(pos_ <= Log::kMessageBufferSize); |
328 const int written = Log::Write(Log::message_buffer_, pos_); | 411 const int written = log_->write_to_file_ ? |
329 if (written != pos_ && write_failure_handler != NULL) { | 412 log_->WriteToFile(log_->message_buffer_, pos_) : |
330 write_failure_handler(); | 413 log_->WriteToMemory(log_->message_buffer_, pos_); |
| 414 if (written != pos_) { |
| 415 log_->stop(); |
| 416 log_->logger_->LogFailure(); |
331 } | 417 } |
332 } | 418 } |
333 | 419 |
| 420 |
334 #endif // ENABLE_LOGGING_AND_PROFILING | 421 #endif // ENABLE_LOGGING_AND_PROFILING |
335 | 422 |
336 } } // namespace v8::internal | 423 } } // namespace v8::internal |
OLD | NEW |