Fix: nestable pthread cancelstate
[lttng-ust.git] / liblttng-ust / lttng-context-perf-counters.c
CommitLineData
d58d1454
MD
1/*
2 * lttng-context-perf-counters.c
3 *
4 * LTTng UST performance monitoring counters (perf-counters) integration.
5 *
6 * Copyright (C) 2009-2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
3fbec7dc 23#define _LGPL_SOURCE
d58d1454
MD
24#include <sys/types.h>
25#include <unistd.h>
26#include <string.h>
27#include <stdlib.h>
28#include <stdio.h>
649fb6b3 29#include <stdbool.h>
d58d1454
MD
30#include <sys/mman.h>
31#include <sys/syscall.h>
d58d1454
MD
32#include <lttng/ust-events.h>
33#include <lttng/ust-tracer.h>
34#include <lttng/ringbuffer-config.h>
595c1577 35#include <lttng/ust-cancelstate.h>
d58d1454
MD
36#include <urcu/system.h>
37#include <urcu/arch.h>
38#include <urcu/rculist.h>
39#include <helper.h>
40#include <urcu/ref.h>
41#include <usterr-signal-safe.h>
42#include <signal.h>
20142124 43#include <urcu/tls-compat.h>
77d7fa98 44#include "perf_event.h"
d58d1454
MD
45#include "lttng-tracer-core.h"
46
47/*
48 * We use a global perf counter key and iterate on per-thread RCU lists
49 * of fields in the fast path, even though this is not strictly speaking
50 * what would provide the best fast-path complexity, to ensure teardown
51 * of sessions vs thread exit is handled racelessly.
52 *
53 * Updates and traversals of thread_list are protected by UST lock.
54 * Updates to rcu_field_list are protected by UST lock.
55 */
56
57struct lttng_perf_counter_thread_field {
58 struct lttng_perf_counter_field *field; /* Back reference */
59 struct perf_event_mmap_page *pc;
60 struct cds_list_head thread_field_node; /* Per-field list of thread fields (node) */
61 struct cds_list_head rcu_field_node; /* RCU per-thread list of fields (node) */
b9389e6e 62 int fd; /* Perf FD */
d58d1454
MD
63};
64
65struct lttng_perf_counter_thread {
66 struct cds_list_head rcu_field_list; /* RCU per-thread list of fields */
67};
68
69struct lttng_perf_counter_field {
70 struct perf_event_attr attr;
71 struct cds_list_head thread_field_list; /* Per-field list of thread fields */
72};
73
74static pthread_key_t perf_counter_key;
75
20142124
MD
76/*
77 * lttng_perf_lock - Protect lttng-ust perf counter data structures
78 *
79 * Nests within the ust_lock, and therefore within the libc dl lock.
80 * Therefore, we need to fixup the TLS before nesting into this lock.
81 * Nests inside RCU bp read-side lock. Protects against concurrent
82 * fork.
83 */
84static pthread_mutex_t ust_perf_mutex = PTHREAD_MUTEX_INITIALIZER;
85
20142124
MD
86/*
87 * Track whether we are tracing from a signal handler nested on an
88 * application thread.
89 */
90static DEFINE_URCU_TLS(int, ust_perf_mutex_nest);
91
92/*
93 * Force a read (imply TLS fixup for dlopen) of TLS variables.
94 */
95void lttng_ust_fixup_perf_counter_tls(void)
96{
97 asm volatile ("" : : "m" (URCU_TLS(ust_perf_mutex_nest)));
98}
99
100void lttng_perf_lock(void)
101{
102 sigset_t sig_all_blocked, orig_mask;
595c1577 103 int ret;
20142124 104
595c1577
MD
105 if (lttng_ust_cancelstate_disable_push()) {
106 ERR("lttng_ust_cancelstate_disable_push");
20142124
MD
107 }
108 sigfillset(&sig_all_blocked);
109 ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
110 if (ret) {
111 ERR("pthread_sigmask: %s", strerror(ret));
112 }
113 if (!URCU_TLS(ust_perf_mutex_nest)++) {
114 /*
115 * Ensure the compiler don't move the store after the close()
116 * call in case close() would be marked as leaf.
117 */
118 cmm_barrier();
119 pthread_mutex_lock(&ust_perf_mutex);
20142124
MD
120 }
121 ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
122 if (ret) {
123 ERR("pthread_sigmask: %s", strerror(ret));
124 }
125}
126
127void lttng_perf_unlock(void)
128{
129 sigset_t sig_all_blocked, orig_mask;
595c1577 130 int ret;
20142124
MD
131
132 sigfillset(&sig_all_blocked);
133 ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
134 if (ret) {
135 ERR("pthread_sigmask: %s", strerror(ret));
136 }
137 /*
138 * Ensure the compiler don't move the store before the close()
139 * call, in case close() would be marked as leaf.
140 */
141 cmm_barrier();
142 if (!--URCU_TLS(ust_perf_mutex_nest)) {
20142124
MD
143 pthread_mutex_unlock(&ust_perf_mutex);
144 }
145 ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
146 if (ret) {
147 ERR("pthread_sigmask: %s", strerror(ret));
148 }
595c1577
MD
149 if (lttng_ust_cancelstate_disable_pop()) {
150 ERR("lttng_ust_cancelstate_disable_pop");
20142124
MD
151 }
152}
153
d58d1454 154static
53569322 155size_t perf_counter_get_size(struct lttng_ctx_field *field, size_t offset)
d58d1454
MD
156{
157 size_t size = 0;
158
159 size += lib_ring_buffer_align(offset, lttng_alignof(uint64_t));
160 size += sizeof(uint64_t);
161 return size;
162}
163
a3a8d943
MD
164static
165uint64_t read_perf_counter_syscall(
166 struct lttng_perf_counter_thread_field *thread_field)
167{
168 uint64_t count;
169
170 if (caa_unlikely(thread_field->fd < 0))
171 return 0;
172
173 if (caa_unlikely(read(thread_field->fd, &count, sizeof(count))
174 < sizeof(count)))
175 return 0;
176
177 return count;
178}
179
d58d1454
MD
180#if defined(__x86_64__) || defined(__i386__)
181
182static
183uint64_t rdpmc(unsigned int counter)
184{
185 unsigned int low, high;
186
187 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
188
189 return low | ((uint64_t) high) << 32;
190}
191
77d7fa98
MD
192static
193bool has_rdpmc(struct perf_event_mmap_page *pc)
194{
195 if (caa_unlikely(!pc->cap_bit0_is_deprecated))
196 return false;
197 /* Since Linux kernel 3.12. */
198 return pc->cap_user_rdpmc;
199}
200
d58d1454 201static
a3a8d943 202uint64_t arch_read_perf_counter(
d286ad50 203 struct lttng_perf_counter_thread_field *thread_field)
d58d1454
MD
204{
205 uint32_t seq, idx;
206 uint64_t count;
d286ad50 207 struct perf_event_mmap_page *pc = thread_field->pc;
d58d1454
MD
208
209 if (caa_unlikely(!pc))
210 return 0;
211
212 do {
213 seq = CMM_LOAD_SHARED(pc->lock);
214 cmm_barrier();
215
216 idx = pc->index;
77d7fa98 217 if (caa_likely(has_rdpmc(pc) && idx)) {
4f58f54f
MD
218 int64_t pmcval;
219
220 pmcval = rdpmc(idx - 1);
221 /* Sign-extend the pmc register result. */
222 pmcval <<= 64 - pc->pmc_width;
223 pmcval >>= 64 - pc->pmc_width;
224 count = pc->offset + pmcval;
225 } else {
a3a8d943
MD
226 /* Fall-back on system call if rdpmc cannot be used. */
227 return read_perf_counter_syscall(thread_field);
4f58f54f 228 }
d58d1454
MD
229 cmm_barrier();
230 } while (CMM_LOAD_SHARED(pc->lock) != seq);
231
232 return count;
233}
234
d286ad50 235static
a3a8d943 236int arch_perf_keep_fd(struct lttng_perf_counter_thread_field *thread_field)
d286ad50 237{
a3a8d943 238 struct perf_event_mmap_page *pc = thread_field->pc;
d286ad50 239
a3a8d943 240 if (!pc)
d286ad50 241 return 0;
77d7fa98 242 return !has_rdpmc(pc);
a3a8d943 243}
d286ad50 244
a3a8d943 245#else
d286ad50 246
a3a8d943
MD
247/* Generic (slow) implementation using a read system call. */
248static
249uint64_t arch_read_perf_counter(
250 struct lttng_perf_counter_thread_field *thread_field)
251{
252 return read_perf_counter_syscall(thread_field);
d286ad50
JD
253}
254
a3a8d943
MD
255static
256int arch_perf_keep_fd(struct lttng_perf_counter_thread_field *thread_field)
257{
258 return 1;
259}
d286ad50 260
a3a8d943 261#endif
d286ad50 262
d58d1454
MD
263static
264int sys_perf_event_open(struct perf_event_attr *attr,
265 pid_t pid, int cpu, int group_fd,
266 unsigned long flags)
267{
268 return syscall(SYS_perf_event_open, attr, pid, cpu,
269 group_fd, flags);
270}
271
272static
b9389e6e 273int open_perf_fd(struct perf_event_attr *attr)
d58d1454 274{
b9389e6e 275 int fd;
d58d1454
MD
276
277 fd = sys_perf_event_open(attr, 0, -1, -1, 0);
278 if (fd < 0)
b9389e6e
JD
279 return -1;
280
281 return fd;
282}
283
d286ad50
JD
284static
285void close_perf_fd(int fd)
286{
287 int ret;
288
289 if (fd < 0)
290 return;
291
292 ret = close(fd);
293 if (ret) {
294 perror("Error closing LTTng-UST perf memory mapping FD");
295 }
296}
297
77d7fa98 298static void setup_perf(struct lttng_perf_counter_thread_field *thread_field)
b9389e6e
JD
299{
300 void *perf_addr;
d58d1454
MD
301
302 perf_addr = mmap(NULL, sizeof(struct perf_event_mmap_page),
b9389e6e 303 PROT_READ, MAP_SHARED, thread_field->fd, 0);
d58d1454 304 if (perf_addr == MAP_FAILED)
b9389e6e 305 perf_addr = NULL;
77d7fa98 306 thread_field->pc = perf_addr;
b9389e6e 307
a3a8d943 308 if (!arch_perf_keep_fd(thread_field)) {
b9389e6e
JD
309 close_perf_fd(thread_field->fd);
310 thread_field->fd = -1;
6c2125af 311 }
d58d1454
MD
312}
313
314static
315void unmap_perf_page(struct perf_event_mmap_page *pc)
316{
317 int ret;
318
319 if (!pc)
320 return;
321 ret = munmap(pc, sizeof(struct perf_event_mmap_page));
322 if (ret < 0) {
323 PERROR("Error in munmap");
324 abort();
325 }
326}
327
328static
329struct lttng_perf_counter_thread *alloc_perf_counter_thread(void)
330{
331 struct lttng_perf_counter_thread *perf_thread;
332 sigset_t newmask, oldmask;
333 int ret;
334
335 ret = sigfillset(&newmask);
336 if (ret)
337 abort();
338 ret = pthread_sigmask(SIG_BLOCK, &newmask, &oldmask);
339 if (ret)
340 abort();
341 /* Check again with signals disabled */
342 perf_thread = pthread_getspecific(perf_counter_key);
343 if (perf_thread)
344 goto skip;
345 perf_thread = zmalloc(sizeof(*perf_thread));
346 if (!perf_thread)
347 abort();
348 CDS_INIT_LIST_HEAD(&perf_thread->rcu_field_list);
349 ret = pthread_setspecific(perf_counter_key, perf_thread);
350 if (ret)
351 abort();
352skip:
353 ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
354 if (ret)
355 abort();
356 return perf_thread;
357}
358
359static
360struct lttng_perf_counter_thread_field *
361 add_thread_field(struct lttng_perf_counter_field *perf_field,
362 struct lttng_perf_counter_thread *perf_thread)
363{
364 struct lttng_perf_counter_thread_field *thread_field;
365 sigset_t newmask, oldmask;
366 int ret;
367
368 ret = sigfillset(&newmask);
369 if (ret)
370 abort();
371 ret = pthread_sigmask(SIG_BLOCK, &newmask, &oldmask);
372 if (ret)
373 abort();
374 /* Check again with signals disabled */
375 cds_list_for_each_entry_rcu(thread_field, &perf_thread->rcu_field_list,
376 rcu_field_node) {
377 if (thread_field->field == perf_field)
378 goto skip;
379 }
380 thread_field = zmalloc(sizeof(*thread_field));
381 if (!thread_field)
382 abort();
383 thread_field->field = perf_field;
b9389e6e
JD
384 thread_field->fd = open_perf_fd(&perf_field->attr);
385 if (thread_field->fd >= 0)
77d7fa98 386 setup_perf(thread_field);
b9389e6e
JD
387 /*
388 * Note: thread_field->pc can be NULL if setup_perf() fails.
389 * Also, thread_field->fd can be -1 if open_perf_fd() fails.
390 */
20142124 391 lttng_perf_lock();
d58d1454
MD
392 cds_list_add_rcu(&thread_field->rcu_field_node,
393 &perf_thread->rcu_field_list);
394 cds_list_add(&thread_field->thread_field_node,
395 &perf_field->thread_field_list);
20142124 396 lttng_perf_unlock();
d58d1454
MD
397skip:
398 ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
399 if (ret)
400 abort();
401 return thread_field;
402}
403
404static
405struct lttng_perf_counter_thread_field *
406 get_thread_field(struct lttng_perf_counter_field *field)
407{
408 struct lttng_perf_counter_thread *perf_thread;
409 struct lttng_perf_counter_thread_field *thread_field;
410
411 perf_thread = pthread_getspecific(perf_counter_key);
412 if (!perf_thread)
413 perf_thread = alloc_perf_counter_thread();
414 cds_list_for_each_entry_rcu(thread_field, &perf_thread->rcu_field_list,
415 rcu_field_node) {
416 if (thread_field->field == field)
417 return thread_field;
418 }
419 /* perf_counter_thread_field not found, need to add one */
420 return add_thread_field(field, perf_thread);
421}
422
423static
424uint64_t wrapper_perf_counter_read(struct lttng_ctx_field *field)
425{
426 struct lttng_perf_counter_field *perf_field;
427 struct lttng_perf_counter_thread_field *perf_thread_field;
428
429 perf_field = field->u.perf_counter;
430 perf_thread_field = get_thread_field(perf_field);
a3a8d943 431 return arch_read_perf_counter(perf_thread_field);
d58d1454
MD
432}
433
434static
435void perf_counter_record(struct lttng_ctx_field *field,
436 struct lttng_ust_lib_ring_buffer_ctx *ctx,
437 struct lttng_channel *chan)
438{
439 uint64_t value;
440
441 value = wrapper_perf_counter_read(field);
442 lib_ring_buffer_align_ctx(ctx, lttng_alignof(value));
443 chan->ops->event_write(ctx, &value, sizeof(value));
444}
445
446static
447void perf_counter_get_value(struct lttng_ctx_field *field,
53569322 448 struct lttng_ctx_value *value)
d58d1454 449{
6e9ac4ae 450 value->u.s64 = wrapper_perf_counter_read(field);
d58d1454
MD
451}
452
20142124 453/* Called with perf lock held */
d58d1454
MD
454static
455void lttng_destroy_perf_thread_field(
456 struct lttng_perf_counter_thread_field *thread_field)
457{
b9389e6e 458 close_perf_fd(thread_field->fd);
d58d1454
MD
459 unmap_perf_page(thread_field->pc);
460 cds_list_del_rcu(&thread_field->rcu_field_node);
461 cds_list_del(&thread_field->thread_field_node);
462 free(thread_field);
463}
464
465static
466void lttng_destroy_perf_thread_key(void *_key)
467{
468 struct lttng_perf_counter_thread *perf_thread = _key;
469 struct lttng_perf_counter_thread_field *pos, *p;
470
20142124 471 lttng_perf_lock();
d58d1454
MD
472 cds_list_for_each_entry_safe(pos, p, &perf_thread->rcu_field_list,
473 rcu_field_node)
474 lttng_destroy_perf_thread_field(pos);
20142124 475 lttng_perf_unlock();
d58d1454
MD
476 free(perf_thread);
477}
478
479/* Called with UST lock held */
480static
481void lttng_destroy_perf_counter_field(struct lttng_ctx_field *field)
482{
483 struct lttng_perf_counter_field *perf_field;
484 struct lttng_perf_counter_thread_field *pos, *p;
485
486 free((char *) field->event_field.name);
487 perf_field = field->u.perf_counter;
488 /*
489 * This put is performed when no threads can concurrently
490 * perform a "get" concurrently, thanks to urcu-bp grace
20142124
MD
491 * period. Holding the lttng perf lock protects against
492 * concurrent modification of the per-thread thread field
493 * list.
d58d1454 494 */
20142124 495 lttng_perf_lock();
d58d1454
MD
496 cds_list_for_each_entry_safe(pos, p, &perf_field->thread_field_list,
497 thread_field_node)
498 lttng_destroy_perf_thread_field(pos);
20142124 499 lttng_perf_unlock();
d58d1454
MD
500 free(perf_field);
501}
502
d286ad50
JD
503#ifdef __ARM_ARCH_7A__
504
505static
506int perf_get_exclude_kernel(void)
507{
508 return 0;
509}
510
511#else /* __ARM_ARCH_7A__ */
512
513static
514int perf_get_exclude_kernel(void)
515{
516 return 1;
517}
518
519#endif /* __ARM_ARCH_7A__ */
520
d58d1454
MD
521/* Called with UST lock held */
522int lttng_add_perf_counter_to_ctx(uint32_t type,
523 uint64_t config,
524 const char *name,
525 struct lttng_ctx **ctx)
526{
527 struct lttng_ctx_field *field;
528 struct lttng_perf_counter_field *perf_field;
d58d1454
MD
529 char *name_alloc;
530 int ret;
531
532 name_alloc = strdup(name);
533 if (!name_alloc) {
534 ret = -ENOMEM;
535 goto name_alloc_error;
536 }
537 perf_field = zmalloc(sizeof(*perf_field));
538 if (!perf_field) {
539 ret = -ENOMEM;
540 goto perf_field_alloc_error;
541 }
542 field = lttng_append_context(ctx);
543 if (!field) {
544 ret = -ENOMEM;
545 goto append_context_error;
546 }
547 if (lttng_find_context(*ctx, name_alloc)) {
548 ret = -EEXIST;
549 goto find_error;
550 }
551
552 field->destroy = lttng_destroy_perf_counter_field;
553
554 field->event_field.name = name_alloc;
555 field->event_field.type.atype = atype_integer;
556 field->event_field.type.u.basic.integer.size =
557 sizeof(uint64_t) * CHAR_BIT;
558 field->event_field.type.u.basic.integer.alignment =
559 lttng_alignof(uint64_t) * CHAR_BIT;
560 field->event_field.type.u.basic.integer.signedness =
561 lttng_is_signed_type(uint64_t);
562 field->event_field.type.u.basic.integer.reverse_byte_order = 0;
563 field->event_field.type.u.basic.integer.base = 10;
564 field->event_field.type.u.basic.integer.encoding = lttng_encode_none;
565 field->get_size = perf_counter_get_size;
566 field->record = perf_counter_record;
567 field->get_value = perf_counter_get_value;
568
569 perf_field->attr.type = type;
570 perf_field->attr.config = config;
d286ad50 571 perf_field->attr.exclude_kernel = perf_get_exclude_kernel();
d58d1454
MD
572 CDS_INIT_LIST_HEAD(&perf_field->thread_field_list);
573 field->u.perf_counter = perf_field;
574
575 /* Ensure that this perf counter can be used in this process. */
b9389e6e
JD
576 ret = open_perf_fd(&perf_field->attr);
577 if (ret < 0) {
d58d1454
MD
578 ret = -ENODEV;
579 goto setup_error;
580 }
b9389e6e 581 close_perf_fd(ret);
d58d1454
MD
582
583 /*
584 * Contexts can only be added before tracing is started, so we
585 * don't have to synchronize against concurrent threads using
586 * the field here.
587 */
588
b2cc986a 589 lttng_context_update(*ctx);
d58d1454
MD
590 return 0;
591
592setup_error:
593find_error:
594 lttng_remove_context_field(ctx, field);
595append_context_error:
596 free(perf_field);
597perf_field_alloc_error:
598 free(name_alloc);
599name_alloc_error:
600 return ret;
601}
602
603int lttng_perf_counter_init(void)
604{
605 int ret;
606
607 ret = pthread_key_create(&perf_counter_key,
608 lttng_destroy_perf_thread_key);
609 if (ret)
610 ret = -ret;
611 return ret;
612}
613
614void lttng_perf_counter_exit(void)
615{
616 int ret;
617
618 ret = pthread_key_delete(perf_counter_key);
619 if (ret) {
620 errno = ret;
621 PERROR("Error in pthread_key_delete");
622 }
623}
This page took 0.054764 seconds and 4 git commands to generate.