|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * HISTORY ! 27: * ! 28: * Revision 1.1.1.1 1998/09/22 21:05:49 wsanchez ! 29: * Import of Mac OS X kernel (~semeria) ! 30: * ! 31: * Revision 1.1.1.1 1998/03/07 02:26:08 wsanchez ! 32: * Import of OSF Mach kernel (~mburg) ! 33: * ! 34: * Revision 1.1.5.1 1995/01/06 19:53:45 devrcs ! 35: * mk6 CR668 - 1.3b26 merge ! 36: * new file for mk6 ! 37: * [1994/10/12 22:25:24 dwm] ! 38: * ! 39: * Revision 1.1.2.2 1994/05/16 19:19:22 meissner ! 40: * Protect against hash_ptr being null in _profile_update_stats. ! 41: * [1994/05/16 17:23:53 meissner] ! 42: * ! 43: * Remove _profile_cnt_to_hex, _profile_strbuffer. ! 44: * _profile_print_stats now takes const pointers. ! 45: * Use the new 64-bit arithmetic support instead of converting to double. ! 46: * Add _profile_merge_stats to merge statistics. ! 47: * [1994/04/28 21:45:04 meissner] ! 48: * ! 49: * If MACH_ASSERT is on in server or kernel, turn on profiling printfs. ! 50: * Print out fractional digits for average # of hash searches in stats. ! 51: * Update overflow_ticks for # times the lprofil counter overflows into high word. ! 52: * Don't make sizes of C/asm structures a const array, since it has pointers in it. ! 53: * Add support for converting 64 bit ints to a string. ! 54: * Use PROF_CNT_TO_DECIMAL where possible instead of PROF_CNT_TO_LDOUBLE. ! 55: * [1994/04/20 15:47:02 meissner] ! 56: * ! 57: * Revision 1.1.2.1 1994/04/08 17:51:51 meissner ! 58: * no change ! 59: * [1994/04/08 02:11:40 meissner] ! 60: * ! 61: * Make most stats 64 bits, except for things like memory allocation. ! 62: * [1994/04/02 14:58:28 meissner] ! 63: * ! 64: * Add some printfs under #idef DEBUG_PROFILE. ! 65: * [1994/03/29 21:00:11 meissner] ! 66: * ! 67: * Further changes for gprof/prof overflow support. ! 68: * Add overflow support for {gprof,prof,old,dummy}_mcount counters. ! 69: * [1994/03/17 20:13:31 meissner] ! 70: * ! 71: * Add gprof/prof overflow support ! 72: * [1994/03/17 14:56:51 meissner] ! 73: * ! 74: * Use memset instead of bzero. ! 75: * [1994/02/28 23:56:10 meissner] ! 76: * ! 77: * Add size of histogram counters & unused fields to profile_profil struct ! 78: * [1994/02/17 21:41:50 meissner] ! 79: * ! 80: * Allocate slop space for server in addition to microkernel. ! 81: * Add 3rd argument to _profile_print_stats for profil info. ! 82: * Print # histogram ticks too low/too high for server/mk. ! 83: * [1994/02/16 22:38:18 meissner] ! 84: * ! 85: * Calculate percentages for # of hash buckets. ! 86: * [1994/02/11 16:52:04 meissner] ! 87: * ! 88: * Print stats as an unsigned number. ! 89: * [1994/02/07 18:47:05 meissner] ! 90: * ! 91: * For kernel and server, include <kern/assert.h> not <assert.h>. ! 92: * Always do assert on comparing asm vs. C structure sizes. ! 93: * Add _profile_reset to reset profiling information. ! 94: * Add _profile_update_stats to update the statistics. ! 95: * Move _gprof_write code that updates hash stats to _profile_update_stats. ! 96: * Don't allocate space for basic block support just yet. ! 97: * Add support for range checking the gprof arc {from,self}pc addresses. ! 98: * _profile_debug now calls _profile_update_stats. ! 99: * Print how many times the acontext was locked. ! 100: * If DEBUG_PROFILE is defined, set pv->debug to 1. ! 101: * Expand copyright. ! 102: * [1994/02/07 12:41:03 meissner] ! 103: * ! 104: * Keep track of the number of times the kernel overflows the HISTCOUNTER counter. ! 105: * [1994/02/03 20:13:28 meissner] ! 106: * ! 107: * Add stats for {user,kernel,idle} mode in the kernel. ! 108: * [1994/02/03 15:17:31 meissner] ! 109: * ! 110: * Print unused stats in hex as well as decimal. ! 111: * [1994/02/03 14:52:20 meissner] ! 112: * ! 113: * _profile_print_stats no longer takes profile_{vars,md} pointer arguments. ! 114: * If stream is NULL, _profile_print_stats will use stdout. ! 115: * Separate _profile_update_stats from _gprof_write. ! 116: * [1994/02/03 00:58:55 meissner] ! 117: * ! 118: * Combine _profile_{vars,stats,md}; Allow more than one _profile_vars. ! 119: * [1994/02/01 12:04:01 meissner] ! 120: * ! 121: * Add allocation flag to _profile_md_init. ! 122: * Fix core dumps in _profile_print_stats if no profile_vars ptr passed. ! 123: * Print numbers in 12 columns, not 8. ! 124: * Print my_cpu/max_cpu if max_cpu != 0. ! 125: * Make allocations print like other stats. ! 126: * Use ACONTEXT_FIRST to start loop on, not ACONTEXT_PROF. ! 127: * [1994/01/28 23:33:26 meissner] ! 128: * ! 129: * Move callback pointers into separate allocation context. ! 130: * Add size fields for other structures to profile-vars. ! 131: * [1994/01/26 20:23:37 meissner] ! 132: * ! 133: * Allocate initial memory at startup. ! 134: * Print structure sizes and version number when printing stats. ! 135: * Initialize size fields and version numbers. ! 136: * Allocation context pointers moved to _profile_vars. ! 137: * [1994/01/25 01:46:04 meissner] ! 138: * ! 139: * Move init code here from assembly language. ! 140: * [1994/01/22 01:13:21 meissner] ! 141: * ! 142: * Include <profile/profile-internal.h> instead of "profile-md.h". ! 143: * [1994/01/20 20:56:49 meissner] ! 144: * ! 145: * Fixup copyright. ! 146: * [1994/01/18 23:08:02 meissner] ! 147: * ! 148: * Rename profile.h -> profile-md.h. ! 149: * [1994/01/18 19:44:57 meissner] ! 150: * ! 151: * Write out stats unused fields. ! 152: * Make _prof_write write out the prof stats gprof collects. ! 153: * [1994/01/15 18:40:37 meissner] ! 154: * ! 155: * Remove debug code called from profile-asm.s. ! 156: * Always print out the # of profil buckets. ! 157: * [1994/01/15 00:59:06 meissner] ! 158: * ! 159: * Fix typo. ! 160: * [1994/01/04 16:34:46 meissner] ! 161: * ! 162: * Move max hash bucket calculation into _gprof_write & put info in stats structure. ! 163: * [1994/01/04 16:15:17 meissner] ! 164: * ! 165: * Use _profile_printf to write diagnostics; add diag_stream to hold stream to write to. ! 166: * [1994/01/04 15:37:46 meissner] ! 167: * ! 168: * Correctly handle case where more than one allocation context was ! 169: * allocated due to multiple threads. ! 170: * Cast stats to long for output. ! 171: * Print number of profil buckets field in _profile_stats. ! 172: * Add support for GFUNC allocation context. ! 173: * [1994/01/04 14:26:00 meissner] ! 174: * ! 175: * CR 10198 - Initial version. ! 176: * [1994/01/01 22:44:10 meissne ! 177: * ! 178: * $EndLog$ ! 179: */ ! 180: ! 181: #include <profiling/profile-internal.h> ! 182: #include <stdlib.h> ! 183: #include <string.h> ! 184: ! 185: #if defined(MACH_KERNEL) || defined(_KERNEL) ! 186: ! 187: #include <mach_assert.h> ! 188: #if MACH_ASSERT && !defined(DEBUG_PROFILE) ! 189: #define DEBUG_PROFILE 1 ! 190: #endif ! 191: ! 192: extern int printf(const char *, ...); ! 193: extern void panic(const char *); ! 194: #else ! 195: #include <assert.h> ! 196: #define panic(str) exit(1) ! 197: #endif ! 198: ! 199: #ifndef PROFILE_NUM_FUNCS ! 200: #define PROFILE_NUM_FUNCS 2000 ! 201: #endif ! 202: ! 203: #ifndef PROFILE_NUM_ARCS ! 204: #define PROFILE_NUM_ARCS 8000 ! 205: #endif ! 206: ! 207: /* ! 208: * Information passed on from profile-asm.s ! 209: */ ! 210: ! 211: extern int _profile_do_stats; ! 212: extern size_t _profile_size; ! 213: extern size_t _profile_stats_size; ! 214: extern size_t _profile_md_size; ! 215: extern size_t _profile_profil_size; ! 216: extern size_t _profile_hash_size; ! 217: ! 218: /* ! 219: * All profiling variables, and a dummy gprof record. ! 220: */ ! 221: ! 222: struct profile_vars _profile_vars = { 0 }; ! 223: struct hasharc _gprof_dummy = { 0 }; ! 224: ! 225: /* ! 226: * Forward references. ! 227: */ ! 228: ! 229: static void *_profile_md_acontext(struct profile_vars *pv, ! 230: void *ptr, ! 231: size_t len, ! 232: acontext_type_t type); ! 233: ! 234: static void _profile_reset_alloc(struct profile_vars *, ! 235: acontext_type_t); ! 236: ! 237: extern void _bogus_function(void); ! 238: ! 239: /* ! 240: * Function to set up the initial allocation for a context block. ! 241: */ ! 242: ! 243: static void * ! 244: _profile_md_acontext(struct profile_vars *pv, ! 245: void *ptr, ! 246: size_t len, ! 247: acontext_type_t type) ! 248: { ! 249: struct memory { ! 250: struct alloc_context context; ! 251: struct page_list plist; ! 252: int data[1]; ! 253: }; ! 254: ! 255: struct memory *mptr = (struct memory *)ptr; ! 256: struct alloc_context *context = &mptr->context; ! 257: struct page_list *plist = &mptr->plist; ! 258: ! 259: #ifdef DEBUG_PROFILE ! 260: _profile_printf("_profile_md_acontext: pv= 0x%lx, ptr= 0x%lx, len= %6ld, type= %d\n", ! 261: (long)pv, ! 262: (long)ptr, ! 263: (long)len, ! 264: (int)type); ! 265: #endif ! 266: ! 267: /* Fill in context block header */ ! 268: context->next = pv->acontext[type]; ! 269: context->plist = plist; ! 270: context->lock = 0; ! 271: ! 272: /* Fill in first page list information */ ! 273: plist->ptr = plist->first = (void *)&mptr->data[0]; ! 274: plist->next = (struct page_list *)0; ! 275: plist->bytes_free = len - ((char *)plist->ptr - (char *)ptr); ! 276: plist->bytes_allocated = 0; ! 277: plist->num_allocations = 0; ! 278: ! 279: /* Update statistics */ ! 280: pv->stats.num_context[type]++; ! 281: pv->stats.wasted[type] += plist->bytes_free; ! 282: pv->stats.overhead[type] += len - plist->bytes_free; ! 283: ! 284: /* And setup context block */ ! 285: pv->acontext[type] = context; ! 286: ! 287: return (void *)((char *)ptr+len); ! 288: } ! 289: ! 290: ! 291: /* ! 292: * Machine dependent function to initialize things. ! 293: */ ! 294: ! 295: void ! 296: _profile_md_init(struct profile_vars *pv, ! 297: profile_type_t type, ! 298: profile_alloc_mem_t alloc_mem) ! 299: { ! 300: size_t page_size = pv->page_size; ! 301: size_t arc_size; ! 302: size_t func_size; ! 303: size_t misc_size; ! 304: size_t hash_size; ! 305: size_t extra_arc_size; ! 306: size_t extra_func_size; ! 307: size_t callback_size = page_size; ! 308: void *ptr; ! 309: acontext_type_t ac; ! 310: int i; ! 311: static struct { ! 312: size_t c_size; /* size C thinks structure is */ ! 313: size_t *asm_size_ptr; /* pointer to size asm thinks struct is */ ! 314: const char *name; /* structure name */ ! 315: } sizes[] = { ! 316: { sizeof(struct profile_profil), &_profile_profil_size, "profile_profil" }, ! 317: { sizeof(struct profile_stats), &_profile_stats_size, "profile_stats" }, ! 318: { sizeof(struct profile_md), &_profile_md_size, "profile_md" }, ! 319: { sizeof(struct profile_vars), &_profile_size, "profile_vars" }}; ! 320: ! 321: #ifdef DEBUG_PROFILE ! 322: _profile_printf("_profile_md_init: pv = 0x%lx, type = %d, alloc = %d\n", ! 323: (long) pv, ! 324: (int)type, ! 325: (int)alloc_mem); ! 326: #endif ! 327: ! 328: for (i = 0; i < sizeof (sizes) / sizeof(sizes[0]); i++) { ! 329: if (sizes[i].c_size != *sizes[i].asm_size_ptr) { ! 330: _profile_printf("C thinks struct %s is %ld bytes, asm thinks it is %ld bytes\n", ! 331: sizes[i].name, ! 332: (long)sizes[i].c_size, ! 333: (long)*sizes[i].asm_size_ptr); ! 334: ! 335: panic(sizes[i].name); ! 336: } ! 337: } ! 338: ! 339: /* Figure out which function will handle compiler generated profiling */ ! 340: if (type == PROFILE_GPROF) { ! 341: pv->md.save_mcount_ptr = _gprof_mcount; ! 342: ! 343: } else if (type == PROFILE_PROF) { ! 344: pv->md.save_mcount_ptr = _prof_mcount; ! 345: ! 346: } else { ! 347: pv->md.save_mcount_ptr = _dummy_mcount; ! 348: } ! 349: ! 350: pv->vars_size = sizeof(struct profile_vars); ! 351: pv->plist_size = sizeof(struct page_list); ! 352: pv->acontext_size = sizeof(struct alloc_context); ! 353: pv->callback_size = sizeof(struct callback); ! 354: pv->major_version = PROFILE_MAJOR_VERSION; ! 355: pv->minor_version = PROFILE_MINOR_VERSION; ! 356: pv->type = type; ! 357: pv->do_profile = 1; ! 358: pv->use_dci = 1; ! 359: pv->use_profil = 1; ! 360: pv->output_uarea = 1; ! 361: pv->output_stats = (prof_flag_t) _profile_do_stats; ! 362: pv->output_clock = 1; ! 363: pv->multiple_sections = 1; ! 364: pv->init_format = 0; ! 365: pv->bogus_func = _bogus_function; ! 366: ! 367: #ifdef DEBUG_PROFILE ! 368: pv->debug = 1; ! 369: #endif ! 370: ! 371: if (!pv->error_msg) { ! 372: pv->error_msg = "error in profiling"; ! 373: } ! 374: ! 375: if (!pv->page_size) { ! 376: pv->page_size = 4096; ! 377: } ! 378: ! 379: pv->stats.stats_size = sizeof(struct profile_stats); ! 380: pv->stats.major_version = PROFILE_MAJOR_VERSION; ! 381: pv->stats.minor_version = PROFILE_MINOR_VERSION; ! 382: ! 383: pv->md.md_size = sizeof(struct profile_md); ! 384: pv->md.major_version = PROFILE_MAJOR_VERSION; ! 385: pv->md.minor_version = PROFILE_MINOR_VERSION; ! 386: pv->md.hash_size = _profile_hash_size; ! 387: pv->md.num_cache = MAX_CACHE; ! 388: pv->md.mcount_ptr_ptr = &_mcount_ptr; ! 389: pv->md.dummy_ptr = &_gprof_dummy; ! 390: pv->md.alloc_pages = _profile_alloc_pages; ! 391: ! 392: /* zero out all allocation context blocks */ ! 393: for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) { ! 394: pv->acontext[ac] = (struct alloc_context *)0; ! 395: } ! 396: ! 397: /* Don't allocate memory if not desired */ ! 398: if (!alloc_mem) { ! 399: return; ! 400: } ! 401: ! 402: /* Allocate some space for the initial allocations */ ! 403: switch (type) { ! 404: default: ! 405: misc_size = page_size; ! 406: ptr = _profile_alloc_pages(misc_size + callback_size); ! 407: ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC); ! 408: ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK); ! 409: break; ! 410: ! 411: case PROFILE_GPROF: ! 412: ! 413: #if defined(MACH_KERNEL) || defined(_KERNEL) ! 414: /* ! 415: * For the MK & server allocate some slop space now for the ! 416: * secondary context blocks in case allocations are done at ! 417: * interrupt level when another allocation is being done. This ! 418: * is done before the main allocation blocks and will be pushed ! 419: * so that it will only be used when the main allocation block ! 420: * is locked. ! 421: */ ! 422: extra_arc_size = 4*page_size; ! 423: extra_func_size = 2*page_size; ! 424: #else ! 425: extra_arc_size = extra_func_size = 0; ! 426: #endif ! 427: ! 428: /* Set up allocation areas */ ! 429: arc_size = ROUNDUP(PROFILE_NUM_ARCS * sizeof(struct hasharc), page_size); ! 430: func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct gfuncs), page_size); ! 431: hash_size = _profile_hash_size * sizeof (struct hasharc *); ! 432: misc_size = ROUNDUP(hash_size + page_size, page_size); ! 433: ! 434: ptr = _profile_alloc_pages(arc_size ! 435: + func_size ! 436: + misc_size ! 437: + callback_size ! 438: + extra_arc_size ! 439: + extra_func_size); ! 440: ! 441: #if defined(MACH_KERNEL) || defined(_KERNEL) ! 442: ptr = _profile_md_acontext(pv, ptr, extra_arc_size, ACONTEXT_GPROF); ! 443: ptr = _profile_md_acontext(pv, ptr, extra_func_size, ACONTEXT_GFUNC); ! 444: #endif ! 445: ptr = _profile_md_acontext(pv, ptr, arc_size, ACONTEXT_GPROF); ! 446: ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_GFUNC); ! 447: ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC); ! 448: ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK); ! 449: ! 450: /* Allocate hash table */ ! 451: pv->md.hash_ptr = (struct hasharc **) _profile_alloc(pv, hash_size, ACONTEXT_MISC); ! 452: break; ! 453: ! 454: case PROFILE_PROF: ! 455: /* Set up allocation areas */ ! 456: func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct prof_ext), page_size); ! 457: misc_size = page_size; ! 458: ! 459: ptr = _profile_alloc_pages(func_size ! 460: + misc_size ! 461: + callback_size); ! 462: ! 463: ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_PROF); ! 464: ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC); ! 465: ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK); ! 466: break; ! 467: } ! 468: } ! 469: ! 470: ! 471: /* ! 472: * Machine dependent functions to start and stop profiling. ! 473: */ ! 474: ! 475: int ! 476: _profile_md_start(void) ! 477: { ! 478: _mcount_ptr = _profile_vars.md.save_mcount_ptr; ! 479: return 0; ! 480: } ! 481: ! 482: int ! 483: _profile_md_stop(void) ! 484: { ! 485: _mcount_ptr = _dummy_mcount; ! 486: return 0; ! 487: } ! 488: ! 489: ! 490: /* ! 491: * Free up all memory in a memory context block. ! 492: */ ! 493: ! 494: static void ! 495: _profile_reset_alloc(struct profile_vars *pv, acontext_type_t ac) ! 496: { ! 497: struct alloc_context *aptr; ! 498: struct page_list *plist; ! 499: ! 500: for (aptr = pv->acontext[ac]; ! 501: aptr != (struct alloc_context *)0; ! 502: aptr = aptr->next) { ! 503: ! 504: for (plist = aptr->plist; ! 505: plist != (struct page_list *)0; ! 506: plist = plist->next) { ! 507: ! 508: plist->ptr = plist->first; ! 509: plist->bytes_free += plist->bytes_allocated; ! 510: plist->bytes_allocated = 0; ! 511: plist->num_allocations = 0; ! 512: memset(plist->first, '\0', plist->bytes_allocated); ! 513: } ! 514: } ! 515: } ! 516: ! 517: ! 518: /* ! 519: * Reset profiling. Since the only user of this function is the kernel ! 520: * and the server, we don't have to worry about other stuff than gprof. ! 521: */ ! 522: ! 523: void ! 524: _profile_reset(struct profile_vars *pv) ! 525: { ! 526: struct alloc_context *aptr; ! 527: struct page_list *plist; ! 528: struct gfuncs *gfunc; ! 529: ! 530: if (pv->active) { ! 531: _profile_md_stop(); ! 532: } ! 533: ! 534: /* Reset all function unique pointers back to 0 */ ! 535: for (aptr = pv->acontext[ACONTEXT_GFUNC]; ! 536: aptr != (struct alloc_context *)0; ! 537: aptr = aptr->next) { ! 538: ! 539: for (plist = aptr->plist; ! 540: plist != (struct page_list *)0; ! 541: plist = plist->next) { ! 542: ! 543: for (gfunc = (struct gfuncs *)plist->first; ! 544: gfunc < (struct gfuncs *)plist->ptr; ! 545: gfunc++) { ! 546: ! 547: *(gfunc->unique_ptr) = (struct hasharc *)0; ! 548: } ! 549: } ! 550: } ! 551: ! 552: /* Release memory */ ! 553: _profile_reset_alloc(pv, ACONTEXT_GPROF); ! 554: _profile_reset_alloc(pv, ACONTEXT_GFUNC); ! 555: _profile_reset_alloc(pv, ACONTEXT_PROF); ! 556: ! 557: memset((void *)pv->profil_buf, '\0', pv->profil_info.profil_len); ! 558: memset((void *)pv->md.hash_ptr, '\0', pv->md.hash_size * sizeof(struct hasharc *)); ! 559: memset((void *)&pv->stats, '\0', sizeof(pv->stats)); ! 560: ! 561: pv->stats.stats_size = sizeof(struct profile_stats); ! 562: pv->stats.major_version = PROFILE_MAJOR_VERSION; ! 563: pv->stats.minor_version = PROFILE_MINOR_VERSION; ! 564: ! 565: if (pv->active) { ! 566: _profile_md_start(); ! 567: } ! 568: } ! 569: ! 570: ! 571: /* ! 572: * Machine dependent function to write out gprof records. ! 573: */ ! 574: ! 575: size_t ! 576: _gprof_write(struct profile_vars *pv, struct callback *callback_ptr) ! 577: { ! 578: struct alloc_context *aptr; ! 579: struct page_list *plist; ! 580: size_t bytes = 0; ! 581: struct hasharc *hptr; ! 582: int i; ! 583: ! 584: for (aptr = pv->acontext[ACONTEXT_GPROF]; ! 585: aptr != (struct alloc_context *)0; ! 586: aptr = aptr->next) { ! 587: ! 588: for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) { ! 589: hptr = (struct hasharc *)plist->first; ! 590: for (i = 0; i < plist->num_allocations; (i++, hptr++)) { ! 591: ! 592: struct gprof_arc arc = hptr->arc; ! 593: int nrecs = 1 + (hptr->overflow * 2); ! 594: int j; ! 595: ! 596: if (pv->check_funcs) { ! 597: if (arc.frompc < pv->profil_info.lowpc || ! 598: arc.frompc > pv->profil_info.highpc) { ! 599: ! 600: arc.frompc = (prof_uptrint_t)pv->bogus_func; ! 601: } ! 602: ! 603: if (arc.selfpc < pv->profil_info.lowpc || ! 604: arc.selfpc > pv->profil_info.highpc) { ! 605: ! 606: arc.selfpc = (prof_uptrint_t)pv->bogus_func; ! 607: } ! 608: } ! 609: ! 610: /* For each overflow, emit 2 extra records with the count ! 611: set to 0x80000000 */ ! 612: for (j = 0; j < nrecs; j++) { ! 613: bytes += sizeof (arc); ! 614: if ((*pv->fwrite_func)((void *)&arc, ! 615: sizeof(arc), ! 616: 1, ! 617: pv->stream) != 1) { ! 618: ! 619: _profile_error(pv); ! 620: } ! 621: ! 622: arc.count = 0x80000000; ! 623: } ! 624: } ! 625: } ! 626: } ! 627: ! 628: return bytes; ! 629: } ! 630: ! 631: ! 632: /* ! 633: * Machine dependent function to write out prof records. ! 634: */ ! 635: ! 636: size_t ! 637: _prof_write(struct profile_vars *pv, struct callback *callback_ptr) ! 638: { ! 639: struct alloc_context *aptr; ! 640: struct page_list *plist; ! 641: size_t bytes = 0; ! 642: struct prof_ext prof_st; ! 643: struct prof_int *pptr; ! 644: struct gfuncs *gptr; ! 645: int nrecs; ! 646: int i, j; ! 647: ! 648: /* Write out information prof_mcount collects */ ! 649: for (aptr = pv->acontext[ACONTEXT_PROF]; ! 650: aptr != (struct alloc_context *)0; ! 651: aptr = aptr->next) { ! 652: ! 653: for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) { ! 654: pptr = (struct prof_int *)plist->first; ! 655: ! 656: for (i = 0; i < plist->num_allocations; (i++, pptr++)) { ! 657: ! 658: /* Write out 2 records for each overflow, each with a ! 659: count of 0x80000000 + the normal record */ ! 660: prof_st = pptr->prof; ! 661: nrecs = 1 + (pptr->overflow * 2); ! 662: ! 663: for (j = 0; j < nrecs; j++) { ! 664: bytes += sizeof (struct prof_ext); ! 665: if ((*pv->fwrite_func)((void *)&prof_st, ! 666: sizeof(prof_st), ! 667: 1, ! 668: pv->stream) != 1) { ! 669: ! 670: _profile_error(pv); ! 671: } ! 672: ! 673: prof_st.cncall = 0x80000000; ! 674: } ! 675: } ! 676: } ! 677: } ! 678: ! 679: /* Now write out the prof information that gprof collects */ ! 680: for (aptr = pv->acontext[ACONTEXT_GFUNC]; ! 681: aptr != (struct alloc_context *)0; ! 682: aptr = aptr->next) { ! 683: ! 684: for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) { ! 685: gptr = (struct gfuncs *)plist->first; ! 686: ! 687: for (i = 0; i < plist->num_allocations; (i++, gptr++)) { ! 688: ! 689: /* Write out 2 records for each overflow, each with a ! 690: count of 0x80000000 + the normal record */ ! 691: prof_st = gptr->prof.prof; ! 692: nrecs = 1 + (gptr->prof.overflow * 2); ! 693: ! 694: for (j = 0; j < nrecs; j++) { ! 695: bytes += sizeof (struct prof_ext); ! 696: if ((*pv->fwrite_func)((void *)&prof_st, ! 697: sizeof(prof_st), ! 698: 1, ! 699: pv->stream) != 1) { ! 700: ! 701: _profile_error(pv); ! 702: } ! 703: ! 704: prof_st.cncall = 0x80000000; ! 705: } ! 706: } ! 707: } ! 708: } ! 709: ! 710: return bytes; ! 711: } ! 712: ! 713: ! 714: /* ! 715: * Update any statistics. For the 386, calculate the hash table loading factor. ! 716: * Also figure out how many overflows occured. ! 717: */ ! 718: ! 719: void ! 720: _profile_update_stats(struct profile_vars *pv) ! 721: { ! 722: struct alloc_context *aptr; ! 723: struct page_list *plist; ! 724: struct hasharc *hptr; ! 725: struct prof_int *pptr; ! 726: struct gfuncs *fptr; ! 727: LHISTCOUNTER *lptr; ! 728: int i; ! 729: ! 730: for(i = 0; i < MAX_BUCKETS+1; i++) { ! 731: pv->stats.buckets[i] = 0; ! 732: } ! 733: ! 734: pv->stats.hash_buckets = 0; ! 735: ! 736: if (pv->md.hash_ptr) { ! 737: for (i = 0; i < pv->md.hash_size; i++) { ! 738: long nbuckets = 0; ! 739: struct hasharc *hptr; ! 740: ! 741: for (hptr = pv->md.hash_ptr[i]; hptr; hptr = hptr->next) { ! 742: nbuckets++; ! 743: } ! 744: ! 745: pv->stats.buckets[ (nbuckets < MAX_BUCKETS) ? nbuckets : MAX_BUCKETS ]++; ! 746: if (pv->stats.hash_buckets < nbuckets) { ! 747: pv->stats.hash_buckets = nbuckets; ! 748: } ! 749: } ! 750: } ! 751: ! 752: /* Count how many times functions are out of bounds */ ! 753: if (pv->check_funcs) { ! 754: pv->stats.bogus_count = 0; ! 755: ! 756: for (aptr = pv->acontext[ACONTEXT_GPROF]; ! 757: aptr != (struct alloc_context *)0; ! 758: aptr = aptr->next) { ! 759: ! 760: for (plist = aptr->plist; ! 761: plist != (struct page_list *)0; ! 762: plist = plist->next) { ! 763: ! 764: hptr = (struct hasharc *)plist->first; ! 765: for (i = 0; i < plist->num_allocations; (i++, hptr++)) { ! 766: ! 767: if (hptr->arc.frompc < pv->profil_info.lowpc || ! 768: hptr->arc.frompc > pv->profil_info.highpc) { ! 769: pv->stats.bogus_count++; ! 770: } ! 771: ! 772: if (hptr->arc.selfpc < pv->profil_info.lowpc || ! 773: hptr->arc.selfpc > pv->profil_info.highpc) { ! 774: pv->stats.bogus_count++; ! 775: } ! 776: } ! 777: } ! 778: } ! 779: } ! 780: ! 781: /* Figure out how many overflows occurred */ ! 782: PROF_ULONG_TO_CNT(pv->stats.prof_overflow, 0); ! 783: PROF_ULONG_TO_CNT(pv->stats.gprof_overflow, 0); ! 784: ! 785: for (aptr = pv->acontext[ACONTEXT_GPROF]; ! 786: aptr != (struct alloc_context *)0; ! 787: aptr = aptr->next) { ! 788: ! 789: for (plist = aptr->plist; ! 790: plist != (struct page_list *)0; ! 791: plist = plist->next) { ! 792: ! 793: hptr = (struct hasharc *)plist->first; ! 794: for (i = 0; i < plist->num_allocations; (i++, hptr++)) { ! 795: PROF_CNT_ADD(pv->stats.gprof_overflow, hptr->overflow); ! 796: } ! 797: } ! 798: } ! 799: ! 800: for (aptr = pv->acontext[ACONTEXT_PROF]; ! 801: aptr != (struct alloc_context *)0; ! 802: aptr = aptr->next) { ! 803: ! 804: for (plist = aptr->plist; ! 805: plist != (struct page_list *)0; ! 806: plist = plist->next) { ! 807: ! 808: pptr = (struct prof_int *)plist->first; ! 809: for (i = 0; i < plist->num_allocations; (i++, pptr++)) { ! 810: PROF_CNT_ADD(pv->stats.prof_overflow, pptr->overflow); ! 811: } ! 812: } ! 813: } ! 814: ! 815: for (aptr = pv->acontext[ACONTEXT_GFUNC]; ! 816: aptr != (struct alloc_context *)0; ! 817: aptr = aptr->next) { ! 818: ! 819: for (plist = aptr->plist; ! 820: plist != (struct page_list *)0; ! 821: plist = plist->next) { ! 822: ! 823: fptr = (struct gfuncs *)plist->first; ! 824: for (i = 0; i < plist->num_allocations; (i++, fptr++)) { ! 825: PROF_CNT_ADD(pv->stats.prof_overflow, fptr->prof.overflow); ! 826: } ! 827: } ! 828: } ! 829: ! 830: /* Now go through & count how many times the LHISTCOUNTER overflowed into a 2nd word */ ! 831: lptr = (LHISTCOUNTER *)pv->profil_buf; ! 832: ! 833: if (pv->use_profil && ! 834: pv->profil_info.counter_size == sizeof(LHISTCOUNTER) && ! 835: lptr != (LHISTCOUNTER *)0) { ! 836: ! 837: PROF_ULONG_TO_CNT(pv->stats.overflow_ticks, 0); ! 838: for (i = 0; i < pv->stats.profil_buckets; i++) { ! 839: PROF_CNT_ADD(pv->stats.overflow_ticks, lptr[i].high); ! 840: } ! 841: } ! 842: } ! 843: ! 844: #if !defined(_KERNEL) && !defined(MACH_KERNEL) ! 845: ! 846: /* ! 847: * Routine callable from the debugger that prints the statistics. ! 848: */ ! 849: ! 850: int _profile_debug(void) ! 851: { ! 852: _profile_update_stats(&_profile_vars); ! 853: _profile_print_stats(stderr, &_profile_vars.stats, &_profile_vars.profil_info); ! 854: return 0; ! 855: } ! 856: ! 857: /* ! 858: * Print the statistics structure in a meaningful way. ! 859: */ ! 860: ! 861: void _profile_print_stats(FILE *stream, ! 862: const struct profile_stats *stats, ! 863: const struct profile_profil *pinfo) ! 864: { ! 865: int i; ! 866: prof_cnt_t total_hits; ! 867: acontext_type_t ac; ! 868: int width_cname = 0; ! 869: int width_alloc = 0; ! 870: int width_wasted = 0; ! 871: int width_overhead = 0; ! 872: int width_context = 0; ! 873: static const char *cname[ACONTEXT_MAX] = ACONTEXT_NAMES; ! 874: char buf[20]; ! 875: ! 876: if (!stats) { ! 877: return; ! 878: } ! 879: ! 880: if (!stream) { ! 881: stream = stdout; ! 882: } ! 883: ! 884: sprintf(buf, "%ld.%ld", (long)stats->major_version, (long)stats->minor_version); ! 885: fprintf(stream, "%12s profiling version number\n", buf); ! 886: fprintf(stream, "%12lu size of profile_vars\n", (long unsigned)sizeof(struct profile_vars)); ! 887: fprintf(stream, "%12lu size of profile_stats\n", (long unsigned)sizeof(struct profile_stats)); ! 888: fprintf(stream, "%12lu size of profile_md\n", (long unsigned)sizeof(struct profile_md)); ! 889: fprintf(stream, "%12s calls to _{,g}prof_mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->cnt)); ! 890: fprintf(stream, "%12s calls to old mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->old_mcount)); ! 891: fprintf(stream, "%12s calls to _dummy_mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->dummy)); ! 892: fprintf(stream, "%12lu functions profiled\n", (long unsigned)stats->prof_records); ! 893: fprintf(stream, "%12lu gprof arcs\n", (long unsigned)stats->gprof_records); ! 894: ! 895: if (pinfo) { ! 896: fprintf(stream, "%12lu profil buckets\n", (long unsigned)stats->profil_buckets); ! 897: fprintf(stream, "%12lu profil lowpc [0x%lx]\n", ! 898: (long unsigned)pinfo->lowpc, ! 899: (long unsigned)pinfo->lowpc); ! 900: ! 901: fprintf(stream, "%12lu profil highpc [0x%lx]\n", ! 902: (long unsigned)pinfo->highpc, ! 903: (long unsigned)pinfo->highpc); ! 904: ! 905: fprintf(stream, "%12lu profil highpc-lowpc\n", (long unsigned)(pinfo->highpc - pinfo->lowpc)); ! 906: fprintf(stream, "%12lu profil buffer length\n", (long unsigned)pinfo->profil_len); ! 907: fprintf(stream, "%12lu profil sizeof counters\n", (long unsigned)pinfo->counter_size); ! 908: fprintf(stream, "%12lu profil scale (%g)\n", ! 909: (long unsigned)pinfo->scale, ! 910: ((double)pinfo->scale) / ((double) 0x10000)); ! 911: ! 912: ! 913: for (i = 0; i < sizeof (pinfo->profil_unused) / sizeof (pinfo->profil_unused[0]); i++) { ! 914: if (pinfo->profil_unused[i]) { ! 915: fprintf(stream, "%12lu profil unused[%2d] {0x%.8lx}\n", ! 916: (long unsigned)pinfo->profil_unused[i], ! 917: i, ! 918: (long unsigned)pinfo->profil_unused[i]); ! 919: } ! 920: } ! 921: } ! 922: ! 923: if (stats->max_cpu) { ! 924: fprintf(stream, "%12lu current cpu/thread\n", (long unsigned)stats->my_cpu); ! 925: fprintf(stream, "%12lu max cpu/thread+1\n", (long unsigned)stats->max_cpu); ! 926: } ! 927: ! 928: if (stats->bogus_count != 0) { ! 929: fprintf(stream, ! 930: "%12lu gprof functions found outside of range\n", ! 931: (long unsigned)stats->bogus_count); ! 932: } ! 933: ! 934: if (PROF_CNT_NE_0(stats->too_low)) { ! 935: fprintf(stream, ! 936: "%12s histogram ticks were too low\n", ! 937: PROF_CNT_TO_DECIMAL((char *)0, stats->too_low)); ! 938: } ! 939: ! 940: if (PROF_CNT_NE_0(stats->too_high)) { ! 941: fprintf(stream, ! 942: "%12s histogram ticks were too high\n", ! 943: PROF_CNT_TO_DECIMAL((char *)0, stats->too_high)); ! 944: } ! 945: ! 946: if (PROF_CNT_NE_0(stats->acontext_locked)) { ! 947: fprintf(stream, ! 948: "%12s times an allocation context was locked\n", ! 949: PROF_CNT_TO_DECIMAL((char *)0, stats->acontext_locked)); ! 950: } ! 951: ! 952: if (PROF_CNT_NE_0(stats->kernel_ticks) ! 953: || PROF_CNT_NE_0(stats->user_ticks) ! 954: || PROF_CNT_NE_0(stats->idle_ticks)) { ! 955: ! 956: prof_cnt_t total_ticks; ! 957: long double total_ticks_dbl; ! 958: ! 959: total_ticks = stats->kernel_ticks; ! 960: PROF_CNT_LADD(total_ticks, stats->user_ticks); ! 961: PROF_CNT_LADD(total_ticks, stats->idle_ticks); ! 962: total_ticks_dbl = PROF_CNT_TO_LDOUBLE(total_ticks); ! 963: ! 964: fprintf(stream, ! 965: "%12s total ticks\n", ! 966: PROF_CNT_TO_DECIMAL((char *)0, total_ticks)); ! 967: ! 968: fprintf(stream, ! 969: "%12s ticks within the kernel (%5.2Lf%%)\n", ! 970: PROF_CNT_TO_DECIMAL((char *)0, stats->kernel_ticks), ! 971: 100.0L * (PROF_CNT_TO_LDOUBLE(stats->kernel_ticks) / total_ticks_dbl)); ! 972: ! 973: fprintf(stream, ! 974: "%12s ticks within user space (%5.2Lf%%)\n", ! 975: PROF_CNT_TO_DECIMAL((char *)0, stats->user_ticks), ! 976: 100.0L * (PROF_CNT_TO_LDOUBLE(stats->user_ticks) / total_ticks_dbl)); ! 977: ! 978: fprintf(stream, ! 979: "%12s ticks idle (%5.2Lf%%)\n", ! 980: PROF_CNT_TO_DECIMAL((char *)0, stats->idle_ticks), ! 981: 100.0L * (PROF_CNT_TO_LDOUBLE(stats->idle_ticks) / total_ticks_dbl)); ! 982: } ! 983: ! 984: if (PROF_CNT_NE_0(stats->overflow_ticks)) { ! 985: fprintf(stream, "%12s times a HISTCOUNTER counter would have overflowed\n", ! 986: PROF_CNT_TO_DECIMAL((char *)0, stats->overflow_ticks)); ! 987: } ! 988: ! 989: if (PROF_CNT_NE_0(stats->hash_num)) { ! 990: long double total_buckets = 0.0L; ! 991: ! 992: for (i = 0; i <= MAX_BUCKETS; i++) { ! 993: total_buckets += (long double)stats->buckets[i]; ! 994: } ! 995: ! 996: fprintf(stream, "%12lu max bucket(s) on hash chain.\n", (long unsigned)stats->hash_buckets); ! 997: for (i = 0; i < MAX_BUCKETS; i++) { ! 998: if (stats->buckets[i] != 0) { ! 999: fprintf(stream, "%12lu bucket(s) had %d entries (%5.2Lf%%)\n", ! 1000: (long unsigned)stats->buckets[i], i, ! 1001: 100.0L * ((long double)stats->buckets[i] / total_buckets)); ! 1002: } ! 1003: } ! 1004: ! 1005: if (stats->buckets[MAX_BUCKETS] != 0) { ! 1006: fprintf(stream, "%12lu bucket(s) had more than %d entries (%5.2Lf%%)\n", ! 1007: (long unsigned)stats->buckets[MAX_BUCKETS], MAX_BUCKETS, ! 1008: 100.0L * ((long double)stats->buckets[MAX_BUCKETS] / total_buckets)); ! 1009: } ! 1010: } ! 1011: ! 1012: PROF_ULONG_TO_CNT(total_hits, 0); ! 1013: for (i = 0; i < MAX_CACHE; i++) { ! 1014: PROF_CNT_LADD(total_hits, stats->cache_hits[i]); ! 1015: } ! 1016: ! 1017: if (PROF_CNT_NE_0(total_hits)) { ! 1018: long double total = PROF_CNT_TO_LDOUBLE(stats->cnt); ! 1019: long double total_hits_dbl = PROF_CNT_TO_LDOUBLE(total_hits); ! 1020: ! 1021: fprintf(stream, ! 1022: "%12s cache hits (%.2Lf%%)\n", ! 1023: PROF_CNT_TO_DECIMAL((char *)0, total_hits), ! 1024: 100.0L * (total_hits_dbl / total)); ! 1025: ! 1026: for (i = 0; i < MAX_CACHE; i++) { ! 1027: if (PROF_CNT_NE_0(stats->cache_hits[i])) { ! 1028: fprintf(stream, ! 1029: "%12s times cache#%d matched (%5.2Lf%% of cache hits, %5.2Lf%% total)\n", ! 1030: PROF_CNT_TO_DECIMAL((char *)0, stats->cache_hits[i]), ! 1031: i+1, ! 1032: 100.0L * (PROF_CNT_TO_LDOUBLE(stats->cache_hits[i]) / total_hits_dbl), ! 1033: 100.0L * (PROF_CNT_TO_LDOUBLE(stats->cache_hits[i]) / total)); ! 1034: } ! 1035: } ! 1036: ! 1037: if (PROF_CNT_NE_0(stats->hash_num)) { ! 1038: fprintf(stream, "%12s times hash table searched\n", PROF_CNT_TO_DECIMAL((char *)0, stats->hash_num)); ! 1039: fprintf(stream, "%12s hash buckets searched\n", PROF_CNT_TO_DECIMAL((char *)0, stats->hash_search)); ! 1040: fprintf(stream, "%12.4Lf average buckets searched\n", ! 1041: PROF_CNT_TO_LDOUBLE(stats->hash_search) / PROF_CNT_TO_LDOUBLE(stats->hash_num)); ! 1042: } ! 1043: } ! 1044: ! 1045: for (i = 0; i < sizeof (stats->stats_unused) / sizeof (stats->stats_unused[0]); i++) { ! 1046: if (PROF_CNT_NE_0(stats->stats_unused[i])) { ! 1047: fprintf(stream, "%12s unused[%2d] {0x%.8lx 0x%.8lx}\n", ! 1048: PROF_CNT_TO_DECIMAL((char *)0, stats->stats_unused[i]), ! 1049: i, ! 1050: (unsigned long)stats->stats_unused[i].high, ! 1051: (unsigned long)stats->stats_unused[i].low); ! 1052: } ! 1053: } ! 1054: ! 1055: /* Get the width for the allocation contexts */ ! 1056: for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) { ! 1057: int len; ! 1058: ! 1059: if (stats->num_context[ac] == 0) { ! 1060: continue; ! 1061: } ! 1062: ! 1063: len = strlen (cname[ac]); ! 1064: if (len > width_cname) ! 1065: width_cname = len; ! 1066: ! 1067: len = sprintf (buf, "%lu", (long unsigned)stats->num_alloc[ac]); ! 1068: if (len > width_alloc) ! 1069: width_alloc = len; ! 1070: ! 1071: len = sprintf (buf, "%lu", (long unsigned)stats->wasted[ac]); ! 1072: if (len > width_wasted) ! 1073: width_wasted = len; ! 1074: ! 1075: len = sprintf (buf, "%lu", (long unsigned)stats->overhead[ac]); ! 1076: if (len > width_overhead) ! 1077: width_overhead = len; ! 1078: ! 1079: len = sprintf (buf, "%lu", (long unsigned)stats->num_context[ac]); ! 1080: if (len > width_context) ! 1081: width_context = len; ! 1082: } ! 1083: ! 1084: /* Print info about allocation contexts */ ! 1085: for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) { ! 1086: if (stats->num_context[ac] == 0) { ! 1087: continue; ! 1088: } ! 1089: ! 1090: fprintf (stream, ! 1091: "%12lu bytes in %-*s %*lu alloc, %*lu unused, %*lu over, %*lu context\n", ! 1092: (long unsigned)stats->bytes_alloc[ac], ! 1093: width_cname, cname[ac], ! 1094: width_alloc, (long unsigned)stats->num_alloc[ac], ! 1095: width_wasted, (long unsigned)stats->wasted[ac], ! 1096: width_overhead, (long unsigned)stats->overhead[ac], ! 1097: width_context, (long unsigned)stats->num_context[ac]); ! 1098: } ! 1099: } ! 1100: ! 1101: ! 1102: /* ! 1103: * Merge a new statistics field into an old one. ! 1104: */ ! 1105: ! 1106: void _profile_merge_stats(struct profile_stats *old_stats, const struct profile_stats *new_stats) ! 1107: { ! 1108: int i; ! 1109: ! 1110: /* If nothing passed, just return */ ! 1111: if (!old_stats || !new_stats) ! 1112: return; ! 1113: ! 1114: /* If the old_stats has not been initialized, just copy in the new stats */ ! 1115: if (old_stats->major_version == 0) { ! 1116: *old_stats = *new_stats; ! 1117: ! 1118: /* Otherwise, update stats, field by field */ ! 1119: } else { ! 1120: if (old_stats->prof_records < new_stats->prof_records) ! 1121: old_stats->prof_records = new_stats->prof_records; ! 1122: ! 1123: if (old_stats->gprof_records < new_stats->gprof_records) ! 1124: old_stats->gprof_records = new_stats->gprof_records; ! 1125: ! 1126: if (old_stats->hash_buckets < new_stats->hash_buckets) ! 1127: old_stats->hash_buckets = new_stats->hash_buckets; ! 1128: ! 1129: if (old_stats->bogus_count < new_stats->bogus_count) ! 1130: old_stats->bogus_count = new_stats->bogus_count; ! 1131: ! 1132: PROF_CNT_LADD(old_stats->cnt, new_stats->cnt); ! 1133: PROF_CNT_LADD(old_stats->dummy, new_stats->dummy); ! 1134: PROF_CNT_LADD(old_stats->old_mcount, new_stats->old_mcount); ! 1135: PROF_CNT_LADD(old_stats->hash_search, new_stats->hash_search); ! 1136: PROF_CNT_LADD(old_stats->hash_num, new_stats->hash_num); ! 1137: PROF_CNT_LADD(old_stats->user_ticks, new_stats->user_ticks); ! 1138: PROF_CNT_LADD(old_stats->kernel_ticks, new_stats->kernel_ticks); ! 1139: PROF_CNT_LADD(old_stats->idle_ticks, new_stats->idle_ticks); ! 1140: PROF_CNT_LADD(old_stats->overflow_ticks, new_stats->overflow_ticks); ! 1141: PROF_CNT_LADD(old_stats->acontext_locked, new_stats->acontext_locked); ! 1142: PROF_CNT_LADD(old_stats->too_low, new_stats->too_low); ! 1143: PROF_CNT_LADD(old_stats->too_high, new_stats->too_high); ! 1144: PROF_CNT_LADD(old_stats->prof_overflow, new_stats->prof_overflow); ! 1145: PROF_CNT_LADD(old_stats->gprof_overflow, new_stats->gprof_overflow); ! 1146: ! 1147: for (i = 0; i < (int)ACONTEXT_MAX; i++) { ! 1148: if (old_stats->num_alloc[i] < new_stats->num_alloc[i]) ! 1149: old_stats->num_alloc[i] = new_stats->num_alloc[i]; ! 1150: ! 1151: if (old_stats->bytes_alloc[i] < new_stats->bytes_alloc[i]) ! 1152: old_stats->bytes_alloc[i] = new_stats->bytes_alloc[i]; ! 1153: ! 1154: if (old_stats->num_context[i] < new_stats->num_context[i]) ! 1155: old_stats->num_context[i] = new_stats->num_context[i]; ! 1156: ! 1157: if (old_stats->wasted[i] < new_stats->wasted[i]) ! 1158: old_stats->wasted[i] = new_stats->wasted[i]; ! 1159: ! 1160: if (old_stats->overhead[i] < new_stats->overhead[i]) ! 1161: old_stats->overhead[i] = new_stats->overhead[i]; ! 1162: ! 1163: } ! 1164: ! 1165: for (i = 0; i < MAX_BUCKETS+1; i++) { ! 1166: if (old_stats->buckets[i] < new_stats->buckets[i]) ! 1167: old_stats->buckets[i] = new_stats->buckets[i]; ! 1168: } ! 1169: ! 1170: for (i = 0; i < MAX_CACHE; i++) { ! 1171: PROF_CNT_LADD(old_stats->cache_hits[i], new_stats->cache_hits[i]); ! 1172: } ! 1173: ! 1174: for (i = 0; i < sizeof(old_stats->stats_unused) / sizeof(old_stats->stats_unused[0]); i++) { ! 1175: PROF_CNT_LADD(old_stats->stats_unused[i], new_stats->stats_unused[i]); ! 1176: } ! 1177: } ! 1178: } ! 1179: ! 1180: #endif ! 1181: ! 1182: ! 1183: /* ! 1184: * Invalid function address used when checking of function addresses is ! 1185: * desired for gprof arcs, and we discover an address out of bounds. ! 1186: * There should be no callers of this function. ! 1187: */ ! 1188: ! 1189: void ! 1190: _bogus_function(void) ! 1191: { ! 1192: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.