diff options
Diffstat (limited to 'gprofng/src/DerivedMetrics.cc')
-rw-r--r-- | gprofng/src/DerivedMetrics.cc | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/gprofng/src/DerivedMetrics.cc b/gprofng/src/DerivedMetrics.cc new file mode 100644 index 0000000..9f504a5 --- /dev/null +++ b/gprofng/src/DerivedMetrics.cc @@ -0,0 +1,293 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <strings.h> +#include "DerivedMetrics.h" +#include "util.h" + +enum opType +{ + opNULL, + opPrimitive, + opDivide +}; + +class definition +{ +public: + definition(); + ~definition(); + char *name; + char *def; + opType op; + definition *arg1; + definition *arg2; + int index; +}; + +definition::definition () +{ + name = def = NULL; + arg1 = arg2 = NULL; +} + +definition::~definition () +{ + free (name); + free (def); +} + +DerivedMetrics::DerivedMetrics () +{ + items = new Vector<definition*>; +} + +DerivedMetrics::~DerivedMetrics () +{ + Destroy (items); +} + +definition * +DerivedMetrics::add_definition (char *_name, char *_username, char *_def) +{ + definition *p; + + // if the name doesn't matter, maybe there is a duplicate we can use + if (_name == NULL) + { + int i; + Vec_loop (definition*, items, i, p) + { + if (strcmp (p->def, _def) == 0) + return p; + } + } + + p = new definition; + p->name = dbe_strdup (_name); + p->def = dbe_strdup (_def); + + // parse the definition + if (strchr (_def, '/') == NULL) + { + // it's a primitive metric + p->op = opPrimitive; + p->arg1 = p->arg2 = NULL; + + } + else + { + // it's some operation on arguments + p->op = opDivide; + char *op_ptr = strchr (p->def, '/'); + *op_ptr = 0; + p->arg1 = add_definition (NULL, NULL, p->def); + *op_ptr = '/'; + p->arg2 = add_definition (NULL, NULL, op_ptr + 1); + } + p->index = items->size (); + items->append (p); + return p; +} + +int * +DerivedMetrics::construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st, char *expr_spec) +{ + if (items == NULL) + return NULL; + int ndm = items->size (); + if (ndm == 0) + return NULL; + int nmetrics = mitems->size (); + + // allocate arrays for the mapping between derived metrics and requested values + int *map = (int *) malloc (ndm * sizeof (int)); + + // map derived metrics to requested metrics // EUGENE explain this more clearly + // 0 means not mapped + // >0 means primitive metric maps to map-1 + // <0 means derived metric maps to 1-map + int ndm_requested = 0; + for (int idm = 0; idm < ndm; idm++) + { + definition *defdm = items->fetch (idm); + map[idm] = 0; + + // figure out what name to use for this derived metric + char *dname; + if (defdm->op == opPrimitive) + dname = defdm->def; + else + { + dname = defdm->name; + if (dname == NULL) break; + } + + // look for this name among metrics + int im; + for (im = 0; im < nmetrics; im++) + { + Metric *m = mitems->fetch (im); + if (strcmp (dname, m->get_cmd ()) == 0 && m->get_subtype () == st) + // apparent match, but let's check comparison mode + if (dbe_strcmp (expr_spec, m->get_expr_spec ()) == 0) + break; + } + + // encode the mapping + if (im >= nmetrics) + map[idm] = 0; // does not map to requested metrics + else if (defdm->op == opPrimitive) + map[idm] = +1 + im; // encode as a positive index + else + { + map[idm] = -1 - im; // encode as a negative index + ndm_requested++; + } + } + if (ndm_requested == 0) + { + free (map); + map = NULL; + } + return map; +} + +void +DerivedMetrics::fill_dependencies (definition *def, int *vec) +{ + switch (def->op) + { + case opPrimitive: + vec[def->index] = 1; + break; + case opDivide: + fill_dependencies (def->arg1, vec); + fill_dependencies (def->arg2, vec); + break; + default: + break; + } +} + +Vector<definition*> * +DerivedMetrics::get_dependencies (definition *def) +{ + int n = items->size (); + + // zero out a vector representing definitions + int *vec = (int *) malloc (n * sizeof (int)); + for (int i = 0; i < n; i++) + vec[i] = 0; + fill_dependencies (def, vec); + + // construct the dependency vector + Vector<definition*> *dependencies = new Vector<definition*>; + for (int i = 0; i < n; i++) + if (vec[i] == 1) + dependencies->append (items->fetch (i)); + free (vec); + return dependencies; +} + +void +DerivedMetrics::dump (FILE *dis_file, int verbosity) +{ + int i; + definition *item; + + // deal with the possibility that names might be NULL + const char *UNNAMED = "(unnamed)"; +#define NAME(x) ( (x) ? (x) : UNNAMED) + + Vec_loop (definition*, items, i, item) + { + // at low verbosity, skip over some items + if (verbosity == 0) + { + if (item->name == NULL) + continue; + if (strcmp (item->name, item->def) && item->op == opPrimitive) + continue; + } + + // dump the definition + switch (item->op) + { + case opPrimitive: + fprintf (dis_file, "%s [%s] is a primitive metric\n", NAME (item->name), + item->def); + break; + case opDivide: + fprintf (dis_file, "%s [%s] = %s [%s] / %s [%s]\n", NAME (item->name), + item->def, NAME (item->arg1->name), item->arg1->def, + NAME (item->arg2->name), item->arg2->def); + break; + default: + fprintf (dis_file, "%s [%s] has an unrecognized op %d\n", + NAME (item->name), item->def, item->op); + break; + } + } +} + +double +DerivedMetrics::eval_one_item (definition *def, int *map, double *values) +{ + switch (def->op) + { + case opNULL: + fprintf (stderr, GTXT ("cannot eval NULL expression\n")); + return 0.; + case opPrimitive: + { + int ival = map[def->index]; + if (ival <= 0) return 0.; + ival--; + return values[ival]; + } + case opDivide: + { + double x1 = eval_one_item (def->arg1, map, values); + double x2 = eval_one_item (def->arg2, map, values); + if (x2 == 0) return 0.; + return (x1 / x2); + } + default: + fprintf (stderr, GTXT ("unknown expression\n")); + return 0.; + } +} + +int +DerivedMetrics::eval (int *map, double *values) +{ + for (int i = 0, n = items->size (); i < n; i++) + { + if (map[i] < 0) + { + int ival = -1 - map[i]; + values[ival] = eval_one_item (items->fetch (i), map, values); + } + } + return 0; +} + |