mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-07 13:33:06 +00:00
2919 lines
85 KiB
C++
2919 lines
85 KiB
C++
/* 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 <br>%s %s <br>%s </th>",
|
|
style, mitem->legend == NULL ? " " : mitem->legend,
|
|
(index == metrics_list->get_sort_ref_index ()) ? "∇" : " ",
|
|
name, name2 == NULL ? " " : name2);
|
|
else
|
|
// but center the others
|
|
fprintf (out_file,
|
|
"<th class=\"th_C%s\">%s <br>%s %s <br>%s </th>",
|
|
style, mitem->legend == NULL ? " " : mitem->legend,
|
|
(index == metrics_list->get_sort_ref_index ()) ?
|
|
"∇" : " ",
|
|
name, name2 == NULL ? NTXT (" ") : name2);
|
|
}
|
|
else
|
|
// name metric can't span columns
|
|
fprintf (out_file,
|
|
"<th colspan=%d class=\"th_C%s\">%s <br>%s %s <br>%s </th>",
|
|
ncols, style,
|
|
mitem->legend == NULL ? " " : mitem->legend,
|
|
index == metrics_list->get_sort_ref_index () ?
|
|
"∇" : " ",
|
|
name, name2 == NULL ? " " : 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\"> (%s)</th>", style,
|
|
GTXT ("sec."));
|
|
if (mitem->is_visible ())
|
|
{
|
|
if (mitem->get_abbr_unit () == NULL)
|
|
fprintf (out_file, "<th class=\"th_C%s\"> </th>", style);
|
|
else
|
|
fprintf (out_file, "<th class=\"th_C%s\">(%s)</th>", style,
|
|
mitem->get_abbr_unit () == NULL ? " "
|
|
: mitem->get_abbr_unit ());
|
|
}
|
|
if (mitem->is_pvisible ())
|
|
fprintf (out_file, "<th class=\"th_C%s\"> (%%)</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. </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. </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. </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. </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 (" "));
|
|
break;
|
|
case '"': sb.append (NTXT ("""));
|
|
break;
|
|
case '&': sb.append (NTXT ("&"));
|
|
break;
|
|
case '<': sb.append (NTXT ("<"));
|
|
break;
|
|
case '>': sb.append (NTXT (">"));
|
|
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;
|
|
}
|