/* * Stop profiling on a process. */ void stopprofclock(struct process *pr) { int s; if (pr->ps_flags & PS_PROFIL) { atomic_clearbits_int(&pr->ps_flags, PS_PROFIL); if (--profprocs == 0 && stathz != 0) { s = splstatclock(); psdiv = pscnt = 1; setstatclockrate(stathz); splx(s); } } }
/* * Start profiling on a process. * * Kernel profiling passes proc0 which never exits and hence * keeps the profile clock running constantly. */ void startprofclock(struct process *pr) { int s; if ((pr->ps_flags & PS_PROFIL) == 0) { atomic_setbits_int(&pr->ps_flags, PS_PROFIL); if (++profprocs == 1 && stathz != 0) { s = splstatclock(); psdiv = pscnt = psratio; setstatclockrate(profhz); splx(s); } } }
/* * Stop profiling on a process. */ void stopprofclock(struct proc *p) { int s; if (p->p_flag & P_PROFIL) { atomic_clearbits_int(&p->p_flag, P_PROFIL); if (--profprocs == 0 && stathz != 0) { s = splstatclock(); psdiv = pscnt = 1; setstatclockrate(stathz); splx(s); } } }
/* * Start profiling on a process. * * Kernel profiling passes proc0 which never exits and hence * keeps the profile clock running constantly. */ void startprofclock(struct proc *p) { int s; if ((p->p_flag & P_PROFIL) == 0) { atomic_setbits_int(&p->p_flag, P_PROFIL); if (++profprocs == 1 && stathz != 0) { s = splstatclock(); psdiv = pscnt = psratio; setstatclockrate(profhz); splx(s); } } }
void cpu_initclocks(void) { /* * Load timer 0 with count down value * This timer generates 100Hz interrupts for the system clock */ aprint_normal("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); timer0_count = TIMER_FREQUENCY / hz; bus_space_write_1(clock_sc->sc_iot, clock_sc->sc_ioh, IOMD_T0LOW, (timer0_count >> 0) & 0xff); bus_space_write_1(clock_sc->sc_iot, clock_sc->sc_ioh, IOMD_T0HIGH, (timer0_count >> 8) & 0xff); /* reload the counter */ bus_space_write_1(clock_sc->sc_iot, clock_sc->sc_ioh, IOMD_T0GO, 0); clockirq = intr_claim(IRQ_TIMER0, IPL_CLOCK, "tmr0 hard clk", clockhandler, 0); if (clockirq == NULL) panic("%s: Cannot installer timer 0 IRQ handler", device_xname(clock_sc->sc_dev)); if (stathz) { setstatclockrate(stathz); statclockirq = intr_claim(IRQ_TIMER1, IPL_CLOCK, "tmr1 stat clk", statclockhandler, 0); if (statclockirq == NULL) panic("%s: Cannot installer timer 1 IRQ handler", device_xname(clock_sc->sc_dev)); } #ifdef DIAGNOSTIC checkdelay(); #endif tc_init(&iomd_timecounter); }
/* * Statistics clock. Grab profile sample, and if divider reaches 0, * do process and kernel statistics. */ void statclock(struct clockframe *frame) { #ifdef GPROF struct gmonparam *g; u_long i; #endif struct cpu_info *ci = curcpu(); struct schedstate_percpu *spc = &ci->ci_schedstate; struct proc *p = curproc; struct process *pr; /* * Notice changes in divisor frequency, and adjust clock * frequency accordingly. */ if (spc->spc_psdiv != psdiv) { spc->spc_psdiv = psdiv; spc->spc_pscnt = psdiv; if (psdiv == 1) { setstatclockrate(stathz); } else { setstatclockrate(profhz); } } if (CLKF_USERMODE(frame)) { pr = p->p_p; if (pr->ps_flags & PS_PROFIL) addupc_intr(p, CLKF_PC(frame)); if (--spc->spc_pscnt > 0) return; /* * Came from user mode; CPU was in user state. * If this process is being profiled record the tick. */ p->p_uticks++; if (pr->ps_nice > NZERO) spc->spc_cp_time[CP_NICE]++; else spc->spc_cp_time[CP_USER]++; } else { #ifdef GPROF /* * Kernel statistics are just like addupc_intr, only easier. */ g = ci->ci_gmon; if (g != NULL && g->state == GMON_PROF_ON) { i = CLKF_PC(frame) - g->lowpc; if (i < g->textsize) { i /= HISTFRACTION * sizeof(*g->kcount); g->kcount[i]++; } } #endif #if defined(PROC_PC) if (p != NULL && p->p_p->ps_flags & PS_PROFIL) addupc_intr(p, PROC_PC(p)); #endif if (--spc->spc_pscnt > 0) return; /* * Came from kernel mode, so we were: * - handling an interrupt, * - doing syscall or trap work on behalf of the current * user process, or * - spinning in the idle loop. * Whichever it is, charge the time as appropriate. * Note that we charge interrupts to the current process, * regardless of whether they are ``for'' that process, * so that we know how much of its real time was spent * in ``non-process'' (i.e., interrupt) work. */ if (CLKF_INTR(frame)) { if (p != NULL) p->p_iticks++; spc->spc_cp_time[CP_INTR]++; } else if (p != NULL && p != spc->spc_idleproc) { p->p_sticks++; spc->spc_cp_time[CP_SYS]++; } else spc->spc_cp_time[CP_IDLE]++; } spc->spc_pscnt = psdiv; if (p != NULL) { p->p_cpticks++; /* * If no schedclock is provided, call it here at ~~12-25 Hz; * ~~16 Hz is best */ if (schedhz == 0) { if ((++curcpu()->ci_schedstate.spc_schedticks & 3) == 0) schedclock(p); } } }
/* * Statistics clock. Grab profile sample, and if divider reaches 0, * do process and kernel statistics. */ void statclock(struct clockframe *frame) { #ifdef GPROF struct gmonparam *g; intptr_t i; #endif struct cpu_info *ci = curcpu(); struct schedstate_percpu *spc = &ci->ci_schedstate; struct proc *p; struct lwp *l; /* * Notice changes in divisor frequency, and adjust clock * frequency accordingly. */ if (spc->spc_psdiv != psdiv) { spc->spc_psdiv = psdiv; spc->spc_pscnt = psdiv; if (psdiv == 1) { setstatclockrate(stathz); } else { setstatclockrate(profhz); } } l = ci->ci_data.cpu_onproc; if ((l->l_flag & LW_IDLE) != 0) { /* * don't account idle lwps as swapper. */ p = NULL; } else { p = l->l_proc; mutex_spin_enter(&p->p_stmutex); } if (CLKF_USERMODE(frame)) { if ((p->p_stflag & PST_PROFIL) && profsrc == PROFSRC_CLOCK) addupc_intr(l, CLKF_PC(frame)); if (--spc->spc_pscnt > 0) { mutex_spin_exit(&p->p_stmutex); return; } /* * Came from user mode; CPU was in user state. * If this process is being profiled record the tick. */ p->p_uticks++; if (p->p_nice > NZERO) spc->spc_cp_time[CP_NICE]++; else spc->spc_cp_time[CP_USER]++; } else { #ifdef GPROF /* * Kernel statistics are just like addupc_intr, only easier. */ g = &_gmonparam; if (profsrc == PROFSRC_CLOCK && g->state == GMON_PROF_ON) { i = CLKF_PC(frame) - g->lowpc; if (i < g->textsize) { i /= HISTFRACTION * sizeof(*g->kcount); g->kcount[i]++; } } #endif #ifdef LWP_PC if (p != NULL && profsrc == PROFSRC_CLOCK && (p->p_stflag & PST_PROFIL)) { addupc_intr(l, LWP_PC(l)); } #endif if (--spc->spc_pscnt > 0) { if (p != NULL) mutex_spin_exit(&p->p_stmutex); return; } /* * Came from kernel mode, so we were: * - handling an interrupt, * - doing syscall or trap work on behalf of the current * user process, or * - spinning in the idle loop. * Whichever it is, charge the time as appropriate. * Note that we charge interrupts to the current process, * regardless of whether they are ``for'' that process, * so that we know how much of its real time was spent * in ``non-process'' (i.e., interrupt) work. */ if (CLKF_INTR(frame) || (curlwp->l_pflag & LP_INTR) != 0) { if (p != NULL) { p->p_iticks++; } spc->spc_cp_time[CP_INTR]++; } else if (p != NULL) { p->p_sticks++; spc->spc_cp_time[CP_SYS]++; } else { spc->spc_cp_time[CP_IDLE]++; } } spc->spc_pscnt = psdiv; if (p != NULL) { atomic_inc_uint(&l->l_cpticks); mutex_spin_exit(&p->p_stmutex); } }