Diff 11161
Properties
Path | Size | ||||
---|---|---|---|---|---|
| |||||
| |||||
| |||||
2 lines | |||||
| |||||
2 lines | |||||
| |||||
21 lines | |||||
579 lines | |||||
| |||||
| |||||
6 lines | |||||
| |||||
4 lines | |||||
3 lines | |||||
| |||||
6 lines | |||||
| |||||
24 lines | |||||
| |||||
13 lines | |||||
9 lines | |||||
66 lines | |||||
193 lines | |||||
| |||||
4 lines | |||||
| |||||
2 lines |
Diff 11161
sys/boot/common/self_reloc.c
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include "hwpmc_soft.h" | #include "hwpmc_soft.h" | ||||
#include "hwpmc_vm.h" | |||||
#ifdef NUMA | #ifdef NUMA | ||||
#define NDOMAINS vm_ndomains | #define NDOMAINS vm_ndomains | ||||
#else | #else | ||||
#define NDOMAINS 1 | #define NDOMAINS 1 | ||||
#define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | ||||
#define free_domain(addr, type) free(addr, type) | #define free_domain(addr, type) free(addr, type) | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 1,356 Lines • ▼ Show 20 Lines | if (PMC_TO_MODE(pm) == PMC_MODE_TS) { | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
KASSERT(newvalue > 0 && newvalue <= | KASSERT(newvalue > 0 && newvalue <= | ||||
pm->pm_sc.pm_reloadcount, | pm->pm_sc.pm_reloadcount, | ||||
("[pmc,%d] pmcval outside of expected range cpu=%d " | ("[pmc,%d] pmcval outside of expected range cpu=%d " | ||||
"ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | "ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | ||||
cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | ||||
} else if (PMC_TO_MODE(pm) == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | ||||
("[pmc,%d] illegal mode=%d", __LINE__, | ("[pmc,%d] illegal mode=%d", __LINE__, | ||||
PMC_TO_MODE(pm))); | PMC_TO_MODE(pm))); | ||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | mtx_pool_lock_spin(pmc_mtxpool, pm); | ||||
newvalue = PMC_PCPU_SAVED(cpu, ri) = | newvalue = PMC_PCPU_SAVED(cpu, ri) = | ||||
pm->pm_gv.pm_savedvalue; | pm->pm_gv.pm_savedvalue; | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} | } | ||||
PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | ||||
pcd->pcd_write_pmc(cpu, adjri, newvalue); | pcd->pcd_write_pmc(cpu, adjri, newvalue); | ||||
/* If a sampling mode PMC, reset stalled state. */ | /* If a sampling mode PMC, reset stalled state. */ | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TS) | if (PMC_TO_MODE(pm) == PMC_MODE_TS || | ||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pm->pm_pcpu_state[cpu].pps_stalled = 0; | pm->pm_pcpu_state[cpu].pps_stalled = 0; | ||||
/* Indicate that we desire this to run. */ | /* Indicate that we desire this to run. */ | ||||
pm->pm_pcpu_state[cpu].pps_cpustate = 1; | pm->pm_pcpu_state[cpu].pps_cpustate = 1; | ||||
/* Start the PMC. */ | /* Start the PMC. */ | ||||
pcd->pcd_start_pmc(cpu, adjri); | pcd->pcd_start_pmc(cpu, adjri); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (pm->pm_state != PMC_STATE_DELETED && pp != NULL && | ||||
*/ | */ | ||||
pp->pp_pmcs[ri].pp_pmcval += newvalue; | pp->pp_pmcs[ri].pp_pmcval += newvalue; | ||||
if (pp->pp_pmcs[ri].pp_pmcval > | if (pp->pp_pmcs[ri].pp_pmcval > | ||||
pm->pm_sc.pm_reloadcount) | pm->pm_sc.pm_reloadcount) | ||||
pp->pp_pmcs[ri].pp_pmcval -= | pp->pp_pmcs[ri].pp_pmcval -= | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} else if (mode == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | ||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | ||||
cpu, ri, tmp); | cpu, ri, tmp); | ||||
/* | /* | ||||
* For counting process-virtual PMCs, | * For counting process-virtual PMCs, | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | ||||
{ | { | ||||
int ri; | int ri; | ||||
pid_t pid; | pid_t pid; | ||||
char *fullpath, *freepath; | char *fullpath, *freepath; | ||||
const struct pmc *pm; | const struct pmc *pm; | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
const struct pmc_process *pp; | const struct pmc_process *pp; | ||||
struct proc *p; | |||||
bool pause_thread; | |||||
freepath = fullpath = NULL; | freepath = fullpath = NULL; | ||||
MPASS(!in_epoch()); | MPASS(!in_epoch()); | ||||
pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | ||||
pid = td->td_proc->p_pid; | pid = td->td_proc->p_pid; | ||||
epoch_enter_preempt(global_epoch_preempt); | epoch_enter_preempt(global_epoch_preempt); | ||||
/* Inform owners of all system-wide sampling PMCs. */ | /* Inform owners of all system-wide sampling PMCs. */ | ||||
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) { | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | goto done; | ||||
} | |||||
p = td->td_proc; | |||||
if ((p->p_flag & P_HWPMC) == 0) { | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | |||||
} | |||||
pause_thread = 0; | |||||
/* | /* | ||||
* Inform sampling PMC owners tracking this process. | * Inform sampling PMC owners tracking this process. | ||||
*/ | */ | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
markj: Use bool literals, "true"/"false". | |||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_in(pm->pm_owner, | pmclog_process_map_in(pm->pm_owner, | ||||
pid, pkm->pm_address, fullpath); | pid, pkm->pm_address, fullpath); | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pause_thread = 1; | |||||
} | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
if (pause_thread) { | |||||
PROC_LOCK(td->td_proc); | |||||
PROC_SLOCK(td->td_proc); | |||||
thread_suspend_switch(td, td->td_proc); | |||||
PROC_SUNLOCK(td->td_proc); | |||||
PROC_UNLOCK(td->td_proc); | |||||
} | |||||
done: | done: | ||||
Done Inline ActionsIsn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the thread stay stuck? ptrace(), for instance, will send SIGKILL to the target process if the tracing process dies. markj: Isn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the… | |||||
Done Inline ActionsYes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how to avoid this. br: Yes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how… | |||||
Done Inline ActionsWhy is it necessary to suspend all threads in the process? At this point we have not yet returned from mmap(), so other application threads should not be accessing the newly mapped region. markj: Why is it necessary to suspend all threads in the process? At this point we have not yet… | |||||
Done Inline ActionsIt is not necessary, so I changed to thread_suspend_one() br: It is not necessary, so I changed to thread_suspend_one() | |||||
if (freepath) | if (freepath) | ||||
free(freepath, M_TEMP); | free(freepath, M_TEMP); | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
} | } | ||||
/* | /* | ||||
* Log an munmap request. | * Log an munmap request. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 12 Lines | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_out(po, pid, pkm->pm_address, | pmclog_process_map_out(po, pid, pkm->pm_address, | ||||
pkm->pm_address + pkm->pm_size); | pkm->pm_address + pkm->pm_size); | ||||
epoch_exit_preempt(global_epoch_preempt); | epoch_exit_preempt(global_epoch_preempt); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | ||||
return; | return; | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_out(pm->pm_owner, pid, | pmclog_process_map_out(pm->pm_owner, pid, | ||||
pkm->pm_address, pkm->pm_address + pkm->pm_size); | pkm->pm_address, pkm->pm_address + pkm->pm_size); | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* Log mapping information about the kernel. | * Log mapping information about the kernel. | ||||
*/ | */ | ||||
static void | static void | ||||
pmc_log_kernel_mappings(struct pmc *pm) | pmc_log_kernel_mappings(struct pmc *pm) | ||||
{ | { | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
struct pmckern_map_in *km, *kmbase; | struct pmckern_map_in *km, *kmbase; | ||||
MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | ||||
KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), | KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST, | |||||
("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ||||
__LINE__, (void *) pm)); | __LINE__, (void *) pm)); | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 732 Lines • ▼ Show 20 Lines | pmc_find_process_descriptor(struct proc *p, uint32_t mode) | ||||
* cannot call malloc(9) once we hold a spin lock. | * cannot call malloc(9) once we hold a spin lock. | ||||
*/ | */ | ||||
if (mode & PMC_FLAG_ALLOCATE) | if (mode & PMC_FLAG_ALLOCATE) | ||||
ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ||||
sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | ||||
mtx_lock_spin(&pmc_processhash_mtx); | mtx_lock_spin(&pmc_processhash_mtx); | ||||
LIST_FOREACH(pp, pph, pp_next) | LIST_FOREACH(pp, pph, pp_next) | ||||
if (pp->pp_proc == p) | if (pp->pp_proc == p) | ||||
break; | break; | ||||
if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | ||||
LIST_REMOVE(pp, pp_next); | LIST_REMOVE(pp, pp_next); | ||||
if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | ||||
ppnew != NULL) { | ppnew != NULL) { | ||||
ppnew->pp_proc = p; | ppnew->pp_proc = p; | ||||
LIST_INIT(&ppnew->pp_tds); | LIST_INIT(&ppnew->pp_tds); | ||||
▲ Show 20 Lines • Show All 548 Lines • ▼ Show 20 Lines | pmc_start(struct pmc *pm) | ||||
if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | ||||
(po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | (po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | ||||
return (EDOOFUS); /* programming error */ | return (EDOOFUS); /* programming error */ | ||||
/* | /* | ||||
* If this is a sampling mode PMC, log mapping information for | * If this is a sampling mode PMC, log mapping information for | ||||
* the kernel modules that are currently loaded. | * the kernel modules that are currently loaded. | ||||
*/ | */ | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST) | |||||
pmc_log_kernel_mappings(pm); | pmc_log_kernel_mappings(pm); | ||||
if (PMC_IS_VIRTUAL_MODE(mode)) { | if (PMC_IS_VIRTUAL_MODE(mode)) { | ||||
/* | /* | ||||
* If a PMCATTACH has never been done on this PMC, | * If a PMCATTACH has never been done on this PMC, | ||||
* attach it to its owner process. | * attach it to its owner process. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 657 Lines • ▼ Show 20 Lines | case PMC_OP_PMCALLOCATE: | ||||
if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | ||||
break; | break; | ||||
caps = pa.pm_caps; | caps = pa.pm_caps; | ||||
mode = pa.pm_mode; | mode = pa.pm_mode; | ||||
cpu = pa.pm_cpu; | cpu = pa.pm_cpu; | ||||
if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC && | if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && | ||||
mode != PMC_MODE_TS && mode != PMC_MODE_TC) || | mode != PMC_MODE_SC && mode != PMC_MODE_TC && | ||||
(cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max())) { | mode != PMC_MODE_ST && mode != PMC_MODE_TT) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max()) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
/* | /* | ||||
* Virtual PMCs should only ask for a default CPU. | * Virtual PMCs should only ask for a default CPU. | ||||
* System mode PMCs need to specify a non-default CPU. | * System mode PMCs need to specify a non-default CPU. | ||||
*/ | */ | ||||
if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | ||||
(PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | (PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
▲ Show 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | case PMC_OP_PMCRELEASE: | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
pmc_release_pmc_descriptor(pm); | pmc_release_pmc_descriptor(pm); | ||||
pmc_maybe_remove_owner(po); | pmc_maybe_remove_owner(po); | ||||
pmc_destroy_pmc_descriptor(pm); | pmc_destroy_pmc_descriptor(pm); | ||||
} | } | ||||
break; | break; | ||||
case PMC_OP_LOG_KERNEL_MAP: | |||||
{ | |||||
struct pmc_op_simple sp; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &sp, sizeof(sp))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(sp.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST) | |||||
break; | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
pmc_log_kernel_mappings(pm); | |||||
} | |||||
break; | |||||
case PMC_OP_THREAD_UNSUSPEND: | |||||
{ | |||||
struct pmc_op_proc_unsuspend u; | |||||
struct proc *p; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &u, sizeof(u))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(u.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
/* lookup pid */ | |||||
if ((p = pfind(u.pm_pid)) == NULL) { | |||||
error = ESRCH; | |||||
break; | |||||
} | |||||
if ((p->p_flag & P_HWPMC) == 0) | |||||
break; | |||||
PROC_SLOCK(p); | |||||
thread_unsuspend(p); | |||||
PROC_SUNLOCK(p); | |||||
PROC_UNLOCK(p); | |||||
} | |||||
break; | |||||
case PMC_OP_TRACE_CONFIG: | |||||
{ | |||||
struct pmc_op_trace_config trc; | |||||
uint64_t *ranges; | |||||
struct pmc *pm; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
uint32_t nranges; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trc, sizeof(trc))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trc.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't proceed with PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trc.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
if (pcd->pcd_trace_config == NULL) | |||||
break; | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
ranges = trc.ranges; | |||||
nranges = trc.nranges; | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_trace_config)(cpu, adjri, | |||||
pm, ranges, nranges); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
} | |||||
break; | |||||
/* | /* | ||||
* Read a PMC trace buffer ptr. | |||||
*/ | |||||
case PMC_OP_TRACE_READ: | |||||
{ | |||||
struct pmc_op_trace_read trr; | |||||
struct pmc_op_trace_read *trr_ret; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
struct pmc *pm; | |||||
pmc_value_t cycle; | |||||
pmc_value_t offset; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trr, sizeof(trr))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trr.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't read a PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trr.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_read_trace)(cpu, adjri, | |||||
pm, &cycle, &offset); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
trr_ret = (struct pmc_op_trace_read *)arg; | |||||
if ((error = copyout(&cycle, &trr_ret->pm_cycle, | |||||
sizeof(trr.pm_cycle)))) | |||||
break; | |||||
if ((error = copyout(&offset, &trr_ret->pm_offset, | |||||
sizeof(trr.pm_offset)))) | |||||
break; | |||||
} | |||||
break; | |||||
/* | |||||
* Read and/or write a PMC. | * Read and/or write a PMC. | ||||
*/ | */ | ||||
case PMC_OP_PMCRW: | case PMC_OP_PMCRW: | ||||
{ | { | ||||
int adjri; | int adjri; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
uint32_t cpu, ri; | uint32_t cpu, ri; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | if (PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm))) { | ||||
/* move this thread to CPU 'cpu' */ | /* move this thread to CPU 'cpu' */ | ||||
pmc_save_cpu_binding(&pb); | pmc_save_cpu_binding(&pb); | ||||
pmc_select_cpu(cpu); | pmc_select_cpu(cpu); | ||||
critical_enter(); | critical_enter(); | ||||
/* save old value */ | /* save old value */ | ||||
if (prw.pm_flags & PMC_F_OLDVALUE) | if (prw.pm_flags & PMC_F_OLDVALUE) | ||||
if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | ||||
&oldvalue))) | &oldvalue))) | ||||
goto error; | goto error; | ||||
/* write out new value */ | /* write out new value */ | ||||
if (prw.pm_flags & PMC_F_NEWVALUE) | if (prw.pm_flags & PMC_F_NEWVALUE) | ||||
error = (*pcd->pcd_write_pmc)(cpu, adjri, | error = (*pcd->pcd_write_pmc)(cpu, adjri, | ||||
prw.pm_value); | prw.pm_value); | ||||
error: | error: | ||||
critical_exit(); | critical_exit(); | ||||
pmc_restore_cpu_binding(&pb); | pmc_restore_cpu_binding(&pb); | ||||
▲ Show 20 Lines • Show All 1,291 Lines • ▼ Show 20 Lines | for (n = 0; n < (int) md->pmd_nclass; n++) { | ||||
pcd->pcd_width, | pcd->pcd_width, | ||||
pcd->pcd_caps, | pcd->pcd_caps, | ||||
"\20" | "\20" | ||||
"\1INT\2USR\3SYS\4EDG\5THR" | "\1INT\2USR\3SYS\4EDG\5THR" | ||||
"\6REA\7WRI\10INV\11QUA\12PRC" | "\6REA\7WRI\10INV\11QUA\12PRC" | ||||
"\13TAG\14CSC"); | "\13TAG\14CSC"); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
error = pmc_vm_initialize(md); | |||||
Done Inline ActionsThis should come earlier. This case is only meant to be executed if initialization completes successfully, but the pmc_vm_initialize() call introduces a new error case. markj: This should come earlier. This case is only meant to be executed if initialization completes… | |||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* prepare to be unloaded */ | /* prepare to be unloaded */ | ||||
static void | static void | ||||
pmc_cleanup(void) | pmc_cleanup(void) | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (pmc_rowindex_to_classdep) { | if (pmc_rowindex_to_classdep) { | ||||
free(pmc_rowindex_to_classdep, M_PMC); | free(pmc_rowindex_to_classdep, M_PMC); | ||||
pmc_rowindex_to_classdep = NULL; | pmc_rowindex_to_classdep = NULL; | ||||
} | } | ||||
pmclog_shutdown(); | pmclog_shutdown(); | ||||
pmc_vm_finalize(); | |||||
counter_u64_free(pmc_stats.pm_intr_ignored); | counter_u64_free(pmc_stats.pm_intr_ignored); | ||||
counter_u64_free(pmc_stats.pm_intr_processed); | counter_u64_free(pmc_stats.pm_intr_processed); | ||||
counter_u64_free(pmc_stats.pm_intr_bufferfull); | counter_u64_free(pmc_stats.pm_intr_bufferfull); | ||||
counter_u64_free(pmc_stats.pm_syscalls); | counter_u64_free(pmc_stats.pm_syscalls); | ||||
counter_u64_free(pmc_stats.pm_syscall_errors); | counter_u64_free(pmc_stats.pm_syscall_errors); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests); | counter_u64_free(pmc_stats.pm_buffer_requests); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests_failed); | counter_u64_free(pmc_stats.pm_buffer_requests_failed); | ||||
counter_u64_free(pmc_stats.pm_log_sweeps); | counter_u64_free(pmc_stats.pm_log_sweeps); | ||||
Show All 40 Lines |
sys/boot/efi/Makefile
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include "hwpmc_soft.h" | #include "hwpmc_soft.h" | ||||
#include "hwpmc_vm.h" | |||||
#ifdef NUMA | #ifdef NUMA | ||||
#define NDOMAINS vm_ndomains | #define NDOMAINS vm_ndomains | ||||
#else | #else | ||||
#define NDOMAINS 1 | #define NDOMAINS 1 | ||||
#define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | ||||
#define free_domain(addr, type) free(addr, type) | #define free_domain(addr, type) free(addr, type) | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 1,356 Lines • ▼ Show 20 Lines | if (PMC_TO_MODE(pm) == PMC_MODE_TS) { | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
KASSERT(newvalue > 0 && newvalue <= | KASSERT(newvalue > 0 && newvalue <= | ||||
pm->pm_sc.pm_reloadcount, | pm->pm_sc.pm_reloadcount, | ||||
("[pmc,%d] pmcval outside of expected range cpu=%d " | ("[pmc,%d] pmcval outside of expected range cpu=%d " | ||||
"ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | "ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | ||||
cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | ||||
} else if (PMC_TO_MODE(pm) == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | ||||
("[pmc,%d] illegal mode=%d", __LINE__, | ("[pmc,%d] illegal mode=%d", __LINE__, | ||||
PMC_TO_MODE(pm))); | PMC_TO_MODE(pm))); | ||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | mtx_pool_lock_spin(pmc_mtxpool, pm); | ||||
newvalue = PMC_PCPU_SAVED(cpu, ri) = | newvalue = PMC_PCPU_SAVED(cpu, ri) = | ||||
pm->pm_gv.pm_savedvalue; | pm->pm_gv.pm_savedvalue; | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} | } | ||||
PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | ||||
pcd->pcd_write_pmc(cpu, adjri, newvalue); | pcd->pcd_write_pmc(cpu, adjri, newvalue); | ||||
/* If a sampling mode PMC, reset stalled state. */ | /* If a sampling mode PMC, reset stalled state. */ | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TS) | if (PMC_TO_MODE(pm) == PMC_MODE_TS || | ||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pm->pm_pcpu_state[cpu].pps_stalled = 0; | pm->pm_pcpu_state[cpu].pps_stalled = 0; | ||||
/* Indicate that we desire this to run. */ | /* Indicate that we desire this to run. */ | ||||
pm->pm_pcpu_state[cpu].pps_cpustate = 1; | pm->pm_pcpu_state[cpu].pps_cpustate = 1; | ||||
/* Start the PMC. */ | /* Start the PMC. */ | ||||
pcd->pcd_start_pmc(cpu, adjri); | pcd->pcd_start_pmc(cpu, adjri); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (pm->pm_state != PMC_STATE_DELETED && pp != NULL && | ||||
*/ | */ | ||||
pp->pp_pmcs[ri].pp_pmcval += newvalue; | pp->pp_pmcs[ri].pp_pmcval += newvalue; | ||||
if (pp->pp_pmcs[ri].pp_pmcval > | if (pp->pp_pmcs[ri].pp_pmcval > | ||||
pm->pm_sc.pm_reloadcount) | pm->pm_sc.pm_reloadcount) | ||||
pp->pp_pmcs[ri].pp_pmcval -= | pp->pp_pmcs[ri].pp_pmcval -= | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} else if (mode == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | ||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | ||||
cpu, ri, tmp); | cpu, ri, tmp); | ||||
/* | /* | ||||
* For counting process-virtual PMCs, | * For counting process-virtual PMCs, | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | ||||
{ | { | ||||
int ri; | int ri; | ||||
pid_t pid; | pid_t pid; | ||||
char *fullpath, *freepath; | char *fullpath, *freepath; | ||||
const struct pmc *pm; | const struct pmc *pm; | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
const struct pmc_process *pp; | const struct pmc_process *pp; | ||||
struct proc *p; | |||||
bool pause_thread; | |||||
freepath = fullpath = NULL; | freepath = fullpath = NULL; | ||||
MPASS(!in_epoch()); | MPASS(!in_epoch()); | ||||
pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | ||||
pid = td->td_proc->p_pid; | pid = td->td_proc->p_pid; | ||||
epoch_enter_preempt(global_epoch_preempt); | epoch_enter_preempt(global_epoch_preempt); | ||||
/* Inform owners of all system-wide sampling PMCs. */ | /* Inform owners of all system-wide sampling PMCs. */ | ||||
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) { | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | goto done; | ||||
} | |||||
p = td->td_proc; | |||||
if ((p->p_flag & P_HWPMC) == 0) { | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | |||||
} | |||||
pause_thread = 0; | |||||
/* | /* | ||||
* Inform sampling PMC owners tracking this process. | * Inform sampling PMC owners tracking this process. | ||||
*/ | */ | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
Done Inline ActionsUse bool literals, "true"/"false". markj: Use bool literals, "true"/"false". | |||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_in(pm->pm_owner, | pmclog_process_map_in(pm->pm_owner, | ||||
pid, pkm->pm_address, fullpath); | pid, pkm->pm_address, fullpath); | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pause_thread = 1; | |||||
} | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
if (pause_thread) { | |||||
PROC_LOCK(td->td_proc); | |||||
PROC_SLOCK(td->td_proc); | |||||
thread_suspend_switch(td, td->td_proc); | |||||
PROC_SUNLOCK(td->td_proc); | |||||
PROC_UNLOCK(td->td_proc); | |||||
} | |||||
done: | done: | ||||
Done Inline ActionsIsn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the thread stay stuck? ptrace(), for instance, will send SIGKILL to the target process if the tracing process dies. markj: Isn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the… | |||||
Done Inline ActionsYes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how to avoid this. br: Yes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how… | |||||
Done Inline ActionsWhy is it necessary to suspend all threads in the process? At this point we have not yet returned from mmap(), so other application threads should not be accessing the newly mapped region. markj: Why is it necessary to suspend all threads in the process? At this point we have not yet… | |||||
Done Inline ActionsIt is not necessary, so I changed to thread_suspend_one() br: It is not necessary, so I changed to thread_suspend_one() | |||||
if (freepath) | if (freepath) | ||||
free(freepath, M_TEMP); | free(freepath, M_TEMP); | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
} | } | ||||
/* | /* | ||||
* Log an munmap request. | * Log an munmap request. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 12 Lines | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_out(po, pid, pkm->pm_address, | pmclog_process_map_out(po, pid, pkm->pm_address, | ||||
pkm->pm_address + pkm->pm_size); | pkm->pm_address + pkm->pm_size); | ||||
epoch_exit_preempt(global_epoch_preempt); | epoch_exit_preempt(global_epoch_preempt); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | ||||
return; | return; | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_out(pm->pm_owner, pid, | pmclog_process_map_out(pm->pm_owner, pid, | ||||
pkm->pm_address, pkm->pm_address + pkm->pm_size); | pkm->pm_address, pkm->pm_address + pkm->pm_size); | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* Log mapping information about the kernel. | * Log mapping information about the kernel. | ||||
*/ | */ | ||||
static void | static void | ||||
pmc_log_kernel_mappings(struct pmc *pm) | pmc_log_kernel_mappings(struct pmc *pm) | ||||
{ | { | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
struct pmckern_map_in *km, *kmbase; | struct pmckern_map_in *km, *kmbase; | ||||
MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | ||||
KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), | KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST, | |||||
("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ||||
__LINE__, (void *) pm)); | __LINE__, (void *) pm)); | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 732 Lines • ▼ Show 20 Lines | pmc_find_process_descriptor(struct proc *p, uint32_t mode) | ||||
* cannot call malloc(9) once we hold a spin lock. | * cannot call malloc(9) once we hold a spin lock. | ||||
*/ | */ | ||||
if (mode & PMC_FLAG_ALLOCATE) | if (mode & PMC_FLAG_ALLOCATE) | ||||
ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ||||
sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | ||||
mtx_lock_spin(&pmc_processhash_mtx); | mtx_lock_spin(&pmc_processhash_mtx); | ||||
LIST_FOREACH(pp, pph, pp_next) | LIST_FOREACH(pp, pph, pp_next) | ||||
if (pp->pp_proc == p) | if (pp->pp_proc == p) | ||||
break; | break; | ||||
if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | ||||
LIST_REMOVE(pp, pp_next); | LIST_REMOVE(pp, pp_next); | ||||
if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | ||||
ppnew != NULL) { | ppnew != NULL) { | ||||
ppnew->pp_proc = p; | ppnew->pp_proc = p; | ||||
LIST_INIT(&ppnew->pp_tds); | LIST_INIT(&ppnew->pp_tds); | ||||
▲ Show 20 Lines • Show All 548 Lines • ▼ Show 20 Lines | pmc_start(struct pmc *pm) | ||||
if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | ||||
(po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | (po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | ||||
return (EDOOFUS); /* programming error */ | return (EDOOFUS); /* programming error */ | ||||
/* | /* | ||||
* If this is a sampling mode PMC, log mapping information for | * If this is a sampling mode PMC, log mapping information for | ||||
* the kernel modules that are currently loaded. | * the kernel modules that are currently loaded. | ||||
*/ | */ | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST) | |||||
pmc_log_kernel_mappings(pm); | pmc_log_kernel_mappings(pm); | ||||
if (PMC_IS_VIRTUAL_MODE(mode)) { | if (PMC_IS_VIRTUAL_MODE(mode)) { | ||||
/* | /* | ||||
* If a PMCATTACH has never been done on this PMC, | * If a PMCATTACH has never been done on this PMC, | ||||
* attach it to its owner process. | * attach it to its owner process. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 657 Lines • ▼ Show 20 Lines | case PMC_OP_PMCALLOCATE: | ||||
if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | ||||
break; | break; | ||||
caps = pa.pm_caps; | caps = pa.pm_caps; | ||||
mode = pa.pm_mode; | mode = pa.pm_mode; | ||||
cpu = pa.pm_cpu; | cpu = pa.pm_cpu; | ||||
if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC && | if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && | ||||
mode != PMC_MODE_TS && mode != PMC_MODE_TC) || | mode != PMC_MODE_SC && mode != PMC_MODE_TC && | ||||
(cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max())) { | mode != PMC_MODE_ST && mode != PMC_MODE_TT) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max()) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
/* | /* | ||||
* Virtual PMCs should only ask for a default CPU. | * Virtual PMCs should only ask for a default CPU. | ||||
* System mode PMCs need to specify a non-default CPU. | * System mode PMCs need to specify a non-default CPU. | ||||
*/ | */ | ||||
if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | ||||
(PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | (PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
▲ Show 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | case PMC_OP_PMCRELEASE: | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
pmc_release_pmc_descriptor(pm); | pmc_release_pmc_descriptor(pm); | ||||
pmc_maybe_remove_owner(po); | pmc_maybe_remove_owner(po); | ||||
pmc_destroy_pmc_descriptor(pm); | pmc_destroy_pmc_descriptor(pm); | ||||
} | } | ||||
break; | break; | ||||
case PMC_OP_LOG_KERNEL_MAP: | |||||
{ | |||||
struct pmc_op_simple sp; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &sp, sizeof(sp))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(sp.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST) | |||||
break; | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
pmc_log_kernel_mappings(pm); | |||||
} | |||||
break; | |||||
case PMC_OP_THREAD_UNSUSPEND: | |||||
{ | |||||
struct pmc_op_proc_unsuspend u; | |||||
struct proc *p; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &u, sizeof(u))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(u.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
/* lookup pid */ | |||||
if ((p = pfind(u.pm_pid)) == NULL) { | |||||
error = ESRCH; | |||||
break; | |||||
} | |||||
if ((p->p_flag & P_HWPMC) == 0) | |||||
break; | |||||
PROC_SLOCK(p); | |||||
thread_unsuspend(p); | |||||
PROC_SUNLOCK(p); | |||||
PROC_UNLOCK(p); | |||||
} | |||||
break; | |||||
case PMC_OP_TRACE_CONFIG: | |||||
{ | |||||
struct pmc_op_trace_config trc; | |||||
uint64_t *ranges; | |||||
struct pmc *pm; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
uint32_t nranges; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trc, sizeof(trc))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trc.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't proceed with PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trc.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
if (pcd->pcd_trace_config == NULL) | |||||
break; | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
ranges = trc.ranges; | |||||
nranges = trc.nranges; | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_trace_config)(cpu, adjri, | |||||
pm, ranges, nranges); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
} | |||||
break; | |||||
/* | /* | ||||
* Read a PMC trace buffer ptr. | |||||
*/ | |||||
case PMC_OP_TRACE_READ: | |||||
{ | |||||
struct pmc_op_trace_read trr; | |||||
struct pmc_op_trace_read *trr_ret; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
struct pmc *pm; | |||||
pmc_value_t cycle; | |||||
pmc_value_t offset; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trr, sizeof(trr))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trr.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't read a PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trr.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_read_trace)(cpu, adjri, | |||||
pm, &cycle, &offset); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
trr_ret = (struct pmc_op_trace_read *)arg; | |||||
if ((error = copyout(&cycle, &trr_ret->pm_cycle, | |||||
sizeof(trr.pm_cycle)))) | |||||
break; | |||||
if ((error = copyout(&offset, &trr_ret->pm_offset, | |||||
sizeof(trr.pm_offset)))) | |||||
break; | |||||
} | |||||
break; | |||||
/* | |||||
* Read and/or write a PMC. | * Read and/or write a PMC. | ||||
*/ | */ | ||||
case PMC_OP_PMCRW: | case PMC_OP_PMCRW: | ||||
{ | { | ||||
int adjri; | int adjri; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
uint32_t cpu, ri; | uint32_t cpu, ri; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | if (PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm))) { | ||||
/* move this thread to CPU 'cpu' */ | /* move this thread to CPU 'cpu' */ | ||||
pmc_save_cpu_binding(&pb); | pmc_save_cpu_binding(&pb); | ||||
pmc_select_cpu(cpu); | pmc_select_cpu(cpu); | ||||
critical_enter(); | critical_enter(); | ||||
/* save old value */ | /* save old value */ | ||||
if (prw.pm_flags & PMC_F_OLDVALUE) | if (prw.pm_flags & PMC_F_OLDVALUE) | ||||
if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | ||||
&oldvalue))) | &oldvalue))) | ||||
goto error; | goto error; | ||||
/* write out new value */ | /* write out new value */ | ||||
if (prw.pm_flags & PMC_F_NEWVALUE) | if (prw.pm_flags & PMC_F_NEWVALUE) | ||||
error = (*pcd->pcd_write_pmc)(cpu, adjri, | error = (*pcd->pcd_write_pmc)(cpu, adjri, | ||||
prw.pm_value); | prw.pm_value); | ||||
error: | error: | ||||
critical_exit(); | critical_exit(); | ||||
pmc_restore_cpu_binding(&pb); | pmc_restore_cpu_binding(&pb); | ||||
▲ Show 20 Lines • Show All 1,291 Lines • ▼ Show 20 Lines | for (n = 0; n < (int) md->pmd_nclass; n++) { | ||||
pcd->pcd_width, | pcd->pcd_width, | ||||
pcd->pcd_caps, | pcd->pcd_caps, | ||||
"\20" | "\20" | ||||
"\1INT\2USR\3SYS\4EDG\5THR" | "\1INT\2USR\3SYS\4EDG\5THR" | ||||
"\6REA\7WRI\10INV\11QUA\12PRC" | "\6REA\7WRI\10INV\11QUA\12PRC" | ||||
"\13TAG\14CSC"); | "\13TAG\14CSC"); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
error = pmc_vm_initialize(md); | |||||
Done Inline ActionsThis should come earlier. This case is only meant to be executed if initialization completes successfully, but the pmc_vm_initialize() call introduces a new error case. markj: This should come earlier. This case is only meant to be executed if initialization completes… | |||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* prepare to be unloaded */ | /* prepare to be unloaded */ | ||||
static void | static void | ||||
pmc_cleanup(void) | pmc_cleanup(void) | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (pmc_rowindex_to_classdep) { | if (pmc_rowindex_to_classdep) { | ||||
free(pmc_rowindex_to_classdep, M_PMC); | free(pmc_rowindex_to_classdep, M_PMC); | ||||
pmc_rowindex_to_classdep = NULL; | pmc_rowindex_to_classdep = NULL; | ||||
} | } | ||||
pmclog_shutdown(); | pmclog_shutdown(); | ||||
pmc_vm_finalize(); | |||||
counter_u64_free(pmc_stats.pm_intr_ignored); | counter_u64_free(pmc_stats.pm_intr_ignored); | ||||
counter_u64_free(pmc_stats.pm_intr_processed); | counter_u64_free(pmc_stats.pm_intr_processed); | ||||
counter_u64_free(pmc_stats.pm_intr_bufferfull); | counter_u64_free(pmc_stats.pm_intr_bufferfull); | ||||
counter_u64_free(pmc_stats.pm_syscalls); | counter_u64_free(pmc_stats.pm_syscalls); | ||||
counter_u64_free(pmc_stats.pm_syscall_errors); | counter_u64_free(pmc_stats.pm_syscall_errors); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests); | counter_u64_free(pmc_stats.pm_buffer_requests); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests_failed); | counter_u64_free(pmc_stats.pm_buffer_requests_failed); | ||||
counter_u64_free(pmc_stats.pm_log_sweeps); | counter_u64_free(pmc_stats.pm_log_sweeps); | ||||
Show All 40 Lines |
sys/boot/efi/boot1/Makefile
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include "hwpmc_soft.h" | #include "hwpmc_soft.h" | ||||
#include "hwpmc_vm.h" | |||||
#ifdef NUMA | #ifdef NUMA | ||||
#define NDOMAINS vm_ndomains | #define NDOMAINS vm_ndomains | ||||
#else | #else | ||||
#define NDOMAINS 1 | #define NDOMAINS 1 | ||||
#define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | ||||
#define free_domain(addr, type) free(addr, type) | #define free_domain(addr, type) free(addr, type) | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 1,356 Lines • ▼ Show 20 Lines | if (PMC_TO_MODE(pm) == PMC_MODE_TS) { | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
KASSERT(newvalue > 0 && newvalue <= | KASSERT(newvalue > 0 && newvalue <= | ||||
pm->pm_sc.pm_reloadcount, | pm->pm_sc.pm_reloadcount, | ||||
("[pmc,%d] pmcval outside of expected range cpu=%d " | ("[pmc,%d] pmcval outside of expected range cpu=%d " | ||||
"ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | "ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | ||||
cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | ||||
} else if (PMC_TO_MODE(pm) == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | ||||
("[pmc,%d] illegal mode=%d", __LINE__, | ("[pmc,%d] illegal mode=%d", __LINE__, | ||||
PMC_TO_MODE(pm))); | PMC_TO_MODE(pm))); | ||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | mtx_pool_lock_spin(pmc_mtxpool, pm); | ||||
newvalue = PMC_PCPU_SAVED(cpu, ri) = | newvalue = PMC_PCPU_SAVED(cpu, ri) = | ||||
pm->pm_gv.pm_savedvalue; | pm->pm_gv.pm_savedvalue; | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} | } | ||||
PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | ||||
pcd->pcd_write_pmc(cpu, adjri, newvalue); | pcd->pcd_write_pmc(cpu, adjri, newvalue); | ||||
/* If a sampling mode PMC, reset stalled state. */ | /* If a sampling mode PMC, reset stalled state. */ | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TS) | if (PMC_TO_MODE(pm) == PMC_MODE_TS || | ||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pm->pm_pcpu_state[cpu].pps_stalled = 0; | pm->pm_pcpu_state[cpu].pps_stalled = 0; | ||||
/* Indicate that we desire this to run. */ | /* Indicate that we desire this to run. */ | ||||
pm->pm_pcpu_state[cpu].pps_cpustate = 1; | pm->pm_pcpu_state[cpu].pps_cpustate = 1; | ||||
/* Start the PMC. */ | /* Start the PMC. */ | ||||
pcd->pcd_start_pmc(cpu, adjri); | pcd->pcd_start_pmc(cpu, adjri); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (pm->pm_state != PMC_STATE_DELETED && pp != NULL && | ||||
*/ | */ | ||||
pp->pp_pmcs[ri].pp_pmcval += newvalue; | pp->pp_pmcs[ri].pp_pmcval += newvalue; | ||||
if (pp->pp_pmcs[ri].pp_pmcval > | if (pp->pp_pmcs[ri].pp_pmcval > | ||||
pm->pm_sc.pm_reloadcount) | pm->pm_sc.pm_reloadcount) | ||||
pp->pp_pmcs[ri].pp_pmcval -= | pp->pp_pmcs[ri].pp_pmcval -= | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} else if (mode == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | ||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | ||||
cpu, ri, tmp); | cpu, ri, tmp); | ||||
/* | /* | ||||
* For counting process-virtual PMCs, | * For counting process-virtual PMCs, | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | ||||
{ | { | ||||
int ri; | int ri; | ||||
pid_t pid; | pid_t pid; | ||||
char *fullpath, *freepath; | char *fullpath, *freepath; | ||||
const struct pmc *pm; | const struct pmc *pm; | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
const struct pmc_process *pp; | const struct pmc_process *pp; | ||||
struct proc *p; | |||||
bool pause_thread; | |||||
freepath = fullpath = NULL; | freepath = fullpath = NULL; | ||||
MPASS(!in_epoch()); | MPASS(!in_epoch()); | ||||
pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | ||||
pid = td->td_proc->p_pid; | pid = td->td_proc->p_pid; | ||||
epoch_enter_preempt(global_epoch_preempt); | epoch_enter_preempt(global_epoch_preempt); | ||||
/* Inform owners of all system-wide sampling PMCs. */ | /* Inform owners of all system-wide sampling PMCs. */ | ||||
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) { | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | goto done; | ||||
} | |||||
p = td->td_proc; | |||||
if ((p->p_flag & P_HWPMC) == 0) { | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | |||||
} | |||||
pause_thread = 0; | |||||
/* | /* | ||||
* Inform sampling PMC owners tracking this process. | * Inform sampling PMC owners tracking this process. | ||||
*/ | */ | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
Done Inline ActionsUse bool literals, "true"/"false". markj: Use bool literals, "true"/"false". | |||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_in(pm->pm_owner, | pmclog_process_map_in(pm->pm_owner, | ||||
pid, pkm->pm_address, fullpath); | pid, pkm->pm_address, fullpath); | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pause_thread = 1; | |||||
} | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
if (pause_thread) { | |||||
PROC_LOCK(td->td_proc); | |||||
PROC_SLOCK(td->td_proc); | |||||
thread_suspend_switch(td, td->td_proc); | |||||
PROC_SUNLOCK(td->td_proc); | |||||
PROC_UNLOCK(td->td_proc); | |||||
} | |||||
done: | done: | ||||
Done Inline ActionsIsn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the thread stay stuck? ptrace(), for instance, will send SIGKILL to the target process if the tracing process dies. markj: Isn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the… | |||||
Done Inline ActionsYes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how to avoid this. br: Yes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how… | |||||
Done Inline ActionsWhy is it necessary to suspend all threads in the process? At this point we have not yet returned from mmap(), so other application threads should not be accessing the newly mapped region. markj: Why is it necessary to suspend all threads in the process? At this point we have not yet… | |||||
Done Inline ActionsIt is not necessary, so I changed to thread_suspend_one() br: It is not necessary, so I changed to thread_suspend_one() | |||||
if (freepath) | if (freepath) | ||||
free(freepath, M_TEMP); | free(freepath, M_TEMP); | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
} | } | ||||
/* | /* | ||||
* Log an munmap request. | * Log an munmap request. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 12 Lines | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_out(po, pid, pkm->pm_address, | pmclog_process_map_out(po, pid, pkm->pm_address, | ||||
pkm->pm_address + pkm->pm_size); | pkm->pm_address + pkm->pm_size); | ||||
epoch_exit_preempt(global_epoch_preempt); | epoch_exit_preempt(global_epoch_preempt); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | ||||
return; | return; | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_out(pm->pm_owner, pid, | pmclog_process_map_out(pm->pm_owner, pid, | ||||
pkm->pm_address, pkm->pm_address + pkm->pm_size); | pkm->pm_address, pkm->pm_address + pkm->pm_size); | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* Log mapping information about the kernel. | * Log mapping information about the kernel. | ||||
*/ | */ | ||||
static void | static void | ||||
pmc_log_kernel_mappings(struct pmc *pm) | pmc_log_kernel_mappings(struct pmc *pm) | ||||
{ | { | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
struct pmckern_map_in *km, *kmbase; | struct pmckern_map_in *km, *kmbase; | ||||
MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | ||||
KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), | KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST, | |||||
("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ||||
__LINE__, (void *) pm)); | __LINE__, (void *) pm)); | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 732 Lines • ▼ Show 20 Lines | pmc_find_process_descriptor(struct proc *p, uint32_t mode) | ||||
* cannot call malloc(9) once we hold a spin lock. | * cannot call malloc(9) once we hold a spin lock. | ||||
*/ | */ | ||||
if (mode & PMC_FLAG_ALLOCATE) | if (mode & PMC_FLAG_ALLOCATE) | ||||
ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ||||
sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | ||||
mtx_lock_spin(&pmc_processhash_mtx); | mtx_lock_spin(&pmc_processhash_mtx); | ||||
LIST_FOREACH(pp, pph, pp_next) | LIST_FOREACH(pp, pph, pp_next) | ||||
if (pp->pp_proc == p) | if (pp->pp_proc == p) | ||||
break; | break; | ||||
if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | ||||
LIST_REMOVE(pp, pp_next); | LIST_REMOVE(pp, pp_next); | ||||
if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | ||||
ppnew != NULL) { | ppnew != NULL) { | ||||
ppnew->pp_proc = p; | ppnew->pp_proc = p; | ||||
LIST_INIT(&ppnew->pp_tds); | LIST_INIT(&ppnew->pp_tds); | ||||
▲ Show 20 Lines • Show All 548 Lines • ▼ Show 20 Lines | pmc_start(struct pmc *pm) | ||||
if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | ||||
(po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | (po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | ||||
return (EDOOFUS); /* programming error */ | return (EDOOFUS); /* programming error */ | ||||
/* | /* | ||||
* If this is a sampling mode PMC, log mapping information for | * If this is a sampling mode PMC, log mapping information for | ||||
* the kernel modules that are currently loaded. | * the kernel modules that are currently loaded. | ||||
*/ | */ | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST) | |||||
pmc_log_kernel_mappings(pm); | pmc_log_kernel_mappings(pm); | ||||
if (PMC_IS_VIRTUAL_MODE(mode)) { | if (PMC_IS_VIRTUAL_MODE(mode)) { | ||||
/* | /* | ||||
* If a PMCATTACH has never been done on this PMC, | * If a PMCATTACH has never been done on this PMC, | ||||
* attach it to its owner process. | * attach it to its owner process. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 657 Lines • ▼ Show 20 Lines | case PMC_OP_PMCALLOCATE: | ||||
if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | ||||
break; | break; | ||||
caps = pa.pm_caps; | caps = pa.pm_caps; | ||||
mode = pa.pm_mode; | mode = pa.pm_mode; | ||||
cpu = pa.pm_cpu; | cpu = pa.pm_cpu; | ||||
if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC && | if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && | ||||
mode != PMC_MODE_TS && mode != PMC_MODE_TC) || | mode != PMC_MODE_SC && mode != PMC_MODE_TC && | ||||
(cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max())) { | mode != PMC_MODE_ST && mode != PMC_MODE_TT) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max()) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
/* | /* | ||||
* Virtual PMCs should only ask for a default CPU. | * Virtual PMCs should only ask for a default CPU. | ||||
* System mode PMCs need to specify a non-default CPU. | * System mode PMCs need to specify a non-default CPU. | ||||
*/ | */ | ||||
if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | ||||
(PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | (PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
▲ Show 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | case PMC_OP_PMCRELEASE: | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
pmc_release_pmc_descriptor(pm); | pmc_release_pmc_descriptor(pm); | ||||
pmc_maybe_remove_owner(po); | pmc_maybe_remove_owner(po); | ||||
pmc_destroy_pmc_descriptor(pm); | pmc_destroy_pmc_descriptor(pm); | ||||
} | } | ||||
break; | break; | ||||
case PMC_OP_LOG_KERNEL_MAP: | |||||
{ | |||||
struct pmc_op_simple sp; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &sp, sizeof(sp))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(sp.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST) | |||||
break; | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
pmc_log_kernel_mappings(pm); | |||||
} | |||||
break; | |||||
case PMC_OP_THREAD_UNSUSPEND: | |||||
{ | |||||
struct pmc_op_proc_unsuspend u; | |||||
struct proc *p; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &u, sizeof(u))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(u.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
/* lookup pid */ | |||||
if ((p = pfind(u.pm_pid)) == NULL) { | |||||
error = ESRCH; | |||||
break; | |||||
} | |||||
if ((p->p_flag & P_HWPMC) == 0) | |||||
break; | |||||
PROC_SLOCK(p); | |||||
thread_unsuspend(p); | |||||
PROC_SUNLOCK(p); | |||||
PROC_UNLOCK(p); | |||||
} | |||||
break; | |||||
case PMC_OP_TRACE_CONFIG: | |||||
{ | |||||
struct pmc_op_trace_config trc; | |||||
uint64_t *ranges; | |||||
struct pmc *pm; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
uint32_t nranges; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trc, sizeof(trc))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trc.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't proceed with PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trc.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
if (pcd->pcd_trace_config == NULL) | |||||
break; | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
ranges = trc.ranges; | |||||
nranges = trc.nranges; | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_trace_config)(cpu, adjri, | |||||
pm, ranges, nranges); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
} | |||||
break; | |||||
/* | /* | ||||
* Read a PMC trace buffer ptr. | |||||
*/ | |||||
case PMC_OP_TRACE_READ: | |||||
{ | |||||
struct pmc_op_trace_read trr; | |||||
struct pmc_op_trace_read *trr_ret; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
struct pmc *pm; | |||||
pmc_value_t cycle; | |||||
pmc_value_t offset; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trr, sizeof(trr))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trr.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't read a PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trr.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_read_trace)(cpu, adjri, | |||||
pm, &cycle, &offset); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
trr_ret = (struct pmc_op_trace_read *)arg; | |||||
if ((error = copyout(&cycle, &trr_ret->pm_cycle, | |||||
sizeof(trr.pm_cycle)))) | |||||
break; | |||||
if ((error = copyout(&offset, &trr_ret->pm_offset, | |||||
sizeof(trr.pm_offset)))) | |||||
break; | |||||
} | |||||
break; | |||||
/* | |||||
* Read and/or write a PMC. | * Read and/or write a PMC. | ||||
*/ | */ | ||||
case PMC_OP_PMCRW: | case PMC_OP_PMCRW: | ||||
{ | { | ||||
int adjri; | int adjri; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
uint32_t cpu, ri; | uint32_t cpu, ri; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | if (PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm))) { | ||||
/* move this thread to CPU 'cpu' */ | /* move this thread to CPU 'cpu' */ | ||||
pmc_save_cpu_binding(&pb); | pmc_save_cpu_binding(&pb); | ||||
pmc_select_cpu(cpu); | pmc_select_cpu(cpu); | ||||
critical_enter(); | critical_enter(); | ||||
/* save old value */ | /* save old value */ | ||||
if (prw.pm_flags & PMC_F_OLDVALUE) | if (prw.pm_flags & PMC_F_OLDVALUE) | ||||
if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | ||||
&oldvalue))) | &oldvalue))) | ||||
goto error; | goto error; | ||||
/* write out new value */ | /* write out new value */ | ||||
if (prw.pm_flags & PMC_F_NEWVALUE) | if (prw.pm_flags & PMC_F_NEWVALUE) | ||||
error = (*pcd->pcd_write_pmc)(cpu, adjri, | error = (*pcd->pcd_write_pmc)(cpu, adjri, | ||||
prw.pm_value); | prw.pm_value); | ||||
error: | error: | ||||
critical_exit(); | critical_exit(); | ||||
pmc_restore_cpu_binding(&pb); | pmc_restore_cpu_binding(&pb); | ||||
▲ Show 20 Lines • Show All 1,291 Lines • ▼ Show 20 Lines | for (n = 0; n < (int) md->pmd_nclass; n++) { | ||||
pcd->pcd_width, | pcd->pcd_width, | ||||
pcd->pcd_caps, | pcd->pcd_caps, | ||||
"\20" | "\20" | ||||
"\1INT\2USR\3SYS\4EDG\5THR" | "\1INT\2USR\3SYS\4EDG\5THR" | ||||
"\6REA\7WRI\10INV\11QUA\12PRC" | "\6REA\7WRI\10INV\11QUA\12PRC" | ||||
"\13TAG\14CSC"); | "\13TAG\14CSC"); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
error = pmc_vm_initialize(md); | |||||
Done Inline ActionsThis should come earlier. This case is only meant to be executed if initialization completes successfully, but the pmc_vm_initialize() call introduces a new error case. markj: This should come earlier. This case is only meant to be executed if initialization completes… | |||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* prepare to be unloaded */ | /* prepare to be unloaded */ | ||||
static void | static void | ||||
pmc_cleanup(void) | pmc_cleanup(void) | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (pmc_rowindex_to_classdep) { | if (pmc_rowindex_to_classdep) { | ||||
free(pmc_rowindex_to_classdep, M_PMC); | free(pmc_rowindex_to_classdep, M_PMC); | ||||
pmc_rowindex_to_classdep = NULL; | pmc_rowindex_to_classdep = NULL; | ||||
} | } | ||||
pmclog_shutdown(); | pmclog_shutdown(); | ||||
pmc_vm_finalize(); | |||||
counter_u64_free(pmc_stats.pm_intr_ignored); | counter_u64_free(pmc_stats.pm_intr_ignored); | ||||
counter_u64_free(pmc_stats.pm_intr_processed); | counter_u64_free(pmc_stats.pm_intr_processed); | ||||
counter_u64_free(pmc_stats.pm_intr_bufferfull); | counter_u64_free(pmc_stats.pm_intr_bufferfull); | ||||
counter_u64_free(pmc_stats.pm_syscalls); | counter_u64_free(pmc_stats.pm_syscalls); | ||||
counter_u64_free(pmc_stats.pm_syscall_errors); | counter_u64_free(pmc_stats.pm_syscall_errors); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests); | counter_u64_free(pmc_stats.pm_buffer_requests); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests_failed); | counter_u64_free(pmc_stats.pm_buffer_requests_failed); | ||||
counter_u64_free(pmc_stats.pm_log_sweeps); | counter_u64_free(pmc_stats.pm_log_sweeps); | ||||
Show All 40 Lines |
sys/boot/efi/boot1/boot1.c
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include "hwpmc_soft.h" | #include "hwpmc_soft.h" | ||||
#include "hwpmc_vm.h" | |||||
#ifdef NUMA | #ifdef NUMA | ||||
#define NDOMAINS vm_ndomains | #define NDOMAINS vm_ndomains | ||||
#else | #else | ||||
#define NDOMAINS 1 | #define NDOMAINS 1 | ||||
#define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) | ||||
#define free_domain(addr, type) free(addr, type) | #define free_domain(addr, type) free(addr, type) | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 1,356 Lines • ▼ Show 20 Lines | if (PMC_TO_MODE(pm) == PMC_MODE_TS) { | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
KASSERT(newvalue > 0 && newvalue <= | KASSERT(newvalue > 0 && newvalue <= | ||||
pm->pm_sc.pm_reloadcount, | pm->pm_sc.pm_reloadcount, | ||||
("[pmc,%d] pmcval outside of expected range cpu=%d " | ("[pmc,%d] pmcval outside of expected range cpu=%d " | ||||
"ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | "ri=%d pmcval=%jx pm_reloadcount=%jx", __LINE__, | ||||
cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | cpu, ri, newvalue, pm->pm_sc.pm_reloadcount)); | ||||
} else if (PMC_TO_MODE(pm) == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC, | ||||
("[pmc,%d] illegal mode=%d", __LINE__, | ("[pmc,%d] illegal mode=%d", __LINE__, | ||||
PMC_TO_MODE(pm))); | PMC_TO_MODE(pm))); | ||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | mtx_pool_lock_spin(pmc_mtxpool, pm); | ||||
newvalue = PMC_PCPU_SAVED(cpu, ri) = | newvalue = PMC_PCPU_SAVED(cpu, ri) = | ||||
pm->pm_gv.pm_savedvalue; | pm->pm_gv.pm_savedvalue; | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} | } | ||||
PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | PMCDBG3(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue); | ||||
pcd->pcd_write_pmc(cpu, adjri, newvalue); | pcd->pcd_write_pmc(cpu, adjri, newvalue); | ||||
/* If a sampling mode PMC, reset stalled state. */ | /* If a sampling mode PMC, reset stalled state. */ | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TS) | if (PMC_TO_MODE(pm) == PMC_MODE_TS || | ||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pm->pm_pcpu_state[cpu].pps_stalled = 0; | pm->pm_pcpu_state[cpu].pps_stalled = 0; | ||||
/* Indicate that we desire this to run. */ | /* Indicate that we desire this to run. */ | ||||
pm->pm_pcpu_state[cpu].pps_cpustate = 1; | pm->pm_pcpu_state[cpu].pps_cpustate = 1; | ||||
/* Start the PMC. */ | /* Start the PMC. */ | ||||
pcd->pcd_start_pmc(cpu, adjri); | pcd->pcd_start_pmc(cpu, adjri); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (pm->pm_state != PMC_STATE_DELETED && pp != NULL && | ||||
*/ | */ | ||||
pp->pp_pmcs[ri].pp_pmcval += newvalue; | pp->pp_pmcs[ri].pp_pmcval += newvalue; | ||||
if (pp->pp_pmcs[ri].pp_pmcval > | if (pp->pp_pmcs[ri].pp_pmcval > | ||||
pm->pm_sc.pm_reloadcount) | pm->pm_sc.pm_reloadcount) | ||||
pp->pp_pmcs[ri].pp_pmcval -= | pp->pp_pmcs[ri].pp_pmcval -= | ||||
pm->pm_sc.pm_reloadcount; | pm->pm_sc.pm_reloadcount; | ||||
} | } | ||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | mtx_pool_unlock_spin(pmc_mtxpool, pm); | ||||
} else if (mode == PMC_MODE_TT) { | |||||
/* Nothing */ | |||||
} else { | } else { | ||||
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | tmp = newvalue - PMC_PCPU_SAVED(cpu,ri); | ||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)", | ||||
cpu, ri, tmp); | cpu, ri, tmp); | ||||
/* | /* | ||||
* For counting process-virtual PMCs, | * For counting process-virtual PMCs, | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm) | ||||
{ | { | ||||
int ri; | int ri; | ||||
pid_t pid; | pid_t pid; | ||||
char *fullpath, *freepath; | char *fullpath, *freepath; | ||||
const struct pmc *pm; | const struct pmc *pm; | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
const struct pmc_process *pp; | const struct pmc_process *pp; | ||||
struct proc *p; | |||||
bool pause_thread; | |||||
freepath = fullpath = NULL; | freepath = fullpath = NULL; | ||||
MPASS(!in_epoch()); | MPASS(!in_epoch()); | ||||
pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath); | ||||
pid = td->td_proc->p_pid; | pid = td->td_proc->p_pid; | ||||
epoch_enter_preempt(global_epoch_preempt); | epoch_enter_preempt(global_epoch_preempt); | ||||
/* Inform owners of all system-wide sampling PMCs. */ | /* Inform owners of all system-wide sampling PMCs. */ | ||||
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | pmclog_process_map_in(po, pid, pkm->pm_address, fullpath); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) { | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | goto done; | ||||
} | |||||
p = td->td_proc; | |||||
if ((p->p_flag & P_HWPMC) == 0) { | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
goto done; | |||||
} | |||||
pause_thread = 0; | |||||
/* | /* | ||||
* Inform sampling PMC owners tracking this process. | * Inform sampling PMC owners tracking this process. | ||||
*/ | */ | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
Done Inline ActionsUse bool literals, "true"/"false". markj: Use bool literals, "true"/"false". | |||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_in(pm->pm_owner, | pmclog_process_map_in(pm->pm_owner, | ||||
pid, pkm->pm_address, fullpath); | pid, pkm->pm_address, fullpath); | ||||
if (PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pause_thread = 1; | |||||
} | |||||
epoch_exit_preempt(global_epoch_preempt); | |||||
if (pause_thread) { | |||||
PROC_LOCK(td->td_proc); | |||||
PROC_SLOCK(td->td_proc); | |||||
thread_suspend_switch(td, td->td_proc); | |||||
PROC_SUNLOCK(td->td_proc); | |||||
PROC_UNLOCK(td->td_proc); | |||||
} | |||||
done: | done: | ||||
Done Inline ActionsIsn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the thread stay stuck? ptrace(), for instance, will send SIGKILL to the target process if the tracing process dies. markj: Isn't this somewhat fragile? If pmctrace crashes before unsuspending the thread, won't the… | |||||
Done Inline ActionsYes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how to avoid this. br: Yes it is fragile. Any crash of pmctrace leaves the tracing pid on a pause. I am not sure how… | |||||
Done Inline ActionsWhy is it necessary to suspend all threads in the process? At this point we have not yet returned from mmap(), so other application threads should not be accessing the newly mapped region. markj: Why is it necessary to suspend all threads in the process? At this point we have not yet… | |||||
Done Inline ActionsIt is not necessary, so I changed to thread_suspend_one() br: It is not necessary, so I changed to thread_suspend_one() | |||||
if (freepath) | if (freepath) | ||||
free(freepath, M_TEMP); | free(freepath, M_TEMP); | ||||
epoch_exit_preempt(global_epoch_preempt); | |||||
} | } | ||||
/* | /* | ||||
* Log an munmap request. | * Log an munmap request. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 12 Lines | CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) | ||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE) | if (po->po_flags & PMC_PO_OWNS_LOGFILE) | ||||
pmclog_process_map_out(po, pid, pkm->pm_address, | pmclog_process_map_out(po, pid, pkm->pm_address, | ||||
pkm->pm_address + pkm->pm_size); | pkm->pm_address + pkm->pm_size); | ||||
epoch_exit_preempt(global_epoch_preempt); | epoch_exit_preempt(global_epoch_preempt); | ||||
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) | ||||
return; | return; | ||||
for (ri = 0; ri < md->pmd_npmc; ri++) | for (ri = 0; ri < md->pmd_npmc; ri++) { | ||||
if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL && | if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL) | ||||
PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | continue; | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | |||||
PMC_TO_MODE(pm) == PMC_MODE_TT) | |||||
pmclog_process_map_out(pm->pm_owner, pid, | pmclog_process_map_out(pm->pm_owner, pid, | ||||
pkm->pm_address, pkm->pm_address + pkm->pm_size); | pkm->pm_address, pkm->pm_address + pkm->pm_size); | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* Log mapping information about the kernel. | * Log mapping information about the kernel. | ||||
*/ | */ | ||||
static void | static void | ||||
pmc_log_kernel_mappings(struct pmc *pm) | pmc_log_kernel_mappings(struct pmc *pm) | ||||
{ | { | ||||
struct pmc_owner *po; | struct pmc_owner *po; | ||||
struct pmckern_map_in *km, *kmbase; | struct pmckern_map_in *km, *kmbase; | ||||
MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | MPASS(in_epoch() || sx_xlocked(&pmc_sx)); | ||||
KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), | KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST, | |||||
("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ("[pmc,%d] non-sampling PMC (%p) desires mapping information", | ||||
__LINE__, (void *) pm)); | __LINE__, (void *) pm)); | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | if (po->po_flags & PMC_PO_INITIAL_MAPPINGS_DONE) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 732 Lines • ▼ Show 20 Lines | pmc_find_process_descriptor(struct proc *p, uint32_t mode) | ||||
* cannot call malloc(9) once we hold a spin lock. | * cannot call malloc(9) once we hold a spin lock. | ||||
*/ | */ | ||||
if (mode & PMC_FLAG_ALLOCATE) | if (mode & PMC_FLAG_ALLOCATE) | ||||
ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc * | ||||
sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO); | ||||
mtx_lock_spin(&pmc_processhash_mtx); | mtx_lock_spin(&pmc_processhash_mtx); | ||||
LIST_FOREACH(pp, pph, pp_next) | LIST_FOREACH(pp, pph, pp_next) | ||||
if (pp->pp_proc == p) | if (pp->pp_proc == p) | ||||
break; | break; | ||||
if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | if ((mode & PMC_FLAG_REMOVE) && pp != NULL) | ||||
LIST_REMOVE(pp, pp_next); | LIST_REMOVE(pp, pp_next); | ||||
if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | if ((mode & PMC_FLAG_ALLOCATE) && pp == NULL && | ||||
ppnew != NULL) { | ppnew != NULL) { | ||||
ppnew->pp_proc = p; | ppnew->pp_proc = p; | ||||
LIST_INIT(&ppnew->pp_tds); | LIST_INIT(&ppnew->pp_tds); | ||||
▲ Show 20 Lines • Show All 548 Lines • ▼ Show 20 Lines | pmc_start(struct pmc *pm) | ||||
if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) && | ||||
(po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | (po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) | ||||
return (EDOOFUS); /* programming error */ | return (EDOOFUS); /* programming error */ | ||||
/* | /* | ||||
* If this is a sampling mode PMC, log mapping information for | * If this is a sampling mode PMC, log mapping information for | ||||
* the kernel modules that are currently loaded. | * the kernel modules that are currently loaded. | ||||
*/ | */ | ||||
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) | if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || | ||||
PMC_TO_MODE(pm) == PMC_MODE_ST) | |||||
pmc_log_kernel_mappings(pm); | pmc_log_kernel_mappings(pm); | ||||
if (PMC_IS_VIRTUAL_MODE(mode)) { | if (PMC_IS_VIRTUAL_MODE(mode)) { | ||||
/* | /* | ||||
* If a PMCATTACH has never been done on this PMC, | * If a PMCATTACH has never been done on this PMC, | ||||
* attach it to its owner process. | * attach it to its owner process. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 657 Lines • ▼ Show 20 Lines | case PMC_OP_PMCALLOCATE: | ||||
if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | if ((error = copyin(arg, &pa, sizeof(pa))) != 0) | ||||
break; | break; | ||||
caps = pa.pm_caps; | caps = pa.pm_caps; | ||||
mode = pa.pm_mode; | mode = pa.pm_mode; | ||||
cpu = pa.pm_cpu; | cpu = pa.pm_cpu; | ||||
if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC && | if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && | ||||
mode != PMC_MODE_TS && mode != PMC_MODE_TC) || | mode != PMC_MODE_SC && mode != PMC_MODE_TC && | ||||
(cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max())) { | mode != PMC_MODE_ST && mode != PMC_MODE_TT) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max()) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
/* | /* | ||||
* Virtual PMCs should only ask for a default CPU. | * Virtual PMCs should only ask for a default CPU. | ||||
* System mode PMCs need to specify a non-default CPU. | * System mode PMCs need to specify a non-default CPU. | ||||
*/ | */ | ||||
if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || | ||||
(PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | (PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
▲ Show 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | case PMC_OP_PMCRELEASE: | ||||
po = pm->pm_owner; | po = pm->pm_owner; | ||||
pmc_release_pmc_descriptor(pm); | pmc_release_pmc_descriptor(pm); | ||||
pmc_maybe_remove_owner(po); | pmc_maybe_remove_owner(po); | ||||
pmc_destroy_pmc_descriptor(pm); | pmc_destroy_pmc_descriptor(pm); | ||||
} | } | ||||
break; | break; | ||||
case PMC_OP_LOG_KERNEL_MAP: | |||||
{ | |||||
struct pmc_op_simple sp; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &sp, sizeof(sp))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(sp.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST) | |||||
break; | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
pmc_log_kernel_mappings(pm); | |||||
} | |||||
break; | |||||
case PMC_OP_THREAD_UNSUSPEND: | |||||
{ | |||||
struct pmc_op_proc_unsuspend u; | |||||
struct proc *p; | |||||
struct pmc *pm; | |||||
if ((error = copyin(arg, &u, sizeof(u))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(u.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
/* lookup pid */ | |||||
if ((p = pfind(u.pm_pid)) == NULL) { | |||||
error = ESRCH; | |||||
break; | |||||
} | |||||
if ((p->p_flag & P_HWPMC) == 0) | |||||
break; | |||||
PROC_SLOCK(p); | |||||
thread_unsuspend(p); | |||||
PROC_SUNLOCK(p); | |||||
PROC_UNLOCK(p); | |||||
} | |||||
break; | |||||
case PMC_OP_TRACE_CONFIG: | |||||
{ | |||||
struct pmc_op_trace_config trc; | |||||
uint64_t *ranges; | |||||
struct pmc *pm; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
uint32_t nranges; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trc, sizeof(trc))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trc.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't proceed with PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trc.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
if (pcd->pcd_trace_config == NULL) | |||||
break; | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
ranges = trc.ranges; | |||||
nranges = trc.nranges; | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_trace_config)(cpu, adjri, | |||||
pm, ranges, nranges); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
} | |||||
break; | |||||
/* | /* | ||||
* Read a PMC trace buffer ptr. | |||||
*/ | |||||
case PMC_OP_TRACE_READ: | |||||
{ | |||||
struct pmc_op_trace_read trr; | |||||
struct pmc_op_trace_read *trr_ret; | |||||
struct pmc_binding pb; | |||||
struct pmc_classdep *pcd; | |||||
struct pmc *pm; | |||||
pmc_value_t cycle; | |||||
pmc_value_t offset; | |||||
uint32_t cpu; | |||||
uint32_t ri; | |||||
int adjri; | |||||
if ((error = copyin(arg, &trr, sizeof(trr))) != 0) | |||||
break; | |||||
/* locate pmc descriptor */ | |||||
if ((error = pmc_find_pmc(trr.pm_pmcid, &pm)) != 0) | |||||
break; | |||||
if (PMC_TO_MODE(pm) != PMC_MODE_ST && | |||||
PMC_TO_MODE(pm) != PMC_MODE_TT) | |||||
break; | |||||
/* Can't read a PMC that hasn't been started. */ | |||||
if (pm->pm_state != PMC_STATE_ALLOCATED && | |||||
pm->pm_state != PMC_STATE_STOPPED && | |||||
pm->pm_state != PMC_STATE_RUNNING) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
cpu = trr.pm_cpu; | |||||
ri = PMC_TO_ROWINDEX(pm); | |||||
pcd = pmc_ri_to_classdep(md, ri, &adjri); | |||||
/* switch to CPU 'cpu' */ | |||||
pmc_save_cpu_binding(&pb); | |||||
pmc_select_cpu(cpu); | |||||
mtx_pool_lock_spin(pmc_mtxpool, pm); | |||||
error = (*pcd->pcd_read_trace)(cpu, adjri, | |||||
pm, &cycle, &offset); | |||||
mtx_pool_unlock_spin(pmc_mtxpool, pm); | |||||
pmc_restore_cpu_binding(&pb); | |||||
trr_ret = (struct pmc_op_trace_read *)arg; | |||||
if ((error = copyout(&cycle, &trr_ret->pm_cycle, | |||||
sizeof(trr.pm_cycle)))) | |||||
break; | |||||
if ((error = copyout(&offset, &trr_ret->pm_offset, | |||||
sizeof(trr.pm_offset)))) | |||||
break; | |||||
} | |||||
break; | |||||
/* | |||||
* Read and/or write a PMC. | * Read and/or write a PMC. | ||||
*/ | */ | ||||
case PMC_OP_PMCRW: | case PMC_OP_PMCRW: | ||||
{ | { | ||||
int adjri; | int adjri; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
uint32_t cpu, ri; | uint32_t cpu, ri; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | if (PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm))) { | ||||
/* move this thread to CPU 'cpu' */ | /* move this thread to CPU 'cpu' */ | ||||
pmc_save_cpu_binding(&pb); | pmc_save_cpu_binding(&pb); | ||||
pmc_select_cpu(cpu); | pmc_select_cpu(cpu); | ||||
critical_enter(); | critical_enter(); | ||||
/* save old value */ | /* save old value */ | ||||
if (prw.pm_flags & PMC_F_OLDVALUE) | if (prw.pm_flags & PMC_F_OLDVALUE) | ||||
if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | if ((error = (*pcd->pcd_read_pmc)(cpu, adjri, | ||||
&oldvalue))) | &oldvalue))) | ||||
goto error; | goto error; | ||||
/* write out new value */ | /* write out new value */ | ||||
if (prw.pm_flags & PMC_F_NEWVALUE) | if (prw.pm_flags & PMC_F_NEWVALUE) | ||||
error = (*pcd->pcd_write_pmc)(cpu, adjri, | error = (*pcd->pcd_write_pmc)(cpu, adjri, | ||||
prw.pm_value); | prw.pm_value); | ||||
error: | error: | ||||
critical_exit(); | critical_exit(); | ||||
pmc_restore_cpu_binding(&pb); | pmc_restore_cpu_binding(&pb); | ||||
▲ Show 20 Lines • Show All 1,291 Lines • ▼ Show 20 Lines | for (n = 0; n < (int) md->pmd_nclass; n++) { | ||||
pcd->pcd_width, | pcd->pcd_width, | ||||
pcd->pcd_caps, | pcd->pcd_caps, | ||||
"\20" | "\20" | ||||
"\1INT\2USR\3SYS\4EDG\5THR" | "\1INT\2USR\3SYS\4EDG\5THR" | ||||
"\6REA\7WRI\10INV\11QUA\12PRC" | "\6REA\7WRI\10INV\11QUA\12PRC" | ||||
"\13TAG\14CSC"); | "\13TAG\14CSC"); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
error = pmc_vm_initialize(md); | |||||
Done Inline ActionsThis should come earlier. This case is only meant to be executed if initialization completes successfully, but the pmc_vm_initialize() call introduces a new error case. markj: This should come earlier. This case is only meant to be executed if initialization completes… | |||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* prepare to be unloaded */ | /* prepare to be unloaded */ | ||||
static void | static void | ||||
pmc_cleanup(void) | pmc_cleanup(void) | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (pmc_rowindex_to_classdep) { | if (pmc_rowindex_to_classdep) { | ||||
free(pmc_rowindex_to_classdep, M_PMC); | free(pmc_rowindex_to_classdep, M_PMC); | ||||
pmc_rowindex_to_classdep = NULL; | pmc_rowindex_to_classdep = NULL; | ||||
} | } | ||||
pmclog_shutdown(); | pmclog_shutdown(); | ||||
pmc_vm_finalize(); | |||||
counter_u64_free(pmc_stats.pm_intr_ignored); | counter_u64_free(pmc_stats.pm_intr_ignored); | ||||
counter_u64_free(pmc_stats.pm_intr_processed); | counter_u64_free(pmc_stats.pm_intr_processed); | ||||
counter_u64_free(pmc_stats.pm_intr_bufferfull); | counter_u64_free(pmc_stats.pm_intr_bufferfull); | ||||
counter_u64_free(pmc_stats.pm_syscalls); | counter_u64_free(pmc_stats.pm_syscalls); | ||||
counter_u64_free(pmc_stats.pm_syscall_errors); | counter_u64_free(pmc_stats.pm_syscall_errors); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests); | counter_u64_free(pmc_stats.pm_buffer_requests); | ||||
counter_u64_free(pmc_stats.pm_buffer_requests_failed); | counter_u64_free(pmc_stats.pm_buffer_requests_failed); | ||||
counter_u64_free(pmc_stats.pm_log_sweeps); | counter_u64_free(pmc_stats.pm_log_sweeps); | ||||
Show All 40 Lines |
Use bool literals, "true"/"false".