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