/* Copyright (C) 2021-2023 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "util.h" #include "DbeSession.h" #include "DbeView.h" #include "IndexObject.h" #include "StringBuilder.h" IndexObject::IndexObject (int _indextype, uint64_t _index) { indextype = _indextype; obj = NULL; id = _index; name = NULL; nameIsFinal = false; } IndexObject::IndexObject (int _indextype, Histable *_obj) { indextype = _indextype; obj = _obj; id = obj ? obj->id : (uint64_t) - 1; name = NULL; nameIsFinal = false; } void IndexObject::set_name (char * other_name) { if (name == NULL) { name = other_name; nameIsFinal = true; } } static uint64_t extractExpgrid (uint64_t id) { return (id >> IndexObject::INDXOBJ_EXPGRID_SHIFT) & IndexObject::INDXOBJ_EXPGRID_MASK; } static uint64_t extractExpid (uint64_t id) { return (id >> IndexObject::INDXOBJ_EXPID_SHIFT) & IndexObject::INDXOBJ_EXPID_MASK; } static uint64_t extractPayload (uint64_t id) { return (id >> IndexObject::INDXOBJ_PAYLOAD_SHIFT) & IndexObject::INDXOBJ_PAYLOAD_MASK; } static void printCompareLabel (StringBuilder *sb, uint64_t grpId); static bool printThread (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id) { uint64_t proc = extractExpid (id); uint64_t thrid = extractPayload (id); bool isFinal = true; bool hasJava = false; bool javaThread = false; if (ctx) { if (ctx->dview && ctx->dview->getProp (PROP_JTHREAD)) { hasJava = true; uint64_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp); if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT) { sbIn->appendf (GTXT ("Process %llu, Thread %llu, JThread %llu \'%s\', Group \'%s\', Parent \'%s\'"), (unsigned long long) proc, (unsigned long long) thrid, (unsigned long long) jthread->jthr_id, get_str(jthread->name, ""), get_str(jthread->group_name, ""), get_str(jthread->parent_name, "")); javaThread = true; } } } if (!javaThread) { sbIn->appendf (GTXT ("Process %llu, Thread %llu"), (unsigned long long) proc, (unsigned long long) thrid); if (hasJava) // sometimes threads start as native and later become Java; keep checking isFinal = false; } if (ctx && ctx->dbev && ctx->dbev->comparingExperiments ()) { Vector *v = ctx->exp->get_comparable_objs (); int st = 0; for (long i = 0, sz = VecSize (v); i < sz; i++) { Experiment *exp = (Experiment *) v->get (i); if (exp) { if (st == 0) { st = 1; continue; } sbIn->appendf (GTXT (" [ Group %llu Process %llu ]"), (unsigned long long) exp->groupId - 1, (unsigned long long) exp->getUserExpId ()); } } } return isFinal; } static bool printProcess (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id) { uint64_t proc = id; if (ctx && ctx->exp) { int st = 0; if (ctx->dbev && ctx->dbev->comparingExperiments ()) { Vector *v = ctx->exp->get_comparable_objs (); for (long i = 0, sz = VecSize (v); i < sz; i++) { Experiment *exp = (Experiment *) v->get (i); if (exp) { if (st == 0) { st = 1; sbIn->appendf (GTXT ("%s, Process %3llu, PID %llu"), get_str (exp->utargname, GTXT ("(unknown)")), (unsigned long long) proc, (unsigned long long) exp->getPID ()); continue; } sbIn->appendf (GTXT (" [ Group %llu, Process %llu, PID %llu ]"), (unsigned long long) exp->groupId - 1, (unsigned long long) exp->getUserExpId (), (unsigned long long) exp->getPID ()); } } } if (st == 0) sbIn->appendf (GTXT ("%s, Process %3llu, PID %llu"), get_str (ctx->exp->utargname, GTXT ("(unknown)")), (unsigned long long) proc, (unsigned long long) ctx->exp->getPID ()); } else sbIn->appendf (GTXT ("Process %3llu"), (unsigned long long) proc); return true; //name is final } static bool printExperiment (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id) { uint64_t grpId = extractExpgrid (id); uint64_t expid = extractExpid (id); if (ctx && ctx->dbev->comparingExperiments ()) printCompareLabel (sbIn, grpId); if (ctx) { Experiment *hasFounder = ctx->exp->founder_exp; int pid = ctx->exp->getPID (); uint64_t founderExpid; if (hasFounder) founderExpid = hasFounder->getUserExpId (); else founderExpid = expid; sbIn->appendf (GTXT ("Base Experiment %llu, Process %llu, PID %llu, %s"), (unsigned long long) founderExpid, (unsigned long long) expid, (unsigned long long) pid, get_str (ctx->exp->utargname, GTXT ("(unknown)"))); } else sbIn->appendf (GTXT ("Process %llu"), (unsigned long long) expid); return true; // name is final } void IndexObject::set_name_from_context (Expression::Context * ctx) { if (name != NULL) if (nameIsFinal && strstr (name, GTXT ("(unknown)")) == NULL) return; if (ctx == NULL || ctx->dview == NULL || ctx->dbev == NULL) return; StringBuilder sb; switch (indextype) { case INDEX_THREADS: nameIsFinal = printThread (&sb, ctx, id); break; case INDEX_PROCESSES: nameIsFinal = printProcess (&sb, ctx, id); break; case INDEX_EXPERIMENTS: nameIsFinal = printExperiment (&sb, ctx, id); break; default: name = NULL; return; } if (sb.length ()) name = sb.toString (); } static void printCompareLabel (StringBuilder *sbIn, uint64_t grpId) { static const char *labels[] = {"", GTXT ("Baseline"), GTXT ("Comparison")}; static int length; if (!length) { length = strlen (labels[1]); int length2 = strlen (labels[2]); if (length < length2) length = length2; length += 5; // for open/close brace and grpId number and spaces } char *s = NULL; if (grpId != 0) { if (grpId <= 2) s = dbe_sprintf ("[%s]", labels[grpId]); else s = dbe_sprintf ("[%s-%llu]", labels[2], (unsigned long long) (grpId - 1)); } sbIn->appendf ("%-*s", length, get_str (s, "")); free (s); } char * IndexObject::get_name (NameFormat fmt) { if (name == NULL) { StringBuilder sb; int64_t upper; int64_t num1; int64_t num2; switch (indextype) { case INDEX_THREADS: printThread (&sb, NULL, id); break; case INDEX_CPUS: sb.sprintf (GTXT ("CPU %llu"), (unsigned long long) id); break; case INDEX_SAMPLES: sb.sprintf (GTXT ("Sample %llu"), (unsigned long long) id); break; case INDEX_GCEVENTS: if (id == 0) { sb.sprintf (GTXT ("Not in any GCEvent")); } else { sb.sprintf (GTXT ("GCEvent %llu"), (unsigned long long) id); } break; case INDEX_SECONDS: sb.sprintf (GTXT ("Second of execution %llu"), (unsigned long long) id); break; case INDEX_PROCESSES: printProcess (&sb, NULL, id); break; case INDEX_EXPERIMENTS: printExperiment (&sb, NULL, id); break; case INDEX_BYTES: upper = id; if (id == -1) { break; } if (id % 2 == 1 && id > 1) { upper = id - 1; if (upper >= 1099511627776) { num1 = upper / 1099511627776; sb.sprintf (GTXT (">= %3llu TB"), (unsigned long long) num1); } else { // XXXX do nothing, this should not happen } } else { if (upper >= 1099511627776) { num1 = upper / 1099511627776; num2 = num1 / 4; if (num2) { sb.sprintf (GTXT ("%3lluTB < n <= %3lluTB"), (unsigned long long) num2, (unsigned long long) num1); } else { sb.sprintf (GTXT ("256GB < n <= %3lluTB"), (unsigned long long) num1); } } else if (upper >= 1073741824) { num1 = upper / 1073741824; num2 = num1 / 4; if (num2) { sb.sprintf (GTXT ("%3lluGB < n <= %3lluGB"), (unsigned long long) num2, (unsigned long long) num1); } else { sb.sprintf (GTXT ("256MB < n <= %3lluGB"), (unsigned long long) num1); } } else if (upper >= 1048576) { num1 = upper / 1048576; num2 = num1 / 4; if (num2) { sb.sprintf (GTXT ("%3lluMB < n <= %3lluMB"), (unsigned long long) num2, (unsigned long long) num1); } else { sb.sprintf (GTXT ("256KB < n <= %3lluMB"), (unsigned long long) num1); } } else if (upper >= 1024) { num1 = upper / 1024; num2 = num1 / 4; if (num2) { sb.sprintf (GTXT ("%3lluKB < n <= %3lluKB"), (unsigned long long) num2, (unsigned long long) num1); } else { sb.sprintf (GTXT (" 256 < n <= %3lluKB"), (unsigned long long) num1); } } else if (upper > 0) { num1 = upper; num2 = num1 / 4; if (num1 == 1) { sb.sprintf (GTXT (" 1 Byte")); } else { sb.sprintf (GTXT ("%5llu < n <= %5llu Bytes"), (unsigned long long) num2, (unsigned long long) num1); } } else if (upper == 0) { sb.sprintf (GTXT (" 0 Bytes")); } else { sb.sprintf (GTXT ("")); } } break; case INDEX_DURATION: if (id == -1) { break; } if (id > 10000000000000) { sb.sprintf (GTXT ("n > 10000s")); } else if (id > 1000000000000) { sb.sprintf (GTXT ("1000s < n <= 10000s")); } else if (id > 100000000000) { sb.sprintf (GTXT (" 100s < n <= 1000s")); } else if (id > 10000000000) { sb.sprintf (GTXT (" 10s < n <= 100s")); } else if (id > 1000000000) { sb.sprintf (GTXT (" 1s < n <= 10s")); } else if (id > 100000000) { sb.sprintf (GTXT ("100ms < n <= 1s")); } else if (id > 10000000) { sb.sprintf (GTXT (" 10ms < n <= 100ms")); } else if (id > 1000000) { sb.sprintf (GTXT (" 1ms < n <= 10ms")); } else if (id > 100000) { sb.sprintf (GTXT ("100us < n <= 1ms")); } else if (id > 10000) { sb.sprintf (GTXT (" 10us < n <= 100us")); } else if (id > 1000) { sb.sprintf (GTXT (" 1us < n <= 10us")); } else if (id > 0) { sb.sprintf (GTXT (" 0s < n <= 1us")); } else if (id == 0) { sb.sprintf (GTXT (" 0s")); } else { sb.sprintf (GTXT ("")); } break; // Custom index objects default: if (obj) sb.sprintf (GTXT ("%s from %s"), dbeSession->getIndexSpaceDescr (indextype), obj->get_name (fmt)); else { IndexObjType_t *indexObj = dbeSession->getIndexSpace (indextype); if (indexObj->memObj) { if (strcasecmp (indexObj->name, NTXT ("Memory_page_size")) == 0) { if (id == 0) sb.append (GTXT ("")); else sb.sprintf (NTXT ("%s 0x%16.16llx (%llu)"), indexObj->name, (unsigned long long) id, (unsigned long long) id); } else if (strcasecmp (indexObj->name, NTXT ("Memory_in_home_lgrp")) == 0) { if (id == 0 || id == 1) sb.sprintf (NTXT ("%s: %s"), indexObj->name, id == 1 ? GTXT ("True") : GTXT ("False")); else sb.sprintf (NTXT ("%s %s (0x%llx"), indexObj->name, GTXT (""), (unsigned long long) id); } else if (strcasecmp (indexObj->name, NTXT ("Memory_lgrp")) == 0) { if (id == 0) sb.append (GTXT ("")); else sb.sprintf (NTXT ("%s %llu"), indexObj->name, (unsigned long long) id); } else sb.sprintf (NTXT ("%s 0x%16.16llx"), indexObj->name, (unsigned long long) id); } else sb.sprintf ("%s 0x%16.16llx (%llu)", indexObj->name, (unsigned long long) id, (unsigned long long) id); } } name = sb.toString (); nameIsFinal = true; } return name; } bool IndexObject::requires_string_sort () { if (indextype == INDEX_PROCESSES || indextype >= INDEX_LAST) return true; return false; } Histable * IndexObject::convertto (Histable_type type, Histable *ext) { if (type == INDEXOBJ) return this; if (obj) return obj->convertto (type, ext); return NULL; } IndexObjType_t::IndexObjType_t () { type = 0; name = NULL; i18n_name = NULL; index_expr_str = NULL; index_expr = NULL; mnemonic = 0; short_description = NULL; long_description = NULL; memObj = NULL; } IndexObjType_t::~IndexObjType_t () { free (name); free (i18n_name); free (index_expr_str); delete index_expr; free (short_description); free (long_description); }