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" | |
19 #include "src/runtime-profiler.h" | 18 #include "src/runtime-profiler.h" |
20 #include "src/serialize.h" | 19 #include "src/serialize.h" |
21 #include "src/string-stream.h" | 20 #include "src/string-stream.h" |
22 #include "src/vm-state-inl.h" | 21 #include "src/vm-state-inl.h" |
23 | 22 |
24 namespace v8 { | 23 namespace v8 { |
25 namespace internal { | 24 namespace internal { |
26 | 25 |
27 | 26 |
28 #define DECLARE_EVENT(ignore1, name) name, | 27 #define DECLARE_EVENT(ignore1, name) name, |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 const char* name, | 282 const char* name, |
284 int length) { | 283 int length) { |
285 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); | 284 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); |
286 | 285 |
287 base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n", | 286 base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n", |
288 reinterpret_cast<uint64_t>(code->instruction_start()), | 287 reinterpret_cast<uint64_t>(code->instruction_start()), |
289 code->instruction_size(), length, name); | 288 code->instruction_size(), length, name); |
290 } | 289 } |
291 | 290 |
292 | 291 |
| 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 |
293 // Low-level logging support. | 458 // Low-level logging support. |
294 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; | 459 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; |
295 | 460 |
296 class LowLevelLogger : public CodeEventLogger { | 461 class LowLevelLogger : public CodeEventLogger { |
297 public: | 462 public: |
298 explicit LowLevelLogger(const char* file_name); | 463 explicit LowLevelLogger(const char* file_name); |
299 virtual ~LowLevelLogger(); | 464 virtual ~LowLevelLogger(); |
300 | 465 |
301 virtual void CodeMoveEvent(Address from, Address to); | 466 virtual void CodeMoveEvent(Address from, Address to); |
302 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } | 467 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } |
(...skipping 1658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1961 if (jit_logger_) { | 2126 if (jit_logger_) { |
1962 removeCodeEventListener(jit_logger_); | 2127 removeCodeEventListener(jit_logger_); |
1963 delete jit_logger_; | 2128 delete jit_logger_; |
1964 jit_logger_ = NULL; | 2129 jit_logger_ = NULL; |
1965 } | 2130 } |
1966 | 2131 |
1967 return log_->Close(); | 2132 return log_->Close(); |
1968 } | 2133 } |
1969 | 2134 |
1970 } } // namespace v8::internal | 2135 } } // namespace v8::internal |
OLD | NEW |