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