linux/arch/ia64/kernel/perfmon_default_smpl.c
<<
>>
Prefs
   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 ususally 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