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 <stdio.h> 23 #include <strings.h> 24 #include <limits.h> 25 #include <sys/param.h> 26 27 #include "hwcentry.h" 28 #include "DbeSession.h" 29 #include "Experiment.h" 30 #include "Expression.h" 31 #include "Metric.h" 32 #include "Table.h" 33 #include "i18n.h" 34 #include "debug.h" 35 36 BaseMetricTreeNode::BaseMetricTreeNode () 37 { 38 init_vars (); 39 build_basic_tree (); 40 } 41 42 BaseMetricTreeNode::BaseMetricTreeNode (BaseMetric *item) 43 { 44 init_vars (); 45 bm = item; 46 name = dbe_strdup (bm->get_cmd ()); 47 uname = dbe_strdup (bm->get_username ()); 48 unit = NULL; //YXXX populate from base_metric (requires updating base_metric) 49 unit_uname = NULL; 50 } 51 52 BaseMetricTreeNode::BaseMetricTreeNode (const char *_name, const char *_uname, 53 const char *_unit, const char *_unit_uname) 54 { 55 init_vars (); 56 name = dbe_strdup (_name); 57 uname = dbe_strdup (_uname); 58 unit = dbe_strdup (_unit); 59 unit_uname = dbe_strdup (_unit_uname); 60 } 61 62 void 63 BaseMetricTreeNode::init_vars () 64 { 65 name = NULL; 66 uname = NULL; 67 unit = NULL; 68 unit_uname = NULL; 69 root = this; 70 parent = NULL; 71 children = new Vector<BaseMetricTreeNode*>; 72 isCompositeMetric = false; 73 bm = NULL; 74 registered = false; 75 num_registered_descendents = 0; 76 } 77 78 BaseMetricTreeNode::~BaseMetricTreeNode () 79 { 80 children->destroy (); 81 delete children; 82 free (name); 83 free (uname); 84 free (unit); 85 free (unit_uname); 86 } 87 88 BaseMetricTreeNode * 89 BaseMetricTreeNode::register_metric (BaseMetric *item) 90 { 91 BaseMetricTreeNode *found = root->find (item->get_cmd ()); 92 if (!found) 93 { 94 switch (item->get_type ()) 95 { 96 case BaseMetric::CP_TOTAL: 97 found = root->find (L_CP_TOTAL); 98 break; 99 case BaseMetric::CP_TOTAL_CPU: 100 found = root->find (L_CP_TOTAL_CPU); 101 break; 102 } 103 if (found && found->bm == NULL) 104 found->bm = item; 105 } 106 if (!found) 107 { 108 switch (item->get_type ()) 109 { 110 case BaseMetric::HEAP_ALLOC_BYTES: 111 case BaseMetric::HEAP_ALLOC_CNT: 112 case BaseMetric::HEAP_LEAK_BYTES: 113 case BaseMetric::HEAP_LEAK_CNT: 114 found = root->find (get_prof_data_type_name (DATA_HEAP)); 115 break; 116 case BaseMetric::CP_KERNEL_CPU: 117 case BaseMetric::CP_TOTAL: 118 found = root->find (get_prof_data_type_name (DATA_CLOCK)); 119 break; 120 case BaseMetric::CP_LMS_DFAULT: 121 case BaseMetric::CP_LMS_TFAULT: 122 case BaseMetric::CP_LMS_KFAULT: 123 case BaseMetric::CP_LMS_STOPPED: 124 case BaseMetric::CP_LMS_WAIT_CPU: 125 case BaseMetric::CP_LMS_SLEEP: 126 case BaseMetric::CP_LMS_USER_LOCK: 127 case BaseMetric::CP_TOTAL_CPU: 128 found = root->find (L_CP_TOTAL); 129 break; 130 case BaseMetric::CP_LMS_USER: 131 case BaseMetric::CP_LMS_SYSTEM: 132 case BaseMetric::CP_LMS_TRAP: 133 found = root->find (L_CP_TOTAL_CPU); 134 break; 135 case BaseMetric::HWCNTR: 136 found = root->find ((item->get_flavors () & BaseMetric::DATASPACE) != 0 ? 137 L2_HWC_DSPACE : L2_HWC_GENERAL); 138 break; 139 case BaseMetric::SYNC_WAIT_TIME: 140 case BaseMetric::SYNC_WAIT_COUNT: 141 found = root->find (get_prof_data_type_name (DATA_SYNCH)); 142 break; 143 case BaseMetric::OMP_WORK: 144 case BaseMetric::OMP_WAIT: 145 case BaseMetric::OMP_OVHD: 146 found = root->find (get_prof_data_type_name (DATA_OMP)); 147 break; 148 case BaseMetric::IO_READ_TIME: 149 case BaseMetric::IO_READ_BYTES: 150 case BaseMetric::IO_READ_CNT: 151 case BaseMetric::IO_WRITE_TIME: 152 case BaseMetric::IO_WRITE_BYTES: 153 case BaseMetric::IO_WRITE_CNT: 154 case BaseMetric::IO_OTHER_TIME: 155 case BaseMetric::IO_OTHER_CNT: 156 case BaseMetric::IO_ERROR_TIME: 157 case BaseMetric::IO_ERROR_CNT: 158 found = root->find (get_prof_data_type_name (DATA_IOTRACE)); 159 break; 160 case BaseMetric::ONAME: 161 case BaseMetric::SIZES: 162 case BaseMetric::ADDRESS: 163 found = root->find (L1_STATIC); 164 break; 165 default: 166 found = root->find (L1_OTHER); 167 break; 168 } 169 assert (found != NULL); 170 switch (item->get_type ()) 171 { 172 case BaseMetric::CP_TOTAL: 173 case BaseMetric::CP_TOTAL_CPU: 174 found->isCompositeMetric = true; 175 break; 176 } 177 found = found->add_child (item); 178 } 179 register_node (found); 180 return found; 181 } 182 183 void 184 BaseMetricTreeNode::register_node (BaseMetricTreeNode *node) 185 { 186 if (!node->registered) 187 { 188 node->registered = true; 189 BaseMetricTreeNode *tmp = node->parent; 190 while (tmp) 191 { 192 tmp->num_registered_descendents++; 193 tmp = tmp->parent; 194 } 195 } 196 } 197 198 BaseMetricTreeNode * 199 BaseMetricTreeNode::find (const char *_name) 200 { 201 BaseMetricTreeNode *found = NULL; 202 if (dbe_strcmp (get_name (), _name) == 0) 203 return this; 204 if (bm && dbe_strcmp (bm->get_cmd (), _name) == 0) 205 return this; 206 BaseMetricTreeNode *child; 207 int index; 208 209 Vec_loop (BaseMetricTreeNode*, children, index, child) 210 { 211 found = child->find (_name); 212 if (found) 213 return found; 214 } 215 return NULL; 216 } 217 218 static void 219 int_get_registered_descendents (BaseMetricTreeNode* curr, 220 Vector<BaseMetricTreeNode*> *dest, bool nearest_only) 221 { 222 if (!curr) 223 return; 224 if (curr->is_registered ()) 225 { 226 dest->append (curr); 227 if (nearest_only) 228 return; // soon as we hit a live node, stop following branch 229 } 230 int index; 231 BaseMetricTreeNode *child; 232 233 Vec_loop (BaseMetricTreeNode*, curr->get_children (), index, child) 234 { 235 int_get_registered_descendents (child, dest, nearest_only); 236 } 237 } 238 239 void 240 BaseMetricTreeNode::get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *dest) 241 { 242 if (!dest || dest->size () != 0) 243 abort (); 244 bool nearest_only = true; 245 int_get_registered_descendents (this, dest, nearest_only); 246 } 247 248 void 249 BaseMetricTreeNode::get_all_registered_descendents (Vector<BaseMetricTreeNode*> *dest) 250 { 251 if (!dest || dest->size () != 0) 252 abort (); 253 bool nearest_only = false; 254 int_get_registered_descendents (this, dest, nearest_only); 255 } 256 257 char * 258 BaseMetricTreeNode::get_description () 259 { 260 if (bm) 261 { 262 Hwcentry* hw_ctr = bm->get_hw_ctr (); 263 if (hw_ctr) 264 return hw_ctr->short_desc; 265 } 266 return NULL; 267 } 268 269 void 270 BaseMetricTreeNode::build_basic_tree () 271 { 272 #define TREE_INSERT_DATA_TYPE(t) add_child(get_prof_data_type_name (t), get_prof_data_type_uname (t)) 273 BaseMetricTreeNode *level1, *level2; 274 // register L1_DURATION here because it has a value but is not a true metric 275 register_node (add_child (L1_DURATION, L1_DURATION_UNAME, UNIT_SECONDS, 276 UNIT_SECONDS_UNAME)); 277 register_node (add_child (L1_GCDURATION, L1_GCDURATION_UNAME, UNIT_SECONDS, 278 UNIT_SECONDS_UNAME)); 279 TREE_INSERT_DATA_TYPE (DATA_HEAP); 280 level1 = TREE_INSERT_DATA_TYPE (DATA_CLOCK); 281 level1 = level1->add_child (L_CP_TOTAL, GTXT ("XXX Total Thread Time")); 282 level1->isCompositeMetric = true; 283 level2 = level1->add_child (L_CP_TOTAL_CPU, GTXT ("XXX Total CPU Time")); 284 level2->isCompositeMetric = true; 285 286 add_child (L1_OTHER, L1_OTHER_UNAME); 287 level1 = TREE_INSERT_DATA_TYPE (DATA_HWC); 288 level1->add_child (L2_HWC_DSPACE, L2_HWC_DSPACE_UNAME); 289 level1->add_child (L2_HWC_GENERAL, L2_HWC_GENERAL_UNAME); 290 TREE_INSERT_DATA_TYPE (DATA_SYNCH); 291 TREE_INSERT_DATA_TYPE (DATA_OMP); 292 TREE_INSERT_DATA_TYPE (DATA_IOTRACE); 293 add_child (L1_STATIC, L1_STATIC_UNAME); 294 } 295 296 BaseMetricTreeNode * 297 BaseMetricTreeNode::add_child (BaseMetric *item) 298 { 299 return add_child (new BaseMetricTreeNode (item)); 300 } 301 302 BaseMetricTreeNode * 303 BaseMetricTreeNode::add_child (const char * _name, const char *_uname, 304 const char * _unit, const char * _unit_uname) 305 { 306 return add_child (new BaseMetricTreeNode (_name, _uname, _unit, _unit_uname)); 307 } 308 309 BaseMetricTreeNode * 310 BaseMetricTreeNode::add_child (BaseMetricTreeNode *new_node) 311 { 312 new_node->parent = this; 313 new_node->root = root; 314 children->append (new_node); 315 return new_node; 316 } 317 318 char * 319 BaseMetricTreeNode::dump () 320 { 321 int len = 4; 322 char *s = bm ? bm->dump () : dbe_strdup ("<no base metric>"); 323 char *msg = dbe_sprintf ("%s\n%*c %*c unit='%s' unit_uname='%s' uname='%s' name='%s'\n", 324 STR (s), len, ' ', len, ' ', 325 STR (get_unit_uname ()), STR (get_unit ()), 326 STR (get_user_name ()), STR (get_name ())); 327 free (s); 328 return msg; 329 } 330