/* $Id: perfctr.h,v 1.64 2005/05/26 00:37:36 mikpe Exp $ * x86/x86_64 Performance-Monitoring Counters driver * * Copyright (C) 1999-2005 Mikael Pettersson */ #ifndef _ASM_I386_PERFCTR_H #define _ASM_I386_PERFCTR_H #include struct perfctr_sum_ctrs { __u64 tsc; __u64 pmc[18]; /* the size is not part of the user ABI */ }; struct perfctr_cpu_control_header { __u32 tsc_on; __u32 nractrs; /* number of accumulation-mode counters */ __u32 nrictrs; /* number of interrupt-mode counters */ }; struct perfctr_cpu_state_user { __u32 cstatus; /* This is a sequence counter to ensure atomic reads by * userspace. The mechanism is identical to that used for * seqcount_t in include/linux/seqlock.h. */ __u32 sequence; __u64 tsc_start; __u64 tsc_sum; struct { __u64 start; __u64 sum; } pmc[18]; /* the size is not part of the user ABI */ }; /* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs which should have less overhead in most cases */ static inline unsigned int __perfctr_mk_cstatus(unsigned int tsc_on, unsigned int have_ictrs, unsigned int nrictrs, unsigned int nractrs) { return (tsc_on<<31) | (have_ictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs; } static inline unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs, unsigned int nrictrs) { return __perfctr_mk_cstatus(tsc_on, nrictrs, nrictrs, nractrs); } static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus) { return cstatus; } static inline int perfctr_cstatus_has_tsc(unsigned int cstatus) { return (int)cstatus < 0; /* test and jump on sign */ } static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus) { return cstatus & 0x7F; /* and with imm8 */ } static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus) { return (cstatus >> 8) & 0x7F; } static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus) { return cstatus & (0x7F << 16); } /* * 'struct siginfo' support for perfctr overflow signals. * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask * describing which perfctrs overflowed is put in si_pmc_ovf_mask. * A bitmask is used since more than one perfctr can have overflowed * by the time the interrupt handler runs. * * glibc's doesn't seem to define __SI_FAULT or __SI_CODE(), * and including as well may cause redefinition errors, * so the user and kernel values are different #defines here. */ #ifdef __KERNEL__ #define SI_PMC_OVF (__SI_FAULT|'P') #else #define SI_PMC_OVF ('P') #endif #define si_pmc_ovf_mask _sifields._pad[0] /* XXX: use an unsigned field later */ #ifdef __KERNEL__ #if defined(CONFIG_PERFCTR) struct perfctr_cpu_control { struct perfctr_cpu_control_header header; unsigned int evntsel[18]; /* primary control registers, physical indices */ unsigned int ireset[18]; /* >= 2^31, for i-mode counters, physical indices */ struct { unsigned int escr[0x3E2-0x3A0]; /* secondary controls, physical indices */ unsigned int pebs_enable; /* for replay tagging */ unsigned int pebs_matrix_vert; /* for replay tagging */ } p4; unsigned int pmc_map[18]; /* virtual to physical (rdpmc) index map */ }; struct perfctr_cpu_state { /* Don't change field order here without first considering the number of cache lines touched during sampling and context switching. */ unsigned int id; int isuspend_cpu; struct perfctr_cpu_state_user user; struct perfctr_cpu_control control; unsigned int p4_escr_map[18]; #ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT unsigned int pending_interrupt; #endif }; /* Driver init/exit. */ extern int perfctr_cpu_init(void); extern void perfctr_cpu_exit(void); /* CPU type name. */ extern char *perfctr_cpu_name; /* Hardware reservation. */ extern const char *perfctr_cpu_reserve(const char *service); extern void perfctr_cpu_release(const char *service); /* PRE: state has no running interrupt-mode counters. Check that the new control data is valid. Update the driver's private control data. is_global should be zero for per-process counters and non-zero for global-mode counters. This matters for HT P4s, alas. Returns a negative error code if the control data is invalid. */ extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global); /* Parse and update control for the given domain. */ extern int perfctr_cpu_control_write(struct perfctr_cpu_control *control, unsigned int domain, const void *srcp, unsigned int srcbytes); /* Retrieve and format control for the given domain. Returns number of bytes written. */ extern int perfctr_cpu_control_read(const struct perfctr_cpu_control *control, unsigned int domain, void *dstp, unsigned int dstbytes); /* Read a-mode counters. Subtract from start and accumulate into sums. Must be called with preemption disabled. */ extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state); /* Write control registers. Read a-mode counters into start. Must be called with preemption disabled. */ extern void perfctr_cpu_resume(struct perfctr_cpu_state *state); /* Perform an efficient combined suspend/resume operation. Must be called with preemption disabled. */ extern void perfctr_cpu_sample(struct perfctr_cpu_state *state); /* The type of a perfctr overflow interrupt handler. It will be called in IRQ context, with preemption disabled. */ typedef void (*perfctr_ihandler_t)(unsigned long pc); /* Operations related to overflow interrupt handling. */ #ifdef CONFIG_X86_LOCAL_APIC extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t); extern void perfctr_cpu_ireload(struct perfctr_cpu_state*); extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*); static inline int perfctr_cpu_has_pending_interrupt(const struct perfctr_cpu_state *state) { return state->pending_interrupt; } #else static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { } static inline int perfctr_cpu_has_pending_interrupt(const struct perfctr_cpu_state *state) { return 0; } #endif #endif /* CONFIG_PERFCTR */ #if defined(CONFIG_PERFCTR) && defined(CONFIG_X86_LOCAL_APIC) asmlinkage void perfctr_interrupt(struct pt_regs*); #define perfctr_vector_init() \ set_intr_gate(LOCAL_PERFCTR_VECTOR, perfctr_interrupt) #else #define perfctr_vector_init() do{}while(0) #endif #endif /* __KERNEL__ */ #endif /* _ASM_I386_PERFCTR_H */