/* Copyright (C) 2021-2024 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 #include #include #include #include #include #include #include #include #include #include #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 (xstrdup (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 *) xmalloc (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 *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 *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 *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 *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 *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 *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 *marks = new Vector; 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 *_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 *_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 if (i == 0) continue; // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack Vector *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 *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 if (i == 0) continue; // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack Vector *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 ("")); 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 *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 , , 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 *sources = func->get_sources (); bool found = false; if (sources == NULL) { fitem = func->getDefSrc (); found = (func->line_first > 0) && strcmp (get_basename (srcFile), get_basename (fitem->get_name ())) == 0; } else { Vec_loop (SourceFile*, sources, index, fitem) { if (strcmp (get_basename (srcFile), get_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; 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, "%s\n", title); fprintf (out_file, "

%s

\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 *mlist = metrics_list->get_items (); mlist_sz = mlist->size (); fprintf (out_file, ""); fprintf (out_file, "
\n"); 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 = xstrdup (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, "", 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, "", 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, "", 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 ("\n")); // 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, "", style, GTXT ("sec.")); if (mitem->is_visible ()) { if (mitem->get_abbr_unit () == NULL) fprintf (out_file, "", style); else fprintf (out_file, "", style, mitem->get_abbr_unit () == NULL ? " " : mitem->get_abbr_unit ()); } if (mitem->is_pvisible ()) fprintf (out_file, "", style); } fprintf (out_file, NTXT ("\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 ("")); 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, "", style); else fprintf (out_file, "", 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 (""), style, n); free (n); } else { value = &(item->value[index]); switch (value->tag) { case VT_DOUBLE: if (value->d == 0.0) fprintf (out_file, "", style); else fprintf (out_file, "", style, value->d); break; case VT_INT: fprintf (out_file, "", style, value->i); break; case VT_LLONG: fprintf (out_file, "", style, value->ll); break; case VT_ULLONG: fprintf (out_file, "", style, value->ull); break; case VT_ADDRESS: fprintf (out_file, "", style, ADDRESS_SEG (value->ll), ADDRESS_OFF (value->ll)); break; case VT_FLOAT: if (value->f == 0.0) fprintf (out_file, "", style); else fprintf (out_file, "", style, value->f); break; case VT_SHORT: fprintf (out_file, "", 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, "", style); else // adjust format below to change format from xx.yy% fprintf (out_file, "", style, (100.0 * percent)); } } fprintf (out_file, NTXT ("\n")); } void print_html_trailer (FILE *out_file) { fprintf (out_file, NTXT ("
%s 
%s %s 
%s 
%s 
%s %s 
%s 
%s 
%s %s 
%s 
 (%s) (%s) (%%)
0.   %4.3lf%s0.   %4.3lf%d%lld%llu%u:0x%08x0.   %4.3f%d0.   %3.2f
\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 *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 = xstrdup (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; }