perfevent.cc revision 13787
12SN/A/* 29952Sdam.sunwoo@arm.com * Copyright (c) 2012 ARM Limited 39952Sdam.sunwoo@arm.com * All rights reserved 49952Sdam.sunwoo@arm.com * 59952Sdam.sunwoo@arm.com * The license below extends only to copyright in the software and shall 69952Sdam.sunwoo@arm.com * not be construed as granting a license to any other intellectual 79952Sdam.sunwoo@arm.com * property including but not limited to intellectual property relating 89952Sdam.sunwoo@arm.com * to a hardware implementation of the functionality of the software 99952Sdam.sunwoo@arm.com * licensed hereunder. You may use the software subject to the license 109952Sdam.sunwoo@arm.com * terms below provided that you ensure that this notice is replicated 119952Sdam.sunwoo@arm.com * unmodified and in its entirety in all distributions of the software, 129952Sdam.sunwoo@arm.com * modified or unmodified, in source code or in binary form. 139952Sdam.sunwoo@arm.com * 141762SN/A * Redistribution and use in source and binary forms, with or without 159983Sstever@gmail.com * modification, are permitted provided that the following conditions are 169983Sstever@gmail.com * met: redistributions of source code must retain the above copyright 172SN/A * notice, this list of conditions and the following disclaimer; 182SN/A * redistributions in binary form must reproduce the above copyright 192SN/A * notice, this list of conditions and the following disclaimer in the 202SN/A * documentation and/or other materials provided with the distribution; 212SN/A * neither the name of the copyright holders nor the names of its 222SN/A * contributors may be used to endorse or promote products derived from 232SN/A * this software without specific prior written permission. 242SN/A * 252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362SN/A * 372SN/A * Authors: Andreas Sandberg 382SN/A */ 392SN/A 402SN/A#include <fcntl.h> 412665Ssaidi@eecs.umich.edu#include <sys/ioctl.h> 422665Ssaidi@eecs.umich.edu#include <sys/mman.h> 432SN/A#include <sys/syscall.h> 442SN/A#include <sys/types.h> 4511793Sbrandon.potter@amd.com#include <syscall.h> 4611793Sbrandon.potter@amd.com#include <unistd.h> 472SN/A 482SN/A#include <cassert> 49601SN/A#include <cerrno> 50601SN/A#include <csignal> 519356Snilay@cs.wisc.edu#include <cstring> 5256SN/A 53695SN/A#include "base/logging.hh" 542SN/A#include "perfevent.hh" 552SN/A 562SN/APerfKvmCounterConfig::PerfKvmCounterConfig(uint32_t type, uint64_t config) 579983Sstever@gmail.com{ 589983Sstever@gmail.com memset(&attr, 0, sizeof(attr)); 5911070Sandreas.sandberg@arm.com 6011070Sandreas.sandberg@arm.com attr.size = PERF_ATTR_SIZE_VER0; 619983Sstever@gmail.com attr.type = type; 629983Sstever@gmail.com attr.config = config; 639983Sstever@gmail.com} 649983Sstever@gmail.com 6513694Sgabeblack@google.comPerfKvmCounterConfig::~PerfKvmCounterConfig() 6613694Sgabeblack@google.com{ 6713694Sgabeblack@google.com} 6813694Sgabeblack@google.com 6913694Sgabeblack@google.com 7013694Sgabeblack@google.comPerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, pid_t tid) 7113694Sgabeblack@google.com : fd(-1), ringBuffer(NULL), pageSize(-1) 729983Sstever@gmail.com{ 739983Sstever@gmail.com attach(config, tid, -1); 749983Sstever@gmail.com} 759983Sstever@gmail.com 769983Sstever@gmail.comPerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, 779983Sstever@gmail.com pid_t tid, const PerfKvmCounter &parent) 789983Sstever@gmail.com : fd(-1), ringBuffer(NULL), pageSize(-1) 799983Sstever@gmail.com{ 809983Sstever@gmail.com attach(config, tid, parent); 819983Sstever@gmail.com} 829983Sstever@gmail.com 839983Sstever@gmail.comPerfKvmCounter::PerfKvmCounter() 849983Sstever@gmail.com : fd(-1), ringBuffer(NULL), pageSize(-1) 859983Sstever@gmail.com{ 869983Sstever@gmail.com} 879983Sstever@gmail.com 889983Sstever@gmail.comPerfKvmCounter::~PerfKvmCounter() 899983Sstever@gmail.com{ 909983Sstever@gmail.com if (attached()) 919983Sstever@gmail.com detach(); 929983Sstever@gmail.com} 9311070Sandreas.sandberg@arm.com 9411070Sandreas.sandberg@arm.comvoid 9511070Sandreas.sandberg@arm.comPerfKvmCounter::detach() 969983Sstever@gmail.com{ 9711070Sandreas.sandberg@arm.com assert(attached()); 989952Sdam.sunwoo@arm.com 999952Sdam.sunwoo@arm.com if (munmap(ringBuffer, ringNumPages * pageSize) == -1) 10013694Sgabeblack@google.com warn("PerfKvmCounter: Failed to unmap ring buffer (%i)\n", 10113694Sgabeblack@google.com errno); 10213694Sgabeblack@google.com close(fd); 10313694Sgabeblack@google.com 10413694Sgabeblack@google.com fd = -1; 10513694Sgabeblack@google.com ringBuffer = NULL; 10613694Sgabeblack@google.com} 1079983Sstever@gmail.com 10811070Sandreas.sandberg@arm.comvoid 10911070Sandreas.sandberg@arm.comPerfKvmCounter::start() 1109952Sdam.sunwoo@arm.com{ 1115606Snate@binkert.org if (ioctl(PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) 1125606Snate@binkert.org panic("KVM: Failed to enable performance counters (%i)\n", errno); 1135606Snate@binkert.org} 1142SN/A 1152SN/Avoid 1162SN/APerfKvmCounter::stop() 1172SN/A{ 1189983Sstever@gmail.com if (ioctl(PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) 1192SN/A panic("KVM: Failed to disable performance counters (%i)\n", errno); 1209983Sstever@gmail.com} 1212SN/A 1222SN/Avoid 1232SN/APerfKvmCounter::period(uint64_t period) 1242SN/A{ 1259983Sstever@gmail.com if (ioctl(PERF_EVENT_IOC_PERIOD, &period) == -1) 1262SN/A panic("KVM: Failed to set period of performance counter (%i)\n", errno); 1272667Sstever@eecs.umich.edu} 1282667Sstever@eecs.umich.edu 1292667Sstever@eecs.umich.eduvoid 1302667Sstever@eecs.umich.eduPerfKvmCounter::refresh(int refresh) 13110905Sandreas.sandberg@arm.com{ 1322667Sstever@eecs.umich.edu if (ioctl(PERF_EVENT_IOC_REFRESH, refresh) == -1) 13310905Sandreas.sandberg@arm.com panic("KVM: Failed to refresh performance counter (%i)\n", errno); 1349952Sdam.sunwoo@arm.com} 1359952Sdam.sunwoo@arm.com 1369952Sdam.sunwoo@arm.comuint64_t 1379952Sdam.sunwoo@arm.comPerfKvmCounter::read() const 1389952Sdam.sunwoo@arm.com{ 1399952Sdam.sunwoo@arm.com uint64_t value; 1409952Sdam.sunwoo@arm.com 14110905Sandreas.sandberg@arm.com read(&value, sizeof(uint64_t)); 1429952Sdam.sunwoo@arm.com return value; 14310905Sandreas.sandberg@arm.com} 1449952Sdam.sunwoo@arm.com 1459952Sdam.sunwoo@arm.comvoid 1469952Sdam.sunwoo@arm.comPerfKvmCounter::enableSignals(pid_t tid, int signal) 1479952Sdam.sunwoo@arm.com{ 1489952Sdam.sunwoo@arm.com struct f_owner_ex sigowner; 1499952Sdam.sunwoo@arm.com 1502SN/A sigowner.type = F_OWNER_TID; 1512SN/A sigowner.pid = tid; 1522SN/A 1535606Snate@binkert.org if (fcntl(F_SETOWN_EX, &sigowner) == -1 || 1545606Snate@binkert.org fcntl(F_SETSIG, signal) == -1 || 1552SN/A fcntl(F_SETFL, O_ASYNC) == -1) 1562SN/A panic("PerfKvmCounter: Failed to enable signals for counter (%i)\n", 1572SN/A errno); 1582SN/A} 1592SN/A 1602SN/Avoid 1612SN/APerfKvmCounter::attach(PerfKvmCounterConfig &config, 1622SN/A pid_t tid, int group_fd) 1632SN/A{ 1642SN/A assert(!attached()); 1652SN/A 1662SN/A fd = syscall(__NR_perf_event_open, 1672SN/A &config.attr, tid, 1682667Sstever@eecs.umich.edu -1, // CPU (-1 => Any CPU that the task happens to run on) 1692SN/A group_fd, 1702SN/A 0); // Flags 1712SN/A if (fd == -1) 1722SN/A { 1732SN/A if (errno == EACCES) 1745336Shines@cs.fsu.edu { 1752SN/A panic("PerfKvmCounter::attach recieved error EACCESS\n" 1762SN/A " This error may be caused by a too restrictive setting\n" 1772SN/A " in the file '/proc/sys/kernel/perf_event_paranoid'\n" 178 " The default value was changed to 2 in kernel 4.6\n" 179 " A value greater than 1 prevents gem5 from making\n" 180 " the syscall to perf_event_open"); 181 } 182 panic("PerfKvmCounter::attach failed (%i)\n", errno); 183 } 184 185 mmapPerf(1); 186} 187 188pid_t 189PerfKvmCounter::gettid() 190{ 191 return syscall(__NR_gettid); 192} 193 194void 195PerfKvmCounter::mmapPerf(int pages) 196{ 197 assert(attached()); 198 assert(ringBuffer == NULL); 199 200 if (pageSize == -1) { 201 pageSize = sysconf(_SC_PAGE_SIZE); 202 if (pageSize == -1) 203 panic("PerfKvmCounter: Failed to determine page size (%i)\n", 204 errno); 205 } 206 207 ringNumPages = pages + 1; 208 ringBuffer = (struct perf_event_mmap_page *)mmap( 209 NULL, ringNumPages * 4096, 210 PROT_READ | PROT_WRITE, MAP_SHARED, 211 fd, 0); 212 if (ringBuffer == MAP_FAILED) 213 panic("PerfKvmCounter: MMAP failed (%i)\n", 214 errno); 215} 216 217int 218PerfKvmCounter::fcntl(int cmd, long p1) 219{ 220 assert(attached()); 221 return ::fcntl(fd, cmd, p1); 222} 223 224int 225PerfKvmCounter::ioctl(int request, long p1) 226{ 227 assert(attached()); 228 return ::ioctl(fd, request, p1); 229} 230 231void 232PerfKvmCounter::read(void *buf, size_t size) const 233{ 234 char *_buf = (char *)buf; 235 size_t _size = size; 236 237 assert(attached()); 238 239 do { 240 ssize_t ret; 241 ret = ::read(fd, _buf, _size); 242 switch (ret) { 243 case -1: 244 if (errno != EAGAIN) 245 panic("PerfKvmCounter::read failed (%i)\n", errno); 246 break; 247 248 case 0: 249 panic("PerfKvmCounter::read unexpected EOF.\n"); 250 251 default: 252 _size -= ret; 253 _buf += ret; 254 break; 255 } 256 } while (_size); 257} 258