perfevent.cc revision 13787
111308Santhony.gutierrez@amd.com/*
211308Santhony.gutierrez@amd.com * Copyright (c) 2012 ARM Limited
311308Santhony.gutierrez@amd.com * All rights reserved
411308Santhony.gutierrez@amd.com *
511308Santhony.gutierrez@amd.com * The license below extends only to copyright in the software and shall
611308Santhony.gutierrez@amd.com * not be construed as granting a license to any other intellectual
711308Santhony.gutierrez@amd.com * property including but not limited to intellectual property relating
811308Santhony.gutierrez@amd.com * to a hardware implementation of the functionality of the software
911308Santhony.gutierrez@amd.com * licensed hereunder.  You may use the software subject to the license
1011308Santhony.gutierrez@amd.com * terms below provided that you ensure that this notice is replicated
1111308Santhony.gutierrez@amd.com * unmodified and in its entirety in all distributions of the software,
1211308Santhony.gutierrez@amd.com * modified or unmodified, in source code or in binary form.
1311308Santhony.gutierrez@amd.com *
1411308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
1511308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are
1611308Santhony.gutierrez@amd.com * met: redistributions of source code must retain the above copyright
1711308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer;
1811308Santhony.gutierrez@amd.com * redistributions in binary form must reproduce the above copyright
1911308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the
2011308Santhony.gutierrez@amd.com * documentation and/or other materials provided with the distribution;
2111308Santhony.gutierrez@amd.com * neither the name of the copyright holders nor the names of its
2211308Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from
2311308Santhony.gutierrez@amd.com * this software without specific prior written permission.
2411308Santhony.gutierrez@amd.com *
2511308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2611308Santhony.gutierrez@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2711308Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2811308Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2911308Santhony.gutierrez@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3011308Santhony.gutierrez@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111308Santhony.gutierrez@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211308Santhony.gutierrez@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311308Santhony.gutierrez@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411308Santhony.gutierrez@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3511308Santhony.gutierrez@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3611308Santhony.gutierrez@amd.com *
3711308Santhony.gutierrez@amd.com * Authors: Andreas Sandberg
3811308Santhony.gutierrez@amd.com */
3911308Santhony.gutierrez@amd.com
4011308Santhony.gutierrez@amd.com#include <fcntl.h>
4111308Santhony.gutierrez@amd.com#include <sys/ioctl.h>
4211308Santhony.gutierrez@amd.com#include <sys/mman.h>
4311308Santhony.gutierrez@amd.com#include <sys/syscall.h>
4411308Santhony.gutierrez@amd.com#include <sys/types.h>
4511308Santhony.gutierrez@amd.com#include <syscall.h>
4611308Santhony.gutierrez@amd.com#include <unistd.h>
4711308Santhony.gutierrez@amd.com
4811308Santhony.gutierrez@amd.com#include <cassert>
4911308Santhony.gutierrez@amd.com#include <cerrno>
5011308Santhony.gutierrez@amd.com#include <csignal>
5111308Santhony.gutierrez@amd.com#include <cstring>
5211308Santhony.gutierrez@amd.com
5311308Santhony.gutierrez@amd.com#include "base/logging.hh"
5411308Santhony.gutierrez@amd.com#include "perfevent.hh"
5511308Santhony.gutierrez@amd.com
5611308Santhony.gutierrez@amd.comPerfKvmCounterConfig::PerfKvmCounterConfig(uint32_t type, uint64_t config)
5711308Santhony.gutierrez@amd.com{
5811308Santhony.gutierrez@amd.com    memset(&attr, 0, sizeof(attr));
5911308Santhony.gutierrez@amd.com
6011308Santhony.gutierrez@amd.com    attr.size = PERF_ATTR_SIZE_VER0;
6111308Santhony.gutierrez@amd.com    attr.type = type;
6211308Santhony.gutierrez@amd.com    attr.config = config;
6311308Santhony.gutierrez@amd.com}
6411308Santhony.gutierrez@amd.com
6511308Santhony.gutierrez@amd.comPerfKvmCounterConfig::~PerfKvmCounterConfig()
6611308Santhony.gutierrez@amd.com{
6711308Santhony.gutierrez@amd.com}
6811308Santhony.gutierrez@amd.com
6911308Santhony.gutierrez@amd.com
7011308Santhony.gutierrez@amd.comPerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config, pid_t tid)
7111308Santhony.gutierrez@amd.com    : fd(-1), ringBuffer(NULL), pageSize(-1)
7211308Santhony.gutierrez@amd.com{
7311308Santhony.gutierrez@amd.com    attach(config, tid, -1);
7411308Santhony.gutierrez@amd.com}
7511308Santhony.gutierrez@amd.com
7611308Santhony.gutierrez@amd.comPerfKvmCounter::PerfKvmCounter(PerfKvmCounterConfig &config,
7711308Santhony.gutierrez@amd.com                         pid_t tid, const PerfKvmCounter &parent)
7811308Santhony.gutierrez@amd.com    : fd(-1), ringBuffer(NULL), pageSize(-1)
7911308Santhony.gutierrez@amd.com{
8011308Santhony.gutierrez@amd.com    attach(config, tid, parent);
8111308Santhony.gutierrez@amd.com}
8211308Santhony.gutierrez@amd.com
8311308Santhony.gutierrez@amd.comPerfKvmCounter::PerfKvmCounter()
8411308Santhony.gutierrez@amd.com    : fd(-1), ringBuffer(NULL), pageSize(-1)
8511308Santhony.gutierrez@amd.com{
8611308Santhony.gutierrez@amd.com}
8711308Santhony.gutierrez@amd.com
8811308Santhony.gutierrez@amd.comPerfKvmCounter::~PerfKvmCounter()
8911308Santhony.gutierrez@amd.com{
9011308Santhony.gutierrez@amd.com    if (attached())
9111308Santhony.gutierrez@amd.com        detach();
9211308Santhony.gutierrez@amd.com}
9311308Santhony.gutierrez@amd.com
9411308Santhony.gutierrez@amd.comvoid
9511308Santhony.gutierrez@amd.comPerfKvmCounter::detach()
9611308Santhony.gutierrez@amd.com{
9711308Santhony.gutierrez@amd.com    assert(attached());
9811308Santhony.gutierrez@amd.com
9911308Santhony.gutierrez@amd.com    if (munmap(ringBuffer, ringNumPages * pageSize) == -1)
10011308Santhony.gutierrez@amd.com        warn("PerfKvmCounter: Failed to unmap ring buffer (%i)\n",
10111308Santhony.gutierrez@amd.com             errno);
10211308Santhony.gutierrez@amd.com    close(fd);
10311308Santhony.gutierrez@amd.com
10411308Santhony.gutierrez@amd.com    fd = -1;
10511308Santhony.gutierrez@amd.com    ringBuffer = NULL;
10611308Santhony.gutierrez@amd.com}
10711308Santhony.gutierrez@amd.com
10811308Santhony.gutierrez@amd.comvoid
10911308Santhony.gutierrez@amd.comPerfKvmCounter::start()
11011308Santhony.gutierrez@amd.com{
11111308Santhony.gutierrez@amd.com    if (ioctl(PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1)
11211308Santhony.gutierrez@amd.com        panic("KVM: Failed to enable performance counters (%i)\n", errno);
11311308Santhony.gutierrez@amd.com}
11411308Santhony.gutierrez@amd.com
11511308Santhony.gutierrez@amd.comvoid
11611308Santhony.gutierrez@amd.comPerfKvmCounter::stop()
11711308Santhony.gutierrez@amd.com{
11811308Santhony.gutierrez@amd.com    if (ioctl(PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1)
11911308Santhony.gutierrez@amd.com        panic("KVM: Failed to disable performance counters (%i)\n", errno);
12011308Santhony.gutierrez@amd.com}
12111308Santhony.gutierrez@amd.com
12211308Santhony.gutierrez@amd.comvoid
12311308Santhony.gutierrez@amd.comPerfKvmCounter::period(uint64_t period)
12411308Santhony.gutierrez@amd.com{
12511308Santhony.gutierrez@amd.com    if (ioctl(PERF_EVENT_IOC_PERIOD, &period) == -1)
12611308Santhony.gutierrez@amd.com        panic("KVM: Failed to set period of performance counter (%i)\n", errno);
12711308Santhony.gutierrez@amd.com}
12811308Santhony.gutierrez@amd.com
12911308Santhony.gutierrez@amd.comvoid
13011308Santhony.gutierrez@amd.comPerfKvmCounter::refresh(int refresh)
13111308Santhony.gutierrez@amd.com{
13211308Santhony.gutierrez@amd.com    if (ioctl(PERF_EVENT_IOC_REFRESH, refresh) == -1)
13311308Santhony.gutierrez@amd.com        panic("KVM: Failed to refresh performance counter (%i)\n", errno);
13411308Santhony.gutierrez@amd.com}
13511308Santhony.gutierrez@amd.com
13611308Santhony.gutierrez@amd.comuint64_t
13711308Santhony.gutierrez@amd.comPerfKvmCounter::read() const
13811308Santhony.gutierrez@amd.com{
13911308Santhony.gutierrez@amd.com    uint64_t value;
14011308Santhony.gutierrez@amd.com
14111308Santhony.gutierrez@amd.com    read(&value, sizeof(uint64_t));
14211308Santhony.gutierrez@amd.com    return value;
14311308Santhony.gutierrez@amd.com}
14411308Santhony.gutierrez@amd.com
14511308Santhony.gutierrez@amd.comvoid
14611308Santhony.gutierrez@amd.comPerfKvmCounter::enableSignals(pid_t tid, int signal)
14711308Santhony.gutierrez@amd.com{
14811308Santhony.gutierrez@amd.com    struct f_owner_ex sigowner;
14911308Santhony.gutierrez@amd.com
15011308Santhony.gutierrez@amd.com    sigowner.type = F_OWNER_TID;
15111308Santhony.gutierrez@amd.com    sigowner.pid = tid;
15211308Santhony.gutierrez@amd.com
15311308Santhony.gutierrez@amd.com    if (fcntl(F_SETOWN_EX, &sigowner) == -1 ||
15411308Santhony.gutierrez@amd.com        fcntl(F_SETSIG, signal) == -1 ||
15511308Santhony.gutierrez@amd.com        fcntl(F_SETFL, O_ASYNC) == -1)
15611308Santhony.gutierrez@amd.com        panic("PerfKvmCounter: Failed to enable signals for counter (%i)\n",
15711308Santhony.gutierrez@amd.com              errno);
15811308Santhony.gutierrez@amd.com}
15911308Santhony.gutierrez@amd.com
16011308Santhony.gutierrez@amd.comvoid
16111308Santhony.gutierrez@amd.comPerfKvmCounter::attach(PerfKvmCounterConfig &config,
16211308Santhony.gutierrez@amd.com                    pid_t tid, int group_fd)
16311308Santhony.gutierrez@amd.com{
16411308Santhony.gutierrez@amd.com    assert(!attached());
16511308Santhony.gutierrez@amd.com
16611308Santhony.gutierrez@amd.com    fd = syscall(__NR_perf_event_open,
16711308Santhony.gutierrez@amd.com                 &config.attr, tid,
16811308Santhony.gutierrez@amd.com                 -1, // CPU (-1 => Any CPU that the task happens to run on)
16911308Santhony.gutierrez@amd.com                 group_fd,
17011308Santhony.gutierrez@amd.com                 0); // Flags
17111308Santhony.gutierrez@amd.com    if (fd == -1)
17211308Santhony.gutierrez@amd.com    {
17311308Santhony.gutierrez@amd.com        if (errno == EACCES)
17411308Santhony.gutierrez@amd.com        {
17511308Santhony.gutierrez@amd.com            panic("PerfKvmCounter::attach recieved error EACCESS\n"
17611308Santhony.gutierrez@amd.com            "  This error may be caused by a too restrictive setting\n"
17711308Santhony.gutierrez@amd.com            "  in the file '/proc/sys/kernel/perf_event_paranoid'\n"
17811308Santhony.gutierrez@amd.com            "  The default value was changed to 2 in kernel 4.6\n"
17911308Santhony.gutierrez@amd.com            "  A value greater than 1 prevents gem5 from making\n"
18011308Santhony.gutierrez@amd.com            "  the syscall to perf_event_open");
18111308Santhony.gutierrez@amd.com        }
18211308Santhony.gutierrez@amd.com        panic("PerfKvmCounter::attach failed (%i)\n", errno);
18311308Santhony.gutierrez@amd.com    }
18411308Santhony.gutierrez@amd.com
18511308Santhony.gutierrez@amd.com    mmapPerf(1);
18611308Santhony.gutierrez@amd.com}
18711308Santhony.gutierrez@amd.com
18811308Santhony.gutierrez@amd.compid_t
18911308Santhony.gutierrez@amd.comPerfKvmCounter::gettid()
19011308Santhony.gutierrez@amd.com{
19111308Santhony.gutierrez@amd.com    return syscall(__NR_gettid);
19211308Santhony.gutierrez@amd.com}
19311308Santhony.gutierrez@amd.com
19411308Santhony.gutierrez@amd.comvoid
19511308Santhony.gutierrez@amd.comPerfKvmCounter::mmapPerf(int pages)
19611308Santhony.gutierrez@amd.com{
19711308Santhony.gutierrez@amd.com    assert(attached());
19811308Santhony.gutierrez@amd.com    assert(ringBuffer == NULL);
19911308Santhony.gutierrez@amd.com
20011308Santhony.gutierrez@amd.com    if (pageSize == -1) {
20111308Santhony.gutierrez@amd.com        pageSize = sysconf(_SC_PAGE_SIZE);
20211308Santhony.gutierrez@amd.com        if (pageSize == -1)
20311308Santhony.gutierrez@amd.com            panic("PerfKvmCounter: Failed to determine page size (%i)\n",
20411308Santhony.gutierrez@amd.com                  errno);
20511308Santhony.gutierrez@amd.com    }
20611308Santhony.gutierrez@amd.com
20711308Santhony.gutierrez@amd.com    ringNumPages = pages + 1;
20811308Santhony.gutierrez@amd.com    ringBuffer = (struct perf_event_mmap_page *)mmap(
20911308Santhony.gutierrez@amd.com        NULL, ringNumPages * 4096,
21011308Santhony.gutierrez@amd.com        PROT_READ | PROT_WRITE, MAP_SHARED,
21111308Santhony.gutierrez@amd.com        fd, 0);
21211308Santhony.gutierrez@amd.com    if (ringBuffer == MAP_FAILED)
21311308Santhony.gutierrez@amd.com        panic("PerfKvmCounter: MMAP failed (%i)\n",
21411308Santhony.gutierrez@amd.com              errno);
21511308Santhony.gutierrez@amd.com}
21611308Santhony.gutierrez@amd.com
21711308Santhony.gutierrez@amd.comint
21811308Santhony.gutierrez@amd.comPerfKvmCounter::fcntl(int cmd, long p1)
21911308Santhony.gutierrez@amd.com{
22011308Santhony.gutierrez@amd.com    assert(attached());
22111308Santhony.gutierrez@amd.com    return ::fcntl(fd, cmd, p1);
22211308Santhony.gutierrez@amd.com}
22311308Santhony.gutierrez@amd.com
22411308Santhony.gutierrez@amd.comint
22511435Smitch.hayenga@arm.comPerfKvmCounter::ioctl(int request, long p1)
22611308Santhony.gutierrez@amd.com{
22711308Santhony.gutierrez@amd.com    assert(attached());
22811308Santhony.gutierrez@amd.com    return ::ioctl(fd, request, p1);
22911308Santhony.gutierrez@amd.com}
23011308Santhony.gutierrez@amd.com
23111308Santhony.gutierrez@amd.comvoid
23211308Santhony.gutierrez@amd.comPerfKvmCounter::read(void *buf, size_t size) const
23311308Santhony.gutierrez@amd.com{
23411308Santhony.gutierrez@amd.com    char *_buf = (char *)buf;
23511308Santhony.gutierrez@amd.com    size_t _size = size;
23611308Santhony.gutierrez@amd.com
23711308Santhony.gutierrez@amd.com    assert(attached());
23811308Santhony.gutierrez@amd.com
23911308Santhony.gutierrez@amd.com    do {
24011308Santhony.gutierrez@amd.com        ssize_t ret;
24111308Santhony.gutierrez@amd.com        ret = ::read(fd, _buf, _size);
24211308Santhony.gutierrez@amd.com        switch (ret) {
24311308Santhony.gutierrez@amd.com          case -1:
24411308Santhony.gutierrez@amd.com            if (errno != EAGAIN)
24511308Santhony.gutierrez@amd.com                panic("PerfKvmCounter::read failed (%i)\n", errno);
24611308Santhony.gutierrez@amd.com            break;
24711308Santhony.gutierrez@amd.com
24811308Santhony.gutierrez@amd.com          case 0:
24911308Santhony.gutierrez@amd.com            panic("PerfKvmCounter::read unexpected EOF.\n");
25011308Santhony.gutierrez@amd.com
25111308Santhony.gutierrez@amd.com          default:
25211308Santhony.gutierrez@amd.com            _size -= ret;
25311308Santhony.gutierrez@amd.com            _buf += ret;
25411308Santhony.gutierrez@amd.com            break;
25511308Santhony.gutierrez@amd.com        }
25611308Santhony.gutierrez@amd.com    } while (_size);
25711308Santhony.gutierrez@amd.com}
25811308Santhony.gutierrez@amd.com