perfevent.cc revision 13787
12810SN/A/* 22810SN/A * Copyright (c) 2012 ARM Limited 32810SN/A * All rights reserved 42810SN/A * 52810SN/A * The license below extends only to copyright in the software and shall 62810SN/A * not be construed as granting a license to any other intellectual 72810SN/A * property including but not limited to intellectual property relating 82810SN/A * to a hardware implementation of the functionality of the software 92810SN/A * licensed hereunder. You may use the software subject to the license 102810SN/A * terms below provided that you ensure that this notice is replicated 112810SN/A * unmodified and in its entirety in all distributions of the software, 122810SN/A * modified or unmodified, in source code or in binary form. 132810SN/A * 142810SN/A * Redistribution and use in source and binary forms, with or without 152810SN/A * modification, are permitted provided that the following conditions are 162810SN/A * met: redistributions of source code must retain the above copyright 172810SN/A * notice, this list of conditions and the following disclaimer; 182810SN/A * redistributions in binary form must reproduce the above copyright 192810SN/A * notice, this list of conditions and the following disclaimer in the 202810SN/A * documentation and/or other materials provided with the distribution; 212810SN/A * neither the name of the copyright holders nor the names of its 222810SN/A * contributors may be used to endorse or promote products derived from 232810SN/A * this software without specific prior written permission. 242810SN/A * 252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 363348SN/A * 373348SN/A * Authors: Andreas Sandberg 388232Snate@binkert.org */ 395338Sstever@gmail.com 405338Sstever@gmail.com#include <fcntl.h> 412810SN/A#include <sys/ioctl.h> 422810SN/A#include <sys/mman.h> 432810SN/A#include <sys/syscall.h> 444965SN/A#include <sys/types.h> 456122SSteve.Reinhardt@amd.com#include <syscall.h> 465314SN/A#include <unistd.h> 475314SN/A 486122SSteve.Reinhardt@amd.com#include <cassert> 492810SN/A#include <cerrno> 504475SN/A#include <csignal> 514475SN/A#include <cstring> 524475SN/A 535034SN/A#include "base/logging.hh" 545034SN/A#include "perfevent.hh" 555314SN/A 565314SN/APerfKvmCounterConfig::PerfKvmCounterConfig(uint32_t type, uint64_t config) 574628SN/A{ 585034SN/A memset(&attr, 0, sizeof(attr)); 595034SN/A 605034SN/A attr.size = PERF_ATTR_SIZE_VER0; 616122SSteve.Reinhardt@amd.com attr.type = type; 628134SAli.Saidi@ARM.com attr.config = config; 634626SN/A} 644626SN/A 655034SN/APerfKvmCounterConfig::~PerfKvmCounterConfig() 666122SSteve.Reinhardt@amd.com{ 676978SLisa.Hsu@amd.com} 686978SLisa.Hsu@amd.com 694458SN/A 702810SN/APerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, pid_t tid) 712810SN/A : fd(-1), ringBuffer(NULL), pageSize(-1) 722811SN/A{ 732810SN/A attach(config, tid, -1); 742810SN/A} 754458SN/A 764458SN/APerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, 774458SN/A pid_t tid, const PerfKvmCounter &parent) 782810SN/A : fd(-1), ringBuffer(NULL), pageSize(-1) 792810SN/A{ 805314SN/A attach(config, tid, parent); 815314SN/A} 825314SN/A 835314SN/APerfKvmCounter::PerfKvmCounter() 845314SN/A : fd(-1), ringBuffer(NULL), pageSize(-1) 855314SN/A{ 865314SN/A} 875314SN/A 885314SN/APerfKvmCounter::~PerfKvmCounter() 895314SN/A{ 905314SN/A if (attached()) 916227Snate@binkert.org detach(); 926227Snate@binkert.org} 932810SN/A 942810SN/Avoid 952810SN/APerfKvmCounter::detach() 962810SN/A{ 973606SN/A assert(attached()); 984458SN/A 994458SN/A if (munmap(ringBuffer, ringNumPages * pageSize) == -1) 1003013SN/A warn("PerfKvmCounter: Failed to unmap ring buffer (%i)\n", 1013236SN/A errno); 1024458SN/A close(fd); 1034458SN/A 1044458SN/A fd = -1; 1053246SN/A ringBuffer = NULL; 1063309SN/A} 1073013SN/A 1082810SN/Avoid 1092810SN/APerfKvmCounter::start() 1103013SN/A{ 1113013SN/A if (ioctl(PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) 1122810SN/A panic("KVM: Failed to enable performance counters (%i)\n", errno); 1133013SN/A} 1143013SN/A 1152810SN/Avoid 1162810SN/APerfKvmCounter::stop() 1172810SN/A{ 1182810SN/A if (ioctl(PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) 1192810SN/A panic("KVM: Failed to disable performance counters (%i)\n", errno); 1203013SN/A} 1213013SN/A 1223013SN/Avoid 1232897SN/APerfKvmCounter::period(uint64_t period) 1242897SN/A{ 1253013SN/A if (ioctl(PERF_EVENT_IOC_PERIOD, &period) == -1) 1262897SN/A panic("KVM: Failed to set period of performance counter (%i)\n", errno); 1274666SN/A} 1284666SN/A 1297823Ssteve.reinhardt@amd.comvoid 1302897SN/APerfKvmCounter::refresh(int refresh) 1312810SN/A{ 1322810SN/A if (ioctl(PERF_EVENT_IOC_REFRESH, refresh) == -1) 1332844SN/A panic("KVM: Failed to refresh performance counter (%i)\n", errno); 1342810SN/A} 1352858SN/A 1362858SN/Auint64_t 1372858SN/APerfKvmCounter::read() const 1382858SN/A{ 1392858SN/A uint64_t value; 1402858SN/A 1412858SN/A read(&value, sizeof(uint64_t)); 1424628SN/A return value; 1432858SN/A} 1442810SN/A 1452810SN/Avoid 1462810SN/APerfKvmCounter::enableSignals(pid_t tid, int signal) 1472810SN/A{ 1482810SN/A struct f_owner_ex sigowner; 1494022SN/A 1504022SN/A sigowner.type = F_OWNER_TID; 1514022SN/A sigowner.pid = tid; 1522810SN/A 1532810SN/A if (fcntl(F_SETOWN_EX, &sigowner) == -1 || 1546978SLisa.Hsu@amd.com fcntl(F_SETSIG, signal) == -1 || 1556978SLisa.Hsu@amd.com fcntl(F_SETFL, O_ASYNC) == -1) 1566978SLisa.Hsu@amd.com panic("PerfKvmCounter: Failed to enable signals for counter (%i)\n", 1576978SLisa.Hsu@amd.com errno); 1586978SLisa.Hsu@amd.com} 1592810SN/A 1602810SN/Avoid 1612810SN/APerfKvmCounter::attach(PerfKvmCounterConfig &config, 1622810SN/A pid_t tid, int group_fd) 1632810SN/A{ 1642810SN/A assert(!attached()); 1654871SN/A 1664871SN/A fd = syscall(__NR_perf_event_open, 1674871SN/A &config.attr, tid, 1684871SN/A -1, // CPU (-1 => Any CPU that the task happens to run on) 1694871SN/A group_fd, 1704871SN/A 0); // Flags 1714871SN/A if (fd == -1) 1724871SN/A { 1734871SN/A if (errno == EACCES) 1744871SN/A { 1752810SN/A panic("PerfKvmCounter::attach recieved error EACCESS\n" 1762810SN/A " This error may be caused by a too restrictive setting\n" 1772810SN/A " in the file '/proc/sys/kernel/perf_event_paranoid'\n" 1782810SN/A " The default value was changed to 2 in kernel 4.6\n" 1792810SN/A " A value greater than 1 prevents gem5 from making\n" 1804871SN/A " the syscall to perf_event_open"); 1812810SN/A } 1822810SN/A panic("PerfKvmCounter::attach failed (%i)\n", errno); 1832810SN/A } 1842810SN/A 1852810SN/A mmapPerf(1); 1862810SN/A} 1874871SN/A 1882810SN/Apid_t 1892810SN/APerfKvmCounter::gettid() 1904022SN/A{ 1914022SN/A return syscall(__NR_gettid); 1924022SN/A} 1932810SN/A 1942810SN/Avoid 1956978SLisa.Hsu@amd.comPerfKvmCounter::mmapPerf(int pages) 1966978SLisa.Hsu@amd.com{ 1976978SLisa.Hsu@amd.com assert(attached()); 1986978SLisa.Hsu@amd.com assert(ringBuffer == NULL); 1996978SLisa.Hsu@amd.com 2002810SN/A if (pageSize == -1) { 2012810SN/A pageSize = sysconf(_SC_PAGE_SIZE); 2022810SN/A if (pageSize == -1) 2032810SN/A panic("PerfKvmCounter: Failed to determine page size (%i)\n", 2042810SN/A errno); 2052810SN/A } 2062810SN/A 2072810SN/A ringNumPages = pages + 1; 2082810SN/A ringBuffer = (struct perf_event_mmap_page *)mmap( 2092810SN/A NULL, ringNumPages * 4096, 2102810SN/A PROT_READ | PROT_WRITE, MAP_SHARED, 2114871SN/A fd, 0); 2122810SN/A if (ringBuffer == MAP_FAILED) 2132810SN/A panic("PerfKvmCounter: MMAP failed (%i)\n", 2142810SN/A errno); 2152810SN/A} 2162810SN/A 2172810SN/Aint 2184871SN/APerfKvmCounter::fcntl(int cmd, long p1) 2192810SN/A{ 2202810SN/A assert(attached()); 2214022SN/A return ::fcntl(fd, cmd, p1); 2224022SN/A} 2234022SN/A 2242810SN/Aint 2252810SN/APerfKvmCounter::ioctl(int request, long p1) 2262810SN/A{ 2272810SN/A assert(attached()); 2282810SN/A return ::ioctl(fd, request, p1); 2292810SN/A} 2302810SN/A 2312810SN/Avoid 2322810SN/APerfKvmCounter::read(void *buf, size_t size) const 2332810SN/A{ 2342810SN/A char *_buf = (char *)buf; 2352810SN/A size_t _size = size; 2362810SN/A 2372810SN/A assert(attached()); 2384871SN/A 2392810SN/A do { 2402810SN/A ssize_t ret; 2412810SN/A ret = ::read(fd, _buf, _size); 2422810SN/A switch (ret) { 2432810SN/A case -1: 2442810SN/A if (errno != EAGAIN) 2454871SN/A panic("PerfKvmCounter::read failed (%i)\n", errno); 2462810SN/A break; 2472810SN/A 2484022SN/A case 0: 2494022SN/A panic("PerfKvmCounter::read unexpected EOF.\n"); 2504022SN/A 2512810SN/A default: 2522810SN/A _size -= ret; 2532810SN/A _buf += ret; 2542810SN/A break; 2552810SN/A } 2562810SN/A } while (_size); 2572810SN/A} 2582810SN/A