| 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 |