19651SAndreas.Sandberg@ARM.com/* 29651SAndreas.Sandberg@ARM.com * Copyright (c) 2012 ARM Limited 39651SAndreas.Sandberg@ARM.com * All rights reserved 49651SAndreas.Sandberg@ARM.com * 59651SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 69651SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 79651SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 89651SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 99651SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 109651SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 119651SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 129651SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 139651SAndreas.Sandberg@ARM.com * 149651SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 159651SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 169651SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 179651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 189651SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 199651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 209651SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 219651SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 229651SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from 239651SAndreas.Sandberg@ARM.com * this software without specific prior written permission. 249651SAndreas.Sandberg@ARM.com * 259651SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 269651SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 279651SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 289651SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 299651SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 309651SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 319651SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 329651SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 339651SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 349651SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 359651SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 369651SAndreas.Sandberg@ARM.com * 379651SAndreas.Sandberg@ARM.com * Authors: Andreas Sandberg 389651SAndreas.Sandberg@ARM.com */ 399651SAndreas.Sandberg@ARM.com 4011793Sbrandon.potter@amd.com#include <fcntl.h> 419651SAndreas.Sandberg@ARM.com#include <sys/ioctl.h> 429651SAndreas.Sandberg@ARM.com#include <sys/mman.h> 439651SAndreas.Sandberg@ARM.com#include <sys/syscall.h> 449651SAndreas.Sandberg@ARM.com#include <sys/types.h> 459651SAndreas.Sandberg@ARM.com#include <syscall.h> 469651SAndreas.Sandberg@ARM.com#include <unistd.h> 479651SAndreas.Sandberg@ARM.com 489651SAndreas.Sandberg@ARM.com#include <cassert> 499651SAndreas.Sandberg@ARM.com#include <cerrno> 509651SAndreas.Sandberg@ARM.com#include <csignal> 519651SAndreas.Sandberg@ARM.com#include <cstring> 529651SAndreas.Sandberg@ARM.com 5312334Sgabeblack@google.com#include "base/logging.hh" 549651SAndreas.Sandberg@ARM.com#include "perfevent.hh" 559651SAndreas.Sandberg@ARM.com 569651SAndreas.Sandberg@ARM.comPerfKvmCounterConfig::PerfKvmCounterConfig(uint32_t type, uint64_t config) 579651SAndreas.Sandberg@ARM.com{ 589651SAndreas.Sandberg@ARM.com memset(&attr, 0, sizeof(attr)); 599651SAndreas.Sandberg@ARM.com 609651SAndreas.Sandberg@ARM.com attr.size = PERF_ATTR_SIZE_VER0; 619651SAndreas.Sandberg@ARM.com attr.type = type; 629651SAndreas.Sandberg@ARM.com attr.config = config; 639651SAndreas.Sandberg@ARM.com} 649651SAndreas.Sandberg@ARM.com 659651SAndreas.Sandberg@ARM.comPerfKvmCounterConfig::~PerfKvmCounterConfig() 669651SAndreas.Sandberg@ARM.com{ 679651SAndreas.Sandberg@ARM.com} 689651SAndreas.Sandberg@ARM.com 699651SAndreas.Sandberg@ARM.com 709651SAndreas.Sandberg@ARM.comPerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, pid_t tid) 719651SAndreas.Sandberg@ARM.com : fd(-1), ringBuffer(NULL), pageSize(-1) 729651SAndreas.Sandberg@ARM.com{ 739651SAndreas.Sandberg@ARM.com attach(config, tid, -1); 749651SAndreas.Sandberg@ARM.com} 759651SAndreas.Sandberg@ARM.com 769651SAndreas.Sandberg@ARM.comPerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, 779651SAndreas.Sandberg@ARM.com pid_t tid, const PerfKvmCounter &parent) 789651SAndreas.Sandberg@ARM.com : fd(-1), ringBuffer(NULL), pageSize(-1) 799651SAndreas.Sandberg@ARM.com{ 809651SAndreas.Sandberg@ARM.com attach(config, tid, parent); 819651SAndreas.Sandberg@ARM.com} 829651SAndreas.Sandberg@ARM.com 839651SAndreas.Sandberg@ARM.comPerfKvmCounter::PerfKvmCounter() 849651SAndreas.Sandberg@ARM.com : fd(-1), ringBuffer(NULL), pageSize(-1) 859651SAndreas.Sandberg@ARM.com{ 869651SAndreas.Sandberg@ARM.com} 879651SAndreas.Sandberg@ARM.com 889651SAndreas.Sandberg@ARM.comPerfKvmCounter::~PerfKvmCounter() 899651SAndreas.Sandberg@ARM.com{ 909651SAndreas.Sandberg@ARM.com if (attached()) 919651SAndreas.Sandberg@ARM.com detach(); 929651SAndreas.Sandberg@ARM.com} 939651SAndreas.Sandberg@ARM.com 949651SAndreas.Sandberg@ARM.comvoid 959651SAndreas.Sandberg@ARM.comPerfKvmCounter::detach() 969651SAndreas.Sandberg@ARM.com{ 979651SAndreas.Sandberg@ARM.com assert(attached()); 989651SAndreas.Sandberg@ARM.com 999651SAndreas.Sandberg@ARM.com if (munmap(ringBuffer, ringNumPages * pageSize) == -1) 1009651SAndreas.Sandberg@ARM.com warn("PerfKvmCounter: Failed to unmap ring buffer (%i)\n", 1019651SAndreas.Sandberg@ARM.com errno); 1029651SAndreas.Sandberg@ARM.com close(fd); 1039651SAndreas.Sandberg@ARM.com 1049651SAndreas.Sandberg@ARM.com fd = -1; 1059651SAndreas.Sandberg@ARM.com ringBuffer = NULL; 1069651SAndreas.Sandberg@ARM.com} 1079651SAndreas.Sandberg@ARM.com 1089651SAndreas.Sandberg@ARM.comvoid 1099651SAndreas.Sandberg@ARM.comPerfKvmCounter::start() 1109651SAndreas.Sandberg@ARM.com{ 1119651SAndreas.Sandberg@ARM.com if (ioctl(PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) 1129651SAndreas.Sandberg@ARM.com panic("KVM: Failed to enable performance counters (%i)\n", errno); 1139651SAndreas.Sandberg@ARM.com} 1149651SAndreas.Sandberg@ARM.com 1159651SAndreas.Sandberg@ARM.comvoid 1169651SAndreas.Sandberg@ARM.comPerfKvmCounter::stop() 1179651SAndreas.Sandberg@ARM.com{ 1189651SAndreas.Sandberg@ARM.com if (ioctl(PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) 1199651SAndreas.Sandberg@ARM.com panic("KVM: Failed to disable performance counters (%i)\n", errno); 1209651SAndreas.Sandberg@ARM.com} 1219651SAndreas.Sandberg@ARM.com 1229651SAndreas.Sandberg@ARM.comvoid 1239651SAndreas.Sandberg@ARM.comPerfKvmCounter::period(uint64_t period) 1249651SAndreas.Sandberg@ARM.com{ 1259651SAndreas.Sandberg@ARM.com if (ioctl(PERF_EVENT_IOC_PERIOD, &period) == -1) 1269651SAndreas.Sandberg@ARM.com panic("KVM: Failed to set period of performance counter (%i)\n", errno); 1279651SAndreas.Sandberg@ARM.com} 1289651SAndreas.Sandberg@ARM.com 1299651SAndreas.Sandberg@ARM.comvoid 1309651SAndreas.Sandberg@ARM.comPerfKvmCounter::refresh(int refresh) 1319651SAndreas.Sandberg@ARM.com{ 1329651SAndreas.Sandberg@ARM.com if (ioctl(PERF_EVENT_IOC_REFRESH, refresh) == -1) 1339651SAndreas.Sandberg@ARM.com panic("KVM: Failed to refresh performance counter (%i)\n", errno); 1349651SAndreas.Sandberg@ARM.com} 1359651SAndreas.Sandberg@ARM.com 1369651SAndreas.Sandberg@ARM.comuint64_t 1379651SAndreas.Sandberg@ARM.comPerfKvmCounter::read() const 1389651SAndreas.Sandberg@ARM.com{ 1399651SAndreas.Sandberg@ARM.com uint64_t value; 1409651SAndreas.Sandberg@ARM.com 1419651SAndreas.Sandberg@ARM.com read(&value, sizeof(uint64_t)); 1429651SAndreas.Sandberg@ARM.com return value; 1439651SAndreas.Sandberg@ARM.com} 1449651SAndreas.Sandberg@ARM.com 1459651SAndreas.Sandberg@ARM.comvoid 1469651SAndreas.Sandberg@ARM.comPerfKvmCounter::enableSignals(pid_t tid, int signal) 1479651SAndreas.Sandberg@ARM.com{ 1489651SAndreas.Sandberg@ARM.com struct f_owner_ex sigowner; 1499651SAndreas.Sandberg@ARM.com 1509651SAndreas.Sandberg@ARM.com sigowner.type = F_OWNER_TID; 1519651SAndreas.Sandberg@ARM.com sigowner.pid = tid; 1529651SAndreas.Sandberg@ARM.com 1539651SAndreas.Sandberg@ARM.com if (fcntl(F_SETOWN_EX, &sigowner) == -1 || 1549651SAndreas.Sandberg@ARM.com fcntl(F_SETSIG, signal) == -1 || 1559651SAndreas.Sandberg@ARM.com fcntl(F_SETFL, O_ASYNC) == -1) 1569651SAndreas.Sandberg@ARM.com panic("PerfKvmCounter: Failed to enable signals for counter (%i)\n", 1579651SAndreas.Sandberg@ARM.com errno); 1589651SAndreas.Sandberg@ARM.com} 1599651SAndreas.Sandberg@ARM.com 1609651SAndreas.Sandberg@ARM.comvoid 1619651SAndreas.Sandberg@ARM.comPerfKvmCounter::attach(PerfKvmCounterConfig &config, 1629651SAndreas.Sandberg@ARM.com pid_t tid, int group_fd) 1639651SAndreas.Sandberg@ARM.com{ 1649651SAndreas.Sandberg@ARM.com assert(!attached()); 1659651SAndreas.Sandberg@ARM.com 1669651SAndreas.Sandberg@ARM.com fd = syscall(__NR_perf_event_open, 1679651SAndreas.Sandberg@ARM.com &config.attr, tid, 1689651SAndreas.Sandberg@ARM.com -1, // CPU (-1 => Any CPU that the task happens to run on) 1699651SAndreas.Sandberg@ARM.com group_fd, 1709651SAndreas.Sandberg@ARM.com 0); // Flags 1719651SAndreas.Sandberg@ARM.com if (fd == -1) 17213787Sgambordr@oregonstate.edu { 17313787Sgambordr@oregonstate.edu if (errno == EACCES) 17413787Sgambordr@oregonstate.edu { 17513787Sgambordr@oregonstate.edu panic("PerfKvmCounter::attach recieved error EACCESS\n" 17613787Sgambordr@oregonstate.edu " This error may be caused by a too restrictive setting\n" 17713787Sgambordr@oregonstate.edu " in the file '/proc/sys/kernel/perf_event_paranoid'\n" 17813787Sgambordr@oregonstate.edu " The default value was changed to 2 in kernel 4.6\n" 17913787Sgambordr@oregonstate.edu " A value greater than 1 prevents gem5 from making\n" 18013787Sgambordr@oregonstate.edu " the syscall to perf_event_open"); 18113787Sgambordr@oregonstate.edu } 18213787Sgambordr@oregonstate.edu panic("PerfKvmCounter::attach failed (%i)\n", errno); 18313787Sgambordr@oregonstate.edu } 1849651SAndreas.Sandberg@ARM.com 1859651SAndreas.Sandberg@ARM.com mmapPerf(1); 1869651SAndreas.Sandberg@ARM.com} 1879651SAndreas.Sandberg@ARM.com 1889651SAndreas.Sandberg@ARM.compid_t 1899651SAndreas.Sandberg@ARM.comPerfKvmCounter::gettid() 1909651SAndreas.Sandberg@ARM.com{ 1919651SAndreas.Sandberg@ARM.com return syscall(__NR_gettid); 1929651SAndreas.Sandberg@ARM.com} 1939651SAndreas.Sandberg@ARM.com 1949651SAndreas.Sandberg@ARM.comvoid 1959651SAndreas.Sandberg@ARM.comPerfKvmCounter::mmapPerf(int pages) 1969651SAndreas.Sandberg@ARM.com{ 1979651SAndreas.Sandberg@ARM.com assert(attached()); 1989651SAndreas.Sandberg@ARM.com assert(ringBuffer == NULL); 1999651SAndreas.Sandberg@ARM.com 2009651SAndreas.Sandberg@ARM.com if (pageSize == -1) { 2019651SAndreas.Sandberg@ARM.com pageSize = sysconf(_SC_PAGE_SIZE); 2029651SAndreas.Sandberg@ARM.com if (pageSize == -1) 2039651SAndreas.Sandberg@ARM.com panic("PerfKvmCounter: Failed to determine page size (%i)\n", 2049651SAndreas.Sandberg@ARM.com errno); 2059651SAndreas.Sandberg@ARM.com } 2069651SAndreas.Sandberg@ARM.com 2079651SAndreas.Sandberg@ARM.com ringNumPages = pages + 1; 2089651SAndreas.Sandberg@ARM.com ringBuffer = (struct perf_event_mmap_page *)mmap( 2099651SAndreas.Sandberg@ARM.com NULL, ringNumPages * 4096, 2109651SAndreas.Sandberg@ARM.com PROT_READ | PROT_WRITE, MAP_SHARED, 2119651SAndreas.Sandberg@ARM.com fd, 0); 2129651SAndreas.Sandberg@ARM.com if (ringBuffer == MAP_FAILED) 2139651SAndreas.Sandberg@ARM.com panic("PerfKvmCounter: MMAP failed (%i)\n", 2149651SAndreas.Sandberg@ARM.com errno); 2159651SAndreas.Sandberg@ARM.com} 2169651SAndreas.Sandberg@ARM.com 2179651SAndreas.Sandberg@ARM.comint 2189651SAndreas.Sandberg@ARM.comPerfKvmCounter::fcntl(int cmd, long p1) 2199651SAndreas.Sandberg@ARM.com{ 2209651SAndreas.Sandberg@ARM.com assert(attached()); 2219651SAndreas.Sandberg@ARM.com return ::fcntl(fd, cmd, p1); 2229651SAndreas.Sandberg@ARM.com} 2239651SAndreas.Sandberg@ARM.com 2249651SAndreas.Sandberg@ARM.comint 2259651SAndreas.Sandberg@ARM.comPerfKvmCounter::ioctl(int request, long p1) 2269651SAndreas.Sandberg@ARM.com{ 2279651SAndreas.Sandberg@ARM.com assert(attached()); 2289651SAndreas.Sandberg@ARM.com return ::ioctl(fd, request, p1); 2299651SAndreas.Sandberg@ARM.com} 2309651SAndreas.Sandberg@ARM.com 2319651SAndreas.Sandberg@ARM.comvoid 2329651SAndreas.Sandberg@ARM.comPerfKvmCounter::read(void *buf, size_t size) const 2339651SAndreas.Sandberg@ARM.com{ 2349651SAndreas.Sandberg@ARM.com char *_buf = (char *)buf; 2359651SAndreas.Sandberg@ARM.com size_t _size = size; 2369651SAndreas.Sandberg@ARM.com 2379651SAndreas.Sandberg@ARM.com assert(attached()); 2389651SAndreas.Sandberg@ARM.com 2399651SAndreas.Sandberg@ARM.com do { 2409651SAndreas.Sandberg@ARM.com ssize_t ret; 2419651SAndreas.Sandberg@ARM.com ret = ::read(fd, _buf, _size); 2429651SAndreas.Sandberg@ARM.com switch (ret) { 2439651SAndreas.Sandberg@ARM.com case -1: 2449651SAndreas.Sandberg@ARM.com if (errno != EAGAIN) 2459651SAndreas.Sandberg@ARM.com panic("PerfKvmCounter::read failed (%i)\n", errno); 2469651SAndreas.Sandberg@ARM.com break; 2479651SAndreas.Sandberg@ARM.com 2489651SAndreas.Sandberg@ARM.com case 0: 2499651SAndreas.Sandberg@ARM.com panic("PerfKvmCounter::read unexpected EOF.\n"); 2509651SAndreas.Sandberg@ARM.com 2519651SAndreas.Sandberg@ARM.com default: 2529651SAndreas.Sandberg@ARM.com _size -= ret; 2539651SAndreas.Sandberg@ARM.com _buf += ret; 2549651SAndreas.Sandberg@ARM.com break; 2559651SAndreas.Sandberg@ARM.com } 25611321Ssteve.reinhardt@amd.com } while (_size); 2579651SAndreas.Sandberg@ARM.com} 258