blob: 0f3764aa52abdef2878b10da207ebd5a948337fe [file] [log] [blame]
Wu Fengguangcea92ce2009-03-20 10:08:02 +08001/*
2 * Ioctls that can be done on a perf counter fd:
3 */
4#define PERF_COUNTER_IOC_ENABLE _IO('$', 0)
5#define PERF_COUNTER_IOC_DISABLE _IO('$', 1)
6
7/*
8 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
9 * counters in the current task.
10 */
11#define PR_TASK_PERF_COUNTERS_DISABLE 31
12#define PR_TASK_PERF_COUNTERS_ENABLE 32
13
14#define MAX_COUNTERS 64
15#define MAX_NR_CPUS 256
16
17#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18
Wu Fengguangf49012f2009-03-20 10:08:03 +080019#define rdclock() \
20({ \
21 struct timespec ts; \
22 \
23 clock_gettime(CLOCK_MONOTONIC, &ts); \
24 ts.tv_sec * 1000000000ULL + ts.tv_nsec; \
25})
26
Wu Fengguangcea92ce2009-03-20 10:08:02 +080027/*
28 * Pick up some kernel type conventions:
29 */
30#define __user
31#define asmlinkage
32
33typedef unsigned int __u32;
34typedef unsigned long long __u64;
35typedef long long __s64;
36
37/*
38 * User-space ABI bits:
39 */
40
41/*
42 * Generalized performance counter event types, used by the hw_event.type
43 * parameter of the sys_perf_counter_open() syscall:
44 */
45enum hw_event_types {
46 /*
47 * Common hardware events, generalized by the kernel:
48 */
49 PERF_COUNT_CPU_CYCLES = 0,
50 PERF_COUNT_INSTRUCTIONS = 1,
51 PERF_COUNT_CACHE_REFERENCES = 2,
52 PERF_COUNT_CACHE_MISSES = 3,
53 PERF_COUNT_BRANCH_INSTRUCTIONS = 4,
54 PERF_COUNT_BRANCH_MISSES = 5,
55 PERF_COUNT_BUS_CYCLES = 6,
56
57 PERF_HW_EVENTS_MAX = 7,
58
59 /*
60 * Special "software" counters provided by the kernel, even if
61 * the hardware does not support performance counters. These
62 * counters measure various physical and sw events of the
63 * kernel (and allow the profiling of them as well):
64 */
65 PERF_COUNT_CPU_CLOCK = -1,
66 PERF_COUNT_TASK_CLOCK = -2,
67 PERF_COUNT_PAGE_FAULTS = -3,
68 PERF_COUNT_CONTEXT_SWITCHES = -4,
69 PERF_COUNT_CPU_MIGRATIONS = -5,
70
71 PERF_SW_EVENTS_MIN = -6,
72};
73
74/*
75 * IRQ-notification data record type:
76 */
77enum perf_counter_record_type {
78 PERF_RECORD_SIMPLE = 0,
79 PERF_RECORD_IRQ = 1,
80 PERF_RECORD_GROUP = 2,
81};
82
83/*
84 * Hardware event to monitor via a performance monitoring counter:
85 */
86struct perf_counter_hw_event {
87 __s64 type;
88
89 __u64 irq_period;
90 __u64 record_type;
91 __u64 read_format;
92
93 __u64 disabled : 1, /* off by default */
94 nmi : 1, /* NMI sampling */
95 raw : 1, /* raw event type */
96 inherit : 1, /* children inherit it */
97 pinned : 1, /* must always be on PMU */
98 exclusive : 1, /* only group on PMU */
99 exclude_user : 1, /* don't count user */
100 exclude_kernel : 1, /* ditto kernel */
101 exclude_hv : 1, /* ditto hypervisor */
102 exclude_idle : 1, /* don't count when idle */
103
104 __reserved_1 : 54;
105
106 __u32 extra_config_len;
107 __u32 __reserved_4;
108
109 __u64 __reserved_2;
110 __u64 __reserved_3;
111};
112
113#ifdef __x86_64__
114# define __NR_perf_counter_open 295
115#endif
116
117#ifdef __i386__
118# define __NR_perf_counter_open 333
119#endif
120
121#ifdef __powerpc__
122#define __NR_perf_counter_open 319
123#endif
124
125asmlinkage int sys_perf_counter_open(
126
127 struct perf_counter_hw_event *hw_event_uptr __user,
128 pid_t pid,
129 int cpu,
130 int group_fd,
131 unsigned long flags)
132{
133 int ret;
134
135 ret = syscall(
136 __NR_perf_counter_open, hw_event_uptr, pid, cpu, group_fd, flags);
137#if defined(__x86_64__) || defined(__i386__)
138 if (ret < 0 && ret > -4096) {
139 errno = -ret;
140 ret = -1;
141 }
142#endif
143 return ret;
144}
145
Wu Fengguangf49012f2009-03-20 10:08:03 +0800146static char *hw_event_names [] = {
147 "CPU cycles",
148 "instructions",
149 "cache references",
150 "cache misses",
151 "branches",
152 "branch misses",
153 "bus cycles",
154};
155
156static char *sw_event_names [] = {
157 "cpu clock ticks",
158 "task clock ticks",
159 "pagefaults",
160 "context switches",
161 "CPU migrations",
162};
163
164struct event_symbol {
165 int event;
166 char *symbol;
167};
168
169static struct event_symbol event_symbols [] = {
170 {PERF_COUNT_CPU_CYCLES, "cpu-cycles", },
171 {PERF_COUNT_CPU_CYCLES, "cycles", },
172 {PERF_COUNT_INSTRUCTIONS, "instructions", },
173 {PERF_COUNT_CACHE_REFERENCES, "cache-references", },
174 {PERF_COUNT_CACHE_MISSES, "cache-misses", },
175 {PERF_COUNT_BRANCH_INSTRUCTIONS, "branch-instructions", },
176 {PERF_COUNT_BRANCH_INSTRUCTIONS, "branches", },
177 {PERF_COUNT_BRANCH_MISSES, "branch-misses", },
178 {PERF_COUNT_BUS_CYCLES, "bus-cycles", },
179 {PERF_COUNT_CPU_CLOCK, "cpu-ticks", },
180 {PERF_COUNT_CPU_CLOCK, "ticks", },
181 {PERF_COUNT_TASK_CLOCK, "task-ticks", },
182 {PERF_COUNT_PAGE_FAULTS, "page-faults", },
183 {PERF_COUNT_PAGE_FAULTS, "faults", },
184 {PERF_COUNT_CONTEXT_SWITCHES, "context-switches", },
185 {PERF_COUNT_CONTEXT_SWITCHES, "cs", },
186 {PERF_COUNT_CPU_MIGRATIONS, "cpu-migrations", },
187 {PERF_COUNT_CPU_MIGRATIONS, "migrations", },
188};
189
190static int type_valid(int type)
191{
192 if (type >= PERF_HW_EVENTS_MAX)
193 return 0;
194 if (type <= PERF_SW_EVENTS_MIN)
195 return 0;
196
197 return 1;
198}
199
200static char *event_name(int ctr)
201{
202 int type = event_id[ctr];
203 static char buf[32];
204
205 if (event_raw[ctr]) {
206 sprintf(buf, "raw 0x%x", type);
207 return buf;
208 }
209 if (!type_valid(type))
210 return "unknown";
211
212 if (type >= 0)
213 return hw_event_names[type];
214
215 return sw_event_names[-type-1];
216}
217
218/*
219 * Each event can have multiple symbolic names.
220 * Symbolic names are (almost) exactly matched.
221 */
222static int match_event_symbols(char *str)
223{
224 unsigned int i;
225
226 if (isdigit(str[0]) || str[0] == '-')
227 return atoi(str);
228
229 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
230 if (!strncmp(str, event_symbols[i].symbol,
231 strlen(event_symbols[i].symbol)))
232 return event_symbols[i].event;
233 }
234
235 return PERF_HW_EVENTS_MAX;
236}
237
238static void parse_events(char *str)
239{
240 int type, raw;
241
242again:
243 nr_counters++;
244 if (nr_counters == MAX_COUNTERS)
245 display_help();
246
247 raw = 0;
248 if (*str == 'r') {
249 raw = 1;
250 ++str;
251 type = strtol(str, NULL, 16);
252 } else {
253 type = match_event_symbols(str);
254 if (!type_valid(type))
255 display_help();
256 }
257
258 event_id[nr_counters] = type;
259 event_raw[nr_counters] = raw;
260
261 str = strstr(str, ",");
262 if (str) {
263 str++;
264 goto again;
265 }
266}
267