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 |