| /* 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 <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 (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<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]); |
| |