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
IndexObject(int _indextype,uint64_t _index)28 IndexObject::IndexObject (int _indextype, uint64_t _index)
29 {
30 indextype = _indextype;
31 obj = NULL;
32 id = _index;
33 name = NULL;
34 nameIsFinal = false;
35 }
36
IndexObject(int _indextype,Histable * _obj)37 IndexObject::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
46 void
set_name(char * other_name)47 IndexObject::set_name (char * other_name)
48 {
49 if (name == NULL)
50 {
51 name = other_name;
52 nameIsFinal = true;
53 }
54 }
55
56 static uint64_t
extractExpgrid(uint64_t id)57 extractExpgrid (uint64_t id)
58 {
59 return (id >> IndexObject::INDXOBJ_EXPGRID_SHIFT)
60 & IndexObject::INDXOBJ_EXPGRID_MASK;
61 }
62
63 static uint64_t
extractExpid(uint64_t id)64 extractExpid (uint64_t id)
65 {
66 return (id >> IndexObject::INDXOBJ_EXPID_SHIFT)
67 & IndexObject::INDXOBJ_EXPID_MASK;
68 }
69
70 static uint64_t
extractPayload(uint64_t id)71 extractPayload (uint64_t id)
72 {
73 return (id >> IndexObject::INDXOBJ_PAYLOAD_SHIFT)
74 & IndexObject::INDXOBJ_PAYLOAD_MASK;
75 }
76
77 static void
78 printCompareLabel (StringBuilder *sb, uint64_t grpId);
79
80 static bool
printThread(StringBuilder * sbIn,Expression::Context * ctx,uint64_t id)81 printThread (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
139 static bool
printProcess(StringBuilder * sbIn,Expression::Context * ctx,uint64_t id)140 printProcess (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
181 static bool
printExperiment(StringBuilder * sbIn,Expression::Context * ctx,uint64_t id)182 printExperiment (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
208 void
set_name_from_context(Expression::Context * ctx)209 IndexObject::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
236 static void
printCompareLabel(StringBuilder * sbIn,uint64_t grpId)237 printCompareLabel (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
262 char *
get_name(NameFormat fmt)263 IndexObject::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
515 bool
requires_string_sort()516 IndexObject::requires_string_sort ()
517 {
518 if (indextype == INDEX_PROCESSES || indextype >= INDEX_LAST)
519 return true;
520 return false;
521 }
522
523 Histable *
convertto(Histable_type type,Histable * ext)524 IndexObject::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
IndexObjType_t()533 IndexObjType_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
~IndexObjType_t()546 IndexObjType_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