void * _profile_alloc_pages (size_t size) { vm_offset_t addr; /* * For the MK, we can't support allocating pages at runtime, because we * might be at interrupt level, so abort if we didn't size the table * properly. */ if (PROFILE_VARS(0)->active) { panic("Call to _profile_alloc_pages while profiling is running."); } if (kmem_alloc(kernel_map, &addr, size)) { panic("Could not allocate memory for profiling"); } memset((void *)addr, '\0', size); if (PROFILE_VARS(0)->debug) { printf("Allocated %d bytes for profiling, address 0x%x\n", (int)size, (int)addr); } return((caddr_t)addr); }
void _profile_free_pages(void *addr, size_t size) { if (PROFILE_VARS(0)->debug) { printf("Freed %d bytes for profiling, address 0x%x\n", (int)size, (int)addr); } kmem_free(kernel_map, (vm_offset_t)addr, size); return; }
long _profile_kgmon(int write, size_t count, long indx, int max_cpus, void **p_ptr, void (*control_func)(kgmon_control_t)) { kgmon_control_t kgmon; int cpu; int error = 0; int i; struct profile_vars *pv; static struct callback dummy_callback; *p_ptr = (void *)0; /* * If the number passed is not within bounds, just copy the data directly. */ if (!LEGAL_KGMON(indx)) { *p_ptr = (void *)indx; if (!write) { if (PROFILE_VARS(0)->debug) { printf("_profile_kgmon: copy %5ld bytes, from 0x%lx\n", (long)count, (long)indx); } } else { if (PROFILE_VARS(0)->debug) { printf("_profile_kgmon: copy %5ld bytes, to 0x%lx\n", (long)count, (long)indx); } } return count; } /* * Decode the record number into the component pieces. */ DECODE_KGMON(indx, kgmon, cpu); if (PROFILE_VARS(0)->debug) { printf("_profile_kgmon: start: kgmon control = %2d, cpu = %d, count = %ld\n", kgmon, cpu, (long)count); } /* Validate the CPU number */ if (cpu < 0 || cpu >= max_cpus) { if (PROFILE_VARS(0)->debug) { printf("KGMON, bad cpu %d\n", cpu); } return -1; } else { pv = PROFILE_VARS(cpu); if (!write) { switch (kgmon) { default: if (PROFILE_VARS(0)->debug) { printf("Unknown KGMON read command\n"); } error = -1; break; case KGMON_GET_STATUS: /* return whether or not profiling is active */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_GET_STATUS: cpu = %d\n", cpu); } error = -1; break; } if (count != sizeof(pv->active)) { if (PROFILE_VARS(0)->debug) { printf("KGMON_GET_STATUS: count = %ld, should be %ld\n", (long)count, (long)sizeof(pv->active)); } error = -1; break; } *p_ptr = (void *)&pv->active; break; case KGMON_GET_DEBUG: /* return whether or not debugging is active */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_GET_DEBUG: cpu = %d\n", cpu); } error = -1; break; } if (count != sizeof(pv->debug)) { if (PROFILE_VARS(0)->debug) { printf("KGMON_GET_DEBUG: count = %ld, should be %ld\n", (long)count, (long)sizeof(pv->active)); } error = -1; break; } *p_ptr = (void *)&pv->debug; break; case KGMON_GET_PROFILE_VARS: /* return the _profile_vars structure */ if (count != sizeof(struct profile_vars)) { if (PROFILE_VARS(0)->debug) { printf("KGMON_GET_PROFILE_VARS: count = %ld, should be %ld\n", (long)count, (long)sizeof(struct profile_vars)); } error = -1; break; } _profile_update_stats(pv); *p_ptr = (void *)pv; break; case KGMON_GET_PROFILE_STATS: /* return the _profile_stats structure */ if (count != sizeof(struct profile_stats)) { if (PROFILE_VARS(0)->debug) { printf("KGMON_GET_PROFILE_STATS: count = %ld, should be = %ld\n", (long)count, (long)sizeof(struct profile_stats)); } error = -1; break; } _profile_update_stats(pv); *p_ptr = (void *)&pv->stats; break; } } else { switch (kgmon) { default: if (PROFILE_VARS(0)->debug) { printf("Unknown KGMON write command\n"); } error = -1; break; case KGMON_SET_PROFILE_ON: /* turn on profiling */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_SET_PROFILE_ON, cpu = %d\n", cpu); } error = -1; break; } if (!PROFILE_VARS(0)->active) { for (i = 0; i < max_cpus; i++) { PROFILE_VARS(i)->active = 1; } if (control_func) { (*control_func)(kgmon); } _profile_md_start(); } count = 0; break; case KGMON_SET_PROFILE_OFF: /* turn off profiling */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_SET_PROFILE_OFF, cpu = %d\n", cpu); } error = -1; break; } if (PROFILE_VARS(0)->active) { for (i = 0; i < max_cpus; i++) { PROFILE_VARS(i)->active = 0; } _profile_md_stop(); if (control_func) { (*control_func)(kgmon); } } count = 0; break; case KGMON_SET_PROFILE_RESET: /* reset profiling */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_SET_PROFILE_RESET, cpu = %d\n", cpu); } error = -1; break; } for (i = 0; i < max_cpus; i++) { _profile_reset(PROFILE_VARS(i)); } if (control_func) { (*control_func)(kgmon); } count = 0; break; case KGMON_SET_DEBUG_ON: /* turn on profiling */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_SET_DEBUG_ON, cpu = %d\n", cpu); } error = -1; break; } if (!PROFILE_VARS(0)->debug) { for (i = 0; i < max_cpus; i++) { PROFILE_VARS(i)->debug = 1; } if (control_func) { (*control_func)(kgmon); } } count = 0; break; case KGMON_SET_DEBUG_OFF: /* turn off profiling */ if (cpu != 0) { if (PROFILE_VARS(0)->debug) { printf("KGMON_SET_DEBUG_OFF, cpu = %d\n", cpu); } error = -1; break; } if (PROFILE_VARS(0)->debug) { for (i = 0; i < max_cpus; i++) { PROFILE_VARS(i)->debug = 0; } if (control_func) { (*control_func)(kgmon); } } count = 0; break; } } } if (error) { if (PROFILE_VARS(0)->debug) { printf("_profile_kgmon: done: kgmon control = %2d, cpu = %d, error = %d\n", kgmon, cpu, error); } return -1; } if (PROFILE_VARS(0)->debug) { printf("_profile_kgmon: done: kgmon control = %2d, cpu = %d, count = %ld\n", kgmon, cpu, (long)count); } return count; }
void kmstartup(void) { prof_uptrint_t textsize; prof_uptrint_t monsize; prof_uptrint_t lowpc; prof_uptrint_t highpc; int i; struct profile_vars *pv; /* * 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. */ lowpc = ROUNDDOWN((prof_uptrint_t)&pstart[0], HISTFRACTION*sizeof(LHISTCOUNTER)); highpc = ROUNDUP((prof_uptrint_t)&etext[0], HISTFRACTION*sizeof(LHISTCOUNTER)); textsize = highpc - lowpc; monsize = (textsize / HISTFRACTION) * sizeof(LHISTCOUNTER); for (i = 0; i < NCPUS; i++) { pv = PROFILE_VARS(i); #if NCPUS > 1 if (!pv) { _profile_vars_cpus[i] = pv = &_profile_vars_aux[i-i]; } #endif #ifdef DEBUG_PROFILE pv->debug = 1; #endif pv->page_size = PAGE_SIZE; _profile_md_init(pv, PROFILE_GPROF, PROFILE_ALLOC_MEM_YES); /* Profil related variables */ pv->profil_buf = _profile_alloc (pv, monsize, ACONTEXT_PROFIL); pv->profil_info.highpc = highpc; pv->profil_info.lowpc = lowpc; pv->profil_info.text_len = textsize; pv->profil_info.profil_len = monsize; pv->profil_info.counter_size = sizeof(LHISTCOUNTER); pv->profil_info.scale = 0x10000 / HISTFRACTION; pv->stats.profil_buckets = monsize / sizeof(LHISTCOUNTER); /* Other gprof variables */ pv->stats.my_cpu = i; pv->stats.max_cpu = NCPUS; pv->init = 1; pv->active = 1; pv->use_dci = 0; pv->use_profil = 1; pv->check_funcs = 1; /* for now */ if (pv->debug) { printf("Profiling kernel, s_textsize=%ld, monsize=%ld [0x%lx..0x%lx], cpu = %d\n", (long)textsize, (long)monsize, (long)lowpc, (long)highpc, i); } } _profile_md_start(); }