1// Copyright 2014 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "src/perf-jit.h" 29 30#if V8_OS_LINUX 31#include <fcntl.h> 32#include <unistd.h> 33#include "src/third_party/kernel/tools/perf/util/jitdump.h" 34#endif // V8_OS_LINUX 35 36namespace v8 { 37namespace internal { 38 39#if V8_OS_LINUX 40 41const char PerfJitLogger::kFilenameFormatString[] = "perfjit-%d.dump"; 42 43// Extra padding for the PID in the filename 44const int PerfJitLogger::kFilenameBufferPadding = 16; 45 46 47PerfJitLogger::PerfJitLogger() : perf_output_handle_(NULL), code_index_(0) { 48 if (!base::TimeTicks::KernelTimestampAvailable()) { 49 FATAL("Cannot profile with perf JIT - kernel timestamps not available."); 50 } 51 52 // Open the perf JIT dump file. 53 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; 54 ScopedVector<char> perf_dump_name(bufferSize); 55 int size = SNPrintF(perf_dump_name, kFilenameFormatString, 56 base::OS::GetCurrentProcessId()); 57 CHECK_NE(size, -1); 58 perf_output_handle_ = 59 base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode); 60 CHECK_NE(perf_output_handle_, NULL); 61 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); 62 63 LogWriteHeader(); 64} 65 66 67PerfJitLogger::~PerfJitLogger() { 68 fclose(perf_output_handle_); 69 perf_output_handle_ = NULL; 70} 71 72 73uint64_t PerfJitLogger::GetTimestamp() { 74 return static_cast<int64_t>( 75 base::TimeTicks::KernelTimestampNow().ToInternalValue()); 76} 77 78 79void PerfJitLogger::LogRecordedBuffer(Code* code, SharedFunctionInfo*, 80 const char* name, int length) { 81 DCHECK(code->instruction_start() == code->address() + Code::kHeaderSize); 82 DCHECK(perf_output_handle_ != NULL); 83 84 const char* code_name = name; 85 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start()); 86 uint32_t code_size = code->is_crankshafted() ? code->safepoint_table_offset() 87 : code->instruction_size(); 88 89 static const char string_terminator[] = "\0"; 90 91 jr_code_load code_load; 92 code_load.p.id = JIT_CODE_LOAD; 93 code_load.p.total_size = sizeof(code_load) + length + 1 + code_size; 94 code_load.p.timestamp = GetTimestamp(); 95 code_load.pid = static_cast<uint32_t>(base::OS::GetCurrentProcessId()); 96 code_load.tid = static_cast<uint32_t>(base::OS::GetCurrentThreadId()); 97 code_load.vma = 0x0; // Our addresses are absolute. 98 code_load.code_addr = reinterpret_cast<uint64_t>(code_pointer); 99 code_load.code_size = code_size; 100 code_load.code_index = code_index_; 101 102 code_index_++; 103 104 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load)); 105 LogWriteBytes(code_name, length); 106 LogWriteBytes(string_terminator, 1); 107 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size); 108} 109 110 111void PerfJitLogger::CodeMoveEvent(Address from, Address to) { 112 // Code relocation not supported. 113 UNREACHABLE(); 114} 115 116 117void PerfJitLogger::CodeDeleteEvent(Address from) { 118 // V8 does not send notification on code unload 119} 120 121 122void PerfJitLogger::SnapshotPositionEvent(Address addr, int pos) {} 123 124 125void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { 126 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); 127 DCHECK(static_cast<size_t>(size) == rv); 128 USE(rv); 129} 130 131 132void PerfJitLogger::LogWriteHeader() { 133 DCHECK(perf_output_handle_ != NULL); 134 jitheader header; 135 header.magic = JITHEADER_MAGIC; 136 header.version = JITHEADER_VERSION; 137 header.total_size = sizeof(jitheader); 138 header.pad1 = 0xdeadbeef; 139 header.elf_mach = GetElfMach(); 140 header.pid = base::OS::GetCurrentProcessId(); 141 header.timestamp = 142 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); 143 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); 144} 145 146#endif // V8_OS_LINUX 147} 148} // namespace v8::internal 149