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