]> Git Repo - binutils.git/blob - gprofng/src/DerivedMetrics.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / DerivedMetrics.cc
1 /* Copyright (C) 2021 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
46 definition::definition ()
47 {
48   name = def = NULL;
49   arg1 = arg2 = NULL;
50 }
51
52 definition::~definition ()
53 {
54   free (name);
55   free (def);
56 }
57
58 DerivedMetrics::DerivedMetrics ()
59 {
60   items = new Vector<definition*>;
61 }
62
63 DerivedMetrics::~DerivedMetrics ()
64 {
65   Destroy (items);
66 }
67
68 definition *
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 *
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
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*> *
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
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
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
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
This page took 0.040021 seconds and 4 git commands to generate.