home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 4 / hacker04 / 04_HACK04.ISO / darwin / darwinx86.iso / usr / include / profile / i386 / profile-md.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-30  |  34.1 KB  |  1,193 lines

  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. }
  1193.