- supported.conf: Added sparse_keymap (eeepc_laptop depends on it)
[linux-flexiantxendom0-3.2.10.git] / perfmon / perfmon_dfl_smpl.c
1 /*
2  * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P.
3  *               Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *
5  * This file implements the new default sampling buffer format
6  * for the perfmon2 subsystem.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  */
22 #include <linux/kernel.h>
23 #include <linux/types.h>
24 #include <linux/module.h>
25 #include <linux/init.h>
26 #include <linux/smp.h>
27
28 #include <linux/perfmon_kern.h>
29 #include <linux/perfmon_dfl_smpl.h>
30
31 MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
32 MODULE_DESCRIPTION("new perfmon default sampling format");
33 MODULE_LICENSE("GPL");
34
35 static int pfm_dfl_fmt_validate(u32 ctx_flags, u16 npmds, void *data)
36 {
37         struct pfm_dfl_smpl_arg *arg = data;
38         u64 min_buf_size;
39
40         if (data == NULL) {
41                 PFM_DBG("no argument passed");
42                 return -EINVAL;
43         }
44
45         /*
46          * sanity check in case size_t is smaller then u64
47          */
48 #if BITS_PER_LONG == 4
49 #define MAX_SIZE_T      (1ULL<<(sizeof(size_t)<<3))
50         if (sizeof(size_t) < sizeof(arg->buf_size)) {
51                 if (arg->buf_size >= MAX_SIZE_T)
52                         return -ETOOBIG;
53         }
54 #endif
55
56         /*
57          * compute min buf size. npmds is the maximum number
58          * of implemented PMD registers.
59          */
60         min_buf_size = sizeof(struct pfm_dfl_smpl_hdr)
61                 + (sizeof(struct pfm_dfl_smpl_entry) + (npmds*sizeof(u64)));
62
63         PFM_DBG("validate ctx_flags=0x%x flags=0x%x npmds=%u "
64                 "min_buf_size=%llu buf_size=%llu\n",
65                 ctx_flags,
66                 arg->buf_flags,
67                 npmds,
68                 (unsigned long long)min_buf_size,
69                 (unsigned long long)arg->buf_size);
70
71         /*
72          * must hold at least the buffer header + one minimally sized entry
73          */
74         if (arg->buf_size < min_buf_size)
75                 return -EINVAL;
76
77         return 0;
78 }
79
80 static int pfm_dfl_fmt_get_size(u32 flags, void *data, size_t *size)
81 {
82         struct pfm_dfl_smpl_arg *arg = data;
83
84         /*
85          * size has been validated in default_validate
86          * we can never loose bits from buf_size.
87          */
88         *size = (size_t)arg->buf_size;
89
90         return 0;
91 }
92
93 static int pfm_dfl_fmt_init(struct pfm_context *ctx, void *buf, u32 ctx_flags,
94                             u16 npmds, void *data)
95 {
96         struct pfm_dfl_smpl_hdr *hdr;
97         struct pfm_dfl_smpl_arg *arg = data;
98
99         hdr = buf;
100
101         hdr->hdr_version = PFM_DFL_SMPL_VERSION;
102         hdr->hdr_buf_size = arg->buf_size;
103         hdr->hdr_buf_flags = arg->buf_flags;
104         hdr->hdr_cur_offs = sizeof(*hdr);
105         hdr->hdr_overflows = 0;
106         hdr->hdr_count = 0;
107         hdr->hdr_min_buf_space = sizeof(struct pfm_dfl_smpl_entry) + (npmds*sizeof(u64));
108         /*
109          * due to cache aliasing, it may be necessary to flush the cache
110          * on certain architectures (e.g., MIPS)
111          */
112         pfm_cacheflush(hdr, sizeof(*hdr));
113
114         PFM_DBG("buffer=%p buf_size=%llu hdr_size=%zu hdr_version=%u.%u "
115                   "min_space=%llu npmds=%u",
116                   buf,
117                   (unsigned long long)hdr->hdr_buf_size,
118                   sizeof(*hdr),
119                   PFM_VERSION_MAJOR(hdr->hdr_version),
120                   PFM_VERSION_MINOR(hdr->hdr_version),
121                   (unsigned long long)hdr->hdr_min_buf_space,
122                   npmds);
123
124         return 0;
125 }
126
127 /*
128  * called from pfm_overflow_handler() to record a new sample
129  *
130  * context is locked, interrupts are disabled (no preemption)
131  */
132 static int pfm_dfl_fmt_handler(struct pfm_context *ctx,
133                                unsigned long ip, u64 tstamp, void *data)
134 {
135         struct pfm_dfl_smpl_hdr *hdr;
136         struct pfm_dfl_smpl_entry *ent;
137         struct pfm_ovfl_arg *arg;
138         void *cur, *last;
139         u64 *e;
140         size_t entry_size, min_size;
141         u16 npmds, i;
142         u16 ovfl_pmd;
143         void *buf;
144
145         hdr = ctx->smpl_addr;
146         arg = &ctx->ovfl_arg;
147
148         buf = hdr;
149         cur = buf+hdr->hdr_cur_offs;
150         last = buf+hdr->hdr_buf_size;
151         ovfl_pmd = arg->ovfl_pmd;
152         min_size = hdr->hdr_min_buf_space;
153
154         /*
155          * precheck for sanity
156          */
157         if ((last - cur) < min_size)
158                 goto full;
159
160         npmds = arg->num_smpl_pmds;
161
162         ent = (struct pfm_dfl_smpl_entry *)cur;
163
164         entry_size = sizeof(*ent) + (npmds << 3);
165
166         /* position for first pmd */
167         e = (u64 *)(ent+1);
168
169         hdr->hdr_count++;
170
171         PFM_DBG_ovfl("count=%llu cur=%p last=%p free_bytes=%zu ovfl_pmd=%d "
172                      "npmds=%u",
173                      (unsigned long long)hdr->hdr_count,
174                      cur, last,
175                      (last-cur),
176                      ovfl_pmd,
177                      npmds);
178
179         /*
180          * current = task running at the time of the overflow.
181          *
182          * per-task mode:
183          *      - this is usually the task being monitored.
184          *        Under certain conditions, it might be a different task
185          *
186          * system-wide:
187          *      - this is not necessarily the task controlling the session
188          */
189         ent->pid = current->pid;
190         ent->ovfl_pmd = ovfl_pmd;
191         ent->last_reset_val = arg->pmd_last_reset;
192
193         /*
194          * where did the fault happen (includes slot number)
195          */
196         ent->ip = ip;
197
198         ent->tstamp = tstamp;
199         ent->cpu = smp_processor_id();
200         ent->set = arg->active_set;
201         ent->tgid = current->tgid;
202
203         /*
204          * selectively store PMDs in increasing index number
205          */
206         if (npmds) {
207                 u64 *val = arg->smpl_pmds_values;
208                 for (i = 0; i < npmds; i++)
209                         *e++ = *val++;
210         }
211
212         /*
213          * update position for next entry
214          */
215         hdr->hdr_cur_offs += entry_size;
216         cur += entry_size;
217
218         pfm_cacheflush(hdr, sizeof(*hdr));
219         pfm_cacheflush(ent, entry_size);
220
221         /*
222          * post check to avoid losing the last sample
223          */
224         if ((last - cur) < min_size)
225                 goto full;
226
227         /* reset before returning from interrupt handler */
228         arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET;
229
230         return 0;
231 full:
232         PFM_DBG_ovfl("sampling buffer full free=%zu, count=%llu",
233                      last-cur,
234                      (unsigned long long)hdr->hdr_count);
235
236         /*
237          * increment number of buffer overflows.
238          * important to detect duplicate set of samples.
239          */
240         hdr->hdr_overflows++;
241
242         /*
243          * request notification and masking of monitoring.
244          * Notification is still subject to the overflowed
245          * register having the FL_NOTIFY flag set.
246          */
247         arg->ovfl_ctrl = PFM_OVFL_CTRL_NOTIFY | PFM_OVFL_CTRL_MASK;
248
249         return -ENOBUFS; /* we are full, sorry */
250 }
251
252 static int pfm_dfl_fmt_restart(struct pfm_context *ctx, u32 *ovfl_ctrl)
253 {
254         struct pfm_dfl_smpl_hdr *hdr;
255
256         hdr = ctx->smpl_addr;
257
258         hdr->hdr_count = 0;
259         hdr->hdr_cur_offs = sizeof(*hdr);
260
261         pfm_cacheflush(hdr, sizeof(*hdr));
262
263         *ovfl_ctrl = PFM_OVFL_CTRL_RESET;
264
265         return 0;
266 }
267
268 static int pfm_dfl_fmt_exit(void *buf)
269 {
270         return 0;
271 }
272
273 static struct pfm_smpl_fmt dfl_fmt = {
274         .fmt_name = "default",
275         .fmt_version = 0x10000,
276         .fmt_arg_size = sizeof(struct pfm_dfl_smpl_arg),
277         .fmt_validate = pfm_dfl_fmt_validate,
278         .fmt_getsize = pfm_dfl_fmt_get_size,
279         .fmt_init = pfm_dfl_fmt_init,
280         .fmt_handler = pfm_dfl_fmt_handler,
281         .fmt_restart = pfm_dfl_fmt_restart,
282         .fmt_exit = pfm_dfl_fmt_exit,
283         .fmt_flags = PFM_FMT_BUILTIN_FLAG,
284         .owner = THIS_MODULE
285 };
286
287 static int pfm_dfl_fmt_init_module(void)
288 {
289         return pfm_fmt_register(&dfl_fmt);
290 }
291
292 static void pfm_dfl_fmt_cleanup_module(void)
293 {
294         pfm_fmt_unregister(&dfl_fmt);
295 }
296
297 module_init(pfm_dfl_fmt_init_module);
298 module_exit(pfm_dfl_fmt_cleanup_module);