Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/log.cc

Issue 115814: Implement a dynamically growing memory log buffer with an upper limit. (Closed)
Patch Set: Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/SConscript ('k') | src/log-utils.h » ('j') | src/log-utils.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 13 matching lines...) Expand all
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 <stdarg.h> 28 #include <stdarg.h>
29 29
30 #include "v8.h" 30 #include "v8.h"
31 31
32 #include "bootstrapper.h" 32 #include "bootstrapper.h"
33 #include "log.h" 33 #include "log.h"
34 #include "log-utils.h"
34 #include "macro-assembler.h" 35 #include "macro-assembler.h"
35 #include "platform.h" 36 #include "platform.h"
36 #include "serialize.h" 37 #include "serialize.h"
37 #include "string-stream.h" 38 #include "string-stream.h"
38 39
39 namespace v8 { 40 namespace v8 {
40 namespace internal { 41 namespace internal {
41 42
42 #ifdef ENABLE_LOGGING_AND_PROFILING 43 #ifdef ENABLE_LOGGING_AND_PROFILING
43 44
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 void Profiler::Run() { 281 void Profiler::Run() {
281 TickSample sample; 282 TickSample sample;
282 bool overflow = Logger::profiler_->Remove(&sample); 283 bool overflow = Logger::profiler_->Remove(&sample);
283 while (running_) { 284 while (running_) {
284 LOG(TickEvent(&sample, overflow)); 285 LOG(TickEvent(&sample, overflow));
285 overflow = Logger::profiler_->Remove(&sample); 286 overflow = Logger::profiler_->Remove(&sample);
286 } 287 }
287 } 288 }
288 289
289 290
290 #ifdef ENABLE_LOGGING_AND_PROFILING
291
292 // Functions and data for performing output of log messages.
293 class Log : public AllStatic {
294 public:
295 // Opens stdout for logging.
296 static void OpenStdout();
297
298 // Opens file for logging.
299 static void OpenFile(const char* name);
300
301 // Opens memory buffer for logging.
302 static void OpenMemoryBuffer();
303
304 // Frees all resources acquired in Open... functions.
305 static void Close();
306
307 // See description in include/v8.h.
308 static int GetLogLines(int from_pos, char* dest_buf, int max_size);
309
310 // Returns whether logging is enabled.
311 static bool IsEnabled() {
312 return output_handle_ != NULL || output_buffer_ != NULL;
313 }
314
315 private:
316 typedef int (*WritePtr)(const char* msg, int length);
317
318 // Initialization function called from Open... functions.
319 static void Init();
320
321 // Write functions assume that mutex_ is acquired by the caller.
322 static WritePtr Write;
323
324 // Implementation of writing to a log file.
325 static int WriteToFile(const char* msg, int length) {
326 ASSERT(output_handle_ != NULL);
327 int rv = fwrite(msg, 1, length, output_handle_);
328 ASSERT(length == rv);
329 return rv;
330 }
331
332 // Implementation of writing to a memory buffer.
333 static int WriteToMemory(const char* msg, int length) {
334 ASSERT(output_buffer_ != NULL);
335 ASSERT(output_buffer_write_pos_ >= output_buffer_);
336 if (output_buffer_write_pos_ + length
337 <= output_buffer_ + kOutputBufferSize) {
338 memcpy(output_buffer_write_pos_, msg, length);
339 output_buffer_write_pos_ += length;
340 return length;
341 } else {
342 // Memory buffer is full, ignore write.
343 return 0;
344 }
345 }
346
347 // When logging is active, either output_handle_ or output_buffer_ is used
348 // to store a pointer to log destination. If logging was opened via OpenStdout
349 // or OpenFile, then output_handle_ is used. If logging was opened
350 // via OpenMemoryBuffer, then output_buffer_ is used.
351 // mutex_ should be acquired before using output_handle_ or output_buffer_.
352 static FILE* output_handle_;
353
354 static char* output_buffer_;
355
356 // mutex_ is a Mutex used for enforcing exclusive
357 // access to the formatting buffer and the log file or log memory buffer.
358 static Mutex* mutex_;
359
360 // Size of buffer used for memory logging.
361 static const int kOutputBufferSize = 2 * 1024 * 1024;
362
363 // Writing position in a memory buffer.
364 static char* output_buffer_write_pos_;
365
366 // Size of buffer used for formatting log messages.
367 static const int kMessageBufferSize = 2048;
368
369 // Buffer used for formatting log messages. This is a singleton buffer and
370 // mutex_ should be acquired before using it.
371 static char* message_buffer_;
372
373 friend class LogMessageBuilder;
374 };
375
376
377 Log::WritePtr Log::Write = NULL;
378 FILE* Log::output_handle_ = NULL;
379 char* Log::output_buffer_ = NULL;
380 Mutex* Log::mutex_ = NULL;
381 char* Log::output_buffer_write_pos_ = NULL;
382 char* Log::message_buffer_ = NULL;
383
384
385 void Log::Init() {
386 mutex_ = OS::CreateMutex();
387 message_buffer_ = NewArray<char>(kMessageBufferSize);
388 }
389
390
391 void Log::OpenStdout() {
392 ASSERT(!IsEnabled());
393 output_handle_ = stdout;
394 Write = WriteToFile;
395 Init();
396 }
397
398
399 void Log::OpenFile(const char* name) {
400 ASSERT(!IsEnabled());
401 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
402 Write = WriteToFile;
403 Init();
404 }
405
406
407 void Log::OpenMemoryBuffer() {
408 ASSERT(!IsEnabled());
409 output_buffer_ = NewArray<char>(kOutputBufferSize);
410 output_buffer_write_pos_ = output_buffer_;
411 Write = WriteToMemory;
412 Init();
413 }
414
415
416 void Log::Close() {
417 if (Write == WriteToFile) {
418 fclose(output_handle_);
419 output_handle_ = NULL;
420 } else if (Write == WriteToMemory) {
421 DeleteArray(output_buffer_);
422 output_buffer_ = NULL;
423 } else {
424 ASSERT(Write == NULL);
425 }
426 Write = NULL;
427
428 delete mutex_;
429 mutex_ = NULL;
430
431 DeleteArray(message_buffer_);
432 message_buffer_ = NULL;
433 }
434
435
436 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) {
437 if (Write != WriteToMemory) return 0;
438 ASSERT(output_buffer_ != NULL);
439 ASSERT(output_buffer_write_pos_ >= output_buffer_);
440 ASSERT(from_pos >= 0);
441 ASSERT(max_size >= 0);
442 int actual_size = max_size;
443 char* buffer_read_pos = output_buffer_ + from_pos;
444 ScopedLock sl(mutex_);
445 if (actual_size == 0
446 || output_buffer_write_pos_ == output_buffer_
447 || buffer_read_pos >= output_buffer_write_pos_) {
448 // No data requested or can be returned.
449 return 0;
450 }
451 if (buffer_read_pos + actual_size > output_buffer_write_pos_) {
452 // Requested size overlaps with current writing position and
453 // needs to be truncated.
454 actual_size = output_buffer_write_pos_ - buffer_read_pos;
455 ASSERT(actual_size == 0 || buffer_read_pos[actual_size - 1] == '\n');
456 } else {
457 // Find previous log line boundary.
458 char* end_pos = buffer_read_pos + actual_size - 1;
459 while (end_pos >= buffer_read_pos && *end_pos != '\n') --end_pos;
460 actual_size = end_pos - buffer_read_pos + 1;
461 }
462 ASSERT(actual_size <= max_size);
463 if (actual_size > 0) {
464 memcpy(dest_buf, buffer_read_pos, actual_size);
465 }
466 return actual_size;
467 }
468
469
470 // Utility class for formatting log messages. It fills the message into the
471 // static buffer in Log.
472 class LogMessageBuilder BASE_EMBEDDED {
473 public:
474 explicit LogMessageBuilder();
475 ~LogMessageBuilder() { }
476
477 void Append(const char* format, ...);
478 void Append(const char* format, va_list args);
479 void Append(const char c);
480 void Append(String* str);
481 void AppendDetailed(String* str, bool show_impl_info);
482
483 void WriteToLogFile();
484 void WriteCStringToLogFile(const char* str);
485
486 private:
487 ScopedLock sl;
488 int pos_;
489 };
490
491
492 // Create a message builder starting from position 0. This acquires the mutex
493 // in the logger as well.
494 LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) {
495 ASSERT(Log::message_buffer_ != NULL);
496 }
497
498
499 // Append string data to the log message.
500 void LogMessageBuilder::Append(const char* format, ...) {
501 Vector<char> buf(Log::message_buffer_ + pos_,
502 Log::kMessageBufferSize - pos_);
503 va_list args;
504 va_start(args, format);
505 Append(format, args);
506 va_end(args);
507 ASSERT(pos_ <= Log::kMessageBufferSize);
508 }
509
510
511 // Append string data to the log message.
512 void LogMessageBuilder::Append(const char* format, va_list args) {
513 Vector<char> buf(Log::message_buffer_ + pos_,
514 Log::kMessageBufferSize - pos_);
515 int result = v8::internal::OS::VSNPrintF(buf, format, args);
516
517 // Result is -1 if output was truncated.
518 if (result >= 0) {
519 pos_ += result;
520 } else {
521 pos_ = Log::kMessageBufferSize;
522 }
523 ASSERT(pos_ <= Log::kMessageBufferSize);
524 }
525
526
527 // Append a character to the log message.
528 void LogMessageBuilder::Append(const char c) {
529 if (pos_ < Log::kMessageBufferSize) {
530 Log::message_buffer_[pos_++] = c;
531 }
532 ASSERT(pos_ <= Log::kMessageBufferSize);
533 }
534
535
536 // Append a heap string.
537 void LogMessageBuilder::Append(String* str) {
538 AssertNoAllocation no_heap_allocation; // Ensure string stay valid.
539 int length = str->length();
540 for (int i = 0; i < length; i++) {
541 Append(static_cast<char>(str->Get(i)));
542 }
543 }
544
545 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
546 AssertNoAllocation no_heap_allocation; // Ensure string stay valid.
547 int len = str->length();
548 if (len > 0x1000)
549 len = 0x1000;
550 if (show_impl_info) {
551 Append(str->IsAsciiRepresentation() ? 'a' : '2');
552 if (StringShape(str).IsExternal())
553 Append('e');
554 if (StringShape(str).IsSymbol())
555 Append('#');
556 Append(":%i:", str->length());
557 }
558 for (int i = 0; i < len; i++) {
559 uc32 c = str->Get(i);
560 if (c > 0xff) {
561 Append("\\u%04x", c);
562 } else if (c < 32 || c > 126) {
563 Append("\\x%02x", c);
564 } else if (c == ',') {
565 Append("\\,");
566 } else if (c == '\\') {
567 Append("\\\\");
568 } else {
569 Append("%lc", c);
570 }
571 }
572 }
573
574 // Write the log message to the log file currently opened.
575 void LogMessageBuilder::WriteToLogFile() {
576 ASSERT(pos_ <= Log::kMessageBufferSize);
577 Log::Write(Log::message_buffer_, pos_);
578 }
579
580 // Write a null-terminated string to to the log file currently opened.
581 void LogMessageBuilder::WriteCStringToLogFile(const char* str) {
582 int len = strlen(str);
583 Log::Write(str, len);
584 }
585 #endif
586
587
588 // 291 //
589 // Logger class implementation. 292 // Logger class implementation.
590 // 293 //
591 Ticker* Logger::ticker_ = NULL; 294 Ticker* Logger::ticker_ = NULL;
592 Profiler* Logger::profiler_ = NULL; 295 Profiler* Logger::profiler_ = NULL;
593 VMState* Logger::current_state_ = NULL; 296 VMState* Logger::current_state_ = NULL;
594 VMState Logger::bottom_state_(EXTERNAL); 297 VMState Logger::bottom_state_(EXTERNAL);
595 SlidingStateWindow* Logger::sliding_state_window_ = NULL; 298 SlidingStateWindow* Logger::sliding_state_window_ = NULL;
596 299
597 300
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after
1414 } else if (previous_->state_ == EXTERNAL) { 1117 } else if (previous_->state_ == EXTERNAL) {
1415 // We are leaving V8. 1118 // We are leaving V8.
1416 Heap::Protect(); 1119 Heap::Protect();
1417 } 1120 }
1418 } 1121 }
1419 #endif 1122 #endif
1420 } 1123 }
1421 #endif 1124 #endif
1422 1125
1423 } } // namespace v8::internal 1126 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/SConscript ('k') | src/log-utils.h » ('j') | src/log-utils.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698