Chromium Code Reviews| 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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 | 120 |
| 121 | 121 |
| 122 bool Log::is_stopped_ = false; | 122 bool Log::is_stopped_ = false; |
| 123 Log::WritePtr Log::Write = NULL; | 123 Log::WritePtr Log::Write = NULL; |
| 124 FILE* Log::output_handle_ = NULL; | 124 FILE* Log::output_handle_ = NULL; |
| 125 LogDynamicBuffer* Log::output_buffer_ = NULL; | 125 LogDynamicBuffer* Log::output_buffer_ = NULL; |
| 126 // Must be the same message as in Logger::PauseProfiler | 126 // Must be the same message as in Logger::PauseProfiler |
| 127 const char* Log::kDynamicBufferSeal = "profiler,\"pause\"\n"; | 127 const char* Log::kDynamicBufferSeal = "profiler,\"pause\"\n"; |
| 128 Mutex* Log::mutex_ = NULL; | 128 Mutex* Log::mutex_ = NULL; |
| 129 char* Log::message_buffer_ = NULL; | 129 char* Log::message_buffer_ = NULL; |
| 130 LogRecordCompressor* Log::record_compressor_ = NULL; | |
| 130 | 131 |
| 131 | 132 |
| 132 void Log::Init() { | 133 void Log::Init() { |
| 133 mutex_ = OS::CreateMutex(); | 134 mutex_ = OS::CreateMutex(); |
| 134 message_buffer_ = NewArray<char>(kMessageBufferSize); | 135 message_buffer_ = NewArray<char>(kMessageBufferSize); |
| 136 if (FLAG_compress_log) { | |
| 137 record_compressor_ = new LogRecordCompressor(kRecordCompressorWindow); | |
| 138 } | |
| 135 } | 139 } |
| 136 | 140 |
| 137 | 141 |
| 138 void Log::OpenStdout() { | 142 void Log::OpenStdout() { |
| 139 ASSERT(!IsEnabled()); | 143 ASSERT(!IsEnabled()); |
| 140 output_handle_ = stdout; | 144 output_handle_ = stdout; |
| 141 Write = WriteToFile; | 145 Write = WriteToFile; |
| 142 Init(); | 146 Init(); |
| 143 } | 147 } |
| 144 | 148 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 166 fclose(output_handle_); | 170 fclose(output_handle_); |
| 167 output_handle_ = NULL; | 171 output_handle_ = NULL; |
| 168 } else if (Write == WriteToMemory) { | 172 } else if (Write == WriteToMemory) { |
| 169 delete output_buffer_; | 173 delete output_buffer_; |
| 170 output_buffer_ = NULL; | 174 output_buffer_ = NULL; |
| 171 } else { | 175 } else { |
| 172 ASSERT(Write == NULL); | 176 ASSERT(Write == NULL); |
| 173 } | 177 } |
| 174 Write = NULL; | 178 Write = NULL; |
| 175 | 179 |
| 180 delete record_compressor_; | |
| 181 record_compressor_ = NULL; | |
| 182 | |
| 183 DeleteArray(message_buffer_); | |
| 184 message_buffer_ = NULL; | |
| 185 | |
| 176 delete mutex_; | 186 delete mutex_; |
| 177 mutex_ = NULL; | 187 mutex_ = NULL; |
| 178 | 188 |
| 179 is_stopped_ = false; | 189 is_stopped_ = false; |
| 180 } | 190 } |
| 181 | 191 |
| 182 | 192 |
| 183 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { | 193 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { |
| 184 if (Write != WriteToMemory) return 0; | 194 if (Write != WriteToMemory) return 0; |
| 185 ASSERT(output_buffer_ != NULL); | 195 ASSERT(output_buffer_ != NULL); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 Append("\\,"); | 283 Append("\\,"); |
| 274 } else if (c == '\\') { | 284 } else if (c == '\\') { |
| 275 Append("\\\\"); | 285 Append("\\\\"); |
| 276 } else { | 286 } else { |
| 277 Append("%lc", c); | 287 Append("%lc", c); |
| 278 } | 288 } |
| 279 } | 289 } |
| 280 } | 290 } |
| 281 | 291 |
| 282 | 292 |
| 293 bool LogMessageBuilder::StoreInCompressor() { | |
| 294 if (!FLAG_compress_log) return true; | |
| 295 ASSERT(Log::record_compressor_ != NULL); | |
| 296 return Log::record_compressor_->Store( | |
| 297 Vector<const char>(Log::message_buffer_, pos_)); | |
| 298 } | |
| 299 | |
| 300 | |
| 301 bool LogMessageBuilder::RetrieveCompressedPrevious(const char* prefix) { | |
| 302 if (!FLAG_compress_log) return true; | |
| 303 ASSERT(Log::record_compressor_ != NULL); | |
| 304 pos_ = 0; | |
| 305 if (prefix[0] != '\0') Append(prefix); | |
| 306 Vector<char> prev_record(Log::message_buffer_ + pos_, | |
| 307 Log::kMessageBufferSize - pos_); | |
| 308 const bool has_previous = | |
| 309 Log::record_compressor_->RetrievePreviousCompressed(&prev_record); | |
| 310 if (!has_previous) return false; | |
| 311 pos_ += prev_record.length(); | |
| 312 return true; | |
| 313 } | |
| 314 | |
| 315 | |
| 283 void LogMessageBuilder::WriteToLogFile() { | 316 void LogMessageBuilder::WriteToLogFile() { |
| 284 ASSERT(pos_ <= Log::kMessageBufferSize); | 317 ASSERT(pos_ <= Log::kMessageBufferSize); |
| 285 const int written = Log::Write(Log::message_buffer_, pos_); | 318 const int written = Log::Write(Log::message_buffer_, pos_); |
| 286 if (written != pos_ && write_failure_handler != NULL) { | 319 if (written != pos_ && write_failure_handler != NULL) { |
| 287 write_failure_handler(); | 320 write_failure_handler(); |
| 288 } | 321 } |
| 289 } | 322 } |
| 290 | 323 |
| 291 | 324 |
| 292 void LogMessageBuilder::WriteCStringToLogFile(const char* str) { | 325 void LogMessageBuilder::WriteCStringToLogFile(const char* str) { |
| 293 const int len = strlen(str); | 326 const int len = strlen(str); |
| 294 const int written = Log::Write(str, len); | 327 const int written = Log::Write(str, len); |
| 295 if (written != len && write_failure_handler != NULL) { | 328 if (written != len && write_failure_handler != NULL) { |
| 296 write_failure_handler(); | 329 write_failure_handler(); |
| 297 } | 330 } |
| 298 } | 331 } |
| 299 | 332 |
| 333 | |
| 334 // Formatting string for back references. E.g. "#2:4" means | |
| 335 // "the second line above, start from the 4th field (0-based)". | |
| 336 const char* LogRecordCompressor::kBackwardReferenceFormat = "#%d:%d"; | |
| 337 | |
| 338 | |
| 339 LogRecordCompressor::~LogRecordCompressor() { | |
| 340 for (int i = 0; i < buffer_.length(); ++i) { | |
| 341 buffer_[i].Dispose(); | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 | |
| 346 bool LogRecordCompressor::Store(const Vector<const char>& record) { | |
| 347 // Check if the record is the same as the last stored one. | |
| 348 if (curr_ != -1) { | |
| 349 Vector<const char>& curr = buffer_[curr_]; | |
| 350 if (record.length() == curr.length() | |
| 351 && strncmp(record.start(), curr.start(), record.length()) == 0) { | |
| 352 return false; | |
| 353 } | |
| 354 } | |
| 355 prev_ = curr_++; | |
|
Søren Thygesen Gjesse
2009/06/11 11:13:56
Maybe add a comment here saying that we keep a cir
Mikhail Naganov
2009/06/11 14:07:12
Done.
| |
| 356 curr_ %= buffer_.length(); | |
| 357 Vector<char> record_copy = Vector<char>::New(record.length()); | |
| 358 memcpy(record_copy.start(), record.start(), record.length()); | |
| 359 buffer_[curr_].Dispose(); | |
| 360 buffer_[curr_] = | |
| 361 Vector<const char>(record_copy.start(), record_copy.length()); | |
| 362 return true; | |
| 363 } | |
| 364 | |
| 365 | |
| 366 bool LogRecordCompressor::RetrievePreviousCompressed( | |
| 367 Vector<char>* prev_record) { | |
| 368 if (prev_ == -1) return false; | |
| 369 | |
| 370 int index = prev_; | |
| 371 // Distance from prev_. | |
| 372 int distance = 0; | |
| 373 // Best compression result among records in the buffer. | |
| 374 struct { | |
| 375 intptr_t truncated_len; | |
| 376 int distance; | |
| 377 int field_num; | |
| 378 } best = {-1, 0, 0}; | |
| 379 Vector<const char>& prev = buffer_[prev_]; | |
| 380 const char* const prev_end = prev.start() + prev.length(); | |
| 381 do { | |
| 382 // We're moving backwards until we reach the current record. | |
| 383 if (--index == -1) index = buffer_.length() - 1; | |
| 384 ++distance; | |
| 385 if (index == curr_) break; | |
| 386 | |
| 387 Vector<const char>& data = buffer_[index]; | |
| 388 if (data.start() == NULL) break; | |
| 389 const char* const data_end = data.start() + data.length(); | |
| 390 const char* prev_ptr = prev_end; | |
| 391 const char* data_ptr = data_end; | |
| 392 // Compare strings backwards, stop on the last matching character. | |
|
Søren Thygesen Gjesse
2009/06/11 11:13:56
I am not sure how expensive this is, but perhaps c
Mikhail Naganov
2009/06/11 14:07:12
I'm aware of this optimization, but don't want to
| |
| 393 while (prev_ptr != prev.start() && data_ptr != data.start() | |
| 394 && *(prev_ptr - 1) == *(data_ptr - 1)) { | |
| 395 --prev_ptr; | |
| 396 --data_ptr; | |
| 397 } | |
| 398 if (prev_end - prev_ptr < kUncompressibleBound) continue; | |
| 399 | |
| 400 // Align to the field boundary. | |
| 401 do { | |
| 402 ++prev_ptr; | |
| 403 ++data_ptr; | |
| 404 } while (prev_ptr != prev_end | |
| 405 && (prev_ptr != prev.start() && *(prev_ptr - 1) != kFieldSeparator | |
|
Søren Thygesen Gjesse
2009/06/11 11:13:56
Will prev_ptr ever become prev.start() as the do l
Mikhail Naganov
2009/06/11 14:07:12
I've removed field alignment, so this code has gon
| |
| 406 || data_ptr != data.start() | |
| 407 && *(data_ptr - 1) != kFieldSeparator)); | |
| 408 // Check if the record is still compressible. | |
| 409 const intptr_t truncated_len = prev_end - prev_ptr; | |
| 410 if (truncated_len < kUncompressibleBound) continue; | |
| 411 | |
| 412 // Determine reference field number. | |
| 413 int field_num = 0; | |
| 414 for (const char* fld_ptr = data.start(); | |
| 415 fld_ptr != data_ptr; ++fld_ptr) { | |
| 416 if (*fld_ptr == kFieldSeparator) field_num++; | |
| 417 } | |
| 418 // Record compression results. | |
| 419 if (truncated_len > best.truncated_len) { | |
| 420 best.truncated_len = truncated_len; | |
| 421 best.distance = distance; | |
| 422 best.field_num = field_num; | |
| 423 } | |
| 424 } while (true); | |
| 425 | |
| 426 if (best.distance == 0) { | |
| 427 // Can't compress the previous record. Return as is. | |
| 428 ASSERT(prev_record->length() >= prev.length()); | |
| 429 memcpy(prev_record->start(), prev.start(), prev.length()); | |
| 430 prev_record->Truncate(prev.length()); | |
| 431 } else { | |
| 432 // Copy the uncompressible part unchanged. | |
| 433 const intptr_t unchanged_len = prev.length() - best.truncated_len; | |
| 434 ASSERT(prev_record->length() >= unchanged_len + kUncompressibleBound); | |
| 435 memcpy(prev_record->start(), prev.start(), unchanged_len); | |
| 436 // Append the backward reference. | |
| 437 Vector<char> patch(prev_record->start() + unchanged_len, | |
| 438 kUncompressibleBound); | |
| 439 OS::SNPrintF(patch, kBackwardReferenceFormat, | |
| 440 best.distance, best.field_num); | |
| 441 prev_record->Truncate(unchanged_len + strlen(patch.start())); | |
| 442 } | |
| 443 return true; | |
| 444 } | |
| 445 | |
| 300 #endif // ENABLE_LOGGING_AND_PROFILING | 446 #endif // ENABLE_LOGGING_AND_PROFILING |
| 301 | 447 |
| 302 } } // namespace v8::internal | 448 } } // namespace v8::internal |
| OLD | NEW |