/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* All routines in this file are for processing new-style, *versioned*
* form the complete set of files to profile new-style mon.out files.
*/
#include <stdlib.h>
#include <string.h>
#include "conv.h"
#include "profv.h"
unsigned char sort_flag;
int
{
}
static void
setup_demangled_names(void)
{
const char *p;
}
for (i = 0; i < total_funcs; i++) {
continue;
namebuf_sz += BUCKET_SZ;
"%s: can't alloc %d bytes\n",
}
}
}
}
int
{
if (a->percent_time > b->percent_time)
return (-1);
else if (a->percent_time < b->percent_time)
return (1);
else
return (0);
}
int
{
return (-1);
return (1);
else
return (0);
}
static void
print_profile_data(void)
{
int i;
int (*sort_func)(const void *, const void *);
double cumsecs = 0;
/*
* Sort the compiled data; the sort flags are mutually exclusive.
*/
switch (sort_flag) {
case BY_NCALLS:
break;
case BY_NAME:
if (Cflag)
break;
case BY_ADDRESS:
sort_flag |= BY_ADDRESS;
break;
case BY_TIME: /* default is to sort by time */
default:
}
if (sort_func) {
}
/*
* If we're sorting by name, and if it is a verbose print, we wouldn't
* have set up the print_mid fields yet.
*/
for (i = 0; i < total_funcs; i++) {
/*
* same as previous or next (if there's one) ?
*/
} else if ((i < (total_funcs - 1)) &&
}
}
}
/*
* The actual printing part.
*/
if (time_in_ticks)
(void) puts(
else
(void) puts(
}
for (i = 0; i < total_funcs; i++) {
/*
* Since the same value may denote different symbols in
* different shared objects, it is debatable if it is
* meaningful to print addresses at all. Especially so
* if we were asked to sort by symbol addresses.
*
* If we've to sort by address, I think it is better to sort
* it on a per-module basis and if verbose mode is on too,
* print a newline to separate out modules.
*/
(void) printf("\n");
}
}
else
}
(void) printf("%8d%12.4f ",
}
else
filler[0] = 0;
(void) puts("\n");
(void) printf("%s Total Object Modules %7d\n",
(void) printf("%s Qualified Symbols %7d\n",
(void) printf("%s Symbols with zero usage %7d\n",
(void) printf("%s Total pc-hits %7d\n",
(void) printf("%s Accounted pc-hits %7d\n",
(void) printf("%s Missed pc-hits (try -g) %7d\n\n",
} else {
(void) printf("%s Missed pc-hits %7d\n\n",
}
}
}
int
{
}
static void
check_dupnames(void)
{
int i;
}
for (i = 0; i < total_funcs; i++) {
}
for (i = 0; i < total_funcs; i++) {
/*
* same as previous or next (if there's one) ?
*/
else if ((i < (total_funcs - 1)) &&
}
}
}
static void
{
static long hz;
if (first_time) {
first_time = FALSE;
}
if (time_in_ticks) {
} else
} else {
} else
}
if (n_pcsamples) {
psym->percent_time =
}
}
static void
collect_profsyms(void)
{
}
ndx = 0;
/*
* I think F_ZSYMS doesn't make sense for the new
* mon.out format, since we don't have a profiling
* *range*, per se. But the man page demands it,
* so...
*/
n_zeros++;
continue;
}
/*
* Initially, we set demangled_name to be
* the same as name. If Cflag is set, we later
* change this to be the demangled name ptr.
*/
ndx++;
}
}
/*
* Adjust total_funcs to actual printable funcs
*/
total_funcs = ndx;
}
static void
{
/* Locate the first pc-hit for this module */
return; /* no pc-hits in this module */
/* Assign all pc-hits in this module to appropriate functions */
/* Update the corresponding function's time */
/*
* Collect all pc-hits in this function. Each
* pc-hit counts as 1 tick.
*/
nticks = 0;
nticks++;
pcptr++;
}
} else {
/*
* pc sample could not be assigned to function;
* probably in a PLT
*/
pcptr++;
}
}
}
static int
{
return (1);
return (-1);
return (0);
}
static void
{
/* buffer with no pc samples ? */
if (nelem == 0)
return;
/* Allocate for the pcsample chunk */
if (pc_samples == NULL) {
}
/* Sort the pc samples */
/*
* Assign pcsamples to functions in the currently active
* module list
*/
continue;
}
/* Update total number of pcsamples read so far */
n_pcsamples += nelem;
}
static void
{
/* LINTED: pointer cast */
continue;
/*
* If we cannot identify a callee with a module, we
* cannot get to its namelist, just skip it.
*/
continue;
/*
* nllookup() returns the next lower entry
* point on a miss. So just make sure the
* callee's pc is not outside this function
*/
}
}
}
}
}
static mod_info_t *
{
/* Create a new module element */
cmdname, sizeof (mod_info_t));
}
}
/* and fill in info... */
n_modules++;
return (mi);
}
/*
* Two modules overlap each other if they don't lie completely *outside*
* each other.
*/
static bool
{
/* case 1: new module lies completely *before* the old one */
return (FALSE);
/* case 2: new module lies completely *after* the old one */
return (FALSE);
/* probably a dlopen: the modules overlap each other */
return (TRUE);
}
static bool
{
}
return (TRUE);
} else
return (FALSE);
}
static void
{
char *so_path;
/* Check version of module type object */
"%s: unsupported version %d for modules\n",
}
/*
* Scan the PROF_MODULES_T list and add modules to current list
* of modules, if they're not present already
*/
/* LINTED: pointer cast */
do {
/*
* Since the aout could've been renamed after its run, we
* should see if current module overlaps aout. If it does, it
* is probably the renamed aout. We should also skip any other
* non-sharedobj's that we see (or should we report an error ?)
*/
(!is_shared_obj(so_path))) {
/* LINTED: pointer cast */
newmodp = (ProfModule *)
continue;
}
/*
* Check all modules (leave the first one, 'cos that
* is the program executable info). If this module is already
* there in the list, skip it.
*/
/*
* We expect the full pathname for all shared objects
* needed by the program executable. In this case, we
* simply need to compare the paths to see if they are
* the same file.
*/
break;
/*
* Check if this new shared object will overlap any
* existing module. If yes, deactivate the old one.
*/
}
/* Module already there, skip it */
/* LINTED: pointer cast */
newmodp = (ProfModule *)
continue;
}
/*
* Check if mon.out is outdated with respect to the new
* module we want to add
*/
"%s: newer shared obj %s outdates profile info\n",
}
/* Create this module's nameslist */
/* Add it to the tail of active module list */
/*
* Move to the next module in the PROF_MODULES_T list
* (if present)
*/
/* LINTED: pointer cast */
} while (more_modules);
}
static void
{
/*
* Save file end pointer and start after header
*/
/* LINTED: pointer cast */
case PROF_MODULES_T :
break;
case PROF_CALLGRAPH_T :
found_cgraph = TRUE;
break;
case PROF_BUFFER_T :
break;
default :
"%s: unknown prof object type=%d\n",
}
/* LINTED: pointer cast */
}
if (!found_cgraph || !found_pcsamples) {
}
}
}
static void
{
}
}
void
profver(void)
{
int fd;
unsigned int magic_num;
bool invalid_version;
/*
* Check the magic and see if this is versioned or *old-style*
* mon.out.
*/
}
perror("read");
}
if (magic_num != (unsigned int) PROF_MAGIC) {
return;
}
/*
* Check versioning info. For now, let's say we provide
* backward compatibility, so we accept all older versions.
*/
perror("read");
}
}
if (invalid_version) {
"%s: mon.out version %d.%d not supported\n",
}
/*
* Map mon.out onto memory.
*/
}
perror("mmap");
}
/*
* Now, read program executable's symbol table. Also save it's
* stat in aout_stat for use while processing mon.out
*/
}
/*
* Process the mon.out, all shared objects it references
* and collect statistics on ticks spent in each function,
* number of calls, etc.
*/
/*
* Based on the flags and the statistics we've got, create
* a list of relevant symbols whose profiling details should
* be printed
*/
/*
* Check for duplicate names in output. We need to print the
* module id's if verbose. Also, if we are sorting by name anyway,
* we don't need to check for duplicates here. We'll do that later.
*/
/*
* Print output
*/
exit(0);
}