#ifndef _SYS_PMC_H_
#define _SYS_PMC_H_
#include <dev/hwpmc/pmc_events.h>
#include <sys/proc.h>
#include <sys/counter.h>
#include <machine/pmc_mdep.h>
#include <machine/profile.h>
#ifdef _KERNEL
#include <sys/epoch.h>
#include <ck_queue.h>
#endif
#define PMC_MODULE_NAME "hwpmc"
#define PMC_NAME_MAX 64
#define PMC_CLASS_MAX 8
#define PMC_VERSION_MAJOR 0x0A
#define PMC_VERSION_MINOR 0x01
#define PMC_VERSION_PATCH 0x0000
#define PMC_VERSION (PMC_VERSION_MAJOR << 24 | \
PMC_VERSION_MINOR << 16 | PMC_VERSION_PATCH)
#define PMC_CPUID_LEN 64
extern char pmc_cpuid[PMC_CPUID_LEN];
#define __PMC_CPUS() \
__PMC_CPU(AMD_K8, 0x01, "AMD K8") \
__PMC_CPU(INTEL_CORE, 0x87, "Intel Core Solo/Duo") \
__PMC_CPU(INTEL_CORE2, 0x88, "Intel Core2") \
__PMC_CPU(INTEL_CORE2EXTREME, 0x89, "Intel Core2 Extreme") \
__PMC_CPU(INTEL_ATOM, 0x8A, "Intel Atom") \
__PMC_CPU(INTEL_COREI7, 0x8B, "Intel Core i7") \
__PMC_CPU(INTEL_WESTMERE, 0x8C, "Intel Westmere") \
__PMC_CPU(INTEL_SANDYBRIDGE, 0x8D, "Intel Sandy Bridge") \
__PMC_CPU(INTEL_IVYBRIDGE, 0x8E, "Intel Ivy Bridge") \
__PMC_CPU(INTEL_SANDYBRIDGE_XEON, 0x8F, "Intel Sandy Bridge Xeon") \
__PMC_CPU(INTEL_IVYBRIDGE_XEON, 0x90, "Intel Ivy Bridge Xeon") \
__PMC_CPU(INTEL_HASWELL, 0x91, "Intel Haswell") \
__PMC_CPU(INTEL_ATOM_SILVERMONT, 0x92, "Intel Atom Silvermont") \
__PMC_CPU(INTEL_NEHALEM_EX, 0x93, "Intel Nehalem Xeon 7500") \
__PMC_CPU(INTEL_WESTMERE_EX, 0x94, "Intel Westmere Xeon E7") \
__PMC_CPU(INTEL_HASWELL_XEON, 0x95, "Intel Haswell Xeon E5 v3") \
__PMC_CPU(INTEL_BROADWELL, 0x96, "Intel Broadwell") \
__PMC_CPU(INTEL_BROADWELL_XEON, 0x97, "Intel Broadwell Xeon") \
__PMC_CPU(INTEL_SKYLAKE, 0x98, "Intel Skylake") \
__PMC_CPU(INTEL_SKYLAKE_XEON, 0x99, "Intel Skylake Xeon") \
__PMC_CPU(INTEL_ATOM_GOLDMONT, 0x9A, "Intel Atom Goldmont") \
__PMC_CPU(INTEL_ICELAKE, 0x9B, "Intel Icelake") \
__PMC_CPU(INTEL_ICELAKE_XEON, 0x9C, "Intel Icelake Xeon") \
__PMC_CPU(INTEL_ALDERLAKE, 0x9D, "Intel Alderlake") \
__PMC_CPU(INTEL_ATOM_GOLDMONT_P, 0x9E, "Intel Atom Goldmont Plus") \
__PMC_CPU(INTEL_ATOM_TREMONT, 0x9F, "Intel Atom Tremont") \
__PMC_CPU(INTEL_EMERALD_RAPIDS, 0xA0, "Intel Emerald Rapids") \
__PMC_CPU(INTEL_ALDERLAKEN, 0xA1, "Intel AlderlakeN") \
__PMC_CPU(INTEL_GRANITE_RAPIDS, 0xA2, "Intel Granite Rapids") \
__PMC_CPU(INTEL_METEOR_LAKE, 0xA3, "Intel Meteorlake") \
__PMC_CPU(PPC_7450, 0x300, "PowerPC MPC7450") \
__PMC_CPU(PPC_E500, 0x340, "PowerPC e500 Core") \
__PMC_CPU(PPC_970, 0x380, "IBM PowerPC 970") \
__PMC_CPU(PPC_POWER8, 0x390, "IBM POWER8") \
__PMC_CPU(GENERIC, 0x400, "Generic") \
__PMC_CPU(ARMV7_CORTEX_A5, 0x500, "ARMv7 Cortex A5") \
__PMC_CPU(ARMV7_CORTEX_A7, 0x501, "ARMv7 Cortex A7") \
__PMC_CPU(ARMV7_CORTEX_A8, 0x502, "ARMv7 Cortex A8") \
__PMC_CPU(ARMV7_CORTEX_A9, 0x503, "ARMv7 Cortex A9") \
__PMC_CPU(ARMV7_CORTEX_A15, 0x504, "ARMv7 Cortex A15") \
__PMC_CPU(ARMV7_CORTEX_A17, 0x505, "ARMv7 Cortex A17") \
__PMC_CPU(ARMV8_CORTEX_A53, 0x600, "ARMv8 Cortex A53") \
__PMC_CPU(ARMV8_CORTEX_A57, 0x601, "ARMv8 Cortex A57") \
__PMC_CPU(ARMV8_CORTEX_A76, 0x602, "ARMv8 Cortex A76")
enum pmc_cputype {
#undef __PMC_CPU
#define __PMC_CPU(S,V,D) PMC_CPU_##S = V,
__PMC_CPUS()
};
#define PMC_CPU_FIRST PMC_CPU_AMD_K8
#define PMC_CPU_LAST PMC_CPU_ARMV8_CORTEX_A76
#define __PMC_CLASSES() \
__PMC_CLASS(TSC, 0x00, "CPU Timestamp counter") \
__PMC_CLASS(K8, 0x02, "AMD K8 performance counters") \
__PMC_CLASS(IBS, 0x03, "AMD IBS performance counters") \
__PMC_CLASS(IAF, 0x06, "Intel Core2/Atom, fixed function") \
__PMC_CLASS(IAP, 0x07, "Intel Core...Atom, programmable") \
__PMC_CLASS(UCF, 0x08, "Intel Uncore fixed function") \
__PMC_CLASS(UCP, 0x09, "Intel Uncore programmable") \
__PMC_CLASS(PPC7450, 0x0D, "Motorola MPC7450 class") \
__PMC_CLASS(PPC970, 0x0E, "IBM PowerPC 970 class") \
__PMC_CLASS(SOFT, 0x0F, "Software events") \
__PMC_CLASS(ARMV7, 0x10, "ARMv7") \
__PMC_CLASS(ARMV8, 0x11, "ARMv8") \
__PMC_CLASS(E500, 0x13, "Freescale e500 class") \
__PMC_CLASS(POWER8, 0x15, "IBM POWER8 class") \
__PMC_CLASS(DMC620_PMU_CD2, 0x16, "ARM DMC620 Memory Controller PMU CLKDIV2") \
__PMC_CLASS(DMC620_PMU_C, 0x17, "ARM DMC620 Memory Controller PMU CLK") \
__PMC_CLASS(CMN600_PMU, 0x18, "Arm CoreLink CMN600 Coherent Mesh Network PMU")
enum pmc_class {
#undef __PMC_CLASS
#define __PMC_CLASS(S,V,D) PMC_CLASS_##S = V,
__PMC_CLASSES()
};
#define PMC_CLASS_FIRST PMC_CLASS_TSC
#define PMC_CLASS_LAST PMC_CLASS_CMN600_PMU
#define __PMC_HWSTATES() \
__PMC_STATE(DISABLED) \
__PMC_STATE(FREE)
#define __PMC_SWSTATES() \
__PMC_STATE(ALLOCATED) \
__PMC_STATE(STOPPED) \
__PMC_STATE(RUNNING) \
__PMC_STATE(DELETED)
#define __PMC_STATES() \
__PMC_HWSTATES() \
__PMC_SWSTATES()
enum pmc_state {
#undef __PMC_STATE
#define __PMC_STATE(S) PMC_STATE_##S,
__PMC_STATES()
__PMC_STATE(MAX)
};
#define PMC_STATE_FIRST PMC_STATE_DISABLED
#define PMC_STATE_LAST PMC_STATE_DELETED
#define __PMC_MODES() \
__PMC_MODE(SS, 0) \
__PMC_MODE(SC, 1) \
__PMC_MODE(TS, 2) \
__PMC_MODE(TC, 3)
enum pmc_mode {
#undef __PMC_MODE
#define __PMC_MODE(M,N) PMC_MODE_##M = N,
__PMC_MODES()
};
#define PMC_MODE_FIRST PMC_MODE_SS
#define PMC_MODE_LAST PMC_MODE_TC
#define PMC_IS_COUNTING_MODE(mode) \
((mode) == PMC_MODE_SC || (mode) == PMC_MODE_TC)
#define PMC_IS_SYSTEM_MODE(mode) \
((mode) == PMC_MODE_SS || (mode) == PMC_MODE_SC)
#define PMC_IS_SAMPLING_MODE(mode) \
((mode) == PMC_MODE_SS || (mode) == PMC_MODE_TS)
#define PMC_IS_VIRTUAL_MODE(mode) \
((mode) == PMC_MODE_TS || (mode) == PMC_MODE_TC)
#define __PMC_DISPOSITIONS(N) \
__PMC_DISP(STANDALONE) \
__PMC_DISP(FREE) \
__PMC_DISP(THREAD) \
__PMC_DISP(UNKNOWN)
enum pmc_disp {
#undef __PMC_DISP
#define __PMC_DISP(D) PMC_DISP_##D ,
__PMC_DISPOSITIONS()
};
#define PMC_DISP_FIRST PMC_DISP_STANDALONE
#define PMC_DISP_LAST PMC_DISP_THREAD
#define __PMC_CAPS() \
__PMC_CAP(INTERRUPT, 0, "generate interrupts") \
__PMC_CAP(USER, 1, "count user-mode events") \
__PMC_CAP(SYSTEM, 2, "count system-mode events") \
__PMC_CAP(EDGE, 3, "do edge detection of events") \
__PMC_CAP(THRESHOLD, 4, "ignore events below a threshold") \
__PMC_CAP(READ, 5, "read PMC counter") \
__PMC_CAP(WRITE, 6, "reprogram PMC counter") \
__PMC_CAP(INVERT, 7, "invert comparison sense") \
__PMC_CAP(QUALIFIER, 8, "further qualify monitored events") \
__PMC_CAP(PRECISE, 9, "perform precise sampling") \
__PMC_CAP(TAGGING, 10, "tag upstream events") \
__PMC_CAP(CASCADE, 11, "cascade counters") \
__PMC_CAP(SYSWIDE, 12, "system wide counter") \
__PMC_CAP(DOMWIDE, 13, "NUMA domain wide counter")
enum pmc_caps
{
#undef __PMC_CAP
#define __PMC_CAP(NAME, VALUE, DESCR) PMC_CAP_##NAME = (1 << VALUE) ,
__PMC_CAPS()
};
#define PMC_CAP_FIRST PMC_CAP_INTERRUPT
#define PMC_CAP_LAST PMC_CAP_DOMWIDE
enum pmc_event {
#undef __PMC_EV
#undef __PMC_EV_BLOCK
#define __PMC_EV_BLOCK(C,V) PMC_EV_ ## C ## __BLOCK_START = (V) - 1 ,
#define __PMC_EV(C,N) PMC_EV_ ## C ## _ ## N ,
__PMC_EVENTS()
};
#define __PMC_OPS() \
__PMC_OP(CONFIGURELOG, "Set log file") \
__PMC_OP(FLUSHLOG, "Flush log file") \
__PMC_OP(GETCPUINFO, "Get system CPU information") \
__PMC_OP(GETDRIVERSTATS, "Get driver statistics") \
__PMC_OP(GETMODULEVERSION, "Get module version") \
__PMC_OP(GETPMCINFO, "Get per-cpu PMC information") \
__PMC_OP(PMCADMIN, "Set PMC state") \
__PMC_OP(PMCALLOCATE, "Allocate and configure a PMC") \
__PMC_OP(PMCATTACH, "Attach a PMC to a process") \
__PMC_OP(PMCDETACH, "Detach a PMC from a process") \
__PMC_OP(PMCGETMSR, "Get a PMC's hardware address") \
__PMC_OP(PMCRELEASE, "Release a PMC") \
__PMC_OP(PMCRW, "Read/Set a PMC") \
__PMC_OP(PMCSETCOUNT, "Set initial count/sampling rate") \
__PMC_OP(PMCSTART, "Start a PMC") \
__PMC_OP(PMCSTOP, "Stop a PMC") \
__PMC_OP(WRITELOG, "Write a cookie to the log file") \
__PMC_OP(CLOSELOG, "Close log file") \
__PMC_OP(GETDYNEVENTINFO, "Get dynamic events list") \
__PMC_OP(GETCAPS, "Get capabilities")
enum pmc_ops {
#undef __PMC_OP
#define __PMC_OP(N, D) PMC_OP_##N,
__PMC_OPS()
};
#define PMC_F_UNUSED1 0x00000001
#define PMC_F_DESCENDANTS 0x00000002
#define PMC_F_LOG_PROCCSW 0x00000004
#define PMC_F_LOG_PROCEXIT 0x00000008
#define PMC_F_NEWVALUE 0x00000010
#define PMC_F_OLDVALUE 0x00000020
#define PMC_F_CALLCHAIN 0x00000080
#define PMC_F_USERCALLCHAIN 0x00000100
#define PMC_F_EV_PMU 0x00000200
#define PMC_F_ATTACHED_TO_OWNER 0x00010000
#define PMC_F_NEEDS_LOGFILE 0x00020000
#define PMC_F_ATTACH_DONE 0x00040000
#define PMC_CALLCHAIN_DEPTH_MAX 512
#define PMC_CC_F_USERSPACE 0x01
#define PMC_CC_F_MULTIPART 0x02
typedef uint32_t pmc_id_t;
typedef uint64_t pmc_value_t;
#define PMC_ID_INVALID (~ (pmc_id_t) 0)
#define PMC_ID_TO_ROWINDEX(ID) ((ID) & 0xFF)
#define PMC_ID_TO_CLASS(ID) (((ID) & 0xFF00) >> 8)
#define PMC_ID_TO_MODE(ID) (((ID) & 0xF0000) >> 16)
#define PMC_ID_TO_CPU(ID) (((ID) & 0xFFF00000) >> 20)
#define PMC_ID_MAKE_ID(CPU,MODE,CLASS,ROWINDEX) \
((((CPU) & 0xFFF) << 20) | (((MODE) & 0xF) << 16) | \
(((CLASS) & 0xFF) << 8) | ((ROWINDEX) & 0xFF))
#define PMC_CPU_ANY ~0
struct pmc_op_pmcallocate {
uint32_t pm_caps;
uint32_t pm_cpu;
enum pmc_class pm_class;
enum pmc_event pm_ev;
uint32_t pm_flags;
enum pmc_mode pm_mode;
pmc_id_t pm_pmcid;
pmc_value_t pm_count;
union pmc_md_op_pmcallocate pm_md;
};
struct pmc_op_pmcadmin {
int pm_cpu;
uint32_t pm_flags;
int pm_pmc;
enum pmc_state pm_state;
};
struct pmc_op_pmcattach {
pmc_id_t pm_pmc;
pid_t pm_pid;
};
struct pmc_op_pmcsetcount {
pmc_value_t pm_count;
pmc_id_t pm_pmcid;
};
struct pmc_op_pmcrw {
uint32_t pm_flags;
pmc_id_t pm_pmcid;
pmc_value_t pm_value;
};
struct pmc_info {
char pm_name[PMC_NAME_MAX];
enum pmc_class pm_class;
int pm_enabled;
enum pmc_disp pm_rowdisp;
pid_t pm_ownerpid;
enum pmc_mode pm_mode;
enum pmc_event pm_event;
uint32_t pm_flags;
pmc_value_t pm_reloadcount;
};
struct pmc_op_getpmcinfo {
int32_t pm_cpu;
struct pmc_info pm_pmcs[];
};
struct pmc_classinfo {
enum pmc_class pm_class;
uint32_t pm_caps;
uint32_t pm_width;
uint32_t pm_num;
};
struct pmc_op_getcpuinfo {
enum pmc_cputype pm_cputype;
uint32_t pm_ncpu;
uint32_t pm_npmc;
uint32_t pm_nclass;
struct pmc_classinfo pm_classes[PMC_CLASS_MAX];
};
struct pmc_op_configurelog {
int pm_flags;
int pm_logfd;
};
#ifdef _KERNEL
struct pmc_driverstats {
counter_u64_t pm_intr_ignored;
counter_u64_t pm_intr_processed;
counter_u64_t pm_intr_bufferfull;
counter_u64_t pm_syscalls;
counter_u64_t pm_syscall_errors;
counter_u64_t pm_buffer_requests;
counter_u64_t pm_buffer_requests_failed;
counter_u64_t pm_log_sweeps;
counter_u64_t pm_merges;
counter_u64_t pm_overwrites;
};
#endif
struct pmc_op_getdriverstats {
unsigned int pm_intr_ignored;
unsigned int pm_intr_processed;
unsigned int pm_intr_bufferfull;
unsigned int pm_syscalls;
unsigned int pm_syscall_errors;
unsigned int pm_buffer_requests;
unsigned int pm_buffer_requests_failed;
unsigned int pm_log_sweeps;
};
struct pmc_op_simple {
pmc_id_t pm_pmcid;
};
struct pmc_op_writelog {
uint32_t pm_userdata;
};
struct pmc_op_getmsr {
uint32_t pm_msr;
pmc_id_t pm_pmcid;
};
struct pmc_dyn_event_descr {
char pm_ev_name[PMC_NAME_MAX];
enum pmc_event pm_ev_code;
};
struct pmc_op_getdyneventinfo {
enum pmc_class pm_class;
unsigned int pm_nevent;
struct pmc_dyn_event_descr pm_events[PMC_EV_DYN_COUNT];
};
struct pmc_op_caps {
pmc_id_t pm_pmcid;
uint32_t pm_caps;
};
#ifdef _KERNEL
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/_cpuset.h>
#include <machine/frame.h>
#define PMC_HASH_SIZE 1024
#define PMC_MTXPOOL_SIZE 2048
#define PMC_LOG_BUFFER_SIZE 256
#define PMC_LOG_BUFFER_SIZE_MAX (16 * 1024)
#define PMC_NLOGBUFFERS_PCPU 32
#define PMC_NLOGBUFFERS_PCPU_MEM_MAX (32 * 1024)
#define PMC_NSAMPLES 256
#define PMC_CALLCHAIN_DEPTH 128
#define PMC_THREADLIST_MAX 128
#define PMC_SYSCTL_NAME_PREFIX "kern." PMC_MODULE_NAME "."
struct pmc_syscall_args {
register_t pmop_code;
void *pmop_data;
};
struct pmc_descr {
char pd_name[PMC_NAME_MAX];
uint32_t pd_caps;
enum pmc_class pd_class;
uint32_t pd_width;
};
struct pmc_target {
LIST_ENTRY(pmc_target) pt_next;
struct pmc_process *pt_process;
};
struct pmc_pcpu_state {
uint32_t pps_overflowcnt;
uint8_t pps_stalled;
uint8_t pps_cpustate;
} __aligned(CACHE_LINE_SIZE);
struct pmc {
LIST_HEAD(,pmc_target) pm_targets;
LIST_ENTRY(pmc) pm_next;
union {
pmc_value_t pm_savedvalue;
} pm_gv;
union {
pmc_value_t pm_reloadcount;
pmc_value_t pm_initial;
} pm_sc;
struct pmc_pcpu_state *pm_pcpu_state;
volatile cpuset_t pm_cpustate;
uint32_t pm_caps;
enum pmc_event pm_event;
uint32_t pm_flags;
struct pmc_owner *pm_owner;
counter_u64_t pm_runcount;
enum pmc_state pm_state;
pmc_id_t pm_id;
enum pmc_class pm_class;
union pmc_md_pmc pm_md;
};
#define PMC_TO_MODE(P) PMC_ID_TO_MODE((P)->pm_id)
#define PMC_TO_CLASS(P) PMC_ID_TO_CLASS((P)->pm_id)
#define PMC_TO_ROWINDEX(P) PMC_ID_TO_ROWINDEX((P)->pm_id)
#define PMC_TO_CPU(P) PMC_ID_TO_CPU((P)->pm_id)
struct pmc_threadpmcstate {
pmc_value_t pt_pmcval;
};
struct pmc_thread {
LIST_ENTRY(pmc_thread) pt_next;
struct thread *pt_td;
struct pmc_threadpmcstate pt_pmcs[];
};
struct pmc_targetstate {
struct pmc *pp_pmc;
pmc_value_t pp_pmcval;
};
struct pmc_process {
LIST_ENTRY(pmc_process) pp_next;
LIST_HEAD(,pmc_thread) pp_tds;
struct mtx *pp_tdslock;
int pp_refcnt;
uint32_t pp_flags;
struct proc *pp_proc;
struct pmc_targetstate pp_pmcs[];
};
#define PMC_PP_ENABLE_MSR_ACCESS 0x00000001
struct pmc_owner {
LIST_ENTRY(pmc_owner) po_next;
CK_LIST_ENTRY(pmc_owner) po_ssnext;
LIST_HEAD(, pmc) po_pmcs;
TAILQ_HEAD(, pmclog_buffer) po_logbuffers;
struct mtx po_mtx;
struct proc *po_owner;
uint32_t po_flags;
struct proc *po_kthread;
struct file *po_file;
int po_error;
short po_sscount;
short po_logprocmaps;
struct pmclog_buffer *po_curbuf[MAXCPU];
};
#define PMC_PO_OWNS_LOGFILE 0x00000001
#define PMC_PO_SHUTDOWN 0x00000010
#define PMC_PO_INITIAL_MAPPINGS_DONE 0x00000020
struct pmc_hw {
uint32_t phw_state;
struct pmc *phw_pmc;
};
#define PMC_PHW_RI_MASK 0x000000FF
#define PMC_PHW_CPU_SHIFT 8
#define PMC_PHW_CPU_MASK 0x0000FF00
#define PMC_PHW_FLAGS_SHIFT 16
#define PMC_PHW_FLAGS_MASK 0xFFFF0000
#define PMC_PHW_INDEX_TO_STATE(ri) ((ri) & PMC_PHW_RI_MASK)
#define PMC_PHW_STATE_TO_INDEX(state) ((state) & PMC_PHW_RI_MASK)
#define PMC_PHW_CPU_TO_STATE(cpu) (((cpu) << PMC_PHW_CPU_SHIFT) & \
PMC_PHW_CPU_MASK)
#define PMC_PHW_STATE_TO_CPU(state) (((state) & PMC_PHW_CPU_MASK) >> \
PMC_PHW_CPU_SHIFT)
#define PMC_PHW_FLAGS_TO_STATE(flags) (((flags) << PMC_PHW_FLAGS_SHIFT) & \
PMC_PHW_FLAGS_MASK)
#define PMC_PHW_STATE_TO_FLAGS(state) (((state) & PMC_PHW_FLAGS_MASK) >> \
PMC_PHW_FLAGS_SHIFT)
#define PMC_PHW_FLAG_IS_ENABLED (PMC_PHW_FLAGS_TO_STATE(0x01))
#define PMC_PHW_FLAG_IS_SHAREABLE (PMC_PHW_FLAGS_TO_STATE(0x02))
struct pmc_sample {
uint16_t ps_nsamples;
uint16_t ps_nsamples_actual;
uint16_t ps_cpu;
uint16_t ps_flags;
lwpid_t ps_tid;
pid_t ps_pid;
int ps_ticks;
struct thread *ps_td;
struct pmc *ps_pmc;
uintptr_t *ps_pc;
uint64_t ps_tsc;
};
#define PMC_SAMPLE_FREE ((uint16_t) 0)
#define PMC_USER_CALLCHAIN_PENDING ((uint16_t) 0xFFFF)
struct pmc_samplebuffer {
volatile uint64_t ps_prodidx;
volatile uint64_t ps_considx;
uintptr_t *ps_callchains;
struct pmc_sample ps_samples[];
};
#define PMC_CONS_SAMPLE(psb) \
(&(psb)->ps_samples[(psb)->ps_considx & pmc_sample_mask])
#define PMC_CONS_SAMPLE_OFF(psb, off) \
(&(psb)->ps_samples[(off) & pmc_sample_mask])
#define PMC_PROD_SAMPLE(psb) \
(&(psb)->ps_samples[(psb)->ps_prodidx & pmc_sample_mask])
struct pmc_multipart {
char pl_type;
char pl_length;
uint64_t pl_mpdata[10];
};
struct pmc_cpu {
uint32_t pc_state;
struct pmc_samplebuffer *pc_sb[3];
struct pmc_hw *pc_hwpmcs[];
};
#define PMC_PCPU_CPU_MASK 0x000000FF
#define PMC_PCPU_FLAGS_MASK 0xFFFFFF00
#define PMC_PCPU_FLAGS_SHIFT 8
#define PMC_PCPU_STATE_TO_CPU(S) ((S) & PMC_PCPU_CPU_MASK)
#define PMC_PCPU_STATE_TO_FLAGS(S) (((S) & PMC_PCPU_FLAGS_MASK) >> PMC_PCPU_FLAGS_SHIFT)
#define PMC_PCPU_FLAGS_TO_STATE(F) (((F) << PMC_PCPU_FLAGS_SHIFT) & PMC_PCPU_FLAGS_MASK)
#define PMC_PCPU_CPU_TO_STATE(C) ((C) & PMC_PCPU_CPU_MASK)
#define PMC_PCPU_FLAG_HTT (PMC_PCPU_FLAGS_TO_STATE(0x1))
struct pmc_binding {
int pb_bound;
int pb_cpu;
u_char pb_priority;
};
struct pmc_mdep;
struct pmc_classdep {
uint32_t pcd_caps;
enum pmc_class pcd_class;
int pcd_num;
int pcd_ri;
int pcd_width;
int (*pcd_config_pmc)(int _cpu, int _ri, struct pmc *_pm);
int (*pcd_get_config)(int _cpu, int _ri, struct pmc **_ppm);
int (*pcd_read_pmc)(int _cpu, int _ri, struct pmc *_pm,
pmc_value_t *_value);
int (*pcd_write_pmc)(int _cpu, int _ri, struct pmc *_pm,
pmc_value_t _value);
int (*pcd_allocate_pmc)(int _cpu, int _ri, struct pmc *_t,
const struct pmc_op_pmcallocate *_a);
int (*pcd_release_pmc)(int _cpu, int _ri, struct pmc *_pm);
int (*pcd_start_pmc)(int _cpu, int _ri, struct pmc *_pm);
int (*pcd_stop_pmc)(int _cpu, int _ri, struct pmc *_pm);
int (*pcd_describe)(int _cpu, int _ri, struct pmc_info *_pi,
struct pmc **_ppmc);
int (*pcd_get_caps)(int _ri, uint32_t *_caps);
int (*pcd_pcpu_init)(struct pmc_mdep *_md, int _cpu);
int (*pcd_pcpu_fini)(struct pmc_mdep *_md, int _cpu);
int (*pcd_get_msr)(int _ri, uint32_t *_msr);
};
struct pmc_mdep {
uint32_t pmd_cputype;
uint32_t pmd_npmc;
uint32_t pmd_nclass;
int (*pmd_switch_in)(struct pmc_cpu *_p, struct pmc_process *_pp);
int (*pmd_switch_out)(struct pmc_cpu *_p, struct pmc_process *_pp);
int (*pmd_intr)(struct trapframe *_tf);
struct pmc_classdep pmd_classdep[];
};
extern struct pmc_cpu **pmc_pcpu;
extern struct pmc_driverstats pmc_stats;
#if defined(HWPMC_DEBUG)
#if !defined(KTR) || !defined(KTR_COMPILE) || ((KTR_COMPILE & KTR_SUBSYS) == 0)
#error "HWPMC_DEBUG requires KTR and KTR_COMPILE=KTR_SUBSYS -- see ktr(4)"
#endif
#include <sys/ktr.h>
#define __pmcdbg_used
struct pmc_debugflags {
int pdb_CPU;
int pdb_CSW;
int pdb_LOG;
int pdb_MDP;
int pdb_MOD;
int pdb_OWN;
int pdb_PMC;
int pdb_PRC;
int pdb_SAM;
};
extern struct pmc_debugflags pmc_debugflags;
#define KTR_PMC KTR_SUBSYS
#define PMC_DEBUG_STRSIZE 128
#define PMC_DEBUG_DEFAULT_FLAGS { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
#define PMCDBG0(M, N, L, F) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR0(KTR_PMC, #M ":" #N ":" #L ": " F); \
} while (0)
#define PMCDBG1(M, N, L, F, p1) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR1(KTR_PMC, #M ":" #N ":" #L ": " F, p1); \
} while (0)
#define PMCDBG2(M, N, L, F, p1, p2) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR2(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2); \
} while (0)
#define PMCDBG3(M, N, L, F, p1, p2, p3) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR3(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3); \
} while (0)
#define PMCDBG4(M, N, L, F, p1, p2, p3, p4) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR4(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3, p4);\
} while (0)
#define PMCDBG5(M, N, L, F, p1, p2, p3, p4, p5) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR5(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3, p4, \
p5); \
} while (0)
#define PMCDBG6(M, N, L, F, p1, p2, p3, p4, p5, p6) do { \
if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \
CTR6(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3, p4, \
p5, p6); \
} while (0)
#define PMC_DEBUG_MAJ_CPU 0
#define PMC_DEBUG_MAJ_CSW 1
#define PMC_DEBUG_MAJ_LOG 2
#define PMC_DEBUG_MAJ_MDP 3
#define PMC_DEBUG_MAJ_MOD 4
#define PMC_DEBUG_MAJ_OWN 5
#define PMC_DEBUG_MAJ_PMC 6
#define PMC_DEBUG_MAJ_PRC 7
#define PMC_DEBUG_MAJ_SAM 8
#define PMC_DEBUG_MIN_ALL 0
#define PMC_DEBUG_MIN_REL 1
#define PMC_DEBUG_MIN_OPS 2
#define PMC_DEBUG_MIN_INI 3
#define PMC_DEBUG_MIN_FND 4
#define PMC_DEBUG_MIN_PMH 14
#define PMC_DEBUG_MIN_PMS 15
#define PMC_DEBUG_MIN_ORM 8
#define PMC_DEBUG_MIN_OMR 9
#define PMC_DEBUG_MIN_TLK 8
#define PMC_DEBUG_MIN_TUL 9
#define PMC_DEBUG_MIN_EXT 10
#define PMC_DEBUG_MIN_EXC 11
#define PMC_DEBUG_MIN_FRK 12
#define PMC_DEBUG_MIN_ATT 13
#define PMC_DEBUG_MIN_SIG 14
#define PMC_DEBUG_MIN_SWI 8
#define PMC_DEBUG_MIN_SWO 9
#define PMC_DEBUG_MIN_REG 8
#define PMC_DEBUG_MIN_ALR 9
#define PMC_DEBUG_MIN_REA 8
#define PMC_DEBUG_MIN_WRI 9
#define PMC_DEBUG_MIN_CFG 10
#define PMC_DEBUG_MIN_STA 11
#define PMC_DEBUG_MIN_STO 12
#define PMC_DEBUG_MIN_INT 13
#define PMC_DEBUG_MIN_BND 8
#define PMC_DEBUG_MIN_SEL 9
#define PMC_DEBUG_MIN_GTB 8
#define PMC_DEBUG_MIN_SIO 9
#define PMC_DEBUG_MIN_FLS 10
#define PMC_DEBUG_MIN_SAM 11
#define PMC_DEBUG_MIN_CLO 12
#else
#define __pmcdbg_used __unused
#define PMCDBG0(M, N, L, F)
#define PMCDBG1(M, N, L, F, p1)
#define PMCDBG2(M, N, L, F, p1, p2)
#define PMCDBG3(M, N, L, F, p1, p2, p3)
#define PMCDBG4(M, N, L, F, p1, p2, p3, p4)
#define PMCDBG5(M, N, L, F, p1, p2, p3, p4, p5)
#define PMCDBG6(M, N, L, F, p1, p2, p3, p4, p5, p6)
#endif
MALLOC_DECLARE(M_PMC);
struct pmc_mdep *pmc_md_initialize(void);
void pmc_md_finalize(struct pmc_mdep *_md);
int pmc_getrowdisp(int _ri);
int pmc_process_interrupt_mp(int _ring, struct pmc *_pm,
struct trapframe *_tf, struct pmc_multipart *mp);
int pmc_process_interrupt(int _ring, struct pmc *_pm,
struct trapframe *_tf);
int pmc_save_kernel_callchain(uintptr_t *_cc, int _maxsamples,
struct trapframe *_tf);
int pmc_save_user_callchain(uintptr_t *_cc, int _maxsamples,
struct trapframe *_tf);
void pmc_restore_cpu_binding(struct pmc_binding *pb);
void pmc_save_cpu_binding(struct pmc_binding *pb);
void pmc_select_cpu(int cpu);
struct pmc_mdep *pmc_mdep_alloc(int nclasses);
void pmc_mdep_free(struct pmc_mdep *md);
uint64_t pmc_rdtsc(void);
#endif
#endif