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(); }
void _profile_md_init(struct profile_vars *pv, profile_type_t type, profile_alloc_mem_t alloc_mem) { size_t page_size = pv->page_size; size_t arc_size; size_t func_size; size_t misc_size; size_t hash_size; size_t extra_arc_size; size_t extra_func_size; size_t callback_size = page_size; void *ptr; acontext_type_t ac; int i; static struct { size_t c_size; /* size C thinks structure is */ size_t *asm_size_ptr; /* pointer to size asm thinks struct is */ const char *name; /* structure name */ } sizes[] = { { sizeof(struct profile_profil), &_profile_profil_size, "profile_profil" }, { sizeof(struct profile_stats), &_profile_stats_size, "profile_stats" }, { sizeof(struct profile_md), &_profile_md_size, "profile_md" }, { sizeof(struct profile_vars), &_profile_size, "profile_vars" }}; #ifdef DEBUG_PROFILE _profile_printf("_profile_md_init: pv = 0x%lx, type = %d, alloc = %d\n", (long) pv, (int)type, (int)alloc_mem); #endif for (i = 0; i < sizeof (sizes) / sizeof(sizes[0]); i++) { if (sizes[i].c_size != *sizes[i].asm_size_ptr) { _profile_printf("C thinks struct %s is %ld bytes, asm thinks it is %ld bytes\n", sizes[i].name, (long)sizes[i].c_size, (long)*sizes[i].asm_size_ptr); panic(sizes[i].name); } } /* Figure out which function will handle compiler generated profiling */ if (type == PROFILE_GPROF) { pv->md.save_mcount_ptr = _gprof_mcount; } else if (type == PROFILE_PROF) { pv->md.save_mcount_ptr = _prof_mcount; } else { pv->md.save_mcount_ptr = _dummy_mcount; } pv->vars_size = sizeof(struct profile_vars); pv->plist_size = sizeof(struct page_list); pv->acontext_size = sizeof(struct alloc_context); pv->callback_size = sizeof(struct callback); pv->major_version = PROFILE_MAJOR_VERSION; pv->minor_version = PROFILE_MINOR_VERSION; pv->type = type; pv->do_profile = 1; pv->use_dci = 1; pv->use_profil = 1; pv->output_uarea = 1; pv->output_stats = (prof_flag_t) _profile_do_stats; pv->output_clock = 1; pv->multiple_sections = 1; pv->init_format = 0; pv->bogus_func = _bogus_function; #ifdef DEBUG_PROFILE pv->debug = 1; #endif if (!pv->error_msg) { pv->error_msg = "error in profiling"; } if (!pv->page_size) { pv->page_size = 4096; } pv->stats.stats_size = sizeof(struct profile_stats); pv->stats.major_version = PROFILE_MAJOR_VERSION; pv->stats.minor_version = PROFILE_MINOR_VERSION; pv->md.md_size = sizeof(struct profile_md); pv->md.major_version = PROFILE_MAJOR_VERSION; pv->md.minor_version = PROFILE_MINOR_VERSION; pv->md.hash_size = _profile_hash_size; pv->md.num_cache = MAX_CACHE; pv->md.mcount_ptr_ptr = &_mcount_ptr; pv->md.dummy_ptr = &_gprof_dummy; pv->md.alloc_pages = _profile_alloc_pages; /* zero out all allocation context blocks */ for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) { pv->acontext[ac] = (struct alloc_context *)0; } /* Don't allocate memory if not desired */ if (!alloc_mem) { return; } /* Allocate some space for the initial allocations */ switch (type) { default: misc_size = page_size; ptr = _profile_alloc_pages(misc_size + callback_size); ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC); ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK); break; case PROFILE_GPROF: #if defined(MACH_KERNEL) || defined(_KERNEL) /* * For the MK & server allocate some slop space now for the * secondary context blocks in case allocations are done at * interrupt level when another allocation is being done. This * is done before the main allocation blocks and will be pushed * so that it will only be used when the main allocation block * is locked. */ extra_arc_size = 4*page_size; extra_func_size = 2*page_size; #else extra_arc_size = extra_func_size = 0; #endif /* Set up allocation areas */ arc_size = ROUNDUP(PROFILE_NUM_ARCS * sizeof(struct hasharc), page_size); func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct gfuncs), page_size); hash_size = _profile_hash_size * sizeof (struct hasharc *); misc_size = ROUNDUP(hash_size + page_size, page_size); ptr = _profile_alloc_pages(arc_size + func_size + misc_size + callback_size + extra_arc_size + extra_func_size); #if defined(MACH_KERNEL) || defined(_KERNEL) ptr = _profile_md_acontext(pv, ptr, extra_arc_size, ACONTEXT_GPROF); ptr = _profile_md_acontext(pv, ptr, extra_func_size, ACONTEXT_GFUNC); #endif ptr = _profile_md_acontext(pv, ptr, arc_size, ACONTEXT_GPROF); ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_GFUNC); ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC); ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK); /* Allocate hash table */ pv->md.hash_ptr = (struct hasharc **) _profile_alloc(pv, hash_size, ACONTEXT_MISC); break; case PROFILE_PROF: /* Set up allocation areas */ func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct prof_ext), page_size); misc_size = page_size; ptr = _profile_alloc_pages(func_size + misc_size + callback_size); ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_PROF); ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC); ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK); break; } }