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