xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/DerivedMetrics.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1*cb63e24eSchristos /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
24f645668Schristos    Contributed by Oracle.
34f645668Schristos 
44f645668Schristos    This file is part of GNU Binutils.
54f645668Schristos 
64f645668Schristos    This program is free software; you can redistribute it and/or modify
74f645668Schristos    it under the terms of the GNU General Public License as published by
84f645668Schristos    the Free Software Foundation; either version 3, or (at your option)
94f645668Schristos    any later version.
104f645668Schristos 
114f645668Schristos    This program is distributed in the hope that it will be useful,
124f645668Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
134f645668Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
144f645668Schristos    GNU General Public License for more details.
154f645668Schristos 
164f645668Schristos    You should have received a copy of the GNU General Public License
174f645668Schristos    along with this program; if not, write to the Free Software
184f645668Schristos    Foundation, 51 Franklin Street - Fifth Floor, Boston,
194f645668Schristos    MA 02110-1301, USA.  */
204f645668Schristos 
214f645668Schristos #include "config.h"
224f645668Schristos #include <strings.h>
234f645668Schristos #include "DerivedMetrics.h"
244f645668Schristos #include "util.h"
254f645668Schristos 
264f645668Schristos enum opType
274f645668Schristos {
284f645668Schristos   opNULL,
294f645668Schristos   opPrimitive,
304f645668Schristos   opDivide
314f645668Schristos };
324f645668Schristos 
334f645668Schristos class definition
344f645668Schristos {
354f645668Schristos public:
364f645668Schristos   definition();
374f645668Schristos   ~definition();
384f645668Schristos   char *name;
394f645668Schristos   char *def;
404f645668Schristos   opType op;
414f645668Schristos   definition *arg1;
424f645668Schristos   definition *arg2;
434f645668Schristos   int index;
444f645668Schristos };
454f645668Schristos 
definition()464f645668Schristos definition::definition ()
474f645668Schristos {
484f645668Schristos   name = def = NULL;
494f645668Schristos   arg1 = arg2 = NULL;
504f645668Schristos }
514f645668Schristos 
~definition()524f645668Schristos definition::~definition ()
534f645668Schristos {
544f645668Schristos   free (name);
554f645668Schristos   free (def);
564f645668Schristos }
574f645668Schristos 
DerivedMetrics()584f645668Schristos DerivedMetrics::DerivedMetrics ()
594f645668Schristos {
604f645668Schristos   items = new Vector<definition*>;
614f645668Schristos }
624f645668Schristos 
~DerivedMetrics()634f645668Schristos DerivedMetrics::~DerivedMetrics ()
644f645668Schristos {
654f645668Schristos   Destroy (items);
664f645668Schristos }
674f645668Schristos 
684f645668Schristos definition *
add_definition(char * _name,char * _username,char * _def)694f645668Schristos DerivedMetrics::add_definition (char *_name, char *_username, char *_def)
704f645668Schristos {
714f645668Schristos   definition *p;
724f645668Schristos 
734f645668Schristos   // if the name doesn't matter, maybe there is a duplicate we can use
744f645668Schristos   if (_name == NULL)
754f645668Schristos     {
764f645668Schristos       int i;
774f645668Schristos       Vec_loop (definition*, items, i, p)
784f645668Schristos       {
794f645668Schristos 	if (strcmp (p->def, _def) == 0)
804f645668Schristos 	  return p;
814f645668Schristos       }
824f645668Schristos     }
834f645668Schristos 
844f645668Schristos   p = new definition;
854f645668Schristos   p->name = dbe_strdup (_name);
864f645668Schristos   p->def = dbe_strdup (_def);
874f645668Schristos 
884f645668Schristos   // parse the definition
894f645668Schristos   if (strchr (_def, '/') == NULL)
904f645668Schristos     {
914f645668Schristos       // it's a primitive metric
924f645668Schristos       p->op = opPrimitive;
934f645668Schristos       p->arg1 = p->arg2 = NULL;
944f645668Schristos 
954f645668Schristos     }
964f645668Schristos   else
974f645668Schristos     {
984f645668Schristos       // it's some operation on arguments
994f645668Schristos       p->op = opDivide;
1004f645668Schristos       char *op_ptr = strchr (p->def, '/');
1014f645668Schristos       *op_ptr = 0;
1024f645668Schristos       p->arg1 = add_definition (NULL, NULL, p->def);
1034f645668Schristos       *op_ptr = '/';
1044f645668Schristos       p->arg2 = add_definition (NULL, NULL, op_ptr + 1);
1054f645668Schristos     }
1064f645668Schristos   p->index = items->size ();
1074f645668Schristos   items->append (p);
1084f645668Schristos   return p;
1094f645668Schristos }
1104f645668Schristos 
1114f645668Schristos int *
construct_map(Vector<Metric * > * mitems,BaseMetric::SubType st,char * expr_spec)1124f645668Schristos DerivedMetrics::construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st, char *expr_spec)
1134f645668Schristos {
1144f645668Schristos   if (items == NULL)
1154f645668Schristos     return NULL;
1164f645668Schristos   int ndm = items->size ();
1174f645668Schristos   if (ndm == 0)
1184f645668Schristos     return NULL;
1194f645668Schristos   int nmetrics = mitems->size ();
1204f645668Schristos 
1214f645668Schristos   // allocate arrays for the mapping between derived metrics and requested values
1224f645668Schristos   int *map = (int *) malloc (ndm * sizeof (int));
1234f645668Schristos 
1244f645668Schristos   // map derived metrics to requested metrics    // EUGENE explain this more clearly
1254f645668Schristos   //   0  means not mapped
1264f645668Schristos   //  >0  means primitive metric maps to map-1
1274f645668Schristos   //  <0  means  derived  metric maps to 1-map
1284f645668Schristos   int ndm_requested = 0;
1294f645668Schristos   for (int idm = 0; idm < ndm; idm++)
1304f645668Schristos     {
1314f645668Schristos       definition *defdm = items->fetch (idm);
1324f645668Schristos       map[idm] = 0;
1334f645668Schristos 
1344f645668Schristos       // figure out what name to use for this derived metric
1354f645668Schristos       char *dname;
1364f645668Schristos       if (defdm->op == opPrimitive)
1374f645668Schristos 	dname = defdm->def;
1384f645668Schristos       else
1394f645668Schristos 	{
1404f645668Schristos 	  dname = defdm->name;
1414f645668Schristos 	  if (dname == NULL) break;
1424f645668Schristos 	}
1434f645668Schristos 
1444f645668Schristos       // look for this name among metrics
1454f645668Schristos       int im;
1464f645668Schristos       for (im = 0; im < nmetrics; im++)
1474f645668Schristos 	{
1484f645668Schristos 	  Metric *m = mitems->fetch (im);
1494f645668Schristos 	  if (strcmp (dname, m->get_cmd ()) == 0 && m->get_subtype () == st)
1504f645668Schristos 	    // apparent match, but let's check comparison mode
1514f645668Schristos 	    if (dbe_strcmp (expr_spec, m->get_expr_spec ()) == 0)
1524f645668Schristos 	      break;
1534f645668Schristos 	}
1544f645668Schristos 
1554f645668Schristos       // encode the mapping
1564f645668Schristos       if (im >= nmetrics)
1574f645668Schristos 	map[idm] = 0; // does not map to requested metrics
1584f645668Schristos       else if (defdm->op == opPrimitive)
1594f645668Schristos 	map[idm] = +1 + im; // encode as a positive index
1604f645668Schristos       else
1614f645668Schristos 	{
1624f645668Schristos 	  map[idm] = -1 - im; // encode as a negative index
1634f645668Schristos 	  ndm_requested++;
1644f645668Schristos 	}
1654f645668Schristos     }
1664f645668Schristos   if (ndm_requested == 0)
1674f645668Schristos     {
1684f645668Schristos       free (map);
1694f645668Schristos       map = NULL;
1704f645668Schristos     }
1714f645668Schristos   return map;
1724f645668Schristos }
1734f645668Schristos 
1744f645668Schristos void
fill_dependencies(definition * def,int * vec)1754f645668Schristos DerivedMetrics::fill_dependencies (definition *def, int *vec)
1764f645668Schristos {
1774f645668Schristos   switch (def->op)
1784f645668Schristos     {
1794f645668Schristos     case opPrimitive:
1804f645668Schristos       vec[def->index] = 1;
1814f645668Schristos       break;
1824f645668Schristos     case opDivide:
1834f645668Schristos       fill_dependencies (def->arg1, vec);
1844f645668Schristos       fill_dependencies (def->arg2, vec);
1854f645668Schristos       break;
1864f645668Schristos     default:
1874f645668Schristos       break;
1884f645668Schristos     }
1894f645668Schristos }
1904f645668Schristos 
1914f645668Schristos Vector<definition*> *
get_dependencies(definition * def)1924f645668Schristos DerivedMetrics::get_dependencies (definition *def)
1934f645668Schristos {
1944f645668Schristos   int n = items->size ();
1954f645668Schristos 
1964f645668Schristos   // zero out a vector representing definitions
1974f645668Schristos   int *vec = (int *) malloc (n * sizeof (int));
1984f645668Schristos   for (int i = 0; i < n; i++)
1994f645668Schristos     vec[i] = 0;
2004f645668Schristos   fill_dependencies (def, vec);
2014f645668Schristos 
2024f645668Schristos   // construct the dependency vector
2034f645668Schristos   Vector<definition*> *dependencies = new Vector<definition*>;
2044f645668Schristos   for (int i = 0; i < n; i++)
2054f645668Schristos     if (vec[i] == 1)
2064f645668Schristos       dependencies->append (items->fetch (i));
2074f645668Schristos   free (vec);
2084f645668Schristos   return dependencies;
2094f645668Schristos }
2104f645668Schristos 
2114f645668Schristos void
dump(FILE * dis_file,int verbosity)2124f645668Schristos DerivedMetrics::dump (FILE *dis_file, int verbosity)
2134f645668Schristos {
2144f645668Schristos   int i;
2154f645668Schristos   definition *item;
2164f645668Schristos 
2174f645668Schristos   // deal with the possibility that names might be NULL
2184f645668Schristos   const char *UNNAMED = "(unnamed)";
2194f645668Schristos #define NAME(x) ( (x) ? (x) : UNNAMED)
2204f645668Schristos 
2214f645668Schristos   Vec_loop (definition*, items, i, item)
2224f645668Schristos   {
2234f645668Schristos     // at low verbosity, skip over some items
2244f645668Schristos     if (verbosity == 0)
2254f645668Schristos       {
2264f645668Schristos 	if (item->name == NULL)
2274f645668Schristos 	  continue;
2284f645668Schristos 	if (strcmp (item->name, item->def) && item->op == opPrimitive)
2294f645668Schristos 	  continue;
2304f645668Schristos       }
2314f645668Schristos 
2324f645668Schristos     // dump the definition
2334f645668Schristos     switch (item->op)
2344f645668Schristos       {
2354f645668Schristos       case opPrimitive:
2364f645668Schristos 	fprintf (dis_file, "%s [%s] is a primitive metric\n", NAME (item->name),
2374f645668Schristos 		 item->def);
2384f645668Schristos 	break;
2394f645668Schristos       case opDivide:
2404f645668Schristos 	fprintf (dis_file, "%s [%s] = %s [%s] / %s [%s]\n", NAME (item->name),
2414f645668Schristos 		 item->def, NAME (item->arg1->name), item->arg1->def,
2424f645668Schristos 		 NAME (item->arg2->name), item->arg2->def);
2434f645668Schristos 	break;
2444f645668Schristos       default:
2454f645668Schristos 	fprintf (dis_file, "%s [%s] has an unrecognized op %d\n",
2464f645668Schristos 		 NAME (item->name), item->def, item->op);
2474f645668Schristos 	break;
2484f645668Schristos       }
2494f645668Schristos   }
2504f645668Schristos }
2514f645668Schristos 
2524f645668Schristos double
eval_one_item(definition * def,int * map,double * values)2534f645668Schristos DerivedMetrics::eval_one_item (definition *def, int *map, double *values)
2544f645668Schristos {
2554f645668Schristos   switch (def->op)
2564f645668Schristos     {
2574f645668Schristos     case opNULL:
2584f645668Schristos       fprintf (stderr, GTXT ("cannot eval NULL expression\n"));
2594f645668Schristos       return 0.;
2604f645668Schristos     case opPrimitive:
2614f645668Schristos       {
2624f645668Schristos 	int ival = map[def->index];
2634f645668Schristos 	if (ival <= 0) return 0.;
2644f645668Schristos 	ival--;
2654f645668Schristos 	return values[ival];
2664f645668Schristos       }
2674f645668Schristos     case opDivide:
2684f645668Schristos       {
2694f645668Schristos 	double x1 = eval_one_item (def->arg1, map, values);
2704f645668Schristos 	double x2 = eval_one_item (def->arg2, map, values);
2714f645668Schristos 	if (x2 == 0) return 0.;
2724f645668Schristos 	return (x1 / x2);
2734f645668Schristos       }
2744f645668Schristos     default:
2754f645668Schristos       fprintf (stderr, GTXT ("unknown expression\n"));
2764f645668Schristos       return 0.;
2774f645668Schristos     }
2784f645668Schristos }
2794f645668Schristos 
2804f645668Schristos int
eval(int * map,double * values)2814f645668Schristos DerivedMetrics::eval (int *map, double *values)
2824f645668Schristos {
2834f645668Schristos   for (int i = 0, n = items->size (); i < n; i++)
2844f645668Schristos     {
2854f645668Schristos       if (map[i] < 0)
2864f645668Schristos 	{
2874f645668Schristos 	  int ival = -1 - map[i];
2884f645668Schristos 	  values[ival] = eval_one_item (items->fetch (i), map, values);
2894f645668Schristos 	}
2904f645668Schristos     }
2914f645668Schristos   return 0;
2924f645668Schristos }
2934f645668Schristos 
294