OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdarg.h> | 5 #include <stdarg.h> |
6 | 6 |
7 #include "src/v8.h" | 7 #include "src/v8.h" |
8 | 8 |
9 #include "src/base/platform/platform.h" | 9 #include "src/base/platform/platform.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
11 #include "src/code-stubs.h" | 11 #include "src/code-stubs.h" |
12 #include "src/cpu-profiler.h" | 12 #include "src/cpu-profiler.h" |
13 #include "src/deoptimizer.h" | 13 #include "src/deoptimizer.h" |
14 #include "src/global-handles.h" | 14 #include "src/global-handles.h" |
15 #include "src/log.h" | 15 #include "src/log.h" |
16 #include "src/log-utils.h" | 16 #include "src/log-utils.h" |
17 #include "src/macro-assembler.h" | 17 #include "src/macro-assembler.h" |
| 18 #include "src/perf-jit.h" |
18 #include "src/runtime-profiler.h" | 19 #include "src/runtime-profiler.h" |
19 #include "src/serialize.h" | 20 #include "src/serialize.h" |
20 #include "src/string-stream.h" | 21 #include "src/string-stream.h" |
21 #include "src/vm-state-inl.h" | 22 #include "src/vm-state-inl.h" |
22 | 23 |
23 namespace v8 { | 24 namespace v8 { |
24 namespace internal { | 25 namespace internal { |
25 | 26 |
26 | 27 |
27 #define DECLARE_EVENT(ignore1, name) name, | 28 #define DECLARE_EVENT(ignore1, name) name, |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 const char* name, | 283 const char* name, |
283 int length) { | 284 int length) { |
284 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); | 285 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); |
285 | 286 |
286 base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n", | 287 base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n", |
287 reinterpret_cast<uint64_t>(code->instruction_start()), | 288 reinterpret_cast<uint64_t>(code->instruction_start()), |
288 code->instruction_size(), length, name); | 289 code->instruction_size(), length, name); |
289 } | 290 } |
290 | 291 |
291 | 292 |
292 // Linux perf tool logging support | |
293 class PerfJitLogger : public CodeEventLogger { | |
294 public: | |
295 PerfJitLogger(); | |
296 virtual ~PerfJitLogger(); | |
297 | |
298 virtual void CodeMoveEvent(Address from, Address to) { } | |
299 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } | |
300 virtual void CodeDeleteEvent(Address from) { } | |
301 | |
302 private: | |
303 virtual void LogRecordedBuffer(Code* code, | |
304 SharedFunctionInfo* shared, | |
305 const char* name, | |
306 int length); | |
307 | |
308 // Extension added to V8 log file name to get the low-level log name. | |
309 static const char kFilenameFormatString[]; | |
310 static const int kFilenameBufferPadding; | |
311 | |
312 // File buffer size of the low-level log. We don't use the default to | |
313 // minimize the associated overhead. | |
314 static const int kLogBufferSize = 2 * MB; | |
315 | |
316 void LogWriteBytes(const char* bytes, int size); | |
317 void LogWriteHeader(); | |
318 | |
319 static const uint32_t kJitHeaderMagic = 0x4F74496A; | |
320 static const uint32_t kJitHeaderVersion = 0x2; | |
321 static const uint32_t kElfMachIA32 = 3; | |
322 static const uint32_t kElfMachX64 = 62; | |
323 static const uint32_t kElfMachARM = 40; | |
324 static const uint32_t kElfMachMIPS = 10; | |
325 static const uint32_t kElfMachX87 = 3; | |
326 | |
327 struct jitheader { | |
328 uint32_t magic; | |
329 uint32_t version; | |
330 uint32_t total_size; | |
331 uint32_t elf_mach; | |
332 uint32_t pad1; | |
333 uint32_t pid; | |
334 uint64_t timestamp; | |
335 }; | |
336 | |
337 enum jit_record_type { | |
338 JIT_CODE_LOAD = 0 | |
339 // JIT_CODE_UNLOAD = 1, | |
340 // JIT_CODE_CLOSE = 2, | |
341 // JIT_CODE_DEBUG_INFO = 3, | |
342 // JIT_CODE_PAGE_MAP = 4, | |
343 // JIT_CODE_MAX = 5 | |
344 }; | |
345 | |
346 struct jr_code_load { | |
347 uint32_t id; | |
348 uint32_t total_size; | |
349 uint64_t timestamp; | |
350 uint64_t vma; | |
351 uint64_t code_addr; | |
352 uint32_t code_size; | |
353 uint32_t align; | |
354 }; | |
355 | |
356 uint32_t GetElfMach() { | |
357 #if V8_TARGET_ARCH_IA32 | |
358 return kElfMachIA32; | |
359 #elif V8_TARGET_ARCH_X64 | |
360 return kElfMachX64; | |
361 #elif V8_TARGET_ARCH_ARM | |
362 return kElfMachARM; | |
363 #elif V8_TARGET_ARCH_MIPS | |
364 return kElfMachMIPS; | |
365 #elif V8_TARGET_ARCH_X87 | |
366 return kElfMachX87; | |
367 #else | |
368 UNIMPLEMENTED(); | |
369 return 0; | |
370 #endif | |
371 } | |
372 | |
373 FILE* perf_output_handle_; | |
374 }; | |
375 | |
376 const char PerfJitLogger::kFilenameFormatString[] = "/tmp/jit-%d.dump"; | |
377 | |
378 // Extra padding for the PID in the filename | |
379 const int PerfJitLogger::kFilenameBufferPadding = 16; | |
380 | |
381 PerfJitLogger::PerfJitLogger() | |
382 : perf_output_handle_(NULL) { | |
383 // Open the perf JIT dump file. | |
384 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; | |
385 ScopedVector<char> perf_dump_name(bufferSize); | |
386 int size = SNPrintF( | |
387 perf_dump_name, | |
388 kFilenameFormatString, | |
389 base::OS::GetCurrentProcessId()); | |
390 CHECK_NE(size, -1); | |
391 perf_output_handle_ = | |
392 base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode); | |
393 CHECK_NE(perf_output_handle_, NULL); | |
394 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); | |
395 | |
396 LogWriteHeader(); | |
397 } | |
398 | |
399 | |
400 PerfJitLogger::~PerfJitLogger() { | |
401 fclose(perf_output_handle_); | |
402 perf_output_handle_ = NULL; | |
403 } | |
404 | |
405 | |
406 void PerfJitLogger::LogRecordedBuffer(Code* code, | |
407 SharedFunctionInfo*, | |
408 const char* name, | |
409 int length) { | |
410 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); | |
411 ASSERT(perf_output_handle_ != NULL); | |
412 | |
413 const char* code_name = name; | |
414 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start()); | |
415 uint32_t code_size = code->instruction_size(); | |
416 | |
417 static const char string_terminator[] = "\0"; | |
418 | |
419 jr_code_load code_load; | |
420 code_load.id = JIT_CODE_LOAD; | |
421 code_load.total_size = sizeof(code_load) + length + 1 + code_size; | |
422 code_load.timestamp = | |
423 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); | |
424 code_load.vma = 0x0; // Our addresses are absolute. | |
425 code_load.code_addr = reinterpret_cast<uint64_t>(code->instruction_start()); | |
426 code_load.code_size = code_size; | |
427 code_load.align = 0; | |
428 | |
429 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load)); | |
430 LogWriteBytes(code_name, length); | |
431 LogWriteBytes(string_terminator, 1); | |
432 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size); | |
433 } | |
434 | |
435 | |
436 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { | |
437 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); | |
438 ASSERT(static_cast<size_t>(size) == rv); | |
439 USE(rv); | |
440 } | |
441 | |
442 | |
443 void PerfJitLogger::LogWriteHeader() { | |
444 ASSERT(perf_output_handle_ != NULL); | |
445 jitheader header; | |
446 header.magic = kJitHeaderMagic; | |
447 header.version = kJitHeaderVersion; | |
448 header.total_size = sizeof(jitheader); | |
449 header.pad1 = 0xdeadbeef; | |
450 header.elf_mach = GetElfMach(); | |
451 header.pid = base::OS::GetCurrentProcessId(); | |
452 header.timestamp = | |
453 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); | |
454 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); | |
455 } | |
456 | |
457 | |
458 // Low-level logging support. | 293 // Low-level logging support. |
459 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; | 294 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; |
460 | 295 |
461 class LowLevelLogger : public CodeEventLogger { | 296 class LowLevelLogger : public CodeEventLogger { |
462 public: | 297 public: |
463 explicit LowLevelLogger(const char* file_name); | 298 explicit LowLevelLogger(const char* file_name); |
464 virtual ~LowLevelLogger(); | 299 virtual ~LowLevelLogger(); |
465 | 300 |
466 virtual void CodeMoveEvent(Address from, Address to); | 301 virtual void CodeMoveEvent(Address from, Address to); |
467 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } | 302 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } |
(...skipping 1658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2126 if (jit_logger_) { | 1961 if (jit_logger_) { |
2127 removeCodeEventListener(jit_logger_); | 1962 removeCodeEventListener(jit_logger_); |
2128 delete jit_logger_; | 1963 delete jit_logger_; |
2129 jit_logger_ = NULL; | 1964 jit_logger_ = NULL; |
2130 } | 1965 } |
2131 | 1966 |
2132 return log_->Close(); | 1967 return log_->Close(); |
2133 } | 1968 } |
2134 | 1969 |
2135 } } // namespace v8::internal | 1970 } } // namespace v8::internal |
OLD | NEW |