aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src/DerivedMetrics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/DerivedMetrics.cc')
-rw-r--r--gprofng/src/DerivedMetrics.cc293
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;
+}
+