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