/* Copyright (C) 2021-2026 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 <assert.h> #include "util.h"#include "DefaultMap.h"#include "DbeSession.h"#include "Experiment.h"#include "DataObject.h"#include "Function.h"#include "Hist_data.h"#include "Histable.h"#include "MemObject.h"#include "IndexObject.h"#include "MetricList.h"#include "Metric.h"#include "Module.h"#include "LoadObject.h"#include "Settings.h"#include "StringBuilder.h"#include "ExpGroup.h"#include "PathTree.h"#include "DbeView.h"#include "FileData.h" Hist_data::HistItem::HistItem (long n){ obj = NULL; type = 0; size = n; value = new TValue[n]; memset (value, 0, sizeof (TValue) * n);} Hist_data::HistItem::~HistItem (){ for (long i = 0; i < size; i++) if (value[i].tag == VT_LABEL) free (value[i].l); delete[] value;} longHist_data::size (){ // If the data values have not been computed, do so // Return the total number of items return hist_items->size ();} Hist_data::HistItem *Hist_data::fetch (long index){ return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL;} intHist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype, long ind, Hist_data *hdata){ // Sort the data depending upon order and type int result = 0; Histable::Type type = hi_1->obj->get_type (); if (stype == ALPHA) { if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ && type != Histable::IOACTVFD && type != Histable::IOACTFILE && type != Histable::IOCALLSTACK) { char *nm1 = hi_1->obj->get_name (); char *nm2 = hi_2->obj->get_name (); if (nm1 != NULL && nm2 != NULL) result = strcoll (nm1, nm2); } else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD || type == Histable::IOACTFILE) { uint64_t idx1, idx2; idx1 = ((FileData *) (hi_1->obj))->get_index (); idx2 = ((FileData *) (hi_2->obj))->get_index (); if (idx1 < idx2) result = -1; else if (idx1 > idx2) result = 1; else result = 0; } else { // for memory and index objects, "alphabetic" is really by index // <Total> has index -2, and always comes first // <Unknown> has index -1, and always comes second. uint64_t i1, i2; bool needsStringCompare = false; if (type == Histable::MEMOBJ) { i1 = ((MemObj *) (hi_1->obj))->get_index (); i2 = ((MemObj *) (hi_2->obj))->get_index (); } else if (type == Histable::INDEXOBJ) { i1 = ((IndexObject *) (hi_1->obj))->get_index (); i2 = ((IndexObject *) (hi_2->obj))->get_index (); needsStringCompare = ((IndexObject *) (hi_1->obj))->requires_string_sort (); } else abort (); if (i1 == (uint64_t) - 2) result = -1; else if (i2 == (uint64_t) - 2) result = 1; else if (i1 == (uint64_t) - 1) result = -1; else if (i2 == (uint64_t) - 1) result = 1; else if (needsStringCompare) { char *nm1 = hi_1->obj->get_name (); char *nm2 = hi_2->obj->get_name (); if (nm1 != NULL && nm2 != NULL) { char nm1_lead = nm1[0]; char nm2_lead = nm2[0]; // put "(unknown)" and friends at end of list if (nm1_lead == '(' && nm1_lead != nm2_lead) result = 1; else if (nm2_lead == '(' && nm1_lead != nm2_lead) result = -1; else result = strcoll (nm1, nm2); } } if (result == 0) { // matches, resolve by index if (i1 < i2) result = -1; else if (i1 > i2) result = 1; } } } else if (stype == AUX) { switch (type) { case Histable::INSTR: { DbeInstr *instr1 = (DbeInstr*) hi_1->obj; DbeInstr *instr2 = (DbeInstr*) hi_2->obj; result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0; break; } case Histable::LINE: { DbeLine *dbl1 = (DbeLine*) hi_1->obj; DbeLine *dbl2 = (DbeLine*) hi_2->obj; result = dbl1->line_cmp (dbl2); } break; default: assert (0); } } else if (stype == VALUE) { Metric *m = hdata->get_metric_list ()->get (ind); if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0) { TValue v1, v2; int first_ind = hdata->hist_metrics[ind].indFirstExp; if ((m->get_visbits () & VAL_DELTA) != 0) { v1.make_delta (hi_1->value + ind, hi_1->value + first_ind); v2.make_delta (hi_2->value + ind, hi_2->value + first_ind); } else { v1.make_ratio (hi_1->value + ind, hi_1->value + first_ind); v2.make_ratio (hi_2->value + ind, hi_2->value + first_ind); } result = v1.compare (&v2); } else result = hi_1->value[ind].compare (hi_2->value + ind); } return result;} intHist_data::sort_compare_all (const void *a, const void *b, const void *arg){ HistItem *hi_1 = *((HistItem **) a); HistItem *hi_2 = *((HistItem **) b); Hist_data *hdata = (Hist_data*) arg; int result = sort_compare (hi_1, hi_2, hdata->sort_type, hdata->sort_ind, hdata); if (hdata->sort_order == DESCEND) result = -result; // Use the name as the 2d sort key (always ASCEND) // except for MemoryObjects and IndexObjects, where the index is used // For the Alphabetic sort if (result == 0) { result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL); if (result == 0) { for (long i = 0, sz = hdata->metrics->size (); i < sz; i++) { Metric *m = hdata->metrics->get (i); if (m->get_type () != Metric::ONAME) { result = sort_compare (hi_1, hi_2, VALUE, i, hdata); if (result != 0) { if (hdata->sort_order == DESCEND) result = -result; break; } } } } } // Use the address as the 3d sort key // ( FUNCTION only, always ASCEND ) if (result == 0 && hi_1->obj->get_type () == Histable::FUNCTION) { Function *f1 = (Function*) hi_1->obj; Function *f2 = (Function*) hi_2->obj; if (f1->get_addr () < f2->get_addr ()) result = -1; else if (f1->get_addr () > f2->get_addr ()) result = 1; } // Use the Histable id (ID of function, line, etc.) as the 4th sort key // Note that IDs are not guaranteed to be stable, if (result == 0) { if (hi_1->obj->id < hi_2->obj->id) result = -1; else if (hi_1->obj->id > hi_2->obj->id) result = 1; } if (result == 0) return result; // shouldn't happen in most cases; line allows for breakpoint if (hdata->rev_sort) result = -result; return result;} intHist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg){ assert ((a != (const void *) NULL)); assert ((b != (const void *) NULL)); HistItem *hi_1 = *((HistItem **) a); HistItem *hi_2 = *((HistItem **) b); DataObject * dobj1 = (DataObject *) (hi_1->obj); DataObject * dobj2 = (DataObject *) (hi_2->obj); DataObject * parent1 = dobj1->parent; DataObject * parent2 = dobj2->parent; Hist_data *hdata = (Hist_data*) arg; // are the two items members of the same object? if (parent1 == parent2) { // yes if (parent1) { // and they have real parents... if (parent1->get_typename ()) { // element // use dobj1/dobj2 offset for sorting uint64_t off1 = dobj1->get_offset (); uint64_t off2 = dobj2->get_offset (); if (off1 < off2) return -1; if (off1 > off2) return 1; return 0; } } } else { // parents differ if (parent1) { if (parent1 == dobj2) // sorting an object and its parent: parent always first return 1; dobj1 = parent1; } if (parent2) { if (parent2 == dobj1) return -1; dobj2 = parent2; } } // Either two unknowns, or two scalars, or two parents hi_1 = hdata->hi_map->get (dobj1); hi_2 = hdata->hi_map->get (dobj2); return sort_compare_all ((const void*) &hi_1, (const void*) &hi_2, hdata);} Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type, Hist_data::Mode _mode, bool _viewowned){ hist_items = new Vector<HistItem*>; metrics = _metrics; nmetrics = metrics->get_items ()->size (); type = _type; mode = _mode; gprof_item = new_hist_item (NULL); viewowned = _viewowned; sort_ind = -1; rev_sort = false; Histable *tobj = new Other; tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); minimum = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("")); maximum = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx")); maximum_inc = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("<Total>")); total = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX")); threshold = new_hist_item (tobj); hi_map = new HashMap<Histable*, HistItem*>; callsite_mark = new DefaultMap<Histable*, int>; hist_metrics = new Metric::HistMetric[metrics->size ()]; for (long i = 0, sz = metrics->size (); i < sz; i++) { Metric::HistMetric *h = hist_metrics + i; h->init (); Metric *m = metrics->get (i); if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO))) h->indFirstExp = metrics->get_listorder (m->get_cmd (), m->get_subtype (), "EXPGRID==1"); if (m->is_tvisible () && m->get_type () == BaseMetric::HWCNTR && m->get_dependent_bm ()) h->indTimeVal = metrics->get_listorder (m->get_dependent_bm ()->get_cmd (), m->get_subtype (), m->get_expr_spec ()); } status = NO_DATA;} Hist_data::~Hist_data (){ delete[] hist_metrics; if (hist_items) { hist_items->destroy (); delete hist_items; hist_items = NULL; } if (gprof_item) { delete gprof_item; gprof_item = NULL; } if (maximum) { delete maximum->obj; delete maximum; maximum = NULL; } if (maximum_inc) { delete maximum_inc->obj; delete maximum_inc; maximum_inc = NULL; } if (minimum) { delete minimum->obj; delete minimum; minimum = NULL; } if (total) { delete total->obj; delete total; total = NULL; } if (threshold) { delete threshold->obj; delete threshold; threshold = NULL; } delete metrics; delete hi_map; delete callsite_mark;} voidHist_data::dump (char *msg, FILE *f){ fprintf (f, " Hist_data dump: %s\n", msg); fprintf (f, " %d=%d metrics\n", (int) nmetrics, (int) metrics->size ()); for (int i = 0; i < nmetrics; i++) { Metric *m = metrics->get_items ()->fetch (i); char *s = m->get_expr_spec (); fprintf (f, " %4d %15s %4d %15s\n", i, m->get_mcmd (0), m->get_id (), s ? s : "(NULL)"); } fprintf (f, NTXT (" HistItem listing\n")); int n = hist_items->size (); for (int j = -1; j < n; j++) { HistItem *hi; if (j < 0) { hi = total; fprintf (f, NTXT (" total")); } else { hi = hist_items->fetch (j); fprintf (f, NTXT ("%30s"), hi->obj->get_name ()); } for (int i = 0; i < nmetrics; i++) { char *stmp = hi->value[i].l; switch (hi->value[i].tag) { case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s); break; case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i); break; case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll); break; case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f); break; case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d); break; case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull); break; case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)"); break; case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll); break; case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p); break; case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull); break; default: fprintf (f, NTXT (" ")); break; } } fprintf (f, NTXT ("\n")); }} voidHist_data::sort (long ind, bool reverse){ if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort) // there's no change to the sorting return; Lines 1–500 of 1889. Load more
/* Copyright (C) 2021-2026 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 <assert.h> #include "util.h" #include "DefaultMap.h" #include "DbeSession.h" #include "Experiment.h" #include "DataObject.h" #include "Function.h" #include "Hist_data.h" #include "Histable.h" #include "MemObject.h" #include "IndexObject.h" #include "MetricList.h" #include "Metric.h" #include "Module.h" #include "LoadObject.h" #include "Settings.h" #include "StringBuilder.h" #include "ExpGroup.h" #include "PathTree.h" #include "DbeView.h" #include "FileData.h" Hist_data::HistItem::HistItem (long n) { obj = NULL; type = 0; size = n; value = new TValue[n]; memset (value, 0, sizeof (TValue) * n); } Hist_data::HistItem::~HistItem () { for (long i = 0; i < size; i++) if (value[i].tag == VT_LABEL) free (value[i].l); delete[] value; } long Hist_data::size () { // If the data values have not been computed, do so // Return the total number of items return hist_items->size (); } Hist_data::HistItem * Hist_data::fetch (long index) { return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL; } int Hist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype, long ind, Hist_data *hdata) { // Sort the data depending upon order and type int result = 0; Histable::Type type = hi_1->obj->get_type (); if (stype == ALPHA) { if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ && type != Histable::IOACTVFD && type != Histable::IOACTFILE && type != Histable::IOCALLSTACK) { char *nm1 = hi_1->obj->get_name (); char *nm2 = hi_2->obj->get_name (); if (nm1 != NULL && nm2 != NULL) result = strcoll (nm1, nm2); } else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD || type == Histable::IOACTFILE) { uint64_t idx1, idx2; idx1 = ((FileData *) (hi_1->obj))->get_index (); idx2 = ((FileData *) (hi_2->obj))->get_index (); if (idx1 < idx2) result = -1; else if (idx1 > idx2) result = 1; else result = 0; } else { // for memory and index objects, "alphabetic" is really by index // <Total> has index -2, and always comes first // <Unknown> has index -1, and always comes second. uint64_t i1, i2; bool needsStringCompare = false; if (type == Histable::MEMOBJ) { i1 = ((MemObj *) (hi_1->obj))->get_index (); i2 = ((MemObj *) (hi_2->obj))->get_index (); } else if (type == Histable::INDEXOBJ) { i1 = ((IndexObject *) (hi_1->obj))->get_index (); i2 = ((IndexObject *) (hi_2->obj))->get_index (); needsStringCompare = ((IndexObject *) (hi_1->obj))->requires_string_sort (); } else abort (); if (i1 == (uint64_t) - 2) result = -1; else if (i2 == (uint64_t) - 2) result = 1; else if (i1 == (uint64_t) - 1) result = -1; else if (i2 == (uint64_t) - 1) result = 1; else if (needsStringCompare) { char *nm1 = hi_1->obj->get_name (); char *nm2 = hi_2->obj->get_name (); if (nm1 != NULL && nm2 != NULL) { char nm1_lead = nm1[0]; char nm2_lead = nm2[0]; // put "(unknown)" and friends at end of list if (nm1_lead == '(' && nm1_lead != nm2_lead) result = 1; else if (nm2_lead == '(' && nm1_lead != nm2_lead) result = -1; else result = strcoll (nm1, nm2); } } if (result == 0) { // matches, resolve by index if (i1 < i2) result = -1; else if (i1 > i2) result = 1; } } } else if (stype == AUX) { switch (type) { case Histable::INSTR: { DbeInstr *instr1 = (DbeInstr*) hi_1->obj; DbeInstr *instr2 = (DbeInstr*) hi_2->obj; result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0; break; } case Histable::LINE: { DbeLine *dbl1 = (DbeLine*) hi_1->obj; DbeLine *dbl2 = (DbeLine*) hi_2->obj; result = dbl1->line_cmp (dbl2); } break; default: assert (0); } } else if (stype == VALUE) { Metric *m = hdata->get_metric_list ()->get (ind); if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0) { TValue v1, v2; int first_ind = hdata->hist_metrics[ind].indFirstExp; if ((m->get_visbits () & VAL_DELTA) != 0) { v1.make_delta (hi_1->value + ind, hi_1->value + first_ind); v2.make_delta (hi_2->value + ind, hi_2->value + first_ind); } else { v1.make_ratio (hi_1->value + ind, hi_1->value + first_ind); v2.make_ratio (hi_2->value + ind, hi_2->value + first_ind); } result = v1.compare (&v2); } else result = hi_1->value[ind].compare (hi_2->value + ind); } return result; } int Hist_data::sort_compare_all (const void *a, const void *b, const void *arg) { HistItem *hi_1 = *((HistItem **) a); HistItem *hi_2 = *((HistItem **) b); Hist_data *hdata = (Hist_data*) arg; int result = sort_compare (hi_1, hi_2, hdata->sort_type, hdata->sort_ind, hdata); if (hdata->sort_order == DESCEND) result = -result; // Use the name as the 2d sort key (always ASCEND) // except for MemoryObjects and IndexObjects, where the index is used // For the Alphabetic sort if (result == 0) { result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL); if (result == 0) { for (long i = 0, sz = hdata->metrics->size (); i < sz; i++) { Metric *m = hdata->metrics->get (i); if (m->get_type () != Metric::ONAME) { result = sort_compare (hi_1, hi_2, VALUE, i, hdata); if (result != 0) { if (hdata->sort_order == DESCEND) result = -result; break; } } } } } // Use the address as the 3d sort key // ( FUNCTION only, always ASCEND ) if (result == 0 && hi_1->obj->get_type () == Histable::FUNCTION) { Function *f1 = (Function*) hi_1->obj; Function *f2 = (Function*) hi_2->obj; if (f1->get_addr () < f2->get_addr ()) result = -1; else if (f1->get_addr () > f2->get_addr ()) result = 1; } // Use the Histable id (ID of function, line, etc.) as the 4th sort key // Note that IDs are not guaranteed to be stable, if (result == 0) { if (hi_1->obj->id < hi_2->obj->id) result = -1; else if (hi_1->obj->id > hi_2->obj->id) result = 1; } if (result == 0) return result; // shouldn't happen in most cases; line allows for breakpoint if (hdata->rev_sort) result = -result; return result; } int Hist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg) { assert ((a != (const void *) NULL)); assert ((b != (const void *) NULL)); HistItem *hi_1 = *((HistItem **) a); HistItem *hi_2 = *((HistItem **) b); DataObject * dobj1 = (DataObject *) (hi_1->obj); DataObject * dobj2 = (DataObject *) (hi_2->obj); DataObject * parent1 = dobj1->parent; DataObject * parent2 = dobj2->parent; Hist_data *hdata = (Hist_data*) arg; // are the two items members of the same object? if (parent1 == parent2) { // yes if (parent1) { // and they have real parents... if (parent1->get_typename ()) { // element // use dobj1/dobj2 offset for sorting uint64_t off1 = dobj1->get_offset (); uint64_t off2 = dobj2->get_offset (); if (off1 < off2) return -1; if (off1 > off2) return 1; return 0; } } } else { // parents differ if (parent1) { if (parent1 == dobj2) // sorting an object and its parent: parent always first return 1; dobj1 = parent1; } if (parent2) { if (parent2 == dobj1) return -1; dobj2 = parent2; } } // Either two unknowns, or two scalars, or two parents hi_1 = hdata->hi_map->get (dobj1); hi_2 = hdata->hi_map->get (dobj2); return sort_compare_all ((const void*) &hi_1, (const void*) &hi_2, hdata); } Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type, Hist_data::Mode _mode, bool _viewowned) { hist_items = new Vector<HistItem*>; metrics = _metrics; nmetrics = metrics->get_items ()->size (); type = _type; mode = _mode; gprof_item = new_hist_item (NULL); viewowned = _viewowned; sort_ind = -1; rev_sort = false; Histable *tobj = new Other; tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); minimum = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("")); maximum = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx")); maximum_inc = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("<Total>")); total = new_hist_item (tobj); tobj = new Other; tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX")); threshold = new_hist_item (tobj); hi_map = new HashMap<Histable*, HistItem*>; callsite_mark = new DefaultMap<Histable*, int>; hist_metrics = new Metric::HistMetric[metrics->size ()]; for (long i = 0, sz = metrics->size (); i < sz; i++) { Metric::HistMetric *h = hist_metrics + i; h->init (); Metric *m = metrics->get (i); if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO))) h->indFirstExp = metrics->get_listorder (m->get_cmd (), m->get_subtype (), "EXPGRID==1"); if (m->is_tvisible () && m->get_type () == BaseMetric::HWCNTR && m->get_dependent_bm ()) h->indTimeVal = metrics->get_listorder (m->get_dependent_bm ()->get_cmd (), m->get_subtype (), m->get_expr_spec ()); } status = NO_DATA; } Hist_data::~Hist_data () { delete[] hist_metrics; if (hist_items) { hist_items->destroy (); delete hist_items; hist_items = NULL; } if (gprof_item) { delete gprof_item; gprof_item = NULL; } if (maximum) { delete maximum->obj; delete maximum; maximum = NULL; } if (maximum_inc) { delete maximum_inc->obj; delete maximum_inc; maximum_inc = NULL; } if (minimum) { delete minimum->obj; delete minimum; minimum = NULL; } if (total) { delete total->obj; delete total; total = NULL; } if (threshold) { delete threshold->obj; delete threshold; threshold = NULL; } delete metrics; delete hi_map; delete callsite_mark; } void Hist_data::dump (char *msg, FILE *f) { fprintf (f, " Hist_data dump: %s\n", msg); fprintf (f, " %d=%d metrics\n", (int) nmetrics, (int) metrics->size ()); for (int i = 0; i < nmetrics; i++) { Metric *m = metrics->get_items ()->fetch (i); char *s = m->get_expr_spec (); fprintf (f, " %4d %15s %4d %15s\n", i, m->get_mcmd (0), m->get_id (), s ? s : "(NULL)"); } fprintf (f, NTXT (" HistItem listing\n")); int n = hist_items->size (); for (int j = -1; j < n; j++) { HistItem *hi; if (j < 0) { hi = total; fprintf (f, NTXT (" total")); } else { hi = hist_items->fetch (j); fprintf (f, NTXT ("%30s"), hi->obj->get_name ()); } for (int i = 0; i < nmetrics; i++) { char *stmp = hi->value[i].l; switch (hi->value[i].tag) { case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s); break; case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i); break; case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll); break; case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f); break; case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d); break; case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull); break; case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)"); break; case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll); break; case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p); break; case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull); break; default: fprintf (f, NTXT (" ")); break; } } fprintf (f, NTXT ("\n")); } } void Hist_data::sort (long ind, bool reverse) { if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort) // there's no change to the sorting return;