1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
//===- Perf.inc ----------------------------------------------------------===//
//
// The SkyPat Team
//
// This file is distributed under the New BSD License.
// See LICENSE for details.
//
//===----------------------------------------------------------------------===//
#include <skypat/Support/ManagedStatic.h>
#include <time.h>
#include <unistd.h>
#include <cassert>
#if defined(HAVE_LINUX_PERF_EVENT_H)
#include <linux/perf_event.h>
#include <sys/ioctl.h>
#include <cstring>
#include <cstdlib>
#if defined(HAVE_ASM_UNISTD_H)
#include <asm/unistd.h>
#endif
#endif
#ifndef SKYPAT_SKYPAT_H
#include <skypat/skypat.h>
#endif
namespace skypat {
namespace testing {
namespace internal {
//===----------------------------------------------------------------------===//
// Perf Implementation
//===----------------------------------------------------------------------===//
class PerfImpl
{
public:
PerfImpl() {
}
~PerfImpl() {
#if defined(HAVE_LINUX_PERF_EVENT_H)
close(m_Fd);
#endif
}
testing::Interval getCounter() {
#if defined(HAVE_LINUX_PERF_EVENT_H)
unsigned long long counter;
read(m_Fd, &counter, sizeof(unsigned long long));
return counter;
#else
return 0;
#endif
return -1;
}
void init(enum PerfEvent pEvent) {
#if defined(HAVE_LINUX_PERF_EVENT_H)
/* store the perf event numbers with the same order of skypat:Perf_event_name */
static const decltype(perf_event_attr::config)
event_list[] = {
PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS,
PERF_COUNT_HW_CACHE_REFERENCES, PERF_COUNT_HW_CACHE_MISSES,
PERF_COUNT_HW_BRANCH_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_MISSES,
PERF_COUNT_HW_BUS_CYCLES, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
PERF_COUNT_HW_STALLED_CYCLES_BACKEND, PERF_COUNT_HW_REF_CPU_CYCLES,
PERF_COUNT_SW_CPU_CLOCK, PERF_COUNT_SW_TASK_CLOCK,
PERF_COUNT_SW_PAGE_FAULTS, PERF_COUNT_SW_CONTEXT_SWITCHES,
PERF_COUNT_SW_CPU_MIGRATIONS, PERF_COUNT_SW_PAGE_FAULTS_MIN,
PERF_COUNT_SW_PAGE_FAULTS_MAJ, PERF_COUNT_SW_ALIGNMENT_FAULTS,
PERF_COUNT_SW_EMULATION_FAULTS,
#ifdef PERF_COUNT_SW_DUMMY
PERF_COUNT_SW_DUMMY
#else
0
#endif
};
struct perf_event_attr attr;
memset(&attr, 0, sizeof(attr));
attr.inherit = 1;
attr.disabled = 1;
attr.config = event_list[pEvent];
if(pEvent < PerfEvent::CPU_CLOCK)
attr.type = PERF_TYPE_HARDWARE;
else
attr.type = PERF_TYPE_SOFTWARE;
attr.size = sizeof(attr);
m_Fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
#endif
}
void start() {
#if defined(HAVE_LINUX_PERF_EVENT_H)
ioctl(m_Fd, PERF_EVENT_IOC_ENABLE);
#endif
m_Start = getCounter();
assert(-1 != m_Start && "fail to get performance counters");
}
void stop() {
#if defined(HAVE_LINUX_PERF_EVENT_H)
ioctl(m_Fd, PERF_EVENT_IOC_DISABLE);
#endif
m_End = getCounter();
assert(-1 != m_End && "fail to get performance counters");
}
testing::Interval getValue() const {
return (m_End - m_Start);
}
private:
testing::Interval m_Start;
testing::Interval m_End;
static long g_ClkTick;
int m_Fd;
};
long PerfImpl::g_ClkTick = -1;
static ManagedStatic<PerfImpl> g_Perf;
//===----------------------------------------------------------------------===//
// Perf
//===----------------------------------------------------------------------===//
Perf::Perf()
: m_Interval(0), m_EventType(PerfEvent::CONTEXT_SWITCHES), m_bIsActive(false) {
g_Perf->init(PerfEvent::CONTEXT_SWITCHES);
g_Perf->start();
}
Perf::Perf(enum PerfEvent pEvent)
: m_Interval(0), m_EventType(pEvent), m_bIsActive(false) {
g_Perf->init(pEvent);
g_Perf->start();
}
Perf::~Perf()
{
g_Perf->stop();
}
void Perf::start()
{
m_Interval = g_Perf->getValue();
m_bIsActive = true;
}
void Perf::stop()
{
m_Interval = g_Perf->getValue() - m_Interval;
m_bIsActive = false;
}
std::string Perf::unit()
{
return "times";
}
} // namespace of internal
} // namespace of testing
} // namespace of skypat
|