* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
* @(#)subr_prof.c 8.3 (Berkeley) %G%
* Froms is actually a bunch of unsigned shorts indexing tos
struct gmonparam _gmonparam
= { GMON_PROF_OFF
};
struct gmonparam
*p
= &_gmonparam
;
* Round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
p
->lowpc
= ROUNDDOWN(KERNBASE
, HISTFRACTION
* sizeof(HISTCOUNTER
));
p
->highpc
= ROUNDUP((u_long
)etext
, HISTFRACTION
* sizeof(HISTCOUNTER
));
p
->textsize
= p
->highpc
- p
->lowpc
;
printf("Profiling kernel, textsize=%d [%x..%x]\n",
p
->textsize
, p
->lowpc
, p
->highpc
);
p
->kcountsize
= p
->textsize
/ HISTFRACTION
;
p
->hashfraction
= HASHFRACTION
;
p
->fromssize
= p
->textsize
/ HASHFRACTION
;
p
->tolimit
= p
->textsize
* ARCDENSITY
/ 100;
if (p
->tolimit
< MINARCS
)
else if (p
->tolimit
> MAXARCS
)
p
->tossize
= p
->tolimit
* sizeof(struct tostruct
);
cp
= (char *)malloc(p
->kcountsize
+ p
->fromssize
+ p
->tossize
,
printf("No memory for profiling.\n");
bzero(cp
, p
->kcountsize
+ p
->tossize
+ p
->fromssize
);
p
->tos
= (struct tostruct
*)cp
;
p
->kcount
= (u_short
*)cp
;
p
->froms
= (u_short
*)cp
;
* Return kernel profiling information.
sysctl_doprof(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
struct gmonparam
*gp
= &_gmonparam
;
/* all sysctl names at this level are terminal */
return (ENOTDIR
); /* overloaded */
error
= sysctl_int(oldp
, oldlenp
, newp
, newlen
, &gp
->state
);
if (gp
->state
== GMON_PROF_OFF
)
return (sysctl_struct(oldp
, oldlenp
, newp
, newlen
,
gp
->kcount
, gp
->kcountsize
));
return (sysctl_struct(oldp
, oldlenp
, newp
, newlen
,
gp
->froms
, gp
->fromssize
));
return (sysctl_struct(oldp
, oldlenp
, newp
, newlen
,
return (sysctl_rdstruct(oldp
, oldlenp
, newp
, gp
, sizeof *gp
));
* The scale factor is a fixed point number with 16 bits of fraction, so that
* 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
register struct profil_args
*uap
;
register struct uprof
*upp
;
if (uap
->scale
> (1 << 16))
upp
= &p
->p_stats
->p_prof
;
/* Block profile interrupts while changing state. */
upp
->pr_off
= uap
->offset
;
upp
->pr_scale
= uap
->scale
;
upp
->pr_base
= uap
->samples
;
upp
->pr_size
= uap
->size
;
* Scale is a fixed-point number with the binary point 16 bits
* into the value, and is <= 1.0. pc is at most 32 bits, so the
* intermediate result is at most 48 bits.
#define PC_TO_INDEX(pc, prof) \
((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
(u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
* Collect user-level profiling statistics; called on a profiling tick,
* when a process is running in user-mode. This routine may be called
* from an interrupt context. We try to update the user profiling buffers
* cheaply with fuswintr() and suswintr(). If that fails, we revert to
* an AST that will vector us to trap() with a context in which copyin
* and copyout will work. Trap will then call addupc_task().
* Note that we may (rarely) not get around to the AST soon enough, and
* lose profile ticks when the next tick overwrites this one, but in this
* case the system is overloaded and the profile is probably already
addupc_intr(p
, pc
, ticks
)
register struct uprof
*prof
;
prof
= &p
->p_stats
->p_prof
;
(i
= PC_TO_INDEX(pc
, prof
)) >= prof
->pr_size
)
return; /* out of range; ignore */
addr
= prof
->pr_base
+ i
;
if ((v
= fuswintr(addr
)) == -1 || suswintr(addr
, v
+ ticks
) == -1) {
* Much like before, but we can afford to take faults here. If the
* update fails, we simply turn off profiling.
addupc_task(p
, pc
, ticks
)
register struct uprof
*prof
;
/* Testing P_PROFIL may be unnecessary, but is certainly safe. */
if ((p
->p_flag
& P_PROFIL
) == 0 || ticks
== 0)
prof
= &p
->p_stats
->p_prof
;
(i
= PC_TO_INDEX(pc
, prof
)) >= prof
->pr_size
)
addr
= prof
->pr_base
+ i
;
if (copyin(addr
, (caddr_t
)&v
, sizeof(v
)) == 0) {
if (copyout((caddr_t
)&v
, addr
, sizeof(v
)) == 0)