blob: d415d591e1ebb328783c259c8968f9c89b7f57a0 [file] [log] [blame]
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <libintl.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "util.h"
#include "Dbe.h"
#include "StringBuilder.h"
#include "DbeSession.h"
#include "DbeView.h"
#include "Settings.h"
#include "Print.h"
#include "DbeView.h"
#include "Experiment.h"
#include "MetricList.h"
#include "Module.h"
#include "Function.h"
#include "DataSpace.h"
#include "DataObject.h"
#include "FilterExp.h"
#include "LoadObject.h"
#include "Emsg.h"
#include "Table.h"
#include "DbeFile.h"
#include "CallStack.h"
int
er_print_common_display::open (Print_params *params)
{
pr_params = *params;
pr_params.name = dbe_strdup (params->name);
if (params->dest == DEST_PRINTER)
{
tmp_file = dbeSession->get_tmp_file_name (NTXT ("print"), false);
dbeSession->tmp_files->append (strdup (tmp_file));
out_file = fopen (tmp_file, NTXT ("w"));
}
else if (params->dest == DEST_OPEN_FILE)
out_file = pr_params.openfile;
else
out_file = fopen (pr_params.name, NTXT ("w"));
if (out_file == NULL)
// Failure
return 1;
return 0;
}
bool
er_print_common_display::print_output ()
{
char *sys_call;
bool ret = true;
if (pr_params.dest != DEST_OPEN_FILE)
fclose (out_file);
if (pr_params.dest == DEST_PRINTER)
{
if (streq ((char *) pr_params.name, NTXT ("")))
sys_call = dbe_sprintf ("(/usr/bin/lp -c -n%d %s) 2>/dev/null 1>&2",
pr_params.ncopies, tmp_file);
else
sys_call = dbe_sprintf ("(/usr/bin/lp -c -d%s -n%d %s) 2>/dev/null 1>&2",
pr_params.name, pr_params.ncopies, tmp_file);
if (system (sys_call) != 0)
ret = false;
unlink (tmp_file);
free (sys_call);
}
return ret;
}
// Return the report. If the report size is greater than max, return truncated report
// Allocates memory, so the caller should free this memory.
char *
er_print_common_display::get_output (int maxsize)
{
off_t max = (off_t) maxsize;
if (out_file != (FILE *) NULL)
{
fclose (out_file); // close tmp_file
out_file = (FILE *) NULL;
}
struct stat sbuf;
int st = stat (tmp_file, &sbuf);
if (st == 0)
{
off_t sz = sbuf.st_size;
if (sz > max)
return dbe_sprintf (GTXT ("Error: report is too long.\n"));
if (sz <= 0)
return dbe_sprintf (GTXT ("Error: empty temporary file: %s\n"),
tmp_file);
max = sz;
}
FILE *f = fopen (tmp_file, "r");
if (f == NULL)
return dbe_sprintf (GTXT ("Error: cannot open temporary file: %s\n"),
tmp_file);
char *report = (char *) malloc (max);
if (report)
{
if (1 != fread (report, max - 1, 1, f))
{
fclose (f);
free (report);
return dbe_sprintf (GTXT ("Error: cannot read temporary file: %s\n"),
tmp_file);
}
report[max - 1] = 0;
}
fclose (f);
return report;
}
void
er_print_common_display::header_dump (int exp_idx)
{
if (load && (exp_idx == exp_idx1))
{
load = false;
print_load_object (out_file);
}
print_header (dbeSession->get_exp (exp_idx), out_file);
}
char *
pr_load_objects (Vector<LoadObject*> *loadobjects, char *lead)
{
int size, i;
LoadObject *lo;
Emsg *m;
char *msg;
StringBuilder sb;
char *lo_name;
size = loadobjects->size ();
for (i = 0; i < size; i++)
{
lo = loadobjects->fetch (i);
lo_name = lo->get_name ();
if (lo_name != NULL)
{
size_t len = strlen (lo_name);
if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
continue;
}
// print the segment name
sb.append (lead);
sb.append (NTXT (" "));
sb.append (lo->get_name ());
sb.append (NTXT (" ("));
sb.append (lo->get_pathname ());
sb.append (NTXT (")\n"));
// and any warnings
m = lo->fetch_warnings ();
if (m != NULL)
{
msg = pr_mesgs (m, NULL, NTXT (" "));
sb.append (msg);
free (msg);
}
}
return sb.toString ();
}
char *
pr_mesgs (Emsg *msg, const char *null_str, const char *lead)
{
Emsg *m;
StringBuilder sb;
if (msg == NULL)
return dbe_strdup (null_str);
for (m = msg; m; m = m->next)
{
sb.append (lead);
sb.append (m->get_msg ());
sb.append (NTXT ("\n"));
}
return sb.toString ();
}
void
print_load_object (FILE *out_file)
{
Vector<LoadObject*> *loadobjects = dbeSession->get_text_segments ();
char *msg = pr_load_objects (loadobjects, NTXT ("\t"));
fprintf (out_file, GTXT ("Load Object Coverage:\n"));
fprintf (out_file, NTXT ("%s"), msg);
fprintf (out_file,
"----------------------------------------------------------------\n");
free (msg);
delete loadobjects;
}
void
print_header (Experiment *exp, FILE *out_file)
{
fprintf (out_file, GTXT ("Experiment: %s\n"), exp->get_expt_name ());
char *msg = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT (""));
fprintf (out_file, NTXT ("%s"), msg);
free (msg);
msg = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT (""));
fprintf (out_file, NTXT ("%s"), msg);
free (msg);
msg = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT (""));
fprintf (out_file, NTXT ("%s"), msg);
free (msg);
msg = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT (""));
fprintf (out_file, NTXT ("%s"), msg);
free (msg);
msg = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT (""));
fprintf (out_file, NTXT ("%s"), msg);
free (msg);
}
static char *
delTrailingBlanks (char *s)
{
for (int i = (int) strlen (s) - 1; i >= 0 && s[i] == ' '; i--)
s[i] = 0;
return s;
}
/**
* Print the 3-line header with column heads for the metrics
* Return offset of "Name" column (this is needed to print Callers-Callees)
*/
int
print_label (FILE *out_file, MetricList *metrics_list,
Metric::HistMetric *hist_metric, int space)
{
char line0[2 * MAX_LEN], line1[2 * MAX_LEN];
char line2[2 * MAX_LEN], line3[2 * MAX_LEN];
int name_offset = 0;
*line0 = *line1 = *line2 = *line3 = '\0';
Vector<Metric*> *mlist = metrics_list->get_items ();
for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++)
{
Metric *mitem = mlist->fetch (index);
if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
{
Metric::HistMetric *hitem = hist_metric + index;
const char *s;
if (index > 0 && mitem->get_type () == Metric::ONAME)
{
s = " ";
name_offset = strlen (line1);
}
else
s = "";
int width = (int) hitem->width;
size_t len = strlen (line1);
snprintf (line1 + len, sizeof (line1) - len, "%s%-*s", s, width,
hitem->legend1);
len = strlen (line2);
snprintf (line2 + len, sizeof (line2) - len, "%s%-*s", s, width,
hitem->legend2);
len = strlen (line3);
snprintf (line3 + len, sizeof (line3) - len, "%s%-*s", s, width,
hitem->legend3);
len = strlen (line0);
snprintf (line0 + len, sizeof (line0) - len, "%s%-*s", s, width,
mitem->legend ? mitem->legend : NTXT (""));
}
}
char *s = delTrailingBlanks (line0);
if (*s)
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), s);
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line1));
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line2));
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line3));
return name_offset;
}
er_print_histogram::er_print_histogram (DbeView *_dbev, Hist_data *data,
MetricList *metrics_list,
Print_mode disp_type, int limit,
char *sort_name, Histable *sobj,
bool show_load, bool show_header)
{
hist_data = data;
mlist = metrics_list;
type = disp_type;
number_entries = limit;
sort_metric = sort_name;
sel_obj = sobj;
dbev = _dbev;
exp_idx1 = 0;
exp_idx2 = dbeSession->nexps () - 1;
load = show_load;
header = show_header;
}
void
er_print_histogram::dump_list (int limit)
{
Histable::NameFormat nfmt = dbev->get_name_format ();
StringBuilder sb;
char *title = NULL; // No title for some formats
enum PrintMode pm = dbev->get_printmode ();
// create a header line, except for delimiter-separated list output
if (pm != PM_DELIM_SEP_LIST)
{
if (hist_data->type == Histable::FUNCTION)
sb.append (GTXT ("Functions sorted by metric: "));
else if (hist_data->type == Histable::INSTR)
sb.append (GTXT ("PCs sorted by metric: "));
else if (hist_data->type == Histable::LINE)
sb.append (GTXT ("Lines sorted by metric: "));
else if (hist_data->type == Histable::DOBJECT)
sb.append (GTXT ("Dataobjects sorted by metric: "));
else
sb.append (GTXT ("Objects sorted by metric: "));
sb.append (sort_metric);
title = sb.toString ();
}
switch (pm)
{
case PM_TEXT:
{
Metric::HistMetric *hist_metric = hist_data->get_histmetrics ();
fprintf (out_file, NTXT ("%s\n\n"), title); //print title
hist_data->print_label (out_file, hist_metric, 0);
hist_data->print_content (out_file, hist_metric, limit);
fprintf (out_file, nl);
break;
}
case PM_HTML:
{
print_html_title (out_file, title);
print_html_label (out_file, mlist);
print_html_content (out_file, hist_data, mlist, limit, nfmt);
print_html_trailer (out_file);
break;
}
case PM_DELIM_SEP_LIST:
{
char delim = dbev->get_printdelimiter ();
print_delim_label (out_file, mlist, delim);
print_delim_content (out_file, hist_data, mlist, limit, nfmt, delim);
print_delim_trailer (out_file, delim);
break;
}
}
free (title);
}
void
er_print_histogram::dump_annotated_dataobjects (Vector<int> *marks,
int ithreshold)
{
if (!dbeSession->is_datamode_available ())
fprintf (out_file,
GTXT ("No dataspace information recorded in experiments\n\n"));
Hist_data *layout_data = dbev->get_data_space ()->get_layout_data (hist_data, marks, ithreshold);
Metric::HistMetric *hist_metric = layout_data->get_histmetrics ();
// snprintf (hist_metric[name_index].legend2, MAX_LEN, GTXT ("* +offset .element"));
layout_data->print_label (out_file, hist_metric, 3);
fprintf (out_file, nl);
StringBuilder sb;
for (long i = 0; i < layout_data->size (); i++)
{
sb.setLength (0);
if (marks->find (i) != -1)
sb.append ("## ");
else
sb.append (" ");
layout_data->print_row (&sb, i, hist_metric, " ");
sb.toFileLn (out_file);
}
fprintf (out_file, nl);
delete layout_data;
}
static int
max_length(size_t len, size_t str_len)
{
if (str_len > len)
return str_len;
return len;
}
void
er_print_histogram::dump_detail (int limit)
{
Histable *obj;
Hist_data *current_data;
Histable::Type htype;
TValue *values;
double dvalue, percent;
MetricList *prop_mlist = new MetricList (mlist);
Metric *mitem;
int index, i;
Module *module;
LoadObject *loadobject;
char *sname, *oname, *lname, *alias, *mangle;
Histable::NameFormat nfmt = dbev->get_name_format ();
// Check max. length of metrics names
size_t len = 0, slen = 0;
Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
{
mitem->set_vvisible (true);
if (mitem->get_vtype () == VT_LABEL)
continue;
if (mitem->get_subtype () != Metric::STATIC)
{
mitem->set_pvisible (true);
len = max_length (len, hist_data->value_maxlen (index));
slen = max_length (slen, strlen (mitem->get_name ()));
}
}
// now get the length of the other (non-performance-data) messages
if (hist_data->type == Histable::FUNCTION)
{
slen = max_length (slen, strlen (GTXT ("Source File")));
slen = max_length (slen, strlen (GTXT ("Object File")));
slen = max_length (slen, strlen (GTXT ("Load Object")));
slen = max_length (slen, strlen (GTXT ("Mangled Name")));
slen = max_length (slen, strlen (GTXT ("Aliases")));
}
else if (hist_data->type == Histable::DOBJECT)
{
slen = max_length (slen, strlen (GTXT ("Scope")));
slen = max_length (slen, strlen (GTXT ("Type")));
slen = max_length (slen, strlen (GTXT ("Member of")));
slen = max_length (slen, strlen (GTXT ("Offset (bytes)")));
slen = max_length (slen, strlen (GTXT ("Size (bytes)")));
slen = max_length (slen, strlen (GTXT ("Elements")));
}
int max_len = (int) len;
int smax_len = (int) slen;
#define PR_TITLE(t) fprintf (out_file, "\t%*s:", smax_len, t)
#define PR(title, nm) PR_TITLE(title); \
if (nm) \
fprintf (out_file, " %s", nm); \
fprintf (out_file, "\n")
// now loop over the objects
int num_printed_items = 0;
for (i = 0; i < hist_data->size (); i++)
{
if (hist_data->type == Histable::FUNCTION)
{
if (num_printed_items >= limit)
break;
obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj;
htype = obj->get_type ();
// ask the view for all the data for the object
// xxxxx may be expensive to rescan all packets via get_hist_data()
current_data = dbev->get_hist_data (prop_mlist,
htype, 0, Hist_data::SELF, obj);
if (current_data->size () == 0)
continue;
values = current_data->fetch (0)->value;
}
else
{
obj = hist_data->fetch (i)->obj;
DataObject *dobj = (DataObject*) obj;
if (sel_obj)
{
// print selected item and its members
if (sel_obj != obj
&& (DataObject*) sel_obj != dobj->get_parent ())
// not a match, advance to next item
continue;
}
else if (num_printed_items >= limit)
break;
htype = obj->get_type ();
values = hist_data->fetch (i)->value;
current_data = hist_data;
}
if (num_printed_items)
// if this isn't the first one, add a blank line
fprintf (out_file, NTXT ("\n"));
num_printed_items++;
// Print full object name
if (htype != Histable::DOBJECT)
fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt));
else
{
DataObject *dobj = (DataObject*) obj;
if (!dobj->get_parent ())
fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt));
else
fprintf (out_file, NTXT (" %s\n"), obj->get_name (nfmt));
}
Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
{
if (mitem->get_vtype () == VT_LABEL)
continue;
if (mitem->get_subtype () == Metric::STATIC
&& htype == Histable::DOBJECT)
continue;
PR_TITLE (mitem->get_name ());
char buf[128];
char *s = values[index].to_str (buf, sizeof (buf));
if (mitem->get_value_styles () & VAL_PERCENT)
{
dvalue = values[index].to_double ();
percent = 100.0 * current_data->get_percentage (dvalue, index);
if (!mitem->is_time_val ())
{
fprintf (out_file, " %*s", max_len, s);
if (dvalue == 0.)
fprintf (out_file, " ( 0. %%)\n");
else
fprintf (out_file, " (%5.1f%%)\n", percent);
continue;
}
TValue v;
v.tag = VT_DOUBLE;
v.sign = false;
v.d = dvalue / (1.e+6 * dbeSession->get_clock (-1));
char buf1[128];
char *s1 = v.to_str (buf1, sizeof (buf1));
fprintf (out_file, " %*s", max_len, s1);
if (dvalue == 0.)
fprintf (out_file, " ( 0. %%)\n");
else
fprintf (out_file, " (%5.1f%%)\n", percent);
PR_TITLE (GTXT ("Count"));
}
int max_len1 = max_len;
for (int j = (int) strlen (s) - 1; j >= 0 && s[j] == ' '; j--)
{
s[j] = 0;
max_len1--;
}
fprintf (out_file, " %*s\n", max_len1, s);
}
// now add the descriptive information about the object
if (htype != Histable::DOBJECT)
{
Function *func = (Function*) obj->convertto (Histable::FUNCTION);
if (func && func->get_type () == Histable::FUNCTION)
{
// Print the source/object/load-object files & aliases
oname = lname = alias = NULL;
sname = func->getDefSrcName ();
mangle = func->get_mangled_name ();
if (mangle && streq (func->get_name (), mangle))
mangle = NULL;
module = func->module;
if (module)
{
oname = module->get_name ();
loadobject = module->loadobject;
if (loadobject)
{
lname = loadobject->get_pathname ();
alias = loadobject->get_alias (func);
}
}
if (htype == Histable::INSTR && dbeSession->is_datamode_available ())
alias = ((DbeInstr*) obj)->get_descriptor ();
PR (GTXT ("Source File"), sname);
PR (GTXT ("Object File"), oname);
PR (GTXT ("Load Object"), lname);
PR (GTXT ("Mangled Name"), mangle);
PR (GTXT ("Aliases"), alias);
}
}
else
{
// Print the dataobject information
DataObject *dobj = (DataObject*) obj;
Histable *scope = dobj->get_scope ();
// print the scope
PR_TITLE (GTXT ("Scope"));
if (!scope)
fprintf (out_file, GTXT ("(Global)\n"));
else switch (scope->get_type ())
{
case Histable::FUNCTION:
fprintf (out_file, NTXT ("%s(%s)\n"),
((Function*) scope)->module->get_name (),
scope->get_name ());
break;
case Histable::LOADOBJECT:
case Histable::MODULE:
default:
fprintf (out_file, NTXT ("%s\n"), scope->get_name ());
}
// print the type name
PR_TITLE (GTXT ("Type"));
if (dobj->get_typename ())
fprintf (out_file, NTXT ("%s\n"), dobj->get_typename ());
else
fprintf (out_file, GTXT ("(Synthetic)\n"));
// print the offset
if (dobj->get_offset () != -1)
{
if (dobj->get_parent ())
{
PR_TITLE (GTXT ("Member of"));
fprintf (out_file, NTXT ("%s\n"), dobj->get_parent ()->get_name ());
}
PR_TITLE (GTXT ("Offset (bytes)"));
fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_offset ());
}
// print the size
if (dobj->get_size ())
{
PR_TITLE (GTXT ("Size (bytes)"));
fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_size ());
}
}
if (hist_data->type == Histable::FUNCTION)
delete current_data;
}
if (num_printed_items == 0 && sel_obj)
fprintf (stderr,
GTXT ("Error: Specified item `%s' had no recorded metrics.\n"),
sel_obj->get_name ());
delete prop_mlist;
}
static Metric::HistMetric *
allocateHistMetric (int no_metrics)
{
Metric::HistMetric *hist_metric = new Metric::HistMetric[no_metrics];
for (int i = 0; i < no_metrics; i++)
{
Metric::HistMetric *hm = &hist_metric[i];
hm->init ();
}
return hist_metric;
}
void
er_print_histogram::dump_gprof (int limit)
{
StringBuilder sb;
Histable *obj;
Hist_data *callers;
Hist_data *callees;
Hist_data *center;
int no_metrics = mlist->get_items ()->size ();
Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics);
for (int i = 0; i < limit; i++)
{
obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj;
callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLERS, obj);
callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLEES, obj);
center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::SELF, obj);
callers->update_max (hist_metric);
callees->update_max (hist_metric);
center->update_max (hist_metric);
callers->update_legend_width (hist_metric);
callers->print_label (out_file, hist_metric, 0);
callers->print_content (out_file, hist_metric, callers->size ());
if (center->size () > 0)
{
center->update_total (callers->get_totals ());
sb.setLength (0);
center->print_row (&sb, 0, hist_metric, NTXT ("*"));
sb.toFileLn (out_file);
}
callees->print_content (out_file, hist_metric, callees->size ());
fprintf (out_file, nl);
delete callers;
delete callees;
delete center;
}
delete[] hist_metric;
}
// dump an annotated file
void
dump_anno_file (FILE *fp, Histable::Type type, Module *module, DbeView *dbev,
MetricList *mlist, TValue *ftotal, const char *srcFile,
Function *func, Vector<int> *marks, int threshold, int vis_bits,
int src_visible, bool hex_visible, bool src_only)
{
int lspace, mspace, tspace, remain, mindex, next_mark, hidx, index;
Metric *mitem;
char buf[MAX_LEN];
Hist_data::HistItem *item;
SourceFile *srcContext = NULL;
bool func_scope = dbev == NULL ? false : dbev->get_func_scope ();
if (srcFile)
{
srcContext = module->findSource (srcFile, false);
if (srcContext == NULL)
{
Vector<SourceFile*> *includes = module->includes;
char *bname = get_basename (srcFile);
for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
{
SourceFile *sf = includes->fetch (i);
if (streq (get_basename (sf->get_name ()), bname))
{
srcContext = sf;
break;
}
}
}
if (func)
func_scope = true;
}
else if (func)
srcContext = func->getDefSrc ();
Hist_data *hdata = module->get_data (dbev, mlist, type, ftotal, srcContext,
func, marks, threshold, vis_bits,
src_visible, hex_visible,
func_scope, src_only);
if (hdata == NULL)
return;
// force the name metric to be invisible
MetricList *nmlist = hdata->get_metric_list ();
nmlist->find_metric (GTXT ("name"), Metric::STATIC)->clear_all_visbits ();
Metric::HistMetric *hist_metric = hdata->get_histmetrics ();
// lspace is for max line number that's inserted; use to set width
int max_lineno = 0;
Vec_loop (Hist_data::HistItem*, hdata, hidx, item)
{
if (!item->obj)
continue;
if (item->obj->get_type () == Histable::LINE
&& ((DbeLine*) item->obj)->lineno > max_lineno)
max_lineno = ((DbeLine*) item->obj)->lineno;
else if (item->obj->get_type () == Histable::INSTR
&& ((DbeInstr*) item->obj)->lineno > max_lineno)
max_lineno = ((DbeInstr*) item->obj)->lineno;
}
lspace = snprintf (buf, sizeof (buf), NTXT ("%d"), max_lineno);
// mspace is the space needed for all metrics, and the mark, if any
mspace = 0;
if (nmlist->get_items ()->size () > 0)
{
mspace = 3; // mark "## "
Vec_loop (Metric*, nmlist->get_items (), index, mitem)
{
if (mitem->is_visible () || mitem->is_tvisible ()
|| mitem->is_pvisible ())
mspace += (int) hist_metric[index].width;
}
}
tspace = 0;
remain = (mspace + lspace + 3) % 8; // " " before, ". " after line#
if (remain)
{ // tab alignment
tspace = 8 - remain;
mspace += tspace;
}
mindex = 0;
next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1;
// Print the header for this list
SourceFile *sf = srcContext ? srcContext : module->getMainSrc ();
char *src_name = sf->dbeFile->get_location_info ();
DbeFile *df = module->dbeFile;
if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
df = module->loadobject->dbeFile;
char *lo_name = df->get_location_info ();
char *dot_o_name = lo_name;
if (module->dot_o_file)
dot_o_name = module->dot_o_file->dbeFile->get_location_info ();
fprintf (fp, GTXT ("Source file: %s\nObject file: %s\nLoad Object: %s\n\n"),
src_name, dot_o_name, lo_name);
// Print metric labels
if (nmlist->get_items ()->size () != 0)
print_label (fp, nmlist, hist_metric, 3);
// determine the name metric (not printed as a metric, though)
int lind = nmlist->get_listorder (GTXT ("name"), Metric::STATIC);
// now loop over the data rows -- the lines in the annotated source/disasm,
// including index lines, compiler commentary, etc.
StringBuilder sb;
Vec_loop (Hist_data::HistItem*, hdata, hidx, item)
{
sb.setLength (0);
if (item->type == Module::AT_DIS || item->type == Module::AT_QUOTE
|| item->type == Module::AT_SRC)
{
// does this line get a high-metric mark?
if (hidx == next_mark)
{
sb.append (NTXT ("## "));
mindex++;
next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1;
}
else
sb.append (NTXT (" "));
hdata->print_row (&sb, hidx, hist_metric, NTXT (" "));
sb.toFile (fp);
for (int i = sb.length (); i < mspace; i++)
{
fputc (' ', fp);
}
}
else
// this line does not get any metrics; insert blanks in lieu of them
for (int i = 0; i < mspace; i++)
fputc (' ', fp);
switch (item->type)
{
case Module::AT_SRC_ONLY:
if (item->obj == NULL)
fprintf (fp, NTXT ("%*s. "), lspace + 1, "?");
else
fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno);
break;
case Module::AT_SRC:
fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno);
break;
case Module::AT_FUNC:
case Module::AT_QUOTE:
fprintf (fp, NTXT ("%*c"), lspace + 3, ' ');
break;
case Module::AT_DIS:
case Module::AT_DIS_ONLY:
if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
fprintf (fp, "%*c[%*s] ", lspace + 3, ' ', lspace, "?");
else
fprintf (fp, "%*c[%*d] ", lspace + 3, ' ', lspace,
((DbeInstr*) item->obj)->lineno);
break;
case Module::AT_COM:
case Module::AT_EMPTY:
break;
}
if (item->value[lind].l == NULL)
item->value[lind].l = dbe_strdup (GTXT ("INTERNAL ERROR: missing line text"));
fprintf (fp, NTXT ("%s\n"), item->value[lind].l);
}
delete hdata;
}
void
er_print_histogram::dump_annotated ()
{
Vector<int> *marks = new Vector<int>;
Function *anno_func = (Function *) sel_obj;
Module *module = anno_func ? anno_func->module : NULL;
if (hist_data->type == Histable::DOBJECT)
dump_annotated_dataobjects (marks, number_entries); // threshold
else if (number_entries == 0)
// Annotated source
dump_anno_file (out_file, Histable::LINE, module, dbev, mlist,
hist_data->get_totals ()->value, NULL, anno_func, marks,
dbev->get_thresh_src (), dbev->get_src_compcom (),
dbev->get_src_visible (), dbev->get_hex_visible (), true);
else
// Annotated disassembly
dump_anno_file (out_file, Histable::INSTR, module, dbev, mlist,
hist_data->get_totals ()->value, NULL, anno_func, marks,
dbev->get_thresh_dis (), dbev->get_dis_compcom (),
dbev->get_src_visible (), dbev->get_hex_visible (), true);
}
void
er_print_histogram::data_dump ()
{
int limit;
if (hist_data->get_status () == Hist_data::SUCCESS)
{
if (sort_metric[0] == '\n')
{ // csingle Callers-Callees entry
sort_metric++;
fprintf (out_file, NTXT ("%s\n\n"), sort_metric);
}
else if (!sel_obj && type != MODE_LIST)
{
if (hist_data->type == Histable::FUNCTION)
fprintf (out_file,
GTXT ("Functions sorted by metric: %s\n\n"), sort_metric);
else if (hist_data->type == Histable::DOBJECT)
fprintf (out_file, GTXT ("Dataobjects sorted by metric: %s\n\n"),
sort_metric);
else
fprintf (out_file,
GTXT ("Objects sorted by metric: %s\n\n"), sort_metric);
}
limit = hist_data->size ();
if ((number_entries > 0) && (number_entries < limit))
limit = number_entries;
switch (type)
{
case MODE_LIST:
dump_list (limit);
break;
case MODE_DETAIL:
dump_detail (limit);
break;
case MODE_GPROF:
dump_gprof (limit);
break;
case MODE_ANNOTATED:
dump_annotated ();
break;
}
}
else
fprintf (out_file, GTXT ("Get_Hist_data call failed %d\n"),
(int) hist_data->get_status ());
}
/*
* Class er_print_ctree to print functions call tree
*/
er_print_ctree::er_print_ctree (DbeView *_dbev, Vector<Histable*> *_cstack,
Histable *_sobj, int _limit)
{
dbev = _dbev;
cstack = _cstack;
sobj = _sobj;
limit = _limit;
print_row = 0;
exp_idx1 = 0;
exp_idx2 = dbeSession->nexps () - 1;
load = false;
header = false;
}
void
er_print_ctree::data_dump ()
{
StringBuilder sb;
Hist_data::HistItem *total;
sb.append (GTXT ("Functions Call Tree. Metric: "));
char *s = dbev->getSort (MET_CALL_AGR);
sb.append (s);
free (s);
sb.toFileLn (out_file);
fprintf (out_file, NTXT ("\n"));
mlist = dbev->get_metric_list (MET_CALL_AGR);
// Change cstack: add sobj to the end of cstack
cstack->append (sobj);
Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::SELF, cstack);
Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLERS, cstack);
Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLEES, cstack);
// Restore cstack
int last = cstack->size () - 1;
cstack->remove (last);
// Prepare formats
int no_metrics = mlist->size ();
// calculate max. width using data from callers, callees, center
hist_metric = allocateHistMetric (no_metrics);
callers->update_max (hist_metric);
callees->update_max (hist_metric);
center->update_max (hist_metric);
callers->update_legend_width (hist_metric);
callers->print_label (out_file, hist_metric, 0); // returns Name column offset
print_row = 0;
// Pass real total to print_children()
total = center->get_totals ();
print_children (center, 0, sobj, NTXT (" "), total);
// Free memory
cstack->reset ();
delete callers;
delete callees;
delete center;
delete[] hist_metric;
}
/*
* Recursive method print_children prints Call Tree elements.
*/
void
er_print_ctree::print_children (Hist_data *data, int index, Histable *my_obj,
char * prefix, Hist_data::HistItem *total)
{
StringBuilder buf;
const char *P0 = "+-";
const char *P2 = " |";
const char *P1 = " ";
// If limit exceeded - return
++print_row;
if (limit > 0 && print_row > limit)
return;
if (my_obj == NULL)
return; // should never happen
// Prepare prefix
buf.append (prefix);
if (buf.endsWith (P2))
{
int len = buf.length () - 1;
buf.setLength (len);
}
buf.append (P0);
// Change cstack: add my_obj to the end of cstack
cstack->append (my_obj);
// Print current node info
char * my_prefix = buf.toString ();
// Replace parent's total values with real total values
data->update_total (total); // Needed to to calculate percentage only
buf.setLength (0);
data->print_row (&buf, index, hist_metric, my_prefix);
buf.toFileLn (out_file);
free (my_prefix);
// Get children
Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLEES, cstack);
int nc = callees->size ();
if (nc > 0)
{
// Print children
Hist_data::HistItem *item;
Histable *ch_obj;
char *ch_prefix;
buf.setLength (0);
buf.append (prefix);
buf.append (P2);
ch_prefix = buf.toString ();
for (int i = 0; i < nc - 1; i++)
{
item = callees->fetch (i);
ch_obj = item->obj;
print_children (callees, i, ch_obj, ch_prefix, total);
}
free (ch_prefix);
buf.setLength (0);
buf.append (prefix);
buf.append (P1);
ch_prefix = buf.toString ();
item = callees->fetch (nc - 1);
ch_obj = item->obj;
print_children (callees, nc - 1, ch_obj, ch_prefix, total);
free (ch_prefix);
}
// Restore cstack
int last = cstack->size () - 1;
cstack->remove (last);
delete callees;
return;
}
er_print_gprof::er_print_gprof (DbeView *_dbev, Vector<Histable*> *_cstack)
{
dbev = _dbev;
cstack = _cstack;
exp_idx1 = 0;
exp_idx2 = dbeSession->nexps () - 1;
load = false;
header = false;
}
void
er_print_gprof::data_dump ()
{
StringBuilder sb;
sb.append (GTXT ("Callers and callees sorted by metric: "));
char *s = dbev->getSort (MET_CALL);
sb.append (s);
free (s);
sb.toFileLn (out_file);
fprintf (out_file, NTXT ("\n"));
MetricList *mlist = dbev->get_metric_list (MET_CALL);
Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::SELF, cstack);
Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLERS, cstack);
Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
Hist_data::CALLEES, cstack);
mlist = center->get_metric_list ();
int no_metrics = mlist->get_items ()->size ();
// update max. width for callers/callees/center function item
Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics);
callers->update_max (hist_metric);
callees->update_max (hist_metric);
center->update_max (hist_metric);
callers->update_legend_width (hist_metric);
int name_offset = callers->print_label (out_file, hist_metric, 0); // returns Name column offset
// Print Callers
sb.setLength (0);
for (int i = 0; i < name_offset; i++)
sb.append (NTXT ("="));
if (name_offset > 0)
sb.append (NTXT (" "));
char *line1 = sb.toString ();
char *line2;
if (callers->size () > 0)
line2 = GTXT ("Callers");
else
line2 = GTXT ("No Callers");
fprintf (out_file, NTXT ("%s%s\n"), line1, line2);
callers->print_content (out_file, hist_metric, callers->size ());
// Print Stack Fragment
line2 = GTXT ("Stack Fragment");
fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2);
for (long i = 0, last = cstack->size () - 1; i <= last; ++i)
{
sb.setLength (0);
if (i == last && center->size () > 0)
{
center->update_total (callers->get_totals ()); // Needed to to calculate percentage only
center->print_row (&sb, center->size () - 1, hist_metric, NTXT (" "));
}
else
{
for (int n = name_offset; n > 0; n--)
sb.append (NTXT (" "));
if (name_offset > 0)
sb.append (NTXT (" "));
sb.append (cstack->get (i)->get_name ());
}
sb.toFileLn (out_file);
}
// Print Callees
if (callees->size () > 0)
line2 = GTXT ("Callees");
else
line2 = GTXT ("No Callees");
fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2);
callees->print_content (out_file, hist_metric, callees->size ());
fprintf (out_file, nl);
free (line1);
delete callers;
delete callees;
delete center;
delete[] hist_metric;
}
er_print_leaklist::er_print_leaklist (DbeView *_dbev, bool show_leak,
bool show_alloca, int _limit)
{
dbev = _dbev;
leak = show_leak;
alloca = show_alloca;
limit = _limit;
}
// Output routine for leak list only
void
er_print_leaklist::data_dump ()
{
CStack_data *lam;
CStack_data::CStack_item *lae;
int index;
if (!dbeSession->is_leaklist_available ())
fprintf (out_file, GTXT ("No leak or allocation information recorded in experiments\n\n"));
MetricList *origmlist = dbev->get_metric_list (MET_NORMAL);
if (leak)
{
// make a copy of the metric list, and set metrics for leaks
MetricList *nmlist = new MetricList (origmlist);
nmlist->set_metrics ("e.heapleakbytes:e.heapleakcnt:name", true,
dbev->get_derived_metrics ());
// now make a compacted version of it to get the right indices
MetricList *mlist = new MetricList (nmlist);
delete nmlist;
// fetch the callstack data
lam = dbev->get_cstack_data (mlist);
// now print it
if (lam && lam->size () != 0)
{
fprintf (out_file, GTXT ("Summary Results: Distinct Leaks = %d, Total Instances = %lld, Total Bytes Leaked = %lld\n\n"),
(int) lam->size (), lam->total->value[1].ll,
lam->total->value[0].ll);
Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
{
fprintf (out_file,
GTXT ("Leak #%d, Instances = %lld, Bytes Leaked = %lld\n"),
index + 1, lae->value[1].ll, lae->value[0].ll);
if (lae->stack != NULL)
for (int i = lae->stack->size () - 1; i >= 0; i--)
{
DbeInstr *instr = lae->stack->fetch (i);
fprintf (out_file, NTXT (" %s\n"), instr->get_name ());
}
fprintf (out_file, NTXT ("\n"));
if (index + 1 == limit) break;
}
}
else
fprintf (out_file, GTXT ("No leak information\n\n"));
delete lam;
delete mlist;
}
if (alloca)
{
// make a copy of the metric list, and set metrics for leaks
MetricList *nmlist = new MetricList (origmlist);
nmlist->set_metrics ("e.heapallocbytes:e.heapalloccnt:name",
true, dbev->get_derived_metrics ());
// now make a compacted version of it to get the right indices
MetricList *mlist = new MetricList (nmlist);
delete nmlist;
// fetch the callstack data
lam = dbev->get_cstack_data (mlist);
// now print it
if (lam && lam->size () != 0)
{
fprintf (out_file, GTXT ("Summary Results: Distinct Allocations = %d, Total Instances = %lld, Total Bytes Allocated = %lld\n\n"),
(int) lam->size (), lam->total->value[1].ll,
lam->total->value[0].ll);
Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
{
fprintf (out_file, GTXT ("Allocation #%d, Instances = %lld, Bytes Allocated = %lld\n"),
index + 1, lae->value[1].ll, lae->value[0].ll);
if (lae->stack != NULL)
for (int i = lae->stack->size () - 1; i >= 0; i--)
{
DbeInstr *instr = lae->stack->fetch (i);
fprintf (out_file, NTXT (" %s\n"), instr->get_name ());
}
fprintf (out_file, NTXT ("\n"));
if (index + 1 == limit) break;
}
}
else
fprintf (out_file, GTXT ("No allocation information\n\n"));
delete lam;
delete mlist;
}
}
er_print_heapactivity::er_print_heapactivity (DbeView *_dbev,
Histable::Type _type,
bool _printStat, int _limit)
{
dbev = _dbev;
type = _type;
printStat = _printStat;
limit = _limit;
}
void
er_print_heapactivity::printCallStacks (Hist_data *hist_data)
{
Hist_data::HistItem *hi;
HeapData *hData;
long stackId;
int size = hist_data->size ();
if (limit > 0 && limit < size)
size = limit;
Histable::NameFormat fmt = dbev->get_name_format ();
for (int i = 0; i < size; i++)
{
hi = hist_data->fetch (i);
hData = (HeapData*) hi->obj;
stackId = hData->id;
if (i != 0)
fprintf (out_file, NTXT ("\n"));
fprintf (out_file, NTXT ("%s\n"), hData->get_name (fmt));
if (hData->getAllocCnt () > 0)
{
fprintf (out_file, GTXT ("Instances = %d "),
(int) (hData->getAllocCnt ()));
fprintf (out_file, GTXT ("Bytes Allocated = %lld\n"),
(long long) hData->getAllocBytes ());
}
if (hData->getLeakCnt () > 0)
{
fprintf (out_file, GTXT ("Instances = %d "),
(int) (hData->getLeakCnt ()));
fprintf (out_file, GTXT ("Bytes Leaked = %lld\n"),
(long long) hData->getLeakBytes ());
}
// There is no stack trace for <Total>
if (i == 0)
continue;
// LIBRARY VISIBILITY pass extra argument if necessary to get hide stack
Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId);
if (instrs != NULL)
{
int stSize = instrs->size ();
for (int j = 0; j < stSize; j++)
{
Histable *instr = instrs->fetch (j);
if (instr != NULL)
fprintf (out_file, NTXT (" %s\n"), instr->get_name ());
}
delete instrs;
}
}
}
void
er_print_heapactivity::printStatistics (Hist_data *hist_data)
{
Hist_data::HistItem *hi;
HeapData *hDataTotal;
hi = hist_data->fetch (0);
hDataTotal = (HeapData*) hi->obj;
Vector<hrtime_t> *pTimestamps;
if (hDataTotal->getPeakMemUsage () > 0)
{
fprintf (out_file, GTXT ("\nProcess With Highest Peak Memory Usage\n"));
fprintf (out_file,
"-------------------------------------------------------\n");
fprintf (out_file, GTXT ("Heap size bytes %lld\n"),
(long long) hDataTotal->getPeakMemUsage ());
fprintf (out_file, GTXT ("Experiment Id %d\n"),
(int) (hDataTotal->getUserExpId ()));
fprintf (out_file, GTXT ("Process Id %d\n"),
(int) (hDataTotal->getPid ()));
pTimestamps = hDataTotal->getPeakTimestamps ();
if (pTimestamps != NULL)
for (int i = 0; i < pTimestamps->size (); i++)
fprintf (out_file,
GTXT ("Time of peak %.3f (secs.)\n"),
(double) (pTimestamps->fetch (i) / (double) NANOSEC));
}
if (hDataTotal->getAllocCnt () > 0)
{
fprintf (out_file, GTXT ("\nMemory Allocations Statistics\n"));
fprintf (out_file,
GTXT ("Allocation Size Range Allocations \n"));
fprintf (out_file,
"-------------------------------------------------------\n");
if (hDataTotal->getA0KB1KBCnt () > 0)
fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
hDataTotal->getA0KB1KBCnt ());
if (hDataTotal->getA1KB8KBCnt () > 0)
fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
hDataTotal->getA1KB8KBCnt ());
if (hDataTotal->getA8KB32KBCnt () > 0)
fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
hDataTotal->getA8KB32KBCnt ());
if (hDataTotal->getA32KB128KBCnt () > 0)
fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
hDataTotal->getA32KB128KBCnt ());
if (hDataTotal->getA128KB256KBCnt () > 0)
fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
hDataTotal->getA128KB256KBCnt ());
if (hDataTotal->getA256KB512KBCnt () > 0)
fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
hDataTotal->getA256KB512KBCnt ());
if (hDataTotal->getA512KB1000KBCnt () > 0)
fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
hDataTotal->getA512KB1000KBCnt ());
if (hDataTotal->getA1000KB10MBCnt () > 0)
fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
hDataTotal->getA1000KB10MBCnt ());
if (hDataTotal->getA10MB100MBCnt () > 0)
fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
hDataTotal->getA10MB100MBCnt ());
if (hDataTotal->getA100MB1GBCnt () > 0)
fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
hDataTotal->getA100MB1GBCnt ());
if (hDataTotal->getA1GB10GBCnt () > 0)
fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
hDataTotal->getA1GB10GBCnt ());
if (hDataTotal->getA10GB100GBCnt () > 0)
fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
hDataTotal->getA10GB100GBCnt ());
if (hDataTotal->getA100GB1TBCnt () > 0)
fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
hDataTotal->getA100GB1TBCnt ());
if (hDataTotal->getA1TB10TBCnt () > 0)
fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
hDataTotal->getA1TB10TBCnt ());
fprintf (out_file, GTXT ("\nSmallest allocation bytes %lld\n"),
(long long) hDataTotal->getASmallestBytes ());
fprintf (out_file, GTXT ("Largest allocation bytes %lld\n"),
(long long) hDataTotal->getALargestBytes ());
fprintf (out_file, GTXT ("Total allocations %d\n"),
hDataTotal->getAllocCnt ());
fprintf (out_file, GTXT ("Total bytes %lld\n"),
(long long) hDataTotal->getAllocBytes ());
}
if (hDataTotal->getLeakCnt () > 0)
{
fprintf (out_file, GTXT ("\nMemory Leaks Statistics\n"));
fprintf (out_file,
GTXT ("Leak Size Range Leaks \n"));
fprintf (out_file,
"-------------------------------------------------------\n");
if (hDataTotal->getL0KB1KBCnt () > 0)
fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
hDataTotal->getL0KB1KBCnt ());
if (hDataTotal->getL1KB8KBCnt () > 0)
fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
hDataTotal->getL1KB8KBCnt ());
if (hDataTotal->getL8KB32KBCnt () > 0)
fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
hDataTotal->getL8KB32KBCnt ());
if (hDataTotal->getL32KB128KBCnt () > 0)
fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
hDataTotal->getL32KB128KBCnt ());
if (hDataTotal->getL128KB256KBCnt () > 0)
fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
hDataTotal->getL128KB256KBCnt ());
if (hDataTotal->getL256KB512KBCnt () > 0)
fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
hDataTotal->getL256KB512KBCnt ());
if (hDataTotal->getL512KB1000KBCnt () > 0)
fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
hDataTotal->getL512KB1000KBCnt ());
if (hDataTotal->getL1000KB10MBCnt () > 0)
fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
hDataTotal->getL1000KB10MBCnt ());
if (hDataTotal->getL10MB100MBCnt () > 0)
fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
hDataTotal->getL10MB100MBCnt ());
if (hDataTotal->getL100MB1GBCnt () > 0)
fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
hDataTotal->getL100MB1GBCnt ());
if (hDataTotal->getL1GB10GBCnt () > 0)
fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
hDataTotal->getL1GB10GBCnt ());
if (hDataTotal->getL10GB100GBCnt () > 0)
fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
hDataTotal->getL10GB100GBCnt ());
if (hDataTotal->getL100GB1TBCnt () > 0)
fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
hDataTotal->getL100GB1TBCnt ());
if (hDataTotal->getL1TB10TBCnt () > 0)
fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
hDataTotal->getL1TB10TBCnt ());
fprintf (out_file, GTXT ("\nSmallest leaked bytes %lld\n"),
(long long) hDataTotal->getLSmallestBytes ());
fprintf (out_file, GTXT ("Largest leaked bytes %lld\n"),
(long long) hDataTotal->getLLargestBytes ());
fprintf (out_file, GTXT ("Total leaked %d \n"),
hDataTotal->getLeakCnt ());
fprintf (out_file, GTXT ("Total bytes %lld\n"),
(long long) hDataTotal->getLeakBytes ());
}
fprintf (out_file, NTXT ("\n"));
}
void
er_print_heapactivity::data_dump ()
{
// get the list of heap events from DbeView
int numExps = dbeSession->nexps ();
if (!numExps)
{
fprintf (out_file,
GTXT ("There is no heap event information in the experiments\n"));
return;
}
MetricList *mlist = dbev->get_metric_list (MET_HEAP);
Hist_data *hist_data;
hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL);
if (printStat)
printStatistics (hist_data);
else
printCallStacks (hist_data);
}
er_print_ioactivity::er_print_ioactivity (DbeView *_dbev, Histable::Type _type,
bool _printStat, int _limit)
{
dbev = _dbev;
type = _type;
printStat = _printStat;
limit = _limit;
}
void
er_print_ioactivity::printCallStacks (Hist_data *hist_data)
{
Hist_data::HistItem *hi;
FileData *fData;
long stackId;
int size = hist_data->size ();
if (limit > 0 && limit < size)
size = limit;
for (int i = 0; i < size; i++)
{
hi = hist_data->fetch (i);
fData = (FileData*) hi->obj;
stackId = fData->id;
if (i != 0)
fprintf (out_file, NTXT ("\n"));
fprintf (out_file, NTXT ("%s\n"), fData->getFileName ());
if (fData->getWriteCnt () > 0)
{
fprintf (out_file, GTXT ("Write Time=%.6f (secs.) "),
(double) (fData->getWriteTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Write Bytes=%lld "),
(long long) fData->getWriteBytes ());
fprintf (out_file, GTXT ("Write Count=%d\n"),
(int) (fData->getWriteCnt ()));
}
if (fData->getReadCnt () > 0)
{
fprintf (out_file, GTXT ("Read Time=%.6f (secs.) "),
(double) (fData->getReadTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Read Bytes=%lld "),
(long long) fData->getReadBytes ());
fprintf (out_file, GTXT ("Read Count=%d\n"),
(int) fData->getReadCnt ());
}
if (fData->getOtherCnt () > 0)
{
fprintf (out_file, GTXT ("Other I/O Time=%.6f (secs.) "),
(double) (fData->getOtherTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Other I/O Count=%d\n"),
(int) (fData->getOtherCnt ()));
}
if (fData->getErrorCnt () > 0)
{
fprintf (out_file, GTXT ("I/O Error Time=%.6f (secs.) "),
(double) (fData->getErrorTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("I/O Error Count=%d\n"),
(int) (fData->getErrorCnt ()));
}
// There is no stack trace for <Total>
if (i == 0)
continue;
// LIBRARY VISIBILITY pass extra argument if necessary to get hide stack
Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId);
if (instrs != NULL)
{
int stSize = instrs->size ();
for (int j = 0; j < stSize; j++)
{
Histable *instr = instrs->fetch (j);
if (instr != NULL)
fprintf (out_file, " %s\n", instr->get_name ());
}
delete instrs;
}
}
}
void
er_print_ioactivity::printStatistics (Hist_data *hist_data)
{
Hist_data::HistItem *hi;
FileData *fDataTotal;
hi = hist_data->fetch (0);
fDataTotal = (FileData*) hi->obj;
if (fDataTotal->getWriteCnt () > 0)
{
fprintf (out_file,
GTXT ("\nWrite Statistics\n"));
fprintf (out_file,
GTXT ("I/O Size Range Write Calls \n"));
fprintf (out_file,
"-------------------------------------------------------\n");
if (fDataTotal->getW0KB1KBCnt () > 0)
fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
fDataTotal->getW0KB1KBCnt ());
if (fDataTotal->getW1KB8KBCnt () > 0)
fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
fDataTotal->getW1KB8KBCnt ());
if (fDataTotal->getW8KB32KBCnt () > 0)
fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
fDataTotal->getW8KB32KBCnt ());
if (fDataTotal->getW32KB128KBCnt () > 0)
fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
fDataTotal->getW32KB128KBCnt ());
if (fDataTotal->getW128KB256KBCnt () > 0)
fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
fDataTotal->getW128KB256KBCnt ());
if (fDataTotal->getW256KB512KBCnt () > 0)
fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
fDataTotal->getW256KB512KBCnt ());
if (fDataTotal->getW512KB1000KBCnt () > 0)
fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
fDataTotal->getW512KB1000KBCnt ());
if (fDataTotal->getW1000KB10MBCnt () > 0)
fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
fDataTotal->getW1000KB10MBCnt ());
if (fDataTotal->getW10MB100MBCnt () > 0)
fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
fDataTotal->getW10MB100MBCnt ());
if (fDataTotal->getW100MB1GBCnt () > 0)
fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
fDataTotal->getW100MB1GBCnt ());
if (fDataTotal->getW1GB10GBCnt () > 0)
fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
fDataTotal->getW1GB10GBCnt ());
if (fDataTotal->getW10GB100GBCnt () > 0)
fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
fDataTotal->getW10GB100GBCnt ());
if (fDataTotal->getW100GB1TBCnt () > 0)
fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
fDataTotal->getW100GB1TBCnt ());
if (fDataTotal->getW1TB10TBCnt () > 0)
fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
fDataTotal->getW1TB10TBCnt ());
fprintf (out_file,
GTXT ("\nLongest write %.6f (secs.)\n"),
(double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC));
fprintf (out_file, GTXT ("Smallest write bytes %lld\n"),
(long long) fDataTotal->getWSmallestBytes ());
fprintf (out_file, GTXT ("Largest write bytes %lld\n"),
(long long) fDataTotal->getWLargestBytes ());
fprintf (out_file,
GTXT ("Total time %.6f (secs.)\n"),
(double) (fDataTotal->getWriteTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Total calls %d\n"),
fDataTotal->getWriteCnt ());
fprintf (out_file, GTXT ("Total bytes %lld\n"),
(long long) fDataTotal->getWriteBytes ());
}
if (fDataTotal->getReadCnt () > 0)
{
fprintf (out_file,
GTXT ("\nRead Statistics\n"));
fprintf (out_file,
GTXT ("I/O Size Range Read Calls \n"));
fprintf (out_file,
"------------------------------------------------------\n");
if (fDataTotal->getR0KB1KBCnt () > 0)
fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
fDataTotal->getR0KB1KBCnt ());
if (fDataTotal->getR1KB8KBCnt () > 0)
fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
fDataTotal->getR1KB8KBCnt ());
if (fDataTotal->getR8KB32KBCnt () > 0)
fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
fDataTotal->getR8KB32KBCnt ());
if (fDataTotal->getR32KB128KBCnt () > 0)
fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
fDataTotal->getR32KB128KBCnt ());
if (fDataTotal->getR128KB256KBCnt () > 0)
fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
fDataTotal->getR128KB256KBCnt ());
if (fDataTotal->getR256KB512KBCnt () > 0)
fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
fDataTotal->getR256KB512KBCnt ());
if (fDataTotal->getR512KB1000KBCnt () > 0)
fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
fDataTotal->getR512KB1000KBCnt ());
if (fDataTotal->getR1000KB10MBCnt () > 0)
fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
fDataTotal->getR1000KB10MBCnt ());
if (fDataTotal->getR10MB100MBCnt () > 0)
fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
fDataTotal->getR10MB100MBCnt ());
if (fDataTotal->getR100MB1GBCnt () > 0)
fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
fDataTotal->getR100MB1GBCnt ());
if (fDataTotal->getR1GB10GBCnt () > 0)
fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
fDataTotal->getR1GB10GBCnt ());
if (fDataTotal->getR10GB100GBCnt () > 0)
fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
fDataTotal->getR10GB100GBCnt ());
if (fDataTotal->getR100GB1TBCnt () > 0)
fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
fDataTotal->getR100GB1TBCnt ());
if (fDataTotal->getR1TB10TBCnt () > 0)
fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
fDataTotal->getR1TB10TBCnt ());
fprintf (out_file,
GTXT ("\nLongest time %.6f (secs.)\n"),
(double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC));
fprintf (out_file, GTXT ("Smallest read bytes %lld\n"),
(long long) fDataTotal->getRSmallestBytes ());
fprintf (out_file, GTXT ("Largest read bytes %lld\n"),
(long long) fDataTotal->getRLargestBytes ());
fprintf (out_file,
GTXT ("Total time %.6f (secs.)\n"),
(double) (fDataTotal->getReadTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Total calls %d\n"),
fDataTotal->getReadCnt ());
fprintf (out_file, GTXT ("Total bytes %lld\n"),
(long long) fDataTotal->getReadBytes ());
}
if (fDataTotal->getOtherCnt () > 0)
{
fprintf (out_file, GTXT ("\nOther I/O Statistics\n"));
fprintf (out_file,
"-----------------------------------------------------\n");
fprintf (out_file,
GTXT ("Total time %.6f (secs.)\n"),
(double) (fDataTotal->getOtherTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Total calls %d \n"),
fDataTotal->getOtherCnt ());
}
if (fDataTotal->getErrorCnt () > 0)
{
fprintf (out_file, GTXT ("\nI/O Error Statistics\n"));
fprintf (out_file,
"-----------------------------------------------------\n");
fprintf (out_file,
GTXT ("Total time %.6f (secs.)\n"),
(double) (fDataTotal->getErrorTime () / (double) NANOSEC));
fprintf (out_file, GTXT ("Total calls %d \n"),
fDataTotal->getErrorCnt ());
}
fprintf (out_file, NTXT ("\n"));
}
void
er_print_ioactivity::data_dump ()
{
// get the list of io events from DbeView
int numExps = dbeSession->nexps ();
if (!numExps)
{
fprintf (out_file,
GTXT ("There is no IO event information in the experiments\n"));
return;
}
MetricList *mlist = dbev->get_metric_list (MET_IO);
Hist_data *hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL);
if (type == Histable::IOCALLSTACK)
printCallStacks (hist_data);
else if (printStat)
printStatistics (hist_data);
else
{
Metric::HistMetric *hist_metric = hist_data->get_histmetrics ();
hist_data->print_label (out_file, hist_metric, 0);
hist_data->print_content (out_file, hist_metric, limit);
fprintf (out_file, nl);
}
}
er_print_experiment::er_print_experiment (DbeView *_dbev, int bgn_idx,
int end_idx, bool show_load,
bool show_header, bool show_stat,
bool show_over, bool show_odetail)
{
dbev = _dbev;
exp_idx1 = bgn_idx;
exp_idx2 = end_idx;
load = show_load;
header = show_header;
stat = show_stat;
over = show_over;
odetail = show_odetail;
}
void
er_print_experiment::data_dump ()
{
int index, maxlen;
maxlen = 0;
if (stat)
{
max_len1 = 50;
if (exp_idx2 > exp_idx1)
{
statistics_sum (maxlen);
fprintf (out_file, nl);
}
for (index = exp_idx1; index <= exp_idx2; index++)
statistics_dump (index, maxlen);
}
else if (over)
{
max_len1 = 50;
if (exp_idx2 > exp_idx1)
{
overview_sum (maxlen);
fprintf (out_file, nl);
}
for (index = exp_idx1; index <= exp_idx2; index++)
overview_dump (index, maxlen);
}
else if (header)
for (index = exp_idx1; index <= exp_idx2; index++)
{
if (index != exp_idx1)
fprintf (out_file,
"----------------------------------------------------------------\n");
header_dump (index);
}
}
void
er_print_experiment::overview_sum (int &maxlen)
{
int index;
Ovw_data *sum_data = new Ovw_data ();
for (index = exp_idx1; index <= exp_idx2; index++)
{
Ovw_data *ovw_data = dbev->get_ovw_data (index);
if (ovw_data == NULL)
continue;
sum_data->sum (ovw_data);
delete ovw_data;
}
fprintf (out_file, GTXT ("<Sum across selected experiments>"));
fprintf (out_file, nl);
overview_summary (sum_data, maxlen);
fprintf (out_file, nl);
delete sum_data;
}
void
er_print_experiment::overview_dump (int exp_idx, int &maxlen)
{
Ovw_data *ovw_data;
Ovw_data::Ovw_item ovw_item_labels;
Ovw_data::Ovw_item ovw_item;
int index;
int size;
ovw_data = dbev->get_ovw_data (exp_idx);
if (ovw_data == NULL)
return;
if (pr_params.header)
header_dump (exp_idx);
else if (odetail)
fprintf (out_file, GTXT ("Experiment: %s\n"),
dbeSession->get_exp (exp_idx)->get_expt_name ());
overview_summary (ovw_data, maxlen);
if (!odetail)
{
delete ovw_data;
return;
}
//Get the collection params for the sample selection and display them.
fprintf (out_file, "\n\n%*s\n\n", max_len1, GTXT ("Individual samples"));
size = ovw_data->size ();
ovw_item_labels = ovw_data->get_labels ();
for (index = 0; index < size; index++)
{
ovw_item = ovw_data->fetch (index);
fprintf (out_file, "%*s: %d\n\n", max_len1, GTXT ("Sample Number"),
ovw_item.number);
overview_item (&ovw_item, &ovw_item_labels);
fprintf (out_file, nl);
}
delete ovw_data;
}
void
er_print_experiment::overview_summary (Ovw_data *ovw_data, int &maxlen)
{
char buf[128];
int len;
Ovw_data::Ovw_item totals;
Ovw_data::Ovw_item ovw_item_labels;
totals = ovw_data->get_totals ();
len = snprintf (buf, sizeof (buf), "%.3lf", tstodouble (totals.total.t));
if (maxlen < len)
maxlen = len;
max_len2 = maxlen;
max_len3 = maxlen;
fprintf (out_file, "%*s\n\n", max_len1,
GTXT ("Aggregated statistics for selected samples"));
ovw_item_labels = ovw_data->get_labels ();
overview_item (&totals, &ovw_item_labels);
}
void
er_print_experiment::overview_item (Ovw_data::Ovw_item *ovw_item,
Ovw_data::Ovw_item *ovw_item_labels)
{
double start, end, total_value;
int index, size;
timestruc_t total_time = {0, 0};
start = tstodouble (ovw_item->start);
end = tstodouble (ovw_item->end);
fprintf (out_file, "%*s: %s\n", max_len1, GTXT ("Start Label"),
ovw_item->start_label);
fprintf (out_file, "%*s: %s\n", max_len1, GTXT ("End Label"),
ovw_item->end_label);
fprintf (out_file, "%*s: ", max_len1, GTXT ("Start Time (sec.)"));
if (start == -1.0)
fprintf (out_file, GTXT ("N/A"));
else
fprintf (out_file, "%*.3f", max_len2, start);
fprintf (out_file, nl);
fprintf (out_file, "%*s: ", max_len1, GTXT ("End Time (sec.)"));
if (end == -1.0)
fprintf (out_file, GTXT ("N/A"));
else
fprintf (out_file, "%*.3f", max_len2, end);
fprintf (out_file, nl);
fprintf (out_file, "%*s: ", max_len1, GTXT ("Duration (sec.)"));
fprintf (out_file, "%*.3f", max_len2, tstodouble (ovw_item->duration));
fprintf (out_file, NTXT ("\n"));
size = ovw_item->size;
for (index = 0; index < size; index++)
tsadd (&total_time, &ovw_item->values[index].t);
total_value = tstodouble (total_time);
fprintf (out_file, "%*s: %*.3f", max_len1, GTXT ("Total Thread Time (sec.)"),
max_len2, tstodouble (ovw_item->tlwp));
fprintf (out_file, NTXT ("\n"));
fprintf (out_file, "%*s: ", max_len1, GTXT ("Average number of Threads"));
if (tstodouble (ovw_item->duration) != 0)
fprintf (out_file, "%*.3f", max_len2, ovw_item->nlwp);
else
fprintf (out_file, GTXT ("N/A"));
fprintf (out_file, NTXT ("\n\n"));
fprintf (out_file, "%*s:\n", max_len1, GTXT ("Process Times (sec.)"));
for (index = 1; index < size; index++)
{
overview_value (&ovw_item_labels->values[index], ovw_item_labels->type,
total_value);
overview_value (&ovw_item->values[index], ovw_item->type,
total_value);
fprintf (out_file, NTXT ("\n"));
}
}
void
er_print_experiment::overview_value (Value *value, ValueTag value_tag,
double total_value)
{
double dvalue;
switch (value_tag)
{
case VT_LABEL:
fprintf (out_file, "%*s: ", max_len1, value->l);
break;
case VT_HRTIME:
dvalue = tstodouble (value->t);
if (dvalue == 0.0)
fprintf (out_file, "%*s ( 0. %%)", max_len3, "0. ");
else
fprintf (out_file, "%*.3f (%5.1f%%)", max_len3, dvalue,
100.0 * dvalue / total_value);
break;
case VT_INT:
fprintf (out_file, NTXT ("%d"), value->i);
break;
default:
fprintf (out_file, "%*.3f", max_len3, total_value);
}
}
void
er_print_experiment::statistics_sum (int &maxlen)
{
int index;
int size, len;
Stats_data *sum_data = new Stats_data ();
for (index = exp_idx1; index <= exp_idx2; index++)
{
Stats_data *stats_data = dbev->get_stats_data (index);
if (stats_data == NULL)
continue;
sum_data->sum (stats_data);
delete stats_data;
}
// get the maximum width of values
size = sum_data->size ();
for (index = 0; index < size; index++)
{
len = (int) sum_data->fetch (index).value.get_len ();
if (maxlen < len)
maxlen = len;
}
// print overview average
overview_sum (maxlen);
// print statistics data
max_len2 = maxlen;
statistics_item (sum_data);
delete sum_data;
}
void
er_print_experiment::statistics_dump (int exp_idx, int &maxlen)
{
Stats_data *stats_data;
int index;
int size, len;
stats_data = dbev->get_stats_data (exp_idx);
if (stats_data == NULL)
return;
if (pr_params.header)
{
header_dump (exp_idx);
fprintf (out_file, nl);
}
else
fprintf (out_file, GTXT ("Experiment: %s\n"),
dbeSession->get_exp (exp_idx)->get_expt_name ());
// get the maximum width of values
size = stats_data->size ();
for (index = 0; index < size; index++)
{
len = (int) stats_data->fetch (index).value.get_len ();
if (maxlen < len)
maxlen = len;
}
// print overview average
overview_dump (exp_idx, maxlen);
fprintf (out_file, nl);
// print statistics data
max_len2 = maxlen;
statistics_item (stats_data);
delete stats_data;
}
void
er_print_experiment::statistics_item (Stats_data *stats_data)
{
int size, index;
Stats_data::Stats_item stats_item;
char buf[256];
size = stats_data->size ();
for (index = 0; index < size; index++)
{
stats_item = stats_data->fetch (index);
fprintf (out_file, "%*s: %*s\n", max_len1, stats_item.label,
max_len2, stats_item.value.to_str (buf, sizeof (buf)));
}
fprintf (out_file, nl);
}
// Print annotated source or disassembly -- called by er_print only
void
print_anno_file (char *name, const char *sel, const char *srcFile,
bool isDisasm, FILE *dis_file, FILE *inp_file, FILE *out_file,
DbeView *dbev, bool xdefault)
{
Histable *obj;
Function *func;
Module *module;
Vector<int> *marks;
Hist_data *hist_data;
char *errstr;
int index;
SourceFile *fitem;
int threshold;
int compcom_bits;
int src_visible;
bool hex_visible;
bool srcmetrics_visible;
if ((name == NULL) || (strlen (name) == 0))
{
fprintf (stderr, GTXT ("Error: No function or file has been specified.\n"));
return;
}
// find the function from the name
if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel,
Histable::FUNCTION, xdefault))
return;
if (obj != NULL)
{
// source or disassembly for <Total>, <Unknown>, or @plt
if (obj->get_type () != Histable::FUNCTION)
{
fprintf (stderr,
GTXT ("Error: %s is not a real function; no source or disassembly available.\n"),
name);
return;
}
func = (Function *) obj;
if (func->flags & FUNC_FLAG_SIMULATED)
{
fprintf (stderr,
GTXT ("Error: %s is not a real function; no source or disassembly available.\n"),
name);
return;
}
else if (dbev != NULL && isDisasm)
dbev->set_func_scope (true);
// function found, set module
module = func->module;
int ix = module->loadobject->seg_idx;
if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
{
char *lo_name = module->loadobject->get_name ();
fprintf (stderr,
GTXT ("Error: No source or disassembly available for hidden object %s.\n"),
lo_name);
return;
}
if (srcFile)
{
Vector<SourceFile*> *sources = func->get_sources ();
bool found = false;
if (sources == NULL)
{
fitem = func->getDefSrc ();
found = (func->line_first > 0)
&& strcmp (basename (srcFile),
basename (fitem->get_name ())) == 0;
}
else
{
Vec_loop (SourceFile*, sources, index, fitem)
{
if (strcmp (basename (srcFile), basename (fitem->get_name ())) == 0)
{
found = true;
break;
}
}
}
if (!found)
{
fprintf (stderr, GTXT ("Error: Source file context %s does not contribute to function `%s'.\n"),
srcFile, name);
return;
}
}
}
else
{
// function not found
if (sel && strrchr (sel, ':'))
{
// 'sel' was "@seg_num:address" or "file_name:address"
fprintf (stderr,
GTXT ("Error: No function with given name `%s %s' found.\n"),
name, sel);
return;
}
// search for a file of that name
if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel,
Histable::MODULE, xdefault))
return;
if (obj == NULL)
{ // neither function nor file found
fprintf (stderr, GTXT ("Error: No function or file with given name `%s' found.\n"),
name);
return;
}
func = NULL;
module = (Module *) obj;
int ix = module->loadobject->seg_idx;
if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
{
char *lo_name = module->loadobject->get_name ();
fprintf (stderr, GTXT ("Error: No source or disassembly available for hidden object %s.\n"),
lo_name);
return;
}
if (name)
srcFile = name;
}
if (module == NULL || module->get_name () == NULL)
{
fprintf (stderr, GTXT ("Error: Object name not recorded in experiment\n"));
return;
}
module->read_stabs ();
if (!isDisasm && (module->file_name == NULL
|| (module->flags & MOD_FLAG_UNKNOWN) != 0
|| *module->file_name == 0))
{
fprintf (stderr, GTXT ("Error: Source location not recorded in experiment\n"));
return;
}
MetricList *metric_list = dbev->get_metric_list (MET_NORMAL);
int sort_ref_index = metric_list->get_sort_ref_index ();
if (isDisasm)
metric_list->set_sort_ref_index (-1);
// Ask DbeView to generate function-level data
// MSI: I think this is used only to get totals to compute percentages
hist_data = dbev->get_hist_data (metric_list, Histable::FUNCTION, 0,
Hist_data::ALL);
MetricList *nmlist = hist_data->get_metric_list ();
metric_list->set_sort_ref_index (sort_ref_index);
if (nmlist->get_items ()->size () != 0
&& hist_data->get_status () != Hist_data::SUCCESS)
{
errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
if (errstr)
{
fprintf (stderr, GTXT ("Error: %s\n"), errstr);
free (errstr);
}
return;
}
marks = new Vector<int>;
if (isDisasm)
{
threshold = dbev->get_thresh_dis ();
compcom_bits = dbev->get_dis_compcom ();
src_visible = dbev->get_src_visible ();
hex_visible = dbev->get_hex_visible ();
srcmetrics_visible = dbev->get_srcmetric_visible ();
}
else
{
threshold = dbev->get_thresh_src ();
compcom_bits = dbev->get_src_compcom ();
src_visible = SRC_NA;
hex_visible = false;
srcmetrics_visible = false;
}
dump_anno_file (out_file, isDisasm ? Histable::INSTR : Histable::LINE,
module, dbev, nmlist, hist_data->get_totals ()->value,
srcFile, func, marks, threshold, compcom_bits,
src_visible, hex_visible, srcmetrics_visible);
delete marks;
errstr = module->anno_str ();
if (errstr)
{
fprintf (stderr, GTXT ("Error: %s\n"), errstr);
free (errstr);
}
delete hist_data;
}
void
print_html_title (FILE *out_file, char *title)
{
// This will print a header row for the report
fprintf (out_file, "<html><title>%s</title>\n", title);
fprintf (out_file, "<center><h3>%s</h3></center>\n", title);
}
void
print_html_label (FILE *out_file, MetricList *metrics_list)
{
int mlist_sz;
// This will print a header row for the metrics
Vector<Metric*> *mlist = metrics_list->get_items ();
mlist_sz = mlist->size ();
fprintf (out_file, "<style type=\"text/css\">\n");
fprintf (out_file, "<!--\nBODY\n");
fprintf (out_file, ".th_C { text-align:center; background-color:lightgoldenrodyellow; }\n");
fprintf (out_file, ".th_CG { text-align:center; background-color:#ffff33; }\n");
fprintf (out_file, ".th_L { text-align:left; background-color:lightgoldenrodyellow; }\n");
fprintf (out_file, ".th_LG { text-align:left; background-color:#ffff33; }\n");
fprintf (out_file, ".td_R { text-align:right; }\n");
fprintf (out_file, ".td_RG { text-align:right; background-color:#ffff33; }\n");
fprintf (out_file, ".td_L { text-align:left; }\n");
fprintf (out_file, ".td_LG { text-align:left; background-color:#ffff33; }\n");
fprintf (out_file, "-->\n</style>");
fprintf (out_file, "<center><table border=1 cellspacing=2>\n<tr>");
for (int index = 0; index < mlist_sz; index++)
{
Metric *mitem = mlist->fetch (index);
int ncols = 0;
if (mitem->is_visible ())
ncols++;
if (mitem->is_tvisible ())
ncols++;
if (mitem->is_pvisible ())
ncols++;
if (ncols == 0)
continue;
char *name = strdup (mitem->get_name ());
char *name2 = split_metric_name (name);
const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
// start the column, with colspan setting, legend, and sort metric indicator
if (ncols == 1)
{
if (mitem->get_vtype () == VT_LABEL)
// left-adjust the name metric
fprintf (out_file,
"<th class=\"th_L%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
style, mitem->legend == NULL ? "&nbsp;" : mitem->legend,
(index == metrics_list->get_sort_ref_index ()) ? "&nabla;" : "&nbsp;",
name, name2 == NULL ? "&nbsp;" : name2);
else
// but center the others
fprintf (out_file,
"<th class=\"th_C%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
style, mitem->legend == NULL ? "&nbsp;" : mitem->legend,
(index == metrics_list->get_sort_ref_index ()) ?
"&nabla;" : "&nbsp;",
name, name2 == NULL ? NTXT ("&nbsp;") : name2);
}
else
// name metric can't span columns
fprintf (out_file,
"<th colspan=%d class=\"th_C%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
ncols, style,
mitem->legend == NULL ? "&nbsp;" : mitem->legend,
index == metrics_list->get_sort_ref_index () ?
"&nabla;" : "&nbsp;",
name, name2 == NULL ? "&nbsp;" : name2);
free (name);
}
// end this row, start the units row
fprintf (out_file, NTXT ("</tr>\n<tr>"));
// now do the units row
for (int index = 0; index < mlist_sz; index++)
{
Metric *mitem = mlist->fetch (index);
const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
if (mitem->is_tvisible ())
fprintf (out_file, "<th class=\"th_C%s\">&nbsp;(%s)</th>", style,
GTXT ("sec."));
if (mitem->is_visible ())
{
if (mitem->get_abbr_unit () == NULL)
fprintf (out_file, "<th class=\"th_C%s\">&nbsp;</th>", style);
else
fprintf (out_file, "<th class=\"th_C%s\">(%s)</th>", style,
mitem->get_abbr_unit () == NULL ? "&nbsp;"
: mitem->get_abbr_unit ());
}
if (mitem->is_pvisible ())
fprintf (out_file, "<th class=\"th_C%s\">&nbsp;(%%)</th>", style);
}
fprintf (out_file, NTXT ("</tr>\n"));
}
void
print_html_content (FILE *out_file, Hist_data *data, MetricList *metrics_list,
int limit, Histable::NameFormat nfmt)
{
Hist_data::HistItem *item;
// printing contents.
for (int i = 0; i < limit; i++)
{
item = data->fetch (i);
print_html_one (out_file, data, item, metrics_list, nfmt);
}
}
void
print_html_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
MetricList *metrics_list, Histable::NameFormat nfmt)
{
Metric *mitem;
int index;
int visible, tvisible, pvisible;
TValue *value;
double percent;
fprintf (out_file, NTXT ("<tr>"));
Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
{
visible = mitem->is_visible ();
tvisible = mitem->is_tvisible ();
pvisible = mitem->is_pvisible ();
const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
if (tvisible)
{
value = &(item->value[index]);
if (value->ll == 0LL)
fprintf (out_file,
"<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
style);
else
fprintf (out_file, "<td class=\"td_R%s\"><tt>%4.3lf</tt></td>",
style, 1.e-6 * value->ll / dbeSession->get_clock (-1));
}
if (visible)
{
if (mitem->get_vtype () == VT_LABEL)
{
value = &(item->value[index]);
char *r;
if (value->tag == VT_OFFSET)
r = ((DataObject*) (item->obj))->get_offset_name ();
else
r = item->obj->get_name (nfmt);
char *n = html_ize_name (r);
fprintf (out_file, NTXT ("<td class=\"td_L%s\">%s</td>"), style, n);
free (n);
}
else
{
value = &(item->value[index]);
switch (value->tag)
{
case VT_DOUBLE:
if (value->d == 0.0)
fprintf (out_file,
"<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
style);
else
fprintf (out_file,
"<td class=\"td_R%s\"><tt>%4.3lf</tt></td>", style,
value->d);
break;
case VT_INT:
fprintf (out_file, "<td class=\"td_R%s\"><tt>%d</tt></td>",
style, value->i);
break;
case VT_LLONG:
fprintf (out_file, "<td class=\"td_R%s\"><tt>%lld</td></tt>",
style, value->ll);
break;
case VT_ULLONG:
fprintf (out_file, "<td class=\"td_R%s\"><tt>%llu</td></tt>",
style, value->ull);
break;
case VT_ADDRESS:
fprintf (out_file,
"<td class=\"td_R%s\"><tt>%u:0x%08x</tt></td>", style,
ADDRESS_SEG (value->ll), ADDRESS_OFF (value->ll));
break;
case VT_FLOAT:
if (value->f == 0.0)
fprintf (out_file,
"<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
style);
else
fprintf (out_file,
"<td class=\"td_R%s\"><tt>%4.3f</tt></td>",
style, value->f);
break;
case VT_SHORT:
fprintf (out_file, "<td class=\"td_R%s\"><tt>%d</tt></td>",
style, value->s);
break;
// ignoring the following cases (why?)
case VT_HRTIME:
case VT_LABEL:
case VT_OFFSET:
break;
}
}
}
if (pvisible)
{
percent = data->get_percentage (item->value[index].to_double (), index);
if (percent == 0.0)
// adjust to change format from xx.yy%
fprintf (out_file, "<td class=\"td_R%s\">0.&nbsp;&nbsp;&nbsp;</td>",
style);
else
// adjust format below to change format from xx.yy%
fprintf (out_file, "<td class=\"td_R%s\">%3.2f</td>", style,
(100.0 * percent));
}
}
fprintf (out_file, NTXT ("</tr>\n"));
}
void
print_html_trailer (FILE *out_file)
{
fprintf (out_file, NTXT ("</table></center></html>\n"));
}
static char *
del_delim (char *s)
{
size_t len = strlen (s);
if (len > 0)
s[len - 1] = 0;
return s;
}
void
print_delim_label (FILE *out_file, MetricList *metrics_list, char delim)
{
char line0[2 * MAX_LEN], line1[2 * MAX_LEN];
char line2[2 * MAX_LEN], line3[2 * MAX_LEN];
size_t len;
// This will print four header rows for the metrics
line0[0] = 0;
line1[0] = 0;
line2[0] = 0;
line3[0] = 0;
Vector<Metric*> *mlist = metrics_list->get_items ();
for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++)
{
Metric *mitem = mlist->fetch (index);
if (!(mitem->is_visible () || mitem->is_tvisible ()
|| mitem->is_pvisible ()))
continue;
char *name = strdup (mitem->get_name ());
char *name2 = split_metric_name (name);
if (mitem->is_tvisible ())
{
len = strlen (line0);
snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"),
mitem->legend == NULL ? NTXT ("") : mitem->legend, delim);
len = strlen (line1);
snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"),
name, delim);
len = strlen (line2);
snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"),
name2 == NULL ? NTXT ("") : name2, delim);
len = strlen (line3);
if (index == metrics_list->get_sort_ref_index ())
snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V %s\"%c"),
GTXT ("(sec.)"), delim);
else
snprintf (line3 + len, sizeof (line3) - len, NTXT ("\" %s\"%c"),
GTXT ("(sec.)"), delim);
}
if (mitem->is_visible ())
{
len = strlen (line0);
snprintf (line0 + len, sizeof (line0) - len, "\"%s\"%c",
mitem->legend == NULL ? "" : mitem->legend, delim);
len = strlen (line1);
snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c",
name, delim);
len = strlen (line2);
snprintf (line2 + len, sizeof (line2) - len, "\"%s\"%c",
name2 == NULL ? NTXT ("") : name2, delim);
len = strlen (line3);
char *au = mitem->get_abbr_unit ();
if (index == metrics_list->get_sort_ref_index ())
{
if (au == NULL)
snprintf (line3 + len, sizeof (line3) - len, "\"V \"%c", delim);
else
snprintf (line3 + len, sizeof (line3) - len, "\"V (%s)\"%c",
au, delim);
}
else
{
if (au == NULL)
snprintf (line3 + len, sizeof (line3) - len, "\" \"%c",
delim);
else
snprintf (line3 + len, sizeof (line3) - len, "\" (%s)\"%c",
au, delim);
}
}
if (mitem->is_pvisible ())
{
len = strlen (line0);
snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"),
mitem->legend == NULL ? NTXT ("") : mitem->legend, delim);
len = strlen (line1);
snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"),
name, delim);
len = strlen (line2);
snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"),
name2 == NULL ? NTXT ("") : name2, delim);
len = strlen (line3);
if (index == metrics_list->get_sort_ref_index ())
snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V %s\"%c"),
NTXT ("%%"), delim);
else
snprintf (line3 + len, sizeof (line3) - len, NTXT ("\" %s\"%c"),
NTXT ("%%"), delim);
}
free (name);
}
// now remove the trailing delimiter, and print the four lines
fprintf (out_file, NTXT ("%s\n"), del_delim (line0));
fprintf (out_file, NTXT ("%s\n"), del_delim (line1));
fprintf (out_file, NTXT ("%s\n"), del_delim (line2));
fprintf (out_file, NTXT ("%s\n"), del_delim (line3));
}
void
print_delim_content (FILE *out_file, Hist_data *data, MetricList *metrics_list,
int limit, Histable::NameFormat nfmt, char delim)
{
Hist_data::HistItem *item;
int i;
// printing contents.
for (i = 0; i < limit; i++)
{
item = data->fetch (i);
print_delim_one (out_file, data, item, metrics_list, nfmt, delim);
}
}
void
print_delim_trailer (FILE */*out_file*/, char /*delim*/) { }
// EUGENE does this function work properly when "-compare ratio" is used?
// how about when the ratio is nonzero-divided-by-zero?
// EUGENE actually, review this entire file
void
print_delim_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
MetricList *metrics_list, Histable::NameFormat nfmt,
char delim)
{
Metric *mitem;
int index;
int visible, tvisible, pvisible;
TValue *value;
double percent;
size_t len;
char line1[2 * MAX_LEN];
*line1 = 0;
Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
{
visible = mitem->is_visible ();
tvisible = mitem->is_tvisible ();
pvisible = mitem->is_pvisible ();
if (tvisible)
{
value = &(item->value[index]);
len = strlen (line1);
if (value->ll == 0LL)
snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim);
else
snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c",
1.e-6 * value->ll / dbeSession->get_clock (-1),
delim);
}
if (visible)
{
len = strlen (line1);
if (mitem->get_vtype () == VT_LABEL)
{
value = &(item->value[index]);
char *r;
if (value->tag == VT_OFFSET)
r = ((DataObject*) (item->obj))->get_offset_name ();
else
r = item->obj->get_name (nfmt);
char *p = csv_ize_name (r, delim);
snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c", p, delim);
free (p);
}
else
{
value = &(item->value[index]);
switch (value->tag)
{
case VT_DOUBLE:
if (value->d == 0.0)
snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c",
delim);
else
snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c",
value->d, delim);
break;
case VT_INT:
snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c",
value->i, delim);
break;
case VT_LLONG:
snprintf (line1 + len, sizeof (line1) - len, "\"%lld\"%c",
value->ll, delim);
break;
case VT_ULLONG:
snprintf (line1 + len, sizeof (line1) - len, "\"%llu\"%c",
value->ull, delim);
break;
case VT_ADDRESS:
snprintf (line1 + len, sizeof (line1) - len, "\"%u:0x%08x\"%c",
ADDRESS_SEG (value->ll),
ADDRESS_OFF (value->ll), delim);
break;
case VT_FLOAT:
if (value->f == 0.0)
snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c",
delim);
else
snprintf (line1 + len, sizeof (line1) - len, "\"%4.3f\"%c",
value->f, delim);
break;
case VT_SHORT:
snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c",
value->s, delim);
break;
// ignoring the following cases (why?)
case VT_HRTIME:
case VT_LABEL:
case VT_OFFSET:
break;
}
}
}
if (pvisible)
{
len = strlen (line1);
percent = data->get_percentage (item->value[index].to_double (), index);
if (percent == 0.0)
// adjust to change format from xx.yy%
snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim);
else
// adjust format below to change format from xx.yy%
snprintf (line1 + len, sizeof (line1) - len, "\"%3.2f\"%c",
(100.0 * percent), delim);
}
}
fprintf (out_file, NTXT ("%s\n"), del_delim (line1));
}
char *
html_ize_name (char *name)
{
StringBuilder sb;
for (size_t i = 0; i < strlen (name); i++)
{
switch (name[i])
{
case ' ': sb.append (NTXT ("&nbsp;"));
break;
case '"': sb.append (NTXT ("&quot;"));
break;
case '&': sb.append (NTXT ("&amp;"));
break;
case '<': sb.append (NTXT ("&lt;"));
break;
case '>': sb.append (NTXT ("&gt;"));
break;
default: sb.append (name[i]);
break;
}
}
char *ret = sb.toString ();
return ret;
}
char *
csv_ize_name (char *name, char /*delim*/)
{
StringBuilder sb;
for (size_t i = 0; i < strlen (name); i++)
sb.append (name[i]);
char *ret = sb.toString ();
return ret;
}
// Split a metric name into two parts, replacing a blank with
// a zero and returning pointer to the rest of the string, or
// leaving the string unchanged, and returning NULL;
char *
split_metric_name (char *name)
{
// figure out the most even split of the name
size_t len = strlen (name);
char *middle = &name[len / 2];
// find the first blank
char *first = strchr (name, (int) ' ');
if (first == NULL) // no blanks
return NULL;
char *last = first;
char *p = first;
for (;;)
{
p = strchr (p + 1, (int) ' ');
if (p == NULL)
break;
if (p < middle)
{
first = p;
last = p;
}
else
{
last = p;
break;
}
}
// pick the better of the two
char *ret;
int f = (int) (middle - first);
int l = (int) (last - middle);
if ((first == last) || (f <= l))
{
*first = '\0';
ret = first + 1;
}
else
{
*last = '\0';
ret = last + 1;
}
return ret;
}