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; | |
131 // Must be the same as compressed tick event name from Logger. | |
132 const char* Log::kCompressedTickEventName = "t,"; | |
133 | 130 |
134 | 131 |
135 void Log::Init() { | 132 void Log::Init() { |
136 mutex_ = OS::CreateMutex(); | 133 mutex_ = OS::CreateMutex(); |
137 message_buffer_ = NewArray<char>(kMessageBufferSize); | 134 message_buffer_ = NewArray<char>(kMessageBufferSize); |
138 if (FLAG_compress_log) { | |
139 record_compressor_ = new LogRecordCompressor( | |
140 kRecordCompressorWindow, strlen(kCompressedTickEventName)); | |
141 } | |
142 } | 135 } |
143 | 136 |
144 | 137 |
145 void Log::OpenStdout() { | 138 void Log::OpenStdout() { |
146 ASSERT(!IsEnabled()); | 139 ASSERT(!IsEnabled()); |
147 output_handle_ = stdout; | 140 output_handle_ = stdout; |
148 Write = WriteToFile; | 141 Write = WriteToFile; |
149 Init(); | 142 Init(); |
150 } | 143 } |
151 | 144 |
(...skipping 21 matching lines...) Expand all Loading... |
173 fclose(output_handle_); | 166 fclose(output_handle_); |
174 output_handle_ = NULL; | 167 output_handle_ = NULL; |
175 } else if (Write == WriteToMemory) { | 168 } else if (Write == WriteToMemory) { |
176 delete output_buffer_; | 169 delete output_buffer_; |
177 output_buffer_ = NULL; | 170 output_buffer_ = NULL; |
178 } else { | 171 } else { |
179 ASSERT(Write == NULL); | 172 ASSERT(Write == NULL); |
180 } | 173 } |
181 Write = NULL; | 174 Write = NULL; |
182 | 175 |
183 delete record_compressor_; | |
184 record_compressor_ = NULL; | |
185 | |
186 DeleteArray(message_buffer_); | 176 DeleteArray(message_buffer_); |
187 message_buffer_ = NULL; | 177 message_buffer_ = NULL; |
188 | 178 |
189 delete mutex_; | 179 delete mutex_; |
190 mutex_ = NULL; | 180 mutex_ = NULL; |
191 | 181 |
192 is_stopped_ = false; | 182 is_stopped_ = false; |
193 } | 183 } |
194 | 184 |
195 | 185 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 | 246 |
257 void LogMessageBuilder::Append(String* str) { | 247 void LogMessageBuilder::Append(String* str) { |
258 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | 248 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. |
259 int length = str->length(); | 249 int length = str->length(); |
260 for (int i = 0; i < length; i++) { | 250 for (int i = 0; i < length; i++) { |
261 Append(static_cast<char>(str->Get(i))); | 251 Append(static_cast<char>(str->Get(i))); |
262 } | 252 } |
263 } | 253 } |
264 | 254 |
265 | 255 |
| 256 void LogMessageBuilder::AppendAddress(Address addr) { |
| 257 static Address last_address_ = NULL; |
| 258 AppendAddress(addr, last_address_); |
| 259 last_address_ = addr; |
| 260 } |
| 261 |
| 262 |
| 263 void LogMessageBuilder::AppendAddress(Address addr, Address bias) { |
| 264 if (!FLAG_compress_log || bias == NULL) { |
| 265 Append("0x%" V8PRIxPTR, addr); |
| 266 } else { |
| 267 intptr_t delta = addr - bias; |
| 268 // To avoid printing negative offsets in an unsigned form, |
| 269 // we are printing an absolute value with a sign. |
| 270 const char sign = delta >= 0 ? '+' : '-'; |
| 271 if (sign == '-') { delta = -delta; } |
| 272 Append("%c%" V8PRIxPTR, sign, delta); |
| 273 } |
| 274 } |
| 275 |
| 276 |
266 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { | 277 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { |
267 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | 278 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. |
268 int len = str->length(); | 279 int len = str->length(); |
269 if (len > 0x1000) | 280 if (len > 0x1000) |
270 len = 0x1000; | 281 len = 0x1000; |
271 if (show_impl_info) { | 282 if (show_impl_info) { |
272 Append(str->IsAsciiRepresentation() ? 'a' : '2'); | 283 Append(str->IsAsciiRepresentation() ? 'a' : '2'); |
273 if (StringShape(str).IsExternal()) | 284 if (StringShape(str).IsExternal()) |
274 Append('e'); | 285 Append('e'); |
275 if (StringShape(str).IsSymbol()) | 286 if (StringShape(str).IsSymbol()) |
(...skipping 10 matching lines...) Expand all Loading... |
286 Append("\\,"); | 297 Append("\\,"); |
287 } else if (c == '\\') { | 298 } else if (c == '\\') { |
288 Append("\\\\"); | 299 Append("\\\\"); |
289 } else { | 300 } else { |
290 Append("%lc", c); | 301 Append("%lc", c); |
291 } | 302 } |
292 } | 303 } |
293 } | 304 } |
294 | 305 |
295 | 306 |
296 bool LogMessageBuilder::StoreInCompressor() { | 307 bool LogMessageBuilder::StoreInCompressor(LogRecordCompressor* compressor) { |
297 if (!FLAG_compress_log) return true; | 308 return compressor->Store(Vector<const char>(Log::message_buffer_, pos_)); |
298 ASSERT(Log::record_compressor_ != NULL); | |
299 return Log::record_compressor_->Store( | |
300 Vector<const char>(Log::message_buffer_, pos_)); | |
301 } | 309 } |
302 | 310 |
303 | 311 |
304 bool LogMessageBuilder::RetrieveCompressedPrevious(const char* prefix) { | 312 bool LogMessageBuilder::RetrieveCompressedPrevious( |
305 if (!FLAG_compress_log) return true; | 313 LogRecordCompressor* compressor, const char* prefix) { |
306 ASSERT(Log::record_compressor_ != NULL); | |
307 pos_ = 0; | 314 pos_ = 0; |
308 if (prefix[0] != '\0') Append(prefix); | 315 if (prefix[0] != '\0') Append(prefix); |
309 Vector<char> prev_record(Log::message_buffer_ + pos_, | 316 Vector<char> prev_record(Log::message_buffer_ + pos_, |
310 Log::kMessageBufferSize - pos_); | 317 Log::kMessageBufferSize - pos_); |
311 const bool has_previous = | 318 const bool has_prev = compressor->RetrievePreviousCompressed(&prev_record); |
312 Log::record_compressor_->RetrievePreviousCompressed(&prev_record); | 319 if (!has_prev) return false; |
313 if (!has_previous) return false; | |
314 pos_ += prev_record.length(); | 320 pos_ += prev_record.length(); |
315 return true; | 321 return true; |
316 } | 322 } |
317 | 323 |
318 | 324 |
319 void LogMessageBuilder::WriteToLogFile() { | 325 void LogMessageBuilder::WriteToLogFile() { |
320 ASSERT(pos_ <= Log::kMessageBufferSize); | 326 ASSERT(pos_ <= Log::kMessageBufferSize); |
321 const int written = Log::Write(Log::message_buffer_, pos_); | 327 const int written = Log::Write(Log::message_buffer_, pos_); |
322 if (written != pos_ && write_failure_handler != NULL) { | 328 if (written != pos_ && write_failure_handler != NULL) { |
323 write_failure_handler(); | 329 write_failure_handler(); |
324 } | 330 } |
325 } | 331 } |
326 | 332 |
327 | 333 |
328 void LogMessageBuilder::WriteCStringToLogFile(const char* str) { | 334 void LogMessageBuilder::WriteCStringToLogFile(const char* str) { |
329 const int len = strlen(str); | 335 const int len = strlen(str); |
330 const int written = Log::Write(str, len); | 336 const int written = Log::Write(str, len); |
331 if (written != len && write_failure_handler != NULL) { | 337 if (written != len && write_failure_handler != NULL) { |
332 write_failure_handler(); | 338 write_failure_handler(); |
333 } | 339 } |
334 } | 340 } |
335 | 341 |
336 | 342 |
| 343 // Formatting string for back references to the whole line. E.g. "#2" means |
| 344 // "the second line above". |
| 345 const char* LogRecordCompressor::kLineBackwardReferenceFormat = "#%d"; |
| 346 |
337 // Formatting string for back references. E.g. "#2:10" means | 347 // Formatting string for back references. E.g. "#2:10" means |
338 // "the second line above, start from char 10 (0-based)". | 348 // "the second line above, start from char 10 (0-based)". |
339 const char* LogRecordCompressor::kBackwardReferenceFormat = "#%d:%d"; | 349 const char* LogRecordCompressor::kBackwardReferenceFormat = "#%d:%d"; |
340 | 350 |
341 | 351 |
342 LogRecordCompressor::~LogRecordCompressor() { | 352 LogRecordCompressor::~LogRecordCompressor() { |
343 for (int i = 0; i < buffer_.length(); ++i) { | 353 for (int i = 0; i < buffer_.length(); ++i) { |
344 buffer_[i].Dispose(); | 354 buffer_[i].Dispose(); |
345 } | 355 } |
346 } | 356 } |
347 | 357 |
348 | 358 |
| 359 static int GetNumberLength(int number) { |
| 360 ASSERT(number >= 0); |
| 361 ASSERT(number < 10000); |
| 362 if (number < 10) return 1; |
| 363 if (number < 100) return 2; |
| 364 if (number < 1000) return 3; |
| 365 return 4; |
| 366 } |
| 367 |
| 368 |
| 369 int LogRecordCompressor::GetBackwardReferenceSize(int distance, int pos) { |
| 370 // See kLineBackwardReferenceFormat and kBackwardReferenceFormat. |
| 371 return pos == 0 ? GetNumberLength(distance) + 1 |
| 372 : GetNumberLength(distance) + GetNumberLength(pos) + 2; |
| 373 } |
| 374 |
| 375 |
| 376 void LogRecordCompressor::PrintBackwardReference(Vector<char> dest, |
| 377 int distance, |
| 378 int pos) { |
| 379 if (pos == 0) { |
| 380 OS::SNPrintF(dest, kLineBackwardReferenceFormat, distance); |
| 381 } else { |
| 382 OS::SNPrintF(dest, kBackwardReferenceFormat, distance, pos); |
| 383 } |
| 384 } |
| 385 |
| 386 |
349 bool LogRecordCompressor::Store(const Vector<const char>& record) { | 387 bool LogRecordCompressor::Store(const Vector<const char>& record) { |
350 // Check if the record is the same as the last stored one. | 388 // Check if the record is the same as the last stored one. |
351 if (curr_ != -1) { | 389 if (curr_ != -1) { |
352 Vector<const char>& curr = buffer_[curr_]; | 390 Vector<const char>& curr = buffer_[curr_]; |
353 if (record.length() == curr.length() | 391 if (record.length() == curr.length() |
354 && strncmp(record.start(), curr.start(), record.length()) == 0) { | 392 && strncmp(record.start(), curr.start(), record.length()) == 0) { |
355 return false; | 393 return false; |
356 } | 394 } |
357 } | 395 } |
358 // buffer_ is circular. | 396 // buffer_ is circular. |
(...skipping 13 matching lines...) Expand all Loading... |
372 if (prev_ == -1) return false; | 410 if (prev_ == -1) return false; |
373 | 411 |
374 int index = prev_; | 412 int index = prev_; |
375 // Distance from prev_. | 413 // Distance from prev_. |
376 int distance = 0; | 414 int distance = 0; |
377 // Best compression result among records in the buffer. | 415 // Best compression result among records in the buffer. |
378 struct { | 416 struct { |
379 intptr_t truncated_len; | 417 intptr_t truncated_len; |
380 int distance; | 418 int distance; |
381 int copy_from_pos; | 419 int copy_from_pos; |
382 } best = {-1, 0, 0}; | 420 int backref_size; |
| 421 } best = {-1, 0, 0, 0}; |
383 Vector<const char>& prev = buffer_[prev_]; | 422 Vector<const char>& prev = buffer_[prev_]; |
384 const char* const prev_start = prev.start() + start_pos_; | 423 const char* const prev_start = prev.start(); |
385 const char* const prev_end = prev.start() + prev.length(); | 424 const char* const prev_end = prev.start() + prev.length(); |
386 do { | 425 do { |
387 // We're moving backwards until we reach the current record. | 426 // We're moving backwards until we reach the current record. |
388 // Remember that buffer_ is circular. | 427 // Remember that buffer_ is circular. |
389 if (--index == -1) index = buffer_.length() - 1; | 428 if (--index == -1) index = buffer_.length() - 1; |
390 ++distance; | 429 ++distance; |
391 if (index == curr_) break; | 430 if (index == curr_) break; |
392 | 431 |
393 Vector<const char>& data = buffer_[index]; | 432 Vector<const char>& data = buffer_[index]; |
394 if (data.start() == NULL) break; | 433 if (data.start() == NULL) break; |
395 const char* const data_end = data.start() + data.length(); | 434 const char* const data_end = data.start() + data.length(); |
396 const char* prev_ptr = prev_end; | 435 const char* prev_ptr = prev_end; |
397 const char* data_ptr = data_end; | 436 const char* data_ptr = data_end; |
398 // Compare strings backwards, stop on the last matching character. | 437 // Compare strings backwards, stop on the last matching character. |
399 while (prev_ptr != prev_start && data_ptr != data.start() | 438 while (prev_ptr != prev_start && data_ptr != data.start() |
400 && *(prev_ptr - 1) == *(data_ptr - 1)) { | 439 && *(prev_ptr - 1) == *(data_ptr - 1)) { |
401 --prev_ptr; | 440 --prev_ptr; |
402 --data_ptr; | 441 --data_ptr; |
403 } | 442 } |
404 const intptr_t truncated_len = prev_end - prev_ptr; | 443 const intptr_t truncated_len = prev_end - prev_ptr; |
405 if (truncated_len < kUncompressibleBound) continue; | 444 const int copy_from_pos = data_ptr - data.start(); |
| 445 // Check if the length of compressed tail is enough. |
| 446 if (truncated_len <= kMaxBackwardReferenceSize |
| 447 && truncated_len <= GetBackwardReferenceSize(distance, copy_from_pos)) { |
| 448 continue; |
| 449 } |
406 | 450 |
407 // Record compression results. | 451 // Record compression results. |
408 if (truncated_len > best.truncated_len) { | 452 if (truncated_len > best.truncated_len) { |
409 best.truncated_len = truncated_len; | 453 best.truncated_len = truncated_len; |
410 best.distance = distance; | 454 best.distance = distance; |
411 best.copy_from_pos = data_ptr - data.start(); | 455 best.copy_from_pos = copy_from_pos; |
| 456 best.backref_size = GetBackwardReferenceSize(distance, copy_from_pos); |
412 } | 457 } |
413 } while (true); | 458 } while (true); |
414 | 459 |
415 if (best.distance == 0) { | 460 if (best.distance == 0) { |
416 // Can't compress the previous record. Return as is. | 461 // Can't compress the previous record. Return as is. |
417 ASSERT(prev_record->length() >= prev.length()); | 462 ASSERT(prev_record->length() >= prev.length()); |
418 memcpy(prev_record->start(), prev.start(), prev.length()); | 463 memcpy(prev_record->start(), prev.start(), prev.length()); |
419 prev_record->Truncate(prev.length()); | 464 prev_record->Truncate(prev.length()); |
420 } else { | 465 } else { |
421 // Copy the uncompressible part unchanged. | 466 // Copy the uncompressible part unchanged. |
422 const intptr_t unchanged_len = prev.length() - best.truncated_len; | 467 const intptr_t unchanged_len = prev.length() - best.truncated_len; |
423 ASSERT(prev_record->length() >= unchanged_len + kUncompressibleBound); | 468 // + 1 for '\0'. |
| 469 ASSERT(prev_record->length() >= unchanged_len + best.backref_size + 1); |
424 memcpy(prev_record->start(), prev.start(), unchanged_len); | 470 memcpy(prev_record->start(), prev.start(), unchanged_len); |
425 // Append the backward reference. | 471 // Append the backward reference. |
426 Vector<char> patch(prev_record->start() + unchanged_len, | 472 Vector<char> backref( |
427 kUncompressibleBound); | 473 prev_record->start() + unchanged_len, best.backref_size + 1); |
428 OS::SNPrintF(patch, kBackwardReferenceFormat, | 474 PrintBackwardReference(backref, best.distance, best.copy_from_pos); |
429 best.distance, best.copy_from_pos); | 475 ASSERT(strlen(backref.start()) - best.backref_size == 0); |
430 prev_record->Truncate(unchanged_len + strlen(patch.start())); | 476 prev_record->Truncate(unchanged_len + best.backref_size); |
431 } | 477 } |
432 return true; | 478 return true; |
433 } | 479 } |
434 | 480 |
435 #endif // ENABLE_LOGGING_AND_PROFILING | 481 #endif // ENABLE_LOGGING_AND_PROFILING |
436 | 482 |
437 } } // namespace v8::internal | 483 } } // namespace v8::internal |
OLD | NEW |