xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/DerivedMetrics.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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