|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * HISTORY ! 27: * ! 28: * Revision 1.1.1.1 1998/09/22 21:05:49 wsanchez ! 29: * Import of Mac OS X kernel (~semeria) ! 30: * ! 31: * Revision 1.1.1.1 1998/03/07 02:26:08 wsanchez ! 32: * Import of OSF Mach kernel (~mburg) ! 33: * ! 34: * Revision 1.1.7.1 1997/09/22 17:41:24 barbou ! 35: * MP+RT: protect cpu_number() usage against preemption. ! 36: * [97/09/16 barbou] ! 37: * ! 38: * Revision 1.1.5.1 1995/01/06 19:53:37 devrcs ! 39: * mk6 CR668 - 1.3b26 merge ! 40: * new file for mk6 ! 41: * [1994/10/12 22:25:20 dwm] ! 42: * ! 43: * Revision 1.1.2.2 1994/05/16 19:19:17 meissner ! 44: * Add support for converting 64-bit integers to a decimal string. ! 45: * Use the correct address (selfpc) when creating the prof header for gprof. ! 46: * [1994/04/28 21:44:59 meissner] ! 47: * ! 48: * Revision 1.1.2.1 1994/04/08 17:51:42 meissner ! 49: * Make most stats 64 bits, except for things like memory allocation. ! 50: * [1994/04/02 14:58:21 meissner] ! 51: * ! 52: * Do not provide old mcount support under MK or server. ! 53: * Fixup stats size so it is the same as in profile-md.h. ! 54: * [1994/03/29 21:00:03 meissner] ! 55: * ! 56: * Use faster sequence for overflow addition. ! 57: * Keep {dummy,prof,gprof,old}_mcount counts in double precision. ! 58: * Add kernel NCPUS > 1 support. ! 59: * [1994/03/17 20:13:23 meissner] ! 60: * ! 61: * Add gprof/prof overflow support ! 62: * [1994/03/17 14:56:44 meissner] ! 63: * ! 64: * Add size of histogram counters & unused fields to profile_profil struct ! 65: * [1994/02/17 21:41:44 meissner] ! 66: * ! 67: * Add too_low/too_high to profile_stats. ! 68: * [1994/02/16 22:38:11 meissner] ! 69: * ! 70: * Bump # allocation contexts to 32 from 16. ! 71: * Store unique ptr address in gprof function header structure for _profile_reset. ! 72: * Add new fields from profile-{internal,md}.h. ! 73: * Align loop looking for an unlocked acontext. ! 74: * Count # times a locked context block was found. ! 75: * Expand copyright. ! 76: * [1994/02/07 12:40:56 meissner] ! 77: * ! 78: * Keep track of the number of times the kernel overflows the HISTCOUNTER counter. ! 79: * [1994/02/03 20:13:23 meissner] ! 80: * ! 81: * Add stats for {user,kernel,idle} mode in the kernel. ! 82: * [1994/02/03 15:17:22 meissner] ! 83: * ! 84: * No change. ! 85: * [1994/02/03 00:58:49 meissner] ! 86: * ! 87: * Combine _profile_{vars,stats,md}; Allow more than one _profile_vars. ! 88: * [1994/02/01 12:03:56 meissner] ! 89: * ! 90: * Move _mcount_ptr to be closer to other data declarations. ! 91: * Add text_len to profile_profil structure for mk. ! 92: * Split records_cnt into prof_cnt/gprof_cnt. ! 93: * Always update prof_cnt/gprof_cnt even if not DO_STATS. ! 94: * Add current/max cpu indicator to stats for kernel. ! 95: * [1994/01/28 23:33:20 meissner] ! 96: * ! 97: * Don't do 4+Lgotoff(lab), use separate labels. ! 98: * Change GPROF_HASH_SHIFT to 9 (from 8). ! 99: * [1994/01/26 22:00:59 meissner] ! 100: * ! 101: * Fixup NO_RECURSIVE_ALLOC to do byte loads, not word loads. ! 102: * [1994/01/26 20:30:57 meissner] ! 103: * ! 104: * Move callback pointers into separate allocation context. ! 105: * Add size fields for other structures to profile-vars. ! 106: * Allocate string table as one large allocation. ! 107: * Rewrite old mcount code once again. ! 108: * Use multiply to make hash value, not divide. ! 109: * Hash table is now a power of two. ! 110: * [1994/01/26 20:23:32 meissner] ! 111: * ! 112: * Cut hash table size back to 16189. ! 113: * Add size fields to all structures. ! 114: * Add major/minor version number to _profile_md. ! 115: * Move allocation context block pointers to _profile_vars. ! 116: * Move _gprof_dummy after _profile_md. ! 117: * New function header code now falls into hash an element ! 118: * to avoid having the hash code duplicated or use a macro. ! 119: * Fix bug in _gprof_mcount with ELF shared libraries. ! 120: * [1994/01/25 01:45:59 meissner] ! 121: * ! 122: * Move init functions to C code; rearrange profil varaibles. ! 123: * [1994/01/22 01:11:14 meissner] ! 124: * ! 125: * No change. ! 126: * [1994/01/20 20:56:43 meissner] ! 127: * ! 128: * Fixup copyright. ! 129: * [1994/01/18 23:07:39 meissner] ! 130: * ! 131: * Make flags byte-sized. ! 132: * Add have_bb flag. ! 133: * Add init_format flag. ! 134: * Always put word size multipler first in .space. ! 135: * [1994/01/18 21:57:14 meissner] ! 136: * ! 137: * Fix elfpic problems in last change. ! 138: * [1994/01/16 14:04:26 meissner] ! 139: * ! 140: * Rewrite gprof caching to be faster & not need a lock. ! 141: * Record prof information for gprof too. ! 142: * Bump reserved stats to 64. ! 143: * Bump up hash table size 30799. ! 144: * Conditionally use lock prefix. ! 145: * Change most #ifdef's to #if. ! 146: * DEBUG_PROFILE turns on stack frames now. ! 147: * Conditionally add externs to gprof to determine where time is spent. ! 148: * Prof_mcount uses xchgl to update function pointer. ! 149: * [1994/01/15 18:40:33 meissner] ! 150: * ! 151: * Fix a comment. ! 152: * Separate statistics from debugging (though debugging turns it on). ! 153: * Remove debug code that traces each gprof request. ! 154: * [1994/01/15 00:59:02 meissner] ! 155: * ! 156: * Move max hash bucket calculation into _gprof_write & put info in stats structure. ! 157: * [1994/01/04 16:15:14 meissner] ! 158: * ! 159: * Use _profile_printf to write diagnostics; add diag_stream to hold stream to write to. ! 160: * [1994/01/04 15:37:44 meissner] ! 161: * ! 162: * Add more allocation memory pools (gprof function hdrs in particular). ! 163: * For prof, gprof arc, and gprof function hdrs, allocate 16 pages at a time. ! 164: * Add major/minor version numbers to _profile_{vars,stats}. ! 165: * Add # profil buckets field to _profil_stats. ! 166: * [19 ! 167: * ! 168: * $EndLog$ ! 169: */ ! 170: ! 171: /* ! 172: * Common 386 profiling module that is shared between the kernel, mach ! 173: * servers, and the user space library. Each environment includes ! 174: * this file. ! 175: */ ! 176: ! 177: .file "profile-asm.s" ! 178: ! 179: #include <cpus.h> ! 180: ! 181: #include <machine/asm.h> ! 182: ! 183: /* ! 184: * By default, debugging turns on statistics and stack frames. ! 185: */ ! 186: ! 187: #if DEBUG_PROFILE ! 188: #ifndef DO_STATS ! 189: #define DO_STATS 1 ! 190: #endif ! 191: ! 192: #ifndef STACK_FRAMES ! 193: #define STACK_FRAMES 1 ! 194: #endif ! 195: #endif ! 196: ! 197: #ifndef OLD_MCOUNT ! 198: #define OLD_MCOUNT 0 /* do not compile old code for mcount */ ! 199: #endif ! 200: ! 201: #ifndef DO_STATS ! 202: #define DO_STATS 1 /* compile in statistics code */ ! 203: #endif ! 204: ! 205: #ifndef DO_LOCK ! 206: #define DO_LOCK 0 /* use lock; in front of increments */ ! 207: #endif ! 208: ! 209: #ifndef LOCK_STATS ! 210: #define LOCK_STATS DO_LOCK /* update stats with lock set */ ! 211: #endif ! 212: ! 213: #ifndef STACK_FRAMES ! 214: #define STACK_FRAMES 0 /* create stack frames for debugger */ ! 215: #endif ! 216: ! 217: #ifndef NO_RECURSIVE_ALLOC ! 218: #define NO_RECURSIVE_ALLOC 0 /* check for recursive allocs */ ! 219: /* (not thread safe!) */ ! 220: #endif ! 221: ! 222: #ifndef MARK_GPROF ! 223: #define MARK_GPROF 0 /* add externs for gprof profiling */ ! 224: #endif ! 225: ! 226: #ifndef OVERFLOW ! 227: #define OVERFLOW 1 /* add overflow checking support */ ! 228: #endif ! 229: ! 230: /* ! 231: * Turn on the use of the lock prefix if desired. ! 232: */ ! 233: ! 234: #ifndef LOCK ! 235: #if DO_LOCK ! 236: #define LOCK lock; ! 237: #else ! 238: #define LOCK ! 239: #endif ! 240: #endif ! 241: ! 242: #ifndef SLOCK ! 243: #if LOCK_STATS ! 244: #define SLOCK LOCK ! 245: #else ! 246: #define SLOCK ! 247: #endif ! 248: #endif ! 249: ! 250: /* ! 251: * Double or single precision incrementing ! 252: */ ! 253: ! 254: #if OVERFLOW ! 255: #define DINC(mem) LOCK addl $1,mem; LOCK adcl $0,4+mem ! 256: #define DINC2(mem,mem2) LOCK addl $1,mem; LOCK adcl $0,mem2 ! 257: #define SDINC(mem) SLOCK addl $1,mem; SLOCK adcl $0,4+mem ! 258: #define SDADD(val,mem) SLOCK addl val,mem; SLOCK adcl $0,4+mem ! 259: #define SDADDNEG(val,mem) SLOCK subl val,mem; SLOCK adcl $0,4+mem ! 260: #define SDSUB(val,mem) SLOCK subl val,mem; SLOCK sbbl $0,4+mem ! 261: ! 262: #else ! 263: #define DINC(mem) LOCK incl mem ! 264: #define DINC2(mem,mem2) LOCK incl mem ! 265: #define SDINC(mem) SLOCK incl mem ! 266: #define SDADD(val,mem) SLOCK addl val,mem ! 267: #define SDADDNEG(val,mem) SLOCK subl val,mem ! 268: #define SDSUB(val,mem) SLOCK subl val,mem ! 269: #endif ! 270: ! 271: /* ! 272: * Stack frame support so that debugger traceback works. ! 273: */ ! 274: ! 275: #if STACK_FRAMES ! 276: #define ENTER pushl %ebp; movl %esp,%ebp ! 277: #define LEAVE0 popl %ebp ! 278: #define Estack 4 ! 279: #else ! 280: #define ENTER ! 281: #define LEAVE0 ! 282: #define Estack 0 ! 283: #endif ! 284: ! 285: /* ! 286: * Gprof profiling. ! 287: */ ! 288: ! 289: #if MARK_GPROF ! 290: #define MARK(name) .globl EXT(name); ELF_FUNC(EXT(name)); ELF_SIZE(EXT(name),0); LEXT(name) ! 291: #else ! 292: #define MARK(name) ! 293: #endif ! 294: ! 295: /* ! 296: * Profiling allocation context block. Each time memory is needed, the ! 297: * allocator loops until it finds an unlocked context block, and allocates ! 298: * from that block. If no context blocks are available, a new memory ! 299: * pool is allocated, and added to the end of the chain. ! 300: */ ! 301: ! 302: LCL(A_next) = 0 /* next context block link (must be 0) */ ! 303: LCL(A_plist) = LCL(A_next)+4 /* head of page list for context block */ ! 304: LCL(A_lock) = LCL(A_plist)+4 /* lock word */ ! 305: LCL(A_size) = LCL(A_lock)+4 /* size of context block */ ! 306: ! 307: #define A_next LCL(A_next) ! 308: #define A_plist LCL(A_plist) ! 309: #define A_lock LCL(A_lock) ! 310: #define A_size LCL(A_size) ! 311: ! 312: /* ! 313: * Allocation contexts used. ! 314: */ ! 315: ! 316: LCL(C_prof) = 0 /* prof records */ ! 317: LCL(C_gprof) = 1 /* gprof arc records */ ! 318: LCL(C_gfunc) = 2 /* gprof function headers */ ! 319: LCL(C_misc) = 3 /* misc. allocations */ ! 320: LCL(C_profil) = 4 /* memory for profil */ ! 321: LCL(C_dci) = 5 /* memory for dci */ ! 322: LCL(C_bb) = 6 /* memory for basic blocks */ ! 323: LCL(C_callback) = 7 /* memory for callbacks */ ! 324: LCL(C_max) = 32 /* # allocation contexts */ ! 325: ! 326: #define C_prof LCL(C_prof) ! 327: #define C_gprof LCL(C_gprof) ! 328: #define C_gfunc LCL(C_gfunc) ! 329: #define C_max LCL(C_max) ! 330: ! 331: /* ! 332: * Linked list of memory allocations. ! 333: */ ! 334: ! 335: LCL(M_first) = 0 /* pointer to first byte available */ ! 336: LCL(M_ptr) = LCL(M_first)+4 /* pointer to next available byte */ ! 337: LCL(M_next) = LCL(M_ptr)+4 /* next page allocated */ ! 338: LCL(M_nfree) = LCL(M_next)+4 /* # bytes available */ ! 339: LCL(M_nalloc) = LCL(M_nfree)+4 /* # bytes allocated */ ! 340: LCL(M_num) = LCL(M_nalloc)+4 /* # allocations done on this page */ ! 341: LCL(M_size) = LCL(M_num)+4 /* size of page header */ ! 342: ! 343: #define M_first LCL(M_first) ! 344: #define M_ptr LCL(M_ptr) ! 345: #define M_next LCL(M_next) ! 346: #define M_nfree LCL(M_nfree) ! 347: #define M_nalloc LCL(M_nalloc) ! 348: #define M_num LCL(M_num) ! 349: #define M_size LCL(M_size) ! 350: ! 351: /* ! 352: * Prof data type. ! 353: */ ! 354: ! 355: LCL(P_addr) = 0 /* function address */ ! 356: LCL(P_count) = LCL(P_addr)+4 /* # times function called */ ! 357: LCL(P_overflow) = LCL(P_count)+4 /* # times count overflowed */ ! 358: LCL(P_size) = LCL(P_overflow)+4 /* size of prof data type */ ! 359: ! 360: #define P_addr LCL(P_addr) ! 361: #define P_count LCL(P_count) ! 362: #define P_overflow LCL(P_overflow) ! 363: #define P_size LCL(P_size) ! 364: ! 365: /* ! 366: * Gprof data type. ! 367: */ ! 368: ! 369: LCL(G_next) = 0 /* next hash link (must be 0) */ ! 370: LCL(G_frompc) = LCL(G_next)+4 /* caller's caller */ ! 371: LCL(G_selfpc) = LCL(G_frompc)+4 /* caller's address */ ! 372: LCL(G_count) = LCL(G_selfpc)+4 /* # times arc traversed */ ! 373: LCL(G_overflow) = LCL(G_count)+4 /* # times count overflowed */ ! 374: LCL(G_size) = LCL(G_overflow)+4 /* size of gprof data type */ ! 375: ! 376: #define G_next LCL(G_next) ! 377: #define G_frompc LCL(G_frompc) ! 378: #define G_selfpc LCL(G_selfpc) ! 379: #define G_count LCL(G_count) ! 380: #define G_overflow LCL(G_overflow) ! 381: #define G_size LCL(G_size) ! 382: ! 383: /* ! 384: * Gprof header. ! 385: * ! 386: * At least one header is allocated for each unique function that is profiled. ! 387: * In order to save time calculating the hash value, the last H_maxcache ! 388: * distinct arcs are cached within this structure. Also, to avoid loading ! 389: * the GOT when searching the hash table, we copy the hash pointer to this ! 390: * structure, so that we only load the GOT when we need to allocate an arc. ! 391: */ ! 392: ! 393: LCL(H_maxcache) = 3 /* # of cache table entries */ ! 394: LCL(H_csize) = 4*LCL(H_maxcache) /* size of each cache array */ ! 395: ! 396: LCL(H_hash_ptr) = 0 /* hash table to use */ ! 397: LCL(H_unique_ptr) = LCL(H_hash_ptr)+4 /* function unique pointer */ ! 398: LCL(H_prof) = LCL(H_unique_ptr)+4 /* prof statistics */ ! 399: LCL(H_cache_ptr) = LCL(H_prof)+P_size /* cache table of element pointers */ ! 400: LCL(H_size) = LCL(H_cache_ptr)+LCL(H_csize) /* size of gprof header type */ ! 401: ! 402: #define H_maxcache LCL(H_maxcache) ! 403: #define H_csize LCL(H_csize) ! 404: #define H_hash_ptr LCL(H_hash_ptr) ! 405: #define H_unique_ptr LCL(H_unique_ptr) ! 406: #define H_prof LCL(H_prof) ! 407: #define H_cache_ptr LCL(H_cache_ptr) ! 408: #define H_size LCL(H_size) ! 409: ! 410: /* ! 411: * Number of digits needed to write a 64 bit number including trailing null. ! 412: * (rounded up to be divisable by 4). ! 413: */ ! 414: ! 415: #define N_digit 24 ! 416: ! 417: ! 418: .data ! 419: ! 420: /* ! 421: * Default gprof hash table size, which must be a power of two. ! 422: * The shift specifies how many low order bits to eliminate when ! 423: * calculating the hash value. ! 424: */ ! 425: ! 426: #ifndef GPROF_HASH_SIZE ! 427: #define GPROF_HASH_SIZE 16384 ! 428: #endif ! 429: ! 430: #ifndef GPROF_HASH_SHIFT ! 431: #define GPROF_HASH_SHIFT 9 ! 432: #endif ! 433: ! 434: #define GPROF_HASH_MASK (GPROF_HASH_SIZE-1) ! 435: ! 436: DATA(_profile_hash_size) ! 437: .long GPROF_HASH_SIZE ! 438: ENDDATA(_profile_hash_size) ! 439: ! 440: ! 441: ! 442: /* ! 443: * Pointer that the compiler uses to call to the appropriate mcount function. ! 444: */ ! 445: ! 446: DATA(_mcount_ptr) ! 447: .long EXT(_dummy_mcount) ! 448: ENDDATA(_mcount_ptr) ! 449: ! 450: /* ! 451: * Global profile variables. The structure that accesses this in C is declared ! 452: * in profile-internal.h. All items in .data that follow this will be used as ! 453: * one giant record, and each unique machine, thread, kgmon output or what have ! 454: * you will create a separate instance. Typically there is only one instance ! 455: * which will be the memory laid out below. ! 456: */ ! 457: ! 458: LCL(var_major_version) = 0 /* major version number */ ! 459: LCL(var_minor_version) = LCL(var_major_version)+4 /* minor version number */ ! 460: LCL(vars_size) = LCL(var_minor_version)+4 /* size of _profile_vars structure */ ! 461: LCL(plist_size) = LCL(vars_size)+4 /* size of page_list structure */ ! 462: LCL(acontext_size) = LCL(plist_size)+4 /* size of allocation contexts */ ! 463: LCL(callback_size) = LCL(acontext_size)+4 /* size of callback structure */ ! 464: LCL(type) = LCL(callback_size)+4 /* profile type (gprof, prof) */ ! 465: LCL(error_msg) = LCL(type)+4 /* error message for perror */ ! 466: LCL(filename) = LCL(error_msg)+4 /* filename to write to */ ! 467: LCL(str_ptr) = LCL(filename)+4 /* string table pointer */ ! 468: LCL(stream) = LCL(str_ptr)+4 /* stdio stream to write to */ ! 469: LCL(diag_stream) = LCL(stream)+4 /* stdio stream to write diagnostics to */ ! 470: LCL(fwrite_func) = LCL(diag_stream)+4 /* function like fwrite to output bytes */ ! 471: LCL(page_size) = LCL(fwrite_func)+4 /* page size in bytes */ ! 472: LCL(str_bytes) = LCL(page_size)+4 /* # bytes in string table */ ! 473: LCL(str_total) = LCL(str_bytes)+4 /* # total bytes allocated for string table */ ! 474: LCL(clock_ticks) = LCL(str_total)+4 /* # clock ticks per second */ ! 475: ! 476: /* profil variables */ ! 477: LCL(profil_start) = LCL(clock_ticks)+4 /* start of profil variables */ ! 478: LCL(lowpc) = LCL(clock_ticks)+4 /* lowest address */ ! 479: LCL(highpc) = LCL(lowpc)+4 /* highest address */ ! 480: LCL(text_len) = LCL(highpc)+4 /* highpc-lowpc */ ! 481: LCL(profil_len) = LCL(text_len)+4 /* size of profil buffer */ ! 482: LCL(counter_size) = LCL(profil_len)+4 /* size of indivual counter */ ! 483: LCL(scale) = LCL(counter_size)+4 /* scale factor */ ! 484: LCL(profil_unused) = LCL(scale)+4 /* unused fields */ ! 485: LCL(profil_end) = LCL(profil_unused)+4*8 /* end of profil_info structure */ ! 486: LCL(profil_buf) = LCL(profil_end) /* buffer for profil */ ! 487: ! 488: /* Output selection func ptrs */ ! 489: LCL(output_init) = LCL(profil_buf)+4 /* Initialization */ ! 490: LCL(output) = LCL(output_init)+4 /* Write out profiling info */ ! 491: LCL(output_ptr) = LCL(output)+4 /* Output specific data ptr */ ! 492: ! 493: /* Memory allocation support */ ! 494: LCL(acontext) = LCL(output_ptr)+4 /* pointers to allocation context blocks */ ! 495: ! 496: LCL(bogus_func) = LCL(acontext)+4*C_max /* function to use if gprof arc is bad */ ! 497: LCL(vars_unused) = LCL(bogus_func)+4 /* future growth */ ! 498: ! 499: /* flags */ ! 500: LCL(init) = LCL(vars_unused)+4*63 /* whether initializations were done */ ! 501: LCL(active) = LCL(init)+1 /* whether profiling is active */ ! 502: LCL(do_profile) = LCL(active)+1 /* whether to do profiling */ ! 503: LCL(use_dci) = LCL(do_profile)+1 /* whether to use DCI */ ! 504: LCL(use_profil) = LCL(use_dci)+1 /* whether to use profil */ ! 505: LCL(recursive_alloc) = LCL(use_profil)+1 /* alloc called recursively */ ! 506: LCL(output_uarea) = LCL(recursive_alloc)+1 /* output uarea */ ! 507: LCL(output_stats) = LCL(output_uarea)+1 /* output stats info */ ! 508: LCL(output_clock) = LCL(output_stats)+1 /* output the clock ticks */ ! 509: LCL(multiple_sections) = LCL(output_clock)+1 /* multiple sections are ok */ ! 510: LCL(have_bb) = LCL(multiple_sections)+1 /* whether we have basic block data */ ! 511: LCL(init_format) = LCL(have_bb)+1 /* The output format has been chosen */ ! 512: LCL(debug) = LCL(init_format)+1 /* Whether or not we are debugging */ ! 513: LCL(check_funcs) = LCL(debug)+1 /* Whether to check functions for validity */ ! 514: LCL(flag_unused) = LCL(check_funcs)+1 /* unused flags */ ! 515: LCL(end_of_vars) = LCL(flag_unused)+62 /* size of machine independent vars */ ! 516: ! 517: /* ! 518: * Data that contains profile statistics that can be dumped out ! 519: * into the {,g}mon.out file. This is defined in profile-md.h. ! 520: */ ! 521: ! 522: LCL(stats_start) = LCL(end_of_vars) /* start of stats substructure */ ! 523: LCL(stats_major_version)= LCL(stats_start) /* major version number */ ! 524: LCL(stats_minor_version)= LCL(stats_major_version)+4 /* minor version number */ ! 525: LCL(stats_size) = LCL(stats_minor_version)+4 /* size of _profile_stats structure */ ! 526: LCL(profil_buckets) = LCL(stats_size)+4 /* # profil buckets */ ! 527: LCL(my_cpu) = LCL(profil_buckets)+4 /* identify which cpu/thread this is */ ! 528: LCL(max_cpu) = LCL(my_cpu)+4 /* identify which cpu/thread this is */ ! 529: LCL(prof_records) = LCL(max_cpu)+4 /* # of profiled functions */ ! 530: LCL(gprof_records) = LCL(prof_records)+4 /* # of gprof arcs created */ ! 531: LCL(hash_buckets) = LCL(gprof_records)+4 /* max gprof hash buckets on a chain */ ! 532: LCL(bogus_count) = LCL(hash_buckets)+4 /* # bogus functions found in gprof */ ! 533: ! 534: LCL(cnt) = LCL(bogus_count)+4 /* # of _{prof,gprof}_mcount calls */ ! 535: LCL(dummy) = LCL(cnt)+8 /* # of _dummy_mcount calls */ ! 536: LCL(old_mcount) = LCL(dummy)+8 /* # of old mcount calls */ ! 537: LCL(hash_search) = LCL(old_mcount)+8 /* # gprof hash buckets searched */ ! 538: LCL(hash_num) = LCL(hash_search)+8 /* # times hash table searched */ ! 539: LCL(user_ticks) = LCL(hash_num)+8 /* # ticks within user space */ ! 540: LCL(kernel_ticks) = LCL(user_ticks)+8 /* # ticks within kernel space */ ! 541: LCL(idle_ticks) = LCL(kernel_ticks)+8 /* # ticks cpu was idle */ ! 542: LCL(overflow_ticks) = LCL(idle_ticks)+8 /* # ticks where histcounter overflowed */ ! 543: LCL(acontext_locked) = LCL(overflow_ticks)+8 /* # times an acontext was locked */ ! 544: LCL(too_low) = LCL(acontext_locked)+8 /* # times histogram tick too low */ ! 545: LCL(too_high) = LCL(too_low)+8 /* # times histogram tick too low */ ! 546: LCL(prof_overflow) = LCL(too_high)+8 /* # times the prof count field overflowed */ ! 547: LCL(gprof_overflow) = LCL(prof_overflow)+8 /* # times the gprof count field overflowed */ ! 548: LCL(num_alloc) = LCL(gprof_overflow)+8 /* # allocations in each context */ ! 549: LCL(bytes_alloc) = LCL(num_alloc)+4*C_max /* bytes allocated in each context */ ! 550: LCL(num_context) = LCL(bytes_alloc)+4*C_max /* # allocation context blocks */ ! 551: LCL(wasted) = LCL(num_context)+4*C_max /* # bytes wasted */ ! 552: LCL(overhead) = LCL(wasted)+4*C_max /* # bytes of overhead */ ! 553: LCL(buckets) = LCL(overhead)+4*C_max /* # hash indexes that have n buckets */ ! 554: LCL(cache_hits1) = LCL(buckets)+4*10 /* # gprof cache hits in bucket #1 */ ! 555: LCL(cache_hits2) = LCL(cache_hits1)+8 /* # gprof cache hits in bucket #2 */ ! 556: LCL(cache_hits3) = LCL(cache_hits2)+8 /* # gprof cache hits in bucket #3 */ ! 557: LCL(stats_unused) = LCL(cache_hits3)+8 /* reserved for future use */ ! 558: LCL(stats_end) = LCL(stats_unused)+8*64 /* end of stats structure */ ! 559: ! 560: /* ! 561: * Machine dependent variables that no C file should access (except for ! 562: * profile-md.c). ! 563: */ ! 564: ! 565: LCL(md_start) = LCL(stats_end) /* start of md structure */ ! 566: LCL(md_major_version) = LCL(md_start) /* major version number */ ! 567: LCL(md_minor_version) = LCL(md_major_version)+4 /* minor version number */ ! 568: LCL(md_size) = LCL(md_minor_version)+4 /* size of _profile_stats structure */ ! 569: LCL(hash_ptr) = LCL(md_size)+4 /* gprof hash pointer */ ! 570: LCL(hash_size) = LCL(hash_ptr)+4 /* gprof hash size */ ! 571: LCL(num_cache) = LCL(hash_size)+4 /* # of cache entries */ ! 572: LCL(save_mcount_ptr) = LCL(num_cache)+4 /* save for mcount_ptr when suspending profiling */ ! 573: LCL(mcount_ptr_ptr) = LCL(save_mcount_ptr)+4 /* pointer to _mcount_ptr */ ! 574: LCL(dummy_ptr) = LCL(mcount_ptr_ptr)+4 /* pointer to gprof_dummy */ ! 575: LCL(alloc_pages) = LCL(dummy_ptr)+4 /* allocate more memory */ ! 576: LCL(num_buffer) = LCL(alloc_pages)+4 /* buffer to convert 64 bit ints in */ ! 577: LCL(md_unused) = LCL(num_buffer)+N_digit /* unused fields */ ! 578: LCL(md_end) = LCL(md_unused)+4*58 /* end of md structure */ ! 579: LCL(total_size) = LCL(md_end) /* size of entire structure */ ! 580: ! 581: /* ! 582: * Size of the entire _profile_vars structure. ! 583: */ ! 584: ! 585: DATA(_profile_size) ! 586: .long LCL(total_size) ! 587: ENDDATA(_profile_size) ! 588: ! 589: /* ! 590: * Size of the statistics substructure. ! 591: */ ! 592: ! 593: DATA(_profile_stats_size) ! 594: .long LCL(stats_end)-LCL(stats_start) ! 595: ENDDATA(_profile_stats_size) ! 596: ! 597: /* ! 598: * Size of the profil info substructure. ! 599: */ ! 600: ! 601: DATA(_profile_profil_size) ! 602: .long LCL(profil_end)-LCL(profil_start) ! 603: ENDDATA(_profile_profil_size) ! 604: ! 605: /* ! 606: * Size of the machine dependent substructure. ! 607: */ ! 608: ! 609: DATA(_profile_md_size) ! 610: .long LCL(md_end)-LCL(md_start) ! 611: ENDDATA(_profile_profil_size) ! 612: ! 613: /* ! 614: * Whether statistics are supported. ! 615: */ ! 616: ! 617: DATA(_profile_do_stats) ! 618: .long DO_STATS ! 619: ENDDATA(_profile_do_stats) ! 620: ! 621: .text ! 622: ! 623: /* ! 624: * Map LCL(xxx) -> into simpler names ! 625: */ ! 626: ! 627: #define V_acontext LCL(acontext) ! 628: #define V_acontext_locked LCL(acontext_locked) ! 629: #define V_alloc_pages LCL(alloc_pages) ! 630: #define V_bogus_func LCL(bogus_func) ! 631: #define V_bytes_alloc LCL(bytes_alloc) ! 632: #define V_cache_hits1 LCL(cache_hits1) ! 633: #define V_cache_hits2 LCL(cache_hits2) ! 634: #define V_cache_hits3 LCL(cache_hits3) ! 635: #define V_cnt LCL(cnt) ! 636: #define V_cnt_overflow LCL(cnt_overflow) ! 637: #define V_check_funcs LCL(check_funcs) ! 638: #define V_dummy LCL(dummy) ! 639: #define V_dummy_overflow LCL(dummy_overflow) ! 640: #define V_dummy_ptr LCL(dummy_ptr) ! 641: #define V_gprof_records LCL(gprof_records) ! 642: #define V_hash_num LCL(hash_num) ! 643: #define V_hash_ptr LCL(hash_ptr) ! 644: #define V_hash_search LCL(hash_search) ! 645: #define V_mcount_ptr_ptr LCL(mcount_ptr_ptr) ! 646: #define V_num_alloc LCL(num_alloc) ! 647: #define V_num_buffer LCL(num_buffer) ! 648: #define V_num_context LCL(num_context) ! 649: #define V_old_mcount LCL(old_mcount) ! 650: #define V_old_mcount_overflow LCL(old_mcount_overflow) ! 651: #define V_overhead LCL(overhead) ! 652: #define V_page_size LCL(page_size) ! 653: #define V_prof_records LCL(prof_records) ! 654: #define V_recursive_alloc LCL(recursive_alloc) ! 655: #define V_wasted LCL(wasted) ! 656: ! 657: /* ! 658: * Loadup %ebx with the address of _profile_vars. On a multiprocessor, this ! 659: * will loads up the appropriate machine's _profile_vars structure. ! 660: * For ELF shared libraries, rely on the fact that we won't need a GOT, ! 661: * except to load this pointer. ! 662: */ ! 663: ! 664: #if defined (MACH_KERNEL) && NCPUS > 1 ! 665: #define ASSEMBLER ! 666: #if AT386 ! 667: #include <i386/AT386/mp.h> ! 668: #endif ! 669: ! 670: #if SQT ! 671: #include <i386/SQT/asm_macros.h> ! 672: #endif ! 673: ! 674: #ifndef CPU_NUMBER ! 675: #error "Cannot determine how to get CPU number" ! 676: #endif ! 677: ! 678: #define Vload CPU_NUMBER(%ebx); movl EXT(_profile_vars_cpus)(,%ebx,4),%ebx ! 679: ! 680: #else /* not kernel or not multiprocessor */ ! 681: #define Vload Gload; Egaddr(%ebx,_profile_vars) ! 682: #endif ! 683: ! 684: ! 685: /* ! 686: * Allocate some memory for profiling. This memory is guaranteed to ! 687: * be zero. ! 688: * %eax contains the memory size requested and will contain ptr on exit. ! 689: * %ebx contains the address of the appropriate profile_vars structure. ! 690: * %ecx is the number of the memory pool to allocate from (trashed on exit). ! 691: * %edx is trashed. ! 692: * %esi is preserved. ! 693: * %edi is preserved. ! 694: * %ebp is preserved. ! 695: */ ! 696: ! 697: Entry(_profile_alloc_asm) ! 698: ENTER ! 699: pushl %esi ! 700: pushl %edi ! 701: ! 702: movl %ecx,%edi /* move context number to saved reg */ ! 703: ! 704: #if NO_RECURSIVE_ALLOC ! 705: movb $-1,%cl ! 706: xchgb %cl,V_recursive_alloc(%ebx) ! 707: cmpb $0,%cl ! 708: je LCL(no_recurse) ! 709: ! 710: int $3 ! 711: ! 712: .align ALIGN ! 713: LCL(no_recurse): ! 714: #endif ! 715: ! 716: leal V_acontext(%ebx,%edi,4),%ecx ! 717: ! 718: /* Loop looking for a free allocation context. */ ! 719: /* %eax = size, %ebx = vars addr, %ecx = ptr to allocation context to try */ ! 720: /* %edi = context number */ ! 721: ! 722: .align ALIGN ! 723: LCL(alloc_loop): ! 724: movl %ecx,%esi /* save ptr in case no more contexts */ ! 725: movl A_next(%ecx),%ecx /* next context block */ ! 726: cmpl $0,%ecx ! 727: je LCL(alloc_context) /* need to allocate a new context block */ ! 728: ! 729: movl $-1,%edx ! 730: xchgl %edx,A_lock(%ecx) /* %edx == 0 if context available */ ! 731: ! 732: #if DO_STATS ! 733: SDADDNEG(%edx,V_acontext_locked(%ebx)) /* increment counter if lock was held */ ! 734: #endif ! 735: ! 736: cmpl $0,%edx ! 737: jne LCL(alloc_loop) /* go back if this context block is not available */ ! 738: ! 739: /* Allocation context found (%ecx), now allocate. */ ! 740: movl A_plist(%ecx),%edx /* pointer to current block */ ! 741: cmpl $0,%edx /* first allocation? */ ! 742: je LCL(alloc_new) ! 743: ! 744: cmpl %eax,M_nfree(%edx) /* see if we have enough space */ ! 745: jl LCL(alloc_new) /* jump if not enough space */ ! 746: ! 747: /* Allocate from local block (and common exit) */ ! 748: /* %eax = bytes to allocate, %ebx = GOT, %ecx = context, %edx = memory block */ ! 749: /* %edi = context number */ ! 750: ! 751: .align ALIGN ! 752: LCL(alloc_ret): ! 753: ! 754: #if DO_STATS ! 755: SLOCK incl V_num_alloc(%ebx,%edi,4) /* update global counters */ ! 756: SLOCK addl %eax,V_bytes_alloc(%ebx,%edi,4) ! 757: SLOCK subl %eax,V_wasted(%ebx,%edi,4) ! 758: #endif ! 759: ! 760: movl M_ptr(%edx),%esi /* pointer return value */ ! 761: subl %eax,M_nfree(%edx) /* decrement bytes remaining */ ! 762: addl %eax,M_nalloc(%edx) /* increment bytes allocated */ ! 763: incl M_num(%edx) /* increment # allocations */ ! 764: addl %eax,M_ptr(%edx) /* advance pointer */ ! 765: movl $0,A_lock(%ecx) /* unlock context block */ ! 766: movl %esi,%eax /* return pointer */ ! 767: ! 768: #if NO_RECURSIVE_ALLOC ! 769: movb $0,V_recursive_alloc(%ebx) ! 770: #endif ! 771: ! 772: popl %edi ! 773: popl %esi ! 774: LEAVE0 ! 775: ret /* return to the caller */ ! 776: ! 777: /* Allocate space in whole number of pages */ ! 778: /* %eax = bytes to allocate, %ebx = vars address, %ecx = context */ ! 779: /* %edi = context number */ ! 780: ! 781: .align ALIGN ! 782: LCL(alloc_new): ! 783: pushl %eax /* save regs */ ! 784: pushl %ecx ! 785: movl V_page_size(%ebx),%edx ! 786: addl $(M_size-1),%eax /* add in overhead size & subtract 1 */ ! 787: decl %edx /* page_size - 1 */ ! 788: addl %edx,%eax /* round up to whole number of pages */ ! 789: notl %edx ! 790: andl %edx,%eax ! 791: leal -M_size(%eax),%esi /* save allocation size */ ! 792: pushl %eax /* argument to _profile_alloc_pages */ ! 793: call *V_alloc_pages(%ebx) /* allocate some memory */ ! 794: addl $4,%esp /* pop off argument */ ! 795: ! 796: #if DO_STATS ! 797: SLOCK addl %esi,V_wasted(%ebx,%edi,4) /* udpate global counters */ ! 798: SLOCK addl $M_size,V_overhead(%ebx,%edi,4) ! 799: #endif ! 800: ! 801: popl %ecx /* context block */ ! 802: movl %eax,%edx /* memory block pointer */ ! 803: movl %esi,M_nfree(%edx) /* # free bytes */ ! 804: addl $M_size,%eax /* bump past overhead */ ! 805: movl A_plist(%ecx),%esi /* previous memory block or 0 */ ! 806: movl %eax,M_first(%edx) /* first space available */ ! 807: movl %eax,M_ptr(%edx) /* current address available */ ! 808: movl %esi,M_next(%edx) /* next memory block allocated */ ! 809: movl %edx,A_plist(%ecx) /* update current page list */ ! 810: popl %eax /* user size request */ ! 811: jmp LCL(alloc_ret) /* goto common return code */ ! 812: ! 813: /* Allocate a context header in addition to memory block header + data */ ! 814: /* %eax = bytes to allocate, %ebx = GOT, %esi = ptr to store context ptr */ ! 815: /* %edi = context number */ ! 816: ! 817: .align ALIGN ! 818: LCL(alloc_context): ! 819: pushl %eax /* save regs */ ! 820: pushl %esi ! 821: movl V_page_size(%ebx),%edx ! 822: addl $(A_size+M_size-1),%eax /* add in overhead size & subtract 1 */ ! 823: decl %edx /* page_size - 1 */ ! 824: addl %edx,%eax /* round up to whole number of pages */ ! 825: notl %edx ! 826: andl %edx,%eax ! 827: leal -A_size-M_size(%eax),%esi /* save allocation size */ ! 828: pushl %eax /* argument to _profile_alloc_pages */ ! 829: call *V_alloc_pages(%ebx) /* allocate some memory */ ! 830: addl $4,%esp /* pop off argument */ ! 831: ! 832: #if DO_STATS ! 833: SLOCK incl V_num_context(%ebx,%edi,4) /* bump # context blocks */ ! 834: SLOCK addl %esi,V_wasted(%ebx,%edi,4) /* update global counters */ ! 835: SLOCK addl $(A_size+M_size),V_overhead(%ebx,%edi,4) ! 836: #endif ! 837: ! 838: movl %eax,%ecx /* context pointer */ ! 839: leal A_size(%eax),%edx /* memory block pointer */ ! 840: movl %esi,M_nfree(%edx) /* # free bytes */ ! 841: addl $(A_size+M_size),%eax /* bump past overhead */ ! 842: movl %eax,M_first(%edx) /* first space available */ ! 843: movl %eax,M_ptr(%edx) /* current address available */ ! 844: movl $0,M_next(%edx) /* next memory block allocated */ ! 845: movl %edx,A_plist(%ecx) /* head of memory block list */ ! 846: movl $1,A_lock(%ecx) /* set lock */ ! 847: popl %esi /* ptr to store context block link */ ! 848: movl %ecx,%eax /* context pointer temp */ ! 849: xchgl %eax,A_next(%esi) /* link into chain */ ! 850: movl %eax,A_next(%ecx) /* add links in case of threading */ ! 851: popl %eax /* user size request */ ! 852: jmp LCL(alloc_ret) /* goto common return code */ ! 853: ! 854: END(_profile_alloc_asm) ! 855: ! 856: /* ! 857: * C callable version of the profile memory allocator. ! 858: * extern void *_profile_alloc(struct profile_vars *, size_t, acontext_type_t); ! 859: */ ! 860: ! 861: Entry(_profile_alloc) ! 862: ENTER ! 863: pushl %ebx ! 864: movl 12+Estack(%esp),%eax /* memory size */ ! 865: movl 8+Estack(%esp),%ebx /* provile_vars address */ ! 866: addl $3,%eax /* round up to word boundary */ ! 867: movl 16+Estack(%esp),%ecx /* which memory pool to allocate from */ ! 868: andl $0xfffffffc,%eax ! 869: call EXT(_profile_alloc_asm) ! 870: popl %ebx ! 871: LEAVE0 ! 872: ret ! 873: END(_profile_alloc) ! 874: ! 875: ! 876: /* ! 877: * Dummy mcount routine that just returns. ! 878: * ! 879: * +-------------------------------+ ! 880: * | | ! 881: * | | ! 882: * | caller's caller stack, | ! 883: * | saved registers, params. | ! 884: * | | ! 885: * | | ! 886: * +-------------------------------+ ! 887: * | caller's caller return addr. | ! 888: * +-------------------------------+ ! 889: * esp --> | caller's return address | ! 890: * +-------------------------------+ ! 891: * ! 892: * edx --> function unqiue LCL ! 893: */ ! 894: ! 895: Entry(_dummy_mcount) ! 896: ENTER ! 897: ! 898: #if DO_STATS ! 899: pushl %ebx ! 900: MP_DISABLE_PREEMPTION(%ebx) ! 901: Vload ! 902: SDINC(V_dummy(%ebx)) ! 903: MP_ENABLE_PREEMPTION(%ebx) ! 904: popl %ebx ! 905: #endif ! 906: ! 907: LEAVE0 ! 908: ret ! 909: END(_dummy_mcount) ! 910: ! 911: ! 912: /* ! 913: * Entry point for System V based profiling, count how many times each function ! 914: * is called. The function label is passed in %edx, and the top two words on ! 915: * the stack are the caller's address, and the caller's return address. ! 916: * ! 917: * +-------------------------------+ ! 918: * | | ! 919: * | | ! 920: * | caller's caller stack, | ! 921: * | saved registers, params. | ! 922: * | | ! 923: * | | ! 924: * +-------------------------------+ ! 925: * | caller's caller return addr. | ! 926: * +-------------------------------+ ! 927: * esp --> | caller's return address | ! 928: * +-------------------------------+ ! 929: * ! 930: * edx --> function unique label ! 931: * ! 932: * We don't worry about the possibility about two threads calling ! 933: * the same function for the first time simulataneously. If that ! 934: * happens, two records will be created, and one of the records ! 935: * address will be stored in in the function unique label (which ! 936: * is aligned by the compiler, so we don't have to watch out for ! 937: * crossing page/cache boundaries). ! 938: */ ! 939: ! 940: Entry(_prof_mcount) ! 941: ENTER ! 942: ! 943: #if DO_STATS ! 944: pushl %ebx ! 945: MP_DISABLE_PREEMPTION(%ebx) ! 946: Vload ! 947: SDINC(V_cnt(%ebx)) ! 948: #endif ! 949: ! 950: movl (%edx),%eax /* initialized? */ ! 951: cmpl $0,%eax ! 952: je LCL(pnew) ! 953: ! 954: DINC2(P_count(%eax),P_overflow(%eax)) /* bump function count (double precision) */ ! 955: ! 956: #if DO_STATS ! 957: MP_ENABLE_PREEMPTION(%ebx) ! 958: popl %ebx ! 959: #endif ! 960: ! 961: LEAVE0 ! 962: ret ! 963: ! 964: .align ALIGN ! 965: LCL(pnew): ! 966: ! 967: #if !DO_STATS ! 968: pushl %ebx ! 969: MP_DISABLE_PREEMPTION(%ebx) ! 970: Vload ! 971: #endif ! 972: ! 973: SLOCK incl V_prof_records(%ebx) ! 974: pushl %edx ! 975: movl $P_size,%eax /* allocation size */ ! 976: movl $C_prof,%ecx /* allocation pool */ ! 977: call EXT(_profile_alloc_asm) /* allocate a new record */ ! 978: popl %edx ! 979: ! 980: movl Estack+4(%esp),%ecx /* caller's address */ ! 981: movl %ecx,P_addr(%eax) ! 982: movl $1,P_count(%eax) /* call count */ ! 983: xchgl %eax,(%edx) /* update function header */ ! 984: MP_ENABLE_PREEMPTION(%ebx) ! 985: popl %ebx ! 986: LEAVE0 ! 987: ret ! 988: ! 989: END(_prof_mcount) ! 990: ! 991: ! 992: /* ! 993: * Entry point for BSD based graph profiling, count how many times each unique ! 994: * call graph (caller + callee) is called. The function label is passed in ! 995: * %edx, and the top two words on the stack are the caller's address, and the ! 996: * caller's return address. ! 997: * ! 998: * +-------------------------------+ ! 999: * | | ! 1000: * | | ! 1001: * | caller's caller stack, | ! 1002: * | saved registers, params. | ! 1003: * | | ! 1004: * | | ! 1005: * +-------------------------------+ ! 1006: * | caller's caller return addr. | ! 1007: * +-------------------------------+ ! 1008: * esp --> | caller's return address | ! 1009: * +-------------------------------+ ! 1010: * ! 1011: * edx --> function unqiue label ! 1012: * ! 1013: * We don't worry about the possibility about two threads calling the same ! 1014: * function simulataneously. If that happens, two records will be created, and ! 1015: * one of the records address will be stored in in the function unique label ! 1016: * (which is aligned by the compiler). ! 1017: * ! 1018: * By design, the gprof header is not locked. Each of the cache pointers is ! 1019: * always a valid pointer (possibily to a null record), and if another thread ! 1020: * comes in and modifies the pointer, it does so automatically with a simple store. ! 1021: * Since all arcs are in the hash table, the caches are just to avoid doing ! 1022: * a multiplication in the common case, and if they don't match, the arcs will ! 1023: * still be found. ! 1024: */ ! 1025: ! 1026: Entry(_gprof_mcount) ! 1027: ! 1028: ENTER ! 1029: movl Estack+4(%esp),%ecx /* caller's caller address */ ! 1030: ! 1031: #if DO_STATS ! 1032: pushl %ebx ! 1033: MP_DISABLE_PREEMPTION(%ebx) ! 1034: Vload ! 1035: SDINC(V_cnt(%ebx)) /* bump profile call counter (double int) */ ! 1036: #endif ! 1037: ! 1038: movl (%edx),%eax /* Gprof header allocated? */ ! 1039: cmpl $0,%eax ! 1040: je LCL(gnew) /* skip if first call */ ! 1041: ! 1042: DINC2(H_prof+P_count(%eax),H_prof+P_overflow(%eax)) /* bump function count */ ! 1043: ! 1044: /* See if this call arc is the same as the last time */ ! 1045: MARK(_gprof_mcount_cache1) ! 1046: movl H_cache_ptr(%eax),%edx /* last arc searched */ ! 1047: cmpl %ecx,G_frompc(%edx) /* skip if not equal */ ! 1048: jne LCL(gcache2) ! 1049: ! 1050: /* Same as last time, increment and return */ ! 1051: ! 1052: DINC2(G_count(%edx),G_overflow(%edx)) /* bump arc count */ ! 1053: ! 1054: #if DO_STATS ! 1055: SDINC(V_cache_hits1(%ebx)) /* update counter */ ! 1056: MP_ENABLE_PREEMPTION(%ebx) ! 1057: popl %ebx ! 1058: #endif ! 1059: ! 1060: LEAVE0 ! 1061: ret ! 1062: ! 1063: /* Search second cache entry */ ! 1064: /* %eax = gprof func header, %ebx = vars address if DO_STATS, %ecx = caller's caller */ ! 1065: /* %edx = first arc searched */ ! 1066: /* %ebx if DO_STATS pushed on stack */ ! 1067: ! 1068: .align ALIGN ! 1069: MARK(_gprof_mcount_cache2) ! 1070: LCL(gcache2): ! 1071: pushl %esi /* get a saved register */ ! 1072: movl H_cache_ptr+4(%eax),%esi /* 2nd arc to be searched */ ! 1073: cmpl %ecx,G_frompc(%esi) /* skip if not equal */ ! 1074: jne LCL(gcache3) ! 1075: ! 1076: /* Element found, increment, reset last arc searched and return */ ! 1077: ! 1078: DINC2(G_count(%esi),G_overflow(%esi)) /* bump arc count */ ! 1079: ! 1080: movl %esi,H_cache_ptr+0(%eax) /* swap 1st and 2nd cached arcs */ ! 1081: popl %esi ! 1082: movl %edx,H_cache_ptr+4(%eax) ! 1083: ! 1084: #if DO_STATS ! 1085: SDINC(V_cache_hits2(%ebx)) /* update counter */ ! 1086: MP_ENABLE_PREEMPTION(%ebx) ! 1087: popl %ebx ! 1088: #endif ! 1089: ! 1090: LEAVE0 ! 1091: ret ! 1092: ! 1093: /* Search third cache entry */ ! 1094: /* %eax = gprof func header, %ebx = vars address if DO_STATS, %ecx = caller's caller */ ! 1095: /* %edx = first arc searched, %esi = second arc searched */ ! 1096: /* %esi, %ebx if DO_STATS pushed on stack */ ! 1097: ! 1098: .align ALIGN ! 1099: MARK(_gprof_mcount_cache3) ! 1100: LCL(gcache3): ! 1101: pushl %edi ! 1102: movl H_cache_ptr+8(%eax),%edi /* 3rd arc to be searched */ ! 1103: cmpl %ecx,G_frompc(%edi) /* skip if not equal */ ! 1104: jne LCL(gnocache) ! 1105: ! 1106: /* Element found, increment, reset last arc searched and return */ ! 1107: ! 1108: DINC2(G_count(%edi),G_overflow(%edi)) /* bump arc count */ ! 1109: ! 1110: movl %edi,H_cache_ptr+0(%eax) /* make this 1st cached arc */ ! 1111: movl %esi,H_cache_ptr+8(%eax) ! 1112: movl %edx,H_cache_ptr+4(%eax) ! 1113: popl %edi ! 1114: popl %esi ! 1115: ! 1116: #if DO_STATS ! 1117: SDINC(V_cache_hits3(%ebx)) /* update counter */ ! 1118: MP_ENABLE_PREEMPTION(%ebx) ! 1119: popl %ebx ! 1120: #endif ! 1121: ! 1122: LEAVE0 ! 1123: ret ! 1124: ! 1125: /* No function context, allocate a new context */ ! 1126: /* %ebx is the variables address if DO_STATS */ ! 1127: /* %ecx is the caller's caller's address */ ! 1128: /* %edx is the unique function pointer */ ! 1129: /* %ebx if DO_STATS pushed on stack */ ! 1130: ! 1131: .align ALIGN ! 1132: MARK(_gprof_mcount_new) ! 1133: LCL(gnew): ! 1134: pushl %esi ! 1135: pushl %edi ! 1136: ! 1137: #if !DO_STATS ! 1138: pushl %ebx /* Address of vars needed for alloc */ ! 1139: MP_DISABLE_PREEMPTION(%ebx) ! 1140: Vload /* stats already loaded address */ ! 1141: #endif ! 1142: ! 1143: SLOCK incl V_prof_records(%ebx) ! 1144: movl %edx,%esi /* save unique function ptr */ ! 1145: movl %ecx,%edi /* and caller's caller address */ ! 1146: movl $H_size,%eax /* memory block size */ ! 1147: movl $C_gfunc,%ecx /* gprof function header memory pool */ ! 1148: call EXT(_profile_alloc_asm) ! 1149: ! 1150: movl V_hash_ptr(%ebx),%ecx /* copy hash_ptr to func header */ ! 1151: movl V_dummy_ptr(%ebx),%edx /* dummy cache entry */ ! 1152: movl %ecx,H_hash_ptr(%eax) ! 1153: movl %edx,H_cache_ptr+0(%eax) /* store dummy cache ptrs */ ! 1154: movl %edx,H_cache_ptr+4(%eax) ! 1155: movl %edx,H_cache_ptr+8(%eax) ! 1156: movl %esi,H_unique_ptr(%eax) /* remember function unique ptr */ ! 1157: movl Estack+12(%esp),%ecx /* caller's address */ ! 1158: movl $1,H_prof+P_count(%eax) /* function called once so far */ ! 1159: movl %ecx,H_prof+P_addr(%eax) /* set up prof information */ ! 1160: movl %eax,(%esi) /* update context block address */ ! 1161: movl %edi,%ecx /* caller's caller address */ ! 1162: movl %edx,%esi /* 2nd cached arc */ ! 1163: ! 1164: #if !DO_STATS ! 1165: popl %ebx ! 1166: #endif ! 1167: ! 1168: /* Fall through to add element to the hash table. This may involve */ ! 1169: /* searching a few hash table elements that don't need to be searched */ ! 1170: /* since we have a new element, but it allows the hash table function */ ! 1171: /* to be specified in only one place */ ! 1172: ! 1173: /* Didn't find entry in cache, search the global hash table */ ! 1174: /* %eax = gprof func header, %ebx = vars address if DO_STATS */ ! 1175: /* %ecx = caller's caller */ ! 1176: /* %edx, %esi = cached arcs that were searched */ ! 1177: /* %edi, %esi, %ebx if DO_STATS pushed on stack */ ! 1178: ! 1179: .align ALIGN ! 1180: MARK(_gprof_mcount_hash) ! 1181: LCL(gnocache): ! 1182: ! 1183: pushl %esi /* save 2nd arc searched */ ! 1184: pushl %edx /* save 1st arc searched */ ! 1185: movl %eax,%esi /* save gprof func header */ ! 1186: ! 1187: #if DO_STATS ! 1188: SDINC(V_hash_num(%ebx)) ! 1189: movl Estack+20(%esp),%edi /* caller's address */ ! 1190: #else ! 1191: movl Estack+16(%esp),%edi /* caller's address */ ! 1192: #endif ! 1193: movl %ecx,%eax /* caller's caller address */ ! 1194: imull %edi,%eax /* multiply to get hash */ ! 1195: movl H_hash_ptr(%esi),%edx /* hash pointer */ ! 1196: shrl $GPROF_HASH_SHIFT,%eax /* eliminate low order bits */ ! 1197: andl $GPROF_HASH_MASK,%eax /* mask to get hash value */ ! 1198: leal 0(%edx,%eax,4),%eax /* pointer to hash bucket */ ! 1199: movl %eax,%edx /* save hash bucket address */ ! 1200: ! 1201: /* %eax = old arc, %ebx = vars address if DO_STATS, %ecx = caller's caller */ ! 1202: /* %edx = hash bucket address, %esi = gfunc ptr, %edi = caller's addr */ ! 1203: /* 2 old arcs, %edi, %esi, %ebx if DO_STATS pushed on stack */ ! 1204: ! 1205: .align ALIGN ! 1206: LCL(ghash): ! 1207: movl G_next(%eax),%eax /* get next hash element */ ! 1208: cmpl $0,%eax /* end of line? */ ! 1209: je LCL(ghashnew) /* skip if allocate new hash */ ! 1210: ! 1211: #if DO_STATS ! 1212: SDINC(V_hash_search(%ebx)) ! 1213: #endif ! 1214: ! 1215: cmpl G_selfpc(%eax),%edi /* loop back if not one we want */ ! 1216: jne LCL(ghash) ! 1217: ! 1218: cmpl G_frompc(%eax),%ecx /* loop back if not one we want */ ! 1219: jne LCL(ghash) ! 1220: ! 1221: /* Found an entry, increment count, set up for caching, and return */ ! 1222: /* %eax = arc, %ebx = vars address if DO_STATS, %esi = func header */ ! 1223: /* 2 old arcs, %edi, %esi, %ebx if DO_STATS pushed on stack */ ! 1224: ! 1225: DINC2(G_count(%eax),G_overflow(%eax)) /* bump arc count */ ! 1226: ! 1227: popl %ecx /* previous 1st arc searched */ ! 1228: movl %eax,H_cache_ptr+0(%esi) /* this element is now 1st arc */ ! 1229: popl %edi /* previous 2nd arc searched */ ! 1230: movl %ecx,H_cache_ptr+4(%esi) /* new 2nd arc to be searched */ ! 1231: movl %edi,H_cache_ptr+8(%esi) /* new 3rd arc to be searched */ ! 1232: popl %edi ! 1233: popl %esi ! 1234: ! 1235: #if DO_STATS ! 1236: MP_ENABLE_PREEMPTION(%ebx) ! 1237: popl %ebx ! 1238: #endif ! 1239: ! 1240: LEAVE0 ! 1241: ret /* return to user */ ! 1242: ! 1243: /* Allocate new arc */ ! 1244: /* %eax = old arc, %ebx = vars address if DO_STATS, %ecx = caller's caller */ ! 1245: /* %edx = hash bucket address, %esi = gfunc ptr, %edi = caller's addr */ ! 1246: /* 2 old arcs, %edi, %esi, %ebx if DO_STATS pushed on stack */ ! 1247: ! 1248: .align ALIGN ! 1249: MARK(_gprof_mcount_hashnew) ! 1250: LCL(ghashnew): ! 1251: ! 1252: #if !DO_STATS ! 1253: pushl %ebx /* load address of vars if we haven't */ ! 1254: MP_DISABLE_PREEMPTION(%ebx) ! 1255: Vload /* already done so */ ! 1256: #endif ! 1257: ! 1258: SLOCK incl V_gprof_records(%ebx) ! 1259: pushl %edx ! 1260: movl %ecx,%edi /* save caller's caller */ ! 1261: movl $G_size,%eax /* arc size */ ! 1262: movl $C_gprof,%ecx /* gprof memory pool */ ! 1263: call EXT(_profile_alloc_asm) ! 1264: popl %edx ! 1265: ! 1266: movl $1,G_count(%eax) /* set call count */ ! 1267: movl Estack+20(%esp),%ecx /* caller's address */ ! 1268: movl %edi,G_frompc(%eax) /* caller's caller */ ! 1269: movl %ecx,G_selfpc(%eax) ! 1270: ! 1271: #if !DO_STATS ! 1272: popl %ebx /* release %ebx if no stats */ ! 1273: #endif ! 1274: ! 1275: movl (%edx),%ecx /* first hash bucket */ ! 1276: movl %ecx,G_next(%eax) /* update link */ ! 1277: movl %eax,%ecx /* copy for xchgl */ ! 1278: xchgl %ecx,(%edx) /* add to hash linked list */ ! 1279: movl %ecx,G_next(%eax) /* update in case list changed */ ! 1280: ! 1281: popl %ecx /* previous 1st arc searched */ ! 1282: popl %edi /* previous 2nd arc searched */ ! 1283: movl %eax,H_cache_ptr+0(%esi) /* this element is now 1st arc */ ! 1284: movl %ecx,H_cache_ptr+4(%esi) /* new 2nd arc to be searched */ ! 1285: movl %edi,H_cache_ptr+8(%esi) /* new 3rd arc to be searched */ ! 1286: ! 1287: popl %edi ! 1288: popl %esi ! 1289: ! 1290: #if DO_STATS ! 1291: MP_ENABLE_PREEMPTION(%ebx) ! 1292: popl %ebx ! 1293: #endif ! 1294: ! 1295: LEAVE0 ! 1296: ret /* return to user */ ! 1297: ! 1298: END(_gprof_mcount) ! 1299: ! 1300: ! 1301: /* ! 1302: * This function assumes that neither the caller or it's caller ! 1303: * has not omitted the frame pointer in order to get the caller's ! 1304: * caller. The stack looks like the following at the time of the call: ! 1305: * ! 1306: * +-------------------------------+ ! 1307: * | | ! 1308: * | | ! 1309: * | caller's caller stack, | ! 1310: * | saved registers, params. | ! 1311: * | | ! 1312: * | | ! 1313: * +-------------------------------+ ! 1314: * | caller's caller return addr. | ! 1315: * +-------------------------------+ ! 1316: * fp --> | previous frame pointer | ! 1317: * +-------------------------------+ ! 1318: * | | ! 1319: * | caller's stack, saved regs, | ! 1320: * | params. | ! 1321: * | | ! 1322: * +-------------------------------+ ! 1323: * sp --> | caller's return address | ! 1324: * +-------------------------------+ ! 1325: * ! 1326: * Recent versions of the compiler put the address of the pointer ! 1327: * sized word in %edx. Previous versions did not, but this code ! 1328: * does not support them. ! 1329: */ ! 1330: ! 1331: /* ! 1332: * Note that OSF/rose blew defining _mcount, since it prepends leading ! 1333: * underscores, and _mcount didn't have a second leading underscore. However, ! 1334: * some of the kernel/server functions 'know' that mcount has a leading ! 1335: * underscore, so we satisfy both camps. ! 1336: */ ! 1337: ! 1338: #if OLD_MCOUNT ! 1339: .globl mcount ! 1340: .globl _mcount ! 1341: ELF_FUNC(mcount) ! 1342: ELF_FUNC(_mcount) ! 1343: .align FALIGN ! 1344: _mcount: ! 1345: mcount: ! 1346: ! 1347: pushl %ebx ! 1348: MP_DISABLE_PREEMPTION(%ebx) ! 1349: Vload ! 1350: ! 1351: #if DO_STATS ! 1352: SDINC(V_old_mcount(%ebx)) ! 1353: #endif ! 1354: ! 1355: /* In calling the functions, we will actually leave 1 extra word on the */ ! 1356: /* top of the stack, but generated code will not notice, since the function */ ! 1357: /* uses a frame pointer */ ! 1358: ! 1359: movl V_mcount_ptr_ptr(%ebx),%ecx /* address of mcount_ptr */ ! 1360: MP_ENABLE_PREEMPTION(%ebx) ! 1361: popl %ebx ! 1362: movl 4(%ebp),%eax /* caller's caller return address */ ! 1363: xchgl %eax,(%esp) /* push & get return address */ ! 1364: pushl %eax /* push return address */ ! 1365: jmp *(%ecx) /* go to profile the function */ ! 1366: ! 1367: End(mcount) ! 1368: End(_mcount) ! 1369: #endif ! 1370: ! 1371: ! 1372: #if !defined(KERNEL) && !defined(MACH_KERNEL) ! 1373: ! 1374: /* ! 1375: * Convert a 64-bit integer to a string. ! 1376: * Arg #1 is a pointer to a string (at least 24 bytes) or NULL ! 1377: * Arg #2 is the low part of the 64-bit integer. ! 1378: * Arg #3 is the high part of the 64-bit integer. ! 1379: */ ! 1380: ! 1381: Entry(_profile_cnt_to_decimal) ! 1382: ENTER ! 1383: pushl %ebx ! 1384: pushl %esi ! 1385: pushl %edi ! 1386: movl Estack+16(%esp),%ebx /* pointer or null */ ! 1387: movl Estack+20(%esp),%edi /* low part of number */ ! 1388: movl $10,%ecx /* divisor */ ! 1389: cmpl $0,%ebx /* skip if pointer ok */ ! 1390: jne LCL(cvt_nonnull) ! 1391: ! 1392: MP_DISABLE_PREEMPTION(%ebx) ! 1393: Vload /* get _profile_vars address */ ! 1394: leal V_num_buffer(%ebx),%ebx /* temp buffer to use */ ! 1395: ! 1396: .align ALIGN ! 1397: LCL(cvt_nonnull): ! 1398: addl $(N_digit-1),%ebx /* point string at end */ ! 1399: movb $0,0(%ebx) /* null terminate string */ ! 1400: ! 1401: #if OVERFLOW ! 1402: movl Estack+24(%esp),%esi /* high part of number */ ! 1403: cmpl $0,%esi /* any thing left in high part? */ ! 1404: je LCL(cvt_low) ! 1405: ! 1406: .align ALIGN ! 1407: LCL(cvt_high): ! 1408: movl %esi,%eax /* calculate high/10 & high%10 */ ! 1409: xorl %edx,%edx ! 1410: divl %ecx ! 1411: movl %eax,%esi ! 1412: ! 1413: movl %edi,%eax /* calculate (low + (high%10)*2^32) / 10 */ ! 1414: divl %ecx ! 1415: movl %eax,%edi ! 1416: ! 1417: decl %ebx /* decrement string pointer */ ! 1418: addl $48,%edx /* convert from 0..9 -> '0'..'9' */ ! 1419: movb %dl,0(%ebx) /* store digit in string */ ! 1420: cmpl $0,%esi /* any thing left in high part? */ ! 1421: jne LCL(cvt_high) ! 1422: ! 1423: #endif /* OVERFLOW */ ! 1424: ! 1425: .align ALIGN ! 1426: LCL(cvt_low): ! 1427: movl %edi,%eax /* get low part into %eax */ ! 1428: ! 1429: .align ALIGN ! 1430: LCL(cvt_low2): ! 1431: xorl %edx,%edx /* 0 */ ! 1432: divl %ecx /* calculate next digit */ ! 1433: decl %ebx /* decrement string pointer */ ! 1434: addl $48,%edx /* convert from 0..9 -> '0'..'9' */ ! 1435: movb %dl,0(%ebx) /* store digit in string */ ! 1436: cmpl $0,%eax /* any more digits to convert? */ ! 1437: jne LCL(cvt_low2) ! 1438: ! 1439: movl %ebx,%eax /* return value */ ! 1440: popl %edi ! 1441: popl %esi ! 1442: MP_ENABLE_PREEMPTION(%ebx) ! 1443: popl %ebx ! 1444: LEAVE0 ! 1445: ret ! 1446: ! 1447: END(_profile_cnt_to_decimal) ! 1448: ! 1449: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.