Commit 050716fa authored by David Mosberger's avatar David Mosberger

ia64: perfmon update.

Here is a ChangeLog for the patch:

        - The perfmon core will invoke the sampling module handler
          routine once for each overflowed PMD. When multiple PMDs
          overflow at the same time (with the same PMU interrupt),
          then up to 64 distinct calls can happen. A common timestamp
          parameter allows the module to identify this kind of
          entries.

        - Changed the module ovfl_ctrl arguments to simplify the reset
          field. Now it is a simple boolean.

        - Updated perfmon.h to convert the "set" field to ushort from
          uint.  Other structure updates to get better layout.

        - Update perfmon_default_smpl.h to reflect the change in
          overflow processing mentioned above.

        - Cleanup some state checking code to use switch-case instead
          of if-then with macros. Make the code more readable and
          easier to optmize for gcc. Thanks to David for the
          suggestion.

        - Added extra safety checks on pfm_context_load() to verify
          that the task actually exists.

        - The default sampling format module now supports the
          fmt_restart_active callbacks. Patch from David.
parent 11d03417
This diff is collapsed.
...@@ -109,21 +109,15 @@ default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, v ...@@ -109,21 +109,15 @@ default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, v
} }
static int static int
default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs) default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp)
{ {
pfm_default_smpl_hdr_t *hdr; pfm_default_smpl_hdr_t *hdr;
pfm_default_smpl_entry_t *ent; pfm_default_smpl_entry_t *ent;
void *cur, *last; void *cur, *last;
unsigned long *e; unsigned long *e;
unsigned long ovfl_mask;
unsigned long ovfl_notify;
unsigned long stamp;
unsigned int npmds, i; unsigned int npmds, i;
unsigned char ovfl_pmd;
/* unsigned char ovfl_notify;
* some time stamp
*/
stamp = ia64_get_itc();
if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) { if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) {
DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg)); DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg));
...@@ -133,8 +127,8 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ...@@ -133,8 +127,8 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct
hdr = (pfm_default_smpl_hdr_t *)buf; hdr = (pfm_default_smpl_hdr_t *)buf;
cur = hdr->hdr_cur_pos; cur = hdr->hdr_cur_pos;
last = hdr->hdr_last_pos; last = hdr->hdr_last_pos;
ovfl_mask = arg->ovfl_pmds[0]; ovfl_pmd = arg->ovfl_pmd;
ovfl_notify = arg->ovfl_notify[0]; ovfl_notify = arg->ovfl_notify;
/* /*
* check for space against largest possibly entry. * check for space against largest possibly entry.
...@@ -153,12 +147,12 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ...@@ -153,12 +147,12 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct
hdr->hdr_count++; hdr->hdr_count++;
DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmds=0x%lx ovfl_notify=0x%lx npmds=%u\n", DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n",
task->pid, task->pid,
hdr->hdr_count, hdr->hdr_count,
cur, last, cur, last,
last-cur, last-cur,
ovfl_mask, ovfl_pmd,
ovfl_notify, npmds)); ovfl_notify, npmds));
/* /*
...@@ -172,7 +166,7 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ...@@ -172,7 +166,7 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct
* - this is not necessarily the task controlling the session * - this is not necessarily the task controlling the session
*/ */
ent->pid = current->pid; ent->pid = current->pid;
ent->cpu = smp_processor_id(); ent->ovfl_pmd = ovfl_pmd;
ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val; ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val;
/* /*
...@@ -180,13 +174,9 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ...@@ -180,13 +174,9 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct
*/ */
ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3); ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3);
/*
* which registers overflowed
*/
ent->ovfl_pmds = ovfl_mask;
ent->tstamp = stamp; ent->tstamp = stamp;
ent->cpu = smp_processor_id();
ent->set = arg->active_set; ent->set = arg->active_set;
ent->reserved1 = 0;
/* /*
* selectively store PMDs in increasing index number * selectively store PMDs in increasing index number
...@@ -206,14 +196,14 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ...@@ -206,14 +196,14 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct
/* /*
* keep same ovfl_pmds, ovfl_notify * keep same ovfl_pmds, ovfl_notify
*/ */
arg->ovfl_ctrl.notify_user = 0; arg->ovfl_ctrl.bits.notify_user = 0;
arg->ovfl_ctrl.block = 0; arg->ovfl_ctrl.bits.block_task = 0;
arg->ovfl_ctrl.stop_monitoring = 0; arg->ovfl_ctrl.bits.mask_monitoring = 0;
arg->ovfl_ctrl.reset_pmds = 1; arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */
return 0; return 0;
full: full:
DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=0x%lx\n", last-cur, hdr->hdr_count, ovfl_notify)); DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify));
/* /*
* increment number of buffer overflow. * increment number of buffer overflow.
...@@ -222,22 +212,21 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ...@@ -222,22 +212,21 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct
hdr->hdr_overflows++; hdr->hdr_overflows++;
/* /*
* if no notification is needed, then we just reset the buffer index. * if no notification is needed, then we saturate the buffer
*/ */
if (ovfl_notify == 0UL) { if (ovfl_notify == 0) {
hdr->hdr_count = 0UL; hdr->hdr_count = 0UL;
arg->ovfl_ctrl.notify_user = 0; arg->ovfl_ctrl.bits.notify_user = 0;
arg->ovfl_ctrl.block = 0; arg->ovfl_ctrl.bits.block_task = 0;
arg->ovfl_ctrl.stop_monitoring = 0; arg->ovfl_ctrl.bits.mask_monitoring = 1;
arg->ovfl_ctrl.reset_pmds = 1; arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0;
} else { } else {
/* keep same ovfl_pmds, ovfl_notify */ arg->ovfl_ctrl.bits.notify_user = 1;
arg->ovfl_ctrl.notify_user = 1; arg->ovfl_ctrl.bits.block_task = 1; /* ignored for non-blocking context */
arg->ovfl_ctrl.block = 1; arg->ovfl_ctrl.bits.mask_monitoring = 1;
arg->ovfl_ctrl.stop_monitoring = 1; arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */
arg->ovfl_ctrl.reset_pmds = 0;
} }
return 0; return -1; /* we are full, sorry */
} }
static int static int
...@@ -250,8 +239,8 @@ default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, stru ...@@ -250,8 +239,8 @@ default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, stru
hdr->hdr_count = 0UL; hdr->hdr_count = 0UL;
hdr->hdr_cur_pos = (void *)((unsigned long)buf)+sizeof(*hdr); hdr->hdr_cur_pos = (void *)((unsigned long)buf)+sizeof(*hdr);
ctrl->stop_monitoring = 0; ctrl->bits.mask_monitoring = 0;
ctrl->reset_pmds = PFM_PMD_LONG_RESET; ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */
return 0; return 0;
} }
...@@ -264,15 +253,16 @@ default_exit(struct task_struct *task, void *buf, struct pt_regs *regs) ...@@ -264,15 +253,16 @@ default_exit(struct task_struct *task, void *buf, struct pt_regs *regs)
} }
static pfm_buffer_fmt_t default_fmt={ static pfm_buffer_fmt_t default_fmt={
.fmt_name = "default_format", .fmt_name = "default_format",
.fmt_uuid = PFM_DEFAULT_SMPL_UUID, .fmt_uuid = PFM_DEFAULT_SMPL_UUID,
.fmt_arg_size = sizeof(pfm_default_smpl_arg_t), .fmt_arg_size = sizeof(pfm_default_smpl_arg_t),
.fmt_validate = default_validate, .fmt_validate = default_validate,
.fmt_getsize = default_get_size, .fmt_getsize = default_get_size,
.fmt_init = default_init, .fmt_init = default_init,
.fmt_handler = default_handler, .fmt_handler = default_handler,
.fmt_restart = default_restart, .fmt_restart = default_restart,
.fmt_exit = default_exit, .fmt_restart_active = default_restart,
.fmt_exit = default_exit,
}; };
static int __init static int __init
......
...@@ -70,64 +70,70 @@ typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type ...@@ -70,64 +70,70 @@ typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type
* Request structure used to define a context * Request structure used to define a context
*/ */
typedef struct { typedef struct {
pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */
unsigned long ctx_flags; /* noblock/block */ unsigned long ctx_flags; /* noblock/block */
unsigned int ctx_nextra_sets; /* number of extra event sets (you always get 1) */ unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */
int ctx_fd; /* return arg: unique identification for context */ unsigned short ctx_reserved1; /* for future use */
void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ int ctx_fd; /* return arg: unique identification for context */
unsigned long ctx_reserved[11]; /* for future use */ void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */
unsigned long ctx_reserved2[11];/* for future use */
} pfarg_context_t; } pfarg_context_t;
/* /*
* Request structure used to write/read a PMC or PMD * Request structure used to write/read a PMC or PMD
*/ */
typedef struct { typedef struct {
unsigned int reg_num; /* which register */ unsigned int reg_num; /* which register */
unsigned int reg_set; /* event set for this register */ unsigned short reg_set; /* event set for this register */
unsigned short reg_reserved1; /* for future use */
unsigned long reg_value; /* initial pmc/pmd value */ unsigned long reg_value; /* initial pmc/pmd value */
unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */
unsigned long reg_long_reset; /* reset after buffer overflow notification */ unsigned long reg_long_reset; /* reset after buffer overflow notification */
unsigned long reg_short_reset; /* reset after counter overflow */ unsigned long reg_short_reset; /* reset after counter overflow */
unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */
unsigned long reg_random_seed; /* seed value when randomization is used */ unsigned long reg_random_seed; /* seed value when randomization is used */
unsigned long reg_random_mask; /* bitmask used to limit random value */ unsigned long reg_random_mask; /* bitmask used to limit random value */
unsigned long reg_last_reset_val;/* return: PMD last reset value */ unsigned long reg_last_reset_val;/* return: PMD last reset value */
unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */
unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ unsigned long reg_smpl_eventid; /* opaque sampling event identifier */
unsigned long reserved[3]; /* for future use */ unsigned long reg_reserved2[3]; /* for future use */
} pfarg_reg_t; } pfarg_reg_t;
typedef struct { typedef struct {
unsigned int dbreg_num; /* which debug register */ unsigned int dbreg_num; /* which debug register */
unsigned int dbreg_set; /* event set for this register */ unsigned short dbreg_set; /* event set for this register */
unsigned long dbreg_value; /* value for debug register */ unsigned short dbreg_reserved1; /* for future use */
unsigned long dbreg_flags; /* return: dbreg error */ unsigned long dbreg_value; /* value for debug register */
unsigned long dbreg_reserved[1]; /* for future use */ unsigned long dbreg_flags; /* return: dbreg error */
unsigned long dbreg_reserved2[1]; /* for future use */
} pfarg_dbreg_t; } pfarg_dbreg_t;
typedef struct { typedef struct {
unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */
unsigned int ft_reserved; /* reserved for future use */ unsigned int ft_reserved; /* reserved for future use */
unsigned long reserved[4]; /* for future use */ unsigned long reserved[4]; /* for future use */
} pfarg_features_t; } pfarg_features_t;
typedef struct { typedef struct {
pid_t load_pid; /* process to load the context into */ pid_t load_pid; /* process to load the context into */
unsigned int load_set; /* first event set to load */ unsigned short load_set; /* first event set to load */
unsigned long load_reserved[2]; /* for future use */ unsigned short load_reserved1; /* for future use */
unsigned long load_reserved2[3]; /* for future use */
} pfarg_load_t; } pfarg_load_t;
typedef struct { typedef struct {
int msg_type; /* generic message header */ int msg_type; /* generic message header */
int msg_ctx_fd; /* generic message header */ int msg_ctx_fd; /* generic message header */
unsigned long msg_tstamp; /* for perf tuning */
unsigned int msg_active_set; /* active set at the time of overflow */
unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */
unsigned short msg_active_set; /* active set at the time of overflow */
unsigned short msg_reserved1; /* for future use */
unsigned int msg_reserved2; /* for future use */
unsigned long msg_tstamp; /* for perf tuning/debug */
} pfm_ovfl_msg_t; } pfm_ovfl_msg_t;
typedef struct { typedef struct {
...@@ -192,25 +198,28 @@ extern void pfm_handle_work(void); ...@@ -192,25 +198,28 @@ extern void pfm_handle_work(void);
#define PFM_PMD_LONG_RESET 1 #define PFM_PMD_LONG_RESET 1
#define PFM_PMD_SHORT_RESET 2 #define PFM_PMD_SHORT_RESET 2
typedef struct { typedef union {
unsigned int notify_user:1; /* notify user program of overflow */ unsigned int val;
unsigned int reset_pmds :2; /* PFM_PMD_NO_RESET, PFM_PMD_LONG_RESET, PFM_PMD_SHORT_RESET */ struct {
unsigned int block:1; /* block monitored task on kernel exit */ unsigned int notify_user:1; /* notify user program of overflow */
unsigned int stop_monitoring:1; /* will mask monitoring via PMCx.plm */ unsigned int reset_ovfl_pmds:1; /* reset overflowed PMDs */
unsigned int reserved:26; /* for future use */ unsigned int block_task:1; /* block monitored task on kernel exit */
unsigned int mask_monitoring:1; /* mask monitors via PMCx.plm */
unsigned int reserved:28; /* for future use */
} bits;
} pfm_ovfl_ctrl_t; } pfm_ovfl_ctrl_t;
typedef struct { typedef struct {
unsigned long ovfl_pmds[4]; /* bitmask of overflowed pmds */ unsigned char ovfl_pmd; /* index of overflowed PMD */
unsigned long ovfl_notify[4]; /* bitmask of overflow pmds which asked for notification */ unsigned char ovfl_notify; /* =1 if monitor requested overflow notification */
unsigned long pmd_value; /* current 64-bit value of 1st pmd which overflowed */ unsigned short active_set; /* event set active at the time of the overflow */
unsigned long pmd_last_reset; /* last reset value of 1st pmd which overflowed */ pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */
unsigned long pmd_eventid; /* eventid associated with 1st pmd which overflowed */
unsigned int active_set; /* event set active at the time of the overflow */ unsigned long pmd_last_reset; /* last reset value of of the PMD */
unsigned int reserved1; unsigned long smpl_pmds[4]; /* bitmask of other PMD of interest on overflow */
unsigned long smpl_pmds[4]; unsigned long smpl_pmds_values[PMU_MAX_PMDS]; /* values for the other PMDs of interest */
unsigned long smpl_pmds_values[PMU_MAX_PMDS]; unsigned long pmd_value; /* current 64-bit value of the PMD */
pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */ unsigned long pmd_eventid; /* eventid associated with PMD */
} pfm_ovfl_arg_t; } pfm_ovfl_arg_t;
...@@ -223,7 +232,7 @@ typedef struct _pfm_buffer_fmt_t { ...@@ -223,7 +232,7 @@ typedef struct _pfm_buffer_fmt_t {
int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg); int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg);
int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size); int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size);
int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg); int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg);
int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs); int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp);
int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs); int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs);
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
*/ */
typedef struct { typedef struct {
unsigned long buf_size; /* size of the buffer in bytes */ unsigned long buf_size; /* size of the buffer in bytes */
unsigned long reserved[3]; /* for future use */ unsigned int flags; /* buffer specific flags */
unsigned int res1; /* for future use */
unsigned long reserved[2]; /* for future use */
} pfm_default_smpl_arg_t; } pfm_default_smpl_arg_t;
/* /*
...@@ -46,28 +48,27 @@ typedef struct { ...@@ -46,28 +48,27 @@ typedef struct {
/* /*
* Entry header in the sampling buffer. The header is directly followed * Entry header in the sampling buffer. The header is directly followed
* with the PMDs saved in increasing index order: PMD4, PMD5, .... How * with the values of the PMD registers of interest saved in increasing
* many PMDs are present depends on how the session was programmed. * index order: PMD4, PMD5, and so on. How many PMDs are present depends
* on how the session was programmed.
* *
* XXX: in this version of the entry, only up to 64 registers can be * In the case where multiple counters overflow at the same time, multiple
* recorded. This should be enough for quite some time. Always check * entries are written consecutively.
* sampling format before parsing entries!
* *
* In the case where multiple counters overflow at the same time, the * last_reset_value member indicates the initial value of the overflowed PMD.
* last_reset_value member indicates the initial value of the
* overflowed PMD with the smallest index. For instance, if PMD2 and
* PMD5 have overflowed, the last_reset_value member contains the
* initial value of PMD2.
*/ */
typedef struct { typedef struct {
int pid; /* current process at PMU interrupt point */ int pid; /* active process at PMU interrupt point */
int cpu; /* cpu on which the overfow occured */ unsigned char reserved1[3]; /* reserved for future use */
unsigned long last_reset_val; /* initial value of 1st overflowed PMD */ unsigned char ovfl_pmd; /* index of overflowed PMD */
unsigned long ip; /* where did the overflow interrupt happened */
unsigned long ovfl_pmds; /* which PMDS registers overflowed (64 max) */ unsigned long last_reset_val; /* initial value of overflowed PMD */
unsigned long tstamp; /* ar.itc on the CPU that took the overflow */ unsigned long ip; /* where did the overflow interrupt happened */
unsigned int set; /* event set active when overflow ocurred */ unsigned long tstamp; /* ar.itc when entering perfmon intr. handler */
unsigned int reserved1; /* for future use */
unsigned short cpu; /* cpu on which the overfow occured */
unsigned short set; /* event set active when overflow ocurred */
unsigned int reserved2; /* for future use */
} pfm_default_smpl_entry_t; } pfm_default_smpl_entry_t;
#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */ #define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment