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