Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2002-2003 Hewlett-Packard Co
  4 *               Stephane Eranian <eranian@hpl.hp.com>
  5 *
  6 * This file implements the default sampling buffer format
  7 * for the Linux/ia64 perfmon-2 subsystem.
  8 */
  9#include <linux/kernel.h>
 10#include <linux/types.h>
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <asm/delay.h>
 14#include <linux/smp.h>
 15
 16#include <asm/perfmon.h>
 17#include <asm/perfmon_default_smpl.h>
 18
 19MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
 20MODULE_DESCRIPTION("perfmon default sampling format");
 21MODULE_LICENSE("GPL");
 22
 23#define DEFAULT_DEBUG 1
 24
 25#ifdef DEFAULT_DEBUG
 26#define DPRINT(a) \
 27	do { \
 28		if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
 29	} while (0)
 30
 31#define DPRINT_ovfl(a) \
 32	do { \
 33		if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
 34	} while (0)
 35
 36#else
 37#define DPRINT(a)
 38#define DPRINT_ovfl(a)
 39#endif
 40
 41static int
 42default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data)
 43{
 44	pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data;
 45	int ret = 0;
 46
 47	if (data == NULL) {
 48		DPRINT(("[%d] no argument passed\n", task_pid_nr(task)));
 49		return -EINVAL;
 50	}
 51
 52	DPRINT(("[%d] validate flags=0x%x CPU%d\n", task_pid_nr(task), flags, cpu));
 53
 54	/*
 55	 * must hold at least the buffer header + one minimally sized entry
 56	 */
 57	if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL;
 58
 59	DPRINT(("buf_size=%lu\n", arg->buf_size));
 60
 61	return ret;
 62}
 63
 64static int
 65default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size)
 66{
 67	pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
 68
 69	/*
 70	 * size has been validated in default_validate
 71	 */
 72	*size = arg->buf_size;
 73
 74	return 0;
 75}
 76
 77static int
 78default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data)
 79{
 80	pfm_default_smpl_hdr_t *hdr;
 81	pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
 82
 83	hdr = (pfm_default_smpl_hdr_t *)buf;
 84
 85	hdr->hdr_version      = PFM_DEFAULT_SMPL_VERSION;
 86	hdr->hdr_buf_size     = arg->buf_size;
 87	hdr->hdr_cur_offs     = sizeof(*hdr);
 88	hdr->hdr_overflows    = 0UL;
 89	hdr->hdr_count        = 0UL;
 90
 91	DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u cur_offs=%lu\n",
 92		task_pid_nr(task),
 93		buf,
 94		hdr->hdr_buf_size,
 95		sizeof(*hdr),
 96		hdr->hdr_version,
 97		hdr->hdr_cur_offs));
 98
 99	return 0;
100}
101
102static int
103default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp)
104{
105	pfm_default_smpl_hdr_t *hdr;
106	pfm_default_smpl_entry_t *ent;
107	void *cur, *last;
108	unsigned long *e, entry_size;
109	unsigned int npmds, i;
110	unsigned char ovfl_pmd;
111	unsigned char ovfl_notify;
112
113	if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) {
114		DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg));
115		return -EINVAL;
116	}
117
118	hdr         = (pfm_default_smpl_hdr_t *)buf;
119	cur         = buf+hdr->hdr_cur_offs;
120	last        = buf+hdr->hdr_buf_size;
121	ovfl_pmd    = arg->ovfl_pmd;
122	ovfl_notify = arg->ovfl_notify;
123
124	/*
125	 * precheck for sanity
126	 */
127	if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
128
129	npmds = hweight64(arg->smpl_pmds[0]);
130
131	ent = (pfm_default_smpl_entry_t *)cur;
132
133	prefetch(arg->smpl_pmds_values);
134
135	entry_size = sizeof(*ent) + (npmds << 3);
136
137	/* position for first pmd */
138	e = (unsigned long *)(ent+1);
139
140	hdr->hdr_count++;
141
142	DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n",
143			task->pid,
144			hdr->hdr_count,
145			cur, last,
146			last-cur,
147			ovfl_pmd,
148			ovfl_notify, npmds));
149
150	/*
151	 * current = task running at the time of the overflow.
152	 *
153	 * per-task mode:
154	 * 	- this is usually the task being monitored.
155	 * 	  Under certain conditions, it might be a different task
156	 *
157	 * system-wide:
158	 * 	- this is not necessarily the task controlling the session
159	 */
160	ent->pid            = current->pid;
161	ent->ovfl_pmd  	    = ovfl_pmd;
162	ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val;
163
164	/*
165	 * where did the fault happen (includes slot number)
166	 */
167	ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3);
168
169	ent->tstamp    = stamp;
170	ent->cpu       = smp_processor_id();
171	ent->set       = arg->active_set;
172	ent->tgid      = current->tgid;
173
174	/*
175	 * selectively store PMDs in increasing index number
176	 */
177	if (npmds) {
178		unsigned long *val = arg->smpl_pmds_values;
179		for(i=0; i < npmds; i++) {
180			*e++ = *val++;
181		}
182	}
183
184	/*
185	 * update position for next entry
186	 */
187	hdr->hdr_cur_offs += entry_size;
188	cur               += entry_size;
189
190	/*
191	 * post check to avoid losing the last sample
192	 */
193	if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
194
195	/*
196	 * keep same ovfl_pmds, ovfl_notify
197	 */
198	arg->ovfl_ctrl.bits.notify_user     = 0;
199	arg->ovfl_ctrl.bits.block_task      = 0;
200	arg->ovfl_ctrl.bits.mask_monitoring = 0;
201	arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */
202
203	return 0;
204full:
205	DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify));
206
207	/*
208	 * increment number of buffer overflow.
209	 * important to detect duplicate set of samples.
210	 */
211	hdr->hdr_overflows++;
212
213	/*
214	 * if no notification requested, then we saturate the buffer
215	 */
216	if (ovfl_notify == 0) {
217		arg->ovfl_ctrl.bits.notify_user     = 0;
218		arg->ovfl_ctrl.bits.block_task      = 0;
219		arg->ovfl_ctrl.bits.mask_monitoring = 1;
220		arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0;
221	} else {
222		arg->ovfl_ctrl.bits.notify_user     = 1;
223		arg->ovfl_ctrl.bits.block_task      = 1; /* ignored for non-blocking context */
224		arg->ovfl_ctrl.bits.mask_monitoring = 1;
225		arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */
226	}
227	return -1; /* we are full, sorry */
228}
229
230static int
231default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs)
232{
233	pfm_default_smpl_hdr_t *hdr;
234
235	hdr = (pfm_default_smpl_hdr_t *)buf;
236
237	hdr->hdr_count    = 0UL;
238	hdr->hdr_cur_offs = sizeof(*hdr);
239
240	ctrl->bits.mask_monitoring = 0;
241	ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */
242
243	return 0;
244}
245
246static int
247default_exit(struct task_struct *task, void *buf, struct pt_regs *regs)
248{
249	DPRINT(("[%d] exit(%p)\n", task_pid_nr(task), buf));
250	return 0;
251}
252
253static pfm_buffer_fmt_t default_fmt={
254 	.fmt_name 	    = "default_format",
255 	.fmt_uuid	    = PFM_DEFAULT_SMPL_UUID,
256 	.fmt_arg_size	    = sizeof(pfm_default_smpl_arg_t),
257 	.fmt_validate	    = default_validate,
258 	.fmt_getsize	    = default_get_size,
259 	.fmt_init	    = default_init,
260 	.fmt_handler	    = default_handler,
261 	.fmt_restart	    = default_restart,
262 	.fmt_restart_active = default_restart,
263 	.fmt_exit	    = default_exit,
264};
265
266static int __init
267pfm_default_smpl_init_module(void)
268{
269	int ret;
270
271	ret = pfm_register_buffer_fmt(&default_fmt);
272	if (ret == 0) {
273		printk("perfmon_default_smpl: %s v%u.%u registered\n",
274			default_fmt.fmt_name,
275			PFM_DEFAULT_SMPL_VERSION_MAJ,
276			PFM_DEFAULT_SMPL_VERSION_MIN);
277	} else {
278		printk("perfmon_default_smpl: %s cannot register ret=%d\n",
279			default_fmt.fmt_name,
280			ret);
281	}
282
283	return ret;
284}
285
286static void __exit
287pfm_default_smpl_cleanup_module(void)
288{
289	int ret;
290	ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid);
291
292	printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret);
293}
294
295module_init(pfm_default_smpl_init_module);
296module_exit(pfm_default_smpl_cleanup_module);
297