1*c42dbd0eSchristos /* Copyright (C) 2021 Free Software Foundation, Inc.
2*c42dbd0eSchristos Contributed by Oracle.
3*c42dbd0eSchristos
4*c42dbd0eSchristos This file is part of GNU Binutils.
5*c42dbd0eSchristos
6*c42dbd0eSchristos This program is free software; you can redistribute it and/or modify
7*c42dbd0eSchristos it under the terms of the GNU General Public License as published by
8*c42dbd0eSchristos the Free Software Foundation; either version 3, or (at your option)
9*c42dbd0eSchristos any later version.
10*c42dbd0eSchristos
11*c42dbd0eSchristos This program is distributed in the hope that it will be useful,
12*c42dbd0eSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c42dbd0eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*c42dbd0eSchristos GNU General Public License for more details.
15*c42dbd0eSchristos
16*c42dbd0eSchristos You should have received a copy of the GNU General Public License
17*c42dbd0eSchristos along with this program; if not, write to the Free Software
18*c42dbd0eSchristos Foundation, 51 Franklin Street - Fifth Floor, Boston,
19*c42dbd0eSchristos MA 02110-1301, USA. */
20*c42dbd0eSchristos
21*c42dbd0eSchristos #include "config.h"
22*c42dbd0eSchristos #include <strings.h>
23*c42dbd0eSchristos #include "DerivedMetrics.h"
24*c42dbd0eSchristos #include "util.h"
25*c42dbd0eSchristos
26*c42dbd0eSchristos enum opType
27*c42dbd0eSchristos {
28*c42dbd0eSchristos opNULL,
29*c42dbd0eSchristos opPrimitive,
30*c42dbd0eSchristos opDivide
31*c42dbd0eSchristos };
32*c42dbd0eSchristos
33*c42dbd0eSchristos class definition
34*c42dbd0eSchristos {
35*c42dbd0eSchristos public:
36*c42dbd0eSchristos definition();
37*c42dbd0eSchristos ~definition();
38*c42dbd0eSchristos char *name;
39*c42dbd0eSchristos char *def;
40*c42dbd0eSchristos opType op;
41*c42dbd0eSchristos definition *arg1;
42*c42dbd0eSchristos definition *arg2;
43*c42dbd0eSchristos int index;
44*c42dbd0eSchristos };
45*c42dbd0eSchristos
definition()46*c42dbd0eSchristos definition::definition ()
47*c42dbd0eSchristos {
48*c42dbd0eSchristos name = def = NULL;
49*c42dbd0eSchristos arg1 = arg2 = NULL;
50*c42dbd0eSchristos }
51*c42dbd0eSchristos
~definition()52*c42dbd0eSchristos definition::~definition ()
53*c42dbd0eSchristos {
54*c42dbd0eSchristos free (name);
55*c42dbd0eSchristos free (def);
56*c42dbd0eSchristos }
57*c42dbd0eSchristos
DerivedMetrics()58*c42dbd0eSchristos DerivedMetrics::DerivedMetrics ()
59*c42dbd0eSchristos {
60*c42dbd0eSchristos items = new Vector<definition*>;
61*c42dbd0eSchristos }
62*c42dbd0eSchristos
~DerivedMetrics()63*c42dbd0eSchristos DerivedMetrics::~DerivedMetrics ()
64*c42dbd0eSchristos {
65*c42dbd0eSchristos Destroy (items);
66*c42dbd0eSchristos }
67*c42dbd0eSchristos
68*c42dbd0eSchristos definition *
add_definition(char * _name,char * _username,char * _def)69*c42dbd0eSchristos DerivedMetrics::add_definition (char *_name, char *_username, char *_def)
70*c42dbd0eSchristos {
71*c42dbd0eSchristos definition *p;
72*c42dbd0eSchristos
73*c42dbd0eSchristos // if the name doesn't matter, maybe there is a duplicate we can use
74*c42dbd0eSchristos if (_name == NULL)
75*c42dbd0eSchristos {
76*c42dbd0eSchristos int i;
77*c42dbd0eSchristos Vec_loop (definition*, items, i, p)
78*c42dbd0eSchristos {
79*c42dbd0eSchristos if (strcmp (p->def, _def) == 0)
80*c42dbd0eSchristos return p;
81*c42dbd0eSchristos }
82*c42dbd0eSchristos }
83*c42dbd0eSchristos
84*c42dbd0eSchristos p = new definition;
85*c42dbd0eSchristos p->name = dbe_strdup (_name);
86*c42dbd0eSchristos p->def = dbe_strdup (_def);
87*c42dbd0eSchristos
88*c42dbd0eSchristos // parse the definition
89*c42dbd0eSchristos if (strchr (_def, '/') == NULL)
90*c42dbd0eSchristos {
91*c42dbd0eSchristos // it's a primitive metric
92*c42dbd0eSchristos p->op = opPrimitive;
93*c42dbd0eSchristos p->arg1 = p->arg2 = NULL;
94*c42dbd0eSchristos
95*c42dbd0eSchristos }
96*c42dbd0eSchristos else
97*c42dbd0eSchristos {
98*c42dbd0eSchristos // it's some operation on arguments
99*c42dbd0eSchristos p->op = opDivide;
100*c42dbd0eSchristos char *op_ptr = strchr (p->def, '/');
101*c42dbd0eSchristos *op_ptr = 0;
102*c42dbd0eSchristos p->arg1 = add_definition (NULL, NULL, p->def);
103*c42dbd0eSchristos *op_ptr = '/';
104*c42dbd0eSchristos p->arg2 = add_definition (NULL, NULL, op_ptr + 1);
105*c42dbd0eSchristos }
106*c42dbd0eSchristos p->index = items->size ();
107*c42dbd0eSchristos items->append (p);
108*c42dbd0eSchristos return p;
109*c42dbd0eSchristos }
110*c42dbd0eSchristos
111*c42dbd0eSchristos int *
construct_map(Vector<Metric * > * mitems,BaseMetric::SubType st,char * expr_spec)112*c42dbd0eSchristos DerivedMetrics::construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st, char *expr_spec)
113*c42dbd0eSchristos {
114*c42dbd0eSchristos if (items == NULL)
115*c42dbd0eSchristos return NULL;
116*c42dbd0eSchristos int ndm = items->size ();
117*c42dbd0eSchristos if (ndm == 0)
118*c42dbd0eSchristos return NULL;
119*c42dbd0eSchristos int nmetrics = mitems->size ();
120*c42dbd0eSchristos
121*c42dbd0eSchristos // allocate arrays for the mapping between derived metrics and requested values
122*c42dbd0eSchristos int *map = (int *) malloc (ndm * sizeof (int));
123*c42dbd0eSchristos
124*c42dbd0eSchristos // map derived metrics to requested metrics // EUGENE explain this more clearly
125*c42dbd0eSchristos // 0 means not mapped
126*c42dbd0eSchristos // >0 means primitive metric maps to map-1
127*c42dbd0eSchristos // <0 means derived metric maps to 1-map
128*c42dbd0eSchristos int ndm_requested = 0;
129*c42dbd0eSchristos for (int idm = 0; idm < ndm; idm++)
130*c42dbd0eSchristos {
131*c42dbd0eSchristos definition *defdm = items->fetch (idm);
132*c42dbd0eSchristos map[idm] = 0;
133*c42dbd0eSchristos
134*c42dbd0eSchristos // figure out what name to use for this derived metric
135*c42dbd0eSchristos char *dname;
136*c42dbd0eSchristos if (defdm->op == opPrimitive)
137*c42dbd0eSchristos dname = defdm->def;
138*c42dbd0eSchristos else
139*c42dbd0eSchristos {
140*c42dbd0eSchristos dname = defdm->name;
141*c42dbd0eSchristos if (dname == NULL) break;
142*c42dbd0eSchristos }
143*c42dbd0eSchristos
144*c42dbd0eSchristos // look for this name among metrics
145*c42dbd0eSchristos int im;
146*c42dbd0eSchristos for (im = 0; im < nmetrics; im++)
147*c42dbd0eSchristos {
148*c42dbd0eSchristos Metric *m = mitems->fetch (im);
149*c42dbd0eSchristos if (strcmp (dname, m->get_cmd ()) == 0 && m->get_subtype () == st)
150*c42dbd0eSchristos // apparent match, but let's check comparison mode
151*c42dbd0eSchristos if (dbe_strcmp (expr_spec, m->get_expr_spec ()) == 0)
152*c42dbd0eSchristos break;
153*c42dbd0eSchristos }
154*c42dbd0eSchristos
155*c42dbd0eSchristos // encode the mapping
156*c42dbd0eSchristos if (im >= nmetrics)
157*c42dbd0eSchristos map[idm] = 0; // does not map to requested metrics
158*c42dbd0eSchristos else if (defdm->op == opPrimitive)
159*c42dbd0eSchristos map[idm] = +1 + im; // encode as a positive index
160*c42dbd0eSchristos else
161*c42dbd0eSchristos {
162*c42dbd0eSchristos map[idm] = -1 - im; // encode as a negative index
163*c42dbd0eSchristos ndm_requested++;
164*c42dbd0eSchristos }
165*c42dbd0eSchristos }
166*c42dbd0eSchristos if (ndm_requested == 0)
167*c42dbd0eSchristos {
168*c42dbd0eSchristos free (map);
169*c42dbd0eSchristos map = NULL;
170*c42dbd0eSchristos }
171*c42dbd0eSchristos return map;
172*c42dbd0eSchristos }
173*c42dbd0eSchristos
174*c42dbd0eSchristos void
fill_dependencies(definition * def,int * vec)175*c42dbd0eSchristos DerivedMetrics::fill_dependencies (definition *def, int *vec)
176*c42dbd0eSchristos {
177*c42dbd0eSchristos switch (def->op)
178*c42dbd0eSchristos {
179*c42dbd0eSchristos case opPrimitive:
180*c42dbd0eSchristos vec[def->index] = 1;
181*c42dbd0eSchristos break;
182*c42dbd0eSchristos case opDivide:
183*c42dbd0eSchristos fill_dependencies (def->arg1, vec);
184*c42dbd0eSchristos fill_dependencies (def->arg2, vec);
185*c42dbd0eSchristos break;
186*c42dbd0eSchristos default:
187*c42dbd0eSchristos break;
188*c42dbd0eSchristos }
189*c42dbd0eSchristos }
190*c42dbd0eSchristos
191*c42dbd0eSchristos Vector<definition*> *
get_dependencies(definition * def)192*c42dbd0eSchristos DerivedMetrics::get_dependencies (definition *def)
193*c42dbd0eSchristos {
194*c42dbd0eSchristos int n = items->size ();
195*c42dbd0eSchristos
196*c42dbd0eSchristos // zero out a vector representing definitions
197*c42dbd0eSchristos int *vec = (int *) malloc (n * sizeof (int));
198*c42dbd0eSchristos for (int i = 0; i < n; i++)
199*c42dbd0eSchristos vec[i] = 0;
200*c42dbd0eSchristos fill_dependencies (def, vec);
201*c42dbd0eSchristos
202*c42dbd0eSchristos // construct the dependency vector
203*c42dbd0eSchristos Vector<definition*> *dependencies = new Vector<definition*>;
204*c42dbd0eSchristos for (int i = 0; i < n; i++)
205*c42dbd0eSchristos if (vec[i] == 1)
206*c42dbd0eSchristos dependencies->append (items->fetch (i));
207*c42dbd0eSchristos free (vec);
208*c42dbd0eSchristos return dependencies;
209*c42dbd0eSchristos }
210*c42dbd0eSchristos
211*c42dbd0eSchristos void
dump(FILE * dis_file,int verbosity)212*c42dbd0eSchristos DerivedMetrics::dump (FILE *dis_file, int verbosity)
213*c42dbd0eSchristos {
214*c42dbd0eSchristos int i;
215*c42dbd0eSchristos definition *item;
216*c42dbd0eSchristos
217*c42dbd0eSchristos // deal with the possibility that names might be NULL
218*c42dbd0eSchristos const char *UNNAMED = "(unnamed)";
219*c42dbd0eSchristos #define NAME(x) ( (x) ? (x) : UNNAMED)
220*c42dbd0eSchristos
221*c42dbd0eSchristos Vec_loop (definition*, items, i, item)
222*c42dbd0eSchristos {
223*c42dbd0eSchristos // at low verbosity, skip over some items
224*c42dbd0eSchristos if (verbosity == 0)
225*c42dbd0eSchristos {
226*c42dbd0eSchristos if (item->name == NULL)
227*c42dbd0eSchristos continue;
228*c42dbd0eSchristos if (strcmp (item->name, item->def) && item->op == opPrimitive)
229*c42dbd0eSchristos continue;
230*c42dbd0eSchristos }
231*c42dbd0eSchristos
232*c42dbd0eSchristos // dump the definition
233*c42dbd0eSchristos switch (item->op)
234*c42dbd0eSchristos {
235*c42dbd0eSchristos case opPrimitive:
236*c42dbd0eSchristos fprintf (dis_file, "%s [%s] is a primitive metric\n", NAME (item->name),
237*c42dbd0eSchristos item->def);
238*c42dbd0eSchristos break;
239*c42dbd0eSchristos case opDivide:
240*c42dbd0eSchristos fprintf (dis_file, "%s [%s] = %s [%s] / %s [%s]\n", NAME (item->name),
241*c42dbd0eSchristos item->def, NAME (item->arg1->name), item->arg1->def,
242*c42dbd0eSchristos NAME (item->arg2->name), item->arg2->def);
243*c42dbd0eSchristos break;
244*c42dbd0eSchristos default:
245*c42dbd0eSchristos fprintf (dis_file, "%s [%s] has an unrecognized op %d\n",
246*c42dbd0eSchristos NAME (item->name), item->def, item->op);
247*c42dbd0eSchristos break;
248*c42dbd0eSchristos }
249*c42dbd0eSchristos }
250*c42dbd0eSchristos }
251*c42dbd0eSchristos
252*c42dbd0eSchristos double
eval_one_item(definition * def,int * map,double * values)253*c42dbd0eSchristos DerivedMetrics::eval_one_item (definition *def, int *map, double *values)
254*c42dbd0eSchristos {
255*c42dbd0eSchristos switch (def->op)
256*c42dbd0eSchristos {
257*c42dbd0eSchristos case opNULL:
258*c42dbd0eSchristos fprintf (stderr, GTXT ("cannot eval NULL expression\n"));
259*c42dbd0eSchristos return 0.;
260*c42dbd0eSchristos case opPrimitive:
261*c42dbd0eSchristos {
262*c42dbd0eSchristos int ival = map[def->index];
263*c42dbd0eSchristos if (ival <= 0) return 0.;
264*c42dbd0eSchristos ival--;
265*c42dbd0eSchristos return values[ival];
266*c42dbd0eSchristos }
267*c42dbd0eSchristos case opDivide:
268*c42dbd0eSchristos {
269*c42dbd0eSchristos double x1 = eval_one_item (def->arg1, map, values);
270*c42dbd0eSchristos double x2 = eval_one_item (def->arg2, map, values);
271*c42dbd0eSchristos if (x2 == 0) return 0.;
272*c42dbd0eSchristos return (x1 / x2);
273*c42dbd0eSchristos }
274*c42dbd0eSchristos default:
275*c42dbd0eSchristos fprintf (stderr, GTXT ("unknown expression\n"));
276*c42dbd0eSchristos return 0.;
277*c42dbd0eSchristos }
278*c42dbd0eSchristos }
279*c42dbd0eSchristos
280*c42dbd0eSchristos int
eval(int * map,double * values)281*c42dbd0eSchristos DerivedMetrics::eval (int *map, double *values)
282*c42dbd0eSchristos {
283*c42dbd0eSchristos for (int i = 0, n = items->size (); i < n; i++)
284*c42dbd0eSchristos {
285*c42dbd0eSchristos if (map[i] < 0)
286*c42dbd0eSchristos {
287*c42dbd0eSchristos int ival = -1 - map[i];
288*c42dbd0eSchristos values[ival] = eval_one_item (items->fetch (i), map, values);
289*c42dbd0eSchristos }
290*c42dbd0eSchristos }
291*c42dbd0eSchristos return 0;
292*c42dbd0eSchristos }
293*c42dbd0eSchristos
294