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 "util.h" 23#include "DbeSession.h" 24#include "DbeView.h" 25#include "IndexObject.h" 26#include "StringBuilder.h" 27 28IndexObject::IndexObject (int _indextype, uint64_t _index) 29{ 30 indextype = _indextype; 31 obj = NULL; 32 id = _index; 33 name = NULL; 34 nameIsFinal = false; 35} 36 37IndexObject::IndexObject (int _indextype, Histable *_obj) 38{ 39 indextype = _indextype; 40 obj = _obj; 41 id = obj ? obj->id : (uint64_t) - 1; 42 name = NULL; 43 nameIsFinal = false; 44} 45 46void 47IndexObject::set_name (char * other_name) 48{ 49 if (name == NULL) 50 { 51 name = other_name; 52 nameIsFinal = true; 53 } 54} 55 56static uint64_t 57extractExpgrid (uint64_t id) 58{ 59 return (id >> IndexObject::INDXOBJ_EXPGRID_SHIFT) 60 & IndexObject::INDXOBJ_EXPGRID_MASK; 61} 62 63static uint64_t 64extractExpid (uint64_t id) 65{ 66 return (id >> IndexObject::INDXOBJ_EXPID_SHIFT) 67 & IndexObject::INDXOBJ_EXPID_MASK; 68} 69 70static uint64_t 71extractPayload (uint64_t id) 72{ 73 return (id >> IndexObject::INDXOBJ_PAYLOAD_SHIFT) 74 & IndexObject::INDXOBJ_PAYLOAD_MASK; 75} 76 77static void 78printCompareLabel (StringBuilder *sb, uint64_t grpId); 79 80static bool 81printThread (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id) 82{ 83 uint64_t proc = extractExpid (id); 84 uint64_t thrid = extractPayload (id); 85 bool isFinal = true; 86 bool hasJava = false; 87 bool javaThread = false; 88 if (ctx) 89 { 90 if (ctx->dview && ctx->dview->getProp (PROP_JTHREAD)) 91 { 92 hasJava = true; 93 uint64_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); 94 JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp); 95 if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT) 96 { 97 sbIn->appendf (GTXT ("Process %llu, Thread %llu, JThread %llu \'%s\', Group \'%s\', Parent \'%s\'"), 98 (unsigned long long) proc, 99 (unsigned long long) thrid, 100 (unsigned long long) jthread->jthr_id, 101 get_str(jthread->name, ""), 102 get_str(jthread->group_name, ""), 103 get_str(jthread->parent_name, "")); 104 javaThread = true; 105 } 106 } 107 } 108 if (!javaThread) 109 { 110 sbIn->appendf (GTXT ("Process %llu, Thread %llu"), 111 (unsigned long long) proc, (unsigned long long) thrid); 112 if (hasJava) 113 // sometimes threads start as native and later become Java; keep checking 114 isFinal = false; 115 } 116 if (ctx && ctx->dbev && ctx->dbev->comparingExperiments ()) 117 { 118 Vector <Histable *> *v = ctx->exp->get_comparable_objs (); 119 int st = 0; 120 for (long i = 0, sz = VecSize (v); i < sz; i++) 121 { 122 Experiment *exp = (Experiment *) v->get (i); 123 if (exp) 124 { 125 if (st == 0) 126 { 127 st = 1; 128 continue; 129 } 130 sbIn->appendf (GTXT (" [ Group %llu Process %llu ]"), 131 (unsigned long long) exp->groupId - 1, 132 (unsigned long long) exp->getUserExpId ()); 133 } 134 } 135 } 136 return isFinal; 137} 138 139static bool 140printProcess (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id) 141{ 142 uint64_t proc = id; 143 if (ctx && ctx->exp) 144 { 145 int st = 0; 146 if (ctx->dbev && ctx->dbev->comparingExperiments ()) 147 { 148 Vector <Histable *> *v = ctx->exp->get_comparable_objs (); 149 for (long i = 0, sz = VecSize (v); i < sz; i++) 150 { 151 Experiment *exp = (Experiment *) v->get (i); 152 if (exp) 153 { 154 if (st == 0) 155 { 156 st = 1; 157 sbIn->appendf (GTXT ("%s, Process %3llu, PID %llu"), 158 get_str (exp->utargname, GTXT ("(unknown)")), 159 (unsigned long long) proc, 160 (unsigned long long) exp->getPID ()); 161 continue; 162 } 163 sbIn->appendf (GTXT (" [ Group %llu, Process %llu, PID %llu ]"), 164 (unsigned long long) exp->groupId - 1, 165 (unsigned long long) exp->getUserExpId (), 166 (unsigned long long) exp->getPID ()); 167 } 168 } 169 } 170 if (st == 0) 171 sbIn->appendf (GTXT ("%s, Process %3llu, PID %llu"), 172 get_str (ctx->exp->utargname, GTXT ("(unknown)")), 173 (unsigned long long) proc, 174 (unsigned long long) ctx->exp->getPID ()); 175 } 176 else 177 sbIn->appendf (GTXT ("Process %3llu"), (unsigned long long) proc); 178 return true; //name is final 179} 180 181static bool 182printExperiment (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id) 183{ 184 uint64_t grpId = extractExpgrid (id); 185 uint64_t expid = extractExpid (id); 186 if (ctx && ctx->dbev->comparingExperiments ()) 187 printCompareLabel (sbIn, grpId); 188 if (ctx) 189 { 190 Experiment *hasFounder = ctx->exp->founder_exp; 191 int pid = ctx->exp->getPID (); 192 uint64_t founderExpid; 193 if (hasFounder) 194 founderExpid = hasFounder->getUserExpId (); 195 else 196 founderExpid = expid; 197 sbIn->appendf (GTXT ("Base Experiment %llu, Process %llu, PID %llu, %s"), 198 (unsigned long long) founderExpid, 199 (unsigned long long) expid, 200 (unsigned long long) pid, 201 get_str (ctx->exp->utargname, GTXT ("(unknown)"))); 202 } 203 else 204 sbIn->appendf (GTXT ("Process %llu"), (unsigned long long) expid); 205 return true; // name is final 206} 207 208void 209IndexObject::set_name_from_context (Expression::Context * ctx) 210{ 211 if (name != NULL) 212 if (nameIsFinal && strstr (name, GTXT ("(unknown)")) == NULL) 213 return; 214 if (ctx == NULL || ctx->dview == NULL || ctx->dbev == NULL) 215 return; 216 StringBuilder sb; 217 switch (indextype) 218 { 219 case INDEX_THREADS: 220 nameIsFinal = printThread (&sb, ctx, id); 221 break; 222 case INDEX_PROCESSES: 223 nameIsFinal = printProcess (&sb, ctx, id); 224 break; 225 case INDEX_EXPERIMENTS: 226 nameIsFinal = printExperiment (&sb, ctx, id); 227 break; 228 default: 229 name = NULL; 230 return; 231 } 232 if (sb.length ()) 233 name = sb.toString (); 234} 235 236static void 237printCompareLabel (StringBuilder *sbIn, uint64_t grpId) 238{ 239 static const char *labels[] = {"", GTXT ("Baseline"), GTXT ("Comparison")}; 240 static int length; 241 if (!length) 242 { 243 length = strlen (labels[1]); 244 int length2 = strlen (labels[2]); 245 if (length < length2) 246 length = length2; 247 length += 5; // for open/close brace and grpId number and spaces 248 } 249 char *s = NULL; 250 if (grpId != 0) 251 { 252 if (grpId <= 2) 253 s = dbe_sprintf ("[%s]", labels[grpId]); 254 else 255 s = dbe_sprintf ("[%s-%llu]", labels[2], 256 (unsigned long long) (grpId - 1)); 257 } 258 sbIn->appendf ("%-*s", length, get_str (s, "")); 259 free (s); 260} 261 262char * 263IndexObject::get_name (NameFormat fmt) 264{ 265 if (name == NULL) 266 { 267 StringBuilder sb; 268 int64_t upper; 269 int64_t num1; 270 int64_t num2; 271 switch (indextype) 272 { 273 case INDEX_THREADS: 274 printThread (&sb, NULL, id); 275 break; 276 277 case INDEX_CPUS: 278 sb.sprintf (GTXT ("CPU %llu"), (unsigned long long) id); 279 break; 280 281 case INDEX_SAMPLES: 282 sb.sprintf (GTXT ("Sample %llu"), (unsigned long long) id); 283 break; 284 285 case INDEX_GCEVENTS: 286 if (id == 0) 287 { 288 sb.sprintf (GTXT ("Not in any GCEvent")); 289 } 290 else 291 { 292 sb.sprintf (GTXT ("GCEvent %llu"), (unsigned long long) id); 293 } 294 break; 295 296 case INDEX_SECONDS: 297 sb.sprintf (GTXT ("Second of execution %llu"), (unsigned long long) id); 298 break; 299 300 case INDEX_PROCESSES: 301 printProcess (&sb, NULL, id); 302 break; 303 304 case INDEX_EXPERIMENTS: 305 printExperiment (&sb, NULL, id); 306 break; 307 case INDEX_BYTES: 308 upper = id; 309 if (id == -1) 310 { 311 break; 312 } 313 if (id % 2 == 1 && id > 1) 314 { 315 upper = id - 1; 316 if (upper >= 1099511627776) 317 { 318 num1 = upper / 1099511627776; 319 sb.sprintf (GTXT (">= %3llu TB"), (unsigned long long) num1); 320 } 321 else 322 { 323 // XXXX do nothing, this should not happen 324 } 325 } 326 else 327 { 328 if (upper >= 1099511627776) 329 { 330 num1 = upper / 1099511627776; 331 num2 = num1 / 4; 332 if (num2) 333 { 334 sb.sprintf (GTXT ("%3lluTB < n <= %3lluTB"), (unsigned long long) num2, (unsigned long long) num1); 335 } 336 else 337 { 338 sb.sprintf (GTXT ("256GB < n <= %3lluTB"), (unsigned long long) num1); 339 } 340 } 341 else if (upper >= 1073741824) 342 { 343 num1 = upper / 1073741824; 344 num2 = num1 / 4; 345 if (num2) 346 { 347 sb.sprintf (GTXT ("%3lluGB < n <= %3lluGB"), (unsigned long long) num2, (unsigned long long) num1); 348 } 349 else 350 { 351 sb.sprintf (GTXT ("256MB < n <= %3lluGB"), (unsigned long long) num1); 352 } 353 } 354 else if (upper >= 1048576) 355 { 356 num1 = upper / 1048576; 357 num2 = num1 / 4; 358 if (num2) 359 { 360 sb.sprintf (GTXT ("%3lluMB < n <= %3lluMB"), (unsigned long long) num2, (unsigned long long) num1); 361 } 362 else 363 { 364 sb.sprintf (GTXT ("256KB < n <= %3lluMB"), (unsigned long long) num1); 365 } 366 } 367 else if (upper >= 1024) 368 { 369 num1 = upper / 1024; 370 num2 = num1 / 4; 371 if (num2) 372 { 373 sb.sprintf (GTXT ("%3lluKB < n <= %3lluKB"), (unsigned long long) num2, (unsigned long long) num1); 374 } 375 else 376 { 377 sb.sprintf (GTXT (" 256 < n <= %3lluKB"), (unsigned long long) num1); 378 } 379 } 380 else if (upper > 0) 381 { 382 num1 = upper; 383 num2 = num1 / 4; 384 if (num1 == 1) 385 { 386 sb.sprintf (GTXT (" 1 Byte")); 387 } 388 else 389 { 390 sb.sprintf (GTXT ("%5llu < n <= %5llu Bytes"), (unsigned long long) num2, (unsigned long long) num1); 391 } 392 } 393 else if (upper == 0) 394 { 395 sb.sprintf (GTXT (" 0 Bytes")); 396 } 397 else 398 { 399 sb.sprintf (GTXT ("<No Data>")); 400 } 401 } 402 break; 403 case INDEX_DURATION: 404 if (id == -1) 405 { 406 break; 407 } 408 409 if (id > 10000000000000) 410 { 411 sb.sprintf (GTXT ("n > 10000s")); 412 } 413 else if (id > 1000000000000) 414 { 415 sb.sprintf (GTXT ("1000s < n <= 10000s")); 416 } 417 else if (id > 100000000000) 418 { 419 sb.sprintf (GTXT (" 100s < n <= 1000s")); 420 } 421 else if (id > 10000000000) 422 { 423 sb.sprintf (GTXT (" 10s < n <= 100s")); 424 } 425 else if (id > 1000000000) 426 { 427 sb.sprintf (GTXT (" 1s < n <= 10s")); 428 } 429 else if (id > 100000000) 430 { 431 sb.sprintf (GTXT ("100ms < n <= 1s")); 432 } 433 else if (id > 10000000) 434 { 435 sb.sprintf (GTXT (" 10ms < n <= 100ms")); 436 } 437 else if (id > 1000000) 438 { 439 sb.sprintf (GTXT (" 1ms < n <= 10ms")); 440 } 441 else if (id > 100000) 442 { 443 sb.sprintf (GTXT ("100us < n <= 1ms")); 444 } 445 else if (id > 10000) 446 { 447 sb.sprintf (GTXT (" 10us < n <= 100us")); 448 } 449 else if (id > 1000) 450 { 451 sb.sprintf (GTXT (" 1us < n <= 10us")); 452 } 453 else if (id > 0) 454 { 455 sb.sprintf (GTXT (" 0s < n <= 1us")); 456 } 457 else if (id == 0) 458 { 459 sb.sprintf (GTXT (" 0s")); 460 } 461 else 462 { 463 sb.sprintf (GTXT ("<No Data>")); 464 } 465 break; 466 467 // Custom index objects 468 default: 469 if (obj) 470 sb.sprintf (GTXT ("%s from %s"), 471 dbeSession->getIndexSpaceDescr (indextype), obj->get_name (fmt)); 472 else 473 { 474 IndexObjType_t *indexObj = dbeSession->getIndexSpace (indextype); 475 if (indexObj->memObj) 476 { 477 if (strcasecmp (indexObj->name, NTXT ("Memory_page_size")) == 0) 478 { 479 if (id == 0) 480 sb.append (GTXT ("<Unknown>")); 481 else 482 sb.sprintf (NTXT ("%s 0x%16.16llx (%llu)"), indexObj->name, 483 (unsigned long long) id, (unsigned long long) id); 484 } 485 else if (strcasecmp (indexObj->name, NTXT ("Memory_in_home_lgrp")) == 0) 486 { 487 if (id == 0 || id == 1) 488 sb.sprintf (NTXT ("%s: %s"), indexObj->name, 489 id == 1 ? GTXT ("True") : GTXT ("False")); 490 else 491 sb.sprintf (NTXT ("%s %s (0x%llx"), indexObj->name, 492 GTXT ("<Unknown>"), (unsigned long long) id); 493 } 494 else if (strcasecmp (indexObj->name, NTXT ("Memory_lgrp")) == 0) 495 { 496 if (id == 0) 497 sb.append (GTXT ("<Unknown>")); 498 else 499 sb.sprintf (NTXT ("%s %llu"), indexObj->name, (unsigned long long) id); 500 } 501 else 502 sb.sprintf (NTXT ("%s 0x%16.16llx"), indexObj->name, (unsigned long long) id); 503 } 504 else 505 sb.sprintf ("%s 0x%16.16llx (%llu)", indexObj->name, 506 (unsigned long long) id, (unsigned long long) id); 507 } 508 } 509 name = sb.toString (); 510 nameIsFinal = true; 511 } 512 return name; 513} 514 515bool 516IndexObject::requires_string_sort () 517{ 518 if (indextype == INDEX_PROCESSES || indextype >= INDEX_LAST) 519 return true; 520 return false; 521} 522 523Histable * 524IndexObject::convertto (Histable_type type, Histable *ext) 525{ 526 if (type == INDEXOBJ) 527 return this; 528 if (obj) 529 return obj->convertto (type, ext); 530 return NULL; 531} 532 533IndexObjType_t::IndexObjType_t () 534{ 535 type = 0; 536 name = NULL; 537 i18n_name = NULL; 538 index_expr_str = NULL; 539 index_expr = NULL; 540 mnemonic = 0; 541 short_description = NULL; 542 long_description = NULL; 543 memObj = NULL; 544} 545 546IndexObjType_t::~IndexObjType_t () 547{ 548 free (name); 549 free (i18n_name); 550 free (index_expr_str); 551 delete index_expr; 552 free (short_description); 553 free (long_description); 554} 555