blob: 3b9da1dc6592d9db64b5094e06e24354c5da77c5 [file] [log] [blame]
Jon Medhurst15ce78d2014-04-10 09:02:02 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2013-2015. All rights reserved.
Jon Medhurst15ce78d2014-04-10 09:02:02 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfBuffer.h"
10
11#include <sys/ioctl.h>
12#include <sys/mman.h>
13
14#include "Buffer.h"
15#include "Logging.h"
16#include "Sender.h"
17#include "SessionData.h"
18
19PerfBuffer::PerfBuffer() {
20 for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
21 mBuf[cpu] = MAP_FAILED;
22 mDiscard[cpu] = false;
Jon Medhurst96b56152014-10-30 18:01:15 +000023 mFds[cpu] = -1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010024 }
25}
26
27PerfBuffer::~PerfBuffer() {
28 for (int cpu = ARRAY_LENGTH(mBuf) - 1; cpu >= 0; --cpu) {
29 if (mBuf[cpu] != MAP_FAILED) {
30 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
31 }
32 }
33}
34
Jon Medhurst96b56152014-10-30 18:01:15 +000035bool PerfBuffer::useFd(const int cpu, const int fd) {
36 if (mFds[cpu] < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010037 if (mBuf[cpu] != MAP_FAILED) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010038 logg->logMessage("cpu %i already online or not correctly cleaned up", cpu);
Jon Medhurst15ce78d2014-04-10 09:02:02 +010039 return false;
40 }
41
42 // The buffer isn't mapped yet
43 mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
44 if (mBuf[cpu] == MAP_FAILED) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010045 logg->logMessage("mmap failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010046 return false;
47 }
Jon Medhurst96b56152014-10-30 18:01:15 +000048 mFds[cpu] = fd;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010049
50 // Check the version
51 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
52 if (pemp->compat_version != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010053 logg->logMessage("Incompatible perf_event_mmap_page compat_version");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010054 return false;
55 }
56 } else {
57 if (mBuf[cpu] == MAP_FAILED) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010058 logg->logMessage("cpu already online or not correctly cleaned up");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010059 return false;
60 }
61
Jon Medhurst96b56152014-10-30 18:01:15 +000062 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, mFds[cpu]) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010063 logg->logMessage("ioctl failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010064 return false;
65 }
66 }
67
68 return true;
69}
70
71void PerfBuffer::discard(const int cpu) {
72 if (mBuf[cpu] != MAP_FAILED) {
73 mDiscard[cpu] = true;
74 }
75}
76
77bool PerfBuffer::isEmpty() {
78 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
79 if (mBuf[cpu] != MAP_FAILED) {
80 // Take a snapshot of the positions
81 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
Jon Medhurstb1d07442015-05-08 12:04:18 +010082 const __u64 head = ACCESS_ONCE(pemp->data_head);
83 const __u64 tail = ACCESS_ONCE(pemp->data_tail);
Jon Medhurst15ce78d2014-04-10 09:02:02 +010084
85 if (head != tail) {
86 return false;
87 }
88 }
89 }
90
91 return true;
92}
93
Jon Medhurstb1d07442015-05-08 12:04:18 +010094bool PerfBuffer::isFull() {
95 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
96 if (mBuf[cpu] != MAP_FAILED) {
97 // Take a snapshot of the positions
98 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
99 const __u64 head = ACCESS_ONCE(pemp->data_head);
Jon Medhurst96b56152014-10-30 18:01:15 +0000100
Jon Medhurstb1d07442015-05-08 12:04:18 +0100101 if (head + 2000 <= (unsigned int)BUF_SIZE) {
102 return true;
103 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000104 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100105 }
106
107 return false;
108}
109
110class PerfFrame {
111public:
112 PerfFrame(Sender *const sender) : mSender(sender), mWritePos(-1), mCpuSizePos(-1) {}
113
114 void add(const int cpu, const __u64 head, __u64 tail, const uint8_t *const b) {
115 cpuHeader(cpu);
Jon Medhurst96b56152014-10-30 18:01:15 +0000116
117 while (head > tail) {
118 const int count = reinterpret_cast<const struct perf_event_header *>(b + (tail & BUF_MASK))->size/sizeof(uint64_t);
119 // Can this whole message be written as Streamline assumes events are not split between frames
Jon Medhurstb1d07442015-05-08 12:04:18 +0100120 if (sizeof(mBuf) <= mWritePos + count*Buffer::MAXSIZE_PACK64) {
121 send();
122 cpuHeader(cpu);
Jon Medhurst96b56152014-10-30 18:01:15 +0000123 }
124 for (int i = 0; i < count; ++i) {
125 // Must account for message size
Jon Medhurstb1d07442015-05-08 12:04:18 +0100126 Buffer::packInt64(mBuf, sizeof(mBuf), mWritePos, *reinterpret_cast<const uint64_t *>(b + (tail & BUF_MASK)));
Jon Medhurst96b56152014-10-30 18:01:15 +0000127 tail += sizeof(uint64_t);
128 }
129 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000130 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100131
132 void send() {
133 if (mWritePos > 0) {
134 writeFrameSize();
135 mSender->writeData(mBuf, mWritePos, RESPONSE_APC_DATA);
136 mWritePos = -1;
137 mCpuSizePos = -1;
138 }
139 }
140
141private:
142 void writeFrameSize() {
143 writeCpuSize();
144 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
145 Buffer::writeLEInt(reinterpret_cast<unsigned char *>(mBuf + typeLength), mWritePos - typeLength - sizeof(uint32_t));
146 }
147
148 void frameHeader() {
149 if (mWritePos < 0) {
150 mWritePos = 0;
151 mCpuSizePos = -1;
152 if (!gSessionData->mLocalCapture) {
153 mBuf[mWritePos++] = RESPONSE_APC_DATA;
154 }
155 // Reserve space for frame size
156 mWritePos += sizeof(uint32_t);
157 Buffer::packInt(mBuf, sizeof(mBuf), mWritePos, FRAME_PERF);
158 }
159 }
160
161 void writeCpuSize() {
162 if (mCpuSizePos >= 0) {
163 Buffer::writeLEInt(reinterpret_cast<unsigned char *>(mBuf + mCpuSizePos), mWritePos - mCpuSizePos - sizeof(uint32_t));
164 }
165 }
166
167 void cpuHeader(const int cpu) {
168 if (sizeof(mBuf) <= mWritePos + Buffer::MAXSIZE_PACK32 + sizeof(uint32_t)) {
169 send();
170 }
171 frameHeader();
172 writeCpuSize();
173 Buffer::packInt(mBuf, sizeof(mBuf), mWritePos, cpu);
174 mCpuSizePos = mWritePos;
175 // Reserve space for cpu size
176 mWritePos += sizeof(uint32_t);
177 }
178
179 // Pick a big size but something smaller than the chunkSize in Sender::writeData which is 100k
180 char mBuf[1<<16];
181 Sender *const mSender;
182 int mWritePos;
183 int mCpuSizePos;
184
185 // Intentionally unimplemented
186 PerfFrame(const PerfFrame &);
187 PerfFrame& operator=(const PerfFrame &);
188};
Jon Medhurst96b56152014-10-30 18:01:15 +0000189
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100190bool PerfBuffer::send(Sender *const sender) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100191 PerfFrame frame(sender);
192
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100193 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
194 if (mBuf[cpu] == MAP_FAILED) {
195 continue;
196 }
197
198 // Take a snapshot of the positions
199 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100200 const __u64 head = ACCESS_ONCE(pemp->data_head);
201 const __u64 tail = ACCESS_ONCE(pemp->data_tail);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100202
203 if (head > tail) {
204 const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
Jon Medhurstb1d07442015-05-08 12:04:18 +0100205 frame.add(cpu, head, tail, b);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100206
207 // Update tail with the data read
208 pemp->data_tail = head;
209 }
210
211 if (mDiscard[cpu]) {
212 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
213 mBuf[cpu] = MAP_FAILED;
214 mDiscard[cpu] = false;
Jon Medhurst96b56152014-10-30 18:01:15 +0000215 mFds[cpu] = -1;
Jon Medhurstb1d07442015-05-08 12:04:18 +0100216 logg->logMessage("Unmaped cpu %i", cpu);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100217 }
218 }
219
Jon Medhurstb1d07442015-05-08 12:04:18 +0100220 frame.send();
221
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100222 return true;
223}