Add bug detection support for alignment header
[lttng-modules.git] / lttng-context-perf-counters.c
CommitLineData
833ad6a0
MD
1/*
2 * (C) Copyright 2009-2011 -
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * LTTng performance monitoring counters (perf-counters) integration module.
6 *
7 * Dual LGPL v2.1/GPL v2 license.
8 */
9
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/perf_event.h>
13#include <linux/list.h>
c24a0d71
MD
14#include <linux/string.h>
15#include "ltt-events.h"
16#include "wrapper/ringbuffer/frontend_types.h"
17#include "wrapper/vmalloc.h"
18#include "ltt-tracer.h"
833ad6a0
MD
19
20/*
21 * TODO: Add CPU hotplug support.
22 */
23
24static DEFINE_MUTEX(perf_counter_mutex);
25static LIST_HEAD(perf_counter_contexts);
26
f1676205
MD
27static
28size_t perf_counter_get_size(size_t offset)
29{
30 size_t size = 0;
31
32 size += lib_ring_buffer_align(offset, ltt_alignof(uint64_t));
33 size += sizeof(uint64_t);
34 return size;
35}
36
833ad6a0
MD
37static
38void perf_counter_record(struct lttng_ctx_field *field,
39 struct lib_ring_buffer_ctx *ctx,
40 struct ltt_channel *chan)
41{
42 struct perf_event *event;
43 uint64_t value;
44
45 event = field->u.perf_counter.e[ctx->cpu];
46 event->pmu->read(event);
47 value = local64_read(&event->count);
9e7e4892 48 lib_ring_buffer_align_ctx(ctx, ltt_alignof(value));
833ad6a0
MD
49 chan->ops->event_write(ctx, &value, sizeof(value));
50}
51
52static
53void overflow_callback(struct perf_event *event, int nmi,
54 struct perf_sample_data *data,
55 struct pt_regs *regs)
56{
57}
58
2dccf128
MD
59static
60void lttng_destroy_perf_counter_field(struct lttng_ctx_field *field)
61{
62 struct perf_event **events = field->u.perf_counter.e;
63 int cpu;
64
65 mutex_lock(&perf_counter_mutex);
66 list_del(&field->u.perf_counter.head);
67 for_each_online_cpu(cpu)
68 perf_event_release_kernel(events[cpu]);
69 mutex_unlock(&perf_counter_mutex);
c24a0d71 70 kfree(field->event_field.name);
2dccf128
MD
71 kfree(field->u.perf_counter.attr);
72 kfree(events);
73}
74
833ad6a0
MD
75int lttng_add_perf_counter_to_ctx(uint32_t type,
76 uint64_t config,
c24a0d71 77 const char *name,
2dccf128 78 struct lttng_ctx **ctx)
833ad6a0
MD
79{
80 struct lttng_ctx_field *field;
81 struct perf_event **events;
82 struct perf_event_attr *attr;
83 int ret;
84 int cpu;
c24a0d71 85 char *name_alloc;
833ad6a0
MD
86
87 events = kzalloc(num_possible_cpus() * sizeof(*events), GFP_KERNEL);
88 if (!events)
89 return -ENOMEM;
90
91 attr = kzalloc(sizeof(*field->u.perf_counter.attr), GFP_KERNEL);
92 if (!attr) {
93 ret = -ENOMEM;
94 goto error_attr;
95 }
96
97 attr->type = type;
98 attr->config = config;
99 attr->size = sizeof(struct perf_event_attr);
100 attr->pinned = 1;
101 attr->disabled = 0;
102
103 mutex_lock(&perf_counter_mutex);
104
105 for_each_online_cpu(cpu) {
106 events[cpu] = perf_event_create_kernel_counter(attr,
107 cpu, NULL, overflow_callback);
108 if (!events[cpu]) {
109 ret = -EINVAL;
bef96e48 110 goto name_alloc_error;
833ad6a0
MD
111 }
112 }
113
c24a0d71 114 name_alloc = kstrdup(name, GFP_KERNEL);
bef96e48
MD
115 if (!name_alloc) {
116 ret = -ENOMEM;
c24a0d71 117 goto name_alloc_error;
bef96e48 118 }
c24a0d71 119
2dccf128
MD
120 field = lttng_append_context(ctx);
121 if (!field) {
122 ret = -ENOMEM;
123 goto error;
833ad6a0 124 }
2dccf128 125 field->destroy = lttng_destroy_perf_counter_field;
833ad6a0 126
c24a0d71 127 field->event_field.name = name_alloc;
8070f5c0
MD
128 field->event_field.type.atype = atype_integer;
129 field->event_field.type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT;
130 field->event_field.type.u.basic.integer.alignment = ltt_alignof(unsigned long) * CHAR_BIT;
131 field->event_field.type.u.basic.integer.signedness = is_signed_type(unsigned long);
132 field->event_field.type.u.basic.integer.reverse_byte_order = 0;
133 field->event_field.type.u.basic.integer.base = 10;
134 field->event_field.type.u.basic.integer.encoding = lttng_encode_none;
f1676205
MD
135 field->get_size = perf_counter_get_size;
136 field->record = perf_counter_record;
833ad6a0
MD
137 field->u.perf_counter.e = events;
138 field->u.perf_counter.attr = attr;
139
140 list_add(&field->u.perf_counter.head, &perf_counter_contexts);
141 mutex_unlock(&perf_counter_mutex);
142
143 wrapper_vmalloc_sync_all();
144 return 0;
145
146error:
c24a0d71
MD
147 kfree(name_alloc);
148name_alloc_error:
833ad6a0
MD
149 for_each_online_cpu(cpu) {
150 if (events[cpu])
151 perf_event_release_kernel(events[cpu]);
152 }
153 mutex_unlock(&perf_counter_mutex);
154 kfree(attr);
155error_attr:
156 kfree(events);
157 return ret;
158}
159
833ad6a0
MD
160MODULE_LICENSE("GPL and additional rights");
161MODULE_AUTHOR("Mathieu Desnoyers");
162MODULE_DESCRIPTION("Linux Trace Toolkit Perf Support");
This page took 0.031934 seconds and 4 git commands to generate.