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