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