perfevent.cc revision 9651:f551c8ad12a5
1/* 2 * Copyright (c) 2012 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andreas Sandberg 38 */ 39 40#include <sys/ioctl.h> 41#include <sys/mman.h> 42#include <sys/syscall.h> 43#include <sys/types.h> 44#include <fcntl.h> 45#include <syscall.h> 46#include <unistd.h> 47 48#include <cassert> 49#include <cerrno> 50#include <csignal> 51#include <cstring> 52 53#include "base/misc.hh" 54#include "perfevent.hh" 55 56PerfKvmCounterConfig::PerfKvmCounterConfig(uint32_t type, uint64_t config) 57{ 58 memset(&attr, 0, sizeof(attr)); 59 60 attr.size = PERF_ATTR_SIZE_VER0; 61 attr.type = type; 62 attr.config = config; 63} 64 65PerfKvmCounterConfig::~PerfKvmCounterConfig() 66{ 67} 68 69 70PerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, pid_t tid) 71 : fd(-1), ringBuffer(NULL), pageSize(-1) 72{ 73 attach(config, tid, -1); 74} 75 76PerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, 77 pid_t tid, const PerfKvmCounter &parent) 78 : fd(-1), ringBuffer(NULL), pageSize(-1) 79{ 80 attach(config, tid, parent); 81} 82 83PerfKvmCounter::PerfKvmCounter() 84 : fd(-1), ringBuffer(NULL), pageSize(-1) 85{ 86} 87 88PerfKvmCounter::~PerfKvmCounter() 89{ 90 if (attached()) 91 detach(); 92} 93 94void 95PerfKvmCounter::detach() 96{ 97 assert(attached()); 98 99 if (munmap(ringBuffer, ringNumPages * pageSize) == -1) 100 warn("PerfKvmCounter: Failed to unmap ring buffer (%i)\n", 101 errno); 102 close(fd); 103 104 fd = -1; 105 ringBuffer = NULL; 106} 107 108void 109PerfKvmCounter::start() 110{ 111 if (ioctl(PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) 112 panic("KVM: Failed to enable performance counters (%i)\n", errno); 113} 114 115void 116PerfKvmCounter::stop() 117{ 118 if (ioctl(PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) 119 panic("KVM: Failed to disable performance counters (%i)\n", errno); 120} 121 122void 123PerfKvmCounter::period(uint64_t period) 124{ 125 if (ioctl(PERF_EVENT_IOC_PERIOD, &period) == -1) 126 panic("KVM: Failed to set period of performance counter (%i)\n", errno); 127} 128 129void 130PerfKvmCounter::refresh(int refresh) 131{ 132 if (ioctl(PERF_EVENT_IOC_REFRESH, refresh) == -1) 133 panic("KVM: Failed to refresh performance counter (%i)\n", errno); 134} 135 136uint64_t 137PerfKvmCounter::read() const 138{ 139 uint64_t value; 140 141 read(&value, sizeof(uint64_t)); 142 return value; 143} 144 145void 146PerfKvmCounter::enableSignals(pid_t tid, int signal) 147{ 148 struct f_owner_ex sigowner; 149 150 sigowner.type = F_OWNER_TID; 151 sigowner.pid = tid; 152 153 if (fcntl(F_SETOWN_EX, &sigowner) == -1 || 154 fcntl(F_SETSIG, signal) == -1 || 155 fcntl(F_SETFL, O_ASYNC) == -1) 156 panic("PerfKvmCounter: Failed to enable signals for counter (%i)\n", 157 errno); 158} 159 160void 161PerfKvmCounter::attach(PerfKvmCounterConfig &config, 162 pid_t tid, int group_fd) 163{ 164 assert(!attached()); 165 166 fd = syscall(__NR_perf_event_open, 167 &config.attr, tid, 168 -1, // CPU (-1 => Any CPU that the task happens to run on) 169 group_fd, 170 0); // Flags 171 if (fd == -1) 172 panic("PerfKvmCounter::open failed (%i)\n", errno); 173 174 mmapPerf(1); 175} 176 177pid_t 178PerfKvmCounter::gettid() 179{ 180 return syscall(__NR_gettid); 181} 182 183void 184PerfKvmCounter::mmapPerf(int pages) 185{ 186 assert(attached()); 187 assert(ringBuffer == NULL); 188 189 if (pageSize == -1) { 190 pageSize = sysconf(_SC_PAGE_SIZE); 191 if (pageSize == -1) 192 panic("PerfKvmCounter: Failed to determine page size (%i)\n", 193 errno); 194 } 195 196 ringNumPages = pages + 1; 197 ringBuffer = (struct perf_event_mmap_page *)mmap( 198 NULL, ringNumPages * 4096, 199 PROT_READ | PROT_WRITE, MAP_SHARED, 200 fd, 0); 201 if (ringBuffer == MAP_FAILED) 202 panic("PerfKvmCounter: MMAP failed (%i)\n", 203 errno); 204} 205 206int 207PerfKvmCounter::fcntl(int cmd, long p1) 208{ 209 assert(attached()); 210 return ::fcntl(fd, cmd, p1); 211} 212 213int 214PerfKvmCounter::ioctl(int request, long p1) 215{ 216 assert(attached()); 217 return ::ioctl(fd, request, p1); 218} 219 220void 221PerfKvmCounter::read(void *buf, size_t size) const 222{ 223 char *_buf = (char *)buf; 224 size_t _size = size; 225 226 assert(attached()); 227 228 do { 229 ssize_t ret; 230 ret = ::read(fd, _buf, _size); 231 switch (ret) { 232 case -1: 233 if (errno != EAGAIN) 234 panic("PerfKvmCounter::read failed (%i)\n", errno); 235 break; 236 237 case 0: 238 panic("PerfKvmCounter::read unexpected EOF.\n"); 239 240 default: 241 _size -= ret; 242 _buf += ret; 243 break; 244 } 245 } while(_size); 246} 247