OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 } | 239 } |
240 | 240 |
241 | 241 |
242 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) { | 242 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) { |
243 name_buffer_->Init(Logger::REG_EXP_TAG); | 243 name_buffer_->Init(Logger::REG_EXP_TAG); |
244 name_buffer_->AppendString(source); | 244 name_buffer_->AppendString(source); |
245 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size()); | 245 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size()); |
246 } | 246 } |
247 | 247 |
248 | 248 |
249 // Linux perf tool logging support | |
250 class PerfBasicLogger : public CodeEventLogger { | |
251 public: | |
252 explicit PerfBasicLogger(); | |
danno
2013/11/13 17:18:10
Don't need explicit here, only for single argument
| |
253 virtual ~PerfBasicLogger(); | |
254 | |
255 virtual void CodeMoveEvent(Address from, Address to) { } | |
256 virtual void CodeDeleteEvent(Address from) { } | |
257 | |
258 private: | |
259 virtual void LogRecordedBuffer(Code* code, | |
260 SharedFunctionInfo* shared, | |
261 const char* name, | |
262 int length); | |
263 | |
264 // Extension added to V8 log file name to get the low-level log name. | |
265 static const char kFilenameFormatString[]; | |
266 static const int kFilenameBufferPadding; | |
267 | |
268 // File buffer size of the low-level log. We don't use the default to | |
269 // minimize the associated overhead. | |
270 static const int kLogBufferSize = 2 * MB; | |
271 | |
272 FILE* perf_output_handle_; | |
273 }; | |
274 | |
275 const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map"; | |
276 // Extra space for the PID in the filename | |
277 const int PerfBasicLogger::kFilenameBufferPadding = 16; | |
278 | |
279 PerfBasicLogger::PerfBasicLogger() | |
280 : perf_output_handle_(NULL) { | |
281 // Open the perf JIT dump file. | |
282 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; | |
283 ScopedVector<char> perf_dump_name(bufferSize); | |
284 int size = OS::SNPrintF( | |
285 perf_dump_name, | |
danno
2013/11/13 17:18:10
nit: 4 char indent
| |
286 kFilenameFormatString, | |
287 OS::GetCurrentProcessId()); | |
288 CHECK_NE(size, -1); | |
289 perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode); | |
bnoordhuis
2013/11/13 23:40:52
This should check for NULL, shouldn't it? Calling
| |
290 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); | |
291 } | |
292 | |
293 | |
294 PerfBasicLogger::~PerfBasicLogger() { | |
295 fclose(perf_output_handle_); | |
296 perf_output_handle_ = NULL; | |
297 } | |
298 | |
299 | |
300 void PerfBasicLogger::LogRecordedBuffer(Code* code, | |
301 SharedFunctionInfo*, | |
302 const char* name, | |
303 int length) { | |
304 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); | |
305 | |
306 OS::FPrint(perf_output_handle_, "%llx %x %.*s\n", | |
307 (uint64_t)code->instruction_start(), | |
danno
2013/11/13 17:18:10
nit: 4 char indent (2 is for nested scopes only)
bnoordhuis
2013/11/13 23:40:52
static_cast? (Here and in a few other places.)
| |
308 code->instruction_size(), | |
309 length, name); | |
310 } | |
311 | |
312 | |
313 // Linux perf tool logging support | |
314 class PerfJitLogger : public CodeEventLogger { | |
315 public: | |
316 explicit PerfJitLogger(); | |
danno
2013/11/13 17:18:10
Don't need explicit here, only for single argument
| |
317 virtual ~PerfJitLogger(); | |
318 | |
319 virtual void CodeMoveEvent(Address from, Address to) { } | |
320 virtual void CodeDeleteEvent(Address from) { } | |
321 | |
322 private: | |
323 virtual void LogRecordedBuffer(Code* code, | |
324 SharedFunctionInfo* shared, | |
325 const char* name, | |
326 int length); | |
327 | |
328 // Extension added to V8 log file name to get the low-level log name. | |
329 static const char kFilenameFormatString[]; | |
330 static const int kFilenameBufferPadding; | |
331 | |
332 // File buffer size of the low-level log. We don't use the default to | |
333 // minimize the associated overhead. | |
334 static const int kLogBufferSize = 2 * MB; | |
335 | |
336 void LogWriteBytes(const char* bytes, int size); | |
337 void LogWriteHeader(); | |
338 | |
339 static const uint32_t kJitHeaderMagic = 0x4F74496A; | |
340 static const uint32_t kJitHeaderVersion = 0x2; | |
341 static const uint32_t kElfMachIA32 = 3; | |
342 static const uint32_t kElfMachX64 = 62; | |
343 static const uint32_t kElfMachARM = 40; | |
344 static const uint32_t kElfMachMIPS = 10; | |
345 | |
346 struct jitheader { | |
347 uint32_t magic; | |
348 uint32_t version; | |
349 uint32_t total_size; | |
350 uint32_t elf_mach; | |
351 uint32_t pad1; | |
352 uint32_t pid; | |
353 uint64_t timestamp; | |
354 }; | |
355 | |
356 enum jit_record_type { | |
357 JIT_CODE_LOAD = 0 | |
358 // JIT_CODE_UNLOAD = 1, | |
359 // JIT_CODE_CLOSE = 2, | |
360 // JIT_CODE_DEBUG_INFO = 3, | |
361 // JIT_CODE_PAGE_MAP = 4, | |
362 // JIT_CODE_MAX = 5 | |
363 }; | |
364 | |
365 struct jr_code_load { | |
366 uint32_t id; | |
367 uint32_t total_size; | |
368 uint64_t timestamp; | |
369 uint64_t vma; | |
370 uint64_t code_addr; | |
371 uint32_t code_size; | |
372 uint32_t align; | |
373 }; | |
374 | |
375 uint32_t GetElfMach() { | |
376 #if V8_TARGET_ARCH_IA32 | |
377 return kElfMachIA32; | |
378 #elif V8_TARGET_ARCH_X64 | |
379 return kElfMachX64; | |
380 #elif V8_TARGET_ARCH_ARM | |
381 return kElfMachARM; | |
382 #elif V8_TARGET_ARCH_MIPS | |
383 return kElfMachMIPS; | |
384 #else | |
385 UNIMPLEMENTED(); | |
386 return 0; | |
387 #endif | |
388 } | |
389 | |
390 FILE* perf_output_handle_; | |
391 }; | |
392 | |
393 const char PerfJitLogger::kFilenameFormatString[] = "/tmp/jit-%d.dump"; | |
394 | |
395 // Extra padding for the PID in the filename | |
396 const int PerfJitLogger::kFilenameBufferPadding = 16; | |
397 | |
398 PerfJitLogger::PerfJitLogger() | |
399 : perf_output_handle_(NULL) { | |
400 // Open the perf JIT dump file. | |
401 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; | |
402 ScopedVector<char> perf_dump_name(bufferSize); | |
403 int size = OS::SNPrintF( | |
404 perf_dump_name, | |
danno
2013/11/13 17:18:10
Indent 4 characters on line continuations
| |
405 kFilenameFormatString, | |
406 OS::GetCurrentProcessId()); | |
407 CHECK_NE(size, -1); | |
408 perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode); | |
409 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); | |
410 | |
411 LogWriteHeader(); | |
412 } | |
413 | |
414 | |
415 PerfJitLogger::~PerfJitLogger() { | |
416 fclose(perf_output_handle_); | |
417 perf_output_handle_ = NULL; | |
418 } | |
419 | |
420 | |
421 void PerfJitLogger::LogRecordedBuffer(Code* code, | |
422 SharedFunctionInfo*, | |
danno
2013/11/13 17:18:10
nit: indentation one char too many on this line an
| |
423 const char* name, | |
424 int length) { | |
425 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); | |
426 ASSERT(perf_output_handle_ != NULL); | |
427 | |
428 const char* code_name = name; | |
429 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start()); | |
430 uint32_t code_size = code->instruction_size(); | |
431 | |
432 static const char string_terminator[] = "\0"; | |
433 | |
434 jr_code_load code_load; | |
435 code_load.id = JIT_CODE_LOAD; | |
436 code_load.total_size = sizeof(code_load) + length + 1 + code_size; | |
437 code_load.timestamp = (uint64_t)(OS::TimeCurrentMillis() * 1000.0); | |
438 code_load.vma = 0x0; // Our addresses are absolute. | |
439 code_load.code_addr = reinterpret_cast<uint64_t>(code->instruction_start()); | |
440 code_load.code_size = code_size; | |
441 code_load.align = 0; | |
442 | |
443 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load)); | |
444 LogWriteBytes(code_name, length); | |
445 LogWriteBytes(string_terminator, 1); | |
446 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size); | |
447 } | |
448 | |
449 | |
450 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { | |
451 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); | |
452 ASSERT(static_cast<size_t>(size) == rv); | |
bnoordhuis
2013/11/13 23:40:52
I don't think that's a safe assumption to make. f
| |
453 USE(rv); | |
454 } | |
455 | |
456 | |
457 void PerfJitLogger::LogWriteHeader() { | |
458 ASSERT(perf_output_handle_ != NULL); | |
459 jitheader header; | |
460 header.magic = kJitHeaderMagic; | |
461 header.version = kJitHeaderVersion; | |
462 header.total_size = sizeof(jitheader); | |
463 header.pad1 = 0xdeadbeef; | |
464 header.elf_mach = GetElfMach(); | |
465 header.pid = OS::GetCurrentProcessId(); | |
466 header.timestamp = (uint64_t)(OS::TimeCurrentMillis() * 1000.0); | |
467 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); | |
468 } | |
469 | |
470 | |
249 // Low-level logging support. | 471 // Low-level logging support. |
250 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; | 472 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; |
251 | 473 |
252 class LowLevelLogger : public CodeEventLogger { | 474 class LowLevelLogger : public CodeEventLogger { |
253 public: | 475 public: |
254 explicit LowLevelLogger(const char* file_name); | 476 explicit LowLevelLogger(const char* file_name); |
255 virtual ~LowLevelLogger(); | 477 virtual ~LowLevelLogger(); |
256 | 478 |
257 virtual void CodeMoveEvent(Address from, Address to); | 479 virtual void CodeMoveEvent(Address from, Address to); |
258 virtual void CodeDeleteEvent(Address from); | 480 virtual void CodeDeleteEvent(Address from); |
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
704 // Logger class implementation. | 926 // Logger class implementation. |
705 // | 927 // |
706 | 928 |
707 Logger::Logger(Isolate* isolate) | 929 Logger::Logger(Isolate* isolate) |
708 : isolate_(isolate), | 930 : isolate_(isolate), |
709 ticker_(NULL), | 931 ticker_(NULL), |
710 profiler_(NULL), | 932 profiler_(NULL), |
711 log_events_(NULL), | 933 log_events_(NULL), |
712 is_logging_(false), | 934 is_logging_(false), |
713 log_(new Log(this)), | 935 log_(new Log(this)), |
936 perf_basic_logger_(NULL), | |
937 perf_jit_logger_(NULL), | |
714 ll_logger_(NULL), | 938 ll_logger_(NULL), |
715 jit_logger_(NULL), | 939 jit_logger_(NULL), |
716 listeners_(5), | 940 listeners_(5), |
717 is_initialized_(false) { | 941 is_initialized_(false) { |
718 } | 942 } |
719 | 943 |
720 | 944 |
721 Logger::~Logger() { | 945 Logger::~Logger() { |
722 delete log_; | 946 delete log_; |
723 } | 947 } |
(...skipping 1113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1837 | 2061 |
1838 // --ll-prof implies --log-code and --log-snapshot-positions. | 2062 // --ll-prof implies --log-code and --log-snapshot-positions. |
1839 if (FLAG_ll_prof) { | 2063 if (FLAG_ll_prof) { |
1840 FLAG_log_snapshot_positions = true; | 2064 FLAG_log_snapshot_positions = true; |
1841 } | 2065 } |
1842 | 2066 |
1843 SmartArrayPointer<const char> log_file_name = | 2067 SmartArrayPointer<const char> log_file_name = |
1844 PrepareLogFileName(isolate, FLAG_logfile); | 2068 PrepareLogFileName(isolate, FLAG_logfile); |
1845 log_->Initialize(*log_file_name); | 2069 log_->Initialize(*log_file_name); |
1846 | 2070 |
2071 | |
2072 if (FLAG_perf_basic_prof) { | |
2073 perf_basic_logger_ = new PerfBasicLogger(); | |
2074 addCodeEventListener(perf_basic_logger_); | |
2075 } | |
2076 | |
2077 if (FLAG_perf_jit_prof) { | |
2078 perf_jit_logger_ = new PerfJitLogger(); | |
2079 addCodeEventListener(perf_jit_logger_); | |
2080 } | |
2081 | |
1847 if (FLAG_ll_prof) { | 2082 if (FLAG_ll_prof) { |
1848 ll_logger_ = new LowLevelLogger(*log_file_name); | 2083 ll_logger_ = new LowLevelLogger(*log_file_name); |
1849 addCodeEventListener(ll_logger_); | 2084 addCodeEventListener(ll_logger_); |
1850 } | 2085 } |
1851 | 2086 |
1852 ticker_ = new Ticker(isolate, kSamplingIntervalMs); | 2087 ticker_ = new Ticker(isolate, kSamplingIntervalMs); |
1853 | 2088 |
1854 if (Log::InitLogAtStart()) { | 2089 if (Log::InitLogAtStart()) { |
1855 is_logging_ = true; | 2090 is_logging_ = true; |
1856 } | 2091 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1899 // Stop the profiler before closing the file. | 2134 // Stop the profiler before closing the file. |
1900 if (profiler_ != NULL) { | 2135 if (profiler_ != NULL) { |
1901 profiler_->Disengage(); | 2136 profiler_->Disengage(); |
1902 delete profiler_; | 2137 delete profiler_; |
1903 profiler_ = NULL; | 2138 profiler_ = NULL; |
1904 } | 2139 } |
1905 | 2140 |
1906 delete ticker_; | 2141 delete ticker_; |
1907 ticker_ = NULL; | 2142 ticker_ = NULL; |
1908 | 2143 |
2144 if (perf_basic_logger_) { | |
2145 removeCodeEventListener(perf_basic_logger_); | |
2146 delete perf_basic_logger_; | |
2147 perf_basic_logger_ = NULL; | |
2148 } | |
2149 | |
2150 if (perf_jit_logger_) { | |
2151 removeCodeEventListener(perf_jit_logger_); | |
2152 delete perf_jit_logger_; | |
2153 perf_jit_logger_ = NULL; | |
2154 } | |
2155 | |
1909 if (ll_logger_) { | 2156 if (ll_logger_) { |
1910 removeCodeEventListener(ll_logger_); | 2157 removeCodeEventListener(ll_logger_); |
1911 delete ll_logger_; | 2158 delete ll_logger_; |
1912 ll_logger_ = NULL; | 2159 ll_logger_ = NULL; |
1913 } | 2160 } |
1914 | 2161 |
1915 if (jit_logger_) { | 2162 if (jit_logger_) { |
1916 removeCodeEventListener(jit_logger_); | 2163 removeCodeEventListener(jit_logger_); |
1917 delete jit_logger_; | 2164 delete jit_logger_; |
1918 jit_logger_ = NULL; | 2165 jit_logger_ = NULL; |
1919 } | 2166 } |
1920 | 2167 |
1921 return log_->Close(); | 2168 return log_->Close(); |
1922 } | 2169 } |
1923 | 2170 |
1924 } } // namespace v8::internal | 2171 } } // namespace v8::internal |
OLD | NEW |