perf: Clean up perf_{session,alloc} management
[akaros.git] / kern / arch / x86 / perfmon.c
1 /* Copyright (c) 2015 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  *
6  * Manages the setting and reading of hardware perf counters across all cores,
7  * including generating samples in response to counter overflow interrupts.
8  *
9  * The hardware interface is pretty straightforward - it's mostly setting and
10  * unsetting fixed and unfixed events, sometimes with interrupts and trigger
11  * counts.
12  *
13  * The 'command' to the cores is a struct perfmon_alloc.  This tells the core
14  * which event to set up (this is the perfmon_event).  The cores respond in
15  * counters[], saying which of their counters it is using for that event.  If
16  * the cores are given different alloc requests, it is possible that they might
17  * choose different counters[] for the same event.
18  *
19  * These perfmon_allocs are collected in a perfmon_session.  The session is just
20  * a bunch of allocs, which are referred to by index (the 'ped').  Currently,
21  * the session is grabbed by whoever opens the perf FD in devarch, and closed
22  * when that FD is closed.  They are 1:1 with devarch's perf_contexts.
23  *
24  * The values for the counters are extracted with perfmon_get_event_status(),
25  * which uses a struct perfmon_status to collect the results.  We pass the
26  * perfmon_alloc as part of the perfmon_status_env, since we need to tell the
27  * core which counter we're talking about.
28  *
29  * You can have multiple sessions, but if you try to install the same counter in
30  * multiple, concurrent sessions, the hardware might complain (it definitely
31  * will if it is a fixed event). */
32
33 #include <sys/types.h>
34 #include <arch/ros/msr-index.h>
35 #include <arch/ros/membar.h>
36 #include <arch/x86.h>
37 #include <arch/msr.h>
38 #include <arch/uaccess.h>
39 #include <ros/errno.h>
40 #include <assert.h>
41 #include <trap.h>
42 #include <smp.h>
43 #include <atomic.h>
44 #include <core_set.h>
45 #include <kref.h>
46 #include <percpu.h>
47 #include <kmalloc.h>
48 #include <err.h>
49 #include <string.h>
50 #include <profiler.h>
51 #include <arch/perfmon.h>
52
53 #define FIXCNTR_NBITS 4
54 #define FIXCNTR_MASK (((uint64_t) 1 << FIXCNTR_NBITS) - 1)
55
56 struct perfmon_cpu_context {
57         spinlock_t lock;
58         struct perfmon_event counters[MAX_VAR_COUNTERS];
59         struct perfmon_event fixed_counters[MAX_FIX_COUNTERS];
60 };
61
62 struct perfmon_status_env {
63         struct perfmon_alloc *pa;
64         struct perfmon_status *pef;
65 };
66
67 static struct perfmon_cpu_caps cpu_caps;
68 static DEFINE_PERCPU(struct perfmon_cpu_context, counters_env);
69 DEFINE_PERCPU_INIT(perfmon_counters_env_init);
70
71 static void perfmon_counters_env_init(void)
72 {
73         for (int i = 0; i < num_cores; i++) {
74                 struct perfmon_cpu_context *cctx = _PERCPU_VARPTR(counters_env, i);
75
76                 spinlock_init_irqsave(&cctx->lock);
77         }
78 }
79
80 static void perfmon_read_cpu_caps(struct perfmon_cpu_caps *pcc)
81 {
82         uint32_t a, b, c, d;
83
84         cpuid(0x0a, 0, &a, &b, &c, &d);
85
86         pcc->proc_arch_events = a >> 24;
87         pcc->bits_x_counter = (a >> 16) & 0xff;
88         pcc->counters_x_proc = (a >> 8) & 0xff;
89         pcc->bits_x_fix_counter = (d >> 5) & 0xff;
90         pcc->fix_counters_x_proc = d & 0x1f;
91         pcc->perfmon_version = a & 0xff;
92 }
93
94 static void perfmon_enable_event(int idx, uint64_t event)
95 {
96         uint64_t gctrl;
97
98         /* Events need to be enabled in both MSRs */
99         write_msr(MSR_ARCH_PERFMON_EVENTSEL0 + idx, event);
100         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
101         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl | (1 << idx));
102 }
103
104 static void perfmon_disable_event(int idx)
105 {
106         uint64_t gctrl;
107
108         /* Events can be disabled in either location.  We could just clear the
109          * global ctrl, but we use the contents of EVENTSEL to say if the counter is
110          * available or not. */
111         write_msr(MSR_ARCH_PERFMON_EVENTSEL0 + idx, 0);
112         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
113         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl & ~(1 << idx));
114 }
115
116 static bool perfmon_event_available(uint32_t idx)
117 {
118         return read_msr(MSR_ARCH_PERFMON_EVENTSEL0 + idx) == 0;
119 }
120
121 /* Helper.  Given an event, a fixed counter index, and the contents of the fixed
122  * counter ctl MSR, output the value for the fixed counter ctl that will enable
123  * the event at idx. */
124 static uint64_t perfmon_apply_fixevent_mask(uint64_t event, int idx,
125                                             uint64_t base)
126 {
127         uint64_t m = 0;
128
129         if (PMEV_GET_OS(event))
130                 m |= (1 << 0);
131         if (PMEV_GET_USR(event))
132                 m |= (1 << 1);
133         if (PMEV_GET_ANYTH(event) && (cpu_caps.perfmon_version >= 3))
134                 m |= (1 << 2);
135         if (PMEV_GET_INTEN(event))
136                 m |= (1 << 3);
137         /* Enable enforcement: we need at least one bit set so that this fixed
138          * counter appears to be in use. */
139         if (PMEV_GET_EN(event) && !PMEV_GET_OS(event) && !PMEV_GET_USR(event))
140                 m |= (1 << 0) | (1 << 1);
141
142         m <<= idx * FIXCNTR_NBITS;
143         m |= base & ~(FIXCNTR_MASK << (idx * FIXCNTR_NBITS));
144
145         return m;
146 }
147
148 /* These helpers take the fxctrl_value to save on a rdmsr. */
149 static void perfmon_enable_fix_event(int idx, uint64_t event,
150                                      uint64_t fxctrl_value)
151 {
152         uint64_t gctrl, fx;
153
154         /* Enable in both locations: the bits in FIXED and the bit in GLOBAL. */
155         fx = perfmon_apply_fixevent_mask(event, idx, fxctrl_value);
156         write_msr(MSR_CORE_PERF_FIXED_CTR_CTRL, fx);
157         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
158         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl | ((uint64_t) 1 << (32 + idx)));
159 }
160
161 static void perfmon_disable_fix_event(int idx, uint64_t fxctrl_value)
162 {
163         uint64_t gctrl;
164
165         /* Events can be disabled in either location.  We could just clear the
166          * global ctrl, but we use the bits of fxctlr to say if the counter is
167          * available or not. */
168         write_msr(MSR_CORE_PERF_FIXED_CTR_CTRL,
169                   fxctrl_value & ~(FIXCNTR_MASK << (idx * FIXCNTR_NBITS)));
170         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
171         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl & ~((uint64_t) 1 << (32 + idx)));
172 }
173
174 static bool perfmon_fix_event_available(uint32_t idx, uint64_t fxctrl_value)
175 {
176         return (fxctrl_value & (FIXCNTR_MASK << (idx * FIXCNTR_NBITS))) == 0;
177 }
178
179 /* Helper to set a fixed perfcounter to trigger/overflow after count events.
180  * Anytime you set a perfcounter to something non-zero, you need to use this
181  * helper. */
182 static void perfmon_set_fixed_trigger(unsigned int idx, uint64_t count)
183 {
184         int64_t write_val = -(int64_t)count;
185
186         write_val &= (1ULL << cpu_caps.bits_x_fix_counter) - 1;
187         write_msr(MSR_CORE_PERF_FIXED_CTR0 + idx, write_val);
188 }
189
190 /* Helper to set a regular perfcounter to trigger/overflow after count events.
191  * Anytime you set a perfcounter to something non-zero, you ought to use this
192  * helper. */
193 static void perfmon_set_unfixed_trigger(unsigned int idx, uint64_t count)
194 {
195         int64_t write_val = -(int64_t)count;
196
197         write_val &= (1ULL << cpu_caps.bits_x_counter) - 1;
198         write_msr(MSR_IA32_PERFCTR0 + idx, write_val);
199 }
200
201 static void perfmon_do_cores_alloc(void *opaque)
202 {
203         struct perfmon_alloc *pa = (struct perfmon_alloc *) opaque;
204         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
205         int i;
206         struct perfmon_event *pev;
207
208         spin_lock_irqsave(&cctx->lock);
209         if (perfmon_is_fixed_event(&pa->ev)) {
210                 uint64_t fxctrl_value = read_msr(MSR_CORE_PERF_FIXED_CTR_CTRL);
211
212                 i = PMEV_GET_EVENT(pa->ev.event);
213                 if (i >= (int) cpu_caps.fix_counters_x_proc) {
214                         i = -EINVAL;
215                 } else if (!perfmon_fix_event_available(i, fxctrl_value)) {
216                         i = -EBUSY;
217                 } else {
218                         /* Keep a copy of pa->ev for later.  pa is read-only and shared. */
219                         cctx->fixed_counters[i] = pa->ev;
220                         pev = &cctx->fixed_counters[i];
221                         if (PMEV_GET_INTEN(pev->event))
222                                 perfmon_set_fixed_trigger(i, pev->trigger_count);
223                         else
224                                 write_msr(MSR_CORE_PERF_FIXED_CTR0 + i, 0);
225                         write_msr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 1ULL << (32 + i));
226                         perfmon_enable_fix_event(i, pev->event, fxctrl_value);
227                 }
228         } else {
229                 for (i = 0; i < (int) cpu_caps.counters_x_proc; i++) {
230                         if (cctx->counters[i].event == 0) {
231                                 /* kernel bug if the MSRs don't agree with our bookkeeping */
232                                 assert(perfmon_event_available(i));
233                                 break;
234                         }
235                 }
236                 if (i < (int) cpu_caps.counters_x_proc) {
237                         cctx->counters[i] = pa->ev;
238                         pev = &cctx->counters[i];
239                         if (PMEV_GET_INTEN(pev->event))
240                                 perfmon_set_unfixed_trigger(i, pev->trigger_count);
241                         else
242                                 write_msr(MSR_IA32_PERFCTR0 + i, 0);
243                         write_msr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 1ULL << i);
244                         perfmon_enable_event(i, pev->event);
245                 } else {
246                         i = -ENOSPC;
247                 }
248         }
249         spin_unlock_irqsave(&cctx->lock);
250
251         pa->cores_counters[core_id()] = (counter_t) i;
252 }
253
254 static void perfmon_do_cores_free(void *opaque)
255 {
256         struct perfmon_alloc *pa = (struct perfmon_alloc *) opaque;
257         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
258         int err = 0, coreno = core_id();
259         counter_t ccno = pa->cores_counters[coreno];
260
261         spin_lock_irqsave(&cctx->lock);
262         if (perfmon_is_fixed_event(&pa->ev)) {
263                 uint64_t fxctrl_value = read_msr(MSR_CORE_PERF_FIXED_CTR_CTRL);
264
265                 if ((ccno >= cpu_caps.fix_counters_x_proc) ||
266                     perfmon_fix_event_available(ccno, fxctrl_value)) {
267                         err = -ENOENT;
268                 } else {
269                         perfmon_init_event(&cctx->fixed_counters[ccno]);
270                         perfmon_disable_fix_event((int) ccno, fxctrl_value);
271                         write_msr(MSR_CORE_PERF_FIXED_CTR0 + ccno, 0);
272                 }
273         } else {
274                 if (ccno < (int) cpu_caps.counters_x_proc) {
275                         perfmon_init_event(&cctx->counters[ccno]);
276                         perfmon_disable_event((int) ccno);
277                         write_msr(MSR_IA32_PERFCTR0 + ccno, 0);
278                 } else {
279                         err = -ENOENT;
280                 }
281         }
282         spin_unlock_irqsave(&cctx->lock);
283
284         pa->cores_counters[coreno] = (counter_t) err;
285 }
286
287 static void perfmon_do_cores_status(void *opaque)
288 {
289         struct perfmon_status_env *env = (struct perfmon_status_env *) opaque;
290         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
291         int coreno = core_id();
292         counter_t ccno = env->pa->cores_counters[coreno];
293
294         spin_lock_irqsave(&cctx->lock);
295         if (perfmon_is_fixed_event(&env->pa->ev))
296                 env->pef->cores_values[coreno] =
297                     read_msr(MSR_CORE_PERF_FIXED_CTR0 + ccno);
298         else
299                 env->pef->cores_values[coreno] =
300                     read_msr(MSR_IA32_PERFCTR0 + ccno);
301         spin_unlock_irqsave(&cctx->lock);
302 }
303
304 static void perfmon_setup_alloc_core_set(const struct perfmon_alloc *pa,
305                                          struct core_set *cset)
306 {
307         int i;
308
309         core_set_init(cset);
310         for (i = 0; i < num_cores; i++) {
311                 if (pa->cores_counters[i] >= 0)
312                         core_set_setcpu(cset, i);
313         }
314 }
315
316 static void perfmon_cleanup_cores_alloc(struct perfmon_alloc *pa)
317 {
318         struct core_set cset;
319
320         perfmon_setup_alloc_core_set(pa, &cset);
321         smp_do_in_cores(&cset, perfmon_do_cores_free, pa);
322 }
323
324 static void perfmon_free_alloc(struct perfmon_alloc *pa)
325 {
326         kfree(pa);
327 }
328
329 static void perfmon_destroy_alloc(struct perfmon_alloc *pa)
330 {
331         perfmon_cleanup_cores_alloc(pa);
332         perfmon_free_alloc(pa);
333 }
334
335 static struct perfmon_alloc *perfmon_create_alloc(const struct perfmon_event *pev)
336 {
337         int i;
338         struct perfmon_alloc *pa = kzmalloc(sizeof(struct perfmon_alloc) +
339                                                 num_cores * sizeof(counter_t),
340                                             MEM_WAIT);
341
342         pa->ev = *pev;
343         for (i = 0; i < num_cores; i++)
344                 pa->cores_counters[i] = INVALID_COUNTER;
345
346         return pa;
347 }
348
349 static struct perfmon_status *perfmon_status_alloc(void)
350 {
351         struct perfmon_status *pef = kzmalloc(sizeof(struct perfmon_status) +
352                                                   num_cores * sizeof(uint64_t),
353                                               MEM_WAIT);
354
355         return pef;
356 }
357
358 static void perfmon_arm_irq(void)
359 {
360         apicrput(MSR_LAPIC_LVT_PERFMON, IdtLAPIC_PCINT);
361 }
362
363 bool perfmon_supported(void)
364 {
365         return cpu_caps.perfmon_version >= 2;
366 }
367
368 void perfmon_global_init(void)
369 {
370         perfmon_read_cpu_caps(&cpu_caps);
371 }
372
373 void perfmon_pcpu_init(void)
374 {
375         int i;
376
377         if (!perfmon_supported())
378                 return;
379         /* Enable user level access to the performance counters */
380         lcr4(rcr4() | CR4_PCE);
381
382         /* Reset all the counters and selectors to zero.
383          */
384         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
385         for (i = 0; i < (int) cpu_caps.counters_x_proc; i++) {
386                 write_msr(MSR_ARCH_PERFMON_EVENTSEL0 + i, 0);
387                 write_msr(MSR_IA32_PERFCTR0 + i, 0);
388         }
389         write_msr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
390         for (i = 0; i < (int) cpu_caps.fix_counters_x_proc; i++)
391                 write_msr(MSR_CORE_PERF_FIXED_CTR0 + i, 0);
392
393         perfmon_arm_irq();
394 }
395
396 static uint64_t perfmon_make_sample_event(const struct perfmon_event *pev)
397 {
398         return pev->user_data;
399 }
400
401 void perfmon_interrupt(struct hw_trapframe *hw_tf, void *data)
402 {
403         int i;
404         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
405         uint64_t gctrl, status;
406
407         spin_lock_irqsave(&cctx->lock);
408         /* We need to save the global control status, because we need to disable
409          * counters in order to be able to reset their values.
410          * We will restore the global control status on exit.
411          */
412         status = read_msr(MSR_CORE_PERF_GLOBAL_STATUS);
413         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
414         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
415         for (i = 0; i < (int) cpu_caps.counters_x_proc; i++) {
416                 if (status & ((uint64_t) 1 << i)) {
417                         if (cctx->counters[i].event) {
418                                 profiler_add_hw_sample(
419                                     hw_tf, perfmon_make_sample_event(cctx->counters + i));
420                                 perfmon_set_unfixed_trigger(i, cctx->counters[i].trigger_count);
421                         }
422                 }
423         }
424         for (i = 0; i < (int) cpu_caps.fix_counters_x_proc; i++) {
425                 if (status & ((uint64_t) 1 << (32 + i))) {
426                         if (cctx->fixed_counters[i].event) {
427                                 profiler_add_hw_sample(
428                                     hw_tf, perfmon_make_sample_event(cctx->fixed_counters + i));
429                                 perfmon_set_fixed_trigger(i,
430                                         cctx->fixed_counters[i].trigger_count);
431                         }
432                 }
433         }
434         write_msr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, status);
435         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl);
436         spin_unlock_irqsave(&cctx->lock);
437
438         /* We need to re-arm the IRQ as the PFM IRQ gets masked on trigger.
439          * Note that KVM and real HW seems to be doing two different things WRT
440          * re-arming the IRQ. KVM re-arms does not mask the IRQ, while real HW does.
441          */
442         perfmon_arm_irq();
443 }
444
445 void perfmon_get_cpu_caps(struct perfmon_cpu_caps *pcc)
446 {
447         memcpy(pcc, &cpu_caps, sizeof(*pcc));
448 }
449
450 static int perfmon_install_session_alloc(struct perfmon_session *ps,
451                                          struct perfmon_alloc *pa)
452 {
453         qlock(&ps->qlock);
454         for (int i = 0; i < ARRAY_SIZE(ps->allocs); i++) {
455                 if (!ps->allocs[i]) {
456                         ps->allocs[i] = pa;
457                         qunlock(&ps->qlock);
458                         return i;
459                 }
460         }
461         qunlock(&ps->qlock);
462         error(ENFILE, "Too many perf allocs in the session");
463 }
464
465 int perfmon_open_event(const struct core_set *cset, struct perfmon_session *ps,
466                        const struct perfmon_event *pev)
467 {
468         ERRSTACK(1);
469         int i;
470         struct perfmon_alloc *pa = perfmon_create_alloc(pev);
471
472         if (waserror()) {
473                 perfmon_destroy_alloc(pa);
474                 nexterror();
475         }
476         /* Ensure we're turning on the event.  The user could have forgotten to set
477          * it.  Our tracking of whether or not a counter is in use depends on it
478          * being enabled, or at least that some bit is set. */
479         PMEV_SET_EN(pa->ev.event, 1);
480         smp_do_in_cores(cset, perfmon_do_cores_alloc, pa);
481
482         for (i = 0; i < num_cores; i++) {
483                 if (core_set_getcpu(cset, i)) {
484                         counter_t ccno = pa->cores_counters[i];
485
486                         if (unlikely(ccno < 0)) {
487                                 perfmon_destroy_alloc(pa);
488                                 return (int) ccno;
489                         }
490                 }
491         }
492         /* The perfmon_alloc data structure will not be visible to userspace,
493          * until the perfmon_install_session_alloc() completes, and at that
494          * time the smp_do_in_cores(perfmon_do_cores_alloc) will have run on
495          * all cores.
496          * The perfmon_alloc data structure will never be changed once published.
497          */
498         i = perfmon_install_session_alloc(ps, pa);
499         poperror();
500
501         return i;
502 }
503
504 /* Helper, looks up a pa, given ped.  Hold the qlock. */
505 static struct perfmon_alloc *__lookup_pa(struct perfmon_session *ps, int ped)
506 {
507         struct perfmon_alloc *pa;
508
509         if (unlikely((ped < 0) || (ped >= ARRAY_SIZE(ps->allocs))))
510                 error(EBADFD, "Perf event %d out of range", ped);
511         pa = ps->allocs[ped];
512         if (!pa)
513                 error(ENOENT, "No perf alloc for event %d", ped);
514         return pa;
515 }
516
517 void perfmon_close_event(struct perfmon_session *ps, int ped)
518 {
519         ERRSTACK(1);
520         struct perfmon_alloc *pa;
521
522         qlock(&ps->qlock);
523         if (waserror()) {
524                 qunlock(&ps->qlock);
525                 nexterror();
526         };
527         /* lookup does the error checking */
528         pa = __lookup_pa(ps, ped);
529         ps->allocs[ped] = NULL;
530         poperror();
531         qunlock(&ps->qlock);
532         perfmon_destroy_alloc(pa);
533 }
534
535 /* Fetches the status (i.e. PMU counters) of event ped from all applicable
536  * cores.  Returns a perfmon_status, which the caller should free. */
537 struct perfmon_status *perfmon_get_event_status(struct perfmon_session *ps,
538                                                 int ped)
539 {
540         ERRSTACK(1);
541         struct core_set cset;
542         struct perfmon_status_env env;
543
544         /* qlock keeps the PA alive.  We don't want to spin, since the spinners
545          * might prevent the smp_do_in_cores(), resulting in a deadlock. */
546         qlock(&ps->qlock);
547         if (waserror()) {
548                 qunlock(&ps->qlock);
549                 nexterror();
550         };
551         env.pa = __lookup_pa(ps, ped);
552         env.pef = perfmon_status_alloc();
553
554         perfmon_setup_alloc_core_set(env.pa, &cset);
555         smp_do_in_cores(&cset, perfmon_do_cores_status, &env);
556
557         poperror();
558         qunlock(&ps->qlock);
559
560         return env.pef;
561 }
562
563 void perfmon_free_event_status(struct perfmon_status *pef)
564 {
565         kfree(pef);
566 }
567
568 static void perfmon_release_session(struct kref *kref)
569 {
570         struct perfmon_session *ps =
571             container_of(kref, struct perfmon_session, ref);
572
573         for (int i = 0; i < ARRAY_SIZE(ps->allocs); i++) {
574                 struct perfmon_alloc *pa = ps->allocs[i];
575
576                 if (pa)
577                         perfmon_destroy_alloc(pa);
578         }
579         kfree(ps);
580 }
581
582 struct perfmon_session *perfmon_create_session(void)
583 {
584         struct perfmon_session *ps = kzmalloc(sizeof(struct perfmon_session),
585                                               MEM_WAIT);
586
587         kref_init(&ps->ref, perfmon_release_session, 1);
588         qlock_init(&ps->qlock);
589         return ps;
590 }
591
592 void perfmon_get_session(struct perfmon_session *ps)
593 {
594         kref_get(&ps->ref, 1);
595 }
596
597 void perfmon_close_session(struct perfmon_session *ps)
598 {
599         kref_put(&ps->ref);
600 }