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