Fix perf counter test bug
[lttng-modules.git] / lttng-context-perf-counters.c
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>
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"
19
20 /*
21 * TODO: Add CPU hotplug support.
22 */
23
24 static DEFINE_MUTEX(perf_counter_mutex);
25 static LIST_HEAD(perf_counter_contexts);
26
27 static
28 size_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
37 static
38 void 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);
48 lib_ring_buffer_align_ctx(ctx, ltt_alignof(value));
49 chan->ops->event_write(ctx, &value, sizeof(value));
50 }
51
52 static
53 void overflow_callback(struct perf_event *event, int nmi,
54 struct perf_sample_data *data,
55 struct pt_regs *regs)
56 {
57 }
58
59 static
60 void 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);
70 kfree(field->event_field.name);
71 kfree(field->u.perf_counter.attr);
72 kfree(events);
73 }
74
75 int lttng_add_perf_counter_to_ctx(uint32_t type,
76 uint64_t config,
77 const char *name,
78 struct lttng_ctx **ctx)
79 {
80 struct lttng_ctx_field *field;
81 struct perf_event **events;
82 struct perf_event_attr *attr;
83 int ret;
84 int cpu;
85 char *name_alloc;
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;
110 goto error;
111 }
112 }
113
114 name_alloc = kstrdup(name, GFP_KERNEL);
115 if (!name_alloc)
116 goto name_alloc_error;
117
118 field = lttng_append_context(ctx);
119 if (!field) {
120 ret = -ENOMEM;
121 goto error;
122 }
123 field->destroy = lttng_destroy_perf_counter_field;
124
125 field->event_field.name = name_alloc;
126 field->event_field.type.atype = atype_integer;
127 field->event_field.type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT;
128 field->event_field.type.u.basic.integer.alignment = ltt_alignof(unsigned long) * CHAR_BIT;
129 field->event_field.type.u.basic.integer.signedness = is_signed_type(unsigned long);
130 field->event_field.type.u.basic.integer.reverse_byte_order = 0;
131 field->event_field.type.u.basic.integer.base = 10;
132 field->event_field.type.u.basic.integer.encoding = lttng_encode_none;
133 field->get_size = perf_counter_get_size;
134 field->record = perf_counter_record;
135 field->u.perf_counter.e = events;
136 field->u.perf_counter.attr = attr;
137
138 list_add(&field->u.perf_counter.head, &perf_counter_contexts);
139 mutex_unlock(&perf_counter_mutex);
140
141 wrapper_vmalloc_sync_all();
142 return 0;
143
144 error:
145 kfree(name_alloc);
146 name_alloc_error:
147 for_each_online_cpu(cpu) {
148 if (events[cpu])
149 perf_event_release_kernel(events[cpu]);
150 }
151 mutex_unlock(&perf_counter_mutex);
152 kfree(attr);
153 error_attr:
154 kfree(events);
155 return ret;
156 }
157
158 MODULE_LICENSE("GPL and additional rights");
159 MODULE_AUTHOR("Mathieu Desnoyers");
160 MODULE_DESCRIPTION("Linux Trace Toolkit Perf Support");
This page took 0.033042 seconds and 5 git commands to generate.