darwin-xnu/osfmk/profiling/i386/profile-md.c
<<
>>
Prefs
   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 <vm/vm_kern.h>
 183#include <stdlib.h>
 184#include <string.h>
 185
 186#if defined(MACH_KERNEL) || defined(_KERNEL)
 187
 188#include <mach_assert.h>
 189#if MACH_ASSERT && !defined(DEBUG_PROFILE)
 190#define DEBUG_PROFILE 1
 191#endif
 192
 193#else
 194#include <assert.h>
 195#define panic(str) exit(1)
 196#endif
 197
 198#ifndef PROFILE_NUM_FUNCS
 199#define PROFILE_NUM_FUNCS       2000
 200#endif
 201
 202#ifndef PROFILE_NUM_ARCS
 203#define PROFILE_NUM_ARCS        8000
 204#endif
 205
 206/*
 207 * Information passed on from profile-asm.s
 208 */
 209
 210extern int _profile_do_stats;
 211extern size_t _profile_size;
 212extern size_t _profile_stats_size;
 213extern size_t _profile_md_size;
 214extern size_t _profile_profil_size;
 215extern size_t _profile_hash_size;
 216
 217/*
 218 * All profiling variables, and a dummy gprof record.
 219 */
 220
 221struct profile_vars _profile_vars = { 0 };
 222struct hasharc _gprof_dummy = { 0 };
 223
 224/*
 225 * Forward references.
 226 */
 227
 228static void *_profile_md_acontext(struct profile_vars *pv,
 229                                  void *ptr,
 230                                  size_t len,
 231                                  acontext_type_t type);
 232
 233static void _profile_reset_alloc(struct profile_vars *,
 234                                 acontext_type_t);
 235
 236extern void _bogus_function(void);
 237
 238
 239#if NCPUS > 1
 240struct profile_vars *_profile_vars_cpus[NCPUS] = { &_profile_vars };
 241struct profile_vars _profile_vars_aux[NCPUS-1];
 242#define PROFILE_VARS(cpu) (_profile_vars_cpus[(cpu)])
 243#else
 244#define PROFILE_VARS(cpu) (&_profile_vars)
 245#endif
 246
 247void *
 248_profile_alloc_pages (size_t size)
 249{
 250        vm_offset_t addr;
 251
 252        /*
 253         * For the MK, we can't support allocating pages at runtime, because we
 254         * might be at interrupt level, so abort if we didn't size the table
 255         * properly.
 256         */
 257
 258        if (PROFILE_VARS(0)->active) {
 259                panic("Call to _profile_alloc_pages while profiling is running.");
 260        }
 261
 262        if (kmem_alloc(kernel_map, &addr, size)) {
 263                panic("Could not allocate memory for profiling");
 264        }
 265
 266        memset((void *)addr, '\0', size);
 267        if (PROFILE_VARS(0)->debug) {
 268                printf("Allocated %d bytes for profiling, address 0x%x\n", (int)size, (int)addr);
 269        }
 270
 271        return((caddr_t)addr);
 272}
 273
 274void
 275_profile_free_pages(void *addr, size_t size)
 276{
 277        if (PROFILE_VARS(0)->debug) {
 278                printf("Freed %d bytes for profiling, address 0x%x\n", (int)size, (int)addr);
 279        }
 280
 281        kmem_free(kernel_map, (vm_offset_t)addr, size);
 282        return;
 283}
 284
 285void _profile_error(struct profile_vars *pv)
 286{
 287        panic("Fatal error in profiling");
 288}
 289
 290
 291/*
 292 * Function to set up the initial allocation for a context block.
 293 */
 294
 295static void *
 296_profile_md_acontext(struct profile_vars *pv,
 297                     void *ptr,
 298                     size_t len,
 299                     acontext_type_t type)
 300{
 301        struct memory {
 302                struct alloc_context context;
 303                struct page_list plist;
 304                int data[1];
 305        };
 306
 307        struct memory *mptr = (struct memory *)ptr;
 308        struct alloc_context *context = &mptr->context;
 309        struct page_list *plist = &mptr->plist;
 310
 311#ifdef DEBUG_PROFILE
 312        _profile_printf("_profile_md_acontext: pv= 0x%lx, ptr= 0x%lx, len= %6ld, type= %d\n",
 313                        (long)pv,
 314                        (long)ptr,
 315                        (long)len,
 316                        (int)type);
 317#endif
 318
 319        /* Fill in context block header */
 320        context->next = pv->acontext[type];
 321        context->plist = plist;
 322        context->lock = 0;
 323
 324        /* Fill in first page list information */
 325        plist->ptr = plist->first = (void *)&mptr->data[0];
 326        plist->next = (struct page_list *)0;
 327        plist->bytes_free = len - ((char *)plist->ptr - (char *)ptr);
 328        plist->bytes_allocated = 0;
 329        plist->num_allocations = 0;
 330
 331        /* Update statistics */
 332        pv->stats.num_context[type]++;
 333        pv->stats.wasted[type] += plist->bytes_free;
 334        pv->stats.overhead[type] += len - plist->bytes_free;
 335
 336        /* And setup context block */
 337        pv->acontext[type] = context;
 338
 339        return (void *)((char *)ptr+len);
 340}
 341
 342
 343/*
 344 * Machine dependent function to initialize things.
 345 */
 346
 347void
 348_profile_md_init(struct profile_vars *pv,
 349                 profile_type_t type,
 350                 profile_alloc_mem_t alloc_mem)
 351{
 352        size_t page_size = pv->page_size;
 353        size_t arc_size;
 354        size_t func_size;
 355        size_t misc_size;
 356        size_t hash_size;
 357        size_t extra_arc_size;
 358        size_t extra_func_size;
 359        size_t callback_size = page_size;
 360        void *ptr;
 361        acontext_type_t ac;
 362        int i;
 363        static struct {
 364                size_t      c_size;             /* size C thinks structure is */
 365                size_t     *asm_size_ptr;       /* pointer to size asm thinks struct is */
 366                const char *name;               /* structure name */
 367        } sizes[] = {
 368                { sizeof(struct profile_profil), &_profile_profil_size, "profile_profil" },
 369                { sizeof(struct profile_stats),  &_profile_stats_size,  "profile_stats" },
 370                { sizeof(struct profile_md),     &_profile_md_size,     "profile_md" },
 371                { sizeof(struct profile_vars),   &_profile_size,        "profile_vars" }};
 372
 373#ifdef DEBUG_PROFILE
 374        _profile_printf("_profile_md_init: pv = 0x%lx, type = %d, alloc = %d\n",
 375                        (long) pv,
 376                        (int)type,
 377                        (int)alloc_mem);
 378#endif
 379
 380        for (i = 0; i < sizeof (sizes) / sizeof(sizes[0]); i++) {
 381                if (sizes[i].c_size != *sizes[i].asm_size_ptr) {
 382                        _profile_printf("C thinks struct %s is %ld bytes, asm thinks it is %ld bytes\n",
 383                                        sizes[i].name,
 384                                        (long)sizes[i].c_size,
 385                                        (long)*sizes[i].asm_size_ptr);
 386
 387                        panic(sizes[i].name);
 388                }
 389        }
 390
 391        /* Figure out which function will handle compiler generated profiling */
 392        if (type == PROFILE_GPROF) {
 393                pv->md.save_mcount_ptr = _gprof_mcount;
 394
 395        } else if (type == PROFILE_PROF) {
 396                pv->md.save_mcount_ptr = _prof_mcount;
 397
 398        } else {
 399                pv->md.save_mcount_ptr = _dummy_mcount;
 400        }
 401
 402        pv->vars_size         = sizeof(struct profile_vars);
 403        pv->plist_size        = sizeof(struct page_list);
 404        pv->acontext_size     = sizeof(struct alloc_context);
 405        pv->callback_size     = sizeof(struct callback);
 406        pv->major_version     = PROFILE_MAJOR_VERSION;
 407        pv->minor_version     = PROFILE_MINOR_VERSION;
 408        pv->type              = type;
 409        pv->do_profile        = 1;
 410        pv->use_dci           = 1;
 411        pv->use_profil        = 1;
 412        pv->output_uarea      = 1;
 413        pv->output_stats      = (prof_flag_t) _profile_do_stats;
 414        pv->output_clock      = 1;
 415        pv->multiple_sections = 1;
 416        pv->init_format       = 0;
 417        pv->bogus_func        = _bogus_function;
 418
 419#ifdef DEBUG_PROFILE
 420        pv->debug             = 1;
 421#endif
 422
 423        if (!pv->error_msg) {
 424                pv->error_msg = "error in profiling";
 425        }
 426
 427        if (!pv->page_size) {
 428                pv->page_size = 4096;
 429        }
 430
 431        pv->stats.stats_size    = sizeof(struct profile_stats);
 432        pv->stats.major_version = PROFILE_MAJOR_VERSION;
 433        pv->stats.minor_version = PROFILE_MINOR_VERSION;
 434
 435        pv->md.md_size         = sizeof(struct profile_md);
 436        pv->md.major_version   = PROFILE_MAJOR_VERSION;
 437        pv->md.minor_version   = PROFILE_MINOR_VERSION;
 438        pv->md.hash_size       = _profile_hash_size;
 439        pv->md.num_cache       = MAX_CACHE;
 440        pv->md.mcount_ptr_ptr  = &_mcount_ptr;
 441        pv->md.dummy_ptr       = &_gprof_dummy;
 442        pv->md.alloc_pages     = _profile_alloc_pages;
 443
 444        /* zero out all allocation context blocks */
 445        for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) {
 446                pv->acontext[ac] = (struct alloc_context *)0;
 447        }
 448
 449        /* Don't allocate memory if not desired */
 450        if (!alloc_mem) {
 451                return;
 452        }
 453
 454        /* Allocate some space for the initial allocations */
 455        switch (type) {
 456        default:
 457                misc_size = page_size;
 458                ptr = _profile_alloc_pages(misc_size + callback_size);
 459                ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC);
 460                ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK);
 461                break;
 462
 463        case PROFILE_GPROF:
 464
 465#if defined(MACH_KERNEL) || defined(_KERNEL)
 466                /*
 467                 * For the MK & server allocate some slop space now for the
 468                 * secondary context blocks in case allocations are done at
 469                 * interrupt level when another allocation is being done.  This
 470                 * is done before the main allocation blocks and will be pushed
 471                 * so that it will only be used when the main allocation block
 472                 * is locked.
 473                 */
 474                extra_arc_size = 4*page_size;
 475                extra_func_size = 2*page_size;
 476#else
 477                extra_arc_size = extra_func_size = 0;
 478#endif
 479
 480                /* Set up allocation areas */
 481                arc_size = ROUNDUP(PROFILE_NUM_ARCS * sizeof(struct hasharc), page_size);
 482                func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct gfuncs), page_size);
 483                hash_size = _profile_hash_size * sizeof (struct hasharc *);
 484                misc_size = ROUNDUP(hash_size + page_size, page_size);
 485
 486                ptr = _profile_alloc_pages(arc_size
 487                                           + func_size
 488                                           + misc_size
 489                                           + callback_size
 490                                           + extra_arc_size
 491                                           + extra_func_size);
 492
 493#if defined(MACH_KERNEL) || defined(_KERNEL)
 494                ptr = _profile_md_acontext(pv, ptr, extra_arc_size, ACONTEXT_GPROF);
 495                ptr = _profile_md_acontext(pv, ptr, extra_func_size, ACONTEXT_GFUNC);
 496#endif
 497                ptr = _profile_md_acontext(pv, ptr, arc_size, ACONTEXT_GPROF);
 498                ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_GFUNC);
 499                ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC);
 500                ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK);
 501
 502                /* Allocate hash table */
 503                pv->md.hash_ptr = (struct hasharc **) _profile_alloc(pv, hash_size, ACONTEXT_MISC);
 504                break;
 505
 506        case PROFILE_PROF:
 507                /* Set up allocation areas */
 508                func_size = ROUNDUP(PROFILE_NUM_FUNCS * sizeof(struct prof_ext), page_size);
 509                misc_size = page_size;
 510
 511                ptr = _profile_alloc_pages(func_size
 512                                           + misc_size
 513                                           + callback_size);
 514
 515                ptr = _profile_md_acontext(pv, ptr, func_size, ACONTEXT_PROF);
 516                ptr = _profile_md_acontext(pv, ptr, misc_size, ACONTEXT_MISC);
 517                ptr = _profile_md_acontext(pv, ptr, callback_size, ACONTEXT_CALLBACK);
 518                break;
 519        }
 520}
 521
 522
 523/*
 524 * Machine dependent functions to start and stop profiling.
 525 */
 526
 527int
 528_profile_md_start(void)
 529{
 530        _mcount_ptr = _profile_vars.md.save_mcount_ptr;
 531        return 0;
 532}
 533
 534int
 535_profile_md_stop(void)
 536{
 537        _mcount_ptr = _dummy_mcount;
 538        return 0;
 539}
 540
 541
 542/*
 543 * Free up all memory in a memory context block.
 544 */
 545
 546static void
 547_profile_reset_alloc(struct profile_vars *pv, acontext_type_t ac)
 548{
 549        struct alloc_context *aptr;
 550        struct page_list *plist;
 551
 552        for (aptr = pv->acontext[ac];
 553             aptr != (struct alloc_context *)0;
 554             aptr = aptr->next) {
 555
 556                for (plist = aptr->plist;
 557                     plist != (struct page_list *)0;
 558                     plist = plist->next) {
 559
 560                        plist->ptr = plist->first;
 561                        plist->bytes_free += plist->bytes_allocated;
 562                        plist->bytes_allocated = 0;
 563                        plist->num_allocations = 0;
 564                        memset(plist->first, '\0', plist->bytes_allocated);
 565                }
 566        }
 567}
 568
 569
 570/*
 571 * Reset profiling.  Since the only user of this function is the kernel
 572 * and the server, we don't have to worry about other stuff than gprof.
 573 */
 574
 575void
 576_profile_reset(struct profile_vars *pv)
 577{
 578        struct alloc_context *aptr;
 579        struct page_list *plist;
 580        struct gfuncs *gfunc;
 581
 582        if (pv->active) {
 583                _profile_md_stop();
 584        }
 585
 586        /* Reset all function unique pointers back to 0 */
 587        for (aptr = pv->acontext[ACONTEXT_GFUNC];
 588             aptr != (struct alloc_context *)0;
 589             aptr = aptr->next) {
 590
 591                for (plist = aptr->plist;
 592                     plist != (struct page_list *)0;
 593                     plist = plist->next) {
 594
 595                        for (gfunc = (struct gfuncs *)plist->first;
 596                             gfunc < (struct gfuncs *)plist->ptr;
 597                             gfunc++) {
 598
 599                                *(gfunc->unique_ptr) = (struct hasharc *)0;
 600                        }
 601                }
 602        }
 603
 604        /* Release memory */
 605        _profile_reset_alloc(pv, ACONTEXT_GPROF);
 606        _profile_reset_alloc(pv, ACONTEXT_GFUNC);
 607        _profile_reset_alloc(pv, ACONTEXT_PROF);
 608
 609        memset((void *)pv->profil_buf, '\0', pv->profil_info.profil_len);
 610        memset((void *)pv->md.hash_ptr, '\0', pv->md.hash_size * sizeof(struct hasharc *));
 611        memset((void *)&pv->stats, '\0', sizeof(pv->stats));
 612
 613        pv->stats.stats_size    = sizeof(struct profile_stats);
 614        pv->stats.major_version = PROFILE_MAJOR_VERSION;
 615        pv->stats.minor_version = PROFILE_MINOR_VERSION;
 616
 617        if (pv->active) {
 618                _profile_md_start();
 619        }
 620}
 621
 622
 623/*
 624 * Machine dependent function to write out gprof records.
 625 */
 626
 627size_t
 628_gprof_write(struct profile_vars *pv, struct callback *callback_ptr)
 629{
 630        struct alloc_context *aptr;
 631        struct page_list *plist;
 632        size_t bytes = 0;
 633        struct hasharc *hptr;
 634        int i;
 635
 636        for (aptr = pv->acontext[ACONTEXT_GPROF];
 637             aptr != (struct alloc_context *)0;
 638             aptr = aptr->next) {
 639
 640                for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) {
 641                        hptr = (struct hasharc *)plist->first;
 642                        for (i = 0; i < plist->num_allocations; (i++, hptr++)) {
 643
 644                                struct gprof_arc arc = hptr->arc;
 645                                int nrecs = 1 + (hptr->overflow * 2);
 646                                int j;
 647
 648                                if (pv->check_funcs) {
 649                                        if (arc.frompc < pv->profil_info.lowpc ||
 650                                            arc.frompc > pv->profil_info.highpc) {
 651
 652                                                arc.frompc = (prof_uptrint_t)pv->bogus_func;
 653                                        }
 654
 655                                        if (arc.selfpc < pv->profil_info.lowpc ||
 656                                            arc.selfpc > pv->profil_info.highpc) {
 657
 658                                                arc.selfpc = (prof_uptrint_t)pv->bogus_func;
 659                                        }
 660                                }
 661
 662                                /* For each overflow, emit 2 extra records with the count
 663                                   set to 0x80000000 */
 664                                for (j = 0; j < nrecs; j++) {
 665                                        bytes += sizeof (arc);
 666                                        if ((*pv->fwrite_func)((void *)&arc,
 667                                                               sizeof(arc),
 668                                                               1,
 669                                                               pv->stream) != 1) {
 670
 671                                                _profile_error(pv);
 672                                        }
 673
 674                                        arc.count = 0x80000000;
 675                                }
 676                        }
 677                }
 678        }
 679
 680        return bytes;
 681}
 682
 683
 684/*
 685 * Machine dependent function to write out prof records.
 686 */
 687
 688size_t
 689_prof_write(struct profile_vars *pv, struct callback *callback_ptr)
 690{
 691        struct alloc_context *aptr;
 692        struct page_list *plist;
 693        size_t bytes = 0;
 694        struct prof_ext prof_st;
 695        struct prof_int *pptr;
 696        struct gfuncs *gptr;
 697        int nrecs;
 698        int i, j;
 699
 700        /* Write out information prof_mcount collects */
 701        for (aptr = pv->acontext[ACONTEXT_PROF];
 702             aptr != (struct alloc_context *)0;
 703             aptr = aptr->next) {
 704
 705                for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) {
 706                        pptr = (struct prof_int *)plist->first;
 707
 708                        for (i = 0; i < plist->num_allocations; (i++, pptr++)) {
 709
 710                                /* Write out 2 records for each overflow, each with a
 711                                   count of 0x80000000 + the normal record */
 712                                prof_st = pptr->prof;
 713                                nrecs = 1 + (pptr->overflow * 2);
 714
 715                                for (j = 0; j < nrecs; j++) {
 716                                        bytes += sizeof (struct prof_ext);
 717                                        if ((*pv->fwrite_func)((void *)&prof_st,
 718                                                               sizeof(prof_st),
 719                                                               1,
 720                                                               pv->stream) != 1) {
 721
 722                                                _profile_error(pv);
 723                                        }
 724
 725                                        prof_st.cncall = 0x80000000;
 726                                }
 727                        }
 728                }
 729        }
 730
 731        /* Now write out the prof information that gprof collects */
 732        for (aptr = pv->acontext[ACONTEXT_GFUNC];
 733             aptr != (struct alloc_context *)0;
 734             aptr = aptr->next) {
 735
 736                for (plist = aptr->plist; plist != (struct page_list *)0; plist = plist->next) {
 737                        gptr = (struct gfuncs *)plist->first;
 738
 739                        for (i = 0; i < plist->num_allocations; (i++, gptr++)) {
 740
 741                                /* Write out 2 records for each overflow, each with a
 742                                   count of 0x80000000 + the normal record */
 743                                prof_st = gptr->prof.prof;
 744                                nrecs = 1 + (gptr->prof.overflow * 2);
 745
 746                                for (j = 0; j < nrecs; j++) {
 747                                        bytes += sizeof (struct prof_ext);
 748                                        if ((*pv->fwrite_func)((void *)&prof_st,
 749                                                               sizeof(prof_st),
 750                                                               1,
 751                                                               pv->stream) != 1) {
 752
 753                                                _profile_error(pv);
 754                                        }
 755
 756                                        prof_st.cncall = 0x80000000;
 757                                }
 758                        }
 759                }
 760        }
 761
 762        return bytes;
 763}
 764
 765
 766/*
 767 * Update any statistics.  For the 386, calculate the hash table loading factor.
 768 * Also figure out how many overflows occurred.
 769 */
 770
 771void
 772_profile_update_stats(struct profile_vars *pv)
 773{
 774        struct alloc_context *aptr;
 775        struct page_list *plist;
 776        struct hasharc *hptr;
 777        struct prof_int *pptr;
 778        struct gfuncs *fptr;
 779        LHISTCOUNTER *lptr;
 780        int i;
 781
 782        for(i = 0; i < MAX_BUCKETS+1; i++) {
 783                pv->stats.buckets[i] = 0;
 784        }
 785
 786        pv->stats.hash_buckets = 0;
 787
 788        if (pv->md.hash_ptr) {
 789                for (i = 0; i < pv->md.hash_size; i++) {
 790                        long nbuckets = 0;
 791                        struct hasharc *hptr;
 792
 793                        for (hptr = pv->md.hash_ptr[i]; hptr; hptr = hptr->next) {
 794                                nbuckets++;
 795                        }
 796
 797                        pv->stats.buckets[ (nbuckets < MAX_BUCKETS) ? nbuckets : MAX_BUCKETS ]++;
 798                        if (pv->stats.hash_buckets < nbuckets) {
 799                                pv->stats.hash_buckets = nbuckets;
 800                        }
 801                }
 802        }
 803
 804        /* Count how many times functions are out of bounds */
 805        if (pv->check_funcs) {
 806                pv->stats.bogus_count = 0;
 807
 808                for (aptr = pv->acontext[ACONTEXT_GPROF];
 809                     aptr != (struct alloc_context *)0;
 810                     aptr = aptr->next) {
 811
 812                        for (plist = aptr->plist;
 813                             plist != (struct page_list *)0;
 814                             plist = plist->next) {
 815
 816                                hptr = (struct hasharc *)plist->first;
 817                                for (i = 0; i < plist->num_allocations; (i++, hptr++)) {
 818
 819                                        if (hptr->arc.frompc < pv->profil_info.lowpc ||
 820                                            hptr->arc.frompc > pv->profil_info.highpc) {
 821                                                pv->stats.bogus_count++;
 822                                        }
 823
 824                                        if (hptr->arc.selfpc < pv->profil_info.lowpc ||
 825                                            hptr->arc.selfpc > pv->profil_info.highpc) {
 826                                                pv->stats.bogus_count++;
 827                                        }
 828                                }
 829                        }
 830                }
 831        }
 832
 833        /* Figure out how many overflows occurred */
 834        PROF_ULONG_TO_CNT(pv->stats.prof_overflow, 0);
 835        PROF_ULONG_TO_CNT(pv->stats.gprof_overflow, 0);
 836
 837        for (aptr = pv->acontext[ACONTEXT_GPROF];
 838             aptr != (struct alloc_context *)0;
 839             aptr = aptr->next) {
 840
 841                for (plist = aptr->plist;
 842                     plist != (struct page_list *)0;
 843                     plist = plist->next) {
 844
 845                        hptr = (struct hasharc *)plist->first;
 846                        for (i = 0; i < plist->num_allocations; (i++, hptr++)) {
 847                                PROF_CNT_ADD(pv->stats.gprof_overflow, hptr->overflow);
 848                        }
 849                }
 850        }
 851
 852        for (aptr = pv->acontext[ACONTEXT_PROF];
 853             aptr != (struct alloc_context *)0;
 854             aptr = aptr->next) {
 855
 856                for (plist = aptr->plist;
 857                     plist != (struct page_list *)0;
 858                     plist = plist->next) {
 859
 860                        pptr = (struct prof_int *)plist->first;
 861                        for (i = 0; i < plist->num_allocations; (i++, pptr++)) {
 862                                PROF_CNT_ADD(pv->stats.prof_overflow, pptr->overflow);
 863                        }
 864                }
 865        }
 866
 867        for (aptr = pv->acontext[ACONTEXT_GFUNC];
 868             aptr != (struct alloc_context *)0;
 869             aptr = aptr->next) {
 870
 871                for (plist = aptr->plist;
 872                     plist != (struct page_list *)0;
 873                     plist = plist->next) {
 874
 875                        fptr = (struct gfuncs *)plist->first;
 876                        for (i = 0; i < plist->num_allocations; (i++, fptr++)) {
 877                                PROF_CNT_ADD(pv->stats.prof_overflow, fptr->prof.overflow);
 878                        }
 879                }
 880        }
 881
 882        /* Now go through & count how many times the LHISTCOUNTER overflowed into a 2nd word */
 883        lptr = (LHISTCOUNTER *)pv->profil_buf;
 884
 885        if (pv->use_profil &&
 886            pv->profil_info.counter_size == sizeof(LHISTCOUNTER) &&
 887            lptr != (LHISTCOUNTER *)0) {
 888
 889                PROF_ULONG_TO_CNT(pv->stats.overflow_ticks, 0);
 890                for (i = 0; i < pv->stats.profil_buckets; i++) {
 891                        PROF_CNT_ADD(pv->stats.overflow_ticks, lptr[i].high);
 892                }
 893        }
 894}
 895
 896#if !defined(_KERNEL) && !defined(MACH_KERNEL)
 897
 898/*
 899 * Routine callable from the debugger that prints the statistics.
 900 */
 901
 902int _profile_debug(void)
 903{
 904        _profile_update_stats(&_profile_vars);
 905        _profile_print_stats(stderr, &_profile_vars.stats, &_profile_vars.profil_info);
 906        return 0;
 907}
 908
 909/*
 910 * Print the statistics structure in a meaningful way.
 911 */
 912
 913void _profile_print_stats(FILE *stream,
 914                          const struct profile_stats *stats,
 915                          const struct profile_profil *pinfo)
 916{
 917        int i;
 918        prof_cnt_t total_hits;
 919        acontext_type_t ac;
 920        int width_cname = 0;
 921        int width_alloc = 0;
 922        int width_wasted = 0;
 923        int width_overhead = 0;
 924        int width_context = 0;
 925        static const char *cname[ACONTEXT_MAX] = ACONTEXT_NAMES;
 926        char buf[20];
 927
 928        if (!stats) {
 929                return;
 930        }
 931
 932        if (!stream) {
 933                stream = stdout;
 934        }
 935
 936        sprintf(buf, "%ld.%ld", (long)stats->major_version, (long)stats->minor_version);
 937        fprintf(stream, "%12s profiling version number\n", buf);
 938        fprintf(stream, "%12lu size of profile_vars\n", (long unsigned)sizeof(struct profile_vars));
 939        fprintf(stream, "%12lu size of profile_stats\n", (long unsigned)sizeof(struct profile_stats));
 940        fprintf(stream, "%12lu size of profile_md\n", (long unsigned)sizeof(struct profile_md));
 941        fprintf(stream, "%12s calls to _{,g}prof_mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->cnt));
 942        fprintf(stream, "%12s calls to old mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->old_mcount));
 943        fprintf(stream, "%12s calls to _dummy_mcount\n", PROF_CNT_TO_DECIMAL((char *)0, stats->dummy));
 944        fprintf(stream, "%12lu functions profiled\n", (long unsigned)stats->prof_records);
 945        fprintf(stream, "%12lu gprof arcs\n", (long unsigned)stats->gprof_records);
 946
 947        if (pinfo) {
 948                fprintf(stream, "%12lu profil buckets\n", (long unsigned)stats->profil_buckets);
 949                fprintf(stream, "%12lu profil lowpc  [0x%lx]\n",
 950                        (long unsigned)pinfo->lowpc,
 951                        (long unsigned)pinfo->lowpc);
 952
 953                fprintf(stream, "%12lu profil highpc [0x%lx]\n",
 954                        (long unsigned)pinfo->highpc,
 955                        (long unsigned)pinfo->highpc);
 956
 957                fprintf(stream, "%12lu profil highpc-lowpc\n", (long unsigned)(pinfo->highpc - pinfo->lowpc));
 958                fprintf(stream, "%12lu profil buffer length\n", (long unsigned)pinfo->profil_len);
 959                fprintf(stream, "%12lu profil sizeof counters\n", (long unsigned)pinfo->counter_size);
 960                fprintf(stream, "%12lu profil scale (%g)\n",
 961                        (long unsigned)pinfo->scale,
 962                        ((double)pinfo->scale) / ((double) 0x10000));
 963
 964
 965                for (i = 0; i < sizeof (pinfo->profil_unused) / sizeof (pinfo->profil_unused[0]); i++) {
 966                        if (pinfo->profil_unused[i]) {
 967                                fprintf(stream, "%12lu profil unused[%2d] {0x%.8lx}\n",
 968                                        (long unsigned)pinfo->profil_unused[i],
 969                                        i,
 970                                        (long unsigned)pinfo->profil_unused[i]);
 971                        }
 972                }
 973        }
 974
 975        if (stats->max_cpu) {
 976                fprintf(stream, "%12lu current cpu/thread\n", (long unsigned)stats->my_cpu);
 977                fprintf(stream, "%12lu max cpu/thread+1\n", (long unsigned)stats->max_cpu);
 978        }
 979
 980        if (stats->bogus_count != 0) {
 981                fprintf(stream,
 982                        "%12lu gprof functions found outside of range\n",
 983                        (long unsigned)stats->bogus_count);
 984        }
 985
 986        if (PROF_CNT_NE_0(stats->too_low)) {
 987                fprintf(stream,
 988                        "%12s histogram ticks were too low\n",
 989                        PROF_CNT_TO_DECIMAL((char *)0, stats->too_low));
 990        }
 991
 992        if (PROF_CNT_NE_0(stats->too_high)) {
 993                fprintf(stream,
 994                        "%12s histogram ticks were too high\n",
 995                        PROF_CNT_TO_DECIMAL((char *)0, stats->too_high));
 996        }
 997
 998        if (PROF_CNT_NE_0(stats->acontext_locked)) {
 999                fprintf(stream,
1000                        "%12s times an allocation context was locked\n",
1001                        PROF_CNT_TO_DECIMAL((char *)0, stats->acontext_locked));
1002        }
1003
1004        if (PROF_CNT_NE_0(stats->kernel_ticks)
1005            || PROF_CNT_NE_0(stats->user_ticks)
1006            || PROF_CNT_NE_0(stats->idle_ticks)) {
1007
1008                prof_cnt_t total_ticks;
1009                long double total_ticks_dbl;
1010
1011                total_ticks = stats->kernel_ticks;
1012                PROF_CNT_LADD(total_ticks, stats->user_ticks);
1013                PROF_CNT_LADD(total_ticks, stats->idle_ticks);
1014                total_ticks_dbl = PROF_CNT_TO_LDOUBLE(total_ticks);
1015
1016                fprintf(stream,
1017                        "%12s total ticks\n",
1018                        PROF_CNT_TO_DECIMAL((char *)0, total_ticks));
1019
1020                fprintf(stream,
1021                        "%12s ticks within the kernel (%5.2Lf%%)\n",
1022                        PROF_CNT_TO_DECIMAL((char *)0, stats->kernel_ticks),
1023                        100.0L * (PROF_CNT_TO_LDOUBLE(stats->kernel_ticks) / total_ticks_dbl));
1024
1025                fprintf(stream,
1026                        "%12s ticks within user space (%5.2Lf%%)\n",
1027                        PROF_CNT_TO_DECIMAL((char *)0, stats->user_ticks),
1028                        100.0L * (PROF_CNT_TO_LDOUBLE(stats->user_ticks) / total_ticks_dbl));
1029
1030                fprintf(stream,
1031                        "%12s ticks idle              (%5.2Lf%%)\n",
1032                        PROF_CNT_TO_DECIMAL((char *)0, stats->idle_ticks),
1033                        100.0L * (PROF_CNT_TO_LDOUBLE(stats->idle_ticks) / total_ticks_dbl));
1034        }
1035
1036        if (PROF_CNT_NE_0(stats->overflow_ticks)) {
1037                fprintf(stream, "%12s times a HISTCOUNTER counter would have overflowed\n",
1038                        PROF_CNT_TO_DECIMAL((char *)0, stats->overflow_ticks));
1039        }
1040
1041        if (PROF_CNT_NE_0(stats->hash_num)) {
1042                long double total_buckets = 0.0L;
1043
1044                for (i = 0; i <= MAX_BUCKETS; i++) {
1045                        total_buckets += (long double)stats->buckets[i];
1046                }
1047
1048                fprintf(stream, "%12lu max bucket(s) on hash chain.\n", (long unsigned)stats->hash_buckets);
1049                for (i = 0; i < MAX_BUCKETS; i++) {
1050                        if (stats->buckets[i] != 0) {
1051                                fprintf(stream, "%12lu bucket(s) had %d entries (%5.2Lf%%)\n",
1052                                        (long unsigned)stats->buckets[i], i,
1053                                        100.0L * ((long double)stats->buckets[i] / total_buckets));
1054                        }
1055                }
1056
1057                if (stats->buckets[MAX_BUCKETS] != 0) {
1058                        fprintf(stream, "%12lu bucket(s) had more than %d entries (%5.2Lf%%)\n",
1059                                (long unsigned)stats->buckets[MAX_BUCKETS], MAX_BUCKETS,
1060                                100.0L * ((long double)stats->buckets[MAX_BUCKETS] / total_buckets));
1061                }
1062        }
1063
1064        PROF_ULONG_TO_CNT(total_hits, 0);
1065        for (i = 0; i < MAX_CACHE; i++) {
1066                PROF_CNT_LADD(total_hits, stats->cache_hits[i]);
1067        }
1068
1069        if (PROF_CNT_NE_0(total_hits)) {
1070                long double total               = PROF_CNT_TO_LDOUBLE(stats->cnt);
1071                long double total_hits_dbl      = PROF_CNT_TO_LDOUBLE(total_hits);
1072
1073                fprintf(stream,
1074                        "%12s cache hits (%.2Lf%%)\n",
1075                        PROF_CNT_TO_DECIMAL((char *)0, total_hits),
1076                        100.0L * (total_hits_dbl / total));
1077
1078                for (i = 0; i < MAX_CACHE; i++) {
1079                        if (PROF_CNT_NE_0(stats->cache_hits[i])) {
1080                                fprintf(stream,
1081                                        "%12s times cache#%d matched (%5.2Lf%% of cache hits, %5.2Lf%% total)\n",
1082                                        PROF_CNT_TO_DECIMAL((char *)0, stats->cache_hits[i]),
1083                                        i+1,
1084                                        100.0L * (PROF_CNT_TO_LDOUBLE(stats->cache_hits[i]) / total_hits_dbl),
1085                                        100.0L * (PROF_CNT_TO_LDOUBLE(stats->cache_hits[i]) / total));
1086                        }
1087                }
1088
1089                if (PROF_CNT_NE_0(stats->hash_num)) {
1090                        fprintf(stream, "%12s times hash table searched\n", PROF_CNT_TO_DECIMAL((char *)0, stats->hash_num));
1091                        fprintf(stream, "%12s hash buckets searched\n", PROF_CNT_TO_DECIMAL((char *)0, stats->hash_search));
1092                        fprintf(stream, "%12.4Lf average buckets searched\n",
1093                                PROF_CNT_TO_LDOUBLE(stats->hash_search) / PROF_CNT_TO_LDOUBLE(stats->hash_num));
1094                }
1095        }
1096
1097        for (i = 0; i < sizeof (stats->stats_unused) / sizeof (stats->stats_unused[0]); i++) {
1098                if (PROF_CNT_NE_0(stats->stats_unused[i])) {
1099                        fprintf(stream, "%12s unused[%2d] {0x%.8lx 0x%.8lx}\n",
1100                                PROF_CNT_TO_DECIMAL((char *)0, stats->stats_unused[i]),
1101                                i,
1102                                (unsigned long)stats->stats_unused[i].high,
1103                                (unsigned long)stats->stats_unused[i].low);
1104                }
1105        }
1106
1107        /* Get the width for the allocation contexts */
1108        for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) {
1109                int len;
1110
1111                if (stats->num_context[ac] == 0) {
1112                        continue;
1113                }
1114
1115                len = strlen (cname[ac]);
1116                if (len > width_cname)
1117                        width_cname = len;
1118
1119                len = sprintf (buf, "%lu", (long unsigned)stats->num_alloc[ac]);
1120                if (len > width_alloc)
1121                        width_alloc = len;
1122
1123                len = sprintf (buf, "%lu", (long unsigned)stats->wasted[ac]);
1124                if (len > width_wasted)
1125                        width_wasted = len;
1126
1127                len = sprintf (buf, "%lu", (long unsigned)stats->overhead[ac]);
1128                if (len > width_overhead)
1129                        width_overhead = len;
1130
1131                len = sprintf (buf, "%lu", (long unsigned)stats->num_context[ac]);
1132                if (len > width_context)
1133                        width_context = len;
1134        }
1135
1136        /* Print info about allocation contexts */
1137        for (ac = ACONTEXT_FIRST; ac < ACONTEXT_MAX; ac++) {
1138                if (stats->num_context[ac] == 0) {
1139                        continue;
1140                }
1141
1142                fprintf (stream,
1143                         "%12lu bytes in %-*s %*lu alloc, %*lu unused, %*lu over, %*lu context\n",
1144                         (long unsigned)stats->bytes_alloc[ac],
1145                         width_cname,    cname[ac],
1146                         width_alloc,    (long unsigned)stats->num_alloc[ac],
1147                         width_wasted,   (long unsigned)stats->wasted[ac],
1148                         width_overhead, (long unsigned)stats->overhead[ac],
1149                         width_context,  (long unsigned)stats->num_context[ac]);
1150        }
1151}
1152
1153
1154/*
1155 * Merge a new statistics field into an old one.
1156 */
1157
1158void _profile_merge_stats(struct profile_stats  *old_stats, const struct profile_stats  *new_stats)
1159{
1160        int i;
1161
1162        /* If nothing passed, just return */
1163        if (!old_stats || !new_stats)
1164                return;
1165
1166        /* If the old_stats has not been initialized, just copy in the new stats */
1167        if (old_stats->major_version == 0) {
1168            *old_stats = *new_stats;
1169
1170        /* Otherwise, update stats, field by field */
1171        } else {
1172                if (old_stats->prof_records < new_stats->prof_records)
1173                        old_stats->prof_records = new_stats->prof_records;
1174
1175                if (old_stats->gprof_records < new_stats->gprof_records)
1176                        old_stats->gprof_records = new_stats->gprof_records;
1177
1178                if (old_stats->hash_buckets < new_stats->hash_buckets)
1179                        old_stats->hash_buckets = new_stats->hash_buckets;
1180
1181                if (old_stats->bogus_count < new_stats->bogus_count)
1182                        old_stats->bogus_count = new_stats->bogus_count;
1183
1184                PROF_CNT_LADD(old_stats->cnt,             new_stats->cnt);
1185                PROF_CNT_LADD(old_stats->dummy,           new_stats->dummy);
1186                PROF_CNT_LADD(old_stats->old_mcount,      new_stats->old_mcount);
1187                PROF_CNT_LADD(old_stats->hash_search,     new_stats->hash_search);
1188                PROF_CNT_LADD(old_stats->hash_num,        new_stats->hash_num);
1189                PROF_CNT_LADD(old_stats->user_ticks,      new_stats->user_ticks);
1190                PROF_CNT_LADD(old_stats->kernel_ticks,    new_stats->kernel_ticks);
1191                PROF_CNT_LADD(old_stats->idle_ticks,      new_stats->idle_ticks);
1192                PROF_CNT_LADD(old_stats->overflow_ticks,  new_stats->overflow_ticks);
1193                PROF_CNT_LADD(old_stats->acontext_locked, new_stats->acontext_locked);
1194                PROF_CNT_LADD(old_stats->too_low,         new_stats->too_low);
1195                PROF_CNT_LADD(old_stats->too_high,        new_stats->too_high);
1196                PROF_CNT_LADD(old_stats->prof_overflow,   new_stats->prof_overflow);
1197                PROF_CNT_LADD(old_stats->gprof_overflow,  new_stats->gprof_overflow);
1198
1199                for (i = 0; i < (int)ACONTEXT_MAX; i++) {
1200                        if (old_stats->num_alloc[i] < new_stats->num_alloc[i])
1201                                old_stats->num_alloc[i] = new_stats->num_alloc[i];
1202
1203                        if (old_stats->bytes_alloc[i] < new_stats->bytes_alloc[i])
1204                                old_stats->bytes_alloc[i] = new_stats->bytes_alloc[i];
1205
1206                        if (old_stats->num_context[i] < new_stats->num_context[i])
1207                                old_stats->num_context[i] = new_stats->num_context[i];
1208
1209                        if (old_stats->wasted[i] < new_stats->wasted[i])
1210                                old_stats->wasted[i] = new_stats->wasted[i];
1211
1212                        if (old_stats->overhead[i] < new_stats->overhead[i])
1213                                old_stats->overhead[i] = new_stats->overhead[i];
1214
1215                }
1216
1217                for (i = 0; i < MAX_BUCKETS+1; i++) {
1218                        if (old_stats->buckets[i] < new_stats->buckets[i])
1219                                old_stats->buckets[i] = new_stats->buckets[i];
1220                }
1221
1222                for (i = 0; i < MAX_CACHE; i++) {
1223                        PROF_CNT_LADD(old_stats->cache_hits[i], new_stats->cache_hits[i]);
1224                }
1225
1226                for (i = 0; i < sizeof(old_stats->stats_unused) / sizeof(old_stats->stats_unused[0]); i++) {
1227                        PROF_CNT_LADD(old_stats->stats_unused[i], new_stats->stats_unused[i]);
1228                }
1229        }
1230}
1231
1232#endif
1233
1234
1235/*
1236 * Invalid function address used when checking of function addresses is
1237 * desired for gprof arcs, and we discover an address out of bounds.
1238 * There should be no callers of this function.
1239 */
1240
1241void
1242_bogus_function(void)
1243{
1244}
1245
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.