MemorySpace.cc revision 1.1.1.1
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 <ctype.h>
23
24#include "util.h"
25#include "DbeSession.h"
26#include "Application.h"
27#include "Experiment.h"
28#include "Exp_Layout.h"
29#include "MetricList.h"
30#include "MemObject.h"
31#include "PathTree.h"
32#include "DbeView.h"
33#include "Metric.h"
34#include "MemorySpace.h"
35#include "Table.h"
36#include "IndexObject.h"
37
38MemObjType_t::MemObjType_t ()
39{
40  type = -1;
41  name = NULL;
42  index_expr = NULL;
43  machmodel = NULL;
44  mnemonic = 0;
45  short_description = NULL;
46  long_description = NULL;
47}
48
49MemObjType_t::~MemObjType_t ()
50{
51  free (name);
52  free (index_expr);
53  free (machmodel);
54  free (short_description);
55  free (long_description);
56}
57
58MemorySpace::MemorySpace (DbeView *_dbev, int _mstype)
59{
60  char *mname;
61  dbev = _dbev;
62  phaseIdx = -1;
63
64  // set up the MemoryObject information
65  objs = new HashMap<uint64_t, MemObj*>;
66  mstype = _mstype;
67  msindex_exp = NULL;
68  msname = NULL;
69  msindex_exp_str = NULL;
70
71  // find the memory space in the table
72  MemObjType_t *mot = findMemSpaceByIndex (mstype);
73  if (mot)
74    {
75      msname = dbe_strdup (mot->name);
76      if (mot->index_expr != NULL)
77	{
78	  msindex_exp_str = dbe_strdup (mot->index_expr);
79	  msindex_exp = dbeSession->ql_parse (msindex_exp_str);
80	  if (msindex_exp == NULL)
81	    // this was checked when the definition was created
82	    abort ();
83	}
84    }
85
86  // create the Total and Unknown objects
87  mname = dbe_strdup (NTXT ("<Total>"));
88  total_memobj = createMemObject ((uint64_t) - 2, mname);
89  mname = dbe_strdup (GTXT ("<Unknown>"));
90  unk_memobj = createMemObject ((uint64_t) - 1, mname);
91  hist_data_all = NULL;
92  selected_mo_index = (uint64_t) - 3;
93  sel_ind = -1;
94}
95
96MemorySpace::~MemorySpace ()
97{
98  reset ();
99  delete objs;
100  free (msname);
101  free (msindex_exp);
102  free (msindex_exp_str);
103}
104
105void
106MemorySpace::reset ()
107{
108  if (hist_data_all != NULL)
109    {
110      delete hist_data_all;
111      hist_data_all = NULL;
112    }
113  // do not clear the selected object's index
114  // selected_mo_index = (uint64_t)-3;
115
116  // destroy any existing objects, but keep the vector
117  // Now that we have a hashmap, which has its own vector,
118  //     safe to delete and reallocate
119  delete objs;
120  objs = new HashMap<uint64_t, MemObj*>;
121}
122
123// find a memory object by its memory-object index
124int
125MemorySpace::findMemObject (uint64_t indx)
126{
127  int index;
128  Hist_data::HistItem *hi;
129  if (indx == (uint64_t) - 3)
130    return -1;
131
132  Vec_loop (Hist_data::HistItem *, hist_data_all->hist_items, index, hi)
133  {
134    if (((uint64_t) ((MemObj *) hi->obj)->id) == indx)
135      return index;
136  }
137  // object does not exist; filter change eliminated it, for example
138  return -1;
139}
140
141// find the object referenced in the packet
142MemObj *
143MemorySpace::lookupMemObject (Experiment *exp, DataView *packets, long i)
144{
145  uint64_t idx;
146  uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
147  if (va == ABS_UNSUPPORTED)
148    // return NULL, to ignore the record
149    return NULL;
150  if (va < ABS_CODE_RANGE)
151    // The va is not valid, rather, it's an error code
152    // return the <Unknown> object
153    return unk_memobj;
154
155  Expression::Context ctx (dbev, exp, packets, i);
156  idx = msindex_exp->eval (&ctx);
157  if (idx == (uint64_t) - 1)
158    return unk_memobj;
159
160  // do a binary search for the memory object
161  MemObj *res = objs->get (idx);
162  if (res == NULL)
163    {
164      res = createMemObject (idx, NULL);
165      objs->put (idx, res);
166    }
167  else
168    return res;
169
170  // recompute range
171  if (idx < idx_min)
172    idx_min = idx;
173  if (idx > idx_max)
174    idx_max = idx;
175  return res;
176}
177
178MemObj *
179MemorySpace::createMemObject (uint64_t index, char *moname)
180{
181  MemObj *res;
182  char *name;
183  if (moname != NULL)
184    {
185      res = new MemObj (index, moname);
186      return res;
187    }
188
189  // Custom memory objects
190  // The memory_page_size is defined in the machine model file such
191  // as ./machinemodels/t4.ermm.
192  // Most users prefer to look at the hexadecimal version of virtual
193  // addresses. Display only the hexadecimal version of virtual addresses
194  // for all machine model views with an exception of virtual page size.
195  if (dbe_strcmp (msname, NTXT ("Memory_page_size")) == 0)
196    name = dbe_sprintf (NTXT ("%s 0x%16.16llx (%llu)"), msname,
197			(long long) index, (unsigned long long) index);
198  else if (dbe_strcmp (msname, NTXT ("Memory_in_home_lgrp")) == 0)
199    name = dbe_sprintf (NTXT ("%s: %s"), msname,
200			index == 1 ? GTXT ("True") : index == 0 ? GTXT ("False")
201			: GTXT ("<Unknown>"));
202  else if (dbe_strcmp (msname, NTXT ("Memory_lgrp")) == 0)
203    name = dbe_sprintf (NTXT ("%s %llu"), msname, (unsigned long long) index);
204  else
205    name = dbe_sprintf (NTXT ("%s 0x%16.16llx"), msname, (long long) index);
206
207  res = new MemObj (index, name);
208  return res;
209}
210
211
212static Vector<MemObjType_t*> dyn_memobj_vec;
213static Vector<MemObjType_t*> *dyn_memobj = &dyn_memobj_vec;
214static Vector<int> *ordlist;
215
216// Static function to get a vector of custom memory object definitions
217
218Vector<void*> *
219MemorySpace::getMemObjects ()
220{
221  MemObjType_t *mot;
222  int ii;
223  int size = dyn_memobj->size ();
224  Vector<int> *indx = new Vector<int>(size);
225  Vector<char*> *name = new Vector<char*>(size);
226  Vector<char> *mnemonic = new Vector<char>(size);
227  Vector<char*> *formula = new Vector<char*>(size);
228  Vector<char*> *machmodel = new Vector<char*>(size);
229  Vector<int> *order = new Vector<int>(size);
230  Vector<char*> *sdesc = new Vector<char*>(size);
231  Vector<char*> *ldesc = new Vector<char*>(size);
232
233  if (size > 0)
234    {
235      Vec_loop (MemObjType_t *, dyn_memobj, ii, mot)
236      {
237	indx->store (ii, mot->type);
238	order->store (ii, ii);
239	name->store (ii, dbe_strdup (mot->name));
240	formula->store (ii, dbe_strdup (mot->index_expr));
241	mnemonic->store (ii, mot->mnemonic);
242	sdesc->store (ii, mot->short_description == NULL ? NULL
243		      : dbe_strdup (mot->short_description));
244	ldesc->store (ii, mot->long_description == NULL ? NULL
245		      : dbe_strdup (mot->long_description));
246	if (mot->machmodel == NULL)
247	  machmodel->store (ii, NULL);
248	else
249	  machmodel->store (ii, dbe_strdup (mot->machmodel));
250      }
251    }
252  Vector<void*> *res = new Vector<void*>(8);
253  res->store (0, indx);
254  res->store (1, name);
255  res->store (2, mnemonic);
256  res->store (3, formula);
257  res->store (4, machmodel);
258  res->store (5, order);
259  res->store (6, sdesc);
260  res->store (7, ldesc);
261  return (res);
262}
263
264// Static function to set order of memory object tabs
265void
266MemorySpace::set_MemTabOrder (Vector<int> *orders)
267{
268  int size = orders->size ();
269  ordlist = new Vector<int>(size);
270  for (int i = 0; i < size; i++)
271    ordlist->store (i, orders->fetch (i));
272}
273
274// Static function to define a new memory object type
275char *
276MemorySpace::mobj_define (char *mname, char *mindex_exp, char *_machmodel,
277			  char *short_description, char *long_description)
278{
279  MemObjType_t *mot;
280
281  if (mname == NULL)
282    return dbe_strdup (GTXT ("No memory object name has been specified."));
283  if (isalpha ((int) (mname[0])) == 0)
284    return dbe_sprintf (GTXT ("Memory Object type name %s does not begin with an alphabetic character"),
285			mname);
286  char *p = mname;
287  while (*p != 0)
288    {
289      if (isalnum ((int) (*p)) == 0 && *p != '_')
290	return dbe_sprintf (GTXT ("Memory Object type name %s contains a non-alphanumeric character"),
291			    mname);
292      p++;
293    }
294
295  mot = findMemSpaceByName (mname);
296  if (mot != NULL)
297    {
298      if (strcmp (mot->index_expr, mindex_exp) == 0)
299	// It's a redefinition, but the new definition is the same
300	return NULL;
301      return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
302			  mname);
303    }
304
305  // make sure the name is not in use
306  if (dbeSession->findIndexSpaceByName (mname) >= 0)
307    return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
308			mname);
309
310  if (mindex_exp == NULL || *mindex_exp == 0)
311    return dbe_strdup (GTXT ("No index-expr has been specified."));
312
313  // verify that the index expression parses correctly
314  Expression *e = dbeSession->ql_parse (mindex_exp);
315  if (e == NULL)
316    return dbe_sprintf (GTXT ("Memory Object index expression is invalid: %s"),
317			mindex_exp);
318  delete e;
319
320  // It's OK, create the new table entry
321  char *s = dbeSession->indxobj_define (mname, NULL, mindex_exp,
322					short_description, long_description);
323  if (s)
324    return s;
325  IndexObjType_t *indObj = dbeSession->findIndexSpace (mname);
326
327  mot = new MemObjType_t;
328  mot->type = indObj->type;
329  indObj->memObj = mot;
330  mot->name = dbe_strdup (mname);
331  mot->index_expr = dbe_strdup (mindex_exp);
332  mot->mnemonic = MemorySpace::pickMnemonic (mname);
333  mot->machmodel = dbe_strdup (_machmodel);
334  mot->short_description = dbe_strdup (short_description);
335  mot->long_description = dbe_strdup (long_description);
336
337  // add it to the list
338  dyn_memobj->append (mot);
339
340  // tell the session
341  if (dbeSession != NULL)
342    dbeSession->mobj_define (mot);
343  return NULL;
344}
345
346// Static function to delete a new memory object type
347
348char *
349MemorySpace::mobj_delete (char *mname)
350{
351  if (mname == NULL)
352    return dbe_strdup (GTXT ("No memory object name has been specified.\n"));
353
354  // search the dynamic types
355  for (long idx = 0, sz = VecSize (dyn_memobj); idx < sz; idx++)
356    {
357      MemObjType_t *mt = dyn_memobj->get (idx);
358      if (strcasecmp (mt->name, mname) == 0)
359	{
360	  // delete it from the vector
361	  mt = dyn_memobj->remove (idx);
362	  delete mt;
363	  dbeSession->removeIndexSpaceByName (mname);
364	  return NULL;
365	}
366    }
367  return dbe_sprintf (GTXT ("Memory object `%s' is not defined.\n"), mname);
368}
369
370// Static function to get a list of memory object names from a machine model
371
372Vector <char*> *
373MemorySpace::getMachineModelMemObjs (char *mname)
374{
375  Vector <char *> *ret = new Vector <char *> ();
376  if (mname == NULL)
377    return ret;
378
379  // search the memory objects
380  int idx;
381  MemObjType_t *mt;
382  Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
383  {
384    if (mt->machmodel != NULL && strcmp (mt->machmodel, mname) == 0)
385      {
386	char *n = dbe_strdup (mt->name);
387	ret->append (n);
388      }
389  }
390  return ret;
391}
392
393char
394MemorySpace::pickMnemonic (char *name)
395{
396  return name[0];
397}
398
399void
400MemorySpace::get_filter_keywords (Vector <void*> *res)
401{
402  Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
403  Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
404  Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
405  Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
406  Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
407  Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
408  Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
409
410  char *vtypeNames[] = VTYPE_TYPE_NAMES;
411  for (int i = 0, sz = dyn_memobj ? dyn_memobj->size () : 0; i < sz; i++)
412    {
413      MemObjType_t *obj = dyn_memobj->fetch (i);
414      kwCategory->append (dbe_strdup (NTXT ("FK_MEMOBJ")));
415      kwCategoryI18N->append (dbe_strdup (GTXT ("Memory Object Definitions")));
416      kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
417      kwKeyword->append (dbe_strdup (obj->name));
418      kwFormula->append (dbe_strdup (obj->index_expr));
419      kwDescription->append (NULL);
420      kwEnumDescs->append (NULL);
421    }
422}
423
424MemObjType_t *
425MemorySpace::findMemSpaceByName (const char *mname)
426{
427  int idx;
428  MemObjType_t *mt;
429
430  // search the dynamic types
431  Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
432  {
433    if (strcasecmp (mt->name, mname) == 0)
434      return mt;
435  }
436  return NULL;
437}
438
439MemObjType_t *
440MemorySpace::findMemSpaceByIndex (int index)
441{
442  int idx;
443  MemObjType_t *mt;
444
445  // search the dynamic types
446  Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
447  {
448    if (mt->type == index)
449      return mt;
450  }
451  return NULL;
452}
453