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 26enum opType 27{ 28 opNULL, 29 opPrimitive, 30 opDivide 31}; 32 33class definition 34{ 35public: 36 definition(); 37 ~definition(); 38 char *name; 39 char *def; 40 opType op; 41 definition *arg1; 42 definition *arg2; 43 int index; 44}; 45 46definition::definition () 47{ 48 name = def = NULL; 49 arg1 = arg2 = NULL; 50} 51 52definition::~definition () 53{ 54 free (name); 55 free (def); 56} 57 58DerivedMetrics::DerivedMetrics () 59{ 60 items = new Vector<definition*>; 61} 62 63DerivedMetrics::~DerivedMetrics () 64{ 65 Destroy (items); 66} 67 68definition * 69DerivedMetrics::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 111int * 112DerivedMetrics::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 174void 175DerivedMetrics::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 191Vector<definition*> * 192DerivedMetrics::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 211void 212DerivedMetrics::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 252double 253DerivedMetrics::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 280int 281DerivedMetrics::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