aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src
diff options
context:
space:
mode:
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>2022-03-11 08:58:31 +0000
committerNick Clifton <nickc@redhat.com>2022-03-11 08:58:31 +0000
commitbb368aad297fe3ad40cf397e6fc85aa471429a28 (patch)
tree0ab25909b8fe789d676bbdb00d501d4d485e4afe /gprofng/src
parenta655f19af95eb685ba64f48ee8fc2b3b7a3d886a (diff)
downloadgdb-bb368aad297fe3ad40cf397e6fc85aa471429a28.zip
gdb-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.gz
gdb-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.bz2
gprofng: a new GNU profiler
top-level * Makefile.def: Add gprofng module. * configure.ac: Add --enable-gprofng option. * src-release.sh: Add gprofng. * Makefile.in: Regenerate. * configure: Regenerate. * gprofng: New directory. binutils * MAINTAINERS: Add gprofng maintainer. * README-how-to-make-a-release: Add gprofng. include. * collectorAPI.h: New file. * libcollector.h: New file. * libfcollector.h: New file.
Diffstat (limited to 'gprofng/src')
-rw-r--r--gprofng/src/ABS.h62
-rw-r--r--gprofng/src/Application.cc259
-rw-r--r--gprofng/src/Application.h108
-rw-r--r--gprofng/src/ArchiveExp.cc149
-rw-r--r--gprofng/src/ArchiveExp.h41
-rw-r--r--gprofng/src/BaseMetric.cc975
-rw-r--r--gprofng/src/BaseMetric.h246
-rw-r--r--gprofng/src/BaseMetricTreeNode.cc329
-rw-r--r--gprofng/src/BaseMetricTreeNode.h100
-rw-r--r--gprofng/src/CacheMap.h186
-rw-r--r--gprofng/src/CallStack.cc1250
-rw-r--r--gprofng/src/CallStack.h114
-rw-r--r--gprofng/src/CatchOutOfMemory.cc59
-rw-r--r--gprofng/src/ClassFile.cc1639
-rw-r--r--gprofng/src/ClassFile.h63
-rw-r--r--gprofng/src/Command.cc562
-rw-r--r--gprofng/src/Command.h286
-rw-r--r--gprofng/src/CompCom.cc313
-rw-r--r--gprofng/src/CompCom.h63
-rw-r--r--gprofng/src/DataObject.cc193
-rw-r--r--gprofng/src/DataObject.h82
-rw-r--r--gprofng/src/DataSpace.cc558
-rw-r--r--gprofng/src/DataSpace.h55
-rw-r--r--gprofng/src/DataStream.cc55
-rw-r--r--gprofng/src/DataStream.h51
-rw-r--r--gprofng/src/Data_window.cc241
-rw-r--r--gprofng/src/Data_window.h99
-rw-r--r--gprofng/src/Dbe.cc10371
-rw-r--r--gprofng/src/Dbe.h294
-rw-r--r--gprofng/src/DbeApplication.cc113
-rw-r--r--gprofng/src/DbeApplication.h50
-rw-r--r--gprofng/src/DbeArray.h99
-rw-r--r--gprofng/src/DbeCacheMap.h109
-rw-r--r--gprofng/src/DbeFile.cc541
-rw-r--r--gprofng/src/DbeFile.h103
-rw-r--r--gprofng/src/DbeJarFile.cc505
-rw-r--r--gprofng/src/DbeJarFile.h46
-rw-r--r--gprofng/src/DbeLinkList.h73
-rw-r--r--gprofng/src/DbeLock.cc41
-rw-r--r--gprofng/src/DbeLock.h38
-rw-r--r--gprofng/src/DbeSession.cc3527
-rw-r--r--gprofng/src/DbeSession.cc.13531
-rw-r--r--gprofng/src/DbeSession.h481
-rw-r--r--gprofng/src/DbeSyncMap.h224
-rw-r--r--gprofng/src/DbeThread.cc224
-rw-r--r--gprofng/src/DbeThread.h61
-rw-r--r--gprofng/src/DbeView.cc3126
-rw-r--r--gprofng/src/DbeView.h842
-rw-r--r--gprofng/src/DefaultHandler.h114
-rw-r--r--gprofng/src/DefaultMap.h232
-rw-r--r--gprofng/src/DefaultMap2D.h147
-rw-r--r--gprofng/src/DerivedMetrics.cc293
-rw-r--r--gprofng/src/DerivedMetrics.h54
-rw-r--r--gprofng/src/Disasm.cc403
-rw-r--r--gprofng/src/Disasm.h66
-rw-r--r--gprofng/src/Dwarf.cc1041
-rw-r--r--gprofng/src/Dwarf.h87
-rw-r--r--gprofng/src/DwarfLib.cc2203
-rw-r--r--gprofng/src/DwarfLib.h313
-rw-r--r--gprofng/src/Elf.cc1138
-rw-r--r--gprofng/src/Elf.h170
-rw-r--r--gprofng/src/Emsg.cc614
-rw-r--r--gprofng/src/Emsg.h112
-rw-r--r--gprofng/src/Emsgnum.h135
-rw-r--r--gprofng/src/ExpGroup.cc163
-rw-r--r--gprofng/src/ExpGroup.h50
-rw-r--r--gprofng/src/Exp_Layout.cc422
-rw-r--r--gprofng/src/Exp_Layout.h158
-rw-r--r--gprofng/src/Experiment.cc6961
-rw-r--r--gprofng/src/Experiment.h689
-rw-r--r--gprofng/src/Expression.cc1279
-rw-r--r--gprofng/src/Expression.h180
-rw-r--r--gprofng/src/FileData.cc400
-rw-r--r--gprofng/src/FileData.h522
-rw-r--r--gprofng/src/Filter.cc514
-rw-r--r--gprofng/src/Filter.h111
-rw-r--r--gprofng/src/FilterExp.h56
-rw-r--r--gprofng/src/FilterSet.cc106
-rw-r--r--gprofng/src/FilterSet.h72
-rw-r--r--gprofng/src/Function.cc1160
-rw-r--r--gprofng/src/Function.h222
-rw-r--r--gprofng/src/HashMap.h435
-rw-r--r--gprofng/src/HeapActivity.cc408
-rw-r--r--gprofng/src/HeapActivity.h76
-rw-r--r--gprofng/src/HeapData.cc284
-rw-r--r--gprofng/src/HeapData.h450
-rw-r--r--gprofng/src/HeapMap.cc325
-rw-r--r--gprofng/src/HeapMap.h59
-rw-r--r--gprofng/src/Hist_data.cc1886
-rw-r--r--gprofng/src/Hist_data.h292
-rw-r--r--gprofng/src/Histable.h333
-rw-r--r--gprofng/src/IOActivity.cc825
-rw-r--r--gprofng/src/IOActivity.h86
-rw-r--r--gprofng/src/IndexMap2D.h119
-rw-r--r--gprofng/src/IndexObject.cc554
-rw-r--r--gprofng/src/IndexObject.h111
-rw-r--r--gprofng/src/IntervalMap.h194
-rw-r--r--gprofng/src/LoadObject.cc1242
-rw-r--r--gprofng/src/LoadObject.h210
-rw-r--r--gprofng/src/MachineModel.cc317
-rw-r--r--gprofng/src/Makefile.am202
-rw-r--r--gprofng/src/Makefile.in1171
-rw-r--r--gprofng/src/Map.h61
-rw-r--r--gprofng/src/Map2D.h53
-rw-r--r--gprofng/src/MemObject.cc44
-rw-r--r--gprofng/src/MemObject.h62
-rw-r--r--gprofng/src/MemorySpace.cc452
-rw-r--r--gprofng/src/MemorySpace.h113
-rw-r--r--gprofng/src/Metric.cc1660
-rw-r--r--gprofng/src/Metric.h188
-rw-r--r--gprofng/src/MetricList.cc1075
-rw-r--r--gprofng/src/MetricList.h163
-rw-r--r--gprofng/src/Module.cc1840
-rw-r--r--gprofng/src/Module.h284
-rw-r--r--gprofng/src/Ovw_data.cc242
-rw-r--r--gprofng/src/Ovw_data.h102
-rw-r--r--gprofng/src/PRBTree.cc480
-rw-r--r--gprofng/src/PRBTree.h106
-rw-r--r--gprofng/src/PathTree.cc2637
-rw-r--r--gprofng/src/PathTree.h405
-rw-r--r--gprofng/src/PreviewExp.cc113
-rw-r--r--gprofng/src/PreviewExp.h49
-rw-r--r--gprofng/src/Print.cc3485
-rw-r--r--gprofng/src/Print.h283
-rw-r--r--gprofng/src/QLParser.h61
-rw-r--r--gprofng/src/QLParser.tab.cc1453
-rw-r--r--gprofng/src/QLParser.tab.hh2038
-rw-r--r--gprofng/src/QLParser.yy390
-rw-r--r--gprofng/src/SAXParser.h49
-rw-r--r--gprofng/src/SAXParserFactory.cc666
-rw-r--r--gprofng/src/SAXParserFactory.h75
-rw-r--r--gprofng/src/Sample.cc94
-rw-r--r--gprofng/src/Sample.h80
-rw-r--r--gprofng/src/SegMem.h76
-rw-r--r--gprofng/src/Settings.cc1586
-rw-r--r--gprofng/src/Settings.h425
-rw-r--r--gprofng/src/SourceFile.cc229
-rw-r--r--gprofng/src/SourceFile.h117
-rw-r--r--gprofng/src/Stabs.cc2650
-rw-r--r--gprofng/src/Stabs.h160
-rw-r--r--gprofng/src/Stats_data.cc203
-rw-r--r--gprofng/src/Stats_data.h59
-rw-r--r--gprofng/src/StringBuilder.cc585
-rw-r--r--gprofng/src/StringBuilder.h101
-rw-r--r--gprofng/src/StringMap.h238
-rw-r--r--gprofng/src/Table.cc1687
-rw-r--r--gprofng/src/Table.h618
-rw-r--r--gprofng/src/UserLabel.cc177
-rw-r--r--gprofng/src/UserLabel.h61
-rw-r--r--gprofng/src/checks.cc516
-rw-r--r--gprofng/src/collctrl.cc3149
-rw-r--r--gprofng/src/collctrl.h405
-rw-r--r--gprofng/src/collect.h156
-rw-r--r--gprofng/src/collector_module.h223
-rw-r--r--gprofng/src/comp_com.c3481
-rw-r--r--gprofng/src/comp_com.h903
-rw-r--r--gprofng/src/count.cc237
-rw-r--r--gprofng/src/data_pckts.h595
-rw-r--r--gprofng/src/dbe_collctrl.cc28
-rw-r--r--gprofng/src/dbe_hwc.h38
-rw-r--r--gprofng/src/dbe_hwcdrv.c23
-rw-r--r--gprofng/src/dbe_hwcfuncs.c23
-rw-r--r--gprofng/src/dbe_hwctable.c23
-rw-r--r--gprofng/src/dbe_memmgr.c118
-rw-r--r--gprofng/src/dbe_structs.h219
-rw-r--r--gprofng/src/dbe_types.h62
-rw-r--r--gprofng/src/debug.h89
-rw-r--r--gprofng/src/enums.h195
-rw-r--r--gprofng/src/envsets.cc420
-rw-r--r--gprofng/src/gethrtime.c166
-rw-r--r--gprofng/src/gp-archive.cc700
-rw-r--r--gprofng/src/gp-archive.h64
-rw-r--r--gprofng/src/gp-collect-app.cc1598
-rw-r--r--gprofng/src/gp-display-src.cc752
-rw-r--r--gprofng/src/gp-display-text.cc2834
-rw-r--r--gprofng/src/gp-print.h118
-rw-r--r--gprofng/src/gprofng.cc301
-rw-r--r--gprofng/src/gprofng.h2m4
-rw-r--r--gprofng/src/gprofng.rc132
-rw-r--r--gprofng/src/i18n.cc30
-rw-r--r--gprofng/src/i18n.h40
-rw-r--r--gprofng/src/info.h73
-rw-r--r--gprofng/src/ipc.cc2829
-rw-r--r--gprofng/src/ipcio.cc1025
-rw-r--r--gprofng/src/ipcio.h176
-rw-r--r--gprofng/src/machinemodels/generic.ermm32
-rw-r--r--gprofng/src/machinemodels/m5.ermm65
-rw-r--r--gprofng/src/machinemodels/m6.ermm65
-rw-r--r--gprofng/src/machinemodels/m7.ermm64
-rw-r--r--gprofng/src/machinemodels/t4.ermm67
-rw-r--r--gprofng/src/machinemodels/t5.ermm65
-rw-r--r--gprofng/src/parse.cc927
-rw-r--r--gprofng/src/stab.h205
-rw-r--r--gprofng/src/util.cc1582
-rw-r--r--gprofng/src/util.h185
-rw-r--r--gprofng/src/vec.h524
196 files changed, 115604 insertions, 0 deletions
diff --git a/gprofng/src/ABS.h b/gprofng/src/ABS.h
new file mode 100644
index 0000000..a5bcbea
--- /dev/null
+++ b/gprofng/src/ABS.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _ABS_H
+#define _ABS_H
+
+/*
+ * Apropos Backtracking Scheme definitions.
+ * Class: com_sun_forte_st_mpmt_timeline_HWCEvent
+ */
+
+/* ABS failure codes */
+typedef enum
+{
+ ABS_NULL = 0x00, /* undefined/disabled/inactive */
+ ABS_UNSUPPORTED = 0x01, /* inappropriate HWC event type */
+ ABS_BLOCKED = 0x02, /* runtime backtrack blocker reached */
+ ABS_INCOMPLETE = 0x03, /* runtime backtrack limit reached */
+ ABS_REG_LOSS = 0x04, /* address register contaminated */
+ ABS_INVALID_EA = 0x05, /* invalid effective address value */
+ ABS_NO_CTI_INFO = 0x10, /* no AnalyzerInfo for validation */
+ ABS_INFO_FAILED = 0x20, /* info failed to validate backtrack */
+ ABS_CTI_TARGET = 0x30, /* CTI target invalidated backtrack */
+ ABS_CODE_RANGE = 0xFF /* reserved ABS code range in Vaddr */
+} ABS_code;
+
+enum {
+ NUM_ABS_RT_CODES = 7,
+ NUM_ABS_PP_CODES = 5
+};
+
+extern const char *ABS_RT_CODES[NUM_ABS_RT_CODES];
+extern char *ABS_PP_CODES[NUM_ABS_PP_CODES];
+
+/* libcollector will mark HWC overflow values that appear to be invalid */
+/* dbe should check HWC values for errors */
+#define HWCVAL_ERR_FLAG (1ULL<<63)
+#define HWCVAL_SET_ERR(ctr) ((ctr) | HWCVAL_ERR_FLAG)
+#define HWCVAL_HAS_ERR(ctr) ((ctr) & HWCVAL_ERR_FLAG ? 1 : 0)
+#define HWCVAL_CLR_ERR(ctr) ((ctr) & ~HWCVAL_ERR_FLAG)
+
+#define ABS_GET_RT_CODE(EA) ((EA) & 0x0FLL)
+#define ABS_GET_PP_CODE(EA) (((EA) & 0xF0LL) / 0xF)
+
+#endif /* _ABS_H */
diff --git a/gprofng/src/Application.cc b/gprofng/src/Application.cc
new file mode 100644
index 0000000..e28956c
--- /dev/null
+++ b/gprofng/src/Application.cc
@@ -0,0 +1,259 @@
+/* Copyright (C) 2021 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 <stdlib.h>
+#include <strings.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "Application.h"
+#include "Settings.h"
+#include "i18n.h"
+#include "util.h"
+
+Application::ProgressFunc Application::progress_func = NULL;
+Application *theApplication;
+
+Application::Application (int argc, char *argv[], char *fdhome)
+{
+ theApplication = this;
+ cur_dir = NULL;
+ prog_version = dbe_strdup (VERSION);
+ set_name (strchr (argv[0], '/') ? argv[0] : NULL);
+ whoami = get_basename (get_name ());
+
+ // set up a queue for comments
+ commentq = new Emsgqueue (NTXT ("app_commentq"));
+
+ // Locate where the binaries are installed
+ set_run_dir (fdhome);
+
+ // Initialize I18N
+ init_locale (run_dir);
+
+ // Initialize licensing data
+ lic_found = 0;
+ lic_err = NULL;
+
+ // Initialize worker threads
+ number_of_worker_threads = 1;
+#if DEBUG
+ char *use_worker_threads = getenv (NTXT ("SP_USE_WORKER_THREADS"));
+ if ((NULL != use_worker_threads) && (0 == strcasecmp (use_worker_threads, NTXT ("no"))))
+ {
+ number_of_worker_threads = 0;
+ }
+#endif /* DEBUG */
+ settings = new Settings (this);
+}
+
+Application::~Application ()
+{
+ delete commentq;
+ delete settings;
+ free (prog_version);
+ free (cur_dir);
+ free (prog_name);
+ free (run_dir);
+}
+
+// Set the name of the application (for messages)
+void
+Application::set_name (const char *_name)
+{
+ prog_name = get_realpath (_name);
+}
+
+char *
+Application::get_realpath (const char *_name)
+{
+ if (_name == NULL)
+ _name = "/proc/self/exe";
+ char *exe_name = realpath (_name, NULL);
+ if (exe_name)
+ return exe_name;
+ if (strchr (_name, '/') == NULL)
+ {
+ char *path = getenv ("PATH");
+ if (path)
+ for (char *s = path;; s++)
+ if (*s == ':' || *s == 0)
+ {
+ if (path != s)
+ {
+ char *nm = dbe_sprintf (NTXT ("%.*s/%s"), (int) (path - s - 1), path, _name);
+ exe_name = realpath (nm, NULL);
+ free (nm);
+ if (exe_name)
+ return exe_name;
+ }
+ if (*s == 0)
+ break;
+ path = s + 1;
+ }
+ }
+ return strdup (_name);
+}
+
+// Set the directory where all binaries are found
+void
+Application::set_run_dir (char *fdhome)
+{
+ run_dir_with_spaces = NULL;
+ if (fdhome)
+ {
+ char *path = dbe_sprintf ("%s/bin", fdhome);
+ struct stat sbuf;
+ if (stat (path, &sbuf) != -1)
+ run_dir = path;
+ else
+ {
+ free (path);
+ run_dir = dbe_strdup (fdhome);
+ }
+ }
+ else
+ {
+ run_dir = realpath (prog_name, NULL);
+ if (run_dir == NULL)
+ {
+ fprintf (stderr, // I18N won't work here -- not catopen yet.
+ GTXT ("Can't find location of %s\n"), prog_name);
+ run_dir = dbe_strdup (get_cur_dir ());
+ }
+ else
+ {
+ char *d = strrchr (run_dir, '/');
+ if (d)
+ *d = 0;
+ // Check if the installation path contains spaces
+ if (strchr (run_dir, ' ') != NULL)
+ {
+ // Create a symbolic link without spaces
+ const char *dir = NTXT ("/tmp/.gprofngLinks");
+ char *symbolic_link = dbe_create_symlink_to_path (run_dir, dir);
+ if (NULL != symbolic_link)
+ {
+ // Save old path to avoid memory leak
+ run_dir_with_spaces = run_dir;
+ // Use the path through symbolic link
+ run_dir = symbolic_link;
+ }
+ }
+ }
+ }
+}
+
+char *
+Application::get_cur_dir ()
+{
+ if (cur_dir == NULL)
+ {
+ char cwd[MAXPATHLEN];
+ if (getcwd (cwd, sizeof (cwd)) == NULL)
+ {
+ perror (prog_name);
+ exit (1);
+ }
+ cur_dir = dbe_strdup (canonical_path (cwd));
+ }
+ return cur_dir;
+}
+
+/**
+ * Get number of worker threads
+ * This is used to decide if it is ok to use worker threads for stat()
+ * and other actions that can hang for a long time
+ * @return number_of_worker_threads
+ */
+int
+Application::get_number_of_worker_threads ()
+{
+ return number_of_worker_threads;
+}
+
+int
+Application::check_args (int argc, char *argv[])
+{
+ int opt;
+ // Parsing the command line
+ opterr = 0;
+ while ((opt = getopt (argc, argv, "V")) != EOF)
+ switch (opt)
+ {
+ case 'V':
+// Ruud
+ Application::print_version_info ();
+/*
+ printf (NTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
+*/
+ exit (0);
+ default:
+ usage ();
+ }
+ return optind;
+}
+
+Emsg *
+Application::fetch_comments ()
+{
+ if (commentq == NULL)
+ return NULL;
+ return commentq->fetch ();
+}
+
+void
+Application::queue_comment (Emsg *m)
+{
+ commentq->append (m);
+}
+
+void
+Application::delete_comments ()
+{
+ if (commentq != NULL)
+ {
+ delete commentq;
+ commentq = new Emsgqueue (NTXT ("app_commentq"));
+ }
+}
+
+int
+Application::set_progress (int percentage, const char *proc_str)
+{
+ if (progress_func != NULL)
+ return progress_func (percentage, proc_str);
+ return 0;
+}
+
+// Ruud
+void
+Application::print_version_info ()
+{
+ printf ( GTXT (
+ "GNU %s binutils version %s\n"
+ "Copyright (C) 2021 Free Software Foundation, Inc.\n"
+ "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n"),
+ get_basename (prog_name), VERSION);
+}
diff --git a/gprofng/src/Application.h b/gprofng/src/Application.h
new file mode 100644
index 0000000..404383b
--- /dev/null
+++ b/gprofng/src/Application.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * The Application class is the base class for all C++ executables
+ * in the Performance Tools Suite
+ *
+ * It determines the directory from which the running binary came,
+ * sets up the I18N catalog, the program name, and initializes
+ * an instance of the Settings class to manage all user preferences
+ * and settings. It also manages usage tracking.
+ *
+ * Applications which read experiments are derived from a subclass
+ * named DbeApplication (q.v.)
+ */
+
+#ifndef _APPLICATION_H
+#define _APPLICATION_H
+
+#include "dbe_types.h"
+
+class Settings;
+class Emsg;
+class Emsgqueue;
+
+// Application object
+class Application
+{
+public:
+ Application (int argc, char *argv[], char *_run_dir = NULL);
+ virtual ~Application ();
+ void set_name (const char *_name);
+ char *get_cur_dir ();
+
+ // Control the settings of a progress bar, used for GUI applications
+ // this function also detects cancel requests and returns 1
+ // if yes, 0 otherwise
+ static int set_progress (int percentage, const char *proc_str);
+ static char *get_realpath (const char *_name);
+
+ // queue for messages (from reading er.rc files, ...)
+ void queue_comment (Emsg *m); // queue for messages
+ Emsg *fetch_comments (void); // fetch the queue of comment messages
+ void delete_comments (void); // delete the queue of comment messages
+
+ // worker threads (currently used in dbe_stat() for stat() calls)
+ int get_number_of_worker_threads ();
+
+ char *get_version () { return prog_version; }
+ char *get_name () { return prog_name; }
+ char *get_run_dir () { return run_dir; }
+ Emsgqueue *get_comments_queue () { return commentq; };
+
+protected: // methods
+ void set_run_dir (char *fdhome = NULL);
+ typedef int (*ProgressFunc)(int, const char *);
+
+ // Write a usage message; to be defined in derived class
+ virtual void usage () = 0;
+
+// Ruud
+ // Write a version message; to be defined in derived class
+ void print_version_info ();
+
+ // Can be overridden in derived class
+ virtual int check_args (int argc, char *argv[]);
+
+ void read_rc ();
+ static void set_progress_func (ProgressFunc func) { progress_func = func; }
+
+protected:
+ Emsgqueue *commentq;
+ Settings *settings;
+ char *prog_version;
+ char *prog_name;
+ char *whoami;
+ char *run_dir;
+ char *run_dir_with_spaces; // used in case there are spaces
+ char *cur_dir;
+ int lic_found;
+ char *lic_err;
+
+private:
+ void set_ut_email (int argc, char *argv[]);
+ int number_of_worker_threads;
+ static ProgressFunc progress_func;
+};
+
+extern Application *theApplication;
+
+#endif /* _APPLICATION_H */
diff --git a/gprofng/src/ArchiveExp.cc b/gprofng/src/ArchiveExp.cc
new file mode 100644
index 0000000..e7ebfa9
--- /dev/null
+++ b/gprofng/src/ArchiveExp.cc
@@ -0,0 +1,149 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "LoadObject.h"
+#include "ArchiveExp.h"
+#include "DbeFile.h"
+#include "CallStack.h"
+#include "gp-archive.h"
+#include "Function.h"
+#include "Module.h"
+
+ArchiveExp::ArchiveExp (char *path) : Experiment ()
+{
+ force_flag = false;
+ copyso_flag = false;
+ use_fndr_archives = true;
+ status = find_expdir (path);
+ if (status == SUCCESS)
+ read_log_file ();
+}
+
+ArchiveExp::~ArchiveExp () { }
+
+void
+ArchiveExp::read_data (int s_option)
+{
+ read_archives ();
+ read_map_file ();
+ if (read_java_classes_file () == SUCCESS)
+ {
+ for (int i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+ {
+ LoadObject *lo = loadObjs->get (i);
+ Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d loadObjs[%d]=%-25s %s\n"),
+ get_basename (__FILE__), (int) __LINE__, i,
+ STR (lo->get_name ()), STR (lo->get_pathname ()));
+ if ((lo->dbeFile->filetype & DbeFile::F_JAVACLASS) == 0)
+ continue;
+ lo->isUsed = true;
+ if ((s_option & ARCH_EXE_ONLY) != 0)
+ continue;
+ lo->sync_read_stabs ();
+ }
+ }
+ if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0)
+ {
+ read_frameinfo_file ();
+ resolveFrameInfo = true;
+ Vector<DataDescriptor*> *ddscr = getDataDescriptors ();
+ delete ddscr; // getDataDescriptors() forces reading of experiment data
+ CallStack *callStack = callTree ();
+ if (callStack)
+ {
+ if (DEBUG_ARCHIVE)
+ {
+ Dprintf (DEBUG_ARCHIVE, NTXT ("stacks=%p\n"), callStack);
+ callStack->print (NULL);
+ }
+ for (int n = 0;; n++)
+ {
+ CallStackNode *node = callStack->get_node (n);
+ if (node == NULL)
+ break;
+ do
+ {
+ Histable *h = node->get_instr ();
+ Histable::Type t = h->get_type ();
+ if (t == Histable::INSTR)
+ {
+ DbeInstr *dbeInstr = (DbeInstr *) h;
+ if (!dbeInstr->isUsed)
+ {
+ Function *func = (Function *) dbeInstr->convertto (Histable::FUNCTION);
+ if (!func->isUsed)
+ {
+ func->isUsed = true;
+ func->module->isUsed = true;
+ func->module->loadobject->isUsed = true;
+ }
+ DbeLine *dbeLine = (DbeLine *) dbeInstr->convertto (Histable::LINE);
+ if (dbeLine)
+ dbeLine->sourceFile->isUsed = true;
+ }
+ }
+ else if (t == Histable::LINE)
+ {
+ DbeLine * dbeLine = (DbeLine *) h;
+ dbeLine->sourceFile->isUsed = true;
+ }
+ node = node->ancestor;
+ }
+ while (node);
+ }
+ }
+ }
+}
+
+char *
+ArchiveExp::createLinkToFndrArchive (LoadObject *lo, int /* hide_msg */)
+{
+ // For example, archives of libc.so will be:
+ // <exp>/archives/<libc.so_check_sum>
+ // <exp>/M_r0.er/archives/libc.so_<hash> -> ../../archives/<libc.so_check_sum>
+ if (!create_dir (get_fndr_arch_name ()))
+ {
+ fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), get_fndr_arch_name ());
+ return NULL;
+ }
+ uint32_t checksum = lo->get_checksum ();
+ char *linkName = dbe_sprintf (NTXT ("../../%s/%u"), SP_ARCHIVES_DIR, checksum);
+ char *nm = lo->get_pathname ();
+ char *symLinkName = getNameInArchive (nm, false);
+ if (symlink (linkName, symLinkName) != 0)
+ {
+ fprintf (stderr, GTXT ("Unable to create link `%s' -> `%s'\n"),
+ symLinkName, linkName);
+ free (linkName);
+ free (symLinkName);
+ return NULL;
+ }
+ free (linkName);
+ free (symLinkName);
+
+ // Return a full path inside founder archive:
+ return dbe_sprintf (NTXT ("%s/%u"), get_fndr_arch_name (), checksum);
+}
diff --git a/gprofng/src/ArchiveExp.h b/gprofng/src/ArchiveExp.h
new file mode 100644
index 0000000..809ed58
--- /dev/null
+++ b/gprofng/src/ArchiveExp.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _ARCHIVE_EXP_H
+#define _ARCHIVE_EXP_H
+
+#include "Experiment.h"
+class LoadObject;
+
+class ArchiveExp : public Experiment
+{
+public:
+ ArchiveExp (char *path);
+ ~ArchiveExp ();
+ char *createLinkToFndrArchive (LoadObject *lo, int hide_msg);
+ void read_data (int s_option);
+
+private:
+ bool force_flag;
+ bool copyso_flag;
+ bool use_fndr_archives;
+};
+
+#endif /* _ARCHIVE_EXP_H */
diff --git a/gprofng/src/BaseMetric.cc b/gprofng/src/BaseMetric.cc
new file mode 100644
index 0000000..bb51ddf
--- /dev/null
+++ b/gprofng/src/BaseMetric.cc
@@ -0,0 +1,975 @@
+/* Copyright (C) 2021 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 <strings.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "BaseMetric.h"
+#include "DbeSession.h"
+#include "Expression.h"
+
+int BaseMetric::last_id = 0;
+
+void
+BaseMetric::init (Type t)
+{
+ id = last_id++;
+ type = t;
+ aux = NULL;
+ cmd = NULL;
+ username = NULL;
+ hw_ctr = NULL;
+ cond = NULL;
+ val = NULL;
+ expr = NULL;
+ cond_spec = NULL;
+ val_spec = NULL;
+ expr_spec = NULL;
+ legend = NULL;
+ definition = NULL;
+ dependent_bm = NULL;
+ zeroThreshold = 0;
+ clock_unit = (Presentation_clock_unit) 0;
+ for (int ii = 0; ii < NSUBTYPES; ii++)
+ default_visbits[ii] = VAL_NA;
+ valtype = VT_DOUBLE;
+ precision = METRIC_HR_PRECISION;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = VAL_TIMEVAL | VAL_PERCENT;
+}
+
+BaseMetric::BaseMetric (Type t)
+{
+ init (t);
+ switch (t)
+ {
+ case CP_LMS_USER:
+ case CP_LMS_SYSTEM:
+ case CP_LMS_WAIT_CPU:
+ case CP_LMS_USER_LOCK:
+ case CP_LMS_TFAULT:
+ case CP_LMS_DFAULT:
+ case OMP_MASTER_THREAD:
+ case CP_TOTAL:
+ case CP_TOTAL_CPU:
+ case CP_LMS_TRAP:
+ case CP_LMS_KFAULT:
+ case CP_LMS_SLEEP:
+ case CP_LMS_STOPPED:
+ case OMP_NONE:
+ case OMP_OVHD:
+ case OMP_WORK:
+ case OMP_IBAR:
+ case OMP_EBAR:
+ case OMP_WAIT:
+ case OMP_SERL:
+ case OMP_RDUC:
+ case OMP_LKWT:
+ case OMP_CTWT:
+ case OMP_ODWT:
+ case OMP_MSTR:
+ case OMP_SNGL:
+ case OMP_ORDD:
+ case CP_KERNEL_CPU:
+ // all of these are floating point, precision = clock profile tick
+ valtype = VT_DOUBLE;
+ precision = METRIC_SIG_PRECISION;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = VAL_TIMEVAL | VAL_PERCENT;
+ break;
+ case SYNC_WAIT_TIME:
+ case IO_READ_TIME:
+ case IO_WRITE_TIME:
+ case IO_OTHER_TIME:
+ case IO_ERROR_TIME:
+ // all of these are floating point, precision = hrtime tick
+ valtype = VT_DOUBLE;
+ precision = METRIC_HR_PRECISION;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = VAL_TIMEVAL | VAL_PERCENT;
+ break;
+ case SYNC_WAIT_COUNT:
+ case HEAP_ALLOC_CNT:
+ case HEAP_LEAK_CNT:
+ case IO_READ_CNT:
+ case IO_WRITE_CNT:
+ case IO_OTHER_CNT:
+ case IO_ERROR_CNT:
+ valtype = VT_LLONG;
+ precision = 1;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = VAL_VALUE | VAL_PERCENT;
+ break;
+ case RACCESS:
+ case DEADLOCKS:
+ // all of these are integer
+ valtype = VT_LLONG;
+ precision = 1;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = VAL_VALUE | VAL_PERCENT;
+ zeroThreshold = 1;
+ break;
+ case HEAP_ALLOC_BYTES:
+ case HEAP_LEAK_BYTES:
+ case IO_READ_BYTES:
+ case IO_WRITE_BYTES:
+ // all of these are longlong
+ valtype = VT_ULLONG;
+ precision = 1;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = VAL_VALUE | VAL_PERCENT;
+ break;
+ case SIZES:
+ valtype = VT_LLONG;
+ precision = 1;
+ flavors = STATIC;
+ value_styles = VAL_VALUE;
+ break;
+ case ADDRESS:
+ valtype = VT_ADDRESS;
+ precision = 1;
+ flavors = STATIC;
+ value_styles = VAL_VALUE;
+ break;
+ case ONAME:
+ valtype = VT_LABEL;
+ precision = 0;
+ flavors = STATIC;
+ value_styles = VAL_VALUE;
+ break;
+ case HWCNTR: // We should call the other constructor for hwc metric
+ default:
+ abort ();
+ }
+ specify ();
+}
+
+// Constructor for linked HW counters (base counter)
+BaseMetric::BaseMetric (Hwcentry *ctr, const char* _aux, const char* _username,
+ int v_styles, BaseMetric* _dependent_bm)
+{
+ hwc_init (ctr, _aux, _aux, _username, v_styles);
+ dependent_bm = _dependent_bm;
+}
+
+// Constructor for linked HW counters (derived counter)
+
+BaseMetric::BaseMetric (Hwcentry *ctr, const char *_aux, const char *_cmdname,
+ const char *_username, int v_styles)
+{
+ hwc_init (ctr, _aux, _cmdname, _username, v_styles);
+}
+
+void
+BaseMetric::hwc_init (Hwcentry *ctr, const char* _aux, const char* _cmdname,
+ const char* _username, int v_styles)
+{
+ init (HWCNTR);
+ aux = dbe_strdup (_aux); // HWC identifier
+ cmd = dbe_strdup (_cmdname); // may differ from _aux for cycles->time hwcs
+ username = dbe_strdup (_username);
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ value_styles = v_styles | VAL_PERCENT;
+ if ((value_styles & (VAL_TIMEVAL | VAL_VALUE)) == VAL_TIMEVAL)
+ valtype = VT_DOUBLE;
+ else
+ valtype = VT_ULLONG;
+ if (ABST_MEMSPACE_ENABLED (ctr->memop))
+ flavors |= DATASPACE; // only for ctrs with memop definitions
+ hw_ctr = ctr;
+ specify ();
+}
+
+// Constructor for derived metrics
+BaseMetric::BaseMetric (const char *_cmd, const char *_username,
+ Definition *def)
+{
+ init (DERIVED);
+ cmd = dbe_strdup (_cmd);
+ username = dbe_strdup (_username);
+ aux = dbe_strdup (_cmd);
+ definition = def;
+ flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+ clock_unit = CUNIT_NULL; // should it be CUNIT_TIME or 0 or something?
+
+ /* we're not going to process packets for derived metrics */
+ packet_type = (ProfData_type) (-1);
+ value_styles = VAL_VALUE;
+ valtype = VT_DOUBLE;
+ precision = 1000;
+}
+
+// Copy constructor
+BaseMetric::BaseMetric (const BaseMetric& m)
+{
+ id = m.id;
+ type = m.type;
+ aux = dbe_strdup (m.aux);
+ cmd = dbe_strdup (m.cmd);
+ username = dbe_strdup (m.username);
+ flavors = m.flavors;
+ value_styles = m.value_styles;
+ valtype = m.valtype;
+ precision = m.precision;
+ hw_ctr = m.hw_ctr;
+ packet_type = m.packet_type;
+ zeroThreshold = m.zeroThreshold;
+ clock_unit = m.clock_unit;
+ for (int ii = 0; ii < NSUBTYPES; ii++)
+ default_visbits[ii] = m.default_visbits[ii];
+ if (m.cond_spec)
+ {
+ cond_spec = strdup (m.cond_spec);
+ cond = m.cond->copy ();
+ }
+ else
+ {
+ cond = NULL;
+ cond_spec = NULL;
+ }
+ if (m.val_spec)
+ {
+ val_spec = strdup (m.val_spec);
+ val = m.val->copy ();
+ }
+ else
+ {
+ val = NULL;
+ val_spec = NULL;
+ }
+ if (m.expr_spec)
+ {
+ expr_spec = strdup (m.expr_spec);
+ expr = m.expr->copy ();
+ }
+ else
+ {
+ expr = NULL;
+ expr_spec = NULL;
+ }
+ legend = dbe_strdup (m.legend);
+ definition = NULL;
+ if (m.definition)
+ definition = Definition::add_definition (m.definition->def);
+ dependent_bm = m.dependent_bm;
+}
+
+BaseMetric::~BaseMetric ()
+{
+ free (aux);
+ free (cmd);
+ free (cond_spec);
+ free (val_spec);
+ free (expr_spec);
+ free (legend);
+ free (username);
+ delete cond;
+ delete val;
+ delete expr;
+ delete definition;
+}
+
+bool
+BaseMetric::is_internal ()
+{
+ return (get_value_styles () & VAL_INTERNAL) != 0;
+}
+
+int
+BaseMetric::get_default_visbits (SubType subtype)
+{
+ int rc = VAL_NA;
+ switch (subtype)
+ {
+ case STATIC:
+ case EXCLUSIVE:
+ rc = default_visbits[0];
+ break;
+ case INCLUSIVE:
+ rc = default_visbits[1];
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+void
+BaseMetric::set_default_visbits (SubType subtype, int _visbits)
+{
+ switch (subtype)
+ {
+ case STATIC:
+ case EXCLUSIVE:
+ default_visbits[0] = _visbits;
+ break;
+ case INCLUSIVE:
+ default_visbits[1] = _visbits;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+BaseMetric::set_cond_spec (char *_cond_spec)
+{
+ if (cond_spec)
+ {
+ free (cond_spec);
+ delete cond;
+ cond_spec = NULL;
+ cond = NULL;
+ }
+ if (_cond_spec)
+ {
+ cond = dbeSession->ql_parse (_cond_spec);
+ if (cond == NULL)
+ {
+ fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _cond_spec);
+ abort ();
+ }
+ cond_spec = dbe_strdup (_cond_spec);
+ }
+}
+
+void
+BaseMetric::set_val_spec (char *_val_spec)
+{
+ if (val_spec)
+ {
+ free (val_spec);
+ delete val;
+ val_spec = NULL;
+ val = NULL;
+ }
+ if (_val_spec)
+ {
+ val = dbeSession->ql_parse (_val_spec);
+ if (val == NULL)
+ {
+ fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _val_spec);
+ abort ();
+ }
+ val_spec = dbe_strdup (_val_spec);
+ }
+}
+
+void
+BaseMetric::set_expr_spec (char *_expr_spec)
+{
+ id = last_id++;
+ if (expr_spec)
+ {
+ free (expr_spec);
+ delete expr;
+ expr_spec = NULL;
+ expr = NULL;
+ }
+ if (_expr_spec)
+ {
+ expr = dbeSession->ql_parse (_expr_spec);
+ if (expr == NULL)
+ {
+ fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _expr_spec);
+ return;
+ }
+ expr_spec = dbe_strdup (_expr_spec);
+ }
+}
+
+void
+BaseMetric::specify_mstate_metric (int st)
+{
+ char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("MSTATE==%d"), st);
+ specify_prof_metric (buf);
+}
+
+void
+BaseMetric::specify_ompstate_metric (int st)
+{
+ char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("OMPSTATE==%d"), st);
+ specify_prof_metric (buf);
+}
+
+void
+BaseMetric::specify_prof_metric (char *_cond_spec)
+{
+ packet_type = DATA_CLOCK;
+ specify_metric (_cond_spec, NTXT ("NTICK_USEC")); // microseconds
+}
+
+void
+BaseMetric::specify_metric (char *_cond_spec, char *_val_spec)
+{
+ set_cond_spec (_cond_spec);
+ set_val_spec (_val_spec);
+}
+
+void
+BaseMetric::specify ()
+{
+ enum
+ {
+ IDLE_STATE_BITS =
+ (1 << OMP_IDLE_STATE) | (1 << OMP_IBAR_STATE) | (1 << OMP_EBAR_STATE) |
+ (1 << OMP_LKWT_STATE) | (1 << OMP_CTWT_STATE) | (1 << OMP_ODWT_STATE) |
+ (1 << OMP_ATWT_STATE) | (1 << OMP_TSKWT_STATE),
+ LMS_USER_BITS =
+ (1 << OMP_NO_STATE) | (1 << OMP_WORK_STATE) | (1 << OMP_SERL_STATE) |
+ (1 << OMP_RDUC_STATE)
+ };
+
+ char buf[256];
+ char buf2[256];
+ packet_type = (ProfData_type) - 1; // illegal value
+ clock_unit = CUNIT_TIME;
+ switch (type)
+ {
+ case SIZES:
+ username = dbe_strdup (GTXT ("Size"));
+ clock_unit = CUNIT_BYTES;
+ cmd = dbe_strdup (NTXT ("size"));
+ break;
+ case ADDRESS:
+ username = dbe_strdup (GTXT ("PC Address"));
+ cmd = dbe_strdup (NTXT ("address"));
+ break;
+ case ONAME:
+ username = dbe_strdup (GTXT ("Name"));
+ cmd = dbe_strdup (NTXT ("name"));
+ break;
+ case CP_LMS_SYSTEM:
+ username = dbe_strdup (GTXT ("System CPU Time"));
+ specify_mstate_metric (LMS_SYSTEM);
+ cmd = dbe_strdup (NTXT ("system"));
+ break;
+ case CP_TOTAL_CPU:
+ username = dbe_strdup (GTXT ("Total CPU Time"));
+ snprintf (buf, sizeof (buf),
+ "(MSTATE==%d)||(MSTATE==%d)||(MSTATE==%d)||(MSTATE==%d)",
+ LMS_USER, LMS_SYSTEM, LMS_TRAP, LMS_LINUX_CPU);
+ specify_prof_metric (buf);
+ cmd = dbe_strdup (NTXT ("totalcpu"));
+ break;
+ case CP_TOTAL:
+ username = dbe_strdup (GTXT ("Total Thread Time"));
+ snprintf (buf, sizeof (buf), NTXT ("(MSTATE!=%d)&&(MSTATE!=%d)"),
+ LMS_KERNEL_CPU, LMS_LINUX_CPU);
+ specify_prof_metric (buf);
+ cmd = dbe_strdup (NTXT ("total"));
+ break;
+ case CP_KERNEL_CPU:
+ username = dbe_strdup (GTXT ("Kernel CPU Time"));
+ specify_mstate_metric (LMS_KERNEL_CPU);
+ cmd = dbe_strdup (NTXT ("kcpu"));
+ break;
+ case OMP_MASTER_THREAD:
+ username = dbe_strdup (GTXT ("Master Thread Time"));
+ specify_prof_metric (NTXT ("LWPID==1"));
+ cmd = dbe_strdup (NTXT ("masterthread"));
+ break;
+ case CP_LMS_USER:
+ username = dbe_strdup (GTXT ("User CPU Time"));
+ specify_mstate_metric (LMS_USER);
+ cmd = dbe_strdup (NTXT ("user"));
+ break;
+ case CP_LMS_WAIT_CPU:
+ username = dbe_strdup (GTXT ("Wait CPU Time"));
+ specify_mstate_metric (LMS_WAIT_CPU);
+ cmd = dbe_strdup (NTXT ("wait"));
+ break;
+ case CP_LMS_USER_LOCK:
+ username = dbe_strdup (GTXT ("User Lock Time"));
+ specify_mstate_metric (LMS_USER_LOCK);
+ cmd = dbe_strdup (NTXT ("lock"));
+ break;
+ case CP_LMS_TFAULT:
+ username = dbe_strdup (GTXT ("Text Page Fault Time"));
+ specify_mstate_metric (LMS_TFAULT);
+ cmd = dbe_strdup (NTXT ("textpfault"));
+ break;
+ case CP_LMS_DFAULT:
+ username = dbe_strdup (GTXT ("Data Page Fault Time"));
+ specify_mstate_metric (LMS_DFAULT);
+ cmd = dbe_strdup (NTXT ("datapfault"));
+ break;
+ case CP_LMS_TRAP:
+ username = dbe_strdup (GTXT ("Trap CPU Time"));
+ specify_mstate_metric (LMS_TRAP);
+ cmd = dbe_strdup (NTXT ("trap"));
+ break;
+ case CP_LMS_KFAULT:
+ username = dbe_strdup (GTXT ("Kernel Page Fault Time"));
+ specify_mstate_metric (LMS_KFAULT);
+ cmd = dbe_strdup (NTXT ("kernelpfault"));
+ break;
+ case CP_LMS_SLEEP:
+ username = dbe_strdup (GTXT ("Sleep Time"));
+ specify_mstate_metric (LMS_SLEEP);
+ cmd = dbe_strdup (NTXT ("sleep"));
+ break;
+ case CP_LMS_STOPPED:
+ username = dbe_strdup (GTXT ("Stopped Time"));
+ specify_mstate_metric (LMS_STOPPED);
+ cmd = dbe_strdup (NTXT ("stop"));
+ break;
+ case OMP_OVHD:
+ username = dbe_strdup (GTXT ("OpenMP Overhead Time"));
+ specify_ompstate_metric (OMP_OVHD_STATE);
+ cmd = dbe_strdup (NTXT ("ompovhd"));
+ break;
+ case OMP_WORK:
+ username = dbe_strdup (GTXT ("OpenMP Work Time"));
+ snprintf (buf, sizeof (buf),
+ NTXT ("(OMPSTATE>=0) && (MSTATE==%d) && ((1<<OMPSTATE) & %d)"),
+ LMS_USER, LMS_USER_BITS);
+ specify_prof_metric (buf);
+ cmd = dbe_strdup (NTXT ("ompwork"));
+ break;
+ case OMP_WAIT:
+ username = dbe_strdup (GTXT ("OpenMP Wait Time"));
+ snprintf (buf, sizeof (buf),
+ "OMPSTATE>=0 && ((1<<OMPSTATE) & ((MSTATE!=%d) ? %d : %d))",
+ LMS_USER, (LMS_USER_BITS | IDLE_STATE_BITS), IDLE_STATE_BITS);
+ specify_prof_metric (buf);
+ cmd = dbe_strdup (NTXT ("ompwait"));
+ break;
+ case OMP_IBAR:
+ username = dbe_strdup (GTXT ("OpenMP Implicit Barrier Time"));
+ specify_ompstate_metric (OMP_IBAR_STATE);
+ cmd = dbe_strdup (NTXT ("ompibar"));
+ break;
+ case OMP_EBAR:
+ username = dbe_strdup (GTXT ("OpenMP Explicit Barrier Time"));
+ specify_ompstate_metric (OMP_EBAR_STATE);
+ cmd = dbe_strdup (NTXT ("ompebar"));
+ break;
+ case OMP_SERL:
+ username = dbe_strdup (GTXT ("OpenMP Serial Time"));
+ specify_ompstate_metric (OMP_SERL_STATE);
+ cmd = dbe_strdup (NTXT ("ompserl"));
+ break;
+ case OMP_RDUC:
+ username = dbe_strdup (GTXT ("OpenMP Reduction Time"));
+ specify_ompstate_metric (OMP_RDUC_STATE);
+ cmd = dbe_strdup (NTXT ("omprduc"));
+ break;
+ case OMP_LKWT:
+ username = dbe_strdup (GTXT ("OpenMP Lock Wait Time"));
+ specify_ompstate_metric (OMP_LKWT_STATE);
+ cmd = dbe_strdup (NTXT ("omplkwt"));
+ break;
+ case OMP_CTWT:
+ username = dbe_strdup (GTXT ("OpenMP Critical Section Wait Time"));
+ specify_ompstate_metric (OMP_CTWT_STATE);
+ cmd = dbe_strdup (NTXT ("ompctwt"));
+ break;
+ case OMP_ODWT:
+ username = dbe_strdup (GTXT ("OpenMP Ordered Section Wait Time"));
+ specify_ompstate_metric (OMP_ODWT_STATE);
+ cmd = dbe_strdup (NTXT ("ompodwt"));
+ break;
+ case SYNC_WAIT_TIME:
+ packet_type = DATA_SYNCH;
+ username = dbe_strdup (GTXT ("Sync Wait Time"));
+ snprintf (buf, sizeof (buf), NTXT ("(EVT_TIME)/%lld"),
+ (long long) (NANOSEC / METRIC_HR_PRECISION));
+ specify_metric (NULL, buf);
+ cmd = dbe_strdup (NTXT ("sync"));
+ break;
+ case SYNC_WAIT_COUNT:
+ packet_type = DATA_SYNCH;
+ username = dbe_strdup (GTXT ("Sync Wait Count"));
+ specify_metric (NULL, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("syncn"));
+ break;
+ case HEAP_ALLOC_CNT:
+ packet_type = DATA_HEAP;
+ username = dbe_strdup (GTXT ("Allocations"));
+ snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
+ FREE_TRACE, MUNMAP_TRACE);
+ specify_metric (buf, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("heapalloccnt"));
+ break;
+ case HEAP_ALLOC_BYTES:
+ packet_type = DATA_HEAP;
+ username = dbe_strdup (GTXT ("Bytes Allocated"));
+ snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
+ FREE_TRACE, MUNMAP_TRACE);
+ specify_metric (buf, NTXT ("HSIZE"));
+ cmd = dbe_strdup (NTXT ("heapallocbytes"));
+ break;
+ case HEAP_LEAK_CNT:
+ packet_type = DATA_HEAP;
+ username = dbe_strdup (GTXT ("Leaks"));
+ snprintf (buf, sizeof (buf), "(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR&&HLEAKED",
+ FREE_TRACE, MUNMAP_TRACE);
+ specify_metric (buf, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("heapleakcnt"));
+ break;
+ case HEAP_LEAK_BYTES:
+ packet_type = DATA_HEAP;
+ username = dbe_strdup (GTXT ("Bytes Leaked"));
+ snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
+ FREE_TRACE, MUNMAP_TRACE);
+ specify_metric (buf, NTXT ("HLEAKED"));
+ cmd = dbe_strdup (NTXT ("heapleakbytes"));
+ break;
+
+ case IO_READ_CNT:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Read Count"));
+ snprintf (buf, sizeof (buf), "(IOTYPE==%d)", READ_TRACE);
+ specify_metric (buf, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("ioreadcnt"));
+ break;
+ case IO_WRITE_CNT:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Write Count"));
+ snprintf (buf, sizeof (buf), "(IOTYPE==%d)", WRITE_TRACE);
+ specify_metric (buf, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("iowritecnt"));
+ break;
+ case IO_OTHER_CNT:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Other I/O Count"));
+ snprintf (buf, sizeof (buf), "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)",
+ OPEN_TRACE, CLOSE_TRACE, OTHERIO_TRACE);
+ specify_metric (buf, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("ioothercnt"));
+ break;
+ case IO_ERROR_CNT:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("I/O Error Count"));
+ snprintf (buf, sizeof (buf),
+ "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)",
+ READ_TRACE_ERROR, WRITE_TRACE_ERROR, OPEN_TRACE_ERROR,
+ CLOSE_TRACE_ERROR, OTHERIO_TRACE_ERROR);
+ specify_metric (buf, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("ioerrorcnt"));
+ break;
+ case IO_READ_BYTES:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Read Bytes"));
+ snprintf (buf, sizeof (buf), NTXT ("(IOTYPE==%d)&&IONBYTE"),
+ READ_TRACE);
+ specify_metric (buf, NTXT ("IONBYTE"));
+ cmd = dbe_strdup (NTXT ("ioreadbytes"));
+ break;
+ case IO_WRITE_BYTES:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Write Bytes"));
+ snprintf (buf, sizeof (buf), "(IOTYPE==%d)&&IONBYTE", WRITE_TRACE);
+ specify_metric (buf, NTXT ("IONBYTE"));
+ cmd = dbe_strdup (NTXT ("iowritebytes"));
+ break;
+ case IO_READ_TIME:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Read Time"));
+ snprintf (buf, sizeof (buf), "(IOTYPE==%d)&&EVT_TIME", READ_TRACE);
+ snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+ (long long) (NANOSEC / METRIC_HR_PRECISION));
+ specify_metric (buf, buf2);
+ cmd = dbe_strdup (NTXT ("ioreadtime"));
+ break;
+ case IO_WRITE_TIME:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Write Time"));
+ snprintf (buf, sizeof (buf), NTXT ("(IOTYPE==%d)&&EVT_TIME"),
+ WRITE_TRACE);
+ snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+ (long long) (NANOSEC / METRIC_HR_PRECISION));
+ specify_metric (buf, buf2);
+ cmd = dbe_strdup (NTXT ("iowritetime"));
+ break;
+ case IO_OTHER_TIME:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("Other I/O Time"));
+ snprintf (buf, sizeof (buf),
+ "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)&&EVT_TIME",
+ OPEN_TRACE, CLOSE_TRACE, OTHERIO_TRACE);
+ snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+ (long long) (NANOSEC / METRIC_HR_PRECISION));
+ specify_metric (buf, buf2);
+ cmd = dbe_strdup (NTXT ("ioothertime"));
+ break;
+ case IO_ERROR_TIME:
+ packet_type = DATA_IOTRACE;
+ username = dbe_strdup (GTXT ("I/O Error Time"));
+ snprintf (buf, sizeof (buf),
+ "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)&&EVT_TIME",
+ READ_TRACE_ERROR, WRITE_TRACE_ERROR, OPEN_TRACE_ERROR,
+ CLOSE_TRACE_ERROR, OTHERIO_TRACE_ERROR);
+ snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+ (long long) (NANOSEC / METRIC_HR_PRECISION));
+ specify_metric (buf, buf2);
+ cmd = dbe_strdup (NTXT ("ioerrortime"));
+ break;
+ case RACCESS:
+ packet_type = DATA_RACE;
+ username = dbe_strdup (GTXT ("Race Accesses"));
+ specify_metric (NULL, NTXT ("RCNT"));
+ cmd = dbe_strdup (NTXT ("raccess"));
+ break;
+ case DEADLOCKS:
+ packet_type = DATA_DLCK;
+ username = dbe_strdup (GTXT ("Deadlocks"));
+ specify_metric (NULL, NTXT ("1"));
+ cmd = dbe_strdup (NTXT ("deadlocks"));
+ break;
+ case HWCNTR:
+ packet_type = DATA_HWC;
+ // username, cmd, and aux set by hwc constructor
+ if (valtype == VT_DOUBLE)
+ {
+ if (hw_ctr->timecvt > 0) // CPU cycles
+ specify_metric (NULL, NTXT ("((HWCINT*1000000)/FREQ_MHZ)"));
+ else if (hw_ctr->timecvt < 0)
+ { // reference clock (frequency is -timecvt MHz)
+ snprintf (buf, sizeof (buf), NTXT ("((HWCINT*1000000)/%d)"), -hw_ctr->timecvt);
+ specify_metric (NULL, buf);
+ }
+ else // shouldn't happen
+ specify_metric (NULL, NTXT ("0"));
+ // resulting unit: seconds * 1e12
+ precision = 1000000LL * 1000000LL; // Seconds * 1e12
+ }
+ else
+ {
+ specify_metric (NULL, NTXT ("HWCINT"));
+ precision = 1;
+ }
+ break;
+ case OMP_MSTR:
+ case OMP_SNGL:
+ case OMP_ORDD:
+ case OMP_NONE:
+ default:
+ username = dbe_strdup (GTXT ("****"));
+ fprintf (stderr, "BaseMetric::init Undefined basemetric %s\n",
+ get_basetype_name ());
+ }
+}
+
+#define CASE_S(x) case x: s = (char *) #x; break
+char *
+BaseMetric::get_basetype_name ()
+{
+ static char buf[128];
+ char *s;
+ switch (type)
+ {
+ CASE_S (CP_LMS_SYSTEM);
+ CASE_S (CP_TOTAL_CPU);
+ CASE_S (CP_TOTAL);
+ CASE_S (OMP_MASTER_THREAD);
+ CASE_S (CP_LMS_USER);
+ CASE_S (CP_LMS_WAIT_CPU);
+ CASE_S (CP_LMS_USER_LOCK);
+ CASE_S (CP_LMS_TFAULT);
+ CASE_S (CP_LMS_DFAULT);
+ CASE_S (CP_LMS_TRAP);
+ CASE_S (CP_LMS_KFAULT);
+ CASE_S (CP_LMS_SLEEP);
+ CASE_S (CP_LMS_STOPPED);
+ CASE_S (OMP_NONE);
+ CASE_S (OMP_OVHD);
+ CASE_S (OMP_WORK);
+ CASE_S (OMP_IBAR);
+ CASE_S (OMP_EBAR);
+ CASE_S (OMP_WAIT);
+ CASE_S (OMP_SERL);
+ CASE_S (OMP_RDUC);
+ CASE_S (OMP_LKWT);
+ CASE_S (OMP_CTWT);
+ CASE_S (OMP_ODWT);
+ CASE_S (OMP_MSTR);
+ CASE_S (OMP_SNGL);
+ CASE_S (OMP_ORDD);
+ CASE_S (CP_KERNEL_CPU);
+ CASE_S (SYNC_WAIT_TIME);
+ CASE_S (IO_READ_TIME);
+ CASE_S (IO_WRITE_TIME);
+ CASE_S (IO_OTHER_TIME);
+ CASE_S (IO_ERROR_TIME);
+ CASE_S (HWCNTR);
+ CASE_S (SYNC_WAIT_COUNT);
+ CASE_S (HEAP_ALLOC_CNT);
+ CASE_S (HEAP_LEAK_CNT);
+ CASE_S (IO_READ_CNT);
+ CASE_S (IO_WRITE_CNT);
+ CASE_S (IO_OTHER_CNT);
+ CASE_S (IO_ERROR_CNT);
+ CASE_S (RACCESS);
+ CASE_S (DEADLOCKS);
+ CASE_S (HEAP_ALLOC_BYTES);
+ CASE_S (HEAP_LEAK_BYTES);
+ CASE_S (IO_READ_BYTES);
+ CASE_S (IO_WRITE_BYTES);
+ CASE_S (SIZES);
+ CASE_S (ADDRESS);
+ CASE_S (ONAME);
+ CASE_S (DERIVED);
+ default:
+ s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, type);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+char *
+BaseMetric::dump ()
+{
+ int len = 4;
+ char *msg = dbe_sprintf (NTXT ("id=%d %s aux='%s' cmd='%s' user_name='%s' expr_spec='%s'\n"
+ "%*c cond_spec='%s' val_spec='%s'"),
+ id, get_basetype_name (), STR (aux), STR (cmd),
+ STR (username), STR (expr_spec),
+ len, ' ', STR (cond_spec), STR (val_spec));
+ return msg;
+}
+
+Histable *
+BaseMetric::get_comparable_obj (Histable *obj)
+{
+ if (obj == NULL || expr == NULL)
+ return obj;
+ if (strncmp (expr_spec, NTXT ("EXPGRID=="), 9) == 0)
+ {
+ int n = atoi (expr_spec + 9);
+ Vector<Histable *> *cmpObjs = obj->get_comparable_objs ();
+ if (cmpObjs && cmpObjs->size () >= n)
+ return cmpObjs->get (n - 1);
+ return NULL;
+ }
+ return obj;
+}
+
+Definition::Definition (opType _op)
+{
+ op = _op;
+ bm = NULL;
+ arg1 = NULL;
+ arg2 = NULL;
+ def = NULL;
+ dependencies = NULL;
+ map = NULL;
+ index = 0;
+}
+
+Definition::~Definition ()
+{
+ delete arg1;
+ delete arg2;
+ delete dependencies;
+ delete[] map;
+}
+
+Vector<BaseMetric *> *
+Definition::get_dependencies ()
+{
+ if (dependencies == NULL)
+ {
+ if (arg1 && arg1->bm && arg2 && arg2->bm)
+ {
+ dependencies = new Vector<BaseMetric *>(2);
+ arg1->index = dependencies->size ();
+ dependencies->append (arg1->bm);
+ arg2->index = dependencies->size ();
+ dependencies->append (arg2->bm);
+ map = new long[2];
+ }
+ }
+ return dependencies;
+}
+
+long *
+Definition::get_map ()
+{
+ get_dependencies ();
+ return map;
+}
+
+Definition *
+Definition::add_definition (char *_def)
+{
+ // parse the definition
+ char *op_ptr = strchr (_def, '/');
+ if (op_ptr == NULL)
+ {
+ // it's a primitive metric
+ BaseMetric *bm = dbeSession->find_base_reg_metric (_def);
+ if (bm)
+ {
+ Definition *p = new Definition (opPrimitive);
+ p->bm = bm;
+ return p;
+ }
+ return NULL; // BaseMetric is not yet specified
+ }
+ Definition *p2 = add_definition (op_ptr + 1);
+ if (p2 == NULL)
+ return NULL;
+ _def = dbe_strdup (_def);
+ op_ptr = strchr (_def, '/');
+ *op_ptr = 0;
+ Definition *p1 = add_definition (_def);
+ if (p1)
+ {
+ *op_ptr = '/';
+ Definition *p = new Definition (opDivide);
+ p->arg1 = p1;
+ p->arg2 = p2;
+ p->def = _def;
+ return p;
+ }
+ free (_def);
+ delete p1;
+ delete p2;
+ return NULL;
+}
+
+double
+Definition::eval (long *indexes, TValue *values)
+{
+ switch (op)
+ {
+ case opPrimitive:
+ return values[indexes[index]].to_double ();
+ case opDivide:
+ {
+ double x2 = arg2->eval (indexes, values);
+ if (x2 == 0)
+ return 0.;
+ double x1 = arg1->eval (indexes, values);
+ return x1 / x2;
+ }
+ default:
+ fprintf (stderr, GTXT ("unknown expression\n"));
+ return 0.;
+ }
+}
diff --git a/gprofng/src/BaseMetric.h b/gprofng/src/BaseMetric.h
new file mode 100644
index 0000000..e056993
--- /dev/null
+++ b/gprofng/src/BaseMetric.h
@@ -0,0 +1,246 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _BASEMETRIC_H
+#define _BASEMETRIC_H
+
+#include "dbe_structs.h"
+#include "hwcentry.h"
+#include "Table.h"
+
+// METRIC_*_PRECISION determine the least threshold value
+// for time measured metrics. Any event that counts for less
+// than 1sec/METRIC_PRECISION is discarded.
+#define METRIC_SIG_PRECISION MICROSEC
+#define METRIC_HR_PRECISION MICROSEC
+
+class Expression;
+class Definition;
+class Histable;
+template <class ITEM> class Vector;
+
+class BaseMetric
+{
+public:
+ // sync enum changes with AnMetric.java
+ enum Type
+ { // Subtype==STATIC metrics:
+ ONAME = 1, //ONAME must be 1
+ SIZES,
+ ADDRESS,
+ // Clock Profiling, Derived Metrics:
+ CP_TOTAL,
+ CP_TOTAL_CPU,
+ // Clock profiling, Solaris Microstates (LMS_* defines)
+ CP_LMS_USER,
+ CP_LMS_SYSTEM,
+ CP_LMS_TRAP,
+ CP_LMS_TFAULT,
+ CP_LMS_DFAULT,
+ CP_LMS_KFAULT,
+ CP_LMS_USER_LOCK,
+ CP_LMS_SLEEP,
+ CP_LMS_WAIT_CPU,
+ CP_LMS_STOPPED,
+ // Kernel clock profiling
+ CP_KERNEL_CPU,
+ // Sync Tracing
+ SYNC_WAIT_TIME,
+ SYNC_WAIT_COUNT,
+ // HWC
+ HWCNTR,
+ // Heap Tracing:
+ HEAP_ALLOC_CNT,
+ HEAP_ALLOC_BYTES,
+ HEAP_LEAK_CNT,
+ HEAP_LEAK_BYTES,
+ // I/O Tracing:
+ IO_READ_BYTES,
+ IO_READ_CNT,
+ IO_READ_TIME,
+ IO_WRITE_BYTES,
+ IO_WRITE_CNT,
+ IO_WRITE_TIME,
+ IO_OTHER_CNT,
+ IO_OTHER_TIME,
+ IO_ERROR_CNT,
+ IO_ERROR_TIME,
+ // MPI Tracing:
+ MPI_TIME,
+ MPI_SEND,
+ MPI_BYTES_SENT,
+ MPI_RCV,
+ MPI_BYTES_RCVD,
+ MPI_OTHER,
+ // OMP states:
+ OMP_NONE,
+ OMP_OVHD,
+ OMP_WORK,
+ OMP_IBAR,
+ OMP_EBAR,
+ OMP_WAIT,
+ OMP_SERL,
+ OMP_RDUC,
+ OMP_LKWT,
+ OMP_CTWT,
+ OMP_ODWT,
+ OMP_MSTR,
+ OMP_SNGL,
+ OMP_ORDD,
+ OMP_MASTER_THREAD,
+ // MPI states:
+ MPI_WORK,
+ MPI_WAIT,
+ // Races and Deadlocks
+ RACCESS,
+ DEADLOCKS,
+ // Derived Metrics
+ DERIVED
+ };
+
+ // sync enum changes with AnMetric.java
+ enum SubType
+ {
+ STATIC = 1, // Type==SIZES, ADDRESS, ONAME
+ EXCLUSIVE = 2,
+ INCLUSIVE = 4,
+ ATTRIBUTED = 8,
+ DATASPACE = 16 // Can be accessed in dataspace views
+ };
+
+ BaseMetric (Type t);
+ BaseMetric (Hwcentry *ctr, const char* _aux, const char* _cmdname,
+ const char* _username, int v_styles); // depended bm
+ BaseMetric (Hwcentry *ctr, const char* _aux, const char* _username,
+ int v_styles, BaseMetric* _depended_bm = NULL); // master bm
+ BaseMetric (const char *_cmd, const char *_username, Definition *def); // derived metrics
+ BaseMetric (const BaseMetric& m);
+ virtual ~BaseMetric ();
+
+ int get_id () { return id; }
+ Type get_type () { return type; }
+ Hwcentry *get_hw_ctr () { return hw_ctr; }
+ char *get_aux () { return aux; }
+ char *get_username () { return username; }
+ char *get_cmd () { return cmd; }
+ int get_flavors () { return flavors; }
+ int get_clock_unit () { return clock_unit; }
+ long long get_precision () { return precision; }
+ ValueTag get_vtype () { return valtype; }
+ int get_value_styles () { return value_styles; }
+ bool is_zeroThreshold () { return zeroThreshold; }
+ ProfData_type get_packet_type () { return packet_type; }
+ Expression *get_cond () { return cond; }
+ Expression *get_val () { return val; }
+ Expression *get_expr () { return expr; }
+ char *get_expr_spec () { return expr_spec; }
+ Definition *get_definition () { return definition; };
+ BaseMetric *get_dependent_bm () { return dependent_bm; };
+
+ bool
+ comparable ()
+ {
+ return val_spec != NULL || type == DERIVED || type == SIZES || type == ADDRESS;
+ }
+
+ // setters..
+ void set_default_visbits (SubType subtype, int _visbits);
+ void set_id (int _id) { id = _id; } //TBR, if possible
+ // For comparison, set which packets to eval:
+ void set_expr_spec (char *_expr_spec);
+ void set_cond_spec (char *_cond_spec);
+ int get_default_visbits (SubType subtype);
+ char *dump ();
+ Histable *get_comparable_obj (Histable *obj);
+ bool is_internal (); // Invisible for users
+
+ char *legend; // for comparison: add'l column text
+
+private:
+ BaseMetric *dependent_bm; // for HWCs only: a link to the timecvt metric
+ Expression *cond; // determines which packets to evaluate
+ char *cond_spec; // used to generate "cond"
+ Expression *val; // determines the numeric value for packet
+ char *val_spec; // used to generate "val"
+ Expression *expr; // for comparison: an additional expression to determine
+ // which packets to eval. Should be NULL otherwise.
+ char *expr_spec; // used to generate "expr"
+ int id; // unique id (assigned to last_id @ "new")
+ Type type; // e.g. HWCNTR
+ char *aux; // for HWCs only: Hwcentry ctr->name
+ char *cmd; // the .rc metric command, e.g. "total"
+ char *username; // e.g. "GTXT("Total Wait Time")"
+ int flavors; // bitmask of SubType capabilities
+ int value_styles; // bitmask of ValueType capabilities
+ static const int NSUBTYPES = 2; // STATIC/EXCLUSIVE, INCLUSIVE
+ int default_visbits[NSUBTYPES]; // ValueType, e.g. VAL_VALUE|VAL_TIMEVAL
+ ValueTag valtype; // e.g. VT_LLONG
+ long long precision; // e.g. METRIC_SIG_PRECISION, 1, etc.
+ Hwcentry *hw_ctr; // HWC definition
+ ProfData_type packet_type; // e.g. DATA_HWC, or -1 for N/A
+ bool zeroThreshold; // deadlock stuff
+ Presentation_clock_unit clock_unit;
+
+ static int last_id; // incremented by 1 w/ every "new". Not MT-safe
+ Definition *definition;
+
+ void hwc_init (Hwcentry *ctr, const char* _aux, const char* _cmdname, const char* _username, int v_styles);
+ void init (Type t);
+ char *get_basetype_name ();
+ void specify ();
+ void specify_metric (char *_cond_spec, char *_val_spec);
+ void set_val_spec (char *_val_spec);
+ void specify_mstate_metric (int st);
+ void specify_ompstate_metric (int st);
+ void specify_prof_metric (char *_cond_spec);
+};
+
+class Definition
+{
+public:
+
+ enum opType
+ {
+ opNULL,
+ opPrimitive,
+ opDivide
+ };
+
+ Definition (opType _op);
+ ~Definition ();
+ static Definition *add_definition (char *_def);
+ Vector<BaseMetric *> *get_dependencies ();
+ long *get_map ();
+ double eval (long *indexes, TValue *values);
+
+ opType op;
+ Definition *arg1;
+ Definition *arg2;
+ char *def;
+
+private:
+ BaseMetric *bm;
+ long *map;
+ Vector<BaseMetric *> *dependencies;
+ long index;
+};
+
+#endif /* _BASEMETRIC_H */
+
diff --git a/gprofng/src/BaseMetricTreeNode.cc b/gprofng/src/BaseMetricTreeNode.cc
new file mode 100644
index 0000000..2d1db99
--- /dev/null
+++ b/gprofng/src/BaseMetricTreeNode.cc
@@ -0,0 +1,329 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <strings.h>
+#include <limits.h>
+#include <sys/param.h>
+
+#include "hwcentry.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Expression.h"
+#include "Metric.h"
+#include "Table.h"
+#include "i18n.h"
+#include "debug.h"
+
+BaseMetricTreeNode::BaseMetricTreeNode ()
+{
+ init_vars ();
+ build_basic_tree ();
+}
+
+BaseMetricTreeNode::BaseMetricTreeNode (BaseMetric *item)
+{
+ init_vars ();
+ bm = item;
+ name = dbe_strdup (bm->get_cmd ());
+ uname = dbe_strdup (bm->get_username ());
+ unit = NULL; //YXXX populate from base_metric (requires updating base_metric)
+ unit_uname = NULL;
+}
+
+BaseMetricTreeNode::BaseMetricTreeNode (const char *_name, const char *_uname,
+ const char *_unit, const char *_unit_uname)
+{
+ init_vars ();
+ name = dbe_strdup (_name);
+ uname = dbe_strdup (_uname);
+ unit = dbe_strdup (_unit);
+ unit_uname = dbe_strdup (_unit_uname);
+}
+
+void
+BaseMetricTreeNode::init_vars ()
+{
+ name = NULL;
+ uname = NULL;
+ unit = NULL;
+ unit_uname = NULL;
+ root = this;
+ parent = NULL;
+ children = new Vector<BaseMetricTreeNode*>;
+ isCompositeMetric = false;
+ bm = NULL;
+ registered = false;
+ num_registered_descendents = 0;
+}
+
+BaseMetricTreeNode::~BaseMetricTreeNode ()
+{
+ children->destroy ();
+ delete children;
+ free (name);
+ free (uname);
+ free (unit);
+ free (unit_uname);
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::register_metric (BaseMetric *item)
+{
+ BaseMetricTreeNode *found = root->find (item->get_cmd ());
+ if (!found)
+ {
+ switch (item->get_type ())
+ {
+ case BaseMetric::CP_TOTAL:
+ found = root->find (L_CP_TOTAL);
+ break;
+ case BaseMetric::CP_TOTAL_CPU:
+ found = root->find (L_CP_TOTAL_CPU);
+ break;
+ }
+ if (found && found->bm == NULL)
+ found->bm = item;
+ }
+ if (!found)
+ {
+ switch (item->get_type ())
+ {
+ case BaseMetric::HEAP_ALLOC_BYTES:
+ case BaseMetric::HEAP_ALLOC_CNT:
+ case BaseMetric::HEAP_LEAK_BYTES:
+ case BaseMetric::HEAP_LEAK_CNT:
+ found = root->find (get_prof_data_type_name (DATA_HEAP));
+ break;
+ case BaseMetric::CP_KERNEL_CPU:
+ case BaseMetric::CP_TOTAL:
+ found = root->find (get_prof_data_type_name (DATA_CLOCK));
+ break;
+ case BaseMetric::CP_LMS_DFAULT:
+ case BaseMetric::CP_LMS_TFAULT:
+ case BaseMetric::CP_LMS_KFAULT:
+ case BaseMetric::CP_LMS_STOPPED:
+ case BaseMetric::CP_LMS_WAIT_CPU:
+ case BaseMetric::CP_LMS_SLEEP:
+ case BaseMetric::CP_LMS_USER_LOCK:
+ case BaseMetric::CP_TOTAL_CPU:
+ found = root->find (L_CP_TOTAL);
+ break;
+ case BaseMetric::CP_LMS_USER:
+ case BaseMetric::CP_LMS_SYSTEM:
+ case BaseMetric::CP_LMS_TRAP:
+ found = root->find (L_CP_TOTAL_CPU);
+ break;
+ case BaseMetric::HWCNTR:
+ found = root->find ((item->get_flavors () & BaseMetric::DATASPACE) != 0 ?
+ L2_HWC_DSPACE : L2_HWC_GENERAL);
+ break;
+ case BaseMetric::SYNC_WAIT_TIME:
+ case BaseMetric::SYNC_WAIT_COUNT:
+ found = root->find (get_prof_data_type_name (DATA_SYNCH));
+ break;
+ case BaseMetric::OMP_WORK:
+ case BaseMetric::OMP_WAIT:
+ case BaseMetric::OMP_OVHD:
+ found = root->find (get_prof_data_type_name (DATA_OMP));
+ break;
+ case BaseMetric::IO_READ_TIME:
+ case BaseMetric::IO_READ_BYTES:
+ case BaseMetric::IO_READ_CNT:
+ case BaseMetric::IO_WRITE_TIME:
+ case BaseMetric::IO_WRITE_BYTES:
+ case BaseMetric::IO_WRITE_CNT:
+ case BaseMetric::IO_OTHER_TIME:
+ case BaseMetric::IO_OTHER_CNT:
+ case BaseMetric::IO_ERROR_TIME:
+ case BaseMetric::IO_ERROR_CNT:
+ found = root->find (get_prof_data_type_name (DATA_IOTRACE));
+ break;
+ case BaseMetric::ONAME:
+ case BaseMetric::SIZES:
+ case BaseMetric::ADDRESS:
+ found = root->find (L1_STATIC);
+ break;
+ default:
+ found = root->find (L1_OTHER);
+ break;
+ }
+ assert (found != NULL);
+ switch (item->get_type ())
+ {
+ case BaseMetric::CP_TOTAL:
+ case BaseMetric::CP_TOTAL_CPU:
+ found->isCompositeMetric = true;
+ break;
+ }
+ found = found->add_child (item);
+ }
+ register_node (found);
+ return found;
+}
+
+void
+BaseMetricTreeNode::register_node (BaseMetricTreeNode *node)
+{
+ if (!node->registered)
+ {
+ node->registered = true;
+ BaseMetricTreeNode *tmp = node->parent;
+ while (tmp)
+ {
+ tmp->num_registered_descendents++;
+ tmp = tmp->parent;
+ }
+ }
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::find (const char *_name)
+{
+ BaseMetricTreeNode *found = NULL;
+ if (dbe_strcmp (get_name (), _name) == 0)
+ return this;
+ if (bm && dbe_strcmp (bm->get_cmd (), _name) == 0)
+ return this;
+ BaseMetricTreeNode *child;
+ int index;
+
+ Vec_loop (BaseMetricTreeNode*, children, index, child)
+ {
+ found = child->find (_name);
+ if (found)
+ return found;
+ }
+ return NULL;
+}
+
+static void
+int_get_registered_descendents (BaseMetricTreeNode* curr,
+ Vector<BaseMetricTreeNode*> *dest, bool nearest_only)
+{
+ if (!curr)
+ return;
+ if (curr->is_registered ())
+ {
+ dest->append (curr);
+ if (nearest_only)
+ return; // soon as we hit a live node, stop following branch
+ }
+ int index;
+ BaseMetricTreeNode *child;
+
+ Vec_loop (BaseMetricTreeNode*, curr->get_children (), index, child)
+ {
+ int_get_registered_descendents (child, dest, nearest_only);
+ }
+}
+
+void
+BaseMetricTreeNode::get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *dest)
+{
+ if (!dest || dest->size () != 0)
+ abort ();
+ bool nearest_only = true;
+ int_get_registered_descendents (this, dest, nearest_only);
+}
+
+void
+BaseMetricTreeNode::get_all_registered_descendents (Vector<BaseMetricTreeNode*> *dest)
+{
+ if (!dest || dest->size () != 0)
+ abort ();
+ bool nearest_only = false;
+ int_get_registered_descendents (this, dest, nearest_only);
+}
+
+char *
+BaseMetricTreeNode::get_description ()
+{
+ if (bm)
+ {
+ Hwcentry* hw_ctr = bm->get_hw_ctr ();
+ if (hw_ctr)
+ return hw_ctr->short_desc;
+ }
+ return NULL;
+}
+
+void
+BaseMetricTreeNode::build_basic_tree ()
+{
+#define TREE_INSERT_DATA_TYPE(t) add_child(get_prof_data_type_name (t), get_prof_data_type_uname (t))
+ BaseMetricTreeNode *level1, *level2;
+ // register L1_DURATION here because it has a value but is not a true metric
+ register_node (add_child (L1_DURATION, L1_DURATION_UNAME, UNIT_SECONDS,
+ UNIT_SECONDS_UNAME));
+ register_node (add_child (L1_GCDURATION, L1_GCDURATION_UNAME, UNIT_SECONDS,
+ UNIT_SECONDS_UNAME));
+ TREE_INSERT_DATA_TYPE (DATA_HEAP);
+ level1 = TREE_INSERT_DATA_TYPE (DATA_CLOCK);
+ level1 = level1->add_child (L_CP_TOTAL, GTXT ("XXX Total Thread Time"));
+ level1->isCompositeMetric = true;
+ level2 = level1->add_child (L_CP_TOTAL_CPU, GTXT ("XXX Total CPU Time"));
+ level2->isCompositeMetric = true;
+
+ add_child (L1_OTHER, L1_OTHER_UNAME);
+ level1 = TREE_INSERT_DATA_TYPE (DATA_HWC);
+ level1->add_child (L2_HWC_DSPACE, L2_HWC_DSPACE_UNAME);
+ level1->add_child (L2_HWC_GENERAL, L2_HWC_GENERAL_UNAME);
+ TREE_INSERT_DATA_TYPE (DATA_SYNCH);
+ TREE_INSERT_DATA_TYPE (DATA_OMP);
+ TREE_INSERT_DATA_TYPE (DATA_IOTRACE);
+ add_child (L1_STATIC, L1_STATIC_UNAME);
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::add_child (BaseMetric *item)
+{
+ return add_child (new BaseMetricTreeNode (item));
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::add_child (const char * _name, const char *_uname,
+ const char * _unit, const char * _unit_uname)
+{
+ return add_child (new BaseMetricTreeNode (_name, _uname, _unit, _unit_uname));
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::add_child (BaseMetricTreeNode *new_node)
+{
+ new_node->parent = this;
+ new_node->root = root;
+ children->append (new_node);
+ return new_node;
+}
+
+char *
+BaseMetricTreeNode::dump ()
+{
+ int len = 4;
+ char *s = bm ? bm->dump () : dbe_strdup ("<no base metric>");
+ char *msg = dbe_sprintf ("%s\n%*c %*c unit='%s' unit_uname='%s' uname='%s' name='%s'\n",
+ STR (s), len, ' ', len, ' ',
+ STR (get_unit_uname ()), STR (get_unit ()),
+ STR (get_user_name ()), STR (get_name ()));
+ free (s);
+ return msg;
+}
diff --git a/gprofng/src/BaseMetricTreeNode.h b/gprofng/src/BaseMetricTreeNode.h
new file mode 100644
index 0000000..0076dff
--- /dev/null
+++ b/gprofng/src/BaseMetricTreeNode.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _BASEMETRICTREENODE_H
+#define _BASEMETRICTREENODE_H
+
+#include "BaseMetric.h"
+
+// Unit values
+#define UNIT_SECONDS "SECONDS"
+#define UNIT_SECONDS_UNAME GTXT("secs.")
+#define UNIT_BYTES "BYTES"
+#define UNIT_BYTES_UNAME GTXT("bytes")
+
+// Name values for intermediate parent nodes that aren't defined elsewhere
+#define L1_DURATION "PROFDATA_TYPE_DURATION"
+#define L1_DURATION_UNAME GTXT("Experiment Duration")
+#define L1_GCDURATION "PROFDATA_TYPE_GCDURATION"
+#define L1_GCDURATION_UNAME GTXT("Java Garbage Collection Duration")
+#define L2_HWC_DSPACE "PROFDATA_TYPE_HWC_DSPACE"
+#define L2_HWC_DSPACE_UNAME GTXT("Memoryspace Hardware Counters")
+#define L2_HWC_GENERAL "PROFDATA_TYPE_HWC_GENERAL"
+#define L2_HWC_GENERAL_UNAME GTXT("General Hardware Counters")
+#define L1_MPI_STATES "PROFDATA_TYPE_MPI_STATES"
+#define L1_MPI_STATES_UNAME GTXT("MPI States")
+#define L1_OTHER "PROFDATA_TYPE_OTHER"
+#define L1_OTHER_UNAME GTXT("Derived and Other Metrics")
+#define L1_STATIC "PROFDATA_TYPE_STATIC"
+#define L1_STATIC_UNAME GTXT("Static")
+#define L_CP_TOTAL "L_CP_TOTAL"
+#define L_CP_TOTAL_CPU "L_CP_TOTAL_CPU"
+
+class BaseMetricTreeNode
+{
+public:
+ BaseMetricTreeNode (); // builds basic metric tree (not including HWCs)
+ virtual ~BaseMetricTreeNode ();
+ BaseMetricTreeNode *register_metric (BaseMetric *item);
+ BaseMetricTreeNode *find (const char *name);
+ void get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *new_vec);
+ void get_all_registered_descendents (Vector<BaseMetricTreeNode*> *new_vec);
+ char *get_description();
+ char *dump();
+
+ BaseMetricTreeNode *get_root () { return root; }
+ BaseMetricTreeNode *get_parent () { return parent; }
+ Vector<BaseMetricTreeNode*> *get_children () { return children; }
+ bool is_registered () { return registered; }
+ int get_num_registered_descendents () { return num_registered_descendents; }
+ bool is_composite_metric () { return isCompositeMetric; }
+ BaseMetric *get_BaseMetric () { return bm; }
+ char *get_name () { return name; }
+ char *get_user_name () { return uname; }
+ char *get_unit () { return unit; }
+ char *get_unit_uname () { return unit_uname; }
+
+private:
+ BaseMetricTreeNode (BaseMetric *item);
+ BaseMetricTreeNode (const char *name, const char *uname,
+ const char *_unit, const char *_unit_uname);
+ void init_vars ();
+ void build_basic_tree ();
+ BaseMetricTreeNode *add_child (BaseMetric *item);
+ BaseMetricTreeNode *add_child (const char *name, const char *uname,
+ const char *unit = NULL, const char *unit_uname = NULL);
+ BaseMetricTreeNode *add_child (BaseMetricTreeNode *new_node);
+ void register_node (BaseMetricTreeNode *);
+
+ BaseMetricTreeNode *root; // root of tree
+ BaseMetricTreeNode *parent; // my parent
+ bool aggregation; // value is based on children's values
+ char *name; // bm->get_cmd() for metrics, unique string otherwise
+ char *uname; // user-visible text
+ char *unit; // see UNIT_* defines
+ char *unit_uname; // see UNIT_*_UNAME defines
+ Vector<BaseMetricTreeNode*> *children; // my children
+ bool isCompositeMetric; // value is sum of children
+ BaseMetric *bm; // metric for this node, or null
+ bool registered; // metric has been officially registered
+ int num_registered_descendents; // does not include self
+};
+
+#endif /* _BASEMETRICTREENODE_H */
diff --git a/gprofng/src/CacheMap.h b/gprofng/src/CacheMap.h
new file mode 100644
index 0000000..a575749
--- /dev/null
+++ b/gprofng/src/CacheMap.h
@@ -0,0 +1,186 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * Cache Map implementation.
+ *
+ * Cache Map makes the following assumptions:
+ * - Cache Map is used for very fast but not guaranteed mapping;
+ * - only REL_EQ Relation can be used;
+ * - all objects used as keys or values has to be managed
+ * outside CacheMap (f.e. deletion);
+ * - (Key_t)0 is invalid key;
+ * - (Value_t)0 is invalid value;
+ * - <TBC>
+ */
+
+#ifndef _DBE_CACHEMAP_H
+#define _DBE_CACHEMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+
+template <typename Key_t, typename Value_t>
+class CacheMap : public Map<Key_t, Value_t>
+{
+public:
+
+ CacheMap ();
+ ~CacheMap ();
+ void put (Key_t key, Value_t val);
+ Value_t get (Key_t key);
+ Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
+ Value_t
+ remove (Key_t key);
+
+private:
+
+ struct Entry
+ {
+ Key_t key;
+ Value_t val;
+
+ Entry ()
+ {
+ key = (Key_t) 0;
+ }
+ };
+
+ static const int INIT_SIZE;
+ static const int MAX_SIZE;
+
+ static unsigned hash (Key_t key);
+ Entry *getEntry (Key_t key);
+
+ int cursize;
+ int nputs;
+ int nchunks;
+ Entry **chunks;
+};
+
+template <typename Key_t, typename Value_t>
+const int CacheMap<Key_t, Value_t>::INIT_SIZE = 1 << 14;
+template <typename Key_t, typename Value_t>
+const int CacheMap<Key_t, Value_t>::MAX_SIZE = 1 << 20;
+
+template <typename Key_t, typename Value_t>CacheMap<Key_t, Value_t>
+::CacheMap ()
+{
+ cursize = INIT_SIZE;
+ chunks = new Entry*[32];
+ nchunks = 0;
+ chunks[nchunks++] = new Entry[cursize];
+ nputs = 0;
+}
+
+template <typename Key_t, typename Value_t>
+CacheMap<Key_t, Value_t>::~CacheMap ()
+{
+ for (int i = 0; i < nchunks; i++)
+ delete[] chunks[i];
+ delete[] chunks;
+}
+
+template <typename Key_t, typename Value_t>
+unsigned
+CacheMap<Key_t, Value_t>::hash (Key_t key)
+{
+ unsigned h = (unsigned) key ^ (unsigned) (key >> 32);
+ h ^= (h >> 20) ^ (h >> 12);
+ return h ^ (h >> 7) ^ (h >> 4);
+}
+
+template <typename Key_t, typename Value_t>
+void
+CacheMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+ if (nputs >= cursize && cursize < MAX_SIZE)
+ {
+ // Allocate new chunk for entries.
+ chunks[nchunks++] = new Entry[cursize];
+ cursize *= 2;
+
+ // Copy all old entries to the newly allocated chunk
+ Entry *newchunk = chunks[nchunks - 1];
+ int prevsz = 0;
+ int nextsz = INIT_SIZE;
+ for (int i = 0; i < nchunks - 1; i++)
+ {
+ Entry *oldchunk = chunks[i];
+ for (int j = prevsz; j < nextsz; j++)
+ newchunk[j] = oldchunk[j - prevsz];
+ prevsz = nextsz;
+ nextsz *= 2;
+ }
+ }
+ Entry *entry = getEntry (key);
+ entry->key = key;
+ entry->val = val;
+ nputs++;
+}
+
+template <typename Key_t, typename Value_t>
+typename CacheMap<Key_t, Value_t>::Entry *
+CacheMap<Key_t, Value_t>::getEntry (Key_t key)
+{
+ unsigned idx = hash (key);
+ int i = nchunks - 1;
+ int j = cursize / 2;
+ for (; i > 0; i -= 1, j /= 2)
+ if (idx & j)
+ break;
+ if (i == 0)
+ j *= 2;
+ return &chunks[i][idx & (j - 1)];
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+CacheMap<Key_t, Value_t>::get (Key_t key)
+{
+ Entry *entry = getEntry (key);
+ return entry->key == key ? entry->val : (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+CacheMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel)
+{
+ if (rel != Map<Key_t, Value_t>::REL_EQ)
+ return (Value_t) 0;
+ return get (key);
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+CacheMap<Key_t, Value_t>::remove (Key_t key)
+{
+ Entry *entry = getEntry (key);
+ Value_t res = (Value_t) 0;
+ if (entry->key == key)
+ {
+ res = entry->val;
+ entry->val = (Value_t) 0;
+ }
+ return res;
+}
+
+#endif
diff --git a/gprofng/src/CallStack.cc b/gprofng/src/CallStack.cc
new file mode 100644
index 0000000..7671f9f
--- /dev/null
+++ b/gprofng/src/CallStack.cc
@@ -0,0 +1,1250 @@
+/* Copyright (C) 2021 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 <new>
+
+#include "util.h"
+#include "CacheMap.h"
+#include "CallStack.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "DbeLinkList.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+
+Descendants::Descendants ()
+{
+ count = 0;
+ limit = sizeof (first_data) / sizeof (CallStackNode *);
+ data = first_data;
+}
+
+Descendants::~Descendants ()
+{
+ if (data != first_data)
+ free (data);
+}
+
+CallStackNode *
+Descendants::find (Histable *hi, int *index)
+{
+ int cnt = count;
+ int left = 0;
+ for (int right = cnt - 1; left <= right;)
+ {
+ int ind = (left + right) / 2;
+ CallStackNode *node = data[ind];
+ Histable *instr = node->get_instr ();
+ if (instr == hi)
+ {
+ if (index)
+ *index = ind;
+ return node;
+ }
+ if (instr->id < hi->id)
+ right = ind - 1;
+ else
+ left = ind + 1;
+ }
+ if (index)
+ *index = left;
+ return NULL;
+}
+
+void
+Descendants::append (CallStackNode* item)
+{
+ if (count < limit)
+ data[count++] = item;
+ else
+ insert (count, item);
+}
+
+void
+Descendants::insert (int ind, CallStackNode* item)
+{
+ CallStackNode **old_data = data;
+ int old_cnt = count;
+ if (old_cnt + 1 >= limit)
+ {
+ int new_limit = (limit == 0) ? DELTA : limit * 2;
+ CallStackNode **new_data = (CallStackNode **) malloc (new_limit * sizeof (CallStackNode *));
+ for (int i = 0; i < ind; i++)
+ new_data[i] = old_data[i];
+ new_data[ind] = item;
+ for (int i = ind; i < old_cnt; i++)
+ new_data[i + 1] = old_data[i];
+ limit = new_limit;
+ data = new_data;
+ if (old_data != first_data)
+ free (old_data);
+ }
+ else
+ {
+ for (int i = ind; i < old_cnt; i++)
+ old_data[i + 1] = old_data[i];
+ old_data[ind] = item;
+ }
+ count++;
+}
+
+/*
+ * Private implementation of CallStack interface
+ */
+
+// When performing pipeline optimization on resolve_frame_info + add_stack
+// cstk_ctx structure contains the state (or context) for one iteration to pass on
+// from Phase 2 to Phase 3 (More details in Experiment.cc)
+class CallStackP : public CallStack
+{
+public:
+ CallStackP (Experiment *exp);
+
+ virtual ~CallStackP ();
+
+ virtual void add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp, cstk_ctx_chunk *cstCtxChunk);
+ virtual void *add_stack (Vector<Histable*> *objs);
+ virtual CallStackNode *get_node (int n);
+ virtual void print (FILE *);
+
+private:
+
+ static const int CHUNKSZ = 16384;
+
+ Experiment *experiment;
+ CallStackNode *root;
+ CallStackNode *jvm_node;
+ int nodes;
+ int nchunks;
+ CallStackNode **chunks;
+ Map<uint64_t, CallStackNode *> *cstackMap;
+ DbeLock *cstackLock;
+
+ CallStackNode *add_stack (long start, long end, Vector<Histable*> *objs, CallStackNode *myRoot);
+ CallStackNode *new_Node (CallStackNode*, Histable*);
+ CallStackNode *find_preg_stack (uint64_t);
+ // objs are in the root..leaf order
+ void *add_stack_d (Vector<Histable*> *objs);
+ void add_stack_java (DataDescriptor *dDscr, long idx, FramePacket *frp, hrtime_t tstamp, uint32_t thrid, Vector<DbeInstr*>* natpcs, bool natpc_added, cstk_ctx_chunk *cstCtxChunk);
+ void add_stack_java_epilogue (DataDescriptor *dDscr, long idx, FramePacket *frp, hrtime_t tstamp, uint32_t thrid, Vector<DbeInstr*>* natpcs, Vector<Histable*>* jpcs, bool natpc_added);
+
+ // Adjust HW counter event to find better trigger PC, etc.
+ DbeInstr *adjustEvent (DbeInstr *leafPC, DbeInstr * candPC,
+ Vaddr &eventEA, int abst_type);
+ Vector<DbeInstr*> *natpcsP;
+ Vector<Histable*> *jpcsP;
+};
+
+CallStackP::CallStackP (Experiment *exp)
+{
+ experiment = exp;
+ nchunks = 0;
+ chunks = NULL;
+ nodes = 0;
+ cstackMap = new CacheMap<uint64_t, CallStackNode *>;
+ cstackLock = new DbeLock ();
+ Function *total = dbeSession->get_Total_Function ();
+ root = new_Node (0, total->find_dbeinstr (0, 0));
+ jvm_node = NULL;
+ natpcsP = NULL;
+ jpcsP = NULL;
+}
+
+CallStackP::~CallStackP ()
+{
+ delete cstackLock;
+ if (chunks)
+ {
+ for (int i = 0; i < nodes; i++)
+ {
+ CallStackNode *node = get_node (i);
+ node->~CallStackNode ();
+ }
+ for (int i = 0; i < nchunks; i++)
+ free (chunks[i]);
+ free (chunks);
+ }
+ delete natpcsP;
+ delete jpcsP;
+ destroy_map (CallStackNode *, cstackMap);
+}
+
+CallStackNode *
+CallStackP::new_Node (CallStackNode *anc, Histable *pcval)
+{
+ // cstackLock->aquireLock(); // Caller already locked it
+ if (nodes >= nchunks * CHUNKSZ)
+ {
+ CallStackNode **old_chunks = chunks;
+ nchunks++;
+
+ // Reallocate Node chunk array
+ chunks = (CallStackNode **) malloc (nchunks * sizeof (CallStackNode *));
+ for (int i = 0; i < nchunks - 1; i++)
+ chunks[i] = old_chunks[i];
+ free (old_chunks);
+ // Allocate new chunk for nodes.
+ chunks[nchunks - 1] = (CallStackNode *) malloc (CHUNKSZ * sizeof (CallStackNode));
+ }
+ nodes++;
+ CallStackNode *node = get_node (nodes - 1);
+ new (node) CallStackNode (anc, pcval);
+ // cstackLock->releaseLock();
+ return node;
+}
+
+CallStackNode *
+CallStackP::find_preg_stack (uint64_t prid)
+{
+ DataView *dview = experiment->getOpenMPdata ();
+ dview->sort (PROP_CPRID);
+ Datum tval;
+ tval.setUINT64 (prid);
+ long idx = dview->getIdxByVals (&tval, DataView::REL_EQ);
+ if (idx < 0)
+ return root;
+ CallStackNode *node = (CallStackNode*) dview->getObjValue (PROP_USTACK, idx);
+ if (node != NULL)
+ return node;
+ uint64_t pprid = dview->getLongValue (PROP_PPRID, idx);
+ if (pprid == prid)
+ return root;
+ void *nat_stack = dview->getObjValue (PROP_MSTACK, idx);
+ Vector<Histable*> *pcs = getStackPCs (nat_stack);
+
+ // Find the bottom frame
+ int btm;
+ bool inOMP = false;
+ DbeInstr *instr;
+ Histable *hist;
+ for (btm = 0; btm < pcs->size (); btm++)
+ {
+ hist = pcs->fetch (btm);
+ if (hist->get_type () == Histable::INSTR)
+ instr = (DbeInstr *) hist;
+ else // DBELINE
+ instr = (DbeInstr *) hist->convertto (Histable::INSTR);
+ LoadObject *lo = instr->func->module->loadobject;
+ if (!inOMP)
+ {
+ if (lo->flags & SEG_FLAG_OMP)
+ inOMP = true;
+ }
+ else if (!(lo->flags & SEG_FLAG_OMP))
+ break;
+ }
+
+ // Find the top frame
+ dview->sort (PROP_CPRID);
+ int top;
+ tval.setUINT64 (pprid);
+ long pidx = dview->getIdxByVals (&tval, DataView::REL_EQ);
+ if (pidx < 0) // No parent. Process the entire nat_stack
+ top = pcs->size () - 1;
+ else
+ {
+ uint32_t thrid = (uint32_t) dview->getIntValue (PROP_THRID, idx);
+ uint32_t pthrid = (uint32_t) dview->getIntValue (PROP_THRID, pidx);
+ if (thrid != pthrid)
+ {
+ // Parent is on a different stack.
+ // Process the entire nat_stack. Skip libthread.
+ for (top = pcs->size () - 1; top >= 0; top--)
+ {
+ hist = pcs->fetch (top);
+ if (hist->get_type () == Histable::INSTR)
+ instr = (DbeInstr *) hist;
+ else // DBELINE
+ instr = (DbeInstr *) hist->convertto (Histable::INSTR);
+ if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+ break;
+ }
+ if (top < 0) // None found. May be incomplete call stack (x86)
+ top = pcs->size () - 1;
+ }
+ else
+ {
+ // Parent is on the same stack. Find match.
+ top = pcs->size () - 1;
+ void *pnat_stack = dview->getObjValue (PROP_MSTACK, pidx);
+ Vector<Histable*> *ppcs = getStackPCs (pnat_stack);
+ for (int ptop = ppcs->size () - 1; top >= 0 && ptop >= 0;
+ top--, ptop--)
+ {
+ if (pcs->fetch (top) != ppcs->fetch (ptop))
+ break;
+ }
+ delete ppcs;
+ }
+ }
+
+ // Process the found range
+ Vector<Histable*> *upcs = new Vector<Histable*>(128);
+ for (int i = btm; i <= top; ++i)
+ {
+ hist = (DbeInstr*) pcs->fetch (i);
+ if (hist->get_type () == Histable::INSTR)
+ instr = (DbeInstr *) hist;
+ else // DBELINE
+ instr = (DbeInstr *) hist->convertto (Histable::INSTR);
+
+ if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+ // Skip all frames from libmtsk
+ continue;
+ upcs->append (instr);
+ }
+ delete pcs;
+ node = find_preg_stack (pprid);
+ while (node != root)
+ {
+ upcs->append (node->instr);
+ node = node->ancestor;
+ }
+ node = (CallStackNode *) add_stack (upcs);
+ dview->setObjValue (PROP_USTACK, idx, node);
+ delete upcs;
+ return node;
+}
+
+#define JNI_MARKER -3
+
+// This is one iteration if the third stage of
+// resolve_frame_info + add_stack pipeline. Works on building the java
+// stacks
+void
+CallStackP::add_stack_java (DataDescriptor *dDscr, long idx, FramePacket *frp,
+ hrtime_t tstamp, uint32_t thrid,
+ Vector<DbeInstr*>* natpcs, bool natpc_added,
+ cstk_ctx_chunk *cstCtxChunk)
+{
+ Vector<Histable*> *jpcs = NULL;
+ cstk_ctx *cstctx = NULL;
+ if (cstCtxChunk != NULL)
+ {
+ cstctx = cstCtxChunk->cstCtxAr[idx % CSTCTX_CHUNK_SZ];
+ jpcs = cstctx->jpcs;
+ jpcs->reset ();
+ }
+ if (jpcs == NULL)
+ {
+ // this is when we are not doing the pipeline optimization
+ // Temporary array for resolved addresses
+ // [leaf_pc .. root_pc] == [0..stack_size-1]
+ // Leave room for a possible "truncated" frame
+ if (jpcsP == NULL)
+ jpcsP = new Vector<Histable*>;
+ jpcs = jpcsP;
+ jpcs->reset ();
+ }
+
+ //
+ // Construct the user stack
+ //
+ // Construct Java user stack
+ int jstack_size = frp->stackSize (true);
+ if (jstack_size)
+ {
+ // jpcs = new Vector<Histable*>( jstack_size );
+ if (frp->isTruncatedStack (true))
+ {
+ Function *truncf = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);
+ jpcs->append (truncf->find_dbeinstr (0, 0));
+ }
+
+ int nind = natpcs->size () - 1; // first native frame
+ for (int jind = jstack_size - 1; jind >= 0; jind--)
+ {
+ bool jleaf = (jind == 0); // is current java frame a leaf?
+ Vaddr mid = frp->getMthdFromStack (jind);
+ int bci = frp->getBciFromStack (jind);
+ DbeInstr *cur_instr = experiment->map_jmid_to_PC (mid, bci, tstamp);
+ jpcs->append (cur_instr);
+ if (bci == JNI_MARKER)
+ {
+ JMethod *j_method = (JMethod*) cur_instr->func;
+ // Find matching native function on the native stack
+ bool found = false;
+ for (; nind >= 0; nind--)
+ {
+ DbeInstr *nat_addr = natpcs->fetch (nind);
+ if (0 == nat_addr)
+ continue;
+ Function *nat_func = nat_addr->func;
+ if (!found && j_method->jni_match (nat_func))
+ found = true;
+ if (found)
+ {
+ // XXX omazur: the following will skip JNI native method
+ // implemented in JVM itself.
+ // If we are back in JVM switch to processing Java
+ // frames if there are any.
+ if ((nat_func->module->loadobject->flags & SEG_FLAG_JVM) && !jleaf)
+ break;
+ jpcs->append (nat_addr);
+ }
+ }
+ }
+ }
+ }
+ add_stack_java_epilogue (dDscr, idx, frp, tstamp, thrid, natpcs, jpcs, natpc_added);
+}
+
+// This is one iteration if the fourth stage of
+// resolve_frame_info + add_stack pipeline.
+// It adds the native and java stacks to the stackmap
+
+void
+CallStackP::add_stack_java_epilogue (DataDescriptor *dDscr, long idx, FramePacket *frp, hrtime_t tstamp, uint32_t thrid, Vector<DbeInstr*>* natpcs, Vector<Histable*> *jpcs, bool natpc_added)
+{
+ CallStackNode *node = NULL;
+ if (!natpc_added)
+ {
+ node = (CallStackNode *) add_stack ((Vector<Histable*>*)natpcs);
+ dDscr->setObjValue (PROP_MSTACK, idx, node);
+ dDscr->setObjValue (PROP_XSTACK, idx, node);
+ dDscr->setObjValue (PROP_USTACK, idx, node);
+ }
+
+ int jstack_size = frp->stackSize (true);
+ if (jstack_size)
+ {
+ if (jpcs != NULL)
+ node = (CallStackNode *) add_stack_d (jpcs);
+ if (node == NULL)
+ node = (CallStackNode*) dDscr->getObjValue (PROP_USTACK, idx);
+ dDscr->setObjValue (PROP_USTACK, idx, node);
+ Function *func = (Function*) node->instr->convertto (Histable::FUNCTION);
+ if (func != dbeSession->get_JUnknown_Function ())
+ dDscr->setObjValue (PROP_XSTACK, idx, node);
+ }
+
+ JThread *jthread = experiment->map_pckt_to_Jthread (thrid, tstamp);
+ if (jthread == JTHREAD_NONE && jstack_size != 0 && node != NULL)
+ {
+ Function *func = (Function*) node->instr->convertto (Histable::FUNCTION);
+ if (func != dbeSession->get_JUnknown_Function ())
+ jthread = JTHREAD_DEFAULT;
+ }
+ dDscr->setObjValue (PROP_JTHREAD, idx, jthread);
+ if (jthread == JTHREAD_NONE || (jthread != JTHREAD_DEFAULT && jthread->is_system ()))
+ {
+ if (jvm_node == NULL)
+ {
+ Function *jvm = dbeSession->get_jvm_Function ();
+ if (jvm)
+ {
+ jvm_node = new_Node (root, jvm->find_dbeinstr (0, 0));
+ CommonPacket::jvm_overhead = jvm_node;
+ }
+ }
+ dDscr->setObjValue (PROP_USTACK, idx, jvm_node);
+ }
+}
+
+// This is one iteration of the 2nd stage of
+// resolve_frame_info + add_stack() pipeline. Builds the stack for a given framepacket.
+// When pipeline optimization is turnd off, cstctxchunk passed is NULL
+void
+CallStackP::add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp,
+ cstk_ctx_chunk* cstCtxChunk)
+{
+ Vector<DbeInstr*> *natpcs = NULL;
+ cstk_ctx *cstctx = NULL;
+ int stack_size = frp->stackSize ();
+ if (cstCtxChunk != NULL)
+ {
+ cstctx = cstCtxChunk->cstCtxAr[idx % CSTCTX_CHUNK_SZ];
+ natpcs = cstctx->natpcs;
+ natpcs->reset ();
+ }
+ if (natpcs == NULL)
+ {
+ // this is when we are not doing the pipeline optimization
+ // Temporary array for resolved addresses
+ // [leaf_pc .. root_pc] == [0..stack_size-1]
+ // Leave room for a possible "truncated" frame
+ if (natpcsP == NULL)
+ natpcsP = new Vector<DbeInstr*>;
+ natpcs = natpcsP;
+ natpcs->reset ();
+ }
+
+ bool leaf = true;
+ hrtime_t tstamp = (hrtime_t) dDscr->getLongValue (PROP_TSTAMP, idx);
+ uint32_t thrid = (uint32_t) dDscr->getIntValue (PROP_THRID, idx);
+
+ enum
+ {
+ NONE,
+ CHECK_O7,
+ USE_O7,
+ SKIP_O7
+ } state = NONE;
+
+ Vaddr o7_to_skip = 0;
+ for (int index = 0; index < stack_size; index++)
+ {
+ if (frp->isLeafMark (index))
+ {
+ state = CHECK_O7;
+ continue;
+ }
+
+ if (state == SKIP_O7)
+ {
+ // remember this bad o7 value since OMP might not recognize it
+ o7_to_skip = frp->getFromStack (index);
+ state = NONE;
+ continue;
+ }
+
+ Vaddr va = frp->getFromStack (index);
+ DbeInstr *cur_instr = experiment->map_Vaddr_to_PC (va, tstamp);
+#if ARCH(Intel)// TBR? FIXUP_XXX_SPARC_LINUX: switch should be on experiment ARCH, not dbe ARCH
+ // We need to adjust return addresses on intel
+ // in order to attribute inclusive metrics to
+ // proper call instructions.
+ if (experiment->exp_maj_version <= 9)
+ if (!leaf && cur_instr->addr != 0)
+ cur_instr = cur_instr->func->find_dbeinstr (0, cur_instr->addr - 1);
+#endif
+
+ // Skip PC's from PLT, update leaf and state accordingly
+ if ((cur_instr->func->flags & FUNC_FLAG_PLT)
+ && (leaf || state == CHECK_O7))
+ {
+ if (state == CHECK_O7)
+ state = USE_O7;
+ leaf = false;
+ continue;
+ }
+ if (state == CHECK_O7)
+ {
+ state = USE_O7;
+ uint64_t saddr = cur_instr->func->save_addr;
+ if (cur_instr->func->isOutlineFunction)
+ // outline functions assume 'save' instruction
+ // Note: they accidentally have saddr == FUNC_ROOT
+ state = SKIP_O7;
+ else if (saddr == FUNC_ROOT)
+ {
+ // If a function is statically determined as a root
+ // but dynamically appears not, don't discard o7.
+ // One such case is __misalign_trap_handler on sparcv9.
+ if (stack_size == 3)
+ state = SKIP_O7;
+ }
+ else if (saddr != FUNC_NO_SAVE && cur_instr->addr > saddr)
+ state = SKIP_O7;
+ }
+ else if (state == USE_O7)
+ {
+ state = NONE;
+ if (cur_instr->flags & PCInvlFlag)
+ continue;
+ }
+ if (leaf)
+ {
+ Vaddr evpc = (Vaddr) dDscr->getLongValue (PROP_VIRTPC, idx);
+ if (evpc != 0
+ && !(index > 0 && frp->isLeafMark (index - 1)
+ && evpc == (Vaddr) (-1)))
+ {
+ /* contains hwcprof info */
+ cur_instr->func->module->read_hwcprof_info ();
+
+ // complete ABS validation of candidate eventPC/eventEA
+ // and correction/adjustment of collected callstack leaf PC
+ DbeInstr *candPC = experiment->map_Vaddr_to_PC (evpc, tstamp);
+ Vaddr vaddr = (Vaddr) dDscr->getLongValue (PROP_VADDR, idx);
+ Vaddr tmp_vaddr = vaddr;
+ int abst_type;
+ uint32_t tag = dDscr->getIntValue (PROP_HWCTAG, idx);
+ if (tag < 0 || tag >= MAX_HWCOUNT)
+ abst_type = ABST_NOPC;
+ else
+ abst_type = experiment->coll_params.hw_tpc[tag];
+
+ // We need to adjust addresses for ABST_EXACT_PEBS_PLUS1
+ // (Nehalem/SandyBridge PEBS identifies PC+1, not PC)
+ if (abst_type == ABST_EXACT_PEBS_PLUS1 && candPC->addr != 0)
+ candPC = candPC->func->find_dbeinstr (0, candPC->func->find_previous_addr (candPC->addr));
+
+ cur_instr = adjustEvent (cur_instr, candPC, tmp_vaddr, abst_type);
+ if (vaddr != tmp_vaddr)
+ {
+ if (tmp_vaddr < ABS_CODE_RANGE)
+ {
+ /* post processing backtrack failed */
+ dDscr->setValue (PROP_VADDR, idx, tmp_vaddr);
+ dDscr->setValue (PROP_PADDR, idx, ABS_NULL);
+ /* hwcp->eventVPC = xxxxx leave eventPC alone,
+ * or can we set it to leafpc? */
+ dDscr->setValue (PROP_PHYSPC, idx, ABS_NULL);
+ }
+ else
+ {
+ /* internal error: why would post-processing modify vaddr? */
+ dDscr->setValue (PROP_PADDR, idx, (Vaddr) (-1));
+ dDscr->setValue (PROP_PHYSPC, idx, (Vaddr) (-1));
+ }
+ }
+ }
+ }
+ natpcs->append (cur_instr);
+ leaf = false;
+
+ // A hack to deceive the user into believing that outlined code
+ // is called from the base function
+ DbeInstr *drvd = cur_instr->func->derivedNode;
+ if (drvd != NULL)
+ natpcs->append (drvd);
+ }
+ if (frp->isTruncatedStack ())
+ {
+ Function *truncf = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);
+ natpcs->append (truncf->find_dbeinstr (0, 0));
+ }
+ else if (frp->isFailedUnwindStack ())
+ {
+ Function *funwf = dbeSession->getSpecialFunction (DbeSession::FailedUnwindFunc);
+ natpcs->append (funwf->find_dbeinstr (0, 0));
+ }
+
+ CallStackNode *node = (CallStackNode*) add_stack ((Vector<Histable*>*)natpcs);
+ dDscr->setObjValue (PROP_MSTACK, idx, node);
+ dDscr->setObjValue (PROP_XSTACK, idx, node);
+ dDscr->setObjValue (PROP_USTACK, idx, node);
+
+ // OpenMP 3.0 stacks
+ stack_size = frp->ompstack->size ();
+ if (stack_size > 0 || frp->omp_state == OMP_IDLE_STATE)
+ {
+ Function *func;
+ Vector<Histable*> *omppcs = new Vector<Histable*>(stack_size);
+ Vector<Histable*> *ompxpcs = new Vector<Histable*>(stack_size);
+ switch (frp->omp_state)
+ {
+ case OMP_IDLE_STATE:
+ case OMP_RDUC_STATE:
+ case OMP_IBAR_STATE:
+ case OMP_EBAR_STATE:
+ case OMP_LKWT_STATE:
+ case OMP_CTWT_STATE:
+ case OMP_ODWT_STATE:
+ case OMP_ATWT_STATE:
+ {
+ func = dbeSession->get_OMP_Function (frp->omp_state);
+ DbeInstr *instr = func->find_dbeinstr (0, 0);
+ omppcs->append (instr);
+ ompxpcs->append (instr);
+ break;
+ }
+ }
+ Vector<Vaddr> *stck = frp->ompstack;
+ leaf = true;
+ for (int index = 0; index < stack_size; index++)
+ {
+ if (stck->fetch (index) == SP_LEAF_CHECK_MARKER)
+ {
+ state = CHECK_O7;
+ continue;
+ }
+ if (state == SKIP_O7)
+ {
+ state = NONE;
+ continue;
+ }
+
+ // The OMP stack might not have enough information to know to discard a bad o7.
+ // So just remember what the native stack skipped.
+ if (o7_to_skip == stck->fetch (index))
+ {
+ state = NONE;
+ continue;
+ }
+ Vaddr va = stck->fetch (index);
+ DbeInstr *cur_instr = experiment->map_Vaddr_to_PC (va, tstamp);
+
+ // Skip PC's from PLT, update leaf and state accordingly
+ if ((cur_instr->func->flags & FUNC_FLAG_PLT) &&
+ (leaf || state == CHECK_O7))
+ {
+ if (state == CHECK_O7)
+ state = USE_O7;
+ leaf = false;
+ continue;
+ }
+ if (state == CHECK_O7)
+ {
+ state = USE_O7;
+ uint64_t saddr = cur_instr->func->save_addr;
+ if (cur_instr->func->isOutlineFunction)
+ // outline functions assume 'save' instruction
+ // Note: they accidentally have saddr == FUNC_ROOT
+ state = SKIP_O7;
+ else if (saddr == FUNC_ROOT)
+ {
+ // If a function is statically determined as a root
+ // but dynamically appears not, don't discard o7.
+ // One such case is __misalign_trap_handler on sparcv9.
+ if (stack_size == 3)
+ state = SKIP_O7;
+ }
+ else if (saddr != FUNC_NO_SAVE && cur_instr->addr > saddr)
+ state = SKIP_O7;
+ }
+ else if (state == USE_O7)
+ {
+ state = NONE;
+ if (cur_instr->flags & PCInvlFlag)
+ continue;
+ }
+
+ DbeLine *dbeline = (DbeLine*) cur_instr->convertto (Histable::LINE);
+ if (cur_instr->func->usrfunc)
+ {
+ dbeline = dbeline->sourceFile->find_dbeline (cur_instr->func->usrfunc, dbeline->lineno);
+ omppcs->append (dbeline);
+ }
+ else if (dbeline->lineno > 0)
+ omppcs->append (dbeline);
+ else
+ omppcs->append (cur_instr);
+ if (dbeline->is_set (DbeLine::OMPPRAGMA) &&
+ frp->omp_state == OMP_WORK_STATE)
+ dDscr->setValue (PROP_OMPSTATE, idx, OMP_OVHD_STATE);
+ ompxpcs->append (cur_instr);
+ leaf = false;
+ }
+ if (frp->omptruncated == SP_TRUNC_STACK_MARKER)
+ {
+ func = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);
+ DbeInstr *instr = func->find_dbeinstr (0, 0);
+ omppcs->append (instr);
+ ompxpcs->append (instr);
+ }
+ else if (frp->omptruncated == SP_FAILED_UNWIND_MARKER)
+ {
+ func = dbeSession->getSpecialFunction (DbeSession::FailedUnwindFunc);
+ DbeInstr *instr = func->find_dbeinstr (0, 0);
+ omppcs->append (instr);
+ ompxpcs->append (instr);
+ }
+
+ // User model call stack
+ node = (CallStackNode*) add_stack (omppcs);
+ dDscr->setObjValue (PROP_USTACK, idx, node);
+ delete omppcs;
+
+ // Expert call stack
+ node = (CallStackNode*) add_stack (ompxpcs);
+ dDscr->setObjValue (PROP_XSTACK, idx, node);
+ delete ompxpcs;
+ dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+ return;
+ }
+
+ // OpenMP 2.5 stacks
+ if (frp->omp_cprid || frp->omp_state)
+ {
+ DataView *dview = experiment->getOpenMPdata ();
+ if (dview == NULL)
+ {
+ // It appears we may get OMP_SERL_STATE from a passive libmtsk
+ dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+ return;
+ }
+ if (dview->getDataDescriptor () == dDscr)
+ {
+ // Don't process the user stack for OpenMP fork events yet
+ dDscr->setObjValue (PROP_USTACK, idx, (void*) NULL);
+ dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+ return;
+ }
+ Vector<Histable*> *omppcs = new Vector<Histable*>(stack_size);
+
+ // Construct OMP user stack
+ // Find the bottom frame
+ int btm = 0;
+ switch (frp->omp_state)
+ {
+ case OMP_IDLE_STATE:
+ {
+ Function *func = dbeSession->get_OMP_Function (frp->omp_state);
+ omppcs->append (func->find_dbeinstr (0, 0));
+ // XXX: workaround for inconsistency between OMP_IDLE_STATE
+ // and omp_cprid != 0
+ frp->omp_cprid = 0;
+ btm = natpcs->size ();
+ break;
+ }
+ case OMP_RDUC_STATE:
+ case OMP_IBAR_STATE:
+ case OMP_EBAR_STATE:
+ case OMP_LKWT_STATE:
+ case OMP_CTWT_STATE:
+ case OMP_ODWT_STATE:
+ case OMP_ATWT_STATE:
+ {
+ Function *func = dbeSession->get_OMP_Function (frp->omp_state);
+ omppcs->append (func->find_dbeinstr (0, 0));
+ bool inOMP = false;
+ for (btm = 0; btm < natpcs->size (); btm++)
+ {
+ LoadObject *lo = natpcs->fetch (btm)->func->module->loadobject;
+ if (!inOMP)
+ {
+ if (lo->flags & SEG_FLAG_OMP)
+ inOMP = true;
+ }
+ else if (!(lo->flags & SEG_FLAG_OMP))
+ break;
+ }
+ break;
+ }
+ case OMP_NO_STATE:
+ case OMP_WORK_STATE:
+ case OMP_SERL_STATE:
+ default:
+ break;
+ }
+
+ // Find the top frame
+ int top = -1;
+ switch (frp->omp_state)
+ {
+ case OMP_IDLE_STATE:
+ break;
+ default:
+ {
+ dview->sort (PROP_CPRID);
+ Datum tval;
+ tval.setUINT64 (frp->omp_cprid);
+ long pidx = dview->getIdxByVals (&tval, DataView::REL_EQ);
+ if (pidx < 0) // No parent. Process the entire nat_stack
+ top = natpcs->size () - 1;
+ else
+ {
+ uint32_t pthrid = (uint32_t) dview->getIntValue (PROP_THRID, pidx);
+ if (thrid != pthrid)
+ {
+ // Parent is on a different stack.
+ // Process the entire nat_stack. Skip libthread.
+ for (top = natpcs->size () - 1; top >= 0; top--)
+ {
+ DbeInstr *instr = natpcs->fetch (top);
+ if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+ break;
+ }
+ if (top < 0) // None found. May be incomplete call stack
+ top = natpcs->size () - 1;
+ }
+ else
+ {
+ // Parent is on the same stack. Find match.
+ top = natpcs->size () - 1;
+ void *pnat_stack = dview->getObjValue (PROP_MSTACK, pidx);
+ Vector<Histable*> *ppcs = getStackPCs (pnat_stack);
+ for (int ptop = ppcs->size () - 1; top >= 0 && ptop >= 0;
+ top--, ptop--)
+ {
+ if (natpcs->fetch (top) != ppcs->fetch (ptop))
+ break;
+ }
+ delete ppcs;
+ }
+ }
+ // If no frames are found for Barrier/Reduction save at least one
+ if ((frp->omp_state == OMP_RDUC_STATE
+ || frp->omp_state == OMP_IBAR_STATE
+ || frp->omp_state == OMP_EBAR_STATE)
+ && top < btm && btm < natpcs->size ())
+ top = btm;
+ }
+ }
+ for (int i = btm; i <= top; ++i)
+ {
+ DbeInstr *instr = natpcs->fetch (i);
+ if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+ continue; // Skip all frames from libmtsk
+ omppcs->append (instr);
+ }
+ node = find_preg_stack (frp->omp_cprid);
+ while (node != root)
+ {
+ omppcs->append (node->instr);
+ node = node->ancestor;
+ }
+ node = (CallStackNode *) add_stack (omppcs);
+ dDscr->setObjValue (PROP_USTACK, idx, node);
+ delete omppcs;
+ dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+ return;
+ }
+
+ // Construct Java user stack
+ add_stack_java (dDscr, idx, frp, tstamp, thrid, natpcs, true, NULL);
+}
+
+// adjustment of leafPC/eventVA for XHWC packets with candidate eventPC
+// Called from CallStack during initial processing of the events
+DbeInstr *
+CallStackP::adjustEvent (DbeInstr *leafPC, DbeInstr *candPC, Vaddr &eventVA,
+ int abst_type)
+{
+ // increment counter of dataspace events
+ experiment->dsevents++;
+ bool isPrecise;
+ if (abst_type == ABST_EXACT_PEBS_PLUS1)
+ isPrecise = true;
+ else if (abst_type == ABST_EXACT)
+ isPrecise = true;
+ else
+ isPrecise = false;
+
+ if (isPrecise)
+ /* precise backtracking */
+ /* assume within 1 instruction of leaf (this could be checked here) */
+ // no change to eventVA or candPC
+ return candPC;
+
+ Function *func = leafPC->func;
+ unsigned int bt_entries = func->module->bTargets.size ();
+ DbeInstr *bestPC = NULL;
+
+ // bt == branch target (potential destination of a branch
+ if (bt_entries == 0)
+ { // no XHWCprof info for this module
+ // increment counter
+ experiment->dsnoxhwcevents++;
+
+ // see if event is to be processed anyway
+ if (!dbeSession->check_ignore_no_xhwcprof ())
+ {
+ // Don't ignore error
+ // XXX -- set error code in event VA -- replace with other mechanism
+ if (eventVA > ABS_CODE_RANGE)
+ eventVA = ABS_NULL;
+ eventVA |= ABS_NO_CTI_INFO; // => effective address can't be validated
+ bestPC = leafPC; // => no PC correction possible
+ }
+ else
+ bestPC = candPC; // assume the event valid
+ }
+ else
+ {
+ // we have the info to verify the backtracking
+ target_info_t *bt;
+ int bt_entry = bt_entries;
+ uint64_t leafPC_offset = func->img_offset + leafPC->addr;
+ uint64_t candPC_offset = candPC->func->img_offset + candPC->addr;
+ do
+ {
+ bt_entry--;
+ bt = func->module->bTargets.fetch (bt_entry);
+ /* bts seem to be sorted by offset, smallest to largest */
+ }
+ while (bt_entry > 0 && bt->offset > leafPC_offset);
+ /* if bt_entry == 0, all items have been checked */
+
+ if (bt->offset > leafPC_offset)
+ { /* XXXX isn't is possible that all bt's are after leafPC_offset? */
+ bestPC = leafPC; // actual event PC can't be determined
+ if (eventVA > ABS_CODE_RANGE)
+ eventVA = ABS_NULL;
+ eventVA |= ABS_INFO_FAILED; // effective address can't be validated
+ }
+ else if (bt->offset > candPC_offset)
+ {
+ // use synthetic PC corresponding to bTarget
+ bestPC = func->find_dbeinstr (PCTrgtFlag, bt->offset - func->img_offset);
+ if (eventVA > ABS_CODE_RANGE)
+ eventVA = ABS_NULL;
+ eventVA |= ABS_CTI_TARGET; // effective address can't be validated
+ }
+ else
+ bestPC = candPC; // accept provided virtual address as valid
+ }
+ return bestPC;
+}
+
+void *
+CallStackP::add_stack_d (Vector<Histable*> *objs)
+{
+ // objs: root..leaf
+ // Reverse objs
+ for (int i = 0, j = objs->size () - 1; i < j; ++i, --j)
+ objs->swap (i, j);
+ return add_stack (objs);
+}
+
+CallStackNode::CallStackNode (CallStackNode *_ancestor, Histable *_instr)
+{
+ ancestor = _ancestor;
+ instr = _instr;
+ alt_node = NULL;
+}
+
+CallStackNode::~CallStackNode () { }
+
+bool
+CallStackNode::compare (long start, long end, Vector<Histable*> *objs, CallStackNode *mRoot)
+{
+ CallStackNode *p = this;
+ for (long i = start; i < end; i++, p = p->get_ancestor ())
+ if (p == NULL || p->get_instr () != objs->get (i))
+ return false;
+ return p == mRoot;
+}
+
+void
+CallStackNode::dump ()
+{
+ const char *s = "";
+ int sz = 0;
+ for (CallStackNode *p = this; p; p = p->get_ancestor ())
+ {
+ fprintf (stderr, NTXT ("%.*s 0x%08llx id=0x%08llx %s\n"), sz, s,
+ (long long) p, (long long) p->get_instr ()->id,
+ STR (p->get_instr ()->get_name ()));
+ s = "-";
+ sz += 1;
+ }
+}
+
+long total_calls_add_stack, total_stacks, total_nodes, call_stack_size[201];
+
+void *
+CallStackP::add_stack (Vector<Histable*> *objs)
+{
+ // objs: leaf..root
+ uint64_t hash = objs->size ();
+ for (long i = objs->size () - 1; i >= 0; --i)
+ hash ^= (unsigned long long) objs->get (i);
+
+ uint64_t key = hash ? hash : 1;
+ CallStackNode *node = cstackMap->get (key);
+#ifdef DEBUG
+ if (DUMP_CALL_STACK)
+ {
+ total_calls_add_stack++;
+ call_stack_size[objs->size () > 200 ? 200 : objs->size ()]++;
+ Dprintf (DUMP_CALL_STACK,
+ "add_stack: %lld size=%lld key=0x%08llx cashNode=0x%08llx\n",
+ (long long) total_calls_add_stack, (long long) objs->size (),
+ (long long) key, (long long) node);
+ for (long i = 0, sz = VecSize (objs); i < sz; i++)
+ Dprintf (DUMP_CALL_STACK, " add_stack: %.*s 0x%08llx id=0x%08llx %s\n",
+ (int) i, NTXT (" "), (long long) objs->get (i),
+ (long long) objs->get (i)->id, STR (objs->get (i)->get_name ()));
+ }
+#endif
+ if (node && node->compare (0, objs->size (), objs, root))
+ {
+ Dprintf (DUMP_CALL_STACK, NTXT ("STACK FOUND: key=0x%08llx 0x%08llx id=0x%08llx %s\n"),
+ (long long) key, (long long) node,
+ (long long) node->get_instr ()->id,
+ STR (node->get_instr ()->get_name ()));
+ return node;
+ }
+ node = root;
+ for (long i = objs->size () - 1; i >= 0; i--)
+ {
+ Histable *instr = objs->get (i);
+ int old_count = node->count;
+ int left;
+ CallStackNode *nd = node->find (instr, &left);
+ if (nd)
+ {
+ node = nd;
+ continue;
+ }
+ cstackLock->aquireLock (); // Use one lock for all nodes
+ // node->aquireLock();
+ if (old_count != node->count)
+ {
+ nd = node->find (instr, &left);
+ if (nd)
+ { // the other thread has created this node
+ cstackLock->releaseLock ();
+ // node->releaseLock();
+ node = nd;
+ continue;
+ }
+ }
+ // New Call Stack
+ total_stacks++;
+ nd = node;
+ CallStackNode *first = NULL;
+ do
+ {
+ CallStackNode *anc = node;
+ total_nodes++;
+ node = new_Node (anc, objs->get (i));
+ if (first)
+ anc->append (node);
+ else
+ first = node;
+ }
+ while (i-- > 0);
+ nd->insert (left, first);
+ cstackLock->releaseLock ();
+ // nd->releaseLock();
+ break;
+ }
+ cstackMap->put (key, node);
+ if (DUMP_CALL_STACK)
+ node->dump ();
+ return node;
+}
+
+CallStackNode *
+CallStackP::get_node (int n)
+{
+ if (n < nodes)
+ return &chunks[n / CHUNKSZ][n % CHUNKSZ];
+ return NULL;
+}
+
+/*
+ * Debugging methods
+ */
+void
+CallStackP::print (FILE *fd)
+{
+ FILE *f = (fd == NULL ? stderr : fd);
+ fprintf (f, GTXT ("CallStack: nodes = %d\n\n"), nodes);
+ int maxdepth = 0;
+ int maxwidth = 0;
+ const char *t;
+ char *n;
+ for (int i = 0; i < nodes; i++)
+ {
+ CallStackNode *node = &chunks[i / CHUNKSZ][i % CHUNKSZ];
+ Histable *instr = node->instr;
+ if (instr->get_type () == Histable::LINE)
+ {
+ t = "L";
+ n = ((DbeLine *) instr)->func->get_name ();
+ }
+ else if (instr->get_type () == Histable::INSTR)
+ {
+ t = "I";
+ n = ((DbeInstr *) instr)->func->get_name ();
+ }
+ else
+ {
+ t = "O";
+ n = instr->get_name ();
+ }
+ long long addr = (long long) instr->get_addr ();
+ fprintf (f, GTXT ("node: 0x%016llx anc: 0x%016llx -- 0x%016llX: %s %s\n"),
+ (unsigned long long) node, (unsigned long long) node->ancestor,
+ addr, t, n);
+ }
+ fprintf (f, GTXT ("md = %d, mw = %d\n"), maxdepth, maxwidth);
+}
+
+/*
+ * Static CallStack methods
+ */
+CallStack *
+CallStack::getInstance (Experiment *exp)
+{
+ return new CallStackP (exp);
+}
+
+int
+CallStack::stackSize (void *stack)
+{
+ CallStackNode *node = (CallStackNode *) stack;
+ int sz = 0;
+ for (; node; node = node->ancestor)
+ sz++;
+ return sz - 1; // don't count the root node
+}
+
+Histable *
+CallStack::getStackPC (void *stack, int n)
+{
+ CallStackNode *node = (CallStackNode *) stack;
+ while (n-- && node)
+ node = node->ancestor;
+ if (node == NULL)
+ return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, 0);
+ return node->instr;
+}
+
+Vector<Histable*> *
+CallStack::getStackPCs (void *stack, bool get_hide_stack)
+{
+ Vector<Histable*> *res = new Vector<Histable*>;
+ CallStackNode *node = (CallStackNode *) stack;
+ if (get_hide_stack && node->alt_node != NULL)
+ node = node->alt_node;
+ while (node && node->ancestor)
+ { // skip the root node
+ res->append (node->instr);
+ node = node->ancestor;
+ }
+ return res;
+}
+
+int
+CallStack::compare (void *stack1, void *stack2)
+{
+ // Quick comparision
+ if (stack1 == stack2)
+ return 0;
+
+ CallStackNode *node1 = (CallStackNode *) stack1;
+ CallStackNode *node2 = (CallStackNode *) stack2;
+ while (node1 != NULL && node2 != NULL)
+ {
+ //to keep the result const on different platforms
+ //we use instr->id instead of instr
+ if (node1->instr->id < node2->instr->id)
+ return -1;
+ else if (node1->instr->id > node2->instr->id)
+ return 1;
+ node1 = node1->ancestor;
+ node2 = node2->ancestor;
+ }
+ if (node1 == NULL && node2 != NULL)
+ return -1;
+ else if (node1 != NULL && node2 == NULL)
+ return 1;
+ else
+ return 0;
+}
+
+// LIBRARY VISIBILITY
+
+void
+CallStack::setHideStack (void *stack, void *hideStack)
+{
+ CallStackNode *hNode = (CallStackNode *) stack;
+ hNode->alt_node = (CallStackNode *) hideStack;
+}
diff --git a/gprofng/src/CallStack.h b/gprofng/src/CallStack.h
new file mode 100644
index 0000000..62e0686
--- /dev/null
+++ b/gprofng/src/CallStack.h
@@ -0,0 +1,114 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _CALLSTACK_H
+#define _CALLSTACK_H
+
+#include <stdio.h>
+#include "dbe_structs.h"
+#include "Experiment.h"
+#include "DbeLock.h"
+
+class DataDescriptor;
+class FramePacket;
+class DbeInstr;
+class Histable;
+template <class ITEM> class Vector;
+class CallStackNode;
+
+class Descendants /* : public DbeLock */
+{
+public:
+ Descendants ();
+ ~Descendants ();
+ CallStackNode *find (Histable *hi, int *index);
+ void append (CallStackNode *item);
+ void insert (int ind, CallStackNode *item);
+ int volatile count;
+
+private:
+
+ enum
+ {
+ DELTA = 8
+ };
+
+ int limit;
+ CallStackNode **data;
+ CallStackNode *first_data[4];
+};
+
+class CallStackNode : public Descendants
+{
+public:
+ CallStackNode (CallStackNode *_ancestor, Histable *_instr);
+ ~CallStackNode ();
+ bool compare (long start, long end, Vector<Histable*> *objs, CallStackNode *mRoot);
+ void dump ();
+
+ CallStackNode *
+ get_ancestor ()
+ {
+ return ancestor;
+ }
+
+ Histable *
+ get_instr ()
+ {
+ return instr;
+ }
+
+ CallStackNode *alt_node;
+ Histable *instr;
+ CallStackNode *ancestor;
+};
+
+class CallStack
+{
+public:
+ static CallStack *getInstance (Experiment *exp);
+ virtual ~CallStack () { };
+
+ virtual void add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp,
+ cstk_ctx_chunk* cstCtxChunk) = 0;
+
+ // Creates a call stack representation for objs and
+ // returns an opaque pointer to it
+ virtual void *add_stack (Vector<Histable*> *objs) = 0;
+
+ // Debugging methods
+ virtual void print (FILE *) = 0;
+
+ // Call stack inquiries
+ static int stackSize (void *stack);
+ static Histable *getStackPC (void *stack, int n);
+ static Vector<Histable*> *getStackPCs (void *stack, bool get_hide_stack = false);
+ static void setHideStack (void *stack, void *hideStack);
+ static int compare (void *stack1, void *stack2);
+
+ virtual CallStackNode *
+ get_node (int)
+ {
+ return NULL;
+ };
+
+};
+
+#endif /* _CALLSTACK_H */
diff --git a/gprofng/src/CatchOutOfMemory.cc b/gprofng/src/CatchOutOfMemory.cc
new file mode 100644
index 0000000..61b91cf
--- /dev/null
+++ b/gprofng/src/CatchOutOfMemory.cc
@@ -0,0 +1,59 @@
+/* Copyright (C) 2021 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 <new> // std::bad_alloc
+#include <stdio.h> // fprintf
+#include <stdlib.h> // exit
+#include "DbeApplication.h"
+
+static char *name = NULL;
+
+/**
+ * Out Of Memory exception handler
+ */
+void
+out_of_mem ()
+{
+ fprintf (stderr, "%s: %s: %s\n", "Error", name ? name : "", "Out of memory\n");
+ exit (2); // Out of memory
+ // throw bad_alloc();
+}
+
+/**
+ * Calls real_main inside try{...}catch(std::bad_alloc *)
+ */
+int
+catch_out_of_memory (int (*real_main)(int, char*[]), int argc, char *argv[])
+{
+ int i = 0;
+ name = argv[0];
+ std::set_new_handler (out_of_mem);
+ try
+ {
+ i = real_main (argc, argv);
+ }
+ catch (std::bad_alloc */*ba*/)
+ {
+ exit (2); // Out of memory
+ }
+ delete theDbeApplication;
+ return i;
+}
diff --git a/gprofng/src/ClassFile.cc b/gprofng/src/ClassFile.cc
new file mode 100644
index 0000000..7dd64a7
--- /dev/null
+++ b/gprofng/src/ClassFile.cc
@@ -0,0 +1,1639 @@
+/* Copyright (C) 2021 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "ClassFile.h"
+#include "Function.h"
+#include "StringBuilder.h"
+#include "DbeFile.h"
+
+class ByteCodeInfo
+{
+public:
+
+ ByteCodeInfo (JMethod *_func, int _bci, int _lno)
+ {
+ func = _func;
+ bci = _bci;
+ lno = _lno;
+ };
+
+ JMethod *func;
+ int bci;
+ int lno;
+};
+
+typedef unsigned char u1;
+typedef unsigned short u2;
+typedef unsigned int u4;
+
+// Class File Constants
+#define JAVA_MAGIC 0xcafebabe
+
+enum {
+ // First argument in access_flags_to_str()
+ ClassAccess = 1,
+ FieldAccess,
+ MethodAccess,
+ NestedClassAccess,
+
+ // jdk/src/share/classes/sun/tools/java/RuntimeConstants.java
+ // Type codes
+ T_CLASS = 0x00000002,
+ T_BOOLEAN = 0x00000004,
+ T_CHAR = 0x00000005,
+ T_FLOAT = 0x00000006,
+ T_DOUBLE = 0x00000007,
+ T_BYTE = 0x00000008,
+ T_SHORT = 0x00000009,
+ T_INT = 0x0000000a,
+ T_LONG = 0x0000000b,
+
+// Access and modifier flags
+ ACC_PUBLIC = 0x00000001,
+ ACC_PRIVATE = 0x00000002,
+ ACC_PROTECTED = 0x00000004,
+ ACC_STATIC = 0x00000008,
+ ACC_FINAL = 0x00000010,
+ ACC_SYNCHRONIZED = 0x00000020,
+ ACC_VOLATILE = 0x00000040,
+ ACC_TRANSIENT = 0x00000080,
+ ACC_NATIVE = 0x00000100,
+ ACC_INTERFACE = 0x00000200,
+ ACC_ABSTRACT = 0x00000400,
+ ACC_STRICT = 0x00000800,
+ ACC_SYNTHETIC = 0x00001000,
+ ACC_ANNOTATION = 0x00002000,
+ ACC_ENUM = 0x00004000,
+
+ ACC_SUPER = 0x00000020,
+ ACC_BRIDGE = 0x00000040,
+ ACC_VARARGS = 0x00000080,
+
+// Opcodes
+ opc_try = -3,
+ opc_dead = -2,
+ opc_label = -1,
+ opc_nop = 0,
+ opc_aconst_null = 1,
+ opc_iconst_m1 = 2,
+ opc_iconst_0 = 3,
+ opc_iconst_1 = 4,
+ opc_iconst_2 = 5,
+ opc_iconst_3 = 6,
+ opc_iconst_4 = 7,
+ opc_iconst_5 = 8,
+ opc_lconst_0 = 9,
+ opc_lconst_1 = 10,
+ opc_fconst_0 = 11,
+ opc_fconst_1 = 12,
+ opc_fconst_2 = 13,
+ opc_dconst_0 = 14,
+ opc_dconst_1 = 15,
+ opc_bipush = 16,
+ opc_sipush = 17,
+ opc_ldc = 18,
+ opc_ldc_w = 19,
+ opc_ldc2_w = 20,
+ opc_iload = 21,
+ opc_lload = 22,
+ opc_fload = 23,
+ opc_dload = 24,
+ opc_aload = 25,
+ opc_iload_0 = 26,
+ opc_iload_1 = 27,
+ opc_iload_2 = 28,
+ opc_iload_3 = 29,
+ opc_lload_0 = 30,
+ opc_lload_1 = 31,
+ opc_lload_2 = 32,
+ opc_lload_3 = 33,
+ opc_fload_0 = 34,
+ opc_fload_1 = 35,
+ opc_fload_2 = 36,
+ opc_fload_3 = 37,
+ opc_dload_0 = 38,
+ opc_dload_1 = 39,
+ opc_dload_2 = 40,
+ opc_dload_3 = 41,
+ opc_aload_0 = 42,
+ opc_aload_1 = 43,
+ opc_aload_2 = 44,
+ opc_aload_3 = 45,
+ opc_iaload = 46,
+ opc_laload = 47,
+ opc_faload = 48,
+ opc_daload = 49,
+ opc_aaload = 50,
+ opc_baload = 51,
+ opc_caload = 52,
+ opc_saload = 53,
+ opc_istore = 54,
+ opc_lstore = 55,
+ opc_fstore = 56,
+ opc_dstore = 57,
+ opc_astore = 58,
+ opc_istore_0 = 59,
+ opc_istore_1 = 60,
+ opc_istore_2 = 61,
+ opc_istore_3 = 62,
+ opc_lstore_0 = 63,
+ opc_lstore_1 = 64,
+ opc_lstore_2 = 65,
+ opc_lstore_3 = 66,
+ opc_fstore_0 = 67,
+ opc_fstore_1 = 68,
+ opc_fstore_2 = 69,
+ opc_fstore_3 = 70,
+ opc_dstore_0 = 71,
+ opc_dstore_1 = 72,
+ opc_dstore_2 = 73,
+ opc_dstore_3 = 74,
+ opc_astore_0 = 75,
+ opc_astore_1 = 76,
+ opc_astore_2 = 77,
+ opc_astore_3 = 78,
+ opc_iastore = 79,
+ opc_lastore = 80,
+ opc_fastore = 81,
+ opc_dastore = 82,
+ opc_aastore = 83,
+ opc_bastore = 84,
+ opc_castore = 85,
+ opc_sastore = 86,
+ opc_pop = 87,
+ opc_pop2 = 88,
+ opc_dup = 89,
+ opc_dup_x1 = 90,
+ opc_dup_x2 = 91,
+ opc_dup2 = 92,
+ opc_dup2_x1 = 93,
+ opc_dup2_x2 = 94,
+ opc_swap = 95,
+ opc_iadd = 96,
+ opc_ladd = 97,
+ opc_fadd = 98,
+ opc_dadd = 99,
+ opc_isub = 100,
+ opc_lsub = 101,
+ opc_fsub = 102,
+ opc_dsub = 103,
+ opc_imul = 104,
+ opc_lmul = 105,
+ opc_fmul = 106,
+ opc_dmul = 107,
+ opc_idiv = 108,
+ opc_ldiv = 109,
+ opc_fdiv = 110,
+ opc_ddiv = 111,
+ opc_irem = 112,
+ opc_lrem = 113,
+ opc_frem = 114,
+ opc_drem = 115,
+ opc_ineg = 116,
+ opc_lneg = 117,
+ opc_fneg = 118,
+ opc_dneg = 119,
+ opc_ishl = 120,
+ opc_lshl = 121,
+ opc_ishr = 122,
+ opc_lshr = 123,
+ opc_iushr = 124,
+ opc_lushr = 125,
+ opc_iand = 126,
+ opc_land = 127,
+ opc_ior = 128,
+ opc_lor = 129,
+ opc_ixor = 130,
+ opc_lxor = 131,
+ opc_iinc = 132,
+ opc_i2l = 133,
+ opc_i2f = 134,
+ opc_i2d = 135,
+ opc_l2i = 136,
+ opc_l2f = 137,
+ opc_l2d = 138,
+ opc_f2i = 139,
+ opc_f2l = 140,
+ opc_f2d = 141,
+ opc_d2i = 142,
+ opc_d2l = 143,
+ opc_d2f = 144,
+ opc_i2b = 145,
+ opc_i2c = 146,
+ opc_i2s = 147,
+ opc_lcmp = 148,
+ opc_fcmpl = 149,
+ opc_fcmpg = 150,
+ opc_dcmpl = 151,
+ opc_dcmpg = 152,
+ opc_ifeq = 153,
+ opc_ifne = 154,
+ opc_iflt = 155,
+ opc_ifge = 156,
+ opc_ifgt = 157,
+ opc_ifle = 158,
+ opc_if_icmpeq = 159,
+ opc_if_icmpne = 160,
+ opc_if_icmplt = 161,
+ opc_if_icmpge = 162,
+ opc_if_icmpgt = 163,
+ opc_if_icmple = 164,
+ opc_if_acmpeq = 165,
+ opc_if_acmpne = 166,
+ opc_goto = 167,
+ opc_jsr = 168,
+ opc_ret = 169,
+ opc_tableswitch = 170,
+ opc_lookupswitch = 171,
+ opc_ireturn = 172,
+ opc_lreturn = 173,
+ opc_freturn = 174,
+ opc_dreturn = 175,
+ opc_areturn = 176,
+ opc_return = 177,
+ opc_getstatic = 178,
+ opc_putstatic = 179,
+ opc_getfield = 180,
+ opc_putfield = 181,
+ opc_invokevirtual = 182,
+ opc_invokespecial = 183,
+ opc_invokestatic = 184,
+ opc_invokeinterface = 185,
+ opc_invokedynamic = 186,
+ opc_new = 187,
+ opc_newarray = 188,
+ opc_anewarray = 189,
+ opc_arraylength = 190,
+ opc_athrow = 191,
+ opc_checkcast = 192,
+ opc_instanceof = 193,
+ opc_monitorenter = 194,
+ opc_monitorexit = 195,
+ opc_wide = 196,
+ opc_multianewarray = 197,
+ opc_ifnull = 198,
+ opc_ifnonnull = 199,
+ opc_goto_w = 200,
+ opc_jsr_w = 201,
+ opc_breakpoint = 202,
+
+// Constant table
+ CONSTANT_UTF8 = 1,
+ CONSTANT_UNICODE = 2,
+ CONSTANT_INTEGER = 3,
+ CONSTANT_FLOAT = 4,
+ CONSTANT_LONG = 5,
+ CONSTANT_DOUBLE = 6,
+ CONSTANT_CLASS = 7,
+ CONSTANT_STRING = 8,
+ CONSTANT_FIELD = 9,
+ CONSTANT_METHOD = 10,
+ CONSTANT_INTERFACEMETHOD = 11,
+ CONSTANT_NAMEANDTYPE = 12,
+ CONSTANT_METHODHANDLE = 15,
+ CONSTANT_METHODTYPE = 16,
+ CONSTANT_INVOKEDYNAMIC = 18
+};
+
+static char *opcNames[] = {
+ NTXT ("nop"),
+ NTXT ("aconst_null"),
+ NTXT ("iconst_m1"),
+ NTXT ("iconst_0"),
+ NTXT ("iconst_1"),
+ NTXT ("iconst_2"),
+ NTXT ("iconst_3"),
+ NTXT ("iconst_4"),
+ NTXT ("iconst_5"),
+ NTXT ("lconst_0"),
+ NTXT ("lconst_1"),
+ NTXT ("fconst_0"),
+ NTXT ("fconst_1"),
+ NTXT ("fconst_2"),
+ NTXT ("dconst_0"),
+ NTXT ("dconst_1"),
+ NTXT ("bipush"),
+ NTXT ("sipush"),
+ NTXT ("ldc"),
+ NTXT ("ldc_w"),
+ NTXT ("ldc2_w"),
+ NTXT ("iload"),
+ NTXT ("lload"),
+ NTXT ("fload"),
+ NTXT ("dload"),
+ NTXT ("aload"),
+ NTXT ("iload_0"),
+ NTXT ("iload_1"),
+ NTXT ("iload_2"),
+ NTXT ("iload_3"),
+ NTXT ("lload_0"),
+ NTXT ("lload_1"),
+ NTXT ("lload_2"),
+ NTXT ("lload_3"),
+ NTXT ("fload_0"),
+ NTXT ("fload_1"),
+ NTXT ("fload_2"),
+ NTXT ("fload_3"),
+ NTXT ("dload_0"),
+ NTXT ("dload_1"),
+ NTXT ("dload_2"),
+ NTXT ("dload_3"),
+ NTXT ("aload_0"),
+ NTXT ("aload_1"),
+ NTXT ("aload_2"),
+ NTXT ("aload_3"),
+ NTXT ("iaload"),
+ NTXT ("laload"),
+ NTXT ("faload"),
+ NTXT ("daload"),
+ NTXT ("aaload"),
+ NTXT ("baload"),
+ NTXT ("caload"),
+ NTXT ("saload"),
+ NTXT ("istore"),
+ NTXT ("lstore"),
+ NTXT ("fstore"),
+ NTXT ("dstore"),
+ NTXT ("astore"),
+ NTXT ("istore_0"),
+ NTXT ("istore_1"),
+ NTXT ("istore_2"),
+ NTXT ("istore_3"),
+ NTXT ("lstore_0"),
+ NTXT ("lstore_1"),
+ NTXT ("lstore_2"),
+ NTXT ("lstore_3"),
+ NTXT ("fstore_0"),
+ NTXT ("fstore_1"),
+ NTXT ("fstore_2"),
+ NTXT ("fstore_3"),
+ NTXT ("dstore_0"),
+ NTXT ("dstore_1"),
+ NTXT ("dstore_2"),
+ NTXT ("dstore_3"),
+ NTXT ("astore_0"),
+ NTXT ("astore_1"),
+ NTXT ("astore_2"),
+ NTXT ("astore_3"),
+ NTXT ("iastore"),
+ NTXT ("lastore"),
+ NTXT ("fastore"),
+ NTXT ("dastore"),
+ NTXT ("aastore"),
+ NTXT ("bastore"),
+ NTXT ("castore"),
+ NTXT ("sastore"),
+ NTXT ("pop"),
+ NTXT ("pop2"),
+ NTXT ("dup"),
+ NTXT ("dup_x1"),
+ NTXT ("dup_x2"),
+ NTXT ("dup2"),
+ NTXT ("dup2_x1"),
+ NTXT ("dup2_x2"),
+ NTXT ("swap"),
+ NTXT ("iadd"),
+ NTXT ("ladd"),
+ NTXT ("fadd"),
+ NTXT ("dadd"),
+ NTXT ("isub"),
+ NTXT ("lsub"),
+ NTXT ("fsub"),
+ NTXT ("dsub"),
+ NTXT ("imul"),
+ NTXT ("lmul"),
+ NTXT ("fmul"),
+ NTXT ("dmul"),
+ NTXT ("idiv"),
+ NTXT ("ldiv"),
+ NTXT ("fdiv"),
+ NTXT ("ddiv"),
+ NTXT ("irem"),
+ NTXT ("lrem"),
+ NTXT ("frem"),
+ NTXT ("drem"),
+ NTXT ("ineg"),
+ NTXT ("lneg"),
+ NTXT ("fneg"),
+ NTXT ("dneg"),
+ NTXT ("ishl"),
+ NTXT ("lshl"),
+ NTXT ("ishr"),
+ NTXT ("lshr"),
+ NTXT ("iushr"),
+ NTXT ("lushr"),
+ NTXT ("iand"),
+ NTXT ("land"),
+ NTXT ("ior"),
+ NTXT ("lor"),
+ NTXT ("ixor"),
+ NTXT ("lxor"),
+ NTXT ("iinc"),
+ NTXT ("i2l"),
+ NTXT ("i2f"),
+ NTXT ("i2d"),
+ NTXT ("l2i"),
+ NTXT ("l2f"),
+ NTXT ("l2d"),
+ NTXT ("f2i"),
+ NTXT ("f2l"),
+ NTXT ("f2d"),
+ NTXT ("d2i"),
+ NTXT ("d2l"),
+ NTXT ("d2f"),
+ NTXT ("i2b"),
+ NTXT ("i2c"),
+ NTXT ("i2s"),
+ NTXT ("lcmp"),
+ NTXT ("fcmpl"),
+ NTXT ("fcmpg"),
+ NTXT ("dcmpl"),
+ NTXT ("dcmpg"),
+ NTXT ("ifeq"),
+ NTXT ("ifne"),
+ NTXT ("iflt"),
+ NTXT ("ifge"),
+ NTXT ("ifgt"),
+ NTXT ("ifle"),
+ NTXT ("if_icmpeq"),
+ NTXT ("if_icmpne"),
+ NTXT ("if_icmplt"),
+ NTXT ("if_icmpge"),
+ NTXT ("if_icmpgt"),
+ NTXT ("if_icmple"),
+ NTXT ("if_acmpeq"),
+ NTXT ("if_acmpne"),
+ NTXT ("goto"),
+ NTXT ("jsr"),
+ NTXT ("ret"),
+ NTXT ("tableswitch"),
+ NTXT ("lookupswitch"),
+ NTXT ("ireturn"),
+ NTXT ("lreturn"),
+ NTXT ("freturn"),
+ NTXT ("dreturn"),
+ NTXT ("areturn"),
+ NTXT ("return"),
+ NTXT ("getstatic"),
+ NTXT ("putstatic"),
+ NTXT ("getfield"),
+ NTXT ("putfield"),
+ NTXT ("invokevirtual"),
+ NTXT ("invokespecial"),
+ NTXT ("invokestatic"),
+ NTXT ("invokeinterface"),
+ NTXT ("invokedynamic"),
+ NTXT ("new"),
+ NTXT ("newarray"),
+ NTXT ("anewarray"),
+ NTXT ("arraylength"),
+ NTXT ("athrow"),
+ NTXT ("checkcast"),
+ NTXT ("instanceof"),
+ NTXT ("monitorenter"),
+ NTXT ("monitorexit"),
+ NTXT ("wide"),
+ NTXT ("multianewarray"),
+ NTXT ("ifnull"),
+ NTXT ("ifnonnull"),
+ NTXT ("goto_w"),
+ NTXT ("jsr_w"),
+ NTXT ("breakpoint")
+};
+
+
+#define APPEND_FLAG(len, buf, flag, x) \
+ if (((x) & (flag)) != 0) \
+ { \
+ flag &= ~(x); \
+ AppendString(len, buf, NTXT("%s%s"), delimiter, #x); \
+ delimiter = NTXT("|"); \
+ }
+
+static char *
+access_flags_to_str (int kind, int flag)
+{
+ static char buf[256];
+ size_t len = 0;
+ buf[0] = 0;
+ if (flag == 0)
+ {
+ AppendString (len, buf, NTXT ("0x%x"), (unsigned int) flag);
+ return buf;
+ }
+ const char *delimiter = "";
+ if (kind == ClassAccess)
+ {
+ APPEND_FLAG (len, buf, flag, ACC_FINAL);
+ APPEND_FLAG (len, buf, flag, ACC_SUPER);
+ APPEND_FLAG (len, buf, flag, ACC_INTERFACE);
+ APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
+ APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+ APPEND_FLAG (len, buf, flag, ACC_ANNOTATION);
+ APPEND_FLAG (len, buf, flag, ACC_ENUM);
+ if (flag)
+ AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+ }
+ else if (kind == FieldAccess)
+ {
+ APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
+ APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
+ APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
+ APPEND_FLAG (len, buf, flag, ACC_STATIC);
+ APPEND_FLAG (len, buf, flag, ACC_FINAL);
+ APPEND_FLAG (len, buf, flag, ACC_VOLATILE);
+ APPEND_FLAG (len, buf, flag, ACC_TRANSIENT);
+ APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+ APPEND_FLAG (len, buf, flag, ACC_ENUM);
+ if (flag)
+ AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+ }
+ else if (kind == MethodAccess)
+ {
+ APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
+ APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
+ APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
+ APPEND_FLAG (len, buf, flag, ACC_STATIC);
+ APPEND_FLAG (len, buf, flag, ACC_FINAL);
+ APPEND_FLAG (len, buf, flag, ACC_SYNCHRONIZED);
+ APPEND_FLAG (len, buf, flag, ACC_BRIDGE);
+ APPEND_FLAG (len, buf, flag, ACC_VARARGS);
+ APPEND_FLAG (len, buf, flag, ACC_NATIVE);
+ APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
+ APPEND_FLAG (len, buf, flag, ACC_STRICT);
+ APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+ if (flag)
+ AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+ }
+ else if (kind == NestedClassAccess)
+ {
+ APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
+ APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
+ APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
+ APPEND_FLAG (len, buf, flag, ACC_STATIC);
+ APPEND_FLAG (len, buf, flag, ACC_FINAL);
+ APPEND_FLAG (len, buf, flag, ACC_INTERFACE);
+ APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
+ APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+ APPEND_FLAG (len, buf, flag, ACC_ANNOTATION);
+ APPEND_FLAG (len, buf, flag, ACC_ENUM);
+ if (flag)
+ AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+ }
+ return buf;
+}
+
+class DataReadException
+{
+public:
+
+ DataReadException (char *s)
+ {
+ str_err = s;
+ }
+
+ ~DataReadException ()
+ {
+ free (str_err);
+ }
+
+ char *
+ toString ()
+ {
+ return str_err;
+ }
+
+private:
+ char *str_err;
+};
+
+class DataInputStream
+{
+public:
+
+ DataInputStream (const unsigned char *bytes, int64_t sz)
+ {
+ bp = bp_orig = bytes;
+ bp_last = bp_orig + sz;
+ }
+
+ DataInputStream (DataInputStream *in)
+ {
+ bp = bp_orig = in->bp_orig;
+ bp_last = in->bp_last;
+ }
+
+ u1
+ readByte ()
+ {
+ check (1);
+ u1 val = *bp;
+ bp++;
+ return val;
+ }
+
+ u2
+ readUnsignedShort ()
+ {
+ check (2);
+ u2 val = (bp[0] << 8) | bp[1];
+ bp += 2;
+ return val;
+ }
+
+ u4
+ readUnsigned ()
+ {
+ check (4);
+ u4 val = (bp[0] << 24) | (bp[1] << 16) | (bp[2] << 8) | bp[3];
+ bp += 4;
+ return val;
+ }
+
+ const u1 *
+ getptr ()
+ {
+ return bp;
+ }
+
+ const size_t
+ get_offset ()
+ {
+ return bp - bp_orig;
+ }
+
+ void
+ skip (int n)
+ {
+ check (n);
+ bp += n;
+ }
+
+ void
+ reset ()
+ {
+ bp = bp_orig;
+ }
+
+ void
+ copy_bytes (char *buf, int64_t len)
+ {
+ check (len);
+ memcpy (buf, bp, len);
+ buf[len] = '\0';
+ }
+
+private:
+
+ void
+ check (int64_t sz)
+ {
+ if (sz < 0 || bp + sz > bp_last)
+ {
+ DataReadException *e1 = new DataReadException (
+ dbe_sprintf (GTXT ("(Cannot read %lld byte(s) offset=0x%llx)\n"),
+ (long long) sz, (long long) get_offset ()));
+ throw (e1);
+ }
+ };
+
+ const unsigned char *bp_last;
+ const unsigned char *bp_orig;
+ const unsigned char *bp;
+};
+
+class BinaryConstantPool
+{
+public:
+ BinaryConstantPool (DataInputStream &in);
+ ~BinaryConstantPool ();
+
+ u1
+ getType (int n)
+ {
+ return (n < nconst && n > 0) ? types[n] : 0;
+ };
+ char *getString (int index);
+
+private:
+ static char *getTypeName (int ty);
+ static char *type_name_to_str (int ty);
+ static char *offset_to_str (long long offset);
+ int nconst;
+ u1 *types;
+ int64_t *offsets;
+ char **strings;
+ DataInputStream *input;
+};
+
+char *
+BinaryConstantPool::type_name_to_str (int ty)
+{
+ static char buf[128];
+ char *tyName = getTypeName (ty);
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), tyName, ty);
+ return buf;
+}
+
+char *
+BinaryConstantPool::offset_to_str (long long offset)
+{
+ static char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("offset=0x%06llx (%llu)"), offset, offset);
+ return buf;
+}
+
+BinaryConstantPool::BinaryConstantPool (DataInputStream &in)
+{
+ nconst = 0;
+ types = NULL;
+ offsets = NULL;
+ strings = NULL;
+ input = new DataInputStream (in);
+ int cntConst = in.readUnsignedShort ();
+ if (cntConst > 0)
+ {
+ types = new u1[cntConst];
+ types[0] = 0;
+ offsets = new int64_t [cntConst];
+ strings = new char * [cntConst];
+ strings[0] = NULL;
+ }
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("# BinaryConstantPool: %d\n"), (int) nconst);
+ for (int i = 1; i < cntConst; i++)
+ {
+ nconst = i + 1;
+ strings[i] = NULL;
+ types[i] = in.readByte ();
+ offsets[i] = in.get_offset ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" %3d %-25s %-25s"), i, offset_to_str (offsets[i]), type_name_to_str (types[i]));
+ switch (types[i])
+ {
+ case CONSTANT_UTF8:
+ {
+ u2 length = in.readUnsignedShort ();
+ in.skip (length);
+ Dprintf (DUMP_JAVA_CLASS, " length=%u\n", (unsigned int) length);
+ break;
+ }
+ case CONSTANT_INTEGER:
+ {
+ u4 bytes = in.readUnsigned ();
+ Dprintf (DUMP_JAVA_CLASS, " bytes=0x%08x\n", (unsigned int) bytes);
+ break;
+ }
+ case CONSTANT_FLOAT:
+ {
+ u4 bytes = in.readUnsigned ();
+ Dprintf (DUMP_JAVA_CLASS, " bytes=0x%08x\n", (unsigned int) bytes);
+ break;
+ }
+ case CONSTANT_LONG:
+ case CONSTANT_DOUBLE:
+ {
+ // JVM 4.4.5: all 8-byte constants take up
+ // two entries in the constant_pool table.
+ i++;
+ nconst++;
+ offsets[i] = 0;
+ strings[i] = NULL;
+ u4 high_bytes = in.readUnsigned ();
+ u4 low_bytes = in.readUnsigned ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" high_bytes=0x%08x low_bytes=0x%08x\n"),
+ (unsigned int) high_bytes, (unsigned int) low_bytes);
+ break;
+ }
+ case CONSTANT_CLASS:
+ {
+ u2 name_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" name_index=%6u\n"), (unsigned int) name_index);
+ break;
+ }
+ case CONSTANT_STRING:
+ {
+ u2 string_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" string_index=%4u\n"), (unsigned int) string_index);
+ break;
+ }
+ case CONSTANT_FIELD:
+ case CONSTANT_METHOD:
+ case CONSTANT_INTERFACEMETHOD:
+ {
+ u2 class_index = in.readUnsignedShort ();
+ u2 name_and_type_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" class_index=%5u name_and_type_index=%u\n"),
+ (unsigned int) class_index, (unsigned int) name_and_type_index);
+ break;
+ }
+ case CONSTANT_NAMEANDTYPE:
+ {
+ u2 name_index = in.readUnsignedShort ();
+ u2 descriptor_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, " name_index=%6u descriptor_index=%u\n",
+ (unsigned int) name_index, (unsigned int) descriptor_index);
+ break;
+ }
+ case CONSTANT_METHODHANDLE:
+ {
+ u1 reference_kind = in.readByte ();
+ u2 reference_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, " reference_kind=%u reference_index=%u\n",
+ (unsigned int) reference_kind, (unsigned int) reference_index);
+ break;
+ }
+ case CONSTANT_METHODTYPE:
+ {
+ u2 descriptor_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" descriptor_index=%u\n"),
+ (unsigned int) descriptor_index);
+ break;
+ }
+ case CONSTANT_INVOKEDYNAMIC:
+ {
+ u2 bootstrap_method_attr_index = in.readUnsignedShort ();
+ u2 name_and_type_index = in.readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" bootstrap_method_attr_index=%5u name_and_type_index=%u\n"),
+ (unsigned int) bootstrap_method_attr_index,
+ (unsigned int) name_and_type_index);
+ break;
+ }
+ default:
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("\n"));
+ DataReadException *e1 = new DataReadException (
+ dbe_sprintf (GTXT ("BinaryConstantPool[%d]: bad tag %d %s\n"),
+ i, types[i], offset_to_str (offsets[i])));
+ throw (e1);
+ }
+ }
+}
+
+BinaryConstantPool::~BinaryConstantPool ()
+{
+ delete[] types;
+ delete[] offsets;
+ delete input;
+ if (strings)
+ {
+ for (int i = 0; i < nconst; i++)
+ free (strings[i]);
+ delete[] strings;
+ }
+}
+
+#define CASE_S(x) case x: return (char *) #x
+
+char *
+BinaryConstantPool::getTypeName (int ty)
+{
+ switch (ty)
+ {
+ CASE_S (CONSTANT_UTF8);
+ CASE_S (CONSTANT_INTEGER);
+ CASE_S (CONSTANT_FLOAT);
+ CASE_S (CONSTANT_LONG);
+ CASE_S (CONSTANT_DOUBLE);
+ CASE_S (CONSTANT_CLASS);
+ CASE_S (CONSTANT_STRING);
+ CASE_S (CONSTANT_FIELD);
+ CASE_S (CONSTANT_METHOD);
+ CASE_S (CONSTANT_INTERFACEMETHOD);
+ CASE_S (CONSTANT_NAMEANDTYPE);
+ CASE_S (CONSTANT_METHODHANDLE);
+ CASE_S (CONSTANT_METHODTYPE);
+ CASE_S (CONSTANT_INVOKEDYNAMIC);
+ default: return NTXT ("UNKNOWN_TYPE");
+ }
+}
+
+char *
+BinaryConstantPool::getString (int index)
+{
+ if (index >= nconst || index <= 0)
+ return NULL;
+ if (strings[index])
+ return strings[index];
+ input->reset ();
+ input->skip (offsets[index]);
+ switch (types[index])
+ {
+ case CONSTANT_CLASS:
+ case CONSTANT_STRING:
+ case CONSTANT_NAMEANDTYPE:
+ strings[index] = dbe_strdup (getString (input->readUnsignedShort ()));
+ return strings[index];
+ case CONSTANT_METHOD:
+ input->readUnsignedShort (); // cl_inx
+ strings[index] = dbe_strdup (getString (input->readUnsignedShort ()));
+ return strings[index];
+ case CONSTANT_UTF8:
+ break;
+ default:
+ return NULL;
+ }
+ u2 len = input->readUnsignedShort ();
+ strings[index] = (char *) malloc (len + 1);
+ input->copy_bytes (strings[index], len);
+ return strings[index];
+}
+
+ClassFile::ClassFile () : Module ()
+{
+ input = NULL;
+ bcpool = NULL;
+ cf_buf = NULL;
+ cur_jmthd = NULL;
+ blanksCnt = 0;
+ cf_bufsz = 0;
+ lang_code = Sp_lang_java;
+ class_name = NULL;
+ class_filename = NULL;
+ source_name = NULL;
+ byteCodeInfo = NULL;
+}
+
+char *
+ClassFile::get_opc_name (int op)
+{
+ if (op >= 0 && ((size_t) op) < sizeof (opcNames) / sizeof (char*))
+ return opcNames[op];
+ switch (op)
+ {
+ case opc_try:
+ return NTXT ("try");
+ case opc_dead:
+ return NTXT ("dead");
+ case opc_label:
+ return NTXT ("label");
+ default:
+ return NTXT ("Unknown op code");
+ }
+}
+
+void
+ClassFile::openFile (const char *fname)
+{
+ if (fname == NULL)
+ return;
+ int fd = open64 (fname, O_RDONLY);
+ if (fd == -1)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot open file %s"), fname);
+ return;
+ }
+ struct stat64 stat_buf;
+ if ((fstat64 (fd, &stat_buf) == -1) || (stat_buf.st_size == 0))
+ {
+ close (fd);
+ append_msg (CMSG_ERROR, GTXT ("Cannot read file %s"), fname);
+ return;
+ }
+ cf_bufsz = stat_buf.st_size;
+ cf_buf = (unsigned char *) malloc (cf_bufsz);
+ if (cf_bufsz != read_from_file (fd, cf_buf, cf_bufsz))
+ {
+ free (cf_buf);
+ cf_buf = NULL;
+ close (fd);
+ append_msg (CMSG_ERROR, GTXT ("Cannot read file %s"), fname);
+ return;
+ }
+ close (fd);
+
+ input = new DataInputStream (cf_buf, cf_bufsz);
+ u4 c_magic = input->readUnsigned ();
+ if (c_magic != JAVA_MAGIC)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Not a class file: %s"), fname);
+ return;
+ }
+ /* u2 minor = */ input->readUnsignedShort ();
+ /* u2 major = */ input->readUnsignedShort ();
+ status = AE_OK;
+}
+
+ClassFile::~ClassFile ()
+{
+ free (cf_buf);
+ free (class_name);
+ free (class_filename);
+ free (source_name);
+ delete bcpool;
+ delete input;
+}
+
+static void
+convertName (char *s)
+{
+ while (*s)
+ {
+ if (*s == '/')
+ *s = '.';
+ s++;
+ }
+}
+
+void
+ClassFile::printConstant (StringBuilder *sb, int index)
+{
+ u1 type = bcpool->getType (index);
+ switch (type)
+ {
+ case CONSTANT_METHOD:
+ {
+ char *str = bcpool->getString (index);
+ if (str)
+ {
+ convertName (str);
+ sb->append (str);
+ sb->append (NTXT ("()"));
+ }
+ break;
+ }
+ case CONSTANT_CLASS:
+ {
+ char *str = bcpool->getString (index);
+ if (str)
+ {
+ convertName (str);
+ sb->append (str);
+ }
+ break;
+ }
+ case CONSTANT_UTF8:
+ {
+ char *str = bcpool->getString (index);
+ if (str)
+ sb->append (str);
+ break;
+ }
+ case CONSTANT_STRING:
+ {
+ char *str = bcpool->getString (index);
+ if (str)
+ {
+ sb->append ('"');
+ sb->append (str);
+ sb->append ('"');
+ }
+ break;
+ }
+ default:
+ sb->append ('#');
+ sb->append ((int) index);
+ break;
+ }
+}
+
+long long
+ClassFile::printCodeSequence (StringBuilder *sb, uint64_t addr, DataInputStream *in)
+{
+ int64_t offset = in->get_offset ();
+ sb->appendf (NTXT ("%08llx: "), (long long) addr);
+ int opcode = in->readByte ();
+ if (opcode == opc_wide)
+ {
+ opcode = in->readByte ();
+ sb->append (get_opc_name (opcode));
+ sb->append (NTXT ("_w "));
+ int arg = in->readUnsignedShort ();
+ switch (opcode)
+ {
+ case opc_aload: case opc_astore:
+ case opc_fload: case opc_fstore:
+ case opc_iload: case opc_istore:
+ case opc_lload: case opc_lstore:
+ case opc_dload: case opc_dstore:
+ case opc_ret:
+ sb->append (arg);
+ break;
+ case opc_iinc:
+ sb->append (arg);
+ sb->append (' ');
+ sb->append (in->readUnsignedShort ());
+ break;
+ default:
+ sb->append (GTXT ("Invalid opcode"));
+ break;
+ }
+ }
+ else
+ {
+ sb->append (get_opc_name (opcode));
+ sb->append (' ');
+ switch (opcode)
+ {
+ case opc_aload: case opc_astore:
+ case opc_fload: case opc_fstore:
+ case opc_iload: case opc_istore:
+ case opc_lload: case opc_lstore:
+ case opc_dload: case opc_dstore:
+ case opc_ret:
+ sb->append (in->readByte ());
+ break;
+ case opc_iinc:
+ sb->append (in->readByte ());
+ sb->append (' ');
+ sb->append (in->readByte ());
+ break;
+ case opc_tableswitch:
+ {
+ int align = (addr + 1) % 4; // 1 byte is a length of opc_lookupswitch
+ if (align != 0)
+ {
+ in->skip (4 - align); // four byte boundry
+ }
+ long default_skip = in->readUnsigned ();
+ long low = in->readUnsigned ();
+ long high = in->readUnsigned ();
+ sb->appendf (GTXT ("%ld to %ld: default=0x%llx"),
+ (long) low, (long) high, (long long) (addr + default_skip));
+ for (long i = low; i <= high; ++i)
+ /* u4 i1 = */ in->readUnsigned ();
+ break;
+ }
+ case opc_lookupswitch:
+ {
+ int align = (addr + 1) % 4; // 1 byte is a length of opc_lookupswitch
+ if (align != 0)
+ in->skip (4 - align); // four byte boundry
+ u4 default_skip = in->readUnsigned ();
+ u4 npairs = in->readUnsigned ();
+ sb->appendf (GTXT ("%d: default=0x%llx"), npairs,
+ (long long) (addr + default_skip));
+ for (int i = 0, nints = npairs * 2; i < nints; i += 2)
+ {
+ /* u4 i1 = */ in->readUnsigned ();
+ /* u4 i2 = */ in->readUnsigned ();
+ }
+ break;
+ }
+ case opc_newarray:
+ switch (in->readByte ())
+ {
+ case T_INT:
+ sb->append (GTXT ("int"));
+ break;
+ case T_LONG:
+ sb->append (GTXT ("long"));
+ break;
+ case T_FLOAT:
+ sb->append (GTXT ("float"));
+ break;
+ case T_DOUBLE:
+ sb->append (GTXT ("double"));
+ break;
+ case T_CHAR:
+ sb->append (GTXT ("char"));
+ break;
+ case T_SHORT:
+ sb->append (GTXT ("short"));
+ break;
+ case T_BYTE:
+ sb->append (GTXT ("byte"));
+ break;
+ case T_BOOLEAN:
+ sb->append (GTXT ("boolean"));
+ break;
+ default:
+ sb->append (GTXT ("BOGUS TYPE"));
+ break;
+ }
+ break;
+ case opc_anewarray:
+ sb->append (GTXT ("class "));
+ printConstant (sb, in->readUnsignedShort ());
+ break;
+ case opc_sipush:
+ sb->append (in->readUnsignedShort ());
+ break;
+ case opc_bipush:
+ sb->append (in->readByte ());
+ break;
+ case opc_ldc:
+ printConstant (sb, in->readByte ());
+ break;
+ case opc_ldc_w: case opc_ldc2_w:
+ case opc_instanceof: case opc_checkcast:
+ case opc_new:
+ case opc_putstatic: case opc_getstatic:
+ case opc_putfield: case opc_getfield:
+ case opc_invokevirtual:
+ case opc_invokespecial:
+ case opc_invokestatic:
+ printConstant (sb, in->readUnsignedShort ());
+ break;
+ case opc_invokeinterface:
+ {
+ u2 index = in->readUnsignedShort ();
+ u1 count = in->readByte ();
+ /* u1 zero = */ in->readByte ();
+ sb->appendf (" #%u, %u) ", (unsigned int) index, (unsigned int) count);
+ printConstant (sb, index);
+ break;
+ }
+ case opc_multianewarray:
+ {
+ u2 index = in->readUnsignedShort ();
+ printConstant (sb, index);
+ sb->appendf (GTXT (" dim #%d "), index);
+ break;
+ }
+ case opc_jsr: case opc_goto:
+ case opc_ifeq: case opc_ifge: case opc_ifgt:
+ case opc_ifle: case opc_iflt: case opc_ifne:
+ case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
+ case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
+ case opc_if_acmpeq: case opc_if_acmpne:
+ case opc_ifnull: case opc_ifnonnull:
+ sb->appendf (NTXT ("0x%llx"), (long long) (addr + (short) in->readUnsignedShort ()));
+ break;
+ case opc_jsr_w:
+ case opc_goto_w:
+ sb->append (addr + (int) in->readUnsigned ());
+ break;
+ default:
+ break;
+ }
+ }
+ return in->get_offset () - offset;
+}
+
+void
+ClassFile::readAttributes (int count)
+{
+ blanksCnt += 4;
+ for (int ax = 0; ax < count; ax++)
+ {
+ u2 attribute_name_index = input->readUnsignedShort ();
+ u4 attribute_length = input->readUnsigned ();
+ char *attribute_name = bcpool->getString (attribute_name_index);
+ if (!attribute_name)
+ {
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d\n"),
+ (int) blanksCnt, ' ', (int) (ax + 1),
+ (int) attribute_name_index, STR (attribute_name), (int) attribute_length);
+ input->skip (attribute_length);
+ continue;
+ }
+
+ if (strcmp (attribute_name, NTXT ("SourceFile")) == 0)
+ {
+ u2 sourcefile_index = input->readUnsignedShort ();
+ source_name = dbe_strdup (bcpool->getString (sourcefile_index));
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d file_name=%d %s\n"),
+ (int) blanksCnt, ' ', (int) (ax + 1),
+ (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+ (int) sourcefile_index, STR (source_name));
+ }
+ else if (strcmp (attribute_name, NTXT ("InnerClasses")) == 0)
+ {
+ int niclasses = input->readUnsignedShort ();
+ for (int ix = 0; ix < niclasses; ix++)
+ {
+ u2 inner_class_info_index = input->readUnsignedShort ();
+ u2 outer_class_info_index = input->readUnsignedShort ();
+ u2 inner_name_index = input->readUnsignedShort ();
+ u2 inner_class_access_flags = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS,
+ NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d name=%d '%s'\n"
+ "%*cinner_class_info_index=%d outer_class_info_index=%d flags=%s\n"),
+ (int) blanksCnt, ' ', (int) (ax + 1),
+ (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+ (int) inner_name_index, STR (bcpool->getString (inner_name_index)),
+ (int) (blanksCnt + 10), ' ',
+ (int) inner_class_info_index, (int) outer_class_info_index,
+ access_flags_to_str (NestedClassAccess, inner_class_access_flags));
+ }
+ }
+ else if (strcmp (attribute_name, NTXT ("Code")) == 0)
+ {
+ u2 max_stack = input->readUnsignedShort ();
+ u2 max_locals = input->readUnsignedShort ();
+ u4 code_length = input->readUnsigned ();
+ if (cur_jmthd)
+ {
+ cur_jmthd->size = code_length;
+ cur_jmthd->img_fname = dbeFile->get_location ();
+ cur_jmthd->img_offset = input->get_offset ();
+ }
+ input->skip (code_length);
+ u2 exception_table_length = input->readUnsignedShort ();
+ input->skip (exception_table_length * (2 + 2 + 2 + 2));
+ Dprintf (DUMP_JAVA_CLASS,
+ NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d max_stack=%d max_locals=%d code_length=%d exception_table_length=%d\n"),
+ (int) blanksCnt, ' ', (int) (ax + 1),
+ (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+ (int) max_stack, (int) max_locals, (int) code_length, (int) exception_table_length);
+ readAttributes (input->readUnsignedShort ());
+ }
+ else if (strcmp (attribute_name, NTXT ("LineNumberTable")) == 0)
+ {
+ int nlines = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d nlines=%d\n"),
+ (int) blanksCnt, ' ', (int) (ax + 1),
+ (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+ (int) nlines);
+ for (int lx = 0; lx < nlines; lx++)
+ {
+ int bci = input->readUnsignedShort ();
+ int lno = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %3d: pc=%4d (0x%04x) line=%d\n"),
+ (int) (blanksCnt + 5), ' ', (int) (lx + 1), (int) bci, (int) bci, (int) lno);
+ if (cur_jmthd)
+ byteCodeInfo->append (new ByteCodeInfo (cur_jmthd, bci, lno));
+ }
+ }
+ else
+ {
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d\n"),
+ (int) blanksCnt, ' ', (int) (ax + 1),
+ (int) attribute_name_index, STR (attribute_name),
+ (int) attribute_length);
+ input->skip (attribute_length);
+ }
+ }
+ blanksCnt -= 4;
+}
+
+int
+ClassFile::readFile ()
+{
+ if (status != AE_NOTREAD)
+ return status;
+ status = AE_OTHER;
+
+ // The ClassFile Structure http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
+ try
+ {
+ blanksCnt = 4;
+ cur_jmthd = NULL;
+ char *fname = dbeFile->get_location ();
+ openFile (fname);
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("\nClassFile::readFile status=%d %s location=%s\n"),
+ (unsigned int) status, STR (get_name ()), STR (fname));
+ if (status != AE_OK)
+ return status;
+ byteCodeInfo = new Vector<ByteCodeInfo *>(512);
+ bcpool = new BinaryConstantPool (*input);
+ u2 access_flags = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("\naccess_flags=%s; %s\n"),
+ access_flags_to_str (ClassAccess, access_flags),
+ STR (dbeFile->get_name ()));
+ u2 classNameInd = input->readUnsignedShort ();
+ class_filename = dbe_strdup (bcpool->getString (classNameInd));
+ if (class_filename)
+ {
+ class_name = strdup (class_filename);
+ convertName (class_name);
+ }
+
+ // Get superclass name
+ u2 superClassInd = input->readUnsignedShort ();
+ //char *str = bcpool->getString(superClassInd);
+ //super_name = str ? convertName( str ) : NULL;
+
+ // Read interfaces
+ int interfaces_count = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS,
+ NTXT (" class_name=%3d %-20s superClass=%3d %s interfaces_count=%d\n"),
+ (int) classNameInd, STR (class_name),
+ (int) superClassInd, STR (bcpool->getString (superClassInd)),
+ (int) interfaces_count);
+ for (int i = 0; i < interfaces_count; i++)
+ {
+ u2 index = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" %6lld%s"), (long long) index,
+ (i % 8 == 7) || (i + 1 == interfaces_count) ? "\n" : "");
+ }
+
+ // Read fields
+ int fields_count = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" fields_count=%d\n"), fields_count);
+ for (int i = 0; i < fields_count; i++)
+ {
+ u2 fld_access_flags = input->readUnsignedShort ();
+ u2 name_index = input->readUnsignedShort ();
+ u2 descriptor_index = input->readUnsignedShort ();
+ u2 attributes_count = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS,
+ NTXT (" %2d: name=%3d %-20s flags=%s; desc_ind=%d attr_count=%d\n"),
+ i, (int) name_index, STR (bcpool->getString (name_index)),
+ access_flags_to_str (FieldAccess, fld_access_flags),
+ (int) descriptor_index, (int) attributes_count);
+ readAttributes (attributes_count);
+ }
+
+ // Read methods
+ int methods_count = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("\n methods_count=%d\n"), (int) methods_count);
+ int func_cnt = functions->size ();
+ for (int i = 0; i < methods_count; i++)
+ {
+ u2 mthd_access_flags = input->readUnsignedShort ();
+ u2 name_index = input->readUnsignedShort ();
+ u2 descriptor_index = input->readUnsignedShort ();
+ char *mname = bcpool->getString (name_index);
+ if (mname == NULL)
+ {
+ DataReadException *e1 = new DataReadException (dbe_sprintf (GTXT ("method name[%d] is NULL\n"), i));
+ throw (e1);
+ }
+ char *msign = bcpool->getString (descriptor_index);
+ if (msign == NULL)
+ {
+ DataReadException *e1 = new DataReadException (dbe_sprintf (GTXT ("method signature[%d] is NULL\n"), i));
+ throw (e1);
+ }
+ size_t len = strlen (class_name);
+ cur_jmthd = NULL;
+ for (int idx = 0; idx < func_cnt; idx++)
+ {
+ JMethod *jmthd = (JMethod*) functions->fetch (idx);
+ char *jmt_name = jmthd->get_name (Histable::SHORT);
+ if (strncmp (jmt_name, class_name, len) == 0)
+ {
+ if (strcmp (jmt_name + len + 1, mname) == 0 &&
+ strcmp (jmthd->get_signature (), msign) == 0)
+ {
+ cur_jmthd = jmthd;
+ break;
+ }
+ }
+ }
+ if (cur_jmthd == NULL)
+ {
+ cur_jmthd = dbeSession->createJMethod ();
+ cur_jmthd->module = this;
+ cur_jmthd->set_signature (dbe_strdup (msign));
+ char *nm = dbe_sprintf (NTXT ("%s.%s"), class_name, mname);
+ cur_jmthd->set_name (nm);
+ free (nm);
+ functions->append (cur_jmthd);
+ }
+ if ((mthd_access_flags & ACC_NATIVE) != 0)
+ {
+ cur_jmthd->flags |= FUNC_FLAG_NATIVE;
+ }
+ u2 attributes_count = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS,
+ NTXT (" %2d: name=%d %-20s flags=%s desc_ind=%d attr_count=%d\n"),
+ (int) (i + 1), (int) name_index, STR (bcpool->getString (name_index)),
+ access_flags_to_str (MethodAccess, mthd_access_flags),
+ (int) descriptor_index, (int) attributes_count);
+ readAttributes (attributes_count);
+ cur_jmthd->popSrcFile ();
+ }
+
+ // Read global attributes
+ u2 global_attributes_count = input->readUnsignedShort ();
+ Dprintf (DUMP_JAVA_CLASS, NTXT (" global_attributes_count=%d\n"), global_attributes_count);
+ readAttributes (global_attributes_count);
+ status = AE_OK;
+ }
+ catch (DataReadException *ex)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot read class file %s (%s)"), get_name (), ex->toString ());
+ delete ex;
+ status = AE_OTHER;
+ }
+
+ char *fnm = NULL;
+ if (class_filename)
+ {
+ if (strcmp (class_filename, get_name ()) != 0)
+ set_name (strdup (class_filename));
+ if (source_name)
+ {
+ char *bname = strrchr (class_filename, '/');
+ if (bname)
+ fnm = dbe_sprintf (NTXT ("%.*s/%s"), (int) (bname - class_filename),
+ class_filename, source_name);
+ else
+ fnm = strdup (source_name);
+ }
+ else
+ fnm = get_java_file_name (class_filename, false);
+ }
+ else if (source_name)
+ fnm = strdup (source_name);
+ if (fnm)
+ {
+ set_file_name (fnm);
+ main_source = findSource (file_name, true);
+ main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
+ }
+
+ for (long i = 0, sz = VecSize (functions); i < sz; i++)
+ functions->get (i)->def_source = main_source;
+ JMethod *func = NULL;
+ for (long i = 0, sz = VecSize (byteCodeInfo); i < sz; i++)
+ {
+ ByteCodeInfo *p = byteCodeInfo->get (i);
+ if (func != p->func)
+ {
+ if (func)
+ func->popSrcFile ();
+ func = p->func;
+ func->line_first = p->lno;
+ func->pushSrcFile (main_source, 0);
+ }
+ func->line_last = p->lno;
+ func->add_PC_info (p->bci, p->lno, main_source);
+ }
+ if (func)
+ func->popSrcFile ();
+ Destroy (byteCodeInfo);
+ Dprintf (DUMP_JAVA_CLASS, NTXT ("\n status=%d class_filename=%s class_name=%s source_name=%s file_name=%s %s\n"),
+ (unsigned int) status, STR (class_filename), STR (class_name),
+ STR (source_name), STR (file_name),
+ STR (get_name ()));
+ return status;
+}
+
+#define MAX_CLASS_SIZE 65536
+
+char *
+ClassFile::get_disasm (uint64_t inst_address, uint64_t end_address,
+ uint64_t start_address, uint64_t f_offset, int64_t &inst_size)
+{
+ int64_t offset = f_offset + (inst_address - start_address);
+ if ((cf_buf == NULL) || (inst_address >= end_address) || (offset >= cf_bufsz))
+ {
+ inst_size = 0;
+ return NULL;
+ }
+
+ // Check for an implausibly large size
+ if ((inst_address - start_address) > MAX_CLASS_SIZE)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot disassemble class file %s (%s), implausible size = %lld"),
+ get_name (), dbeFile->get_location (),
+ (end_address - start_address));
+ inst_size = 0;
+ return NULL;
+ }
+
+ StringBuilder sb;
+ DataInputStream *in = new DataInputStream (input);
+ try
+ {
+ in->skip (offset);
+ inst_size = printCodeSequence (&sb, inst_address - start_address, in);
+ }
+ catch (DataReadException *ex)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot disassemble class file %s (%s) %s"),
+ get_name (), dbeFile->get_location (), ex->toString ());
+ delete ex;
+ inst_size = 0;
+ }
+ delete in;
+ if (inst_size == 0)
+ return NULL;
+ return sb.toString ();
+}
+
+char *
+ClassFile::get_java_file_name (char *clname, bool classSuffix)
+{
+ size_t len = strlen (clname);
+ if (len > 6 && streq (clname + len - 6, NTXT (".class")))
+ len -= 6;
+ if (!classSuffix)
+ { // remove $SubClassName from "ClassName$SubClassName"
+ char *tmp = strchr (clname, '$');
+ if (tmp)
+ len = tmp - clname;
+ }
+ char *clpath = (char *) malloc (len + 10);
+ for (size_t i = 0; i < len; i++)
+ clpath[i] = (clname[i] == '.') ? '/' : clname[i];
+ snprintf (clpath + len, 10, classSuffix ? NTXT (".class") : NTXT (".java"));
+ return clpath;
+}
diff --git a/gprofng/src/ClassFile.h b/gprofng/src/ClassFile.h
new file mode 100644
index 0000000..bd4c61b
--- /dev/null
+++ b/gprofng/src/ClassFile.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _CLASSFILE_H
+#define _CLASSFILE_H
+
+#include "Module.h"
+
+class DataInputStream;
+class BinaryConstantPool;
+class JMethod;
+class StringBuilder;
+class ByteCodeInfo;
+
+class ClassFile : public Module
+{
+public:
+ ClassFile ();
+ virtual ~ClassFile ();
+ virtual int readFile ();
+ virtual char *get_disasm (uint64_t inst_address, uint64_t end_address,
+ uint64_t start_address, uint64_t f_offset,
+ int64_t &inst_size);
+ static char *get_java_file_name (char *clname, bool classSuffix);
+
+private:
+
+ void openFile (const char *fname);
+ char *get_opc_name (int op);
+ void readAttributes (int count);
+ void printConstant (StringBuilder *sb, int index);
+ long long printCodeSequence (StringBuilder *sb, uint64_t addr, DataInputStream *in);
+
+ unsigned char *cf_buf;
+ int64_t cf_bufsz;
+ int blanksCnt;
+ DataInputStream *input;
+ BinaryConstantPool *bcpool;
+ JMethod *cur_jmthd;
+ char *class_name;
+ char *class_filename;
+ char *source_name;
+ Vector<ByteCodeInfo *> *byteCodeInfo;
+};
+
+#endif
diff --git a/gprofng/src/Command.cc b/gprofng/src/Command.cc
new file mode 100644
index 0000000..d1620d7
--- /dev/null
+++ b/gprofng/src/Command.cc
@@ -0,0 +1,562 @@
+/* Copyright (C) 2021 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 <string.h>
+#include <stdlib.h>
+#include <sys/param.h>
+
+#include "gp-defs.h"
+#include "Command.h"
+#include "DbeSession.h"
+#include "MemorySpace.h"
+#include "i18n.h"
+#include "StringBuilder.h"
+
+const char *Command::DEFAULT_CMD = "default"; // token for default
+const char *Command::ALL_CMD = "all"; // token for all
+const char *Command::ANY_CMD = "any"; // token for any
+const char *Command::NONE_CMD = "none"; // token for none
+const char *Command::HWC_CMD = "hwc"; // token for all HWC
+const char *Command::BIT_CMD = "bit"; // token for any bit-generated metric
+const char *Command::DEFAULT_METRICS = "ei.user:name"; // if no .rc files read
+const char *Command::DEFAULT_SORT = "e.user:name"; // if no .rc files read
+
+static char *fhdr, *cchdr, *lahdr, *iohdr, *sdhdr, *lsthdr, *lohdr;
+static char *methdr, *othdr, *mischdr, *deflthdr;
+static char *selhdr, *filthdr, *outhdr, *exphdr, *obj_allhdr;
+static char *unsuphdr, *indxobjhdr;
+static char *helphdr, *rahdr, *ddhdr, *typehdr, *typehdr2;
+
+// This is the list of commands, which governs the parser scan, as
+// well as the help command.
+// A line with the tag NO_CMD is skipped in parsing, but is used
+// to provide subheadings for the help
+// The HELP line must be the last one in the list of commands
+// to be shown by "-help"; The HHELP line must be the
+// last one to be shown by "-xhelp"
+// The LAST_CMD line must be the last one recognized by the parser
+//
+// The ordering of this list should match the ordering in the man
+// page, and the subheader lines should match the subheadings in
+// the man page.
+
+static char *desc[LAST_CMD];
+
+static Cmdtable cmd_lst[] = { // list of commands
+ // User Commands
+ { NO_CMD, "", NULL, NULL, 0, &fhdr},
+ { FUNCS, "functions", NULL, NULL, 0, &desc[FUNCS]},
+ { METRICS, "metrics", NULL, "metric_spec", 1, &desc[METRICS]},
+ { SORT, "sort", NULL, "metric_spec", 1, &desc[SORT]},
+ { FDETAIL, "fsummary", NULL, NULL, 0, &desc[FDETAIL]},
+ { FSINGLE, "fsingle", NULL, "function_name #", 2, &desc[FSINGLE]},
+
+ { NO_CMD, "", NULL, NULL, 0, &cchdr},
+ { GPROF, "callers-callees", "gprof", NULL, 0, &desc[GPROF]},
+ { CSINGLE, "csingle", NULL, "function_name #", 2, &desc[CSINGLE]},
+ { CPREPEND, "cprepend", NULL, "function_name #", 2, &desc[CPREPEND]},
+ { CAPPEND, "cappend", NULL, "function_name #", 2, &desc[CAPPEND]},
+ { CRMFIRST, "crmfirst", NULL, NULL, 0, &desc[CRMFIRST]},
+ { CRMLAST, "crmlast", NULL, NULL, 0, &desc[CRMLAST]},
+ { CALLTREE, "calltree", "ctree", NULL, 0, &desc[CALLTREE]},
+
+ { NO_CMD, "", NULL, NULL, 0, &lahdr},
+ { LEAKS, "leaks", NULL, NULL, 0, &desc[LEAKS]},
+ { ALLOCS, "allocs", NULL, NULL, 0, &desc[ALLOCS]},
+ { HEAP, "heap", NULL, NULL, 0, &desc[HEAP]},
+ { HEAPSTAT, "heapstat", NULL, NULL, 0, &desc[HEAPSTAT]},
+
+ { NO_CMD, "", NULL, NULL, 0, &iohdr},
+ { IOACTIVITY, "ioactivity", NULL, NULL, 0, &desc[IOACTIVITY]},
+ { IOVFD, "iodetail", NULL, NULL, 0, &desc[IOVFD]},
+ { IOCALLSTACK, "iocallstack", NULL, NULL, 0, &desc[IOCALLSTACK]},
+ { IOSTAT, "iostat", NULL, NULL, 0, &desc[IOSTAT]},
+
+ // PC, line, source and dissassembly commands
+ { NO_CMD, "", NULL, NULL, 0, &sdhdr},
+ { HOTPCS, "pcs", NULL, NULL, 0, &desc[HOTPCS]},
+ { PDETAIL, "psummary", NULL, NULL, 0, &desc[PDETAIL]},
+ { HOTLINES, "lines", NULL, NULL, 0, &desc[HOTLINES]},
+ { LDETAIL, "lsummary", NULL, NULL, 0, &desc[LDETAIL]},
+ { SOURCE, "source", NULL, "func/file #", 2, &desc[SOURCE]},
+ { DISASM, "disasm", NULL, "func/file #", 2, &desc[DISASM]},
+ { SCOMPCOM, "scc", NULL, "com_spec", 1, &desc[SCOMPCOM]},
+ { STHRESH, "sthresh", NULL, "value", 1, &desc[STHRESH]},
+ { DCOMPCOM, "dcc", NULL, "com_spec", 1, &desc[DCOMPCOM]},
+ { COMPCOM, "cc", NULL, "com_spec", 1, &desc[COMPCOM]},
+ { DTHRESH, "dthresh", NULL, "value", 1, &desc[DTHRESH]},
+ { SETPATH, "setpath", NULL, "path_list", 1, &desc[SETPATH]},
+ { ADDPATH, "addpath", NULL, "path_list", 1, &desc[ADDPATH]},
+ { PATHMAP, "pathmap", NULL, "old_prefix new_prefix", 2, &desc[PATHMAP]},
+ { LIBDIRS, "preload_libdirs", NULL, NULL, 1, &desc[PATHMAP]},
+
+ // Index Object commands
+ { NO_CMD, "", NULL, NULL, 0, &indxobjhdr},
+ { INDXOBJ, "indxobj", NULL, "type", 1, &desc[INDXOBJ]},
+ { INDXOBJLIST, "indxobj_list", NULL, NULL, 0, &desc[INDXOBJLIST]},
+ { INDXOBJDEF, "indxobj_define", NULL, "type \"index-expr\"", 2, &desc[INDXOBJDEF]},
+
+ // Deadlock detection commands
+ { NO_CMD, "", NULL, NULL, 0, &ddhdr},
+ { DEADLOCK_EVNTS, "deadlocks", NULL, NULL, 0, &desc[DEADLOCK_EVNTS]},
+ { DEADLOCK_SUM, "dsummary", NULL, "{deadlock_id|all}", 1, &desc[DEADLOCK_SUM]},
+
+ { NO_CMD, "", NULL, NULL, 0, &lsthdr},
+ { EXP_LIST, "experiment_list", "exp_list", NULL, 0, &desc[EXP_LIST]},
+ { SAMPLE_LIST, "sample_list", NULL, NULL, 0, &desc[SAMPLE_LIST]},
+ { LWP_LIST, "lwp_list", NULL, NULL, 0, &desc[LWP_LIST]},
+ { THREAD_LIST, "thread_list", NULL, NULL, 0, &desc[THREAD_LIST]},
+ { CPU_LIST, "cpu_list", NULL, NULL, 0, &desc[CPU_LIST]},
+
+ { NO_CMD, "", NULL, NULL, 0, &filthdr},
+ { FILTERS, "filters", NULL, "filter-specification", 1, &desc[FILTERS]},
+ { DESCRIBE, "describe", NULL, NULL, 0, &desc[DESCRIBE]},
+
+ { NO_CMD, "", NULL, NULL, 0, &selhdr},
+ { SAMPLE_SELECT, "sample_select", NULL, "sample_spec", 1, &desc[SAMPLE_SELECT]},
+ { LWP_SELECT, "lwp_select", NULL, "lwp_spec", 1, &desc[LWP_SELECT]},
+ { THREAD_SELECT, "thread_select", NULL, "thread_spec", 1, &desc[THREAD_SELECT]},
+ { CPU_SELECT, "cpu_select", NULL, "cpu_spec", 1, &desc[CPU_SELECT]},
+
+ { NO_CMD, "", NULL, NULL, 0, &lohdr},
+ { OBJECT_LIST, "object_list", NULL, NULL, 0, &desc[OBJECT_LIST]},
+ { OBJECT_SHOW, "object_show", NULL, "obj1,...", 1, &desc[OBJECT_SHOW]},
+ { OBJECT_HIDE, "object_hide", NULL, "obj1,...", 1, &desc[OBJECT_HIDE]},
+ { OBJECT_API, "object_api", NULL, "obj1,...", 1, &desc[OBJECT_API]},
+ { DUMMY_CMD, " ", NULL, NULL, 0, &obj_allhdr},
+ { OBJECTS_DEFAULT, "objects_default", NULL, NULL, 1, &desc[OBJECTS_DEFAULT]},
+
+ { OBJECT_SELECT, "object_select", NULL, "obj1,...", 1, &desc[OBJECT_SELECT]},
+
+ { NO_CMD, "", NULL, NULL, 0, &methdr},
+ { METRIC_LIST, "metric_list", NULL, NULL, 0, &desc[METRIC_LIST]},
+ { GMETRIC_LIST, "cmetric_list", "gmetric_list", NULL, 0, &desc[GMETRIC_LIST]},
+ { INDX_METRIC_LIST, "indx_metric_list", NULL, NULL, 1, &desc[INDX_METRIC_LIST]},
+
+ { NO_CMD, "", NULL, NULL, 0, &outhdr},
+ { OUTFILE, "outfile", NULL, "filename", 1, &desc[OUTFILE]},
+ { APPENDFILE, "appendfile", NULL, "filename", 1, &desc[APPENDFILE]},
+ { LIMIT, "limit", NULL, "n", 1, &desc[LIMIT]},
+ { NAMEFMT, "name", NULL, "{long|short|mangled}[:{soname|nosoname}]", 1, &desc[NAMEFMT]},
+ { VIEWMODE, "viewmode", NULL, "{user|expert|machine}", 1, &desc[VIEWMODE]},
+ { COMPARE, "compare", NULL, "{on|off|delta|ratio}", 1, &desc[COMPARE]},
+ { PRINTMODE, "printmode", NULL, "string", 1, &desc[PRINTMODE]},
+
+ { NO_CMD, "", NULL, NULL, 0, &othdr},
+ { HEADER, "header", NULL, "exp_id", 1, &desc[HEADER]},
+ { OBJECTS, "objects", NULL, NULL, 0, &desc[OBJECTS]},
+ { OVERVIEW_NEW, "overview", NULL, NULL, 0, &desc[OVERVIEW_NEW]},
+ { SAMPLE_DETAIL, "sample_detail", NULL, "exp_id", 1, &desc[SAMPLE_DETAIL]},
+ { STATISTICS, "statistics", NULL, "exp_id", 1, &desc[STATISTICS]},
+
+ { NO_CMD, "", NULL, NULL, 0, &exphdr},
+ { OPEN_EXP, "open_exp", NULL, "experiment", 1, &desc[OPEN_EXP]},
+ { ADD_EXP, "add_exp", NULL, "experiment", 1, &desc[ADD_EXP]},
+ { DROP_EXP, "drop_exp", NULL, "experiment", 1, &desc[DROP_EXP]},
+
+ { NO_CMD, "", NULL, NULL, 0, &deflthdr},
+ { DMETRICS, "dmetrics", NULL, "metric_spec", 1, &desc[DMETRICS]},
+ { DSORT, "dsort", NULL, "metric_spec", 1, &desc[DSORT]},
+ { EN_DESC, "en_desc", NULL, "{on|off|=<regex>}", 1, &desc[EN_DESC]},
+
+ { NO_CMD, "", NULL, NULL, 0, &mischdr},
+ { DUMMY_CMD, "<type>", NULL, NULL, 0, &typehdr},
+ { DUMMY_CMD, " ", NULL, NULL, 0, &typehdr2},
+
+ { IFREQ, "ifreq", NULL, NULL, 0, &desc[IFREQ]},
+ { PROCSTATS, "procstats", NULL, NULL, 0, &desc[PROCSTATS]},
+ { SCRIPT, "script", NULL, "file", 1, &desc[SCRIPT]},
+ { VERSION_cmd, "version", NULL, NULL, 0, &desc[VERSION_cmd]},
+ { QUIT, "quit", "exit", NULL, 0, &desc[QUIT]},
+
+ { NO_CMD, "", NULL, NULL, 0, &helphdr},
+ { HELP, "help", NULL, NULL, 0, &desc[HELP]},
+
+ { NO_CMD, "", NULL, NULL, 0, &unsuphdr},
+ { HELP, "-help", NULL, NULL, 0, &desc[HELP]},
+ { DUMPFUNC, "dfuncs", NULL, "string", 1, &desc[DUMPFUNC]},
+ { DUMPDOBJS, "ddobjs", NULL, "string", 1, &desc[DUMPDOBJS]},
+ { DUMPNODES, "dnodes", NULL, NULL, 0, &desc[DUMPNODES]},
+ { DUMPSTACKS, "dstacks", NULL, NULL, 0, &desc[DUMPSTACKS]},
+ { DUMPUNK, "dunkpc", NULL, NULL, 0, &desc[DUMPUNK]},
+ { DUMPMAP, "dmap", NULL, NULL, 0, &desc[DUMPMAP]},
+ { DUMPENTITIES, "dentities", NULL, NULL, 0, &desc[DUMPENTITIES]},
+ { IGNORE_NO_XHWCPROF, "ignore_no_xhwcprof", NULL, NULL, 0, &desc[IGNORE_NO_XHWCPROF]},
+ { IGNORE_FS_WARN, "ignore_fs_warn", NULL, NULL, 0, &desc[IGNORE_FS_WARN]},
+
+ { DUMP_PROFILE, "dprofile", NULL, NULL, 0, &desc[DUMP_PROFILE]},
+ { DUMP_SYNC, "dsync", NULL, NULL, 0, &desc[DUMP_SYNC]},
+ { DUMP_IOTRACE, "diotrace", NULL, NULL, 0, &desc[DUMP_IOTRACE]},
+ { DUMP_HWC, "dhwc", NULL, NULL, 0, &desc[DUMP_HWC]},
+ { DUMP_HEAP, "dheap", NULL, NULL, 0, &desc[DUMP_HEAP]},
+ { RACE_ACCS, "r_accs", NULL, NULL, 0, &desc[RACE_ACCS]},
+
+ { DMPI_FUNCS, "dmpi_funcs", NULL, NULL, 0, &desc[DMPI_FUNCS]},
+ { DMPI_MSGS, "dmpi_msgs", NULL, NULL, 0, &desc[DMPI_MSGS]},
+ { DMPI_EVENTS, "dmpi_events", NULL, NULL, 0, &desc[DMPI_EVENTS]},
+
+ { DMEM, "dmem", NULL, NULL, 1, &desc[DMEM]},
+ { DUMP_GC, "dumpgc", NULL, NULL, 0, &desc[DUMP_GC]},
+ { DKILL, "dkill", NULL, NULL, 2, &desc[DKILL]},
+
+ { QQUIT, "xquit", NULL, NULL, 0, &desc[QQUIT]},
+ // use xquit for memory leak detection in dbe; it's
+ // like quit, but deletes all data loaded
+
+ { HHELP, "xhelp", NULL, NULL, 0, &desc[HHELP]},
+ { WHOAMI, "-whoami", NULL, NULL, 0, &desc[WHOAMI]},
+
+ // these are not recognized at this point
+ { LOADOBJECT, "segments", "pmap", NULL, 0, &desc[LOADOBJECT]},
+ { LOADOBJECT_LIST, "segment_list", NULL, NULL, 0, &desc[LOADOBJECT_LIST]},
+ { LOADOBJECT_SELECT, "segment_select", NULL, "seg1,...", 1, &desc[LOADOBJECT_SELECT]},
+
+ { LAST_CMD, "xxxx", NULL, NULL, 0, NULL}
+};
+
+CmdType
+Command::get_command (char *cmd, int &arg_count, int &cparam)
+{
+ int i;
+ int len = (int) strlen (cmd);
+ bool got = false;
+ CmdType token = UNKNOWN_CMD;
+ arg_count = 0;
+ cparam = -1;
+ if (*cmd == '\0') // - command
+ return STDIN;
+ if (*cmd == '#') // comment
+ return COMMENT;
+ if (strcmp (cmd, "V") == 0 || strcmp (cmd, "-version") == 0)
+ return VERSION_cmd;
+ if (strcmp (cmd, "-help") == 0)
+ return HELP;
+ if (strncmp (cmd, NTXT ("-whoami="), 8) == 0)
+ {
+ cparam = 8;
+ return WHOAMI;
+ }
+
+ if (*cmd == '-')
+ cmd++;
+ for (i = 0;; i++)
+ {
+ if (cmd_lst[i].token == LAST_CMD)
+ break;
+ if (!strncasecmp (cmd, cmd_lst[i].str, len) ||
+ (cmd_lst[i].alt && !strncasecmp (cmd, cmd_lst[i].alt, len)))
+ {
+ // Is it unambiguous?
+ if (!strcasecmp (cmd, cmd_lst[i].str)
+ || (cmd_lst[i].alt && !strcasecmp (cmd, cmd_lst[i].alt)))
+ {
+ // exact, full-length match
+ token = cmd_lst[i].token;
+ arg_count = cmd_lst[i].arg_count;
+ return token;
+ }
+ if (got)
+ return AMBIGUOUS_CMD;
+ got = true;
+ token = cmd_lst[i].token;
+ arg_count = cmd_lst[i].arg_count;
+ }
+ }
+
+ // Did we find it?
+ if (token != UNKNOWN_CMD)
+ return token;
+
+ // See if it's the name of a index object
+ if (dbeSession)
+ {
+ int indxtype = dbeSession->findIndexSpaceByName (cmd);
+ if (indxtype >= 0)
+ {
+ // found it
+ cparam = indxtype;
+ return INDXOBJ;
+ }
+ }
+ return token;
+}
+
+const char *
+Command::get_cmd_str (CmdType type)
+{
+ for (int i = 0;; i++)
+ {
+ if (cmd_lst[i].token == LAST_CMD)
+ break;
+ if (type == cmd_lst[i].token)
+ return cmd_lst[i].str;
+ }
+ return "xxxx";
+}
+
+char *
+Command::get_err_string (Cmd_status err)
+{
+ switch (err)
+ {
+ case CMD_OK:
+ return NULL;
+ case CMD_BAD:
+ return GTXT ("command bad");
+ case CMD_AMBIGUOUS:
+ return GTXT ("command ambiguous");
+ case CMD_BAD_ARG:
+ return GTXT ("Invalid argument to command");
+ case CMD_OUTRANGE:
+ return GTXT ("argument to command is out-of-range");
+ case CMD_INVALID:
+ return GTXT ("invalid command");
+ }
+ return NULL;
+}
+
+void
+Command::print_help (char *prog_name, bool cmd_line, bool usermode, FILE *outf)
+{
+ char *fmt, *msg;
+ int i;
+ StringBuilder sb;
+ enum CmdType nc;
+ init_desc ();
+ if (usermode) // show the hidden ones, too
+ nc = HELP;
+ else
+ nc = HHELP;
+
+ if (cmd_line)
+ fprintf (outf, GTXT ("Usage: %s [ -script script | -command | - ] exper_1 ... exper_n\n"),
+ prog_name);
+ fprintf (outf, GTXT ("An alternate spelling for a command is shown in [], where applicable.\n\n"
+ "Those commands followed by a * may appear in .rc files.\n\n"
+ "Those commands followed by a $ can only appear in .rc files.\n\n"));
+ fmt = fmt_help (nc, ' ');
+ for (i = 0;; i++)
+ {
+ // check for end of list
+ if (cmd_lst[i].token == LAST_CMD)
+ break;
+ if (cmd_lst[i].token == NO_CMD) // this is a header line
+ fprintf (outf, NTXT (" %s\n"), *cmd_lst[i].desc);
+ else
+ {
+ if (strlen (cmd_lst[i].str) == 0)
+ continue;
+ // this is a real command line
+ sb.setLength (0);
+ sb.append (cmd_lst[i].str);
+ if (cmd_lst[i].alt)
+ {
+ sb.append ('[');
+ sb.append (cmd_lst[i].alt);
+ sb.append (']');
+ }
+ if (cmd_lst[i].arg)
+ {
+ sb.append (' ');
+ sb.append (cmd_lst[i].arg);
+ }
+ msg = sb.toString ();
+ fprintf (outf, fmt, msg, *cmd_lst[i].desc);
+ free (msg);
+ }
+ // check for end of list
+ if (cmd_lst[i].token == nc)
+ break;
+ }
+}
+
+// construct format for printing help
+char *
+Command::fmt_help (int nc, char head)
+{
+ int len, max_len, i;
+ static char fmt[BUFSIZ];
+
+ max_len = 0;
+ for (i = 0; i < nc; i++)
+ {
+ len = (int) strlen (cmd_lst[i].str);
+ if (cmd_lst[i].alt)
+ len += (int) strlen (cmd_lst[i].alt) + 2;
+ if (cmd_lst[i].arg)
+ len += (int) strlen (cmd_lst[i].arg) + 2;
+ if (max_len < len)
+ max_len = len;
+ }
+ snprintf (fmt, sizeof (fmt), NTXT (" %c%%-%ds %%s\n"), head, max_len + 1);
+ return fmt;
+}
+
+void
+Command::init_desc ()
+{
+ if (desc[0] != NULL)
+ return;
+ desc[FUNCS] = GTXT ("display functions with current metrics");
+ desc[HOTPCS] = GTXT ("display hot PC's with current metrics");
+ desc[HOTLINES] = GTXT ("display hot lines with current metrics");
+ desc[FDETAIL] = GTXT ("display summary metrics for each function");
+ desc[OBJECTS] = GTXT ("display object list with errors or warnings");
+ desc[COMPARE] = GTXT ("enable comparison mode for experiments *");
+ desc[PRINTMODE] = GTXT ("set the mode for printing tables *");
+ desc[LDETAIL] = GTXT ("display summary metrics for each hot line");
+ desc[PDETAIL] = GTXT ("display summary metrics for each hot PC");
+ desc[SOURCE] = GTXT ("display annotated source for function/file");
+ desc[DISASM] = GTXT ("display annotated disassembly for function/file");
+ desc[SCOMPCOM] = GTXT ("set compiler commentary classes for source *");
+ desc[STHRESH] = GTXT ("set highlight threshold for source *");
+ desc[DCOMPCOM] = GTXT ("set compiler commentary classes for disasm *");
+ desc[COMPCOM] = GTXT ("set compiler commentary classes for both source and disasm *");
+ desc[DTHRESH] = GTXT ("set highlight threshold for disasm *");
+ desc[METRIC_LIST] = GTXT ("display the available metrics and dmetrics keywords");
+ desc[METRICS] = GTXT ("set a new list of metrics");
+ desc[SORT] = GTXT ("sort tables by the specified metric");
+ desc[GPROF] = GTXT ("display the callers-callees for each function");
+ desc[CALLTREE] = GTXT ("display the tree of function calls");
+ desc[CALLFLAME] = GTXT ("request calltree flame chart -- not a command, but used in the tabs command");
+ desc[GMETRIC_LIST] = GTXT ("display the available callers-callees metrics");
+ desc[FSINGLE] = GTXT ("display the summary metrics for specified function");
+ desc[CSINGLE] = GTXT ("display the callers-callees for the specified function");
+ desc[CPREPEND] = GTXT ("add specified function to the head of the callstack fragment");
+ desc[CAPPEND] = GTXT ("add specified function to the end of the callstack fragment");
+ desc[CRMFIRST] = GTXT ("remove the first function from the callstack fragment");
+ desc[CRMLAST] = GTXT ("remove the last function from the callstack fragment");
+ desc[LEAKS] = GTXT ("display memory leaks, aggregated by callstack");
+ desc[ALLOCS] = GTXT ("display allocations, aggregated by callstack");
+ desc[HEAP] = GTXT ("display memory allocations and leaks, aggregated by callstack");
+ desc[HEAPSTAT] = GTXT ("display heap statistics report");
+ desc[IOACTIVITY] = GTXT ("display I/O activity report, aggregated by file name");
+ desc[IOVFD] = GTXT ("display I/O activity report, aggregated by file descriptor");
+ desc[IOCALLSTACK] = GTXT ("display I/O activity report, aggregated by callstack");
+ desc[IOSTAT] = GTXT ("display I/O statistics report");
+ desc[RACE_ACCS] = GTXT ("dump race access events");
+ desc[DMPI_MSGS] = GTXT ("dump mpi messages");
+ desc[DMPI_FUNCS] = GTXT ("dump mpi function calls");
+ desc[DMPI_EVENTS] = GTXT ("dump mpi trace events");
+ desc[DMEM] = GTXT ("debug command for internal use");
+ desc[DUMP_GC] = GTXT ("dump Java garbage collector events");
+ desc[DKILL] = GTXT ("send process p signal s");
+ desc[DEADLOCK_EVNTS] = GTXT ("display deadlock events");
+ desc[DEADLOCK_SUM] = GTXT ("display summary for the deadlock event");
+ desc[HEADER] = GTXT ("display information about the experiment");
+ desc[OVERVIEW_NEW] = GTXT ("display the overview of all loaded experiments");
+ desc[SAMPLE_DETAIL] = GTXT ("display the current sample list with data");
+ desc[STATISTICS] = GTXT ("display the execution statistics data");
+ desc[EXP_LIST] = GTXT ("display the existing experiments");
+ desc[DESCRIBE] = GTXT ("describe recorded data and tokens available for filtering data");
+ desc[OBJECT_SHOW] = GTXT ("set load objects to show all functions *");
+ desc[OBJECT_HIDE] = GTXT ("set load objects to hide functions *");
+ desc[OBJECT_API] = GTXT ("set load objects to show API (entry point) only *");
+ desc[OBJECTS_DEFAULT] = GTXT ("reset load objects show to defaults");
+ desc[OBJECT_LIST] = GTXT ("display load objects, functions-shown flag");
+ desc[OBJECT_SELECT] = GTXT ("set list of load objects whose functions are shown");
+ desc[SAMPLE_LIST] = GTXT ("display the list of existing samples");
+ desc[SAMPLE_SELECT] = GTXT ("set a new list of samples");
+ desc[THREAD_LIST] = GTXT ("display the list of existing threads");
+ desc[THREAD_SELECT] = GTXT ("set a new list of threads");
+ desc[LWP_LIST] = GTXT ("display the list of existing LWPs");
+ desc[LWP_SELECT] = GTXT ("set a new list of LWPs");
+ desc[CPU_LIST] = GTXT ("display the list of CPUs");
+ desc[CPU_SELECT] = GTXT ("set a new list of CPUs");
+ desc[OUTFILE] = GTXT ("open filename for subsequent output");
+ desc[APPENDFILE] = GTXT ("open filename for subsequent appended output");
+ desc[LIMIT] = GTXT ("limit output to the first n entries (n=0 for no limit)");
+ desc[NAMEFMT] = GTXT ("set long/short/mangled names for functions *");
+ desc[VIEWMODE] = GTXT ("set viewmode user|expert|machine *");
+ desc[EN_DESC] = GTXT ("enable descendant processes on|off|regex matches lineage or program name $");
+ desc[SETPATH] = GTXT ("set search path for annotated src/dis");
+ desc[ADDPATH] = GTXT ("add search path for annotated src/dis *");
+ desc[PATHMAP] = GTXT ("remap path prefix for annotated src/dis *");
+ desc[LIBDIRS] = GTXT ("set path where the gprofng libraries are installed");
+ desc[SCRIPT] = GTXT ("read er_print commands from script file");
+ desc[PROCSTATS] = GTXT ("display processing statistics");
+ desc[ADD_EXP] = GTXT ("add experiment or group");
+ desc[DROP_EXP] = GTXT ("drop experiment");
+ desc[OPEN_EXP] = GTXT ("open experiment or group (drops all loaded experiments first)");
+ desc[VERSION_cmd] = GTXT ("display the current release version");
+ desc[HELP] = GTXT ("display the list of available commands");
+ desc[QUIT] = GTXT ("terminate processing and exit");
+ desc[DMETRICS] = GTXT ("set default function list metrics $");
+ desc[DSORT] = GTXT ("set default function list sort metric $");
+ desc[TLMODE] = GTXT ("set default timeline mode, align, depth $");
+ desc[TLDATA] = GTXT ("set default timeline visible data $");
+ desc[TABS] = GTXT ("set default visible tabs $");
+ desc[RTABS] = GTXT ("set default visible tabs for Thread Analyzer Experiment $");
+ desc[INDXOBJ] = GTXT ("display index objects of a specified type with current metrics");
+ desc[INDXOBJLIST] = GTXT ("display list of index objects");
+ desc[INDXOBJDEF] = GTXT ("define a new index object type *");
+ desc[INDX_METRIC_LIST] = GTXT ("display the available index object metrics");
+ desc[IFREQ] = GTXT ("display instruction-frequency report");
+ desc[TIMELINE] = GTXT ("request timeline -- not a command, but used in the tabs command");
+ desc[MPI_TIMELINE] = GTXT ("request mpi-timeline -- not a command, but used in the tabs command");
+ desc[MPI_CHART] = GTXT ("request mpi chart -- not a command, but used in the tabs command");
+ desc[DUALSOURCE] = GTXT ("request dualsource tab -- not a command, but used in the tabs command");
+ desc[SOURCEDISAM] = GTXT ("request source/disassembly tab -- not a command, but used in the tabs command");
+ desc[DUMPNODES] = GTXT ("dump pathtree node table");
+ desc[DUMPSTACKS] = GTXT ("dump Experiment callstack tables");
+ desc[DUMPUNK] = GTXT ("dump <Unknown> PCs");
+ desc[DUMPFUNC] = GTXT ("dump functions whose name matches string");
+ desc[DUMPDOBJS] = GTXT ("dump dataobjects whose name matches string");
+ desc[DUMPMAP] = GTXT ("dump load-object map");
+ desc[DUMPENTITIES] = GTXT ("dump threads, lwps, cpus");
+ desc[DUMP_PROFILE] = GTXT ("dump clock profile events");
+ desc[DUMP_SYNC] = GTXT ("dump synchronization trace events");
+ desc[DUMP_IOTRACE] = GTXT ("dump IO trace events");
+ desc[DUMP_HWC] = GTXT ("dump HWC profile events");
+ desc[DUMP_HEAP] = GTXT ("dump heap trace events");
+ desc[IGNORE_NO_XHWCPROF] = GTXT ("ignore absence of -xhwcprof info in dataspace profiling $");
+ desc[IGNORE_FS_WARN] = GTXT ("ignore filesystem (nfs, ...) warning $");
+ desc[HHELP] = GTXT ("display help including unsupported commands");
+ desc[QQUIT] = GTXT ("terminate processing and exit");
+ desc[LOADOBJECT] = GTXT ("display the address map with current metrics");
+ desc[LOADOBJECT_LIST] = GTXT ("display segments, indicating which are selected");
+ desc[LOADOBJECT_SELECT] = GTXT ("set a new list of segments");
+ desc[FILTERS] = GTXT ("define a filter");
+
+ fhdr = GTXT ("\nCommands controlling the function list:");
+ cchdr = GTXT ("\nCommands controlling the callers-callees and calltree lists:");
+ lahdr = GTXT ("\nCommands controlling the leak and allocation lists:");
+ iohdr = GTXT ("\nCommand controlling the I/O activity report:");
+ rahdr = GTXT ("\nCommands controlling the race events lists:");
+ ddhdr = GTXT ("\nCommands controlling the deadlock events lists:");
+ typehdr = GTXT ("equivalent to \"memobj type\", or \"indxobj type\"");
+ typehdr2 = GTXT (" where type is a memory object or index object type");
+ sdhdr = GTXT ("\nCommands controlling the source and disassembly listings:");
+ lsthdr = GTXT ("\nCommands listing experiments, samples and threads:");
+ lohdr = GTXT ("\nCommands controlling load object selection:");
+ obj_allhdr = GTXT (" the special object name `all' refers to all load objects");
+ methdr = GTXT ("\nCommands that list metrics:");
+ othdr = GTXT ("\nCommands that print other displays:");
+ outhdr = GTXT ("\nCommands that control output:");
+ mischdr = GTXT ("\nMiscellaneous commands:");
+ exphdr = GTXT ("\nCommands for experiments (scripts and interactive mode only):");
+ deflthdr = GTXT ("\nDefault-setting commands:");
+ selhdr = GTXT ("\nCommands controlling old-style filters/selection:");
+ filthdr = GTXT ("\nCommands controlling filters:");
+ indxobjhdr = GTXT ("\nCommands controlling the index objects:");
+ unsuphdr = GTXT ("\nUnsupported commands:");
+ helphdr = GTXT ("\nHelp command:");
+}
diff --git a/gprofng/src/Command.h b/gprofng/src/Command.h
new file mode 100644
index 0000000..4dd28ad
--- /dev/null
+++ b/gprofng/src/Command.h
@@ -0,0 +1,286 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _COMMAND_H
+#define _COMMAND_H
+
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "Metric.h"
+#include "Hist_data.h"
+#include "dbe_types.h"
+#include "vec.h"
+#include "enums.h"
+
+// This enum lists all the commands parsed by er_print
+// The ordering here is not important, but LAST_CMD must
+// be defined as the last command for which a help line will exist
+// Command.cc has a matching list, and the ordering in
+// that list determines what shows up under the help and xhelp commands.
+// In particular, the entry for HELP is the last one printed
+// for the help command, and the entry for HHELP is the last
+// one printed for xhelp.
+
+enum CmdType
+{
+ // Pathtree-related commands
+ FUNCS = 0,
+ HOTPCS,
+ HOTLINES,
+ FDETAIL,
+ OBJECTS,
+ LDETAIL,
+ PDETAIL,
+ SOURCE,
+ DISASM,
+ METRIC_LIST,
+ METRICS,
+ SORT,
+ GPROF,
+ GMETRIC_LIST,
+ FSINGLE,
+ CSINGLE,
+ CPREPEND,
+ CAPPEND,
+ CRMFIRST,
+ CRMLAST,
+ CALLTREE,
+ CALLFLAME,
+
+ // Source/disassembly control commands
+ SCOMPCOM,
+ STHRESH,
+ DCOMPCOM,
+ COMPCOM,
+ DTHRESH,
+
+ // Heap trace-related commands
+ LEAKS,
+ ALLOCS,
+ HEAP,
+ HEAPSTAT,
+
+ // I/O trace-related commands
+ IOACTIVITY,
+ IOVFD,
+ IOCALLSTACK,
+ IOSTAT,
+
+ // Race detection related commands
+ RACE_EVNTS,
+ RACE_SUM,
+
+ // Deadlock detection commands
+ DEADLOCK_EVNTS,
+ DEADLOCK_SUM,
+
+ // DataSpace commands
+ DOBJECTS,
+ DO_SINGLE,
+ DO_LAYOUT,
+ DO_METRIC_LIST,
+
+ // MemorySpace commands
+ MEMOBJ,
+ MEMOBJLIST,
+ MEMOBJDEF,
+ MEMOBJDROP,
+ MACHINEMODEL,
+
+ // Custom tab commands
+ INDXOBJDEF,
+ INDXOBJLIST,
+ INDXOBJ,
+ INDX_METRIC_LIST,
+
+ // Old-style filtering commands
+ OBJECT_LIST,
+ OBJECT_SELECT,
+ SAMPLE_LIST,
+ SAMPLE_SELECT,
+ THREAD_LIST,
+ THREAD_SELECT,
+ LWP_LIST,
+ LWP_SELECT,
+ CPU_LIST,
+ CPU_SELECT,
+
+ // Shared Object display commands
+ OBJECT_SHOW,
+ OBJECT_HIDE,
+ OBJECT_API,
+ OBJECTS_DEFAULT,
+
+ // the new filtering commands
+ FILTERS,
+
+ // Miscellaneous commands
+ COMPARE,
+ PRINTMODE,
+ HEADER,
+ OVERVIEW_NEW,
+ SAMPLE_DETAIL,
+ STATISTICS,
+ EXP_LIST,
+ DESCRIBE,
+ OUTFILE,
+ APPENDFILE,
+ LIMIT,
+ NAMEFMT,
+ VIEWMODE,
+ EN_DESC,
+ SETPATH,
+ ADDPATH,
+ PATHMAP,
+ LIBDIRS,
+ SCRIPT,
+ VERSION_cmd,
+ QUIT,
+ PROCSTATS,
+
+ // Experiments handling commands
+ ADD_EXP,
+ DROP_EXP,
+ OPEN_EXP,
+
+ // .rc-only Commands
+ DMETRICS,
+ DSORT,
+ TLMODE,
+ TLDATA,
+ TABS,
+ TIMELINE,
+ MPI_TIMELINE,
+ MPI_CHART,
+ TIMELINE_CLASSIC_TBR,
+ SOURCE_V2,
+ DISASM_V2,
+ RTABS,
+ DUALSOURCE,
+ SOURCEDISAM,
+
+ HELP, // this is the last of the commands listed with "help"
+ IFREQ,
+ DUMPNODES,
+ DUMPSTACKS,
+ DUMPUNK,
+ DUMPFUNC,
+ DUMPDOBJS,
+ DUMPMAP,
+ DUMPENTITIES,
+ DUMP_PROFILE,
+ DUMP_SYNC,
+ DUMP_HWC,
+ DUMP_HEAP,
+ DUMP_IOTRACE,
+ RACE_ACCS,
+ DMPI_FUNCS,
+ DMPI_MSGS,
+ DMPI_EVENTS,
+ DMEM,
+ DUMP_GC,
+ DKILL,
+ IGNORE_NO_XHWCPROF,
+ IGNORE_FS_WARN,
+ QQUIT,
+ HHELP, // this is the last command listed with "xhelp"
+ NO_CMD, // Dummy command, used for headers in help
+ DUMMY_CMD, // Dummy command, used for help
+
+ // unused commands
+ LOADOBJECT,
+ LOADOBJECT_LIST,
+ LOADOBJECT_SELECT,
+
+ // Internal-only Commands
+ LAST_CMD, // No more commands for which a help line is possible
+ STDIN,
+ COMMENT,
+ WHOAMI,
+
+ // Error return "commands"
+ AMBIGUOUS_CMD,
+ UNKNOWN_CMD
+};
+
+typedef struct
+{
+ const CmdType token; // command key
+ const char *str; // command string
+ const char *alt; // alternate command string
+ const char *arg; // argument string for help
+ const int arg_count; // no. of arguments
+ char **desc; // description for help
+} Cmdtable;
+
+// Command class: never instantiated, completely static
+class Command
+{
+public:
+
+ // look up a string in the command table, return type, set number of args
+ static CmdType get_command (char *cmd, int &arg_count, int &param);
+ static const char *get_cmd_str (CmdType type);
+ static void print_help (char *prog_name, bool cmd_line, bool usermode, FILE *outf);
+ static char *get_err_string (Cmd_status err);
+
+ static const char *DEFAULT_METRICS; // default if no .rc files read
+ static const char *DEFAULT_SORT; // default if no .rc files read
+ static const char *DEFAULT_CMD; // token for default
+ static const char *ALL_CMD; // token for all
+ static const char *ANY_CMD; // token for any
+ static const char *NONE_CMD; // token for none
+ static const char *HWC_CMD; // token for all HWC
+ static const char *BIT_CMD; // token for any bit-derived metric
+
+private:
+ static const int user_no; // the last user command
+ static const int hidden_no; // the last hidden command
+ static const int command_no; // the last parsable command
+
+ static void init_desc ();
+ static char *fmt_help (int nc, char head);
+};
+
+// Analyzer display tabs
+struct DispTab
+{
+ DispTab (int ntype, int num, bool vis, CmdType token)
+ {
+ type = ntype;
+ order = num;
+ visible = vis;
+ available = true;
+ cmdtoken = token;
+ }
+
+ void setAvailability (bool val) { available = val; }
+
+ int type; // Display type
+ int order; // Order in which tabs should appear in GUI
+ bool visible; // Is Tab visible
+ bool available; // Is tab available for this experiment
+ CmdType cmdtoken; // command token
+ int param; // command parameter (used for memory space)
+};
+
+#endif /* ! _COMMAND_H */
diff --git a/gprofng/src/CompCom.cc b/gprofng/src/CompCom.cc
new file mode 100644
index 0000000..3a035a9
--- /dev/null
+++ b/gprofng/src/CompCom.cc
@@ -0,0 +1,313 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <sys/param.h>
+
+#include "demangle.h"
+#include "gp-defs.h"
+#include "StringBuilder.h"
+#include "CompCom.h"
+#include "Elf.h"
+#include "util.h"
+#include "i18n.h"
+#include "comp_com.c"
+
+CompComment::CompComment (Elf *_elf, int _compcom)
+{
+ elf = _elf;
+ compcom = _compcom;
+ elf_cls = elf->elf_getclass ();
+}
+
+CompComment::~CompComment () { }
+
+int
+CompComment::get_align (int64_t offset, int align)
+{
+ int val = (int) (offset % align);
+ if (val)
+ val = align - val;
+ return val;
+}
+
+/*
+ * Preprocesses the header structure, builds a table of messages with the line
+ * numbers, PCoffsets, original index, and compmsg pointer for each message.
+ * If the show_bits field is not in the message, this routine would fill it in
+ * from the mapping from COMPMSG_ID
+ */
+int
+CompComment::compcom_open (CheckSrcName check_src)
+{
+ if (check_src == NULL)
+ return 0;
+ Elf_Data *data = elf->elf_getdata (compcom);
+ uint64_t b_offset = data->d_off;
+ if (get_align (b_offset, 4)) // not align 4
+ return 0;
+ char *CommData = (char *) data->d_buf;
+ uint64_t offset = b_offset;
+ for (uint64_t e_offset = b_offset + data->d_size; offset < e_offset;)
+ {
+ offset += get_align (offset, (int) data->d_align);
+ if (offset >= e_offset)
+ return 0;
+ compcomhdr *hdr = (compcomhdr *) (CommData + (offset - b_offset));
+ int hdr_msgcount = elf->decode (hdr->msgcount);
+ int hdr_srcname = elf->decode (hdr->srcname);
+ int hdr_stringlen = elf->decode (hdr->stringlen);
+ int hdr_paramcount = elf->decode (hdr->paramcount);
+ size_t length = sizeof (compcomhdr) + hdr_msgcount * sizeof (compmsg) +
+ hdr_paramcount * sizeof (int32_t);
+ if (offset + length + hdr_stringlen > e_offset || hdr_srcname < 0
+ || hdr_srcname >= hdr_stringlen)
+ return 0;
+
+ // check source file
+ char *src_name = (char *) (((char*) hdr) + length + hdr_srcname);
+ if (check_src (src_name))
+ {
+ msgs = (compmsg *) (((char *) hdr) + sizeof (compcomhdr));
+ params = (int32_t *) ((char *) msgs + hdr_msgcount * sizeof (compmsg));
+ strs = (char *) ((char *) params + hdr_paramcount * sizeof (int32_t));
+
+ // initialize the I18N/L10N strings & set the visible table
+ ccm_vis_init ();
+ return hdr_msgcount;
+ }
+ offset += (length + hdr_stringlen);
+ }
+ return 0;
+}
+
+char *
+CompComment::get_demangle_name (char *fname)
+{
+ if (*fname == '_')
+ return cplus_demangle (fname, DMGL_PARAMS);
+ return NULL;
+}
+
+/*
+ * takes the message, and returns the I18N string for the message.
+ */
+char *
+CompComment::compcom_format (int index, compmsg *msg, int &visible)
+{
+ compmsg *p = msgs + index;
+ msg->instaddr = elf->decode (p->instaddr);
+ msg->lineno = elf->decode (p->lineno);
+ msg->msg_type = elf->decode (p->msg_type);
+ msg->nparam = elf->decode (p->nparam);
+ msg->param_index = elf->decode (p->param_index);
+
+ int vindex = ccm_vis_index (msg->msg_type);
+ char *mbuf;
+ Ccm_Primtype_t prim_ty;
+ visible = ccm_attrs[vindex].vis;
+ if (ccm_attrs[vindex].msg == NULL)
+ {
+ /* Print CCM_UNKNOWN message */
+ int uindex = ccm_vis_index (CCM_UNKNOWN);
+ visible = ccm_attrs[uindex].vis;
+ return dbe_sprintf (ccm_attrs[uindex].msg, vindex);
+ }
+
+ /*
+ * Construct the output buffer based on the primitive types of the
+ * message parameters.
+ *
+ * Parameter lists have to be handled carefully -- the 1 parameter
+ * is built up of all the elements separated by ", ".
+ *
+ * Old way: Case by message format string.
+ */
+ int *ind = params + msg->param_index;
+ int plist_idx = ccm_paramlist_index (msg->msg_type);
+ if (plist_idx <= 0)
+ {
+ /* No parameter list to handle; 0 parameters case is handled */
+
+ enum
+ {
+ MAX_COMPCOM_ARGS = 13
+ };
+ char *parms[MAX_COMPCOM_ARGS];
+ if (msg->nparam >= MAX_COMPCOM_ARGS)
+ {
+ fprintf (stderr,
+ GTXT ("Warning: improperly formatted compiler commentary message (%d parameters >= %d);\n please report this bug against the compiler\n"),
+ msg->nparam, MAX_COMPCOM_ARGS);
+ return NULL;
+ }
+ for (int i = 0; i < MAX_COMPCOM_ARGS; i++)
+ parms[i] = NULL; // initialize array
+ int prm_cnt = ccm_num_params (msg->msg_type);
+ if (prm_cnt != msg->nparam)
+ {
+ fprintf (stderr,
+ GTXT ("Warning, improperly formatted compiler commentary message (parameter count mismatch = %d, param# = %d, msg_type = %x, `%s');\n please report this bug against the compiler\n"),
+ prm_cnt, msg->nparam, msg->msg_type, ccm_attrs[vindex].msg);
+ return NULL;
+ }
+ for (int i = 0; i < msg->nparam; i++)
+ {
+ /* Parameters in message-type numbered from '1' */
+ prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+ if (prim_ty == CCM_PRIMTYPE_INTEGER)
+ {
+ unsigned long v = elf->decode (ind[i]);
+ parms[i] = (char*) v;
+ }
+ else if (prim_ty == CCM_PRIMTYPE_STRING)
+ {
+ char *fname = strs + elf->decode (ind[i]);
+ char *demName = get_demangle_name (fname);
+ parms[i] = demName ? demName : dbe_strdup (fname);
+ }
+ else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
+ parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
+ (unsigned long long) msg->instaddr);
+ else
+ {
+ fprintf (stderr,
+ GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n please report this bug against the compiler\n"),
+ prim_ty);
+ // Dummy code to avoid compiler's warning: static function ccm_param_hightype is not used
+ Ccm_Hitype_t hightype = CCM_HITYPE_NONE;
+ if (hightype != CCM_HITYPE_NONE)
+ hightype = ccm_param_hightype (msg->msg_type, i + 1);
+ return NULL;
+ }
+ }
+
+ /*
+ * Must make sure to pass _ALL_ params; may pass more because
+ * the format won't access the 'extra' parameters if all the
+ * rules for messages have been followed.
+ */
+ mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2],
+ parms[3], parms[4], parms[5], parms[6], parms[7],
+ parms[8], parms[9], parms[10], parms[11]);
+ // Cleanup allocated memory.
+ for (int i = 0; i < msg->nparam; i++)
+ {
+ prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+ if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_HEXSTRING)
+ free (parms[i]);
+ }
+ }
+ else
+ {
+ /*
+ * Parameter list messages never have 0 parameters; the
+ * primitive type for the parameter list elements is always
+ * the same. And as of 22-Sep-2006, it was always
+ * CCM_PRIMTYPE_STRING.
+ *
+ * Account for different bases of parameter indices and
+ * 'nparam' count (1 and 0, respectively).
+ */
+ char *parms[3];
+ if (plist_idx > (int) ((sizeof (parms) / sizeof (char*))))
+ {
+ fprintf (stderr,
+ GTXT ("Warning: improperly formatted compiler commentary message (msg->nparam=%d plist_idx=%d);\n please report this bug against the compiler\n"),
+ msg->nparam, plist_idx);
+ return NULL;
+ }
+ for (size_t i = 0; i < (sizeof (parms) / sizeof (char*)); i++)
+ parms[i] = NULL; // initialize array
+
+ StringBuilder sb;
+ prim_ty = ccm_param_primtype (msg->msg_type, plist_idx);
+ for (int i = plist_idx - 1; i < msg->nparam; i++)
+ {
+ if (i != plist_idx - 1)
+ sb.append (GTXT (", "));
+ if (prim_ty == CCM_PRIMTYPE_INTEGER)
+ sb.append (elf->decode (ind[i]));
+ else if (prim_ty == CCM_PRIMTYPE_STRING)
+ {
+ char *fname = strs + elf->decode (ind[i]);
+ char *demName = get_demangle_name (fname);
+ if (demName)
+ {
+ sb.append (demName);
+ delete demName;
+ }
+ else
+ sb.append (fname);
+ }
+ else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
+ sb.appendf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
+ (unsigned long long) msg->instaddr);
+ }
+ parms[plist_idx - 1] = sb.toString ();
+
+ for (int i = 0; i < plist_idx - 1; i++)
+ {
+ prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+ if (prim_ty == CCM_PRIMTYPE_INTEGER)
+ {
+ unsigned long v = elf->decode (ind[i]);
+ parms[i] = (char*) v;
+ }
+ else if (prim_ty == CCM_PRIMTYPE_STRING)
+ {
+ char *fname = strs + elf->decode (ind[i]);
+ char *demName = get_demangle_name (fname);
+ parms[i] = demName ? demName : dbe_strdup (fname);
+ }
+ else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
+ parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
+ (unsigned long long) msg->instaddr);
+ else
+ {
+ fprintf (stderr,
+ GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n please report this bug against the compiler\n"),
+ prim_ty);
+ return NULL;
+ }
+ }
+
+ /*
+ * We have reduced the parameter list to a single string (as
+ * the printf format specifier requires), so only have
+ * 'plist_idx' parameters.
+ */
+ mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2]);
+
+ // Cleanup allocated memory.
+ free (parms[plist_idx - 1]);
+ for (int i = 0; i < plist_idx - 1; i++)
+ {
+ prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+ if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_STRING)
+ free (parms[i]);
+ }
+ }
+ return mbuf;
+}
diff --git a/gprofng/src/CompCom.h b/gprofng/src/CompCom.h
new file mode 100644
index 0000000..e653939
--- /dev/null
+++ b/gprofng/src/CompCom.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _COMPCOM_H
+#define _COMPCOM_H
+
+#include <sys/types.h>
+#include "comp_com.h"
+
+class Elf;
+typedef int (*CheckSrcName) (char *);
+
+class CompComment
+{
+public:
+ CompComment (Elf *_elf, int _compcom);
+ ~CompComment ();
+ int compcom_open (CheckSrcName check_src);
+ char *compcom_format (int index, compmsg *msg, int &visible);
+
+private:
+ int get_align (int64_t, int align);
+ char *get_demangle_name (char *fname);
+
+ Elf *elf;
+ int compcom, elf_cls;
+ compmsg *msgs; /* the array of messages */
+ int32_t *params; /* the parameters used in the messages parameters are
+ * either integers or string-indices */
+ char *strs; /* the strings used in the messages */
+};
+
+class ComC
+{
+public:
+ ComC () { com_str = NULL; };
+ ~ComC () { free (com_str); };
+
+ int sec;
+ int type;
+ int visible;
+ int line;
+ char *com_str;
+};
+
+#endif /* _COMPCOM_H */
diff --git a/gprofng/src/DataObject.cc b/gprofng/src/DataObject.cc
new file mode 100644
index 0000000..870a531
--- /dev/null
+++ b/gprofng/src/DataObject.cc
@@ -0,0 +1,193 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Application.h"
+#include "DataObject.h"
+#include "Module.h"
+#include "debug.h"
+
+DataObject::DataObject ()
+{
+ name = NULL;
+ parent = NULL;
+ master = NULL;
+ _unannotated_name = NULL;
+ _typename = NULL;
+ _instname = NULL;
+ scope = NULL;
+ EAs = new Vector<DbeEA*>;
+ size = 0;
+ offset = (uint64_t) (-1);
+}
+
+DataObject::~DataObject ()
+{
+ free (_unannotated_name);
+ free (_typename);
+ free (_instname);
+ EAs->destroy ();
+ delete EAs;
+}
+
+// get_addr() doesn't return an actual address for a DataObject
+// but rather synthesises an address-like identifier tuple.
+// XXXX since an aggregate and its first element have identical tuples
+// may need to arrange for special-purpose sorting "by address"
+uint64_t
+DataObject::get_addr ()
+{
+ uint64_t addr;
+ if (parent && parent->get_typename ())
+ addr = MAKE_ADDRESS (parent->id, offset); // element
+ else if (parent)
+ addr = MAKE_ADDRESS (parent->id, id) | 0x8000000000000000ULL; // Scalar, Unknown
+ else if (id == dbeSession->get_Scalars_DataObject ()->id)
+ addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL; // Scalar aggregate
+ else if (id == dbeSession->get_Unknown_DataObject ()->id)
+ addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL; // Unknown aggregate
+ else
+ addr = MAKE_ADDRESS (id, 0); // aggregate
+ return addr;
+}
+
+Histable *
+DataObject::convertto (Histable_type type, Histable *)
+{
+ return type == DOBJECT ? this : NULL;
+}
+
+char
+DataObject::get_offset_mark ()
+{
+ enum
+ {
+ blocksize = 32
+ };
+
+ if (size == 0 || offset == -1)
+ return '?'; // undefined
+ if (size > blocksize)
+ return '#'; // requires multiple blocks
+ if (size == blocksize && (offset % blocksize == 0))
+ return '<'; // fits block entirely
+ if (offset % blocksize == 0)
+ return '/'; // starts block
+ if ((offset + size) % blocksize == 0)
+ return '\\'; // closes block
+ if (offset / blocksize == ((offset + size) / blocksize))
+ return '|'; // inside block
+ return 'X'; // crosses blocks unnecessarily
+}
+
+char *
+DataObject::get_offset_name ()
+{
+ char *offset_name;
+ if (parent && parent->get_typename ()) // element
+ offset_name = dbe_sprintf (GTXT ("%c%+6lld .{%s %s}"),
+ get_offset_mark (), (long long) offset,
+ _typename ? _typename : GTXT ("NO_TYPE"),
+ _instname ? _instname : GTXT ("-")); // "NO_NAME"
+ else if ((offset != -1) && (offset > 0)) // filler
+ offset_name = dbe_sprintf (GTXT ("%c%+6lld %s"), get_offset_mark (),
+ (long long) offset, get_name ());
+ else if (parent) // Scalar/Unknown element
+ offset_name = dbe_sprintf (GTXT (" .%s"), get_unannotated_name ());
+ else // aggregate
+ offset_name = dbe_strdup (get_name ());
+ return offset_name;
+}
+
+void
+DataObject::set_dobjname (char *type_name, char *inst_name)
+{
+ _unannotated_name = _typename = _instname = NULL;
+ if (inst_name)
+ _instname = dbe_strdup (inst_name);
+
+ char *buf;
+ if (parent == dbeSession->get_Scalars_DataObject ())
+ {
+ if (type_name)
+ _typename = dbe_strdup (type_name);
+ _unannotated_name = dbe_sprintf (NTXT ("{%s %s}"), type_name,
+ inst_name ? inst_name : NTXT ("-"));
+ buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name);
+ }
+ else if (parent == dbeSession->get_Unknown_DataObject ())
+ {
+ _unannotated_name = dbe_strdup (type_name);
+ buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name);
+ }
+ else
+ {
+ if (type_name)
+ _typename = dbe_strdup (type_name);
+ if (parent && parent->get_typename ())
+ buf = dbe_sprintf (NTXT ("%s.{%s %s}"),
+ parent->get_name () ? parent->get_name () : NTXT ("ORPHAN"),
+ type_name ? type_name : NTXT ("NO_TYPE"),
+ inst_name ? inst_name : NTXT ("-")); // "NO_NAME"
+ else
+ buf = dbe_sprintf (NTXT ("{%s %s}"),
+ type_name ? type_name : NTXT ("NO_TYPE"),
+ inst_name ? inst_name : NTXT ("-")); // "NO_NAME"
+ }
+ name = buf;
+ dbeSession->dobj_updateHT (this);
+}
+
+void
+DataObject::set_name (char *string)
+{
+ name = dbe_strdup (string);
+ dbeSession->dobj_updateHT (this);
+}
+
+DbeEA *
+DataObject::find_dbeEA (Vaddr EA)
+{
+ DbeEA *dbeEA;
+ int left = 0;
+ int right = EAs->size () - 1;
+ while (left <= right)
+ {
+ int index = (left + right) / 2;
+ dbeEA = EAs->fetch (index);
+ if (EA < dbeEA->eaddr)
+ right = index - 1;
+ else if (EA > dbeEA->eaddr)
+ left = index + 1;
+ else
+ return dbeEA;
+ }
+
+ // None found, create a new one
+ dbeEA = new DbeEA (this, EA);
+ EAs->insert (left, dbeEA);
+ return dbeEA;
+}
diff --git a/gprofng/src/DataObject.h b/gprofng/src/DataObject.h
new file mode 100644
index 0000000..f70bbad
--- /dev/null
+++ b/gprofng/src/DataObject.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DATAOBJECT_H
+#define _DATAOBJECT_H
+
+// A DataObject object represents a distinct dataobject.
+
+#include "dbe_structs.h"
+#include "Histable.h"
+
+extern char *DOBJ_UNSPECIFIED;
+extern char *DOBJ_UNIDENTIFIED;
+extern char *DOBJ_UNDETERMINED;
+extern char *DOBJ_ANON;
+extern char *DOBJ_UNASCERTAINABLE;
+extern char *DOBJ_UNVERIFIABLE;
+extern char *DOBJ_UNRESOLVABLE;
+
+class DataObject : public Histable
+{
+public:
+ DataObject ();
+ ~DataObject ();
+
+ static const unsigned UNSPECIFIED_ID = 0xFFFFFFFF;
+
+ int64_t size; // size of the dataobject in bytes
+ int64_t offset; // offset of dataobject from parent
+ DataObject *parent; // this dataobject's parent (if any)
+ Histable *scope; // scope of this dataobject
+ DataObject *master; // this dataobject's master (if any)
+
+ Histable_type get_type () { return DOBJECT; }
+ int64_t get_size () { return size; }
+ int64_t get_offset () { return offset; }
+ DataObject *get_parent () { return parent; }
+ DataObject *get_master () { return master; }
+ char *get_typename () { return _typename; }
+ char *get_instname () { return _instname; }
+ Histable *get_scope () { return scope; }
+
+ char *get_unannotated_name ()
+ { // name without a <Scalar> or <Unknown> prefix
+ if (_unannotated_name)
+ return _unannotated_name;
+ return get_name ();
+ }
+
+ uint64_t get_addr ();
+ char get_offset_mark ();
+ char *get_offset_name ();
+ void set_dobjname (char *type_name, char *inst_name); // dobj->parent must already be set
+ void set_name (char *);
+ Histable *convertto (Histable_type type, Histable *obj = NULL);
+ DbeEA *find_dbeEA (Vaddr EA);
+
+private:
+ char *_unannotated_name; // name without a <Scalar> or <Unknown> prefix
+ char *_typename; // name of this dataobject's type
+ char *_instname; // name of this dataobject instance
+ Vector<DbeEA*> *EAs;
+};
+
+#endif /* _DATAOBJECT_H */
diff --git a/gprofng/src/DataSpace.cc b/gprofng/src/DataSpace.cc
new file mode 100644
index 0000000..e5b48dd
--- /dev/null
+++ b/gprofng/src/DataSpace.cc
@@ -0,0 +1,558 @@
+/* Copyright (C) 2021 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 <stdlib.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataObject.h"
+#include "DbeSession.h"
+#include "MetricList.h"
+#include "Function.h"
+#include "Module.h"
+#include "MemObject.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "DataSpace.h"
+#include "LoadObject.h"
+
+#include "debug.h"
+#include "ABS.h"
+
+//char *DOBJ_UNSPECIFIED = STXT("(Not identified by the compiler as a memory-referencing instruction)");
+char *DOBJ_UNSPECIFIED = STXT("(No type information)");
+char *DOBJ_UNIDENTIFIED = STXT("(No identifying descriptor provided by the compiler)");
+char *DOBJ_UNDETERMINED = STXT("(Not determined from the symbolic information provided by the compiler)");
+char *DOBJ_ANON = STXT("(Padding in structure)");
+
+// run-time codes
+// ABS_UNSUPPORTED = 0x01, /* inappropriate HWC event type */
+// ABS_BLOCKED = 0x02, /* runtime backtrack blocker reached */
+// ABS_INCOMPLETE = 0x03, /* runtime backtrack limit reached */
+// ABS_REG_LOSS = 0x04, /* address register contaminated */
+// ABS_INVALID_EA = 0x05, /* invalid effective address value */
+
+const char *ABS_RT_CODES[NUM_ABS_RT_CODES] = {
+ "(OK)",
+ "(Dataspace data not requested during data collection)",
+ "(Backtracking was prevented by a jump or call instruction)",
+ "(Backtracking did not find trigger PC)",
+ "(Could not determine VA because registers changed after trigger instruction)",
+ "(Memory-referencing instruction did not specify a valid VA)",
+ "(UNKNOWN)"
+};
+
+// post-processing codes
+// ABS_NO_CTI_INFO = 0x10, /* no AnalyzerInfo for validation */
+// ABS_INFO_FAILED = 0x20, /* info failed to validate backtrack */
+// ABS_CTI_TARGET = 0x30, /* CTI target invalidated backtrack */
+char *DOBJ_UNASCERTAINABLE = STXT("(Module with trigger PC not compiled with -xhwcprof)");
+char *DOBJ_UNVERIFIABLE = STXT("(Backtracking failed to find a valid branch target)");
+char *DOBJ_UNRESOLVABLE = STXT("(Backtracking traversed a branch target)");
+
+char *ABS_PP_CODES[NUM_ABS_PP_CODES] = {
+ STXT ("(OK)"),
+ DOBJ_UNASCERTAINABLE,
+ DOBJ_UNVERIFIABLE,
+ DOBJ_UNRESOLVABLE,
+ STXT ("(<INTERNAL ERROR DURING POST-PROCESSING>)")
+};
+
+DataSpace::DataSpace (DbeView *_dbev, int /* _picked */)
+{
+ dbev = _dbev;
+}
+
+DataSpace::~DataSpace () { }
+
+void
+DataSpace::reset () { }
+
+char *
+DataSpace::status_str ()
+{
+ return NULL;
+}
+
+Histable *
+DataSpace::get_hist_obj (Histable::Type type, DataView *dview, long i)
+{
+ DataObject *dobj = NULL;
+ char *errcode = NTXT ("<internal error>");
+ switch (type)
+ {
+ case Histable::DOBJECT:
+ dobj = (DataObject*) dview->getObjValue (PROP_HWCDOBJ, i);
+ if (dobj == NULL)
+ {
+ Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
+ unsigned rt_code = (unsigned) ABS_GET_RT_CODE (leafVA);
+ unsigned pp_code = (unsigned) ABS_GET_PP_CODE (leafVA);
+ if (leafVA < ABS_CODE_RANGE
+ && (pp_code || (rt_code && rt_code != ABS_REG_LOSS)))
+ {
+ if (rt_code >= NUM_ABS_RT_CODES)
+ rt_code = NUM_ABS_RT_CODES - 1;
+ if (pp_code >= NUM_ABS_PP_CODES)
+ pp_code = NUM_ABS_PP_CODES - 1;
+ if (rt_code)
+ errcode = PTXT (ABS_RT_CODES[rt_code]);
+ else
+ errcode = PTXT (ABS_PP_CODES[pp_code]);
+ }
+ else
+ {
+ // associate dataobject with event
+ int index;
+
+ // search for memop in Module infoList
+ void *cstack = dview->getObjValue (PROP_MSTACK, i);
+ Histable *leafPCObj = CallStack::getStackPC (cstack, 0);
+ DbeInstr *leafPC = NULL;
+ if (leafPCObj->get_type () == Histable::INSTR)
+ leafPC = (DbeInstr*) leafPCObj;
+ else // DBELINE
+ leafPC = (DbeInstr*) leafPCObj->convertto (Histable::INSTR);
+ Function *func = leafPC->func;
+ uint64_t leafPC_offset = func->img_offset + leafPC->addr;
+ Module *mod = func->module;
+ uint32_t dtype_id = 0;
+ inst_info_t *info = NULL;
+ Vec_loop (inst_info_t*, mod->infoList, index, info)
+ {
+ if (info->offset == leafPC_offset)
+ {
+ dtype_id = info->memop->datatype_id;
+ break;
+ }
+ }
+ dobj = mod->get_dobj (dtype_id);
+ if (dobj == NULL)
+ {
+ // ensure dobj is determined
+ if (dtype_id == DataObject::UNSPECIFIED_ID)
+ errcode = PTXT (DOBJ_UNSPECIFIED);
+ else
+ errcode = PTXT (DOBJ_UNIDENTIFIED);
+ }
+ else
+ {
+ // determine associated master dataobject
+ if (!dobj->master && dobj->scope)
+ dobj->master = dbeSession->createMasterDataObject (dobj);
+ if (dobj->scope)
+ dobj = dobj->master; // use associated master
+ }
+ }
+ if (!dobj)
+ {
+ // if dobj is not set yet, supply a dobj for errcode
+ // search for a dobj with the same name
+ dobj = dbeSession->find_dobj_by_name (errcode);
+ if (dobj == NULL)
+ {
+ // create new DataObject for unknown code
+ dobj = (DataObject*) dbeSession->createHistObject (Histable::DOBJECT);
+ dobj->size = 0;
+ dobj->offset = -1;
+ dobj->parent = dbeSession->get_Unknown_DataObject ();
+ dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+ }
+ }
+ dview->setObjValue (PROP_HWCDOBJ, i, dobj);
+ }
+ break;
+ default:
+ break;
+ }
+ return dobj;
+}
+
+Hist_data *
+DataSpace::compute_metrics (MetricList *mlist, Histable::Type type,
+ Hist_data::Mode mode, Histable *sel_obj)
+{
+ int nmetrics = mlist->get_items ()->size ();
+ int sort_ind = -1;
+ Hist_data::HistItem *hi;
+ int index;
+
+ // reset event_data count for all datatypes
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ for (int i = 0, sz = lobjs ? lobjs->size () : -1; i < sz; i++)
+ {
+ LoadObject *lo = lobjs->fetch (i);
+ Vector<Module*> *modules = lo->seg_modules;
+ for (int j = 0, msize = modules ? modules->size () : -1; j < msize; j++)
+ {
+ Module *mod = modules->fetch (j);
+ mod->reset_datatypes ();
+ }
+ }
+ Hist_data *hist_data = new Hist_data (mlist, type, mode);
+
+ // add each experiment, skipping disabled and broken experiments
+ for (index = 0; index < dbeSession->nexps (); index++)
+ {
+ Experiment *exp = dbeSession->get_exp (index);
+ if (exp->broken)
+ continue;
+
+ Collection_params *params = exp->get_params ();
+ if (!params->xhw_mode)
+ continue;
+
+ char *expt_name = exp->get_expt_name ();
+ char *base_name = strrchr (expt_name, '/');
+ base_name = base_name ? base_name + 1 : expt_name;
+
+ // Determine mapping of experiment HWC metrics to hist_data metric list
+ int *xlate = new int[MAX_HWCOUNT];
+ for (unsigned i = 0; i < MAX_HWCOUNT; i++)
+ {
+ xlate[i] = -1;
+ if (params->hw_interval[i] > 0)
+ {
+ const char *ctr_name = params->hw_aux_name[i];
+ int mindex;
+ Metric *met;
+ Vec_loop (Metric*, mlist->get_items (), mindex, met)
+ {
+ if (dbe_strcmp (met->get_cmd (), ctr_name) == 0)
+ xlate[i] = mindex;
+ }
+ }
+ }
+
+ //
+ // Process hardware profiling data
+ //
+ DataView *dview = dbev->get_filtered_events (index, DATA_HWC);
+ if (dview)
+ {
+ DataDescriptor *ddscr = dview ->getDataDescriptor ();
+ if (ddscr->getProp (PROP_HWCDOBJ) == NULL)
+ {
+ PropDescr *prop = new PropDescr (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+ prop->uname = NULL;
+ prop->vtype = TYPE_OBJ;
+ ddscr->addProperty (prop);
+ }
+ }
+ if (dview && dview->getSize () != 0)
+ {
+ char *msg = NULL;
+ for (long i = 0; i < dview->getSize (); i++)
+ {
+ if (i % 5000 == 0)
+ {
+ int percent = (int) (100.0 * i / dview->getSize ());
+ if (percent == 0 && msg == NULL)
+ msg = dbe_sprintf (GTXT ("Filtering HW Profile Address Data: %s"), base_name);
+ theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+ }
+
+ uint32_t tag = dview->getIntValue (PROP_HWCTAG, i);
+ if (tag < 0 || tag >= MAX_HWCOUNT)
+ continue; // invalid HWC tag in the record; ignore it
+ int mHwcntr_idx = xlate[tag];
+ if (mHwcntr_idx < 0)
+ continue;
+
+ Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
+ if (leafVA == ABS_UNSUPPORTED)
+ continue; // skip this record
+ Histable *obj = get_hist_obj (type, dview, i);
+ if (obj == NULL)
+ continue;
+ uint64_t interval = dview->getLongValue (PROP_HWCINT, i);
+ if (HWCVAL_HAS_ERR (interval))
+ continue;
+ if (mode == Hist_data::ALL)
+ { // data_objects
+ hi = hist_data->append_hist_item (obj);
+ hi->value[mHwcntr_idx].ll += interval;
+ for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+ {
+ hi = hist_data->append_hist_item (dobj);
+ hi->value[mHwcntr_idx].ll += interval;
+ }
+ }
+ else if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
+ { // data_single
+ {
+ // for data layout, insert elements that have no metrics yet
+ DataObject *tmpParent = ((DataObject *) obj)->parent;
+ if (tmpParent && tmpParent->get_typename ())
+ {
+ // dobj is an aggregate element
+ if (!hist_data->find_hist_item (tmpParent))
+ {
+ // parent not yet a member of hist_data
+ // supply parent's children with 0 values for layout
+ Vector<DataObject*> *elements = dbeSession->get_dobj_elements (tmpParent);
+ for (long eli = 0, sz = elements->size (); eli < sz; eli++)
+ {
+ DataObject* element = elements->fetch (eli);
+ assert (!hist_data->find_hist_item (element));
+ hi = hist_data->append_hist_item (element);
+ }
+ }
+ }
+ }
+
+ // Same as for mode == Hist_data::ALL:
+ hi = hist_data->append_hist_item (obj);
+ hi->value[mHwcntr_idx].ll += interval;
+ for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+ {
+ hi = hist_data->append_hist_item (dobj);
+ hi->value[mHwcntr_idx].ll += interval;
+ }
+ }
+ else if (mode == Hist_data::SELF)
+ { // used by dbeGetSummary()
+ if (obj == sel_obj)
+ {
+ hi = hist_data->append_hist_item (obj);
+ hi->value[mHwcntr_idx].ll += interval;
+ }
+ else
+ {
+ for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+ {
+ if ((Histable*) dobj == sel_obj)
+ {
+ hi = hist_data->append_hist_item (dobj);
+ hi->value[mHwcntr_idx].ll += interval;
+ break;
+ }
+ }
+ }
+ }
+ // Update total
+ hist_data->total->value[mHwcntr_idx].ll += interval;
+ }
+ free (msg);
+ theApplication->set_progress (0, NTXT (""));
+ }
+ delete[] xlate;
+ }
+
+ // include a regular HistItem for <Total> -- for all DataObjects, and MemObjects
+ DataObject *dtot = dbeSession->get_Total_DataObject ();
+ if (mode == Hist_data::ALL || mode == Hist_data::DETAIL
+ || mode == Hist_data::LAYOUT ||
+ sel_obj == dtot)
+ {
+ hi = hist_data->append_hist_item (dtot);
+ for (int mind = 0; mind < nmetrics; mind++)
+ hi->value[mind] = hist_data->total->value[mind];
+ }
+ if (hist_data->get_status () != Hist_data::SUCCESS)
+ return hist_data;
+ theApplication->set_progress (0, GTXT ("Constructing Metrics"));
+
+ // Determine by which metric to sort if any
+ bool rev_sort = mlist->get_sort_rev ();
+
+ // Compute static metrics: SIZES, ADDRESS.
+ for (int mind = 0; mind < nmetrics; mind++)
+ {
+ Metric *mtr = mlist->get_items ()->fetch (mind);
+ if (mlist->get_sort_ref_index () == mind)
+ sort_ind = mind;
+ else if (!mtr->is_visible () && !mtr->is_tvisible ()
+ && !mtr->is_pvisible ())
+ continue;
+ Metric::Type mtype = mtr->get_type ();
+ if (mtype == Metric::SIZES)
+ {
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ Histable *h = mtr->get_comparable_obj (hi->obj);
+ hi->value[mind].tag = VT_LLONG;
+ hi->value[mind].ll = h ? h->get_size () : 0;
+ }
+ }
+ else if (mtype == Metric::ONAME
+ && (mode == Hist_data::SELF
+ || ((DataObject*) sel_obj == dbeSession->get_Total_DataObject ())))
+ {
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = VT_OFFSET; // offset labels
+ }
+ }
+ else if (mtype == Metric::ADDRESS)
+ { // pseudo-address
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = VT_ADDRESS;
+ Histable *h = mtr->get_comparable_obj (hi->obj);
+ hi->value[mind].ll = h ? h->get_addr () : 0;
+ }
+ // force sort by offset // XXXX should visibility also be set?
+ if (mode == Hist_data::SELF)
+ { // used by dbeGetSummary()
+ sort_ind = mind;
+ //hist_data->metrics->fetch(mind)->set_visible(T);
+ }
+ }
+ else
+ {
+ ValueTag vtype = mtr->get_vtype ();
+ switch (vtype)
+ {
+ case VT_ULLONG: // most Data-derived HWC metrics are VT_ULLONG
+ hist_data->total->value[mind].tag = vtype;
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = vtype;
+ }
+ break;
+ case VT_DOUBLE:
+ {
+ double prec = mtr->get_precision ();
+ hist_data->total->value[mind].tag = vtype;
+ hist_data->total->value[mind].d = hist_data->total->value[mind].ll / prec;
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = vtype;
+ hi->value[mind].d = hi->value[mind].ll / prec;
+ }
+ break;
+ }
+ default:
+ if (mtr->get_subtype () != Metric::STATIC)
+ abort ();
+ break;
+ }
+ }
+ }
+ hist_data->sort (sort_ind, rev_sort);
+ hist_data->compute_minmax ();
+ theApplication->set_progress (0, NTXT (""));
+ return hist_data;
+}
+
+
+// generate annotated structure info for data_layout
+// note: similar data traversal found in er_print_histogram::dump_detail()
+Hist_data *
+DataSpace::get_layout_data (Hist_data *sorted_data,
+ Vector<int> *marks, int /* _threshold */)
+{
+ Hist_data *data_items = NULL;
+ Hist_data::HistItem *new_item;
+ MetricList *mlist = new MetricList (sorted_data->get_metric_list ());
+ int no_metrics = mlist->get_items ()->size ();
+ int index, addr_index = -1, name_index = -1;
+ Dprintf (DEBUG_DATAOBJ, NTXT ("DataSpace::get_layout_data(ALL)\n"));
+
+ // Allocate a new Hist_data for the list, to be copied from the DataObect list
+ data_items = new Hist_data (mlist, Histable::DOBJECT, Hist_data::MODL);
+ data_items->set_status (sorted_data->get_status ());
+
+ // suppress threshold setting
+ // XXX this threshold should probably not be used
+ sorted_data->set_threshold ((double) 75. / 100.0);
+ TValue* all_empty = new TValue[no_metrics];
+ memset (all_empty, 0, sizeof (TValue) * no_metrics);
+
+ Metric *mitem;
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ // new data items have same total as original items
+ data_items->total->value[index] = sorted_data->total->value[index];
+ // empty metric items need matching types
+ all_empty[index].tag = mitem->get_vtype ();
+ if (mitem->get_type () == Metric::ONAME) name_index = index;
+ if (mitem->get_type () == Metric::ADDRESS) addr_index = index;
+ }
+
+ int64_t next_elem_offset = 0;
+ for (long i = 0; i < sorted_data->size (); i++)
+ {
+ Hist_data::HistItem* ditem = sorted_data->fetch (i);
+ DataObject* dobj = (DataObject*) (ditem->obj);
+ if (!dobj->get_parent ())
+ { // doesn't have a parent; top level item
+ next_elem_offset = 0;
+ if (i > 0)
+ { // add a blank line as separator
+ // fixme xxxxx, is it really ok to create a DataObject just for this?
+ DataObject* empty = new DataObject ();
+ empty->size = 0;
+ empty->offset = 0;
+ empty->set_name (NTXT (""));
+ new_item = sorted_data->new_hist_item (empty, Module::AT_EMPTY, all_empty);
+ new_item->value[name_index].tag = VT_LABEL;
+ new_item->value[name_index].l = NULL;
+ data_items->append_hist_item (new_item);
+ }
+ // then add the aggregate
+ new_item = sorted_data->new_hist_item (dobj, Module::AT_SRC, ditem->value);
+ new_item->value[name_index].tag = VT_OFFSET;
+ new_item->value[name_index].l = dbe_strdup (dobj->get_name ());
+ data_items->append_hist_item (new_item);
+ }
+ else
+ { // is a child
+ if (dobj->get_parent ()->get_typename ())
+ { // typed sub-element that has offset
+ if (dobj->offset > next_elem_offset)
+ { // filler entry
+ // hole in offsets
+ // fixme xxxxx, is it really ok to create a DataObject just for this?
+ DataObject* filler = new DataObject ();
+ filler->set_name (PTXT (DOBJ_ANON));
+ filler->size = (dobj->offset - next_elem_offset);
+ filler->offset = next_elem_offset;
+ new_item = sorted_data->new_hist_item (filler, Module::AT_EMPTY, all_empty);
+ new_item->value[name_index].tag = VT_OFFSET;
+ new_item->value[name_index].l = dbe_strdup (filler->get_offset_name ());
+ if (addr_index >= 0)
+ {
+ new_item->value[addr_index].tag = VT_ADDRESS;
+ new_item->value[addr_index].ll = (dobj->get_addr () - filler->size);
+ }
+ data_items->append_hist_item (new_item);
+ }
+ next_elem_offset = dobj->offset + dobj->size;
+ }
+ // then add the aggregate's subelement
+ if (marks)
+ if (sorted_data->above_threshold (ditem))
+ marks->append (data_items->size ());
+ new_item = sorted_data->new_hist_item (dobj, Module::AT_DIS, ditem->value);
+ new_item->value[name_index].tag = VT_OFFSET;
+ new_item->value[name_index].l = dbe_strdup (dobj->get_offset_name ());
+ data_items->append_hist_item (new_item);
+ }
+ }
+ delete[] all_empty;
+ return data_items;
+}
diff --git a/gprofng/src/DataSpace.h b/gprofng/src/DataSpace.h
new file mode 100644
index 0000000..c4d80fb
--- /dev/null
+++ b/gprofng/src/DataSpace.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DATASPACE_H
+#define _DATASPACE_H
+
+#include <stdio.h>
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "Exp_Layout.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "Metric.h"
+
+class DbeView;
+class DataView;
+
+class DataSpace
+{
+public:
+ DataSpace (DbeView *_dbev, int picked = 0);
+ ~DataSpace ();
+ void reset ();
+ Hist_data *compute_metrics (MetricList *, Histable::Type,
+ Hist_data::Mode, Histable*);
+ Hist_data *get_layout_data (Hist_data *sorted_data, Vector<int> *marks,
+ int threshold);
+
+ static char *status_str ();
+
+private:
+ Histable *get_hist_obj (Histable::Type, DataView*, long);
+
+ DbeView *dbev;
+};
+
+#endif /* _DATASPACE_H */
diff --git a/gprofng/src/DataStream.cc b/gprofng/src/DataStream.cc
new file mode 100644
index 0000000..8e244e2
--- /dev/null
+++ b/gprofng/src/DataStream.cc
@@ -0,0 +1,55 @@
+/* Copyright (C) 2021 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 "DataStream.h"
+#include "debug.h"
+
+DataStream::DataStream (char *filename) : Data_window (filename)
+{
+ set_span (0, -1);
+}
+
+DataStream::~DataStream () { }
+
+void
+DataStream::set_span (int64_t f_offset, int64_t sz)
+{
+ span_offset = 0;
+ span_fileoffset = f_offset;
+ int64_t fsz = get_fsize ();
+ span_size = sz == -1 ? fsz : sz;
+ if (span_fileoffset >= fsz)
+ span_fileoffset = fsz;
+ if (span_size > fsz - span_fileoffset)
+ span_size = fsz - span_fileoffset;
+}
+
+int64_t
+DataStream::read (void *buf, int64_t len)
+{
+ if (len > span_size - span_offset)
+ len = span_size - span_offset;
+ int64_t off = span_offset + span_fileoffset;
+ span_offset += len;
+ get_data (off, len, buf);
+ return len;
+}
diff --git a/gprofng/src/DataStream.h b/gprofng/src/DataStream.h
new file mode 100644
index 0000000..59ee293
--- /dev/null
+++ b/gprofng/src/DataStream.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DATASTREAM_H
+#define _DATASTREAM_H
+
+#include "Data_window.h"
+
+// sequential access to the file
+class DataStream : public Data_window
+{
+public:
+ // Create an empty data window.
+ DataStream (char *file_name);
+ ~DataStream ();
+ void set_span (int64_t f_offset, int64_t sz);
+ int64_t read (void *buf, int64_t len);
+
+ template <typename Key_t> inline int64_t
+ read (Key_t &val)
+ {
+ int64_t sz = read (&val, sizeof (val));
+ if (need_swap_endian && sz == sizeof (val))
+ swapByteOrder (&val, sizeof (val));
+ return sz;
+ }
+
+private:
+ int64_t span_offset;
+ int64_t span_size; // the window size
+ int64_t span_fileoffset; // the window begin on the file
+};
+
+#endif /* _DATASTREAM_H */
diff --git a/gprofng/src/Data_window.cc b/gprofng/src/Data_window.cc
new file mode 100644
index 0000000..d9b0067
--- /dev/null
+++ b/gprofng/src/Data_window.cc
@@ -0,0 +1,241 @@
+/* Copyright (C) 2021 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 <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h> // for close();
+
+#include "util.h"
+#include "Data_window.h"
+#include "debug.h"
+
+enum
+{
+ MINBUFSIZE = 1 << 16,
+ WIN_ALIGN = 8
+};
+
+Data_window::Data_window (char *file_name)
+{
+ Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:%d %s\n"), (int) __LINE__, STR (file_name));
+ page_size = sysconf (_SC_PAGESIZE);
+ need_swap_endian = false;
+ opened = false;
+ fsize = 0;
+ base = NULL;
+ woffset = 0;
+ wsize = 0;
+ basesize = 0;
+ fname = dbe_strdup (file_name);
+ mmap_on_file = false;
+ use_mmap = false;
+#if DEBUG
+ if (DBE_USE_MMAP)
+ use_mmap = true;
+#endif /* DEBUG */
+ fd = open64 (fname, O_RDONLY);
+ if (fd == -1)
+ return;
+ fsize = lseek (fd, 0, SEEK_END);
+ if (fsize == 0)
+ {
+ close (fd);
+ fd = -1;
+ return;
+ }
+ opened = true;
+ if (use_mmap)
+ {
+ if (fsize != -1)
+ {
+ base = (void*) mmap (NULL, (size_t) fsize, PROT_READ, MAP_PRIVATE, fd, 0);
+ close (fd);
+ fd = -1;
+ if (base == MAP_FAILED)
+ {
+ base = NULL;
+ use_mmap = false;
+ return;
+ }
+ mmap_on_file = true;
+ wsize = fsize;
+ }
+ }
+}
+
+void *
+Data_window::bind (int64_t file_offset, int64_t minSize)
+{
+ Span span;
+ span.length = fsize - file_offset;
+ span.offset = file_offset;
+ return bind (&span, minSize);
+}
+
+void *
+Data_window::bind (Span *span, int64_t minSize)
+{
+ // Do any necessary mapping to access the desired span of data
+ // and return a pointer to the first byte.
+ Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:bind:%d offset=%llx:%lld minSize=%lld \n"),
+ (int) __LINE__, (long long) span->offset, (long long) span->length, (long long) minSize);
+ if (minSize == 0 || span->length < minSize)
+ return NULL;
+
+ if (span->offset < woffset || span->offset + minSize > woffset + wsize)
+ {
+ // Remap the window
+ if (span->offset + minSize > fsize)
+ return NULL;
+ int myfd = fd;
+ if (myfd == -1)
+ {
+ if (fname)
+ myfd = open64 (fname, O_RDONLY, 0);
+ if (myfd == -1)
+ return NULL;
+ }
+ bool remap_failed = true;
+ if (use_mmap)
+ {
+ if (base)
+ {
+ munmap ((caddr_t) base, (size_t) wsize);
+ base = NULL;
+ }
+ woffset = span->offset & ~(page_size - 1);
+ wsize = page_size * ((MINBUFSIZE + page_size - 1) / page_size);
+ if (span->offset + minSize > woffset + wsize)
+ // Extend a window
+ wsize += page_size * ((span->offset + minSize -
+ woffset - wsize + page_size - 1) / page_size);
+ base = (void *) mmap (0, (size_t) wsize, PROT_READ, MAP_SHARED, fd, woffset);
+ if (base == MAP_FAILED)
+ {
+ base = NULL;
+ use_mmap = false;
+ }
+ remap_failed = (base == NULL);
+ }
+ if (remap_failed)
+ {
+ remap_failed = false;
+ woffset = span->offset & ~(WIN_ALIGN - 1);
+ wsize = minSize + (span->offset % WIN_ALIGN);
+ if (wsize < MINBUFSIZE)
+ wsize = MINBUFSIZE;
+ if (wsize > fsize)
+ wsize = fsize;
+ if (basesize < wsize)
+ { // Need to realloc 'base'
+ free (base);
+ basesize = wsize;
+ base = (void *) malloc (basesize);
+ Dprintf (DEBUG_DATA_WINDOW,
+ NTXT ("Data_window:bind:%d realloc basesize=%llx woffset=%lld \n"),
+ (int) __LINE__, (long long) basesize, (long long) woffset);
+ if (base == NULL)
+ {
+ basesize = 0;
+ remap_failed = true;
+ }
+ }
+ if (wsize > fsize - woffset)
+ wsize = fsize - woffset;
+ off_t woff = (off_t) woffset;
+ if (base == NULL || woff != lseek (myfd, woff, SEEK_SET)
+ || wsize != read_from_file (myfd, base, wsize))
+ remap_failed = true;
+ }
+ if (fd == -1)
+ close (myfd);
+ if (remap_failed)
+ {
+ woffset = 0;
+ wsize = 0;
+ return NULL;
+ }
+ }
+ return (void *) ((char*) base + span->offset - woffset);
+}
+
+void *
+Data_window::get_data (int64_t offset, int64_t size, void *datap)
+{
+ if (size <= 0)
+ return NULL;
+ void *buf = bind (offset, size);
+ if (buf == NULL)
+ return NULL;
+ if (datap == NULL && !mmap_on_file)
+ // Can be remmaped or reallocated. Need to make a copy
+ datap = (void *) malloc (size);
+ if (datap)
+ {
+ memcpy (datap, buf, (size_t) size);
+ return datap;
+ }
+ return buf;
+}
+
+Data_window::~Data_window ()
+{
+ free (fname);
+ if (fd != -1)
+ close (fd);
+ if (base)
+ {
+ if (use_mmap)
+ munmap ((caddr_t) base, (size_t) wsize);
+ else
+ free (base);
+ }
+}
+
+int64_t
+Data_window::get_buf_size ()
+{
+ int64_t sz = MINBUFSIZE;
+ if (sz < basesize)
+ sz = basesize;
+ if (sz > fsize)
+ sz = fsize;
+ return sz;
+}
+
+int64_t
+Data_window::copy_to_file (int f, int64_t offset, int64_t size)
+{
+ long long bsz = get_buf_size ();
+ for (long long n = 0; n < size;)
+ {
+ long long sz = (bsz <= (size - n)) ? bsz : (size - n);
+ void *b = bind (offset + n, sz);
+ if (b == NULL)
+ return n;
+ long long len = write (f, b, sz);
+ if (len <= 0)
+ return n;
+ n += len;
+ }
+ return size;
+}
diff --git a/gprofng/src/Data_window.h b/gprofng/src/Data_window.h
new file mode 100644
index 0000000..a3e98c0
--- /dev/null
+++ b/gprofng/src/Data_window.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DATA_WINDOW_H
+#define _DATA_WINDOW_H
+
+// The Data_window class hiearchy is used to access raw data in the
+// experiment record.
+//
+// The Data_window base class implements a set of windows into a raw data file.
+// It is responsible for mapping and unmapping regions of the file as
+// requested by other levels inside of the DBE.
+
+#include "util.h"
+
+class Data_window
+{
+public:
+
+ // Span in data file
+ typedef struct
+ {
+ int64_t offset; // file offset
+ int64_t length; // span length
+ } Span;
+
+ Data_window (char *filename);
+ ~Data_window ();
+
+ // Return address of "offset" byte of window for "length" bytes.
+ // Return 0 on error or locked.
+ void *bind (Span *span, int64_t minSize);
+ void *bind (int64_t file_offset, int64_t minSize);
+ void *get_data (int64_t offset, int64_t size, void *datap);
+ int64_t get_buf_size ();
+ int64_t copy_to_file (int f, int64_t offset, int64_t size);
+
+ bool not_opened () { return !opened; }
+ off64_t get_fsize () { return fsize; }
+
+ template <typename Key_t> inline Key_t
+ get_align_val (Key_t *vp)
+ {
+ if (sizeof (Key_t) <= sizeof (int))
+ return *vp;
+ // 64-bit value can have a wrong alignment
+ Key_t val = (Key_t) 0;
+ uint32_t *p1 = (uint32_t *) vp;
+ uint32_t *p2 = (uint32_t*) (&val);
+ p2[0] = p1[0];
+ p2[1] = p1[1];
+ return val;
+ }
+
+ template <typename Key_t> inline Key_t
+ decode (Key_t &v)
+ {
+ Key_t val = get_align_val (&v);
+ if (need_swap_endian)
+ swapByteOrder (&val, sizeof (val));
+ return val;
+ }
+
+ bool need_swap_endian;
+ char *fname; // file name
+
+protected:
+ int fd; // file descriptor
+ bool mmap_on_file;
+
+private:
+ long page_size; // used in mmap()
+ bool use_mmap;
+ bool opened;
+ int64_t fsize; // file size
+ void *base; // current window
+ int64_t woffset; // offset of current window
+ int64_t wsize; // size of current window
+ int64_t basesize; // size of allocated window
+};
+
+#endif /* _DATA_WINDOW_H */
diff --git a/gprofng/src/Dbe.cc b/gprofng/src/Dbe.cc
new file mode 100644
index 0000000..1a6e521
--- /dev/null
+++ b/gprofng/src/Dbe.cc
@@ -0,0 +1,10371 @@
+/* Copyright (C) 2021 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 <errno.h>
+#include <sys/types.h> // open, chmod
+#include <signal.h>
+#include <fcntl.h> // open
+#include <strings.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "Histable.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "BaseMetric.h"
+#include "CallStack.h"
+#include "collctrl.h"
+#include "Command.h"
+#include "Dbe.h"
+#include "DbeApplication.h"
+#include "DefaultMap.h"
+#include "LoadObject.h"
+#include "Experiment.h"
+#include "IndexObject.h"
+#include "IOActivity.h"
+#include "PreviewExp.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "DataSpace.h"
+#include "MemorySpace.h"
+#include "DataObject.h"
+#include "MemObject.h"
+#include "Filter.h"
+#include "FilterSet.h"
+#include "FilterExp.h"
+#include "Sample.h"
+#include "Print.h"
+#include "StringBuilder.h"
+#include "dbe_types.h"
+#include "ExpGroup.h"
+#include "vec.h"
+#include "UserLabel.h"
+#include "DbeFile.h"
+#include "PathTree.h"
+
+// Data structures for managing the collector control info for Collection GUI
+static Coll_Ctrl *col_ctr = NULL;
+
+template<> VecType Vector<int>::type ()
+{
+ return VEC_INTEGER;
+}
+
+template<> VecType Vector<unsigned>::type ()
+{
+ return VEC_INTEGER;
+}
+
+template<> VecType Vector<char>::type ()
+{
+ return VEC_CHAR;
+}
+
+template<> VecType Vector<bool>::type ()
+{
+ return VEC_BOOL;
+}
+
+template<> VecType Vector<double>::type ()
+{
+ return VEC_DOUBLE;
+}
+
+template<> VecType Vector<long long>::type ()
+{
+ return VEC_LLONG;
+}
+
+template<> VecType Vector<uint64_t>::type ()
+{
+ return VEC_LLONG;
+}
+
+template<> VecType Vector<void*>::type ()
+{
+ return VEC_VOIDARR;
+}
+
+template<> VecType Vector<char*>::type ()
+{
+ return VEC_STRING;
+}
+
+template<> VecType Vector<Vector<int>*>::type ()
+{
+ return VEC_INTARR;
+}
+
+template<> VecType Vector<Vector<char*>*>::type ()
+{
+ return VEC_STRINGARR;
+}
+
+template<> VecType Vector<Vector<long long>*>::type ()
+{
+ return VEC_LLONGARR;
+}
+
+// gcc won't instantiate Vector<unsigned>::type() without it
+Vector<unsigned> __dummy_unsigned_vector;
+
+#define CASE_S(x) case x: return #x
+static const char *
+dsp_type_to_string (int t)
+{
+ switch (t)
+ {
+ CASE_S (DSP_FUNCTION);
+ CASE_S (DSP_LINE);
+ CASE_S (DSP_PC);
+ CASE_S (DSP_SOURCE);
+ CASE_S (DSP_DISASM);
+ CASE_S (DSP_SELF);
+ CASE_S (DSP_CALLER);
+ CASE_S (DSP_CALLEE);
+ CASE_S (DSP_CALLTREE);
+ CASE_S (DSP_TIMELINE);
+ CASE_S (DSP_STATIS);
+ CASE_S (DSP_EXP);
+ CASE_S (DSP_LEAKLIST);
+ CASE_S (DSP_MEMOBJ);
+ CASE_S (DSP_DATAOBJ);
+ CASE_S (DSP_DLAYOUT);
+ CASE_S (DSP_SRC_FILE);
+ CASE_S (DSP_IFREQ);
+ CASE_S (DSP_RACES);
+ CASE_S (DSP_INDXOBJ);
+ CASE_S (DSP_DUALSOURCE);
+ CASE_S (DSP_SOURCE_DISASM);
+ CASE_S (DSP_DEADLOCKS);
+ CASE_S (DSP_SOURCE_V2);
+ CASE_S (DSP_DISASM_V2);
+ CASE_S (DSP_IOACTIVITY);
+ CASE_S (DSP_OVERVIEW);
+ CASE_S (DSP_IOCALLSTACK);
+ CASE_S (DSP_HEAPCALLSTACK);
+ CASE_S (DSP_SAMPLE);
+ default:
+ break;
+ }
+ return NTXT ("ERROR");
+}
+
+enum
+{
+ COMPARE_BIT = 1 << 8,
+ MTYPE_MASK = (1 << 8) - 1,
+ GROUP_ID_SHIFT = 16
+};
+
+static DbeView *
+getDbeView (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ return dbev;
+}
+
+
+Vector<char*> *
+dbeGetInitMessages ()
+{
+ // If any comments from the .rc files, send them to the GUI
+ Emsg *msg = theDbeApplication->fetch_comments ();
+ int size = 0;
+ while (msg != NULL)
+ {
+ size++;
+ msg = msg->next;
+ }
+
+ // Initialize Java String array
+ Vector<char*> *list = new Vector<char*>(size);
+ msg = theDbeApplication->fetch_comments ();
+ size = 0;
+ int i = 0;
+ while (msg != NULL)
+ {
+ char *str = msg->get_msg ();
+ list->store (i, dbe_strdup (str));
+ i++;
+ msg = msg->next;
+ }
+
+ // now delete the comments
+ theDbeApplication->delete_comments ();
+ return list;
+}
+
+Vector<char*> *
+dbeGetExpPreview (int /*dbevindex*/, char *exp_name)
+{
+ PreviewExp *preview = new PreviewExp ();
+ preview->experiment_open (exp_name);
+ preview->open_epilogue ();
+
+ // Initialize Java String array
+ Vector<char*> *info = preview->preview_info ();
+ int size = info->size ();
+ Vector<char*> *list = new Vector<char*>(size);
+
+ // Get experiment names
+ for (int i = 0; i < size; i++)
+ {
+ char *str = info->fetch (i);
+ if (str == NULL)
+ str = GTXT ("N/A");
+ list->store (i, dbe_strdup (str));
+ }
+ delete info;
+ delete preview;
+ return list;
+}
+
+char *
+dbeGetExpParams (int /*dbevindex*/, char *exp_name)
+{
+ PreviewExp *preview = new PreviewExp ();
+ preview->experiment_open (exp_name);
+
+ // Initialize Java String array
+ char *arg_list = dbe_strdup (preview->getArgList ());
+ delete preview;
+ return arg_list;
+}
+
+/**
+ * Gets File Attributes according to the specified format
+ * Supported formats:
+ * "/bin/ls -dl " - see 'man ls' for details
+ * @param filename
+ * @param format
+ * @return char * attributes
+ */
+char *
+dbeGetFileAttributes (const char *filename, const char *format)
+{
+ if (format != NULL)
+ {
+ if (!strcmp (format, NTXT ("/bin/ls -dl ")))
+ {
+ // A kind of "/bin/ls -dl " simulation
+ struct stat64 sbuf;
+ sbuf.st_mode = 0;
+ dbe_stat (filename, &sbuf);
+ if (S_IREAD & sbuf.st_mode)
+ { // Readable
+ if (S_ISDIR (sbuf.st_mode) != 0)
+ return dbe_sprintf (NTXT ("%s %s\n"), NTXT ("drwxrwxr-x"), filename);
+ else if (S_ISREG (sbuf.st_mode) != 0)
+ return dbe_sprintf (NTXT ("%s %s\n"), NTXT ("-rwxrwxr-x"), filename);
+ }
+ }
+ }
+ return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Gets list of files for specified directory according to the specified format
+ * Supported formats:
+ * "/bin/ls -a" - see 'man ls' for details
+ * "/bin/ls -aF" - see 'man ls' for details
+ * @param dirname
+ * @param format
+ * @return char * files
+ */
+char *
+dbeGetFiles (const char *dirname, const char *format)
+{
+ if (format != NULL)
+ return dbe_read_dir (dirname, format);
+ return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Creates the directory named by this full path name, including any
+ * necessary but nonexistent parent directories.
+ * @param dirname
+ * @return result
+ */
+char *
+dbeCreateDirectories (const char *dirname)
+{
+ if (dirname != NULL)
+ {
+ char *res = dbe_create_directories (dirname);
+ if (res != NULL)
+ return res;
+ }
+ return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Deletes the file or the directory named by the specified path name.
+ * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
+ * @param const char *pathname
+ * @return int result
+ */
+char *
+dbeDeleteFile (const char *pathname)
+{
+ // return unlink(pathname);
+ if (pathname != NULL)
+ {
+ char *res = dbe_delete_file (pathname);
+ if (res != NULL)
+ return res;
+ }
+ return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Reads the file named by the specified path name.
+ * Temporary limitation: file should be "text only" and its size should be less than the 1 MB limit.
+ * If the operation was successful, the contents is in the first element, and second element is NULL.
+ * If the operation failed, then first element is NULL, and second element contains the error message.
+ * @param const char *pathname
+ * @return Vector<char*> *result
+ */
+Vector<char*> *
+dbeReadFile (const char *pathname)
+{
+ Vector<char*> *result = new Vector<char*>(2);
+ int limit = 1024 * 1024; // Temporary limit: 1 MB
+ char * contents = (char *) malloc (limit);
+ StringBuilder sb;
+ if (NULL == contents)
+ {
+ sb.sprintf (NTXT ("\nError: Cannot allocate %d bytes\n"), limit);
+ result->store (0, NULL);
+ result->store (1, sb.toString ()); // failure
+ return result;
+ }
+ int fd = open (pathname, O_RDONLY);
+ if (fd >= 0)
+ {
+ int64_t bytes = read_from_file (fd, contents, limit);
+ close (fd);
+ if (bytes >= limit)
+ {
+ sb.sprintf (NTXT ("\nError: file size is greater than the limit (%d bytes)\n"), limit);
+ result->store (0, NULL);
+ result->store (1, sb.toString ()); // failure
+ }
+ else
+ {
+ contents[bytes] = '\0'; // add string terminator
+ result->store (0, contents);
+ result->store (1, NULL); // success
+ }
+ }
+ else
+ {
+ sb.sprintf (NTXT ("\nError: Cannot open file %s\n"), pathname);
+ result->store (0, NULL);
+ result->store (1, sb.toString ()); // failure
+ free (contents);
+ }
+ return result;
+}
+
+/**
+ * Writes the file named by the specified path name.
+ * Temporary limitation: file should be "text only" and its size should be less than the 1 MB limit.
+ * If the operation failed, then -1 is returned.
+ * @param const char *pathname
+ * @return int result (written bytes)
+ */
+int
+dbeWriteFile (const char *pathname, const char *contents)
+{
+ int result = -1; // error
+ size_t len = 0;
+ if (NULL != contents)
+ len = strlen (contents);
+ size_t limit = 1024 * 1024; // Temporary limit: 1 MB
+ if (len > limit) return result;
+ unlink (pathname);
+ mode_t mode = S_IRUSR | S_IWUSR;
+ int fd = open (pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (fd >= 0)
+ { // replace file contents
+ chmod (pathname, /*S_IRUSR || S_IWUSR*/ 0600); // rw for owner only
+ ssize_t bytes = 0;
+ if (len > 0)
+ bytes = write (fd, contents, len);
+ close (fd);
+ result = (int) bytes;
+ }
+ return result;
+}
+
+/**
+ * Gets list of running processes according to the specified format
+ * Supported formats:
+ * "/bin/ps -ef" - see 'man ps' for details
+ * @param format
+ * @return char * processes
+ */
+char *
+dbeGetRunningProcesses (const char *format)
+{
+ if (format != NULL)
+ return dbe_get_processes (format);
+ return dbe_strdup (NTXT (""));
+}
+
+//
+// Open experiment
+//
+char *
+dbeOpenExperimentList (int /* dbevindex */, Vector<Vector<char*>*> *groups,
+ bool sessionRestart)
+{
+ if (sessionRestart)
+ dbeSession->reset ();
+ char *errstr;
+ // Open experiments
+ try
+ {
+ errstr = dbeSession->setExperimentsGroups (groups);
+ }
+ catch (ExperimentLoadCancelException *)
+ {
+ errstr = dbe_strdup (NTXT ("Experiment Load Cancelled"));
+ }
+ return errstr;
+}
+
+//
+// Drop experiments
+//
+char *
+dbeDropExperiment (int /* dbevindex */, Vector<int> *drop_index)
+{
+ for (int i = drop_index->size () - 1; i >= 0; i--)
+ {
+ char *ret = dbeSession->drop_experiment (drop_index->fetch (i));
+ if (ret != NULL)
+ return ret;
+ }
+ return NULL;
+}
+
+/**
+ * Read .er.rc file from the specified location
+ * @param path
+ * @return
+ */
+char *
+dbeReadRCFile (int dbevindex, char* path)
+{
+ DbeView *dbev = getDbeView (dbevindex);
+ char *err_msg = dbev->get_settings ()->read_rc (path);
+ return err_msg;
+}
+
+char *
+dbeSetExperimentsGroups (Vector<Vector<char*>*> *groups)
+{
+ int cmp_mode = dbeSession->get_settings ()->get_compare_mode ();
+ if (groups->size () < 2)
+ cmp_mode = CMP_DISABLE;
+ else if (cmp_mode == CMP_DISABLE)
+ cmp_mode = CMP_ENABLE;
+ for (int i = 0;; i++)
+ {
+ DbeView *dbev = dbeSession->getView (i);
+ if (dbev == NULL)
+ break;
+ dbev->get_settings ()->set_compare_mode (cmp_mode);
+ }
+ char *err_msg = dbeSession->setExperimentsGroups (groups);
+
+ // automatically load machine model if applicable
+ dbeDetectLoadMachineModel (0);
+ return err_msg;
+}
+
+Vector<Vector<char*>*> *
+dbeGetExperimensGroups ()
+{
+ Vector<Vector<char*>*> *grops = dbeSession->getExperimensGroups ();
+ return grops;
+}
+
+Vector<int> *
+dbeGetFounderExpId (Vector<int> *expIds)
+{
+ Vector<int> *ret = new Vector<int>(expIds->size ());
+ for (int i = 0; i < expIds->size (); i++)
+ {
+ int expId = expIds->fetch (i);
+ Experiment *exp = dbeSession->get_exp (expId);
+ if (exp != NULL)
+ {
+ int founderExpId = exp->getBaseFounder ()->getExpIdx ();
+ ret->store (i, founderExpId);
+ }
+ else
+ ret->store (i, -1);
+ }
+ return ret;
+}
+
+Vector<int> *
+dbeGetUserExpId (Vector<int> *expIds)
+{
+ // returns "User Visible" ids used for EXPID filters and timeline processes
+ Vector<int> *ret = new Vector<int>(expIds->size ());
+ for (int i = 0; i < expIds->size (); i++)
+ {
+ int expId = expIds->fetch (i);
+ Experiment *exp = dbeSession->get_exp (expId);
+ if (exp != NULL)
+ {
+ int userExpId = exp->getUserExpId ();
+ ret->store (i, userExpId);
+ }
+ else
+ ret->store (i, -1);
+ }
+ return ret;
+}
+
+//
+// Get experiment groupid
+//
+Vector<int> *
+dbeGetExpGroupId (Vector<int> *expIds)
+{
+ Vector<int> *ret = new Vector<int>(expIds->size ());
+ for (int i = 0; i < expIds->size (); i++)
+ {
+ int expId = expIds->fetch (i);
+ Experiment *exp = dbeSession->get_exp (expId);
+ if (exp != NULL)
+ {
+ int gId = exp->groupId;
+ ret->store (i, gId);
+ }
+ else
+ ret->store (i, -1);
+ }
+ return ret;
+}
+
+Vector<char*> *
+dbeGetExpsProperty (const char *prop_name)
+{
+ long nexps = dbeSession->nexps ();
+ if (prop_name == NULL || nexps == 0)
+ return NULL;
+ Vector<char*> *list = new Vector<char*>(nexps);
+ StringBuilder sb;
+ int empty = 1;
+ int prop = 99;
+ if (strcasecmp (prop_name, NTXT ("ERRORS")) == 0)
+ prop = 1;
+ else if (strcasecmp (prop_name, NTXT ("WARNINGS")) == 0)
+ prop = 2;
+ if (prop < 3)
+ {
+ for (long i = 0; i < nexps; i++)
+ {
+ Experiment *exp = dbeSession->get_exp (i);
+ char *nm = exp->get_expt_name ();
+ sb.setLength (0);
+ for (Emsg *emsg = (prop == 1) ? exp->fetch_errors () : exp->fetch_warnings ();
+ emsg; emsg = emsg->next)
+ sb.appendf (NTXT ("%s: %s\n"), STR (nm), STR (emsg->get_msg ()));
+ char *s = NULL;
+ if (sb.length () > 0)
+ {
+ s = sb.toString ();
+ empty = 0;
+ }
+ list->append (s);
+ }
+ }
+ if (empty)
+ {
+ delete list;
+ list = NULL;
+ }
+ return list;
+}
+
+//
+// Get experiment names
+//
+Vector<char*> *
+dbeGetExpName (int /*dbevindex*/)
+{
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return NULL;
+ // Initialize Java String array
+ Vector<char*> *list = new Vector<char*>(size);
+
+ // Get experiment names
+ for (int i = 0; i < size; i++)
+ {
+ Experiment *texp = dbeSession->get_exp (i);
+ char *buf = dbe_sprintf (NTXT ("%s [%s]"), texp->get_expt_name (),
+ texp->utargname != NULL ? texp->utargname : GTXT ("(unknown)"));
+ list->store (i, buf);
+ }
+ return list;
+}
+
+//
+// Get experiment state
+//
+Vector<int> *
+dbeGetExpState (int /* dbevindex */)
+{
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return NULL;
+ // Initialize Java array
+ Vector<int> *state = new Vector<int>(size);
+
+ // Get experiment state
+ for (int i = 0; i < size; i++)
+ {
+ Experiment *exp = dbeSession->get_exp (i);
+ int set = EXP_SUCCESS;
+ if (exp->get_status () == Experiment::FAILURE)
+ set |= EXP_FAILURE;
+ if (exp->get_status () == Experiment::INCOMPLETE)
+ set |= EXP_INCOMPLETE;
+ if (exp->broken)
+ set |= EXP_BROKEN;
+ if (exp->obsolete)
+ set |= EXP_OBSOLETE;
+ state->store (i, set);
+ }
+ return state;
+}
+
+//
+// Get enabled experiment indices
+//
+Vector<bool> *
+dbeGetExpEnable (int dbevindex)
+{
+ DbeView *dbev = getDbeView (dbevindex);
+ int size = dbeSession->nexps ();
+ if (dbev == NULL || size == 0)
+ return NULL;
+
+ // Get enabled experiment
+ Vector<bool> *enable = new Vector<bool>(size);
+ for (int i = 0; i < size; i++)
+ {
+ bool val = dbev->get_exp_enable (i) && !dbeSession->get_exp (i)->broken;
+ enable->store (i, val);
+ }
+ return enable;
+}
+
+//
+// Get enabled experiment indices
+//
+bool
+dbeSetExpEnable (int dbevindex, Vector<bool> *enable)
+{
+ DbeView *dbev = getDbeView (dbevindex);
+ bool ret = false;
+ int size = dbeSession->nexps ();
+ if (dbev == NULL || size == 0)
+ return false;
+
+ // set enable, as per input vector
+ for (int i = 0; i < size; i++)
+ if (!dbeSession->get_exp (i)->broken
+ && dbev->get_exp_enable (i) != enable->fetch (i))
+ {
+ dbev->set_exp_enable (i, enable->fetch (i));
+ ret = true;
+ }
+ return ret;
+}
+
+//
+// Get experiment info
+//
+Vector<char*> *
+dbeGetExpInfo (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return NULL;
+
+ // Initialize Java String array
+ Vector<char*> *list = new Vector<char*>(size * 2 + 1);
+
+ // Get experiment names
+ Vector<LoadObject*> *text_segments = dbeSession->get_text_segments ();
+ char *msg = pr_load_objects (text_segments, NTXT (""));
+ delete text_segments;
+ list->store (0, msg);
+ int k = 1;
+ for (int i = 0; i < size; i++)
+ {
+ Experiment *exp = dbeSession->get_exp (i);
+ char *msg0 = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT (""));
+ char *msg1 = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT (""));
+ char *msg2 = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT (""));
+ char *msg3 = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT (""));
+ char *msg4 = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT (""));
+ msg = dbe_sprintf (NTXT ("%s%s%s%s"), msg1, msg2, msg3, msg4);
+ list->store (k++, msg0);
+ list->store (k++, msg);
+ free (msg1);
+ free (msg2);
+ free (msg3);
+ free (msg4);
+ }
+ return list;
+}
+
+bool
+dbeGetViewModeEnable ()
+{
+ return dbeSession->has_ompavail () || dbeSession->has_java ();
+}
+
+bool
+dbeGetJavaEnable ()
+{
+ return dbeSession->has_java ();
+}
+
+int
+dbeUpdateNotes (int dbevindex, int exp_id, int type, char* text, bool handle_file)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return -1;
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ return (type == 0) ? exp->save_notes (text, handle_file) : exp->delete_notes (handle_file);
+}
+
+//
+// Get load object names
+//
+Vector<char*> *
+dbeGetLoadObjectName (int /* dbevindex */)
+{
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ int size = lobjs->size ();
+
+ // Initialize Java String array
+ Vector<char*> *list = new Vector<char*>(size);
+
+ // Get load object names
+ LoadObject *lo;
+ int index;
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ list->store (index, dbe_strdup (lo->get_name ()));
+ }
+ delete lobjs;
+ return list;
+}
+
+// XXX Will use later when order has to be passed too,
+// Get complete List of tabs
+//
+Vector<void*> *
+dbeGetTabList (int /* dbevindex */)
+{
+ //DbeView *dbev = getDbeView (dbevindex);
+ //Vector<void*> *tabs = dbeSession->get_TabList();
+ //return tabs;
+ return NULL;
+}
+
+//
+// Returns list of available tabs
+//
+Vector<void*> *
+dbeGetTabListInfo (int dbevindex)
+{
+ int index;
+ DispTab *dsptab;
+ DbeView *dbev = getDbeView (dbevindex);
+
+ // make sure the tabs are initialized properly
+ dbev->get_settings ()->proc_tabs (theDbeApplication->rdtMode);
+ Vector<DispTab*> *tabs = dbev->get_TabList ();
+
+ // Get number of available tabs
+ int size = 0;
+ Vec_loop (DispTab*, tabs, index, dsptab)
+ {
+ if (!dsptab->available)
+ continue;
+ size++;
+ }
+ Vector<void*> *data = new Vector<void*>(2);
+ Vector<int> *typelist = new Vector<int>(size);
+ Vector<char*> *cmdlist = new Vector<char*>(size);
+ Vector<int> *ordlist = new Vector<int>(size);
+
+ // Build list of avaliable tabs
+ int i = 0;
+
+ Vec_loop (DispTab*, tabs, index, dsptab)
+ {
+ if (!dsptab->available)
+ continue;
+ typelist->store (i, dsptab->type);
+ cmdlist->store (i, dbe_strdup (Command::get_cmd_str (dsptab->cmdtoken)));
+ ordlist->store (i, dsptab->order);
+ i++;
+ }
+ data->store (0, typelist);
+ data->store (1, cmdlist);
+ data->store (2, ordlist);
+ return data;
+}
+
+// Return visibility state for all available tabs
+//
+Vector<bool> *
+dbeGetTabSelectionState (int dbevindex)
+{
+ int index;
+ DispTab *dsptab;
+ DbeView *dbev = getDbeView (dbevindex);
+ Vector<DispTab*> *tabs = dbev->get_TabList ();
+
+ // Get number of available tabs
+ int size = 0;
+ Vec_loop (DispTab*, tabs, index, dsptab)
+ {
+ if (!dsptab->available)
+ continue;
+ size++;
+ }
+ Vector<bool> *states = new Vector<bool>(size);
+
+ // Get visibility bit for all available tabs
+ int i = 0;
+ Vec_loop (DispTab*, tabs, index, dsptab)
+ {
+ if (!dsptab->available)
+ continue;
+ states->store (i++, dsptab->visible);
+ }
+ return states;
+}
+
+// Set visibility bit for a tab
+void
+dbeSetTabSelectionState (int dbevindex, Vector<bool> *selected)
+{
+ int index;
+ DispTab *dsptab;
+ DbeView *dbev = getDbeView (dbevindex);
+ Vector<DispTab*> *tabs = dbev->get_TabList ();
+ int i = 0;
+ Vec_loop (DispTab*, tabs, index, dsptab)
+ {
+ if (!dsptab->available)
+ continue;
+ dsptab->visible = selected->fetch (i++);
+ }
+}
+
+// Return visibility state for all available MemObj tabs
+Vector<bool> *
+dbeGetMemTabSelectionState (int dbevindex)
+{
+ int index;
+ bool dsptab;
+ DbeView *dbev = getDbeView (dbevindex);
+ Vector<bool> *memtabs = dbev->get_MemTabState ();
+
+ // set the output vector
+ int size = memtabs->size ();
+ Vector<bool> *states = new Vector<bool>(size);
+
+ // Get visibility bit for all available tabs
+ int i = 0;
+ Vec_loop (bool, memtabs, index, dsptab)
+ {
+ states->store (i++, dsptab);
+ }
+ return states;
+}
+
+// Set visibility bit for a memory tab
+//
+void
+dbeSetMemTabSelectionState (int dbevindex, Vector<bool> *selected)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_MemTabState (selected);
+}
+
+// Return visibility state for all available index tabs
+Vector<bool> *
+dbeGetIndxTabSelectionState (int dbevindex)
+{
+ int index;
+ bool dsptab;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<bool> *indxtabs = dbev->get_IndxTabState ();
+
+ // set the output vector
+ int size = indxtabs->size ();
+ Vector<bool> *states = new Vector<bool>(size);
+
+ // Get visibility bit for all available tabs
+ int i = 0;
+ Vec_loop (bool, indxtabs, index, dsptab)
+ {
+ states->store (i++, dsptab);
+ }
+ return states;
+}
+
+// Set visibility bit for a index tab
+void
+dbeSetIndxTabSelectionState (int dbevindex, Vector<bool> *selected)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_IndxTabState (selected);
+}
+
+//
+// Get search path
+//
+Vector<char*> *
+dbeGetSearchPath (int /*dbevindex*/)
+{
+ Vector<char*> *path = dbeSession->get_search_path ();
+ int size = path->size ();
+ Vector<char*> *list = new Vector<char*>(size);
+ int index;
+ char *name;
+ Vec_loop (char*, path, index, name)
+ {
+ list->store (index, dbe_strdup (name));
+ }
+ return list;
+}
+
+//
+// Set search path
+//
+void
+dbeSetSearchPath (int /*dbevindex*/, Vector<char*> *path)
+{
+ dbeSession->set_search_path (path, true);
+ return;
+}
+
+//
+// Get pathmaps
+//
+Vector<void*> *
+dbeGetPathmaps (int /*dbevindex*/)
+{
+ int index;
+ pathmap_t *pthmap;
+ Vector<pathmap_t*> *path = dbeSession->get_pathmaps ();
+ int size = path->size ();
+ Vector<void*> *data = new Vector<void*>(2);
+ Vector<char*> *oldlist = new Vector<char*>(size);
+ Vector<char*> *newlist = new Vector<char*>(size);
+
+ int i = 0;
+ Vec_loop (pathmap_t*, path, index, pthmap)
+ {
+ oldlist->store (i, dbe_strdup (pthmap->old_prefix));
+ newlist->store (i, dbe_strdup (pthmap->new_prefix));
+ i++;
+ }
+ data->store (0, oldlist);
+ data->store (1, newlist);
+ return data;
+} // dbeGetPathmaps
+
+char *
+dbeSetPathmaps (Vector<char*> *from, Vector<char*> *to)
+{
+ if (from == NULL || to == NULL || from->size () != to->size ())
+ return dbe_strdup ("dbeSetPathmaps: size of 'from' does not match for size of 'to'\n");
+ Vector<pathmap_t*> *newPath = new Vector<pathmap_t*>(from->size ());
+ for (int i = 0, sz = from->size (); i < sz; i++)
+ {
+ char *err = Settings::add_pathmap (newPath, from->get (i), to->get (i));
+ if (err)
+ {
+ newPath->destroy ();
+ delete newPath;
+ return err;
+ }
+ }
+ dbeSession->set_pathmaps (newPath);
+ return NULL;
+}
+
+//
+// Add pathmap
+char *
+dbeAddPathmap (int /* dbevindex */, char *from, char *to)
+{
+ Vector<pathmap_t*> *pmp = dbeSession->get_pathmaps ();
+ char *err = Settings::add_pathmap (pmp, from, to);
+ return err;
+}
+
+//
+// Get error/warning string of data
+char *
+dbeGetMsg (int dbevindex, int type)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ char *msgstr = NULL;
+ if (type == ERROR_MSG)
+ msgstr = dbev->get_error_msg ();
+ else if (type == WARNING_MSG)
+ msgstr = dbev->get_warning_msg ();
+ else if (type == PSTAT_MSG)
+ msgstr = dbev->get_processor_msg (PSTAT_MSG);
+ else if (type == PWARN_MSG)
+ msgstr = dbev->get_processor_msg (PWARN_MSG);
+ return msgstr ? dbe_strdup (msgstr) : NULL;
+}
+
+// Create a DbeView, given new index, and index of view to clone
+int
+dbeInitView (int id, int cloneid)
+{
+ return dbeSession->createView (id, cloneid);
+}
+
+
+// Delete a DbeView
+void
+dbeDeleteView (int dbevindex)
+{
+ dbeSession->dropView (dbevindex);
+ return;
+} // dbeDeleteView
+
+MetricList *
+dbeGetMetricListV2 (int dbevindex, MetricType mtype,
+ Vector<int> *type, Vector<int> *subtype, Vector<bool> *sort,
+ Vector<int> *vis, Vector<char*> *cmd,
+ Vector<char*> *expr_spec, Vector<char*> *legends)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ MetricList *mlist = new MetricList (mtype);
+ for (int i = 0, msize = type->size (); i < msize; i++)
+ {
+ BaseMetric *bm = dbev->register_metric_expr ((BaseMetric::Type) type->fetch (i),
+ cmd->fetch (i),
+ expr_spec->fetch (i));
+ Metric *m = new Metric (bm, (Metric::SubType) subtype->fetch (i));
+ m->set_raw_visbits (vis->fetch (i));
+ if (m->legend == NULL)
+ m->legend = dbe_strdup (legends->fetch (i));
+ mlist->append (m);
+ if (sort->fetch (i))
+ {
+ mlist->set_sort_ref_index (i);
+ }
+ }
+ return mlist;
+}
+
+static Vector<void*> *
+dbeGetMetricList (MetricList *mlist)
+{
+ int clock_val = dbeSession->get_clock (-1);
+ Vector<Metric*> *items = mlist->get_items ();
+ int size = items->size ();
+
+ Vector<int> *type = new Vector<int>(size);
+ Vector<int> *subtype = new Vector<int>(size);
+ Vector<int> *clock = new Vector<int>(size);
+ Vector<int> *flavors = new Vector<int>(size);
+ Vector<int> *vis = new Vector<int>(size);
+ Vector<bool> *sorted = new Vector<bool>(size);
+ Vector<int> *value_styles = new Vector<int>(size);
+ Vector<char*> *aux = new Vector<char*>(size);
+ Vector<char*> *name = new Vector<char*>(size);
+ Vector<char*> *abbr = new Vector<char*>(size);
+ Vector<char*> *comd = new Vector<char*>(size);
+ Vector<char*> *unit = new Vector<char*>(size);
+ Vector<char*> *user_name = new Vector<char*>(size);
+ Vector<char*> *expr_spec = new Vector<char*>(size);
+ Vector<char*> *legend = new Vector<char*>(size);
+ Vector<int> *valtype = new Vector<int>(size);
+ Vector<char*> *data_type_name = new Vector<char*>(size);
+ Vector<char*> *data_type_uname = new Vector<char*>(size);
+ Vector<char*> *short_desc = new Vector<char*>(size);
+
+ int sort_index = mlist->get_sort_ref_index ();
+ // Fill metric elements
+ for (int i = 0; i < size; i++)
+ {
+ Metric *m = items->fetch (i);
+ type->append (m->get_type ());
+ subtype->append (m->get_subtype ());
+ flavors->append (m->get_flavors ());
+ abbr->append (dbe_strdup (m->get_abbr ()));
+ char *s = m->get_abbr_unit ();
+ if ((m->get_visbits () & VAL_RATIO) != 0)
+ s = NULL;
+ unit->append (dbe_strdup (s ? s : NTXT ("")));
+ value_styles->append (m->get_value_styles ());
+ vis->append (m->get_visbits ());
+ sorted->append (i == sort_index);
+ clock->append (m->get_type () == Metric::HWCNTR ? clock_val
+ : m->get_clock_unit ());
+ aux->append (dbe_strdup (m->get_aux ()));
+ name->append (dbe_strdup (m->get_name ()));
+ comd->append (dbe_strdup (m->get_cmd ()));
+ user_name->append (dbe_strdup (m->get_username ()));
+ expr_spec->append (dbe_strdup (m->get_expr_spec ()));
+ legend->append (dbe_strdup (m->legend));
+ valtype->append (m->get_vtype2 ());
+
+ char* _data_type_name = NULL;
+ char* _data_type_uname = NULL;
+ int data_type = m->get_packet_type ();
+ if (data_type >= 0 && data_type < DATA_LAST)
+ {
+ _data_type_name = dbe_strdup (get_prof_data_type_name (data_type));
+ _data_type_uname = dbe_strdup (get_prof_data_type_uname (data_type));
+ }
+ data_type_name->append (_data_type_name);
+ data_type_uname->append (_data_type_uname);
+
+ char* _short_desc = NULL;
+ if (m->get_type () == Metric::HWCNTR)
+ {
+ Hwcentry * hwctr = m->get_hw_ctr ();
+ if (hwctr)
+ _short_desc = dbe_strdup (hwctr->short_desc);
+ }
+ short_desc->append (_short_desc);
+ }
+
+ // Set Java array
+ Vector<void*> *data = new Vector<void*>(16);
+ data->append (type);
+ data->append (subtype);
+ data->append (clock);
+ data->append (flavors);
+ data->append (value_styles);
+ data->append (user_name);
+ data->append (expr_spec);
+ data->append (aux);
+ data->append (name);
+ data->append (abbr);
+ data->append (comd);
+ data->append (unit);
+ data->append (vis);
+ data->append (sorted);
+ data->append (legend);
+ data->append (valtype);
+ data->append (data_type_name);
+ data->append (data_type_uname);
+ data->append (short_desc);
+ return data;
+}
+
+Vector<void*> *
+dbeGetRefMetricsV2 ()
+{
+ MetricList *mlist = new MetricList (MET_NORMAL);
+ Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
+ for (long i = 0, sz = base_metrics->size (); i < sz; i++)
+ {
+ BaseMetric *bm = base_metrics->fetch (i);
+ Metric *m;
+ if (bm->get_flavors () & Metric::EXCLUSIVE)
+ {
+ m = new Metric (bm, Metric::EXCLUSIVE);
+ m->enable_all_visbits ();
+ mlist->append (m);
+ }
+ else if (bm->get_flavors () & BaseMetric::STATIC)
+ {
+ m = new Metric (bm, BaseMetric::STATIC);
+ m->enable_all_visbits ();
+ mlist->append (m);
+ }
+ }
+ Vector<void*> *data = dbeGetMetricList (mlist);
+ delete mlist;
+ return data;
+}
+
+Vector<void*> *
+dbeGetCurMetricsV2 (int dbevindex, MetricType mtype)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ MetricList *mlist = dbev->get_metric_list (mtype);
+ Vector<void*> *data = dbeGetMetricList (mlist);
+ return data;
+}
+
+// YXXX we should refactor Metrics/BaseMetrics so that it no longer uses VAL_VALUE to enable time.
+static int
+convert_visbits_to_gui_checkbox_bits (BaseMetric *bm, const int visbits)
+{
+ // The purpose of this function is to handle the following case:
+ // When bm->get_value_styles() supports VAL_TIMEVAL but not VAL_VALUE
+ // Metric and BaseMetric use (visbits&VAL_VALUE) to enable time.
+ // However, the Overview expects the VAL_TIMEVAL bit to enable time.
+ // Inputs: visbits as returned by BaseMetric->get_default_visbits();
+ // Returns: valuebits, as used for checks in GUI checkboxes
+ int valuebits = visbits;
+ const int value_styles = bm->get_value_styles ();
+ if ((value_styles & VAL_TIMEVAL) && // supports time
+ !(value_styles & VAL_VALUE))
+ { // but not value
+ unsigned mask = ~(VAL_VALUE | VAL_TIMEVAL);
+ valuebits = (unsigned) valuebits & mask; // clear bits
+ if (visbits & VAL_VALUE)
+ valuebits |= VAL_TIMEVAL; // set VAL_TIMEVAL
+ if (visbits & VAL_TIMEVAL)
+ valuebits |= VAL_TIMEVAL; // weird, this should never happen.
+ }
+ return valuebits;
+}
+
+static Vector<void*> *
+dbeGetMetricTreeNode (BaseMetricTreeNode* curr, MetricList *mlist,
+ bool include_unregistered, bool has_clock_profiling_data)
+{
+ Vector<void*> *data = new Vector<void*>(2);
+
+ // ----- fields
+ Vector<void*> *fields = new Vector<void*>();
+ Vector<char*> *name = new Vector<char*>(1);
+ Vector<char*> *username = new Vector<char*>(1);
+ Vector<char*> *description = new Vector<char*>(1);
+ Vector<int> * flavors = new Vector<int>(1);
+ Vector<int> * vtype = new Vector<int>(1);
+ Vector<int> * vstyles_capable = new Vector<int>(1);
+
+ // Specifies which default styles should be enabled when a metric is enabled.
+ // Also, specifies if metric should start enabled
+ Vector<int> *vstyles_e_defaults = new Vector<int>(1);
+ Vector<int> *vstyles_i_defaults = new Vector<int>(1);
+ Vector<bool> *registered = new Vector<bool>(1);
+ Vector<bool> *aggregation = new Vector<bool>(1);
+ Vector<bool> *has_value = new Vector<bool>(1);
+ Vector<char*> *unit = new Vector<char*>(1);
+ Vector<char*> *unit_uname = new Vector<char*>(1);
+
+ char *_name = NULL;
+ char *_username = NULL;
+ char *_description = dbe_strdup (curr->get_description ());
+
+ // BaseMetric fields
+ int _flavors = 0; // SubType bitmask: (e.g. EXCLUSIVE)
+ int _vtype = 0; // ValueTag: e.g. VT_INT, VT_FLOAT, ...
+ int _vstyles_capable = 0; // ValueType bitmask, e.g. VAL_TIMEVAL
+ int _vstyles_e_default_values = 0; // default visibility settings, exclusive/static
+ int _vstyles_i_derault_values = 0; // default visibility settings, inclusive
+ bool _registered = curr->is_registered ()
+ || curr->get_num_registered_descendents () > 0;
+ bool _aggregation = curr->is_composite_metric ()
+ && curr->get_num_registered_descendents () > 0;
+ bool _has_value = false; //not used yet; for nodes that don't have metrics
+ char *_unit = NULL;
+ char *_unit_uname = NULL;
+
+ BaseMetric *bm = curr->get_BaseMetric ();
+ if (bm)
+ {
+ _name = dbe_strdup (bm->get_cmd ());
+ _username = dbe_strdup (bm->get_username ());
+ if (!include_unregistered && !curr->is_registered ())
+ abort ();
+ _flavors = bm->get_flavors ();
+ _vtype = bm->get_vtype ();
+ _vstyles_capable = bm->get_value_styles ();
+ int e_visbits = bm->get_default_visbits (BaseMetric::EXCLUSIVE);
+ int i_visbits = bm->get_default_visbits (BaseMetric::INCLUSIVE);
+ _vstyles_e_default_values = convert_visbits_to_gui_checkbox_bits (bm, e_visbits);
+ _vstyles_i_derault_values = convert_visbits_to_gui_checkbox_bits (bm, i_visbits);
+ // not all metrics shown in er_print cmd line should be selected in the GUI at startup:
+ if (has_clock_profiling_data && bm->get_hw_ctr ())
+ {
+ bool hide = true; // by default, hide HWCs
+ if (dbe_strcmp (bm->get_hw_ctr ()->name, NTXT ("c_stalls")) == 0 ||
+ dbe_strcmp (bm->get_hw_ctr ()->name, NTXT ("K_c_stalls")) == 0)
+ {
+ bool is_time = (bm->get_value_styles () & VAL_TIMEVAL) != 0;
+ if (is_time)
+ // By default, show time variant of c_stalls
+ hide = false;
+ }
+ if (hide)
+ {
+ _vstyles_e_default_values |= VAL_HIDE_ALL;
+ _vstyles_i_derault_values |= VAL_HIDE_ALL;
+ }
+ }
+ }
+ else
+ {
+ // not a base metric
+ _name = dbe_strdup (curr->get_name ());
+ _username = dbe_strdup (curr->get_user_name ());
+ if (curr->get_unit ())
+ { // represents a value
+ _has_value = true;
+ _unit = dbe_strdup (curr->get_unit ());
+ _unit_uname = dbe_strdup (curr->get_unit_uname ());
+ }
+ }
+ name->append (_name); // unique id string (dmetrics cmd)
+ username->append (_username); // user-visible name
+ description->append (_description);
+ flavors->append (_flavors); // SubType bitmask: (e.g. EXCLUSIVE)
+ vtype->append (_vtype); // ValueTag: e.g. VT_INT, VT_FLOAT, ...
+ vstyles_capable->append (_vstyles_capable); // ValueType bitmask, e.g. VAL_TIMEVAL
+ vstyles_e_defaults->append (_vstyles_e_default_values);
+ vstyles_i_defaults->append (_vstyles_i_derault_values);
+ registered->append (_registered); // is a "live" metric
+ aggregation->append (_aggregation); // value derived from children nodes
+ has_value->append (_has_value); // value generated from other source
+ unit->append (_unit); // See BaseMetric.h, e.g. UNIT_SECONDS
+ unit_uname->append (_unit_uname); //See BaseMetric.h,
+
+ fields->append (name);
+ fields->append (username);
+ fields->append (description);
+ fields->append (flavors);
+ fields->append (vtype);
+ fields->append (vstyles_capable);
+ fields->append (vstyles_e_defaults);
+ fields->append (vstyles_i_defaults);
+ fields->append (registered);
+ fields->append (aggregation);
+ fields->append (has_value);
+ fields->append (unit);
+ fields->append (unit_uname);
+ data->append (fields);
+
+ // ----- children
+ Vector<BaseMetricTreeNode*> *children = curr->get_children ();
+ int num_children = children->size ();
+ Vector<void*> *children_list = new Vector<void*>(num_children);
+ BaseMetricTreeNode *child_node;
+ int index;
+
+ Vec_loop (BaseMetricTreeNode*, children, index, child_node)
+ {
+ if (include_unregistered /* fetch everything */
+ || child_node->is_registered ()
+ || child_node->get_num_registered_descendents () > 0)
+ {
+ //Special case for metrics that aren't registered
+ // but have registered children
+ // Linux example: Total Time is unregistered, CPU Time is registered
+ if (!include_unregistered && /* not fetching everything */
+ !child_node->is_registered () &&
+ (child_node->get_BaseMetric () != NULL ||
+ child_node->is_composite_metric ()))
+ {
+ Vector<BaseMetricTreeNode*> *registered_descendents =
+ new Vector<BaseMetricTreeNode*>();
+ child_node->get_nearest_registered_descendents (registered_descendents);
+ int idx2;
+ BaseMetricTreeNode*desc_node;
+ Vec_loop (BaseMetricTreeNode*, registered_descendents, idx2, desc_node)
+ {
+ Vector<void*> *desc_data;
+ desc_data = dbeGetMetricTreeNode (desc_node, mlist,
+ include_unregistered, has_clock_profiling_data);
+ children_list->append (desc_data);
+ }
+ delete registered_descendents;
+ continue;
+ }
+ Vector<void*> *child_data;
+ child_data = dbeGetMetricTreeNode (child_node, mlist,
+ include_unregistered, has_clock_profiling_data);
+ children_list->append (child_data);
+ }
+ }
+ data->append (children_list);
+ return data;
+}
+
+Vector<void*> *
+dbeGetRefMetricTree (int dbevindex, bool include_unregistered)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ MetricList *mlist = dbev->get_metric_list (MET_NORMAL);
+ bool has_clock_profiling_data = false;
+ for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get_items ()->fetch (i);
+ if (m->get_packet_type () == DATA_CLOCK)
+ {
+ has_clock_profiling_data = true;
+ break;
+ }
+ }
+ BaseMetricTreeNode *curr = dbeSession->get_reg_metrics_tree ();
+ return dbeGetMetricTreeNode (curr, mlist, include_unregistered, has_clock_profiling_data);
+}
+
+static Vector<void*> *
+dbeGetTableDataV2Data (DbeView *dbev, Hist_data *data);
+
+static Vector<void*> *dbeGetTableDataOneColumn (Hist_data *data, int met_ind);
+static Vector<void*> *
+dbeGetTableDataOneColumn (DbeView *dbev, Vector<Hist_data::HistItem*> *data,
+ ValueTag vtype, int metricColumnNumber);
+
+static hrtime_t
+dbeCalcGroupDuration (int grInd)
+{
+ int thisGroupSize = 1;
+ hrtime_t max_time = 0;
+ Experiment *exp;
+ if (dbeSession->expGroups->size () > 0)
+ {
+ ExpGroup *grp = dbeSession->expGroups->fetch (grInd);
+ thisGroupSize = grp->exps->size ();
+ for (int ii = 0; ii < thisGroupSize; ii++)
+ {
+ exp = grp->exps->fetch (ii);
+ Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+ delete ddscr;// getDataDescriptors() forces reading of experiment data
+ if (exp != NULL)
+ {
+ hrtime_t tot_time = exp->getLastEvent () - exp->getStartTime ()
+ + exp->getRelativeStartTime ();
+ if (max_time < tot_time)
+ max_time = tot_time;
+ }
+ }
+ }
+ else
+ {
+ exp = dbeSession->get_exp (0);
+ if (exp != NULL)
+ max_time = exp->getLastEvent () - exp->getStartTime ();
+ }
+ return max_time; //nanoseconds
+}
+
+static hrtime_t
+dbeCalcGroupGCDuration (int grInd)
+{
+ int thisGroupSize = 1;
+ hrtime_t tot_time = 0;
+ Experiment *exp;
+ if (dbeSession->expGroups->size () > 0)
+ {
+ ExpGroup *grp = dbeSession->expGroups->fetch (grInd);
+ thisGroupSize = grp->exps->size ();
+ for (int ii = 0; ii < thisGroupSize; ii++)
+ {
+ exp = grp->exps->fetch (ii);
+ Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+ delete ddscr; // getDataDescriptors() forces reading of experiment data
+ if (exp != NULL)
+ tot_time += exp->getGCDuration ();
+ }
+ }
+ else
+ {
+ exp = dbeSession->get_exp (0);
+ if (exp != NULL)
+ tot_time = exp->getGCDuration ();
+ }
+ return tot_time; //nanoseconds
+}
+
+Vector<void*> *
+dbeGetRefMetricTreeValues (int dbevindex, Vector<char *> *metric_cmds,
+ Vector<char *> *non_metric_cmds)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ // valueTable will have N "columns" of values, where N is the number of
+ // requested metrics and non-metrics.
+ // Each column will be a vector with M "rows", where M is the number of
+ // compare groups.
+ // highlightTable mirrors the structure of valueTable. Each cell indicates
+ // if the corresponding valueTable cell is "hot" (interesting)
+ int numMetrics = metric_cmds->size ();
+ int numNonMetrics = non_metric_cmds->size ();
+ int totalColumns = numMetrics + numNonMetrics; // Columns
+ Vector<void*> *valueTable = new Vector<void*>(totalColumns);
+ Vector<void*> *highlightTable = new Vector<void*>(totalColumns);
+
+ // the return value consists of the two tables discussed above.
+ Vector<void*> *rc = new Vector<void*>(2);
+ rc->append (valueTable);
+ rc->append (highlightTable);
+ if (dbeSession->nexps () == 0)
+ { // no experiments are loaded
+ for (int jj = 0; jj < totalColumns; jj++)
+ {
+ Vector<void *> *columnData = new Vector<void *>();
+ valueTable->append (columnData);
+ highlightTable->append (columnData);
+ }
+ return rc;
+ }
+
+ int ngroups = dbeSession->expGroups->size (); // Rows (one per compare group)
+ if (ngroups == 0 || !dbev->comparingExperiments ())
+ ngroups = 1;
+
+ Vector<double> *groupTotalTime = new Vector<double>(ngroups);
+ Vector<double> *groupCpuTime = new Vector<double>(ngroups);
+ // initialize highlight table
+ for (int ii = 0; ii < totalColumns; ii++)
+ { // metrics
+ Vector<bool> *columnData = new Vector<bool>(ngroups);
+ highlightTable->append (columnData);
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ columnData->store (grInd, false); // non-highlight
+ }
+
+ if (numMetrics > 0)
+ {
+ MetricList *bmlist;
+ // set bmlist to list of requested base metrics
+ BaseMetricTreeNode *root = dbeSession->get_reg_metrics_tree ();
+ int index;
+ char *mcmd;
+ Vector<BaseMetric*> *base_metrics = new Vector<BaseMetric*>();
+ Vec_loop (char *, metric_cmds, index, mcmd)
+ {
+ BaseMetricTreeNode *bmt_node = root->find (mcmd);
+ if (!bmt_node)
+ abort (); //YXXX weird
+ BaseMetric * baseNetric = bmt_node->get_BaseMetric ();
+ if (!baseNetric)
+ abort ();
+ base_metrics->append (baseNetric);
+ }
+
+ // MET_INDX will create MetricList of Exclusive metrics
+ bmlist = new MetricList (base_metrics, MET_SRCDIS);
+
+ // Use the Function List to fetch <Total> values
+ // A temporary table, v_totals, stores <total> by group
+ Vector<Hist_data::HistItem *> *v_totals = new Vector<Hist_data::HistItem *>(ngroups);
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ MetricList *mlist;
+ if (ngroups > 1)
+ mlist = dbev->get_compare_mlist (bmlist, grInd);
+ else
+ mlist = bmlist;
+ if (mlist->size () != numMetrics)
+ abort ();
+
+ Hist_data *data;
+ data = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::ALL);
+ Hist_data::HistItem * totals = data->get_totals ();
+ v_totals->append (totals);
+ }
+
+ // store the Hist_data totals in valueTable
+ {
+ Metric *mitem;
+ int index;
+ Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+ {
+ Vector<void*> * columnData = dbeGetTableDataOneColumn (dbev,
+ v_totals, mitem->get_vtype (), index);
+ valueTable->append (columnData);
+ }
+ }
+
+ // 7207285: hack for hwc profiling cycles conversion:
+ {
+ Metric *mitem;
+ int index;
+ Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+ {
+ if (mitem->is_time_val ()
+ && mitem->get_vtype () == VT_ULLONG)
+ {
+ Vector<long long> *cycleValues = (Vector<long long> *)valueTable->fetch (index);
+ Vector<double> *timeValues = new Vector<double>(ngroups);
+ assert (cycleValues->size () == ngroups);
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ long long cycles = cycleValues->fetch (grInd);
+ int expId;
+ if (dbeSession->expGroups->size () > 0)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (grInd);
+ Experiment *exp = gr->exps->fetch (0);
+ expId = exp->getExpIdx ();
+ }
+ else
+ expId = -1;
+ int clock = dbeSession->get_clock (expId);
+ double time;
+ if (clock)
+ time = cycles / (1.e+6 * clock);
+ else
+ time = cycles; //weird
+ timeValues->store (grInd, time);
+ }
+ delete cycleValues;
+ valueTable->store (index, timeValues);
+ }
+ }
+ }
+
+ // Scan metrics for best measure of CPU time
+ int bestCpuTimeIndx = -1;
+ {
+ Metric *mitem;
+ int index;
+ Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+ {
+ BaseMetric::Type type = mitem->get_type ();
+ if (type == BaseMetric::CP_KERNEL_CPU)
+ {
+ bestCpuTimeIndx = index;
+ break; // CP_KERNEL_CPU trumps other measures
+ }
+ if (type == BaseMetric::CP_TOTAL_CPU)
+ {
+ // clock profiling CPU time
+ bestCpuTimeIndx = index;
+ // keep looking in case CP_KERNEL_CPU also exists
+ continue;
+ }
+
+ bool isTime = ((mitem->get_value_styles () & VAL_TIMEVAL) != 0);
+ bool isHwcCycles = (type == BaseMetric::HWCNTR
+ && (dbe_strcmp (mitem->get_aux (), "cycles") == 0)
+ && isTime);
+ if (isHwcCycles)
+ if (bestCpuTimeIndx < 0)
+ bestCpuTimeIndx = index;
+ }
+ if (bestCpuTimeIndx >= 0)
+ {
+ Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (bestCpuTimeIndx);
+ if (timeValues->type () == VEC_DOUBLE)
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ double time = timeValues->fetch (grInd);
+ groupCpuTime->append (time);
+ }
+ }
+ }
+
+ // Scan metrics for Total Thread time
+ {
+ Metric *mitem;
+ int index;
+ Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+ {
+ BaseMetric::Type type = mitem->get_type ();
+ if (type == BaseMetric::CP_TOTAL)
+ {
+ Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (index);
+ if (timeValues->type () != VEC_DOUBLE)
+ continue; // weird
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ double time = timeValues->fetch (grInd);
+ groupTotalTime->append (time);
+ }
+ break;
+ }
+ }
+ }
+
+ // highlight metrics based on cpu time
+#define CPUSEC_PERCENT_THRESHOLD 10.0
+#define HWC_OVERFLOWS_PER_CPUSEC_THRESHOLD 15
+ {
+ Metric *mitem;
+ int index;
+ Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+ {
+ BaseMetric::Type type = mitem->get_type ();
+ Vector<bool> * columnHilites = (Vector<bool> *)highlightTable->fetch (index);
+
+ // always highlight the following
+ if (index == bestCpuTimeIndx)
+ {
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ columnHilites->store (grInd, true);
+ continue;
+ }
+
+ // skip certain types
+ bool typeIsCycles = (type == BaseMetric::HWCNTR
+ && dbe_strcmp (mitem->get_aux (), NTXT ("cycles")) == 0);
+ bool typeIsInsts = (type == BaseMetric::HWCNTR
+ && dbe_strcmp (mitem->get_aux (), NTXT ("insts")) == 0);
+ if (type == BaseMetric::CP_TOTAL
+ || type == BaseMetric::CP_TOTAL_CPU
+ || type == BaseMetric::CP_LMS_USER
+ || type == BaseMetric::CP_LMS_SYSTEM
+ || type == BaseMetric::CP_LMS_TRAP
+ || type == BaseMetric::CP_LMS_USER_LOCK
+ || type == BaseMetric::CP_LMS_SLEEP
+ || type == BaseMetric::CP_KERNEL_CPU
+ || type == BaseMetric::OMP_WORK
+ || typeIsCycles
+ || typeIsInsts
+ // || type == BaseMetric::CP_TOTAL_WAIT
+ )
+ continue; // types we never highlight
+
+ // for time values, compare against CPUSEC_PERCENT_THRESHOLD
+ bool isTime = ((mitem->get_value_styles () & VAL_TIMEVAL) != 0);
+ if (isTime)
+ {
+ if (groupCpuTime->size () == 0)
+ continue; // no time to use as reference
+ Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (index);
+ if (timeValues->type () != VEC_DOUBLE)
+ continue; // weird
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ double thistime = timeValues->fetch (grInd);
+ double usertime = groupCpuTime->fetch (grInd);
+ if (thistime / (CPUSEC_PERCENT_THRESHOLD / 100) > usertime)
+ columnHilites->store (grInd, true);
+ }
+ continue;
+ }
+
+ // for HWC event counts, look at rate of events
+ if (type == BaseMetric::HWCNTR)
+ {
+ Hwcentry *hwctr = mitem->get_hw_ctr ();
+ if (!hwctr)
+ continue; // weird
+ if (!hwctr->metric)
+ continue; // raw counter
+ if (groupCpuTime->size () == 0)
+ continue; // no time to use as reference
+ if (mitem->get_base_metric ()->get_dependent_bm ())
+ continue; // has a derived time metric, only flag time version
+ Vector<long long> *llValues = (Vector<long long> *)valueTable->fetch (index);
+ if (llValues->type () != VEC_LLONG)
+ continue; // weird
+ int overflowVal = hwctr->val; //overflow count
+ if (!overflowVal)
+ continue; // weird
+ if (overflowVal > (4000000))
+ // cut off events that are very frequent like loads/stores
+ // 4Ghz * (0.01 seconds/event) / (4000000 events/overflow) = 10 cycles
+ continue;
+ // for HWCs we could base it on the overflow rate
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ double thisVal = llValues->fetch (grInd);
+ thisVal /= overflowVal;
+ double usertime = groupCpuTime->fetch (grInd);
+ if (thisVal > usertime * HWC_OVERFLOWS_PER_CPUSEC_THRESHOLD)
+ columnHilites->store (grInd, true);
+ }
+ continue;
+ }
+
+ // check for non-zero counts of the following
+ if (type == BaseMetric::DEADLOCKS ||
+ type == BaseMetric::RACCESS ||
+ type == BaseMetric::HEAP_ALLOC_BYTES ||
+ type == BaseMetric::HEAP_LEAK_BYTES)
+ {
+ Vector<long long> *llValues = (Vector<long long> *)valueTable->fetch (index);
+ if (llValues->type () != VEC_LLONG)
+ continue; // weird
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ long long thisVal = llValues->fetch (grInd);
+ if (thisVal)
+ columnHilites->store (grInd, true);
+ }
+ continue;
+ }
+ // continue adding cases as needed
+ }
+ }
+ }
+
+ if (numNonMetrics > 0)
+ {
+ int index;
+ char *mcmd;
+ Vec_loop (char *, non_metric_cmds, index, mcmd)
+ {
+ if (dbe_strcmp (mcmd, NTXT ("YXXX_TOTAL_TIME_PLUS_THREADS")) == 0
+ && groupCpuTime->size () == ngroups)
+ {
+ Vector<char *> *columnData = new Vector<char *>(ngroups);
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ double totaltime = groupTotalTime->fetch (grInd);
+ columnData->append (dbe_sprintf (NTXT ("%0.3f %s"), totaltime, GTXT ("Seconds")));
+ }
+ valueTable->append (columnData);
+ }
+ else if (dbe_strcmp (mcmd, L1_DURATION) == 0)
+ {
+ Vector<double> *columnData = new Vector<double>(ngroups);
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ hrtime_t duration = dbeCalcGroupDuration (grInd);
+ double seconds = duration * 1.e-9;
+ columnData->append (seconds);
+ }
+ valueTable->append (columnData);
+ }
+ else if (dbe_strcmp (mcmd, L1_GCDURATION) == 0)
+ {
+ Vector<double> *columnData = new Vector<double>(ngroups);
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ hrtime_t duration = dbeCalcGroupGCDuration (grInd);
+ double seconds = duration * 1.e-9;
+ columnData->append (seconds);
+ }
+ valueTable->append (columnData);
+ }
+ else
+ {
+ Vector<char *> *columnData = new Vector<char *>(ngroups);
+ char * valueString = NTXT ("<unknown>");
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ columnData->append (dbe_strdup (valueString));
+ valueTable->append (columnData);
+ }
+ }
+ }
+ return rc;
+}
+
+Vector<char*> *
+dbeGetOverviewText (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ Vector<char*> *info = new Vector<char*>;
+ char *field;
+ int ngroups = dbeSession->expGroups->size (); // Rows (one per compare group)
+ if (ngroups == 0 || !dbev->comparingExperiments ())
+ ngroups = 1;
+ for (int grInd = 0; grInd < ngroups; grInd++)
+ {
+ int thisGroupSize = 1;
+ Experiment *exp;
+ if (dbeSession->expGroups->size () > 0)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (grInd);
+ exp = gr->exps->fetch (0);
+ thisGroupSize = gr->exps->size ();
+ }
+ else
+ {
+ if (dbeSession->nexps () == 0)
+ return info;
+ exp = dbeSession->get_exp (0);
+ }
+ char * expHeader;
+ if (ngroups == 1)
+ expHeader = dbe_strdup (GTXT ("Experiment :"));
+ else if (grInd == 0)
+ expHeader = dbe_strdup (GTXT ("Base Group : "));
+ else if (ngroups == 2)
+ expHeader = dbe_strdup (GTXT ("Compare Group : "));
+ else
+ expHeader = dbe_sprintf (GTXT ("Compare Group %d : "), grInd);
+ if (thisGroupSize == 1)
+ info->append (dbe_sprintf ("%s%s", expHeader, exp->get_expt_name ()));
+ else
+ info->append (dbe_sprintf ("%s%s (plus %d more)",
+ expHeader, exp->get_expt_name (), thisGroupSize - 1));
+ free (expHeader);
+ field = exp->uarglist;
+ if (field && field[0])
+ info->append (dbe_sprintf (GTXT (" Target : '%s'"), field));
+ field = exp->hostname;
+ if (field && field[0])
+ info->append (dbe_sprintf (NTXT (" %s %s (%s, %s)"),
+ GTXT ("Host :"),
+ field,
+ exp->architecture ? exp->architecture
+ : GTXT ("<CPU architecture not recorded>"),
+ exp->os_version ? exp->os_version
+ : GTXT ("<OS version not recorded>")));
+ long start_sec = exp->start_sec;
+ char *p = ctime (&start_sec); // does this need to be freed? YXXX
+ hrtime_t tot_time = dbeCalcGroupDuration (grInd);
+ double seconds = tot_time * 1.e-9;
+ info->append (dbe_sprintf (NTXT (" %s %s %s %0.3f %s"),
+ GTXT ("Start Time :"), p,
+ GTXT ("Duration :"), seconds,
+ GTXT ("Seconds")));
+ // Number of descendants/processes would be nice
+ info->append (dbe_strdup (NTXT ("")));
+ }
+ return info;
+}
+
+//--------------------------------------------------------------------------
+// Set Sort by index
+//
+void
+dbeSetSort (int dbevindex, int sort_index, MetricType mtype, bool reverse)
+{
+ DbeView *dbev;
+
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->setSort (sort_index, mtype, reverse);
+ return;
+}
+
+//
+// Get annotation setting
+//
+Vector<int> *
+dbeGetAnoValue (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<int> *set = new Vector<int>(9);
+ set->store (0, dbev->get_src_compcom ());
+ set->store (1, dbev->get_dis_compcom ());
+ set->store (2, dbev->get_thresh_src ());
+ set->store (3, dbev->get_thresh_src ());
+ set->store (4, dbev->get_src_visible ());
+ set->store (5, (int) dbev->get_srcmetric_visible ());
+ set->store (6, (int) dbev->get_hex_visible ());
+ set->store (7, (int) dbev->get_cmpline_visible ());
+ set->store (8, (int) dbev->get_func_scope ());
+ return set;
+}
+
+//
+// Set annotation setting
+//
+void
+dbeSetAnoValue (int dbevindex, Vector<int> *set)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (set->size () != 10)
+ return;
+ dbev->set_src_compcom (set->fetch (0));
+ dbev->set_dis_compcom (set->fetch (1));
+ dbev->set_thresh_src (set->fetch (2));
+ dbev->set_thresh_dis (set->fetch (3));
+ dbev->set_src_visible (set->fetch (4));
+ dbev->set_srcmetric_visible ((bool)set->fetch (5));
+ dbev->set_hex_visible ((bool)set->fetch (6));
+ dbev->set_cmpline_visible ((bool)set->fetch (7));
+ dbev->set_func_scope (set->fetch (8));
+ dbev->set_funcline_visible ((bool)set->fetch (9));
+ return;
+}
+
+//
+// Get name formats
+//
+int
+dbeGetNameFormat (int dbevindex)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable::NameFormat fmt = dbev->get_name_format ();
+ return Histable::fname_fmt (fmt);
+}
+
+bool
+dbeGetSoName (int dbevindex)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable::NameFormat fmt = dbev->get_name_format ();
+ return Histable::soname_fmt (fmt);
+}
+
+//
+// Set name formats
+//
+void
+dbeSetNameFormat (int dbevindex, int nformat, bool soname)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_name_format (nformat, soname);
+}
+
+//
+// Get View mode
+//
+int
+dbeGetViewMode (int dbevindex)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ return (int) dbev->get_view_mode ();
+}
+
+// Set View mode
+void
+dbeSetViewMode (int dbevindex, int nmode)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_view_mode ((VMode) nmode);
+ return;
+}
+
+// Get timeline setting
+//
+Vector<void*> *
+dbeGetTLValue (int dbevindex)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<char *> *strings = new Vector<char *>();
+ char *tldata_cmd = dbev->get_tldata ();
+ strings->store (0, tldata_cmd);
+
+ Vector<int> *ints = new Vector<int>(3);
+ int val;
+ val = dbev->get_tlmode ();
+ ints->store (0, val);
+ val = dbev->get_stack_align ();
+ ints->store (1, val);
+ val = dbev->get_stack_depth ();
+ ints->store (2, val);
+
+ Vector<void*> *objs = new Vector<void*>(2);
+ objs->store (0, strings);
+ objs->store (1, ints);
+ return objs;
+}
+
+//
+// Set timeline setting
+//
+void
+dbeSetTLValue (int dbevindex, const char *tldata_cmd,
+ int entitiy_prop_id, int stackalign, int stackdepth)
+{
+ DbeView *dbev;
+ dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_tldata (tldata_cmd);
+ dbev->set_tlmode (entitiy_prop_id);
+ dbev->set_stack_align (stackalign);
+ dbev->set_stack_depth (stackdepth);
+ return;
+}
+
+//
+// Get founder experiments and their descendants
+//
+Vector<void*> *
+dbeGetExpFounderDescendants ()
+{
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return NULL;
+ Vector<void*> *table = new Vector<void*>(2);
+ Vector<int> *founderExpIds = new Vector<int>();
+ Vector<Vector<int> *> *subExpIds = new Vector<Vector<int>*>();
+ for (int index = 0; index < size; index++)
+ {
+ Experiment *exp = dbeSession->get_exp (index);
+ if (exp->founder_exp == NULL)
+ {
+ founderExpIds->append (exp->getExpIdx ());
+ Vector<int> *subExps = new Vector<int>();
+ for (int i = 0; i < exp->children_exps->size (); i++)
+ {
+ Experiment * subExp = exp->children_exps->fetch (i);
+ subExps->append (subExp->getExpIdx ());
+ }
+ subExpIds->append (subExps);
+ }
+ }
+ table->store (0, founderExpIds);
+ table->store (1, subExpIds);
+ return table;
+}
+
+//
+// Get experiment selection
+//
+Vector<void*> *
+dbeGetExpSelection (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return NULL;
+ Vector<void*> *table = new Vector<void*>(3);
+ Vector<char*> *names = new Vector<char*>(size);
+ Vector<bool> *enable = new Vector<bool>(size);
+ Vector<int> *userExpIds = new Vector<int>(size);
+
+ // Get experiment names
+ for (int index = 0; index < size; index++)
+ {
+ Experiment *exp = dbeSession->get_exp (index);
+ char *buf = dbeGetName (dbevindex, index);
+ names->store (index, buf);
+ bool val;
+ val = dbev->get_exp_enable (index);
+ enable->store (index, val);
+ userExpIds->store (index, exp->getUserExpId ());
+ }
+ table->store (0, names);
+ table->store (1, enable);
+ table->store (2, userExpIds);
+ return table;
+}
+
+int
+dbeValidateFilterExpression (char *str_expr)
+{
+ if (str_expr == NULL)
+ return 0;
+ Expression *expr = dbeSession->ql_parse (str_expr);
+ if (expr == NULL)
+ return 0;
+ delete expr;
+ return 1;
+}
+
+Vector<void*> *
+dbeGetFilterKeywords (int /* dbevindex */)
+{
+ Vector <char*> *kwCategory = new Vector<char *>();
+ Vector <char*> *kwCategoryI18N = new Vector<char *>();
+ Vector <char*> *kwDataType = new Vector<char *>();
+ Vector <char*> *kwKeyword = new Vector<char *>();
+ Vector <char*> *kwFormula = new Vector<char *>();
+ Vector <char*> *kwDescription = new Vector<char *>();
+ Vector <void*> *kwEnumDescs = new Vector<void *>();
+
+ Vector<void*> *res = new Vector<void*>(7);
+ res->append (kwCategory);
+ res->append (kwCategoryI18N);
+ res->append (kwDataType);
+ res->append (kwKeyword);
+ res->append (kwFormula);
+ res->append (kwDescription);
+ res->append (kwEnumDescs);
+
+ char *vtypeNames[] = VTYPE_TYPE_NAMES;
+ // section header for global definitions
+ kwCategory->append (dbe_strdup (NTXT ("FK_SECTION")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Global Definitions")));
+ kwDataType->append (NULL);
+ kwKeyword->append (NULL);
+ kwFormula->append (NULL);
+ kwDescription->append (NULL);
+ kwEnumDescs->append (NULL);
+ dbeSession->get_filter_keywords (res);
+ MemorySpace::get_filter_keywords (res);
+
+ // loop thru all founder experiments
+ int nexp = dbeSession->nexps ();
+ for (int ii = 0; ii < nexp; ++ii)
+ {
+ Experiment* fexp = dbeSession->get_exp (ii);
+ if (fexp->founder_exp != NULL)
+ continue; // is a child; should be covered when we get to founder
+
+ // section header for each founder
+ // section header for founder experiment
+ kwCategory->append (dbe_strdup (NTXT ("FK_SECTION")));
+ kwCategoryI18N->append (dbe_sprintf (NTXT ("%s [EXPGRID==%d]"),
+ fexp->get_expt_name (),
+ fexp->groupId));
+ kwDataType->append (NULL);
+ kwKeyword->append (NULL);
+ kwFormula->append (NULL);
+ kwDescription->append (NULL);
+ kwEnumDescs->append (NULL);
+
+ int nchildren = fexp->children_exps->size ();
+ Experiment *exp;
+ // category header: Experiments
+ {
+ char *propUName = dbeSession->getPropUName (PROP_EXPID);
+
+ // store list of subexperiments in kwEnumDescs
+ Vector <char*> *enumDescs = new Vector<char *>();
+ int jj = 0;
+ exp = fexp;
+ while (1)
+ {
+ char * expBasename = get_basename (exp->get_expt_name ());
+ char * targetName = exp->utargname ? exp->utargname
+ : (char *) GTXT ("(unknown)");
+ enumDescs->append (dbe_sprintf (NTXT ("(%d) -> %s [%s, PID %d]"),
+ exp->getUserExpId (), expBasename,
+ targetName, exp->getPID ()));
+ if (jj >= nchildren)
+ break;
+ exp = fexp->children_exps->fetch (jj);
+ jj++;
+ }
+ kwCategory->append (dbe_strdup (NTXT ("FK_EXPLIST")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Experiments")));
+ kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT32]));
+ kwKeyword->append (dbe_strdup (NTXT ("EXPID")));
+ kwFormula->append (NULL);
+ kwDescription->append (propUName);
+ kwEnumDescs->append (enumDescs);
+ }
+
+ // select representative experiment
+ if (nchildren == 0)
+ exp = fexp; // founder
+ else
+ exp = fexp->children_exps->fetch (0); // first child
+ int expIdx = exp->getExpIdx ();
+ Vector<void*> *data = dbeGetDataDescriptorsV2 (expIdx);
+ if (data == NULL)
+ continue;
+ Vector<int> *dataId = (Vector<int>*)data->fetch (0);
+ Vector<char*> *dataName = (Vector<char*>*)data->fetch (1);
+ Vector<char*> *dataUName = (Vector<char*>*)data->fetch (2);
+ if (dataId == NULL || dataName == NULL)
+ {
+ destroy (data);
+ continue;
+ }
+ // loop thru data descriptors
+ int ndata = dataId->size ();
+ for (int j = 0; j < ndata; ++j)
+ {
+ // category: data name (e.g. Clock Profiling)
+ char * catName = dataName->fetch (j);
+ char * dUname = dataUName ? dataUName->fetch (j) : catName;
+ char * catUname = dUname ? dUname : catName;
+
+ Vector<void*> *props = dbeGetDataPropertiesV2 (expIdx, dataId->fetch (j));
+ if (props == NULL)
+ continue;
+ Vector<char*> *propUName = (Vector<char*>*)props->fetch (1);
+ Vector<int> *propTypeId = (Vector<int> *)props->fetch (2);
+ Vector<char*> *propType = (Vector<char*>*)props->fetch (3);
+ Vector<char*> *propName = (Vector<char*>*)props->fetch (5);
+ Vector<Vector<char*>*> *propStateNames =
+ (Vector<Vector<char*>*> *)props->fetch (6);
+ Vector<Vector<char*>*> *propStateUNames =
+ (Vector<Vector<char*>*> *)props->fetch (7);
+ if (propName == NULL || propUName == NULL || propType == NULL
+ || propName->size () <= 0)
+ {
+ destroy (props);
+ continue;
+ }
+ int nprop = propName->size ();
+ for (int k = 0; k < nprop; ++k)
+ {
+ if (propTypeId->fetch (k) == TYPE_OBJ)
+ continue;
+ if (dbe_strcmp (propName->fetch (k), NTXT ("FRINFO")) == 0)
+ continue;
+
+ // store list of states in kwEnumDescs
+ Vector<char*> *enumDescs = new Vector<char *>();
+ Vector<char*>* stateNames = propStateNames->fetch (k);
+ Vector<char*>* stateUNames = propStateUNames->fetch (k);
+ int nStates = stateNames ? stateNames->size () : 0;
+ for (int kk = 0; kk < nStates; ++kk)
+ {
+ const char *stateName = stateNames->fetch (kk);
+ if (stateName == NULL || strlen (stateName) == 0)
+ continue;
+ const char *stateUName = stateUNames->fetch (kk);
+ if (stateUName == NULL || strlen (stateUName) == 0)
+ stateUName = stateName;
+ enumDescs->append (dbe_sprintf (NTXT ("(%d) -> %s"), kk, stateUName));
+ }
+ kwCategory->append (dbe_strdup (catName));
+ kwCategoryI18N->append (dbe_strdup (catUname));
+ kwDataType->append (dbe_strdup (propType->fetch (k)));
+ kwKeyword->append (dbe_strdup (propName->fetch (k)));
+ kwFormula->append (NULL);
+ kwDescription->append (dbe_strdup (propUName->fetch (k)));
+ kwEnumDescs->append (enumDescs);
+ }
+ destroy (props);
+ }
+ destroy (data);
+ }
+ return (res);
+}
+
+// GetFilters -- returns the list of filters for the indexed experiment
+// returns false if there's a problem; true otherwise
+//
+Vector<void*> *
+dbeGetFilters (int dbevindex, int nexp)
+{
+ FilterNumeric *filt;
+ int index;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<FilterNumeric *>*filters = dbev->get_all_filters (nexp);
+ if (filters == NULL)
+ return NULL;
+
+ // return an array of filter data for that experiment
+ Vector <int> *findex = new Vector<int>(); // index of the filters
+ Vector <char*> *shortname = new Vector<char *>();
+ // short name of filter
+ Vector <char*> *i18n_name = new Vector<char *>();
+ // External I18N'd name of filter
+ Vector <char*> *pattern = new Vector<char *>();
+ // current setting string
+ Vector <char*> *status = new Vector<char *>();
+ // current status of filter (%, range, etc.)
+
+ Vec_loop (FilterNumeric *, filters, index, filt)
+ {
+ findex->append (index);
+ shortname->append (dbe_strdup (filt->get_cmd ()));
+ i18n_name->append (dbe_strdup (filt->get_name ()));
+ pattern->append (dbe_strdup (filt->get_pattern ()));
+ status->append (dbe_strdup (filt->get_status ()));
+ }
+ Vector<void*> *res = new Vector<void*>(5);
+ res->store (0, findex);
+ res->store (1, shortname);
+ res->store (2, i18n_name);
+ res->store (3, pattern);
+ res->store (4, status);
+ return (res);
+}
+
+// Set a filter string for a view
+// Returns NULL if OK, error message if not
+
+char *
+dbeSetFilterStr (int dbevindex, char *filter_str)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->clear_error_msg ();
+ dbev->clear_warning_msg ();
+ char *ret = dbev->set_filter (filter_str);
+ return ret;
+}
+
+// Get the current filter setting for the view
+char *
+dbeGetFilterStr (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ char *ret = dbev->get_filter ();
+ return ret;
+}
+
+// Update a filters for a single experiment
+// Returns true if any filter->set_pattern() returns true,
+// implying rereading the data is needed (i.e., a filter changed)
+//
+bool
+dbeUpdateFilters (int dbevindex, Vector<bool> *selected, Vector<char *> *pattern_str)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->clear_error_msg ();
+ dbev->clear_warning_msg ();
+
+ // Get index of first selected experiment
+ int size = selected->size ();
+ int nselexp = -1;
+ for (int index = 0; index < size; index++)
+ {
+ if (selected->fetch (index) == true)
+ {
+ nselexp = index;
+ break;
+ }
+ }
+ if (nselexp == -1) // No experiment selected
+ return false;
+
+ bool ret = false;
+ for (int j = 0; j < size; j++)
+ {
+ if (selected->fetch (j) == false)
+ continue;
+ bool error;
+ if (dbev->set_pattern (j, pattern_str, &error))
+ ret = true;
+ }
+ dbev->update_advanced_filter ();
+ return ret;
+}
+
+char *
+dbeComposeFilterClause (int dbevindex, int type, int subtype, Vector<int> *selections)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ // ask the cached data to generate the string
+ Hist_data *data;
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = dbev->func_data;
+ break;
+ case DSP_DLAYOUT:
+ data = dbev->dlay_data;
+ break;
+ case DSP_DATAOBJ:
+ data = dbev->dobj_data;
+ break;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ case DSP_LINE:
+ data = dbev->line_data;
+ break;
+ case DSP_PC:
+ data = dbev->pc_data;
+ break;
+ case DSP_SOURCE:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ data = dbev->dis_data;
+ break;
+ case DSP_IOACTIVITY:
+ data = dbev->iofile_data;
+ break;
+ case DSP_IOVFD:
+ data = dbev->iovfd_data;
+ break;
+ case DSP_IOCALLSTACK:
+ data = dbev->iocs_data;
+ break;
+ case DSP_HEAPCALLSTACK:
+ data = dbev->heapcs_data;
+ break;
+ default:
+ return NULL;
+ }
+ if (data == NULL)
+ return NULL;
+
+ // Get array of object indices, and compose filter string
+ Vector<uint64_t> *obj_ids = data->get_object_indices (selections);
+ if (obj_ids == NULL || obj_ids->size () == 0)
+ return NULL;
+
+ uint64_t sel;
+ int index;
+ int found = 0;
+ char buf[128];
+ StringBuilder sb;
+ sb.append ('(');
+ switch (type)
+ {
+ case DSP_LINE:
+ case DSP_PC:
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ case DSP_FUNCTION:
+ sb.append (NTXT ("LEAF IN "));
+ break;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ sb.append (dbeSession->getIndexSpaceName (subtype));
+ sb.append (NTXT (" IN "));
+ break;
+ }
+ Vec_loop (uint64_t, obj_ids, index, sel)
+ {
+ if (found == 0)
+ {
+ found = 1;
+ sb.append ('(');
+ }
+ else
+ sb.append (NTXT (", "));
+ snprintf (buf, sizeof (buf), NTXT ("%llu"), (long long) sel);
+ sb.append (buf);
+ }
+ if (found == 1)
+ sb.append (')');
+
+ switch (type)
+ {
+ case DSP_DLAYOUT:
+ case DSP_DATAOBJ:
+ sb.append (NTXT (" SOME IN DOBJ"));
+ break;
+ }
+ sb.append (')');
+ return sb.toString ();
+}
+
+//
+// Get load object states
+//
+Vector<void *> *
+dbeGetLoadObjectList (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ int size = lobjs->size ();
+
+ // Initialize Java boolean array
+ Vector<char *> *names = new Vector<char *>(size);
+ Vector<int> *states = new Vector<int>(size);
+ Vector<int> *indices = new Vector<int>(size);
+ Vector<char *> *paths = new Vector<char *>(size);
+ Vector<int> *isJava = new Vector<int>(size);
+
+ // Get load object states
+ int index;
+ LoadObject *lo;
+ char *lo_name;
+
+ // lobjectsNoJava is a trimmed list of indices provided to front-end skipping the Java
+ // classes. lobjectsNoJava preserves the mapping of the index into the complete lobjs
+ // vector. What front-end sees as lobj[i] is really lobj[lobjectsNoJava[i]];
+
+ // This list is constructed every time GetLoadObjectList() or GetLoadObjectState() is
+ // called. Possibility of further optimization by making it more persistent.
+ // Only consumer of this list is dbeSetLoadObjectState
+ int new_index = 0;
+ if (dbev->lobjectsNoJava == NULL)
+ dbev->lobjectsNoJava = new Vector<int>(1);
+ else
+ dbev->lobjectsNoJava->reset ();
+
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ // Set 0, 1, or 2 for show/hide/api
+ enum LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
+
+ lo_name = lo->get_name ();
+ if (lo_name != NULL)
+ {
+ size_t len = strlen (lo_name);
+ if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+ isJava->store (new_index, 1);
+ else
+ isJava->store (new_index, 0);
+ }
+ else
+ isJava->store (new_index, 0);
+ dbev->lobjectsNoJava->append (index);
+
+ names->store (new_index, dbe_sprintf (NTXT ("%s"), lo_name));
+ states->store (new_index, (int) expand);
+ indices->store (new_index, (int) lo->seg_idx);
+ paths->store (new_index, dbe_sprintf (NTXT ("%s"), lo->get_pathname ()));
+ new_index++;
+ }
+ Vector<void*> *res = new Vector<void*>(5);
+ res->store (0, names);
+ res->store (1, states);
+ res->store (2, indices);
+ res->store (3, paths);
+ res->store (4, isJava);
+ delete lobjs;
+ return res;
+}
+
+Vector<int> *
+dbeGetLoadObjectState (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ int size = lobjs->size ();
+
+ // Initialize Java boolean array
+ Vector<int> *states = new Vector<int>(size);
+ char *lo_name;
+
+ // lobjectsNoJava is a trimmed list of indices provided to front-end skipping the Java
+ // classes. lobjectsNoJava preserves the mapping of the index into the complete lobjs
+ // vector. What front-end sees as lobj[i] is really lobj[lobjectsNoJava[i]];
+
+ // This list is constructed every time GetLoadObjectList() or GetLoadObjectState() is
+ // called. Possibility of further optimization by making it more persistent.
+ // Only consumer of this list is dbeSetLoadObjectState
+ int new_index = 0;
+ if (dbev->lobjectsNoJava == NULL)
+ dbev->lobjectsNoJava = new Vector<int>(1);
+ else
+ dbev->lobjectsNoJava->reset ();
+
+ // Get load object states
+ int index;
+ LoadObject *lo;
+
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ // Set 0, 1, or 2 for show/hide/api
+ lo_name = lo->get_name ();
+ if (lo_name != NULL)
+ {
+ size_t len = strlen (lo_name);
+ if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+ continue;
+ }
+ else
+ dbev->lobjectsNoJava->append (index);
+
+ enum LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
+ states->store (new_index, (int) expand);
+ new_index++;
+ }
+ delete lobjs;
+ return states;
+}
+
+// Set load object states
+void
+dbeSetLoadObjectState (int dbevindex, Vector<int> *selected)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+
+ int index;
+ bool changed = false;
+
+ LoadObject *lo;
+ int new_index = 0;
+ dbev->setShowAll ();
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ if (dbev->lobjectsNoJava != NULL)
+ {
+ // This loadobject is a java class and was skipped
+ if (dbev->lobjectsNoJava->fetch (new_index) != index)
+ continue;
+ }
+ // Get array of settings
+ enum LibExpand expand = (enum LibExpand) selected->fetch (new_index);
+ if (expand == LIBEX_HIDE)
+ {
+ dbev->resetShowAll ();
+ dbeSession->set_lib_visibility_used ();
+ }
+ changed = changed | dbev->set_libexpand (lo->get_pathname (), expand);
+ new_index++;
+ }
+ delete lobjs;
+ if (changed == true)
+ {
+ dbev->setShowHideChanged ();
+ dbev->update_lo_expands ();
+ }
+
+ return;
+}
+
+// Reset load object states
+void
+dbeSetLoadObjectDefaults (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_libdefaults ();
+}
+
+// Get Machine model
+Vector<char*>*
+dbeGetCPUVerMachineModel (int dbevindex)
+{
+ Vector<char*>* table = new Vector<char*>();
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ char * mach_model = dbev->get_settings ()->get_machinemodel ();
+ if (mach_model != NULL)
+ {
+ table->append (mach_model);
+ return table;
+ }
+ int grsize = dbeSession->expGroups->size ();
+ for (int j = 0; j < grsize; j++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (j);
+ Vector<Experiment*> *exps = gr->exps;
+ for (int i = 0, sz = exps->size (); i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ char *model = exp->machinemodel;
+ if (model != NULL)
+ table->append (dbe_strdup (model));
+ }
+ }
+ return table;
+}
+
+// automatically load machine model if applicable
+void
+dbeDetectLoadMachineModel (int dbevindex)
+{
+ if (dbeSession->is_datamode_available ())
+ {
+ char *model = dbeGetMachineModel ();
+ if (model == NULL)
+ {
+ Vector<char*>* models = dbeGetCPUVerMachineModel (dbevindex);
+ char * machineModel = NTXT ("generic");
+ if (models->size () > 0)
+ {
+ machineModel = models->get (0);
+ for (int i = 1; i < models->size (); i++)
+ {
+ if (strncmp (models->get (i), machineModel, strlen (machineModel)) == 0)
+ {
+ machineModel = NTXT ("generic");
+ break;
+ }
+ }
+ dbeLoadMachineModel (machineModel);
+ }
+ delete models;
+ }
+ }
+}
+
+// Managing Memory Objects
+char *
+dbeDefineMemObj (char *name, char *index_expr, char *machinemodel,
+ char *sdesc, char *ldesc)
+{
+ return MemorySpace::mobj_define (name, index_expr, machinemodel, sdesc, ldesc);
+}
+
+char *
+dbeDeleteMemObj (char *name)
+{
+ return MemorySpace::mobj_delete (name);
+}
+
+Vector<void*> *
+dbeGetMemObjects (int /*dbevindex*/)
+{
+ Vector<void*> *res = MemorySpace::getMemObjects ();
+ return res;
+}
+
+// Managing machine model
+char *
+dbeLoadMachineModel (char *name)
+{
+ return dbeSession->load_mach_model (name);
+}
+
+char *
+dbeGetMachineModel ()
+{
+ return dbeSession->get_mach_model ();
+}
+
+Vector <char *> *
+dbeListMachineModels ()
+{
+ return dbeSession->list_mach_models ();
+}
+
+// Managing Index Objects
+char *
+dbeDefineIndxObj (char *name, char *index_expr, char *sdesc, char *ldesc)
+{
+ return dbeSession->indxobj_define (name, NULL, index_expr, sdesc, ldesc);
+}
+
+Vector<void*> *
+dbeGetIndxObjDescriptions (int /*dbevindex*/)
+{
+ Vector<void*> *res = dbeSession->getIndxObjDescriptions ();
+ return res;
+}
+
+Vector<void*> *
+dbeGetCustomIndxObjects (int /*dbevindex*/)
+{
+ Vector<void*> *res = dbeSession->getCustomIndxObjects ();
+ return res;
+}
+
+void
+dbeSetSelObj (int dbevindex, Obj sel_obj_or_ind, int type, int subtype)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable *sel_obj;
+ Hist_data *data;
+ int sel_ind = (int) sel_obj_or_ind;
+
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = dbev->func_data;
+ break;
+ case DSP_LINE:
+ data = dbev->line_data;
+ break;
+ case DSP_PC:
+ data = dbev->pc_data;
+ break;
+ case DSP_CALLER:
+ data = dbev->callers;
+ break;
+ case DSP_CALLEE:
+ data = dbev->callees;
+ break;
+ case DSP_SOURCE:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ data = dbev->dis_data;
+ break;
+ case DSP_DLAYOUT:
+ data = dbev->dlay_data;
+ if (data == NULL)
+ {
+ dbev->sel_binctx = NULL;
+ return;
+ }
+ if (sel_ind >= 0 && sel_ind < dbev->dlay_data->size ())
+ dbev->sel_dobj = dbev->dlay_data->fetch (sel_ind)->obj;
+ return;
+ case DSP_DATAOBJ:
+ data = dbev->dobj_data;
+ if (data == NULL)
+ {
+ dbev->sel_binctx = NULL;
+ return;
+ }
+ if (sel_ind >= 0 && sel_ind < dbev->dobj_data->size ())
+ dbev->sel_dobj = dbev->dobj_data->fetch (sel_ind)->obj;
+ return;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ dbev->set_indxobj_sel (subtype, sel_ind);
+ sel_obj = dbev->get_indxobj_sel (subtype);
+ if (sel_obj && sel_obj->get_type () == Histable::INDEXOBJ)
+ dbev->set_sel_obj (((IndexObject*) sel_obj)->get_obj ());
+ return;
+ case DSP_SOURCE_V2:
+ case DSP_DISASM_V2:
+ case DSP_TIMELINE:
+ case DSP_LEAKLIST:
+ case DSP_RACES:
+ case DSP_DEADLOCKS:
+ case DSP_DUALSOURCE:
+ case DSP_SOURCE_DISASM:
+ case DSP_IOACTIVITY:
+ case DSP_IOVFD:
+ case DSP_IOCALLSTACK:
+ case DSP_HEAPCALLSTACK:
+ case DSP_MINICALLER:
+ dbev->set_sel_obj ((Histable *) sel_obj_or_ind);
+ return;
+ default:
+ // abort();
+ return;
+ }
+ if (type != DSP_SOURCE && type != DSP_DISASM && type != DSP_SOURCE_V2
+ && type != DSP_DISASM_V2)
+ dbev->sel_binctx = NULL;
+
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS
+ || sel_ind >= data->size ())
+ return;
+
+ if (sel_ind >= 0 && sel_ind < data->size ())
+ dbev->set_sel_obj (data->fetch (sel_ind)->obj);
+}
+
+void
+dbeSetSelObjV2 (int dbevindex, uint64_t id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->set_sel_obj (dbeSession->findObjectById (id));
+}
+
+Obj
+dbeGetSelObj (int dbevindex, int type, int subtype)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ Histable *sel_obj = NULL;
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ sel_obj = dbev->get_sel_obj (Histable::FUNCTION);
+ break;
+ case DSP_LINE:
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ sel_obj = dbev->get_sel_obj (Histable::LINE);
+ break;
+ case DSP_PC:
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ sel_obj = dbev->get_sel_obj (Histable::INSTR);
+ break;
+ case DSP_SRC_FILE:
+ sel_obj = dbev->get_sel_obj (Histable::SOURCEFILE);
+ break;
+ case DSP_DATAOBJ:
+ case DSP_DLAYOUT:
+ if (dbev->sel_dobj)
+ sel_obj = dbev->sel_dobj->convertto (Histable::DOBJECT);
+ break;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ sel_obj = dbev->get_indxobj_sel (subtype);
+ break;
+ default:
+ abort ();
+ }
+ Dprintf (DEBUG_DBE, NTXT ("### dbeGetSelObj: Dbe.cc:%d %s (%d) returns %s\n"),
+ __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () : "NULL");
+ return (Obj) sel_obj;
+}
+
+Obj
+dbeConvertSelObj (Obj obj, int type)
+{
+ Histable *sel_obj = (Histable *) obj;
+ Dprintf (DEBUG_DBE, NTXT ("### dbeConvertSelObj: Dbe.cc:%d %s (%d) sel_obj=%s\n"),
+ __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump ()
+ : "NULL");
+ if (sel_obj == NULL)
+ return (Obj) NULL;
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ return (Obj) sel_obj->convertto (Histable::FUNCTION);
+ case DSP_LINE:
+ return (Obj) sel_obj->convertto (Histable::LINE);
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ {
+ SourceFile* srcCtx = NULL;
+ if (sel_obj->get_type () == Histable::INSTR)
+ {
+ DbeInstr* dbei = (DbeInstr *) sel_obj;
+ srcCtx = (SourceFile*) dbei->convertto (Histable::SOURCEFILE);
+ }
+ else if (sel_obj->get_type () == Histable::LINE)
+ {
+ DbeLine * dbel = (DbeLine *) sel_obj;
+ srcCtx = dbel->sourceFile;
+ }
+ sel_obj = sel_obj->convertto (Histable::LINE, srcCtx);
+ Dprintf (DEBUG_DBE, NTXT ("### dbeConvertSelObj: Dbe.cc:%d %s (%d) returns %s\n"),
+ __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () : "NULL");
+ if (sel_obj && sel_obj->get_type () == Histable::LINE)
+ {
+ DbeLine * dbel = (DbeLine *) sel_obj;
+ return (Obj) dbel->dbeline_base;
+ }
+ return (Obj) sel_obj->convertto (Histable::LINE, srcCtx);
+ }
+ case DSP_PC:
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ return (Obj) sel_obj->convertto (Histable::INSTR);
+ case DSP_SRC_FILE:
+ return (Obj) sel_obj->convertto (Histable::SOURCEFILE);
+ default:
+ abort ();
+ }
+ return (Obj) NULL;
+}
+
+uint64_t
+dbeGetSelObjV2 (int dbevindex, char *typeStr)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable *obj = NULL;
+ if (typeStr != NULL)
+ {
+ if (streq (typeStr, NTXT ("FUNCTION")))
+ obj = dbev->get_sel_obj (Histable::FUNCTION);
+ else if (streq (typeStr, NTXT ("INSTRUCTION")))
+ obj = dbev->get_sel_obj (Histable::INSTR);
+ else if (streq (typeStr, NTXT ("SOURCELINE")))
+ obj = dbev->get_sel_obj (Histable::LINE);
+ else if (streq (typeStr, NTXT ("SOURCEFILE")))
+ obj = dbev->get_sel_obj (Histable::SOURCEFILE);
+ }
+ Dprintf (DEBUG_DBE, NTXT ("### dbeGetSelObjV2: Dbe.cc:%d %s returns %s\n"),
+ __LINE__, STR (typeStr), obj ? obj->dump () : "NULL");
+ return obj != NULL ? obj->id : (uint64_t) - 1;
+}
+
+Vector<uint64_t> *
+dbeGetSelObjsIO (int dbevindex, Vector<uint64_t> *ids, int type)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<uint64_t> *res = NULL;
+ Vector<uint64_t> *result = new Vector<uint64_t>();
+ for (int i = 0; i < ids->size (); i++)
+ {
+ res = dbeGetSelObjIO (dbevindex, ids->fetch (i), type);
+ if (res != NULL)
+ {
+ result->addAll (res);
+ delete res;
+ }
+ }
+ return result;
+}
+
+Vector<uint64_t> *
+dbeGetSelObjIO (int dbevindex, uint64_t id, int type)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable *obj = NULL;
+ Vector<uint64_t> *res = NULL;
+ int size = 0;
+ switch (type)
+ {
+ case DSP_IOACTIVITY:
+ obj = dbev->get_sel_obj_io (id, Histable::IOACTFILE);
+ size = obj != NULL ? ((FileData*) obj)->getVirtualFds ()->size () : 0;
+ if (size)
+ {
+ res = new Vector<uint64_t>();
+ Vector<int64_t> *vfds = ((FileData*) obj)->getVirtualFds ();
+ for (int i = 0; i < size; i++)
+ res->append (vfds->fetch (i));
+ }
+ break;
+ case DSP_IOVFD:
+ obj = dbev->get_sel_obj_io (id, Histable::IOACTVFD);
+ if (obj)
+ {
+ res = new Vector<uint64_t>();
+ res->append (obj->id);
+ }
+ break;
+ case DSP_IOCALLSTACK:
+ obj = dbev->get_sel_obj_io (id, Histable::IOCALLSTACK);
+ if (obj)
+ {
+ Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, obj->id);
+ if (instrs == NULL)
+ return NULL;
+ int stsize = instrs->size ();
+ res = new Vector<uint64_t>(stsize);
+ for (int i = 0; i < stsize; i++)
+ {
+ Histable *objFunc = (DbeInstr*) (instrs->fetch (i));
+ if (objFunc->get_type () != Histable::LINE)
+ {
+ objFunc = objFunc->convertto (Histable::FUNCTION);
+ res->insert (0, objFunc->id);
+ }
+ }
+ delete instrs;
+ }
+ break;
+ default:
+ break;
+ }
+ return res;
+}
+
+uint64_t
+dbeGetSelObjHeapTimestamp (int dbevindex, uint64_t id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable *obj = NULL;
+ uint64_t res = 0;
+ Vector<uint64_t> *peakStackIds;
+ Vector<hrtime_t> *peakTimestamps;
+
+ // Find and return the timestamp for the peak
+ bool foundPeakId = false;
+ if (id > 0)
+ {
+ obj = dbev->get_sel_obj_heap (0);
+ if (obj != NULL)
+ {
+ peakStackIds = ((HeapData*) obj)->getPeakStackIds ();
+ peakTimestamps = ((HeapData*) obj)->getPeakTimestamps ();
+ for (int i = 0; i < peakStackIds->size (); i++)
+ {
+ if (id == peakStackIds->fetch (i))
+ {
+ res = peakTimestamps->fetch (i);
+ foundPeakId = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Return the first timestamp for the peak
+ // if the callstack id is zero or it
+ // doesn't match with the peak stack id
+ if (id == 0 || !foundPeakId)
+ {
+ obj = dbev->get_sel_obj_heap (0);
+ res = obj != NULL ? ((HeapData*) obj)->getPeakTimestamps ()->fetch (0) : 0;
+ }
+ return res;
+}
+
+int
+dbeGetSelObjHeapUserExpId (int dbevindex, uint64_t id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable *obj = NULL;
+ int res = 0;
+ obj = dbev->get_sel_obj_heap (id);
+ res = obj != NULL ? ((HeapData*) obj)->getUserExpId () : 0;
+ return res;
+}
+
+//
+// Get index of selected function/object
+//
+int
+dbeGetSelIndex (int dbevindex, Obj sel_obj, int type, int subtype)
+{
+ Hist_data *data;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = dbev->func_data;
+ break;
+ case DSP_LINE:
+ data = dbev->line_data;
+ break;
+ case DSP_PC:
+ data = dbev->pc_data;
+ break;
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ break;
+ case DSP_DLAYOUT:
+ data = dbev->dlay_data;
+ break;
+ case DSP_DATAOBJ:
+ data = dbev->dobj_data;
+ break;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return -1;
+
+ Histable *chk_obj = (Histable *) sel_obj;
+ Vector<Hist_data::HistItem*> *histItems = data->get_hist_items ();
+ if (histItems == NULL || chk_obj == NULL)
+ return -1;
+ for (int i = 0, sz = histItems->size (); i < sz; i++)
+ {
+ if (histItems->get (i)->obj == chk_obj)
+ return i;
+ if (histItems->get (i)->obj == NULL)
+ continue;
+ if (histItems->get (i)->obj->get_type () == Histable::LINE
+ && chk_obj->get_type () == Histable::LINE)
+ {
+ if (((DbeLine*) histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+ == ((DbeLine*) chk_obj)->convertto (Histable::FUNCTION)
+ && ((DbeLine*) histItems->get (i)->obj)->lineno
+ == ((DbeLine*) chk_obj)->lineno)
+ return i;
+ }
+ else if (histItems->get (i)->obj->get_type () == Histable::INSTR
+ && chk_obj->get_type () == Histable::INSTR)
+ if (((DbeInstr*) histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+ == ((DbeInstr*) chk_obj)->convertto (Histable::FUNCTION)
+ && ((DbeInstr*) histItems->get (i)->obj)->addr
+ == ((DbeInstr*) chk_obj)->addr)
+ return i;
+ }
+
+ Histable *chk_obj1 = NULL;
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ chk_obj1 = chk_obj->convertto (Histable::FUNCTION);
+ break;
+ case DSP_LINE:
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ chk_obj1 = chk_obj->convertto (Histable::LINE);
+ break;
+ case DSP_PC:
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ chk_obj1 = chk_obj->convertto (Histable::INSTR);
+ break;
+ }
+ if (chk_obj1 && chk_obj != chk_obj1)
+ for (int i = 0, sz = histItems->size (); i < sz; i++)
+ if (histItems->get (i)->obj == chk_obj1)
+ return i;
+
+ if (type == DSP_LINE)
+ {
+ for (int i = 0, sz = histItems->size (); i < sz; i++)
+ if (histItems->get (i)->obj != NULL
+ && chk_obj->convertto (Histable::FUNCTION)
+ == histItems->get (i)->obj->convertto (Histable::FUNCTION))
+ return i;
+ }
+ else if (type == DSP_PC)
+ {
+ for (int i = 0, sz = histItems->size (); i < sz; i++)
+ if (histItems->get (i)->obj != NULL
+ && (histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+ == (chk_obj)->convertto (Histable::FUNCTION)
+ && ((DbeLine*) histItems->get (i)->obj->convertto (Histable::LINE))->lineno
+ == ((DbeLine*) chk_obj->convertto (Histable::LINE))->lineno)
+ return i;
+ for (int i = 0, sz = histItems->size (); i < sz; i++)
+ if (histItems->get (i)->obj != NULL
+ && (histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+ == (chk_obj)->convertto (Histable::FUNCTION))
+ return i;
+ }
+
+ // If we clicked on an mfunction line in the called-by call mini in user mode for omp
+ // we might not find that function in func data
+ if (dbev->isOmpDisMode () && type == DSP_FUNCTION)
+ {
+ int p = dbeGetSelIndex (dbevindex, sel_obj, DSP_DISASM, subtype);
+ if (p != -1)
+ return p;
+ }
+ return -1;
+}
+
+// Print data
+//
+char *
+dbePrintData (int dbevindex, int type, int subtype, char *printer,
+ char *fname, FILE *outfile)
+{
+ Histable *current_obj;
+ Function *func;
+ Module *module;
+ MetricList *mlist_orig;
+ bool header;
+ Print_params params;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+
+ // Set print parameters
+ if (printer != NULL)
+ {
+ params.dest = DEST_PRINTER;
+ params.name = printer;
+ }
+ else if (outfile != NULL)
+ {
+ params.dest = DEST_OPEN_FILE;
+ params.openfile = outfile;
+ params.name = NULL;
+ }
+ else
+ {
+ params.dest = DEST_FILE;
+ params.name = fname;
+ if (*(params.name) == '\0')
+ {
+ free (params.name);
+ return dbe_strdup (GTXT ("Please enter the name of the file to which to print"));
+ }
+ }
+ params.ncopies = 1;
+ if (outfile != NULL)
+ header = false;
+ else
+ header = !(type == DSP_SOURCE || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2);
+
+ params.header = header;
+
+ // figure out what kind of metrics to use
+ if (type == DSP_SELF || type == DSP_CALLER || type == DSP_CALLEE
+ || type == DSP_CALLTREE)
+ mlist_orig = dbev->get_metric_list (MET_CALL);
+ else if (type == DSP_DATAOBJ || type == DSP_DLAYOUT || type == DSP_MEMOBJ)
+ mlist_orig = dbev->get_metric_list (MET_DATA);
+ else if (type == DSP_INDXOBJ)
+ mlist_orig = dbev->get_metric_list (MET_INDX);
+ else if (type == DSP_IOACTIVITY || type == DSP_IOVFD
+ || type == DSP_IOCALLSTACK)
+ mlist_orig = dbev->get_metric_list (MET_IO);
+ else if (type == DSP_HEAPCALLSTACK)
+ mlist_orig = dbev->get_metric_list (MET_HEAP);
+ else
+ mlist_orig = dbev->get_metric_list (MET_NORMAL);
+
+ // make a compacted version of the input list
+ // the list will either be moved to the generated data,
+ // or freed below if it wasn't needed
+ MetricList *mlist = new MetricList (mlist_orig);
+ Hist_data *data = NULL;
+ er_print_common_display *cd = NULL;
+ int ix;
+ // Set data
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ case DSP_LINE:
+ case DSP_PC:
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ case DSP_DATAOBJ:
+ data = dbev->get_hist_data (mlist,
+ ((type == DSP_FUNCTION) ? Histable::FUNCTION :
+ (type == DSP_LINE) ? Histable::LINE :
+ (type == DSP_PC) ? Histable::INSTR :
+ (type == DSP_INDXOBJ) ? Histable::INDEXOBJ :
+ (type == DSP_MEMOBJ) ? Histable::MEMOBJ
+ : Histable::DOBJECT),
+ subtype, Hist_data::ALL);
+ if (data->get_status () != Hist_data::SUCCESS)
+ return DbeView::status_str (DbeView::DBEVIEW_NO_DATA); // no strdup()
+
+ cd = new er_print_histogram (dbev, data, mlist, MODE_LIST,
+ dbev->get_limit (),
+ mlist->get_sort_name (), NULL, true, true);
+ break;
+ case DSP_DLAYOUT:
+ {
+ data = dbev->get_hist_data (mlist, Histable::DOBJECT, 0, Hist_data::LAYOUT);
+ if (data->get_status () != Hist_data::SUCCESS)
+ return DbeView::status_str (DbeView::DBEVIEW_NO_DATA); // no strdup()
+ cd = new er_print_histogram (dbev, data, mlist, MODE_ANNOTATED,
+ dbev->get_thresh_dis (),
+ mlist->get_sort_name (), NULL, true, true);
+ break;
+ }
+
+ // source and disassembly
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ case DSP_SOURCE_V2:
+ case DSP_DISASM_V2:
+ if (dbev->sel_obj == NULL)
+ return NULL;
+ current_obj = dbev->sel_obj->convertto (Histable::FUNCTION);
+ if (current_obj->get_type () != Histable::FUNCTION)
+ return dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+ func = (Function*) current_obj->convertto (Histable::FUNCTION);
+ if (func->flags & FUNC_FLAG_SIMULATED)
+ return dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+ if (func->get_name () == NULL)
+ return dbe_strdup (GTXT ("Source location not recorded in experiment"));
+ module = func->module;
+ if (module == NULL || module->get_name () == NULL)
+ return dbe_strdup (GTXT ("Object name not recorded in experiment"));
+ ix = module->loadobject->seg_idx;
+ if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+ return dbe_strdup (GTXT ("No source or disassembly available for hidden object"));
+ cd = new er_print_histogram (dbev, dbev->func_data, mlist, MODE_ANNOTATED,
+ type == DSP_DISASM || type == DSP_DISASM_V2,
+ mlist->get_sort_name (),
+ func, false, false);
+ break;
+
+ // callers-callees
+ case DSP_SELF:
+ case DSP_CALLER:
+ case DSP_CALLEE:
+ if (dbev->sel_obj == NULL)
+ return NULL;
+ current_obj = dbev->sel_obj->convertto (Histable::FUNCTION);
+ cd = new er_print_histogram (dbev, dbev->func_data, mlist, MODE_GPROF, 1,
+ mlist->get_sort_name (), current_obj,
+ false, false);
+ break;
+
+ // statistics; this won't use the metric list copied above, so delete it
+ case DSP_STATIS:
+ cd = new er_print_experiment (dbev, 0, dbeSession->nexps () - 1,
+ true, true, true, true, false);
+ delete mlist;
+ break;
+ case DSP_EXP:
+ cd = new er_print_experiment (dbev, 0, dbeSession->nexps () - 1,
+ true, true, false, false, false);
+ delete mlist;
+ break;
+ case DSP_LEAKLIST:
+ cd = new er_print_leaklist (dbev, true, true, dbev->get_limit ());
+ delete mlist;
+ break;
+ case DSP_HEAPCALLSTACK:
+ cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false,
+ dbev->get_limit ());
+ delete mlist;
+ break;
+ case DSP_IOACTIVITY:
+ cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false,
+ dbev->get_limit ());
+ delete mlist;
+ break;
+ case DSP_IOVFD:
+ cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false,
+ dbev->get_limit ());
+ delete mlist;
+ break;
+
+ // the io call stack
+ case DSP_IOCALLSTACK:
+ cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false,
+ dbev->get_limit ());
+ delete mlist;
+ break;
+
+ // some unknown panel -- return an error string
+ default:
+ delete mlist;
+ return dbe_strdup (GTXT ("Print not available"));
+ }
+
+ // Start printing
+ char *buf = NULL;
+
+ // first open the file/device/whatever
+ if (cd->open (&params) == 0)
+ {
+ // now call the actual print routine
+ cd->data_dump ();
+ if (params.dest == DEST_PRINTER)
+ {
+ if (streq ((char *) params.name, NTXT ("-")))
+ {
+ // Special case - return report to the GUI
+ int maxbytes = 2 * 1024 * 1024; // IPC large buffer limit
+ char *report = cd->get_output (maxbytes);
+ delete data;
+ delete cd;
+ return report; // TEMPORARY
+ }
+ }
+ if (cd->print_output () == false)
+ buf = dbe_sprintf (NTXT ("%s: %s"),
+ GTXT ("Unable to submit print request to"),
+ params.name);
+ }
+ else
+ // if unable to set up the print, return an error
+ buf = dbe_sprintf (NTXT ("%s: %s"),
+ GTXT ("Unable to open file"),
+ params.name);
+
+ // dbe_free((void *) params.name); XXX when should this happen?
+ if (data)
+ if (data->isViewOwned () == false)
+ delete data;
+ delete cd;
+ return buf;
+}
+
+// Set limit for print data
+//
+char *
+dbeSetPrintLimit (int dbevindex, int limit)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ return (dbev->set_limit (limit));
+}
+
+// get limit for print data
+int
+dbeGetPrintLimit (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ int limit = dbev->get_limit ();
+ return limit;
+}
+
+// set printmode for data
+char *
+dbeSetPrintMode (int dbevindex, char * pmode)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ char *r = dbev->set_printmode (pmode);
+ return r;
+}
+
+// get printmode for data
+int
+dbeGetPrintMode (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ return (dbev->get_printmode ());
+}
+
+// get printmode for data
+char *
+dbeGetPrintModeString (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ return ( dbev->get_printmode_str ());
+}
+
+// get print delimiter for csv data
+char
+dbeGetPrintDelim (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ return (dbev->get_printdelimiter ());
+}
+
+// Set Source/Object/Load-Object file names
+static void
+set_file_names (Function *func, char *names[3])
+{
+ Module *module = func->module;
+ LoadObject *loadobject = module->loadobject;
+ if (loadobject == NULL)
+ loadobject = dbeSession->get_Unknown_LoadObject ();
+ free (names[0]);
+ free (names[1]);
+ free (names[2]);
+ SourceFile *sf = func->getDefSrc ();
+ char *src_name = sf->dbeFile->get_location_info ();
+ DbeFile *df = module->dbeFile;
+ if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
+ df = module->loadobject->dbeFile;
+ char *lo_name = df->get_location_info ();
+ char *dot_o_name = lo_name;
+ if (module->dot_o_file)
+ dot_o_name = module->dot_o_file->dbeFile->get_location_info ();
+ names[0] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Source File"), src_name);
+ names[1] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Object File"), dot_o_name);
+ names[2] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Load Object"), lo_name);
+}
+
+// dbeSetFuncData
+// Master function to generate all Tab data for the analyzer
+// Returns the index of the selected item in the specified list
+//
+// After calling it to set up, the Analyzer calls dbeGetFuncList
+// to format the generated data and return the table
+// Most of the data is destined for a JTable
+//
+int
+dbeSetFuncData (int dbevindex, Obj sel_obj, int type, int subtype)
+{
+ MetricList *_mlist;
+ Histable *org_obj;
+ Hist_data *data = NULL;
+ int index, sel_index;
+ Function *func;
+ char *name;
+ int ix;
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ sel_index = -1;
+ dbev->resetOmpDisMode ();
+ dbev->error_msg = dbev->warning_msg = NULL;
+
+ // get metric list, make a compact duplicate
+ _mlist = dbev->get_metric_list (MET_NORMAL);
+ MetricList *mlist = new MetricList (_mlist);
+
+ // Remove old function/obj list data & Get new function/obj list data
+ org_obj = (Histable *) sel_obj;
+
+ // Figure out which "function" data is being asked for, i.e.,
+ // which of the analyzer displays is asking for data
+ switch (type)
+ {
+ // the various tables: functions, lines, PCs, DataObjects, IndexObjects
+ case DSP_FUNCTION:
+ case DSP_LINE:
+ case DSP_PC:
+ case DSP_DATAOBJ:
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ if (dbev->func_data)
+ delete dbev->func_data;
+ dbev->func_data = data = dbev->get_hist_data (mlist,
+ Histable::FUNCTION, subtype, Hist_data::ALL);
+ break;
+ case DSP_LINE:
+ if (dbev->line_data)
+ delete dbev->line_data;
+ dbev->line_data = data = dbev->get_hist_data (mlist,
+ Histable::LINE, subtype, Hist_data::ALL);
+ break;
+ case DSP_PC:
+ if (dbev->pc_data)
+ delete dbev->pc_data;
+ dbev->pc_data = data = dbev->get_hist_data (mlist,
+ Histable::INSTR, subtype, Hist_data::ALL);
+ break;
+ case DSP_DATAOBJ:
+ if (dbev->dobj_data)
+ delete dbev->dobj_data;
+ mlist = dbev->get_metric_list (MET_DATA);
+ dbev->dobj_data = data = dbev->get_hist_data (mlist,
+ Histable::DOBJECT, subtype, Hist_data::ALL);
+ break;
+ case DSP_MEMOBJ:
+ mlist = dbev->get_metric_list (MET_DATA);
+ data = dbev->get_hist_data (mlist, Histable::MEMOBJ, subtype,
+ Hist_data::ALL);
+ dbev->indx_data->store (subtype, data);
+ break;
+ case DSP_INDXOBJ:
+ mlist = dbev->get_metric_list (MET_INDX);
+ data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, subtype,
+ Hist_data::ALL);
+ dbev->indx_data->store (subtype, data);
+ break;
+ default:
+ break;
+ }
+
+ // Set the selection of row item
+ if (data->get_status () == Hist_data::SUCCESS)
+ {
+ // otherwise, look for it
+ sel_index = -1;
+ if (org_obj)
+ {
+ Hist_data::HistItem *hi;
+ Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+ {
+ if (hi->obj == org_obj)
+ {
+ sel_index = index;
+ break;
+ }
+ }
+ if (sel_index == -1 && (type == DSP_LINE || type == DSP_PC))
+ {
+ Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+ {
+ name = hi->obj->get_name ();
+ if (strcmp (name, NTXT ("<Total>")) &&
+ strcmp (name, GTXT ("<Unknown>")))
+ {
+ int done = 0;
+ switch (type)
+ {
+ case DSP_LINE:
+ if (org_obj->convertto (Histable::FUNCTION)
+ == hi->obj->convertto (Histable::FUNCTION))
+ {
+ sel_index = index;
+ done = 1;
+ }
+ break;
+ case DSP_PC:
+ if (hi->obj->convertto (Histable::FUNCTION)
+ == org_obj->convertto (Histable::FUNCTION)
+ && ((DbeLine*) hi->obj->convertto (Histable::LINE))->lineno
+ == ((DbeLine*) org_obj->convertto (Histable::LINE))->lineno)
+ {
+ sel_index = index;
+ done = 1;
+ }
+ break;
+ }
+ if (done)
+ break;
+ }
+ }
+ }
+ if (sel_index == -1 && type == DSP_PC)
+ {
+ Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+ {
+ name = hi->obj->get_name ();
+ if (strcmp (name, NTXT ("<Total>")) &&
+ strcmp (name, GTXT ("<Unknown>")))
+ {
+ int done = 0;
+ if (hi->obj->convertto (Histable::FUNCTION) ==
+ org_obj->convertto (Histable::FUNCTION))
+ {
+ sel_index = index;
+ done = 1;
+ }
+ if (done)
+ break;
+ }
+ }
+ }
+ }
+ if (sel_index == -1)
+ {
+ Hist_data::HistItem *hi;
+ Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+ {
+ name = hi->obj->get_name ();
+ if (strcmp (name, NTXT ("<Total>")) &&
+ strcmp (name, GTXT ("<Unknown>")))
+ {
+ sel_index = index;
+ break;
+ }
+ }
+ }
+ }
+ else
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ return sel_index;
+ // the end of the code for the regular tables
+
+ // Data Layout
+ case DSP_DLAYOUT:
+ if (dbev->dlay_data)
+ delete dbev->dlay_data;
+ dbev->marks->reset ();
+ mlist = dbev->get_metric_list (MET_DATA);
+
+ // initial dobj list ...
+ data = dbev->get_hist_data (mlist, Histable::DOBJECT, subtype,
+ Hist_data::LAYOUT);
+ // .. provides metric data for layout
+ dbev->dlay_data = data = dbev->get_data_space ()->get_layout_data (data,
+ dbev->marks, dbev->get_thresh_dis ());
+ if (data->get_status () != Hist_data::SUCCESS)
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ return sel_index;
+
+ // Source or disassembly
+ case DSP_SOURCE_V2:
+ case DSP_DISASM_V2:
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ {
+ if (org_obj == NULL)
+ {
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_SEL_OBJ);
+ return sel_index;
+ }
+ if (org_obj->get_type () != Histable::FUNCTION)
+ {
+ dbev->error_msg = dbe_strdup (
+ GTXT ("Not a real function; no source or disassembly available."));
+ return sel_index;
+ }
+ func = (Function *) org_obj;
+ if (func->flags & FUNC_FLAG_SIMULATED)
+ {
+ dbev->error_msg = dbe_strdup (
+ GTXT ("Not a real function; no source or disassembly available."));
+ return sel_index;
+ }
+ if (func->get_name () == NULL)
+ {
+ dbev->error_msg = dbe_strdup (
+ GTXT ("Source location not recorded in experiment"));
+ return sel_index;
+ }
+ Module *module = func->module;
+ if ((module == NULL) || (module->get_name () == NULL))
+ {
+ dbev->error_msg = dbe_strdup (
+ GTXT ("Object name not recorded in experiment"));
+ return sel_index;
+ }
+ ix = module->loadobject->seg_idx;
+ if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+ {
+ dbev->error_msg = dbe_strdup (
+ GTXT ("No source or disassembly available for hidden object"));
+ return sel_index;
+ }
+
+ if ((type == DSP_DISASM || type == DSP_DISASM_V2)
+ && dbev->get_view_mode () == VMODE_USER
+ && dbeSession->is_omp_available ())
+ dbev->setOmpDisMode ();
+
+ dbev->marks->reset ();
+ SourceFile *srcContext = NULL;
+ switch (dbev->sel_obj->get_type ())
+ {
+ case Histable::FUNCTION:
+ {
+ Function *f = (Function *) dbev->sel_obj;
+ srcContext = f->getDefSrc ();
+ dbev->sel_binctx = f->module;
+ break;
+ }
+ case Histable::LINE:
+ {
+ DbeLine *dl = (DbeLine *) dbev->sel_obj;
+ srcContext = dl->sourceFile;
+ Function *f = dl->func;
+ if (f)
+ dbev->sel_binctx = f;
+ break;
+ }
+ case Histable::INSTR:
+ {
+ Function *f = (Function *) dbev->sel_obj->convertto (Histable::FUNCTION);
+ if (f)
+ {
+ dbev->sel_binctx = f;
+ srcContext = f->getDefSrc ();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ mlist = dbev->get_metric_list (MET_SRCDIS);
+
+ // for source and disassembly the name needs to be invisible,
+ // but that's handled in the module code
+ if (type == DSP_SOURCE)
+ {
+ if (dbev->src_data)
+ delete dbev->src_data;
+
+ // func_data computation needed for get_totals
+ if (dbev->func_data == NULL)
+ dbev->func_data = data = dbev->get_hist_data (mlist,
+ Histable::FUNCTION, subtype, Hist_data::ALL);
+ dbev->marks2dsrc->reset ();
+ dbev->marks2dsrc_inc->reset ();
+ data = dbev->src_data = module->get_data (dbev, mlist,
+ Histable::LINE, dbev->func_data->get_totals ()->value,
+ srcContext, func, dbev->marks,
+ dbev->get_thresh_src (), dbev->get_src_compcom (),
+ dbev->get_src_visible (), dbev->get_hex_visible (),
+ false, false, dbev->marks2dsrc, dbev->marks2dsrc_inc);
+ set_file_names (func, dbev->names_src);
+ if (srcContext)
+ {
+ free (dbev->names_src[0]);
+ dbev->names_src[0] = dbe_sprintf (GTXT ("Source File: %s"),
+ srcContext->dbeFile->get_location_info ());
+ }
+ Obj obj = (Obj) func->convertto (Histable::LINE, srcContext);
+ sel_index = dbeGetSelIndex (dbevindex, obj, type, subtype);
+ }
+ else
+ { /* type == DSP_DISASM */
+ if (dbev->dis_data)
+ delete dbev->dis_data;
+
+ // func_data computation needed for get_totals
+ if (dbev->func_data == NULL)
+ dbev->func_data = data = dbev->get_hist_data (mlist,
+ Histable::FUNCTION, subtype, Hist_data::ALL);
+ dbev->marks2ddis->reset ();
+ dbev->marks2ddis_inc->reset ();
+ data = dbev->dis_data = module->get_data (dbev, mlist,
+ Histable::INSTR, dbev->func_data->get_totals ()->value,
+ srcContext, func, dbev->marks, dbev->get_thresh_dis (),
+ dbev->get_dis_compcom (), dbev->get_src_visible (),
+ dbev->get_hex_visible (), dbev->get_func_scope (),
+ false, dbev->marks2ddis, dbev->marks2ddis_inc);
+ set_file_names (func, dbev->names_dis);
+ if (srcContext)
+ {
+ free (dbev->names_dis[0]);
+ dbev->names_dis[0] = dbe_sprintf (GTXT ("Source File: %s"),
+ srcContext->dbeFile->get_location_info ());
+ }
+ Obj obj = (Obj) func->convertto (Histable::INSTR);
+ sel_index = dbeGetSelIndex (dbevindex, obj, type, subtype);
+ }
+ return sel_index;
+ }
+
+ // the three cases for caller-callee
+ case DSP_SELF:
+ case DSP_CALLER:
+ case DSP_CALLEE:
+ if (org_obj == NULL)
+ {
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_SEL_OBJ);
+ return sel_index;
+ }
+
+ // Caller data
+ if (dbev->callers)
+ delete dbev->callers;
+ mlist = dbev->get_metric_list (MET_CALL);
+ dbev->callers = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype,
+ Hist_data::CALLERS, org_obj);
+ if (dbev->callers->get_status () != Hist_data::SUCCESS)
+ {
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ return sel_index;
+ }
+
+ // Callee data
+ if (dbev->callees)
+ delete dbev->callees;
+ dbev->callees = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype,
+ Hist_data::CALLEES, org_obj);
+ if (dbev->callees->get_status () != Hist_data::SUCCESS)
+ {
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ return sel_index;
+ }
+
+ // Center Function item
+ if (dbev->fitem_data)
+ delete dbev->fitem_data;
+ dbev->fitem_data = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype,
+ Hist_data::SELF, org_obj);
+ if (dbev->fitem_data->get_status () != Hist_data::SUCCESS)
+ {
+ dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ return sel_index;
+ }
+ return sel_index;
+ default:
+ abort ();
+ }
+ return sel_index;
+}
+
+Vector<void*>*
+dbeGetTotals (int dbevindex, int dsptype, int subtype)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ MetricList *mlist = dbev->get_metric_list (dsptype, subtype);
+ Hist_data *data = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::ALL);
+ Hist_data::HistItem *totals = data->get_totals ();
+ Vector<void*> *tbl = new Vector<void*>(mlist->size ());
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get (i);
+ switch (m->get_vtype ())
+ {
+ case VT_DOUBLE:
+ {
+ Vector<double> *lst = new Vector<double>(1);
+ lst->append (totals->value[i].d);
+ tbl->append (lst);
+ break;
+ }
+ case VT_INT:
+ {
+ Vector<int> *lst = new Vector<int>(1);
+ lst->append (totals->value[i].i);
+ tbl->append (lst);
+ break;
+ }
+ case VT_LLONG:
+ case VT_ULLONG:
+ case VT_ADDRESS:
+ {
+ Vector<long long> *lst = new Vector<long long>(1);
+ lst->append (totals->value[i].ll);
+ tbl->append (lst);
+ break;
+ }
+ case VT_LABEL:
+ {
+ Vector<char *> *lst = new Vector<char *>(1);
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ lst->append (dbe_strdup (totals->obj->get_name (nfmt)));
+ tbl->append (lst);
+ break;
+ }
+ default:
+ abort ();
+ }
+ }
+ Vector<void*> *res = new Vector<void*>(2);
+ res->append (dbeGetMetricList (mlist));
+ res->append (tbl);
+ return res;
+}
+
+Vector<void*>*
+dbeGetHotMarks (int dbevindex, int type)
+{
+ Vector<void*>* table = new Vector<void*>(2);
+ Vector<int>* table0 = new Vector<int> ();
+ Vector<int>* table1 = new Vector<int> ();
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ return NULL;
+
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ for (int i = 0; i < dbev->marks2dsrc->size (); i++)
+ {
+ table0->append (dbev->marks2dsrc->fetch (i).index1);
+ table1->append (dbev->marks2dsrc->fetch (i).index2);
+ }
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ for (int i = 0; i < dbev->marks2ddis->size (); i++)
+ {
+ table0->append (dbev->marks2ddis->fetch (i).index1);
+ table1->append (dbev->marks2ddis->fetch (i).index2);
+ }
+ break;
+ default:
+ break;
+ }
+ table->store (0, table0);
+ table->store (1, table1);
+ return table;
+}
+
+Vector<void*>*
+dbeGetHotMarksInc (int dbevindex, int type)
+{
+ Vector<void*>* table = new Vector<void*>(2);
+ Vector<int>* table0 = new Vector<int> ();
+ Vector<int>* table1 = new Vector<int> ();
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ return NULL;
+
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ for (int i = 0; i < dbev->marks2dsrc_inc->size (); i++)
+ {
+ table0->append (dbev->marks2dsrc_inc->fetch (i).index1);
+ table1->append (dbev->marks2dsrc_inc->fetch (i).index2);
+ }
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ for (int i = 0; i < dbev->marks2ddis_inc->size (); i++)
+ {
+ table0->append (dbev->marks2ddis_inc->fetch (i).index1);
+ table1->append (dbev->marks2ddis_inc->fetch (i).index2);
+ }
+ break;
+ default:
+ break;
+ }
+ table->store (0, table0);
+ table->store (1, table1);
+ return table;
+}
+
+Vector<void*>*
+dbeGetSummaryHotMarks (int dbevindex, Vector<Obj> *sel_objs, int type)
+{
+ Vector<void*>* table = new Vector<void*>(2);
+ Vector<int>* table0 = new Vector<int> ();
+ Vector<int>* table1 = new Vector<int> ();
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ return NULL;
+ if (sel_objs == NULL || sel_objs->size () == 0)
+ return NULL;
+
+ Hist_data *data;
+ Vector<int_pair_t> *marks2d;
+ Vector<int_pair_t>* marks2d_inc;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ marks2d = dbev->marks2dsrc;
+ marks2d_inc = dbev->marks2dsrc_inc;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ marks2d = dbev->marks2ddis;
+ marks2d_inc = dbev->marks2ddis_inc;
+ break;
+ default:
+ data = NULL;
+ marks2d = NULL;
+ marks2d_inc = NULL;
+ break;
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS
+ || marks2d_inc == NULL || marks2d == NULL)
+ return NULL;
+
+ MetricList *orig_mlist = data->get_metric_list ();
+ MetricList *prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL));
+ if (prop_mlist && dbev->comparingExperiments ())
+ prop_mlist = dbev->get_compare_mlist (prop_mlist, 0);
+ Metric *mitem;
+ int index, index2;
+ index2 = 0;
+ Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+ {
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+
+ for (int i = 0; i < marks2d_inc->size (); i++)
+ {
+ int found = 0;
+ for (int j = 0; j < sel_objs->size (); j++)
+ {
+ int sel_index = (int) sel_objs->fetch (j);
+ int marked_index = marks2d_inc->fetch (i).index1;
+ if (sel_index == marked_index)
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ int mindex = marks2d_inc->fetch (i).index2;
+ Metric *orig_metric = orig_mlist->get_items ()->fetch (mindex);
+ if (orig_metric->get_id () == mitem->get_id ()
+ && mitem->get_subtype () == Metric::INCLUSIVE)
+ {
+ table0->append (index2);
+ table1->append (1);
+ }
+ }
+
+ for (int i = 0; i < marks2d->size (); i++)
+ {
+ int found = 0;
+ for (int j = 0; j < sel_objs->size (); j++)
+ {
+ int sel_index = (int) sel_objs->fetch (j);
+ int marked_index = marks2d->fetch (i).index1;
+ if (sel_index == marked_index)
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ int mindex = marks2d->fetch (i).index2;
+ Metric *orig_metric = orig_mlist->get_items ()->fetch (mindex);
+ if (orig_metric->get_id () == mitem->get_id ()
+ && mitem->get_subtype () == Metric::EXCLUSIVE)
+ {
+ table0->append (index2);
+ table1->append (0);
+ }
+ }
+ if (!(mitem->get_subtype () == Metric::EXCLUSIVE
+ || mitem->get_subtype () == Metric::DATASPACE))
+ index2++;
+ }
+ table->store (0, table0);
+ table->store (1, table1);
+ return table;
+}
+
+// Get a vector of function ids of data(begin, begin + length - 1)
+// Currently only support source/disassembly view
+Vector<uint64_t>*
+dbeGetFuncId (int dbevindex, int type, int begin, int length)
+{
+ Vector<uint64_t>* table = new Vector<uint64_t > ();
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+
+ Hist_data *data;
+ Function* given_func = NULL;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ break;
+ default:
+ data = NULL;
+ abort ();
+ }
+
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+
+ if (begin < 0 || begin + length > data->size ())
+ return NULL;
+
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ {
+ for (int i = begin; i < begin + length; i++)
+ {
+ given_func = NULL;
+ Histable * sel_obj = data->fetch (i)->obj;
+ if (sel_obj != NULL)
+ given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev);
+ if (given_func == NULL)
+ table->append (0);
+ else
+ table->append (given_func->id);
+ }
+ }
+ break;
+ default:
+ abort ();
+ }
+ return table;
+}
+
+Vector<void*>*
+dbeGetFuncCallerInfo (int dbevindex, int type, Vector<int>* idxs, int groupId)
+{
+ Vector<void*>* data = new Vector<void*>();
+ if (type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+ {
+ Obj sel_func = dbeGetSelObj (dbevindex, DSP_FUNCTION, 0);
+ if (sel_func == 0)
+ return data;
+ Vector<Obj> * cmpObjs = dbeGetComparableObjsV2 (dbevindex, sel_func, type);
+ if (cmpObjs == NULL)
+ return data;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ int mtype = MET_COMMON | COMPARE_BIT | ((groupId + 1) << GROUP_ID_SHIFT);
+ MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK),
+ (mtype & COMPARE_BIT) != 0,
+ mtype >> GROUP_ID_SHIFT);
+ Histable *selObj = (Histable *) cmpObjs->fetch (groupId);
+ int subtype = 0;
+ Hist_data *hist_data = dbev->get_data (mlist, selObj, type, subtype);
+ if (hist_data == NULL)
+ return data;
+ }
+ for (int i = 0; i < idxs->size (); i++)
+ data->append (dbeGetFuncCallerInfoById (dbevindex, type, idxs->fetch (i)));
+ return data;
+}
+
+//
+// Get Table of Caller info:
+// param: idx -- selected AT_FUNC row
+// return: callsite_id, callsite_name (function: file: line)
+Vector<void*>*
+dbeGetFuncCallerInfoById (int dbevindex, int type, int idx)
+{
+ Vector<void*>* table = new Vector<void*>(3);
+ Vector<uint64_t>* table0 = new Vector<uint64_t> ();
+ Vector<int>* table1 = new Vector<int> ();
+ Vector<char*>* table2 = new Vector<char*>();
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Hist_data *data;
+ Function* given_func = NULL;
+ Vector<Histable*> *instr_info = NULL;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ break;
+ default:
+ data = NULL;
+ abort ();
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+
+ if (idx < 0 || idx >= data->size ())
+ return NULL;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ {
+ Histable * sel_obj = data->fetch (idx)->obj;
+ if (sel_obj == NULL)
+ return NULL;
+ given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev);
+ if (given_func == NULL)
+ return NULL;
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return NULL;
+ instr_info = ptree->get_clr_instr (given_func);
+ DefaultMap<uint64_t, int> * line_seen = new DefaultMap<uint64_t, int>();
+ for (int j = 0; j < ((Vector<Histable*>*)instr_info)->size (); j++)
+ {
+ Histable *instr = ((Vector<Histable*>*)instr_info)->fetch (j);
+ Function *cur_func = NULL;
+ if (instr->get_type () == Histable::INSTR)
+ cur_func = ((DbeInstr*) instr)->func;
+ else if (instr->get_type () == Histable::LINE)
+ cur_func = ((DbeLine*) instr)->func;
+ if (cur_func == NULL || (cur_func->flags & FUNC_FLAG_SIMULATED))
+ continue; // skip functions like <Total>
+ Histable* line;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ if (cur_func != NULL)
+ {
+ SourceFile *sourceFile = cur_func->getDefSrc ();
+ if (sourceFile == NULL ||
+ (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
+ continue; // skip functions like <Function: %s, instructions without line numbers>
+ }
+ line = instr->convertto (Histable::LINE, NULL);
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ line = instr->convertto (Histable::INSTR, NULL);
+ break;
+ default:
+ abort ();
+ }
+ uint64_t func_id = cur_func->id;
+ uint64_t line_id = instr->id;
+ int is_null = 0;
+ int line_no = -1;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ is_null = (((DbeLine*) line)->func == NULL) ? 1 : 0;
+ if (is_null)
+ ((DbeLine*) line)->func = cur_func;
+ line_no = ((DbeLine*) line)->lineno;
+ if (line_seen->get (line_id) == 0)
+ {
+ line_seen->put (line_id, 1);
+ table0->append (func_id);
+ table1->append (line_no);
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ table2->append (dbe_strdup (line->get_name (nfmt)));
+ }
+ if (is_null)
+ ((DbeLine*) line)->func = NULL;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ is_null = (((DbeInstr*) line)->func == NULL) ? 1 : 0;
+ if (is_null)
+ ((DbeInstr*) line)->func = cur_func;
+ line_no = ((DbeInstr*) line)->addr;
+ if (line_seen->get (line_id) == 0)
+ {
+ line_seen->put (line_id, 1);
+ table0->append (func_id);
+ table1->append (line_no);
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ table2->append (dbe_strdup (line->get_name (nfmt)));
+ }
+ if (is_null)
+ ((DbeInstr*) line)->func = NULL;
+ break;
+ default:
+ abort ();
+ }
+ }
+ delete line_seen;
+ delete instr_info;
+ }
+ break;
+ default:
+ abort ();
+ }
+ table->store (0, table0);
+ table->store (1, table1);
+ table->store (2, table2);
+ return table;
+}
+
+Vector<void*>*
+dbeGetFuncCalleeInfo (int dbevindex, int type, Vector<int>* idxs, int groupId)
+{
+ Vector<void*>* data = new Vector<void*>();
+ if (type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+ {
+ Obj sel_func = dbeGetSelObj (dbevindex, DSP_FUNCTION, 0);
+ if (sel_func == 0)
+ return data;
+ Vector<Obj> * cmpObjs = dbeGetComparableObjsV2 (dbevindex, sel_func, type);
+ if (cmpObjs == NULL)
+ return data;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ int mtype = MET_COMMON | COMPARE_BIT | ((groupId + 1) << GROUP_ID_SHIFT);
+ MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK),
+ (mtype & COMPARE_BIT) != 0,
+ mtype >> GROUP_ID_SHIFT);
+ Histable *selObj = (Histable *) cmpObjs->fetch (groupId);
+ int subtype = 0;
+ Hist_data *hist_data = dbev->get_data (mlist, selObj, type, subtype);
+ if (hist_data == NULL)
+ return data;
+ }
+
+ for (int i = 0; i < idxs->size (); i++)
+ data->append (dbeGetFuncCalleeInfoById (dbevindex, type, idxs->fetch (i)));
+ return data;
+}
+
+//
+// Get Table of Callee info:
+// param: idx -- selected AT_FUNC row
+// return: callsite_row, callee_id, callee_name
+//
+Vector<void*>*
+dbeGetFuncCalleeInfoById (int dbevindex, int type, int idx)
+{
+ Vector<void*>* table = new Vector<void*>(3);
+ Vector<int>* table0 = new Vector<int>();
+ Vector<uint64_t>* table1 = new Vector<uint64_t > ();
+ Vector<char*>* table2 = new Vector<char*>();
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Hist_data *data;
+ Function* given_func = NULL;
+ Vector<Histable*> *instr_info = NULL;
+ Vector<void*> *func_info = NULL;
+
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ break;
+ default:
+ data = NULL;
+ abort ();
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+ if (idx < 0 || idx >= data->size ())
+ return NULL;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ {
+ Histable * sel_obj = data->fetch (idx)->obj;
+ if (sel_obj == NULL)
+ return NULL;
+ given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev);
+ if (given_func == NULL)
+ return NULL;
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return NULL;
+ Vector<Histable*> *instrs = NULL;
+ Vector<void*> *callee_instrs = ptree->get_cle_instr (given_func, instrs);
+ func_info = new Vector<void*>();
+ instr_info = new Vector<Histable*>();
+ for (long a = 0, sz_a = callee_instrs ? callee_instrs->size () : 0; a < sz_a; a++)
+ {
+ Vector<Histable*> *temp = ((Vector<Vector<Histable*>*>*)callee_instrs)->get (a);
+ DefaultMap<Function*, int> * func_seen = new DefaultMap<Function*, int>();
+ Histable* instr0 = (Histable*) instrs->fetch (a);
+ for (long b = 0, sz_b = temp ? temp->size () : 0; b < sz_b; b++)
+ {
+ Histable *instr = temp->get (b);
+ if (instr->get_type () == Histable::INSTR)
+ {
+ Function* func1 = ((DbeInstr *) instr)->func;
+ func_seen->put (func1, 1);
+ }
+ else if (instr->get_type () == Histable::LINE)
+ {
+ Function* func1 = ((DbeLine *) instr)->func;
+ func_seen->put (func1, 1);
+ }
+ }
+ Vector<Function*> *funcs = func_seen->keySet ();
+ delete func_seen;
+ if (funcs->size () > 0)
+ {
+ instr_info->append (instr0);
+ func_info->append (funcs);
+ }
+ }
+ delete instrs;
+ destroy (callee_instrs);
+
+ DefaultMap<uint64_t, Vector<int>* > * instr_idxs = new DefaultMap<uint64_t, Vector<int>* >();
+ DefaultMap<uint64_t, int> * func_idxs = new DefaultMap<uint64_t, int>();
+ for (long j = 0, sz_j = instr_info ? instr_info->size () : 0; j < sz_j; j++)
+ {
+ Histable *instr = instr_info->get (j);
+ Function *cur_func = NULL;
+ if (instr->get_type () == Histable::INSTR)
+ cur_func = ((DbeInstr*) instr)->func;
+ else if (instr->get_type () == Histable::LINE)
+ cur_func = ((DbeLine*) instr)->func;
+ if (cur_func != NULL && (cur_func->flags & FUNC_FLAG_SIMULATED))
+ continue; // skip functions like <Total>
+ Histable* line;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ if (cur_func != NULL)
+ {
+ SourceFile *sourceFile = cur_func->getDefSrc ();
+ if (sourceFile == NULL ||
+ (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
+ // skip functions like <Function: %s, instructions without line numbers>
+ continue;
+ }
+ line = instr->convertto (Histable::LINE, NULL);
+ if (type == DSP_SOURCE_V2)
+ line = dbev->get_compare_obj (line);
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ line = instr;
+ if (type == DSP_DISASM_V2)
+ line = dbev->get_compare_obj (line);
+ break;
+ default:
+ abort ();
+ }
+ if (func_idxs->get (line->id) == 0)
+ {
+ func_idxs->put (line->id, 1);
+ Vector<int> *temp_idx = new Vector<int>();
+ temp_idx->append (j);
+ instr_idxs->put (line->id, temp_idx);
+ }
+ else
+ {
+ Vector<int> *temp_idx = instr_idxs->get (line->id);
+ temp_idx->append (j);
+ }
+ }
+ for (long i = 0; i < data->size (); i++)
+ {
+ Histable* line = data->fetch (i)->obj;
+ if (line == NULL)
+ continue;
+ Vector<int> * instr_idx = instr_idxs->get (line->id);
+ if (instr_idx == NULL)
+ continue;
+ for (long j = 0; j < instr_idx->size (); j++)
+ {
+ Vector<void*>* callee_funcs_vec = (Vector<void*>*)func_info;
+ if (callee_funcs_vec->size () == 0)
+ continue;
+ Vector<Function*>* callee_funcs_value = (Vector<Function*>*)callee_funcs_vec->fetch (instr_idx->fetch (j));
+ for (int k = 0; callee_funcs_value != NULL && k < callee_funcs_value->size (); k++)
+ {
+ uint64_t funcobj_id = ((Function*) callee_funcs_value->fetch (k))->id;
+ int old_size = table0->size ();
+ if (old_size > 0 && i == table0->fetch (old_size - 1)
+ && funcobj_id == table1->fetch (old_size - 1))
+ continue;
+ table0->append (i);
+ table1->append (funcobj_id);
+ table2->append (dbe_strdup (((Function*) callee_funcs_value->fetch (k))->get_name ()));
+ }
+ }
+ }
+ delete instr_idxs;
+ delete func_idxs;
+ destroy (func_info);
+ delete instr_info;
+ }
+ break;
+ default:
+ abort ();
+ }
+ table->store (0, table0);
+ table->store (1, table1);
+ table->store (2, table2);
+ return table;
+}
+
+//
+// Get Table of Function List data with only total values
+//
+Vector<void*> *
+dbeGetFuncListMini (int dbevindex, int type, int /*subtype*/)
+{
+ Hist_data *data;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = dbev->func_data;
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+
+ MetricList *mlist = data->get_metric_list ();
+
+ // Get table size: count visible metrics
+ int nvisible = 0;
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get (i);
+ if (m->is_visible () || m->is_tvisible () || m->is_pvisible ())
+ nvisible++;
+ }
+ Vector<void*> *table = new Vector<void*>(nvisible + 1);
+
+ // Fill function list elements
+ Hist_data::HistItem *totals = data->get_totals ();
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get (i);
+ if (!m->is_visible () && !m->is_tvisible () && !m->is_pvisible ())
+ continue;
+ TValue res;
+ TValue *v = data->get_value (&res, i, totals);
+ if ((m->get_visbits () & VAL_RATIO) != 0)
+ {
+ Vector<double> *col = new Vector<double>(1);
+ double d = (v->tag != VT_LABEL) ? v->to_double () : 100.; // NaN
+ col->append (d);
+ table->append (col);
+ continue;
+ }
+ switch (m->get_vtype ())
+ {
+ case VT_INT:
+ {
+ Vector<int> *col = new Vector<int>(1);
+ col->append (v->i);
+ table->append (col);
+ break;
+ }
+ case VT_ADDRESS:
+ case VT_ULLONG:
+ case VT_LLONG:
+ {
+ Vector<long long> *col = new Vector<long long>(1);
+ col->append (v->ll);
+ table->append (col);
+ break;
+ }
+ case VT_LABEL:
+ {
+ Vector<char *> *col = new Vector<char *>(1);
+ col->append (dbe_strdup (v->l));
+ table->append (col);
+ break;
+ }
+ case VT_DOUBLE:
+ default:
+ {
+ Vector<double> *col = new Vector<double>(1);
+ col->append (v->d);
+ table->append (col);
+ break;
+ }
+ }
+ }
+ table->append (NULL);
+ return table;
+}
+
+// Get Table of Function List data
+Vector<void*> *
+dbeGetFuncList (int dbevindex, int type, int subtype)
+{
+ MetricList *mlist;
+ Metric *mitem;
+ int nitems, nvisible;
+ int index, index2, nv;
+ char *cell;
+ Vector<int> *ji_list;
+ Hist_data *data;
+ Hist_data::HistItem *item;
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+
+ // fprintf(stderr, NTXT("XXX dbeGetFuncList, FuncListDisp_type = %d\n"), type);
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = dbev->func_data;
+ break;
+ case DSP_LINE:
+ data = dbev->line_data;
+ break;
+ case DSP_PC:
+ data = dbev->pc_data;
+ break;
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ break;
+ case DSP_SELF:
+ data = dbev->fitem_data;
+ break;
+ case DSP_CALLER:
+ data = dbev->callers;
+ break;
+ case DSP_CALLEE:
+ data = dbev->callees;
+ break;
+ case DSP_DLAYOUT:
+ data = dbev->dlay_data;
+ break;
+ case DSP_DATAOBJ:
+ data = dbev->dobj_data;
+ break;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+ mlist = data->get_metric_list ();
+
+ // Get table size: count visible metrics
+ nitems = data->size ();
+ nvisible = 0;
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
+ nvisible++;
+ }
+
+ // Initialize Java String array
+ Vector<void*> *table = new Vector<void*>(nvisible + 1);
+
+ // Mark Hi-value metric items for annotated src/dis/layout
+ if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_DLAYOUT
+ || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+ {
+ ji_list = new Vector<int>(nitems);
+
+ if (dbev->marks->size () > 0)
+ index = dbev->marks->fetch (0);
+ else
+ index = -1;
+ int mindex = 0;
+ for (index2 = 0; index2 < nitems; index2++)
+ {
+ item = data->fetch (index2);
+ if (index2 == index)
+ {
+ ji_list->store (index2, -item->type);
+ if (++mindex < dbev->marks->size ())
+ index = dbev->marks->fetch (mindex);
+ else
+ index = -1;
+ }
+ else
+ ji_list->store (index2, item->type);
+ }
+ table->store (nvisible, ji_list);
+ }
+ else
+ table->store (nvisible, NULL);
+
+ // Fill function list elements
+ nv = 0;
+
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ if (!mitem->is_visible () && !mitem->is_tvisible () &&
+ !mitem->is_pvisible ())
+ continue;
+
+ // Fill values
+ switch (mitem->get_vtype ())
+ {
+ case VT_LABEL:
+ {
+ Vector<char*> *jobjects = new Vector<char*>(nitems);
+ char *buf = NULL;
+ size_t bufsz = 0;
+ int lspace = 0;
+ if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+ || type == DSP_DISASM_V2)
+ {
+ // if this is source or disassembly, where we'll insert
+ // a preface into the output line, figure out how wide
+ // it needs to be
+ // first, scan all the lines, to get the maximum line number
+ bufsz = 1024;
+ buf = (char *) malloc (bufsz);
+ int max_lineno = 0;
+ int hidx;
+ Hist_data::HistItem *hitem;
+ Vec_loop (Hist_data::HistItem*, data, hidx, hitem)
+ {
+ if (!hitem->obj)
+ continue;
+ if (hitem->obj->get_type () == Histable::LINE &&
+ ((DbeLine*) hitem->obj)->lineno > max_lineno)
+ max_lineno = ((DbeLine*) hitem->obj)->lineno;
+ else if (hitem->obj->get_type () == Histable::INSTR
+ && ((DbeInstr*) hitem->obj)->lineno > max_lineno)
+ max_lineno = ((DbeInstr*) hitem->obj)->lineno;
+ }
+
+ // we have the maximum integer over all linenumbers in the file
+ // figure out how many digits are needed
+ lspace = snprintf (buf, bufsz, NTXT ("%d"), max_lineno);
+ }
+ for (index2 = 0; index2 < nitems; index2++)
+ {
+ item = data->fetch (index2);
+ if (type == DSP_DLAYOUT)
+ cell = dbe_strdup (((DataObject*) (item->obj))->get_offset_name ());
+ else if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+ {
+ // This code is duplicated in output.cc, yet it's
+ // intended for presentation purpose and thus is
+ // potentially different for er_print and analyzer.
+ switch (item->type)
+ {
+ case Module::AT_SRC_ONLY:
+ case Module::AT_SRC:
+ if (item->obj == NULL)
+ snprintf (buf, bufsz, NTXT (" %*c. "), lspace, ' ');
+ else
+ snprintf (buf, bufsz, NTXT (" %*d. "), lspace, ((DbeLine*) item->obj)->lineno);
+ break;
+ case Module::AT_FUNC:
+ case Module::AT_QUOTE:
+ snprintf (buf, bufsz, NTXT ("%*c"), lspace + 3, ' ');
+ break;
+ case Module::AT_DIS:
+ case Module::AT_DIS_ONLY:
+ if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
+ snprintf (buf, bufsz, NTXT ("%*c[%*s] "), lspace + 3, ' ', lspace, NTXT ("?"));
+ else
+ snprintf (buf, bufsz, NTXT ("%*c[%*d] "), lspace + 3, ' ', lspace,
+ ((DbeInstr*) item->obj)->lineno);
+ break;
+ case Module::AT_COM:
+ case Module::AT_EMPTY:
+ *buf = (char) 0;
+ break;
+ }
+ // get the line's text
+ char *s = item->value[index].l;
+ if (s != NULL)
+ {
+ // copy the string expanding all tabulations
+ // (JTable doesn't render them)
+ char *d = buf + strlen (buf);
+ char c;
+ size_t column = 0;
+ do
+ {
+ c = *s++;
+ if (c == '\t')
+ {
+ do
+ {
+ *d++ = ' ';
+ column++;
+ }
+ while (column & 07);
+ }
+ else
+ {
+ *d++ = c;
+ column++;
+ }
+ if (column + 32 > bufsz)
+ {
+ // Reallocate the buffer
+ size_t curlen = d - buf;
+ bufsz += 1024;
+ char *buf_new = (char *) malloc (bufsz);
+ strncpy (buf_new, buf, curlen);
+ buf_new[curlen] = '\0';
+ free (buf);
+ buf = buf_new;
+ d = buf + curlen;
+ }
+ }
+ while (c != (char) 0);
+ }
+ cell = dbe_strdup (buf);
+ free (item->value[index].l);
+ item->value[index].l = NULL; //YXXX missing from dbeGetFuncListV2
+ }
+ else
+ {
+ // omazur: why don't we have it as metric value
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ cell = dbe_strdup (item->obj->get_name (nfmt));
+ }
+ jobjects->store (index2, cell);
+ }
+ if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+ || type == DSP_DISASM_V2)
+ free (buf);
+ table->store (nv++, jobjects);
+ break;
+ }
+ default:
+ table->store (nv++, dbeGetTableDataOneColumn (data, index));
+ break;
+ }
+ }
+ return table;
+}
+
+Vector<Obj> *
+dbeGetComparableObjsV2 (int /* dbevindex */, Obj sel_obj, int type)
+{
+ long grsize = dbeSession->expGroups->size ();
+ Vector<Obj> *res = new Vector<Obj> (grsize + 1);
+ for (long j = 0; j < grsize; j++)
+ res->append ((Obj) NULL);
+ res->append (sel_obj);
+ Histable *obj = (Histable *) sel_obj;
+ if (obj == NULL)
+ return res;
+ Function *func = (Function *) obj->convertto (Histable::FUNCTION);
+ if (func == NULL)
+ return res;
+ Vector<Histable *> *cmpObjs = func->get_comparable_objs ();
+ if (cmpObjs == NULL || cmpObjs->size () != grsize)
+ return res;
+
+ Histable::Type conv_type = (type == DSP_SOURCE || type == DSP_SOURCE_V2) ?
+ Histable::LINE : Histable::INSTR;
+ switch (obj->get_type ())
+ {
+ case Histable::FUNCTION:
+ for (long j = 0; j < grsize; j++)
+ res->store (j, (Obj) cmpObjs->get (j));
+ return res;
+ case Histable::INSTR:
+ case Histable::LINE:
+ {
+ SourceFile *srcContext = (SourceFile *) obj->convertto (Histable::SOURCEFILE);
+ char *bname = get_basename (srcContext->get_name ());
+ for (long j = 0; j < grsize; j++)
+ {
+ Function *func1 = (Function *) cmpObjs->get (j);
+ if (func == func1)
+ {
+ if (conv_type == Histable::LINE)
+ res->store (j, (Obj) obj);
+ else
+ res->store (j, (Obj) obj->convertto (conv_type, srcContext));
+ continue;
+ }
+ if (func1 == NULL)
+ continue;
+ Vector<SourceFile*> *sources = func1->get_sources ();
+ SourceFile *sf = NULL;
+ for (long j1 = 0, sz1 = sources ? sources->size () : 0; j1 < sz1; j1++)
+ {
+ SourceFile *sf1 = sources->get (j1);
+ if (sf1 == srcContext)
+ { // the same file
+ sf = srcContext;
+ break;
+ }
+ else if (sf == NULL)
+ {
+ char *bname1 = get_basename (sf1->get_name ());
+ if (dbe_strcmp (bname, bname1) == 0)
+ sf = sf1;
+ }
+ }
+ res->store (j, (Obj) func1->convertto (conv_type, srcContext));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return res;
+}
+
+// Get Table of Function List data
+Vector<void *> *
+dbeGetFuncListV2 (int dbevindex, int mtype, Obj sel_obj, int type, int subtype)
+{
+ Metric *mitem;
+ int nitems, nvisible;
+ int index, index2, nv;
+ char *cell;
+ Hist_data::HistItem *item;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ dbev->error_msg = dbev->warning_msg = NULL;
+ MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK),
+ (mtype & COMPARE_BIT) != 0,
+ mtype >> GROUP_ID_SHIFT);
+ Histable *selObj = (Histable *) sel_obj;
+ int old_compare_mode = dbev->get_compare_mode ();
+ if ((mtype & COMPARE_BIT) != 0)
+ dbev->reset_compare_mode (CMP_DISABLE);
+ Hist_data *data = dbev->get_data (mlist, selObj, type, subtype);
+ dbev->reset_compare_mode (old_compare_mode);
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+ nitems = data->size ();
+ nvisible = mlist->get_items ()->size ();
+
+ // Initialize Java String array
+ Vector<void*> *table = new Vector<void*>(nvisible + 3);
+ // Mark Hi-value metric items for annotated src/dis/layout
+ if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_DLAYOUT
+ || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+ {
+ Vector<int> *types = new Vector<int>(nitems);
+ Vector<Obj> *ids = new Vector<Obj > (nitems);
+ if (dbev->marks->size () > 0)
+ index = dbev->marks->fetch (0);
+ else
+ index = -1;
+ int mindex = 0;
+ for (int i = 0; i < nitems; i++)
+ {
+ item = data->fetch (i);
+ ids->store (i, (Obj) item->obj);
+ if (i == index)
+ {
+ types->store (i, -item->type);
+ if (++mindex < dbev->marks->size ())
+ index = dbev->marks->fetch (mindex);
+ else
+ index = -1;
+ }
+ else
+ types->store (i, item->type);
+ }
+ table->store (nvisible, types);
+ table->store (nvisible + 1, ids);
+ }
+ else
+ {
+ table->store (nvisible, NULL);
+ table->store (nvisible + 1, NULL);
+ }
+
+ // Fill function list elements
+ nv = 0;
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ if (!mitem->is_visible () && !mitem->is_tvisible () &&
+ !mitem->is_pvisible ())
+ continue;
+
+ // Fill values
+ switch (mitem->get_vtype ())
+ {
+ default:
+ table->store (nv++, dbeGetTableDataOneColumn (data, index));
+ break;
+ case VT_LABEL:
+ Vector<char*> *jobjects = new Vector<char*>(nitems);
+ char *buf = NULL;
+ size_t bufsz = 0;
+ int lspace = 0;
+ if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+ || type == DSP_DISASM_V2)
+ {
+ // if this is source or disassembly, where we'll insert
+ // a preface into the output line, figure out how wide
+ // it needs to be
+ // first, scan all the lines, to get the maximum line number
+ bufsz = 1024;
+ buf = (char *) malloc (bufsz);
+ int max_lineno = 0;
+ int hidx;
+ Hist_data::HistItem *hitem;
+ Vec_loop (Hist_data::HistItem*, data, hidx, hitem)
+ {
+ if (!hitem->obj)
+ continue;
+ if (hitem->obj->get_type () == Histable::LINE &&
+ ((DbeLine*) hitem->obj)->lineno > max_lineno)
+ max_lineno = ((DbeLine*) hitem->obj)->lineno;
+ else if (hitem->obj->get_type () == Histable::INSTR
+ && ((DbeInstr*) hitem->obj)->lineno > max_lineno)
+ max_lineno = ((DbeInstr*) hitem->obj)->lineno;
+ }
+
+ // we have the maximum integer over all linenumbers in the file
+ // figure out how many digits are needed
+ lspace = snprintf (buf, bufsz, NTXT ("%d"), max_lineno);
+ }
+
+ for (index2 = 0; index2 < nitems; index2++)
+ {
+ item = data->fetch (index2);
+ if (type == DSP_DLAYOUT)
+ cell = dbe_strdup (((DataObject*) (item->obj))->get_offset_name ());
+ else if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+ {
+ // This code is duplicated in output.cc, yet it's
+ // intended for presentation purpose and thus is
+ // potentially different for er_print and analyzer.
+ switch (item->type)
+ {
+ case Module::AT_SRC_ONLY:
+ case Module::AT_SRC:
+ if (item->obj == NULL)
+ snprintf (buf, bufsz, NTXT (" %*c. "), lspace, ' ');
+ else
+ snprintf (buf, bufsz, NTXT (" %*d. "), lspace,
+ ((DbeLine*) item->obj)->lineno);
+ break;
+ case Module::AT_FUNC:
+ case Module::AT_QUOTE:
+ snprintf (buf, bufsz, NTXT ("%*c"), lspace + 3, ' ');
+ break;
+ case Module::AT_DIS:
+ case Module::AT_DIS_ONLY:
+ if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
+ snprintf (buf, bufsz, NTXT ("%*c[%*s] "), lspace + 3, ' ',
+ lspace, NTXT ("?"));
+ else
+ snprintf (buf, bufsz, NTXT ("%*c[%*d] "), lspace + 3, ' ',
+ lspace,
+ ((DbeInstr*) item->obj)->lineno);
+ break;
+ case Module::AT_COM:
+ case Module::AT_EMPTY:
+ *buf = (char) 0;
+ break;
+ }
+ // get the line's text
+ char *s = item->value[index].l;
+ if (s != NULL)
+ {
+ // copy the string expanding all tabulations
+ // (JTable doesn't render them)
+ char *d = buf + strlen (buf);
+ char c;
+ size_t column = 0;
+ do
+ {
+ c = *s++;
+ if (c == '\t')
+ {
+ do
+ {
+ *d++ = ' ';
+ column++;
+ }
+ while (column & 07);
+ }
+ else
+ {
+ *d++ = c;
+ column++;
+ }
+ if (column + 32 > bufsz)
+ {
+ // Reallocate the buffer
+ size_t curlen = d - buf;
+ bufsz += 1024;
+ char *buf_new = (char *) malloc (bufsz);
+ strncpy (buf_new, buf, curlen);
+ buf_new[curlen] = '\0';
+ free (buf);
+ buf = buf_new;
+ d = buf + curlen;
+ }
+ }
+ while (c != (char) 0);
+ }
+ cell = dbe_strdup (buf);
+ }
+ else
+ {
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ cell = dbe_strdup (item->obj->get_name (nfmt));
+ }
+ jobjects->store (index2, cell);
+ }
+
+ if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+ || type == DSP_DISASM_V2)
+ free (buf);
+ table->store (nv++, jobjects);
+ break;
+ }
+ }
+ table->append (dbeGetMetricList (mlist));
+ return table;
+} // dbeGetFuncListV2
+
+//
+// Get Table DataV2
+//
+Vector<void*> *
+dbeGetTableDataV2 (int dbevindex, char *mlistStr, char *modeStr, char *typeStr,
+ char *subtypeStr, Vector<uint64_t> *ids)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+
+ // Process metric list specification
+ if (mlistStr == NULL)
+ return NULL;
+ bool met_call = false;
+ MetricList *mlist = NULL;
+ if (streq (mlistStr, NTXT ("MET_NORMAL")))
+ mlist = dbev->get_metric_list (MET_NORMAL);
+ else if (streq (mlistStr, NTXT ("MET_CALL")))
+ {
+ met_call = true;
+ mlist = dbev->get_metric_list (MET_CALL);
+ }
+ else if (streq (mlistStr, NTXT ("MET_CALL_AGR")))
+ mlist = dbev->get_metric_list (MET_CALL_AGR);
+ else if (streq (mlistStr, NTXT ("MET_DATA")))
+ mlist = dbev->get_metric_list (MET_DATA);
+ else if (streq (mlistStr, NTXT ("MET_INDX")))
+ mlist = dbev->get_metric_list (MET_INDX);
+ else if (streq (mlistStr, NTXT ("MET_IO")))
+ mlist = dbev->get_metric_list (MET_IO);
+ else if (streq (mlistStr, NTXT ("MET_HEAP")))
+ mlist = dbev->get_metric_list (MET_HEAP);
+ else
+ return NULL;
+
+ // Process mode specification
+ if (modeStr == NULL)
+ return NULL;
+ Hist_data::Mode mode = (Hist_data::Mode)0;
+ if (streq (modeStr, NTXT ("CALLERS")))
+ mode = Hist_data::CALLERS;
+ else if (streq (modeStr, NTXT ("CALLEES")))
+ mode = Hist_data::CALLEES;
+ else if (streq (modeStr, NTXT ("SELF")))
+ mode = Hist_data::SELF;
+ else if (streq (modeStr, NTXT ("ALL")))
+ mode = Hist_data::ALL;
+ else
+ return NULL;
+
+ // Process type specification
+ if (typeStr == NULL)
+ return NULL;
+ Histable::Type type = Histable::OTHER;
+ if (streq (typeStr, NTXT ("FUNCTION")))
+ type = Histable::FUNCTION;
+ else if (streq (typeStr, NTXT ("INDEXOBJ")))
+ type = Histable::INDEXOBJ;
+ else if (streq (typeStr, NTXT ("IOACTFILE")))
+ type = Histable::IOACTFILE;
+ else if (streq (typeStr, NTXT ("IOACTVFD")))
+ type = Histable::IOACTVFD;
+ else if (streq (typeStr, NTXT ("IOCALLSTACK")))
+ type = Histable::IOCALLSTACK;
+ else if (streq (typeStr, NTXT ("HEAPCALLSTACK")))
+ type = Histable::HEAPCALLSTACK;
+ else if (streq (typeStr, NTXT ("LINE")))
+ type = Histable::LINE;
+ else if (streq (typeStr, NTXT ("INSTR")))
+ type = Histable::INSTR;
+ else
+ // XXX Accepting objects other than above may require a different
+ // implementation of the id -> Histable mapping below
+ return NULL;
+
+ // Process subtype specification
+ int subtype = 0;
+ if (subtypeStr != NULL)
+ subtype = atoi (subtypeStr);
+ Vector<Histable*> *hobjs = NULL;
+ if (ids != NULL)
+ {
+ hobjs = new Vector<Histable*>();
+ for (int i = 0; i < ids->size (); ++i)
+ {
+ Histable::Type obj_type = type;
+ if ((obj_type == Histable::LINE || obj_type == Histable::INSTR)
+ && subtype == 0)
+ obj_type = Histable::FUNCTION;
+ Histable *hobj = dbeSession->findObjectById (obj_type, subtype, ids->fetch (i));
+ if ((obj_type == Histable::LINE || obj_type == Histable::INSTR)
+ && subtype == 0 && hobj == NULL)
+ return NULL;
+ hobjs->append (hobj);
+ }
+ }
+
+ PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE;
+ if (dbev->isOmpDisMode () && type == Histable::FUNCTION
+ && mode == Hist_data::CALLEES && met_call)
+ flag = PathTree::COMPUTEOPT_OMP_CALLEE;
+
+ Hist_data *data = dbev->get_hist_data (mlist, type, subtype, mode, hobjs, NULL, NULL, flag);
+ return dbeGetTableDataV2Data (dbev, data);
+}
+
+static Vector<void*> *
+dbeGetTableDataV2Data (DbeView * /*dbev*/, Hist_data *data)
+{
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+ MetricList *mlist;
+ mlist = data->get_metric_list ();
+ int nitems = data->size ();
+
+ // Initialize Java String array
+ Vector<void*> *table = new Vector<void*>(mlist->size () + 1);
+
+ // Fill function list elements
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ Metric *mitem = mlist->get (i);
+ if (!mitem->is_visible () && !mitem->is_tvisible () &&
+ !mitem->is_pvisible ())
+ continue;
+ table->append (dbeGetTableDataOneColumn (data, i));
+ }
+
+ // Add an array of Histable IDs
+ Vector<uint64_t> *idList = new Vector<uint64_t>(nitems);
+ for (int i = 0; i < nitems; ++i)
+ {
+ Hist_data::HistItem *item = data->fetch (i);
+ if (item->obj->get_type () == Histable::LINE
+ || item->obj->get_type () == Histable::INSTR)
+ idList->store (i, (uint64_t) (item->obj));
+ else
+ idList->store (i, item->obj->id);
+ }
+ table->append (idList);
+ return table;
+} // dbeGetTableData
+
+//YXXX try to use the following to consolidate similar cut/paste code
+
+static Vector<void*> *
+dbeGetTableDataOneColumn (Hist_data *data, int met_ind)
+{
+ // Allocates a vector and fills it with metric values for one column
+ TValue res;
+ Metric *m = data->get_metric_list ()->get (met_ind);
+ if ((m->get_visbits () & VAL_RATIO) != 0)
+ {
+ Vector<double> *col = new Vector<double>(data->size ());
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ TValue *v = data->get_value (&res, met_ind, row);
+ double d = (v->tag != VT_LABEL) ? v->to_double () : 100.; // NaN
+ col->append (d);
+ }
+ return (Vector<void*> *) col;
+ }
+
+ switch (m->get_vtype ())
+ {
+ case VT_DOUBLE:
+ {
+ Vector<double> *col = new Vector<double>(data->size ());
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ TValue *v = data->get_value (&res, met_ind, row);
+ col->append (v->d);
+ }
+ return (Vector<void*> *) col;
+ }
+ case VT_INT:
+ {
+ Vector<int> *col = new Vector<int>(data->size ());
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ TValue *v = data->get_value (&res, met_ind, row);
+ col->append (v->i);
+ }
+ return (Vector<void*> *) col;
+ }
+ case VT_ULLONG:
+ case VT_LLONG:
+ {
+ Vector<long long> *col = new Vector<long long>(data->size ());
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ TValue *v = data->get_value (&res, met_ind, row);
+ col->append (v->ll);
+ }
+ return (Vector<void*> *) col;
+ }
+ case VT_ADDRESS:
+ {
+ Vector<long long> *col = new Vector<long long>(data->size ());
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ TValue *v = data->get_value (&res, met_ind, row);
+ // set the highest bit to mark this jlong as
+ // a VT_ADDRESS (rather than a regular VT_LLONG)
+ col->append (v->ll | 0x8000000000000000ULL);
+ }
+ return (Vector<void*> *) col;
+ }
+ case VT_LABEL:
+ {
+ Vector<char *> *col = new Vector<char *>(data->size ());
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ TValue *v = data->get_value (&res, met_ind, row);
+ col->append (dbe_strdup (v->l));
+ }
+ return (Vector<void*> *) col;
+ }
+ default:
+ return NULL;
+ }
+}
+
+static Vector<void*> *
+dbeGetTableDataOneColumn (DbeView *dbev, Vector<Hist_data::HistItem*> *data,
+ ValueTag vtype, int metricColumnNumber)
+// Allocates a vector and fills it with metric values for one column
+{
+ Vector<void*> *column_data = NULL;
+ int nitems = data->size (); // number of rows
+ int index = metricColumnNumber;
+ switch (vtype)
+ {
+ case VT_DOUBLE:
+ {
+ Vector<double> *jd_list = new Vector<double>(nitems);
+ for (int index2 = 0; index2 < nitems; index2++)
+ {
+ Hist_data::HistItem *item = data->fetch (index2);
+ jd_list->store (index2, item->value[index].d);
+ }
+ column_data = (Vector<void*> *)jd_list;
+ break;
+ }
+ case VT_INT:
+ {
+ Vector<int> *ji_list = new Vector<int>(nitems);
+ for (int index2 = 0; index2 < nitems; index2++)
+ {
+ Hist_data::HistItem *item = data->fetch (index2);
+ ji_list->store (index2, item->value[index].i);
+ }
+ column_data = (Vector<void*> *)ji_list;
+ break;
+ }
+ case VT_ULLONG:
+ case VT_LLONG:
+ {
+ Vector<long long> *jl_list = new Vector<long long>(nitems);
+ for (int index2 = 0; index2 < nitems; index2++)
+ {
+ Hist_data::HistItem *item = data->fetch (index2);
+ jl_list->store (index2, item->value[index].ll);
+ }
+ column_data = (Vector<void*> *)jl_list;
+ break;
+ }
+ case VT_ADDRESS:
+ {
+ Vector<long long> *jl_list = new Vector<long long>(nitems);
+ for (int index2 = 0; index2 < nitems; index2++)
+ {
+ Hist_data::HistItem *item = data->fetch (index2);
+
+ // set the highest bit to mark this jlong as
+ // a VT_ADDRESS (rather than a regular VT_LLONG)
+ uint64_t addr = item->value[index].ll;
+ addr |= 0x8000000000000000ULL;
+ jl_list->store (index2, addr);
+ }
+ column_data = (Vector<void*> *)jl_list;
+ break;
+ }
+ case VT_LABEL:
+ {
+ Vector<char*> *jobjects = new Vector<char*>(nitems);
+ for (int index2 = 0; index2 < nitems; index2++)
+ {
+ Hist_data::HistItem *item = data->fetch (index2);
+
+ // omazur: why don't we have it as metric value
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ char *str = dbe_strdup (item->obj->get_name (nfmt));
+ jobjects->store (index2, str);
+ }
+ column_data = (Vector<void*> *)jobjects;
+ break;
+ }
+ default:
+ abort ();
+ }
+ return column_data;
+}
+
+int
+dbeGetCallTreeNumLevels (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return 0;
+ return ptree->get_ftree_depth ();
+}
+
+Vector<void*>*
+dbeGetCallTreeLevel (int dbevindex, char *mcmd, int level)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return NULL;
+ if (mcmd == NULL)
+ return NULL;
+ BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd);
+ if (bm == NULL)
+ return NULL;
+ return ptree->get_ftree_level (bm, level);
+}
+
+Vector<void*>*
+dbeGetCallTreeLevels (int dbevindex, char *mcmd)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return NULL;
+ if (mcmd == NULL)
+ return NULL;
+ BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd);
+ if (bm == NULL)
+ return NULL;
+
+ int depth = ptree->get_ftree_depth ();
+ Vector<void*> *results = new Vector<void*>(depth);
+ for (int ii = 0; ii < depth; ii++)
+ results->append (ptree->get_ftree_level (bm, ii));
+ return results;
+}
+
+Vector<void*>*
+dbeGetCallTreeLevelFuncs (int dbevindex, int start_level, int end_level)
+{ // (0,-1) -> all levels
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return NULL;
+
+ int depth = ptree->get_ftree_depth ();
+ if (start_level < 0)
+ start_level = 0;
+ if (end_level < 0 || end_level >= depth)
+ end_level = depth - 1;
+
+ Histable::NameFormat nfmt = dbev->get_name_format (); //YXXX or fixed format?
+ Vector<char*> *funcNames = new Vector<char*>();
+ Vector<long long> *funcIds = new Vector<long long>();
+ Vector<Obj> *funcObjs = new Vector<Obj>();
+
+ if (start_level == 0 && end_level == depth - 1)
+ return dbeGetCallTreeFuncs (dbevindex);
+ else
+ {
+ for (int ii = start_level; ii <= end_level; ii++)
+ {
+ Vector<void*> *info = ptree->get_ftree_level (NULL, ii); /*no metric*/
+ if (!info)
+ continue;
+ Vector<long long> *fids = (Vector<long long> *)info->get (2);
+ if (!fids)
+ continue;
+ int index;
+ long long fid;
+ Vec_loop (long long, fids, index, fid)
+ {
+ funcIds->append (fid);
+ Histable *obj = dbeSession->findObjectById (fid);
+ char * fname = obj ? dbe_strdup (obj->get_name (nfmt)) : NULL;
+ funcNames->append (fname);
+ funcObjs->append ((unsigned long) obj); // avoiding sign extension
+ }
+ destroy (info);
+ }
+ }
+ Vector<void*> *results = new Vector<void*>(3);
+ results->append (funcIds);
+ results->append (funcNames);
+ results->append (funcObjs);
+ return results;
+}
+
+Vector<void*> *
+dbeGetCallTreeFuncs (int dbevindex)
+{ // does not require ptree->get_ftree_level() to be computed
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return 0;
+ Vector<Function*>* funcs = ptree->get_funcs (); // Unique functions in tree
+ if (funcs == NULL)
+ return NULL;
+
+ long sz = funcs->size ();
+ Vector<void*> *results = new Vector<void*>(3);
+ Vector<long long> *funcIds = new Vector<long long>(sz);
+ Vector<char*> *funcNames = new Vector<char*>(sz);
+ Vector<Obj> *funcObjs = new Vector<Obj>(sz);
+
+ int index;
+ Function * func;
+ Histable::NameFormat nfmt = dbev->get_name_format (); //YXXX or fixed format?
+ Vec_loop (Function *, funcs, index, func)
+ {
+ funcIds->append (func->id); // do we need IDs?
+ char *fname = dbe_strdup (func->get_name (nfmt));
+ funcNames->append (fname);
+ funcObjs->append ((unsigned long) func); // avoiding sign extension
+ }
+ results->put (0, funcIds);
+ results->put (1, funcNames);
+ results->put (2, funcObjs);
+ destroy (funcs);
+ return results;
+}
+
+Vector<void*>*
+dbeGetCallTreeChildren (int dbevindex, char *mcmd, Vector<int /*NodeIdx*/>*node_idxs)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (node_idxs == NULL || node_idxs->size () == 0)
+ return NULL;
+ long sz = node_idxs->size ();
+ PathTree * ptree = dbev->get_path_tree ();
+ if (ptree == NULL)
+ return NULL;
+ if (mcmd == NULL)
+ return NULL;
+ BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd);
+ if (bm == NULL)
+ return NULL;
+
+ Vector<void*> *results = new Vector<void*>(sz);
+ for (long ii = 0; ii < sz; ii++)
+ {
+ PathTree::NodeIdx nodeIdx = node_idxs->get (ii); // upcasted from int
+ results->append (ptree->get_ftree_node_children (bm, nodeIdx));
+ }
+ return results;
+}
+
+Vector<int> *
+dbeGetGroupIds (int /*dbevindex*/)
+{
+ Vector<ExpGroup*> *groups = dbeSession->expGroups;
+ int sz = groups->size ();
+ Vector<int> *grIds = new Vector<int>(sz);
+ for (int i = 0; i < sz; i++)
+ grIds->store (i, groups->fetch (i)->groupId);
+ return grIds;
+}
+
+//
+// Get label for name column
+//
+Vector<char*> *
+dbeGetNames (int dbevindex, int type, Obj sel_obj)
+{
+ char *s0, *s1, *s2;
+ bool need_strdup = true;
+ switch (type)
+ {
+ case DSP_SOURCE_V2:
+ case DSP_DISASM_V2:
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ {
+ if (sel_obj)
+ {
+ Histable *selObj = (Histable*) sel_obj;
+ Function *func = (Function *) selObj->convertto (Histable::FUNCTION);
+ if (func)
+ {
+ char *names[3] = {NULL, NULL, NULL};
+ set_file_names (func, names);
+ s0 = names[0];
+ s1 = names[1];
+ s2 = names[2];
+ need_strdup = false;
+ break;
+ }
+ }
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ char **names = type == DSP_SOURCE || type == DSP_SOURCE_V2 ? dbev->names_src : dbev->names_dis;
+ s0 = names[0];
+ s1 = names[1];
+ s2 = names[2];
+ break;
+ }
+ case DSP_LINE:
+ s0 = GTXT ("Lines");
+ s1 = GTXT ("Function, line # in \"sourcefile\"");
+ s2 = NTXT ("");
+ break;
+ case DSP_PC:
+ s0 = GTXT ("PCs");
+ s1 = GTXT ("Function + offset");
+ s2 = NTXT ("");
+ break;
+ case DSP_DLAYOUT:
+ s0 = GTXT ("Name");
+ s1 = GTXT ("* +offset .element");
+ s2 = NTXT ("");
+ break;
+ default:
+ s0 = GTXT ("Name");
+ s1 = s2 = NTXT ("");
+ break;
+ }
+ if (need_strdup)
+ {
+ s0 = dbe_strdup (s0);
+ s1 = dbe_strdup (s1);
+ s2 = dbe_strdup (s2);
+ }
+ Vector<char*> *table = new Vector<char*>(3);
+ table->store (0, s0);
+ table->store (1, s1);
+ table->store (2, s2);
+ return table;
+}
+
+//
+// Get Total/Maximum element of Function List
+//
+Vector<void*> *
+dbeGetTotalMax (int dbevindex, int type, int subtype)
+{
+ Hist_data *data;
+ int index;
+ Hist_data::HistItem *total_item, *maximum_item;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+
+ switch (type)
+ {
+ case DSP_LINE:
+ data = dbev->line_data;
+ break;
+ case DSP_PC:
+ data = dbev->pc_data;
+ break;
+ case DSP_CALLER:
+ data = dbev->callers;
+ break;
+ case DSP_SELF:
+ case DSP_CALLEE:
+ data = dbev->callees;
+ break;
+ case DSP_DLAYOUT:
+ data = dbev->dlay_data;
+ break;
+ case DSP_DATAOBJ:
+ data = dbev->dobj_data;
+ break;
+ case DSP_MEMOBJ:
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ case DSP_INDXOBJ:
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ case DSP_FUNCTION: // annotated src/dis use func total/max
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ case DSP_SOURCE_V2:
+ case DSP_DISASM_V2:
+ data = dbev->func_data;
+ break;
+ default:
+ abort ();
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+
+ // Get list size
+ // XXX -- the original list has all items, visible or not;
+ // XXX -- the one from Hist_data has only visible items,
+ // XXX -- and should be the only ones computed
+ // XXX -- Analyzer got confused (yesterday), when we used the shorter list
+ // XXX -- Why can we fetch total/max for metrics never
+ // XXX -- computed without core dumping?
+ MetricList *mlist2 = data->get_metric_list ();
+ int size = mlist2->get_items ()->size ();
+
+ // Initialize Java array
+ Vector<void*> *total_max = new Vector<void*>(2);
+ Vector<double> *total = new Vector<double>(size);
+ Vector<double> *maximum = new Vector<double>(size);
+
+ // Fill total/maximum element
+ total_item = data->get_totals ();
+ maximum_item = data->get_maximums ();
+
+ for (index = 0; index < size; index++)
+ {
+ total->store (index, total_item->value[index].to_double ());
+ maximum->store (index, maximum_item->value[index].to_double ());
+ }
+ total_max->store (0, total);
+ total_max->store (1, maximum);
+ return total_max;
+}
+
+//
+// Get Table of Overview List
+Vector<void*> *
+dbeGetStatisOverviewList (int dbevindex)
+{
+ int size;
+ Ovw_data **data;
+ Ovw_data::Ovw_item labels, *totals;
+ int nitems;
+ int index, index2;
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->error_msg = dbev->warning_msg = NULL;
+
+ size = dbeSession->nexps ();
+ totals = new Ovw_data::Ovw_item[size + 1];
+ data = new Ovw_data*[size + 1];
+ data[0] = new Ovw_data ();
+
+ for (index = 1; index <= size; index++)
+ {
+ data[index] = dbev->get_ovw_data (index - 1);
+ if (data[index] == NULL)
+ {
+ Ovw_data::reset_item (&totals[index]); // set contents to zeros
+ continue;
+ }
+ data[0]->sum (data[index]);
+ totals[index] = data[index]->get_totals (); //shallow copy!
+ }
+ totals[0] = data[0]->get_totals ();
+
+ // Get table size
+ labels = data[0]->get_labels ();
+ nitems = labels.size + 4;
+
+ // Initialize Java String array
+ Vector<void*> *table = new Vector<void*>(size + 4);
+ Vector<char*> *jobjects = new Vector<char*>(nitems);
+
+ // Set the label
+ jobjects->store (0, dbe_strdup (GTXT ("Start Time (sec.)")));
+ jobjects->store (1, dbe_strdup (GTXT ("End Time (sec.)")));
+ jobjects->store (2, dbe_strdup (GTXT ("Duration (sec.)")));
+ jobjects->store (3, dbe_strdup (GTXT ("Total Thread Time (sec.)")));
+ jobjects->store (4, dbe_strdup (GTXT ("Average number of Threads")));
+
+ for (index2 = 5; index2 < nitems; index2++)
+ jobjects->store (index2, dbe_strdup (labels.values[index2 - 4].l));
+ table->store (0, jobjects);
+
+ // Set the data
+ for (index = 0; index <= size; index++)
+ {
+ Vector<double> *jd_list = new Vector<double>(nitems);
+ jd_list->store (0, tstodouble (totals[index].start));
+ jd_list->store (1, tstodouble (totals[index].end));
+ jd_list->store (2, tstodouble (totals[index].duration));
+ jd_list->store (3, tstodouble (totals[index].tlwp));
+ jd_list->store (4, totals[index].nlwp);
+ for (index2 = 5; index2 < nitems; index2++)
+ jd_list->store (index2, tstodouble (totals[index].values[index2 - 4].t));
+ table->store (index + 1, jd_list);
+ }
+ for (index = 0; index <= size; index++)
+ delete data[index];
+ delete[] data;
+ delete[] totals;
+ return table;
+}
+
+// Get Table of Statistics List
+Vector<void*> *
+dbeGetStatisList (int dbevindex)
+{
+ int size;
+ Stats_data **data;
+ int nitems;
+ int index, index2;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ dbev->error_msg = dbev->warning_msg = NULL;
+ if ((size = dbeSession->nexps ()) == 0)
+ return NULL;
+
+ // Get statistics data
+ data = (Stats_data **) malloc ((size + 1) * sizeof (Stats_data *));
+ data[0] = new Stats_data ();
+ for (index = 1; index <= size; index++)
+ {
+ data[index] = dbev->get_stats_data (index - 1);
+ if (data[index] == NULL)
+ continue;
+ data[0]->sum (data[index]);
+ }
+
+ // Get table size
+ nitems = data[0]->size ();
+
+ // Initialize Java String array
+ Vector<void*> *table = new Vector<void*>(size + 2);
+ Vector<char*> *jobjects = new Vector<char*>(nitems);
+
+ // Set the label
+ for (index2 = 0; index2 < nitems; index2++)
+ jobjects->store (index2, dbe_strdup (data[0]->fetch (index2).label));
+ table->store (0, jobjects);
+
+ // Set the data
+ for (index = 0; index <= size; index++)
+ {
+ Vector<double> *jd_list = new Vector<double>(nitems);
+ for (index2 = 0; index2 < nitems; index2++)
+ {
+ double val = 0;
+ if (data[index])
+ val = data[index]->fetch (index2).value.to_double ();
+ jd_list->store (index2, val);
+ }
+ table->store (index + 1, jd_list);
+ }
+ if (data)
+ {
+ for (index = 0; index <= size; index++)
+ delete data[index];
+ free (data);
+ }
+ return table;
+}
+
+
+//
+// Set summary list
+//
+static void
+setSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+ Vector<char> *mnemonic, Vector<char*> *jlabels, Vector<char*> *jvalues)
+{
+ char *sname = NULL, *oname = NULL, *lname = NULL, *alias = NULL,
+ *mangle = NULL, *address = NULL, *size = NULL,
+ *name_0 = NULL, *sname_0 = NULL, *oname_0 = NULL, *lname_0 = NULL,
+ *alias_0 = NULL, *mangle_0 = NULL;
+ Function *func, *last_func = NULL;
+ int one_func = 1;
+
+ // Get the source/object/load-object files & aliases
+ long long ll_size = 0;
+ for (long i = 0; i < objs->size (); i++)
+ {
+ Histable *current_obj = objs->fetch (i);
+ Histable::Type htype = current_obj->get_type ();
+ if (htype == Histable::LOADOBJECT)
+ lname = ((LoadObject *) current_obj)->dbeFile->get_location_info ();
+ else if ((func = (Function*) current_obj->convertto (Histable::FUNCTION)) != NULL)
+ {
+ if (one_func && last_func != NULL && last_func != func)
+ one_func = 0;
+ last_func = func;
+ sname = NULL;
+ DbeLine *dbeline = (DbeLine*) current_obj->convertto (Histable::LINE);
+ if (dbeline)
+ {
+ SourceFile *sf;
+ if (dbeline->lineno == 0 && dbeline->include != NULL)
+ sf = dbeline->include;
+ else if (dbeline->sourceFile != NULL)
+ sf = dbeline->sourceFile;
+ else
+ sf = func->getDefSrc ();
+ if (sf)
+ sname = sf->dbeFile->get_location_info ();
+ }
+ char *func_name = func->get_name ();
+ mangle = func->get_mangled_name ();
+ if (mangle && streq (func_name, mangle))
+ mangle = NULL;
+ Module *module = func->module;
+ if (module != NULL)
+ {
+ module->read_stabs ();
+ if (sname == NULL || strlen (sname) == 0)
+ {
+ SourceFile *sf = module->getMainSrc ();
+ sname = sf->dbeFile->get_location_info ();
+ }
+ DbeFile *df = module->dbeFile;
+ if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
+ df = module->loadobject->dbeFile;
+ lname = df->get_location_info ();
+ oname = lname;
+ if (module->dot_o_file)
+ oname = module->dot_o_file->dbeFile->get_location_info ();
+ }
+
+ if (htype == Histable::INSTR && dbeSession->is_datamode_available ())
+ alias = ((DbeInstr*) current_obj)->get_descriptor ();
+ }
+
+ char *name = current_obj->get_name ();
+ if (i == 0)
+ {
+ name_0 = name;
+ lname_0 = lname;
+ sname_0 = sname;
+ oname_0 = oname;
+ mangle_0 = mangle;
+ alias_0 = alias;
+ if (objs->size () == 1)
+ {
+ uint64_t addr = current_obj->get_addr ();
+ address = dbe_sprintf (NTXT ("%lld:0x%08llX"),
+ (long long) ADDRESS_SEG (addr),
+ (long long) ADDRESS_OFF (addr));
+ }
+ }
+ else
+ {
+ if (name_0 != name)
+ name_0 = NULL;
+ if (lname_0 != lname)
+ lname_0 = NULL;
+ if (sname_0 != sname)
+ sname_0 = NULL;
+ if (oname_0 != oname)
+ oname_0 = NULL;
+ if (mangle_0 != mangle)
+ mangle_0 = NULL;
+ if (alias_0 != alias)
+ alias_0 = NULL;
+ }
+ if (current_obj->get_size () == -1)
+ {
+ if (size == NULL)
+ size = dbe_strdup (GTXT ("(Unknown)"));
+ }
+ else
+ ll_size += current_obj->get_size ();
+ }
+ if (size == NULL)
+ size = dbe_sprintf (NTXT ("%lld"), ll_size);
+ if (name_0 == NULL)
+ {
+ if (objs->size () > 1)
+ {
+ char *func_name = last_func == NULL ? NULL :
+ (one_func == 0 ? NULL : last_func->get_name ());
+ name_0 = dbe_sprintf (NTXT ("%s%s%s (%lld %s)"),
+ func_name == NULL ? "" : func_name,
+ func_name == NULL ? "" : ": ",
+ GTXT ("Multiple Selection"),
+ (long long) objs->size (),
+ GTXT ("objects"));
+ }
+ }
+ else
+ name_0 = dbe_strdup (name_0);
+
+ // Set the name area
+ saligns->store (0, TEXT_LEFT);
+ mnemonic->store (0, 'N');
+ jlabels->store (0, dbe_strdup (GTXT ("Name")));
+ jvalues->store (0, name_0);
+
+ saligns->store (1, TEXT_LEFT);
+ mnemonic->store (1, 'P');
+ jlabels->store (1, dbe_strdup (GTXT ("PC Address")));
+ jvalues->store (1, address);
+
+ saligns->store (2, TEXT_LEFT);
+ mnemonic->store (2, 'z');
+ jlabels->store (2, dbe_strdup (GTXT ("Size")));
+ jvalues->store (2, size);
+
+ saligns->store (3, TEXT_RIGHT);
+ mnemonic->store (3, 'r');
+ jlabels->store (3, dbe_strdup (GTXT ("Source File")));
+ jvalues->store (3, dbe_strdup (sname_0));
+
+ saligns->store (4, TEXT_RIGHT);
+ mnemonic->store (4, 'b');
+ jlabels->store (4, dbe_strdup (GTXT ("Object File")));
+ jvalues->store (4, dbe_strdup (oname_0));
+
+ saligns->store (5, TEXT_LEFT);
+ mnemonic->store (5, 'j');
+ jlabels->store (5, dbe_strdup (GTXT ("Load Object")));
+ jvalues->store (5, dbe_strdup (lname_0));
+
+ saligns->store (6, TEXT_LEFT);
+ mnemonic->store (6, 'm');
+ jlabels->store (6, dbe_strdup (GTXT ("Mangled Name")));
+ jvalues->store (6, dbe_strdup (mangle_0));
+
+ saligns->store (7, TEXT_LEFT);
+ mnemonic->store (7, 'A');
+ jlabels->store (7, dbe_strdup (GTXT ("Aliases")));
+ jvalues->store (7, dbe_strdup (alias_0));
+}
+
+// Set memory-object summary list
+//
+static void
+setMemSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+ Vector<char> *mnemonic, Vector<char*> *jlabels,
+ Vector<char*> *jvalues)
+{
+ saligns->store (0, TEXT_LEFT);
+ mnemonic->store (0, 'M');
+ jlabels->store (0, dbe_strdup (GTXT ("Memory Object")));
+ if (objs->size () == 1)
+ {
+ Histable *current_obj = objs->fetch (0);
+ jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+ }
+ else
+ {
+ char *name = dbe_sprintf (NTXT ("%s (%lld %s)"),
+ GTXT ("Multiple Selection"),
+ (long long) objs->size (), GTXT ("objects"));
+ jvalues->store (0, name);
+ }
+}
+
+// Set index-object summary list
+//
+static void
+setIndxSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+ Vector<char> *mnemonic, Vector<char*> *jlabels,
+ Vector<char*> *jvalues)
+{
+ saligns->store (0, TEXT_LEFT);
+ mnemonic->store (0, 'I');
+ jlabels->store (0, dbe_strdup (GTXT ("Index Object")));
+
+ if (objs->size () == 1)
+ {
+ Histable *current_obj = objs->fetch (0);
+ jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+ }
+ else
+ {
+ char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+ (long long) objs->size (), GTXT ("objects"));
+ jvalues->store (0, name);
+ }
+}
+
+// Set I/O activity summary list
+//
+static void
+setIOActivitySummary (Vector<Histable*> *objs, Vector<int> *saligns,
+ Vector<char> *mnemonic, Vector<char*> *jlabels,
+ Vector<char*> *jvalues)
+{
+ saligns->store (0, TEXT_LEFT);
+ mnemonic->store (0, 'O');
+ jlabels->store (0, dbe_strdup (GTXT ("I/O Activity")));
+ if (objs->size () == 1)
+ {
+ Histable *current_obj = objs->fetch (0);
+ jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+ }
+ else
+ {
+ char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+ (long long) objs->size (), GTXT ("objects"));
+ jvalues->store (0, name);
+ }
+}
+
+// Set heap activity summary list
+//
+static void
+setHeapActivitySummary (Vector<Histable*> *objs, Vector<int> *saligns,
+ Vector<char> *mnemonic, Vector<char*> *jlabels,
+ Vector<char*> *jvalues)
+{
+ saligns->store (0, TEXT_LEFT);
+ mnemonic->store (0, 'O');
+ jlabels->store (0, dbe_strdup (GTXT ("Heap Activity")));
+
+ if (objs->size () == 1)
+ {
+ Histable *current_obj = objs->fetch (0);
+ jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+ }
+ else
+ {
+ char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+ (long long) objs->size (), GTXT ("objects"));
+ jvalues->store (0, name);
+ }
+}
+
+//
+// Set data-object summary list
+//
+static void
+setDataSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+ Vector<char> *mnemonic, Vector<char*> *jlabels,
+ Vector<char*> *jvalues)
+{
+ char *name, *type, *member, *elist;
+ DataObject *dobj;
+ Vector<DataObject *> *delem;
+ Histable *scope;
+ int index;
+ char *size, *offset, *elements, *scopename;
+
+ // Get the data object elements
+ member = elist = type = size = offset = elements = scopename = NULL;
+
+ if (objs->size () == 1)
+ {
+ Histable *current_obj = objs->fetch (0);
+ name = dbe_strdup (current_obj->get_name ());
+ dobj = (DataObject *) current_obj;
+ type = dobj->get_typename ();
+ scope = dobj->get_scope ();
+ delem = dbeSession->get_dobj_elements (dobj);
+ if (type == NULL)
+ type = GTXT ("(Synthetic)");
+ if (!scope)
+ scopename = dbe_strdup (GTXT ("(Global)"));
+ else
+ {
+ switch (scope->get_type ())
+ {
+ case Histable::FUNCTION:
+ scopename = dbe_sprintf (NTXT ("%s(%s)"),
+ ((Function*) scope)->module->get_name (),
+ scope->get_name ());
+ break;
+ case Histable::LOADOBJECT:
+ case Histable::MODULE:
+ default:
+ scopename = dbe_strdup (scope->get_name ());
+ break;
+ }
+ }
+
+ if (dobj->get_offset () != -1)
+ {
+ if (dobj->get_parent ())
+ member = dbe_strdup (dobj->get_parent ()->get_name ());
+ offset = dbe_sprintf (NTXT ("%lld"), (long long) dobj->get_offset ());
+ }
+ size = dbe_sprintf ("%lld", (long long) dobj->get_size ());
+
+ if (delem->size () > 0)
+ {
+ elements = dbe_sprintf (NTXT ("%lld"), (long long) delem->size ());
+ StringBuilder sb_tmp, sb;
+ sb.append (GTXT ("Offset Size Name\n"));
+ for (index = 0; index < delem->size (); index++)
+ {
+ DataObject *ditem = delem->fetch (index);
+ sb_tmp.sprintf (NTXT ("%6lld %5lld %s\n"),
+ (long long) ditem->get_offset (),
+ (long long) ditem->get_size (), ditem->get_name ());
+ sb.append (&sb_tmp);
+ }
+ if (sb.charAt (sb.length () - 1) == '\n')
+ sb.setLength (sb.length () - 1);
+ elist = sb.toString ();
+ }
+ }
+ else
+ name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+ (long long) objs->size (), GTXT ("objects"));
+
+ saligns->store (0, TEXT_LEFT);
+ mnemonic->store (0, 'D');
+ jlabels->store (0, dbe_strdup (GTXT ("Data Object")));
+ jvalues->store (0, name);
+
+ saligns->store (1, TEXT_LEFT);
+ mnemonic->store (1, 'S');
+ jlabels->store (1, dbe_strdup (GTXT ("Scope")));
+ jvalues->store (1, scopename);
+
+ saligns->store (2, TEXT_LEFT);
+ mnemonic->store (2, 'T');
+ jlabels->store (2, dbe_strdup (GTXT ("Type")));
+ jvalues->store (2, dbe_strdup (type));
+
+ saligns->store (3, TEXT_LEFT);
+ mnemonic->store (3, 'M');
+ jlabels->store (3, dbe_strdup (GTXT ("Member of")));
+ jvalues->store (3, member);
+
+ saligns->store (4, TEXT_LEFT);
+ mnemonic->store (4, 'O');
+ jlabels->store (4, dbe_strdup (GTXT ("Offset")));
+ jvalues->store (4, offset);
+
+ saligns->store (5, TEXT_LEFT);
+ mnemonic->store (5, 'z');
+ jlabels->store (5, dbe_strdup (GTXT ("Size")));
+ jvalues->store (5, size);
+
+ saligns->store (6, TEXT_LEFT);
+ mnemonic->store (6, 'E');
+ jlabels->store (6, dbe_strdup (GTXT ("Elements")));
+ jvalues->store (6, elements);
+
+ saligns->store (7, TEXT_LEFT);
+ mnemonic->store (7, 'L');
+ jlabels->store (7, dbe_strdup (GTXT ("List")));
+ jvalues->store (7, elist);
+}
+
+#define SUMMARY_NAME 8
+#define DSUMMARY_NAME 8
+#define LSUMMARY_NAME 7
+#define IMSUMMARY_NAME 1
+
+Vector<void*> *
+dbeGetSummaryV2 (int dbevindex, Vector<Obj> *sel_objs, int type, int subtype)
+{
+ if (sel_objs == NULL || sel_objs->size () == 0)
+ return NULL;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ Vector<Histable*>*objs = new Vector<Histable*>(sel_objs->size ());
+ for (int i = 0; i < sel_objs->size (); i++)
+ {
+ Histable *obj = (Histable *) sel_objs->fetch (i);
+ if (obj == NULL)
+ continue;
+ char *nm = obj->get_name ();
+ if (streq (nm, NTXT ("<Total>")))
+ {
+ // Special case for 'Total'.
+ // Multi selection which includes 'Total' is only 'Total'
+ objs->reset ();
+ objs->append (obj);
+ break;
+ }
+ objs->append (obj);
+ }
+ if (objs->size () == 0)
+ return NULL;
+
+ // Set name area
+ int nname = SUMMARY_NAME;
+ Vector<int> *saligns = new Vector<int>(nname);
+ Vector<char>*mnemonic = new Vector<char>(nname);
+ Vector<char*> *jlabels = new Vector<char*>(nname);
+ Vector<char*> *jvalues = new Vector<char*>(nname);
+ Vector<void*> *name_objs = new Vector<void*>(4);
+ name_objs->store (0, saligns);
+ name_objs->store (1, mnemonic);
+ name_objs->store (2, jlabels);
+ name_objs->store (3, jvalues);
+ setSummary (objs, saligns, mnemonic, jlabels, jvalues);
+
+ MetricList *prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL));
+ if (prop_mlist && dbev->comparingExperiments ())
+ prop_mlist = dbev->get_compare_mlist (prop_mlist, 0);
+
+ int nitems = prop_mlist->get_items ()->size ();
+
+ // Set the metrics area
+ jlabels = new Vector<char*>(nitems);
+ Vector<double> *clock_list = new Vector<double>(nitems);
+ Vector<double> *excl_list = new Vector<double>(nitems);
+ Vector<double> *ep_list = new Vector<double>(nitems);
+ Vector<double> *incl_list = new Vector<double>(nitems);
+ Vector<double> *ip_list = new Vector<double>(nitems);
+ Vector<int> *vtype = new Vector<int>(nitems);
+
+ // Initialize Java String array
+ Vector<void*> *metric_objs = new Vector<void*>(8);
+ metric_objs->store (0, jlabels);
+ metric_objs->store (1, clock_list);
+ metric_objs->store (2, excl_list);
+ metric_objs->store (3, ep_list);
+ metric_objs->store (4, incl_list);
+ metric_objs->store (5, ip_list);
+ metric_objs->store (6, vtype);
+
+ int last_init = -1;
+ for (int i = 0; i < objs->size (); i++)
+ {
+ Histable *obj = objs->fetch (i);
+ // Get the data to be displayed
+ Hist_data *data = dbev->get_hist_data (prop_mlist, obj->get_type (), subtype,
+ Hist_data::SELF, obj, dbev->sel_binctx, objs);
+
+ if (data->get_status () != Hist_data::SUCCESS)
+ {
+ if (type != DSP_DLAYOUT)
+ { // For data_layout, rows with zero metrics are OK
+ delete data;
+ continue;
+ }
+ }
+ TValue *values = NULL;
+ if (data->get_status () == Hist_data::SUCCESS)
+ {
+ Hist_data::HistItem *hi = data->fetch (0);
+ if (hi)
+ values = hi->value;
+ }
+ Hist_data::HistItem *total = data->get_totals ();
+ int index2 = 0;
+ char *tstr = GTXT (" Time");
+ char *estr = GTXT ("Exclusive ");
+ size_t len = strlen (estr);
+
+ // get the metric list from the data
+ MetricList *mlist = data->get_metric_list ();
+ int index;
+ Metric *mitem;
+ double clock;
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ if (last_init < index2)
+ {
+ last_init = index2;
+ jlabels->store (index2, NULL);
+ clock_list->store (index2, 0.0);
+ excl_list->store (index2, 0.0);
+ ep_list->store (index2, 0.0);
+ incl_list->store (index2, 0.0);
+ ip_list->store (index2, 0.0);
+ vtype->store (index2, 0);
+ }
+ double dvalue = (values != NULL) ? values[index].to_double () : 0.0;
+ double dtotal = total->value[index].to_double ();
+ if (mitem->is_time_val ())
+ clock = 1.e+6 * dbeSession->get_clock (-1);
+ else
+ clock = 0.0;
+
+ clock_list->store (index2, clock);
+ if ((mitem->get_subtype () == Metric::EXCLUSIVE) ||
+ (mitem->get_subtype () == Metric::DATASPACE))
+ {
+ if (i == 0)
+ {
+ char *sstr = mitem->get_name ();
+ if (!strncmp (sstr, estr, len))
+ sstr += len;
+ char *buf, *lstr = strstr (sstr, tstr);
+ if (lstr)
+ buf = dbe_strndup (sstr, lstr - sstr);
+ else
+ buf = dbe_strdup (sstr);
+ jlabels->store (index2, buf);
+ vtype->store (index2, mitem->get_vtype ());
+ }
+ dvalue += excl_list->fetch (index2);
+ double percent = dtotal == 0.0 ? dtotal : (dvalue / dtotal) * 100;
+ excl_list->store (index2, dvalue);
+ ep_list->store (index2, percent);
+ }
+ else
+ {
+ dvalue += incl_list->fetch (index2);
+ if (dvalue > dtotal)
+ dvalue = dtotal; // temporary correction
+ double percent = dtotal == 0.0 ? dtotal : (dvalue / dtotal) * 100;
+ incl_list->store (index2, dvalue);
+ ip_list->store (index2, percent);
+ index2++;
+ }
+ }
+ delete data;
+ }
+ delete prop_mlist;
+ Vector<void*> *summary = new Vector<void*>(2);
+ summary->store (0, name_objs);
+ summary->store (1, metric_objs);
+ return summary;
+}
+
+// Get Summary List
+Vector<void*> *
+dbeGetSummary (int dbevindex, Vector<Obj> *sel_objs, int type, int subtype)
+{
+ bool is_data, is_mem, is_indx, is_iodata, is_heapdata;
+ Hist_data::HistItem *total;
+ MetricList *prop_mlist; // as passed to get_hist_data
+ MetricList *mlist; // as stored in the data
+ Metric *mitem;
+ int i, nname, nitems, index, index2;
+ TValue *values;
+ double dvalue, clock;
+ Hist_data *data;
+ Vector<double> *percent_scale;
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (sel_objs == NULL || sel_objs->size () == 0)
+ return NULL;
+
+ is_mem = false;
+ is_data = false;
+ is_indx = false;
+ is_iodata = false;
+ is_heapdata = false;
+ nname = SUMMARY_NAME;
+ Vector<Histable*>*objs = new Vector<Histable*>(sel_objs->size ());
+ if (type == DSP_TIMELINE)
+ objs->append ((Histable *) sel_objs->fetch (0));
+ else
+ {
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = dbev->func_data;
+ break;
+ case DSP_LINE:
+ data = dbev->line_data;
+ break;
+ case DSP_PC:
+ data = dbev->pc_data;
+ break;
+ case DSP_SELF:
+ data = dbev->fitem_data;
+ break;
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = dbev->src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dbev->dis_data;
+ break;
+ case DSP_DLAYOUT:
+ is_data = true;
+ nname = LSUMMARY_NAME;
+ data = dbev->dlay_data;
+ break;
+ case DSP_DATAOBJ:
+ is_data = true;
+ nname = DSUMMARY_NAME;
+ data = dbev->dobj_data;
+ break;
+ case DSP_MEMOBJ:
+ is_data = true;
+ is_mem = true;
+ nname = IMSUMMARY_NAME;
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ case DSP_INDXOBJ:
+ is_indx = true;
+ nname = IMSUMMARY_NAME;
+ data = dbev->get_indxobj_data (subtype);
+ break;
+ case DSP_IOACTIVITY:
+ is_iodata = true;
+ nname = IMSUMMARY_NAME;
+ data = dbev->iofile_data;
+ break;
+ case DSP_IOVFD:
+ is_iodata = true;
+ nname = IMSUMMARY_NAME;
+ data = dbev->iovfd_data;
+ break;
+ case DSP_IOCALLSTACK:
+ is_iodata = true;
+ nname = IMSUMMARY_NAME;
+ data = dbev->iocs_data;
+ break;
+ case DSP_HEAPCALLSTACK:
+ is_heapdata = true;
+ nname = IMSUMMARY_NAME;
+ data = dbev->heapcs_data;
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return NULL;
+
+ Hist_data::HistItem *current_item;
+ for (i = 0; i < sel_objs->size (); i++)
+ {
+ int sel_index = (int) sel_objs->fetch (i);
+ if (type != DSP_IOACTIVITY && type != DSP_IOVFD &&
+ type != DSP_IOCALLSTACK && type != DSP_HEAPCALLSTACK)
+ {
+ if (sel_index < 0 || sel_index >= data->size ())
+ continue;
+ current_item = data->fetch (sel_index);
+ if (current_item->obj == NULL)
+ continue;
+ }
+ else
+ {
+ if (sel_index < 0)
+ continue;
+ bool found = false;
+ for (int j = 0; j < data->size (); j++)
+ {
+ current_item = data->fetch (j);
+ if ((current_item->obj != NULL) && (current_item->obj->id == sel_index))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ }
+ char *nm = current_item->obj->get_name ();
+ if (streq (nm, NTXT ("<Total>")))
+ {
+ // Special case for 'Total'.
+ // Multi selection which includes 'Total' is only 'Total'
+ objs->reset ();
+ objs->append (current_item->obj);
+ break;
+ }
+ objs->append (current_item->obj);
+ }
+ }
+ if (objs->size () == 0)
+ return NULL;
+
+ // Set name area
+ Vector<int> *saligns = new Vector<int>(nname);
+ Vector<char>*mnemonic = new Vector<char>(nname);
+ Vector<char*> *jlabels = new Vector<char*>(nname);
+ Vector<char*> *jvalues = new Vector<char*>(nname);
+ Vector<void*> *name_objs = new Vector<void*>(4);
+ name_objs->store (0, saligns);
+ name_objs->store (1, mnemonic);
+ name_objs->store (2, jlabels);
+ name_objs->store (3, jvalues);
+ if (is_mem)
+ setMemSummary (objs, saligns, mnemonic, jlabels, jvalues);
+ else if (is_indx)
+ setIndxSummary (objs, saligns, mnemonic, jlabels, jvalues);
+ else if (is_data)
+ setDataSummary (objs, saligns, mnemonic, jlabels, jvalues);
+ else if (is_iodata)
+ setIOActivitySummary (objs, saligns, mnemonic, jlabels, jvalues);
+ else if (is_heapdata)
+ setHeapActivitySummary (objs, saligns, mnemonic, jlabels, jvalues);
+ else
+ setSummary (objs, saligns, mnemonic, jlabels, jvalues);
+
+ // Get the reference metrics
+ if (is_data)
+ prop_mlist = new MetricList (dbev->get_metric_ref (MET_DATA));
+ else if (is_indx)
+ prop_mlist = new MetricList (dbev->get_metric_ref (MET_INDX));
+ else if (is_iodata)
+ prop_mlist = new MetricList (dbev->get_metric_ref (MET_IO));
+ else if (is_heapdata)
+ prop_mlist = new MetricList (dbev->get_metric_ref (MET_HEAP));
+ else
+ prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL));
+
+ // XXXX a workaround to avoid aggregated data for compare mode, only show base experiment data
+ if (prop_mlist && dbev->comparingExperiments ())
+ prop_mlist = dbev->get_compare_mlist (prop_mlist, 0);
+ nitems = prop_mlist->get_items ()->size ();
+
+ // Set the metrics area
+ jlabels = new Vector<char*>(nitems);
+ Vector<double> *clock_list = new Vector<double>(nitems);
+ Vector<double> *excl_list = new Vector<double>(nitems);
+ Vector<double> *ep_list = new Vector<double>(nitems);
+ Vector<double> *incl_list = new Vector<double>(nitems);
+ Vector<double> *ip_list = new Vector<double>(nitems);
+ Vector<int> *vtype = new Vector<int>(nitems);
+
+ // Initialize Java String array
+ Vector<void*> *metric_objs = new Vector<void*>(8);
+ metric_objs->store (0, jlabels);
+ metric_objs->store (1, clock_list);
+ metric_objs->store (2, excl_list);
+ metric_objs->store (3, ep_list);
+ metric_objs->store (4, incl_list);
+ metric_objs->store (5, ip_list);
+ metric_objs->store (6, vtype);
+ percent_scale = new Vector<double>();
+ int last_init = -1;
+ for (i = 0; i < objs->size (); i++)
+ {
+ Histable *current_obj = objs->fetch (i);
+ // Get the data to be displayed
+ data = dbev->get_hist_data (prop_mlist, current_obj->get_type (), subtype,
+ Hist_data::SELF, current_obj, dbev->sel_binctx, objs);
+ if (data->get_status () != Hist_data::SUCCESS)
+ {
+ if (type != DSP_DLAYOUT)
+ { // For data_layout, rows with zero metrics are OK
+ delete data;
+ continue;
+ }
+ }
+ Hist_data::HistItem *hi = data->fetch (0);
+ values = hi ? hi->value : NULL;
+ total = data->get_totals ();
+ index2 = 0;
+
+ // get the metric list from the data
+ mlist = data->get_metric_list ();
+
+ // We loop over the metrics in mlist.
+ // We construct index2, which tells us
+ // the corresponding entry in the metric_objs lists.
+ // We need this mapping multiple times.
+ // So, if you change the looping in any way here,
+ // do so as well in other similar loops.
+ // All such loops are marked so:
+ // See discussion on "mlist-to-index2 mapping".
+
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ if (last_init < index2)
+ {
+ last_init = index2;
+ jlabels->store (index2, NULL);
+ clock_list->store (index2, 0.0);
+ excl_list->store (index2, 0.0);
+ ep_list->store (index2, 0.0);
+ incl_list->store (index2, 0.0);
+ ip_list->store (index2, 0.0);
+ vtype->store (index2, 0);
+ }
+ dvalue = (values != NULL) ? values[index].to_double () : 0.0;
+ double dtotal = total->value[index].to_double ();
+ percent_scale->store (index, dtotal == 0. ? 0. : 100. / dtotal);
+ if (mitem->is_time_val ())
+ clock = 1.e+6 * dbeSession->get_clock (-1);
+ else
+ clock = 0.0;
+
+ clock_list->store (index2, clock);
+ if (mitem->get_subtype () == Metric::EXCLUSIVE ||
+ mitem->get_subtype () == Metric::DATASPACE)
+ {
+ if (i == 0)
+ {
+ char *sstr = mitem->get_username ();
+ char *buf = dbe_strdup (sstr);
+ jlabels->store (index2, buf);
+ vtype->store (index2, mitem->get_vtype ());
+ }
+ dvalue += excl_list->fetch (index2);
+ double percent = dvalue * percent_scale->fetch (index);
+ excl_list->store (index2, dvalue);
+ ep_list->store (index2, percent);
+ if (is_data || is_indx || is_iodata || is_heapdata)
+ // move to next row, except if there's inclusive data, too
+ index2++;
+ }
+ else
+ {
+ dvalue += incl_list->fetch (index2);
+ if (dvalue > dtotal && mitem->get_type () != BaseMetric::DERIVED)
+ dvalue = dtotal; // temporary correction
+ double percent = dvalue * percent_scale->fetch (index);
+ incl_list->store (index2, dvalue);
+ ip_list->store (index2, percent);
+ index2++;
+ }
+ }
+ delete data;
+ }
+
+ // for multi-selection, we have to recompute the derived metrics
+ if (objs->size () > 1 &&
+ dbev->get_derived_metrics () != NULL &&
+ dbev->get_derived_metrics ()->get_items () != NULL &&
+ dbev->get_derived_metrics ()->get_items ()->size () > 0)
+ {
+ // See discussion on "mlist-to-index2 mapping".
+ Vector<Metric*> *mvec = new Vector<Metric*>(nitems);
+ index2 = 0;
+ Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+ {
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ if (mitem->get_subtype () == Metric::EXCLUSIVE ||
+ mitem->get_subtype () == Metric::DATASPACE)
+ {
+ mvec->store (index2, mitem);
+ if (is_data || is_indx || is_iodata || is_heapdata)
+ index2++;
+ }
+ else
+ {
+ assert (strcmp (mvec->fetch (index2)->get_cmd (), mitem->get_cmd ()) == 0);
+ index2++;
+ }
+ }
+ int *map = dbev->get_derived_metrics ()->construct_map (mvec, BaseMetric::EXCLUSIVE, mvec->fetch (0)->get_expr_spec ());
+ if (map != NULL)
+ {
+ int nmetrics = mvec->size ();
+ double *evalues = (double *) malloc (nmetrics * sizeof (double));
+ double *ivalues = (double *) malloc (nmetrics * sizeof (double));
+ for (index2 = 0; index2 < nmetrics; index2++)
+ {
+ evalues[index2] = excl_list->fetch (index2);
+ ivalues[index2] = incl_list->fetch (index2);
+ }
+
+ // evaluate derived metrics
+ dbev->get_derived_metrics ()->eval (map, evalues);
+ dbev->get_derived_metrics ()->eval (map, ivalues);
+ for (index2 = 0; index2 < nmetrics; index2++)
+ {
+ excl_list->store (index2, evalues[index2]);
+ incl_list->store (index2, ivalues[index2]);
+ }
+
+ // recompute percentages for derived metrics EUGENE maybe all percentage computations should be moved here
+ // See discussion on "mlist-to-index2 mapping".
+ index2 = 0;
+ Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+ {
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ if (mitem->get_subtype () == Metric::EXCLUSIVE ||
+ mitem->get_subtype () == Metric::DATASPACE)
+ {
+ if (mitem->get_type () == BaseMetric::DERIVED)
+ ep_list->store (index2, excl_list->fetch (index2) * percent_scale->fetch (index));
+ if (is_data || is_indx || is_iodata || is_heapdata)
+ index2++;
+ }
+ else
+ {
+ if (mitem->get_type () == BaseMetric::DERIVED)
+ ip_list->store (index2, incl_list->fetch (index2) * percent_scale->fetch (index));
+ index2++;
+ }
+ }
+ free (evalues);
+ free (ivalues);
+ free (map);
+ }
+ delete mvec;
+ }
+ delete prop_mlist;
+ Vector<void*> *summary = new Vector<void*>(2);
+ summary->store (0, name_objs);
+ summary->store (1, metric_objs);
+ delete objs;
+ delete percent_scale;
+ return summary;
+}
+
+char *
+dbeGetExpName (int /*dbevindex*/, char *dir_name)
+{
+ char *ret;
+ char *warn;
+ if (col_ctr == NULL)
+ col_ctr = new Coll_Ctrl (1); // Potential race condition?
+ if (dir_name != NULL)
+ {
+ ret = col_ctr->set_directory (dir_name, &warn);
+ // note that the warning and error msgs are written to stderr, not returned to caller
+ if (warn != NULL)
+ fprintf (stderr, NTXT ("%s"), warn);
+ if (ret != NULL)
+ fprintf (stderr, NTXT ("%s"), ret);
+ }
+ return dbe_strdup (col_ctr->get_expt ());
+}
+
+// === CollectDialog HWC info ===
+
+Vector<Vector<char*>*> *
+dbeGetHwcSets (int /*dbevindex*/, bool forKernel)
+{
+ Vector<Vector<char*>*> *list = new Vector<Vector<char*>*>(2);
+ char * defctrs = hwc_get_default_cntrs2 (forKernel, 1);
+ Vector<char*> *i18n = new Vector<char*>(1); // User name
+ Vector<char*> *name = new Vector<char*>(1); // Internal name
+ if (NULL != defctrs)
+ {
+ i18n->store (0, strdup (defctrs));
+ name->store (0, strdup (NTXT ("default")));
+ }
+ list->store (0, i18n);
+ list->store (1, name);
+ return list;
+}
+
+static Vector<void*> *
+dbeGetHwcs (Hwcentry **hwcs)
+{
+ int sz;
+ for (sz = 0; hwcs && hwcs[sz]; sz++)
+ ;
+ Vector<void*> *list = new Vector<void*>(9);
+ Vector<char*> *i18n = new Vector<char*>(sz);
+ Vector<char*> *name = new Vector<char*>(sz);
+ Vector<char*> *int_name = new Vector<char*>(sz);
+ Vector<char*> *metric = new Vector<char*>(sz);
+ Vector<long long> *val = new Vector<long long>(sz);
+ Vector<int> *timecvt = new Vector<int>(sz);
+ Vector<int> *memop = new Vector<int>(sz);
+ Vector<char*> *short_desc = new Vector<char*>(sz);
+ Vector<Vector<int>*> *reglist_v = new Vector<Vector<int>*>(sz);
+ Vector<bool> *supportsAttrs = new Vector<bool>(sz);
+ Vector<bool> *supportsMemspace = new Vector<bool>(sz);
+
+ for (int i = 0; i < sz; i++)
+ {
+ Hwcentry *ctr = hwcs[i];
+ Vector<int> *registers = new Vector<int>(MAX_PICS);
+ regno_t *reglist = ctr->reg_list;
+ for (int k = 0; !REG_LIST_EOL (reglist[k]) && k < MAX_PICS; k++)
+ registers->store (k, reglist[k]);
+
+ i18n->store (i, dbe_strdup (hwc_i18n_metric (ctr)));
+ name->store (i, dbe_strdup (ctr->name));
+ int_name->store (i, dbe_strdup (ctr->int_name));
+ metric->store (i, dbe_strdup (ctr->metric));
+ val->store (i, ctr->val); // signed promotion from int
+ timecvt->store (i, ctr->timecvt);
+ memop->store (i, ctr->memop);
+ reglist_v->store (i, registers);
+ short_desc->store (i, dbe_strdup (ctr->short_desc));
+ supportsAttrs->store (i, true);
+ supportsMemspace->store (i, ABST_MEMSPACE_ENABLED (ctr->memop));
+ }
+ list->store (0, i18n);
+ list->store (1, name);
+ list->store (2, int_name);
+ list->store (3, metric);
+ list->store (4, val);
+ list->store (5, timecvt);
+ list->store (6, memop);
+ list->store (7, short_desc);
+ list->store (8, reglist_v);
+ list->store (9, supportsAttrs);
+ list->store (10, supportsMemspace);
+ return list;
+}
+
+Vector<void *> *
+dbeGetHwcsAll (int /*dbevindex*/, bool forKernel)
+{
+ Vector<void*> *list = new Vector<void*>(2);
+ list->store (0, dbeGetHwcs (hwc_get_std_ctrs (forKernel)));
+ list->store (1, dbeGetHwcs (hwc_get_raw_ctrs (forKernel)));
+ return list;
+}
+
+Vector<char*> *
+dbeGetHwcHelp (int /*dbevindex*/, bool forKernel)
+{
+ Vector<char*> *strings = new Vector<char*>(32);
+ FILE *f = tmpfile ();
+ hwc_usage_f (forKernel, f, "", 0, 0, 1); // writes to f
+ fflush (f);
+ fseek (f, 0, SEEK_SET);
+#define MAX_LINE_LEN 2048
+ char buff[MAX_LINE_LEN];
+ int ii = 0;
+ while (fgets (buff, MAX_LINE_LEN, f))
+ strings->store (ii++, dbe_strdup (buff));
+ fclose (f);
+ return strings;
+}
+
+Vector<char*> *
+dbeGetHwcAttrList (int /*dbevindex*/, bool forKernel)
+{
+ char ** attr_list = hwc_get_attrs (forKernel); // Get Attribute list
+ int size;
+ for (size = 0; attr_list && attr_list[size]; size++)
+ ;
+
+ Vector<char*> *name = new Vector<char*>(size);
+ for (int i = 0; i < size; i++)
+ name->store (i, dbe_strdup (attr_list[i]));
+ return name;
+}
+
+//Get maximum number of simultaneous counters
+int
+dbeGetHwcMaxConcurrent (int /*dbevindex*/, bool forKernel)
+{
+ return hwc_get_max_concurrent (forKernel);
+}
+
+// === End CollectDialog HWC info ===
+
+
+// Instruction-frequency data
+Vector<char*> *
+dbeGetIfreqData (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (!dbeSession->is_ifreq_available ())
+ return NULL;
+ int size = dbeSession->nexps ();
+ if (size == 0)
+ return NULL;
+
+ // Initialize Java String array
+ Vector<char*> *list = new Vector<char*>();
+ for (int i = 0; i < size; i++)
+ {
+ Experiment *exp = dbeSession->get_exp (i);
+ if (exp->broken || !dbev->get_exp_enable (i) || !exp->ifreqavail)
+ continue;
+ // write a header for the experiment
+ list->append (dbe_sprintf (GTXT ("Instruction frequency data from experiment %s\n\n"),
+ exp->get_expt_name ()));
+ // add its instruction frequency messages
+ char *ifreq = pr_mesgs (exp->fetch_ifreq (), NTXT (""), NTXT (""));
+ list->append (ifreq);
+ }
+ return list;
+}
+
+// LeakList related methods
+//
+Vector<void*> *
+dbeGetLeakListInfo (int dbevindex, bool leakflag)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ MetricList *origmlist = dbev->get_metric_list (MET_NORMAL);
+ MetricList *nmlist = new MetricList (origmlist);
+ if (leakflag)
+ nmlist->set_metrics (NTXT ("e.heapleakbytes:e.heapleakcnt:name"), true,
+ dbev->get_derived_metrics ());
+ else
+ nmlist->set_metrics (NTXT ("e.heapallocbytes:e.heapalloccnt:name"), true,
+ dbev->get_derived_metrics ());
+ MetricList *mlist = new MetricList (nmlist);
+ delete nmlist;
+
+ CStack_data *lam = dbev->get_cstack_data (mlist);
+ if (lam == NULL || lam->size () == 0)
+ {
+ delete lam;
+ delete mlist;
+ return NULL;
+ }
+ Vector<Vector<Obj>*> *evalue = new Vector<Vector<Obj>*>(lam->size ());
+ Vector<Vector<Obj>*> *pcstack = new Vector<Vector<Obj>*>(lam->size ());
+ Vector<Vector<Obj>*> *offstack = new Vector<Vector<Obj>*>(lam->size ());
+ Vector<Vector<Obj>*> *fpcstack = new Vector<Vector<Obj>*>(lam->size ());
+ Vector<Vector<Obj>*> *sumval = new Vector<Vector<Obj>*>(lam->size ());
+
+ int index;
+ CStack_data::CStack_item *lae;
+ Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
+ {
+ Vector<Obj> *jivals = NULL;
+ if (lae != NULL)
+ {
+ jivals = new Vector<Obj>(4);
+ jivals->store (0, (Obj) (index + 1));
+ jivals->store (1, (Obj) lae->value[1].ll);
+ jivals->store (2, (Obj) lae->value[0].ll);
+ jivals->store (3, (Obj) (leakflag ? 1 : 2));
+ }
+ evalue->store (index, jivals);
+ int snum = lae->stack->size ();
+ Vector<Obj> *jivals1 = new Vector<Obj>(snum);
+ Vector<Obj> *jivals2 = new Vector<Obj>(snum);
+ Vector<Obj> *jivals3 = new Vector<Obj>(snum);
+ if (lae->stack != NULL)
+ {
+ for (int i = lae->stack->size () - 1; i >= 0; i--)
+ {
+ DbeInstr *instr = lae->stack->fetch (i);
+ jivals1->store (i, (Obj) instr);
+ jivals2->store (i, (Obj) instr->func);
+ jivals3->store (i, (Obj) instr->addr);
+ }
+ }
+ fpcstack->store (index, jivals1);
+ pcstack->store (index, jivals2);
+ offstack->store (index, jivals3);
+ lae++;
+ }
+ Vector<Obj> *jivals4 = new Vector<Obj>(3);
+ jivals4->store (0, (Obj) lam->size ());
+ jivals4->store (1, (Obj) lam->total->value[1].ll);
+ jivals4->store (2, (Obj) lam->total->value[0].ll);
+ sumval->store (0, jivals4);
+ delete lam;
+ delete mlist;
+ Vector<void*> *earray = new Vector<void*>(5);
+ earray->store (0, evalue);
+ earray->store (1, pcstack);
+ earray->store (2, offstack);
+ earray->store (3, fpcstack);
+ earray->store (4, sumval);
+ return earray;
+}
+
+// Map timeline address to function instr
+//
+Obj
+dbeGetObject (int dbevindex, Obj sel_func, Obj sel_pc)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (sel_pc)
+ return sel_pc;
+ return sel_func;
+}
+
+char *
+dbeGetName (int /*dbevindex*/, int exp_id)
+// This function's name is not descriptive enough - it returns a string
+// containing the full experiment name with path, process name, and PID.
+// There are various dbe functions that provide experiment name and experiment
+// details, and they should probably be consolidated/refactored. (TBR)
+// For another example of similar output formatting, see dbeGetExpName().
+{
+ int id = (exp_id < 0) ? 0 : exp_id;
+ Experiment *exp = dbeSession->get_exp (id);
+ if (exp == NULL)
+ return NULL;
+ char *buf =
+ dbe_sprintf (NTXT ("%s [%s, PID %d]"),
+ exp->get_expt_name (),
+ exp->utargname != NULL ? exp->utargname : GTXT ("(unknown)"),
+ exp->getPID ());
+ return buf;
+}
+
+Vector<char*> *
+dbeGetExpVerboseName (Vector<int> *exp_ids)
+{
+ int len = exp_ids->size ();
+ Vector<char*> *list = new Vector<char*>(len);
+ for (int i = 0; i < len; i++)
+ {
+ char * verboseName = dbeGetName (0, exp_ids->fetch (i)); // no strdup()
+ list->store (i, verboseName);
+ }
+ return list;
+}
+
+long long
+dbeGetStartTime (int /*dbevindex*/, int exp_id)
+{
+ int id = (exp_id < 0) ? 0 : exp_id;
+ Experiment *exp = dbeSession->get_exp (id);
+ return exp ? exp->getStartTime () : (long long) 0;
+}
+
+long long
+dbeGetRelativeStartTime (int /*dbevindex*/, int exp_id)
+{
+ int id = (exp_id < 0) ? 0 : exp_id;
+ Experiment *exp = dbeSession->get_exp (id);
+ return exp ? exp->getRelativeStartTime () : (long long) 0;
+}
+
+long long
+dbeGetEndTime (int /*dbevindex*/, int exp_id)
+{
+ int id = (exp_id < 0) ? 0 : exp_id;
+ Experiment *exp = dbeSession->get_exp (id);
+
+ // Experiment::getEndTime was initially implemented as
+ // returning exp->last_event. To preserve the semantics
+ // new Experiment::getLastEvent() is used here.
+ return exp ? exp->getLastEvent () : (long long) 0;
+}
+
+int
+dbeGetClock (int /*dbevindex*/, int exp_id)
+{
+ return dbeSession->get_clock (exp_id);
+}
+
+long long
+dbeGetWallStartSec (int /*dbevindex*/, int exp_id)
+{
+ int id = (exp_id < 0) ? 0 : exp_id;
+ Experiment *exp = dbeSession->get_exp (id);
+ return exp ? exp->getWallStartSec () : 0ll;
+}
+
+char *
+dbeGetHostname (int /*dbevindex*/, int exp_id)
+{
+ int id = (exp_id < 0) ? 0 : exp_id;
+ Experiment *exp = dbeSession->get_exp (id);
+ return exp ? dbe_strdup (exp->hostname) : NULL;
+}
+
+static DataView *
+getTimelinePackets (int dbevindex, int exp_id, int data_id, int entity_prop_id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ const int sortprop_count = 3;
+ const int sortprops[sortprop_count] = {
+ PROP_HWCTAG, // aux
+ entity_prop_id,
+ PROP_TSTAMP
+ };
+ DataView *packets = dbev->get_filtered_events (exp_id, data_id,
+ sortprops, sortprop_count);
+ return packets;
+}
+
+static long
+getIdxByVals (DataView * packets, int aux, int entity_prop_val,
+ uint64_t time, DataView::Relation rel)
+{
+ const int sortprop_count = 3;
+ Datum tval[sortprop_count];
+ tval[0].setUINT32 (aux);
+ tval[1].setUINT32 (entity_prop_val); //CPUID, LWPID, THRID are downsized to 32
+ tval[2].setUINT64 (time);
+ long idx = packets->getIdxByVals (tval, rel);
+ return idx;
+}
+
+static bool
+isValidIdx (DataView * packets, int entity_prop_id,
+ int aux, int entity_prop_val, long idx)
+{
+ if (idx < 0 || idx >= packets->getSize ())
+ return false;
+ int pkt_aux = packets->getIntValue (PROP_HWCTAG, idx);
+ if (pkt_aux != aux)
+ return false;
+ if (entity_prop_id == PROP_EXPID)
+ return true; // not a packet property; we know the packet is in this experiment
+ if (entity_prop_id == PROP_NONE)
+ return true; // not a packet property; we know the packet is in this experiment
+ int pkt_ent = packets->getIntValue (entity_prop_id, idx);
+ if (pkt_ent != entity_prop_val)
+ return false;
+ return true;
+}
+
+static bool
+hasInvisbleTLEvents (Experiment *exp, VMode view_mode)
+{
+ if (exp->has_java && view_mode == VMODE_USER)
+ return true;
+ return false;
+}
+
+static bool
+isVisibleTLEvent (Experiment *exp, VMode view_mode, DataView* packets, long idx)
+{
+ if (hasInvisbleTLEvents (exp, view_mode))
+ {
+ JThread *jthread = (JThread*) packets->getObjValue (PROP_JTHREAD, idx);
+ if (jthread == JTHREAD_NONE || (jthread != NULL && jthread->is_system ()))
+ return false;
+ }
+ return true;
+}
+
+static long
+getTLVisibleIdxByStepping (Experiment *exp, VMode view_mode, int entity_prop_id,
+ DataView * packets, int aux, int entity_prop_val,
+ long idx, long move_count, int direction)
+{
+ assert (move_count >= 0);
+ assert (direction == 1 || direction == -1 || direction == 0);
+ if (direction == 0 /* precise hit required */)
+ move_count = 0;
+ do
+ {
+ if (!isValidIdx (packets, entity_prop_id, aux, entity_prop_val, idx))
+ return -1;
+ if (isVisibleTLEvent (exp, view_mode, packets, idx))
+ {
+ if (move_count <= 0)
+ break;
+ move_count--;
+ }
+ if (direction == 0)
+ return -1;
+ idx += direction;
+ }
+ while (1);
+ return idx;
+}
+
+static long
+getTLVisibleIdxByVals (Experiment *exp, VMode view_mode, int entity_prop_id,
+ DataView * packets,
+ int aux, int entity_prop_val, uint64_t time, DataView::Relation rel)
+{
+ long idx = getIdxByVals (packets, aux, entity_prop_val, time, rel);
+ if (!hasInvisbleTLEvents (exp, view_mode))
+ return idx;
+ if (idx < 0)
+ return idx;
+ if (rel == DataView::REL_EQ)
+ return -1; // would require bi-directional search... not supported for now
+ int direction = (rel == DataView::REL_LT || rel == DataView::REL_LTEQ) ? -1 : 1;
+ idx = getTLVisibleIdxByStepping (exp, view_mode, entity_prop_id, packets,
+ aux, entity_prop_val,
+ idx, 0 /* first match */, direction);
+ return idx;
+}
+
+// In thread mode, the entity name for non Java thread should be the 1st func
+// from the current thread's stack. See #4961315
+static char*
+getThreadRootFuncName (int, int, int, int, VMode)
+{
+ return NULL; // until we figure out what we want to show... YXXX
+}
+
+Vector<void*> *
+dbeGetEntityProps (int dbevindex) //YXXX TBD, should this be exp-specific?
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Vector<int> *prop_id = new Vector<int>();
+ Vector<char*> *prop_name = new Vector<char*>();
+ Vector<char*> *prop_uname = new Vector<char*>();
+ Vector<char*> *prop_cname = new Vector<char*>(); //must match TLModeCmd vals!
+
+ prop_id->append (PROP_NONE);
+ prop_name->append (dbe_strdup (GTXT ("NONE")));
+ prop_uname->append (dbe_strdup (GTXT ("Unknown")));
+ prop_cname->append (dbe_strdup (NTXT ("unknown")));
+
+ prop_id->append (PROP_LWPID);
+ prop_name->append (dbe_strdup (GTXT ("LWPID")));
+ prop_uname->append (dbe_strdup (GTXT ("LWP")));
+ prop_cname->append (dbe_strdup (NTXT ("lwp")));
+
+ prop_id->append (PROP_THRID);
+ prop_name->append (dbe_strdup (GTXT ("THRID")));
+ prop_uname->append (dbe_strdup (GTXT ("Thread")));
+ prop_cname->append (dbe_strdup (NTXT ("thread")));
+
+ prop_id->append (PROP_CPUID);
+ prop_name->append (dbe_strdup (GTXT ("CPUID")));
+ prop_uname->append (dbe_strdup (GTXT ("CPU")));
+ prop_cname->append (dbe_strdup (NTXT ("cpu")));
+
+ prop_id->append (PROP_EXPID);
+ prop_name->append (dbe_strdup (GTXT ("EXPID")));
+ prop_uname->append (dbe_strdup (GTXT ("Process"))); // placeholder...
+ // ...until we finalize how to expose user-level Experiments, descendents
+ prop_cname->append (dbe_strdup (NTXT ("experiment")));
+ Vector<void*> *darray = new Vector<void*>();
+ darray->store (0, prop_id);
+ darray->store (1, prop_name);
+ darray->store (2, prop_uname);
+ darray->store (3, prop_cname);
+ return darray;
+}
+
+Vector<void*> *
+dbeGetEntities (int dbevindex, int exp_id, int entity_prop_id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ if (exp == NULL)
+ return NULL;
+
+ // Recognize and skip faketime experiments
+ if (exp->timelineavail == false)
+ return NULL;
+ Vector<Histable*> *tagObjs = exp->getTagObjs ((Prop_type) entity_prop_id);
+ int total_nelem;
+ if (tagObjs)
+ total_nelem = (int) tagObjs->size ();
+ else
+ total_nelem = 0;
+ const VMode view_mode = dbev->get_view_mode ();
+ bool show_java_threadnames = (entity_prop_id == PROP_THRID &&
+ view_mode != VMODE_MACHINE);
+ // allocate the structures for the return
+ Vector<int> *entity_prop_vals = new Vector<int>();
+ Vector<char*> *jthr_names = new Vector<char*>();
+ Vector<char*> *jthr_g_names = new Vector<char*>();
+ Vector<char*> *jthr_p_names = new Vector<char*>();
+
+ // now walk the tagObjs from the experiment, and check for filtering
+ for (int tagObjsIdx = 0; tagObjsIdx < total_nelem; tagObjsIdx++)
+ {
+ int entity_prop_val = (int) ((Other *) tagObjs->fetch (tagObjsIdx))->tag;
+ entity_prop_vals->append (entity_prop_val);
+ char *jname, *jgname, *jpname;
+ JThread *jthread = NULL;
+ bool has_java_threadnames = false;
+ if (show_java_threadnames)
+ {
+ jthread = exp->get_jthread (entity_prop_val);
+ has_java_threadnames = (jthread != JTHREAD_DEFAULT
+ && jthread != JTHREAD_NONE);
+ }
+ if (!has_java_threadnames)
+ {
+ jname = jgname = jpname = NULL;
+ if (entity_prop_id == PROP_THRID || entity_prop_id == PROP_LWPID)
+ // if non Java thread, set thread name to the 1st func
+ // from the current thread's stack. see #4961315
+ jname = getThreadRootFuncName (dbevindex, exp_id, entity_prop_id,
+ entity_prop_val, view_mode);
+ }
+ else
+ {
+ jname = dbe_strdup (jthread->name);
+ jgname = dbe_strdup (jthread->group_name);
+ jpname = dbe_strdup (jthread->parent_name);
+ }
+ jthr_names->append (jname);
+ jthr_g_names->append (jgname);
+ jthr_p_names->append (jpname);
+ }
+ Vector<char*> *entity_prop_name_v = new Vector<char*>();
+ char* entity_prop_name = dbeSession->getPropName (entity_prop_id);
+ entity_prop_name_v->append (entity_prop_name);
+ Vector<void*> *darray = new Vector<void*>(5);
+ darray->store (0, entity_prop_vals);
+ darray->store (1, jthr_names);
+ darray->store (2, jthr_g_names);
+ darray->store (3, jthr_p_names);
+ darray->store (4, entity_prop_name_v); // vector only has 1 element
+ return darray;
+}
+
+// TBR: dbeGetEntities() can be set to private now that we have dbeGetEntitiesV2()
+Vector<void*> *
+dbeGetEntitiesV2 (int dbevindex, Vector<int> *exp_ids, int entity_prop_id)
+{
+ int sz = exp_ids->size ();
+ Vector<void*> *res = new Vector<void*>(sz);
+ for (int ii = 0; ii < sz; ii++)
+ {
+ int expIdx = exp_ids->fetch (ii);
+ Vector<void*>* ents = dbeGetEntities (dbevindex, expIdx, entity_prop_id);
+ res->store (ii, ents);
+ }
+ return res;
+}
+
+//YXXX old-tl packets still used for details
+static Vector<void*> *
+getTLDetailValues (int dbevindex, Experiment * exp, int data_id,
+ VMode view_mode, DataView *packets, long idx)
+{
+ Vector<long long> *value = new Vector<long long>(15);
+ long i = idx;
+ if (data_id == DATA_SAMPLE || data_id == DATA_GCEVENT)
+ {
+ //YXXX DATA_SAMPLE not handled but could be.
+ }
+ Obj stack = (unsigned long) getStack (view_mode, packets, i);
+ Vector<Obj> *funcs = stack ? dbeGetStackFunctions (dbevindex, stack) : NULL;
+ Function *func = (Function*)
+ getStackPC (0, view_mode, packets, i)->convertto (Histable::FUNCTION);
+ // Fill common data
+ value->store (0, packets->getIntValue (PROP_LWPID, i));
+ value->store (1, packets->getIntValue (PROP_THRID, i));
+ value->store (2, packets->getIntValue (PROP_CPUID, i));
+ value->store (3, packets->getLongValue (PROP_TSTAMP, i));
+ value->store (4, (unsigned long) stack);
+ value->store (5, (unsigned long) func);
+
+ // Fill specific data
+ switch (data_id)
+ {
+ case DATA_CLOCK:
+ value->store (6, packets->getIntValue (PROP_MSTATE, i));
+ {
+ hrtime_t interval = exp->get_params ()->ptimer_usec * 1000LL // nanoseconds
+ * packets->getLongValue (PROP_NTICK, i);
+ value->store (7, interval);
+ }
+ value->store (8, packets->getIntValue (PROP_OMPSTATE, i));
+ value->store (9, packets->getLongValue (PROP_EVT_TIME, i)); // visual duration
+ break;
+ case DATA_SYNCH:
+ value->store (6, packets->getLongValue (PROP_EVT_TIME, i));
+ value->store (7, packets->getLongValue (PROP_SOBJ, i));
+ break;
+ case DATA_HWC:
+ value->store (6, packets->getLongValue (PROP_HWCINT, i));
+ value->store (7, packets->getLongValue (PROP_VADDR, i)); // data vaddr
+ value->store (8, packets->getLongValue (PROP_PADDR, i)); // data paddr
+ value->store (9, packets->getLongValue (PROP_VIRTPC, i)); // pc paddr
+ value->store (10, packets->getLongValue (PROP_PHYSPC, i)); // pc vaddr
+ break;
+ case DATA_RACE:
+ value->store (6, packets->getIntValue (PROP_RTYPE, i));
+ value->store (7, packets->getIntValue (PROP_RID, i));
+ value->store (8, packets->getLongValue (PROP_RVADDR, i));
+ break;
+ case DATA_DLCK:
+ value->store (6, packets->getIntValue (PROP_DTYPE, i));
+ value->store (7, packets->getIntValue (PROP_DLTYPE, i));
+ value->store (8, packets->getIntValue (PROP_DID, i));
+ value->store (9, packets->getLongValue (PROP_DVADDR, i));
+ break;
+ case DATA_HEAP:
+ case DATA_HEAPSZ:
+ value->store (6, packets->getIntValue (PROP_HTYPE, i));
+ value->store (7, packets->getLongValue (PROP_HSIZE, i));
+ value->store (8, packets->getLongValue (PROP_HVADDR, i));
+ value->store (9, packets->getLongValue (PROP_HOVADDR, i));
+ value->store (10, packets->getLongValue (PROP_HLEAKED, i));
+ value->store (11, packets->getLongValue (PROP_HFREED, i));
+ value->store (12, packets->getLongValue (PROP_HCUR_ALLOCS, i)); // signed int64_t
+ value->store (13, packets->getLongValue (PROP_HCUR_LEAKS, i));
+ break;
+ case DATA_IOTRACE:
+ value->store (6, packets->getIntValue (PROP_IOTYPE, i));
+ value->store (7, packets->getIntValue (PROP_IOFD, i));
+ value->store (8, packets->getLongValue (PROP_IONBYTE, i));
+ value->store (9, packets->getLongValue (PROP_EVT_TIME, i));
+ value->store (10, packets->getIntValue (PROP_IOVFD, i));
+ break;
+ }
+ Vector<void*> *result = new Vector<void*>(5);
+ result->store (0, value);
+ result->store (1, funcs); // Histable::Function*
+ result->store (2, funcs ? dbeGetFuncNames (dbevindex, funcs) : 0); // formatted func names
+ result->store (3, stack ? dbeGetStackPCs (dbevindex, stack) : 0); // Histable::DbeInstr*
+ result->store (4, stack ? dbeGetStackNames (dbevindex, stack) : 0); // formatted pc names
+ return result;
+}
+
+Vector<void*> *
+dbeGetTLDetails (int dbevindex, int exp_id, int data_id,
+ int entity_prop_id, Obj event_id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Experiment *exp = dbeSession->get_exp (exp_id < 0 ? 0 : exp_id);
+ if (exp == NULL)
+ return NULL;
+ DataView *packets =
+ getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id);
+ if (!packets)
+ return NULL;
+
+ VMode view_mode = dbev->get_view_mode ();
+ long idx = (long) event_id;
+ Vector<void*> *values = getTLDetailValues (dbevindex, exp, data_id, view_mode, packets, idx);
+ return values;
+}
+
+Vector<Obj> *
+dbeGetStackFunctions (int dbevindex, Obj stack)
+{
+ Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, stack);
+ if (instrs == NULL)
+ return NULL;
+ int stsize = instrs->size ();
+ Vector<Obj> *jivals = new Vector<Obj>(stsize);
+ for (int i = 0; i < stsize; i++)
+ {
+ Histable *obj = (Histable*) instrs->fetch (i);
+ // if ( obj->get_type() != Histable::LINE ) {//YXXX what is this?
+ // Remove the above check: why not do this conversion for lines -
+ // otherwise filtering in timeline by function stack in omp user mode is broken
+ obj = obj->convertto (Histable::FUNCTION);
+ jivals->store (i, (Obj) obj);
+ }
+ delete instrs;
+ return jivals;
+}
+
+Vector<void*> *
+dbeGetStacksFunctions (int dbevindex, Vector<Obj> *stacks)
+{
+ long sz = stacks->size ();
+ Vector<void*> *res = new Vector<void*>(sz);
+ for (int ii = 0; ii < sz; ii++)
+ {
+ Obj stack = stacks->fetch (ii);
+ Vector<Obj> *jivals = dbeGetStackFunctions (dbevindex, stack);
+ res->store (ii, jivals);
+ }
+ return res;
+}
+
+Vector<Obj> *
+dbeGetStackPCs (int dbevindex, Obj stack)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (stack == 0)
+ return NULL;
+
+ bool show_all = dbev->isShowAll ();
+ Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stack, !show_all);
+ int stsize = instrs->size ();
+ int istart = 0;
+ bool showAll = dbev->isShowAll ();
+ for (int i = 0; i < stsize - 1; i++)
+ {
+ Function *func = (Function*) instrs->fetch (i)->convertto (Histable::FUNCTION);
+ int ix = func->module->loadobject->seg_idx;
+ if (showAll && dbev->get_lo_expand (ix) == LIBEX_API)
+ // truncate stack here: LIBRARY_VISIBILITY if we are using API only but no hide
+ istart = i;
+ }
+ stsize = stsize - istart;
+ Vector<Obj> *jlvals = new Vector<Obj>(stsize);
+ for (int i = 0; i < stsize; i++)
+ {
+ Histable *instr = instrs->fetch (i + istart);
+ jlvals->store (i, (Obj) instr);
+ }
+ delete instrs;
+ return jlvals;
+}
+
+Vector<char*> *
+dbeGetStackNames (int dbevindex, Obj stack)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, stack);
+ if (instrs == NULL)
+ return NULL;
+ int stsize = instrs->size ();
+ Vector<char*> *list = new Vector<char*>(stsize);
+ bool showAll = dbev->isShowAll ();
+ for (int i = 0; i < stsize; i++)
+ {
+ Histable* instr = (Histable*) instrs->fetch (i);
+ if (!showAll)
+ {
+ // LIBRARY_VISIBILITY
+ Function *func = (Function*) instr->convertto (Histable::FUNCTION);
+ LoadObject *lo = ((Function*) func)->module->loadobject;
+ if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+ {
+ list->store (i, dbe_strdup (lo->get_name ()));
+ continue;
+ }
+ }
+ list->store (i, dbe_strdup (instr->get_name (dbev->get_name_format ())));
+ }
+ delete instrs;
+ return list;
+}
+
+Vector<void*> *
+dbeGetSamples (int dbevindex, int exp_id, int64_t lo_idx, int64_t hi_idx)
+{
+ DataView * packets =
+ getTimelinePackets (dbevindex, exp_id, DATA_SAMPLE, PROP_EXPID);
+ if (packets == NULL || packets->getSize () == 0)
+ return NULL;
+ long lo;
+ if (lo_idx < 0)
+ lo = 0;
+ else
+ lo = (long) lo_idx;
+
+ long long max = packets->getSize () - 1;
+ long hi;
+ if (hi_idx < 0 || hi_idx > max)
+ hi = (long) max;
+ else
+ hi = (long) hi_idx;
+
+ Vector<Vector<long long>*> *sarray = new Vector<Vector<long long>*>;
+ Vector<long long>* starts = new Vector<long long>;
+ Vector<long long>* ends = new Vector<long long>;
+ Vector<long long>* rtimes = new Vector<long long>;
+ Vector<char*> *startNames = new Vector<char*>;
+ Vector<char*> *endNames = new Vector<char*>;
+ Vector<int> *sampId = new Vector<int>;
+
+ for (long index = lo; index <= hi; index++)
+ {
+ Sample *sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
+ PrUsage *prusage = sample->get_usage ();
+ if (prusage == NULL)
+ prusage = new PrUsage;
+ Vector<long long> *states = prusage->getMstateValues ();
+ sarray->append (states);
+ starts->append (sample->get_start_time ());
+ ends->append (sample->get_end_time ());
+ rtimes->append (prusage->pr_rtime);
+ startNames->append (dbe_strdup (sample->get_start_label ()));
+ endNames->append (dbe_strdup (sample->get_end_label ()));
+ sampId->append (sample->get_number ());
+ }
+ Vector<void *> *res = new Vector<void*>(6);
+ res->store (0, sarray);
+ res->store (1, starts);
+ res->store (2, ends);
+ res->store (3, rtimes);
+ res->store (4, startNames);
+ res->store (5, endNames);
+ res->store (6, sampId);
+ return res;
+}
+
+Vector<void*> *
+dbeGetGCEvents (int dbevindex, int exp_id, int64_t lo_idx, int64_t hi_idx)
+{
+ DataView *packets =
+ getTimelinePackets (dbevindex, exp_id, DATA_GCEVENT, PROP_EXPID);
+ if (packets == NULL || packets->getSize () == 0)
+ return NULL;
+
+ long lo;
+ if (lo_idx < 0)
+ lo = 0;
+ else
+ lo = (long) lo_idx;
+ long long max = packets->getSize () - 1;
+ long hi;
+ if (hi_idx < 0 || hi_idx > max)
+ hi = (long) max;
+ else
+ hi = (long) hi_idx;
+
+ Vector<long long>* starts = new Vector<long long>;
+ Vector<long long>* ends = new Vector<long long>;
+ Vector<int> *eventId = new Vector<int>;
+ for (long index = lo; index <= hi; index++)
+ {
+ GCEvent *gcevent = (GCEvent*) packets->getObjValue (PROP_GCEVENTOBJ, index);
+ if (gcevent)
+ {
+ starts->append (gcevent->start);
+ ends->append (gcevent->end);
+ eventId->append (gcevent->id);
+ }
+ }
+ Vector<void *> *res = new Vector<void*>(3);
+ res->store (0, starts);
+ res->store (1, ends);
+ res->store (2, eventId);
+ return res;
+}
+
+Vector<Vector<char*>*>*
+dbeGetIOStatistics (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ Hist_data *hist_data;
+ Hist_data::HistItem *hi;
+ FileData *fDataTotal;
+
+ hist_data = dbev->iofile_data;
+ if (hist_data == NULL)
+ return NULL;
+ hi = hist_data->fetch (0);
+ fDataTotal = (FileData*) hi->obj;
+
+ Vector<char*> *writeStat = new Vector<char*>;
+ Vector<char*> *readStat = new Vector<char*>;
+ Vector<char*> *otherStat = new Vector<char*>;
+ Vector<char*> *errorStat = new Vector<char*>;
+
+ writeStat->append (dbe_strdup (GTXT ("Write Statistics")));
+ readStat->append (dbe_strdup (GTXT ("Read Statistics")));
+ otherStat->append (dbe_strdup (GTXT ("Other I/O Statistics")));
+ errorStat->append (dbe_strdup (GTXT ("I/O Error Statistics")));
+
+ StringBuilder sb;
+ if (fDataTotal->getWriteCnt () > 0)
+ {
+ if (fDataTotal->getW0KB1KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("0KB - 1KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW0KB1KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW1KB8KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1KB - 8KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW1KB8KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW8KB32KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("8KB - 32KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW8KB32KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW32KB128KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("32KB - 128KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW32KB128KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW128KB256KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("128KB - 256KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW128KB256KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW256KB512KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("256KB - 512KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW256KB512KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW512KB1000KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("512KB - 1000KB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW512KB1000KBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW1000KB10MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1000KB - 10MB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW1000KB10MBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW10MB100MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10MB - 100MB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW10MB100MBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW100MB1GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100MB - 1GB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW100MB1GBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW1GB10GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1GB - 10GB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW1GB10GBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW10GB100GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10GB - 100GB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW10GB100GBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW100GB1TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100GB - 1TB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW100GB1TBCnt ());
+ writeStat->append (sb.toString ());
+ }
+ if (fDataTotal->getW1TB10TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1TB - 10TB"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getW1TB10TBCnt ());
+ writeStat->append (sb.toString ());
+ }
+
+ sb.sprintf (GTXT ("Longest write"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%.6f (secs.)"),
+ (double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC));
+ writeStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Smallest write bytes"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWSmallestBytes ()));
+ writeStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Largest write bytes"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWLargestBytes ()));
+ writeStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total time"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%.6f (secs.)"),
+ (double) (fDataTotal->getWriteTime () / (double) NANOSEC));
+ writeStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total calls"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWriteCnt ()));
+ writeStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total bytes"));
+ writeStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%lld"), (long long) (fDataTotal->getWriteBytes ()));
+ writeStat->append (sb.toString ());
+ }
+
+ if (fDataTotal->getReadCnt () > 0)
+ {
+ if (fDataTotal->getR0KB1KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("0KB - 1KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR0KB1KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR1KB8KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1KB - 8KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR1KB8KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR8KB32KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("8KB - 32KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR8KB32KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR32KB128KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("32KB - 128KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR32KB128KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR128KB256KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("128KB - 256KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR128KB256KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR256KB512KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("256KB - 512KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR256KB512KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR512KB1000KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("512KB - 1000KB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR512KB1000KBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR1000KB10MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1000KB - 10MB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR1000KB10MBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR10MB100MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10MB - 100MB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR10MB100MBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR100MB1GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100MB - 1GB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR100MB1GBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR1GB10GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1GB - 10GB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR1GB10GBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR10GB100GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10GB - 100GB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR10GB100GBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR100GB1TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100GB - 1TB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR100GB1TBCnt ());
+ readStat->append (sb.toString ());
+ }
+ if (fDataTotal->getR1TB10TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1TB - 10TB"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), fDataTotal->getR1TB10TBCnt ());
+ readStat->append (sb.toString ());
+ }
+
+ sb.sprintf (GTXT ("Longest read"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%.6f (secs.)"),
+ (double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC));
+ readStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Smallest read bytes"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getRSmallestBytes ()));
+ readStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Largest read bytes"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getRLargestBytes ()));
+ readStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total time"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%.6f (secs.)"),
+ (double) (fDataTotal->getReadTime () / (double) NANOSEC));
+ readStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total calls"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getReadCnt ()));
+ readStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total bytes"));
+ readStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%lld"), (long long) (fDataTotal->getReadBytes ()));
+ readStat->append (sb.toString ());
+ }
+
+ if (fDataTotal->getOtherCnt () > 0)
+ {
+ sb.sprintf (GTXT ("Total time"));
+ otherStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%.6f (secs.)"),
+ (double) (fDataTotal->getOtherTime () / (double) NANOSEC));
+ otherStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total calls"));
+ otherStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getOtherCnt ()));
+ otherStat->append (sb.toString ());
+ }
+
+ if (fDataTotal->getErrorCnt () > 0)
+ {
+ sb.sprintf (GTXT ("Total time"));
+ errorStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%.6f (secs.)"),
+ (double) (fDataTotal->getErrorTime () / (double) NANOSEC));
+ errorStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total calls"));
+ errorStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getErrorCnt ()));
+ errorStat->append (sb.toString ());
+ }
+ Vector<Vector<char*>*>* statisticsData = new Vector<Vector<char*>*>(4);
+ statisticsData->store (0, writeStat);
+ statisticsData->store (1, readStat);
+ statisticsData->store (2, otherStat);
+ statisticsData->store (3, errorStat);
+ return statisticsData;
+}
+
+Vector<Vector<char*>*>*
+dbeGetHeapStatistics (int dbevindex)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ Hist_data *hist_data;
+ Hist_data::HistItem *hi;
+ HeapData *hDataTotal;
+ hist_data = dbev->heapcs_data;
+ if (hist_data == NULL)
+ return NULL;
+
+ hi = hist_data->fetch (0);
+ hDataTotal = (HeapData*) hi->obj;
+ Vector<char*> *memoryUsage = new Vector<char*>;
+ Vector<char*> *allocStat = new Vector<char*>;
+ Vector<char*> *leakStat = new Vector<char*>;
+
+ memoryUsage->append (dbe_strdup (GTXT ("Process With Highest Peak Memory Usage")));
+ allocStat->append (dbe_strdup (GTXT ("Memory Allocations Statistics")));
+ leakStat->append (dbe_strdup (GTXT ("Memory Leaks Statistics")));
+ StringBuilder sb;
+ if (hDataTotal->getPeakMemUsage () > 0)
+ {
+ sb.sprintf (GTXT ("Heap size bytes"));
+ memoryUsage->append (sb.toString ());
+ sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getPeakMemUsage ()));
+ memoryUsage->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Experiment Id"));
+ memoryUsage->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getUserExpId ()));
+ memoryUsage->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Process Id"));
+ memoryUsage->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getPid ()));
+ memoryUsage->append (sb.toString ());
+
+ Vector<hrtime_t> *pTimestamps;
+ pTimestamps = hDataTotal->getPeakTimestamps ();
+ if (pTimestamps != NULL)
+ {
+ for (int i = 0; i < pTimestamps->size (); i++)
+ {
+ sb.sprintf (GTXT ("Time of peak"));
+ memoryUsage->append (sb.toString ());
+ sb.sprintf (NTXT ("%.3f (secs.)"), (double) (pTimestamps->fetch (i) / (double) NANOSEC));
+ memoryUsage->append (sb.toString ());
+ }
+ }
+ }
+
+ if (hDataTotal->getAllocCnt () > 0)
+ {
+ if (hDataTotal->getA0KB1KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("0KB - 1KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA0KB1KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA1KB8KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1KB - 8KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA1KB8KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA8KB32KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("8KB - 32KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA8KB32KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA32KB128KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("32KB - 128KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA32KB128KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA128KB256KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("128KB - 256KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA128KB256KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA256KB512KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("256KB - 512KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA256KB512KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA512KB1000KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("512KB - 1000KB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA512KB1000KBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA1000KB10MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1000KB - 10MB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA1000KB10MBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA10MB100MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10MB - 100MB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA10MB100MBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA100MB1GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100MB - 1GB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA100MB1GBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA1GB10GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1GB - 10GB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA1GB10GBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA10GB100GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10GB - 100GB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA10GB100GBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA100GB1TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100GB - 1TB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA100GB1TBCnt ());
+ allocStat->append (sb.toString ());
+ }
+ if (hDataTotal->getA1TB10TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1TB - 10TB"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getA1TB10TBCnt ());
+ allocStat->append (sb.toString ());
+ }
+
+ sb.sprintf (GTXT ("Smallest allocation bytes"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getASmallestBytes ()));
+ allocStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Largest allocation bytes"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getALargestBytes ()));
+ allocStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total allocations"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getAllocCnt ()));
+ allocStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total bytes"));
+ allocStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getAllocBytes ()));
+ allocStat->append (sb.toString ());
+ }
+
+ if (hDataTotal->getLeakCnt () > 0)
+ {
+ if (hDataTotal->getL0KB1KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("0KB - 1KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL0KB1KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL1KB8KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1KB - 8KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL1KB8KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL8KB32KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("8KB - 32KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL8KB32KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL32KB128KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("32KB - 128KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL32KB128KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL128KB256KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("128KB - 256KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL128KB256KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL256KB512KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("256KB - 512KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL256KB512KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL512KB1000KBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("512KB - 1000KB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL512KB1000KBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL1000KB10MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1000KB - 10MB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL1000KB10MBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL10MB100MBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10MB - 100MB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL10MB100MBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL100MB1GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100MB - 1GB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL100MB1GBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL1GB10GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1GB - 10GB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL1GB10GBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL10GB100GBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("10GB - 100GB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL10GB100GBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL100GB1TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("100GB - 1TB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL100GB1TBCnt ());
+ leakStat->append (sb.toString ());
+ }
+ if (hDataTotal->getL1TB10TBCnt () > 0)
+ {
+ sb.sprintf (GTXT ("1TB - 10TB"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), hDataTotal->getL1TB10TBCnt ());
+ leakStat->append (sb.toString ());
+ }
+
+ sb.sprintf (GTXT ("Smallest leaked bytes"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLSmallestBytes ()));
+ leakStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Largest leaked bytes"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLLargestBytes ()));
+ leakStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total leaked"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLeakCnt ()));
+ leakStat->append (sb.toString ());
+
+ sb.sprintf (GTXT ("Total bytes"));
+ leakStat->append (sb.toString ());
+ sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getLeakBytes ()));
+ leakStat->append (sb.toString ());
+ }
+ Vector<Vector<char*>*>* statisticsData = new Vector<Vector<char*>*>(3);
+ statisticsData->store (0, memoryUsage);
+ statisticsData->store (1, allocStat);
+ statisticsData->store (2, leakStat);
+ return statisticsData;
+}
+
+Vector<char*> *
+dbeGetFuncNames (int dbevindex, Vector<Obj> *funcs)
+{
+ int len = funcs->size ();
+ Vector<char*> *list = new Vector<char*>(len);
+ for (int i = 0; i < len; i++)
+ list->store (i, dbeGetFuncName (dbevindex, funcs->fetch (i))); // no strdup()
+ return list;
+}
+
+Vector<char*> *
+dbeGetObjNamesV2 (int dbevindex, Vector<uint64_t> *ids)
+{
+ int len = ids->size ();
+ Vector<char*> *list = new Vector<char*>(len);
+ for (int i = 0; i < len; i++)
+ list->store (i, dbeGetObjNameV2 (dbevindex, ids->fetch (i))); // no strdup()
+ return list;
+}
+
+char *
+dbeGetFuncName (int dbevindex, Obj func)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (func == 0)
+ return NULL;
+ char *fname;
+ fname = ((Histable *) func)->get_name (dbev->get_name_format ());
+ return fname ? dbe_strdup (fname) : NULL;
+}
+
+Vector<uint64_t> *
+dbeGetFuncIds (int dbevindex, Vector<Obj> *funcs)
+{
+ int len = funcs->size ();
+ Vector<uint64_t> *list = new Vector<uint64_t>(len);
+ for (int i = 0; i < len; i++)
+ list->store (i, dbeGetFuncId (dbevindex, funcs->fetch (i)));
+ return list;
+}
+
+uint64_t
+dbeGetFuncId (int dbevindex, Obj func)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ if (func == 0)
+ return 0;
+ uint64_t id = ((Histable *) func)->id;
+ return id;
+}
+
+char *
+dbeGetObjNameV2 (int dbevindex, uint64_t id)
+{
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Histable *obj = dbeSession->findObjectById (id);
+ if (obj == NULL)
+ return NULL;
+ char *fname = obj->get_name (dbev->get_name_format ());
+ return fname ? dbe_strdup (fname) : NULL;
+}
+
+char *
+dbeGetDataspaceTypeDesc (int /*dbevindex*/, Obj stack)
+{
+ if (stack == 0)
+ return NULL;
+ Histable *hist = CallStack::getStackPC ((void *) stack, 0);
+ DbeInstr *instr;
+ Histable::Type type = hist->get_type ();
+ if (type != Histable::INSTR)
+ return NULL;
+ else
+ instr = (DbeInstr *) hist;
+ char *descriptor = instr->get_descriptor ();
+ return descriptor ? dbe_strdup (descriptor) : NULL;
+}
+
+Vector<void*> *
+dbeGetDataDescriptorsV2 (int exp_id)
+{
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ if (exp == NULL)
+ return NULL;
+ Vector<int> *dataId = new Vector<int>;
+ Vector<char*> *dataName = new Vector<char*>;
+ Vector<char*> *dataUName = new Vector<char*>;
+ Vector<int> *auxProp = new Vector<int>;
+ Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+ for (int i = 0; i < ddscr->size (); i++)
+ {
+ DataDescriptor *dataDscr = ddscr->fetch (i);
+ if (dataDscr->getFlags () & DDFLAG_NOSHOW)
+ continue;
+ int data_id = dataDscr->getId ();
+ int aux_prop_id = (data_id == DATA_HWC) ? PROP_HWCTAG : PROP_NONE;
+ dataId->append (data_id);
+ dataName->append (strdup (dataDscr->getName ()));
+ dataUName->append (strdup (dataDscr->getUName ()));
+ auxProp->append (aux_prop_id);
+ }
+ delete ddscr;
+ Vector<void*> *res = new Vector<void*>(3);
+ res->store (0, dataId);
+ res->store (1, dataName);
+ res->store (2, dataUName);
+ res->store (3, auxProp);
+ return res;
+}
+
+Vector<void*> *
+dbeGetDataPropertiesV2 (int exp_id, int data_id)
+{
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ if (exp == NULL)
+ return NULL;
+ DataDescriptor *dataDscr = exp->get_raw_events (data_id);
+ if (dataDscr == NULL)
+ return NULL;
+ Vector<PropDescr*> *props = dataDscr->getProps ();
+ Vector<int> *propId = new Vector<int>(props->size ());
+ Vector<char*> *propUName = new Vector<char*>(props->size ());
+ Vector<int> *propTypeId = new Vector<int>(props->size ());
+ Vector<char*> *propTypeName = new Vector<char*>(props->size ());
+ Vector<int> *propFlags = new Vector<int>(props->size ());
+ Vector<char*> *propName = new Vector<char*>(props->size ());
+ Vector<void*> *propStateNames = new Vector<void*>(props->size ());
+ Vector<void*> *propStateUNames = new Vector<void*>(props->size ());
+
+ for (int i = 0; i < props->size (); i++)
+ {
+ PropDescr *prop = props->fetch (i);
+ char *pname = prop->name;
+ if (pname == NULL)
+ pname = NTXT ("");
+ char *uname = prop->uname;
+ if (uname == NULL)
+ uname = pname;
+ int vtypeNum = prop->vtype;
+ if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
+ vtypeNum = TYPE_NONE;
+ const char * vtypeNames[] = VTYPE_TYPE_NAMES;
+ const char *vtype = vtypeNames[prop->vtype];
+ Vector<char*> *stateNames = NULL;
+ Vector<char*> *stateUNames = NULL;
+ int nStates = prop->getMaxState ();
+ if (nStates > 0)
+ {
+ stateNames = new Vector<char*>(nStates);
+ stateUNames = new Vector<char*>(nStates);
+ for (int kk = 0; kk < nStates; kk++)
+ {
+ const char * stateName = prop->getStateName (kk);
+ stateNames->store (kk, dbe_strdup (stateName));
+ const char * Uname = prop->getStateUName (kk);
+ stateUNames->store (kk, dbe_strdup (Uname));
+ }
+ }
+ propId->store (i, prop->propID);
+ propUName->store (i, dbe_strdup (uname));
+ propTypeId->store (i, prop->vtype);
+ propTypeName->store (i, dbe_strdup (vtype));
+ propFlags->store (i, prop->flags);
+ propName->store (i, dbe_strdup (pname));
+ propStateNames->store (i, stateNames);
+ propStateUNames->store (i, stateUNames);
+ }
+ Vector<void*> *res = new Vector<void*>(7);
+ res->store (0, propId);
+ res->store (1, propUName);
+ res->store (2, propTypeId);
+ res->store (3, propTypeName);
+ res->store (4, propFlags);
+ res->store (5, propName);
+ res->store (6, propStateNames);
+ res->store (7, propStateUNames);
+ return res;
+}
+
+Vector<void *> *
+dbeGetExperimentTimeInfo (Vector<int> *exp_ids)
+{
+ int sz = exp_ids->size ();
+ Vector<long long> *offset_time = new Vector<long long> (sz);
+ Vector<long long> *start_time = new Vector<long long> (sz);
+ Vector<long long> *end_time = new Vector<long long> (sz);
+ Vector<long long> *start_wall_sec = new Vector<long long> (sz);
+ Vector<char* > *hostname = new Vector<char*> (sz);
+ Vector<int> *cpu_freq = new Vector<int> (sz);
+ for (int ii = 0; ii < sz; ii++)
+ {
+ int expIdx = exp_ids->fetch (ii);
+ { // update end_time by forcing fetch of experiment data
+ // workaround until dbeGetEndTime() is more robust
+ int id = (expIdx < 0) ? 0 : expIdx;
+ Experiment *exp = dbeSession->get_exp (id);
+ if (exp)
+ {
+ Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+ delete ddscr;
+ }
+ }
+ offset_time->store (ii, dbeGetRelativeStartTime (0, expIdx));
+ start_time->store (ii, dbeGetStartTime (0, expIdx));
+ end_time->store (ii, dbeGetEndTime (0, expIdx));
+ start_wall_sec->store (ii, dbeGetWallStartSec (0, expIdx));
+ hostname->store (ii, dbeGetHostname (0, expIdx));
+ cpu_freq->store (ii, dbeGetClock (0, expIdx));
+ }
+ Vector<void*> *res = new Vector<void*>(4);
+ res->store (0, offset_time);
+ res->store (1, start_time);
+ res->store (2, end_time);
+ res->store (3, start_wall_sec);
+ res->store (4, hostname);
+ res->store (5, cpu_freq);
+ return res;
+}
+
+Vector<void *> *
+dbeGetExperimentDataDescriptors (Vector<int> *exp_ids)
+{
+ int sz = exp_ids->size ();
+ Vector<void*> *exp_dscr_info = new Vector<void*> (sz);
+ Vector<void*> *exp_dscr_props = new Vector<void*> (sz);
+
+ for (int ii = 0; ii < sz; ii++)
+ {
+ int expIdx = exp_ids->fetch (ii);
+ Vector<void*> *ddscrInfo = dbeGetDataDescriptorsV2 (expIdx);
+ Vector<void*> *ddscrProps = new Vector<void*> (); // one entry per ddscrInfo
+ if (ddscrInfo)
+ {
+ Vector<int> *dataId = (Vector<int>*)ddscrInfo->fetch (0);
+ if (dataId)
+ {
+ // loop thru data descriptors
+ int ndata = dataId->size ();
+ for (int j = 0; j < ndata; ++j)
+ {
+ Vector<void*> *props = dbeGetDataPropertiesV2 (expIdx, dataId->fetch (j));
+ ddscrProps->store (j, props);
+ }
+ }
+ }
+ exp_dscr_info->store (ii, ddscrInfo);
+ exp_dscr_props->store (ii, ddscrProps);
+ }
+ Vector<void*> *res = new Vector<void*>(2);
+ res->store (0, exp_dscr_info);
+ res->store (1, exp_dscr_props);
+ return res;
+}
+
+static Vector<void *> *
+dbeGetTLDataRepVals (VMode view_mode, hrtime_t start_ts, hrtime_t delta,
+ int numDeltas, DataView*packets,
+ Vector<long> *representativeEvents, bool showDuration);
+
+static bool
+dbeHasTLData (int dbevindex, int exp_id, int data_id, int entity_prop_id,
+ int entity_prop_value, int aux)
+{
+ DataView *packets =
+ getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id);
+ if (!packets || packets->getSize () == 0)
+ return false;
+ long start_ind = getIdxByVals (packets, aux, entity_prop_value,
+ 0, DataView::REL_GTEQ); // time >= 0
+ if (start_ind < 0)
+ return false;
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ VMode view_mode = dbev->get_view_mode ();
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ if (!hasInvisbleTLEvents (exp, view_mode))
+ return true; // all events are visible, no further checking required
+ long end_ind = getIdxByVals (packets, aux, entity_prop_value,
+ MAX_TIME, DataView::REL_LTEQ);
+ for (long ii = start_ind; ii <= end_ind; ii++)
+ {
+ if (!isVisibleTLEvent (exp, view_mode, packets, ii))
+ continue;
+ return true; // first visible packet => has data
+ }
+ return false;
+}
+
+Vector<bool> *
+dbeHasTLData (int dbev_index, Vector<int> *exp_ids, Vector<int> *data_ids,
+ Vector<int> *entity_prop_ids, // LWP,CPU,THR, etc
+ Vector<int> *entity_prop_values, Vector<int> *auxs)
+{
+ DbeView *dbev = dbeSession->getView (dbev_index);
+ if (!dbev->isShowAll () && (dbev->isShowHideChanged ()
+ || dbev->isNewViewMode ()))
+ {
+ // LIBRARY_VISIBILITY
+ dbev->resetAndConstructShowHideStacks ();
+ if (dbev->isNewViewMode ())
+ dbev->resetNewViewMode ();
+ if (dbev->isShowHideChanged ())
+ dbev->resetShowHideChanged ();
+ }
+
+ int sz = exp_ids->size ();
+ Vector<bool> *hasVec = new Vector<bool>(sz);
+ for (int ii = 0; ii < sz; ii++)
+ {
+ bool hasData = dbeHasTLData (dbev_index, exp_ids->fetch (ii),
+ data_ids->fetch (ii),
+ entity_prop_ids->fetch (ii),
+ entity_prop_values->fetch (ii),
+ auxs->fetch (ii));
+ hasVec->store (ii, hasData);
+ }
+ return hasVec;
+}
+
+/*
+ * dbeGetTLData implements:
+ * FROM data_id
+ * DURATION >= delta AND ( start_ts <= TSTAMP < start_ts+num*delta OR
+ * start_ts <= TSTAMP-DURATION < start_ts+num*delta )
+ * OR
+ * FAIR( DURATION < delta AND ( start_ts <= TSTAMP < start_ts+num*delta ) )
+ * WHERE lfilter
+ */
+
+Vector<void *> *
+dbeGetTLData (
+ int dbevindex,
+ int exp_id,
+ int data_id, // DATA_*
+ int entity_prop_id, // Show PROP_LWPID, PROP_CPUID, PROP_THRID, PROP_EXPID, or N/A
+ int entity_prop_value, // which LWPID, CPUID, THRID, EXPID for this request
+ int aux,
+ hrtime_t param_start_ts,
+ hrtime_t param_delta,
+ int param_numDeltas,
+ bool getRepresentatives, // fetch TL representatives
+ Vector<char *> *chartProps) // calculate sums for these property vals
+{
+ const hrtime_t start_ts = param_start_ts;
+ const hrtime_t delta = param_delta;
+ const int numDeltas = param_numDeltas;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ if (dbev == NULL)
+ abort ();
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ if (exp == NULL)
+ return NULL;
+ if (getRepresentatives == false && chartProps == NULL)
+ return NULL;
+ if (delta <= 0)
+ return NULL;
+
+ hrtime_t tmp_ts = start_ts + delta * numDeltas;
+ if (tmp_ts < start_ts)
+ tmp_ts = MAX_TIME;
+ const hrtime_t end_ts = tmp_ts;
+ if (exp->get_status () == Experiment::INCOMPLETE &&
+ exp->getLastEvent () < end_ts)
+ exp->update ();
+ DataView *packets =
+ getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id);
+ if (packets == NULL)
+ return NULL; // strange, no data view?
+
+ VMode view_mode = dbev->get_view_mode (); // user, expert, machine //YXXX yuck
+
+ // storage for calculating timeline representative events
+ Vector<long> *representativeEvents = NULL;
+ // list of representative events to be displayed on TL
+ Vector<int> *binRepIdx = NULL;
+ // for each bin, index of current "best" representativeEvent
+ Vector<void*> *representativeVals = NULL;
+ // TL representative packets' values
+
+ // storage for calculating charts
+ Vector<int> *propIds = NULL; // [propIdx], which prop to measure
+ Vector<void*> *propVals = NULL; // [propIdx][bin], prop vals
+ Vector<int> *propNumStates = NULL; // [propIdx], how many states for prop?
+ Vector<bool> *propCumulativeChart = NULL; // [propIdx], data represents cumulative totals
+ Vector<long long> *propCumulativeRecentBinLastVal = NULL; // [propIdx], most recent value
+ Vector<long long> *propCumulativeRecentBinHighVal = NULL; // [propIdx], highest value for propCumulativeRecentBin
+ Vector<int> *propCumulativeRecentBin = NULL; // [propIdx], most recent bin
+
+ // determine when to show duration of events
+ bool tmp_repsShowDuration = false;
+ bool tmp_statesUseDuration = false;
+ bool tmp_extendMicrostates = false;
+ const hrtime_t ptimerTickDuration = exp->get_params ()->ptimer_usec * 1000LL; // nanoseconds per tick
+ const bool hasDuration = packets->getProp (PROP_EVT_TIME) ? true : false;
+ if (hasDuration)
+ {
+ switch (entity_prop_id)
+ {
+ case PROP_CPUID:
+ tmp_repsShowDuration = false;
+ tmp_statesUseDuration = false;
+ break;
+ case PROP_THRID:
+ case PROP_LWPID:
+ tmp_repsShowDuration = true;
+ tmp_statesUseDuration = true;
+ tmp_extendMicrostates = (DATA_CLOCK == data_id) && (ptimerTickDuration < param_delta);
+ break;
+ case PROP_EXPID:
+ case PROP_NONE: // experiment summary row uses this
+ default:
+ if (DATA_SAMPLE == data_id)
+ {
+ tmp_repsShowDuration = true;
+ tmp_statesUseDuration = true;
+ }
+ else if (DATA_GCEVENT == data_id)
+ {
+ tmp_repsShowDuration = true;
+ tmp_statesUseDuration = true;
+ }
+ else if (DATA_CLOCK == data_id)
+ {
+ tmp_repsShowDuration = false;
+ tmp_statesUseDuration = true;
+ tmp_extendMicrostates = true;
+ }
+ else
+ {
+ tmp_repsShowDuration = false;
+ tmp_statesUseDuration = true;
+ }
+ break;
+ }
+ }
+ const bool repsShowDuration = tmp_repsShowDuration; // show stretched callstacks
+ const bool statesUseDuration = tmp_statesUseDuration; // use duration to calculate state charts
+ const bool extendMicrostates = tmp_extendMicrostates; // we show discrete profiling microstates with
+ // width=(tick-1), but for computing
+ // zoomed-out graphs we need to extend to
+ // account for all ticks, width=(ntick)
+ const bool reverseScan = repsShowDuration || extendMicrostates; // scan packets in reverse
+
+ // determine range of packet indices (lo_pkt_idx, hi_pkt_idx)
+ long lo_pkt_idx, hi_pkt_idx;
+ if (extendMicrostates && !(entity_prop_id == PROP_THRID || entity_prop_id == PROP_LWPID))
+ {
+ // merging data from multiple threads, need to scan all packets with timestamp [start_ts, exp end]
+ hrtime_t exp_end_time = exp->getLastEvent () + 1;
+ hi_pkt_idx = getIdxByVals (packets, aux, entity_prop_value,
+ exp_end_time, DataView::REL_LT); // last item
+ }
+ else
+ hi_pkt_idx = getIdxByVals (packets, aux, entity_prop_value,
+ end_ts, DataView::REL_LT);
+ if (repsShowDuration)
+ {
+ // There are two issues to deal with
+ // 1. events that end "off screen" to the right
+ // 2. overlapping events
+
+ // 1. events that end "off screen" to the right
+ // For now, we only consistently handle the case where events don't overlap.
+ // Note that packet timestamps mark end of duration, not start.
+ // This means that the rightmost event won't be within hi_pkt_idx.
+ // Solution: Check if end+1 packet _started_ in-range
+ // Caveat: because we only look ahead by one packet, if there are
+ // overlapping duration events (e.g. EXPID aggregation)), zoom level
+ // and panning combo may cause events with TSTAMP>end_ts
+ // to appear/disappear. A complete solution would involve
+ // a solution to 2.
+
+ // 2. overlapping events
+ // For now, we have a simplistic solution that makes "wide" events win. However,
+ // a future solution for deterministically dealing with overlap might look like this:
+ // - find all packets that touch the visible time range
+ // - possibly use two DataViews: one with TSTAMP_HI sort and one with TSTAMP_LO
+ // sort to allow efficient determination of packets with HI and LO endpoints in-range
+ // - create buckets to capture "winning" event for each bin (each pixel, that is)
+ // - sort the new list of packets by TSTAMP_HI (for example)
+ // - looping thru the packets that are in-range, update every bin it touches with it's id
+ // - if there is overlap, earlier packets will be kicked out of bins
+ // - On the GUI side, paint one event at a time, as normal.
+ // - However, for selections, recognize that duration of event may span many bins
+ //
+ long idx;
+ if (hi_pkt_idx >= 0)
+ // a packet was found to the left of the end time
+ idx = hi_pkt_idx + 1; // attempt to go one packet right
+ else
+ idx = getIdxByVals (packets, aux, entity_prop_value,
+ end_ts, DataView::REL_GTEQ);
+ if (isValidIdx (packets, entity_prop_id, aux, entity_prop_value, idx))
+ {
+ int64_t pkt_ts = packets->getLongValue (PROP_TSTAMP, idx);
+ int64_t duration = packets->getLongValue (PROP_EVT_TIME, idx);
+ pkt_ts -= duration;
+ if (pkt_ts < end_ts)
+ hi_pkt_idx = idx;
+ }
+ }
+ lo_pkt_idx = getIdxByVals (packets, aux, entity_prop_value,
+ start_ts, DataView::REL_GTEQ);
+
+ // allocate structs that return chart data
+ bool hasCumulativeCharts = false;
+ if (chartProps && chartProps->size () > 0)
+ {
+ int nprops = chartProps->size ();
+ // pre-allocate storage
+ propIds = new Vector<int> (nprops);
+ propVals = new Vector<void*>(nprops);
+ propNumStates = new Vector<int> (nprops);
+ propCumulativeChart = new Vector<bool>(nprops);
+ propCumulativeRecentBinLastVal = new Vector<long long>(nprops);
+ propCumulativeRecentBinHighVal = new Vector<long long>(nprops);
+ propCumulativeRecentBin = new Vector<int>(nprops);
+ for (int propNum = 0; propNum < nprops; propNum++)
+ {
+ const char* propStr = chartProps->fetch (propNum);
+ int items_per_prop = 0;
+ int prop_id = PROP_NONE;
+ if (!strcmp (propStr, "EVT_COUNT"))
+ items_per_prop = 1; // use PROP_NONE for counting packets
+ else
+ {
+ int lookup_prop_id = dbeSession->getPropIdByName (propStr);
+ PropDescr *propDscr = packets->getProp (lookup_prop_id);
+ if (propDscr != NULL)
+ {
+ switch (propDscr->vtype)
+ {
+ case TYPE_INT32:
+ case TYPE_UINT32:
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ items_per_prop = propDscr->getMaxState () + 1;
+ // add extra slot to store values with out-of-range idx
+ prop_id = lookup_prop_id;
+ break;
+ case TYPE_DOUBLE:
+ break; // not implemented yet
+ case TYPE_STRING:
+ case TYPE_OBJ:
+ case TYPE_DATE:
+ default:
+ break;
+ }
+ }
+ }
+ void *vals;
+ if (!items_per_prop)
+ vals = NULL;
+ else if (items_per_prop == 1)
+ {
+ Vector<long long> *longVals = new Vector<long long> ();
+ longVals->store (numDeltas - 1, 0); // initialize all elements
+ vals = longVals;
+ }
+ else
+ {
+ Vector<Vector<long long>*> *stateVals =
+ new Vector<Vector<long long>*> ();
+ vals = stateVals;
+ // initialize only on-demand, some may not be needed
+ }
+
+ bool isCumulativeChart;
+#define YXXX_HEAP_VS_TIME 1 // YXXX add data meaning to properties?
+#if YXXX_HEAP_VS_TIME
+ isCumulativeChart = (prop_id == PROP_HCUR_LEAKS || prop_id == PROP_HCUR_ALLOCS);
+#endif
+ if (isCumulativeChart)
+ hasCumulativeCharts = true;
+ propIds->store (propNum, prop_id);
+ propVals->store (propNum, vals);
+ propNumStates->store (propNum, items_per_prop);
+ propCumulativeRecentBinLastVal->store (propNum, 0);
+ propCumulativeRecentBinHighVal->store (propNum, 0);
+ propCumulativeRecentBin->store (propNum, 0);
+ propCumulativeChart->store (propNum, isCumulativeChart);
+ }
+ }
+
+ // Adjust idx range for calculating 'cumulative charts' e.g. heap size
+ if (hasCumulativeCharts)
+ {
+ // set initial values if earlier packet exists
+ long lo_idx;
+ if (lo_pkt_idx >= 0)
+ // packet was found to the right of start
+ lo_idx = lo_pkt_idx - 1; // attempt to go left by one event
+ else
+ // no packet was to the right of start, look left of start
+ lo_idx = getIdxByVals (packets, aux, entity_prop_value,
+ start_ts, DataView::REL_LT);
+ if (isValidIdx (packets, entity_prop_id, aux, entity_prop_value, lo_idx))
+ {
+ // preceding packet found
+ // update initial values
+ int nprops = propCumulativeChart->size ();
+ for (int propNum = 0; propNum < nprops; propNum++)
+ {
+ if (!propCumulativeChart->fetch (propNum))
+ continue;
+ int propId = propIds->fetch (propNum);
+ long long value = packets->getLongValue (propId, lo_idx);
+ propCumulativeRecentBinLastVal->store (propNum, value);
+ propCumulativeRecentBinHighVal->store (propNum, value);
+ }
+ // update indices used for iterating
+ lo_pkt_idx = lo_idx;
+ if (hi_pkt_idx < lo_pkt_idx)
+ hi_pkt_idx = lo_pkt_idx;
+ }
+ }
+ if (lo_pkt_idx < 0 || hi_pkt_idx < 0)
+ goto dbeGetTLData_done; // no data; return empty vectors, not null
+
+ // representative events (subset of callstacks to represent on TL)
+ if (getRepresentatives)
+ {
+ representativeEvents = new Vector<long>(numDeltas);
+ // per-bin, longest event's index
+ binRepIdx = new Vector<int>(numDeltas);
+ for (int ii = 0; ii < numDeltas; ++ii)
+ binRepIdx->append (-1);
+ }
+ // While packets are sorted by _end_ timestamp (TSTAMP),
+ // after calculating start times for non-zero durations,
+ // start times are not guaranteed be monotonically increasing.
+ // For packets with duration, we'll scan them in reverse order to
+ // take advantage of the monotonically decreasing _end_ timestamps.
+ long start_idx, idx_inc;
+ if (!reverseScan)
+ {
+ start_idx = lo_pkt_idx;
+ idx_inc = 1;
+ }
+ else
+ {
+ start_idx = hi_pkt_idx;
+ idx_inc = -1;
+ }
+ for (long ii = start_idx; ii >= lo_pkt_idx && ii <= hi_pkt_idx; ii += idx_inc)
+ {
+ if (!isVisibleTLEvent (exp, view_mode, packets, ii) && !hasCumulativeCharts)
+ continue;
+
+ // determine packet time duration and start bin
+ int tmp_start_bin; // packet start bin
+ int tmp_end_bin; // packet end bin (inclusive)
+ const hrtime_t pkt_end_ts = packets->getLongValue (PROP_TSTAMP, ii);
+ const hrtime_t pkt_dur = packets->getLongValue (PROP_EVT_TIME, ii);
+ const hrtime_t pkt_start_ts = pkt_end_ts - pkt_dur;
+ if (pkt_end_ts < start_ts && !hasCumulativeCharts)
+ continue; // weird, should not happen
+ if (pkt_start_ts >= end_ts)
+ continue; // could happen
+ hrtime_t bin_end_ts = pkt_end_ts;
+ if (bin_end_ts >= end_ts)
+ bin_end_ts = end_ts - 1;
+ tmp_end_bin = (int) ((bin_end_ts - start_ts) / delta);
+ hrtime_t bin_start_ts = pkt_start_ts;
+ if (bin_start_ts < start_ts)
+ bin_start_ts = start_ts; // event truncated to left.
+ tmp_start_bin = (int) ((bin_start_ts - start_ts) / delta);
+ // By definition
+ // (end_ts - start_ts) == delta * numDeltas
+ // and we know
+ // pkt_start < end_ts
+ // therefore
+ // (pkt_start - start_ts) < delta * numDeltas
+ // (pkt_start - start_ts) / delta < numDeltas
+ // bin < numDeltas
+ assert (tmp_end_bin < numDeltas);
+ assert (tmp_start_bin < numDeltas);
+ const bool is_offscreen = tmp_end_bin < 0 ? true : false;
+ if (tmp_end_bin < 0)
+ tmp_end_bin = 0;
+ const int pkt_end_bin = tmp_end_bin; // packet end bin (inclusive)
+ const int pkt_start_bin = tmp_start_bin;
+ if (getRepresentatives && !is_offscreen)
+ { // find best representative
+ // Note: for events with duration, we're scanning packets in order
+ // of decreasing end-timestamp. This means that the first packet
+ // that hits a particular _start_ bin will have the longest duration
+ // of any later packet that might hit that start bin. The
+ // the first packet will be the best (longest) packet.
+ const int bin = reverseScan ? pkt_start_bin : pkt_end_bin;
+ int eventIdx = binRepIdx->fetch (bin);
+ if (eventIdx == -1)
+ {
+ eventIdx = representativeEvents->size (); // append to end
+ representativeEvents->append (ii);
+ binRepIdx->store (bin, eventIdx);
+ }
+ }
+ if (propIds)
+ { // per-bin chart: sum across filtered packets
+ for (int propNum = 0; propNum < propIds->size (); propNum++)
+ {
+ void *thisProp = propVals->fetch (propNum);
+ if (thisProp == NULL)
+ continue; // no valid data
+ if (is_offscreen && !propCumulativeChart->fetch (propNum))
+ continue; // offscreen events are only processed for cumulative charts
+ int propId = propIds->fetch (propNum);
+ long long val;
+ if (propId == PROP_NONE)
+ val = 1; // count
+ else
+ val = packets->getLongValue (propId, ii);
+ long nitems = propNumStates->fetch (propNum);
+ if (nitems < 1)
+ continue;
+ else if (nitems == 1)
+ {
+ // chart is not based on not multiple states
+ Vector<long long>* thisPropVals =
+ (Vector<long long>*)thisProp;
+ if (thisPropVals->size () == 0)
+ thisPropVals->store (numDeltas - 1, 0);
+ const int bin = statesUseDuration ? pkt_start_bin : pkt_end_bin;
+ if (!propCumulativeChart->fetch (propNum))
+ {
+ val += thisPropVals->fetch (bin);
+ thisPropVals->store (bin, val);
+ }
+ else
+ {
+ // propCumulativeChart
+ long long high_value = propCumulativeRecentBinHighVal->fetch (propNum);
+ int last_bin = propCumulativeRecentBin->fetch (propNum);
+ if (last_bin < bin)
+ {
+ // backfill from previous event
+ // last_bin: store largest value (in case of multiple events)
+ thisPropVals->store (last_bin, high_value);
+ // propagate forward the bin's last value
+ long long last_value = propCumulativeRecentBinLastVal->fetch (propNum);
+ for (int kk = last_bin + 1; kk < bin; kk++)
+ thisPropVals->store (kk, last_value);
+ // prepare new bin for current event
+ high_value = 0; // high value of next bin is 0.
+ propCumulativeRecentBinHighVal->store (propNum, high_value);
+ propCumulativeRecentBin->store (propNum, bin);
+ }
+ long long this_value = packets->getLongValue (propId, ii);
+ propCumulativeRecentBinLastVal->store (propNum, this_value);
+ if (high_value < this_value)
+ {
+ // record the max
+ high_value = this_value;
+ propCumulativeRecentBinHighVal->store (propNum, high_value);
+ }
+ if (ii == hi_pkt_idx)
+ {
+ // bin: show largest value (in case of multiple events
+ thisPropVals->store (bin, high_value);
+ //forward fill remaining bins
+ for (int kk = bin + 1; kk < numDeltas; kk++)
+ thisPropVals->store (kk, this_value);
+ }
+ }
+ }
+ else
+ {
+ // means val is actually a state #
+ Vector<Vector<long long>*>* thisPropStateVals =
+ (Vector<Vector<long long>*>*)thisProp;
+ if (thisPropStateVals->size () == 0)
+ thisPropStateVals->store (numDeltas - 1, 0);
+ long stateNum;
+ if (val >= 0 && val < nitems)
+ stateNum = (long) val;
+ else
+ stateNum = nitems - 1; // out of range, use last slot
+ hrtime_t graph_pkt_dur = pkt_dur;
+ hrtime_t graph_pkt_start_ts = pkt_start_ts;
+ int tmp2_start_bin = pkt_start_bin;
+ if (propId == PROP_MSTATE)
+ {
+ if (statesUseDuration && extendMicrostates)
+ {
+ // microstate stacks are shown and filtered with width=NTICK-1
+ // but for microstate graph calcs use width=NTICK.
+ graph_pkt_dur += ptimerTickDuration;
+ graph_pkt_start_ts -= ptimerTickDuration;
+ hrtime_t bin_start_ts = graph_pkt_start_ts;
+ if (bin_start_ts < start_ts)
+ bin_start_ts = start_ts; // event truncated to left.
+ tmp2_start_bin = (int) ((bin_start_ts - start_ts) / delta);
+ }
+ }
+ const int graph_pkt_start_bin = statesUseDuration ? tmp2_start_bin : pkt_end_bin;
+
+ // We will distribute the state's presence evenly over duration of the event.
+ // When only a 'partial bin' is touched by an event, adjust accordingly.
+ long long value_per_bin; // weight to be applied to each bin
+ {
+ long long weight;
+ if (propId == PROP_MSTATE) // ticks to nanoseconds
+ weight = packets->getLongValue (PROP_NTICK, ii) * ptimerTickDuration;
+ else if (graph_pkt_dur)
+ weight = graph_pkt_dur; // nanoseconds
+ else
+ weight = 1; // no duration; indicate presence
+ if (graph_pkt_start_bin != pkt_end_bin)
+ {
+ // spans multiple bins
+ double nbins = (double) graph_pkt_dur / delta;
+ value_per_bin = weight / nbins;
+ }
+ else
+ value_per_bin = weight;
+ }
+ for (int evtbin = graph_pkt_start_bin; evtbin <= pkt_end_bin; evtbin++)
+ {
+ Vector<long long>* stateValues =
+ (Vector<long long>*) thisPropStateVals->fetch (evtbin);
+ if (stateValues == NULL)
+ {
+ // on-demand storage
+ stateValues = new Vector<long long>(nitems);
+ stateValues->store (nitems - 1, 0); // force memset of full vector
+ thisPropStateVals->store (evtbin, stateValues);
+ }
+ long long new_val = stateValues->fetch (stateNum);
+ if (graph_pkt_start_bin == pkt_end_bin ||
+ (evtbin > graph_pkt_start_bin && evtbin < pkt_end_bin))
+ {
+ new_val += value_per_bin;
+ }
+ else
+ {
+ // partial bin
+ const hrtime_t bin_start = start_ts + evtbin * delta;
+ const hrtime_t bin_end = start_ts + (evtbin + 1) * delta - 1;
+ if (evtbin == graph_pkt_start_bin)
+ {
+ // leftmost bin
+ if (graph_pkt_start_ts < bin_start)
+ new_val += value_per_bin;
+ else
+ {
+ double percent = (double) (bin_end - graph_pkt_start_ts) / delta;
+ new_val += value_per_bin*percent;
+ }
+ }
+ else
+ {
+ // rightmost bin
+ if (pkt_end_ts > bin_end)
+ new_val += value_per_bin;
+ else
+ {
+ double percent = (double) (pkt_end_ts - bin_start) / delta;
+ new_val += value_per_bin*percent;
+ }
+ }
+ }
+ stateValues->store (stateNum, new_val);
+ }
+ }
+ }
+ }
+ }
+ delete binRepIdx;
+ delete propIds;
+ delete propCumulativeChart;
+ delete propCumulativeRecentBinLastVal;
+ delete propCumulativeRecentBinHighVal;
+ delete propCumulativeRecentBin;
+ if (representativeEvents != NULL && reverseScan)
+ {
+ if (repsShowDuration)
+ {
+ //YXXX for now prune here, but in the future, let gui decide what to show
+ // Prune events that are completely obscured long duration events.
+ // Note: representativeEvents is sorted by decreasing _end_ timestamps.
+ Vector<long> *prunedEvents = new Vector<long>(numDeltas);
+ hrtime_t prev_start_ts = MAX_TIME;
+ long repCnt = representativeEvents->size ();
+ for (long kk = 0; kk < repCnt; kk++)
+ {
+ long ii = representativeEvents->fetch (kk);
+ hrtime_t tmp_end_ts = packets->getLongValue (PROP_TSTAMP, ii);
+ hrtime_t tmp_dur = packets->getLongValue (PROP_EVT_TIME, ii);
+ hrtime_t tmp_start_ts = tmp_end_ts - tmp_dur;
+ if (tmp_start_ts >= prev_start_ts)
+ // this event would be completely hidden
+ // (because of sorting, we know tmp_end_ts <= prev_end_ts)
+ continue;
+ prev_start_ts = tmp_start_ts;
+ prunedEvents->append (ii);
+ }
+ // invert order to to get increasing _end_ timestamps
+ representativeEvents->reset ();
+ for (long kk = prunedEvents->size () - 1; kk >= 0; kk--)
+ {
+ long packet_idx = prunedEvents->fetch (kk);
+ representativeEvents->append (packet_idx);
+ }
+ delete prunedEvents;
+ }
+ else
+ { // !repsShowDuration
+ // Note: representativeEvents is sorted by decreasing _end_ timestamps.
+ // Reverse the order:
+ long hi_idx = representativeEvents->size () - 1;
+ long lo_idx = 0;
+ while (hi_idx > lo_idx)
+ {
+ // swap
+ long lo = representativeEvents->fetch (lo_idx);
+ long hi = representativeEvents->fetch (hi_idx);
+ representativeEvents->store (lo_idx, hi);
+ representativeEvents->store (hi_idx, lo);
+ hi_idx--;
+ lo_idx++;
+ }
+ }
+ }
+
+dbeGetTLData_done:
+ if (getRepresentatives)
+ {
+ representativeVals = dbeGetTLDataRepVals (view_mode, start_ts, delta,
+ numDeltas, packets, representativeEvents, repsShowDuration);
+ delete representativeEvents;
+ }
+ Vector<void*> *results = new Vector<void*> (2);
+ results->store (0, representativeVals);
+ results->store (1, propVals);
+ return results;
+}
+
+// add representative events to return buffer
+
+static Vector<void *> *
+dbeGetTLDataRepVals (VMode view_mode, hrtime_t start_ts, hrtime_t delta,
+ int numDeltas, DataView*packets,
+ Vector<long> *representativeEvents, bool showDuration)
+{
+ int numrecs = representativeEvents ? representativeEvents->size () : 0;
+ // allocate storage for results
+ Vector<int> *startBins = new Vector<int>(numrecs);
+ Vector<int> *numBins = new Vector<int>(numrecs);
+ Vector<Obj> *eventIdxs = new Vector<Obj>(numrecs);
+ Vector<Obj> *stackIds = NULL;
+ if (packets->getProp (PROP_FRINFO))
+ stackIds = new Vector<Obj>(numrecs);
+ Vector<int> *mstates = NULL;
+ if (packets->getProp (PROP_MSTATE))
+ mstates = new Vector<int>(numrecs);
+ Vector<Vector<long long>*> *sampleVals = NULL;
+ if (packets->getProp (PROP_SMPLOBJ))
+ sampleVals = new Vector<Vector<long long>*>(numrecs);
+ Vector<long long> *timeStart = new Vector<long long>(numrecs);
+ Vector<long long> *timeEnd = new Vector<long long>(numrecs);
+ int prevEndBin = -1; // make sure we don't overlap bins
+ for (int eventIdx = 0; eventIdx < numrecs; eventIdx++)
+ {
+ long packetIdx = representativeEvents->fetch (eventIdx);
+ // long eventId = packets->getIdByIdx( packetIdx );
+ const hrtime_t pkt_tstamp = packets->getLongValue (PROP_TSTAMP, packetIdx);
+ const hrtime_t pkt_dur = showDuration ? packets->getLongValue (PROP_EVT_TIME, packetIdx) : 0;
+ timeStart->store (eventIdx, pkt_tstamp - pkt_dur);
+ timeEnd->store (eventIdx, pkt_tstamp);
+
+ // calc startBin
+ int startBin = (int) ((pkt_tstamp - pkt_dur - start_ts) / delta);
+ if (startBin <= prevEndBin)
+ startBin = prevEndBin + 1;
+ // calc binCnt
+ int endBin = (int) ((pkt_tstamp - start_ts) / delta);
+ if (endBin >= numDeltas)
+ endBin = numDeltas - 1;
+ int binCnt = endBin - startBin + 1;
+ prevEndBin = endBin;
+ startBins->store (eventIdx, startBin);
+ numBins->store (eventIdx, binCnt);
+ eventIdxs->store (eventIdx, packetIdx); // store packet's idx
+ if (stackIds != NULL)
+ {
+ void* stackId = getStack (view_mode, packets, packetIdx);
+ stackIds->store (eventIdx, (Obj) (unsigned long) stackId);
+ }
+ if (mstates != NULL)
+ {
+ int mstate = packets->getIntValue (PROP_MSTATE, packetIdx);
+ mstates->store (eventIdx, mstate);
+ }
+ if (sampleVals != NULL)
+ {
+ Sample* sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, packetIdx);
+ if (!sample || !sample->get_usage ())
+ sample = sample;
+ else
+ {
+ PrUsage* prusage = sample->get_usage ();
+ Vector<long long> *mstateVals = prusage->getMstateValues ();
+ sampleVals->store (eventIdx, mstateVals);
+ }
+ }
+ }
+ // caller responsible for: delete representativeEvents;
+ Vector<void*> *results = new Vector<void*> (8);
+ results->store (0, startBins);
+ results->store (1, numBins);
+ results->store (2, eventIdxs);
+ results->store (3, stackIds);
+ results->store (4, mstates);
+ results->store (5, sampleVals);
+ results->store (6, timeStart);
+ results->store (7, timeEnd);
+ return results;
+}
+
+// starting from <event_id> packet idx, step <move_count> visible events
+// return the resulting idx and that packet's center time, or null if no event.
+Vector<long long> *
+dbeGetTLEventCenterTime (int dbevindex, int exp_id, int data_id,
+ int entity_prop_id, int entity_prop_val, int aux,
+ long long event_id, long long move_count)
+{
+ DataView *packets = getTimelinePackets (dbevindex, exp_id, data_id,
+ entity_prop_id);
+ if (packets == NULL)
+ return NULL;
+ long idx = (long) event_id;
+
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ VMode view_mode = dbev->get_view_mode ();
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ int direction;
+ if (move_count == 0)
+ direction = 0;
+ else if (move_count < 0)
+ {
+ move_count = -move_count;
+ direction = -1;
+ }
+ else
+ direction = 1;
+ idx = getTLVisibleIdxByStepping (exp, view_mode, entity_prop_id, packets, aux,
+ entity_prop_val, idx, move_count, direction);
+ if (idx >= 0)
+ {
+ long long ts = packets->getLongValue (PROP_TSTAMP, idx);
+ long long dur = packets->getLongValue (PROP_EVT_TIME, idx);
+ long long center = ts - dur / 2;
+ Vector<long long> *results = new Vector<long long> (2);
+ results->store (0, idx); // result idx
+ results->store (1, center); // result timestamp
+ return results;
+ }
+ return NULL;
+}
+
+long long
+dbeGetTLEventIdxNearTime (int dbevindex, int exp_id, int data_id,
+ int entity_prop_id, int entity_prop_val, int aux,
+ int searchDirection, long long tstamp)
+{
+ DataView *packets = getTimelinePackets (dbevindex, exp_id, data_id,
+ entity_prop_id);
+ if (packets == NULL)
+ return -1;
+ DbeView *dbev = dbeSession->getView (dbevindex);
+ VMode view_mode = dbev->get_view_mode ();
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ if (searchDirection < 0)
+ {
+ int idx = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+ packets, aux, entity_prop_val, tstamp,
+ DataView::REL_LTEQ);
+ if (idx != -1)
+ return idx;
+ searchDirection = 1; // couldn't find to left, try to right
+ }
+ if (searchDirection > 0)
+ {
+ int idx = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+ packets, aux, entity_prop_val, tstamp,
+ DataView::REL_GTEQ);
+ if (idx != -1)
+ return idx;
+ // couldn't find to right, fall through to generic
+ }
+ // search left and right of timestamp
+ long idx1, idx2;
+ idx1 = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+ packets, aux, entity_prop_val, tstamp,
+ DataView::REL_LT);
+ idx2 = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+ packets, aux, entity_prop_val, tstamp,
+ DataView::REL_GTEQ);
+ if (idx1 == -1)
+ return idx2;
+ else if (idx2 == -1)
+ return idx1;
+
+ // both valid, so need to compare to see which is closer
+ long long t1 = packets->getLongValue (PROP_TSTAMP, idx1);
+ long long t2 = packets->getLongValue (PROP_TSTAMP, idx2);
+ long long t2dur = packets->getLongValue (PROP_EVT_TIME, idx2);
+ long long delta1 = tstamp - t1; // should always be positive
+ long long delta2 = (t2 - t2dur) - tstamp; // if negative, overlaps idx1
+ if (delta1 > delta2)
+ return idx2;
+ else
+ return idx1;
+}
+
+enum Aggr_type
+{
+ AGGR_NONE,
+ AGGR_FAIR,
+ AGGR_MAX,
+ AGGR_MIN,
+ AGGR_CNT,
+ AGGR_SUM,
+ AGGR_AVG
+};
+
+static Aggr_type
+getAggrFunc (char *aname)
+{
+ Aggr_type agrfn = AGGR_NONE;
+ if (aname == NULL)
+ return agrfn;
+ if (strcmp (aname, NTXT ("FAIR")) == 0)
+ agrfn = AGGR_FAIR;
+ else if (strcmp (aname, NTXT ("MAX")) == 0)
+ agrfn = AGGR_MAX;
+ else if (strcmp (aname, NTXT ("MIN")) == 0)
+ agrfn = AGGR_MIN;
+ else if (strcmp (aname, NTXT ("CNT")) == 0)
+ agrfn = AGGR_CNT;
+ else if (strcmp (aname, NTXT ("SUM")) == 0)
+ agrfn = AGGR_SUM;
+ else if (strcmp (aname, NTXT ("AVG")) == 0)
+ agrfn = AGGR_AVG;
+ return agrfn;
+}
+
+static long long
+computeAggrVal (DefaultMap<long long, long long> *fval_map, Aggr_type agrfn)
+{
+ long long aval = 0;
+ long cnt = 0;
+ Vector<long long> *fvals = fval_map->values ();
+ long nvals = fvals->size ();
+ for (int i = 0; i < nvals; ++i)
+ {
+ long long val = fvals->fetch (i);
+ switch (agrfn)
+ {
+ case AGGR_FAIR:
+ aval = val;
+ break;
+ case AGGR_MAX:
+ if (aval < val || cnt == 0)
+ aval = val;
+ break;
+ case AGGR_MIN:
+ if (aval > val || cnt == 0)
+ aval = val;
+ break;
+ case AGGR_CNT:
+ aval = cnt + 1;
+ break;
+ case AGGR_SUM:
+ case AGGR_AVG:
+ aval += val;
+ break;
+ case AGGR_NONE:
+ break;
+ }
+ if (agrfn == AGGR_FAIR)
+ break;
+ cnt += 1;
+ }
+
+ // Finalize aggregation
+ if (agrfn == AGGR_AVG)
+ if (cnt > 0)
+ aval = (aval + cnt / 2) / cnt;
+ delete fvals;
+ return aval;
+}
+
+Vector<long long> *
+dbeGetAggregatedValue (int data_id, // data table id
+ char *lfilter, // local filter
+ char *fexpr, // function expression
+ char *pname_ts, // property name for timestamp
+ hrtime_t start_ts, // start of the first time interval
+ hrtime_t delta, // time interval length
+ int num, // number of time intervals
+ char *pname_key, // property name for aggregation key
+ char *aggr_func) // aggregation function
+{
+ Vector<long long> *res = new Vector<long long>;
+ Experiment *exp = dbeSession->get_exp (0);
+ if (exp == NULL)
+ return res;
+ hrtime_t end_ts = start_ts + delta * num;
+ if (end_ts < start_ts) // check overflow
+ end_ts = MAX_TIME;
+
+ if (exp->get_status () == Experiment::INCOMPLETE
+ && exp->getLastEvent () < end_ts)
+ exp->update ();
+
+ DataDescriptor *dataDscr = exp->get_raw_events (data_id);
+ if (dataDscr == NULL)
+ return res;
+
+ // Process timestamp argument
+ int prop_ts = dbeSession->getPropIdByName (pname_ts);
+ if (prop_ts == PROP_NONE)
+ return res;
+ assert (prop_ts == -1);
+
+ // Parse all expressions
+ Expression *flt_expr = NULL;
+ if (lfilter != NULL)
+ flt_expr = dbeSession->ql_parse (lfilter);
+ Expression *func_expr = NULL;
+ if (fexpr != NULL)
+ func_expr = dbeSession->ql_parse (fexpr);
+ if (func_expr == NULL) // Not specified or malformed
+ return res;
+
+ // Process aggregation key argument
+ int prop_key = PROP_NONE;
+ Data *data_key = NULL;
+ if (pname_key != NULL)
+ {
+ prop_key = dbeSession->getPropIdByName (pname_key);
+ data_key = dataDscr->getData (prop_key);
+ if (data_key == NULL) // Specified but not found
+ return res;
+ }
+
+ // Process aggregation function argument
+ Aggr_type agrfn = AGGR_FAIR;
+ if (aggr_func != NULL)
+ {
+ agrfn = getAggrFunc (aggr_func);
+ if (agrfn == AGGR_NONE) // Specified but not recognized
+ return res;
+ }
+ DefaultMap<long long, long long> *
+ fval_map = new DefaultMap<long long, long long>; // key_val -> func_val
+ Vector<long long> *key_set = NULL;
+ assert (key_set != NULL);
+ if (key_set == NULL)
+ {
+ key_set = new Vector<long long>;
+ key_set->append (0L);
+ }
+ DefaultMap<long long, int> *key_seen = new DefaultMap<long long, int>;
+ long idx_prev = -1;
+ for (int tidx = 0; tidx < num; ++tidx)
+ {
+ long idx_cur = -1;
+ assert (idx_cur != -1);
+ int left = key_set->size ();
+ key_seen->clear ();
+ for (long idx = idx_cur; idx > idx_prev; --idx)
+ {
+ long id = 0;
+ assert (id != 0);
+
+ // Pre-create expression context
+ Expression::Context ctx (dbeSession->getView (0), exp, NULL, id);
+ // First use the filter
+ if (flt_expr != NULL)
+ if (flt_expr->eval (&ctx) == 0)
+ continue;
+
+ // Calculate the key
+ // keys are limited to integral values
+ long long key = 0;
+ if (data_key != NULL)
+ key = data_key->fetchLong (id);
+
+ // Check if already seen
+ if (key_seen->get (key) == 1)
+ continue;
+ key_seen->put (key, 1);
+ left -= 1;
+
+ // Calculate function value
+ // function values are limited to integral values
+ long long fval = func_expr->eval (&ctx);
+ fval_map->put (key, fval);
+ if (left == 0)
+ break;
+ }
+ idx_prev = idx_cur;
+ long long aval = computeAggrVal (fval_map, agrfn);
+ res->store (tidx, aval);
+ }
+ delete key_seen;
+ delete fval_map;
+ delete flt_expr;
+ delete func_expr;
+ return res;
+}
+
+Vector<char*> *
+dbeGetLineInfo (Obj pc)
+{
+ DbeInstr *instr = (DbeInstr*) pc;
+ if (instr == NULL || instr->get_type () != Histable::INSTR)
+ return NULL;
+ DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
+ const char *fname = dbeline ? dbeline->sourceFile->get_name () : NTXT ("");
+ char lineno[16];
+ *lineno = '\0';
+ if (dbeline != NULL)
+ snprintf (lineno, sizeof (lineno), NTXT ("%d"), dbeline->lineno);
+ Vector<char*> *res = new Vector<char*>(2);
+ res->store (0, strdup (fname));
+ res->store (1, strdup (lineno));
+ return res;
+}
+
+int
+dbeSetAlias (char *name, char *uname, char *expr)
+{
+ char *res = dbeSession->indxobj_define (name, uname, expr, NULL, NULL);
+ return res == NULL ? 0 : 1;
+}
+
+Vector<char*> *
+dbeGetAlias (char *name)
+{
+ Vector<char*> *res = new Vector<char*>;
+ int idx = dbeSession->findIndexSpaceByName (name);
+ if (idx >= 0)
+ {
+ char *str = dbeSession->getIndexSpaceDescr (idx);
+ res->append (dbe_strdup (str));
+ str = dbeSession->getIndexSpaceExprStr (idx);
+ res->append (dbe_strdup (str));
+ }
+ return res;
+}
+
+static int
+key_cmp (const void *p1, const void *p2)
+{
+ long long ll1 = *(long long*) p1;
+ long long ll2 = *(long long*) p2;
+ return ll1 < ll2 ? -1 : ll1 > ll2 ? 1 : 0;
+}
+
+Vector<Vector<long long>*> *
+dbeGetXYPlotData (
+ int data_id, // data table id
+ char *lfilter, // local filter expression
+ char *arg, // name for the argument
+ char *func1, // expression for the first axis (x)
+ char *aggr1, // aggregation function for func1: "SUM","CNT",...
+ char *func2, // expression for the second axis (y)
+ char *aggr2, // aggregation function for func2
+ char *func3, // expression for the third axis (color)
+ char *aggr3) // aggregation function for func3
+{
+ Vector<Vector<long long>*> *res = new Vector<Vector<long long>*>;
+ Experiment *exp = dbeSession->get_exp (0);
+ if (exp == NULL)
+ return res;
+ if (exp->get_status () == Experiment::INCOMPLETE)
+ exp->update ();
+
+ DataDescriptor *dataDscr = exp->get_raw_events (data_id);
+ if (dataDscr == NULL)
+ return res;
+
+ // Parse all expressions
+ Vector<Expression*> *funcs = new Vector<Expression*>;
+ Vector<Aggr_type> *aggrs = new Vector<Aggr_type>;
+ Vector<DefaultMap<long long, long long>*> *fval_maps =
+ new Vector<DefaultMap<long long, long long>*>;
+ Vector<DefaultMap<long long, long>*> *cnt_maps =
+ new Vector<DefaultMap<long long, long>*>;
+ if (func1 != NULL)
+ {
+ Expression *expr = dbeSession->ql_parse (func1);
+ funcs->append (expr);
+ aggrs->append (getAggrFunc (aggr1));
+ fval_maps->append (new DefaultMap<long long, long long>);
+ cnt_maps->append (new DefaultMap<long long, long>);
+ res->append (new Vector<long long>);
+ if (func2 != NULL)
+ {
+ expr = dbeSession->ql_parse (func2);
+ funcs->append (expr);
+ aggrs->append (getAggrFunc (aggr2));
+ fval_maps->append (new DefaultMap<long long, long long>);
+ cnt_maps->append (new DefaultMap<long long, long>);
+ res->append (new Vector<long long>);
+ if (func3 != NULL)
+ {
+ expr = dbeSession->ql_parse (func3);
+ funcs->append (expr);
+ aggrs->append (getAggrFunc (aggr3));
+ fval_maps->append (new DefaultMap<long long, long long>);
+ cnt_maps->append (new DefaultMap<long long, long>);
+ res->append (new Vector<long long>);
+ }
+ }
+ }
+ if (funcs->size () == 0)
+ {
+ funcs->destroy ();
+ delete funcs;
+ fval_maps->destroy ();
+ delete fval_maps;
+ cnt_maps->destroy ();
+ delete cnt_maps;
+ delete aggrs;
+ return res;
+ }
+ Expression *arg_expr = NULL;
+ if (arg != NULL)
+ arg_expr = dbeSession->ql_parse (arg);
+ if (arg_expr == NULL)
+ {
+ funcs->destroy ();
+ delete funcs;
+ fval_maps->destroy ();
+ delete fval_maps;
+ cnt_maps->destroy ();
+ delete cnt_maps;
+ delete aggrs;
+ return res;
+ }
+ Expression *flt_expr = NULL;
+ if (lfilter != NULL)
+ flt_expr = dbeSession->ql_parse (lfilter);
+ Vector<long long> *kidx_map = new Vector<long long>(); // key_idx -> key_val
+ for (long i = 0; i < dataDscr->getSize (); i++)
+ {
+ Expression::Context ctx (dbeSession->getView (0), exp, NULL, i);
+ // First use the filter
+ if (flt_expr != NULL)
+ if (flt_expr->eval (&ctx) == 0)
+ continue;
+
+ // Compute the argument
+ long long key = arg_expr->eval (&ctx);
+ if (kidx_map->find (key) == -1)
+ kidx_map->append (key);
+ for (long j = 0; j < funcs->size (); ++j)
+ {
+ Expression *func = funcs->fetch (j);
+ Aggr_type aggr = aggrs->fetch (j);
+ DefaultMap<long long, long long> *fval_map = fval_maps->fetch (j);
+ DefaultMap<long long, long> *cnt_map = cnt_maps->fetch (j);
+ long long fval = func->eval (&ctx);
+ long long aval = fval_map->get (key);
+ long cnt = cnt_map->get (key);
+ switch (aggr)
+ {
+ case AGGR_NONE:
+ case AGGR_FAIR:
+ if (cnt == 0)
+ aval = fval;
+ break;
+ case AGGR_MAX:
+ if (aval < fval || cnt == 0)
+ aval = fval;
+ break;
+ case AGGR_MIN:
+ if (aval > fval || cnt == 0)
+ aval = fval;
+ break;
+ case AGGR_CNT:
+ aval = cnt + 1;
+ break;
+ case AGGR_SUM:
+ case AGGR_AVG:
+ aval += fval;
+ break;
+ }
+ cnt_map->put (key, cnt + 1);
+ fval_map->put (key, aval);
+ }
+ }
+ kidx_map->sort (key_cmp);
+
+ // Finalize aggregation, prepare result
+ for (long j = 0; j < funcs->size (); ++j)
+ {
+ Aggr_type aggr = aggrs->fetch (j);
+ Vector<long long> *resj = res->fetch (j);
+ DefaultMap<long long, long long> *
+ fval_map = fval_maps->fetch (j);
+ DefaultMap<long long, long> *
+ cnt_map = cnt_maps->fetch (j);
+ for (int kidx = 0; kidx < kidx_map->size (); ++kidx)
+ {
+ long long key = kidx_map->fetch (kidx);
+ long long aval = fval_map->get (key);
+ if (aggr == AGGR_AVG)
+ {
+ long cnt = cnt_map->get (key);
+ if (cnt > 0)
+ aval = (aval + cnt / 2) / cnt;
+ }
+ resj->append (aval);
+ }
+ }
+ delete flt_expr;
+ funcs->destroy ();
+ delete funcs;
+ delete aggrs;
+ delete arg_expr;
+ delete kidx_map;
+ fval_maps->destroy ();
+ delete fval_maps;
+ cnt_maps->destroy ();
+ delete cnt_maps;
+ return res;
+}
+
+/* ********************************************************************* */
+/* Routines for use by Collector GUI */
+/**
+ * Returns signal value for provided name. Example of name: "SIGUSR1"
+ * @param signal
+ * @return value
+ */
+int
+dbeGetSignalValue (char *signal)
+{
+ int ret = -1;
+ if (signal == NULL)
+ return ret;
+ if (strcmp (signal, "SIGUSR1") == 0)
+ return (SIGUSR1);
+ if (strcmp (signal, "SIGUSR2") == 0)
+ return (SIGUSR2);
+ if (strcmp (signal, "SIGPROF") == 0)
+ return (SIGPROF);
+ return ret;
+}
+
+char *
+dbeSendSignal (pid_t p, int signum)
+{
+ int ret = kill (p, signum);
+ if (p == 0 || p == -1)
+ return (dbe_sprintf (GTXT ("kill of process %d not supported\n"), p));
+ if (ret == 0)
+ return NULL;
+ char *msg = dbe_sprintf (GTXT ("kill(%d, %d) failed: %s\n"), p, signum,
+ strerror (errno));
+ return msg;
+}
+
+char *
+dbeGetCollectorControlValue (char *control)
+{
+ if (control == NULL)
+ return NULL;
+ if (col_ctr == NULL)
+ col_ctr = new Coll_Ctrl (1);
+ char *msg = col_ctr->get (control);
+ return msg;
+}
+
+char *
+dbeSetCollectorControlValue (char *control, char * value)
+{
+ if (control == NULL)
+ return NULL;
+ if (col_ctr == NULL)
+ col_ctr = new Coll_Ctrl (1);
+ char *msg = col_ctr->set (control, value);
+ return msg;
+}
+
+char *
+dbeUnsetCollectorControlValue (char *control)
+{
+ if (control == NULL)
+ return NULL;
+ if (col_ctr == NULL)
+ col_ctr = new Coll_Ctrl (1);
+ char *msg = col_ctr->unset (control);
+ return msg;
+}
+
+void
+dbeSetLocation (const char *fname, const char *location)
+{
+ Vector<SourceFile*> *sources = dbeSession->get_sources ();
+ for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+ {
+ SourceFile *src = sources->get (i);
+ DbeFile *df = src->dbeFile;
+ if (df && (strcmp (fname, df->get_name ()) == 0))
+ {
+ df->find_file ((char *) location);
+ break;
+ }
+ }
+}
+
+void
+dbeSetLocations (Vector<const char *> *fnames, Vector<const char *> *locations)
+{
+ if (fnames == NULL || locations == NULL
+ || fnames->size () != locations->size ())
+ return;
+ for (long i = 0, sz = fnames->size (); i < sz; i++)
+ dbeSetLocation (fnames->get (i), locations->get (i));
+}
+
+Vector<void*> *
+dbeResolvedWith_setpath (const char *path)
+{
+ Vector<char*> *names = new Vector<char*>();
+ Vector<char*> *pathes = new Vector<char*>();
+ Vector<long long> *ids = new Vector<long long>();
+ Vector<SourceFile*> *sources = dbeSession->get_sources ();
+ for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+ {
+ SourceFile *src = sources->get (i);
+ DbeFile *df = src->dbeFile;
+ if (df == NULL || (df->filetype & DbeFile::F_FICTION) != 0)
+ continue;
+ char *fnm = df->get_name ();
+ if ((df->filetype & (DbeFile::F_JAVACLASS | DbeFile::F_JAVA_SOURCE)) != 0)
+ {
+ char *jnm = dbe_sprintf (NTXT ("%s/%s"), path, fnm);
+ if (df->check_access (jnm) == DbeFile::F_FILE)
+ {
+ names->append (dbe_strdup (fnm));
+ pathes->append (jnm);
+ ids->append (src->id);
+ continue;
+ }
+ free (jnm);
+ }
+ char *nm = dbe_sprintf (NTXT ("%s/%s"), path, get_basename (fnm));
+ if (df->check_access (nm) == DbeFile::F_FILE)
+ {
+ names->append (dbe_strdup (fnm));
+ pathes->append (nm);
+ ids->append (src->id);
+ continue;
+ }
+ free (nm);
+ }
+ if (names->size () != 0)
+ {
+ Vector<void*> *data = new Vector<void*>(3);
+ data->append (names);
+ data->append (pathes);
+ data->append (ids);
+ return data;
+ }
+ return NULL;
+}
+
+Vector<void*> *
+dbeResolvedWith_pathmap (const char *old_prefix, const char *new_prefix)
+{
+ size_t len = strlen (old_prefix);
+ Vector<char*> *names = new Vector<char*>();
+ Vector<char*> *pathes = new Vector<char*>();
+ Vector<long long> *ids = new Vector<long long>();
+ Vector<SourceFile*> *sources = dbeSession->get_sources ();
+ for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+ {
+ SourceFile *src = sources->get (i);
+ DbeFile *df = src->dbeFile;
+ if (df == NULL || (df->filetype & DbeFile::F_FICTION) != 0)
+ continue;
+ char *fnm = df->get_name ();
+ if (strncmp (old_prefix, fnm, len) == 0
+ && (fnm[len] == '/' || fnm[len] == '\0'))
+ {
+ char *nm = dbe_sprintf (NTXT ("%s/%s"), new_prefix, fnm + len);
+ if (df->check_access (nm) == DbeFile::F_FILE)
+ {
+ names->append (dbe_strdup (fnm));
+ pathes->append (nm);
+ ids->append (src->id);
+ continue;
+ }
+ if ((df->filetype & DbeFile::F_JAVA_SOURCE) != 0)
+ {
+ free (nm);
+ nm = dbe_sprintf (NTXT ("%s/%s"), new_prefix, fnm);
+ if (df->check_access (nm) == DbeFile::F_FILE)
+ {
+ names->append (dbe_strdup (fnm));
+ pathes->append (nm);
+ ids->append (src->id);
+ continue;
+ }
+ }
+ free (nm);
+ }
+ }
+ if (names->size () != 0)
+ {
+ Vector<void*> *data = new Vector<void*>(3);
+ data->append (names);
+ data->append (pathes);
+ data->append (ids);
+ return data;
+ }
+ return NULL;
+}
+
+void
+dbe_archive (Vector<long long> *ids, Vector<const char *> *locations)
+{
+ if (ids == NULL || locations == NULL || ids->size () != locations->size ())
+ return;
+ Experiment *exp = dbeSession->get_exp (0);
+ if (exp == NULL)
+ return;
+ Vector<SourceFile*> *sources = dbeSession->get_sources ();
+ for (long i1 = 0, sz1 = ids->size (); i1 < sz1; i1++)
+ {
+ long long id = ids->get (i1);
+ for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+ {
+ SourceFile *src = sources->get (i);
+ if (src->id == id)
+ {
+ DbeFile *df = src->dbeFile;
+ if (df)
+ {
+ char *fnm = df->find_file ((char *) locations->get (i1));
+ if (fnm)
+ {
+ char *nm = df->get_name ();
+ char *anm = exp->getNameInArchive (nm, false);
+ exp->copy_file (fnm, anm, true);
+ free (anm);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************************************************************************ */
+
+/* Routines to check connection between Remote Analyzer Client and er_print */
+char *
+dbeCheckConnection (char *str)
+{
+ return dbe_strdup (str);
+}
diff --git a/gprofng/src/Dbe.h b/gprofng/src/Dbe.h
new file mode 100644
index 0000000..f811096
--- /dev/null
+++ b/gprofng/src/Dbe.h
@@ -0,0 +1,294 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_H_
+#define _DBE_H_
+
+#include <stdio.h>
+#include "enums.h"
+
+class MetricList;
+template <class ITEM> class Vector;
+typedef long long Obj;
+
+Vector<char*> *dbeGetInitMessages (void);
+Vector<char*> *dbeGetExpPreview (int dbevindex, char *exp_name);
+char *dbeGetExpParams (int dbevindex, char *exp_name);
+char *dbeCreateDirectories (const char *dirname);
+char *dbeDeleteFile (const char *pathname);
+Vector<char*> *dbeReadFile (const char *pathname);
+int dbeWriteFile (const char *pathname, const char *contents);
+char *dbeGetFileAttributes (const char *filename, const char *format);
+char *dbeGetFiles (const char *dirname, const char *format);
+char *dbeGetRunningProcesses (const char *format);
+char *dbeOpenExperimentList (int dbevindex, Vector<Vector<char*>*> *groups,
+ bool sessionRestart);
+char *dbeReadRCFile (int dbevindex, char* path);
+char *dbeSetExperimentsGroups (Vector<Vector<char*>*> *groups);
+Vector<Vector<char*>*> *dbeGetExperimensGroups ();
+char *dbeDropExperiment (int dbevindex, Vector<int> *drop_index);
+Vector<char*> *dbeGetExpsProperty (const char *prop_name);
+Vector<char*> *dbeGetExpName (int dbevindex);
+Vector<int> *dbeGetExpState (int dbevindex);
+Vector<bool> *dbeGetExpEnable (int dbevindex);
+bool dbeSetExpEnable (int dbevindex, Vector<bool> *enable);
+Vector<char*> *dbeGetExpInfo (int dbevindex);
+bool dbeGetViewModeEnable ();
+bool dbeGetJavaEnable ();
+int dbeUpdateNotes (int dbevindex, int exp_id, int type, char* text,
+ bool handle_file);
+Vector<void*> *dbeGetTabListInfo (int dbevindex);
+Vector<bool> *dbeGetTabSelectionState (int dbevindex);
+void dbeSetTabSelectionState (int dbevindex, Vector<bool> *selected);
+Vector<bool> *dbeGetMemTabSelectionState (int dbevindex);
+void dbeSetMemTabSelectionState (int dbevindex, Vector<bool> *selected);
+Vector<bool> *dbeGetIndxTabSelectionState (int dbevindex);
+void dbeSetIndxTabSelectionState (int dbevindex, Vector<bool> *selected);
+Vector<char*> *dbeGetLoadObjectName (int dbevindex);
+Vector<void *> *dbeGetLoadObjectList (int dbevindex);
+Vector<char*> *dbeGetSearchPath (int dbevindex);
+void dbeSetSearchPath (int dbevindex, Vector<char*> *path);
+Vector<void*> *dbeGetPathmaps (int dbevindex);
+char *dbeSetPathmaps (Vector<char*> *from, Vector<char*> *to);
+char *dbeAddPathmap (int dbevindex, char *from, char *to);
+char *dbeGetMsg (int dbevindex, int type);
+int dbeInitView (int index, int cloneindex);
+void dbeDeleteView (int dbevindex);
+
+// methods concerning metrics
+MetricList *dbeGetMetricListV2 (int dbevindex, MetricType mtype,
+ Vector<int> *type, Vector<int> *subtype,
+ Vector<bool> *sort, Vector<int> *vis,
+ Vector<char*> *aux, Vector<char*> *expr_spec,
+ Vector<char*> *legends);
+Vector<void*> *dbeGetRefMetricsV2 ();
+Vector<void*> *dbeGetCurMetricsV2 (int dbevindex, MetricType mtype);
+void dbeSetSort (int dbevindex, int sort_index, MetricType mtype, bool reverse);
+
+// methods concerning metrics for Overview Tab
+Vector<void*> *dbeGetRefMetricTree (int dbevindex, bool include_unregistered);
+Vector<void*> *dbeGetRefMetricTreeValues (int dbevindex, Vector<char *> *met_cmds,
+ Vector<char *> *non_met_cmds);
+Vector<char*> *dbeGetOverviewText (int dbevindex);
+Vector<int> *dbeGetAnoValue (int dbevindex);
+void dbeSetAnoValue (int dbevindex, Vector<int> *set);
+int dbeGetNameFormat (int dbevindex);
+bool dbeGetSoName (int dbevindex);
+void dbeSetNameFormat (int dbevindex, int fnames, bool soname);
+int dbeGetViewMode (int dbevindex);
+void dbeSetViewMode (int dbevindex, int nmode);
+Vector<void*> *dbeGetTLValue (int dbevindex);
+void dbeSetTLValue (int dbevindex, const char *tldata_cmd,
+ int entitiy_prop_id, int stackalign, int stackdepth);
+Vector<void*> *dbeGetExpFounderDescendants ();
+Vector<void*> *dbeGetExpSelection (int dbevindex);
+Vector<void*> *dbeGetSampleStatus (int dbevindex, int nselected,
+ Vector<bool> *selected);
+Vector<unsigned> *dbeGetSampleSize (int dbevindex, Vector<bool> *selected);
+char *dbeCheckPattern (int dbevindex, Vector<bool> *selected, char *pattern,
+ int type);
+char *dbeSetFilterStr (int dbevindex, char *filter_str);
+char *dbeGetFilterStr (int dbevindex);
+int dbeValidateFilterExpression (char *str_expr);
+Vector<void*> *dbeGetFilterKeywords (int dbevindex);
+Vector<void*> *dbeGetFilters (int dbevindex, int nexp);
+bool dbeUpdateFilters (int dbevindex, Vector<bool> *selected,
+ Vector<char*> *pattern_str);
+char *dbeComposeFilterClause (int dbevindex, int type, int subtype,
+ Vector<int>*selections);
+Vector<int> *dbeGetLoadObjectState (int dbevindex);
+void dbeSetLoadObjectState (int dbevindex, Vector<int> *selected);
+void dbeSetLoadObjectDefaults (int dbevindex);
+Vector<void*> *dbeGetMemObjects (int dbevindex);
+char *dbeDefineMemObj (char *name, char *index_expr, char *_machmodel,
+ char *sdesc, char *ldesc);
+char *dbeDeleteMemObj (char *name);
+Vector<char*> *dbeGetCPUVerMachineModel (int dbevindex);
+char *dbeLoadMachineModel (char *name);
+char *dbeGetMachineModel ();
+Vector<char*> *dbeListMachineModels ();
+void dbeDetectLoadMachineModel (int dbevindex);
+Vector<void*> *dbeGetIndxObjDescriptions (int dbevindex);
+Vector<void*> *dbeGetCustomIndxObjects (int dbevindex);
+char *dbeDefineIndxObj (char *name, char *index_expr, char *sdesc, char *ldesc);
+void dbeSetSelObj (int dbevindex, Obj sel_obj, int type, int subtype);
+void dbeSetSelObjV2 (int dbevindex, uint64_t id);
+Obj dbeGetSelObj (int dbevindex, int type, int subtype);
+uint64_t dbeGetSelObjV2 (int dbevindex, char *typeStr);
+int dbeGetSelIndex (int dbevindex, Obj sel_obj, int type, int subtype);
+Vector<uint64_t> *dbeGetSelObjsIO (int dbevindex, Vector<uint64_t> *ids, int type);
+Vector<uint64_t> *dbeGetSelObjIO (int dbevindex, uint64_t id, int type);
+uint64_t dbeGetSelObjHeapTimestamp (int dbevindex, uint64_t id);
+int dbeGetSelObjHeapUserExpId (int dbevindex, uint64_t id);
+char *dbeSetPrintLimit (int dbevindex, int limit);
+int dbeGetPrintLimit (int dbevindex);
+char *dbeSetPrintMode (int dbevindex, char *printmode);
+int dbeGetPrintMode (int dbevindex);
+char *dbeGetPrintModeString (int dbevindex);
+char dbeGetPrintDelim (int dbevindex);
+Vector<void*> *dbeGetTotals (int dbevindex, int dsptype, int subtype);
+Vector<void*> *dbeGetHotMarks (int dbevindex, int type);
+Vector<void*> *dbeGetHotMarksInc (int dbevindex, int type);
+Vector<void*> *dbeGetSummaryHotMarks (int dbevindex, Vector<Obj> *sel_objs, int type);
+Vector<uint64_t> *dbeGetFuncId (int dbevindex, int type, int begin, int length);
+Vector<void*> *dbeGetFuncCalleeInfo (int dbevindex, int type, Vector<int>* idxs, int groupId);
+Vector<void*> *dbeGetFuncCallerInfo (int dbevindex, int type, Vector<int>* idxs, int groupId);
+Vector<void*> *dbeGetFuncCalleeInfoById (int dbevindex, int type, int idx);
+Vector<void*> *dbeGetFuncCallerInfoById (int dbevindex, int type, int idx);
+char *dbePrintData (int dbevindex, int type, int subtype, char *printer,
+ char *fname, FILE *outfile);
+int dbeSetFuncData (int dbevindex, Obj sel_obj, int type, int subtype);
+Vector<void*> *dbeGetFuncList (int dbevindex, int type, int subtype);
+Vector<void*> *dbeGetFuncListV2 (int dbevindex, int mtype, Obj sel_obj, int type, int subtype);
+Vector<void*> *dbeGetFuncListMini (int dbevindex, int type, int subtype);
+Vector<Obj> *dbeGetComparableObjsV2 (int dbevindex, Obj sel_obj, int type);
+Obj dbeConvertSelObj (Obj obj, int type);
+Vector<int> *dbeGetGroupIds (int dbevindex);
+Vector<void*> *dbeGetTableDataV2 (int dbevindex, char *mlistStr, char *modeStr,
+ char *typeStr, char *subtypeStr, Vector<uint64_t> *ids);
+
+int dbeGetCallTreeNumLevels (int dbevindex);
+Vector<void*> *dbeGetCallTreeLevel (int dbevindex, char *mcmd, int level);
+Vector<void*> *dbeGetCallTreeLevels (int dbevindex, char *mcmd);
+Vector<void*> *dbeGetCallTreeChildren (int dbevindex, char *mcmd, Vector<int /*NodeIdx*/>*nodes);
+Vector<void*> *dbeGetCallTreeLevelFuncs (int dbevindex, int level_start, int level_end);
+Vector<void*> *dbeGetCallTreeFuncs (int dbevindex);
+Vector<char*> *dbeGetNames (int dbevindex, int type, Obj sel_obj);
+Vector<void*> *dbeGetTotalMax (int dbevindex, int type, int subtype);
+Vector<void*> *dbeGetStatisOverviewList (int dbevindex);
+Vector<void*> *dbeGetStatisList (int dbevindex);
+Vector<void*> *dbeGetSummary (int dbevindex, Vector<Obj> *objs, int type, int subtype);
+Vector<void*> *dbeGetSummaryV2 (int dbevindex, Vector<Obj> *objs, int type, int subtype);
+Vector<int> *dbeGetFounderExpId (Vector<int> *expIds);
+Vector<int> *dbeGetUserExpId (Vector<int> *expIds); // filter "user visible" experiment id
+Vector<int> *dbeGetExpGroupId (Vector<int> *expIds);
+char *dbeGetExpName (int dbevindex, char *dir_name);
+Vector<char*> *dbeGetHwcHelp (int dbevindex, bool forKernel);
+Vector<Vector<char*>*> *dbeGetHwcSets (int dbevindex, bool forKernel);
+Vector<void*> *dbeGetHwcsAll (int dbevindex, bool forKernel);
+Vector<char*> *dbeGetHwcAttrList (int dbevindex, bool forKernel);
+int dbeGetHwcMaxConcurrent (int dbevindex, bool forKernel);
+int dbeGetHwcMaxReg (int dbevindex); // TBR?
+
+Vector<char*> *dbeGetIfreqData (int dbevindex);
+Vector<void*> *dbeGetLeakListInfo (int dbevindex, bool leakflag);
+Vector<void*> *dbeMpviewGetTlFuncReps (int dbevindex, int exp_id,
+ long long binSizeTime, long long startTime, long long endTime,
+ long long binSizeRank, long long startRank, long long endRank);
+Vector<void*> *dbeMpviewGetTlMsgReps (int dbevindex, int exp_id, int throttle,
+ long long binSizeTime, long long startTime, long long endTime,
+ long long binSizeRank, long long startRank, long long endRank);
+Vector<long long> *dbeMpviewGetAxisRange (int dbevindex, int exp_id,
+ int chart_type, int axis_type);
+Vector<char*> *dbeMpviewGetAxisDiscreteLabels (int dbevindex, int exp_id,
+ int chart_type, int axis_type);
+Vector<void*> *dbeMpviewGetFuncDetails (int dbevindex, int exp_id, Obj funcId);
+Vector<void*> *dbeMpviewGetMesgDetails (int dbevindex, int exp_id, Obj mesgId);
+Vector<long long> *dbeMpviewGetChartData (int dbevindex, int exp_id, int ctype,
+ int attr1, long long start1,
+ long long end1, int nbins1,
+ int attr2, long long start2,
+ long long end2, int nbins2,
+ int metric, int reduction);
+void dbeMpviewFilterSet (int dbevindex, int exp_id, Vector<int> *ctid,
+ Vector<int > *axid, Vector<long long> *startVal,
+ Vector<long long> *endVal);
+void dbeMpviewLoadStacks (int dbevindex, int exp_id);
+
+
+Obj dbeGetObject (int dbevindex, Obj sel_func, Obj sel_pc);
+char *dbeGetName (int dbevindex, int exp_id);
+Vector<char*> *dbeGetExpVerboseName (Vector<int> *exp_ids);
+long long dbeGetStartTime (int dbevindex, int exp_id);
+long long dbeGetRelativeStartTime (int dbevindex, int exp_id);
+long long dbeGetEndTime (int dbevindex, int exp_id);
+int dbeGetClock (int dbevindex, int exp_id);
+long long dbeGetWallStartSec (int dbevindex, int exp_id);
+char *dbeGetHostname (int dbevindex, int exp_id);
+Vector<void*> *dbeGetEntityProps (int dbevindex);
+Vector<void*> *dbeGetEntities (int dbevindex, int exp_id, int ekind);
+Vector<void*> *dbeGetEntitiesV2 (int dbevindex, Vector<int> *exp_ids, int ekind);
+Vector<void*> *dbeGetTLDetails (int dbevindex, int exp_id, int data_id,
+ int entity_prop_id, Obj event_id);
+Vector<Obj> *dbeGetStackFunctions (int dbevindex, Obj stack);
+Vector<void*> *dbeGetStacksFunctions (int dbevindex, Vector<Obj> *stacks);
+Vector<Obj> *dbeGetStackPCs (int dbevindex, Obj stack);
+Vector<char*> *dbeGetStackNames (int dbevindex, Obj stack);
+Vector<void*> *dbeGetSamples (int dbevindex, int exp_id, int64_t lo, int64_t hi);
+Vector<void*> *dbeGetGCEvents (int dbevindex, int exp_id, int64_t lo, int64_t hi);
+Vector<Vector<char*>*>* dbeGetIOStatistics (int dbevindex);
+Vector<Vector<char*>*>* dbeGetHeapStatistics (int dbevindex);
+Vector<char*> *dbeGetFuncNames (int dbevindex, Vector<Obj> *funcs);
+Vector<char*> *dbeGetObjNamesV2 (int dbevindex, Vector<uint64_t> *ids);
+char *dbeGetFuncName (int dbevindex, Obj func);
+char *dbeGetObjNameV2 (int dbevindex, uint64_t id);
+Vector<uint64_t> *dbeGetFuncIds (int dbevindex, Vector<Obj> *funcs);
+uint64_t dbeGetFuncId (int dbevindex, Obj func);
+char *dbeGetDataspaceTypeDesc (int dbevindex, Obj stack);
+Vector<void*> *dbeGetDataDescriptorsV2 (int exp_id);
+Vector<void*> *dbeGetDataPropertiesV2 (int exp_id, int data_id);
+Vector<void*> *dbeGetExperimentTimeInfo (Vector<int> *exp_ids);
+Vector<void*> *dbeGetExperimentDataDescriptors (Vector<int> *exp_ids);
+
+/* New Timeline Interface */
+Vector<long long> *dbeGetAggregatedValue (int data_id, char *lfilter, char *fexpr,
+ char *pname_ts, hrtime_t start_ts,
+ hrtime_t delta, int num,
+ char *pname_key, char *aggr_func);
+Vector<char*> *dbeGetLineInfo (Obj pc);
+int dbeSetAlias (char *name, char *uname, char *expr);
+Vector<char*> *dbeGetAlias (char *name);
+Vector<Vector<long long>*> *dbeGetXYPlotData (int data_id, char *lfilter,
+ char *arg, char *func1, char *aggr1,
+ char *func2, char *aggr2,
+ char *func3, char *aggr3);
+Vector<bool> *dbeHasTLData (int dbev_index, Vector<int> *exp_ids,
+ Vector<int> *data_ids, // DATA_*
+ Vector<int> *entity_prop_ids, // LWP,CPU,THR, etc
+ Vector<int> *entity_prop_values,
+ Vector<int> *auxs);
+Vector<void*> *dbeGetTLData (int dbevindex, int exp_id, int data_id,
+ int entity_prop_id, int entity_prop_val, int aux,
+ hrtime_t start_ts, hrtime_t delta, int num,
+ bool getRepresentatives, Vector<char*> *chartProperties);
+Vector<long long> *dbeGetTLEventCenterTime (int dbevindex, int exp_id,
+ int data_id, int entity_prop_id,
+ int entity_prop_val, int aux,
+ long long event_idx, long long move_count);
+long long dbeGetTLEventIdxNearTime (int dbevindex, int exp_id,
+ int data_id,
+ int entity_prop_id, int entity_prop_val, int aux,
+ int searchDirection,
+ long long timestamp);
+
+/* Interface for use by Collector GUI */
+int dbeGetSignalValue (char *);
+char *dbeSendSignal (pid_t, int);
+char *dbeGetCollectorControlValue (char *);
+char *dbeSetCollectorControlValue (char *, char *);
+char *dbeUnsetCollectorControlValue (char *);
+char *dbeCheckConnection (char *);
+void dbe_archive (Vector<long long> *ids, Vector<const char *> *locations);
+void dbeSetLocation (const char *fname, const char *location);
+void dbeSetLocations (Vector<const char *> *fnames, Vector<const char *> *locations);
+Vector<void*> *dbeResolvedWith_setpath (const char *path);
+Vector<void*> *dbeResolvedWith_pathmap (const char *old_prefix, const char *new_prefix);
+
+#endif /* _DBE_H_ */
diff --git a/gprofng/src/DbeApplication.cc b/gprofng/src/DbeApplication.cc
new file mode 100644
index 0000000..382bd45
--- /dev/null
+++ b/gprofng/src/DbeApplication.cc
@@ -0,0 +1,113 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "DbeSession.h"
+#include "DbeApplication.h"
+#include "LoadObject.h"
+#include "Experiment.h"
+#include "PreviewExp.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "Module.h"
+#include "DataObject.h"
+#include "Sample.h"
+#include "CallStack.h"
+#include "Print.h"
+#include "util.h"
+#include "libgen.h"
+#include "i18n.h"
+
+DbeApplication *theDbeApplication;
+
+DbeApplication::DbeApplication (int argc, char *argv[], char* _run_dir)
+: Application (argc, argv, _run_dir)
+{
+ theDbeApplication = this;
+ ipcMode = false;
+ rdtMode = false;
+ if (argc > 1)
+ if (strcmp (argv[1], NTXT ("-IPC")) == 0
+ || strcmp (argv[1], NTXT ("-DIPC")) == 0)
+ ipcMode = true;
+ lic_found = 0;
+ lic_err = NULL;
+
+ // Instantiate a session
+ (void) new DbeSession (settings, ipcMode, rdtMode);
+}
+
+DbeApplication::~DbeApplication ()
+{
+ delete dbeSession;
+ theDbeApplication = NULL;
+}
+
+Vector<char*> *
+DbeApplication::initApplication (char *fdhome, char *licpath, ProgressFunc func)
+{
+ // set the home directory
+ if (fdhome != NULL)
+ set_run_dir (fdhome);
+
+ // Set progress function
+ set_progress_func (func);
+
+ // Get license
+ char *license_err = NULL;
+ char *sts;
+ if (licpath != NULL)
+ {
+ lic_found = 0;
+ if (lic_found == 0)
+ {
+ lic_err = dbe_strdup (DbeApplication::get_version ());
+ sts = dbe_strdup (GTXT ("OK"));
+ }
+ else if (lic_found == 2)
+ {
+ lic_err = dbe_strdup (license_err);
+ sts = dbe_strdup (GTXT ("WARN"));
+ }
+ else if (lic_found == 3)
+ {
+ lic_err = dbe_strdup (license_err);
+ sts = dbe_strdup (GTXT ("FATAL"));
+ }
+ else
+ {
+ lic_err = dbe_strdup (license_err);
+ sts = dbe_strdup (GTXT ("ERROR"));
+ }
+ }
+ else
+ {
+ lic_err = dbe_strdup (DbeApplication::get_version ());
+ sts = dbe_strdup (GTXT ("OK"));
+ }
+ Vector<char*> *data = new Vector<char*>(2);
+ data->store (0, sts);
+ data->store (1, lic_err);
+ return data;
+}
diff --git a/gprofng/src/DbeApplication.h b/gprofng/src/DbeApplication.h
new file mode 100644
index 0000000..b6bdaaf
--- /dev/null
+++ b/gprofng/src/DbeApplication.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * The DbeApplication class is the base class for all C++ executables
+ * that read Experiments
+ *
+ * It is derived from the Application class, and differs from it
+ * only in that it instantiates a DbeSession (q.v.) to manage
+ * the reading and processing of Experiments
+ */
+
+#ifndef _DBEAPPLICATION_H
+#define _DBEAPPLICATION_H
+
+#include "Application.h"
+
+template <class ITEM> class Vector;
+
+class DbeApplication : public Application
+{
+public:
+ DbeApplication (int argc, char *argv[], char *_run_dir = NULL);
+ ~DbeApplication ();
+ Vector<char*> *initApplication (char *fdhome, char *licpath, ProgressFunc func);
+
+ bool rdtMode;
+ bool ipcMode;
+};
+
+extern DbeApplication *theDbeApplication;
+
+#endif /* _DBEAPPLICATION_H */
diff --git a/gprofng/src/DbeArray.h b/gprofng/src/DbeArray.h
new file mode 100644
index 0000000..af7c36e
--- /dev/null
+++ b/gprofng/src/DbeArray.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DbeArray_H
+#define _DbeArray_H
+
+template <typename ITEM> class DbeArray
+{
+public:
+
+ DbeArray (long sz)
+ {
+ count = 0;
+ limit = sz;
+ data = new ITEM[limit];
+ };
+
+ virtual
+ ~DbeArray ()
+ {
+ delete[] data;
+ }
+
+ int
+ append (const ITEM &item)
+ {
+ int n = allocate (1);
+ ITEM *p = get (n);
+ *p = item;
+ return n;
+ };
+
+ ITEM *
+ get (long index)
+ {
+ return (index < count && index >= 0) ? data + index : (ITEM *) NULL;
+ };
+
+ int
+ allocate (int cnt)
+ {
+ count += cnt;
+ resize (count);
+ return count - cnt;
+ };
+
+ int
+ size ()
+ {
+ return (int) count;
+ };
+
+ void
+ reset ()
+ {
+ count = 0;
+ };
+
+private:
+
+ void
+ resize (long cnt)
+ {
+ if (limit <= cnt)
+ {
+ limit *= 2;
+ if (limit < cnt)
+ limit = cnt + 1;
+ ITEM *d = new ITEM[limit];
+ if (count > 0)
+ memcpy (d, data, sizeof (ITEM) * count);
+ delete[] data;
+ data = d;
+ }
+ };
+
+ ITEM *data; // Pointer to data vector
+ long count; // Number of items
+ long limit; // Array length
+};
+
+#endif /* _DbeArray_H */
diff --git a/gprofng/src/DbeCacheMap.h b/gprofng/src/DbeCacheMap.h
new file mode 100644
index 0000000..4c51a34
--- /dev/null
+++ b/gprofng/src/DbeCacheMap.h
@@ -0,0 +1,109 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * Dbe Cache Map implementation.
+ *
+ * Simple Cache Map makes the following assumptions:
+ * - Cache Map is used for very fast but not guaranteed mapping;
+ * - No Relations can be used;
+ * - all objects used as keys or values has to be managed
+ * outside CacheMap (f.e. deletion);
+ */
+
+#ifndef _DbeCacheMap_h
+#define _DbeCacheMap_h
+
+#include <Map.h>
+
+template <typename Key_t, class ITEM>
+class DbeCacheMap : public Map<Key_t, ITEM *>
+{
+public:
+
+ DbeCacheMap (int _size = DefaultSize)
+ { // _size should be 2 ** N
+ size = _size;
+ table = new DbeCache_T[size];
+ memset (table, 0, size * sizeof (DbeCache_T));
+ };
+
+ ~DbeCacheMap ()
+ {
+ delete[] table;
+ };
+
+ void
+ put (Key_t key, ITEM *val)
+ {
+ int ind = get_hash (key);
+ table[ind].key = key;
+ table[ind].value = val;
+ };
+
+ ITEM *
+ get (Key_t key)
+ {
+ int ind = get_hash (key);
+ if (table[ind].key == key)
+ return table[ind].value;
+ return (ITEM *) NULL;
+ };
+
+ ITEM *
+ remove (Key_t key)
+ {
+ int ind = get_hash (key);
+ ITEM *v = table[ind].value;
+ table[ind].value = (ITEM *) NULL;
+ return v;
+ };
+
+ ITEM *
+ get (Key_t /* key */, typename Map<Key_t, ITEM *>::Relation /* rel */)
+ {
+ return (ITEM *) NULL;
+ };
+
+private:
+
+ enum
+ {
+ DefaultSize = (1 << 13)
+ };
+
+ typedef struct DbeCache_S
+ {
+ Key_t key;
+ ITEM *value;
+ } DbeCache_T;
+ DbeCache_T *table;
+ int size;
+
+ int
+ get_hash (Key_t key)
+ {
+ unsigned long long h = (unsigned long long) key;
+ h ^= (h >> 20) ^ (h >> 12);
+ return (h ^ (h >> 7) ^ (h >> 4)) & (size - 1);
+ }
+};
+
+#endif
diff --git a/gprofng/src/DbeFile.cc b/gprofng/src/DbeFile.cc
new file mode 100644
index 0000000..9e1fe1c
--- /dev/null
+++ b/gprofng/src/DbeFile.cc
@@ -0,0 +1,541 @@
+/* Copyright (C) 2021 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 "Experiment.h"
+#include "DbeFile.h"
+#include "ExpGroup.h"
+#include "DbeJarFile.h"
+
+DbeFile::DbeFile (const char *filename)
+{
+ filetype = 0;
+ name = dbe_strdup (filename);
+ name = canonical_path (name);
+ orig_location = NULL;
+ location = NULL;
+ location_info = NULL;
+ jarFile = NULL;
+ container = NULL;
+ need_refind = true;
+ inArchive = false;
+ sbuf.st_atim.tv_sec = 0;
+ experiment = NULL;
+}
+
+DbeFile::~DbeFile ()
+{
+ free (name);
+ free (location);
+ free (orig_location);
+ free (location_info);
+}
+
+void
+DbeFile::set_need_refind (bool val)
+{
+ if (val != need_refind)
+ {
+ free (location_info);
+ location_info = NULL;
+ need_refind = val;
+ }
+}
+
+void
+DbeFile::set_location (const char *filename)
+{
+ free (location);
+ location = NULL;
+ if (filename)
+ {
+ if (strncmp (filename, NTXT ("./"), 2) == 0)
+ filename += 2;
+ location = canonical_path (dbe_strdup (filename));
+ }
+ free (location_info);
+ location_info = NULL;
+ set_need_refind (false);
+}
+
+char *
+DbeFile::get_location_info ()
+{
+ if (location_info == NULL)
+ {
+ char *fnm = get_name ();
+ char *loc = get_location ();
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location_info: %s %s\n"),
+ STR (fnm), STR (loc));
+ if (loc == NULL)
+ {
+ if (filetype & F_FICTION)
+ location_info = dbe_strdup (fnm);
+ else
+ location_info = dbe_sprintf (GTXT ("%s (not found)"),
+ get_relative_path (fnm));
+ }
+ else
+ {
+ char *r_fnm = get_relative_path (fnm);
+ char *r_loc = get_relative_path (loc);
+ if (strcmp (r_fnm, r_loc) == 0)
+ location_info = dbe_strdup (r_fnm);
+ else
+ {
+ char *bname = get_basename (r_fnm);
+ if (strcmp (bname, r_loc) == 0) // found in current directory
+ location_info = dbe_strdup (bname);
+ else
+ location_info = dbe_sprintf (GTXT ("%s (found as %s)"), bname, r_loc);
+ }
+ }
+ }
+ return location_info;
+}
+
+char *
+DbeFile::getResolvedPath ()
+{
+ if (get_location ())
+ return location;
+ return name;
+}
+
+DbeFile *
+DbeFile::getJarDbeFile (char *fnm, int sym)
+{
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::getJarDbeFile: %s fnm='%s' sym=%d\n"),
+ STR (name), STR (fnm), sym);
+ DbeFile *df = NULL;
+ if (sym)
+ {
+ char *s = strchr (fnm, sym);
+ if (s)
+ {
+ s = dbe_strndup (fnm, s - fnm);
+ df = dbeSession->getDbeFile (s, F_JAR_FILE | F_FILE);
+ free (s);
+ }
+ }
+ if (df == NULL)
+ df = dbeSession->getDbeFile (fnm, F_JAR_FILE | F_FILE);
+ if (df && (df->experiment == NULL))
+ df->experiment = experiment;
+ return df;
+}
+
+char *
+DbeFile::get_location (bool find_needed)
+{
+ Dprintf (DEBUG_DBE_FILE, NTXT ("get_location 0x%x %s\n"), filetype, STR (name));
+ if (!find_needed)
+ return need_refind ? NULL : location;
+ if (location || !need_refind)
+ return location;
+ set_need_refind (false);
+ if ((filetype & F_FICTION) != 0)
+ return NULL;
+ if (filetype == F_DIR_OR_JAR)
+ {
+ find_in_archives (name);
+ if (location)
+ {
+ filetype |= F_JAR_FILE | F_FILE;
+ return location;
+ }
+ find_in_pathmap (name);
+ if (location)
+ return location;
+ if (check_access (name) == F_DIRECTORY)
+ {
+ filetype |= F_DIRECTORY;
+ set_location (name);
+ return location;
+ }
+ }
+
+ if ((filetype & F_FILE) != 0)
+ {
+ if (experiment)
+ {
+ char *fnm = experiment->checkFileInArchive (name, false);
+ if (fnm)
+ {
+ set_location (fnm);
+ inArchive = true;
+ sbuf.st_mtime = 0; // Don't check timestamps
+ free (fnm);
+ return location;
+ }
+ if ((filetype & F_JAVACLASS) != 0)
+ {
+ if (orig_location)
+ {
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d name='%s' orig_location='%s'\n"),
+ (int) __LINE__, name, orig_location);
+ // Parse a fileName attribute. There are 4 possibilities:
+ // file:<Class_Name>
+ // file:<name_of_jar_or_zip_file>
+ // jar:file:<name_of_jar_or_zip_file>!<Class_Name>
+ // zip:<name_of_jar_or_zip_file>!<Class_Name>
+ DbeFile *jar_df = NULL;
+ if (strncmp (orig_location, NTXT ("zip:"), 4) == 0)
+ jar_df = getJarDbeFile (orig_location + 4, '!');
+ else if (strncmp (orig_location, NTXT ("jar:file:"), 9) == 0)
+ jar_df = getJarDbeFile (orig_location + 9, '!');
+ else if (strncmp (orig_location, NTXT ("file:"), 5) == 0
+ && isJarOrZip (orig_location + 5))
+ jar_df = getJarDbeFile (orig_location + 5, 0);
+ if (jar_df)
+ {
+ if (find_in_jar_file (name, jar_df->get_jar_file ()))
+ {
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s' jar='%s'\n"),
+ (int) __LINE__, name, STR (location), STR (jar_df->get_location ()));
+ inArchive = jar_df->inArchive;
+ container = jar_df;
+ return location;
+ }
+ }
+ if (strncmp (orig_location, NTXT ("file:"), 5) == 0
+ && !isJarOrZip (orig_location + 5))
+ {
+ DbeFile *df = new DbeFile (orig_location + 5);
+ df->filetype = DbeFile::F_FILE;
+ df->experiment = experiment;
+ fnm = df->get_location ();
+ if (fnm)
+ {
+ set_location (fnm);
+ inArchive = df->inArchive;
+ sbuf.st_mtime = df->sbuf.st_mtime;
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' orig_location='%s' location='%s'\n"),
+ (int) __LINE__, name, orig_location, fnm);
+ delete df;
+ return location;
+ }
+ delete df;
+ }
+ }
+ fnm = dbe_sprintf (NTXT ("%s/%s/%s"), experiment->get_expt_name (), SP_DYNAMIC_CLASSES, name);
+ if (find_file (fnm))
+ {
+ inArchive = true;
+ sbuf.st_mtime = 0; // Don't check timestamps
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s'\n"),
+ (int) __LINE__, name, fnm);
+ free (fnm);
+ return location;
+ }
+ free (fnm);
+ }
+ }
+ }
+
+ if (dbeSession->archive_mode)
+ {
+ find_file (name);
+ if (location)
+ return location;
+ }
+
+ bool inPathMap = find_in_pathmap (name);
+ if (location)
+ return location;
+ find_in_setpath (name, dbeSession->get_search_path ());
+ if (location)
+ return location;
+ if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
+ {
+ find_in_classpath (name, dbeSession->get_classpath ());
+ if (location)
+ return location;
+ }
+ if (!inPathMap)
+ find_file (name);
+ Dprintf (DEBUG_DBE_FILE && (location == NULL),
+ "DbeFile::get_location:%d NOT FOUND name='%s'\n", __LINE__, name);
+ return location;
+}
+
+int
+DbeFile::check_access (const char *filename)
+{
+ if (filename == NULL)
+ return F_NOT_FOUND;
+ int st = dbe_stat (filename, &sbuf);
+ Dprintf (DEBUG_DBE_FILE, NTXT ("check_access: %d 0x%x %s\n"), st, filetype, filename);
+ if (st == 0)
+ {
+ if (S_ISDIR (sbuf.st_mode))
+ return F_DIRECTORY;
+ else if (S_ISREG (sbuf.st_mode))
+ return F_FILE;
+ return F_UNKNOWN; // Symbolic link or unknown type of file
+ }
+ sbuf.st_atim.tv_sec = 0;
+ sbuf.st_mtime = 0; // Don't check timestamps
+ return F_NOT_FOUND; // File not found
+}
+
+bool
+DbeFile::isJarOrZip (const char *fnm)
+{
+ size_t len = strlen (fnm) - 4;
+ return len > 0 && (strcmp (fnm + len, NTXT (".jar")) == 0
+ || strcmp (fnm + len, NTXT (".zip")) == 0);
+}
+
+char *
+DbeFile::find_file (const char *filename)
+{
+ switch (check_access (filename))
+ {
+ case F_DIRECTORY:
+ if (filetype == F_DIR_OR_JAR)
+ filetype |= F_DIRECTORY;
+ if ((filetype & F_DIRECTORY) != 0)
+ set_location (filename);
+ break;
+ case F_FILE:
+ if (filetype == F_DIR_OR_JAR)
+ {
+ filetype |= F_FILE;
+ if (isJarOrZip (filename))
+ filetype |= F_JAR_FILE;
+ }
+ if ((filetype & F_DIRECTORY) == 0)
+ set_location (filename);
+ break;
+ }
+ return location;
+}
+
+DbeJarFile *
+DbeFile::get_jar_file ()
+{
+ if (jarFile == NULL)
+ {
+ char *fnm = get_location ();
+ if (fnm)
+ jarFile = dbeSession->get_JarFile (fnm);
+ }
+ return jarFile;
+}
+
+char *
+DbeFile::find_package_name (const char *filename, const char *dirname)
+{
+ char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename);
+ if (!find_in_pathmap (nm))
+ find_file (nm);
+ free (nm);
+ return location;
+}
+
+char *
+DbeFile::find_in_directory (const char *filename, const char *dirname)
+{
+ if (filename && dirname)
+ {
+ char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename);
+ find_file (nm);
+ free (nm);
+ }
+ return location;
+}
+
+char *
+DbeFile::find_in_jar_file (const char *filename, DbeJarFile *jfile)
+{
+ // Read .jar or .zip
+ if (jfile == NULL)
+ return NULL;
+ int entry = jfile->get_entry (filename);
+ if (entry >= 0)
+ {
+ char *fnm = dbeSession->get_tmp_file_name (filename, true);
+ long long fsize = jfile->copy (fnm, entry);
+ if (fsize >= 0)
+ {
+ dbeSession->tmp_files->append (fnm);
+ set_location (fnm);
+ sbuf.st_size = fsize;
+ sbuf.st_mtime = 0; // Don't check timestamps
+ fnm = NULL;
+ }
+ free (fnm);
+ }
+ return location;
+}
+
+bool
+DbeFile::find_in_pathmap (char *filename)
+{
+ Vector<pathmap_t*> *pathmaps = dbeSession->get_pathmaps ();
+ bool inPathMap = false;
+ if (strncmp (filename, NTXT ("./"), 2) == 0)
+ filename += 2;
+ for (int i = 0, sz = pathmaps ? pathmaps->size () : 0; i < sz; i++)
+ {
+ pathmap_t *pmp = pathmaps->fetch (i);
+ size_t len = strlen (pmp->old_prefix);
+ if (strncmp (pmp->old_prefix, filename, len) == 0
+ && (filename[len] == '/' || filename[len] == '\0'))
+ {
+ inPathMap = true;
+ if (find_in_directory (filename + len, pmp->new_prefix))
+ {
+ return inPathMap;
+ }
+ }
+ }
+ return inPathMap;
+}
+
+void
+DbeFile::find_in_archives (char *filename)
+{
+ for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (i1);
+ if (gr->founder)
+ {
+ char *nm = gr->founder->checkFileInArchive (filename, false);
+ if (nm)
+ {
+ find_file (nm);
+ if (location)
+ {
+ sbuf.st_mtime = 0; // Don't check timestamps
+ return;
+ }
+ }
+ }
+ }
+}
+
+void
+DbeFile::find_in_setpath (char *filename, Vector<char*> *searchPath)
+{
+ char *base = get_basename (filename);
+ for (int i = 0, sz = searchPath ? searchPath->size () : 0; i < sz; i++)
+ {
+ char *spath = searchPath->fetch (i);
+ // Check file in each experiment directory
+ if (streq (spath, "$") || streq (spath, NTXT ("$expts")))
+ {
+ // find only in founders and only LoadObj.
+ for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (i1);
+ char *exp_name = gr->founder->get_expt_name ();
+ if (gr->founder)
+ {
+ if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
+ {
+ // Find with the package name
+ if (find_in_directory (filename, exp_name))
+ return;
+ }
+ if (find_in_directory (base, exp_name))
+ return;
+ }
+ }
+ continue;
+ }
+ DbeFile *df = dbeSession->getDbeFile (spath, DbeFile::F_DIR_OR_JAR);
+ if (df->get_location () == NULL)
+ continue;
+ if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
+ {
+ if ((df->filetype & F_JAR_FILE) != 0)
+ {
+ if (find_in_jar_file (filename, df->get_jar_file ()))
+ {
+ container = df;
+ return;
+ }
+ continue;
+ }
+ else if ((df->filetype & F_DIRECTORY) != 0)
+ // Find with the package name
+ if (find_package_name (filename, spath))
+ return;
+ }
+ if ((df->filetype & F_DIRECTORY) != 0)
+ if (find_in_directory (base, df->get_location ()))
+ return;
+ }
+}
+
+void
+DbeFile::find_in_classpath (char *filename, Vector<DbeFile*> *classPath)
+{
+ for (int i = 0, sz = classPath ? classPath->size () : 0; i < sz; i++)
+ {
+ DbeFile *df = classPath->fetch (i);
+ if (df->get_location () == NULL)
+ continue;
+ if ((df->filetype & F_JAR_FILE) != 0)
+ {
+ if (find_in_jar_file (filename, df->get_jar_file ()))
+ {
+ container = df;
+ return;
+ }
+ }
+ else if ((df->filetype & F_DIRECTORY) != 0)
+ // Find with the package name
+ if (find_package_name (filename, df->get_name ()))
+ return;
+ }
+}
+
+struct stat64 *
+DbeFile::get_stat ()
+{
+ if (sbuf.st_atim.tv_sec == 0)
+ {
+ int st = check_access (get_location (false));
+ if (st == F_NOT_FOUND)
+ return NULL;
+ }
+ return &sbuf;
+}
+
+bool
+DbeFile::compare (DbeFile *df)
+{
+ if (df == NULL)
+ return false;
+ struct stat64 *st1 = get_stat ();
+ struct stat64 *st2 = df->get_stat ();
+ if (st1 == NULL || st2 == NULL)
+ return false;
+ if (st1->st_size != st2->st_size)
+ return false;
+ if (st1->st_mtim.tv_sec != st2->st_mtim.tv_sec)
+ return false;
+ return true;
+}
diff --git a/gprofng/src/DbeFile.h b/gprofng/src/DbeFile.h
new file mode 100644
index 0000000..abd7180
--- /dev/null
+++ b/gprofng/src/DbeFile.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_FILE_H
+#define _DBE_FILE_H
+
+#include <fcntl.h>
+
+class DbeJarFile;
+class Experiment;
+template <class ITEM> class Vector;
+
+class DbeFile
+{
+public:
+
+ enum
+ {
+ F_NOT_FOUND = 0,
+ F_FICTION = 1,
+ F_LOADOBJ = 2,
+ F_SOURCE = 4,
+ F_JAVACLASS = 8,
+ F_JAVA_SOURCE = 16,
+ F_DOT_O = 32,
+ F_DEBUG_FILE = 64,
+ F_DOT_A_LIB = 128,
+ F_DIR_OR_JAR = 256,
+ F_DIRECTORY = 512,
+ F_FILE = 1024,
+ F_JAR_FILE = 2048,
+ F_UNKNOWN = 65536
+ };
+
+ DbeFile (const char *filename);
+ ~DbeFile ();
+
+ char *
+ get_name ()
+ {
+ return name;
+ };
+
+ bool
+ get_need_refind ()
+ {
+ return need_refind;
+ };
+
+ char *get_location (bool find_needed = true);
+ char *getResolvedPath ();
+ char *get_location_info ();
+ struct stat64 *get_stat ();
+ bool compare (DbeFile *df);
+ void set_need_refind (bool val);
+ void set_location (const char *filename);
+ int check_access (const char *filename);
+ char *find_file (const char *filename);
+ DbeFile *getJarDbeFile (char *fnm, int sym);
+ char *find_in_jar_file (const char *filename, DbeJarFile *jfile);
+ DbeJarFile *get_jar_file ();
+
+ bool inArchive;
+ int filetype;
+ struct stat64 sbuf;
+ DbeFile *container;
+ char *orig_location;
+ Experiment *experiment;
+
+protected:
+ static bool isJarOrZip (const char *fnm);
+ char *find_package_name (const char *filename, const char *dirname);
+ char *find_in_directory (const char *filename, const char *dirname);
+ bool find_in_pathmap (char *filename);
+ void find_in_archives (char *filename);
+ void find_in_setpath (char *filename, Vector<char*> *searchPath);
+ void find_in_classpath (char *filename, Vector<DbeFile*> *classPath);
+
+ char *name;
+ char *location;
+ char *location_info;
+ bool need_refind;
+ DbeJarFile *jarFile;
+};
+
+#endif /* _DBE_FILE_H */
diff --git a/gprofng/src/DbeJarFile.cc b/gprofng/src/DbeJarFile.cc
new file mode 100644
index 0000000..9029512
--- /dev/null
+++ b/gprofng/src/DbeJarFile.cc
@@ -0,0 +1,505 @@
+/* Copyright (C) 2021 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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "zlib.h"
+#include "util.h"
+#include "DbeJarFile.h"
+#include "Data_window.h"
+#include "vec.h"
+
+static uint32_t
+get_u1 (unsigned char *b)
+{
+ return (uint32_t) ((b)[0]);
+}
+
+static uint32_t
+get_u2 (unsigned char *b)
+{
+ return (get_u1 (b + 1) << 8) | get_u1 (b);
+}
+
+static uint32_t
+get_u4 (unsigned char *b)
+{
+ return (get_u2 (b + 2) << 16) | get_u2 (b);
+}
+
+static uint64_t
+get_u8 (unsigned char *b)
+{
+ return (((uint64_t) get_u4 (b + 4)) << 32) | get_u4 (b);
+}
+
+enum
+{
+ END_CENT_DIR_SIZE = 22,
+ LOC_FILE_HEADER_SIZE = 30,
+ CENT_FILE_HEADER_SIZE = 46,
+ ZIP64_LOCATOR_SIZE = 20,
+ ZIP64_CENT_DIR_SIZE = 56,
+ ZIP_BUF_SIZE = 65536
+};
+
+struct EndCentDir
+{
+ uint64_t count;
+ uint64_t size;
+ uint64_t offset;
+};
+
+class ZipEntry
+{
+public:
+
+ ZipEntry ()
+ {
+ name = NULL;
+ data_offset = 0;
+ }
+
+ ~ZipEntry ()
+ {
+ free (name);
+ }
+
+ int
+ compare (ZipEntry *ze)
+ {
+ return dbe_strcmp (name, ze->name);
+ }
+
+ char *name; // entry name
+ int time; // modification time
+ int64_t size; // size of uncompressed data
+ int64_t csize; // size of compressed data (zero if uncompressed)
+ uint32_t compressionMethod;
+ int64_t offset; // offset of LOC header
+ int64_t data_offset;
+};
+
+static int
+cmp_names (const void *a, const void *b)
+{
+ ZipEntry *e1 = *((ZipEntry **) a);
+ ZipEntry *e2 = *((ZipEntry **) b);
+ return e1->compare (e2);
+}
+
+template<> void Vector<ZipEntry *>::dump (const char *msg)
+{
+ Dprintf (1, NTXT ("Vector<ZipEntry *> %s [%lld]\n"), msg ? msg : NTXT (""), (long long) size ());
+ for (long i = 0, sz = size (); i < sz; i++)
+ {
+ ZipEntry *ze = get (i);
+ Dprintf (1, NTXT (" %lld offset:%lld (0x%llx) size: %lld --> %lld %s\n"),
+ (long long) i, (long long) ze->offset, (long long) ze->offset,
+ (long long) ze->csize, (long long) ze->size, STR (ze->name));
+ }
+}
+
+DbeJarFile::DbeJarFile (const char *jarName)
+{
+ name = strdup (jarName);
+ fnames = NULL;
+ dwin = new Data_window (name);
+ get_entries ();
+}
+
+DbeJarFile::~DbeJarFile ()
+{
+ free (name);
+ delete fnames;
+}
+
+void
+DbeJarFile::get_entries ()
+{
+ Dprintf (DUMP_JAR_FILE, NTXT ("\nArchive: %s\n"), STR (name));
+ if (dwin->not_opened ())
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot open file `%s'"), name);
+ return;
+ }
+ struct EndCentDir endCentDir;
+ if (get_EndCentDir (&endCentDir) == 0)
+ return;
+
+ if (endCentDir.count == 0)
+ {
+ append_msg (CMSG_WARN, GTXT ("No files in %s"), name);
+ return;
+ }
+ unsigned char *b = (unsigned char *) dwin->bind (endCentDir.offset, endCentDir.size);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: cannot read the central directory record"), name);
+ return;
+ }
+
+ fnames = new Vector<ZipEntry*>(endCentDir.count);
+ for (uint64_t i = 0, offset = endCentDir.offset, last = endCentDir.offset + endCentDir.size; i < endCentDir.count; i++)
+ {
+ if ((last - offset) < CENT_FILE_HEADER_SIZE)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: cannot read the central file header (%lld (from %lld), offset=0x%016llx last=0x%016llx"),
+ name, (long long) i, (long long) endCentDir.count, (long long) offset, (long long) last);
+ break;
+ }
+ b = (unsigned char *) dwin->bind (offset, CENT_FILE_HEADER_SIZE);
+ // Central file header
+ // Offset Bytes Description
+ // 0 4 central file header signature = 0x02014b50
+ // 4 2 version made by
+ // 6 2 version needed to extract
+ // 8 2 general purpose bit flag
+ // 10 2 compression method
+ // 12 2 last mod file time
+ // 14 2 last mod file date
+ // 16 4 crc-32
+ // 20 4 compressed size
+ // 24 4 uncompressed size
+ // 28 2 file name length
+ // 30 2 extra field length
+ // 32 2 file comment length
+ // 34 2 disk number start
+ // 36 2 internal file attributes
+ // 38 4 external file attributes
+ // 42 4 relative offset of local header
+ // 46 file name (variable size)
+ // extra field (variable size)
+ // file comment (variable size)
+ uint32_t signature = get_u4 (b);
+ if (signature != 0x02014b50)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: wrong header signature (%lld (total %lld), offset=0x%016llx last=0x%016llx"),
+ name, (long long) i, (long long) endCentDir.count, (long long) offset, (long long) last);
+ break;
+ }
+ ZipEntry *ze = new ZipEntry ();
+ fnames->append (ze);
+ uint32_t name_len = get_u2 (b + 28);
+ uint32_t extra_len = get_u2 (b + 30);
+ uint32_t comment_len = get_u2 (b + 32);
+ ze->compressionMethod = get_u2 (b + 10);
+ ze->csize = get_u4 (b + 20);
+ ze->size = get_u4 (b + 24);
+ ze->offset = get_u4 (b + 42);
+ char *nm = (char *) dwin->bind (offset + 46, name_len);
+ if (nm)
+ {
+ ze->name = (char *) malloc (name_len + 1);
+ strncpy (ze->name, nm, name_len);
+ ze->name[name_len] = 0;
+ }
+ offset += CENT_FILE_HEADER_SIZE + name_len + extra_len + comment_len;
+ }
+ fnames->sort (cmp_names);
+ if (DUMP_JAR_FILE)
+ fnames->dump (get_basename (name));
+}
+
+int
+DbeJarFile::get_entry (const char *fname)
+{
+ if (fnames == NULL)
+ return -1;
+ ZipEntry zipEntry, *ze = &zipEntry;
+ ze->name = (char *) fname;
+ int ind = fnames->bisearch (0, -1, &ze, cmp_names);
+ ze->name = NULL;
+ return ind;
+}
+
+long long
+DbeJarFile::copy (char *toFileNname, int fromEntryNum)
+{
+ if (fromEntryNum < 0 || fromEntryNum >= VecSize (fnames))
+ return -1;
+ ZipEntry *ze = fnames->get (fromEntryNum);
+ if (ze->data_offset == 0)
+ {
+ // Local file header
+ // Offset Bytes Description
+ // 0 4 local file header signature = 0x04034b50
+ // 4 2 version needed to extract
+ // 6 2 general purpose bit flag
+ // 8 2 compression method
+ // 10 2 last mod file time
+ // 12 2 last mod file date
+ // 14 4 crc-32
+ // 18 4 compressed size
+ // 22 4 uncompressed size
+ // 26 2 file name length
+ // 28 2 extra field length
+ // 30 2 file name (variable size)
+ // extra field (variable size)
+ unsigned char *b = (unsigned char *) dwin->bind (ze->offset, LOC_FILE_HEADER_SIZE);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("%s: Cannot read a local file header (%s offset=0x%lld"),
+ name, STR (ze->name), (long long) ze->offset);
+ return -1;
+ }
+ uint32_t signature = get_u4 (b);
+ if (signature != 0x04034b50)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("%s: wrong local header signature ('%s' offset=%lld (0x%llx)"),
+ name, STR (ze->name), (long long) ze->offset,
+ (long long) ze->offset);
+ return -1;
+ }
+ ze->data_offset = ze->offset + LOC_FILE_HEADER_SIZE + get_u2 (b + 26) + get_u2 (b + 28);
+ }
+
+ if (ze->compressionMethod == 0)
+ {
+ int fd = open (toFileNname, O_CREAT | O_WRONLY | O_LARGEFILE, 0644);
+ if (fd == -1)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot create file %s (%s)"), toFileNname, STR (strerror (errno)));
+ return -1;
+ }
+ long long len = dwin->copy_to_file (fd, ze->data_offset, ze->size);
+ close (fd);
+ if (len != ze->size)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: Cannot write %lld bytes (only %lld)"),
+ toFileNname, (long long) ze->size, (long long) len);
+ unlink (toFileNname);
+ return -1;
+ }
+ return len;
+ }
+
+ unsigned char *b = (unsigned char *) dwin->bind (ze->data_offset, ze->csize);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("%s: Cannot extract file %s (offset=0x%lld csize=%lld)"),
+ name, STR (ze->name), (long long) ze->offset,
+ (long long) ze->csize);
+ return -1;
+ }
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.next_in = Z_NULL;
+ strm.avail_in = 0;
+ if (inflateInit2 (&strm, -MAX_WBITS) != Z_OK)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: inflateInit2 failed (%s)"), STR (ze->name), STR (strm.msg));
+ return -1;
+ }
+ strm.avail_in = ze->csize;
+ strm.next_in = b;
+ int retval = ze->size;
+ unsigned char *buf = (unsigned char *) malloc (ze->size);
+ for (;;)
+ {
+ strm.next_out = buf;
+ strm.avail_out = ze->size;
+ int ret = inflate (&strm, Z_SYNC_FLUSH);
+ if ((ret == Z_NEED_DICT) || (ret == Z_DATA_ERROR) || (ret == Z_MEM_ERROR) || (ret == Z_STREAM_ERROR))
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: inflate('%s') error %d (%s)"), name, STR (ze->name), ret, STR (strm.msg));
+ retval = -1;
+ break;
+ }
+ if (strm.avail_out != 0)
+ break;
+ }
+ inflateEnd (&strm);
+ if (retval != -1)
+ {
+ int fd = open (toFileNname, O_CREAT | O_WRONLY | O_LARGEFILE, 0644);
+ if (fd == -1)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot create file %s (%s)"), toFileNname, STR (strerror (errno)));
+ retval = -1;
+ }
+ else
+ {
+ long long len = write (fd, buf, ze->size);
+ if (len != ze->size)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: Cannot write %lld bytes (only %lld)"),
+ toFileNname, (long long) strm.avail_out, (long long) len);
+ retval = -1;
+ }
+ close (fd);
+ }
+ }
+ free (buf);
+ return retval;
+}
+
+int
+DbeJarFile::get_EndCentDir (struct EndCentDir *endCentDir)
+{
+ int64_t fsize = dwin->get_fsize ();
+ int64_t sz = (fsize < ZIP_BUF_SIZE) ? fsize : ZIP_BUF_SIZE;
+
+ // Find the end of central directory record:
+ unsigned char *b = (unsigned char *) dwin->bind (fsize - sz, sz);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: cannot find the central directory record (fsize=%lld)"),
+ name, (long long) fsize);
+ return 0;
+ }
+
+ // End of central directory record:
+ // Offset Bytes Description
+ // 0 4 end of central directory signature = 0x06054b50
+ // 4 2 number of this disk
+ // 6 2 disk where central directory starts
+ // 8 2 number of central directory records on this disk
+ // 10 2 total number of central directory records
+ // 12 4 size of central directory(bytes)
+ // 16 4 offset of start of central directory, relative to start of archive
+ // 20 2 comment length(n)
+ // 22 n comment
+
+ endCentDir->count = 0;
+ endCentDir->size = 0;
+ endCentDir->offset = 0;
+ int64_t ecdrOffset = fsize;
+ for (int64_t i = END_CENT_DIR_SIZE; i < sz; i++)
+ {
+ b = (unsigned char *) dwin->bind (fsize - i, END_CENT_DIR_SIZE);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: read failed (offset:0x%llx bytes:%lld"),
+ name, (long long) (fsize - i), (long long) END_CENT_DIR_SIZE);
+ break;
+ }
+ uint32_t signature = get_u4 (b);
+ if (signature == 0x06054b50)
+ {
+ int64_t len_comment = get_u2 (b + 20);
+ if (i != (len_comment + END_CENT_DIR_SIZE))
+ continue;
+ ecdrOffset = fsize - i;
+ endCentDir->count = get_u2 (b + 10);
+ endCentDir->size = get_u4 (b + 12);
+ endCentDir->offset = get_u4 (b + 16);
+ Dprintf (DUMP_JAR_FILE,
+ " Zip archive file size: %10lld (0x%016llx)\n"
+ " end-cent-dir record offset: %10lld (0x%016llx)\n"
+ " cent-dir offset: %10lld (0x%016llx)\n"
+ " cent-dir size: %10lld (0x%016llx)\n"
+ " cent-dir entries: %10lld\n",
+ (long long) fsize, (long long) fsize,
+ (long long) ecdrOffset, (long long) ecdrOffset,
+ (long long) endCentDir->offset, (long long) endCentDir->offset,
+ (long long) endCentDir->size, (long long) endCentDir->size,
+ (long long) endCentDir->count);
+ break;
+ }
+ }
+ if (ecdrOffset == fsize)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("%s: cannot find the central directory record"), name);
+ return 0;
+ }
+ if (endCentDir->count == 0xffff || endCentDir->offset == 0xffffffff
+ || endCentDir->size == 0xffffffff)
+ {
+ // Zip64 format:
+ // Zip64 end of central directory record
+ // Zip64 end of central directory locator ( Can be absent )
+ // End of central directory record
+ b = (unsigned char *) dwin->bind (ecdrOffset - ZIP64_LOCATOR_SIZE,
+ ZIP64_LOCATOR_SIZE);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("%s: cannot find the Zip64 central directory record"), name);
+ return 0;
+ }
+ uint32_t signature = get_u4 (b);
+ if (signature == 0x07064b50)
+ { // Get an offset from the Zip64 cent-dir locator
+ // Zip64 end of central directory locator
+ // Offset Bytes Description
+ // 0 4 Zip64 end of central dir locator signature = 0x07064b50
+ // 4 4 number of the disk with the start of the zip64 end of central directory
+ // 8 8 relative offset of the Zip64 end of central directory record
+ // 12 4 total number of disks
+ Dprintf (DUMP_JAR_FILE, " cent-dir locator offset %10lld (0x%016llx)\n",
+ (long long) (ecdrOffset - ZIP64_LOCATOR_SIZE), (long long) (ecdrOffset - ZIP64_LOCATOR_SIZE));
+ ecdrOffset = get_u8 (b + 8);
+ }
+ else // the Zip64 end of central directory locator is absent
+ ecdrOffset -= ZIP64_CENT_DIR_SIZE;
+ Dprintf (DUMP_JAR_FILE, NTXT (" Zip64 end-cent-dir record offset: %10lld (0x%016llx)\n"),
+ (long long) ecdrOffset, (long long) ecdrOffset);
+
+ b = (unsigned char *) dwin->bind (ecdrOffset, ZIP64_CENT_DIR_SIZE);
+ if (b == NULL)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("%s: cannot find the Zip64 central directory record"), name);
+ return 0;
+ }
+ // Zip64 end of central directory record
+ // Offset Bytes Description
+ // 0 4 Zip64 end of central dir signature = 0x06064b50
+ // 4 8 size of zip64 end of central directory record
+ // 12 2 version made by
+ // 14 2 version needed to extract
+ // 16 4 number of this disk
+ // 20 4 number of the disk with the start of the central directory
+ // 24 8 total number of entries in the central directory on this disk
+ // 32 8 total number of entries in the central directory
+ // 40 8 size of the central directory
+ // 48 8 offset of start of centraldirectory with respect to the starting disk number
+ // 56 Zip64 extensible data sector (variable size)
+ signature = get_u4 (b);
+ if (signature != 0x06064b50)
+ {
+ append_msg (CMSG_ERROR, GTXT ("%s: cannot find the Zip64 central directory record"), name);
+ return 0;
+ }
+ endCentDir->count = get_u8 (b + 32);
+ endCentDir->size = get_u8 (b + 40);
+ endCentDir->offset = get_u8 (b + 48);
+ Dprintf (DUMP_JAR_FILE,
+ NTXT (" cent-dir offset: %10lld (0x%016llx)\n"
+ " cent-dir size: %10lld (0x%016llx)\n"
+ " cent-dir entries: %10lld\n"),
+ (long long) endCentDir->offset, (long long) endCentDir->offset,
+ (long long) endCentDir->size, (long long) endCentDir->size,
+ (long long) endCentDir->count);
+ }
+ return 1;
+}
+
diff --git a/gprofng/src/DbeJarFile.h b/gprofng/src/DbeJarFile.h
new file mode 100644
index 0000000..f0b4f7b
--- /dev/null
+++ b/gprofng/src/DbeJarFile.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_JAR_FILE_H
+#define _DBE_JAR_FILE_H
+
+#include "Emsg.h"
+
+class Data_window;
+class ZipEntry;
+template <class ITEM> class Vector;
+
+class DbeJarFile : public DbeMessages
+{
+public:
+ DbeJarFile (const char *jarName);
+ ~DbeJarFile ();
+
+ int get_entry (const char *fname);
+ long long copy (char *toFileNname, int fromEntryNum);
+
+private:
+ void get_entries ();
+ int get_EndCentDir (struct EndCentDir *endCentDir);
+ char *name;
+ Vector<ZipEntry *> *fnames;
+ Data_window *dwin;
+};
+#endif /* _DBE_JAR_FILE_H */
diff --git a/gprofng/src/DbeLinkList.h b/gprofng/src/DbeLinkList.h
new file mode 100644
index 0000000..760cc67
--- /dev/null
+++ b/gprofng/src/DbeLinkList.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DbeLinkList_h
+#define _DbeLinkList_h
+
+template <typename ITEM> class DbeLinkList
+{
+public:
+
+ DbeLinkList (ITEM _item)
+ {
+ item = _item;
+ next = NULL;
+ };
+
+ ~DbeLinkList () { };
+
+ ITEM
+ get_item ()
+ {
+ return item;
+ }
+
+ DbeLinkList<ITEM> *
+ get_next ()
+ {
+ return next;
+ }
+
+ void
+ set_next (DbeLinkList<ITEM> *p)
+ {
+ next = p;
+ }
+
+ void
+ destroy (bool deleteItem = false)
+ {
+ for (DbeLinkList<ITEM> *p = next; p;)
+ {
+ DbeLinkList<ITEM> *p1 = p->get_next ();
+ if (deleteItem)
+ delete p->get_item ();
+ delete p;
+ p = p1;
+ }
+ next = NULL;
+ }
+
+private:
+ ITEM item;
+ DbeLinkList<ITEM> *next;
+};
+
+#endif /* _DbeLinkList_h */
diff --git a/gprofng/src/DbeLock.cc b/gprofng/src/DbeLock.cc
new file mode 100644
index 0000000..14a1eb3
--- /dev/null
+++ b/gprofng/src/DbeLock.cc
@@ -0,0 +1,41 @@
+/* Copyright (C) 2021 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 "DbeLock.h"
+
+DbeLock::DbeLock ()
+{
+ pthread_mutex_init (&lock, NULL);
+}
+
+DbeLock::~DbeLock () { }
+
+void
+DbeLock::aquireLock ()
+{
+ pthread_mutex_lock (&lock);
+}
+
+void
+DbeLock::releaseLock ()
+{
+ pthread_mutex_unlock (&lock);
+}
diff --git a/gprofng/src/DbeLock.h b/gprofng/src/DbeLock.h
new file mode 100644
index 0000000..28dfb6e
--- /dev/null
+++ b/gprofng/src/DbeLock.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_LOCK_H
+#define _DBE_LOCK_H
+
+#include <pthread.h>
+
+class DbeLock
+{
+public:
+ DbeLock ();
+ ~DbeLock ();
+ void aquireLock ();
+ void releaseLock ();
+
+private:
+ pthread_mutex_t lock;
+};
+
+#endif /* _DBE_LOCK_H */
diff --git a/gprofng/src/DbeSession.cc b/gprofng/src/DbeSession.cc
new file mode 100644
index 0000000..4370114
--- /dev/null
+++ b/gprofng/src/DbeSession.cc
@@ -0,0 +1,3527 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "ExpGroup.h"
+#include "Expression.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "DbeSession.h"
+#include "LoadObject.h"
+#include "DbeSyncMap.h"
+#include "DbeThread.h"
+#include "ClassFile.h"
+#include "IndexObject.h"
+#include "PathTree.h"
+#include "Print.h"
+#include "QLParser.tab.hh"
+#include "DbeView.h"
+#include "MemorySpace.h"
+#include "Module.h"
+#include "SourceFile.h"
+#include "StringBuilder.h"
+#include "BaseMetric.h"
+#include "BaseMetricTreeNode.h"
+#include "Command.h"
+#include "UserLabel.h"
+#include "StringMap.h"
+#include "DbeFile.h"
+#include "DbeJarFile.h"
+#include "IOActivity.h"
+#include "HeapActivity.h"
+
+// This is a universal List structure to organize objects
+// of various types, even if different.
+struct List
+{
+ List *next;
+ void *val;
+};
+
+struct Countable
+{
+ Countable (void *_item)
+ {
+ item = _item;
+ ref_count = 0;
+ }
+
+ void *item;
+ int ref_count;
+};
+
+Platform_t DbeSession::platform =
+#if ARCH(SPARC)
+ Sparc;
+#elif ARCH(Aarch64)
+ Aarch64;
+#else // ARCH(Intel)
+ Intel;
+#endif
+
+// This constant determines the size of the data object name hash table.
+static const int HTableSize = 8192;
+static int DEFAULT_TINY_THRESHOLD = -1;
+
+unsigned int mpmt_debug_opt = 0;
+DbeSession *dbeSession = NULL;
+
+DbeSession::DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode)
+{
+ dbeSession = this;
+ ipc_mode = _ipc_mode;
+ rdt_mode = _rdt_mode;
+ settings = new Settings (_settings);
+ views = new Vector<DbeView*>;
+ exps = new Vector<Experiment*>;
+ lobjs = new Vector<LoadObject*>;
+ objs = new Vector<Histable*>;
+ dobjs = new Vector<DataObject*>;
+ metrics = new Vector<Countable*>;
+ reg_metrics = new Vector<BaseMetric*>;
+ hwcentries = NULL;
+ reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse
+ idxobjs = new Vector<HashMap<uint64_t, Histable*>*>;
+ tmp_files = new Vector<char*>;
+ search_path = new Vector<char*>;
+ classpath = new Vector<char*>;
+ classpath_df = NULL;
+ expGroups = new Vector<ExpGroup*>;
+ sourcesMap = new HashMap<char*, SourceFile*>;
+ sources = new Vector<SourceFile*>;
+ comp_lobjs = new HashMap<char*, LoadObject*>;
+ comp_dbelines = new HashMap<char*, DbeLine*>;
+ comp_sources = new HashMap<char*, SourceFile*>;
+ loadObjMap = new DbeSyncMap<LoadObject>;
+ f_special = new Vector<Function*>(LastSpecialFunction);
+ omp_functions = new Vector<Function*>(OMP_LAST_STATE);
+ interactive = false;
+ lib_visibility_used = false;
+
+ // Define all known property names
+ propNames = new Vector<PropDescr*>;
+ propNames_name_store (PROP_NONE, NTXT (""));
+ propNames_name_store (PROP_ATSTAMP, NTXT ("ATSTAMP"));
+ propNames_name_store (PROP_ETSTAMP, NTXT ("ETSTAMP"));
+ propNames_name_store (PROP_TSTAMP, NTXT ("TSTAMP"));
+ propNames_name_store (PROP_THRID, NTXT ("THRID"));
+ propNames_name_store (PROP_LWPID, NTXT ("LWPID"));
+ propNames_name_store (PROP_CPUID, NTXT ("CPUID"));
+ propNames_name_store (PROP_FRINFO, NTXT ("FRINFO"));
+ propNames_name_store (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+
+ // Samples
+ propNames_name_store (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
+ propNames_name_store (PROP_SAMPLE, NTXT ("SAMPLE"));
+
+ // GCEvents
+ propNames_name_store (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
+ propNames_name_store (PROP_GCEVENT, NTXT ("GCEVENT"));
+
+ // Metadata used by some packet types
+ propNames_name_store (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"),
+ NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+ // Clock profiling properties
+ propNames_name_store (PROP_UCPU, NTXT ("UCPU"));
+ propNames_name_store (PROP_SCPU, NTXT ("SCPU"));
+ propNames_name_store (PROP_TRAP, NTXT ("TRAP"));
+ propNames_name_store (PROP_TFLT, NTXT ("TFLT"));
+ propNames_name_store (PROP_DFLT, NTXT ("DFLT"));
+ propNames_name_store (PROP_KFLT, NTXT ("KFLT"));
+ propNames_name_store (PROP_ULCK, NTXT ("ULCK"));
+ propNames_name_store (PROP_TSLP, NTXT ("TSLP"));
+ propNames_name_store (PROP_WCPU, NTXT ("WCPU"));
+ propNames_name_store (PROP_TSTP, NTXT ("TSTP"));
+
+ propNames_name_store (PROP_MSTATE, NTXT ("MSTATE"));
+ propNames_name_store (PROP_NTICK, NTXT ("NTICK"));
+ propNames_name_store (PROP_OMPSTATE, NTXT ("OMPSTATE"));
+
+ // Synchronization tracing properties
+ propNames_name_store (PROP_SRQST, NTXT ("SRQST"));
+ propNames_name_store (PROP_SOBJ, NTXT ("SOBJ"));
+
+ // Hardware counter profiling properties
+ propNames_name_store (PROP_HWCTAG, NTXT ("HWCTAG"));
+ propNames_name_store (PROP_HWCINT, NTXT ("HWCINT"));
+ propNames_name_store (PROP_VADDR, NTXT ("VADDR"));
+ propNames_name_store (PROP_PADDR, NTXT ("PADDR"));
+ propNames_name_store (PROP_VIRTPC, NTXT ("VIRTPC"));
+ propNames_name_store (PROP_PHYSPC, NTXT ("PHYSPC"));
+ propNames_name_store (PROP_LWP_LGRP_HOME, NTXT ("LWP_LGRP_HOME"));
+ propNames_name_store (PROP_PS_LGRP_HOME, NTXT ("PS_LGRP_HOME"));
+ propNames_name_store (PROP_EA_PAGESIZE, NTXT ("EA_PAGESIZE"));
+ propNames_name_store (PROP_EA_LGRP, NTXT ("EA_LGRP"));
+ propNames_name_store (PROP_PC_PAGESIZE, NTXT ("PC_PAGESIZE"));
+ propNames_name_store (PROP_PC_LGRP, NTXT ("PC_LGRP"));
+ propNames_name_store (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+ propNames_name_store (PROP_MEM_LAT, NTXT ("MEM_LAT"));
+ propNames_name_store (PROP_MEM_SRC, NTXT ("MEM_SRC"));
+
+ // Heap tracing properties
+ propNames_name_store (PROP_HTYPE, NTXT ("HTYPE"));
+ propNames_name_store (PROP_HSIZE, NTXT ("HSIZE"));
+ propNames_name_store (PROP_HVADDR, NTXT ("HVADDR"));
+ propNames_name_store (PROP_HOVADDR, NTXT ("HOVADDR"));
+ propNames_name_store (PROP_HLEAKED, NTXT ("HLEAKED"),
+ GTXT ("Leaked bytes"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
+ propNames_name_store (PROP_HFREED, NTXT ("HFREED"),
+ GTXT ("Freed bytes"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"),
+ GTXT ("Current allocations"), TYPE_INT64, 0);
+ propNames_name_store (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"),
+ NULL, TYPE_INT64, DDFLAG_NOSHOW);
+ propNames_name_store (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"),
+ GTXT ("Current leaks"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"),
+ NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+ // IO tracing properties
+ propNames_name_store (PROP_IOTYPE, NTXT ("IOTYPE"));
+ propNames_name_store (PROP_IOFD, NTXT ("IOFD"));
+ propNames_name_store (PROP_IONBYTE, NTXT ("IONBYTE"));
+ propNames_name_store (PROP_IORQST, NTXT ("IORQST"));
+ propNames_name_store (PROP_IOOFD, NTXT ("IOOFD"));
+ propNames_name_store (PROP_IOFNAME, NTXT ("IOFNAME"));
+ propNames_name_store (PROP_IOVFD, NTXT ("IOVFD"));
+ propNames_name_store (PROP_IOFSTYPE, NTXT ("IOFSTYPE"));
+
+ // omptrace raw properties
+ propNames_name_store (PROP_CPRID, NTXT ("CPRID"));
+ propNames_name_store (PROP_PPRID, NTXT ("PPRID"));
+ propNames_name_store (PROP_TSKID, NTXT ("TSKID"));
+ propNames_name_store (PROP_PTSKID, NTXT ("PTSKID"));
+ propNames_name_store (PROP_PRPC, NTXT ("PRPC"));
+
+ // Data race detection properties
+ propNames_name_store (PROP_RID, NTXT ("RID"));
+ propNames_name_store (PROP_RTYPE, NTXT ("RTYPE"));
+ propNames_name_store (PROP_LEAFPC, NTXT ("LEAFPC"));
+ propNames_name_store (PROP_RVADDR, NTXT ("RVADDR"));
+ propNames_name_store (PROP_RCNT, NTXT ("RCNT"));
+
+ // Deadlock detection properties
+ propNames_name_store (PROP_DID, NTXT ("DID"));
+ propNames_name_store (PROP_DLTYPE, NTXT ("DLTYPE"));
+ propNames_name_store (PROP_DTYPE, NTXT ("DTYPE"));
+ propNames_name_store (PROP_DVADDR, NTXT ("DVADDR"));
+
+ // Synthetic properties (queries only)
+ propNames_name_store (PROP_STACK, NTXT ("STACK"));
+ propNames_name_store (PROP_MSTACK, NTXT ("MSTACK"));
+ propNames_name_store (PROP_USTACK, NTXT ("USTACK"));
+ propNames_name_store (PROP_XSTACK, NTXT ("XSTACK"));
+ propNames_name_store (PROP_HSTACK, NTXT ("HSTACK"));
+ propNames_name_store (PROP_STACKID, NTXT ("STACKID"));
+ //propNames_name_store( PROP_CPRID, NTXT("CPRID") );
+ //propNames_name_store( PROP_TSKID, NTXT("TSKID") );
+ propNames_name_store (PROP_JTHREAD, NTXT ("JTHREAD"),
+ GTXT ("Java thread number"), TYPE_UINT64, 0);
+
+ propNames_name_store (PROP_LEAF, NTXT ("LEAF"));
+ propNames_name_store (PROP_DOBJ, NTXT ("DOBJ"));
+ propNames_name_store (PROP_SAMPLE_MAP, NTXT ("SAMPLE_MAP"));
+ propNames_name_store (PROP_GCEVENT_MAP, NTXT ("GCEVENT_MAP"));
+ propNames_name_store (PROP_PID, NTXT ("PID"),
+ GTXT ("Process id"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_EXPID, NTXT ("EXPID"),
+ GTXT ("Experiment id"), TYPE_UINT64, DDFLAG_NOSHOW);
+ propNames_name_store (PROP_EXPID_CMP, NTXT ("EXPID_CMP"),
+ GTXT ("Comparable Experiment Id"), TYPE_UINT64,
+ DDFLAG_NOSHOW); //YXXX find better description
+ propNames_name_store (PROP_EXPGRID, NTXT ("EXPGRID"),
+ GTXT ("Comparison Group id"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_PARREG, NTXT ("PARREG"));
+ propNames_name_store (PROP_TSTAMP_LO, NTXT ("TSTAMP_LO"),
+ GTXT ("Start Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_TSTAMP_HI, NTXT ("TSTAMP_HI"),
+ GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_TSTAMP2, NTXT ("TSTAMP2"),
+ GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64,
+ DDFLAG_NOSHOW);
+ propNames_name_store (PROP_FREQ_MHZ, NTXT ("FREQ_MHZ"),
+ GTXT ("CPU Frequency, MHz"), TYPE_UINT32, 0);
+ propNames_name_store (PROP_NTICK_USEC, NTXT ("NTICK_USEC"),
+ GTXT ("Clock Profiling Interval, Microseconds"),
+ TYPE_UINT64, 0);
+
+ propNames_name_store (PROP_IOHEAPBYTES, NTXT ("IOHEAPBYTES"));
+
+ propNames_name_store (PROP_STACKL, NTXT ("STACKL"));
+ propNames_name_store (PROP_MSTACKL, NTXT ("MSTACKL"));
+ propNames_name_store (PROP_USTACKL, NTXT ("USTACKL"));
+ propNames_name_store (PROP_XSTACKL, NTXT ("XSTACKL"));
+
+ propNames_name_store (PROP_STACKI, NTXT ("STACKI"));
+ propNames_name_store (PROP_MSTACKI, NTXT ("MSTACKI"));
+ propNames_name_store (PROP_USTACKI, NTXT ("USTACKI"));
+ propNames_name_store (PROP_XSTACKI, NTXT ("XSTACKI"));
+
+ // Make sure predefined names are not used for dynamic properties
+ propNames_name_store (PROP_LAST, NTXT (""));
+
+ localized_SP_UNKNOWN_NAME = GTXT ("(unknown)");
+
+ // define Index objects
+ dyn_indxobj = new Vector<IndexObjType_t*>();
+ dyn_indxobj_indx = 0;
+ char *s = dbe_sprintf (NTXT ("((EXPID_CMP<<%llu) | THRID)"),
+ (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+ indxobj_define (NTXT ("Threads"), GTXT ("Threads"), s, NULL, NULL);
+ free (s);
+ indxobj_define (NTXT ("CPUs"), GTXT ("CPUs"), NTXT ("(CPUID)"), NULL, NULL);
+ indxobj_define (NTXT ("Samples"), GTXT ("Samples"), NTXT ("(SAMPLE_MAP)"),
+ NULL, NULL);
+ indxobj_define (NTXT ("GCEvents"), GTXT ("GCEvents"), NTXT ("(GCEVENT_MAP)"),
+ NULL, NULL);
+ indxobj_define (NTXT ("Seconds"), GTXT ("Seconds"),
+ NTXT ("(TSTAMP/1000000000)"), NULL, NULL);
+ indxobj_define (NTXT ("Processes"), GTXT ("Processes"), NTXT ("(EXPID_CMP)"),
+ NULL, NULL);
+ s = dbe_sprintf (NTXT ("((EXPGRID<<%llu) | (EXPID<<%llu))"),
+ (unsigned long long) IndexObject::INDXOBJ_EXPGRID_SHIFT,
+ (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+ indxobj_define (NTXT ("Experiment_IDs"), GTXT ("Experiment_IDs"), s, NULL, NULL);
+ free (s);
+ indxobj_define (NTXT ("Datasize"), GTXT ("Datasize"),
+ "(IOHEAPBYTES==0?0:"
+ "((IOHEAPBYTES<=(1<<0)?(1<<0):"
+ "((IOHEAPBYTES<=(1<<2)?(1<<2):"
+ "((IOHEAPBYTES<=(1<<4)?(1<<4):"
+ "((IOHEAPBYTES<=(1<<6)?(1<<6):"
+ "((IOHEAPBYTES<=(1<<8)?(1<<8):"
+ "((IOHEAPBYTES<=(1<<10)?(1<<10):"
+ "((IOHEAPBYTES<=(1<<12)?(1<<12):"
+ "((IOHEAPBYTES<=(1<<14)?(1<<14):"
+ "((IOHEAPBYTES<=(1<<16)?(1<<16):"
+ "((IOHEAPBYTES<=(1<<18)?(1<<18):"
+ "((IOHEAPBYTES<=(1<<20)?(1<<20):"
+ "((IOHEAPBYTES<=(1<<22)?(1<<22):"
+ "((IOHEAPBYTES<=(1<<24)?(1<<24):"
+ "((IOHEAPBYTES<=(1<<26)?(1<<26):"
+ "((IOHEAPBYTES<=(1<<28)?(1<<28):"
+ "((IOHEAPBYTES<=(1<<30)?(1<<30):"
+ "((IOHEAPBYTES<=(1<<32)?(1<<32):"
+ "((IOHEAPBYTES<=(1<<34)?(1<<34):"
+ "((IOHEAPBYTES<=(1<<36)?(1<<36):"
+ "((IOHEAPBYTES<=(1<<38)?(1<<38):"
+ "((IOHEAPBYTES<=(1<<40)?(1<<40):"
+ "((IOHEAPBYTES<=(1<<42)?(1<<42):"
+ "((IOHEAPBYTES<=(1<<44)?(1<<44):"
+ "((IOHEAPBYTES<=(1<<46)?(1<<46):"
+ "((IOHEAPBYTES<=(1<<48)?(1<<48):"
+ "((IOHEAPBYTES<=(1<<50)?(1<<50):"
+ "(IOHEAPBYTES==-1?-1:(1<<50|1)"
+ "))))))))))))))))))))))))))))))))))))))))))))))))))))))",
+ NULL, NULL);
+ indxobj_define (NTXT ("Duration"), GTXT ("Duration"),
+ "((TSTAMP_HI-TSTAMP_LO)==0?0:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000?1000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000?10000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=100000?100000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000000?1000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000000?10000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=100000000?100000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000000000?1000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000000000?10000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=100000000000?100000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000000000000?1000000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000000000000?10000000000000:"
+ "(10000000000001))))))))))))))))))))))))", NULL, NULL);
+ dyn_indxobj_indx_fixed = dyn_indxobj_indx;
+ Elf::elf_init ();
+ defExpName = NULL;
+ mach_model_loaded = NULL;
+ tmp_dir_name = NULL;
+ settings->read_rc (ipc_mode || rdt_mode);
+
+ init ();
+}
+
+DbeSession::~DbeSession ()
+{
+ Destroy (views);
+ Destroy (exps);
+ Destroy (dobjs);
+ Destroy (metrics);
+ Destroy (search_path);
+ Destroy (classpath);
+ Destroy (propNames);
+ Destroy (expGroups);
+ Destroy (userLabels);
+ if (hwcentries)
+ {
+ for (long i = 0, sz = hwcentries->size (); i < sz; i++)
+ {
+ Hwcentry *h = hwcentries->get (i);
+ free (h->int_name);
+ free (h->name);
+ delete h;
+ }
+ delete hwcentries;
+ }
+
+ if (idxobjs)
+ {
+ for (int i = 0; i < idxobjs->size (); ++i)
+ {
+ HashMap<uint64_t, Histable*> *hMap = idxobjs->get (i);
+ if (hMap)
+ {
+ hMap->values ()->destroy ();
+ delete hMap;
+ }
+ }
+ delete idxobjs;
+ }
+
+ for (int i = 0; i < HTableSize; i++)
+ {
+ List *list = dnameHTable[i];
+ while (list)
+ {
+ List *tmp = list;
+ list = list->next;
+ delete tmp;
+ }
+ }
+ delete[] dnameHTable;
+ delete classpath_df;
+ Destroy (objs);
+ Destroy (reg_metrics);
+ Destroy (dyn_indxobj);
+ delete lobjs;
+ delete f_special;
+ destroy_map (DbeFile *, dbeFiles);
+ destroy_map (DbeJarFile *, dbeJarFiles);
+ delete loadObjMap;
+ delete omp_functions;
+ delete sourcesMap;
+ delete sources;
+ delete comp_lobjs;
+ delete comp_dbelines;
+ delete comp_sources;
+ delete reg_metrics_tree;
+ delete settings;
+ free (mach_model_loaded);
+
+ if (defExpName != NULL)
+ {
+ StringBuilder *sb = new StringBuilder ();
+ sb->append (NTXT ("/bin/rm -rf "));
+ sb->append (defExpName);
+ char *cmd = sb->toString ();
+ system (cmd);
+ free (cmd);
+ delete sb;
+ free (defExpName);
+ }
+ unlink_tmp_files ();
+ delete tmp_files;
+ dbeSession = NULL;
+}
+
+void
+DbeSession::unlink_tmp_files ()
+{
+ if (tmp_files)
+ {
+ for (int i = 0, sz = tmp_files->size (); i < sz; i++)
+ unlink (tmp_files->fetch (i));
+ tmp_files->destroy ();
+ delete tmp_files;
+ tmp_files = NULL;
+ }
+ if (tmp_dir_name)
+ {
+ char *cmd = dbe_sprintf (NTXT ("/bin/rm -rf %s"), tmp_dir_name);
+ system (cmd);
+ free (cmd);
+ free (tmp_dir_name);
+ tmp_dir_name = NULL;
+ }
+}
+
+char *
+DbeSession::get_tmp_file_name (const char *nm, bool for_java)
+{
+ if (tmp_dir_name == NULL)
+ {
+ tmp_dir_name = dbe_sprintf (NTXT ("/tmp/analyzer.%llu.%lld"),
+ (unsigned long long) getuid (), (long long) getpid ());
+ mkdir (tmp_dir_name, S_IRWXU);
+ }
+ char *fnm = dbe_sprintf (NTXT ("%s/%s"), tmp_dir_name, nm);
+ if (for_java)
+ for (char *s = fnm + strlen (tmp_dir_name) + 1; *s; s++)
+ if (*s == '/')
+ *s = '.';
+ return fnm;
+}
+
+void
+DbeSession::init ()
+{
+ user_exp_id_counter = 0;
+ status_ompavail = 0;
+ archive_mode = 0;
+
+#if DEBUG
+ char *s = getenv (NTXT ("MPMT_DEBUG"));
+ if (s)
+ mpmt_debug_opt = atoi (s);
+#endif /* DEBUG */
+ dbeFiles = new StringMap<DbeFile*>();
+ dbeJarFiles = new StringMap<DbeJarFile*>(128, 128);
+
+ // set up the initial (after .rc file reading) search path
+ set_search_path (settings->str_search_path, true);
+ userLabels = NULL;
+
+ // Preset all objects as they may reuse each other
+ lo_unknown = NULL;
+ f_unknown = NULL;
+ j_unknown = NULL;
+ lo_total = NULL;
+ sf_unknown = NULL;
+ f_total = NULL;
+ f_jvm = NULL;
+ d_total = NULL;
+ d_scalars = NULL;
+ d_unknown = NULL;
+ expGroups->destroy ();
+ f_special->reset ();
+ for (int i = 0; i < LastSpecialFunction; i++)
+ f_special->append (NULL);
+
+ lo_omp = NULL;
+ omp_functions->reset ();
+ for (int i = 0; i < OMP_LAST_STATE; i++)
+ omp_functions->append (NULL);
+
+ // make sure the metric list is initialized
+ register_metric (Metric::SIZES);
+ register_metric (Metric::ADDRESS);
+ register_metric (Metric::ONAME);
+
+ // This is needed only to maintain loadobject id's
+ // for <Total> and <Unknown> in tests
+ (void) get_Unknown_LoadObject ();
+ (void) get_Total_LoadObject ();
+
+ // Create the data object name hash table.
+ dnameHTable = new List*[HTableSize];
+ for (int i = 0; i < HTableSize; i++)
+ dnameHTable[i] = NULL;
+
+ d_total = createDataObject ();
+ d_total->set_name (NTXT ("<Total>"));
+
+ // XXXX <Scalars> only appropriate for Program/Data-oriented analyses
+ d_scalars = createDataObject ();
+ d_scalars->set_name (GTXT ("<Scalars>"));
+
+ d_unknown = createDataObject ();
+ d_unknown->set_name (GTXT ("<Unknown>"));
+
+ // assign d_unknown's children so data_olayout has consistent sorting
+ for (unsigned pp_code = 1; pp_code < NUM_ABS_PP_CODES + 2; pp_code++)
+ {
+ char *errcode;
+ DataObject* dobj = createDataObject ();
+ switch (pp_code)
+ {
+ case NUM_ABS_PP_CODES + 1:
+ errcode = PTXT (DOBJ_UNDETERMINED);
+ break;
+ case NUM_ABS_PP_CODES:
+ errcode = PTXT (DOBJ_UNSPECIFIED);
+ break;
+ case NUM_ABS_PP_CODES - 1:
+ errcode = PTXT (DOBJ_UNIDENTIFIED);
+ break;
+ default:
+ errcode = PTXT (ABS_PP_CODES[pp_code]);
+ }
+ dobj->parent = d_unknown;
+ dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+ }
+
+ for (unsigned rt_code = 1; rt_code < NUM_ABS_RT_CODES - 1; rt_code++)
+ {
+ DataObject* dobj = createDataObject ();
+ dobj->parent = d_unknown;
+ dobj->set_dobjname (PTXT (ABS_RT_CODES[rt_code]), NULL); // dobj->parent must already be set
+ }
+}
+
+void
+DbeSession::reset_data ()
+{
+ for (long i = 0, sz = VecSize (idxobjs); i < sz; ++i)
+ if (idxobjs->get (i))
+ idxobjs->get (i)->reset ();
+}
+
+void
+DbeSession::reset ()
+{
+ loadObjMap->reset ();
+ DbeView *dbev;
+ int index;
+
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->reset ();
+ }
+
+ destroy_map (DbeFile *, dbeFiles);
+ destroy_map (DbeJarFile *, dbeJarFiles);
+ exps->destroy ();
+ lobjs->reset (); // all LoadObjects belong to objs
+ dobjs->destroy (); // deletes d_unknown and d_total as well
+ objs->destroy ();
+ comp_lobjs->clear ();
+ comp_dbelines->clear ();
+ comp_sources->clear ();
+ sourcesMap->clear ();
+ sources->reset ();
+
+ // Delete the data object name hash table.
+ for (int i = 0; i < HTableSize; i++)
+ {
+ List *list = dnameHTable[i];
+ while (list)
+ {
+ List *tmp = list;
+ list = list->next;
+ delete tmp;
+ }
+ }
+ delete[] dnameHTable;
+
+ // IndexObect definitions remain, objects themselves may go
+ for (int i = 0; i < idxobjs->size (); ++i)
+ {
+ HashMap<uint64_t, Histable*> *v = idxobjs->fetch (i);
+ if (v != NULL)
+ {
+ v->values ()->destroy ();
+ v->clear ();
+ }
+ }
+ init ();
+}
+
+Vector<SourceFile*> *
+DbeSession::get_sources ()
+{
+ return sources;
+}
+
+DbeFile *
+DbeSession::getDbeFile (char *filename, int filetype)
+{
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeSession::getDbeFile filetype=0x%x %s\n"), filetype, filename);
+ if (strncmp (filename, NTXT ("./"), 2) == 0)
+ filename += 2;
+ DbeFile *dbeFile = dbeFiles->get (filename);
+ if (dbeFile == NULL)
+ {
+ dbeFile = new DbeFile (filename);
+ dbeFiles->put (filename, dbeFile);
+ }
+ dbeFile->filetype |= filetype;
+ return dbeFile;
+}
+
+LoadObject *
+DbeSession::get_Total_LoadObject ()
+{
+ if (lo_total == NULL)
+ {
+ lo_total = createLoadObject (NTXT ("<Total>"));
+ lo_total->dbeFile->filetype |= DbeFile::F_FICTION;
+ }
+ return lo_total;
+}
+
+Function *
+DbeSession::get_Total_Function ()
+{
+ if (f_total == NULL)
+ {
+ f_total = createFunction ();
+ f_total->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ f_total->set_name (NTXT ("<Total>"));
+ Module *mod = get_Total_LoadObject ()->noname;
+ f_total->module = mod;
+ mod->functions->append (f_total);
+ }
+ return f_total;
+}
+
+LoadObject *
+DbeSession::get_Unknown_LoadObject ()
+{
+ if (lo_unknown == NULL)
+ {
+ lo_unknown = createLoadObject (GTXT ("<Unknown>"));
+ lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable
+ lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+
+ // force creation of the <Unknown> function
+ (void) get_Unknown_Function ();
+ }
+ return lo_unknown;
+}
+
+SourceFile *
+DbeSession::get_Unknown_Source ()
+{
+ if (sf_unknown == NULL)
+ {
+ sf_unknown = createSourceFile (localized_SP_UNKNOWN_NAME);
+ sf_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+ sf_unknown->flags |= SOURCE_FLAG_UNKNOWN;
+ }
+ return sf_unknown;
+}
+
+Function *
+DbeSession::get_Unknown_Function ()
+{
+ if (f_unknown == NULL)
+ {
+ f_unknown = createFunction ();
+ f_unknown->flags |= FUNC_FLAG_SIMULATED;
+ f_unknown->set_name (GTXT ("<Unknown>"));
+ Module *mod = get_Unknown_LoadObject ()->noname;
+ f_unknown->module = mod;
+ mod->functions->append (f_unknown);
+ }
+ return f_unknown;
+}
+
+// LIBRARY_VISIBILITY
+
+Function *
+DbeSession::create_hide_function (LoadObject *lo)
+{
+ Function *h_function = createFunction ();
+ h_function->set_name (lo->get_name ());
+ h_function->module = lo->noname;
+ h_function->isHideFunc = true;
+ lo->noname->functions->append (h_function);
+ return h_function;
+}
+
+Function *
+DbeSession::get_JUnknown_Function ()
+{
+ if (j_unknown == NULL)
+ {
+ j_unknown = createFunction ();
+ j_unknown->flags |= FUNC_FLAG_SIMULATED;
+ j_unknown->set_name (GTXT ("<no Java callstack recorded>"));
+ Module *mod = get_Unknown_LoadObject ()->noname;
+ j_unknown->module = mod;
+ mod->functions->append (j_unknown);
+ }
+ return j_unknown;
+}
+
+Function *
+DbeSession::get_jvm_Function ()
+{
+ if (f_jvm == NULL)
+ {
+ f_jvm = createFunction ();
+ f_jvm->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ f_jvm->set_name (GTXT ("<JVM-System>"));
+
+ // Find the JVM LoadObject
+ LoadObject *jvm = get_Unknown_LoadObject ();
+ for (int i = 0; i < lobjs->size (); ++i)
+ {
+ LoadObject *lo = lobjs->fetch (i);
+ if (lo->flags & SEG_FLAG_JVM)
+ {
+ jvm = lo;
+ break;
+ }
+ }
+ Module *mod = jvm->noname;
+ f_jvm->module = mod;
+ mod->functions->append (f_jvm);
+ // XXXX is it required? no consistency among all special functions
+ // jvm->functions->append( f_jvm );
+ }
+ return f_jvm;
+}
+
+Function *
+DbeSession::getSpecialFunction (SpecialFunction kind)
+{
+ if (kind < 0 || kind >= LastSpecialFunction)
+ return NULL;
+
+ Function *func = f_special->fetch (kind);
+ if (func == NULL)
+ {
+ char *fname;
+ switch (kind)
+ {
+ case TruncatedStackFunc:
+ fname = GTXT ("<Truncated-stack>");
+ break;
+ case FailedUnwindFunc:
+ fname = GTXT ("<Stack-unwind-failed>");
+ break;
+ default:
+ return NULL;
+ }
+ func = createFunction ();
+ func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ Module *mod = get_Total_LoadObject ()->noname;
+ func->module = mod;
+ mod->functions->append (func);
+ func->set_name (fname);
+ f_special->store (kind, func);
+ }
+ return func;
+}
+
+LoadObject *
+DbeSession::get_OMP_LoadObject ()
+{
+ if (lo_omp == NULL)
+ {
+ for (int i = 0, sz = lobjs->size (); i < sz; i++)
+ {
+ LoadObject *lo = lobjs->fetch (i);
+ if (lo->flags & SEG_FLAG_OMP)
+ {
+ lo_omp = lo;
+ return lo_omp;
+ }
+ }
+ lo_omp = createLoadObject (GTXT ("<OMP>"));
+ lo_omp->type = LoadObject::SEG_TEXT;
+ lo_omp->dbeFile->filetype |= DbeFile::F_FICTION;
+ }
+ return lo_omp;
+}
+
+Function *
+DbeSession::get_OMP_Function (int n)
+{
+ if (n < 0 || n >= OMP_LAST_STATE)
+ return NULL;
+
+ Function *func = omp_functions->fetch (n);
+ if (func == NULL)
+ {
+ char *fname;
+ switch (n)
+ {
+ case OMP_OVHD_STATE:
+ fname = GTXT ("<OMP-overhead>");
+ break;
+ case OMP_IDLE_STATE:
+ fname = GTXT ("<OMP-idle>");
+ break;
+ case OMP_RDUC_STATE:
+ fname = GTXT ("<OMP-reduction>");
+ break;
+ case OMP_IBAR_STATE:
+ fname = GTXT ("<OMP-implicit_barrier>");
+ break;
+ case OMP_EBAR_STATE:
+ fname = GTXT ("<OMP-explicit_barrier>");
+ break;
+ case OMP_LKWT_STATE:
+ fname = GTXT ("<OMP-lock_wait>");
+ break;
+ case OMP_CTWT_STATE:
+ fname = GTXT ("<OMP-critical_section_wait>");
+ break;
+ case OMP_ODWT_STATE:
+ fname = GTXT ("<OMP-ordered_section_wait>");
+ break;
+ case OMP_ATWT_STATE:
+ fname = GTXT ("<OMP-atomic_wait>");
+ break;
+ default:
+ return NULL;
+ }
+ func = createFunction ();
+ func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ func->set_name (fname);
+
+ LoadObject *omp = get_OMP_LoadObject ();
+ func->module = omp->noname;
+ omp->noname->functions->append (func);
+ omp->functions->append (func);
+ omp_functions->store (n, func);
+ }
+ return func;
+}
+
+// Divide the original createExperiment() into two steps
+// In part1, we just create the data structure, in part2, if
+// we decide to keep the experiment around, add it to various
+// lists in DbeSession
+Experiment *
+DbeSession::createExperimentPart1 ()
+{
+ Experiment *exp = new Experiment ();
+ return exp;
+}
+
+void
+DbeSession::createExperimentPart2 (Experiment *exp)
+{
+ int ind = expGroups->size ();
+ if (ind > 0)
+ {
+ ExpGroup *gr = expGroups->fetch (ind - 1);
+ exp->groupId = gr->groupId;
+ gr->append (exp);
+ }
+ exp->setExpIdx (exps->size ());
+ exp->setUserExpId (++user_exp_id_counter);
+ exps->append (exp);
+}
+
+Experiment *
+DbeSession::createExperiment ()
+{
+ Experiment *exp = new Experiment ();
+ append (exp);
+ return exp;
+}
+
+void
+DbeSession::append (Experiment *exp)
+{
+ exp->setExpIdx (exps->size ());
+ exp->setUserExpId (++user_exp_id_counter);
+ exps->append (exp);
+ if (exp->founder_exp)
+ {
+ if (exp->founder_exp->children_exps == NULL)
+ exp->founder_exp->children_exps = new Vector<Experiment *>;
+ exp->founder_exp->children_exps->append (exp);
+ if (exp->founder_exp->groupId > 0)
+ {
+ exp->groupId = exp->founder_exp->groupId;
+ expGroups->get (exp->groupId - 1)->append (exp);
+ }
+ }
+ if (exp->groupId == 0)
+ {
+ long ind = VecSize (expGroups);
+ if (ind > 0)
+ {
+ ExpGroup *gr = expGroups->get (ind - 1);
+ exp->groupId = gr->groupId;
+ gr->append (exp);
+ }
+ }
+}
+
+void
+DbeSession::append (Hwcentry *h)
+{
+ if (hwcentries == NULL)
+ hwcentries = new Vector<Hwcentry*>;
+ hwcentries->append (h);
+}
+
+int
+DbeSession::ngoodexps ()
+{
+ return exps->size ();
+}
+
+int
+DbeSession::createView (int index, int cloneindex)
+{
+ // ensure that there is no view with that index
+ DbeView *dbev = getView (index);
+ if (dbev != NULL)
+ abort ();
+
+ // find the view to be cloned
+ dbev = getView (cloneindex);
+ DbeView *newview;
+ if (dbev == NULL)
+ newview = new DbeView (theApplication, settings, index);
+ else
+ newview = new DbeView (dbev, index);
+ views->append (newview);
+ return index;
+}
+
+DbeView *
+DbeSession::getView (int index)
+{
+ int i;
+ DbeView *dbev;
+ Vec_loop (DbeView*, views, i, dbev)
+ {
+ if (dbev->vindex == index)
+ return dbev;
+ }
+ return NULL;
+}
+
+void
+DbeSession::dropView (int index)
+{
+ int i;
+ DbeView *dbev;
+
+ Vec_loop (DbeView*, views, i, dbev)
+ {
+ if (dbev->vindex == index)
+ {
+ views->remove (i);
+ delete dbev;
+ return;
+ }
+ }
+ // view not found; ignore for now
+}
+
+Vector<char*> *
+DbeSession::get_group_or_expt (char *path)
+{
+ Vector<char*> *exp_list = new Vector<char*>;
+ FILE *fptr;
+ char *new_path, buf[MAXPATHLEN], name[MAXPATHLEN];
+
+ fptr = fopen (path, NTXT ("r"));
+ if (!fptr || !fgets (buf, (int) sizeof (buf), fptr)
+ || strncmp (buf, SP_GROUP_HEADER, strlen (SP_GROUP_HEADER)))
+ {
+ // it's not an experiment group
+ new_path = dbe_strdup (path);
+ new_path = canonical_path (new_path);
+ exp_list->append (new_path);
+ }
+ else
+ {
+ // it is an experiment group, read the list to get them all
+ while (fgets (buf, (int) sizeof (buf), fptr))
+ {
+ if ((*buf != '#') && (sscanf (buf, NTXT ("%s"), name) == 1))
+ {
+ new_path = dbe_strdup (name);
+ new_path = canonical_path (new_path);
+ exp_list->append (new_path);
+ }
+ }
+ }
+ if (fptr)
+ fclose (fptr);
+ return exp_list;
+}
+
+#define GET_INT_VAL(v, s, len) \
+ for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
+
+static int
+dir_name_cmp (const void *a, const void *b)
+{
+ char *s1 = *((char **) a);
+ char *s2 = *((char **) b);
+ while (*s1)
+ {
+ if (isdigit (*s1) && isdigit (*s2))
+ {
+ int v1, v2, len1, len2;
+ GET_INT_VAL (v1, s1, len1);
+ GET_INT_VAL (v2, s2, len2);
+ if (v1 != v2)
+ return v1 - v2;
+ if (len1 != len2)
+ return len2 - len1;
+ continue;
+ }
+ if (*s1 != *s2)
+ break;
+ s1++;
+ s2++;
+ }
+ return *s1 - *s2;
+}
+
+static int
+read_experiment_data_in_parallel (void *arg)
+{
+ exp_ctx *ctx = (exp_ctx *) arg;
+ Experiment *dexp = ctx->exp;
+ bool read_ahead = ctx->read_ahead;
+ dexp->read_experiment_data (read_ahead);
+ free (ctx);
+ return 0;
+}
+
+void
+DbeSession::open_experiment (Experiment *exp, char *path)
+{
+ exp->open (path);
+ if (exp->get_status () != Experiment::FAILURE)
+ exp->read_experiment_data (false);
+ exp->open_epilogue ();
+
+ // Update all DbeViews
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ dbev->add_experiment (exp->getExpIdx (), true);
+ }
+
+ if (exp->get_status () == Experiment::FAILURE)
+ {
+ check_tab_avail ();
+ return;
+ }
+
+ char *discard_tiny = getenv (NTXT ("SP_ANALYZER_DISCARD_TINY_EXPERIMENTS"));
+ int user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; // in milliseconds
+ if (discard_tiny != NULL)
+ {
+ user_specified_tiny_threshold = (atoi (discard_tiny));
+ if (user_specified_tiny_threshold < 0)
+ user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD;
+ }
+
+ // Open descendant experiments
+ DIR *exp_dir = opendir (path);
+ if (exp_dir == NULL)
+ {
+ check_tab_avail ();
+ return;
+ }
+
+ Vector<char*> *exp_names = new Vector<char*>();
+ struct dirent *entry = NULL;
+ while ((entry = readdir (exp_dir)) != NULL)
+ {
+ if (entry->d_name[0] != '_')
+ continue;
+ size_t len = strlen (entry->d_name);
+ if (len < 3 || strcmp (entry->d_name + len - 3, NTXT (".er")) != 0)
+ continue;
+ exp_names->append (dbe_strdup (entry->d_name));
+ }
+ closedir (exp_dir);
+ exp_names->sort (dir_name_cmp);
+ Experiment **t_exp_list = new Experiment *[exp_names->size ()];
+ int nsubexps = 0;
+
+ for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+ {
+ t_exp_list[j] = NULL;
+
+ char *lineage_name = exp_names->fetch (j);
+ struct stat64 sbuf;
+ char *dpath = dbe_sprintf (NTXT ("%s/%s"), path, lineage_name);
+
+ // look for experiments with no profile collected
+ if (user_specified_tiny_threshold == DEFAULT_TINY_THRESHOLD)
+ {
+ char *frinfoname = dbe_sprintf (NTXT ("%s/%s"), dpath, "data." SP_FRINFO_FILE);
+ int st = dbe_stat (frinfoname, &sbuf);
+ free (frinfoname);
+ if (st == 0)
+ {
+ // if no profile/trace data do not process this experiment any further
+ if (sbuf.st_size == 0)
+ {
+ free (dpath);
+ continue;
+ }
+ }
+ }
+ else
+ { // check if dpath is a directory
+ if (dbe_stat (dpath, &sbuf) != 0)
+ {
+ free (dpath);
+ continue;
+ }
+ else if (!S_ISDIR (sbuf.st_mode))
+ {
+ free (dpath);
+ continue;
+ }
+ }
+ size_t lineage_name_len = strlen (lineage_name);
+ lineage_name[lineage_name_len - 3] = 0; /* remove .er */
+ Experiment *dexp = new Experiment ();
+ dexp->founder_exp = exp;
+ if (user_specified_tiny_threshold > DEFAULT_TINY_THRESHOLD)
+ {
+ dexp->setTinyThreshold (user_specified_tiny_threshold);
+ dexp->open (dpath);
+ if (dexp->isDiscardedTinyExperiment ())
+ {
+ delete dexp;
+ free (dpath);
+ continue;
+ }
+ }
+ else
+ dexp->open (dpath);
+ append (dexp);
+ t_exp_list[j] = dexp;
+ nsubexps++;
+ dexp->set_clock (exp->clock);
+
+ // DbeView add_experiment() is split into two parts
+ // add_subexperiment() is called repeeatedly for
+ // all sub_experiments, later add_experiment_epilogue() finishes up the task
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ bool enabled = settings->check_en_desc (lineage_name, dexp->utargname);
+ dbev->add_subexperiment (dexp->getExpIdx (), enabled);
+ }
+ free (dpath);
+ }
+
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ dbev->add_experiment_epilogue ();
+ }
+
+ DbeThreadPool * threadPool = new DbeThreadPool (-1);
+ for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+ {
+ if (t_exp_list[j] == NULL) continue;
+ Experiment *dexp = t_exp_list[j];
+ exp_ctx *new_ctx = (exp_ctx*) malloc (sizeof (exp_ctx));
+ new_ctx->path = NULL;
+ new_ctx->exp = dexp;
+ new_ctx->ds = this;
+ new_ctx->read_ahead = true;
+ DbeQueue *q = new DbeQueue (read_experiment_data_in_parallel, new_ctx);
+ threadPool->put_queue (q);
+ }
+ threadPool->wait_queues ();
+ delete threadPool;
+
+ for (long j = 0, jsz = exp_names->size (); j < jsz; j++)
+ {
+ if (t_exp_list[j] == NULL) continue;
+ Experiment *dexp = t_exp_list[j];
+ dexp->open_epilogue ();
+ }
+ exp_names->destroy ();
+ delete[] t_exp_list;
+ delete exp_names;
+
+ // update setting for leaklist and dataspace
+ check_tab_avail ();
+}
+
+void
+DbeSession::append_mesgs (StringBuilder *sb, char *path, Experiment *exp)
+{
+ if (exp->fetch_errors () != NULL)
+ {
+ // yes, there were errors
+ char *ststr = pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT (""));
+ sb->append (path);
+ sb->append (NTXT (": "));
+ sb->append (ststr);
+ free (ststr);
+ }
+
+ Emsg *m = exp->fetch_warnings ();
+ if (m != NULL)
+ {
+ sb->append (path);
+ sb->append (NTXT (": "));
+ if (!is_interactive ())
+ sb->append (GTXT ("Experiment has warnings, see header for details\n"));
+ else
+ sb->append (GTXT ("Experiment has warnings, see experiment panel for details\n"));
+ }
+
+ // Check for descendant experiments that are not loaded
+ int num_desc = VecSize (exp->children_exps);
+ if ((num_desc > 0) && !settings->check_en_desc (NULL, NULL))
+ {
+ char *s;
+ if (!is_interactive ())
+ s = dbe_sprintf (GTXT ("Has %d descendant(s), use commands controlling selection to load descendant data\n"), num_desc);
+ else
+ s = dbe_sprintf (GTXT ("Has %d descendant(s), use filter panel to load descendant data\n"), num_desc);
+ sb->append (path);
+ sb->append (NTXT (": "));
+ sb->append (s);
+ free (s);
+ }
+}
+
+Experiment *
+DbeSession::get_exp (int exp_ind)
+{
+ if (exp_ind < 0 || exp_ind >= exps->size ())
+ return NULL;
+ Experiment *exp = exps->fetch (exp_ind);
+ exp->setExpIdx (exp_ind);
+ return exp;
+}
+
+Vector<Vector<char*>*> *
+DbeSession::getExperimensGroups ()
+{
+ if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0)
+ return NULL;
+ bool compare_mode = expGroups->size () > 1;
+ Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*> (
+ compare_mode ? expGroups->size () : 1);
+ for (int i = 0; i < expGroups->size (); i++)
+ {
+ ExpGroup *grp = expGroups->fetch (i);
+ Vector<Experiment*> *founders = grp->get_founders ();
+ if (founders && founders->size () != 0)
+ {
+ Vector<char *> *names = new Vector<char*> (founders->size ());
+ for (int j = 0; j < founders->size (); j++)
+ {
+ Experiment *exp = founders->fetch (j);
+ names->append (dbe_strdup (exp->get_expt_name ()));
+ }
+ if (compare_mode || groups->size () == 0)
+ groups->append (names);
+ else
+ groups->fetch (0)->addAll (names);
+ }
+ delete founders;
+ }
+ return groups;
+}
+
+char *
+DbeSession::setExperimentsGroups (Vector<Vector<char*>*> *groups)
+{
+ StringBuilder sb;
+ for (int i = 0; i < groups->size (); i++)
+ {
+ Vector<char *> *names = groups->fetch (i);
+ ExpGroup *grp;
+ if (names->size () == 1)
+ grp = new ExpGroup (names->fetch (0));
+ else
+ {
+ char *nm = dbe_sprintf (GTXT ("Group %d"), i + 1);
+ grp = new ExpGroup (nm);
+ free (nm);
+ }
+ expGroups->append (grp);
+ grp->groupId = expGroups->size ();
+
+ for (int j = 0; j < names->size (); j++)
+ {
+ char *path = names->fetch (j);
+ size_t len = strlen (path);
+ if ((len > 4) && !strcmp (path + len - 4, NTXT (".erg")))
+ {
+ Vector<char*> *lst = get_group_or_expt (path);
+ for (int j1 = 0; j1 < lst->size (); j1++)
+ {
+ Experiment *exp = new Experiment ();
+ append (exp);
+ open_experiment (exp, lst->get (j1));
+ if (exp->get_status () == Experiment::FAILURE)
+ append_mesgs (&sb, path, exp);
+ }
+ lst->destroy ();
+ delete lst;
+ }
+ else
+ {
+ Experiment *exp = new Experiment ();
+ append (exp);
+ open_experiment (exp, path);
+ if (exp->get_status () == Experiment::FAILURE)
+ append_mesgs (&sb, path, exp);
+ }
+ }
+ }
+
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ dbev->update_advanced_filter ();
+ int cmp = dbev->get_settings ()->get_compare_mode ();
+ dbev->set_compare_mode (CMP_DISABLE);
+ dbev->set_compare_mode (cmp);
+ }
+ return sb.length () == 0 ? NULL : sb.toString ();
+}
+
+char *
+DbeSession::drop_experiment (int exp_ind)
+{
+ DbeView *dbev;
+ int index;
+ Experiment *exp2;
+
+ status_ompavail = -1;
+ Experiment *exp = exps->fetch (exp_ind);
+
+ // If this is a sub experiment, don't do it
+ if (exp->founder_exp != NULL) // this is a sub experiment; don't do it
+ return (dbe_strdup (GTXT ("Can not drop subexperiments")));
+
+ if (VecSize (exp->children_exps) > 0)
+ for (;;)
+ {
+ // search the list of experiments to find all that have this one as founder
+ bool found = false;
+ Vec_loop (Experiment*, exps, index, exp2)
+ {
+ if (exp2->founder_exp == exp)
+ {
+ exp2->founder_exp = NULL;
+ drop_experiment (index);
+ found = true;
+ break;
+ }
+ }
+ if (found == false)
+ break;
+ }
+
+ // then proceed to finish the drop
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->drop_experiment (exp_ind);
+ }
+
+ int old_cnt = expGroups->size ();
+ for (int i = 0; i < old_cnt; i++)
+ {
+ ExpGroup *gr = expGroups->fetch (i);
+ if (gr->groupId == exp->groupId)
+ {
+ gr->drop_experiment (exp);
+ if ((gr->founder == NULL) && (gr->exps->size () == 0))
+ {
+ delete gr;
+ expGroups->remove (i);
+ }
+ break;
+ }
+ }
+ delete exps->remove (exp_ind);
+ if (old_cnt != expGroups->size ())
+ {
+ for (int i = 0, sz = expGroups->size (); i < sz; i++)
+ {
+ ExpGroup *gr = expGroups->fetch (i);
+ gr->groupId = i + 1;
+ Vector<Experiment*> *expList = gr->exps;
+ for (int i1 = 0, sz1 = expList->size (); i1 < sz1; i1++)
+ expList->fetch (i1)->groupId = gr->groupId;
+ }
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ dbev = views->fetch (i);
+ int cmp = dbev->get_compare_mode ();
+ dbev->set_compare_mode (CMP_DISABLE);
+ dbev->set_compare_mode (cmp);
+ }
+ }
+ check_tab_avail (); // update tab availability
+ return NULL;
+}
+
+int
+DbeSession::find_experiment (char *path)
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (strcmp (exp->get_expt_name (), path) == 0)
+ return exp->getExpIdx ();
+ }
+ return -1;
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, int64_t cksum)
+{
+ return loadObjMap->sync_create_item (nm, cksum);
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, const char *runTimePath, DbeFile *df)
+{
+ return loadObjMap->sync_create_item (nm, runTimePath, df);
+}
+
+void
+DbeSession::append (LoadObject *lobj)
+{
+ Histable *obj = lobj; // workaround for a C++ problem
+ objs->append (obj);
+ lobj->id = objs->size () - 1;
+ lobjs->append (lobj);
+ lobj->seg_idx = lobjs->size () - 1;
+ char *loname = lobj->get_pathname ();
+ dbeFiles->put (loname, lobj->dbeFile);
+}
+
+DbeJarFile *
+DbeSession::get_JarFile (const char *name)
+{
+ DbeJarFile *jf = dbeJarFiles->get (name);
+ if (jf == NULL)
+ {
+ jf = new DbeJarFile (name);
+ dbeJarFiles->put (name, jf);
+ }
+ return jf;
+}
+
+Module *
+DbeSession::createModule (LoadObject *lo, const char *nm)
+{
+ Module *mod = new Module ();
+ Histable *obj = mod; // workaround for a C++ problem
+ objs->append (obj);
+ mod->id = objs->size () - 1;
+ mod->loadobject = lo;
+ mod->set_name (dbe_strdup (nm ? nm : localized_SP_UNKNOWN_NAME));
+ lo->seg_modules->append (mod);
+ return mod;
+}
+
+Module *
+DbeSession::createUnknownModule (LoadObject *lo)
+{
+ Module *mod = createModule (lo, localized_SP_UNKNOWN_NAME);
+ mod->flags |= MOD_FLAG_UNKNOWN;
+ mod->set_file_name (dbe_strdup (localized_SP_UNKNOWN_NAME));
+ return mod;
+}
+
+SourceFile *
+DbeSession::createSourceFile (const char *_path)
+{
+ char *path = (char *) _path;
+ if (strncmp (path, NTXT ("./"), 2) == 0)
+ path += 2;
+ SourceFile *source = sourcesMap->get (path);
+ if (source == NULL)
+ {
+ source = new SourceFile (path);
+ (void) sourcesMap->put (path, source);
+ append (source);
+ }
+ return source;
+}
+
+Function *
+DbeSession::createFunction ()
+{
+ Function *func = new Function (objs->size ());
+ Histable *obj = func; // workaround for a C++ problem
+ objs->append (obj);
+ return func;
+}
+
+JMethod *
+DbeSession::createJMethod ()
+{
+ JMethod *jmthd = new JMethod (objs->size ());
+ Histable *obj = jmthd; // workaround for a C++ problem
+ objs->append (obj);
+ return jmthd;
+}
+
+Module *
+DbeSession::createClassFile (char *className)
+{
+ ClassFile *cls = new ClassFile ();
+ cls->set_name (className);
+ char *clpath = cls->get_java_file_name (className, true);
+ cls->dbeFile = getDbeFile (clpath, DbeFile::F_JAVACLASS);
+ free (clpath);
+ Histable *obj = cls; // workaround for a C++ problem
+ objs->append (obj);
+ cls->id = objs->size () - 1;
+ return cls;
+}
+
+Histable *
+DbeSession::createHistObject (Histable::Type type)
+{
+ switch (type)
+ {
+ case Histable::DOBJECT:
+ {
+ DataObject *dataobj = new DataObject ();
+ dobjs->append (dataobj);
+ dataobj->id = dobjs->size () - 1;
+ return dataobj;
+ }
+ default:
+ assert (0);
+ }
+ return NULL;
+}
+
+DataObject *
+DbeSession::createDataObject ()
+{
+ DataObject *dataobj = new DataObject ();
+ dobjs->append (dataobj);
+ dataobj->id = dobjs->size () - 1;
+ return dataobj;
+}
+
+DataObject *
+DbeSession::createDataObject (DataObject *dobj, DataObject *parent)
+{
+ DataObject *dataobj = new DataObject ();
+ dataobj->size = dobj->size;
+ dataobj->offset = dobj->offset;
+ dataobj->parent = parent;
+ dataobj->set_dobjname (dobj->get_typename (), dobj->get_instname ());
+ dobjs->append (dataobj);
+ dataobj->id = dobjs->size () - 1;
+ return dataobj;
+}
+
+DataObject *
+DbeSession::createMasterDataObject (DataObject *dobj)
+{
+ DataObject *parent = NULL;
+ if (dobj->parent)
+ { // define master parent first
+ parent = find_dobj_master (dobj->parent);
+ if (!parent)
+ { // clone master from this dataobject parent
+ parent = createDataObject (dobj->parent);
+ parent->scope = NULL; // master is scope-less
+ Dprintf (DEBUG_DATAOBJ,
+ "Master DataObject(%llu) cloned from (%llu) %s\n",
+ (ull_t) parent->id, (ull_t) dobj->parent->id,
+ dobj->parent->get_name ());
+ // clone master DataObject elements
+ Vector<DataObject*> *delem = get_dobj_elements (dobj->parent);
+ int element_index = 0;
+ DataObject *element = NULL;
+ Vec_loop (DataObject*, delem, element_index, element)
+ {
+ DataObject *master_element = createDataObject (element, parent);
+ master_element->scope = NULL; // master is scope-less
+ Dprintf (DEBUG_DATAOBJ,
+ "Member DataObject(%llu) cloned from (%llu) %s\n",
+ (ull_t) master_element->id, (ull_t) element->id,
+ element->get_name ());
+ }
+ }
+ else
+ Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+ (ull_t) parent->id, (ull_t) dobj->parent->id,
+ dobj->parent->get_name ());
+ }
+
+ DataObject *master = find_dobj_master (dobj);
+ if (!master)
+ { // clone master from this dataobject
+ master = createDataObject (dobj, parent);
+ master->scope = NULL; // master is scope-less
+ Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) cloned from (%llu) %s\n",
+ (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+ }
+ else
+ Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+ (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+ return master;
+}
+
+void
+DbeSession::insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist)
+{
+ if ((mtr->get_flavors () & Metric::STATIC) == 0)
+ {
+ // insert in front of the first STATIC
+ for (int i = 0, mlist_sz = mlist->size (); i < mlist_sz; i++)
+ {
+ BaseMetric *m = mlist->fetch (i);
+ if (m->get_flavors () & Metric::STATIC)
+ {
+ mlist->insert (i, mtr);
+ return;
+ }
+ }
+ }
+ mlist->append (mtr);
+}
+
+BaseMetricTreeNode*
+DbeSession::get_reg_metrics_tree ()
+{
+ if (reg_metrics_tree == NULL)
+ // Can't init earlier because BaseMetric() requires DbeSession::ql_parse
+ reg_metrics_tree = new BaseMetricTreeNode ();
+ return reg_metrics_tree;
+}
+
+void
+DbeSession::update_metric_tree (BaseMetric *m)
+{
+ get_reg_metrics_tree ()->register_metric (m);
+}
+
+BaseMetric *
+DbeSession::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
+{
+ BaseMetric *m = find_metric (type, cmd, expr_spec);
+ if (m)
+ return m;
+ BaseMetric *bm = find_metric (type, cmd, NULL); // clone this version
+ m = new BaseMetric (*bm);
+ m->set_expr_spec (expr_spec);
+ insert_metric (m, reg_metrics);
+ return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (BaseMetric::Type type)
+{
+ BaseMetric *m = find_metric (type, NULL, NULL);
+ if (m)
+ return m;
+ m = new BaseMetric (type);
+ insert_metric (m, reg_metrics);
+ update_metric_tree (m);
+ return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (Hwcentry *ctr, const char* aux, const char* username)
+{
+ BaseMetric *m = find_metric (BaseMetric::HWCNTR, aux, NULL);
+ if (m)
+ // That may be a problem when metrics aren't an exact match.
+ // For example, memoryspace is disabled in one experiment and not in another.
+ return m;
+ if (ctr->timecvt)
+ {
+ char *time_cmd = dbe_sprintf (NTXT ("t%s"), aux);
+ char *time_username = dbe_sprintf (GTXT ("%s Time"),
+ ctr->metric ? ctr->metric :
+ (ctr->name ? ctr->name : ctr->int_name));
+ BaseMetric *m1;
+ if (ipc_mode)
+ {
+ // Two visible metrics are presented in GUI
+ m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL);
+ insert_metric (m1, reg_metrics);
+ update_metric_tree (m1);
+ m = new BaseMetric (ctr, aux, username, VAL_VALUE, m1);
+ }
+ else
+ {
+ // Only one visible metric is presented in er_print
+ m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL | VAL_INTERNAL);
+ insert_metric (m1, reg_metrics);
+ m = new BaseMetric (ctr, aux, username, VAL_TIMEVAL | VAL_VALUE, m1);
+ }
+ free (time_cmd);
+ free (time_username);
+ }
+ else
+ m = new BaseMetric (ctr, aux, username, VAL_VALUE);
+ insert_metric (m, reg_metrics);
+ update_metric_tree (m);
+ return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (char *name, char *username, char *_def)
+{
+ BaseMetric *m = find_metric (BaseMetric::DERIVED, name, NULL);
+ if (m)
+ return m;
+ Definition *p = Definition::add_definition (_def);
+ if (p == NULL)
+ return NULL;
+ m = new BaseMetric (name, username, p);
+ insert_metric (m, reg_metrics);
+ update_metric_tree (m);
+ return m;
+}
+
+void
+DbeSession::drop_metric (BaseMetric *mtr)
+{
+ Countable *cnt;
+ int index;
+
+ Vec_loop (Countable*, metrics, index, cnt)
+ {
+ if (mtr == (BaseMetric *) cnt->item)
+ {
+ cnt->ref_count--;
+ if (cnt->ref_count == 0)
+ {
+ // Remove this metric from all views
+ DbeView *dbev;
+ int index2;
+ Vec_loop (DbeView*, views, index2, dbev)
+ {
+ dbev->reset_metrics ();
+ }
+ delete metrics->remove (index);
+ delete mtr;
+ return;
+ }
+ }
+ }
+}
+
+BaseMetric *
+DbeSession::find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec)
+{
+ for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+ {
+ BaseMetric *bm = reg_metrics->fetch (i);
+ if (bm->get_type () == type && dbe_strcmp (bm->get_expr_spec (), expr_spec) == 0)
+ {
+ if ((type == BaseMetric::DERIVED || type == BaseMetric::HWCNTR)
+ && dbe_strcmp (bm->get_cmd (), cmd) != 0)
+ continue;
+ return bm;
+ }
+ }
+ return NULL;
+}
+
+BaseMetric *
+DbeSession::find_base_reg_metric (char * mcmd)
+{
+ for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+ {
+ BaseMetric *bm = reg_metrics->fetch (i);
+ if (bm->get_expr_spec () != NULL)
+ continue; // skip compare metrics
+ if (dbe_strcmp (bm->get_cmd (), mcmd) == 0)
+ return bm;
+ }
+ return NULL;
+}
+
+Vector<BaseMetric*> *
+DbeSession::get_base_reg_metrics ()
+{
+ Vector<BaseMetric*> *mlist = new Vector<BaseMetric*>;
+ Vector<BaseMetric*> *ml = get_all_reg_metrics ();
+ for (int i = 0, sz = ml->size (); i < sz; i++)
+ {
+ BaseMetric *m = ml->fetch (i);
+ if (m->get_expr_spec () == NULL)
+ mlist->append (m);
+ }
+ return mlist;
+}
+
+void
+DbeSession::check_tab_avail ()
+{
+ DbeView *dbev;
+ int index;
+ // tell the views to update their tab lists
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->get_settings ()->updateTabAvailability ();
+ }
+}
+
+bool
+DbeSession::is_datamode_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->dataspaceavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_leaklist_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->leaklistavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_heapdata_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->heapdataavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_iodata_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->iodataavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_racelist_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->racelistavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_deadlocklist_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->deadlocklistavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_timeline_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->timelineavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_ifreq_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->ifreqavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_omp_available ()
+{
+ if (status_ompavail == -1)
+ {
+ status_ompavail = 0;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->ompavail)
+ {
+ status_ompavail = 1;
+ break;
+ }
+ }
+ }
+ return status_ompavail == 1;
+}
+
+bool
+DbeSession::has_java ()
+{
+ int status_has_java = 0;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->has_java)
+ {
+ status_has_java = 1;
+ break;
+ }
+ }
+ return status_has_java == 1;
+}
+
+bool
+DbeSession::has_ompavail ()
+{
+ int status_has_ompavail = 0;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->ompavail)
+ {
+ status_has_ompavail = 1;
+ break;
+ }
+ }
+ return status_has_ompavail == 1;
+}
+
+int
+DbeSession::get_clock (int whichexp)
+{
+ // XXXX clock frequency should be an attribute of each CPU,
+ // XXX and not a property of the session
+ // if whichexp is -1, pick the first exp that has a clock
+ // otherwise return the clock from the numbered experiment
+ Experiment *exp;
+ if (whichexp != -1)
+ {
+ exp = get_exp (whichexp);
+ if (exp != NULL)
+ return exp->clock;
+ return 0;
+ }
+ int n = nexps ();
+ for (int i = 0; i < n; i++)
+ {
+ exp = get_exp (i);
+ if (exp != NULL && exp->clock != 0)
+ return exp->clock;
+ }
+ return 0;
+}
+
+LoadObject *
+DbeSession::find_lobj_by_name (const char *lobj_name, int64_t cksum)
+{
+ return loadObjMap->get (lobj_name, cksum);
+}
+
+static unsigned
+hash (char *s)
+{
+ unsigned res = 0;
+ for (int i = 0; i < 64 && *s; i++)
+ res = res * 13 + *s++;
+ return res;
+}
+
+// This method is introduced to fix performance
+// problems with the data space profiling in the
+// current release. A better design is desired.
+void
+DbeSession::dobj_updateHT (DataObject *dobj)
+{
+ unsigned index = hash (dobj->get_unannotated_name ()) % HTableSize;
+ List *list = new List;
+ list->val = (void*) dobj;
+ list->next = dnameHTable[index];
+ dnameHTable[index] = list;
+}
+
+DataObject *
+DbeSession::find_dobj_by_name (char *dobj_name)
+{
+ unsigned index = hash (dobj_name) % HTableSize;
+ List *list = dnameHTable[index];
+ for (; list; list = list->next)
+ {
+ DataObject *d = (DataObject*) list->val;
+ if (strcmp (d->get_unannotated_name (), dobj_name) == 0)
+ return d;
+ }
+ return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_match (DataObject *dobj)
+{
+ char *dobj_name = dobj->get_unannotated_name ();
+ unsigned index = hash (dobj_name) % HTableSize;
+ List *list = dnameHTable[index];
+ for (; list; list = list->next)
+ {
+ DataObject *d = (DataObject*) list->val;
+ if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+ && d->size == dobj->size && d->offset == dobj->offset
+ && d->scope == dobj->scope)
+ return d;
+ }
+ return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_master (DataObject *dobj)
+{
+ char *dobj_name = dobj->get_unannotated_name ();
+ unsigned index = hash (dobj_name) % HTableSize;
+ List *list = dnameHTable[index];
+ for (; list; list = list->next)
+ {
+ DataObject *d = (DataObject*) list->val;
+ // XXXX should parent also match?
+ if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+ && d->size == dobj->size && d->offset == dobj->offset
+ && d->master == NULL && d->scope == NULL)
+ return d;
+ }
+ return (DataObject *) NULL;
+}
+
+Vector<DataObject*>*
+DbeSession::get_dobj_elements (DataObject *dobj)
+{
+ DataObject *d;
+ int index;
+ Vector<DataObject*> *elements = new Vector<DataObject*>;
+ if (dobj == d_total)
+ return elements;
+ Vec_loop (DataObject*, dobjs, index, d)
+ {
+ if (d->get_parent () && d->get_parent () == dobj)
+ elements->append (d);
+ }
+ return elements;
+}
+
+Vector<LoadObject*>*
+DbeSession::get_text_segments ()
+{
+ LoadObject *lo;
+ int index;
+ Vector<LoadObject*> *tlobjs = new Vector<LoadObject*>;
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ if (lo->type == LoadObject::SEG_TEXT)
+ tlobjs->append (lo);
+ }
+ return tlobjs;
+}
+
+static long long
+getNumber (const char *s, char * &last)
+{
+ long long val;
+ char *sp;
+ errno = 0;
+ val = strtoll (s, &sp, 0);
+ if (errno == EINVAL)
+ last = NULL;
+ else
+ {
+ while (isspace (*sp))
+ sp++;
+ last = sp;
+ }
+ return (val);
+}
+
+bool
+DbeSession::find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj,
+ char *name, const char *sel, Histable::Type type, bool xdefault)
+{
+ Vector<Histable*> *obj_lst;
+ int which = -1;
+ char *last = NULL;
+ if (type != Histable::FUNCTION && sel)
+ {
+ // check that a number has been provided
+ which = (int) getNumber (sel, last);
+ if (last == NULL || *last != '\0')
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ sel = NULL;
+ which = 0;
+ }
+ which--;
+ }
+ obj_lst = new Vector<Histable*>;
+ switch (type)
+ {
+ case Histable::FUNCTION:
+ obj = map_NametoFunction (name, obj_lst, sel);
+ break;
+ case Histable::MODULE:
+ obj = map_NametoModule (name, obj_lst, which);
+ break;
+ case Histable::LOADOBJECT:
+ obj = map_NametoLoadObject (name, obj_lst, which);
+ break;
+ case Histable::DOBJECT:
+ obj = map_NametoDataObject (name, obj_lst, which);
+ break;
+ default:
+ abort (); // unexpected Histable!
+ }
+
+ if ((obj == NULL) && (obj_lst->size () > 0))
+ {
+ if (obj_lst->size () == 1)
+ which = 0;
+ else
+ {
+ if (sel && (which < 0 || which >= obj_lst->size ()))
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ if (xdefault)
+ {
+ fprintf (stderr, GTXT ("Default selection \"1\" made\n"));
+ which = 0;
+ }
+ else
+ {
+ which = ask_which (dis_file, inp_file, obj_lst, name);
+ if (which == -1)
+ {
+ delete obj_lst;
+ return false;
+ }
+ }
+ }
+ obj = obj_lst->fetch (which);
+ }
+ delete obj_lst;
+ return true;
+}
+
+int
+DbeSession::ask_which (FILE *dis_file, FILE *inp_file,
+ Vector<Histable*> *list, char *name)
+{
+ Histable *hitem;
+ Function *func;
+ Module *module;
+ int which, index, index1;
+ char *item_name, *lo_name, *fname, *last;
+ char buf[BUFSIZ];
+ for (;;)
+ {
+ fprintf (dis_file, GTXT ("Available name list:\n"));
+ fprintf (dis_file, GTXT ("%8d) Cancel\n"), 0);
+ Vec_loop (Histable*, list, index, hitem)
+ {
+ index1 = index + 1;
+ item_name = hitem->get_name ();
+ switch (hitem->get_type ())
+ {
+ case Histable::FUNCTION:
+ func = (Function *) hitem;
+ module = func->module;
+
+ // id == -1 indicates er_src invocation
+ if (module == NULL || (module->lang_code == Sp_lang_java
+ && module->loadobject->id == -1))
+ fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+ else
+ {
+ lo_name = module->loadobject->get_pathname ();
+ fname = (module->file_name && *module->file_name) ?
+ module->file_name : module->get_name ();
+ if (fname && *fname)
+ fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx (%s)\n"), index1,
+ item_name, lo_name, (ull_t) func->img_offset, fname);
+ else
+ fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx\n"), index1,
+ item_name, lo_name, (ull_t) func->img_offset);
+ }
+ break;
+ case Histable::MODULE:
+ module = (Module *) hitem;
+ lo_name = module->loadobject->get_pathname ();
+ if (name[strlen (name) - 1] ==
+ module->file_name[strlen (module->file_name) - 1])
+ fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1,
+ module->file_name, lo_name);
+ else
+ fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, item_name,
+ lo_name);
+ break;
+ default:
+ fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+ break;
+ }
+ }
+ if (inp_file != stdin)
+ return -1;
+ fprintf (dis_file, GTXT ("Enter selection: "));
+ if (fgets (buf, (int) sizeof (buf), inp_file) == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered:\n"));
+ return -1;
+ }
+ which = (int) getNumber (buf, last);
+ if (last && *last == '\0')
+ if (which >= 0 && which <= list->size ())
+ return which - 1;
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), buf);
+ }
+}
+
+static bool
+match_basename (char *name, char *full_name, int len = -1)
+{
+ if (full_name == NULL)
+ return false;
+ if (!strchr (name, '/'))
+ full_name = get_basename (full_name);
+ if (len == -1)
+ return streq (name, full_name);
+ return strncmp (name, full_name, len) == 0;
+}
+
+LoadObject *
+DbeSession::map_NametoLoadObject (char *name, Vector<Histable*> *list, int which)
+{
+ // Search the tree to find the first module whose module name
+ // matches "name" or whose source file name matches "name"
+ // Issues: is the name a pathname, or a base name?
+ // Should we look at suffix to disambiguate?
+ LoadObject *loitem;
+ int index;
+ Vec_loop (LoadObject*, lobjs, index, loitem)
+ {
+ // try pathname first
+ // if failed, try object name next
+ if (match_basename (name, loitem->get_pathname ()) ||
+ match_basename (name, loitem->get_name ()))
+ {
+ if (which == list->size ())
+ return loitem;
+ list->append (loitem);
+ }
+ }
+ return (LoadObject *) NULL;
+}
+
+Module *
+DbeSession::map_NametoModule (char *name, Vector<Histable*> *list, int which)
+{
+ // Search the tree to find the first loadobject whose loadobject name
+ // matches "name".
+
+ // Issues: is the name a pathname, or a base name?
+ // Should we look at suffix to disambiguate?
+ LoadObject *loitem;
+ Module *mitem;
+ int index1, index2;
+ Vec_loop (LoadObject*, lobjs, index1, loitem)
+ {
+ Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+ {
+ // try source name first
+ // if failed, try object name next
+ if (match_basename (name, mitem->file_name) ||
+ match_basename (name, mitem->get_name ()))
+ {
+ if (which == list->size ())
+ return mitem;
+ list->append (mitem);
+ }
+ }
+ }
+ return (Module *) NULL;
+}
+
+Function *
+DbeSession::map_NametoFunction (char *name, Vector<Histable*> *list,
+ const char *sel)
+{
+ // Search the tree to find the first function whose
+ // name matches "name".
+ // Issues: is the name a full name, or a short name?
+ // Is it a demangled name? If so, what about spaces
+ // within the name?
+ // Is there a way to return all names that match?
+ // How can the user specify a particular function of that name?
+ LoadObject *loitem;
+ Function *fitem, *main_func = NULL;
+ Module *mitem, *main_mod = NULL;
+ int index1, index2, index3, which = -1;
+ if (sel)
+ {
+ char *last = NULL;
+ if (*sel == '@')
+ { // 'sel' is "@seg_num:address"
+ which = (int) getNumber (sel + 1, last);
+ if (last == NULL || *last != ':' || (which < 0) || (which >= lobjs->size ()))
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ return NULL;
+ }
+ uint64_t address = getNumber (last + 1, last);
+ if (last == NULL || *last != '\0')
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ return NULL;
+ }
+ loitem = lobjs->fetch (which);
+ Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+ {
+ Vec_loop (Function*, mitem->functions, index3, fitem)
+ {
+ if (address == fitem->img_offset && match_FName (name, fitem))
+ return fitem;
+ }
+ }
+ return NULL;
+ }
+
+ which = (int) getNumber (sel, last);
+ if (last == NULL || *last != '\0')
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ return NULL;
+ }
+ which--;
+ }
+
+ int len_path = 0;
+ char *with_path = name;
+ name = StrRchr (name, '`');
+ if (name != with_path)
+ len_path = (int) (name - with_path);
+ else
+ with_path = NULL;
+
+ Vec_loop (LoadObject*, lobjs, index1, loitem)
+ {
+ Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+ {
+ if (with_path)
+ { // with file name
+ // try source name first
+ // if failed, try object name next
+ if (!match_basename (with_path, mitem->file_name, len_path) &&
+ !match_basename (with_path, mitem->get_name (), len_path))
+ continue;
+ }
+ Vec_loop (Function*, mitem->functions, index3, fitem)
+ {
+ if (match_FName (name, fitem))
+ {
+ if (which == list->size ())
+ return fitem;
+ list->append (fitem);
+ continue;
+ }
+ if (streq (fitem->get_name (), NTXT ("MAIN_")) && mitem->is_fortran ())
+ {
+ main_func = fitem;
+ main_mod = mitem;
+ }
+ }
+ }
+ }
+
+ if (main_mod && main_func)
+ {
+ main_mod->read_stabs ();
+ if (streq (main_func->get_match_name (), name) && which <= 1)
+ return main_func;
+ }
+ return (Function *) NULL;
+}
+
+DataObject *
+DbeSession::map_NametoDataObject (char *name, Vector<Histable*> *list,
+ int which)
+{
+ // Search master list to find dataobjects whose names match "name"
+ // selecting only the entry corresponding to "which" if it is not -1.
+ // Issues: is the name fully qualified or only partially?
+ DataObject *ditem = NULL;
+ int index;
+ char *full_name;
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ if (ditem->scope) continue; // skip non-master dataobjects
+
+ // try fully-qualified dataobject name first
+ if ((full_name = ditem->get_name ()) != NULL)
+ {
+ if (streq (name, full_name))
+ {
+ if (which == list->size ())
+ return ditem;
+ list->append (ditem);
+ }
+ }
+ }
+ if (list->size () > 0)
+ return ditem; // return fully-qualified match
+
+ // if fully-qualified name doesn't match anything, try a partial match
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ if (ditem->scope) continue; // skip non-master dataobjects
+
+ // try fully-qualified dataobject name first
+ if ((full_name = ditem->get_name ()) != NULL)
+ {
+ if (strstr (full_name, name))
+ {
+ if (which == list->size ())
+ return ditem;
+ list->append (ditem);
+ }
+ }
+ }
+ return (DataObject *) NULL;
+}
+
+bool
+DbeSession::match_FName (char *name, Function *func)
+{
+ size_t len;
+ char buf[MAXDBUF];
+ char *full_name;
+ if (streq (func->get_name (), name)) // try full name comparison
+ return true;
+ if (streq (func->get_mangled_name (), name)) // try mangled name
+ return true;
+ if (streq (func->get_match_name (), name)) // try match name
+ return true;
+
+ Module *md = func->module; // try FORTRAN name
+ if (md && md->is_fortran ())
+ {
+ char *mangled_name = func->get_mangled_name ();
+ len = strlen (name);
+ if (((len + 1) == strlen (mangled_name)) &&
+ (strncmp (name, mangled_name, len) == 0))
+ return true;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s"), func->get_name ());
+ full_name = buf;
+ char *arg = NULL; // find modifier and C++ class name
+ int i = get_paren (buf);
+ if (i >= 0)
+ {
+ arg = buf + i;
+ *arg = '\0';
+ }
+
+ char *mod = strchr (full_name, ' ');
+ char *cls = strchr (full_name, ':');
+
+ if (mod)
+ {
+ len = mod - full_name + 1;
+ if (!strncmp (full_name, name, len))
+ name += len;
+ full_name += len;
+ if (streq (full_name, name)) // try without modifier
+ return true;
+ }
+
+ size_t len_cmp = strlen (name);
+ if (arg)
+ {
+ *arg = '(';
+ len = arg - full_name; // try without 'args'
+ if (len_cmp == len && !strncmp (full_name, name, len))
+ return true;
+ if (cls)
+ {
+ len = arg - cls - 2; // and without 'class name'
+ if ((len_cmp == len) && !strncmp (cls + 2, name, len))
+ return true;
+ }
+ }
+
+ if (cls)
+ {
+ len = cls - full_name; // try C++ class name only
+ if (len_cmp == len && !strncmp (full_name, name, len))
+ return true;
+ if (streq (cls + 2, name)) // try without 'class name'
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::add_path (char *path)
+{
+ return add_path (path, get_search_path ());
+}
+
+bool
+DbeSession::add_classpath (char *path)
+{
+ return add_path (path, classpath);
+}
+
+Vector<DbeFile*> *
+DbeSession::get_classpath ()
+{
+ if (classpath_df == NULL)
+ classpath_df = new Vector<DbeFile*>;
+ for (int i = classpath_df->size (), sz = classpath->size (); i < sz; i++)
+ classpath_df->store (i, getDbeFile (classpath->fetch (i),
+ DbeFile::F_DIR_OR_JAR));
+ return classpath_df;
+}
+
+bool
+DbeSession::add_path (char *path, Vector<char*> *pathes)
+{
+ bool result = false;
+ Vector <char *> *tokens = split_str (path, ':');
+ for (long j = 0, jsz = VecSize (tokens); j < jsz; j++)
+ {
+ char *spath = tokens->get (j);
+ // Don't append path if it's already there
+ bool got = false;
+ for (int i = 0, sz = pathes->size (); i < sz; i++)
+ {
+ char *nm = pathes->get (i);
+ if (streq (nm, spath))
+ {
+ got = true;
+ break;
+ }
+ }
+ if (!got)
+ {
+ pathes->append (spath);
+ result = true;
+ }
+ else
+ free (spath);
+ }
+ delete tokens;
+ return result;
+}
+
+void
+DbeSession::set_need_refind ()
+{
+ Vector<DbeFile*> *f_list = dbeFiles->values ();
+ for (long i = 0, sz = f_list == NULL ? 0 : f_list->size (); i < sz; i++)
+ {
+ DbeFile *f = f_list->get (i);
+ f->set_need_refind (true);
+ }
+ delete f_list;
+ for (long i = 0, sz = sources == NULL ? 0 : sources->size (); i < sz; i++)
+ {
+ SourceFile *f = sources->get (i);
+ if (f && f->dbeFile)
+ f->dbeFile->set_need_refind (true);
+ }
+}
+
+void
+DbeSession::set_search_path (Vector<char*> *path, bool reset)
+{
+ if (reset)
+ search_path->destroy ();
+ for (int i = 0, sz = path == NULL ? 0 : path->size (); i < sz; i++)
+ {
+ char *name = path->fetch (i);
+ if (add_path (name))
+ reset = true;
+ }
+ if (reset)
+ {
+ set_need_refind ();
+
+ // now reset the string setting for it
+ StringBuilder sb;
+ for (int i = 0, sz = search_path == NULL ? 0 : search_path->size (); i < sz; i++)
+ {
+ char *name = search_path->fetch (i);
+ if (sb.length () != 0)
+ sb.append (':');
+ sb.append (name);
+ }
+ free (settings->str_search_path);
+ settings->str_search_path = sb.toString ();
+ }
+}
+
+void
+DbeSession::set_search_path (char *_lpath, bool reset)
+{
+ Vector<char *> *path = new Vector<char*>;
+ char *lpath = dbe_strdup (_lpath);
+ for (char *s = lpath; s;)
+ {
+ path->append (s);
+ s = strchr (s, ':');
+ if (s)
+ {
+ *s = 0;
+ s++;
+ }
+ }
+ set_search_path (path, reset);
+ delete path;
+ free (lpath);
+}
+
+void
+DbeSession::set_pathmaps (Vector<pathmap_t*> *newPathMap)
+{
+ set_need_refind ();
+ settings->set_pathmaps (newPathMap);
+}
+
+Vector<pathmap_t*> *
+DbeSession::get_pathmaps ()
+{
+ return settings->pathmaps;
+}
+
+void
+DbeSession::mobj_define (MemObjType_t *mobj)
+{
+ settings->mobj_define (mobj, false);
+ DbeView *dbev;
+ int index;
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->get_settings ()->mobj_define (mobj, false);
+ }
+}
+
+void
+DbeSession::dump_segments (FILE *out)
+{
+ int index;
+ LoadObject *loitem;
+ Vec_loop (LoadObject*, lobjs, index, loitem)
+ {
+ fprintf (out, NTXT ("Segment %d -- %s -- %s\n\n"),
+ index, loitem->get_name (), loitem->get_pathname ());
+ loitem->dump_functions (out);
+ fprintf (out, NTXT ("\n End Segment %d -- %s -- %s\n\n"),
+ index, loitem->get_name (), loitem->get_pathname ());
+ }
+}
+
+void
+DbeSession::dump_dataobjects (FILE *out)
+{
+ DataObject *ditem;
+ int index;
+
+ fprintf (out, NTXT ("\nMaster list of DataObjects:\n"));
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ Histable* scope = ditem->get_scope ();
+ DataObject* parent = ditem->get_parent ();
+ DataObject* master = ditem->get_master ();
+ if (parent != NULL)
+ fprintf (out, "id %6lld: [%4lld] parent = %6lld, offset = %+4lld %s\n",
+ (ll_t) ditem->id, (ll_t) ditem->get_size (),
+ (ll_t) parent->id, (ll_t) ditem->get_offset (),
+ ditem->get_name ());
+ else
+ {
+ // parent is NULL
+ fprintf (out, NTXT ("id %6lld: [%4lld] %s "),
+ (ll_t) ditem->id, (ll_t) ditem->get_size (),
+ ditem->get_name ());
+ if (master != NULL)
+ fprintf (out, NTXT (" master=%lld "), (ll_t) master->id);
+ else if (scope != NULL)
+ fprintf (out, NTXT (" master=?? "));
+ else
+ fprintf (out, NTXT (" MASTER "));
+#if DEBUG
+ if (scope != NULL)
+ {
+ switch (scope->get_type ())
+ {
+ case Histable::LOADOBJECT:
+ case Histable::FUNCTION:
+ fprintf (out, NTXT ("%s"), scope->get_name ());
+ break;
+ case Histable::MODULE:
+ {
+ char *filename = get_basename (scope->get_name ());
+ fprintf (out, NTXT ("%s"), filename);
+ break;
+ }
+ default:
+ fprintf (out, NTXT (" Unexpected scope %d:%s"),
+ scope->get_type (), scope->get_name ());
+ }
+ }
+#endif
+ fprintf (out, NTXT ("\n"));
+ }
+ }
+}
+
+void
+DbeSession::dump_map (FILE *out)
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ exp->dump_map (out);
+ }
+}
+
+void
+DbeSession::dump_stacks (FILE *outfile)
+{
+ Experiment *exp;
+ int n = nexps ();
+ FILE *f = (outfile == NULL ? stderr : outfile);
+ for (int i = 0; i < n; i++)
+ {
+ exp = get_exp (i);
+ fprintf (f, GTXT ("Experiment %d -- %s\n"), i, exp->get_expt_name ());
+ exp->dump_stacks (f);
+ }
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char *propName)
+{
+ PropDescr *prop = new PropDescr (propId, propName);
+ prop->flags = PRFLAG_NOSHOW; // do not show descriptions
+ propNames->store (propId, prop);
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char* propName,
+ const char* propUname, VType_type dataType,
+ int flags)
+{
+ PropDescr *prop = new PropDescr (propId, propName);
+ prop->vtype = dataType;
+ prop->uname = dbe_strdup (propUname);
+ prop->flags = flags;
+ propNames->store (propId, prop);
+}
+
+char *
+DbeSession::propNames_name_fetch (int i)
+{
+ PropDescr *prop = propNames->fetch (i);
+ if (prop)
+ return prop->name;
+ return NULL;
+}
+
+int
+DbeSession::registerPropertyName (const char *name)
+{
+ if (name == NULL)
+ return PROP_NONE;
+ for (int i = 0; i < propNames->size (); i++)
+ {
+ char *pname = propNames_name_fetch (i);
+ if (pname && strcasecmp (pname, name) == 0)
+ return i;
+ }
+ int propId = propNames->size ();
+ propNames_name_store (propId, name);
+ return propId;
+}
+
+int
+DbeSession::getPropIdByName (const char *name)
+{
+ if (name == NULL)
+ return PROP_NONE;
+ for (int i = 0; i < propNames->size (); i++)
+ {
+ char *pname = propNames_name_fetch (i);
+ if (pname && strcasecmp (pname, name) == 0)
+ return i;
+ }
+ return PROP_NONE;
+}
+
+char *
+DbeSession::getPropName (int propId)
+{
+ if (!propNames)
+ return NULL;
+ if (propId < 0 || propId >= propNames->size ())
+ return NULL;
+ return dbe_strdup (propNames_name_fetch (propId));
+}
+
+char *
+DbeSession::getPropUName (int propId)
+{
+ if (!propNames)
+ return NULL;
+ if (propId < 0 || propId >= propNames->size ())
+ return NULL;
+ PropDescr *prop = propNames->fetch (propId);
+ if (prop)
+ return dbe_strdup (prop->uname);
+ return NULL;
+}
+
+void
+DbeSession::append (UserLabel *lbl)
+{
+ if (lbl->expr)
+ {
+ if (userLabels == NULL)
+ userLabels = new Vector<UserLabel*> ();
+ userLabels->append (lbl);
+ }
+}
+
+void
+DbeSession::append (SourceFile *sf)
+{
+ sources->append (sf);
+ objs->append (sf);
+}
+
+UserLabel *
+DbeSession::findUserLabel (char *name)
+{
+ for (int i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+ {
+ UserLabel *lbl = userLabels->fetch (i);
+ if (strcasecmp (lbl->name, name) == 0)
+ return lbl;
+ }
+ return NULL;
+}
+
+Expression *
+DbeSession::findObjDefByName (char *name)
+{
+ Expression *expr = NULL;
+
+ MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
+ if (mot != NULL)
+ {
+ char *index_expr_str = mot->index_expr;
+ expr = ql_parse (index_expr_str);
+ }
+
+ if (expr == NULL)
+ {
+ int indxtype = findIndexSpaceByName (name);
+ expr = getIndexSpaceExpr (indxtype);
+ }
+ if (expr == NULL)
+ {
+ UserLabel *ulbl = findUserLabel (name);
+ if (ulbl)
+ expr = ulbl->expr;
+ }
+ return expr;
+}
+
+Expression *
+DbeSession::ql_parse (const char *expr_spec)
+{
+ /* (This slight duplication means we don't need to worry about copy
+ constructors for the QL::Result, nor about the lifetime of the
+ expr_spec.) */
+ if (expr_spec != NULL)
+ {
+ QL::Result result (expr_spec);
+ QL::Parser qlparser (result);
+ if (qlparser () != 0)
+ return NULL;
+ return result ();
+ }
+ else
+ {
+ QL::Result result;
+ QL::Parser qlparser (result);
+ if (qlparser () != 0)
+ return NULL;
+ return result ();
+ }
+}
+
+Vector<void*> *
+DbeSession::getIndxObjDescriptions ()
+{
+ int size = dyn_indxobj_indx;
+ if (size == 0)
+ return NULL;
+ Vector<int> *type = new Vector<int>(dyn_indxobj_indx);
+ Vector<char*> *desc = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char*> *i18ndesc = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char> *mnemonic = new Vector<char>(dyn_indxobj_indx);
+ Vector<int> *orderList = new Vector<int>(dyn_indxobj_indx);
+ Vector<char*> *exprList = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char*> *sdesc = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char*> *ldesc = new Vector<char*>(dyn_indxobj_indx);
+
+ for (long i = 0, sz = VecSize (dyn_indxobj); i < sz; i++)
+ {
+ IndexObjType_t *tot = dyn_indxobj->get (i);
+ if (tot->memObj == NULL)
+ {
+ type->append ((int) tot->type);
+ desc->append (dbe_strdup (tot->name));
+ i18ndesc->append (dbe_strdup (tot->i18n_name));
+ sdesc->append (dbe_strdup (tot->short_description));
+ ldesc->append (dbe_strdup (tot->long_description));
+ mnemonic->append (tot->mnemonic);
+ orderList->append (settings->indx_tab_order->fetch (i));
+ exprList->append (dbe_strdup (tot->index_expr_str));
+ }
+ }
+ Vector<void*> *res = new Vector<void*>(8);
+ res->store (0, type);
+ res->store (1, desc);
+ res->store (2, mnemonic);
+ res->store (3, i18ndesc);
+ res->store (4, orderList);
+ res->store (5, exprList);
+ res->store (6, sdesc);
+ res->store (7, ldesc);
+ return (res);
+}
+
+// Static function to get a vector of custom index object definitions
+Vector<void*> *
+DbeSession::getCustomIndxObjects ()
+{
+ Vector<char*> *name = new Vector<char*>;
+ Vector<char*> *formula = new Vector<char*>;
+ for (long i = dyn_indxobj_indx_fixed, sz = VecSize (dyn_indxobj); i < sz; i++)
+ {
+ IndexObjType_t *tot = dyn_indxobj->get (i);
+ if (tot->memObj == NULL)
+ {
+ name->append (dbe_strdup (tot->name));
+ formula->append (dbe_strdup (tot->index_expr_str));
+ }
+ }
+ Vector<void*> *res = new Vector<void*>(2);
+ res->store (0, name);
+ res->store (1, formula);
+ return (res);
+}
+
+// Static function to define a new index object type
+char *
+DbeSession::indxobj_define (const char *mname, char *i18nname, const char *index_expr_str, char *short_description, char *long_description)
+{
+ if (mname == NULL)
+ return dbe_strdup (GTXT ("No index object type name has been specified."));
+ if (isalpha ((int) (mname[0])) == 0)
+ return dbe_sprintf (GTXT ("Index Object type name %s does not begin with an alphabetic character"),
+ mname);
+ const char *p = mname;
+ while (*p != 0)
+ {
+ if ((isalnum ((int) (*p)) == 0) && (*p != '_'))
+ return dbe_sprintf (GTXT ("Index Object type name %s contains a non-alphanumeric character"),
+ mname);
+ p++;
+ }
+
+ // make sure the name is not in use
+ if (MemorySpace::findMemSpaceByName (mname) != NULL)
+ return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+ mname);
+
+ int idxx = findIndexSpaceByName (mname);
+ if (idxx >= 0)
+ {
+ IndexObjType_t *mt = dyn_indxobj->fetch (idxx);
+ if (strcmp (mt->index_expr_str, index_expr_str) == 0)
+ // It's a redefinition, but the new definition is the same
+ return NULL;
+ return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+ mname);
+ }
+ if (index_expr_str == NULL)
+ return dbe_strdup (GTXT ("No index-expr has been specified."));
+ if (strlen (index_expr_str) == 0)
+ return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+ index_expr_str);
+
+ // verify that the index expression parses correctly
+ char *expr_str = dbe_strdup (index_expr_str);
+ Expression *expr = ql_parse (expr_str);
+ if (expr == NULL)
+ return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+ expr_str);
+
+ // It's OK, create the new table entry
+ IndexObjType_t *tot = new IndexObjType_t;
+ tot->type = dyn_indxobj_indx++;
+ tot->name = dbe_strdup (mname);
+ tot->i18n_name = dbe_strdup (i18nname);
+ tot->short_description = dbe_strdup (short_description);
+ tot->long_description = dbe_strdup (long_description);
+ tot->index_expr_str = expr_str;
+ tot->index_expr = expr;
+ tot->mnemonic = mname[0];
+
+ // add it to the list
+ dyn_indxobj->append (tot);
+ idxobjs->append (new HashMap<uint64_t, Histable*>);
+
+ // tell the session
+ settings->indxobj_define (tot->type, false);
+
+ DbeView *dbev;
+ int index;
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->addIndexSpace (tot->type);
+ }
+ return NULL;
+}
+
+char *
+DbeSession::getIndexSpaceName (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->name;
+}
+
+char *
+DbeSession::getIndexSpaceDescr (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->i18n_name;
+}
+
+Expression *
+DbeSession::getIndexSpaceExpr (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->index_expr;
+}
+
+char *
+DbeSession::getIndexSpaceExprStr (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->index_expr_str;
+}
+
+int
+DbeSession::findIndexSpaceByName (const char *mname)
+{
+ int idx;
+ IndexObjType_t *mt;
+ Vec_loop (IndexObjType_t*, dyn_indxobj, idx, mt)
+ {
+ if (strcasecmp (mt->name, mname) == 0)
+ return idx;
+ }
+ return -1;
+}
+
+void
+DbeSession::removeIndexSpaceByName (const char *mname)
+{
+ IndexObjType_t *indObj = findIndexSpace (mname);
+ if (indObj)
+ indObj->name[0] = 0;
+}
+
+IndexObjType_t *
+DbeSession::getIndexSpace (int index)
+{
+ return ((index < 0) || (index >= VecSize (dyn_indxobj))) ? NULL : dyn_indxobj->get (index);
+}
+
+IndexObjType_t *
+DbeSession::findIndexSpace (const char *mname)
+{
+ return getIndexSpace (findIndexSpaceByName (mname));
+}
+
+void
+DbeSession::get_filter_keywords (Vector<void*> *res)
+{
+ Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
+ Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+ Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
+ Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+ Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+ Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
+ Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+
+ char *vtypeNames[] = VTYPE_TYPE_NAMES;
+ for (long i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+ {
+ UserLabel *lbl = userLabels->fetch (i);
+ kwCategory->append (dbe_strdup (NTXT ("FK_LABEL")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Labels")));
+ kwDataType->append (dbe_strdup (vtypeNames[TYPE_BOOL]));
+ kwKeyword->append (dbe_strdup (lbl->name));
+ kwFormula->append (dbe_strdup (lbl->str_expr));
+ kwDescription->append (dbe_strdup (lbl->comment));
+ kwEnumDescs->append (NULL);
+ }
+
+ for (long i = 0, sz = propNames ? propNames->size () : 0; i < sz; i++)
+ {
+ PropDescr *prop = propNames->fetch (i);
+ char *pname = prop ? prop->name : NULL;
+ if (pname == NULL || *pname == 0 || prop->flags & PRFLAG_NOSHOW)
+ continue;
+ int vtypeNum = prop->vtype;
+ if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
+ vtypeNum = TYPE_NONE;
+ kwCategory->append (dbe_strdup (NTXT ("FK_EVTPROP"))); //Event Property
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Misc. Definitions")));
+ kwDataType->append (dbe_strdup (vtypeNames[vtypeNum]));
+ kwKeyword->append (dbe_strdup (pname));
+ kwFormula->append (NULL);
+ kwDescription->append (dbe_strdup (prop->uname));
+ kwEnumDescs->append (NULL);
+ }
+
+ for (long i = 0, sz = dyn_indxobj ? dyn_indxobj->size () : 0; i < sz; i++)
+ {
+ IndexObjType_t *obj = dyn_indxobj->get (i);
+ if (obj->memObj)
+ continue;
+ kwCategory->append (dbe_strdup (NTXT ("FK_IDXOBJ")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Index Object Definitions")));
+ kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
+ kwKeyword->append (dbe_strdup (obj->name));
+ kwFormula->append (dbe_strdup (obj->index_expr_str));
+ kwDescription->append (dbe_strdup (obj->i18n_name));
+ kwEnumDescs->append (NULL);
+ }
+}
+
+Histable *
+DbeSession::findIndexObject (int idxtype, uint64_t idx)
+{
+ HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+ return iobjs->get (idx);
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, int64_t idx)
+{
+ HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+
+ Histable *idxobj = iobjs->get (idx);
+ if (idxobj == NULL)
+ {
+ idxobj = new IndexObject (idxtype, idx);
+ if (idx == -1)
+ idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+ iobjs->put (idx, idxobj);
+ }
+
+ return idxobj;
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, Histable *hobj)
+{
+ HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+ int64_t idx = hobj ? hobj->id : -1;
+ Histable *idxobj = iobjs->get (idx);
+ if (idxobj == NULL)
+ {
+ idxobj = new IndexObject (idxtype, hobj);
+ if (idx == -1)
+ idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+ iobjs->put (idx, idxobj);
+ }
+
+ return idxobj;
+}
+
+Histable *
+DbeSession::findObjectById (Histable::Type type, int subtype, uint64_t id)
+{
+ switch (type)
+ {
+ case Histable::FUNCTION:
+ case Histable::MODULE:
+ case Histable::LOADOBJECT:
+ return ( id < (uint64_t) objs->size ()) ? objs->fetch ((int) id) : NULL;
+ case Histable::INDEXOBJ:
+ return findIndexObject (subtype, id);
+ // ignoring the following cases
+ case Histable::INSTR:
+ case Histable::LINE:
+ case Histable::EADDR:
+ case Histable::MEMOBJ:
+ case Histable::PAGE:
+ case Histable::DOBJECT:
+ case Histable::SOURCEFILE:
+ case Histable::IOACTFILE:
+ case Histable::IOACTVFD:
+ case Histable::IOCALLSTACK:
+ case Histable::HEAPCALLSTACK:
+ case Histable::OTHER:
+ case Histable::EXPERIMENT:
+ break;
+ }
+ return NULL;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<JThread *> *
+DbeSession::match_java_threads (char *ustr, int matchParent,
+ Vector<uint64_t> * &grids,
+ Vector<uint64_t> * &expids)
+{
+ if (ustr == NULL)
+ return NULL;
+
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<JThread *> *ret = new Vector<JThread*>;
+ grids = new Vector<uint64_t>;
+ expids = new Vector<uint64_t>;
+
+ int index;
+ JThread *jthread;
+ int expid;
+ Experiment* exp;
+ Vec_loop (Experiment*, exps, expid, exp)
+ {
+
+ Vec_loop (JThread*, exp->get_jthreads (), index, jthread)
+ {
+ const char * name;
+ if (matchParent)
+ name = jthread->parent_name;
+ else
+ name = jthread->group_name;
+ if (name == NULL)
+ name = "";
+ if (!regexec (&regex_desc, name, 0, NULL, 0))
+ {
+ // this one matches
+ ret->append (jthread);
+ grids->append (exp->groupId);
+ expids->append (exp->getUserExpId ());
+ }
+ }
+ }
+
+ regfree (&regex_desc);
+ return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<Function *> *
+DbeSession::match_func_names (const char *ustr, Histable::NameFormat nfmt)
+{
+ if (ustr == NULL)
+ return NULL;
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<Function *> *ret = new Vector<Function*>;
+
+ int index;
+ Histable *obj;
+ Vec_loop (Histable*, objs, index, obj)
+ {
+ if (obj->get_type () == Histable::FUNCTION)
+ {
+ Function *func = (Function*) obj;
+ if (!regexec (&regex_desc, func->get_name (nfmt), 0, NULL, 0))
+ // this one matches
+ ret->append (func);
+ }
+ }
+ regfree (&regex_desc);
+ return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<FileData *> *
+DbeSession::match_file_names (char *ustr, Histable::NameFormat nfmt)
+{
+ if (ustr == NULL)
+ return NULL;
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<FileData *> *ret = new Vector<FileData*>;
+ int numExps = nexps ();
+ DefaultMap<int64_t, FileData*>* fDataMap;
+ Vector<FileData *> *fDataObjs;
+ FileData *fData;
+ int size;
+ for (int i = 0; i < numExps; i++)
+ {
+ Experiment *exp = get_exp (i);
+ fDataMap = exp->getFDataMap ();
+ fDataObjs = fDataMap->values ();
+ size = fDataObjs->size ();
+ for (int j = 0; j < size; j++)
+ {
+ fData = fDataObjs->fetch (j);
+ if (fData
+ && !regexec (&regex_desc, fData->get_raw_name (nfmt), 0, NULL, 0))
+ // this one matches
+ ret->append (fData);
+ }
+ }
+ regfree (&regex_desc);
+ return ret;
+}
+
+// return a vector of DataObjects that match the regular expression input string
+Vector<DataObject *> *
+DbeSession::match_dobj_names (char *ustr)
+{
+ if (ustr == NULL)
+ return NULL;
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<DataObject *> *ret = new Vector<DataObject*>;
+ int index;
+ DataObject *ditem;
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ // does this one match
+ if (!regexec (&regex_desc, ditem->get_name (), 0, NULL, 0))
+ // this one matches
+ ret->append (ditem);
+ }
+ regfree (&regex_desc);
+ return ret;
+}
+
+void
+DbeSession::dump (char *msg, Vector<BaseMetric*> *mlist)
+{
+ if (msg)
+ fprintf (stderr, "%s\n", msg);
+ int sz = mlist ? mlist->size () : -1;
+ for (int i = 0; i < sz; i++)
+ {
+ BaseMetric *m = mlist->fetch (i);
+ char *s = m->dump ();
+ fprintf (stderr, "%2d %s\n", i, s);
+ free (s);
+ }
+ fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
+
+void
+DbeSession::dump (char *msg, Vector<Metric*> *mlist)
+{
+ if (msg)
+ fprintf (stderr, "%s\n", msg);
+ int sz = mlist ? mlist->size () : -1;
+ for (int i = 0; i < sz; i++)
+ {
+ Metric *m = mlist->fetch (i);
+ char *s = m->dump ();
+ fprintf (stderr, "%2d %s\n", i, s);
+ free (s);
+ }
+ fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
diff --git a/gprofng/src/DbeSession.cc.1 b/gprofng/src/DbeSession.cc.1
new file mode 100644
index 0000000..7d635d2
--- /dev/null
+++ b/gprofng/src/DbeSession.cc.1
@@ -0,0 +1,3531 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "ExpGroup.h"
+#include "Expression.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "DbeSession.h"
+#include "LoadObject.h"
+#include "DbeSyncMap.h"
+#include "DbeThread.h"
+#include "ClassFile.h"
+#include "IndexObject.h"
+#include "PathTree.h"
+#include "Print.h"
+#include "QLParser.tab.hh"
+#include "DbeView.h"
+#include "MemorySpace.h"
+#include "Module.h"
+#include "SourceFile.h"
+#include "StringBuilder.h"
+#include "BaseMetric.h"
+#include "BaseMetricTreeNode.h"
+#include "Command.h"
+#include "UserLabel.h"
+#include "StringMap.h"
+#include "DbeFile.h"
+#include "DbeJarFile.h"
+#include "IOActivity.h"
+#include "HeapActivity.h"
+
+// This is a universal List structure to organize objects
+// of various types, even if different.
+struct List
+{
+ List *next;
+ void *val;
+};
+
+struct Countable
+{
+ Countable (void *_item)
+ {
+ item = _item;
+ ref_count = 0;
+ }
+
+ void *item;
+ int ref_count;
+};
+
+Platform_t DbeSession::platform =
+#if ARCH(SPARC)
+ Sparc;
+#elif ARCH(Aarch64)
+ Aarch64;
+#else // ARCH(Intel)
+ Intel;
+#endif
+
+// This constant determines the size of the data object name hash table.
+static const int HTableSize = 8192;
+static int DEFAULT_TINY_THRESHOLD = -1;
+
+unsigned int mpmt_debug_opt = 0;
+DbeSession *dbeSession = NULL;
+
+DbeSession::DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode)
+{
+ dbeSession = this;
+ ipc_mode = _ipc_mode;
+ rdt_mode = _rdt_mode;
+ settings = new Settings (_settings);
+ views = new Vector<DbeView*>;
+ exps = new Vector<Experiment*>;
+ lobjs = new Vector<LoadObject*>;
+ objs = new Vector<Histable*>;
+ dobjs = new Vector<DataObject*>;
+ metrics = new Vector<Countable*>;
+ reg_metrics = new Vector<BaseMetric*>;
+ hwcentries = NULL;
+ reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse
+ idxobjs = new Vector<HashMap<uint64_t, Histable*>*>;
+ tmp_files = new Vector<char*>;
+ search_path = new Vector<char*>;
+ classpath = new Vector<char*>;
+ classpath_df = NULL;
+ expGroups = new Vector<ExpGroup*>;
+ sourcesMap = new HashMap<char*, SourceFile*>;
+ sources = new Vector<SourceFile*>;
+ comp_lobjs = new HashMap<char*, LoadObject*>;
+ comp_dbelines = new HashMap<char*, DbeLine*>;
+ comp_sources = new HashMap<char*, SourceFile*>;
+ loadObjMap = new DbeSyncMap<LoadObject>;
+ f_special = new Vector<Function*>(LastSpecialFunction);
+ omp_functions = new Vector<Function*>(OMP_LAST_STATE);
+ interactive = false;
+ lib_visibility_used = false;
+
+ // Define all known property names
+ propNames = new Vector<PropDescr*>;
+ propNames_name_store (PROP_NONE, NTXT (""));
+ propNames_name_store (PROP_ATSTAMP, NTXT ("ATSTAMP"));
+ propNames_name_store (PROP_ETSTAMP, NTXT ("ETSTAMP"));
+ propNames_name_store (PROP_TSTAMP, NTXT ("TSTAMP"));
+ propNames_name_store (PROP_THRID, NTXT ("THRID"));
+ propNames_name_store (PROP_LWPID, NTXT ("LWPID"));
+ propNames_name_store (PROP_CPUID, NTXT ("CPUID"));
+ propNames_name_store (PROP_FRINFO, NTXT ("FRINFO"));
+ propNames_name_store (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+
+ // Samples
+ propNames_name_store (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
+ propNames_name_store (PROP_SAMPLE, NTXT ("SAMPLE"));
+
+ // GCEvents
+ propNames_name_store (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
+ propNames_name_store (PROP_GCEVENT, NTXT ("GCEVENT"));
+
+ // Metadata used by some packet types
+ propNames_name_store (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"),
+ NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+ // Clock profiling properties
+ propNames_name_store (PROP_UCPU, NTXT ("UCPU"));
+ propNames_name_store (PROP_SCPU, NTXT ("SCPU"));
+ propNames_name_store (PROP_TRAP, NTXT ("TRAP"));
+ propNames_name_store (PROP_TFLT, NTXT ("TFLT"));
+ propNames_name_store (PROP_DFLT, NTXT ("DFLT"));
+ propNames_name_store (PROP_KFLT, NTXT ("KFLT"));
+ propNames_name_store (PROP_ULCK, NTXT ("ULCK"));
+ propNames_name_store (PROP_TSLP, NTXT ("TSLP"));
+ propNames_name_store (PROP_WCPU, NTXT ("WCPU"));
+ propNames_name_store (PROP_TSTP, NTXT ("TSTP"));
+
+ propNames_name_store (PROP_MSTATE, NTXT ("MSTATE"));
+ propNames_name_store (PROP_NTICK, NTXT ("NTICK"));
+ propNames_name_store (PROP_OMPSTATE, NTXT ("OMPSTATE"));
+
+ // Synchronization tracing properties
+ propNames_name_store (PROP_SRQST, NTXT ("SRQST"));
+ propNames_name_store (PROP_SOBJ, NTXT ("SOBJ"));
+
+ // Hardware counter profiling properties
+ propNames_name_store (PROP_HWCTAG, NTXT ("HWCTAG"));
+ propNames_name_store (PROP_HWCINT, NTXT ("HWCINT"));
+ propNames_name_store (PROP_VADDR, NTXT ("VADDR"));
+ propNames_name_store (PROP_PADDR, NTXT ("PADDR"));
+ propNames_name_store (PROP_VIRTPC, NTXT ("VIRTPC"));
+ propNames_name_store (PROP_PHYSPC, NTXT ("PHYSPC"));
+ propNames_name_store (PROP_LWP_LGRP_HOME, NTXT ("LWP_LGRP_HOME"));
+ propNames_name_store (PROP_PS_LGRP_HOME, NTXT ("PS_LGRP_HOME"));
+ propNames_name_store (PROP_EA_PAGESIZE, NTXT ("EA_PAGESIZE"));
+ propNames_name_store (PROP_EA_LGRP, NTXT ("EA_LGRP"));
+ propNames_name_store (PROP_PC_PAGESIZE, NTXT ("PC_PAGESIZE"));
+ propNames_name_store (PROP_PC_LGRP, NTXT ("PC_LGRP"));
+ propNames_name_store (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+ propNames_name_store (PROP_MEM_LAT, NTXT ("MEM_LAT"));
+ propNames_name_store (PROP_MEM_SRC, NTXT ("MEM_SRC"));
+
+ // Heap tracing properties
+ propNames_name_store (PROP_HTYPE, NTXT ("HTYPE"));
+ propNames_name_store (PROP_HSIZE, NTXT ("HSIZE"));
+ propNames_name_store (PROP_HVADDR, NTXT ("HVADDR"));
+ propNames_name_store (PROP_HOVADDR, NTXT ("HOVADDR"));
+ propNames_name_store (PROP_HLEAKED, NTXT ("HLEAKED"),
+ GTXT ("Leaked bytes"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
+ propNames_name_store (PROP_HFREED, NTXT ("HFREED"),
+ GTXT ("Freed bytes"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"),
+ GTXT ("Current allocations"), TYPE_INT64, 0);
+ propNames_name_store (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"),
+ NULL, TYPE_INT64, DDFLAG_NOSHOW);
+ propNames_name_store (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"),
+ GTXT ("Current leaks"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"),
+ NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+ // IO tracing properties
+ propNames_name_store (PROP_IOTYPE, NTXT ("IOTYPE"));
+ propNames_name_store (PROP_IOFD, NTXT ("IOFD"));
+ propNames_name_store (PROP_IONBYTE, NTXT ("IONBYTE"));
+ propNames_name_store (PROP_IORQST, NTXT ("IORQST"));
+ propNames_name_store (PROP_IOOFD, NTXT ("IOOFD"));
+ propNames_name_store (PROP_IOFNAME, NTXT ("IOFNAME"));
+ propNames_name_store (PROP_IOVFD, NTXT ("IOVFD"));
+ propNames_name_store (PROP_IOFSTYPE, NTXT ("IOFSTYPE"));
+
+ // omptrace raw properties
+ propNames_name_store (PROP_CPRID, NTXT ("CPRID"));
+ propNames_name_store (PROP_PPRID, NTXT ("PPRID"));
+ propNames_name_store (PROP_TSKID, NTXT ("TSKID"));
+ propNames_name_store (PROP_PTSKID, NTXT ("PTSKID"));
+ propNames_name_store (PROP_PRPC, NTXT ("PRPC"));
+
+ // Data race detection properties
+ propNames_name_store (PROP_RID, NTXT ("RID"));
+ propNames_name_store (PROP_RTYPE, NTXT ("RTYPE"));
+ propNames_name_store (PROP_LEAFPC, NTXT ("LEAFPC"));
+ propNames_name_store (PROP_RVADDR, NTXT ("RVADDR"));
+ propNames_name_store (PROP_RCNT, NTXT ("RCNT"));
+
+ // Deadlock detection properties
+ propNames_name_store (PROP_DID, NTXT ("DID"));
+ propNames_name_store (PROP_DLTYPE, NTXT ("DLTYPE"));
+ propNames_name_store (PROP_DTYPE, NTXT ("DTYPE"));
+ propNames_name_store (PROP_DVADDR, NTXT ("DVADDR"));
+
+ // Synthetic properties (queries only)
+ propNames_name_store (PROP_STACK, NTXT ("STACK"));
+ propNames_name_store (PROP_MSTACK, NTXT ("MSTACK"));
+ propNames_name_store (PROP_USTACK, NTXT ("USTACK"));
+ propNames_name_store (PROP_XSTACK, NTXT ("XSTACK"));
+ propNames_name_store (PROP_HSTACK, NTXT ("HSTACK"));
+ propNames_name_store (PROP_STACKID, NTXT ("STACKID"));
+ //propNames_name_store( PROP_CPRID, NTXT("CPRID") );
+ //propNames_name_store( PROP_TSKID, NTXT("TSKID") );
+ propNames_name_store (PROP_JTHREAD, NTXT ("JTHREAD"),
+ GTXT ("Java thread number"), TYPE_UINT64, 0);
+
+ propNames_name_store (PROP_LEAF, NTXT ("LEAF"));
+ propNames_name_store (PROP_DOBJ, NTXT ("DOBJ"));
+ propNames_name_store (PROP_SAMPLE_MAP, NTXT ("SAMPLE_MAP"));
+ propNames_name_store (PROP_GCEVENT_MAP, NTXT ("GCEVENT_MAP"));
+ propNames_name_store (PROP_PID, NTXT ("PID"),
+ GTXT ("Process id"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_EXPID, NTXT ("EXPID"),
+ GTXT ("Experiment id"), TYPE_UINT64, DDFLAG_NOSHOW);
+ propNames_name_store (PROP_EXPID_CMP, NTXT ("EXPID_CMP"),
+ GTXT ("Comparable Experiment Id"), TYPE_UINT64,
+ DDFLAG_NOSHOW); //YXXX find better description
+ propNames_name_store (PROP_EXPGRID, NTXT ("EXPGRID"),
+ GTXT ("Comparison Group id"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_PARREG, NTXT ("PARREG"));
+ propNames_name_store (PROP_TSTAMP_LO, NTXT ("TSTAMP_LO"),
+ GTXT ("Start Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_TSTAMP_HI, NTXT ("TSTAMP_HI"),
+ GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+ propNames_name_store (PROP_TSTAMP2, NTXT ("TSTAMP2"),
+ GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64,
+ DDFLAG_NOSHOW);
+ propNames_name_store (PROP_FREQ_MHZ, NTXT ("FREQ_MHZ"),
+ GTXT ("CPU Frequency, MHz"), TYPE_UINT32, 0);
+ propNames_name_store (PROP_NTICK_USEC, NTXT ("NTICK_USEC"),
+ GTXT ("Clock Profiling Interval, Microseconds"),
+ TYPE_UINT64, 0);
+
+ propNames_name_store (PROP_IOHEAPBYTES, NTXT ("IOHEAPBYTES"));
+
+ propNames_name_store (PROP_STACKL, NTXT ("STACKL"));
+ propNames_name_store (PROP_MSTACKL, NTXT ("MSTACKL"));
+ propNames_name_store (PROP_USTACKL, NTXT ("USTACKL"));
+ propNames_name_store (PROP_XSTACKL, NTXT ("XSTACKL"));
+
+ propNames_name_store (PROP_STACKI, NTXT ("STACKI"));
+ propNames_name_store (PROP_MSTACKI, NTXT ("MSTACKI"));
+ propNames_name_store (PROP_USTACKI, NTXT ("USTACKI"));
+ propNames_name_store (PROP_XSTACKI, NTXT ("XSTACKI"));
+
+ // Make sure predefined names are not used for dynamic properties
+ propNames_name_store (PROP_LAST, NTXT (""));
+
+ localized_SP_UNKNOWN_NAME = GTXT ("(unknown)");
+
+ // define Index objects
+ dyn_indxobj = new Vector<IndexObjType_t*>();
+ dyn_indxobj_indx = 0;
+ char *s = dbe_sprintf (NTXT ("((EXPID_CMP<<%llu) | THRID)"),
+ (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+ indxobj_define (NTXT ("Threads"), GTXT ("Threads"), s, NULL, NULL);
+ free (s);
+ indxobj_define (NTXT ("CPUs"), GTXT ("CPUs"), NTXT ("(CPUID)"), NULL, NULL);
+ indxobj_define (NTXT ("Samples"), GTXT ("Samples"), NTXT ("(SAMPLE_MAP)"),
+ NULL, NULL);
+ indxobj_define (NTXT ("GCEvents"), GTXT ("GCEvents"), NTXT ("(GCEVENT_MAP)"),
+ NULL, NULL);
+ indxobj_define (NTXT ("Seconds"), GTXT ("Seconds"),
+ NTXT ("(TSTAMP/1000000000)"), NULL, NULL);
+ indxobj_define (NTXT ("Processes"), GTXT ("Processes"), NTXT ("(EXPID_CMP)"),
+ NULL, NULL);
+ s = dbe_sprintf (NTXT ("((EXPGRID<<%llu) | (EXPID<<%llu))"),
+ (unsigned long long) IndexObject::INDXOBJ_EXPGRID_SHIFT,
+ (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+ indxobj_define (NTXT ("Experiment_IDs"), GTXT ("Experiment_IDs"), s, NULL, NULL);
+ free (s);
+ indxobj_define (NTXT ("Datasize"), GTXT ("Datasize"),
+ "(IOHEAPBYTES==0?0:"
+ "((IOHEAPBYTES<=(1<<0)?(1<<0):"
+ "((IOHEAPBYTES<=(1<<2)?(1<<2):"
+ "((IOHEAPBYTES<=(1<<4)?(1<<4):"
+ "((IOHEAPBYTES<=(1<<6)?(1<<6):"
+ "((IOHEAPBYTES<=(1<<8)?(1<<8):"
+ "((IOHEAPBYTES<=(1<<10)?(1<<10):"
+ "((IOHEAPBYTES<=(1<<12)?(1<<12):"
+ "((IOHEAPBYTES<=(1<<14)?(1<<14):"
+ "((IOHEAPBYTES<=(1<<16)?(1<<16):"
+ "((IOHEAPBYTES<=(1<<18)?(1<<18):"
+ "((IOHEAPBYTES<=(1<<20)?(1<<20):"
+ "((IOHEAPBYTES<=(1<<22)?(1<<22):"
+ "((IOHEAPBYTES<=(1<<24)?(1<<24):"
+ "((IOHEAPBYTES<=(1<<26)?(1<<26):"
+ "((IOHEAPBYTES<=(1<<28)?(1<<28):"
+ "((IOHEAPBYTES<=(1<<30)?(1<<30):"
+ "((IOHEAPBYTES<=(1<<32)?(1<<32):"
+ "((IOHEAPBYTES<=(1<<34)?(1<<34):"
+ "((IOHEAPBYTES<=(1<<36)?(1<<36):"
+ "((IOHEAPBYTES<=(1<<38)?(1<<38):"
+ "((IOHEAPBYTES<=(1<<40)?(1<<40):"
+ "((IOHEAPBYTES<=(1<<42)?(1<<42):"
+ "((IOHEAPBYTES<=(1<<44)?(1<<44):"
+ "((IOHEAPBYTES<=(1<<46)?(1<<46):"
+ "((IOHEAPBYTES<=(1<<48)?(1<<48):"
+ "((IOHEAPBYTES<=(1<<50)?(1<<50):"
+ "(IOHEAPBYTES==-1?-1:(1<<50|1)"
+ "))))))))))))))))))))))))))))))))))))))))))))))))))))))",
+ NULL, NULL);
+ indxobj_define (NTXT ("Duration"), GTXT ("Duration"),
+ "((TSTAMP_HI-TSTAMP_LO)==0?0:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000?1000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000?10000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=100000?100000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000000?1000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000000?10000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=100000000?100000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000000000?1000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000000000?10000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=100000000000?100000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=1000000000000?1000000000000:"
+ "(((TSTAMP_HI-TSTAMP_LO)<=10000000000000?10000000000000:"
+ "(10000000000001))))))))))))))))))))))))", NULL, NULL);
+ dyn_indxobj_indx_fixed = dyn_indxobj_indx;
+ Elf::elf_init ();
+ defExpName = NULL;
+ mach_model_loaded = NULL;
+ tmp_dir_name = NULL;
+ settings->read_rc (ipc_mode || rdt_mode);
+
+ init ();
+}
+
+DbeSession::~DbeSession ()
+{
+ Destroy (views);
+ Destroy (exps);
+ Destroy (dobjs);
+ Destroy (metrics);
+ Destroy (search_path);
+ Destroy (classpath);
+ Destroy (propNames);
+ Destroy (expGroups);
+ Destroy (userLabels);
+ if (hwcentries)
+ {
+ for (long i = 0, sz = hwcentries->size (); i < sz; i++)
+ {
+ Hwcentry *h = hwcentries->get (i);
+ free (h->int_name);
+ free (h->name);
+ delete h;
+ }
+ delete hwcentries;
+ }
+
+ if (idxobjs)
+ {
+ for (int i = 0; i < idxobjs->size (); ++i)
+ {
+ HashMap<uint64_t, Histable*> *hMap = idxobjs->get (i);
+ if (hMap)
+ {
+ hMap->values ()->destroy ();
+ delete hMap;
+ }
+ }
+ delete idxobjs;
+ }
+
+ for (int i = 0; i < HTableSize; i++)
+ {
+ List *list = dnameHTable[i];
+ while (list)
+ {
+ List *tmp = list;
+ list = list->next;
+ delete tmp;
+ }
+ }
+ delete[] dnameHTable;
+ delete classpath_df;
+ Destroy (objs);
+ Destroy (reg_metrics);
+ Destroy (dyn_indxobj);
+ delete lobjs;
+ delete f_special;
+ destroy_map (DbeFile *, dbeFiles);
+ destroy_map (DbeJarFile *, dbeJarFiles);
+ delete loadObjMap;
+ delete omp_functions;
+ delete sourcesMap;
+ delete sources;
+ delete comp_lobjs;
+ delete comp_dbelines;
+ delete comp_sources;
+ delete reg_metrics_tree;
+ delete settings;
+ free (mach_model_loaded);
+
+ if (defExpName != NULL)
+ {
+ StringBuilder *sb = new StringBuilder ();
+ sb->append (NTXT ("/bin/rm -rf "));
+ sb->append (defExpName);
+ char *cmd = sb->toString ();
+ system (cmd);
+ free (cmd);
+ delete sb;
+ free (defExpName);
+ }
+ unlink_tmp_files ();
+ delete tmp_files;
+ dbeSession = NULL;
+}
+
+void
+DbeSession::unlink_tmp_files ()
+{
+ if (tmp_files)
+ {
+ for (int i = 0, sz = tmp_files->size (); i < sz; i++)
+ unlink (tmp_files->fetch (i));
+ tmp_files->destroy ();
+ delete tmp_files;
+ tmp_files = NULL;
+ }
+ if (tmp_dir_name)
+ {
+ char *cmd = dbe_sprintf (NTXT ("/bin/rm -rf %s"), tmp_dir_name);
+ system (cmd);
+ free (cmd);
+ free (tmp_dir_name);
+ tmp_dir_name = NULL;
+ }
+}
+
+char *
+DbeSession::get_tmp_file_name (const char *nm, bool for_java)
+{
+ if (tmp_dir_name == NULL)
+ {
+ tmp_dir_name = dbe_sprintf (NTXT ("/tmp/analyzer.%llu.%lld"),
+ (unsigned long long) getuid (), (long long) getpid ());
+ mkdir (tmp_dir_name, S_IRWXU);
+ }
+ char *fnm = dbe_sprintf (NTXT ("%s/%s"), tmp_dir_name, nm);
+ if (for_java)
+ for (char *s = fnm + strlen (tmp_dir_name) + 1; *s; s++)
+ if (*s == '/')
+ *s = '.';
+ return fnm;
+}
+
+void
+DbeSession::init ()
+{
+ user_exp_id_counter = 0;
+ status_ompavail = 0;
+ archive_mode = 0;
+
+#if DEBUG
+ char *s = getenv (NTXT ("MPMT_DEBUG"));
+ if (s)
+ mpmt_debug_opt = atoi (s);
+#endif /* DEBUG */
+ dbeFiles = new StringMap<DbeFile*>();
+ dbeJarFiles = new StringMap<DbeJarFile*>(128, 128);
+
+ // set up the initial (after .rc file reading) search path
+ set_search_path (settings->str_search_path, true);
+ userLabels = NULL;
+
+ // Preset all objects as they may reuse each other
+ lo_unknown = NULL;
+ f_unknown = NULL;
+ j_unknown = NULL;
+ lo_total = NULL;
+ sf_unknown = NULL;
+ f_total = NULL;
+ f_jvm = NULL;
+ d_total = NULL;
+ d_scalars = NULL;
+ d_unknown = NULL;
+ expGroups->destroy ();
+ f_special->reset ();
+ for (int i = 0; i < LastSpecialFunction; i++)
+ f_special->append (NULL);
+
+ lo_omp = NULL;
+ omp_functions->reset ();
+ for (int i = 0; i < OMP_LAST_STATE; i++)
+ omp_functions->append (NULL);
+
+ // make sure the metric list is initialized
+ register_metric (Metric::SIZES);
+ register_metric (Metric::ADDRESS);
+ register_metric (Metric::ONAME);
+
+ // This is needed only to maintain loadobject id's
+ // for <Total> and <Unknown> in tests
+ (void) get_Unknown_LoadObject ();
+ (void) get_Total_LoadObject ();
+
+ // Create the data object name hash table.
+ dnameHTable = new List*[HTableSize];
+ for (int i = 0; i < HTableSize; i++)
+ dnameHTable[i] = NULL;
+
+ d_total = createDataObject ();
+ d_total->set_name (NTXT ("<Total>"));
+
+ // XXXX <Scalars> only appropriate for Program/Data-oriented analyses
+ d_scalars = createDataObject ();
+ d_scalars->set_name (GTXT ("<Scalars>"));
+
+ d_unknown = createDataObject ();
+ d_unknown->set_name (GTXT ("<Unknown>"));
+
+ // assign d_unknown's children so data_olayout has consistent sorting
+ for (unsigned pp_code = 1; pp_code < NUM_ABS_PP_CODES + 2; pp_code++)
+ {
+ char *errcode;
+ DataObject* dobj = createDataObject ();
+ switch (pp_code)
+ {
+ case NUM_ABS_PP_CODES + 1:
+ errcode = PTXT (DOBJ_UNDETERMINED);
+ break;
+ case NUM_ABS_PP_CODES:
+ errcode = PTXT (DOBJ_UNSPECIFIED);
+ break;
+ case NUM_ABS_PP_CODES - 1:
+ errcode = PTXT (DOBJ_UNIDENTIFIED);
+ break;
+ default:
+ errcode = PTXT (ABS_PP_CODES[pp_code]);
+ }
+ dobj->parent = d_unknown;
+ dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+ }
+
+ for (unsigned rt_code = 1; rt_code < NUM_ABS_RT_CODES - 1; rt_code++)
+ {
+ DataObject* dobj = createDataObject ();
+ dobj->parent = d_unknown;
+ dobj->set_dobjname (PTXT (ABS_RT_CODES[rt_code]), NULL); // dobj->parent must already be set
+ }
+}
+
+void
+DbeSession::reset_data ()
+{
+ for (long i = 0, sz = VecSize (idxobjs); i < sz; ++i)
+ if (idxobjs->get (i))
+ idxobjs->get (i)->reset ();
+}
+
+void
+DbeSession::reset ()
+{
+ loadObjMap->reset ();
+ DbeView *dbev;
+ int index;
+
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->reset ();
+ }
+
+ destroy_map (DbeFile *, dbeFiles);
+ destroy_map (DbeJarFile *, dbeJarFiles);
+ exps->destroy ();
+ lobjs->reset (); // all LoadObjects belong to objs
+ dobjs->destroy (); // deletes d_unknown and d_total as well
+ objs->destroy ();
+ comp_lobjs->clear ();
+ comp_dbelines->clear ();
+ comp_sources->clear ();
+ sourcesMap->clear ();
+ sources->reset ();
+
+ // Delete the data object name hash table.
+ for (int i = 0; i < HTableSize; i++)
+ {
+ List *list = dnameHTable[i];
+ while (list)
+ {
+ List *tmp = list;
+ list = list->next;
+ delete tmp;
+ }
+ }
+ delete[] dnameHTable;
+
+ // IndexObect definitions remain, objects themselves may go
+ for (int i = 0; i < idxobjs->size (); ++i)
+ {
+ HashMap<uint64_t, Histable*> *v = idxobjs->fetch (i);
+ if (v != NULL)
+ {
+ v->values ()->destroy ();
+ v->clear ();
+ }
+ }
+ init ();
+}
+
+Vector<SourceFile*> *
+DbeSession::get_sources ()
+{
+ return sources;
+}
+
+DbeFile *
+DbeSession::getDbeFile (char *filename, int filetype)
+{
+ Dprintf (DEBUG_DBE_FILE, NTXT ("DbeSession::getDbeFile filetype=0x%x %s\n"), filetype, filename);
+ if (strncmp (filename, NTXT ("./"), 2) == 0)
+ filename += 2;
+ DbeFile *dbeFile = dbeFiles->get (filename);
+ if (dbeFile == NULL)
+ {
+ dbeFile = new DbeFile (filename);
+ dbeFiles->put (filename, dbeFile);
+ }
+ dbeFile->filetype |= filetype;
+ return dbeFile;
+}
+
+LoadObject *
+DbeSession::get_Total_LoadObject ()
+{
+ if (lo_total == NULL)
+ {
+ lo_total = createLoadObject (NTXT ("<Total>"));
+ lo_total->dbeFile->filetype |= DbeFile::F_FICTION;
+ }
+ return lo_total;
+}
+
+Function *
+DbeSession::get_Total_Function ()
+{
+ if (f_total == NULL)
+ {
+ f_total = createFunction ();
+ f_total->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ f_total->set_name (NTXT ("<Total>"));
+ Module *mod = get_Total_LoadObject ()->noname;
+ f_total->module = mod;
+ mod->functions->append (f_total);
+ }
+ return f_total;
+}
+
+LoadObject *
+DbeSession::get_Unknown_LoadObject ()
+{
+ if (lo_unknown == NULL)
+ {
+ lo_unknown = createLoadObject (GTXT ("<Unknown>"));
+ lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable
+ lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+
+ // force creation of the <Unknown> function
+ (void) get_Unknown_Function ();
+ }
+ return lo_unknown;
+}
+
+SourceFile *
+DbeSession::get_Unknown_Source ()
+{
+ if (sf_unknown == NULL)
+ {
+ sf_unknown = createSourceFile (localized_SP_UNKNOWN_NAME);
+ sf_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+ sf_unknown->flags |= SOURCE_FLAG_UNKNOWN;
+ }
+ return sf_unknown;
+}
+
+Function *
+DbeSession::get_Unknown_Function ()
+{
+ if (f_unknown == NULL)
+ {
+ f_unknown = createFunction ();
+ f_unknown->flags |= FUNC_FLAG_SIMULATED;
+ f_unknown->set_name (GTXT ("<Unknown>"));
+ Module *mod = get_Unknown_LoadObject ()->noname;
+ f_unknown->module = mod;
+ mod->functions->append (f_unknown);
+ }
+ return f_unknown;
+}
+
+// LIBRARY_VISIBILITY
+
+Function *
+DbeSession::create_hide_function (LoadObject *lo)
+{
+ Function *h_function = createFunction ();
+ h_function->set_name (lo->get_name ());
+ h_function->module = lo->noname;
+ h_function->isHideFunc = true;
+ lo->noname->functions->append (h_function);
+ return h_function;
+}
+
+Function *
+DbeSession::get_JUnknown_Function ()
+{
+ if (j_unknown == NULL)
+ {
+ j_unknown = createFunction ();
+ j_unknown->flags |= FUNC_FLAG_SIMULATED;
+ j_unknown->set_name (GTXT ("<no Java callstack recorded>"));
+ Module *mod = get_Unknown_LoadObject ()->noname;
+ j_unknown->module = mod;
+ mod->functions->append (j_unknown);
+ }
+ return j_unknown;
+}
+
+Function *
+DbeSession::get_jvm_Function ()
+{
+ if (f_jvm == NULL)
+ {
+ f_jvm = createFunction ();
+ f_jvm->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ f_jvm->set_name (GTXT ("<JVM-System>"));
+
+ // Find the JVM LoadObject
+ LoadObject *jvm = get_Unknown_LoadObject ();
+ for (int i = 0; i < lobjs->size (); ++i)
+ {
+ LoadObject *lo = lobjs->fetch (i);
+ if (lo->flags & SEG_FLAG_JVM)
+ {
+ jvm = lo;
+ break;
+ }
+ }
+ Module *mod = jvm->noname;
+ f_jvm->module = mod;
+ mod->functions->append (f_jvm);
+ // XXXX is it required? no consistency among all special functions
+ // jvm->functions->append( f_jvm );
+ }
+ return f_jvm;
+}
+
+Function *
+DbeSession::getSpecialFunction (SpecialFunction kind)
+{
+ if (kind < 0 || kind >= LastSpecialFunction)
+ return NULL;
+
+ Function *func = f_special->fetch (kind);
+ if (func == NULL)
+ {
+ char *fname;
+ switch (kind)
+ {
+ case TruncatedStackFunc:
+ fname = GTXT ("<Truncated-stack>");
+ break;
+ case FailedUnwindFunc:
+ fname = GTXT ("<Stack-unwind-failed>");
+ break;
+ default:
+ return NULL;
+ }
+ func = createFunction ();
+ func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ Module *mod = get_Total_LoadObject ()->noname;
+ func->module = mod;
+ mod->functions->append (func);
+ func->set_name (fname);
+ f_special->store (kind, func);
+ }
+ return func;
+}
+
+LoadObject *
+DbeSession::get_OMP_LoadObject ()
+{
+ if (lo_omp == NULL)
+ {
+ for (int i = 0, sz = lobjs->size (); i < sz; i++)
+ {
+ LoadObject *lo = lobjs->fetch (i);
+ if (lo->flags & SEG_FLAG_OMP)
+ {
+ lo_omp = lo;
+ return lo_omp;
+ }
+ }
+ lo_omp = createLoadObject (GTXT ("<OMP>"));
+ lo_omp->type = LoadObject::SEG_TEXT;
+ lo_omp->dbeFile->filetype |= DbeFile::F_FICTION;
+ }
+ return lo_omp;
+}
+
+Function *
+DbeSession::get_OMP_Function (int n)
+{
+ if (n < 0 || n >= OMP_LAST_STATE)
+ return NULL;
+
+ Function *func = omp_functions->fetch (n);
+ if (func == NULL)
+ {
+ char *fname;
+ switch (n)
+ {
+ case OMP_OVHD_STATE:
+ fname = GTXT ("<OMP-overhead>");
+ break;
+ case OMP_IDLE_STATE:
+ fname = GTXT ("<OMP-idle>");
+ break;
+ case OMP_RDUC_STATE:
+ fname = GTXT ("<OMP-reduction>");
+ break;
+ case OMP_IBAR_STATE:
+ fname = GTXT ("<OMP-implicit_barrier>");
+ break;
+ case OMP_EBAR_STATE:
+ fname = GTXT ("<OMP-explicit_barrier>");
+ break;
+ case OMP_LKWT_STATE:
+ fname = GTXT ("<OMP-lock_wait>");
+ break;
+ case OMP_CTWT_STATE:
+ fname = GTXT ("<OMP-critical_section_wait>");
+ break;
+ case OMP_ODWT_STATE:
+ fname = GTXT ("<OMP-ordered_section_wait>");
+ break;
+ case OMP_ATWT_STATE:
+ fname = GTXT ("<OMP-atomic_wait>");
+ break;
+ default:
+ return NULL;
+ }
+ func = createFunction ();
+ func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+ func->set_name (fname);
+
+ LoadObject *omp = get_OMP_LoadObject ();
+ func->module = omp->noname;
+ omp->noname->functions->append (func);
+ omp->functions->append (func);
+ omp_functions->store (n, func);
+ }
+ return func;
+}
+
+// Divide the original createExperiment() into two steps
+// In part1, we just create the data structure, in part2, if
+// we decide to keep the experiment around, add it to various
+// lists in DbeSession
+Experiment *
+DbeSession::createExperimentPart1 ()
+{
+ Experiment *exp = new Experiment ();
+ return exp;
+}
+
+void
+DbeSession::createExperimentPart2 (Experiment *exp)
+{
+ int ind = expGroups->size ();
+ if (ind > 0)
+ {
+ ExpGroup *gr = expGroups->fetch (ind - 1);
+ exp->groupId = gr->groupId;
+ gr->append (exp);
+ }
+ exp->setExpIdx (exps->size ());
+ exp->setUserExpId (++user_exp_id_counter);
+ exps->append (exp);
+}
+
+Experiment *
+DbeSession::createExperiment ()
+{
+ Experiment *exp = new Experiment ();
+ append (exp);
+ return exp;
+}
+
+void
+DbeSession::append (Experiment *exp)
+{
+ exp->setExpIdx (exps->size ());
+ exp->setUserExpId (++user_exp_id_counter);
+ exps->append (exp);
+ if (exp->founder_exp)
+ {
+ if (exp->founder_exp->children_exps == NULL)
+ exp->founder_exp->children_exps = new Vector<Experiment *>;
+ exp->founder_exp->children_exps->append (exp);
+ if (exp->founder_exp->groupId > 0)
+ {
+ exp->groupId = exp->founder_exp->groupId;
+ expGroups->get (exp->groupId - 1)->append (exp);
+ }
+ }
+ if (exp->groupId == 0)
+ {
+ long ind = VecSize (expGroups);
+ if (ind > 0)
+ {
+ ExpGroup *gr = expGroups->get (ind - 1);
+ exp->groupId = gr->groupId;
+ gr->append (exp);
+ }
+ }
+}
+
+void
+DbeSession::append (Hwcentry *h)
+{
+ if (hwcentries == NULL)
+ hwcentries = new Vector<Hwcentry*>;
+ hwcentries->append (h);
+}
+
+int
+DbeSession::ngoodexps ()
+{
+ int cnt = 0;
+ for (long i = 0, sz = VecSize (exps); i < sz; i++)
+ if (exps->get (i)->get_status () == Experiment::SUCCESS)
+ cnt++;
+ return cnt;
+}
+
+int
+DbeSession::createView (int index, int cloneindex)
+{
+ // ensure that there is no view with that index
+ DbeView *dbev = getView (index);
+ if (dbev != NULL)
+ abort ();
+
+ // find the view to be cloned
+ dbev = getView (cloneindex);
+ DbeView *newview;
+ if (dbev == NULL)
+ newview = new DbeView (theApplication, settings, index);
+ else
+ newview = new DbeView (dbev, index);
+ views->append (newview);
+ return index;
+}
+
+DbeView *
+DbeSession::getView (int index)
+{
+ int i;
+ DbeView *dbev;
+ Vec_loop (DbeView*, views, i, dbev)
+ {
+ if (dbev->vindex == index)
+ return dbev;
+ }
+ return NULL;
+}
+
+void
+DbeSession::dropView (int index)
+{
+ int i;
+ DbeView *dbev;
+
+ Vec_loop (DbeView*, views, i, dbev)
+ {
+ if (dbev->vindex == index)
+ {
+ views->remove (i);
+ delete dbev;
+ return;
+ }
+ }
+ // view not found; ignore for now
+}
+
+Vector<char*> *
+DbeSession::get_group_or_expt (char *path)
+{
+ Vector<char*> *exp_list = new Vector<char*>;
+ FILE *fptr;
+ char *new_path, buf[MAXPATHLEN], name[MAXPATHLEN];
+
+ fptr = fopen (path, NTXT ("r"));
+ if (!fptr || !fgets (buf, (int) sizeof (buf), fptr)
+ || strncmp (buf, SP_GROUP_HEADER, strlen (SP_GROUP_HEADER)))
+ {
+ // it's not an experiment group
+ new_path = dbe_strdup (path);
+ new_path = canonical_path (new_path);
+ exp_list->append (new_path);
+ }
+ else
+ {
+ // it is an experiment group, read the list to get them all
+ while (fgets (buf, (int) sizeof (buf), fptr))
+ {
+ if ((*buf != '#') && (sscanf (buf, NTXT ("%s"), name) == 1))
+ {
+ new_path = dbe_strdup (name);
+ new_path = canonical_path (new_path);
+ exp_list->append (new_path);
+ }
+ }
+ }
+ if (fptr)
+ fclose (fptr);
+ return exp_list;
+}
+
+#define GET_INT_VAL(v, s, len) \
+ for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
+
+static int
+dir_name_cmp (const void *a, const void *b)
+{
+ char *s1 = *((char **) a);
+ char *s2 = *((char **) b);
+ while (*s1)
+ {
+ if (isdigit (*s1) && isdigit (*s2))
+ {
+ int v1, v2, len1, len2;
+ GET_INT_VAL (v1, s1, len1);
+ GET_INT_VAL (v2, s2, len2);
+ if (v1 != v2)
+ return v1 - v2;
+ if (len1 != len2)
+ return len2 - len1;
+ continue;
+ }
+ if (*s1 != *s2)
+ break;
+ s1++;
+ s2++;
+ }
+ return *s1 - *s2;
+}
+
+static int
+read_experiment_data_in_parallel (void *arg)
+{
+ exp_ctx *ctx = (exp_ctx *) arg;
+ Experiment *dexp = ctx->exp;
+ bool read_ahead = ctx->read_ahead;
+ dexp->read_experiment_data (read_ahead);
+ free (ctx);
+ return 0;
+}
+
+void
+DbeSession::open_experiment (Experiment *exp, char *path)
+{
+ exp->open (path);
+ if (exp->get_status () != Experiment::FAILURE)
+ exp->read_experiment_data (false);
+ exp->open_epilogue ();
+
+ // Update all DbeViews
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ dbev->add_experiment (exp->getExpIdx (), true);
+ }
+
+ if (exp->get_status () == Experiment::FAILURE)
+ {
+ check_tab_avail ();
+ return;
+ }
+
+ char *discard_tiny = getenv (NTXT ("SP_ANALYZER_DISCARD_TINY_EXPERIMENTS"));
+ int user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; // in milliseconds
+ if (discard_tiny != NULL)
+ {
+ user_specified_tiny_threshold = (atoi (discard_tiny));
+ if (user_specified_tiny_threshold < 0)
+ user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD;
+ }
+
+ // Open descendant experiments
+ DIR *exp_dir = opendir (path);
+ if (exp_dir == NULL)
+ {
+ check_tab_avail ();
+ return;
+ }
+
+ Vector<char*> *exp_names = new Vector<char*>();
+ struct dirent *entry = NULL;
+ while ((entry = readdir (exp_dir)) != NULL)
+ {
+ if (entry->d_name[0] != '_')
+ continue;
+ size_t len = strlen (entry->d_name);
+ if (len < 3 || strcmp (entry->d_name + len - 3, NTXT (".er")) != 0)
+ continue;
+ exp_names->append (dbe_strdup (entry->d_name));
+ }
+ closedir (exp_dir);
+ exp_names->sort (dir_name_cmp);
+ Experiment **t_exp_list = new Experiment *[exp_names->size ()];
+ int nsubexps = 0;
+
+ for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+ {
+ t_exp_list[j] = NULL;
+
+ char *lineage_name = exp_names->fetch (j);
+ struct stat64 sbuf;
+ char *dpath = dbe_sprintf (NTXT ("%s/%s"), path, lineage_name);
+
+ // look for experiments with no profile collected
+ if (user_specified_tiny_threshold == DEFAULT_TINY_THRESHOLD)
+ {
+ char *frinfoname = dbe_sprintf (NTXT ("%s/%s"), dpath, "data." SP_FRINFO_FILE);
+ int st = dbe_stat (frinfoname, &sbuf);
+ free (frinfoname);
+ if (st == 0)
+ {
+ // if no profile/trace data do not process this experiment any further
+ if (sbuf.st_size == 0)
+ {
+ free (dpath);
+ continue;
+ }
+ }
+ }
+ else
+ { // check if dpath is a directory
+ if (dbe_stat (dpath, &sbuf) != 0)
+ {
+ free (dpath);
+ continue;
+ }
+ else if (!S_ISDIR (sbuf.st_mode))
+ {
+ free (dpath);
+ continue;
+ }
+ }
+ size_t lineage_name_len = strlen (lineage_name);
+ lineage_name[lineage_name_len - 3] = 0; /* remove .er */
+ Experiment *dexp = new Experiment ();
+ dexp->founder_exp = exp;
+ if (user_specified_tiny_threshold > DEFAULT_TINY_THRESHOLD)
+ {
+ dexp->setTinyThreshold (user_specified_tiny_threshold);
+ dexp->open (dpath);
+ if (dexp->isDiscardedTinyExperiment ())
+ {
+ delete dexp;
+ free (dpath);
+ continue;
+ }
+ }
+ else
+ dexp->open (dpath);
+ append (dexp);
+ t_exp_list[j] = dexp;
+ nsubexps++;
+ dexp->set_clock (exp->clock);
+
+ // DbeView add_experiment() is split into two parts
+ // add_subexperiment() is called repeeatedly for
+ // all sub_experiments, later add_experiment_epilogue() finishes up the task
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ bool enabled = settings->check_en_desc (lineage_name, dexp->utargname);
+ dbev->add_subexperiment (dexp->getExpIdx (), enabled);
+ }
+ free (dpath);
+ }
+
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ dbev->add_experiment_epilogue ();
+ }
+
+ DbeThreadPool * threadPool = new DbeThreadPool (-1);
+ for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+ {
+ if (t_exp_list[j] == NULL) continue;
+ Experiment *dexp = t_exp_list[j];
+ exp_ctx *new_ctx = (exp_ctx*) malloc (sizeof (exp_ctx));
+ new_ctx->path = NULL;
+ new_ctx->exp = dexp;
+ new_ctx->ds = this;
+ new_ctx->read_ahead = true;
+ DbeQueue *q = new DbeQueue (read_experiment_data_in_parallel, new_ctx);
+ threadPool->put_queue (q);
+ }
+ threadPool->wait_queues ();
+ delete threadPool;
+
+ for (long j = 0, jsz = exp_names->size (); j < jsz; j++)
+ {
+ if (t_exp_list[j] == NULL) continue;
+ Experiment *dexp = t_exp_list[j];
+ dexp->open_epilogue ();
+ }
+ exp_names->destroy ();
+ delete[] t_exp_list;
+ delete exp_names;
+
+ // update setting for leaklist and dataspace
+ check_tab_avail ();
+}
+
+void
+DbeSession::append_mesgs (StringBuilder *sb, char *path, Experiment *exp)
+{
+ if (exp->fetch_errors () != NULL)
+ {
+ // yes, there were errors
+ char *ststr = pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT (""));
+ sb->append (path);
+ sb->append (NTXT (": "));
+ sb->append (ststr);
+ free (ststr);
+ }
+
+ Emsg *m = exp->fetch_warnings ();
+ if (m != NULL)
+ {
+ sb->append (path);
+ sb->append (NTXT (": "));
+ if (!is_interactive ())
+ sb->append (GTXT ("Experiment has warnings, see header for details\n"));
+ else
+ sb->append (GTXT ("Experiment has warnings, see experiment panel for details\n"));
+ }
+
+ // Check for descendant experiments that are not loaded
+ int num_desc = VecSize (exp->children_exps);
+ if ((num_desc > 0) && !settings->check_en_desc (NULL, NULL))
+ {
+ char *s;
+ if (!is_interactive ())
+ s = dbe_sprintf (GTXT ("Has %d descendant(s), use commands controlling selection to load descendant data\n"), num_desc);
+ else
+ s = dbe_sprintf (GTXT ("Has %d descendant(s), use filter panel to load descendant data\n"), num_desc);
+ sb->append (path);
+ sb->append (NTXT (": "));
+ sb->append (s);
+ free (s);
+ }
+}
+
+Experiment *
+DbeSession::get_exp (int exp_ind)
+{
+ if (exp_ind < 0 || exp_ind >= exps->size ())
+ return NULL;
+ Experiment *exp = exps->fetch (exp_ind);
+ exp->setExpIdx (exp_ind);
+ return exp;
+}
+
+Vector<Vector<char*>*> *
+DbeSession::getExperimensGroups ()
+{
+ if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0)
+ return NULL;
+ bool compare_mode = expGroups->size () > 1;
+ Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*> (
+ compare_mode ? expGroups->size () : 1);
+ for (int i = 0; i < expGroups->size (); i++)
+ {
+ ExpGroup *grp = expGroups->fetch (i);
+ Vector<Experiment*> *founders = grp->get_founders ();
+ if (founders && founders->size () != 0)
+ {
+ Vector<char *> *names = new Vector<char*> (founders->size ());
+ for (int j = 0; j < founders->size (); j++)
+ {
+ Experiment *exp = founders->fetch (j);
+ names->append (dbe_strdup (exp->get_expt_name ()));
+ }
+ if (compare_mode || groups->size () == 0)
+ groups->append (names);
+ else
+ groups->fetch (0)->addAll (names);
+ }
+ delete founders;
+ }
+ return groups;
+}
+
+char *
+DbeSession::setExperimentsGroups (Vector<Vector<char*>*> *groups)
+{
+ StringBuilder sb;
+ for (int i = 0; i < groups->size (); i++)
+ {
+ Vector<char *> *names = groups->fetch (i);
+ ExpGroup *grp;
+ if (names->size () == 1)
+ grp = new ExpGroup (names->fetch (0));
+ else
+ {
+ char *nm = dbe_sprintf (GTXT ("Group %d"), i + 1);
+ grp = new ExpGroup (nm);
+ free (nm);
+ }
+ expGroups->append (grp);
+ grp->groupId = expGroups->size ();
+
+ for (int j = 0; j < names->size (); j++)
+ {
+ char *path = names->fetch (j);
+ size_t len = strlen (path);
+ if ((len > 4) && !strcmp (path + len - 4, NTXT (".erg")))
+ {
+ Vector<char*> *lst = get_group_or_expt (path);
+ for (int j1 = 0; j1 < lst->size (); j1++)
+ {
+ Experiment *exp = new Experiment ();
+ append (exp);
+ open_experiment (exp, lst->get (j1));
+ if (exp->get_status () == Experiment::FAILURE)
+ append_mesgs (&sb, path, exp);
+ }
+ lst->destroy ();
+ delete lst;
+ }
+ else
+ {
+ Experiment *exp = new Experiment ();
+ append (exp);
+ open_experiment (exp, path);
+ if (exp->get_status () == Experiment::FAILURE)
+ append_mesgs (&sb, path, exp);
+ }
+ }
+ }
+
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ DbeView *dbev = views->fetch (i);
+ dbev->update_advanced_filter ();
+ int cmp = dbev->get_settings ()->get_compare_mode ();
+ dbev->set_compare_mode (CMP_DISABLE);
+ dbev->set_compare_mode (cmp);
+ }
+ return sb.length () == 0 ? NULL : sb.toString ();
+}
+
+char *
+DbeSession::drop_experiment (int exp_ind)
+{
+ DbeView *dbev;
+ int index;
+ Experiment *exp2;
+
+ status_ompavail = -1;
+ Experiment *exp = exps->fetch (exp_ind);
+
+ // If this is a sub experiment, don't do it
+ if (exp->founder_exp != NULL) // this is a sub experiment; don't do it
+ return (dbe_strdup (GTXT ("Can not drop subexperiments")));
+
+ if (VecSize (exp->children_exps) > 0)
+ for (;;)
+ {
+ // search the list of experiments to find all that have this one as founder
+ bool found = false;
+ Vec_loop (Experiment*, exps, index, exp2)
+ {
+ if (exp2->founder_exp == exp)
+ {
+ exp2->founder_exp = NULL;
+ drop_experiment (index);
+ found = true;
+ break;
+ }
+ }
+ if (found == false)
+ break;
+ }
+
+ // then proceed to finish the drop
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->drop_experiment (exp_ind);
+ }
+
+ int old_cnt = expGroups->size ();
+ for (int i = 0; i < old_cnt; i++)
+ {
+ ExpGroup *gr = expGroups->fetch (i);
+ if (gr->groupId == exp->groupId)
+ {
+ gr->drop_experiment (exp);
+ if ((gr->founder == NULL) && (gr->exps->size () == 0))
+ {
+ delete gr;
+ expGroups->remove (i);
+ }
+ break;
+ }
+ }
+ delete exps->remove (exp_ind);
+ if (old_cnt != expGroups->size ())
+ {
+ for (int i = 0, sz = expGroups->size (); i < sz; i++)
+ {
+ ExpGroup *gr = expGroups->fetch (i);
+ gr->groupId = i + 1;
+ Vector<Experiment*> *expList = gr->exps;
+ for (int i1 = 0, sz1 = expList->size (); i1 < sz1; i1++)
+ expList->fetch (i1)->groupId = gr->groupId;
+ }
+ for (int i = 0, sz = views->size (); i < sz; i++)
+ {
+ dbev = views->fetch (i);
+ int cmp = dbev->get_compare_mode ();
+ dbev->set_compare_mode (CMP_DISABLE);
+ dbev->set_compare_mode (cmp);
+ }
+ }
+ check_tab_avail (); // update tab availability
+ return NULL;
+}
+
+int
+DbeSession::find_experiment (char *path)
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (strcmp (exp->get_expt_name (), path) == 0)
+ return exp->getExpIdx ();
+ }
+ return -1;
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, int64_t cksum)
+{
+ return loadObjMap->sync_create_item (nm, cksum);
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, const char *runTimePath, DbeFile *df)
+{
+ return loadObjMap->sync_create_item (nm, runTimePath, df);
+}
+
+void
+DbeSession::append (LoadObject *lobj)
+{
+ Histable *obj = lobj; // workaround for a C++ problem
+ objs->append (obj);
+ lobj->id = objs->size () - 1;
+ lobjs->append (lobj);
+ lobj->seg_idx = lobjs->size () - 1;
+ char *loname = lobj->get_pathname ();
+ dbeFiles->put (loname, lobj->dbeFile);
+}
+
+DbeJarFile *
+DbeSession::get_JarFile (const char *name)
+{
+ DbeJarFile *jf = dbeJarFiles->get (name);
+ if (jf == NULL)
+ {
+ jf = new DbeJarFile (name);
+ dbeJarFiles->put (name, jf);
+ }
+ return jf;
+}
+
+Module *
+DbeSession::createModule (LoadObject *lo, const char *nm)
+{
+ Module *mod = new Module ();
+ Histable *obj = mod; // workaround for a C++ problem
+ objs->append (obj);
+ mod->id = objs->size () - 1;
+ mod->loadobject = lo;
+ mod->set_name (dbe_strdup (nm ? nm : localized_SP_UNKNOWN_NAME));
+ lo->seg_modules->append (mod);
+ return mod;
+}
+
+Module *
+DbeSession::createUnknownModule (LoadObject *lo)
+{
+ Module *mod = createModule (lo, localized_SP_UNKNOWN_NAME);
+ mod->flags |= MOD_FLAG_UNKNOWN;
+ mod->set_file_name (dbe_strdup (localized_SP_UNKNOWN_NAME));
+ return mod;
+}
+
+SourceFile *
+DbeSession::createSourceFile (const char *_path)
+{
+ char *path = (char *) _path;
+ if (strncmp (path, NTXT ("./"), 2) == 0)
+ path += 2;
+ SourceFile *source = sourcesMap->get (path);
+ if (source == NULL)
+ {
+ source = new SourceFile (path);
+ (void) sourcesMap->put (path, source);
+ append (source);
+ }
+ return source;
+}
+
+Function *
+DbeSession::createFunction ()
+{
+ Function *func = new Function (objs->size ());
+ Histable *obj = func; // workaround for a C++ problem
+ objs->append (obj);
+ return func;
+}
+
+JMethod *
+DbeSession::createJMethod ()
+{
+ JMethod *jmthd = new JMethod (objs->size ());
+ Histable *obj = jmthd; // workaround for a C++ problem
+ objs->append (obj);
+ return jmthd;
+}
+
+Module *
+DbeSession::createClassFile (char *className)
+{
+ ClassFile *cls = new ClassFile ();
+ cls->set_name (className);
+ char *clpath = cls->get_java_file_name (className, true);
+ cls->dbeFile = getDbeFile (clpath, DbeFile::F_JAVACLASS);
+ free (clpath);
+ Histable *obj = cls; // workaround for a C++ problem
+ objs->append (obj);
+ cls->id = objs->size () - 1;
+ return cls;
+}
+
+Histable *
+DbeSession::createHistObject (Histable::Type type)
+{
+ switch (type)
+ {
+ case Histable::DOBJECT:
+ {
+ DataObject *dataobj = new DataObject ();
+ dobjs->append (dataobj);
+ dataobj->id = dobjs->size () - 1;
+ return dataobj;
+ }
+ default:
+ assert (0);
+ }
+ return NULL;
+}
+
+DataObject *
+DbeSession::createDataObject ()
+{
+ DataObject *dataobj = new DataObject ();
+ dobjs->append (dataobj);
+ dataobj->id = dobjs->size () - 1;
+ return dataobj;
+}
+
+DataObject *
+DbeSession::createDataObject (DataObject *dobj, DataObject *parent)
+{
+ DataObject *dataobj = new DataObject ();
+ dataobj->size = dobj->size;
+ dataobj->offset = dobj->offset;
+ dataobj->parent = parent;
+ dataobj->set_dobjname (dobj->get_typename (), dobj->get_instname ());
+ dobjs->append (dataobj);
+ dataobj->id = dobjs->size () - 1;
+ return dataobj;
+}
+
+DataObject *
+DbeSession::createMasterDataObject (DataObject *dobj)
+{
+ DataObject *parent = NULL;
+ if (dobj->parent)
+ { // define master parent first
+ parent = find_dobj_master (dobj->parent);
+ if (!parent)
+ { // clone master from this dataobject parent
+ parent = createDataObject (dobj->parent);
+ parent->scope = NULL; // master is scope-less
+ Dprintf (DEBUG_DATAOBJ,
+ "Master DataObject(%llu) cloned from (%llu) %s\n",
+ (ull_t) parent->id, (ull_t) dobj->parent->id,
+ dobj->parent->get_name ());
+ // clone master DataObject elements
+ Vector<DataObject*> *delem = get_dobj_elements (dobj->parent);
+ int element_index = 0;
+ DataObject *element = NULL;
+ Vec_loop (DataObject*, delem, element_index, element)
+ {
+ DataObject *master_element = createDataObject (element, parent);
+ master_element->scope = NULL; // master is scope-less
+ Dprintf (DEBUG_DATAOBJ,
+ "Member DataObject(%llu) cloned from (%llu) %s\n",
+ (ull_t) master_element->id, (ull_t) element->id,
+ element->get_name ());
+ }
+ }
+ else
+ Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+ (ull_t) parent->id, (ull_t) dobj->parent->id,
+ dobj->parent->get_name ());
+ }
+
+ DataObject *master = find_dobj_master (dobj);
+ if (!master)
+ { // clone master from this dataobject
+ master = createDataObject (dobj, parent);
+ master->scope = NULL; // master is scope-less
+ Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) cloned from (%llu) %s\n",
+ (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+ }
+ else
+ Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+ (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+ return master;
+}
+
+void
+DbeSession::insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist)
+{
+ if ((mtr->get_flavors () & Metric::STATIC) == 0)
+ {
+ // insert in front of the first STATIC
+ for (int i = 0, mlist_sz = mlist->size (); i < mlist_sz; i++)
+ {
+ BaseMetric *m = mlist->fetch (i);
+ if (m->get_flavors () & Metric::STATIC)
+ {
+ mlist->insert (i, mtr);
+ return;
+ }
+ }
+ }
+ mlist->append (mtr);
+}
+
+BaseMetricTreeNode*
+DbeSession::get_reg_metrics_tree ()
+{
+ if (reg_metrics_tree == NULL)
+ // Can't init earlier because BaseMetric() requires DbeSession::ql_parse
+ reg_metrics_tree = new BaseMetricTreeNode ();
+ return reg_metrics_tree;
+}
+
+void
+DbeSession::update_metric_tree (BaseMetric *m)
+{
+ get_reg_metrics_tree ()->register_metric (m);
+}
+
+BaseMetric *
+DbeSession::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
+{
+ BaseMetric *m = find_metric (type, cmd, expr_spec);
+ if (m)
+ return m;
+ BaseMetric *bm = find_metric (type, cmd, NULL); // clone this version
+ m = new BaseMetric (*bm);
+ m->set_expr_spec (expr_spec);
+ insert_metric (m, reg_metrics);
+ return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (BaseMetric::Type type)
+{
+ BaseMetric *m = find_metric (type, NULL, NULL);
+ if (m)
+ return m;
+ m = new BaseMetric (type);
+ insert_metric (m, reg_metrics);
+ update_metric_tree (m);
+ return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (Hwcentry *ctr, const char* aux, const char* username)
+{
+ BaseMetric *m = find_metric (BaseMetric::HWCNTR, aux, NULL);
+ if (m)
+ // That may be a problem when metrics aren't an exact match.
+ // For example, memoryspace is disabled in one experiment and not in another.
+ return m;
+ if (ctr->timecvt)
+ {
+ char *time_cmd = dbe_sprintf (NTXT ("t%s"), aux);
+ char *time_username = dbe_sprintf (GTXT ("%s Time"),
+ ctr->metric ? ctr->metric :
+ (ctr->name ? ctr->name : ctr->int_name));
+ BaseMetric *m1;
+ if (ipc_mode)
+ {
+ // Two visible metrics are presented in GUI
+ m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL);
+ insert_metric (m1, reg_metrics);
+ update_metric_tree (m1);
+ m = new BaseMetric (ctr, aux, username, VAL_VALUE, m1);
+ }
+ else
+ {
+ // Only one visible metric is presented in er_print
+ m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL | VAL_INTERNAL);
+ insert_metric (m1, reg_metrics);
+ m = new BaseMetric (ctr, aux, username, VAL_TIMEVAL | VAL_VALUE, m1);
+ }
+ free (time_cmd);
+ free (time_username);
+ }
+ else
+ m = new BaseMetric (ctr, aux, username, VAL_VALUE);
+ insert_metric (m, reg_metrics);
+ update_metric_tree (m);
+ return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (char *name, char *username, char *_def)
+{
+ BaseMetric *m = find_metric (BaseMetric::DERIVED, name, NULL);
+ if (m)
+ return m;
+ Definition *p = Definition::add_definition (_def);
+ if (p == NULL)
+ return NULL;
+ m = new BaseMetric (name, username, p);
+ insert_metric (m, reg_metrics);
+ update_metric_tree (m);
+ return m;
+}
+
+void
+DbeSession::drop_metric (BaseMetric *mtr)
+{
+ Countable *cnt;
+ int index;
+
+ Vec_loop (Countable*, metrics, index, cnt)
+ {
+ if (mtr == (BaseMetric *) cnt->item)
+ {
+ cnt->ref_count--;
+ if (cnt->ref_count == 0)
+ {
+ // Remove this metric from all views
+ DbeView *dbev;
+ int index2;
+ Vec_loop (DbeView*, views, index2, dbev)
+ {
+ dbev->reset_metrics ();
+ }
+ delete metrics->remove (index);
+ delete mtr;
+ return;
+ }
+ }
+ }
+}
+
+BaseMetric *
+DbeSession::find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec)
+{
+ for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+ {
+ BaseMetric *bm = reg_metrics->fetch (i);
+ if (bm->get_type () == type && dbe_strcmp (bm->get_expr_spec (), expr_spec) == 0)
+ {
+ if ((type == BaseMetric::DERIVED || type == BaseMetric::HWCNTR)
+ && dbe_strcmp (bm->get_cmd (), cmd) != 0)
+ continue;
+ return bm;
+ }
+ }
+ return NULL;
+}
+
+BaseMetric *
+DbeSession::find_base_reg_metric (char * mcmd)
+{
+ for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+ {
+ BaseMetric *bm = reg_metrics->fetch (i);
+ if (bm->get_expr_spec () != NULL)
+ continue; // skip compare metrics
+ if (dbe_strcmp (bm->get_cmd (), mcmd) == 0)
+ return bm;
+ }
+ return NULL;
+}
+
+Vector<BaseMetric*> *
+DbeSession::get_base_reg_metrics ()
+{
+ Vector<BaseMetric*> *mlist = new Vector<BaseMetric*>;
+ Vector<BaseMetric*> *ml = get_all_reg_metrics ();
+ for (int i = 0, sz = ml->size (); i < sz; i++)
+ {
+ BaseMetric *m = ml->fetch (i);
+ if (m->get_expr_spec () == NULL)
+ mlist->append (m);
+ }
+ return mlist;
+}
+
+void
+DbeSession::check_tab_avail ()
+{
+ DbeView *dbev;
+ int index;
+ // tell the views to update their tab lists
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->get_settings ()->updateTabAvailability ();
+ }
+}
+
+bool
+DbeSession::is_datamode_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->dataspaceavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_leaklist_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->leaklistavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_heapdata_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->heapdataavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_iodata_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->iodataavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_racelist_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->racelistavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_deadlocklist_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->deadlocklistavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_timeline_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->timelineavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_ifreq_available ()
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ if (exp->ifreqavail)
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::is_omp_available ()
+{
+ if (status_ompavail == -1)
+ {
+ status_ompavail = 0;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->ompavail)
+ {
+ status_ompavail = 1;
+ break;
+ }
+ }
+ }
+ return status_ompavail == 1;
+}
+
+bool
+DbeSession::has_java ()
+{
+ int status_has_java = 0;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->has_java)
+ {
+ status_has_java = 1;
+ break;
+ }
+ }
+ return status_has_java == 1;
+}
+
+bool
+DbeSession::has_ompavail ()
+{
+ int status_has_ompavail = 0;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->ompavail)
+ {
+ status_has_ompavail = 1;
+ break;
+ }
+ }
+ return status_has_ompavail == 1;
+}
+
+int
+DbeSession::get_clock (int whichexp)
+{
+ // XXXX clock frequency should be an attribute of each CPU,
+ // XXX and not a property of the session
+ // if whichexp is -1, pick the first exp that has a clock
+ // otherwise return the clock from the numbered experiment
+ Experiment *exp;
+ if (whichexp != -1)
+ {
+ exp = get_exp (whichexp);
+ if (exp != NULL)
+ return exp->clock;
+ return 0;
+ }
+ int n = nexps ();
+ for (int i = 0; i < n; i++)
+ {
+ exp = get_exp (i);
+ if (exp != NULL && exp->clock != 0)
+ return exp->clock;
+ }
+ return 0;
+}
+
+LoadObject *
+DbeSession::find_lobj_by_name (const char *lobj_name, int64_t cksum)
+{
+ return loadObjMap->get (lobj_name, cksum);
+}
+
+static unsigned
+hash (char *s)
+{
+ unsigned res = 0;
+ for (int i = 0; i < 64 && *s; i++)
+ res = res * 13 + *s++;
+ return res;
+}
+
+// This method is introduced to fix performance
+// problems with the data space profiling in the
+// current release. A better design is desired.
+void
+DbeSession::dobj_updateHT (DataObject *dobj)
+{
+ unsigned index = hash (dobj->get_unannotated_name ()) % HTableSize;
+ List *list = new List;
+ list->val = (void*) dobj;
+ list->next = dnameHTable[index];
+ dnameHTable[index] = list;
+}
+
+DataObject *
+DbeSession::find_dobj_by_name (char *dobj_name)
+{
+ unsigned index = hash (dobj_name) % HTableSize;
+ List *list = dnameHTable[index];
+ for (; list; list = list->next)
+ {
+ DataObject *d = (DataObject*) list->val;
+ if (strcmp (d->get_unannotated_name (), dobj_name) == 0)
+ return d;
+ }
+ return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_match (DataObject *dobj)
+{
+ char *dobj_name = dobj->get_unannotated_name ();
+ unsigned index = hash (dobj_name) % HTableSize;
+ List *list = dnameHTable[index];
+ for (; list; list = list->next)
+ {
+ DataObject *d = (DataObject*) list->val;
+ if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+ && d->size == dobj->size && d->offset == dobj->offset
+ && d->scope == dobj->scope)
+ return d;
+ }
+ return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_master (DataObject *dobj)
+{
+ char *dobj_name = dobj->get_unannotated_name ();
+ unsigned index = hash (dobj_name) % HTableSize;
+ List *list = dnameHTable[index];
+ for (; list; list = list->next)
+ {
+ DataObject *d = (DataObject*) list->val;
+ // XXXX should parent also match?
+ if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+ && d->size == dobj->size && d->offset == dobj->offset
+ && d->master == NULL && d->scope == NULL)
+ return d;
+ }
+ return (DataObject *) NULL;
+}
+
+Vector<DataObject*>*
+DbeSession::get_dobj_elements (DataObject *dobj)
+{
+ DataObject *d;
+ int index;
+ Vector<DataObject*> *elements = new Vector<DataObject*>;
+ if (dobj == d_total)
+ return elements;
+ Vec_loop (DataObject*, dobjs, index, d)
+ {
+ if (d->get_parent () && d->get_parent () == dobj)
+ elements->append (d);
+ }
+ return elements;
+}
+
+Vector<LoadObject*>*
+DbeSession::get_text_segments ()
+{
+ LoadObject *lo;
+ int index;
+ Vector<LoadObject*> *tlobjs = new Vector<LoadObject*>;
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ if (lo->type == LoadObject::SEG_TEXT)
+ tlobjs->append (lo);
+ }
+ return tlobjs;
+}
+
+static long long
+getNumber (const char *s, char * &last)
+{
+ long long val;
+ char *sp;
+ errno = 0;
+ val = strtoll (s, &sp, 0);
+ if (errno == EINVAL)
+ last = NULL;
+ else
+ {
+ while (isspace (*sp))
+ sp++;
+ last = sp;
+ }
+ return (val);
+}
+
+bool
+DbeSession::find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj,
+ char *name, const char *sel, Histable::Type type, bool xdefault)
+{
+ Vector<Histable*> *obj_lst;
+ int which = -1;
+ char *last = NULL;
+ if (type != Histable::FUNCTION && sel)
+ {
+ // check that a number has been provided
+ which = (int) getNumber (sel, last);
+ if (last == NULL || *last != '\0')
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ sel = NULL;
+ which = 0;
+ }
+ which--;
+ }
+ obj_lst = new Vector<Histable*>;
+ switch (type)
+ {
+ case Histable::FUNCTION:
+ obj = map_NametoFunction (name, obj_lst, sel);
+ break;
+ case Histable::MODULE:
+ obj = map_NametoModule (name, obj_lst, which);
+ break;
+ case Histable::LOADOBJECT:
+ obj = map_NametoLoadObject (name, obj_lst, which);
+ break;
+ case Histable::DOBJECT:
+ obj = map_NametoDataObject (name, obj_lst, which);
+ break;
+ default:
+ abort (); // unexpected Histable!
+ }
+
+ if ((obj == NULL) && (obj_lst->size () > 0))
+ {
+ if (obj_lst->size () == 1)
+ which = 0;
+ else
+ {
+ if (sel && (which < 0 || which >= obj_lst->size ()))
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ if (xdefault)
+ {
+ fprintf (stderr, GTXT ("Default selection \"1\" made\n"));
+ which = 0;
+ }
+ else
+ {
+ which = ask_which (dis_file, inp_file, obj_lst, name);
+ if (which == -1)
+ {
+ delete obj_lst;
+ return false;
+ }
+ }
+ }
+ obj = obj_lst->fetch (which);
+ }
+ delete obj_lst;
+ return true;
+}
+
+int
+DbeSession::ask_which (FILE *dis_file, FILE *inp_file,
+ Vector<Histable*> *list, char *name)
+{
+ Histable *hitem;
+ Function *func;
+ Module *module;
+ int which, index, index1;
+ char *item_name, *lo_name, *fname, *last;
+ char buf[BUFSIZ];
+ for (;;)
+ {
+ fprintf (dis_file, GTXT ("Available name list:\n"));
+ fprintf (dis_file, GTXT ("%8d) Cancel\n"), 0);
+ Vec_loop (Histable*, list, index, hitem)
+ {
+ index1 = index + 1;
+ item_name = hitem->get_name ();
+ switch (hitem->get_type ())
+ {
+ case Histable::FUNCTION:
+ func = (Function *) hitem;
+ module = func->module;
+
+ // id == -1 indicates er_src invocation
+ if (module == NULL || (module->lang_code == Sp_lang_java
+ && module->loadobject->id == -1))
+ fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+ else
+ {
+ lo_name = module->loadobject->get_pathname ();
+ fname = (module->file_name && *module->file_name) ?
+ module->file_name : module->get_name ();
+ if (fname && *fname)
+ fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx (%s)\n"), index1,
+ item_name, lo_name, (ull_t) func->img_offset, fname);
+ else
+ fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx\n"), index1,
+ item_name, lo_name, (ull_t) func->img_offset);
+ }
+ break;
+ case Histable::MODULE:
+ module = (Module *) hitem;
+ lo_name = module->loadobject->get_pathname ();
+ if (name[strlen (name) - 1] ==
+ module->file_name[strlen (module->file_name) - 1])
+ fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1,
+ module->file_name, lo_name);
+ else
+ fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, item_name,
+ lo_name);
+ break;
+ default:
+ fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+ break;
+ }
+ }
+ if (inp_file != stdin)
+ return -1;
+ fprintf (dis_file, GTXT ("Enter selection: "));
+ if (fgets (buf, (int) sizeof (buf), inp_file) == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered:\n"));
+ return -1;
+ }
+ which = (int) getNumber (buf, last);
+ if (last && *last == '\0')
+ if (which >= 0 && which <= list->size ())
+ return which - 1;
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), buf);
+ }
+}
+
+static bool
+match_basename (char *name, char *full_name, int len = -1)
+{
+ if (full_name == NULL)
+ return false;
+ if (!strchr (name, '/'))
+ full_name = get_basename (full_name);
+ if (len == -1)
+ return streq (name, full_name);
+ return strncmp (name, full_name, len) == 0;
+}
+
+LoadObject *
+DbeSession::map_NametoLoadObject (char *name, Vector<Histable*> *list, int which)
+{
+ // Search the tree to find the first module whose module name
+ // matches "name" or whose source file name matches "name"
+ // Issues: is the name a pathname, or a base name?
+ // Should we look at suffix to disambiguate?
+ LoadObject *loitem;
+ int index;
+ Vec_loop (LoadObject*, lobjs, index, loitem)
+ {
+ // try pathname first
+ // if failed, try object name next
+ if (match_basename (name, loitem->get_pathname ()) ||
+ match_basename (name, loitem->get_name ()))
+ {
+ if (which == list->size ())
+ return loitem;
+ list->append (loitem);
+ }
+ }
+ return (LoadObject *) NULL;
+}
+
+Module *
+DbeSession::map_NametoModule (char *name, Vector<Histable*> *list, int which)
+{
+ // Search the tree to find the first loadobject whose loadobject name
+ // matches "name".
+
+ // Issues: is the name a pathname, or a base name?
+ // Should we look at suffix to disambiguate?
+ LoadObject *loitem;
+ Module *mitem;
+ int index1, index2;
+ Vec_loop (LoadObject*, lobjs, index1, loitem)
+ {
+ Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+ {
+ // try source name first
+ // if failed, try object name next
+ if (match_basename (name, mitem->file_name) ||
+ match_basename (name, mitem->get_name ()))
+ {
+ if (which == list->size ())
+ return mitem;
+ list->append (mitem);
+ }
+ }
+ }
+ return (Module *) NULL;
+}
+
+Function *
+DbeSession::map_NametoFunction (char *name, Vector<Histable*> *list,
+ const char *sel)
+{
+ // Search the tree to find the first function whose
+ // name matches "name".
+ // Issues: is the name a full name, or a short name?
+ // Is it a demangled name? If so, what about spaces
+ // within the name?
+ // Is there a way to return all names that match?
+ // How can the user specify a particular function of that name?
+ LoadObject *loitem;
+ Function *fitem, *main_func = NULL;
+ Module *mitem, *main_mod = NULL;
+ int index1, index2, index3, which = -1;
+ if (sel)
+ {
+ char *last = NULL;
+ if (*sel == '@')
+ { // 'sel' is "@seg_num:address"
+ which = (int) getNumber (sel + 1, last);
+ if (last == NULL || *last != ':' || (which < 0) || (which >= lobjs->size ()))
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ return NULL;
+ }
+ uint64_t address = getNumber (last + 1, last);
+ if (last == NULL || *last != '\0')
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ return NULL;
+ }
+ loitem = lobjs->fetch (which);
+ Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+ {
+ Vec_loop (Function*, mitem->functions, index3, fitem)
+ {
+ if (address == fitem->img_offset && match_FName (name, fitem))
+ return fitem;
+ }
+ }
+ return NULL;
+ }
+
+ which = (int) getNumber (sel, last);
+ if (last == NULL || *last != '\0')
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+ return NULL;
+ }
+ which--;
+ }
+
+ int len_path = 0;
+ char *with_path = name;
+ name = StrRchr (name, '`');
+ if (name != with_path)
+ len_path = (int) (name - with_path);
+ else
+ with_path = NULL;
+
+ Vec_loop (LoadObject*, lobjs, index1, loitem)
+ {
+ Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+ {
+ if (with_path)
+ { // with file name
+ // try source name first
+ // if failed, try object name next
+ if (!match_basename (with_path, mitem->file_name, len_path) &&
+ !match_basename (with_path, mitem->get_name (), len_path))
+ continue;
+ }
+ Vec_loop (Function*, mitem->functions, index3, fitem)
+ {
+ if (match_FName (name, fitem))
+ {
+ if (which == list->size ())
+ return fitem;
+ list->append (fitem);
+ continue;
+ }
+ if (streq (fitem->get_name (), NTXT ("MAIN_")) && mitem->is_fortran ())
+ {
+ main_func = fitem;
+ main_mod = mitem;
+ }
+ }
+ }
+ }
+
+ if (main_mod && main_func)
+ {
+ main_mod->read_stabs ();
+ if (streq (main_func->get_match_name (), name) && which <= 1)
+ return main_func;
+ }
+ return (Function *) NULL;
+}
+
+DataObject *
+DbeSession::map_NametoDataObject (char *name, Vector<Histable*> *list,
+ int which)
+{
+ // Search master list to find dataobjects whose names match "name"
+ // selecting only the entry corresponding to "which" if it is not -1.
+ // Issues: is the name fully qualified or only partially?
+ DataObject *ditem = NULL;
+ int index;
+ char *full_name;
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ if (ditem->scope) continue; // skip non-master dataobjects
+
+ // try fully-qualified dataobject name first
+ if ((full_name = ditem->get_name ()) != NULL)
+ {
+ if (streq (name, full_name))
+ {
+ if (which == list->size ())
+ return ditem;
+ list->append (ditem);
+ }
+ }
+ }
+ if (list->size () > 0)
+ return ditem; // return fully-qualified match
+
+ // if fully-qualified name doesn't match anything, try a partial match
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ if (ditem->scope) continue; // skip non-master dataobjects
+
+ // try fully-qualified dataobject name first
+ if ((full_name = ditem->get_name ()) != NULL)
+ {
+ if (strstr (full_name, name))
+ {
+ if (which == list->size ())
+ return ditem;
+ list->append (ditem);
+ }
+ }
+ }
+ return (DataObject *) NULL;
+}
+
+bool
+DbeSession::match_FName (char *name, Function *func)
+{
+ size_t len;
+ char buf[MAXDBUF];
+ char *full_name;
+ if (streq (func->get_name (), name)) // try full name comparison
+ return true;
+ if (streq (func->get_mangled_name (), name)) // try mangled name
+ return true;
+ if (streq (func->get_match_name (), name)) // try match name
+ return true;
+
+ Module *md = func->module; // try FORTRAN name
+ if (md && md->is_fortran ())
+ {
+ char *mangled_name = func->get_mangled_name ();
+ len = strlen (name);
+ if (((len + 1) == strlen (mangled_name)) &&
+ (strncmp (name, mangled_name, len) == 0))
+ return true;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s"), func->get_name ());
+ full_name = buf;
+ char *arg = NULL; // find modifier and C++ class name
+ int i = get_paren (buf);
+ if (i >= 0)
+ {
+ arg = buf + i;
+ *arg = '\0';
+ }
+
+ char *mod = strchr (full_name, ' ');
+ char *cls = strchr (full_name, ':');
+
+ if (mod)
+ {
+ len = mod - full_name + 1;
+ if (!strncmp (full_name, name, len))
+ name += len;
+ full_name += len;
+ if (streq (full_name, name)) // try without modifier
+ return true;
+ }
+
+ size_t len_cmp = strlen (name);
+ if (arg)
+ {
+ *arg = '(';
+ len = arg - full_name; // try without 'args'
+ if (len_cmp == len && !strncmp (full_name, name, len))
+ return true;
+ if (cls)
+ {
+ len = arg - cls - 2; // and without 'class name'
+ if ((len_cmp == len) && !strncmp (cls + 2, name, len))
+ return true;
+ }
+ }
+
+ if (cls)
+ {
+ len = cls - full_name; // try C++ class name only
+ if (len_cmp == len && !strncmp (full_name, name, len))
+ return true;
+ if (streq (cls + 2, name)) // try without 'class name'
+ return true;
+ }
+ return false;
+}
+
+bool
+DbeSession::add_path (char *path)
+{
+ return add_path (path, get_search_path ());
+}
+
+bool
+DbeSession::add_classpath (char *path)
+{
+ return add_path (path, classpath);
+}
+
+Vector<DbeFile*> *
+DbeSession::get_classpath ()
+{
+ if (classpath_df == NULL)
+ classpath_df = new Vector<DbeFile*>;
+ for (int i = classpath_df->size (), sz = classpath->size (); i < sz; i++)
+ classpath_df->store (i, getDbeFile (classpath->fetch (i),
+ DbeFile::F_DIR_OR_JAR));
+ return classpath_df;
+}
+
+bool
+DbeSession::add_path (char *path, Vector<char*> *pathes)
+{
+ bool result = false;
+ Vector <char *> *tokens = split_str (path, ':');
+ for (long j = 0, jsz = VecSize (tokens); j < jsz; j++)
+ {
+ char *spath = tokens->get (j);
+ // Don't append path if it's already there
+ bool got = false;
+ for (int i = 0, sz = pathes->size (); i < sz; i++)
+ {
+ char *nm = pathes->get (i);
+ if (streq (nm, spath))
+ {
+ got = true;
+ break;
+ }
+ }
+ if (!got)
+ {
+ pathes->append (spath);
+ result = true;
+ }
+ else
+ free (spath);
+ }
+ delete tokens;
+ return result;
+}
+
+void
+DbeSession::set_need_refind ()
+{
+ Vector<DbeFile*> *f_list = dbeFiles->values ();
+ for (long i = 0, sz = f_list == NULL ? 0 : f_list->size (); i < sz; i++)
+ {
+ DbeFile *f = f_list->get (i);
+ f->set_need_refind (true);
+ }
+ delete f_list;
+ for (long i = 0, sz = sources == NULL ? 0 : sources->size (); i < sz; i++)
+ {
+ SourceFile *f = sources->get (i);
+ if (f && f->dbeFile)
+ f->dbeFile->set_need_refind (true);
+ }
+}
+
+void
+DbeSession::set_search_path (Vector<char*> *path, bool reset)
+{
+ if (reset)
+ search_path->destroy ();
+ for (int i = 0, sz = path == NULL ? 0 : path->size (); i < sz; i++)
+ {
+ char *name = path->fetch (i);
+ if (add_path (name))
+ reset = true;
+ }
+ if (reset)
+ {
+ set_need_refind ();
+
+ // now reset the string setting for it
+ StringBuilder sb;
+ for (int i = 0, sz = search_path == NULL ? 0 : search_path->size (); i < sz; i++)
+ {
+ char *name = search_path->fetch (i);
+ if (sb.length () != 0)
+ sb.append (':');
+ sb.append (name);
+ }
+ free (settings->str_search_path);
+ settings->str_search_path = sb.toString ();
+ }
+}
+
+void
+DbeSession::set_search_path (char *_lpath, bool reset)
+{
+ Vector<char *> *path = new Vector<char*>;
+ char *lpath = dbe_strdup (_lpath);
+ for (char *s = lpath; s;)
+ {
+ path->append (s);
+ s = strchr (s, ':');
+ if (s)
+ {
+ *s = 0;
+ s++;
+ }
+ }
+ set_search_path (path, reset);
+ delete path;
+ free (lpath);
+}
+
+void
+DbeSession::set_pathmaps (Vector<pathmap_t*> *newPathMap)
+{
+ set_need_refind ();
+ settings->set_pathmaps (newPathMap);
+}
+
+Vector<pathmap_t*> *
+DbeSession::get_pathmaps ()
+{
+ return settings->pathmaps;
+}
+
+void
+DbeSession::mobj_define (MemObjType_t *mobj)
+{
+ settings->mobj_define (mobj, false);
+ DbeView *dbev;
+ int index;
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->get_settings ()->mobj_define (mobj, false);
+ }
+}
+
+void
+DbeSession::dump_segments (FILE *out)
+{
+ int index;
+ LoadObject *loitem;
+ Vec_loop (LoadObject*, lobjs, index, loitem)
+ {
+ fprintf (out, NTXT ("Segment %d -- %s -- %s\n\n"),
+ index, loitem->get_name (), loitem->get_pathname ());
+ loitem->dump_functions (out);
+ fprintf (out, NTXT ("\n End Segment %d -- %s -- %s\n\n"),
+ index, loitem->get_name (), loitem->get_pathname ());
+ }
+}
+
+void
+DbeSession::dump_dataobjects (FILE *out)
+{
+ DataObject *ditem;
+ int index;
+
+ fprintf (out, NTXT ("\nMaster list of DataObjects:\n"));
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ Histable* scope = ditem->get_scope ();
+ DataObject* parent = ditem->get_parent ();
+ DataObject* master = ditem->get_master ();
+ if (parent != NULL)
+ fprintf (out, "id %6lld: [%4lld] parent = %6lld, offset = %+4lld %s\n",
+ (ll_t) ditem->id, (ll_t) ditem->get_size (),
+ (ll_t) parent->id, (ll_t) ditem->get_offset (),
+ ditem->get_name ());
+ else
+ {
+ // parent is NULL
+ fprintf (out, NTXT ("id %6lld: [%4lld] %s "),
+ (ll_t) ditem->id, (ll_t) ditem->get_size (),
+ ditem->get_name ());
+ if (master != NULL)
+ fprintf (out, NTXT (" master=%lld "), (ll_t) master->id);
+ else if (scope != NULL)
+ fprintf (out, NTXT (" master=?? "));
+ else
+ fprintf (out, NTXT (" MASTER "));
+#if DEBUG
+ if (scope != NULL)
+ {
+ switch (scope->get_type ())
+ {
+ case Histable::LOADOBJECT:
+ case Histable::FUNCTION:
+ fprintf (out, NTXT ("%s"), scope->get_name ());
+ break;
+ case Histable::MODULE:
+ {
+ char *filename = get_basename (scope->get_name ());
+ fprintf (out, NTXT ("%s"), filename);
+ break;
+ }
+ default:
+ fprintf (out, NTXT (" Unexpected scope %d:%s"),
+ scope->get_type (), scope->get_name ());
+ }
+ }
+#endif
+ fprintf (out, NTXT ("\n"));
+ }
+ }
+}
+
+void
+DbeSession::dump_map (FILE *out)
+{
+ Experiment *exp;
+ int index;
+ Vec_loop (Experiment*, exps, index, exp)
+ {
+ exp->dump_map (out);
+ }
+}
+
+void
+DbeSession::dump_stacks (FILE *outfile)
+{
+ Experiment *exp;
+ int n = nexps ();
+ FILE *f = (outfile == NULL ? stderr : outfile);
+ for (int i = 0; i < n; i++)
+ {
+ exp = get_exp (i);
+ fprintf (f, GTXT ("Experiment %d -- %s\n"), i, exp->get_expt_name ());
+ exp->dump_stacks (f);
+ }
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char *propName)
+{
+ PropDescr *prop = new PropDescr (propId, propName);
+ prop->flags = PRFLAG_NOSHOW; // do not show descriptions
+ propNames->store (propId, prop);
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char* propName,
+ const char* propUname, VType_type dataType,
+ int flags)
+{
+ PropDescr *prop = new PropDescr (propId, propName);
+ prop->vtype = dataType;
+ prop->uname = dbe_strdup (propUname);
+ prop->flags = flags;
+ propNames->store (propId, prop);
+}
+
+char *
+DbeSession::propNames_name_fetch (int i)
+{
+ PropDescr *prop = propNames->fetch (i);
+ if (prop)
+ return prop->name;
+ return NULL;
+}
+
+int
+DbeSession::registerPropertyName (const char *name)
+{
+ if (name == NULL)
+ return PROP_NONE;
+ for (int i = 0; i < propNames->size (); i++)
+ {
+ char *pname = propNames_name_fetch (i);
+ if (pname && strcasecmp (pname, name) == 0)
+ return i;
+ }
+ int propId = propNames->size ();
+ propNames_name_store (propId, name);
+ return propId;
+}
+
+int
+DbeSession::getPropIdByName (const char *name)
+{
+ if (name == NULL)
+ return PROP_NONE;
+ for (int i = 0; i < propNames->size (); i++)
+ {
+ char *pname = propNames_name_fetch (i);
+ if (pname && strcasecmp (pname, name) == 0)
+ return i;
+ }
+ return PROP_NONE;
+}
+
+char *
+DbeSession::getPropName (int propId)
+{
+ if (!propNames)
+ return NULL;
+ if (propId < 0 || propId >= propNames->size ())
+ return NULL;
+ return dbe_strdup (propNames_name_fetch (propId));
+}
+
+char *
+DbeSession::getPropUName (int propId)
+{
+ if (!propNames)
+ return NULL;
+ if (propId < 0 || propId >= propNames->size ())
+ return NULL;
+ PropDescr *prop = propNames->fetch (propId);
+ if (prop)
+ return dbe_strdup (prop->uname);
+ return NULL;
+}
+
+void
+DbeSession::append (UserLabel *lbl)
+{
+ if (lbl->expr)
+ {
+ if (userLabels == NULL)
+ userLabels = new Vector<UserLabel*> ();
+ userLabels->append (lbl);
+ }
+}
+
+void
+DbeSession::append (SourceFile *sf)
+{
+ sources->append (sf);
+ objs->append (sf);
+}
+
+UserLabel *
+DbeSession::findUserLabel (char *name)
+{
+ for (int i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+ {
+ UserLabel *lbl = userLabels->fetch (i);
+ if (strcasecmp (lbl->name, name) == 0)
+ return lbl;
+ }
+ return NULL;
+}
+
+Expression *
+DbeSession::findObjDefByName (char *name)
+{
+ Expression *expr = NULL;
+
+ MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
+ if (mot != NULL)
+ {
+ char *index_expr_str = mot->index_expr;
+ expr = ql_parse (index_expr_str);
+ }
+
+ if (expr == NULL)
+ {
+ int indxtype = findIndexSpaceByName (name);
+ expr = getIndexSpaceExpr (indxtype);
+ }
+ if (expr == NULL)
+ {
+ UserLabel *ulbl = findUserLabel (name);
+ if (ulbl)
+ expr = ulbl->expr;
+ }
+ return expr;
+}
+
+Expression *
+DbeSession::ql_parse (const char *expr_spec)
+{
+ /* (This slight duplication means we don't need to worry about copy
+ constructors for the QL::Result, nor about the lifetime of the
+ expr_spec.) */
+ if (expr_spec != NULL)
+ {
+ QL::Result result (expr_spec);
+ QL::Parser qlparser (result);
+ if (qlparser () != 0)
+ return NULL;
+ return result ();
+ }
+ else
+ {
+ QL::Result result;
+ QL::Parser qlparser (result);
+ if (qlparser () != 0)
+ return NULL;
+ return result ();
+ }
+}
+
+Vector<void*> *
+DbeSession::getIndxObjDescriptions ()
+{
+ int size = dyn_indxobj_indx;
+ if (size == 0)
+ return NULL;
+ Vector<int> *type = new Vector<int>(dyn_indxobj_indx);
+ Vector<char*> *desc = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char*> *i18ndesc = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char> *mnemonic = new Vector<char>(dyn_indxobj_indx);
+ Vector<int> *orderList = new Vector<int>(dyn_indxobj_indx);
+ Vector<char*> *exprList = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char*> *sdesc = new Vector<char*>(dyn_indxobj_indx);
+ Vector<char*> *ldesc = new Vector<char*>(dyn_indxobj_indx);
+
+ for (long i = 0, sz = VecSize (dyn_indxobj); i < sz; i++)
+ {
+ IndexObjType_t *tot = dyn_indxobj->get (i);
+ if (tot->memObj == NULL)
+ {
+ type->append ((int) tot->type);
+ desc->append (dbe_strdup (tot->name));
+ i18ndesc->append (dbe_strdup (tot->i18n_name));
+ sdesc->append (dbe_strdup (tot->short_description));
+ ldesc->append (dbe_strdup (tot->long_description));
+ mnemonic->append (tot->mnemonic);
+ orderList->append (settings->indx_tab_order->fetch (i));
+ exprList->append (dbe_strdup (tot->index_expr_str));
+ }
+ }
+ Vector<void*> *res = new Vector<void*>(8);
+ res->store (0, type);
+ res->store (1, desc);
+ res->store (2, mnemonic);
+ res->store (3, i18ndesc);
+ res->store (4, orderList);
+ res->store (5, exprList);
+ res->store (6, sdesc);
+ res->store (7, ldesc);
+ return (res);
+}
+
+// Static function to get a vector of custom index object definitions
+Vector<void*> *
+DbeSession::getCustomIndxObjects ()
+{
+ Vector<char*> *name = new Vector<char*>;
+ Vector<char*> *formula = new Vector<char*>;
+ for (long i = dyn_indxobj_indx_fixed, sz = VecSize (dyn_indxobj); i < sz; i++)
+ {
+ IndexObjType_t *tot = dyn_indxobj->get (i);
+ if (tot->memObj == NULL)
+ {
+ name->append (dbe_strdup (tot->name));
+ formula->append (dbe_strdup (tot->index_expr_str));
+ }
+ }
+ Vector<void*> *res = new Vector<void*>(2);
+ res->store (0, name);
+ res->store (1, formula);
+ return (res);
+}
+
+// Static function to define a new index object type
+char *
+DbeSession::indxobj_define (const char *mname, char *i18nname, const char *index_expr_str, char *short_description, char *long_description)
+{
+ if (mname == NULL)
+ return dbe_strdup (GTXT ("No index object type name has been specified."));
+ if (isalpha ((int) (mname[0])) == 0)
+ return dbe_sprintf (GTXT ("Index Object type name %s does not begin with an alphabetic character"),
+ mname);
+ const char *p = mname;
+ while (*p != 0)
+ {
+ if ((isalnum ((int) (*p)) == 0) && (*p != '_'))
+ return dbe_sprintf (GTXT ("Index Object type name %s contains a non-alphanumeric character"),
+ mname);
+ p++;
+ }
+
+ // make sure the name is not in use
+ if (MemorySpace::findMemSpaceByName (mname) != NULL)
+ return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+ mname);
+
+ int idxx = findIndexSpaceByName (mname);
+ if (idxx >= 0)
+ {
+ IndexObjType_t *mt = dyn_indxobj->fetch (idxx);
+ if (strcmp (mt->index_expr_str, index_expr_str) == 0)
+ // It's a redefinition, but the new definition is the same
+ return NULL;
+ return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+ mname);
+ }
+ if (index_expr_str == NULL)
+ return dbe_strdup (GTXT ("No index-expr has been specified."));
+ if (strlen (index_expr_str) == 0)
+ return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+ index_expr_str);
+
+ // verify that the index expression parses correctly
+ char *expr_str = dbe_strdup (index_expr_str);
+ Expression *expr = ql_parse (expr_str);
+ if (expr == NULL)
+ return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+ expr_str);
+
+ // It's OK, create the new table entry
+ IndexObjType_t *tot = new IndexObjType_t;
+ tot->type = dyn_indxobj_indx++;
+ tot->name = dbe_strdup (mname);
+ tot->i18n_name = dbe_strdup (i18nname);
+ tot->short_description = dbe_strdup (short_description);
+ tot->long_description = dbe_strdup (long_description);
+ tot->index_expr_str = expr_str;
+ tot->index_expr = expr;
+ tot->mnemonic = mname[0];
+
+ // add it to the list
+ dyn_indxobj->append (tot);
+ idxobjs->append (new HashMap<uint64_t, Histable*>);
+
+ // tell the session
+ settings->indxobj_define (tot->type, false);
+
+ DbeView *dbev;
+ int index;
+ Vec_loop (DbeView*, views, index, dbev)
+ {
+ dbev->addIndexSpace (tot->type);
+ }
+ return NULL;
+}
+
+char *
+DbeSession::getIndexSpaceName (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->name;
+}
+
+char *
+DbeSession::getIndexSpaceDescr (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->i18n_name;
+}
+
+Expression *
+DbeSession::getIndexSpaceExpr (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->index_expr;
+}
+
+char *
+DbeSession::getIndexSpaceExprStr (int index)
+{
+ if (index < 0 || index >= dyn_indxobj->size ())
+ return NULL;
+ return dyn_indxobj->fetch (index)->index_expr_str;
+}
+
+int
+DbeSession::findIndexSpaceByName (const char *mname)
+{
+ int idx;
+ IndexObjType_t *mt;
+ Vec_loop (IndexObjType_t*, dyn_indxobj, idx, mt)
+ {
+ if (strcasecmp (mt->name, mname) == 0)
+ return idx;
+ }
+ return -1;
+}
+
+void
+DbeSession::removeIndexSpaceByName (const char *mname)
+{
+ IndexObjType_t *indObj = findIndexSpace (mname);
+ if (indObj)
+ indObj->name[0] = 0;
+}
+
+IndexObjType_t *
+DbeSession::getIndexSpace (int index)
+{
+ return ((index < 0) || (index >= VecSize (dyn_indxobj))) ? NULL : dyn_indxobj->get (index);
+}
+
+IndexObjType_t *
+DbeSession::findIndexSpace (const char *mname)
+{
+ return getIndexSpace (findIndexSpaceByName (mname));
+}
+
+void
+DbeSession::get_filter_keywords (Vector<void*> *res)
+{
+ Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
+ Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+ Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
+ Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+ Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+ Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
+ Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+
+ char *vtypeNames[] = VTYPE_TYPE_NAMES;
+ for (long i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+ {
+ UserLabel *lbl = userLabels->fetch (i);
+ kwCategory->append (dbe_strdup (NTXT ("FK_LABEL")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Labels")));
+ kwDataType->append (dbe_strdup (vtypeNames[TYPE_BOOL]));
+ kwKeyword->append (dbe_strdup (lbl->name));
+ kwFormula->append (dbe_strdup (lbl->str_expr));
+ kwDescription->append (dbe_strdup (lbl->comment));
+ kwEnumDescs->append (NULL);
+ }
+
+ for (long i = 0, sz = propNames ? propNames->size () : 0; i < sz; i++)
+ {
+ PropDescr *prop = propNames->fetch (i);
+ char *pname = prop ? prop->name : NULL;
+ if (pname == NULL || *pname == 0 || prop->flags & PRFLAG_NOSHOW)
+ continue;
+ int vtypeNum = prop->vtype;
+ if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
+ vtypeNum = TYPE_NONE;
+ kwCategory->append (dbe_strdup (NTXT ("FK_EVTPROP"))); //Event Property
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Misc. Definitions")));
+ kwDataType->append (dbe_strdup (vtypeNames[vtypeNum]));
+ kwKeyword->append (dbe_strdup (pname));
+ kwFormula->append (NULL);
+ kwDescription->append (dbe_strdup (prop->uname));
+ kwEnumDescs->append (NULL);
+ }
+
+ for (long i = 0, sz = dyn_indxobj ? dyn_indxobj->size () : 0; i < sz; i++)
+ {
+ IndexObjType_t *obj = dyn_indxobj->get (i);
+ if (obj->memObj)
+ continue;
+ kwCategory->append (dbe_strdup (NTXT ("FK_IDXOBJ")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Index Object Definitions")));
+ kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
+ kwKeyword->append (dbe_strdup (obj->name));
+ kwFormula->append (dbe_strdup (obj->index_expr_str));
+ kwDescription->append (dbe_strdup (obj->i18n_name));
+ kwEnumDescs->append (NULL);
+ }
+}
+
+Histable *
+DbeSession::findIndexObject (int idxtype, uint64_t idx)
+{
+ HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+ return iobjs->get (idx);
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, int64_t idx)
+{
+ HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+
+ Histable *idxobj = iobjs->get (idx);
+ if (idxobj == NULL)
+ {
+ idxobj = new IndexObject (idxtype, idx);
+ if (idx == -1)
+ idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+ iobjs->put (idx, idxobj);
+ }
+
+ return idxobj;
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, Histable *hobj)
+{
+ HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+ int64_t idx = hobj ? hobj->id : -1;
+ Histable *idxobj = iobjs->get (idx);
+ if (idxobj == NULL)
+ {
+ idxobj = new IndexObject (idxtype, hobj);
+ if (idx == -1)
+ idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+ iobjs->put (idx, idxobj);
+ }
+
+ return idxobj;
+}
+
+Histable *
+DbeSession::findObjectById (Histable::Type type, int subtype, uint64_t id)
+{
+ switch (type)
+ {
+ case Histable::FUNCTION:
+ case Histable::MODULE:
+ case Histable::LOADOBJECT:
+ return ( id < (uint64_t) objs->size ()) ? objs->fetch ((int) id) : NULL;
+ case Histable::INDEXOBJ:
+ return findIndexObject (subtype, id);
+ // ignoring the following cases
+ case Histable::INSTR:
+ case Histable::LINE:
+ case Histable::EADDR:
+ case Histable::MEMOBJ:
+ case Histable::PAGE:
+ case Histable::DOBJECT:
+ case Histable::SOURCEFILE:
+ case Histable::IOACTFILE:
+ case Histable::IOACTVFD:
+ case Histable::IOCALLSTACK:
+ case Histable::HEAPCALLSTACK:
+ case Histable::OTHER:
+ case Histable::EXPERIMENT:
+ break;
+ }
+ return NULL;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<JThread *> *
+DbeSession::match_java_threads (char *ustr, int matchParent,
+ Vector<uint64_t> * &grids,
+ Vector<uint64_t> * &expids)
+{
+ if (ustr == NULL)
+ return NULL;
+
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<JThread *> *ret = new Vector<JThread*>;
+ grids = new Vector<uint64_t>;
+ expids = new Vector<uint64_t>;
+
+ int index;
+ JThread *jthread;
+ int expid;
+ Experiment* exp;
+ Vec_loop (Experiment*, exps, expid, exp)
+ {
+
+ Vec_loop (JThread*, exp->get_jthreads (), index, jthread)
+ {
+ const char * name;
+ if (matchParent)
+ name = jthread->parent_name;
+ else
+ name = jthread->group_name;
+ if (name == NULL)
+ name = "";
+ if (!regexec (&regex_desc, name, 0, NULL, 0))
+ {
+ // this one matches
+ ret->append (jthread);
+ grids->append (exp->groupId);
+ expids->append (exp->getUserExpId ());
+ }
+ }
+ }
+
+ regfree (&regex_desc);
+ return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<Function *> *
+DbeSession::match_func_names (const char *ustr, Histable::NameFormat nfmt)
+{
+ if (ustr == NULL)
+ return NULL;
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<Function *> *ret = new Vector<Function*>;
+
+ int index;
+ Histable *obj;
+ Vec_loop (Histable*, objs, index, obj)
+ {
+ if (obj->get_type () == Histable::FUNCTION)
+ {
+ Function *func = (Function*) obj;
+ if (!regexec (&regex_desc, func->get_name (nfmt), 0, NULL, 0))
+ // this one matches
+ ret->append (func);
+ }
+ }
+ regfree (&regex_desc);
+ return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<FileData *> *
+DbeSession::match_file_names (char *ustr, Histable::NameFormat nfmt)
+{
+ if (ustr == NULL)
+ return NULL;
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<FileData *> *ret = new Vector<FileData*>;
+ int numExps = nexps ();
+ DefaultMap<int64_t, FileData*>* fDataMap;
+ Vector<FileData *> *fDataObjs;
+ FileData *fData;
+ int size;
+ for (int i = 0; i < numExps; i++)
+ {
+ Experiment *exp = get_exp (i);
+ fDataMap = exp->getFDataMap ();
+ fDataObjs = fDataMap->values ();
+ size = fDataObjs->size ();
+ for (int j = 0; j < size; j++)
+ {
+ fData = fDataObjs->fetch (j);
+ if (fData
+ && !regexec (&regex_desc, fData->get_raw_name (nfmt), 0, NULL, 0))
+ // this one matches
+ ret->append (fData);
+ }
+ }
+ regfree (&regex_desc);
+ return ret;
+}
+
+// return a vector of DataObjects that match the regular expression input string
+Vector<DataObject *> *
+DbeSession::match_dobj_names (char *ustr)
+{
+ if (ustr == NULL)
+ return NULL;
+ char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+ regex_t regex_desc;
+ int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ if (rc) // syntax error in parsing string
+ return NULL;
+
+ // allocate the new vector
+ Vector<DataObject *> *ret = new Vector<DataObject*>;
+ int index;
+ DataObject *ditem;
+ Vec_loop (DataObject*, dobjs, index, ditem)
+ {
+ // does this one match
+ if (!regexec (&regex_desc, ditem->get_name (), 0, NULL, 0))
+ // this one matches
+ ret->append (ditem);
+ }
+ regfree (&regex_desc);
+ return ret;
+}
+
+void
+DbeSession::dump (char *msg, Vector<BaseMetric*> *mlist)
+{
+ if (msg)
+ fprintf (stderr, "%s\n", msg);
+ int sz = mlist ? mlist->size () : -1;
+ for (int i = 0; i < sz; i++)
+ {
+ BaseMetric *m = mlist->fetch (i);
+ char *s = m->dump ();
+ fprintf (stderr, "%2d %s\n", i, s);
+ free (s);
+ }
+ fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
+
+void
+DbeSession::dump (char *msg, Vector<Metric*> *mlist)
+{
+ if (msg)
+ fprintf (stderr, "%s\n", msg);
+ int sz = mlist ? mlist->size () : -1;
+ for (int i = 0; i < sz; i++)
+ {
+ Metric *m = mlist->fetch (i);
+ char *s = m->dump ();
+ fprintf (stderr, "%2d %s\n", i, s);
+ free (s);
+ }
+ fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
diff --git a/gprofng/src/DbeSession.h b/gprofng/src/DbeSession.h
new file mode 100644
index 0000000..0a5c01c
--- /dev/null
+++ b/gprofng/src/DbeSession.h
@@ -0,0 +1,481 @@
+/* Copyright (C) 2021 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. */
+
+/* The DbeSession class is instantiated by a DbeApplication, and contains
+ * all the data referring to a set of loaded experiments
+ *
+ * It manages a set of tables for the Experiments, for the LoadObjects
+ * referenced in them, and for the other objects representing the
+ * elements in the program hierarchy that can have metrics associated
+ * with them. It also has a master list of all the metrics available
+ * from all the loaded experiments.
+ *
+ * It gets an instance of the Settings class, instantiated as a copy
+ * of the one in the DbeApplication that instantiated the DbeSession.
+ *
+ * In addition, it manages a vector of DbeView's (q.v.); each DbeView
+ * represents a window into the DbeSession, and has its own set of
+ * Settings, and FilterSets for the Experiments, and is the access point
+ * for all processed data.
+ */
+
+#ifndef _DBESESSION_H
+#define _DBESESSION_H
+
+
+#include <stdio.h>
+#include "dbe_structs.h"
+#include "vec.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "BaseMetric.h"
+#include "BaseMetricTreeNode.h"
+#include "MemorySpace.h"
+#include "hwcentry.h"
+#include "dbe_types.h"
+#include "Settings.h"
+#include "HashMap.h"
+#include "Table.h"
+#include "Experiment.h"
+
+class DbeSession;
+class Experiment;
+class Expression;
+class ExpGroup;
+class Function;
+class JMethod;
+class Histable;
+class DbeView;
+class Module;
+class LoadObject;
+class DataObject;
+class SourceFile;
+class Settings;
+class StringBuilder;
+class UserLabel;
+class DbeFile;
+class DbeJarFile;
+class FileData;
+class HeapData;
+template <typename ITEM> class DbeSyncMap;
+template <class ITEM> class Vector;
+
+struct DispTab;
+struct List;
+struct Countable;
+class IndexObjType_t;
+
+typedef struct
+{
+ char *path;
+ Experiment *exp;
+ DbeSession *ds;
+ bool read_ahead;
+} exp_ctx;
+
+class DbeSession
+{
+public:
+ DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode);
+ ~DbeSession ();
+
+ void reset ();
+ void reset_data ();
+
+ void
+ set_interactive (bool _interactive)
+ {
+ interactive = _interactive;
+ }
+
+ bool
+ is_interactive ()
+ {
+ return interactive;
+ }
+
+ bool is_datamode_available ();
+ bool is_leaklist_available ();
+ bool is_heapdata_available ();
+ bool is_iodata_available ();
+ bool is_racelist_available ();
+ bool is_deadlocklist_available ();
+ bool is_timeline_available ();
+ bool is_ifreq_available ();
+ bool is_omp_available ();
+ bool has_java ();
+ bool has_ompavail ();
+
+ // XXX get_clock should be removed, to support cpus with different clocks
+ // XXX means reworking time-convertible HWC code
+ int get_clock (int id);
+
+ // Access functions for DbeView's
+ int createView ();
+ int createView (int index, int cloneindex);
+ DbeView *getView (int index);
+ void dropView (int index);
+
+ // Access functions controlling the experiment list
+ Vector<char*> *get_group_or_expt (char *path); // load an experiment or group
+
+ void open_experiment (Experiment *exp, char *path);
+ Experiment *get_exp (int exp_ind);
+ Vector<Vector<char*>*> *getExperimensGroups ();
+ char *setExperimentsGroups (Vector<Vector<char*>*> *groups);
+ char *drop_experiment (int exp_ind);
+ int find_experiment (char *path);
+
+ int
+ nexps ()
+ {
+ return exps->size ();
+ }
+ int ngoodexps ();
+
+ // Access functions controlling the DataObject list
+ DataObject *createDataObject ();
+ DataObject *createDataObject (DataObject *d, DataObject *p = NULL);
+ DataObject *createMasterDataObject (DataObject *);
+ Vector<DataObject*> *get_dobj_elements (DataObject *);
+
+ DataObject *
+ get_Total_DataObject ()
+ {
+ return d_total;
+ };
+
+ DataObject *
+ get_Unknown_DataObject ()
+ {
+ return d_unknown;
+ };
+
+ DataObject *
+ get_Scalars_DataObject ()
+ {
+ return d_scalars;
+ };
+
+ DataObject *find_dobj_by_name (char *dobj_name);
+ DataObject *find_dobj_match (DataObject *dobj);
+ DataObject *find_dobj_master (DataObject *dobj);
+
+ int
+ ndobjs ()
+ {
+ return dobjs->size ();
+ }
+
+ // check if no -xhwcprof should be ignored
+ bool
+ check_ignore_no_xhwcprof ()
+ {
+ return settings->get_ignore_no_xhwcprof ();
+ };
+
+ // check if FS warning should be comment, or real warning
+ bool
+ check_ignore_fs_warn ()
+ {
+ return settings->get_ignore_fs_warn ();
+ };
+
+ // Access functions controlling the LoadObject list
+ DbeSyncMap<LoadObject> *loadObjMap;
+ void append (LoadObject *lobj);
+ LoadObject *createLoadObject (const char *nm, int64_t cksum = 0);
+ LoadObject *createLoadObject (const char *nm, const char *runTimePath, DbeFile *df);
+
+ Vector<LoadObject *> *
+ get_LoadObjects ()
+ {
+ return lobjs;
+ };
+
+ void dobj_updateHT (DataObject *dobj);
+ LoadObject *get_Total_LoadObject ();
+ Vector<LoadObject*> *get_text_segments ();
+ LoadObject *get_Unknown_LoadObject ();
+ LoadObject *find_lobj_by_name (const char *lobj_name, int64_t cksum = 0);
+
+ // Access functions controlling the Tab list
+ Vector<DispTab*> *
+ get_TabList ()
+ {
+ return settings->get_TabList ();
+ };
+
+ Vector<bool> *
+ get_MemTabList ()
+ {
+ return settings->get_MemTabState ();
+ };
+
+ void mobj_define (MemObjType_t *);
+
+ // Access functions controlling metrics
+ BaseMetric *find_base_reg_metric (char *mcmd);
+ Vector<BaseMetric*> *get_base_reg_metrics (); // excludes comparison (expr) variants
+
+ Vector<BaseMetric*> *
+ get_all_reg_metrics ()
+ {
+ return reg_metrics; // includes comparison (expr) variants
+ };
+
+ BaseMetricTreeNode *get_reg_metrics_tree ();
+ BaseMetric *register_metric_expr (BaseMetric::Type type, char *aux, char *expr_spec);
+ BaseMetric *register_metric (BaseMetric::Type type);
+ BaseMetric *register_metric (char *name, char *username, char *_def);
+ BaseMetric *register_metric (Hwcentry *ctr, const char* cmdname, const char* username);
+ void drop_metric (BaseMetric *);
+ Module *createModule (LoadObject *lo, const char *nm);
+ Module *createUnknownModule (LoadObject *lo);
+ Module *createClassFile (char *className);
+ DbeFile *getDbeFile (char *filename, int filetype);
+ SourceFile *get_Unknown_Source ();
+ SourceFile *createSourceFile (const char *path);
+ Histable *createHistObject (Histable::Type);
+ Function *createFunction ();
+ Function *create_hide_function (LoadObject *lo);
+ Function *get_Total_Function ();
+ Function *get_Unknown_Function ();
+ Function *get_JUnknown_Function ();
+ Function *get_jvm_Function ();
+ LoadObject *get_OMP_LoadObject ();
+ Function *get_OMP_Function (int);
+ JMethod *createJMethod ();
+ Histable *createIndexObject (int idxtype, int64_t idx);
+ Histable *createIndexObject (int idxtype, Histable *hobj);
+
+ enum SpecialFunction
+ {
+ TruncatedStackFunc,
+ FailedUnwindFunc,
+ LastSpecialFunction
+ };
+ Function *getSpecialFunction (SpecialFunction);
+
+ Histable *
+ findObjectById (uint64_t _id)
+ {
+ long id = (long) _id;
+ return (id >= 0 && id < objs->size ()) ? objs->fetch (id) : NULL;
+ }
+
+ Histable *findObjectById (Histable::Type type, int subtype, uint64_t id);
+
+ // Other access functions
+ bool find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj, char *name,
+ const char *sel, Histable::Type type, bool xdefault);
+ int ask_which (FILE *dis_file, FILE *inp_file, Vector<Histable*> *list, char *name);
+ LoadObject *map_NametoLoadObject (char *name, Vector<Histable*> *, int which);
+ Module *map_NametoModule (char *name, Vector<Histable*> *, int which);
+ Function *map_NametoFunction (char *, Vector<Histable*> *, const char *);
+ DataObject *map_NametoDataObject (char *name, Vector<Histable*> *, int which);
+ bool match_FName (char *name, Function *func);
+
+ // Functions to convert a string to all matching Functions/DataObjects
+ Vector<Function *> *match_func_names (const char *ustr, Histable::NameFormat nfmt);
+ Vector<DataObject *> *match_dobj_names (char *);
+
+ // Functions to convert a string to all matching JThreads
+ Vector<JThread*> *match_java_threads (char *ustr, int matchParent,
+ Vector<uint64_t> * &grids,
+ Vector<uint64_t> * &expids);
+ // Function to convert a string to all matching File names
+ Vector<FileData *> *match_file_names (char *ustr, Histable::NameFormat nfmt);
+
+ // Access functions concerning the search path
+ Vector<char*> *
+ get_search_path ()
+ {
+ return search_path;
+ }
+
+ Vector<DbeFile*>*get_classpath ();
+ void set_search_path (Vector<char*> *path, bool reset);
+ void set_search_path (char *lpath, bool reset);
+ bool add_classpath (char *path);
+ bool add_path (char *path);
+ void set_pathmaps (Vector<pathmap_t*> *newPathMap);
+ Vector<pathmap_t*> *get_pathmaps ();
+
+ // functions to aid debugging
+ void dump_stacks (FILE *);
+ void dump_dataobjects (FILE *);
+ void dump_segments (FILE *);
+ void dump_map (FILE *);
+
+ // Find dynamic property by name
+ int registerPropertyName (const char *name);
+ int getPropIdByName (const char *name);
+ char* getPropName (int propId);
+ char* getPropUName (int propId);
+
+ Vector<UserLabel*> *userLabels; // List of er_labels
+ UserLabel *findUserLabel (char *name);
+ DbeJarFile *get_JarFile (const char *name);
+ void append (UserLabel *lbl);
+ void append (SourceFile *sf);
+ void append (Experiment *exp);
+ void append (Hwcentry *exp);
+ void set_need_refind ();
+
+ // Find user defined object by name
+ Expression *findObjDefByName (char *);
+ void get_filter_keywords (Vector<void*> *res);
+
+ // Get the Settings class object
+ Settings *
+ get_settings ()
+ {
+ return settings;
+ }
+
+ // static members, used to define or fetch the various IndexSpaces
+ Vector<void*> *getIndxObjDescriptions (void);
+ Vector<void*> *getCustomIndxObjects (void);
+ char *indxobj_define (const char *, char *, const char *, char *, char *);
+ char *getIndexSpaceName (int index);
+ char *getIndexSpaceDescr (int index);
+ Expression *getIndexSpaceExpr (int index);
+ char *getIndexSpaceExprStr (int index);
+ int findIndexSpaceByName (const char *mname);
+ void removeIndexSpaceByName (const char *mname);
+ IndexObjType_t *getIndexSpace (int index);
+ IndexObjType_t *findIndexSpace (const char *mname);
+ Expression *ql_parse (const char *expr_spec);
+ BaseMetric *find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec = NULL);
+ static void dump (char *msg, Vector<Metric*> *mlist);
+ static void dump (char *msg, Vector<BaseMetric*> *mlist);
+ static Platform_t platform; // Sparc, Intel
+ Vector<ExpGroup *> *expGroups;
+ HashMap<char*, LoadObject *> *comp_lobjs; // list of comparable LoadObjects
+ HashMap<char*, DbeLine *> *comp_dbelines; // list of comparable DbeLines
+ HashMap<char*, SourceFile*>*comp_sources; // list of comparable SourceFiles
+ char *localized_SP_UNKNOWN_NAME;
+
+ void
+ set_lib_visibility_used ()
+ {
+ lib_visibility_used = true;
+ }
+
+ bool
+ is_lib_visibility_used ()
+ {
+ return lib_visibility_used;
+ }
+
+ void unlink_tmp_files ();
+ char *get_tmp_file_name (const char *nm, bool for_java);
+
+ Vector<char *> *tmp_files;
+ int status_ompavail;
+ int archive_mode;
+ bool ipc_mode;
+ bool rdt_mode;
+
+ // data and methods concerning the machine model
+ // methods are in source file MachineModel.cc
+ Vector<char*> *list_mach_models (); // scan . and system lib directory for models
+ char *load_mach_model (char *);
+
+ char *
+ get_mach_model ()
+ {
+ return dbe_strdup (mach_model_loaded);
+ };
+ Vector<SourceFile *> *get_sources ();
+
+private:
+ void init ();
+ void check_tab_avail ();
+ bool add_path (char *path, Vector<char*> *pathes);
+ Experiment *createExperiment ();
+
+ // Divide the regular createExperiment into two parts -
+ // Part1 creates just the Experiment data structure
+ // Part2 updates related fields and vectors
+ Experiment *createExperimentPart1 ();
+ void createExperimentPart2 (Experiment *exp);
+
+ Histable *findIndexObject (int idxtype, uint64_t idx);
+ void append_mesgs (StringBuilder *sb, char *path, Experiment *exp);
+ static void insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist);
+ void update_metric_tree (BaseMetric *m);
+
+ char *find_mach_model (char *); // fine machine model file by name
+ Vector<Experiment*> *exps; // Master list of experiments
+ Vector<Histable*> *objs; // Master list of Functions,Modules,Segments
+ Vector<DataObject*> *dobjs; // Master list of DataObjects
+ Vector<LoadObject*> *lobjs; // Auxiliary list of LoadObjects
+ Vector<Hwcentry*> *hwcentries;
+ Vector<HashMap<uint64_t, Histable*>*> *idxobjs; // Master list of IndexObjects
+ HashMap<char*, SourceFile*> *sourcesMap; // list of Source which were not archived
+ Vector<SourceFile*> *sources; // list of SourceFiles
+ Map<const char*, DbeJarFile*>*dbeJarFiles;
+ Vector<Countable*> *metrics;
+ Vector<BaseMetric*> *reg_metrics; // Master list of BaseMetrics
+ BaseMetricTreeNode* reg_metrics_tree; // Hierarchy of BaseMetrics
+ Vector<char*> *search_path;
+ Vector<char*> *classpath;
+ Vector<DbeFile*> *classpath_df;
+ Map<const char*, DbeFile*>*dbeFiles;
+ Vector<DbeView*> *views; // Master list of DbeViews
+ bool interactive; // interactive mode
+ bool lib_visibility_used;
+ LoadObject *lo_total; // Total LoadObject
+ Function *f_total; // Total function
+ LoadObject *lo_unknown; // Unknown LoadObject
+ Function *f_unknown; // Unknown function
+ SourceFile *sf_unknown; // Unknown source file
+ Function *f_jvm; // pseudo-function <JVM-System>
+ Vector<Function*> *f_special; // pseudo-functions
+ Function *j_unknown; // pseudo-function <no Java callstack>
+ LoadObject *lo_omp; // OMP LoadObject (libmtsk)
+ Vector<Function*> *omp_functions; // OMP-overhead, etc.
+ DataObject *d_unknown; // Unknown dataobject
+ DataObject *d_scalars; // Scalars dataobject
+ DataObject *d_total; // Total dataobject
+ List **dnameHTable; // DataObject name hash table
+ Settings *settings; // setting/defaults structure
+ Vector<IndexObjType_t*> *dyn_indxobj; // Index Object definitions
+ int dyn_indxobj_indx;
+ int dyn_indxobj_indx_fixed;
+
+ void propNames_name_store (int propId, const char *propName);
+ void propNames_name_store (int propId, const char *propName,
+ const char *propUName, VType_type vType, int flags);
+ char* propNames_name_fetch (int propId);
+ Vector<PropDescr*> *propNames;
+ char *defExpName;
+ int user_exp_id_counter;
+ char *mach_model_loaded;
+ char *tmp_dir_name;
+};
+
+// For now, there's only one, so keep its pointer
+extern DbeSession *dbeSession;
+
+extern Vector<char *> *split_str (char *str, char delimiter);
+#endif /* _DBESESSION_H */
diff --git a/gprofng/src/DbeSyncMap.h b/gprofng/src/DbeSyncMap.h
new file mode 100644
index 0000000..f13f7b4
--- /dev/null
+++ b/gprofng/src/DbeSyncMap.h
@@ -0,0 +1,224 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DbeSyncMap_h
+#define _DbeSyncMap_h
+
+#include "DbeLock.h"
+#include "DbeLinkList.h"
+#include "vec.h"
+
+typedef unsigned long hash_ty;
+
+template <class ITEM> class DbeSyncMap : public DbeLock
+{
+public:
+ DbeSyncMap (int _chunkSize = DefaultChunkSize);
+ virtual ~DbeSyncMap ();
+ void reset ();
+ ITEM *get (const char *nm, int64_t chksum);
+ ITEM *sync_create_item (const char *nm, int64_t chksum);
+ ITEM *get (const char *nm, const char *path, DbeFile *df);
+ ITEM *sync_create_item (const char *nm, const char *path, DbeFile *df);
+ virtual void dump ();
+
+ Vector<ITEM *> *
+ values ()
+ {
+ return items;
+ };
+
+private:
+ hash_ty hash (const char *key);
+
+ DbeLinkList<ITEM *> **chunk;
+ Vector<ITEM *> *items;
+ long chunkSize;
+
+ enum
+ {
+ DefaultChunkSize = 1024
+ };
+};
+
+template <class ITEM>
+DbeSyncMap<ITEM>::DbeSyncMap (int _chunkSize)
+{
+ chunkSize = _chunkSize;
+ chunk = new DbeLinkList<ITEM *> * [chunkSize];
+ for (long i = 0; i < chunkSize; i++)
+ chunk[i] = NULL;
+ items = new Vector<ITEM *>(512);
+}
+
+template <class ITEM>
+DbeSyncMap<ITEM>::~DbeSyncMap ()
+{
+ for (long i = 0; i < chunkSize; i++)
+ Destroy (chunk[i]);
+ delete[] chunk;
+ delete items;
+}
+
+template <class ITEM>
+void
+DbeSyncMap<ITEM>::reset ()
+{
+ for (long i = 0; i < chunkSize; i++)
+ {
+ Destroy (chunk[i]);
+ chunk[i] = NULL;
+ }
+ items->reset ();
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::get (const char *nm, int64_t chksum)
+{
+ hash_ty h = hash (nm);
+ for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+ {
+ ITEM *item = dl->get_item ();
+ if (item->compare (nm, chksum))
+ return item;
+ }
+ return NULL;
+}
+
+template <class ITEM>
+hash_ty
+DbeSyncMap<ITEM>::hash (const char *key)
+{
+ return (hash_ty) (crc64 (key, strlen (key)) % chunkSize);
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::sync_create_item (const char *nm, int64_t chksum)
+{
+ hash_ty h = hash (nm);
+ for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+ {
+ ITEM *item = dl->get_item ();
+ if (item->compare (nm, chksum))
+ return item;
+ }
+ aquireLock ();
+ for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+ {
+ ITEM *item = dl->get_item ();
+ if (item->compare (nm, chksum))
+ {
+ releaseLock ();
+ return item;
+ }
+ }
+ ITEM *item = ITEM::create_item (nm, chksum);
+ DbeLinkList<ITEM *> *dl = new DbeLinkList<ITEM *>(item);
+ dl->set_next (chunk[h]);
+ chunk[h] = dl;
+ items->append (item);
+ releaseLock ();
+ return item;
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::get (const char *nm, const char *path, DbeFile *df)
+{
+ int mask = 1 + (path != NULL ? 2 : 0) + (df != NULL ? 4 : 0);
+ hash_ty h = hash (nm);
+ for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+ {
+ ITEM *item = dl->get_item ();
+ if (mask == item->compare (nm, path, df))
+ return item;
+ }
+ return NULL;
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::sync_create_item (const char *nm, const char *path, DbeFile *df)
+{
+ int mask = CMP_PATH;
+ if (path != NULL)
+ mask += CMP_RUNTIMEPATH;
+ if (df != NULL)
+ mask += CMP_CHKSUM;
+ hash_ty h = hash (nm);
+ for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+ {
+ ITEM *item = dl->get_item ();
+ if (mask == item->compare (nm, path, df))
+ return item;
+ }
+ aquireLock ();
+ for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+ {
+ ITEM *item = dl->get_item ();
+ if (mask == item->compare (nm, path, df))
+ {
+ releaseLock ();
+ return item;
+ }
+ }
+ ITEM *item = ITEM::create_item (nm, path, df);
+ DbeLinkList<ITEM *> *dl = new DbeLinkList<ITEM *>(item);
+ dl->set_next (chunk[h]);
+ chunk[h] = dl;
+ items->append (item);
+ releaseLock ();
+ return item;
+}
+
+template <class ITEM>
+void
+DbeSyncMap<ITEM>::dump ()
+{
+ Dprintf (1, NTXT ("\nDbeSyncMap::dump: vals=%ld\n"), (long) VecSize (items));
+ int tot = 0;
+ int max_cnt = 0;
+ for (long i = 0; i < chunkSize; i++)
+ {
+ DbeLinkList<ITEM *> *lp = chunk[i];
+ if (lp)
+ {
+ int cnt = 0;
+ for (DbeLinkList<ITEM *> *lp1 = lp; lp1; lp1 = lp1->get_next ())
+ cnt++;
+ tot += cnt;
+ if (max_cnt < cnt)
+ max_cnt = cnt;
+ cnt = 1;
+ for (DbeLinkList<ITEM *> *lp1 = lp; lp1; lp1 = lp1->get_next ())
+ {
+ ITEM *p = lp1->get_item ();
+ Dprintf (1, NTXT (" %2d %s\n"), cnt, p->get_name ());
+ cnt++;
+ }
+ }
+ }
+ Dprintf (1, NTXT ("\nDbeSyncMap::dump: vals=%ld max_cnt=%d tot=%d\n"),
+ (long) VecSize (items), max_cnt, tot);
+}
+
+#endif /* _DbeSyncMap_h */
diff --git a/gprofng/src/DbeThread.cc b/gprofng/src/DbeThread.cc
new file mode 100644
index 0000000..7eb3cb7
--- /dev/null
+++ b/gprofng/src/DbeThread.cc
@@ -0,0 +1,224 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "DbeThread.h"
+#include "util.h"
+#include "vec.h"
+
+static void
+cleanup_free_mutex (void* arg) {
+ // pthread_mutex_t *p_mutex = (pthread_mutex_t *) arg;
+ // if (p_mutex)
+ // pthread_mutex_unlock (p_mutex);
+}
+
+static void*
+thread_pool_loop (void* arg)
+{
+ DbeThreadPool *thrp = (DbeThreadPool*) arg;
+ Dprintf (DEBUG_THREADS, "thread_pool_loop:%d starting thread=%llu\n",
+ __LINE__, (unsigned long long) pthread_self ());
+
+ /* set my cancel state to 'enabled', and cancel type to 'defered'. */
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL);
+
+ /* set thread cleanup handler */
+ pthread_cleanup_push (cleanup_free_mutex, (void*) & (thrp->p_mutex));
+ for (;;)
+ {
+ DbeQueue *q = thrp->get_queue ();
+ if (q)
+ { /* a request is pending */
+ Dprintf (DEBUG_THREADS,
+ "thread_pool_loop:%d thread=%llu queue=%d start\n",
+ __LINE__, (unsigned long long) pthread_self (), q->id);
+ q->func (q->arg);
+ Dprintf (DEBUG_THREADS,
+ "thread_pool_loop:%d thread=%llu queue=%d done\n",
+ __LINE__, (unsigned long long) pthread_self (), q->id);
+ delete q;
+ continue;
+ }
+ if (thrp->no_new_queues)
+ {
+ Dprintf (DEBUG_THREADS, "thread_pool_loop:%d exit thread=%llu\n",
+ __LINE__, (unsigned long long) pthread_self ());
+ pthread_exit (NULL);
+ }
+ Dprintf (DEBUG_THREADS,
+ "thread_pool_loop:%d before pthread_cond_wait thread=%llu\n",
+ __LINE__, (unsigned long long) pthread_self ());
+ pthread_mutex_lock (&thrp->p_mutex);
+ pthread_cond_wait (&thrp->p_cond_var, &thrp->p_mutex);
+ Dprintf (DEBUG_THREADS,
+ "thread_pool_loop:%d after pthread_cond_wait thread=%llu\n",
+ __LINE__, (unsigned long long) pthread_self ());
+ pthread_mutex_unlock (&thrp->p_mutex);
+ }
+
+ // never reached, but we must use it here. See `man pthread_cleanup_push`
+ pthread_cleanup_pop (0);
+}
+
+DbeThreadPool::DbeThreadPool (int _max_threads)
+{
+ static const int DBE_NTHREADS_DEFAULT = 4;
+ char *s = getenv ("GPROFNG_DBE_NTHREADS");
+ if (s)
+ {
+ max_threads = atoi (s);
+ if (max_threads < 0)
+ max_threads = 0;
+ if (_max_threads > 0 && max_threads < _max_threads)
+ max_threads = _max_threads;
+ }
+ else
+ {
+ max_threads = _max_threads;
+ if (max_threads < 0)
+ max_threads = DBE_NTHREADS_DEFAULT;
+ }
+ Dprintf (DEBUG_THREADS, "DbeThreadPool:%d max_threads %d ---> %d\n",
+ __LINE__, _max_threads, max_threads);
+ pthread_mutex_init (&p_mutex, NULL);
+ pthread_cond_init (&p_cond_var, NULL);
+ threads = new Vector <pthread_t>(max_threads);
+ queue = NULL;
+ last_queue = NULL;
+ no_new_queues = false;
+ queues_cnt = 0;
+ total_queues = 0;
+}
+
+DbeThreadPool::~DbeThreadPool ()
+{
+ delete threads;
+}
+
+DbeQueue *
+DbeThreadPool::get_queue ()
+{
+ pthread_mutex_lock (&p_mutex);
+ DbeQueue *q = queue;
+ Dprintf (DEBUG_THREADS,
+ "get_queue:%d thr: %lld id=%d queues_cnt=%d threads_cnt=%d max_threads=%d\n",
+ __LINE__, (unsigned long long) pthread_self (),
+ q ? q->id : -1, queues_cnt, (int) threads->size (), max_threads);
+ if (q)
+ {
+ queue = q->next;
+ queues_cnt--;
+ }
+ pthread_mutex_unlock (&p_mutex);
+ return q;
+}
+
+void
+DbeThreadPool::put_queue (DbeQueue *q)
+{
+ if (max_threads == 0)
+ {
+ // nothing runs in parallel
+ q->id = ++total_queues;
+ Dprintf (DEBUG_THREADS, NTXT ("put_queue:%d thr=%lld max_threads=%d queue (%d) runs on the worked thread\n"),
+ __LINE__, (unsigned long long) pthread_self (), max_threads, q->id);
+ q->func (q->arg);
+ delete q;
+ return;
+ }
+
+ pthread_mutex_lock (&p_mutex);
+ // nothing runs in parallel
+ q->id = ++total_queues;
+ Dprintf (DEBUG_THREADS, "put_queue:%d thr=%lld max_threads=%d queue (%d)\n",
+ __LINE__, (unsigned long long) pthread_self (), max_threads, q->id);
+ if (queue)
+ {
+ last_queue->next = q;
+ last_queue = q;
+ }
+ else
+ {
+ queue = q;
+ last_queue = q;
+ }
+ queues_cnt++;
+ Dprintf (DEBUG_THREADS,
+ "put_queue:%d id=%d queues_cnt=%d threads_cnt=%d max_threads=%d\n",
+ __LINE__, q->id, queues_cnt, (int) threads->size (), max_threads);
+ if (queues_cnt > threads->size () && threads->size () < max_threads)
+ {
+ pthread_t thr;
+ int r = pthread_create (&thr, NULL, thread_pool_loop, (void *) this);
+ Dprintf (DEBUG_THREADS,
+ "put_queue:%d pthread_create returns %d thr=%llu\n",
+ __LINE__, r, (unsigned long long) thr);
+ if (r)
+ fprintf (stderr, GTXT ("pthread_create failed. errnum=%d (%s)\n"), r,
+ STR (strerror (r)));
+ else
+ threads->append (thr);
+ }
+ pthread_cond_signal (&p_cond_var);
+ pthread_mutex_unlock (&p_mutex);
+}
+
+void
+DbeThreadPool::wait_queues ()
+{
+ pthread_mutex_lock (&p_mutex);
+ no_new_queues = true;
+ pthread_mutex_unlock (&p_mutex);
+ pthread_cond_broadcast (&p_cond_var);
+ for (;;) // Run requests on the worked thread too
+ {
+ DbeQueue *q = get_queue ();
+ if (q == NULL)
+ break;
+ Dprintf (DEBUG_THREADS, "wait_queues:%d thread=%llu queue=%d start\n",
+ __LINE__, (unsigned long long) pthread_self (), q->id);
+ q->func (q->arg);
+ Dprintf (DEBUG_THREADS, "wait_queues:%d thread=%llu queue=%d done\n",
+ __LINE__, (unsigned long long) pthread_self (), q->id);
+ delete q;
+ }
+ for (int i = 0, sz = threads->size (); i < sz; i++)
+ {
+ void *retval;
+ pthread_join (threads->get (i), &retval);
+ }
+}
+
+DbeQueue::DbeQueue (int (*_func) (void *arg), void *_arg)
+{
+ func = _func;
+ arg = _arg;
+ next = NULL;
+}
+
+DbeQueue::~DbeQueue () { }
diff --git a/gprofng/src/DbeThread.h b/gprofng/src/DbeThread.h
new file mode 100644
index 0000000..8ee148b
--- /dev/null
+++ b/gprofng/src/DbeThread.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBETHREAD_H
+#define _DBETHREAD_H
+#include <pthread.h>
+#include "DbeLinkList.h"
+
+template <class ITEM> class Vector;
+
+class DbeQueue
+{
+public:
+ DbeQueue (int (*_func)(void *arg), void *_arg);
+ ~DbeQueue ();
+
+ int (*func) (void *arg);
+ void *arg;
+ int id;
+ DbeQueue *next;
+};
+
+class DbeThreadPool
+{
+public:
+ DbeThreadPool (int _max_threads);
+ ~DbeThreadPool ();
+ DbeQueue *get_queue ();
+ void put_queue (DbeQueue *q);
+ void wait_queues ();
+
+ pthread_mutex_t p_mutex;
+ pthread_cond_t p_cond_var;
+ volatile bool no_new_queues;
+private:
+ Vector<pthread_t> *threads;
+ int max_threads;
+ DbeQueue *volatile queue;
+ DbeQueue *volatile last_queue;
+ volatile int queues_cnt;
+ volatile int total_queues;
+};
+
+#endif
diff --git a/gprofng/src/DbeView.cc b/gprofng/src/DbeView.cc
new file mode 100644
index 0000000..68613a5
--- /dev/null
+++ b/gprofng/src/DbeView.cc
@@ -0,0 +1,3126 @@
+/* Copyright (C) 2021 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 "Application.h"
+#include "DbeSession.h"
+#include "CallStack.h"
+#include "Command.h"
+#include "DataObject.h"
+#include "Experiment.h"
+#include "ExpGroup.h"
+#include "FilterExp.h"
+#include "FilterSet.h"
+#include "Function.h"
+#include "DbeView.h"
+#include "PathTree.h"
+#include "DataSpace.h"
+#include "MemorySpace.h"
+#include "IOActivity.h"
+#include "HeapActivity.h"
+#include "Print.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "Filter.h"
+#include "LoadObject.h"
+#include "dbe_types.h"
+#include "StringBuilder.h"
+
+DbeView::DbeView (Application *_app, Settings *_settings, int _vindex)
+{
+ init ();
+ phaseIdx = 0;
+ settings = new Settings (_settings);
+ ptree = new PathTree (this);
+ dspace = new DataSpace (this);
+ memspaces = new Vector<MemorySpace*>;
+ iospace = new IOActivity (this);
+ heapspace = new HeapActivity (this);
+ filters = new Vector<FilterSet*>;
+ lo_expands = new Vector<enum LibExpand>;
+ cur_filter_str = NULL;
+ prev_filter_str = NULL;
+ cur_filter_expr = NULL;
+ filter_active = false;
+ noParFilter = false;
+ dataViews = new Vector<Vector<DataView*>*>;
+ names_src[0] = NULL;
+ names_src[1] = NULL;
+ names_src[2] = NULL;
+ names_dis[0] = NULL;
+ names_dis[1] = NULL;
+ names_dis[2] = NULL;
+ marks = new Vector<int>;
+ marks2dsrc = new Vector<int_pair_t>;
+ marks2dsrc_inc = new Vector<int_pair_t>;
+ marks2ddis = new Vector<int_pair_t>;
+ marks2ddis_inc = new Vector<int_pair_t>;
+ app = _app;
+
+ // set the view's index
+ vindex = _vindex;
+
+ // clear the precomputed data
+ func_data = NULL;
+ line_data = NULL;
+ pc_data = NULL;
+ src_data = NULL;
+ dis_data = NULL;
+ fitem_data = NULL;
+ callers = NULL;
+ callees = NULL;
+ dobj_data = NULL;
+ dlay_data = NULL;
+ iofile_data = NULL;
+ iovfd_data = NULL;
+ iocs_data = NULL;
+ heapcs_data = NULL;
+
+ // and clear the selections
+ sel_obj = NULL;
+ sel_dobj = NULL;
+ sel_binctx = NULL;
+ func_scope = false;
+ lastSelInstr = NULL;
+ lastSelFunc = NULL;
+
+ // Initialize index spaces
+ int sz = settings->get_IndxTabState ()->size ();
+ indxspaces = new Vector<PathTree*>(sz);
+ indx_data = new Vector<Hist_data*>(sz);
+ sel_idxobj = new Vector<Histable*>(sz);
+ for (int i = 0; i < sz; i++)
+ {
+ PathTree *is = new PathTree (this, i);
+ indxspaces->store (i, is);
+ indx_data->store (i, NULL);
+ sel_idxobj->store (i, NULL);
+ }
+ reset ();
+
+ lobjectsNoJava = NULL;
+
+ // set lo_expands for already existing LoadObjects
+ int idx;
+ LoadObject *lo;
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ Vec_loop (LoadObject*, lobjs, idx, lo)
+ {
+ lo_expands->store (lo->seg_idx, LIBEX_SHOW);
+ set_lo_expand (lo->seg_idx, LIBEX_SHOW);
+ }
+ delete lobjs;
+}
+
+DbeView::DbeView (DbeView *dbev, int _vindex)
+{
+ init ();
+ phaseIdx = 0;
+ settings = new Settings (dbev->settings);
+ ptree = new PathTree (this);
+ dspace = new DataSpace (this);
+ iospace = new IOActivity (this);
+ heapspace = new HeapActivity (this);
+ memspaces = new Vector<MemorySpace*>;
+ filters = new Vector<FilterSet*>;
+ lo_expands = new Vector<enum LibExpand>;
+ cur_filter_str = NULL;
+ prev_filter_str = NULL;
+ cur_filter_expr = NULL;
+ noParFilter = false;
+ dataViews = new Vector<Vector<DataView*>*>;
+ names_src[0] = NULL;
+ names_src[1] = NULL;
+ names_src[2] = NULL;
+ names_dis[0] = NULL;
+ names_dis[1] = NULL;
+ names_dis[2] = NULL;
+ marks = new Vector<int>;
+ marks2dsrc = new Vector<int_pair_t>;
+ marks2dsrc_inc = new Vector<int_pair_t>;
+ marks2ddis = new Vector<int_pair_t>;
+ marks2ddis_inc = new Vector<int_pair_t>;
+ app = dbev->app;
+
+ // set the view's index
+ vindex = _vindex;
+
+ // clear the precomputed data
+ func_data = NULL;
+ line_data = NULL;
+ pc_data = NULL;
+ src_data = NULL;
+ dis_data = NULL;
+ fitem_data = NULL;
+ callers = NULL;
+ callees = NULL;
+ dobj_data = NULL;
+ dlay_data = NULL;
+ iofile_data = NULL;
+ iovfd_data = NULL;
+ iocs_data = NULL;
+ heapcs_data = NULL;
+
+ // and clear the selections
+ sel_obj = NULL;
+ sel_dobj = NULL;
+ sel_binctx = NULL;
+ func_scope = false;
+ lastSelInstr = NULL;
+ lastSelFunc = NULL;
+
+ // create the vector of IndexSpaces
+ int sz = dbev->indxspaces->size ();
+ indxspaces = new Vector<PathTree*>(sz);
+ indx_data = new Vector<Hist_data*>(sz);
+ sel_idxobj = new Vector<Histable*>(sz);
+ for (int i = 0; i < sz; i++)
+ {
+ PathTree *is = new PathTree (this, i);
+ indxspaces->store (i, is);
+ indx_data->store (i, NULL);
+ sel_idxobj->store (i, NULL);
+ }
+ reset ();
+
+ // now copy the relevant information from the original view
+ for (int i = 0; i < dbeSession->nexps (); i++)
+ add_experiment (i, dbev->get_exp_enable (i));
+ update_advanced_filter ();
+ delete lo_expands;
+ lo_expands = dbev->lo_expands->copy ();
+ lobjectsNoJava = NULL;
+}
+
+DbeView::~DbeView ()
+{
+ delete settings;
+ delete ptree;
+ delete dspace;
+ delete iospace;
+ delete heapspace;
+ Destroy (memspaces);
+ Destroy (filters);
+ delete lo_expands;
+ free (cur_filter_str);
+ free (prev_filter_str);
+ delete cur_filter_expr;
+ for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id)
+ {
+ Vector<DataView*> *expDataViewList = dataViews->fetch (exp_id);
+ Destroy (expDataViewList);
+ }
+ delete dataViews;
+ delete reg_metrics;
+ metrics_lists->destroy ();
+ delete metrics_lists;
+ metrics_ref_lists->destroy ();
+ delete metrics_ref_lists;
+ delete derived_metrics;
+ delete marks;
+ delete marks2dsrc;
+ delete marks2dsrc_inc;
+ delete marks2ddis;
+ delete marks2ddis_inc;
+
+ // Index spaces
+ indxspaces->destroy ();
+ delete indxspaces;
+
+ indx_data->destroy ();
+ delete indx_data;
+ delete sel_idxobj;
+ delete lobjectsNoJava;
+}
+
+void
+DbeView::init ()
+{
+ phaseIdx = 0;
+ reg_metrics = new Vector<BaseMetric*>;
+ metrics_lists = new Vector<MetricList*>;
+ metrics_ref_lists = new Vector<MetricList*>;
+ for (int i = 0; i <= MET_HEAP; i++)
+ {
+ metrics_lists->append (NULL);
+ metrics_ref_lists->append (NULL);
+ }
+ derived_metrics = new DerivedMetrics;
+ derived_metrics->add_definition (GTXT ("CPI"), GTXT ("Cycles Per Instruction"), GTXT ("cycles/insts"));
+ derived_metrics->add_definition (GTXT ("IPC"), GTXT ("Instructions Per Cycle"), GTXT ("insts/cycles"));
+ derived_metrics->add_definition (GTXT ("K_CPI"), GTXT ("Kernel Cycles Per Instruction"), GTXT ("K_cycles/K_insts"));
+ derived_metrics->add_definition (GTXT ("K_IPC"), GTXT ("Kernel Instructions Per Cycle"), GTXT ("K_insts/K_cycles"));
+}
+
+bool
+DbeView::set_libexpand (char *liblist, enum LibExpand flag)
+{
+ bool changed = settings->set_libexpand (liblist, flag, false);
+ // Show/hide performance optimization:
+ // No need to call update_lo_expand for every library because dbev->set_libexpand()
+ // is called from a loop in Dbe.cc SetLoadObjectState for every load object.
+ // It is sufficient to call update_lo_expand() just once at the end of the loop.
+ // At all other places such as er_print.cc which calls specific set_libexpand()
+ // explicitly call update_lo_expands();
+ return changed;
+}
+
+bool
+DbeView::set_libdefaults ()
+{
+ bool changed = settings->set_libdefaults ();
+ if (changed == true)
+ update_lo_expands ();
+ return changed;
+}
+
+void
+DbeView::update_lo_expands ()
+{
+ int index;
+ LoadObject *lo;
+
+ // search all load objects
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ // now search the settings list for this one
+ enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ());
+ set_lo_expand (lo->seg_idx, flag);
+ }
+ delete lobjs;
+}
+
+enum LibExpand
+DbeView::get_lo_expand (int idx)
+{
+ if (idx < lo_expands->size ())
+ return lo_expands->get (idx);
+ return LIBEX_SHOW;
+}
+
+bool
+DbeView::set_lo_expand (int idx, enum LibExpand flag)
+{
+ // LIBRARY_VISIBILITY
+ if (flag == LIBEX_HIDE)
+ {
+ resetShowAll ();
+ dbeSession->set_lib_visibility_used ();
+ }
+ // if no change
+ if (idx < lo_expands->size () && flag == get_lo_expand (idx))
+ return false;
+ setShowHideChanged (); // this is necessary if called from er_print
+
+ // change the flag
+ lo_expands->store (idx, flag);
+
+ // and reset the data
+ fflush (stderr);
+ purge_events ();
+ reset_data (true);
+ return true;
+}
+
+void
+DbeView::reset ()
+{
+ phaseIdx++;
+
+ // reset all the per-experiment arrays
+ filters->destroy ();
+ lo_expands->reset ();
+ free (cur_filter_str);
+ cur_filter_str = NULL;
+ free (prev_filter_str);
+ prev_filter_str = NULL;
+ delete cur_filter_expr;
+ cur_filter_expr = NULL;
+ noParFilter = false;
+ for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id)
+ {
+ Vector<DataView*> *expDataViewList = dataViews->fetch (exp_id);
+ if (expDataViewList)
+ expDataViewList->destroy ();
+ }
+ dataViews->destroy ();
+ reset_metrics ();
+
+ // now reset any cached data
+ reset_data (true);
+ ompDisMode = false;
+ showAll = true;
+ showHideChanged = false;
+ newViewMode = false;
+}
+
+void
+DbeView::reset_data (bool all)
+{
+ // clear the precomputed data
+ if (func_data != NULL)
+ {
+ delete func_data;
+ func_data = NULL;
+ }
+ if (line_data != NULL)
+ {
+ delete line_data;
+ line_data = NULL;
+ }
+ if (pc_data != NULL)
+ {
+ delete pc_data;
+ pc_data = NULL;
+ }
+ if (src_data != NULL)
+ {
+ delete src_data;
+ src_data = NULL;
+ }
+ if (dis_data != NULL)
+ {
+ delete dis_data;
+ dis_data = NULL;
+ }
+ if (fitem_data != NULL)
+ {
+ delete fitem_data;
+ fitem_data = NULL;
+ }
+ if (callers != NULL)
+ {
+ delete callers;
+ callers = NULL;
+ }
+ if (callees != NULL)
+ {
+ delete callees;
+ callees = NULL;
+ }
+ if (dobj_data != NULL)
+ {
+ delete dobj_data;
+ dobj_data = NULL;
+ }
+ if (dlay_data != NULL)
+ {
+ delete dlay_data;
+ dlay_data = NULL;
+ }
+ if (iofile_data != NULL)
+ {
+ delete iofile_data;
+ iofile_data = NULL;
+ }
+ if (iovfd_data != NULL)
+ {
+ delete iovfd_data;
+ iovfd_data = NULL;
+ }
+ if (iocs_data != NULL)
+ {
+ delete iocs_data;
+ iocs_data = NULL;
+ }
+ if (heapcs_data != NULL)
+ {
+ delete heapcs_data;
+ heapcs_data = NULL;
+ }
+
+ // and reset the selections
+ if (all)
+ {
+ sel_obj = NULL;
+ sel_dobj = NULL;
+ lastSelInstr = NULL;
+ lastSelFunc = NULL;
+ // Set selected object <Total> if possible
+ Function * ft = dbeSession->get_Total_Function ();
+ set_sel_obj (ft);
+ }
+ sel_binctx = NULL;
+
+ dspace->reset ();
+ iospace->reset ();
+ heapspace->reset ();
+
+ // loop over MemorySpaces, resetting each one
+ for (long i = 0, sz = VecSize (memspaces); i < sz; i++)
+ {
+ MemorySpace *ms = memspaces->get (i);
+ ms->reset ();
+ }
+
+ // loop over IndexSpaces, resetting cached data
+ indx_data->destroy ();
+ for (long i = 0, sz = VecSize (indxspaces); i < sz; i++)
+ {
+ indx_data->store (i, NULL);
+ sel_idxobj->store (i, NULL);
+ }
+}
+
+Vector<BaseMetric*> *
+DbeView::get_all_reg_metrics ()
+{
+ Vector<BaseMetric*> *mlist = dbeSession->get_all_reg_metrics ();
+ return mlist;
+}
+
+BaseMetric *
+DbeView::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
+{
+ BaseMetric *bm = dbeSession->register_metric_expr (type, cmd, expr_spec);
+ return bm;
+}
+
+Metric *
+DbeView::get_compare_metric (Metric *mtr, int groupNum)
+{
+ if (groupNum == 0 || !mtr->comparable ())
+ return new Metric (*mtr);
+ ExpGroup *gr = dbeSession->expGroups->get (groupNum - 1);
+ char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId);
+ BaseMetric *bm = register_metric_expr (mtr->get_type (), mtr->get_cmd (), buf);
+ Metric *m = new Metric (bm, mtr->get_subtype ());
+ m->set_raw_visbits (mtr->get_visbits ());
+ if (m->legend == NULL)
+ m->legend = dbe_strdup (get_basename (gr->name));
+ return m;
+}
+
+MetricList *
+DbeView::get_metric_ref (MetricType mtype)
+{
+ if (metrics_ref_lists->fetch (MET_COMMON) == NULL)
+ {
+ Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
+ metrics_ref_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS));
+ metrics_ref_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON));
+ metrics_ref_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL));
+ metrics_ref_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL));
+ metrics_ref_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR));
+ metrics_ref_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA));
+ metrics_ref_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX));
+ metrics_ref_lists->store (MET_IO, new MetricList (base_metrics, MET_IO));
+ metrics_ref_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP));
+ delete base_metrics;
+ }
+ return metrics_ref_lists->fetch (mtype);
+}
+
+// logically, the function list must be created first, and it
+// will create the other two;
+MetricList *
+DbeView::get_metric_list (MetricType mtype)
+{
+ if (metrics_lists->fetch (MET_COMMON) == NULL)
+ {
+ Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
+ metrics_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS));
+ metrics_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON));
+ metrics_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL));
+ metrics_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL));
+ metrics_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR));
+ metrics_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA));
+ metrics_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX));
+ metrics_lists->store (MET_IO, new MetricList (base_metrics, MET_IO));
+ metrics_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP));
+ delete base_metrics;
+
+ // set the defaults
+ if (settings->str_dmetrics == NULL)
+ settings->str_dmetrics = strdup (Command::DEFAULT_METRICS);
+ char *status = setMetrics (settings->str_dmetrics, true);
+ if (status != NULL)
+ {
+ fprintf (stderr, "XXX setMetrics(\"%s\") failed: %s\n", settings->str_dmetrics, status);
+ abort ();
+ }
+
+ // set the default sort
+ setSort (settings->str_dsort, MET_NORMAL, true);
+ }
+ return metrics_lists->fetch (mtype);
+}
+
+MetricList *
+DbeView::get_metric_list (int dsptype, int subtype)
+{
+ MetricList *mlist;
+ switch (dsptype)
+ {
+ case DSP_DISASM:
+ case DSP_SOURCE:
+ case DSP_SOURCE_DISASM:
+ mlist = get_metric_list (MET_COMMON);
+ mlist = new MetricList (mlist);
+ if (subtype != 0)
+ {
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get (i);
+ if (m->comparable ())
+ {
+ Metric *m1 = get_compare_metric (m, subtype);
+ mlist->put (i, m1);
+ delete m;
+ }
+ }
+ }
+ break;
+ default:
+ mlist = get_metric_list (MET_NORMAL);
+ mlist = new MetricList (mlist);
+ break;
+ }
+ return mlist;
+}
+
+void
+DbeView::reset_metrics ()
+{
+ for (int i = 0, sz = metrics_lists->size (); i < sz; i++)
+ {
+ delete metrics_lists->fetch (i);
+ metrics_lists->store (i, NULL);
+ }
+ for (int i = 0, sz = metrics_ref_lists->size (); i < sz; i++)
+ {
+ delete metrics_ref_lists->fetch (i);
+ metrics_ref_lists->store (i, NULL);
+ }
+}
+
+bool
+DbeView::comparingExperiments ()
+{
+ if (dbeSession->expGroups->size () <= 1)
+ return false;
+ return 0 != (settings->get_compare_mode () & (CMP_DELTA | CMP_ENABLE | CMP_RATIO));
+}
+
+void
+DbeView::set_compare_mode (int mode)
+{
+ if (mode == get_compare_mode ())
+ return;
+ settings->set_compare_mode (mode);
+ if (comparingExperiments ())
+ {
+ Vector<BaseMetric*> *bm_list = dbeSession->get_base_reg_metrics ();
+ for (int i = 0, sz = bm_list->size (); i < sz; i++)
+ {
+ BaseMetric *m = bm_list->fetch (i);
+ if (m->get_expr_spec () || !m->comparable ())
+ continue;
+ for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (i1);
+ char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId);
+ register_metric_expr (m->get_type (), m->get_cmd (), buf);
+ }
+ }
+ }
+ MetricList *mlist = get_metric_list (MET_NORMAL);
+ MetricList *gmlist = get_metric_list (MET_CALL);
+ MetricList *dmlist = get_metric_list (MET_DATA);
+ MetricList *imlist = get_metric_list (MET_INDX);
+ if (comparingExperiments ())
+ {
+ add_compare_metrics (mlist);
+ add_compare_metrics (gmlist);
+ add_compare_metrics (dmlist);
+ add_compare_metrics (imlist);
+ }
+ else
+ {
+ remove_compare_metrics (mlist);
+ remove_compare_metrics (gmlist);
+ remove_compare_metrics (dmlist);
+ remove_compare_metrics (imlist);
+ }
+}
+
+void
+DbeView::ifreq (FILE *outfile)
+{
+ if (!dbeSession->is_ifreq_available ())
+ {
+ fprintf (outfile, GTXT ("No instruction frequency data available\n"));
+ return;
+ }
+ for (int index = 0; index < filters->size (); index++)
+ {
+ Experiment *exp = dbeSession->get_exp (index);
+ if (exp->broken || !get_exp_enable (index) || !exp->ifreqavail)
+ continue;
+
+ // this experiment has the data; print it
+ fprintf (outfile,
+ GTXT ("Instruction frequency data from experiment %s\n\n"),
+ exp->get_expt_name ());
+ fprintf (outfile, NTXT ("%s"), pr_mesgs (exp->fetch_ifreq (), "", ""));
+ }
+}
+
+// When adding multiple sub-experiments of an experiment, it is
+// not necessary to do the following every-time. It is sufficient to call reset_metrics()
+// and call get_metric_ref() and get_metric_list() in the end after all the sub-experiments
+// have been added
+void
+DbeView::add_experiment_epilogue ()
+{
+ bool flag_LIBEX_HIDE = false;
+ bool flag_ShowHideChanged = false;
+ Vector<LoadObject*> *lobjs = dbeSession->get_LoadObjects ();
+ for (long i = lo_expands->size (), sz = lobjs ? lobjs->size () : 0; i < sz; i++)
+ {
+ flag_ShowHideChanged = true;
+ LoadObject *lo = lobjs->get (i);
+ enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ());
+ if (flag == LIBEX_HIDE)
+ flag_LIBEX_HIDE = true;
+ lo_expands->store (lo->seg_idx, flag);
+ }
+ if (flag_LIBEX_HIDE)
+ {
+ resetShowAll ();
+ dbeSession->set_lib_visibility_used ();
+ }
+ if (flag_ShowHideChanged)
+ {
+ setShowHideChanged (); // this is necessary if called from er_print
+ purge_events ();
+ reset_data (true);
+ }
+ reset_metrics ();
+ (void) get_metric_ref (MET_NORMAL);
+ (void) get_metric_ref (MET_CALL);
+ (void) get_metric_ref (MET_CALL_AGR);
+ (void) get_metric_ref (MET_DATA);
+ (void) get_metric_ref (MET_INDX);
+ (void) get_metric_ref (MET_IO);
+ (void) get_metric_ref (MET_HEAP);
+ (void) get_metric_list (MET_NORMAL);
+ (void) get_metric_list (MET_CALL);
+ (void) get_metric_list (MET_CALL_AGR);
+ (void) get_metric_list (MET_DATA);
+ (void) get_metric_list (MET_INDX);
+ (void) get_metric_list (MET_IO);
+ (void) get_metric_list (MET_HEAP);
+}
+
+// When adding multiple sub-experiments of an experiment, avoid invoking the steps in
+// add_experiment_epilogue() every time and instead call it separately in the end
+// after all sub-experiments have been added
+void
+DbeView::add_subexperiment (int index, bool enabled)
+{
+ // phaseIdx doesn't change, PathTree can handle adding
+ // new experiments without reset
+
+ // Set up the FilterSet for the experiments
+ Experiment *exp = dbeSession->get_exp (index);
+ FilterSet *filterset = new FilterSet (this, exp);
+ filterset->set_enabled (enabled);
+ filters->store (index, filterset);
+
+ assert (index == dataViews->size ());
+ Vector<DataView*> *expDataViewList = new Vector<DataView*>;
+ for (int data_id = 0; data_id < DATA_LAST; ++data_id)
+ expDataViewList->append (NULL); //experiment data_id's are not known yet
+ dataViews->store (index, expDataViewList);
+}
+
+void
+DbeView::add_experiment (int index, bool enabled)
+{
+ // phaseIdx doesn't change, PathTree can handle adding
+ // new experiments without reset
+
+ // delete any cached data
+ reset_data (true);
+
+ // Set up the FilterSet for the experiments
+ Experiment *exp = dbeSession->get_exp (index);
+ FilterSet *filterset = new FilterSet (this, exp);
+ filterset->set_enabled (enabled);
+ filters->store (index, filterset);
+
+ assert (index == dataViews->size ());
+ Vector<DataView*> *expDataViewList = new Vector<DataView*>;
+ for (int data_id = 0; data_id < DATA_LAST; ++data_id)
+ expDataViewList->append (NULL); //experiment data_id's are not known yet
+ dataViews->store (index, expDataViewList);
+
+ reset_metrics ();
+ (void) get_metric_ref (MET_NORMAL);
+ (void) get_metric_ref (MET_CALL);
+ (void) get_metric_ref (MET_CALL_AGR);
+ (void) get_metric_ref (MET_DATA);
+ (void) get_metric_ref (MET_INDX);
+ (void) get_metric_ref (MET_IO);
+ (void) get_metric_ref (MET_HEAP);
+ (void) get_metric_list (MET_NORMAL);
+ (void) get_metric_list (MET_CALL);
+ (void) get_metric_list (MET_CALL_AGR);
+ (void) get_metric_list (MET_DATA);
+ (void) get_metric_list (MET_INDX);
+ (void) get_metric_list (MET_IO);
+ (void) get_metric_list (MET_HEAP);
+}
+
+void
+DbeView::drop_experiment (int index)
+{
+ phaseIdx++;
+ filters->remove (index);
+
+ // reset any cached data
+ reset_data (true);
+
+ Vector<DataView*> *expDataViewList = dataViews->remove (index);
+ if (expDataViewList)
+ {
+ expDataViewList->destroy ();
+ delete expDataViewList;
+ }
+}
+
+bool
+DbeView::get_exp_enable (int n)
+{
+ return filters ? filters->fetch (n)->get_enabled () : true;
+}
+
+void
+DbeView::set_exp_enable (int n, bool e)
+{
+ FilterSet *fs = filters->fetch (n);
+ if (fs->get_enabled () != e)
+ {
+ fs->set_enabled (e);
+ purge_events (n);
+ phaseIdx++;
+ }
+}
+
+void
+DbeView::reset_metric_list (MetricList *mlist, int cmp_mode)
+{
+ MetricType mtype = mlist->get_type ();
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ case MET_COMMON:
+ delete metrics_lists->fetch (MET_COMMON);
+ metrics_lists->store (MET_COMMON, new MetricList (mlist));
+ remove_compare_metrics (metrics_lists->fetch (MET_COMMON));
+ break;
+ // ignoring the following cases (why?)
+ case MET_SRCDIS:
+ case MET_CALL:
+ case MET_DATA:
+ case MET_INDX:
+ case MET_CALL_AGR:
+ case MET_IO:
+ case MET_HEAP:
+ break;
+ }
+
+ if (cmp_mode != -1)
+ {
+ settings->set_compare_mode (cmp_mode);
+ if (comparingExperiments ())
+ add_compare_metrics (mlist);
+ }
+
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ delete metrics_lists->fetch (mtype);
+ metrics_lists->store (mtype, mlist);
+ // fall through to next case
+ case MET_COMMON:
+ metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist);
+ metrics_lists->fetch (MET_CALL)->set_metrics (mlist);
+ metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist);
+ remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR));
+ metrics_lists->fetch (MET_DATA)->set_metrics (mlist);
+ metrics_lists->fetch (MET_INDX)->set_metrics (mlist);
+ metrics_lists->fetch (MET_IO)->set_metrics (mlist);
+ metrics_lists->fetch (MET_HEAP)->set_metrics (mlist);
+ break;
+ case MET_CALL_AGR:
+ delete metrics_lists->fetch (MET_CALL_AGR);
+ metrics_lists->store (MET_CALL_AGR, mlist);
+ remove_compare_metrics (mlist);
+ break;
+ case MET_SRCDIS:
+ case MET_CALL:
+ case MET_DATA:
+ case MET_INDX:
+ case MET_IO:
+ case MET_HEAP:
+ delete metrics_lists->fetch (mtype);
+ metrics_lists->store (mtype, mlist);
+ break;
+ default:
+ abort ();
+ }
+ reset_data (false);
+}
+
+void
+DbeView::add_compare_metrics (MetricList *mlist)
+{
+ if (mlist == NULL || !comparingExperiments ())
+ return;
+ int sort_ref_index = mlist->get_sort_ref_index ();
+ Vector<Metric*> *items = mlist->get_items ();
+ Vector<Metric*> *newItems = new Vector<Metric*>();
+ int mode = get_compare_mode ();
+ int cmp_vbits = 0;
+ if ((mode & CMP_DELTA) != 0)
+ cmp_vbits = VAL_DELTA;
+ else if ((mode & CMP_RATIO) != 0)
+ cmp_vbits = VAL_RATIO;
+ for (long i = 0, sz = items->size (); i < sz; i++)
+ {
+ Metric *mtr = items->get (i);
+ if (sort_ref_index == i)
+ mlist->set_sort_ref_index (newItems->size ());
+ int vbits = mtr->get_visbits () & ~(VAL_DELTA | VAL_RATIO);
+ mtr->set_raw_visbits (vbits);
+ if (!mtr->comparable ())
+ {
+ newItems->append (mtr);
+ continue;
+ }
+ if (mtr->get_expr_spec ())
+ {
+ if (strcmp (mtr->get_expr_spec (), NTXT ("EXPGRID==1")) != 0)
+ {
+ if ((cmp_vbits & VAL_RATIO) != 0)
+ // for ratios, make sure VAL_TIMEVAL is off and VAL_VALUE is on
+ mtr->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL);
+ else
+ {
+ int ind = mlist->get_listorder (mtr->get_cmd (), mtr->get_subtype (), NTXT ("EXPGRID==1"));
+ if (ind >= 0)
+ // take VAL_VALUE and VAL_TIMEVAL from base experiment
+ mtr->set_raw_visbits (cmp_vbits
+ | (vbits & ~(VAL_VALUE | VAL_TIMEVAL))
+ | (mlist->get (ind)->get_visbits ()
+ & (VAL_VALUE | VAL_TIMEVAL)));
+ else
+ mtr->set_raw_visbits (cmp_vbits | vbits);
+ }
+ }
+ newItems->append (mtr);
+ continue;
+ }
+ for (long i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+ {
+ Metric *m = get_compare_metric (mtr, i1 + 1);
+ switch (m->get_vtype ())
+ {
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ m->set_raw_visbits (vbits);
+ break;
+ default:
+ if (i1 == 0)
+ m->set_raw_visbits (vbits);
+ else if (cmp_vbits == VAL_RATIO
+ && ((vbits & (VAL_VALUE | VAL_TIMEVAL))
+ == (VAL_VALUE | VAL_TIMEVAL)))
+ // make ratios for VAL_VALUE only
+ m->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL);
+ else
+ m->set_raw_visbits (vbits | cmp_vbits);
+ break;
+ }
+ newItems->append (m);
+ }
+ }
+ items->reset ();
+ items->addAll (newItems);
+ delete newItems;
+ phaseIdx++;
+ reset_data (false);
+}
+
+MetricList *
+DbeView::get_compare_mlist (MetricList *met_list, int grInd)
+{
+ MetricList *mlist = new MetricList (met_list->get_type ());
+ mlist->set_sort_ref_index (met_list->get_sort_ref_index ());
+ mlist->set_sort_rev (met_list->get_sort_rev ());
+
+ Vector<Metric*> *items_old = met_list->get_items ();
+ for (int i = 0, sz = items_old->size (); i < sz; i++)
+ {
+ Metric *m = get_compare_metric (items_old->get (i), grInd + 1);
+ mlist->append (m);
+ }
+ return mlist;
+}
+
+void
+DbeView::remove_compare_metrics (MetricList *mlist)
+{
+ Vector<Metric*> *items = mlist->get_items ();
+ Vector<Metric*> *items_old = items->copy ();
+ items->reset ();
+ int sort_index = mlist->get_sort_ref_index ();
+ mlist->set_sort_ref_index (0);
+ for (int i = 0, sz = items_old->size (); i < sz; i++)
+ {
+ Metric *m = items_old->fetch (i);
+ if (m->get_expr_spec () == NULL)
+ {
+ // this is a 'non-compare' metric; add it
+ items->append (m);
+ if (sort_index == i)
+ mlist->set_sort_ref_index (items->size () - 1);
+ continue;
+ }
+ // is the 'non-compare' version of the metric already in the list?
+ int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype ());
+ if (ind == -1)
+ {
+ // not in the list; add it
+ BaseMetric *bm = dbeSession->find_metric (m->get_type (), m->get_cmd (), NULL);
+ Metric *new_met = new Metric (bm, m->get_subtype ());
+ new_met->set_raw_visbits (m->get_visbits () & ~(CMP_DELTA | CMP_RATIO));
+ items->append (new_met);
+ if (sort_index == i)
+ mlist->set_sort_ref_index (items->size () - 1);
+ }
+ delete m;
+ }
+ delete items_old;
+ reset_data (false);
+}
+
+// setMetrics -- set the metric list according to specification
+// The previous sort is preserved, if possible
+// Otherwise, the default sort setting is used
+// Returns NULL if OK, or an error string if not
+//YXXX only MET_NORMAL appears to be used... code could be simplified
+char *
+DbeView::setMetrics (char *mspec, bool fromRcFile)
+{
+ char *ret;
+ MetricType mtype = MET_NORMAL;
+ // note that setting the default is done here, while all else is in MetricList
+ if (mspec == NULL) abort ();
+ if (strcasecmp (mspec, Command::DEFAULT_CMD) == 0)
+ {
+ mspec = settings->get_default_metrics ();
+ fromRcFile = true;
+ }
+ MetricList *mlist = get_metric_list (mtype);
+ mlist = new MetricList (mlist);
+ ret = mlist->set_metrics (mspec, fromRcFile, derived_metrics);
+ if (ret == NULL)
+ {
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ case MET_COMMON:
+ delete metrics_lists->fetch (MET_COMMON);
+ metrics_lists->store (MET_COMMON, new MetricList (mlist));
+ break;
+ // ignoring the following cases (why?)
+ case MET_SRCDIS:
+ case MET_CALL:
+ case MET_DATA:
+ case MET_INDX:
+ case MET_CALL_AGR:
+ case MET_IO:
+ case MET_HEAP:
+ break;
+ }
+ add_compare_metrics (mlist);
+
+ //YXXX looks like cut/paste code here, see reset_metric_list()
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ delete metrics_lists->fetch (mtype);
+ metrics_lists->store (mtype, mlist);
+ //YXXX is lack of break intentional? If so, add comment...
+ case MET_COMMON:
+ metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist);
+ metrics_lists->fetch (MET_CALL)->set_metrics (mlist);
+ metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist);
+ remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR));
+ metrics_lists->fetch (MET_DATA)->set_metrics (mlist);
+ metrics_lists->fetch (MET_INDX)->set_metrics (mlist);
+ metrics_lists->fetch (MET_IO)->set_metrics (mlist);
+ metrics_lists->fetch (MET_HEAP)->set_metrics (mlist);
+ break;
+ case MET_CALL_AGR:
+ delete metrics_lists->fetch (MET_CALL_AGR);
+ metrics_lists->store (MET_CALL_AGR, mlist);
+ remove_compare_metrics (mlist);
+ break;
+ case MET_SRCDIS:
+ case MET_CALL:
+ case MET_DATA:
+ case MET_INDX:
+ case MET_IO:
+ case MET_HEAP:
+ delete metrics_lists->fetch (mtype);
+ metrics_lists->store (mtype, mlist);
+ break;
+ default:
+ abort ();
+ }
+ reset_data (false);
+ }
+ else
+ delete mlist;
+ return ret;
+}
+
+
+// Set Sort by name (er_print)
+char *
+DbeView::setSort (char * sort_list, MetricType mtype, bool fromRcFile)
+{
+ MetricList *mlist = NULL;
+
+ // note that setting the default is done here, while all else is in MetricList
+ if ((sort_list == NULL) || (strcmp (sort_list, Command::DEFAULT_CMD) == 0))
+ {
+ if (settings->str_dsort == NULL)
+ settings->str_dsort = strdup (Command::DEFAULT_METRICS);
+ sort_list = settings->get_default_sort ();
+ }
+ mlist = get_metric_list (mtype);
+
+ if (mlist == NULL)
+ abort ();
+
+ // set the new sort
+ char *ret = mlist->set_sort (sort_list, fromRcFile);
+ if (ret != NULL)
+ return ret;
+
+ // now resort all cached data
+ resortData (mtype);
+ return NULL;
+}
+
+// Set sort from the visible index (Analyzer)
+void
+DbeView::setSort (int visindex, MetricType mtype, bool reverse)
+{
+ MetricList *mlist = get_metric_list (mtype);
+ Vector<Metric*> *items = mlist->get_items ();
+ if (visindex >= items->size ())
+ return;
+ mlist->set_sort (visindex, reverse);
+ resortData (mtype);
+ if (mtype == MET_NORMAL)
+ {
+ int idx_cc = -1;
+ MetricList *mlist_cc = get_metric_list (MET_CALL);
+ Vector<Metric*> *items_cc = mlist_cc->get_items ();
+ for (int i = 0; i < items_cc->size (); i++)
+ {
+ char * name_cc = items_cc->fetch (i)->get_username ();
+ char * name_normal = items->fetch (visindex)->get_username ();
+ if (0 == strncmp (name_cc, name_normal, strlen (name_cc)))
+ {
+ idx_cc = i;
+ break;
+ }
+ }
+ if (idx_cc != -1)
+ {
+ mlist_cc->set_sort (idx_cc, reverse);
+ resortData (MET_CALL);
+ // Change a sort metric for MET_CALL_AGR
+ Metric *m = items_cc->fetch (idx_cc);
+ MetricList *cList = get_metric_list (MET_CALL_AGR);
+ Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ());
+ if (m1)
+ cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse);
+ }
+ }
+ if (mtype == MET_CALL)
+ {
+ int idx_norm = -1;
+ MetricList *mlist_norm = get_metric_list (MET_NORMAL);
+ Vector<Metric*> *items_norm = mlist_norm->get_items ();
+ for (int i = 0; i < items_norm->size (); i++)
+ {
+ char * name_norm = items_norm->fetch (i)->get_username ();
+ char * name_cc = items->fetch (visindex)->get_username ();
+ if (mlist_norm->get_sort_ref_index () == i
+ && 0 == strncmp (name_norm, name_cc, strlen (name_norm)))
+ {
+ idx_norm = i;
+ break;
+ }
+ }
+ if (idx_norm == -1)
+ {
+ for (int i = 0; i < items_norm->size (); i++)
+ {
+ char * name_norm = items_norm->fetch (i)->get_username ();
+ char * name_cc = items->fetch (visindex)->get_username ();
+ if (0 == strncmp (name_norm, name_cc, strlen (name_norm)))
+ {
+ idx_norm = i;
+ break;
+ }
+ }
+ }
+ if (idx_norm != -1)
+ {
+ mlist_norm->set_sort (idx_norm, reverse);
+ resortData (MET_NORMAL);
+ }
+ // Change a sort metric for MET_CALL_AGR
+ Metric *m = items->fetch (visindex);
+ MetricList *cList = get_metric_list (MET_CALL_AGR);
+ Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ());
+ if (m1)
+ cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse);
+ }
+}
+
+void
+DbeView::resortData (MetricType mtype)
+{
+ int idx;
+ Hist_data *data;
+
+ MetricList *mlist = get_metric_list (mtype);
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ if (func_data != NULL)
+ func_data->resort (mlist);
+ if (line_data != NULL)
+ line_data->resort (mlist);
+ if (pc_data != NULL)
+ pc_data->resort (mlist);
+ break;
+ case MET_CALL:
+ case MET_CALL_AGR:
+ if (fitem_data != NULL)
+ fitem_data->resort (mlist);
+ if (callers != NULL)
+ callers->resort (mlist);
+ if (callees != NULL)
+ callees->resort (mlist);
+ break;
+ case MET_DATA:
+ if (dobj_data != NULL)
+ dobj_data->resort (mlist);
+ if (dlay_data != NULL)
+ {
+ delete dlay_data;
+ dlay_data = NULL;
+ }
+ break;
+ case MET_INDX:
+ Vec_loop (Hist_data*, indx_data, idx, data)
+ {
+ if (data)
+ data->resort (mlist);
+ }
+ break;
+ case MET_IO:
+ if (iofile_data != NULL)
+ iofile_data->resort (mlist);
+ if (iovfd_data != NULL)
+ iovfd_data->resort (mlist);
+ if (iocs_data != NULL)
+ iocs_data->resort (mlist);
+ break;
+ case MET_HEAP:
+ if (heapcs_data != NULL)
+ heapcs_data->resort (mlist);
+ break;
+ case MET_COMMON:
+ case MET_SRCDIS:
+ break;
+ }
+}
+
+// Get the sort metric name
+char *
+DbeView::getSort (MetricType mtype)
+{
+ MetricList *mlist = get_metric_list (mtype);
+ return mlist->get_sort_name ();
+}
+
+// Get the sort command (to use for resetting)
+char *
+DbeView::getSortCmd (MetricType mtype)
+{
+ MetricList *mlist = get_metric_list (mtype);
+ return mlist->get_sort_cmd ();
+}
+
+int
+DbeView::get_sel_ind (Histable *selObj, int type, int subtype)
+{
+ Hist_data *data;
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ data = func_data;
+ break;
+ case DSP_LINE:
+ data = line_data;
+ break;
+ case DSP_PC:
+ data = pc_data;
+ break;
+ case DSP_SOURCE:
+ case DSP_SOURCE_V2:
+ data = src_data;
+ break;
+ case DSP_DISASM:
+ case DSP_DISASM_V2:
+ data = dis_data;
+ break;
+ case DSP_DLAYOUT:
+ data = dlay_data;
+ break;
+ case DSP_DATAOBJ:
+ data = dobj_data;
+ break;
+ case DSP_IOACTIVITY:
+ data = iofile_data;
+ break;
+ case DSP_IOVFD:
+ data = iovfd_data;
+ break;
+ case DSP_IOCALLSTACK:
+ data = iocs_data;
+ break;
+ case DSP_HEAPCALLSTACK:
+ data = heapcs_data;
+ break;
+ case DSP_MEMOBJ:
+ case DSP_INDXOBJ:
+ data = get_indxobj_data (subtype);
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+ if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+ return -1;
+ Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
+ for (int i = 0, sz = hi_data->size (); i < sz; i++)
+ {
+ Hist_data::HistItem *hi = hi_data->fetch (i);
+ if (hi->obj == selObj)
+ return i;
+ }
+ return -1;
+}
+
+MetricList *
+DbeView::get_metric_list (MetricType mtype, bool compare, int gr_num)
+{
+ MetricList *mlist;
+ switch (mtype)
+ {
+ case MET_COMMON:// comparison mode, src & disasm views
+ if (gr_num == 0)
+ {// signifies same src file (or load obj) used by all groups
+ // show compare metrics in columns (not in separate source panels)
+ mlist = get_metric_list (MET_NORMAL);
+ break;
+ }
+ // once source panel per group; get metrics for this group
+ mlist = get_metric_list (mtype);
+ if (compare)
+ {
+ mlist = get_compare_mlist (mlist, gr_num - 1);
+ int mode = get_compare_mode ();
+ if ((mode & (CMP_DELTA | CMP_RATIO)) != 0)
+ {
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get (i);
+ char *expr_spec = m->get_expr_spec ();
+ if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0))
+ {
+ int vbits = m->get_visbits () & ~(VAL_DELTA | VAL_RATIO);
+ if ((mode & CMP_RATIO) != 0)
+ vbits |= VAL_RATIO;
+ else if ((mode & CMP_DELTA) != 0)
+ vbits |= VAL_DELTA;
+ m->set_raw_visbits (vbits);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ mlist = get_metric_list (mtype);
+ break;
+ }
+ return mlist;
+}
+
+Hist_data *
+DbeView::get_data (MetricList *mlist, Histable *selObj, int type, int subtype)
+{
+ Hist_data *data;
+ switch (type)
+ {
+ case DSP_FUNCTION:
+ delete func_data;
+ mlist = new MetricList (mlist);
+ func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL);
+ return func_data;
+ case DSP_LINE:
+ delete line_data;
+ mlist = new MetricList (mlist);
+ line_data = get_hist_data (mlist, Histable::LINE, subtype, Hist_data::ALL);
+ return line_data;
+ case DSP_PC:
+ delete pc_data;
+ mlist = new MetricList (mlist);
+ pc_data = get_hist_data (mlist, Histable::INSTR, subtype, Hist_data::ALL);
+ return pc_data;
+ case DSP_DATAOBJ:
+ delete dobj_data;
+ dobj_data = get_hist_data (mlist, Histable::DOBJECT, subtype,
+ Hist_data::ALL);
+ break;
+ case DSP_MEMOBJ:
+ return get_hist_data (mlist, Histable::MEMOBJ, subtype, Hist_data::ALL);
+ case DSP_INDXOBJ:
+ data = get_hist_data (mlist, Histable::INDEXOBJ, subtype, Hist_data::ALL);
+ indx_data->store (subtype, data);
+ return data;
+ case DSP_DLAYOUT:
+ delete dlay_data;
+ marks->reset ();
+ data = get_hist_data (mlist, Histable::DOBJECT, subtype,
+ Hist_data::LAYOUT);
+ // .. provides metric data for layout
+ dlay_data = get_data_space ()->get_layout_data (data, marks,
+ get_thresh_dis ());
+ return dlay_data;
+ case DSP_CALLER:
+ delete callers;
+ callers = get_hist_data (mlist, Histable::FUNCTION, subtype,
+ Hist_data::CALLERS, selObj);
+ return callers;
+ case DSP_CALLEE:
+ delete callees;
+ callees = get_hist_data (mlist, Histable::FUNCTION, subtype,
+ Hist_data::CALLEES, selObj);
+ return callees;
+ case DSP_SELF:
+ // Center Function item
+ delete fitem_data;
+ fitem_data = get_hist_data (mlist, Histable::FUNCTION, subtype,
+ Hist_data::SELF, selObj);
+ return fitem_data;
+ case DSP_SOURCE_V2:
+ case DSP_DISASM_V2:
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ {
+ // Source or disassembly
+ if (selObj == NULL)
+ {
+ error_msg = status_str (DBEVIEW_NO_SEL_OBJ);
+ return NULL;
+ }
+ Function *func = (Function *) selObj->convertto (Histable::FUNCTION);
+ if (func == NULL)
+ {
+ error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+ return NULL;
+ }
+ if (func->flags & FUNC_FLAG_SIMULATED)
+ {
+ error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+ return NULL;
+ }
+ if (func->get_name () == NULL)
+ {
+ error_msg = dbe_strdup (GTXT ("Source location not recorded in experiment"));
+ return NULL;
+ }
+ Module *module = func->module;
+ if (module == NULL || module->get_name () == NULL)
+ {
+ error_msg = dbe_strdup (GTXT ("Object name not recorded in experiment"));
+ return NULL;
+ }
+ marks->reset ();
+ SourceFile *srcContext = (SourceFile *) selObj->convertto (Histable::SOURCEFILE);
+ sel_binctx = func;
+
+ if (func_data == NULL)
+ func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL);
+
+ // for source and disassembly the name needs to be invisible,
+ // but that's handled in the module code
+ if (type == DSP_SOURCE || type == DSP_SOURCE_V2)
+ {
+ marks2dsrc->reset ();
+ marks2dsrc_inc->reset ();
+ delete src_data;
+ data = src_data = module->get_data (this, mlist, Histable::LINE,
+ func_data->get_totals ()->value, srcContext, func,
+ marks, get_thresh_src (), get_src_compcom (),
+ get_src_visible (), get_hex_visible (),
+ false, false, marks2dsrc, marks2dsrc_inc);
+ }
+ else
+ { /* type == DSP_DISASM */
+ marks2ddis->reset ();
+ marks2ddis_inc->reset ();
+ delete dis_data;
+ data = dis_data = module->get_data (this, mlist, Histable::INSTR,
+ func_data->get_totals ()->value, srcContext, func,
+ marks, get_thresh_dis (), get_dis_compcom (),
+ get_src_visible (), get_hex_visible (),
+ get_func_scope (), false, marks2ddis,
+ marks2ddis_inc);
+ }
+ return data;
+ }
+ default:
+ abort ();
+ }
+ return NULL;
+}
+
+Histable *
+DbeView::get_compare_obj (Histable *obj)
+{
+ char *nm;
+ switch (obj->get_type ())
+ {
+ case Histable::LINE:
+ nm = obj->get_name ();
+ if (nm == NULL)
+ break;
+ if (dbeSession->comp_dbelines == NULL)
+ dbeSession->comp_dbelines = new HashMap<char*, DbeLine*>;
+ return dbeSession->comp_dbelines->get (nm, (DbeLine*) obj);
+ case Histable::SOURCEFILE:
+ nm = obj->get_name ();
+ if (nm == NULL)
+ break;
+ nm = get_basename (nm);
+ if (dbeSession->comp_sources == NULL)
+ dbeSession->comp_sources = new HashMap<char*, SourceFile*>;
+ return dbeSession->comp_sources->get (nm, (SourceFile*) obj);
+ default:
+ return obj->get_compare_obj ();
+ }
+ return obj;
+}
+
+//
+// get_hist_data() creates a new Hist_data object;
+// it's caller's responsibility to delete it.
+Hist_data *
+DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type,
+ int subtype, Hist_data::Mode mode, Histable *obj,
+ Histable *context, Vector<Histable*> *sel_objs,
+ PathTree::PtreeComputeOption flag)
+{
+ Vector<Histable*> *objs = NULL;
+ if (obj != NULL)
+ {
+ objs = new Vector<Histable*>();
+ objs->append (obj);
+ }
+ Hist_data *res = get_hist_data (mlist_orig, type, subtype, mode, objs, context, sel_objs, flag);
+ delete objs;
+ return res;
+}
+
+Hist_data *
+DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type,
+ int subtype, Hist_data::Mode mode,
+ Vector<Histable*> *objs,
+ Histable *context, Vector<Histable*> *sel_objs,
+ PathTree::PtreeComputeOption flag)
+{
+ MetricList *mlist = new MetricList (mlist_orig);
+ /*
+ * mlist differs from mlist_orig in two ways:
+ * - extra metrics have been added as needed to compute derived metrics
+ * - extra metrics have been added as needed to compute time for HWC (time converted) metrics
+ * (We don't drop those extra metrics but we don't display they to user.)
+ * - visibility bits have been added for compare mode (e.g., VAL_DELTA or VAL_RATIO)
+ * (We want to preserve those visbits.)
+ */
+ // loop over mlist to add missing dependencies for derived metrics
+ for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get_items ()->fetch (i);
+ char *expr_spec = m->get_expr_spec ();
+ if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0))
+ {
+ int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype (), NTXT ("EXPGRID==1"));
+ if (ind < 0)
+ {
+ BaseMetric *bm1 = dbeSession->find_metric (m->get_type (), m->get_cmd (), NTXT ("EXPGRID==1"));
+ Metric *m1 = new Metric (bm1, m->get_subtype ());
+ m1->set_dmetrics_visbits (VAL_VALUE);
+ mlist->append (m1);
+ }
+ }
+ }
+
+ for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get_items ()->fetch (i);
+ if (m->get_type () == BaseMetric::DERIVED)
+ {
+ Definition *def = m->get_definition ();
+ Vector<BaseMetric*> *dependencies = def->get_dependencies ();
+ long *map = def->get_map ();
+ for (long i1 = 0, sz1 = dependencies ? dependencies->size () : 0; i1 < sz1; i1++)
+ {
+ BaseMetric *bm = dependencies->fetch (i1);
+ int ind = mlist->get_listorder (bm->get_cmd (), m->get_subtype (), m->get_expr_spec ());
+ if (ind < 0)
+ {
+ BaseMetric *bm1 = dbeSession->find_metric (bm->get_type (), bm->get_cmd (), m->get_expr_spec ());
+ assert (bm1 != NULL);
+ Metric *m1 = new Metric (bm1, m->get_subtype ());
+ m1->set_dmetrics_visbits (VAL_VALUE);
+ ind = mlist->size ();
+ mlist->append (m1);
+ }
+ map[i1] = ind;
+ }
+ }
+ else if (m->get_type () == BaseMetric::HWCNTR)
+ {
+ if (m->is_tvisible () && m->get_dependent_bm ())
+ {
+ int ii = mlist->get_listorder (m->get_dependent_bm ()->get_cmd (),
+ m->get_subtype (), m->get_expr_spec ());
+ if (ii < 0)
+ {
+ BaseMetric *bm1 = dbeSession->find_metric (m->get_type (),
+ m->get_dependent_bm ()->get_cmd (),
+ m->get_expr_spec ());
+ assert (bm1 != NULL);
+ Metric *m1 = new Metric (bm1, m->get_subtype ());
+ m1->set_dmetrics_visbits ((m->get_visbits ()
+ & ~VAL_VALUE) | VAL_TIMEVAL);
+ mlist->append (m1);
+ }
+ }
+ }
+ }
+
+ // compute Hist_data
+ Hist_data *data;
+ switch (type)
+ {
+ case Histable::INSTR:
+ case Histable::LINE:
+ data = ptree->compute_metrics (mlist, type, mode, objs, context, sel_objs);
+ break;
+ case Histable::FUNCTION:
+ case Histable::MODULE:
+ case Histable::LOADOBJECT:
+ data = ptree->compute_metrics (mlist, type, mode, objs, NULL,
+ sel_objs, flag);
+ break;
+ case Histable::DOBJECT:
+ data = dspace->compute_metrics (mlist, type, mode,
+ objs ? objs->fetch (0) : NULL);
+ break;
+ case Histable::MEMOBJ:
+ case Histable::INDEXOBJ:
+ data = indxspaces->get (subtype)->compute_metrics (mlist, type, mode,
+ objs, NULL);
+ break;
+ case Histable::IOACTFILE:
+ if (objs == NULL)
+ {
+ data = iofile_data = iospace->compute_metrics (mlist, type, mode,
+ NULL);
+ break;
+ }
+ else
+ {
+ data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
+ break;
+ }
+ case Histable::IOACTVFD:
+ if (objs == NULL)
+ data = iovfd_data = iospace->compute_metrics (mlist, type, mode, NULL);
+ else
+ data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
+ break;
+ case Histable::IOCALLSTACK:
+ if (objs == NULL)
+ data = iocs_data = iospace->compute_metrics (mlist, type, mode, NULL);
+ else
+ data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
+ break;
+ case Histable::HEAPCALLSTACK:
+ if (objs == NULL)
+ data = heapcs_data = heapspace->compute_metrics (mlist, type, mode, NULL);
+ else
+ data = heapspace->compute_metrics (mlist, type, mode, objs->fetch (0));
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+ for (long i = mlist_orig->get_items ()->size (),
+ sz = mlist->get_items ()->size (); i < sz; i++)
+ {
+ Metric *m = mlist->get_items ()->get (i);
+ m->set_dmetrics_visbits (VAL_HIDE_ALL | m->get_visbits ());
+ }
+ if (data)
+ data->nmetrics = mlist_orig->size ();
+ return data;
+}
+
+char *
+DbeView::get_mobj_name (int subtype)
+{
+ MemorySpace *ms = getMemorySpace (subtype);
+ if (ms == NULL)
+ ms = addMemorySpace (subtype);
+ return ms->getMemObjTypeName ();
+}
+
+MemorySpace *
+DbeView::getMemorySpace (int subtype)
+{
+ for (long i = 0, sz = VecSize (memspaces); i < sz; i++)
+ {
+ MemorySpace *ms = memspaces->get (i);
+ if (subtype == ms->getMemObjType ())
+ return ms;
+ }
+ return NULL;
+}
+
+MemorySpace *
+DbeView::addMemorySpace (int subtype)
+{
+ MemorySpace *ms = new MemorySpace (this, subtype);
+ memspaces->append (ms);
+ return ms;
+}
+
+Hist_data *
+DbeView::get_indxobj_data (int subtype)
+{
+ if (subtype < 0 || subtype >= indx_data->size ())
+ return NULL;
+ return indx_data->fetch (subtype);
+}
+
+void
+DbeView::set_indxobj_sel (int subtype, int sel_ind)
+{
+ Hist_data *data = get_indxobj_data (subtype);
+ if (data == NULL)
+ return;
+ if (sel_ind >= 0 && sel_ind < data->size ())
+ {
+ Histable *obj = data->fetch (sel_ind)->obj;
+ sel_idxobj->store (subtype, obj);
+ }
+}
+
+Histable *
+DbeView::get_indxobj_sel (int subtype)
+{
+ return sel_idxobj->fetch (subtype);
+}
+
+void
+DbeView::addIndexSpace (int subtype)
+{
+ PathTree *is = new PathTree (this, subtype);
+ indxspaces->store (subtype, is);
+ indx_data->store (subtype, NULL);
+ sel_idxobj->store (subtype, NULL);
+ settings->indxobj_define (subtype, false);
+}
+
+Histable *
+DbeView::get_sel_obj_io (uint64_t id, Histable::Type type)
+{
+ if (iospace == NULL)
+ return NULL;
+ Histable *obj = NULL;
+ Hist_data *data = NULL;
+ switch (type)
+ {
+ case Histable::IOACTFILE:
+ data = iofile_data;
+ break;
+ case Histable::IOACTVFD:
+ data = iovfd_data;
+ break;
+ case Histable::IOCALLSTACK:
+ data = iocs_data;
+ break;
+ default:
+ break;
+ }
+ if (data == NULL)
+ return NULL;
+
+ Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
+ int size = hi_data->size ();
+ for (int i = 0; i < size; i++)
+ {
+ Hist_data::HistItem *hi = hi_data->fetch (i);
+ if (hi->obj != NULL && (uint64_t) hi->obj->id == id)
+ {
+ obj = hi->obj;
+ break;
+ }
+ }
+ return obj;
+}
+
+Histable *
+DbeView::get_sel_obj_heap (uint64_t id)
+{
+ if (heapspace == NULL || heapcs_data == NULL)
+ return NULL;
+ Histable *obj = NULL;
+ Hist_data *data = heapcs_data;
+ Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
+ int size = hi_data->size ();
+ for (int i = 0; i < size; i++)
+ {
+ Hist_data::HistItem *hi = hi_data->fetch (i);
+ if ((hi->obj != NULL) && ((uint64_t) hi->obj->id) == id)
+ {
+ obj = hi->obj;
+ break;
+ }
+ }
+ return obj;
+}
+
+CStack_data *
+DbeView::get_cstack_data (MetricList *mlist)
+{
+ return ptree->get_cstack_data (mlist);
+}
+
+Stats_data *
+DbeView::get_stats_data (int index)
+{
+ DataView *packets = get_filtered_events (index, DATA_SAMPLE);
+ if (packets == NULL)
+ return NULL;
+ return new Stats_data (packets);
+}
+
+Ovw_data *
+DbeView::get_ovw_data (int index)
+{
+ DataView *packets = get_filtered_events (index, DATA_SAMPLE);
+ Experiment* exp = dbeSession->get_exp (index);
+ hrtime_t starttime = 0;
+ if (exp != NULL)
+ starttime = exp->getStartTime ();
+ if (packets == NULL)
+ return NULL;
+ return new Ovw_data (packets, starttime);
+}
+
+char *
+DbeView::set_filter (const char *filter_spec)
+{
+ if (dbe_strcmp (filter_spec, cur_filter_str) == 0) // Nothing was changed
+ return NULL;
+
+ // if string is NULL, delete the filter
+ if (filter_spec == NULL)
+ {
+ if (cur_filter_str)
+ {
+ free (cur_filter_str);
+ cur_filter_str = NULL;
+ }
+ if (cur_filter_expr)
+ {
+ delete cur_filter_expr;
+ cur_filter_expr = NULL;
+ }
+ noParFilter = false;
+ purge_events ();
+ reset_data (false);
+ return NULL;
+ }
+
+ // process the filter
+ Expression *expr = dbeSession->ql_parse (filter_spec);
+ if (expr == NULL)
+ return dbe_sprintf (GTXT ("Invalid filter specification `%s'\n"), filter_spec);
+
+ if (dbe_strcmp (filter_spec, "1") == 0)
+ noParFilter = false;
+ else if (sel_obj != NULL)
+ if (sel_obj->get_type () == Histable::LINE)
+ if (expr->verifyObjectInExpr (sel_obj))
+ noParFilter = true;
+
+ // valid new filter
+ if (cur_filter_str != NULL)
+ {
+ free (prev_filter_str);
+ prev_filter_str = dbe_strdup (cur_filter_str);
+ }
+ free (cur_filter_str);
+ cur_filter_str = dbe_strdup (filter_spec);
+ delete cur_filter_expr;
+ cur_filter_expr = expr;
+ purge_events ();
+ reset_data (false);
+ return NULL;
+}
+
+FilterExp *
+DbeView::get_FilterExp (Experiment *exp)
+{
+ if (cur_filter_expr == NULL)
+ return NULL;
+ Expression::Context *ctx = new Expression::Context (this, exp);
+ return new FilterExp (cur_filter_expr, ctx, noParFilter);
+}
+
+char *
+DbeView::get_filter ()
+{
+ return dbe_strdup (cur_filter_str);
+}
+
+FilterSet *
+DbeView::get_filter_set (int n)
+{
+ fflush (stderr);
+ if (n >= filters->size ())
+ return NULL;
+ return ( filters->fetch (n));
+}
+
+Vector<FilterNumeric*> *
+DbeView::get_all_filters (int nexp)
+{
+ FilterSet *fs = get_filter_set (nexp);
+ return fs ? fs->get_all_filters () : NULL;
+}
+
+FilterNumeric *
+DbeView::get_FilterNumeric (int nexp, int idx)
+{
+ FilterSet *fs = get_filter_set (nexp);
+ return fs ? fs->get_filter (idx) : NULL;
+}
+
+void
+DbeView::backtrack_filter()
+{
+ if (prev_filter_str != NULL)
+ set_filter(prev_filter_str);
+ else set_filter("1"); // reset
+
+}
+
+void
+DbeView::update_advanced_filter ()
+{
+ char *s = get_advanced_filter ();
+ if (dbe_strcmp (s, cur_filter_str))
+ {
+ phaseIdx++;
+ char *err_msg = set_filter (s);
+ if (err_msg)
+ {
+#ifdef DEBUG
+ fprintf (stderr, NTXT ("ERROR: Advanced Filter: '%s'\n"), err_msg);
+#endif
+ }
+ }
+ free (s);
+}
+
+bool
+DbeView::set_pattern (int n, Vector<char *> *pattern_str, bool *error)
+{
+ Vector<FilterNumeric*> *filts = get_all_filters (n);
+
+ bool ret = false;
+ *error = false;
+ int imax = pattern_str->size ();
+ if (imax > filts->size ())
+ imax = filts->size ();
+ for (int i = 0; i < imax; i++)
+ {
+ FilterNumeric *f = filts->fetch (i);
+ char *s = pattern_str->fetch (i);
+ if (s == NULL)
+ continue;
+ if (f->set_pattern (s, error))
+ ret = true;
+ }
+
+ if (ret || cur_filter_expr)
+ {
+ update_advanced_filter ();
+ filter_active = true;
+ }
+ return ret;
+}
+
+static void
+append_experiments (StringBuilder *sb, int first, int last)
+{
+ if (first == -1)
+ return;
+ if (sb->length () != 0)
+ sb->append (NTXT (" || "));
+ sb->append ('(');
+ if (first == last)
+ {
+ sb->append (NTXT ("EXPID=="));
+ sb->append (first);
+ }
+ else
+ {
+ sb->append (NTXT ("EXPID>="));
+ sb->append (first);
+ sb->append (NTXT (" && EXPID<="));
+ sb->append (last);
+ }
+ sb->append (')');
+}
+
+char *
+DbeView::get_advanced_filter ()
+{
+ StringBuilder sb;
+ bool wasFalse = false;
+ int first = -1, last = -1;
+ for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++)
+ {
+ FilterSet *fs = get_filter_set (n);
+ char *s = fs->get_advanced_filter ();
+ if (s)
+ {
+ if (streq (s, NTXT ("1")))
+ {
+ last = n + 1;
+ if (first == -1)
+ first = last;
+ continue;
+ }
+ append_experiments (&sb, first, last);
+ first = -1;
+ if (streq (s, NTXT ("0")))
+ {
+ wasFalse = true;
+ continue;
+ }
+ if (sb.length () != 0)
+ sb.append (NTXT (" || "));
+ sb.append (NTXT ("(EXPID=="));
+ sb.append (n + 1);
+ sb.append (NTXT (" && ("));
+ sb.append (s);
+ free (s);
+ sb.append (NTXT ("))"));
+ }
+ else
+ {
+ last = n + 1;
+ if (first == -1)
+ first = last;
+ }
+ }
+ if (first != 1)
+ {
+ append_experiments (&sb, first, last);
+ first = -1;
+ }
+ if (sb.length () == 0)
+ sb.append (wasFalse ? '0' : '1');
+ else
+ append_experiments (&sb, first, last);
+ return sb.toString ();
+}
+
+bool
+DbeView::set_pattern (int m, char *pattern)
+{
+ bool error = false;
+
+ // Store original setting in case of error
+ int nexps = dbeSession->nexps ();
+ int orig_phaseIdx = phaseIdx;
+ bool *orig_enable = new bool[nexps];
+ char **orig_pattern = new char*[nexps];
+ for (int i = 0; i < nexps; i++)
+ {
+ orig_pattern[i] = get_FilterNumeric (i, m)->get_pattern ();
+ orig_enable[i] = get_exp_enable (i);
+ set_exp_enable (i, false);
+ }
+
+ // Copy the pattern so that we could safely modify it
+ char *buf = dbe_strdup (pattern);
+ FilterNumeric *fexp = NULL;
+ char *pb, *pe;
+ pb = pe = buf;
+ for (bool done = false; !done; pe++)
+ {
+ if (*pe == ':')
+ {
+ // experiment filter;
+ *pe = '\0';
+ fexp = new FilterNumeric (NULL, NULL, NULL);
+ fexp->set_range (1, nexps, nexps);
+ fexp->set_pattern (pb, &error);
+ if (error)
+ break;
+ pb = pe + 1;
+ }
+ else if (*pe == '+' || *pe == '\0')
+ {
+ // entity filter
+ if (*pe == '\0')
+ done = true;
+ else
+ *pe = '\0';
+ for (int i = 0; i < nexps; i++)
+ {
+ if (!fexp || fexp->is_selected (i + 1))
+ {
+ FilterNumeric *f = get_FilterNumeric (i, m);
+ f->set_pattern (pb, &error);
+ if (error)
+ break;
+ set_exp_enable (i, true);
+ }
+ }
+ if (error)
+ break;
+ delete fexp;
+ fexp = NULL;
+ pb = pe + 1;
+ }
+ }
+
+ if (error)
+ {
+ for (int i = 0; i < nexps; i++)
+ {
+ bool err;
+ set_exp_enable (i, orig_enable[i]);
+ FilterNumeric *f = get_FilterNumeric (i, m);
+ f->set_pattern (orig_pattern[i], &err);
+ free (orig_pattern[i]);
+ }
+ phaseIdx = orig_phaseIdx;
+ }
+ else
+ {
+ update_advanced_filter ();
+ filter_active = true;
+ }
+ delete[] orig_enable;
+ delete[] orig_pattern;
+ delete fexp;
+ free (buf);
+ return !error;
+}
+
+void
+DbeView::set_view_mode (VMode newmode)
+{
+ if (newmode != settings->get_view_mode ())
+ {
+
+ // For OpenMP, the expert mode path-tree is already present with the user mode
+ // No need to increase the phaseIdx to trigger recomputation of path-tree
+ // if we toggle between user and expert modes
+ if (!(dbeSession->is_omp_available ()
+ && ((newmode == VMODE_EXPERT
+ && settings->get_view_mode () == VMODE_USER)
+ || (newmode == VMODE_USER
+ && settings->get_view_mode () == VMODE_EXPERT))))
+ phaseIdx++; // For all other cases
+ setNewViewMode ();
+ settings->set_view_mode (newmode);
+ }
+}
+
+Cmd_status
+DbeView::set_view_mode (char *str, bool fromRC)
+{
+ VMode old = settings->get_view_mode ();
+ Cmd_status ret = settings->set_view_mode (str, fromRC);
+ if (old != settings->get_view_mode ())
+ phaseIdx++;
+ return ret;
+}
+
+Cmd_status
+DbeView::set_en_desc (char *str, bool fromRC)
+{
+ // Tell the session
+ Settings *s = dbeSession->get_settings ();
+ s->set_en_desc (str, fromRC);
+
+ // and tell our settings
+ return settings->set_en_desc (str, fromRC);
+}
+
+// Get processor stats messages
+char *
+DbeView::get_processor_msg (int type)
+{
+ if (ptree == NULL) // if no PathTree, no messages
+ return NULL;
+
+ StringBuilder sb;
+ Emsg *m = (type == PSTAT_MSG) ? ptree->fetch_stats () : ptree->fetch_warnings ();
+ for (; m != NULL; m = m->next)
+ {
+ char* newmsg = m->get_msg ();
+ sb.append (newmsg);
+ sb.append ("\n");
+ }
+
+ if (type == PSTAT_MSG)
+ ptree->delete_stats ();
+ else
+ ptree->delete_warnings ();
+ return (sb.length () > 0) ? sb.toString () : NULL;
+}
+
+void
+DbeView::dump_nodes (FILE *outfile)
+{
+ FILE *f = (outfile == NULL ? stderr : outfile);
+ ptree->print (f);
+}
+
+// Dump the clock profile events
+void
+DbeView::dump_profile (FILE *out_file)
+{
+ for (int idx = 0; idx < dbeSession->nexps (); idx++)
+ {
+ Experiment *exp = dbeSession->get_exp (idx);
+ VMode view_mode = get_view_mode ();
+ char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS;
+
+ // Process clock profile date
+ DataView *packets = get_filtered_events (idx, DATA_CLOCK);
+ if (packets && packets->getSize () != 0)
+ {
+ hrtime_t start = exp->getStartTime ();
+ fprintf (out_file,
+ GTXT ("\nTotal Clock Profiling Packets: %d Experiment: %s\n"),
+ (int) packets->getSize (), exp->get_expt_name ());
+ for (long i = 0; i < packets->getSize (); i++)
+ {
+ hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+ hrtime_t ts = expr_ts - start;
+
+ // get the properties from the packet
+ uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+ uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+ int mstate = (int) packets->getIntValue (PROP_MSTATE, i);
+ int nticks = (int) packets->getIntValue (PROP_NTICK, i);
+
+ char *sname;
+ char buf[1024];
+ if (mstate >= 0 && mstate < LMS_NUM_STATES)
+ sname = stateNames[mstate];
+ else
+ {
+ snprintf (buf, sizeof (buf), NTXT ("Unexpected mstate = %d"), mstate);
+ sname = buf;
+ }
+
+ // get the stack IGNORE HIDE
+ Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+ int stack_size = stack->size ();
+
+ // print the packet header with the count of stack frames
+ fprintf (out_file,
+ GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+ i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+ expr_ts / NANOSEC, expr_ts % NANOSEC,
+ thrid, cpuid, stack_size);
+ fprintf (out_file,
+ GTXT (" mstate = %d (%s), nticks = %d\n"),
+ mstate, sname, nticks);
+
+ // dump the callstack
+ for (int j = stack_size - 1; j >= 0; j--)
+ {
+ Histable *frame = stack->fetch (j);
+ fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+ }
+ fprintf (out_file, "\n");
+ }
+ }
+ else
+ fprintf (out_file,
+ GTXT ("\nNo Clock Profiling Packets in Experiment: %s\n"),
+ exp->get_expt_name ());
+ }
+}
+
+// Dump the sync trace events
+void
+DbeView::dump_sync (FILE *out_file)
+{
+ for (int idx = 0; idx < dbeSession->nexps (); idx++)
+ {
+ Experiment *exp = dbeSession->get_exp (idx);
+ VMode view_mode = get_view_mode ();
+
+ // Process heap trace date
+ DataView *packets = get_filtered_events (idx, DATA_SYNCH);
+ if (packets && packets->getSize () != 0)
+ {
+ hrtime_t start = exp->getStartTime ();
+ fprintf (out_file,
+ GTXT ("\nTotal Synctrace Packets: %d Experiment: %s\n"),
+ (int) packets->getSize (), exp->get_expt_name ());
+
+ for (long i = 0; i < packets->getSize (); i++)
+ {
+ hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+ hrtime_t ts = expr_ts - start;
+
+ // get the properties from the packet
+ uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+ uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+ uint64_t syncobj = (uint64_t) packets->getLongValue (PROP_SOBJ, i);
+ hrtime_t syncrtime = (uint64_t) packets->getLongValue (PROP_SRQST, i);
+ hrtime_t syncdelay = expr_ts - syncrtime;
+
+ // get the stack IGNORE HIDE
+ Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+ int stack_size = stack->size ();
+
+ // print the packet header with the count of stack frames
+ fprintf (out_file,
+ GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+ i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+ expr_ts / NANOSEC, expr_ts % NANOSEC, thrid,
+ cpuid, stack_size);
+ fprintf (stderr,
+ GTXT (" synchronization object @ 0x%016llx; synchronization delay %3lld.%09lld\n"),
+ (unsigned long long) syncobj, (long long) (syncdelay / NANOSEC), (long long) (syncdelay % NANOSEC));
+
+ // dump the callstack
+ for (int j = stack_size - 1; j >= 0; j--)
+ {
+ Histable *frame = stack->fetch (j);
+ fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+ }
+ fprintf (out_file, "\n");
+ }
+ }
+ else
+ fprintf (out_file, GTXT ("\nNo Synctrace Packets in Experiment: %s\n"),
+ exp->get_expt_name ());
+ }
+}
+
+// Dump the IO trace events
+void
+DbeView::dump_iotrace (FILE *out_file)
+{
+ for (int idx = 0; idx < dbeSession->nexps (); idx++)
+ {
+ Experiment *exp = dbeSession->get_exp (idx);
+ VMode view_mode = get_view_mode ();
+
+ // Process IO trace date
+ DataView *packets = get_filtered_events (idx, DATA_IOTRACE);
+ if (packets && packets->getSize () != 0)
+ {
+ hrtime_t start = exp->getStartTime ();
+ fprintf (out_file,
+ GTXT ("\nTotal IO trace Packets: %d Experiment: %s\n"),
+ (int) packets->getSize (), exp->get_expt_name ());
+ for (long i = 0; i < packets->getSize (); i++)
+ {
+ hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+ hrtime_t ts = expr_ts - start;
+
+ // get the properties from the packet
+ uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+ uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+ IOTrace_type iotrtype = (IOTrace_type) packets->getIntValue (PROP_IOTYPE, i);
+ uint32_t iofd = (uint32_t) packets->getIntValue (PROP_IOFD, i);
+ uint64_t ionbyte = (uint64_t) packets->getIntValue (PROP_IONBYTE, i);
+ hrtime_t iorqst = (hrtime_t) packets->getLongValue (PROP_IORQST, i);
+ uint32_t ioofd = (uint32_t) packets->getIntValue (PROP_IOOFD, i);
+ FileSystem_type iofstype = (FileSystem_type) packets->getIntValue (PROP_CPUID, i);
+ int64_t iovfd = (int64_t) packets->getIntValue (PROP_IOVFD, i);
+
+ char *fName = NULL;
+ StringBuilder *sb = (StringBuilder*) packets->getObjValue (PROP_IOFNAME, i);
+ if (sb != NULL && sb->length () > 0)
+ fName = sb->toString ();
+
+ // get the stack IGNORE HIDE
+ Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+ int stack_size = stack->size ();
+ const char *iotrname;
+ switch (iotrtype)
+ {
+ case READ_TRACE:
+ iotrname = "ReadTrace";
+ break;
+ case WRITE_TRACE:
+ iotrname = "WriteTrace";
+ break;
+ case OPEN_TRACE:
+ iotrname = "OpenTrace";
+ break;
+ case CLOSE_TRACE:
+ iotrname = "CloseTrace";
+ break;
+ case OTHERIO_TRACE:
+ iotrname = "OtherIOTrace";
+ break;
+ case READ_TRACE_ERROR:
+ iotrname = "ReadTraceError";
+ break;
+ case WRITE_TRACE_ERROR:
+ iotrname = "WriteTraceError";
+ break;
+ case OPEN_TRACE_ERROR:
+ iotrname = "OpenTraceError";
+ break;
+ case CLOSE_TRACE_ERROR:
+ iotrname = "CloseTraceError";
+ break;
+ case OTHERIO_TRACE_ERROR:
+ iotrname = "OtherIOTraceError";
+ break;
+ default:
+ iotrname = "UnknownIOTraceType";
+ break;
+ }
+
+ // print the packet header with the count of stack frames
+ fprintf (out_file,
+ GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+ i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+ expr_ts / NANOSEC, expr_ts % NANOSEC,
+ thrid, cpuid, stack_size);
+ fprintf (out_file,
+ GTXT (" %s: fd = %d, ofd = %d, vfd = %lld, fstype = %d, rqst = %3lld.%09lld\n"),
+ iotrname, (int) iofd, (int) ioofd, (long long) iovfd,
+ (int) iofstype, (long long) (iorqst / NANOSEC),
+ (long long) (iorqst % NANOSEC));
+ fprintf (out_file, GTXT (" filename = `%s', nbytes = %d\n"),
+ STR (fName), (int) ionbyte);
+ free (fName);
+
+ // dump the callstack
+ for (int j = stack_size - 1; j >= 0; j--)
+ {
+ Histable *frame = stack->fetch (j);
+ fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+ }
+ fprintf (out_file, "\n");
+ }
+ }
+ else
+ fprintf (out_file, GTXT ("\nNo IO trace Packets in Experiment: %s\n"),
+ exp->get_expt_name ());
+ }
+}
+
+// Dump the HWC Profiling events
+void
+DbeView::dump_hwc (FILE *out_file)
+{
+ for (int idx = 0; idx < dbeSession->nexps (); idx++)
+ {
+ Experiment *exp = dbeSession->get_exp (idx);
+ VMode view_mode = get_view_mode ();
+
+ // Dump HWC profiling data
+ DataView *packets = get_filtered_events (idx, DATA_HWC);
+ if (packets && packets->getSize () != 0)
+ {
+ hrtime_t start = exp->getStartTime ();
+ fprintf (out_file,
+ GTXT ("\nTotal HW Counter Profiling Packets: %d Experiment: %s\n"),
+ (int) packets->getSize (), exp->get_expt_name ());
+ for (long i = 0; i < packets->getSize (); i++)
+ {
+ const char * hwc_name;
+ hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+ hrtime_t ts = expr_ts - start;
+ uint32_t tag = (uint32_t) packets->getIntValue (PROP_HWCTAG, i);
+ uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+ uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+
+ // This will work even with a different counter in every packet.
+ if (tag < 0 || tag >= MAX_HWCOUNT
+ || !exp->coll_params.hw_aux_name[tag])
+ // if the packet has an invalid tag, use <invalid> as its name
+ hwc_name = "<invalid>";
+ else
+ hwc_name = exp->coll_params.hw_aux_name[tag];
+ int64_t mval = packets->getLongValue (PROP_HWCINT, i);
+ const char *err = HWCVAL_HAS_ERR (mval) ? " $$" : "";
+
+ // get the stack IGNORE HIDE
+ Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+ int stack_size = stack->size ();
+
+ // print the packet header with the count of stack frames
+ fprintf (out_file,
+ GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n count = %10lld (0x%016llx), tag = %d (%s)%s\n"),
+ (long) i, (long long) expr_ts,
+ (long long) (ts / NANOSEC), (long long) (ts % NANOSEC),
+ (long long) (expr_ts / NANOSEC), (long long) (expr_ts % NANOSEC),
+ (int) thrid, (int) cpuid, (int) stack_size,
+ (long long) (HWCVAL_CLR_ERR (mval)), (long long) mval,
+ (int) tag, hwc_name, err);
+
+ // dump extended HWC packets values
+ uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
+ uint64_t pa = (uint64_t) packets->getLongValue (PROP_PADDR, i);
+ fprintf (out_file, GTXT (" va = 0x%016llx, pa = 0x%016llx\n"),
+ (unsigned long long) va, (unsigned long long) pa);
+
+ // dump the callstack
+ for (int j = stack_size - 1; j >= 0; j--)
+ {
+ Histable *frame = stack->fetch (j);
+ fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+ }
+ fprintf (out_file, "\n");
+ }
+ }
+ else
+ fprintf (out_file,
+ GTXT ("\nNo HWC Profiling Packets in Experiment: %s\n"),
+ exp->get_expt_name ());
+ }
+}
+
+// Dump the Heap events
+void
+DbeView::dump_heap (FILE *out_file)
+{
+ char *heapstrings[] = HEAPTYPE_STATE_USTRINGS;
+ for (int idx = 0; idx < dbeSession->nexps (); idx++)
+ {
+ Experiment *exp = dbeSession->get_exp (idx);
+ VMode view_mode = get_view_mode ();
+
+ // Process heap trace date
+ DataView *packets = get_filtered_events (idx, DATA_HEAP);
+ if (packets && packets->getSize () != 0)
+ {
+ hrtime_t start = exp->getStartTime ();
+ fprintf (out_file, GTXT ("\nTotal Heaptrace Packets: %d Experiment: %s\n"),
+ (int) packets->getSize (), exp->get_expt_name ());
+ for (long i = 0; i < packets->getSize (); i++)
+ {
+ hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+ hrtime_t ts = expr_ts - start;
+
+ // get the properties from the packet
+ uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+ uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+ uint32_t heaptype = (uint32_t) packets->getIntValue (PROP_HTYPE, i);
+ uint64_t heapsize = (uint64_t) packets->getULongValue (PROP_HSIZE, i);
+ uint64_t heapvaddr = (uint64_t) packets->getULongValue (PROP_HVADDR, i);
+ uint64_t heapovaddr = (uint64_t) packets->getULongValue (PROP_HOVADDR, i);
+ if (heaptype == MUNMAP_TRACE)
+ {
+ heapsize = (uint64_t) packets->getULongValue (PROP_HOVADDR, i);
+ heapovaddr = 0;
+ }
+
+ // get the stack IGNORE HIDE
+ Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+ int stack_size = stack->size ();
+
+ // print the packet header with the count of stack frames
+ fprintf (out_file,
+ GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+ i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+ expr_ts / NANOSEC, expr_ts % NANOSEC,
+ thrid, cpuid, stack_size);
+ char *typestr = heapstrings[heaptype];
+ fprintf (out_file,
+ GTXT (" type = %d (%s), size = %llu (0x%llx), VADDR = 0x%016llx, OVADDR = 0x%016llx\n"),
+ (int) heaptype, typestr, (long long unsigned int) heapsize,
+ (long long unsigned int) heapsize,
+ (long long unsigned int) heapvaddr,
+ (long long unsigned int) heapovaddr);
+
+ // dump the callstack
+ for (int j = stack_size - 1; j >= 0; j--)
+ {
+ Histable *frame = stack->fetch (j);
+ fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+ }
+ fprintf (out_file, "\n");
+ }
+ }
+ else
+ fprintf (out_file, GTXT ("\nNo Heaptrace Packets in Experiment: %s\n"),
+ exp->get_expt_name ());
+ }
+}
+
+// Dump the Java garbage collector events
+void
+DbeView::dump_gc_events (FILE *out_file)
+{
+ for (int idx = 0; idx < dbeSession->nexps (); idx++)
+ {
+ Experiment *exp = dbeSession->get_exp (idx);
+ if (!exp->has_java)
+ fprintf (out_file,
+ GTXT ("# No GC events in experiment %d, %s (PID %d, %s)\n"),
+ idx, exp->get_expt_name (), exp->getPID (), exp->utargname);
+ else
+ {
+ Vector<GCEvent*> *gce = exp->get_gcevents ();
+ GCEvent *this_event;
+ int index;
+ fprintf (out_file,
+ GTXT ("# %li events in experiment %d: %s (PID %d, %s)\n"),
+ gce->size (), idx,
+ exp->get_expt_name (), exp->getPID (), exp->utargname);
+ fprintf (out_file,
+ GTXT ("# exp:idx GC_start, GC_end, GC_duration\n"));
+ Vec_loop (GCEvent*, gce, index, this_event)
+ {
+ hrtime_t start = this_event->start - exp->getStartTime ();
+ hrtime_t end = this_event->end - exp->getStartTime ();
+ hrtime_t delta = this_event->end - this_event->start;
+ fprintf (out_file,
+ "%5d:%d, %3lld.%09lld, %3lld.%09lld, %3lld.%09lld\n",
+ idx, index,
+ (long long) (start / NANOSEC), (long long) (start % NANOSEC),
+ (long long) (end / NANOSEC), (long long) (end % NANOSEC),
+ (long long) (delta / NANOSEC), (long long) (delta % NANOSEC));
+ }
+ }
+ }
+}
+
+void
+DbeView::purge_events (int n)
+{
+ phaseIdx++;
+ int lst;
+ if (n == -1)
+ lst = filters->size ();
+ else
+ lst = n > filters->size () ? filters->size () : n + 1;
+ for (int i = n == -1 ? 0 : n; i < lst; i++)
+ {
+ Vector<DataView*> *expDataViewList = dataViews->fetch (i);
+ if (expDataViewList)
+ {
+ // clear out all the data_ids, but don't change the vector size
+ for (int data_id = 0; data_id < expDataViewList->size (); ++data_id)
+ {
+ delete expDataViewList->fetch (data_id);
+ expDataViewList->store (data_id, NULL);
+ }
+ }
+ }
+ filter_active = false;
+}
+
+
+// LIBRARY_VISIBILITY
+void
+DbeView::resetAndConstructShowHideStacks ()
+{
+ for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++)
+ {
+ Experiment *exp = dbeSession->get_exp (n);
+ if (exp != NULL)
+ resetAndConstructShowHideStack (exp);
+ }
+}
+
+// LIBRARY_VISIBILITY
+void
+DbeView::resetAndConstructShowHideStack (Experiment *exp)
+{
+ exp->resetShowHideStack ();
+ /* Vector<DataDescriptor*> *dDscrs = */ exp->getDataDescriptors ();
+
+ DataDescriptor *dd;
+ // Construct show hide stack only for objects which have call stacks
+ // list below similar to path tree. What about HEAP_SZ? (DBFIXME)
+ dd = exp->get_raw_events (DATA_CLOCK);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+ dd = exp->get_raw_events (DATA_SYNCH);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+ dd = exp->get_raw_events (DATA_IOTRACE);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+ dd = exp->get_raw_events (DATA_HWC);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+ dd = exp->get_raw_events (DATA_HEAP);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+ dd = exp->get_raw_events (DATA_RACE);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+ dd = exp->get_raw_events (DATA_DLCK);
+ if (dd != NULL)
+ constructShowHideStack (dd, exp);
+}
+
+// LIBRARY_VISIBILITY
+void
+DbeView::constructShowHideStack (DataDescriptor *dDscr, Experiment *exp)
+{
+ if (dDscr == NULL)
+ return;
+ int stack_prop = PROP_NONE;
+ VMode view_mode = get_view_mode ();
+ if (view_mode == VMODE_MACHINE)
+ stack_prop = PROP_MSTACK;
+ else if (view_mode == VMODE_EXPERT)
+ stack_prop = PROP_XSTACK;
+ else if (view_mode == VMODE_USER)
+ stack_prop = PROP_USTACK;
+
+ for (long j = 0, sz = dDscr->getSize (); j < sz; j++)
+ {
+ void *stackId = dDscr->getObjValue (stack_prop, j);
+ Vector<Histable*> *stack = (Vector<Histable*>*)CallStack::getStackPCs (stackId);
+ int stack_size = stack->size ();
+ bool hide_on = false;
+ LoadObject *hide_lo = NULL;
+ Histable *last_addr = NULL;
+ Histable *api_addr = NULL;
+ DbeInstr *h_instr;
+
+ Vector<Histable*> *hidepcs = new Vector<Histable*>;
+ for (int i = stack_size - 1; i >= 0; i--)
+ {
+ bool leaf = (i == 0);
+ Histable *cur_addr = stack->fetch (i);
+ Function *func = (Function*) cur_addr->convertto (Histable::FUNCTION);
+ if (func != NULL)
+ {
+ Module *mod = func->module;
+ LoadObject *lo = mod->loadobject;
+ int segx = lo->seg_idx;
+ if ((get_lo_expand (segx) == LIBEX_API) && (i != (stack_size - 1)))
+ {
+ leaf = true;
+ api_addr = cur_addr;
+ }
+ else if (get_lo_expand (segx) == LIBEX_HIDE)
+ {
+ if (hide_on)
+ {
+ if (lo != hide_lo)
+ {
+ // Changed hidden loadobject
+ if (last_addr != NULL)
+ {
+ h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr);
+ hidepcs->append (h_instr);
+ last_addr = cur_addr;
+ }
+ hide_lo = lo;
+ }
+ }
+ else
+ {
+ // Start hide
+ hide_on = true;
+ last_addr = cur_addr;
+ hide_lo = lo;
+ }
+ if (!leaf)
+ continue;
+ }
+ else
+ {
+ hide_on = false;
+ if (last_addr != NULL)
+ {
+ h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr);
+ hidepcs->append (h_instr);
+ last_addr = NULL;
+ }
+ }
+ }
+ if (last_addr != NULL && leaf) cur_addr = last_addr;
+ if (hide_on)
+ {
+ h_instr = hide_lo->get_hide_instr ((DbeInstr*) cur_addr);
+ hidepcs->append (h_instr);
+ if (api_addr != NULL)
+ hidepcs->append (api_addr);
+ }
+ else
+ hidepcs->append (cur_addr);
+ if (leaf)
+ break;
+ }
+ for (int i = 0, k = hidepcs->size () - 1; i < k; ++i, --k)
+ hidepcs->swap (i, k);
+
+ CallStack *cstkSH = exp->callTreeShowHide ();
+ CallStackNode *hstack = (CallStackNode *) cstkSH->add_stack (hidepcs);
+ dDscr->setObjValue (PROP_HSTACK, j, hstack);
+ CallStack::setHideStack (stackId, hstack);
+ delete hidepcs;
+ delete stack;
+ }
+}
+
+DataView *
+DbeView::get_filtered_events (int idx, int data_id)
+{
+ if (idx < 0 || idx >= dataViews->size ())
+ return NULL;
+ Vector<DataView*> *expDataViewList = dataViews->fetch (idx);
+ if (!expDataViewList)
+ return NULL; // Weird
+
+ DataView *dview = expDataViewList->fetch (data_id);
+ Experiment *exp = dbeSession->get_exp (idx);
+ if (dview)
+ {
+ // if show-hide is on force a reconstruction of hide stacks
+ // LIBRARY_VISIBILITY
+ if (!showAll && (showHideChanged || newViewMode))
+ {
+ DataDescriptor *dDscr = exp->get_raw_events (data_id);
+ constructShowHideStack (dDscr, exp);
+ }
+ return dview;
+ }
+
+ int orig_data_id = data_id;
+ data_id = exp->base_data_id (data_id);
+ if (orig_data_id != data_id)
+ // orig_data_id is a derived DataView. Get the master DataView:
+ dview = expDataViewList->fetch (data_id);
+ if (dview == NULL)
+ {
+ Expression *saved = cur_filter_expr;
+ if (!adjust_filter (exp))
+ return NULL;
+
+ DataDescriptor *dDscr = exp->get_raw_events (data_id);
+ if (!showAll && (showHideChanged || newViewMode))
+ constructShowHideStack (dDscr, exp);
+
+ Emsg *m = exp->fetch_warnings ();
+ if (m != NULL)
+ this->warning_msg = m->get_msg ();
+
+ if (dDscr != NULL)
+ {
+ FilterExp *filter = get_FilterExp (exp);
+ dview = dDscr->createView ();
+ dview->setFilter (filter);
+ if (dview->getSize () < dDscr->getSize ())
+ filter_active = true;
+ }
+ expDataViewList->store (data_id, dview);
+
+ if (saved)
+ {
+ delete cur_filter_expr;
+ cur_filter_expr = saved;
+ }
+ }
+ if (orig_data_id != data_id)
+ {
+ // create the derived DataView:
+ dview = exp->create_derived_data_view (orig_data_id, dview);
+ expDataViewList->store (orig_data_id, dview);
+ }
+ return dview;
+}
+
+DataView *
+DbeView::get_filtered_events (int idx, int data_id,
+ const int sortprops[], int sortprop_count)
+{
+ DataView *packets = get_filtered_events (idx, data_id);
+ if (packets)
+ packets->sort (sortprops, sortprop_count);
+ return packets;
+}
+
+bool
+DbeView::adjust_filter (Experiment *exp)
+{
+ if (cur_filter_expr)
+ {
+ Expression::Context ctx (this, exp);
+ resetFilterHideMode ();
+ Expression *fltr = cur_filter_expr->pEval (&ctx);
+ if (fltr->complete ())
+ { // Filter is a constant
+ if (fltr->eval (NULL) == 0)
+ return false;
+ delete fltr;
+ fltr = NULL;
+ }
+ cur_filter_expr = fltr;
+ }
+ return true;
+}
+
+// Moved from Cacheable.cc:
+char *
+DbeView::status_str (DbeView_status status)
+{
+ switch (status)
+ {
+ case DBEVIEW_SUCCESS:
+ return NULL;
+ case DBEVIEW_NO_DATA:
+ return dbe_strdup (GTXT ("Data not available for this filter selection"));
+ case DBEVIEW_IO_ERROR:
+ return dbe_strdup (GTXT ("Unable to open file"));
+ case DBEVIEW_BAD_DATA:
+ return dbe_strdup (GTXT ("Data corrupted"));
+ case DBEVIEW_BAD_SYMBOL_DATA:
+ return dbe_strdup (GTXT ("Functions/Modules information corrupted"));
+ case DBEVIEW_NO_SEL_OBJ:
+ return dbe_strdup (GTXT ("No selected object, bring up Functions Tab"));
+ }
+ return NULL;
+}
+
+Histable *
+DbeView::set_sel_obj (Histable *obj)
+{
+ if (obj)
+ {
+ switch (obj->get_type ())
+ {
+ case Histable::INSTR:
+ lastSelInstr = (DbeInstr *) obj;
+ lastSelFunc = lastSelInstr->func;
+ this->sel_binctx = lastSelFunc;
+ break;
+ case Histable::FUNCTION:
+ if (lastSelInstr && lastSelInstr->func != obj)
+ lastSelInstr = NULL;
+ lastSelFunc = (Function *) obj;
+ break;
+ case Histable::LINE:
+ {
+ DbeLine *dbeLine = (DbeLine *) obj;
+ if (dbeLine->func)
+ {
+ // remember previous DbeInstr and DbeFunc
+ lastSelFunc = dbeLine->func;
+ if (lastSelInstr && lastSelInstr->func != lastSelFunc)
+ lastSelInstr = NULL;
+ this->sel_binctx = lastSelFunc;
+ }
+ else
+ this->sel_binctx = dbeLine->convertto (Histable::FUNCTION);
+ break;
+ }
+ case Histable::MODULE:
+ case Histable::LOADOBJECT:
+ case Histable::EADDR:
+ case Histable::MEMOBJ:
+ case Histable::INDEXOBJ:
+ case Histable::PAGE:
+ case Histable::DOBJECT:
+ case Histable::SOURCEFILE:
+ case Histable::IOACTFILE:
+ case Histable::IOACTVFD:
+ case Histable::IOCALLSTACK:
+ case Histable::HEAPCALLSTACK:
+ case Histable::EXPERIMENT:
+ case Histable::OTHER:
+ break;
+ }
+ }
+ sel_obj = obj;
+ Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d obj %s\n"),
+ __LINE__, obj ? obj->dump () : "NULL");
+ Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d sel_obj %s\n"),
+ __LINE__, sel_obj ? sel_obj->dump () : "NULL");
+ Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelFunc %s\n"),
+ __LINE__, lastSelFunc ? lastSelFunc->dump () : "NULL");
+ Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelInstr %s\n"),
+ __LINE__, lastSelInstr ? lastSelInstr->dump () : "NULL");
+ return sel_obj;
+}
+
+DbeInstr *
+DbeView::convert_line_to_instr (DbeLine *dbeLine)
+{
+ Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d dbeLine=%s\n", __LINE__, dbeLine->dump ());
+ Function *func = convert_line_to_func (dbeLine);
+ if (func)
+ {
+ Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d func=%s\n", __LINE__, func->dump ());
+ DbeInstr *dbeInstr = func->mapLineToPc (dbeLine);
+ Dprintf (DEBUG_DBE && dbeInstr, "### convert_line_to_instr DbeView::%d dbeInstr=%s\n", __LINE__, dbeInstr->dump ());
+ return dbeInstr;
+ }
+ Dprintf (DEBUG_DBE && lastSelInstr, "### convert_line_to_instr DbeView::%d lastSelInstr=%s\n", __LINE__, lastSelInstr->dump ());
+ return lastSelInstr;
+}
+
+DbeInstr *
+DbeView::convert_func_to_instr (Function *func)
+{
+ return (lastSelInstr && lastSelInstr->func == func) ?
+ lastSelInstr : (DbeInstr *) func->convertto (Histable::INSTR);
+}
+
+Function *
+DbeView::convert_line_to_func (DbeLine *dbeLine)
+{
+ Function *func = dbeLine->func;
+ if (func)
+ return func;
+ if (lastSelFunc != NULL)
+ // Can be mapped to the same function ?
+ for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next)
+ if (dl->func == lastSelFunc)
+ return lastSelFunc;
+
+ PathTree *pathTree = NULL;
+ Function *firstFunc = NULL;
+ for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next)
+ {
+ // Find a first function with non-zero metrics
+ if (dl->func)
+ {
+ if (pathTree == NULL)
+ pathTree = get_path_tree ();
+ if (pathTree->get_func_nodeidx (dl->func))
+ return dl->func;
+ if (firstFunc == NULL)
+ firstFunc = dl->func;
+ }
+ }
+ // Take a first function
+ return firstFunc;
+}
+
+Histable *
+DbeView::get_sel_obj (Histable::Type type)
+{
+ Histable *lastSelObj = sel_obj;
+ Dprintf (DEBUG_DBE, NTXT ("### get_sel_obj: DbeView.cc:%d type=%d sel_obj %s\n"),
+ __LINE__, type, lastSelObj ? lastSelObj->dump () : "NULL");
+ if (lastSelObj == NULL)
+ return NULL;
+ switch (type)
+ {
+ case Histable::INSTR:
+ if (!showAll)
+ {
+ // DBFIXME LIBRARY VISIBILITY
+ // hack to get to the hide mode object for PCs when filtering
+ // with a PC in timeline
+ if (lastSelObj->get_type () == Histable::INSTR)
+ {
+ Function *func = (Function*) (lastSelObj->convertto (Histable::FUNCTION));
+ LoadObject *lo = func->module->loadobject;
+ if (get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+ return lo->get_hide_function ();
+ }
+ }
+ if (lastSelObj->get_type () == Histable::LINE)
+ return convert_line_to_instr ((DbeLine*) lastSelObj);
+ else if (lastSelObj->get_type () == Histable::FUNCTION)
+ return convert_func_to_instr ((Function *) lastSelObj);
+ return lastSelObj->convertto (type);
+ case Histable::FUNCTION:
+ if (lastSelObj->get_type () == Histable::LINE)
+ {
+ Function *func = convert_line_to_func ((DbeLine*) lastSelObj);
+ if (func)
+ return func;
+ return NULL;
+ }
+ return lastSelObj->convertto (type);
+ case Histable::LINE:
+ default:
+ return lastSelObj->convertto (type);
+ }
+}
diff --git a/gprofng/src/DbeView.h b/gprofng/src/DbeView.h
new file mode 100644
index 0000000..bb6bb90
--- /dev/null
+++ b/gprofng/src/DbeView.h
@@ -0,0 +1,842 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * The DbeView class represents a window into the data managed by a DbeSession
+ *
+ * A DbeView has a Settings class that determines the user preferences,
+ * instantiated initially as a copy of the one in the DbeSession
+ * that created it, or in the DbeView being cloned by the DbeSession
+ *
+ * A DbeView has a vector of Experiment pointers, matching the one in the
+ * DbeSession, and a vector of enable bits governing which of the
+ * Experiments are currently being used to process the data.
+ *
+ * A DbeView has three vectors of Metrics, one for functions, etc.,
+ * a second for callers/callees, and a third for dataspace/memoryspace.
+ *
+ * A DbeView has a vector of FilterSet's (q.v.), one for each Experiment,
+ * used to determine how the data is filtered.
+ *
+ * Each DbeView has its own instantiation of the objects representing
+ * the processed, filtered data. Currently these are a PathTree
+ * for computing text-based metrics, a DataSpace for computing
+ * data-based metrics, and a MemorySpace used for computing
+ * memory-object-based metrics.
+ */
+
+#ifndef _DBEVIEW_H
+#define _DBEVIEW_H
+
+#include <stdio.h>
+#include "dbe_structs.h"
+#include "vec.h"
+#include "enums.h"
+#include "util.h"
+#include "DerivedMetrics.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Settings.h"
+#include "Metric.h"
+#include "Table.h"
+#include "PathTree.h"
+
+class Application;
+class DataView;
+class Experiment;
+class Expression;
+class FilterSet;
+class FilterNumeric;
+class FilterExp;
+class Function;
+class Histable;
+class MetricList;
+class Module;
+class Ovw_data;
+class PathTree;
+class DataSpace;
+class MemorySpace;
+class Stats_data;
+class LoadObject;
+class IOActivity;
+class HeapActivity;
+
+class DbeView
+{
+public:
+ DbeView (Application *app, Settings *_settings, int _vindex);
+ DbeView (DbeView *dbev, int _vindex);
+ ~DbeView ();
+
+ // Access functions for settings in the view
+ Settings *
+ get_settings ()
+ {
+ return settings;
+ };
+
+ // Get the list of tabs for this view
+ Vector<DispTab*> *
+ get_TabList ()
+ {
+ return settings->get_TabList ();
+ };
+
+ // Get the list of memory tabs for this view
+ Vector<bool> *
+ get_MemTabState ()
+ {
+ return settings->get_MemTabState ();
+ };
+
+ // Set the list of memory tabs for this view
+ void
+ set_MemTabState (Vector<bool>*sel)
+ {
+ settings->set_MemTabState (sel);
+ };
+
+ // Get the list of index tabs for this view
+ Vector<bool> *
+ get_IndxTabState ()
+ {
+ return settings->get_IndxTabState ();
+ };
+
+ // Set the list of memory tabs for this view
+ void
+ set_IndxTabState (Vector<bool>*sel)
+ {
+ settings->set_IndxTabState (sel);
+ };
+
+ // controlling the name format
+ Cmd_status
+ set_name_format (char *str)
+ {
+ return settings->set_name_format (str);
+ };
+
+ void
+ set_name_format (int fname_format, bool soname)
+ {
+ settings->set_name_format (fname_format, soname);
+ };
+
+ Histable::NameFormat
+ get_name_format ()
+ {
+ return settings->name_format;
+ }
+
+ // processing modes: view_mode
+ Cmd_status set_view_mode (char *str, bool fromRC); // from a string
+ void set_view_mode (VMode mode); // from the analyzer
+
+ VMode
+ get_view_mode ()
+ {
+ return settings->get_view_mode ();
+ };
+
+ // handling of descendant processes
+ Cmd_status set_en_desc (char *str, bool rc); // from a string
+
+ bool
+ check_en_desc (const char * lineage_name = NULL, const char *targname = NULL)
+ {
+ return settings->check_en_desc (lineage_name, targname);
+ };
+
+ // Controlling the print line-limit
+ char *
+ set_limit (char *str, bool rc) // from a string
+ {
+ settings->set_limit (str, rc);
+ return NULL;
+ };
+
+ char *
+ set_limit (int _limit)
+ {
+ settings->limit = _limit;
+ return NULL;
+ };
+
+ int
+ get_limit ()
+ {
+ return settings->limit;
+ };
+
+ // Controlling the print format mode
+ char *
+ set_printmode (char *str)
+ {
+ return settings->set_printmode (str);
+ };
+
+ enum PrintMode
+ get_printmode ()
+ {
+ return settings->print_mode;
+ };
+
+ char
+ get_printdelimiter ()
+ {
+ return settings->print_delim;
+ };
+
+ char *
+ get_printmode_str ()
+ {
+ return dbe_strdup (settings->str_printmode);
+ };
+
+ // processing compiler commentary visibility bits, and other source annotation
+ // controls
+ Cmd_status
+ proc_compcom (const char *cmd, bool isSrc, bool rc)
+ {
+ return settings->proc_compcom (cmd, isSrc, rc);
+ };
+
+ char *
+ get_str_scompcom ()
+ {
+ return settings->str_scompcom;
+ };
+
+ char *
+ get_str_dcompcom ()
+ {
+ return settings->str_dcompcom;
+ };
+
+ void
+ set_src_compcom (int v)
+ {
+ settings->src_compcom = v;
+ };
+
+ int
+ get_src_compcom ()
+ {
+ return settings->src_compcom;
+ };
+
+ void
+ set_dis_compcom (int v)
+ {
+ settings->dis_compcom = v;
+ };
+
+ int
+ get_dis_compcom ()
+ {
+ return settings->dis_compcom;
+ };
+
+ void
+ set_cmpline_visible (bool vis)
+ {
+ settings->set_cmpline_visible (vis);
+ }
+
+ int
+ get_cmpline_visible ()
+ {
+ return settings->cmpline_visible;
+ }
+
+ void
+ set_funcline_visible (bool vis)
+ {
+ settings->set_funcline_visible (vis);
+ }
+
+ int
+ get_funcline_visible ()
+ {
+ return settings->funcline_visible;
+ }
+
+ // controls for disassembly presentation
+ void
+ set_src_visible (int vis)
+ {
+ settings->set_src_visible (vis);
+ }
+
+ int
+ get_src_visible ()
+ {
+ return settings->src_visible;
+ }
+
+ void
+ set_srcmetric_visible (bool vis)
+ {
+ settings->set_srcmetric_visible (vis);
+ }
+
+ bool
+ get_srcmetric_visible ()
+ {
+ return settings->srcmetric_visible;
+ }
+
+ void
+ set_hex_visible (bool vis)
+ {
+ settings->set_hex_visible (vis);
+ }
+
+ bool
+ get_hex_visible ()
+ {
+ return settings->hex_visible;
+ }
+
+ // processing and accessing the threshold settings
+ Cmd_status
+ proc_thresh (char *cmd, bool isSrc, bool rc)
+ {
+ return settings->proc_thresh (cmd, isSrc, rc);
+ };
+
+ void
+ set_thresh_src (int v)
+ {
+ settings->threshold_src = v;
+ };
+
+ int
+ get_thresh_src ()
+ {
+ return settings->threshold_src;
+ };
+
+ void
+ set_thresh_dis (int v)
+ {
+ settings->threshold_dis = v;
+ };
+
+ int
+ get_thresh_dis ()
+ {
+ return settings->threshold_dis;
+ };
+
+ // controls for the Timeline mode, stack presentation
+ Cmd_status
+ proc_tlmode (char *cmd, bool rc)
+ {
+ return settings->proc_tlmode (cmd, rc);
+ };
+
+ void
+ set_tlmode (int _tlmode)
+ {
+ settings->tlmode = _tlmode;
+ };
+
+ int
+ get_tlmode ()
+ {
+ return settings->tlmode;
+ };
+
+ void
+ set_stack_align (int _stack_align)
+ {
+ settings->stack_align = _stack_align;
+ };
+
+ int
+ get_stack_align ()
+ {
+ return settings->stack_align;
+ };
+
+ void
+ set_stack_depth (int _stack_depth)
+ {
+ settings->stack_depth = _stack_depth;
+ };
+
+ int
+ get_stack_depth ()
+ {
+ return settings->stack_depth;
+ };
+
+ // Controls for which data is shown in Timeline
+ Cmd_status
+ proc_tldata (char *cmd, bool rc)
+ {
+ return settings->proc_tldata (cmd, rc);
+ };
+
+ void
+ set_tldata (const char* tldata_cmd)
+ {
+ settings->set_tldata (tldata_cmd);
+ };
+
+ char*
+ get_tldata ()
+ {
+ return settings->get_tldata ();
+ };
+
+ // settings controlling the expand/collapse of functions within each LoadObject
+ enum LibExpand get_lo_expand (int idx);
+
+ // set_lo_expand -- returns true if any change
+ bool set_lo_expand (int idx, enum LibExpand how);
+
+ // set_libexpand -- returns true if any change
+ bool set_libexpand (char *liblist, enum LibExpand flag);
+ void update_lo_expands ();
+ bool set_libdefaults ();
+ void reset ();
+ void reset_data (bool all);
+
+ char *
+ get_error_msg ()
+ {
+ return error_msg;
+ };
+
+ void
+ clear_error_msg ()
+ {
+ error_msg = NULL;
+ };
+
+ char *
+ get_warning_msg ()
+ {
+ return warning_msg;
+ };
+
+ void
+ clear_warning_msg ()
+ {
+ warning_msg = NULL;
+ };
+ char *get_processor_msg (int type);
+
+ // methods controlling the metric list
+ BaseMetric *register_metric_expr (BaseMetric::Type type, char *aux, char *expr_spec);
+ Vector<BaseMetric*> *get_all_reg_metrics ();
+ void reset_metric_list (MetricList *mlist, int cmp_mode);
+
+ // Get the various metric master lists
+ MetricList *get_metric_ref (MetricType mtype);
+
+ // Get the various current metric lists
+ MetricList *get_metric_list (int dsptype, int subtype);
+ MetricList *get_metric_list (MetricType mtype);
+ MetricList *get_metric_list (MetricType mtype, bool compare, int gr_num);
+ MetricList *get_compare_mlist (MetricList *met_list, int grInd);
+
+ // Set the metric list, from a string specification
+ char *setMetrics (char *metricspec, bool fromRcFile);
+
+ // Set the sort metric, from its name
+ char *setSort (char *sortname, MetricType mtype, bool fromRcFile);
+
+ // Set the sort metric, from its visible index (Analyzer)
+ void setSort (int visindex, MetricType mtype, bool reverse);
+
+ // Resort any cached data, after changing sort
+ void resortData (MetricType mtype);
+
+ // Get the sort metric
+ char *getSort (MetricType mtype);
+ char *getSortCmd (MetricType mtype);
+
+ // reset the metrics
+ void reset_metrics ();
+ bool comparingExperiments ();
+
+ int
+ get_compare_mode ()
+ {
+ return settings->compare_mode;
+ };
+
+ void
+ reset_compare_mode (int mode)
+ {
+ settings->compare_mode = mode;
+ };
+
+ void set_compare_mode (int mode); // modifies the global MET_* arrays
+ void add_compare_metrics (MetricList *mlist);
+ void remove_compare_metrics (MetricList *mlist);
+ Histable *get_compare_obj (Histable *obj);
+
+ // method for printing the instruction-frequency report
+ void ifreq (FILE *);
+
+ // methods controlling the experiment list
+ void add_experiment (int index, bool enabled);
+ void add_subexperiment (int index, bool enabled);
+ void add_experiment_epilogue ();
+ void drop_experiment (int index);
+ bool get_exp_enable (int n);
+ void set_exp_enable (int n, bool e);
+
+ // method for new-style filtering
+ char *set_filter (const char *filter_spec);
+ char *get_filter (void);
+ char *get_advanced_filter ();
+ void backtrack_filter ();
+ void update_advanced_filter ();
+ FilterExp *get_FilterExp (Experiment *exp);
+
+ Expression *
+ get_filter_expr ()
+ {
+ return cur_filter_expr;
+ };
+
+ // methods controlling old-style filtering
+ Vector<FilterNumeric*> *get_all_filters (int nexp);
+ FilterNumeric *get_FilterNumeric (int nexp, int idx);
+ bool set_pattern (int n, Vector<char *> *pattern_str, bool *error);
+ bool set_pattern (int m, char *pattern);
+
+ // Data processing objects
+ PathTree *
+ get_path_tree ()
+ {
+ return ptree;
+ };
+
+ DataSpace *
+ get_data_space ()
+ {
+ return dspace;
+ };
+
+ IOActivity *
+ get_io_space ()
+ {
+ return iospace;
+ };
+
+ HeapActivity *
+ get_heap_space ()
+ {
+ return heapspace;
+ };
+ Hist_data *get_data (MetricList *mlist, Histable *selObj, int type, int subtype);
+ int get_sel_ind (Histable *selObj, int type, int subtype);
+
+ // Return histogram data for the specified arguments.
+ Hist_data *get_hist_data (MetricList *mlist, Histable::Type type,
+ int subtype, // used for memory objects only
+ Hist_data::Mode mode,
+ Vector<Histable*> *objs = NULL,
+ Histable *context = NULL,
+ Vector<Histable*> *sel_objs = NULL,
+ PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE
+ );
+ Hist_data *get_hist_data (MetricList *mlist, Histable::Type type,
+ int subtype, // used for memory objects only
+ Hist_data::Mode mode, Histable *obj,
+ Histable *context = NULL,
+ Vector<Histable*> *sel_objs = NULL,
+ PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE
+ );
+ CStack_data *get_cstack_data (MetricList *);
+ Stats_data *get_stats_data (int index);
+ Ovw_data *get_ovw_data (int index);
+
+ char *names_src[3]; // names for anno-src
+ char *names_dis[3]; // names for anno-dis
+
+ // Get filtered packets. Ordering is NOT guaranteed to be
+ // stable between calls; DataView indexes are not persistent -
+ // use underlying DataDescriptor ids if you don't consume data right away.
+ // Parameters: idx==exp_id, data_id==kind==ProfData_type
+ DataView *get_filtered_events (int idx, int data_id);
+ DataView *get_filtered_events (int idx, int data_id,
+ const int sortprops[], int sortprop_count);
+
+ // SORT is not used for PathTree.
+ // PathTree reads data once and discards. It doesn't
+ // depend on the indices so sort can be performed w/o recomputing pathtree.
+ // Timeline is the primary consumer of sort(), however Races also need to sort.
+ //
+ // YM: I can't remember the context for the following note, but
+ // In case I need it when we refactor more TBR stuff, here it is:
+ // base metrics like USER_CPU are known,(but we should/should not?)
+ // explicitly set DATA_CLOCK as a property/attribute?
+ bool adjust_filter (Experiment *exp);
+
+ // Generated report data
+ Hist_data *func_data; // function list data
+ Hist_data *line_data; // hot line list data
+ Hist_data *pc_data; // hot PC list data
+ Hist_data *src_data; // annotated source data
+ Hist_data *dis_data; // annotated disasm data
+ Hist_data *fitem_data; // func item for callers/callees
+ Hist_data *callers; // callers data
+ Hist_data *callees; // callees data
+ Hist_data *dobj_data; // data object list data
+ Hist_data *dlay_data; // data layout data
+ Hist_data *iofile_data; // io data aggregated by file name
+ Hist_data *iovfd_data; // io data aggregated by virtual fd
+ Hist_data *iocs_data; // io data aggregated by call stack
+ Hist_data *heapcs_data; // heap data aggregated by call stack
+ Vector<Hist_data*> *indx_data; // index object data
+ Vector<int> *lobjectsNoJava; // List of indices into LoadObjects excluding java classes
+
+ // memory object data -- create MemorySpace, if needed
+ MemorySpace *getMemorySpace (int subtype);
+ char *get_mobj_name (int subtype);
+ void addIndexSpace (int type);
+ Hist_data *get_indxobj_data (int subtype);
+ void set_indxobj_sel (int subtype, int sel_ind);
+ Histable *get_indxobj_sel (int subtype);
+ void set_obj_sel_io (int type, long sel_ind);
+ Histable *set_sel_obj (Histable *obj);
+ Histable *get_sel_obj (Histable::Type type);
+ Histable *get_sel_obj_io (uint64_t id, Histable::Type type);
+ Histable *get_sel_obj_heap (uint64_t id);
+ Histable *sel_obj; // current selected obj
+ Histable *sel_dobj; // current selected data obj
+ Histable *sel_binctx; // current binary context
+ Vector<Histable*> *sel_idxobj; // selected index objects
+ char *error_msg; // error message
+ char *warning_msg; // warning message
+ Vector<int> *marks; // flagged as important for anno src/dis
+ Vector<int_pair_t> *marks2dsrc;
+ Vector<int_pair_t> *marks2dsrc_inc;
+ Vector<int_pair_t> *marks2ddis;
+ Vector<int_pair_t> *marks2ddis_inc;
+
+ void dump_nodes (FILE *); // dump out the pathtree nodes
+ void dump_profile (FILE *); // dump out the clock profiling events
+ void dump_sync (FILE *); // dump out the synctrace events
+ void dump_iotrace (FILE *); // dump out the IO trace events
+ void dump_hwc (FILE *); // dump out the HWC Profiling events
+ void dump_heap (FILE *); // dump out the heap trace events
+ void dump_gc_events (FILE *); // dump out the Java garbage collector events
+
+ int vindex; // index of this view -- set by Analyzer
+ bool func_scope;
+
+ bool
+ get_func_scope ()
+ {
+ return func_scope;
+ };
+
+ void
+ set_func_scope (bool scope_only)
+ {
+ func_scope = scope_only;
+ };
+
+ // value set T if filtering is active, i.e., some packets were dropped
+ bool filter_active;
+
+ bool
+ get_filter_active ()
+ {
+ return filter_active;
+ };
+
+ DerivedMetrics *
+ get_derived_metrics ()
+ {
+ return derived_metrics;
+ }
+
+ // Internal time (time means change)
+ int
+ getPhaseIdx ()
+ {
+ return phaseIdx;
+ }
+
+ enum DbeView_status
+ {
+ DBEVIEW_SUCCESS = 0,
+ DBEVIEW_NO_DATA,
+ DBEVIEW_IO_ERROR,
+ DBEVIEW_BAD_DATA,
+ DBEVIEW_BAD_SYMBOL_DATA,
+ DBEVIEW_NO_SEL_OBJ
+ };
+ static char *status_str (DbeView_status status);
+
+ bool
+ isOmpDisMode ()
+ {
+ return ompDisMode;
+ }
+
+ void
+ setOmpDisMode ()
+ {
+ ompDisMode = true;
+ }
+
+ void
+ resetOmpDisMode ()
+ {
+ ompDisMode = false;
+ }
+
+ bool
+ isShowHideChanged ()
+ {
+ return showHideChanged;
+ }
+
+ void
+ setShowHideChanged ()
+ {
+ showHideChanged = true;
+ }
+
+ void
+ resetShowHideChanged ()
+ {
+ showHideChanged = false;
+ }
+
+ bool
+ isNewViewMode ()
+ {
+ return newViewMode;
+ }
+
+ void
+ setNewViewMode ()
+ {
+ newViewMode = true;
+ }
+
+ void
+ resetNewViewMode ()
+ {
+ newViewMode = false;
+ }
+
+ bool
+ isFilterHideMode ()
+ {
+ return filterHideMode;
+ }
+
+ void
+ setFilterHideMode ()
+ {
+ filterHideMode = true;
+ }
+
+ void
+ resetFilterHideMode ()
+ {
+ filterHideMode = false;
+ }
+
+ bool
+ isShowAll ()
+ {
+ return showAll;
+ }
+
+ void
+ setShowAll ()
+ {
+ showAll = true;
+ }
+
+ void
+ resetShowAll ()
+ {
+ showAll = false;
+ }
+ void resetAndConstructShowHideStacks ();
+
+private:
+ void init ();
+ Metric *get_compare_metric (Metric *mtr, int groupNum);
+
+ // methods controlling old-style filtering
+ FilterSet *get_filter_set (int n);
+
+ void purge_events (int n = -1);
+
+ char *cur_filter_str;
+ char *prev_filter_str;
+ Expression *cur_filter_expr;
+ bool noParFilter;
+
+ // MemorySpace's -- added when a request is made; for now, never dropped
+ Vector<MemorySpace*> *memspaces;
+ MemorySpace *addMemorySpace (int mtype);
+
+ Vector<FilterSet*> *filters;
+ Vector<enum LibExpand> *lo_expands;
+ Vector<BaseMetric*> *reg_metrics; // vector of registered metrics
+ Vector<MetricList*> *metrics_lists; // metrics list of MET_NORMAL, MET_CALL...
+ // note: includes compare metrics
+ Vector<MetricList*> *metrics_ref_lists;
+ DerivedMetrics *derived_metrics; // vector of derived metrics
+
+ DataSpace *dspace;
+ PathTree *ptree;
+ Vector<PathTree *> *indxspaces;
+ IOActivity *iospace;
+ HeapActivity *heapspace;
+ int phaseIdx;
+ bool ompDisMode;
+ bool filterHideMode;
+ bool showAll;
+ bool showHideChanged;
+ bool newViewMode;
+
+ // Filtered events
+ Vector<Vector<DataView*>*> *dataViews; //outer idx is exp_id, inner is data_id
+ Settings *settings;
+
+ Application *app;
+ Function *convert_line_to_func (DbeLine *dbeLine);
+ DbeInstr *convert_line_to_instr (DbeLine *dbeLine);
+ DbeInstr *convert_func_to_instr (Function *func);
+ DbeInstr *lastSelInstr;
+ Function *lastSelFunc;
+ void constructShowHideStack (DataDescriptor* dDscr, Experiment *exp);
+ void resetAndConstructShowHideStack (Experiment *exp);
+};
+
+#endif /* _DBEVIEW_H */
diff --git a/gprofng/src/DefaultHandler.h b/gprofng/src/DefaultHandler.h
new file mode 100644
index 0000000..4c3d82c
--- /dev/null
+++ b/gprofng/src/DefaultHandler.h
@@ -0,0 +1,114 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * org/xml/sax/helpers/DefaultHandler.java
+ * Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _DefaultHandler_h
+#define _DefaultHandler_h
+
+/*
+ * org/xml/sax/Attributes.java
+ */
+class Attributes
+{
+public:
+ virtual ~Attributes () { };
+
+ virtual int getLength () = 0;
+ virtual const char *getQName (int index) = 0;
+ virtual const char *getValue (int index) = 0;
+ virtual int getIndex (const char *qName) = 0;
+ virtual const char *getValue (const char *qName) = 0;
+};
+
+/*
+ * org/xml/sax/SAXException.java
+ */
+class SAXException
+{
+public:
+ SAXException ();
+ SAXException (const char *message);
+ virtual ~SAXException ();
+ char *getMessage ();
+
+private:
+ char *message;
+};
+
+class SAXParseException : public SAXException
+{
+public:
+ SAXParseException (char *message, int lineNumber, int columnNumber);
+
+ int
+ getLineNumber ()
+ {
+ return lineNumber;
+ }
+
+ int
+ getColumnNumber ()
+ {
+ return columnNumber;
+ }
+
+private:
+ int lineNumber;
+ int columnNumber;
+};
+
+class DefaultHandler
+{
+public:
+ virtual ~DefaultHandler () { };
+
+ virtual void startDocument () = 0;
+ virtual void endDocument () = 0;
+ virtual void startElement (char *uri, char *localName, char *qName,
+ Attributes *attributes) = 0;
+ virtual void endElement (char *uri, char *localName, char *qName) = 0;
+ virtual void characters (char *ch, int start, int length) = 0;
+ virtual void ignorableWhitespace (char *ch, int start, int length) = 0;
+
+ virtual void
+ warning (SAXParseException *e)
+ {
+ delete e;
+ }
+
+ virtual void
+ error (SAXParseException *e)
+ {
+ delete e;
+ }
+
+ virtual void
+ fatalError (SAXParseException *e)
+ {
+ throw ( e);
+ }
+ void dump_startElement (const char *qName, Attributes *attributes);
+};
+
+#endif /* _DefaultHandler_h */
diff --git a/gprofng/src/DefaultMap.h b/gprofng/src/DefaultMap.h
new file mode 100644
index 0000000..4a87fcc
--- /dev/null
+++ b/gprofng/src/DefaultMap.h
@@ -0,0 +1,232 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_DEFAULTMAP_H
+#define _DBE_DEFAULTMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+
+template <typename Key_t, typename Value_t>
+class DefaultMap : public Map<Key_t, Value_t>
+{
+public:
+
+ DefaultMap ();
+ ~DefaultMap ();
+ void clear ();
+ void put (Key_t key, Value_t val);
+ Value_t get (Key_t key);
+ Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
+ Value_t remove (Key_t);
+ Vector<Key_t> *keySet ();
+ Vector<Value_t> *values ();
+
+private:
+
+ struct Entry
+ {
+ Key_t key;
+ Value_t val;
+ };
+
+ static const int CHUNK_SIZE;
+ static const int HTABLE_SIZE;
+
+ int entries;
+ int nchunks;
+ Entry **chunks;
+ Vector<Entry*> *index;
+ Entry **hashTable;
+};
+
+
+template <typename Key_t, typename Value_t>
+const int DefaultMap<Key_t, Value_t>::CHUNK_SIZE = 16384;
+template <typename Key_t, typename Value_t>
+const int DefaultMap<Key_t, Value_t>::HTABLE_SIZE = 1024;
+
+template <typename Key_t, typename Value_t>
+DefaultMap<Key_t, Value_t>::DefaultMap ()
+{
+ entries = 0;
+ nchunks = 0;
+ chunks = NULL;
+ index = new Vector<Entry*>;
+ hashTable = new Entry*[HTABLE_SIZE];
+ for (int i = 0; i < HTABLE_SIZE; i++)
+ hashTable[i] = NULL;
+}
+
+template <typename Key_t, typename Value_t>
+DefaultMap<Key_t, Value_t>::~DefaultMap ()
+{
+ for (int i = 0; i < nchunks; i++)
+ delete[] chunks[i];
+ delete[] chunks;
+ delete index;
+ delete[] hashTable;
+}
+
+template <typename Key_t, typename Value_t>
+void
+DefaultMap<Key_t, Value_t>::clear ()
+{
+ entries = 0;
+ index->reset ();
+ for (int i = 0; i < HTABLE_SIZE; i++)
+ hashTable[i] = NULL;
+}
+
+template <typename Key_t>
+inline unsigned
+hash (Key_t key)
+{
+ unsigned h = (unsigned) ((unsigned long) key);
+ h ^= (h >> 20) ^ (h >> 12);
+ return (h ^ (h >> 7) ^ (h >> 4));
+}
+
+template <typename Key_t, typename Value_t>
+void
+DefaultMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+ unsigned idx = hash (key) % HTABLE_SIZE;
+ Entry *entry = hashTable[idx];
+ if (entry && entry->key == key)
+ {
+ entry->val = val;
+ return;
+ }
+ int lo = 0;
+ int hi = entries - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ entry = index->fetch (md);
+ int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+ if (cmp < 0)
+ lo = md + 1;
+ else if (cmp > 0)
+ hi = md - 1;
+ else
+ {
+ entry->val = val;
+ return;
+ }
+ }
+ if (entries >= nchunks * CHUNK_SIZE)
+ {
+ nchunks++;
+ // Reallocate Entry chunk array
+ Entry **new_chunks = new Entry*[nchunks];
+ for (int i = 0; i < nchunks - 1; i++)
+ new_chunks[i] = chunks[i];
+ delete[] chunks;
+ chunks = new_chunks;
+
+ // Allocate new chunk for entries.
+ chunks[nchunks - 1] = new Entry[CHUNK_SIZE];
+ }
+ entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE];
+ entry->key = key;
+ entry->val = val;
+ index->insert (lo, entry);
+ hashTable[idx] = entry;
+ entries++;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+DefaultMap<Key_t, Value_t>::get (Key_t key)
+{
+ unsigned idx = hash (key) % HTABLE_SIZE;
+ Entry *entry = hashTable[idx];
+ if (entry && entry->key == key)
+ return entry->val;
+
+ int lo = 0;
+ int hi = entries - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ entry = index->fetch (md);
+ int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+ if (cmp < 0)
+ lo = md + 1;
+ else if (cmp > 0)
+ hi = md - 1;
+ else
+ {
+ hashTable[idx] = entry;
+ return entry->val;
+ }
+ }
+ return (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+DefaultMap<Key_t, Value_t>::get (Key_t key,
+ typename Map<Key_t, Value_t>::Relation rel)
+{
+ if (rel != Map<Key_t, Value_t>::REL_EQ)
+ return (Value_t) 0;
+ return get (key);
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+DefaultMap<Key_t, Value_t>::remove (Key_t)
+{
+ // Not implemented
+ if (1)
+ assert (0);
+ return (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Vector<Value_t> *
+DefaultMap<Key_t, Value_t>::values ()
+{
+ Vector<Value_t> *vals = new Vector<Value_t>(entries);
+ for (int i = 0; i < entries; ++i)
+ {
+ Entry *entry = index->fetch (i);
+ vals->append (entry->val);
+ }
+ return vals;
+}
+
+template <typename Key_t, typename Value_t>
+Vector<Key_t> *
+DefaultMap<Key_t, Value_t>::keySet ()
+{
+ Vector<Key_t> *keys = new Vector<Key_t>(entries);
+ for (int i = 0; i < entries; ++i)
+ {
+ Entry *entry = index->fetch (i);
+ keys->append (entry->key);
+ }
+ return keys;
+}
+
+#endif
diff --git a/gprofng/src/DefaultMap2D.h b/gprofng/src/DefaultMap2D.h
new file mode 100644
index 0000000..8045aad
--- /dev/null
+++ b/gprofng/src/DefaultMap2D.h
@@ -0,0 +1,147 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_DEFAULTMAP2D_H
+#define _DBE_DEFAULTMAP2D_H
+
+#include <assert.h>
+#include <vec.h>
+#include <DefaultMap.h>
+#include <IntervalMap.h>
+#include <Map2D.h>
+
+/*
+ * Default Map2D implementation.
+ *
+ * Default Map2D is a cartesian product of two default Maps.
+ */
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+class DefaultMap2D : public Map2D<Key1_t, Key2_t, Value_t>
+{
+public:
+ DefaultMap2D ();
+ DefaultMap2D (typename Map2D<Key1_t, Key2_t, Value_t>::MapType _type);
+ ~DefaultMap2D ();
+ void put (Key1_t key1, Key2_t key2, Value_t val);
+ Value_t get (Key1_t key1, Key2_t key2);
+ Value_t get (Key1_t key1, Key2_t key2,
+ typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel);
+ Value_t remove (Key1_t, Key2_t);
+
+private:
+ typename Map2D<Key1_t, Key2_t, Value_t>::MapType type;
+ Map<Key1_t, Map<Key2_t, Value_t>*> *map1;
+ Vector<Map<Key2_t, Value_t>*> *map2list;
+};
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+DefaultMap2D<Key1_t, Key2_t, Value_t>::DefaultMap2D ()
+{
+ type = Map2D<Key1_t, Key2_t, Value_t>::Default;
+ map1 = new DefaultMap<Key1_t, Map<Key2_t, Value_t>*>;
+ map2list = new Vector<Map<Key2_t, Value_t>*>;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+DefaultMap2D<Key1_t, Key2_t, Value_t>::DefaultMap2D (
+ typename Map2D<Key1_t, Key2_t, Value_t>::MapType _type)
+{
+ type = _type;
+ map1 = new DefaultMap<Key1_t, Map<Key2_t, Value_t>*>;
+ map2list = new Vector<Map<Key2_t, Value_t>*>;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+DefaultMap2D<Key1_t, Key2_t, Value_t>::~DefaultMap2D ()
+{
+ map2list->destroy ();
+ delete map2list;
+ delete map1;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+void
+DefaultMap2D<Key1_t, Key2_t, Value_t>::put (Key1_t key1, Key2_t key2, Value_t val)
+{
+ Map<Key2_t, Value_t> *map2 = map1->get (key1);
+ if (map2 == NULL)
+ {
+ if (type == Map2D<Key1_t, Key2_t, Value_t>::Interval)
+ map2 = new IntervalMap<Key2_t, Value_t>;
+ else
+ map2 = new DefaultMap<Key2_t, Value_t>;
+ map2list->append (map2);
+ map1->put (key1, map2);
+ }
+ map2->put (key2, val);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+DefaultMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2)
+{
+ Map<Key2_t, Value_t> *map2 = map1->get (key1);
+ if (map2 == NULL)
+ return (Value_t) 0;
+ return map2->get (key2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+DefaultMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2,
+ typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel)
+{
+ Map<Key2_t, Value_t> *map2 = map1->get (key1);
+ if (map2 == NULL)
+ return (Value_t) 0;
+ typename Map<Key2_t, Value_t>::Relation rel2;
+ switch (rel)
+ {
+ case Map2D<Key1_t, Key2_t, Value_t>::REL_EQLT:
+ rel2 = map2->REL_LT;
+ break;
+ case Map2D<Key1_t, Key2_t, Value_t>::REL_EQLE:
+ rel2 = map2->REL_LE;
+ break;
+ case Map2D<Key1_t, Key2_t, Value_t>::REL_EQGE:
+ rel2 = map2->REL_GE;
+ break;
+ case Map2D<Key1_t, Key2_t, Value_t>::REL_EQGT:
+ rel2 = map2->REL_GT;
+ break;
+ default:
+ rel2 = map2->REL_EQ;
+ break;
+ }
+ return map2->get (key2, rel2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+DefaultMap2D<Key1_t, Key2_t, Value_t>::remove (Key1_t, Key2_t)
+{
+ // Not implemented
+ if (1)
+ assert (0);
+ return (Value_t) 0;
+}
+
+#endif
diff --git a/gprofng/src/DerivedMetrics.cc b/gprofng/src/DerivedMetrics.cc
new file mode 100644
index 0000000..9f504a5
--- /dev/null
+++ b/gprofng/src/DerivedMetrics.cc
@@ -0,0 +1,293 @@
+/* Copyright (C) 2021 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 <strings.h>
+#include "DerivedMetrics.h"
+#include "util.h"
+
+enum opType
+{
+ opNULL,
+ opPrimitive,
+ opDivide
+};
+
+class definition
+{
+public:
+ definition();
+ ~definition();
+ char *name;
+ char *def;
+ opType op;
+ definition *arg1;
+ definition *arg2;
+ int index;
+};
+
+definition::definition ()
+{
+ name = def = NULL;
+ arg1 = arg2 = NULL;
+}
+
+definition::~definition ()
+{
+ free (name);
+ free (def);
+}
+
+DerivedMetrics::DerivedMetrics ()
+{
+ items = new Vector<definition*>;
+}
+
+DerivedMetrics::~DerivedMetrics ()
+{
+ Destroy (items);
+}
+
+definition *
+DerivedMetrics::add_definition (char *_name, char *_username, char *_def)
+{
+ definition *p;
+
+ // if the name doesn't matter, maybe there is a duplicate we can use
+ if (_name == NULL)
+ {
+ int i;
+ Vec_loop (definition*, items, i, p)
+ {
+ if (strcmp (p->def, _def) == 0)
+ return p;
+ }
+ }
+
+ p = new definition;
+ p->name = dbe_strdup (_name);
+ p->def = dbe_strdup (_def);
+
+ // parse the definition
+ if (strchr (_def, '/') == NULL)
+ {
+ // it's a primitive metric
+ p->op = opPrimitive;
+ p->arg1 = p->arg2 = NULL;
+
+ }
+ else
+ {
+ // it's some operation on arguments
+ p->op = opDivide;
+ char *op_ptr = strchr (p->def, '/');
+ *op_ptr = 0;
+ p->arg1 = add_definition (NULL, NULL, p->def);
+ *op_ptr = '/';
+ p->arg2 = add_definition (NULL, NULL, op_ptr + 1);
+ }
+ p->index = items->size ();
+ items->append (p);
+ return p;
+}
+
+int *
+DerivedMetrics::construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st, char *expr_spec)
+{
+ if (items == NULL)
+ return NULL;
+ int ndm = items->size ();
+ if (ndm == 0)
+ return NULL;
+ int nmetrics = mitems->size ();
+
+ // allocate arrays for the mapping between derived metrics and requested values
+ int *map = (int *) malloc (ndm * sizeof (int));
+
+ // map derived metrics to requested metrics // EUGENE explain this more clearly
+ // 0 means not mapped
+ // >0 means primitive metric maps to map-1
+ // <0 means derived metric maps to 1-map
+ int ndm_requested = 0;
+ for (int idm = 0; idm < ndm; idm++)
+ {
+ definition *defdm = items->fetch (idm);
+ map[idm] = 0;
+
+ // figure out what name to use for this derived metric
+ char *dname;
+ if (defdm->op == opPrimitive)
+ dname = defdm->def;
+ else
+ {
+ dname = defdm->name;
+ if (dname == NULL) break;
+ }
+
+ // look for this name among metrics
+ int im;
+ for (im = 0; im < nmetrics; im++)
+ {
+ Metric *m = mitems->fetch (im);
+ if (strcmp (dname, m->get_cmd ()) == 0 && m->get_subtype () == st)
+ // apparent match, but let's check comparison mode
+ if (dbe_strcmp (expr_spec, m->get_expr_spec ()) == 0)
+ break;
+ }
+
+ // encode the mapping
+ if (im >= nmetrics)
+ map[idm] = 0; // does not map to requested metrics
+ else if (defdm->op == opPrimitive)
+ map[idm] = +1 + im; // encode as a positive index
+ else
+ {
+ map[idm] = -1 - im; // encode as a negative index
+ ndm_requested++;
+ }
+ }
+ if (ndm_requested == 0)
+ {
+ free (map);
+ map = NULL;
+ }
+ return map;
+}
+
+void
+DerivedMetrics::fill_dependencies (definition *def, int *vec)
+{
+ switch (def->op)
+ {
+ case opPrimitive:
+ vec[def->index] = 1;
+ break;
+ case opDivide:
+ fill_dependencies (def->arg1, vec);
+ fill_dependencies (def->arg2, vec);
+ break;
+ default:
+ break;
+ }
+}
+
+Vector<definition*> *
+DerivedMetrics::get_dependencies (definition *def)
+{
+ int n = items->size ();
+
+ // zero out a vector representing definitions
+ int *vec = (int *) malloc (n * sizeof (int));
+ for (int i = 0; i < n; i++)
+ vec[i] = 0;
+ fill_dependencies (def, vec);
+
+ // construct the dependency vector
+ Vector<definition*> *dependencies = new Vector<definition*>;
+ for (int i = 0; i < n; i++)
+ if (vec[i] == 1)
+ dependencies->append (items->fetch (i));
+ free (vec);
+ return dependencies;
+}
+
+void
+DerivedMetrics::dump (FILE *dis_file, int verbosity)
+{
+ int i;
+ definition *item;
+
+ // deal with the possibility that names might be NULL
+ const char *UNNAMED = "(unnamed)";
+#define NAME(x) ( (x) ? (x) : UNNAMED)
+
+ Vec_loop (definition*, items, i, item)
+ {
+ // at low verbosity, skip over some items
+ if (verbosity == 0)
+ {
+ if (item->name == NULL)
+ continue;
+ if (strcmp (item->name, item->def) && item->op == opPrimitive)
+ continue;
+ }
+
+ // dump the definition
+ switch (item->op)
+ {
+ case opPrimitive:
+ fprintf (dis_file, "%s [%s] is a primitive metric\n", NAME (item->name),
+ item->def);
+ break;
+ case opDivide:
+ fprintf (dis_file, "%s [%s] = %s [%s] / %s [%s]\n", NAME (item->name),
+ item->def, NAME (item->arg1->name), item->arg1->def,
+ NAME (item->arg2->name), item->arg2->def);
+ break;
+ default:
+ fprintf (dis_file, "%s [%s] has an unrecognized op %d\n",
+ NAME (item->name), item->def, item->op);
+ break;
+ }
+ }
+}
+
+double
+DerivedMetrics::eval_one_item (definition *def, int *map, double *values)
+{
+ switch (def->op)
+ {
+ case opNULL:
+ fprintf (stderr, GTXT ("cannot eval NULL expression\n"));
+ return 0.;
+ case opPrimitive:
+ {
+ int ival = map[def->index];
+ if (ival <= 0) return 0.;
+ ival--;
+ return values[ival];
+ }
+ case opDivide:
+ {
+ double x1 = eval_one_item (def->arg1, map, values);
+ double x2 = eval_one_item (def->arg2, map, values);
+ if (x2 == 0) return 0.;
+ return (x1 / x2);
+ }
+ default:
+ fprintf (stderr, GTXT ("unknown expression\n"));
+ return 0.;
+ }
+}
+
+int
+DerivedMetrics::eval (int *map, double *values)
+{
+ for (int i = 0, n = items->size (); i < n; i++)
+ {
+ if (map[i] < 0)
+ {
+ int ival = -1 - map[i];
+ values[ival] = eval_one_item (items->fetch (i), map, values);
+ }
+ }
+ return 0;
+}
+
diff --git a/gprofng/src/DerivedMetrics.h b/gprofng/src/DerivedMetrics.h
new file mode 100644
index 0000000..b457e5e
--- /dev/null
+++ b/gprofng/src/DerivedMetrics.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DERIVEDMETRICS_H
+#define _DERIVEDMETRICS_H
+
+#include <stdio.h>
+#include "BaseMetric.h"
+#include "Metric.h"
+
+class definition;
+
+class DerivedMetrics
+{
+public:
+ DerivedMetrics ();
+ ~DerivedMetrics ();
+ definition *add_definition (char *_name, char *_username, char *_def);
+ int *construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st,
+ char *expr_spec);
+ void dump (FILE *dis_file, int verbosity);
+ double eval_one_item (definition *def, int *map, double *values);
+ int eval (int *map, double *values);
+ void fill_dependencies (definition *def, int *vec);
+ Vector<definition*> *get_dependencies (definition *def);
+
+ Vector<definition*> *
+ get_items ()
+ {
+ return items;
+ }
+
+private:
+ Vector<definition*> *items;
+};
+
+#endif
diff --git a/gprofng/src/Disasm.cc b/gprofng/src/Disasm.cc
new file mode 100644
index 0000000..0fec9c3
--- /dev/null
+++ b/gprofng/src/Disasm.cc
@@ -0,0 +1,403 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include "disassemble.h"
+#include "dis-asm.h"
+#include "demangle.h"
+#include "dbe_types.h"
+#include "DbeSession.h"
+#include "Elf.h"
+#include "Disasm.h"
+#include "Stabs.h"
+#include "i18n.h"
+#include "util.h"
+#include "StringBuilder.h"
+
+struct DisContext
+{
+ bool is_Intel;
+ Stabs *stabs;
+ uint64_t pc; // first_pc <= pc < last_pc
+ uint64_t first_pc;
+ uint64_t last_pc;
+ uint64_t f_offset; // file offset for first_pc
+ int codeptr[4]; // longest instruction length may not be > 16
+ Data_window *elf;
+};
+
+static const int MAX_DISASM_STR = 2048;
+static const int MAX_INSTR_SIZE = 8;
+
+Disasm::Disasm (char *fname)
+{
+ dwin = NULL;
+ dis_str = NULL;
+ need_swap_endian = false;
+ my_stabs = Stabs::NewStabs (fname, fname);
+ if (my_stabs == NULL)
+ return;
+ stabs = my_stabs;
+ platform = stabs->get_platform ();
+ disasm_open ();
+}
+
+Disasm::Disasm (Platform_t _platform, Stabs *_stabs)
+{
+ dwin = NULL;
+ dis_str = NULL;
+ need_swap_endian = false;
+ stabs = _stabs;
+ platform = _platform;
+ my_stabs = NULL;
+ disasm_open ();
+}
+
+static int
+fprintf_func (void *arg, const char *fmt, ...)
+{
+ char buf[512];
+ va_list vp;
+ va_start (vp, fmt);
+ int cnt = vsnprintf (buf, sizeof (buf), fmt, vp);
+ va_end (vp);
+
+ Disasm *dis = (Disasm *) arg;
+ dis->dis_str->append (buf);
+ return cnt;
+}
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+ Transfer them to myaddr. */
+static int
+read_memory_func (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+ disassemble_info *info)
+{
+ unsigned int opb = info->octets_per_byte;
+ size_t end_addr_offset = length / opb;
+ size_t max_addr_offset = info->buffer_length / opb;
+ size_t octets = (memaddr - info->buffer_vma) * opb;
+ if (memaddr < info->buffer_vma
+ || memaddr - info->buffer_vma > max_addr_offset
+ || memaddr - info->buffer_vma + end_addr_offset > max_addr_offset
+ || (info->stop_vma && (memaddr >= info->stop_vma
+ || memaddr + end_addr_offset > info->stop_vma)))
+ return -1;
+ memcpy (myaddr, info->buffer + octets, length);
+ return 0;
+}
+
+static void
+print_address_func (bfd_vma addr, disassemble_info *info)
+{
+ (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long) addr);
+}
+
+static asymbol *
+symbol_at_address_func (bfd_vma addr ATTRIBUTE_UNUSED,
+ disassemble_info *info ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+static bfd_boolean
+symbol_is_valid (asymbol * sym ATTRIBUTE_UNUSED,
+ disassemble_info *info ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+static void
+memory_error_func (int status, bfd_vma addr, disassemble_info *info)
+{
+ info->fprintf_func (info->stream, "Address 0x%llx is out of bounds.\n",
+ (unsigned long long) addr);
+}
+
+void
+Disasm::disasm_open ()
+{
+ hex_visible = 1;
+ snprintf (addr_fmt, sizeof (addr_fmt), NTXT ("%s"), NTXT ("%8llx: "));
+ if (dis_str == NULL)
+ dis_str = new StringBuilder;
+
+ switch (platform)
+ {
+ case Aarch64:
+ case Intel:
+ case Amd64:
+ need_swap_endian = (DbeSession::platform == Sparc);
+ break;
+ case Sparcv8plus:
+ case Sparcv9:
+ case Sparc:
+ default:
+ need_swap_endian = (DbeSession::platform != Sparc);
+ break;
+ }
+
+ memset (&dis_info, 0, sizeof (dis_info));
+ dis_info.flavour = bfd_target_unknown_flavour;
+ dis_info.endian = BFD_ENDIAN_UNKNOWN;
+ dis_info.endian_code = dis_info.endian;
+ dis_info.octets_per_byte = 1;
+ dis_info.disassembler_needs_relocs = FALSE;
+ dis_info.fprintf_func = fprintf_func;
+ dis_info.stream = this;
+ dis_info.disassembler_options = NULL;
+ dis_info.read_memory_func = read_memory_func;
+ dis_info.memory_error_func = memory_error_func;
+ dis_info.print_address_func = print_address_func;
+ dis_info.symbol_at_address_func = symbol_at_address_func;
+ dis_info.symbol_is_valid = symbol_is_valid;
+ dis_info.display_endian = BFD_ENDIAN_UNKNOWN;
+ dis_info.symtab = NULL;
+ dis_info.symtab_size = 0;
+ dis_info.buffer_vma = 0;
+ switch (platform)
+ {
+ case Aarch64:
+ dis_info.arch = bfd_arch_aarch64;
+ dis_info.mach = bfd_mach_aarch64;
+ break;
+ case Intel:
+ case Amd64:
+ dis_info.arch = bfd_arch_i386;
+ dis_info.mach = bfd_mach_x86_64;
+ break;
+ case Sparcv8plus:
+ case Sparcv9:
+ case Sparc:
+ default:
+ dis_info.arch = bfd_arch_unknown;
+ dis_info.endian = BFD_ENDIAN_UNKNOWN;
+ break;
+ }
+ dis_info.display_endian = dis_info.endian = BFD_ENDIAN_BIG;
+ dis_info.display_endian = dis_info.endian = BFD_ENDIAN_LITTLE;
+ dis_info.display_endian = dis_info.endian = BFD_ENDIAN_UNKNOWN;
+ disassemble_init_for_target (&dis_info);
+}
+
+Disasm::~Disasm ()
+{
+ delete my_stabs;
+ delete dwin;
+ delete dis_str;
+}
+
+void
+Disasm::set_img_name (char *img_fname)
+{
+ if (stabs == NULL && img_fname && dwin == NULL)
+ {
+ dwin = new Data_window (img_fname);
+ if (dwin->not_opened ())
+ {
+ delete dwin;
+ dwin = NULL;
+ return;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+ }
+}
+
+void
+Disasm::remove_disasm_hndl (void *hndl)
+{
+ DisContext *ctx = (DisContext *) hndl;
+ delete ctx;
+}
+
+#if 0
+int
+Disasm::get_instr_size (uint64_t vaddr, void *hndl)
+{
+ DisContext *ctx = (DisContext *) hndl;
+ if (ctx == NULL || vaddr < ctx->first_pc || vaddr >= ctx->last_pc)
+ return -1;
+ ctx->pc = vaddr;
+ size_t sz = ctx->is_Intel ? sizeof (ctx->codeptr) : 4;
+ if (sz > ctx->last_pc - vaddr)
+ sz = (size_t) (ctx->last_pc - vaddr);
+ if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc),
+ sz, ctx->codeptr) == NULL)
+ return -1;
+
+ char buf[MAX_DISASM_STR];
+ *buf = 0;
+ uint64_t inst_vaddr = vaddr;
+#if MEZ_NEED_TO_FIX
+ size_t instrs_cnt = 0;
+ disasm_err_code_t status = disasm (handle, &inst_vaddr, ctx->last_pc, 1,
+ ctx, buf, sizeof (buf), &instrs_cnt);
+ if (instrs_cnt != 1 || status != disasm_err_ok)
+ return -1;
+#endif
+ return (int) (inst_vaddr - vaddr);
+}
+#endif
+
+void
+Disasm::set_addr_end (uint64_t end_address)
+{
+ char buf[32];
+ int len = snprintf (buf, sizeof (buf), "%llx", (long long) end_address);
+ snprintf (addr_fmt, sizeof (addr_fmt), "%%%dllx: ", len < 8 ? 8 : len);
+}
+
+char *
+Disasm::get_disasm (uint64_t inst_address, uint64_t end_address,
+ uint64_t start_address, uint64_t f_offset, int64_t &inst_size)
+{
+ inst_size = 0;
+ if (inst_address >= end_address)
+ return NULL;
+ Data_window *dw = stabs ? stabs->openElf (false) : dwin;
+ if (dw == NULL)
+ return NULL;
+
+ unsigned char buffer[MAX_DISASM_STR];
+ dis_info.buffer = buffer;
+ dis_info.buffer_length = end_address - inst_address;
+ if (dis_info.buffer_length > sizeof (buffer))
+ dis_info.buffer_length = sizeof (buffer);
+ dw->get_data (f_offset + (inst_address - start_address),
+ dis_info.buffer_length, dis_info.buffer);
+
+ dis_str->setLength (0);
+ bfd abfd;
+ disassembler_ftype disassemble = disassembler (dis_info.arch, dis_info.endian,
+ dis_info.mach, &abfd);
+ if (disassemble == NULL)
+ {
+ printf ("ERROR: unsupported disassemble\n");
+ return NULL;
+ }
+ inst_size = disassemble (0, &dis_info);
+ if (inst_size <= 0)
+ {
+ inst_size = 0;
+ return NULL;
+ }
+ StringBuilder sb;
+ sb.appendf (addr_fmt, inst_address); // Write address
+
+ // Write hex bytes of instruction
+ if (hex_visible)
+ {
+ char bytes[64];
+ *bytes = '\0';
+ for (int i = 0; i < inst_size; i++)
+ {
+ unsigned int hex_value = buffer[i] & 0xff;
+ snprintf (bytes + 3 * i, sizeof (bytes) - 3 * i, "%02x ", hex_value);
+ }
+ const char *fmt = "%s ";
+ if (platform == Intel)
+ fmt = "%-21s "; // 21 = 3 * 7 - maximum instruction length on Intel
+ sb.appendf (fmt, bytes);
+ }
+ sb.append (dis_str);
+#if MEZ_NEED_TO_FIX
+ // Write instruction
+ if (ctx.is_Intel) // longest instruction length for Intel is 7
+ sb.appendf (NTXT ("%-7s %s"), parts_array[1], parts_array[2]);
+ else // longest instruction length for SPARC is 11
+ sb.appendf (NTXT ("%-11s %s"), parts_array[1], parts_array[2]);
+ if (strcmp (parts_array[1], NTXT ("call")) == 0)
+ {
+ if (strncmp (parts_array[2], NTXT ("0x"), 2) == 0)
+ sb.append (GTXT ("\t! (Unable to determine target symbol)"));
+ }
+#endif
+ return sb.toString ();
+}
+
+#if MEZ_NEED_TO_FIX
+void *
+Disasm::get_inst_ptr (disasm_handle_t, uint64_t vaddr, void *pass_through)
+{
+ // Actually it fetches only one instruction at a time for sparc,
+ // and one byte at a time for intel.
+ DisContext *ctx = (DisContext*) pass_through;
+ size_t sz = ctx->is_Intel ? 1 : 4;
+ if (vaddr + sz > ctx->last_pc)
+ {
+ ctx->codeptr[0] = -1;
+ return ctx->codeptr;
+ }
+ if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc), sz, ctx->codeptr) == NULL)
+ {
+ ctx->codeptr[0] = -1;
+ return ctx->codeptr;
+ }
+ if (ctx->elf->need_swap_endian && !ctx->is_Intel)
+ ctx->codeptr[0] = ctx->elf->decode (ctx->codeptr[0]);
+ return ctx->codeptr;
+}
+
+// get a symbol name for an address
+disasm_err_code_t
+Disasm::get_sym_name (disasm_handle_t, // an open disassembler handle
+ uint64_t target_address, // the target virtual address
+ uint64_t inst_address, // virtual address of instruction
+ // being disassembled
+ int use_relocation, // flag to use relocation information
+ char *buffer, // places the symbol here
+ size_t buffer_size, // limit on symbol length
+ int *, // sys/elf_{SPARC.386}.h
+ uint64_t *offset, // from the symbol to the address
+ void *pass_through) // disassembler context
+{
+ char buf[MAXPATHLEN];
+ if (!use_relocation)
+ return disasm_err_symbol;
+
+ DisContext *ctxp = (DisContext*) pass_through;
+ char *name = NULL;
+ if (ctxp->stabs)
+ {
+ uint64_t addr = ctxp->f_offset + (inst_address - ctxp->first_pc);
+ name = ctxp->stabs->sym_name (target_address, addr, use_relocation);
+ }
+ if (name == NULL)
+ return disasm_err_symbol;
+
+ char *s = NULL;
+ if (*name == '_')
+ s = cplus_demangle (name, DMGL_PARAMS);
+ if (s)
+ {
+ snprintf (buffer, buffer_size, NTXT ("%s"), s);
+ free (s);
+ }
+ else
+ snprintf (buffer, buffer_size, NTXT ("%s"), name);
+
+ *offset = 0;
+ return disasm_err_ok;
+}
+#endif
diff --git a/gprofng/src/Disasm.h b/gprofng/src/Disasm.h
new file mode 100644
index 0000000..c1530cc
--- /dev/null
+++ b/gprofng/src/Disasm.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DISASM_H
+#define _DISASM_H
+
+#include "disassemble.h"
+
+class Data_window;
+class Stabs;
+class StringBuilder;
+enum Platform_t;
+
+class Disasm
+{
+public:
+ Disasm (char *fname);
+ Disasm (Platform_t _platform, Stabs *_stabs);
+ ~Disasm ();
+ void remove_disasm_hndl (void *hndl);
+ void *get_disasm_hndl (uint64_t vaddr, uint64_t f_offset, size_t size);
+ int get_instr_size (uint64_t vaddr, void *hndl);
+ void set_addr_end (uint64_t end_address);
+
+ void
+ set_hex_visible (int set)
+ {
+ hex_visible = set;
+ }
+
+ char *get_disasm (uint64_t inst_address, uint64_t end_address,
+ uint64_t start_address, uint64_t f_offset, int64_t &inst_size);
+ void set_img_name (char *fname); // Only for dynfunc
+
+ StringBuilder *dis_str;
+
+private:
+ void disasm_open ();
+
+ disassemble_info dis_info;
+ Data_window *dwin;
+ Stabs *stabs, *my_stabs;
+ Platform_t platform;
+ char addr_fmt[32];
+ int hex_visible;
+ bool need_swap_endian;
+};
+
+#endif /* _DISASM_H */
diff --git a/gprofng/src/Dwarf.cc b/gprofng/src/Dwarf.cc
new file mode 100644
index 0000000..eb8bd9e
--- /dev/null
+++ b/gprofng/src/Dwarf.cc
@@ -0,0 +1,1041 @@
+/* Copyright (C) 2021 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 "Elf.h"
+#include "Stabs.h"
+#include "Dwarf.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "DefaultMap.h"
+
+static int
+datatypeCmp (const void *a, const void *b)
+{
+ uint32_t o1 = ((datatype_t *) a)->datatype_id;
+ uint32_t o2 = ((datatype_t *) b)->datatype_id;
+ return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+static int
+targetOffsetCmp (const void *a, const void *b)
+{
+ uint32_t o1 = ((target_info_t *) a)->offset;
+ uint32_t o2 = ((target_info_t *) b)->offset;
+ return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+
+//////////////////////////////////////////////////////////
+// class Dwr_type
+class Dwr_type
+{
+public:
+
+ Dwr_type (int64_t _cu_die_offset, int _tag)
+ {
+ cu_die_offset = _cu_die_offset;
+ tag = _tag;
+ name = NULL;
+ dobj_name = NULL;
+ dtype = NULL;
+ extent = 0;
+ parent = 0;
+ child = 0;
+ next = 0;
+ ref_type = 0;
+ size = 0;
+ elems = 0;
+ offset = -1;
+ bit_size = 0;
+ };
+
+ char *name, *dobj_name;
+ int64_t cu_die_offset, ref_type, extent, parent, child, next;
+ int64_t size, elems, offset;
+ int tag, bit_size;
+
+ DataObject *get_dobj (Dwarf_cnt *ctx);
+ char *get_dobjname (Dwarf_cnt *ctx);
+ char *dump ();
+
+private:
+ datatype_t *dtype;
+ datatype_t *get_datatype (Dwarf_cnt *ctx);
+ void get_dobj_for_members (Dwarf_cnt *ctx);
+ void set_dobjname (char *spec, char *nm);
+};
+
+
+//////////////////////////////////////////////////////////
+// class Dwarf_cnt
+Dwarf_cnt::Dwarf_cnt ()
+{
+ cu_offset = 0;
+ parent = 0;
+ module = NULL;
+ name = NULL;
+ func = NULL;
+ fortranMAIN = NULL;
+ dwr_types = NULL;
+ inlinedSubr = NULL;
+ level = 0;
+}
+
+Dwr_type *
+Dwarf_cnt::get_dwr_type (int64_t cu_die_offset)
+{
+ Dwr_type *t = dwr_types->get (cu_die_offset);
+ if (t == NULL)
+ {
+ Dprintf (DUMP_DWARFLIB, "DWARF_ERROR: %s:%d wrong cu_die_offset=%lld in Dwarf_cnt::get_dwr_type\n",
+ get_basename (__FILE__), (int) __LINE__,
+ (long long) cu_die_offset);
+ t = put_dwr_type (cu_die_offset, 0); // DOBJ_UNSPECIFIED
+ }
+ return t;
+}
+
+Dwr_type *
+Dwarf_cnt::put_dwr_type (int64_t cu_die_offset, int tag)
+{
+ Dwr_type *t = new Dwr_type (cu_die_offset, tag);
+ dwr_types->put (cu_die_offset, t);
+ return t;
+}
+
+Dwr_type *
+Dwarf_cnt::put_dwr_type (Dwr_Tag *dwrTag)
+{
+ Dwr_type *t = new Dwr_type (dwrTag->die, dwrTag->tag);
+ dwr_types->put (dwrTag->die, t);
+ return t;
+}
+
+//////////////////////////////////////////////////////////
+// class Dwr_type
+char *
+Dwr_type::dump ()
+{
+ char *s = dbe_sprintf ("%lld %-15s name='%s' parent=%lld next=%lld child=%lld dtype=%llx",
+ (long long) cu_die_offset, DwrCU::tag2str (tag),
+ STR (name), (long long) parent, (long long) next,
+ (long long) child, (long long) dtype);
+ return s;
+}
+
+void
+Dwr_type::set_dobjname (char *spec, char *nm)
+{
+ if (spec)
+ {
+ if (nm)
+ dobj_name = dbe_sprintf ("%s%s", spec, nm);
+ else
+ dobj_name = dbe_sprintf ("%s<ANON=%lld>", spec,
+ (long long) cu_die_offset);
+ }
+ else
+ {
+ if (nm)
+ dobj_name = dbe_sprintf ("%s", nm);
+ else
+ dobj_name = dbe_sprintf ("<ANON=%lld>", (long long) cu_die_offset);
+ }
+}
+
+char *
+Dwr_type::get_dobjname (Dwarf_cnt *ctx)
+{
+ if (dobj_name)
+ return dobj_name;
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ set_dobjname (NULL, name);
+ for (int i = 0, len = (int) strlen (dobj_name); i < len; i++)
+ {
+ if (dobj_name[i] == ' ')
+ dobj_name[i] = '_';
+ }
+ break;
+ case DW_TAG_constant:
+ case DW_TAG_formal_parameter:
+ case DW_TAG_variable:
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ set_dobjname (NULL, t->get_dobjname (ctx));
+ break;
+ }
+ case DW_TAG_unspecified_type:
+ set_dobjname (NTXT ("unspecified:"), name);
+ break;
+ case DW_TAG_enumeration_type:
+ set_dobjname (NTXT ("enumeration:"), name);
+ break;
+ case DW_TAG_typedef:
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ dobj_name = dbe_sprintf ("%s=%s", name, t->get_dobjname (ctx));
+ break;
+ }
+ case DW_TAG_const_type:
+ set_dobjname (NTXT ("const+"), name);
+ break;
+ case DW_TAG_volatile_type:
+ set_dobjname (NTXT ("volatile+"), name);
+ break;
+ case DW_TAG_pointer_type:
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ set_dobjname (NTXT ("pointer+"), t->get_dobjname (ctx));
+ break;
+ }
+ case DW_TAG_reference_type:
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ set_dobjname (NTXT ("reference+"), t->get_dobjname (ctx));
+ break;
+ }
+ case DW_TAG_array_type:
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ if (elems > 0)
+ dobj_name = dbe_sprintf ("array[%lld]:%s",
+ (long long) elems, t->get_dobjname (ctx));
+ else
+ dobj_name = dbe_sprintf ("array[]:%s", t->get_dobjname (ctx));
+ break;
+ }
+ case DW_TAG_structure_type:
+ set_dobjname (NTXT ("structure:"), name);
+ break;
+ case DW_TAG_union_type:
+ set_dobjname (NTXT ("union:"), name);
+ break;
+ case DW_TAG_class_type:
+ set_dobjname (NTXT ("class:"), name);
+ break;
+ case DW_TAG_member:
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ if (bit_size > 0)
+ dobj_name = dbe_sprintf (NTXT ("%s:%lld"), t->get_dobjname (ctx),
+ (long long) bit_size);
+ else
+ dobj_name = dbe_sprintf (NTXT ("%s"), t->get_dobjname (ctx));
+ break;
+ }
+ default:
+ Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d No case for %s cu_die_offset=%lld\n"),
+ get_basename (__FILE__), (int) __LINE__,
+ DwrCU::tag2str (tag), (long long) cu_die_offset);
+ set_dobjname (NTXT ("Undefined:"), NULL);
+ break;
+ }
+ return dobj_name;
+}
+
+datatype_t*
+Dwr_type::get_datatype (Dwarf_cnt *ctx)
+{
+ if (dtype)
+ return dtype;
+ dtype = new datatype_t;
+ dtype->datatype_id = (unsigned) cu_die_offset;
+ dtype->memop_refs = 0;
+ dtype->event_data = 0;
+ dtype->dobj = NULL;
+ ctx->module->datatypes->incorporate (dtype, datatypeCmp);
+ return dtype;
+}
+
+DataObject *
+Dwr_type::get_dobj (Dwarf_cnt *ctx)
+{
+ if (dtype == NULL)
+ dtype = get_datatype (ctx);
+ dtype->memop_refs++;
+ DataObject *dobj = dtype->dobj;
+ if (dobj)
+ return dobj;
+
+ if (tag == 0)
+ dobj = dbeSession->find_dobj_by_name (PTXT (DOBJ_UNSPECIFIED));
+ else
+ {
+ dobj = dbeSession->createDataObject ();
+ dobj->size = size;
+ dobj->offset = offset;
+ dobj->scope = ctx->func ? (Histable*) ctx->func : (Histable*) ctx->module;
+ }
+ dtype->dobj = dobj;
+ if (parent)
+ {
+ Dwr_type *t = ctx->get_dwr_type (parent);
+ dobj->parent = t->get_dobj (ctx);
+ }
+
+ if (ref_type)
+ {
+ Dwr_type *t = ctx->get_dwr_type (ref_type);
+ t->get_dobj (ctx);
+ if (size == 0)
+ {
+ size = t->size;
+ dobj->size = size;
+ }
+ }
+
+ switch (tag)
+ {
+ case 0:
+ break;
+ case DW_TAG_array_type:
+ case DW_TAG_base_type:
+ case DW_TAG_unspecified_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ dobj->set_dobjname (get_dobjname (ctx), NULL);
+ break;
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ dobj->set_dobjname (get_dobjname (ctx), NULL);
+ dobj->master = dbeSession->find_dobj_by_name (dobj_name);
+ get_dobj_for_members (ctx);
+ break;
+ case DW_TAG_constant:
+ case DW_TAG_formal_parameter:
+ case DW_TAG_member:
+ case DW_TAG_variable:
+ if (dobj->parent == NULL)
+ dobj->parent = dbeSession->get_Scalars_DataObject ();
+ dobj->set_dobjname (get_dobjname (ctx), name);
+ break;
+ default:
+ Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d No case for %s cu_die_offset=%lld\n"),
+ get_basename (__FILE__), (int) __LINE__,
+ DwrCU::tag2str (tag), (long long) cu_die_offset);
+ break;
+ }
+ return dobj;
+}
+
+void
+Dwr_type::get_dobj_for_members (Dwarf_cnt *ctx)
+{
+ for (int64_t i = child; i != 0;)
+ {
+ Dwr_type *t = ctx->get_dwr_type (i);
+ t->get_dobj (ctx);
+ i = t->next;
+ }
+}
+
+//////////////////////////////////////////////////////////
+// class Dwarf
+Dwarf::Dwarf (Stabs *_stabs)
+{
+ stabs = _stabs;
+ status = Stabs::DBGD_ERR_NONE;
+ dwrCUs = 0;
+ debug_infoSec = NULL;
+ debug_abbrevSec = NULL;
+ debug_strSec = NULL;
+ debug_lineSec = NULL;
+ debug_rangesSec = NULL;
+ elf = stabs->openElf (true);
+ if (elf == NULL)
+ {
+ status = Stabs::DBGD_ERR_BAD_ELF_FORMAT;
+ return;
+ }
+ debug_infoSec = dwrGetSec (NTXT (".debug_info"));
+ if (debug_infoSec)
+ {
+ debug_infoSec->reloc = ElfReloc::get_elf_reloc (elf, NTXT (".rela.debug_info"), NULL);
+ debug_infoSec->reloc = ElfReloc::get_elf_reloc (elf, NTXT (".rel.debug_info"), debug_infoSec->reloc);
+ if (debug_infoSec->reloc)
+ debug_infoSec->reloc->dump ();
+ }
+ debug_abbrevSec = dwrGetSec (NTXT (".debug_abbrev"));
+ debug_strSec = dwrGetSec (NTXT (".debug_str"));
+ debug_lineSec = dwrGetSec (NTXT (".debug_line"));
+ debug_rangesSec = dwrGetSec (NTXT (".debug_ranges"));
+
+ if ((debug_infoSec == NULL) || (debug_abbrevSec == NULL) || (debug_lineSec == NULL))
+ {
+ status = Stabs::DBGD_ERR_NO_DWARF;
+ return;
+ }
+}
+
+Dwarf::~Dwarf ()
+{
+ delete debug_infoSec;
+ delete debug_abbrevSec;
+ delete debug_strSec;
+ delete debug_lineSec;
+ delete debug_rangesSec;
+ Destroy (dwrCUs);
+}
+
+DwrSec *
+Dwarf::dwrGetSec (const char *sec_name)
+{
+ int secN = elf->elf_get_sec_num (sec_name);
+ if (secN > 0)
+ {
+ Elf_Data *elfData = elf->elf_getdata (secN);
+ if (elfData)
+ return new DwrSec ((unsigned char *) elfData->d_buf, elfData->d_size,
+ elf->need_swap_endian,
+ elf->elf_getclass () == ELFCLASS32);
+ }
+ return NULL;
+}
+
+uint64_t
+DwrCU::get_low_pc ()
+{
+ uint64_t pc = Dwarf_addr (DW_AT_low_pc);
+ if (pc)
+ return pc;
+ return pc;
+}
+
+char *
+DwrCU::get_linkage_name ()
+{
+ char *nm = Dwarf_string (DW_AT_linkage_name);
+ if (nm != NULL)
+ return nm;
+ nm = Dwarf_string (DW_AT_SUN_link_name);
+ if (nm != NULL)
+ return nm;
+ return Dwarf_string (DW_AT_MIPS_linkage_name);
+}
+
+void
+DwrCU::parseChild (Dwarf_cnt *ctx)
+{
+ if (!dwrTag.hasChild)
+ return;
+ uint64_t old_size = debug_infoSec->size;
+ uint64_t next_die_offset = 0;
+ Dwarf_Die next_die;
+ if (read_ref_attr (DW_AT_sibling, &next_die) == DW_DLV_OK)
+ {
+ next_die_offset = next_die + cu_offset;
+ if (next_die_offset <= debug_infoSec->offset)
+ {
+ Dprintf (DEBUG_ERR_MSG, NTXT ("DwrCU::parseChild: next_die(0x%llx) <= debug_infoSec->offset(%llx)\n"),
+ (long long) next_die, (long long) debug_infoSec->offset);
+ next_die_offset = 0;
+ }
+ else if (debug_infoSec->size > next_die_offset)
+ debug_infoSec->size = next_die_offset;
+ }
+ dwrTag.level++;
+ ctx->level++;
+ for (;;)
+ {
+ if (set_die (0) != DW_DLV_OK)
+ break;
+ Function *func;
+ char *old_name;
+ int hasChild = dwrTag.hasChild;
+ switch (dwrTag.tag)
+ {
+ case DW_TAG_imported_declaration:
+ if (Stabs::is_fortran (ctx->module->lang_code))
+ {
+ char *link_name = Dwarf_string (DW_AT_name);
+ ctx->fortranMAIN = NULL;
+ parseChild (ctx);
+ hasChild = 0;
+ if (ctx->fortranMAIN)
+ {
+ ctx->fortranMAIN->set_match_name (link_name);
+ ctx->fortranMAIN = NULL;
+ }
+ }
+ break;
+ case DW_TAG_subprogram:
+ if (dwrTag.get_attr (DW_AT_abstract_origin))
+ break;
+ if (dwrTag.get_attr (DW_AT_declaration))
+ {
+ // Only declaration
+ if (Stabs::is_fortran (ctx->module->lang_code))
+ {
+ char *link_name = Dwarf_string (DW_AT_name);
+ if (link_name && streq (link_name, NTXT ("MAIN")))
+ ctx->fortranMAIN = Stabs::find_func (NTXT ("MAIN"), ctx->module->functions, true, true);
+ }
+ if (get_linkage_name () == NULL)
+ break;
+ }
+ func = append_Function (ctx);
+ if (func)
+ {
+ if (Stabs::is_fortran (ctx->module->lang_code) &&
+ streq (func->get_match_name (), NTXT ("MAIN")))
+ ctx->fortranMAIN = func;
+ old_name = ctx->name;
+ Function *old_func = ctx->func;
+ ctx->name = func->get_match_name ();
+ ctx->func = func;
+ parseChild (ctx);
+ hasChild = 0;
+ ctx->name = old_name;
+ ctx->func = old_func;
+ }
+ break;
+ case DW_TAG_module:
+ old_name = ctx->name;
+ ctx->name = Dwarf_string (DW_AT_SUN_link_name);
+ parseChild (ctx);
+ hasChild = 0;
+ ctx->name = old_name;
+ break;
+ case DW_TAG_class_type:
+ old_name = ctx->name;
+ ctx->name = Dwarf_string (DW_AT_name);
+ parseChild (ctx);
+ hasChild = 0;
+ ctx->name = old_name;
+ break;
+ case DW_TAG_structure_type:
+ old_name = ctx->name;
+ ctx->name = NULL;
+ parseChild (ctx);
+ hasChild = 0;
+ ctx->name = old_name;
+ break;
+ case DW_TAG_namespace:
+ old_name = ctx->name;
+ ctx->name = Dwarf_string (DW_AT_name);
+ parseChild (ctx);
+ hasChild = 0;
+ ctx->name = old_name;
+ break;
+ case DW_TAG_lexical_block:
+ old_name = ctx->name;
+ ctx->name = NULL;
+ parseChild (ctx);
+ hasChild = 0;
+ ctx->name = old_name;
+ break;
+ case DW_TAG_SUN_memop_info:
+ isMemop = true;
+ break;
+ case DW_TAG_inlined_subroutine:
+ if (ctx->module)
+ {
+ parse_inlined_subroutine (ctx);
+ hasChild = 0;
+ }
+ break;
+ default: // No more special cases
+ break;
+ }
+ if (hasChild)
+ parseChild (ctx);
+ }
+ ctx->level--;
+ dwrTag.level--;
+ if (next_die_offset != 0)
+ debug_infoSec->offset = next_die_offset;
+ debug_infoSec->size = old_size;
+}
+
+bool
+Dwarf::archive_Dwarf (LoadObject *lo)
+{
+ if (debug_infoSec == NULL)
+ return false;
+ if (dwrCUs)
+ return true;
+ dwrCUs = new Vector<DwrCU *>;
+
+ debug_infoSec->offset = 0;
+ while (debug_infoSec->offset < debug_infoSec->sizeSec)
+ {
+ DwrCU *dwrCU = new DwrCU (this);
+ dwrCUs->append (dwrCU);
+ debug_infoSec->size = debug_infoSec->sizeSec;
+ debug_infoSec->offset = dwrCU->next_cu_offset;
+
+ if (dwrCU->set_die (dwrCU->cu_header_offset) != DW_DLV_OK)
+ {
+ Dprintf (1, "DwrCU::archive_Dwarf: CU=%lld (offset=0x%llx); set_die(0x%llx) failed\n",
+ (long long) dwrCUs->size (), (long long) dwrCU->cu_offset,
+ (long long) dwrCU->cu_header_offset);
+ continue;
+ }
+
+ Module *mod = dwrCU->parse_cu_header (lo);
+ if (mod)
+ {
+ mod->hdrOffset = dwrCUs->size ();
+ DwrLineRegs *lineReg = dwrCU->get_dwrLineReg ();
+ dwrCU->srcFiles = new Vector<SourceFile *> (VecSize (lineReg->file_names));
+ for (long i = 0, sz = VecSize (lineReg->file_names); i < sz; i++)
+ {
+ char *fname = lineReg->getPath (i + 1);
+ SourceFile *sf = mod->findSource (fname, true);
+ dwrCU->srcFiles->append (sf);
+ }
+
+ Dwarf_cnt ctx;
+ ctx.module = mod;
+ dwrCU->parseChild (&ctx);
+ if (dwrCU->dwrInlinedSubrs && DUMP_DWARFLIB)
+ {
+ char msg[128];
+ char *lo_name = mod->loadobject ? mod->loadobject->get_name ()
+ : NULL;
+ snprintf (msg, sizeof (msg), NTXT ("\ndwrCUs[%lld]: %s:%s\n"),
+ (long long) dwrCUs->size (),
+ STR (lo_name), STR (mod->get_name ()));
+ dwrCU->dwrInlinedSubrs->dump (msg);
+ }
+ }
+ }
+ return true;
+}
+
+void
+Dwarf::srcline_Dwarf (Module *module)
+{
+ if (module == NULL || module->hdrOffset == 0)
+ return;
+ DwrCU *dwrCU = dwrCUs->get (module->hdrOffset - 1);
+ dwrCU->map_dwarf_lines (module);
+}
+
+
+// parse hwcprof info for given module in loadobject
+
+void
+Dwarf::read_hwcprof_info (Module *module)
+{
+ if (module->datatypes || (module->hdrOffset == 0))
+ return;
+ DwrCU *dwrCU = dwrCUs->get (module->hdrOffset - 1);
+ if (!dwrCU->isMemop)
+ return;
+ module->datatypes = new Vector<datatype_t*>;
+ if (dwrCU->set_die (dwrCU->cu_header_offset) != DW_DLV_OK)
+ {
+ Dprintf (1, "Dwarf::read_hwcprof_info: CU=%lld (offset=0x%llx); set_die(0x%llx) failed\n",
+ (long long) module->hdrOffset, (long long) dwrCU->cu_offset,
+ (long long) dwrCU->cu_header_offset);
+ return;
+ }
+ Dwarf_cnt ctx;
+ ctx.module = module;
+ ctx.cu_offset = dwrCU->cu_offset; // CU header offset;
+ ctx.dwr_types = new DefaultMap<int64_t, Dwr_type*>;
+ ctx.put_dwr_type (0, 0); // for DOBJ_UNSPECIFIED
+ dwrCU->read_hwcprof_info (&ctx);
+
+ Vector<inst_info_t*> *infoList = module->infoList;
+ Dprintf (DUMP_DWARFLIB,
+ "\n\n ### Dwarf::read_hwcprof_info: module: '%s' infoList->size()=%lld\n",
+ STR (module->get_name ()),
+ (long long) (infoList ? infoList->size () : -1));
+ for (int i = 0, sz = infoList ? infoList->size () : -1; i < sz; i++)
+ {
+ inst_info_t *ip = infoList->fetch (i);
+ memop_info_t *mp = ip->memop;
+ Dwr_type *t = ctx.get_dwr_type (mp->datatype_id);
+ t->get_dobj (&ctx);
+ }
+
+#ifdef DEBUG
+ Dprintf (DUMP_DWARFLIB,
+ "\n\n ### Dwarf::read_hwcprof_info: '%s' infoList->size()=%lld\n",
+ STR (module->get_name ()),
+ (long long) (infoList ? infoList->size () : 1));
+ for (int i = 0, sz = infoList ? infoList->size () : -1; i < sz; i++)
+ {
+ inst_info_t *ip = infoList->fetch (i);
+ memop_info_t *mp = ip->memop;
+ Dprintf (DUMP_DWARFLIB,
+ " %d id=%lld offset=%lld signature=%lld datatype_id=%lld \n",
+ i, (long long) mp->id, (long long) mp->offset,
+ (long long) mp->signature, (long long) mp->datatype_id);
+ }
+
+ Vector<int64_t> *keys = ctx.dwr_types->keySet ();
+ Dprintf (DUMP_DWARFLIB,
+ "\n\n ### Dwarf::read_hwcprof_info: '%s' keys->size()=%lld\n",
+ STR (module->get_name ()), (long long) (keys ? keys->size () : -1));
+ for (int i = 0, sz = keys->size (); i < sz; i++)
+ {
+ int64_t ind = keys->fetch (i);
+ Dwr_type *t = ctx.get_dwr_type (ind);
+ Dprintf (DUMP_DWARFLIB, NTXT (" %d %lld %s\n"), i,
+ (long long) ind, t->dump ());
+ }
+#endif
+}
+
+void
+DwrCU::read_hwcprof_info (Dwarf_cnt *ctx)
+{
+ if (!dwrTag.hasChild)
+ return;
+ uint64_t old_size = debug_infoSec->size;
+ uint64_t next_die_offset = 0;
+ Dwarf_Die next_die;
+ if (read_ref_attr (DW_AT_sibling, &next_die) == DW_DLV_OK)
+ {
+ next_die_offset = next_die + cu_offset;
+ if (next_die_offset <= debug_infoSec->offset)
+ next_die_offset = 0;
+ else if (debug_infoSec->size > next_die_offset)
+ debug_infoSec->size = next_die_offset;
+ }
+ dwrTag.level++;
+ ctx->level++;
+ for (;;)
+ {
+ if (set_die (0) != DW_DLV_OK)
+ break;
+ Dprintf (DUMP_DWARFLIB, NTXT ("%s:%d <%lld:%lld> cu_die=%lld %-15s\n"),
+ get_basename (__FILE__), (int) __LINE__, (long long) ctx->level,
+ (long long) dwrTag.die, (long long) dwrTag.offset,
+ DwrCU::tag2str (dwrTag.tag));
+ switch (dwrTag.tag)
+ {
+ case DW_TAG_SUN_memop_info:
+ {
+ if (ctx->func == NULL)
+ break;
+ Dwarf_Unsigned mid = Dwarf_data (DW_AT_SUN_profile_id);
+ Dwarf_Unsigned off = Dwarf_data (DW_AT_SUN_func_offset);
+ Dwarf_Unsigned sig = Dwarf_data (DW_AT_SUN_memop_signature);
+ Dwarf_Off ref = Dwarf_ref (DW_AT_SUN_memop_type_ref);
+
+ // define memop entry
+ memop_info_t *memop = new memop_info_t;
+ memop->id = (unsigned) mid;
+ memop->signature = (unsigned) sig;
+ memop->datatype_id = ref ? (unsigned) ref : 0;
+ memop->offset = (unsigned) (ctx->func->img_offset + off);
+
+ // define instop entry
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_PREFETCH; // XXXX UNKNOWN
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ if (ctx->module->infoList == NULL)
+ ctx->module->infoList = new Vector<inst_info_t*>;
+ ctx->module->infoList->append (instop);
+ break;
+ }
+ case DW_TAG_SUN_codeflags:
+ {
+ if (ctx->func == NULL)
+ break;
+ Dwarf_Unsigned kind = Dwarf_data (DW_AT_SUN_cf_kind);
+ if (kind == DW_ATCF_SUN_branch_target)
+ {
+ DwrSec *secp = Dwarf_block (DW_AT_SUN_func_offsets);
+ if (secp)
+ {
+ int foffset = 0;
+ for (int i = 0; secp->offset < secp->size; i++)
+ {
+ int val = (int) secp->GetSLEB128 ();
+ if (i == 0 || val != 0)
+ {
+ foffset += val;
+ target_info_t *t = new target_info_t;
+ t->offset = (unsigned) (ctx->func->img_offset + foffset);
+ ctx->module->bTargets.incorporate (t, targetOffsetCmp);
+ }
+ }
+ delete(secp);
+ }
+ }
+ break;
+ }
+ case DW_TAG_subprogram:
+ {
+ Function *old_func = ctx->func;
+ if (dwrTag.get_attr (DW_AT_abstract_origin)
+ || dwrTag.get_attr (DW_AT_declaration))
+ ctx->func = NULL;
+ else
+ ctx->func = append_Function (ctx);
+ read_hwcprof_info (ctx);
+ ctx->func = old_func;
+ break;
+ }
+ case DW_TAG_base_type:
+ {
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->size = Dwarf_data (DW_AT_byte_size);
+ break;
+ }
+ case DW_TAG_unspecified_type:
+ ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ break;
+ case DW_TAG_enumeration_type:
+ {
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->size = Dwarf_data (DW_AT_byte_size);
+ break;
+ }
+ case DW_TAG_constant:
+ case DW_TAG_formal_parameter:
+ case DW_TAG_variable:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_volatile_type:
+ {
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->ref_type = Dwarf_ref (DW_AT_type);
+ break;
+ }
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ {
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->ref_type = Dwarf_ref (DW_AT_type);
+ t->size = (dwarf->stabs->get_class () == W64) ? 8 : 4;
+ break;
+ }
+ case DW_TAG_array_type:
+ {
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->ref_type = Dwarf_ref (DW_AT_type);
+ t->size = Dwarf_data (DW_AT_byte_size);
+ ctx->size = -1;
+ read_hwcprof_info (ctx);
+ t->elems = ctx->size;
+ break;
+ }
+ case DW_TAG_subrange_type:
+ {
+ int64_t ref_type = Dwarf_ref (DW_AT_type);
+ int64_t hi = Dwarf_data (DW_AT_upper_bound);
+ int64_t lo = Dwarf_data (DW_AT_lower_bound);
+ int64_t ss = Dwarf_data (DW_AT_stride_size);
+ ctx->size = 1 + hi - lo;
+ if (ss != 0)
+ ctx->size /= ss;
+ Dprintf (DUMP_DWARFLIB,
+ "Got subrange [%lld:%lld:%lld] indexed <%lld>: size=%lld\n",
+ (long long) lo, (long long) hi, (long long) ss,
+ (long long) ref_type, (long long) ctx->size);
+ break;
+ }
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->size = Dwarf_data (DW_AT_byte_size);
+ t->extent = Dwarf_ref (DW_AT_sibling);
+ int64_t old_parent = ctx->parent;
+ ctx->parent = t->cu_die_offset;
+
+ char *old_name = ctx->name;
+ ctx->name = (dwrTag.tag == DW_TAG_class_type) ? Dwarf_string (DW_AT_name) : NULL;
+ read_hwcprof_info (ctx);
+ ctx->name = old_name;
+ ctx->parent = old_parent;
+ // Reverse children
+ for (int64_t i = t->child, last = 0; i != 0;)
+ {
+ Dwr_type *t1 = ctx->get_dwr_type (i);
+ t->child = i;
+ i = t1->next;
+ t1->next = last;
+ last = t->child;
+ }
+ break;
+ }
+ case DW_TAG_member:
+ {
+ if (ctx->parent == 0)
+ {
+ Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d %s cu_die_offset=%lld\n"),
+ get_basename (__FILE__), (int) __LINE__,
+ DwrCU::tag2str (dwrTag.tag), (long long) dwrTag.die);
+ break;
+ }
+ Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+ t->name = Dwarf_string (DW_AT_name);
+ t->ref_type = Dwarf_ref (DW_AT_type);
+ t->offset = Dwarf_location (DW_AT_data_member_location);
+ Dwr_type *parent = ctx->get_dwr_type (ctx->parent);
+ t->parent = ctx->parent;
+ t->next = parent->child; // a reverse order of members
+ parent->child = t->cu_die_offset;
+ t->bit_size = (uint32_t) Dwarf_data (DW_AT_bit_size);
+ break;
+ }
+ case DW_TAG_module:
+ {
+ char *old_name = ctx->name;
+ ctx->name = Dwarf_string (DW_AT_SUN_link_name);
+ read_hwcprof_info (ctx);
+ ctx->name = old_name;
+ break;
+ }
+ case DW_TAG_namespace:
+ {
+ char *old_name = ctx->name;
+ ctx->name = Dwarf_string (DW_AT_name);
+ read_hwcprof_info (ctx);
+ ctx->name = old_name;
+ break;
+ }
+ case DW_TAG_lexical_block:
+ {
+ char *old_name = ctx->name;
+ ctx->name = NULL;
+ read_hwcprof_info (ctx);
+ ctx->name = old_name;
+ break;
+ }
+ default: // No more special cases
+ read_hwcprof_info (ctx);
+ break;
+ }
+ }
+ ctx->level--;
+ dwrTag.level--;
+ if (next_die_offset != 0)
+ debug_infoSec->offset = next_die_offset;
+ debug_infoSec->size = old_size;
+}
+
+// Append function to module
+Function *
+DwrCU::append_Function (Dwarf_cnt *ctx)
+{
+ char *outerName = ctx->name, *name, tmpname[2048];
+ Function *func;
+ char *fname = Dwarf_string (DW_AT_name);
+ if (fname && outerName && !strchr (fname, '.'))
+ {
+ size_t outerlen = strlen (outerName);
+ if (outerlen > 0 && outerName[outerlen - 1] == '_')
+ {
+ outerlen--;
+ snprintf (tmpname, sizeof (tmpname), NTXT ("%s"), outerName);
+ snprintf (tmpname + outerlen, sizeof (tmpname) - outerlen, NTXT (".%s_"), fname);
+ }
+ else
+ snprintf (tmpname, sizeof (tmpname), NTXT ("%s.%s"), outerName, fname);
+ name = tmpname;
+ Dprintf (DUMP_DWARFLIB, NTXT ("Generated innerfunc name %s\n"), name);
+ }
+ else
+ name = fname;
+
+ char *link_name = get_linkage_name ();
+ if (link_name == NULL)
+ link_name = name;
+
+ uint64_t pc = get_low_pc ();
+ func = dwarf->stabs->append_Function (module, link_name, pc);
+ if (func != NULL)
+ {
+ int lineno = (int) Dwarf_data (DW_AT_decl_line);
+ func->set_match_name (name);
+ if (lineno > 0)
+ {
+ func->setLineFirst (lineno);
+ if (dwrLineReg == NULL)
+ dwrLineReg = new DwrLineRegs (new DwrSec (dwarf->debug_lineSec,
+ stmt_list_offset), comp_dir);
+ int fileno = ((int) Dwarf_data (DW_AT_decl_file)) - 1;
+ SourceFile *sf = ((fileno >= 0) && (fileno < VecSize (srcFiles))) ? srcFiles->get (fileno)
+ : module->getMainSrc ();
+ func->setDefSrc (sf);
+ func->pushSrcFile (func->def_source, 0);
+ func->popSrcFile ();
+ }
+ }
+ return func;
+}
+
+// Get language code
+Sp_lang_code
+DwrCU::Dwarf_lang ()
+{
+ char *str = Dwarf_string (DW_AT_producer);
+ if (str && strncmp (str, NTXT ("GNU"), 3) == 0)
+ isGNU = true;
+ int64_t lang = Dwarf_data (DW_AT_language);
+ switch (lang)
+ {
+ case DW_LANG_C89:
+ case DW_LANG_C:
+ return Sp_lang_c; // Sp_lang_ansic?
+ case DW_LANG_C99:
+ return Sp_lang_c99;
+ case DW_LANG_C_plus_plus:
+ return isGNU ? Sp_lang_gcc : Sp_lang_cplusplus;
+ case DW_LANG_Fortran90:
+ return Sp_lang_fortran90;
+ case DW_LANG_Fortran77:
+ return Sp_lang_fortran;
+ case DW_LANG_Java:
+ return Sp_lang_java;
+ case DW_LANG_Mips_Assembler:
+ case DW_LANG_SUN_Assembler:
+ return Sp_lang_asm;
+ case DW_LANG_Pascal83:
+ return Sp_lang_pascal;
+ default:
+ case DW_LANG_Ada83:
+ case DW_LANG_Cobol74:
+ case DW_LANG_Cobol85:
+ case DW_LANG_Modula2:
+ case DW_LANG_Ada95:
+ case DW_LANG_Fortran95:
+ case DW_LANG_lo_user:
+ return Sp_lang_unknown;
+ }
+}
diff --git a/gprofng/src/Dwarf.h b/gprofng/src/Dwarf.h
new file mode 100644
index 0000000..12ffbc0
--- /dev/null
+++ b/gprofng/src/Dwarf.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _Dwarf_h_
+#define _Dwarf_h_ 1
+
+#include "dwarf2.h"
+
+#include "Stabs.h"
+#include "dbe_structs.h"
+#include "DwarfLib.h"
+
+enum
+{
+ /* ICC extensions */
+ DW_AT_icc_flags = 0x3b01,
+ DW_TAG_icc_compile_unit = 0x7000,
+
+ /* Sun extensions */
+ DW_ATCF_SUN_branch_target = 0x46,
+ DW_AT_SUN_command_line = 0x2205,
+ DW_AT_SUN_func_offsets = 0x2211,
+ DW_AT_SUN_cf_kind = 0x2212,
+ DW_AT_SUN_func_offset = 0x2216,
+ DW_AT_SUN_memop_type_ref = 0x2217,
+ DW_AT_SUN_profile_id = 0x2218,
+ DW_AT_SUN_memop_signature = 0x2219,
+ DW_AT_SUN_obj_dir = 0x2220,
+ DW_AT_SUN_obj_file = 0x2221,
+ DW_AT_SUN_original_name = 0x2222,
+ DW_AT_SUN_link_name = 0x2226,
+
+ DW_TAG_SUN_codeflags = 0x4206,
+ DW_TAG_SUN_memop_info = 0x4207,
+ DW_TAG_SUN_dtor_info = 0x420a,
+ DW_TAG_SUN_dtor = 0x420b,
+
+ DW_LANG_SUN_Assembler = 0x9001
+};
+
+
+class LoadObject;
+class Module;
+class DwrCU;
+class DwrSec;
+
+class Dwarf
+{
+public:
+ Dwarf (Stabs *_stabs);
+ ~Dwarf ();
+ bool archive_Dwarf (LoadObject *lo);
+ void srcline_Dwarf (Module *module);
+ void read_hwcprof_info (Module *module);
+
+ Stabs::Stab_status status;
+ Vector<DwrCU *> *dwrCUs;
+ DwrSec *debug_infoSec;
+ DwrSec *debug_abbrevSec;
+ DwrSec *debug_strSec;
+ DwrSec *debug_lineSec;
+ DwrSec *debug_rangesSec;
+ Elf *elf;
+ Stabs *stabs;
+
+private:
+ DwrSec *dwrGetSec (const char *sec_name);
+};
+
+#endif /* _Dwarf_h_ */
diff --git a/gprofng/src/DwarfLib.cc b/gprofng/src/DwarfLib.cc
new file mode 100644
index 0000000..c8af0ab
--- /dev/null
+++ b/gprofng/src/DwarfLib.cc
@@ -0,0 +1,2203 @@
+/* Copyright (C) 2021 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 <ctype.h>
+
+#include "util.h"
+#include "Dwarf.h"
+#include "DwarfLib.h"
+#include "Elf.h"
+#include "Function.h"
+#include "Module.h"
+#include "StringBuilder.h"
+#include "DbeArray.h"
+#include "DbeSession.h"
+
+#define CASE_S(x) case x: s = (char *) #x; break
+
+static char *
+gelf_st_type2str (int type)
+{
+ static char buf[128];
+ char *s;
+ switch (type)
+ {
+ CASE_S (STT_NOTYPE);
+ CASE_S (STT_OBJECT);
+ CASE_S (STT_FUNC);
+ CASE_S (STT_SECTION);
+ CASE_S (STT_FILE);
+ CASE_S (STT_COMMON);
+ CASE_S (STT_TLS);
+ // CASE_S(STT_NUM);
+ CASE_S (STT_LOPROC);
+ CASE_S (STT_HIPROC);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, type);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+static char *
+special_opcode2str (int opcode)
+{
+ static char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("SpecialOpcode: %3d"), opcode);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+static char *
+extended_opcode2str (int opcode)
+{
+ static char buf[128];
+ char *s;
+ switch (opcode)
+ {
+ CASE_S (DW_LNE_end_sequence);
+ CASE_S (DW_LNE_set_address);
+ CASE_S (DW_LNE_define_file);
+ default:
+ snprintf (buf, sizeof (buf), NTXT ("??? (%d)"), opcode);
+ buf[sizeof (buf) - 1] = 0;
+ s = buf;
+ break;
+ }
+ return s;
+}
+
+static char *
+standard_opcode2str (int opcode)
+{
+ static char buf[128];
+ char *s;
+ switch (opcode)
+ {
+ CASE_S (DW_LNS_copy);
+ CASE_S (DW_LNS_advance_pc);
+ CASE_S (DW_LNS_advance_line);
+ CASE_S (DW_LNS_set_file);
+ CASE_S (DW_LNS_set_column);
+ CASE_S (DW_LNS_negate_stmt);
+ CASE_S (DW_LNS_set_basic_block);
+ CASE_S (DW_LNS_const_add_pc);
+ CASE_S (DW_LNS_fixed_advance_pc);
+ default:
+ snprintf (buf, sizeof (buf), NTXT ("??? (%d)"), opcode);
+ buf[sizeof (buf) - 1] = 0;
+ s = buf;
+ break;
+ }
+ return s;
+}
+
+template<> void Vector<DwrInlinedSubr *>
+::dump (const char *msg)
+{
+ Dprintf (1, NTXT ("%s Vector<DwrInlinedSubr *> [%lld]\n"),
+ msg ? msg : NTXT (""), (long long) size ());
+ for (long i = 0, sz = size (); i < sz; i++)
+ {
+ DwrInlinedSubr *p = get (i);
+ Dprintf (1, NTXT ("%ld: "), (long) i);
+ p->dump ();
+ }
+}
+
+template<> void Vector<DwrLine *>
+::dump (const char *msg)
+{
+ Dprintf (1, "%s Vector<DwrLine *> [%lld]:\n address [file line column]\n",
+ msg ? msg : NTXT (""), (long long) size ());
+ for (long i = 0, sz = size (); i < sz; i++)
+ {
+ DwrLine *lnp = get (i);
+ Dprintf (1, NTXT (" %2lld 0x%08llx [ %2lld, %lld, %lld ] \n"),
+ (long long) i, (long long) lnp->address, (long long) lnp->file,
+ (long long) lnp->line, (long long) lnp->column);
+ }
+ Dprintf (1, NTXT ("\n\n"));
+}
+
+//////////////////////////////////////////////////////////
+// class ElfReloc
+
+ElfReloc::ElfReloc (Elf *_elf)
+{
+ elf = _elf;
+ reloc = NULL;
+ cur_reloc_ind = 0;
+}
+
+ElfReloc::~ElfReloc ()
+{
+ if (reloc)
+ {
+ reloc->destroy ();
+ delete reloc;
+ }
+}
+
+void
+ElfReloc::dump_rela_debug_sec (int sec)
+{
+ if (!DUMP_RELA_SEC)
+ return;
+ Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+ if (shdr == NULL)
+ return;
+
+ Elf_Data *data = elf->elf_getdata (sec);
+ if (data == NULL)
+ return;
+
+ uint64_t ScnSize = data->d_size;
+ uint64_t EntSize = shdr->sh_entsize;
+ if (ScnSize == 0 || EntSize == 0)
+ return;
+
+ Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link);
+ if (shdr_sym == NULL)
+ return;
+ Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link);
+ Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link);
+ char *Strtab = data_str ? (char*) data_str->d_buf : NULL;
+ Elf_Internal_Rela rela;
+ int n, cnt = (int) (ScnSize / EntSize);
+
+ char *sec_name = elf->get_sec_name (sec);
+ if (sec_name == NULL) // It can not be, but let's check
+ return;
+ Dprintf (DUMP_RELA_SEC,
+ "======= DwarfLib::dump_rela_debug_sec Section:%2d '%s'\n",
+ sec, sec_name);
+ Dprintf (DUMP_RELA_SEC,
+ " N |addend| offset | r_info | stt_type |\n");
+ for (n = 0; n < cnt; n++)
+ {
+ if (strncmp (sec_name, NTXT (".rela."), 6) == 0)
+ elf->elf_getrela (data, n, &rela);
+ else
+ {
+ elf->elf_getrel (data, n, &rela);
+ rela.r_addend = 0;
+ }
+ int ndx = (int) GELF_R_SYM (rela.r_info);
+ Elf_Internal_Shdr *secHdr;
+ Elf_Internal_Sym sym;
+ elf->elf_getsym (data_sym, ndx, &sym);
+ Dprintf (DUMP_RELA_SEC, NTXT ("%3d:%5d |%11lld |0x%016llx | %-15s|"),
+ n, (int) rela.r_addend,
+ (long long) rela.r_offset, (long long) rela.r_info,
+ gelf_st_type2str ((int) GELF_ST_TYPE (sym.st_info)));
+ switch (GELF_ST_TYPE (sym.st_info))
+ {
+ case STT_FUNC:
+ case STT_OBJECT:
+ case STT_NOTYPE:
+ secHdr = elf->get_shdr (sym.st_shndx);
+ if (secHdr)
+ Dprintf (DUMP_RELA_SEC, NTXT (" img_offset=0x%llx"),
+ (long long) (sym.st_value + secHdr->sh_offset));
+ if (Strtab && sym.st_name)
+ Dprintf (DUMP_RELA_SEC, NTXT (" %s"), Strtab + sym.st_name);
+ break;
+ case STT_SECTION:
+ secHdr = elf->get_shdr (sym.st_shndx);
+ if (secHdr)
+ {
+ Dprintf (DUMP_RELA_SEC, NTXT (" value=0x%016llx (%lld)"),
+ (long long) (secHdr->sh_offset + rela.r_addend),
+ (long long) (secHdr->sh_offset + rela.r_addend));
+ }
+ break;
+ default:
+ break;
+ }
+ Dprintf (DUMP_RELA_SEC, NTXT ("\n"));
+ }
+ Dprintf (DUMP_RELA_SEC, NTXT ("\n"));
+}
+
+void
+ElfReloc::dump ()
+{
+ if (!DUMP_ELF_RELOC || (reloc == NULL) || (reloc->size () == 0))
+ return;
+ Dprintf (DUMP_ELF_RELOC, NTXT ("======= ElfReloc::dump\n"));
+ Dprintf (DUMP_ELF_RELOC, NTXT (" N | offset | value | STT_TYPE\n"));
+ for (int i = 0; i < reloc->size (); i++)
+ {
+ Sreloc *srlc = reloc->fetch (i);
+ Dprintf (DUMP_ELF_RELOC, NTXT ("%3d:%11lld |%11lld | %s\n"),
+ i, (long long) srlc->offset, (long long) srlc->value,
+ gelf_st_type2str (srlc->stt_type));
+ }
+ Dprintf (DUMP_ELF_RELOC, NTXT ("\n"));
+}
+
+static int
+DwrRelocOffsetCmp (const void *a, const void *b)
+{
+ ElfReloc::Sreloc *item1 = *((ElfReloc::Sreloc **) a);
+ ElfReloc::Sreloc *item2 = *((ElfReloc::Sreloc **) b);
+ return item1->offset < item2->offset ? -1 :
+ item1->offset == item2->offset ? 0 : 1;
+}
+
+ElfReloc *
+ElfReloc::get_elf_reloc (Elf *elfp, char *sec_name, ElfReloc *rlc)
+{
+ int et = elfp->elf_getehdr ()->e_type;
+ if (et == ET_EXEC || et == ET_DYN)
+ return rlc;
+ int sec = elfp->elf_get_sec_num (sec_name);
+ if (sec == 0)
+ return rlc;
+ Elf_Internal_Shdr *shdr = elfp->get_shdr (sec);
+ if (shdr == NULL || shdr->sh_entsize == 0)
+ return rlc;
+
+ Elf_Data *data = elfp->elf_getdata (sec);
+ if (data == NULL || data->d_size == 0)
+ return rlc;
+
+ int cnt = (int) (data->d_size / shdr->sh_entsize);
+ Elf_Internal_Shdr *shdr_sym = elfp->get_shdr (shdr->sh_link);
+ if (shdr_sym == NULL)
+ return rlc;
+ Elf_Data *data_sym = elfp->elf_getdata (shdr->sh_link);
+ Vector<Sreloc *> *vp = NULL;
+
+ for (int n = 0; n < cnt; n++)
+ {
+ Elf_Internal_Shdr *secHdr;
+ Sreloc *srlc;
+ Elf_Internal_Rela rela;
+ if (strncmp (sec_name, NTXT (".rela."), 6) == 0)
+ elfp->elf_getrela (data, n, &rela);
+ else
+ {
+ elfp->elf_getrel (data, n, &rela);
+ rela.r_addend = 0;
+ }
+ int ndx = (int) GELF_R_SYM (rela.r_info);
+ Elf_Internal_Sym sym;
+ elfp->elf_getsym (data_sym, ndx, &sym);
+
+ srlc = new Sreloc;
+ srlc->offset = rela.r_offset;
+ srlc->value = 0;
+ srlc->stt_type = (int) GELF_ST_TYPE (sym.st_info);
+ switch (GELF_ST_TYPE (sym.st_info))
+ {
+ case STT_FUNC:
+ secHdr = elfp->get_shdr (sym.st_shndx);
+ if (secHdr)
+ srlc->value = secHdr->sh_offset + sym.st_value;
+ break;
+ case STT_OBJECT:
+ case STT_NOTYPE:
+ secHdr = elfp->get_shdr (shdr->sh_info);
+ if (secHdr)
+ {
+ srlc->offset = rela.r_info;
+ srlc->value = secHdr->sh_offset + rela.r_addend;
+ }
+ break;
+ case STT_SECTION:
+ secHdr = elfp->get_shdr (sym.st_shndx);
+ if (secHdr)
+ srlc->value = rela.r_addend;
+ break;
+ default:
+ srlc->value = 0;
+ break;
+ }
+ if (rlc == NULL)
+ {
+ rlc = new ElfReloc (elfp);
+ vp = rlc->reloc;
+ }
+ if (vp == NULL)
+ {
+ vp = new Vector<Sreloc*>;
+ rlc->reloc = vp;
+ }
+ vp->append (srlc);
+ }
+ if (vp)
+ vp->sort (DwrRelocOffsetCmp);
+ if (rlc)
+ {
+ rlc->dump_rela_debug_sec (sec);
+ rlc->dump ();
+ }
+ return rlc;
+}
+
+long long
+ElfReloc::get_reloc_addr (long long offset)
+{
+ Sreloc *srlc;
+ int i = cur_reloc_ind - 1;
+ if (i >= 0 && i < reloc->size ())
+ {
+ srlc = reloc->fetch (i);
+ if (srlc->offset > offset) // need to reset
+ cur_reloc_ind = 0;
+ }
+ for (; cur_reloc_ind < reloc->size (); cur_reloc_ind++)
+ {
+ srlc = reloc->fetch (cur_reloc_ind);
+ if (srlc->offset == offset)
+ return srlc->value;
+ if (srlc->offset > offset)
+ return 0;
+ }
+ return 0;
+}
+
+DwrLocation *
+DwrCU::dwr_get_location (DwrSec *secp, DwrLocation *lp)
+{
+ lp->offset = secp->offset;
+ lp->lc_number = 0;
+ lp->lc_number2 = 0;
+ lp->op = secp->Get_8 ();
+ switch (lp->op)
+ {
+ // registers
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ break;
+ case DW_OP_regx:
+ lp->lc_number = secp->GetULEB128 ();
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ lp->lc_number = secp->GetSLEB128 ();
+ break;
+ case DW_OP_fbreg:
+ lp->lc_number = secp->GetSLEB128 ();
+ break;
+ case DW_OP_bregx:
+ lp->lc_number = secp->GetULEB128 ();
+ lp->lc_number2 = secp->GetSLEB128 ();
+ break;
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ lp->lc_number = lp->op - DW_OP_lit0;
+ break;
+ case DW_OP_addr:
+ lp->lc_number = secp->GetADDR ();
+ break;
+ case DW_OP_const1u:
+ lp->lc_number = secp->Get_8 ();
+ break;
+ case DW_OP_const1s:
+ {
+ signed char x;
+ x = secp->Get_8 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_const2u:
+ lp->lc_number = secp->Get_16 ();
+ break;
+ case DW_OP_const2s:
+ {
+ signed short x;
+ x = secp->Get_16 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_const4u:
+ lp->lc_number = secp->Get_32 ();
+ break;
+ case DW_OP_const4s:
+ {
+ signed int x;
+ x = secp->Get_32 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_const8u:
+ lp->lc_number = secp->Get_64 ();
+ break;
+ case DW_OP_const8s:
+ {
+ signed long long x;
+ x = secp->Get_64 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_plus_uconst:
+ case DW_OP_constu:
+ lp->lc_number = secp->GetULEB128 ();
+ break;
+ case DW_OP_consts:
+ lp->lc_number = secp->GetSLEB128 ();
+ break;
+
+ // Stack operations
+ case DW_OP_pick:
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ lp->lc_number = secp->Get_8 ();
+ break;
+ case DW_OP_dup:
+ case DW_OP_drop:
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_deref:
+ case DW_OP_xderef:
+ // Arithmetic and Logical Operations
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ case DW_OP_nop:
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ lp->lc_number = secp->Get_16 ();
+ break;
+ case DW_OP_piece:
+ lp->lc_number = secp->GetULEB128 ();
+ break;
+ case DW_OP_push_object_address: /* DWARF3 */
+ break;
+ case DW_OP_call2: /* DWARF3 */
+ lp->lc_number = secp->Get_16 ();
+ break;
+ case DW_OP_call4: /* DWARF3 */
+ lp->lc_number = secp->Get_32 ();
+ break;
+ case DW_OP_call_ref: /* DWARF3 */
+ lp->lc_number = secp->GetADDR ();
+ break;
+ default:
+ return (NULL);
+ }
+ return lp;
+}
+
+char *
+DwrCU::tag2str (int tag)
+{
+ static char buf[128];
+ char *s;
+
+ switch (tag)
+ {
+ CASE_S (DW_TAG_array_type);
+ CASE_S (DW_TAG_class_type);
+ CASE_S (DW_TAG_entry_point);
+ CASE_S (DW_TAG_enumeration_type);
+ CASE_S (DW_TAG_formal_parameter);
+ CASE_S (DW_TAG_imported_declaration);
+ CASE_S (DW_TAG_label);
+ CASE_S (DW_TAG_lexical_block);
+ CASE_S (DW_TAG_member);
+ CASE_S (DW_TAG_pointer_type);
+ CASE_S (DW_TAG_reference_type);
+ CASE_S (DW_TAG_compile_unit);
+ CASE_S (DW_TAG_string_type);
+ CASE_S (DW_TAG_structure_type);
+ CASE_S (DW_TAG_subroutine_type);
+ CASE_S (DW_TAG_typedef);
+ CASE_S (DW_TAG_union_type);
+ CASE_S (DW_TAG_unspecified_parameters);
+ CASE_S (DW_TAG_variant);
+ CASE_S (DW_TAG_common_block);
+ CASE_S (DW_TAG_common_inclusion);
+ CASE_S (DW_TAG_inheritance);
+ CASE_S (DW_TAG_inlined_subroutine);
+ CASE_S (DW_TAG_module);
+ CASE_S (DW_TAG_ptr_to_member_type);
+ CASE_S (DW_TAG_set_type);
+ CASE_S (DW_TAG_subrange_type);
+ CASE_S (DW_TAG_with_stmt);
+ CASE_S (DW_TAG_access_declaration);
+ CASE_S (DW_TAG_base_type);
+ CASE_S (DW_TAG_catch_block);
+ CASE_S (DW_TAG_const_type);
+ CASE_S (DW_TAG_constant);
+ CASE_S (DW_TAG_enumerator);
+ CASE_S (DW_TAG_file_type);
+ CASE_S (DW_TAG_friend);
+ CASE_S (DW_TAG_namelist);
+ CASE_S (DW_TAG_namelist_item);
+ CASE_S (DW_TAG_packed_type);
+ CASE_S (DW_TAG_subprogram);
+ CASE_S (DW_TAG_template_type_param);
+ CASE_S (DW_TAG_template_value_param);
+ CASE_S (DW_TAG_thrown_type);
+ CASE_S (DW_TAG_try_block);
+ CASE_S (DW_TAG_variant_part);
+ CASE_S (DW_TAG_variable);
+ CASE_S (DW_TAG_volatile_type);
+ CASE_S (DW_TAG_dwarf_procedure);
+ CASE_S (DW_TAG_restrict_type);
+ CASE_S (DW_TAG_interface_type);
+ CASE_S (DW_TAG_namespace);
+ CASE_S (DW_TAG_imported_module);
+ CASE_S (DW_TAG_unspecified_type);
+ CASE_S (DW_TAG_partial_unit);
+ CASE_S (DW_TAG_imported_unit);
+ CASE_S (DW_TAG_lo_user);
+ CASE_S (DW_TAG_MIPS_loop);
+ CASE_S (DW_TAG_format_label);
+ CASE_S (DW_TAG_function_template);
+ CASE_S (DW_TAG_class_template);
+ CASE_S (DW_TAG_GNU_BINCL);
+ CASE_S (DW_TAG_GNU_EINCL);
+ CASE_S (DW_TAG_GNU_call_site);
+ CASE_S (DW_TAG_GNU_call_site_parameter);
+ CASE_S (DW_TAG_SUN_codeflags);
+ CASE_S (DW_TAG_SUN_memop_info);
+ CASE_S (DW_TAG_hi_user);
+ CASE_S (DW_TAG_icc_compile_unit);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+char *
+DwrCU::at2str (int tag)
+{
+ static char buf[128];
+ char *s;
+ switch (tag)
+ {
+ CASE_S (DW_AT_sibling);
+ CASE_S (DW_AT_location);
+ CASE_S (DW_AT_name);
+ CASE_S (DW_AT_ordering);
+ CASE_S (DW_AT_subscr_data);
+ CASE_S (DW_AT_byte_size);
+ CASE_S (DW_AT_bit_offset);
+ CASE_S (DW_AT_bit_size);
+ CASE_S (DW_AT_element_list);
+ CASE_S (DW_AT_stmt_list);
+ CASE_S (DW_AT_low_pc);
+ CASE_S (DW_AT_high_pc);
+ CASE_S (DW_AT_language);
+ CASE_S (DW_AT_member);
+ CASE_S (DW_AT_discr);
+ CASE_S (DW_AT_discr_value);
+ CASE_S (DW_AT_visibility);
+ CASE_S (DW_AT_import);
+ CASE_S (DW_AT_string_length);
+ CASE_S (DW_AT_common_reference);
+ CASE_S (DW_AT_comp_dir);
+ CASE_S (DW_AT_const_value);
+ CASE_S (DW_AT_containing_type);
+ CASE_S (DW_AT_default_value);
+ CASE_S (DW_AT_inline);
+ CASE_S (DW_AT_is_optional);
+ CASE_S (DW_AT_lower_bound);
+ CASE_S (DW_AT_producer);
+ CASE_S (DW_AT_prototyped);
+ CASE_S (DW_AT_return_addr);
+ CASE_S (DW_AT_start_scope);
+ CASE_S (DW_AT_stride_size);
+ CASE_S (DW_AT_upper_bound);
+ CASE_S (DW_AT_abstract_origin);
+ CASE_S (DW_AT_accessibility);
+ CASE_S (DW_AT_address_class);
+ CASE_S (DW_AT_artificial);
+ CASE_S (DW_AT_base_types);
+ CASE_S (DW_AT_calling_convention);
+ CASE_S (DW_AT_count);
+ CASE_S (DW_AT_data_member_location);
+ CASE_S (DW_AT_decl_column);
+ CASE_S (DW_AT_decl_file);
+ CASE_S (DW_AT_decl_line);
+ CASE_S (DW_AT_declaration);
+ CASE_S (DW_AT_discr_list);
+ CASE_S (DW_AT_encoding);
+ CASE_S (DW_AT_external);
+ CASE_S (DW_AT_frame_base);
+ CASE_S (DW_AT_friend);
+ CASE_S (DW_AT_identifier_case);
+ CASE_S (DW_AT_macro_info);
+ CASE_S (DW_AT_namelist_item);
+ CASE_S (DW_AT_priority);
+ CASE_S (DW_AT_segment);
+ CASE_S (DW_AT_specification);
+ CASE_S (DW_AT_static_link);
+ CASE_S (DW_AT_type);
+ CASE_S (DW_AT_use_location);
+ CASE_S (DW_AT_variable_parameter);
+ CASE_S (DW_AT_virtuality);
+ CASE_S (DW_AT_vtable_elem_location);
+ CASE_S (DW_AT_allocated);
+ CASE_S (DW_AT_associated);
+ CASE_S (DW_AT_data_location);
+ CASE_S (DW_AT_byte_stride);
+ CASE_S (DW_AT_entry_pc);
+ CASE_S (DW_AT_use_UTF8);
+ CASE_S (DW_AT_extension);
+ CASE_S (DW_AT_ranges);
+ CASE_S (DW_AT_trampoline);
+ CASE_S (DW_AT_call_column);
+ CASE_S (DW_AT_call_file);
+ CASE_S (DW_AT_call_line);
+ CASE_S (DW_AT_description);
+ CASE_S (DW_AT_binary_scale);
+ CASE_S (DW_AT_decimal_scale);
+ CASE_S (DW_AT_small);
+ CASE_S (DW_AT_decimal_sign);
+ CASE_S (DW_AT_digit_count);
+ CASE_S (DW_AT_picture_string);
+ CASE_S (DW_AT_mutable);
+ CASE_S (DW_AT_threads_scaled);
+ CASE_S (DW_AT_explicit);
+ CASE_S (DW_AT_object_pointer);
+ CASE_S (DW_AT_endianity);
+ CASE_S (DW_AT_elemental);
+ CASE_S (DW_AT_pure);
+ CASE_S (DW_AT_recursive);
+ CASE_S (DW_AT_signature);
+ CASE_S (DW_AT_main_subprogram);
+ CASE_S (DW_AT_data_bit_offset);
+ CASE_S (DW_AT_const_expr);
+ CASE_S (DW_AT_enum_class);
+ CASE_S (DW_AT_linkage_name);
+ CASE_S (DW_AT_lo_user);
+ CASE_S (DW_AT_MIPS_fde);
+ CASE_S (DW_AT_MIPS_loop_begin);
+ CASE_S (DW_AT_MIPS_tail_loop_begin);
+ CASE_S (DW_AT_MIPS_epilog_begin);
+ CASE_S (DW_AT_MIPS_loop_unroll_factor);
+ CASE_S (DW_AT_MIPS_software_pipeline_depth);
+ CASE_S (DW_AT_MIPS_linkage_name);
+ CASE_S (DW_AT_MIPS_stride);
+ CASE_S (DW_AT_MIPS_abstract_name);
+ CASE_S (DW_AT_MIPS_clone_origin);
+ CASE_S (DW_AT_MIPS_has_inlines);
+ CASE_S (DW_AT_sf_names);
+ CASE_S (DW_AT_src_info);
+ CASE_S (DW_AT_mac_info);
+ CASE_S (DW_AT_src_coords);
+ CASE_S (DW_AT_body_begin);
+ CASE_S (DW_AT_body_end);
+ CASE_S (DW_AT_GNU_vector);
+ CASE_S (DW_AT_GNU_guarded_by);
+ CASE_S (DW_AT_GNU_pt_guarded_by);
+ CASE_S (DW_AT_GNU_guarded);
+ CASE_S (DW_AT_GNU_pt_guarded);
+ CASE_S (DW_AT_GNU_locks_excluded);
+ CASE_S (DW_AT_GNU_exclusive_locks_required);
+ CASE_S (DW_AT_GNU_shared_locks_required);
+ CASE_S (DW_AT_GNU_odr_signature);
+ CASE_S (DW_AT_GNU_template_name);
+ CASE_S (DW_AT_GNU_call_site_value);
+ CASE_S (DW_AT_GNU_call_site_data_value);
+ CASE_S (DW_AT_GNU_call_site_target);
+ CASE_S (DW_AT_GNU_call_site_target_clobbered);
+ CASE_S (DW_AT_GNU_tail_call);
+ CASE_S (DW_AT_GNU_all_tail_call_sites);
+ CASE_S (DW_AT_GNU_all_call_sites);
+ CASE_S (DW_AT_GNU_all_source_call_sites);
+ CASE_S (DW_AT_SUN_command_line);
+ CASE_S (DW_AT_SUN_func_offsets);
+ CASE_S (DW_AT_SUN_cf_kind);
+ CASE_S (DW_AT_SUN_func_offset);
+ CASE_S (DW_AT_SUN_memop_type_ref);
+ CASE_S (DW_AT_SUN_profile_id);
+ CASE_S (DW_AT_SUN_memop_signature);
+ CASE_S (DW_AT_SUN_obj_dir);
+ CASE_S (DW_AT_SUN_obj_file);
+ CASE_S (DW_AT_SUN_original_name);
+ CASE_S (DW_AT_SUN_link_name);
+ CASE_S (DW_AT_hi_user);
+ CASE_S (DW_AT_icc_flags);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+char *
+DwrCU::form2str (int tag)
+{
+ static char buf[128];
+ char *s;
+ switch (tag)
+ {
+ CASE_S (DW_FORM_addr);
+ CASE_S (DW_FORM_block2);
+ CASE_S (DW_FORM_block4);
+ CASE_S (DW_FORM_data2);
+ CASE_S (DW_FORM_data4);
+ CASE_S (DW_FORM_data8);
+ CASE_S (DW_FORM_string);
+ CASE_S (DW_FORM_block);
+ CASE_S (DW_FORM_block1);
+ CASE_S (DW_FORM_data1);
+ CASE_S (DW_FORM_flag);
+ CASE_S (DW_FORM_sdata);
+ CASE_S (DW_FORM_strp);
+ CASE_S (DW_FORM_udata);
+ CASE_S (DW_FORM_ref_addr);
+ CASE_S (DW_FORM_ref1);
+ CASE_S (DW_FORM_ref2);
+ CASE_S (DW_FORM_ref4);
+ CASE_S (DW_FORM_ref8);
+ CASE_S (DW_FORM_ref_udata);
+ CASE_S (DW_FORM_indirect);
+ CASE_S (DW_FORM_sec_offset);
+ CASE_S (DW_FORM_exprloc);
+ CASE_S (DW_FORM_flag_present);
+ CASE_S (DW_FORM_ref_sig8);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+void
+Dwr_Tag::dump ()
+{
+ Dprintf (DUMP_DWARFLIB,
+ "\n<%2d>:<0x%08llx> %-30s <abbrev %lld> offset=0x%llx %s\n",
+ (int) level, (long long) die, DwrCU::tag2str (tag), (long long) num,
+ (long long) offset,
+ hasChild ? NTXT ("DW_children_yes") : NTXT ("DW_children_no"));
+ for (int i1 = firstAttribute; i1 < lastAttribute; i1++)
+ {
+ Dwr_Attr *atrp = abbrevAtForm->get (i1);
+ Dprintf (DUMP_DWARFLIB, " %-30s ", DwrCU::at2str (atrp->at_name));
+ switch (atrp->at_form)
+ {
+ case DW_FORM_strp:
+ case DW_FORM_string:
+ Dprintf (DUMP_DWARFLIB, " \"%s\" len=%ld",
+ atrp->u.str ? atrp->u.str : NTXT ("<NULL>"),
+ (long) atrp->len);
+ break;
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ Dprintf (DUMP_DWARFLIB, " len=%3ld %p", (long) atrp->len,
+ atrp->u.str);
+ break;
+ case DW_FORM_addr:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_indirect:
+ case DW_FORM_sec_offset:
+ case DW_FORM_exprloc:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_flag_present:
+ Dprintf (DUMP_DWARFLIB, " 0x%llx (%lld)", (long long) atrp->u.val,
+ (long long) atrp->u.val);
+ break;
+ default:
+ DEBUG_CODE
+ {
+ Dprintf (1, "Attribute form 0x%llx (%lld) is not implemented\n",
+ (long long) atrp->at_form, (long long) atrp->at_form);
+ assert (false);
+ }
+ }
+ Dprintf (DUMP_DWARFLIB, NTXT ("\n"));
+ }
+}
+
+
+//////////////////////////////////////////////////////////
+// class DwrSec
+
+DwrSec::DwrSec (unsigned char *_data, uint64_t _size, bool _need_swap_endian, bool _addr32)
+{
+ isCopy = false;
+ data = _data;
+ sizeSec = _size;
+ size = (data ? _size : 0);
+ offset = 0;
+ fmt64 = false;
+ reloc = NULL;
+ need_swap_endian = _need_swap_endian;
+ addr32 = _addr32;
+}
+
+DwrSec::DwrSec (DwrSec *secp, uint64_t _offset)
+{
+ isCopy = true;
+ data = secp->data;
+ sizeSec = secp->sizeSec;
+ size = secp->size;
+ offset = _offset;
+ fmt64 = secp->fmt64;
+ reloc = secp->reloc;
+ need_swap_endian = secp->need_swap_endian;
+ addr32 = secp->addr32;
+}
+
+DwrSec::~DwrSec ()
+{
+ if (!isCopy)
+ delete reloc;
+}
+
+bool
+DwrSec::bounds_violation (uint64_t sz)
+{
+ if (offset + sz > size)
+ {
+ Dprintf (DEBUG_ERR_MSG, "DwrSec::bounds_violation: offset=%lld + sz=%lld > size=%lld\n",
+ (long long) offset, (long long) sz, (long long) size);
+ return true;
+ }
+ return false;
+}
+
+uint64_t
+DwrSec::ReadLength ()
+{
+ fmt64 = false;
+ uint64_t val = Get_32 ();
+ if (((uint32_t) val) == 0xffffffff)
+ {
+ fmt64 = true;
+ val = Get_64 ();
+ }
+ size = (val + offset < sizeSec) ? val + offset : sizeSec;
+ return size;
+}
+
+unsigned char
+DwrSec::Get_8 ()
+{
+ unsigned char n = 0;
+ if (bounds_violation (sizeof (char)))
+ return n;
+ n = data[offset];
+ offset += sizeof (char);
+ return n;
+}
+
+unsigned short
+DwrSec::Get_16 ()
+{
+ unsigned short n = 0;
+ if (bounds_violation (sizeof (short)))
+ return n;
+ memcpy ((char *) &n, data + offset, sizeof (short));
+ offset += sizeof (short);
+ if (need_swap_endian)
+ SWAP_ENDIAN (n);
+ return n;
+}
+
+uint32_t
+DwrSec::Get_32 ()
+{
+ uint32_t n = 0;
+ if (bounds_violation (sizeof (uint32_t)))
+ return n;
+ memcpy ((char *) &n, data + offset, sizeof (uint32_t));
+ offset += sizeof (uint32_t);
+ if (need_swap_endian)
+ SWAP_ENDIAN (n);
+ return n;
+}
+
+uint64_t
+DwrSec::Get_64 ()
+{
+ uint64_t n = 0;
+ if (bounds_violation (sizeof (uint64_t)))
+ return n;
+ memcpy ((char *) &n, data + offset, sizeof (uint64_t));
+ offset += sizeof (uint64_t);
+ if (need_swap_endian)
+ SWAP_ENDIAN (n);
+ return n;
+}
+
+char *
+DwrSec::GetData (uint64_t len)
+{
+ char *s = ((char *) data) + offset;
+ if (bounds_violation (len))
+ s = NULL;
+ offset += len;
+ return s;
+}
+
+char *
+DwrSec::GetString (uint64_t *lenp)
+{
+ if (offset < size)
+ {
+ uint64_t len = 0;
+ for (char *s = ((char *) data) + offset; offset + len < size; len++)
+ {
+ if (s[len] == 0)
+ { // '\0' is inside section
+ offset += len + 1;
+ if (len == 0)
+ return NULL;
+ if (lenp)
+ *lenp = len + 1;
+ return s;
+ }
+ }
+ offset += len;
+ return NULL; // The section is not '\0' terminated
+ }
+ return NULL;
+}
+
+uint64_t
+DwrSec::GetLong ()
+{
+ if (fmt64)
+ return Get_64 ();
+ return Get_32 ();
+}
+
+uint64_t
+DwrSec::GetADDR_32 ()
+{
+ uint64_t res = reloc ? reloc->get_reloc_addr (offset) : 0;
+ res += Get_32 ();
+ return res;
+}
+
+uint64_t
+DwrSec::GetADDR_64 ()
+{
+ uint64_t res = reloc ? reloc->get_reloc_addr (offset) : 0;
+ res += Get_64 ();
+ return res;
+}
+
+uint64_t
+DwrSec::GetADDR ()
+{
+ if (addr32)
+ return GetADDR_32 ();
+ return GetADDR_64 ();
+}
+
+uint64_t
+DwrSec::GetRef ()
+{
+ if (fmt64)
+ return GetADDR_64 ();
+ return GetADDR_32 ();
+}
+
+ULEB128
+DwrSec::GetULEB128 ()
+{
+ ULEB128 res = 0;
+ for (int shift = 0;; shift += 7)
+ {
+ ULEB128 val = Get_8 ();
+ res |= (val & 0x7f) << shift;
+ if ((val & 0x80) == 0)
+ break;
+ }
+ return res;
+}
+
+SLEB128
+DwrSec::GetSLEB128 ()
+{
+ ULEB128 res = 0, val = 0;
+ size_t shift;
+ for (shift = 0;;)
+ {
+ val = Get_8 ();
+ res |= (val & 0x7f) << shift;
+ shift += 7;
+ if ((val & 0x80) == 0)
+ break;
+ }
+ if ((val & 0x40) && (shift < 8 * sizeof (res)))
+ res |= -(((ULEB128) 1) << shift);
+ return (SLEB128) res;
+}
+
+static void
+fillBuf (unsigned char *s, int len, int col, unsigned char *buf)
+{
+ const char *nameX = "0123456789abcdef";
+ int i, n, posCh = 2 * col + col / 4 + 5;
+
+ if (len >= col)
+ len = col;
+ for (i = n = 0; i < len; i++, n += 2)
+ {
+ if ((i % 4) == 0 && i > 0)
+ {
+ buf[n] = ' ';
+ n++;
+ }
+ buf[n] = nameX[s[i] >> 4];
+ buf[n + 1] = nameX[s[i] & 0xf];
+ buf[posCh + i] = isprint (s[i]) ? s[i] : ' ';
+ }
+ buf[posCh + i] = 0;
+ for (i = n; i < posCh; i++)
+ buf[i] = ' ';
+}
+
+static void
+dumpArr (unsigned char *s, int len, int col, int num)
+{
+ unsigned char buf[128];
+ if (col <= 0)
+ return;
+ for (int i = 0; i < len; i += col, num += col)
+ {
+ fillBuf (s + i, len - i, col, buf);
+ Dprintf (DUMP_DWARFLIB, "%5d: %s\n", num, buf);
+ }
+}
+
+void
+DwrSec::dump (char *msg)
+{
+ if (sizeSec > 0)
+ {
+ Dprintf (DUMP_DWARFLIB, NTXT ("======= DwrSec::dump\n"));
+ if (msg)
+ Dprintf (DUMP_DWARFLIB, NTXT ("%s:\n"), msg);
+ dumpArr (data, (int) sizeSec, 32, 0);
+ Dprintf (DUMP_DWARFLIB, NTXT ("\n"));
+ }
+}
+
+//////////////////////////////////////////////////////////
+// class DwrFileNames
+
+DwrFileName::DwrFileName (char *_fname)
+{
+ path = NULL;
+ fname = _fname;
+ dir_index = 0;
+ timestamp = 0;
+ file_size = 0;
+ isUsed = false;
+}
+
+DwrFileName::~DwrFileName ()
+{
+ if (path != fname)
+ free (path);
+}
+
+
+//////////////////////////////////////////////////////////
+// class DwrLine
+DwrLine::DwrLine ()
+{
+ address = 0;
+ file = 0;
+ line = 0;
+ column = 0;
+}
+
+DwrLine::~DwrLine () { }
+
+
+//////////////////////////////////////////////////////////
+// class DwrLineRegs
+static int
+LineRegsCmp (const void *a, const void *b)
+{
+ DwrLine *item1 = *((DwrLine **) a);
+ DwrLine *item2 = *((DwrLine **) b);
+ return item1->address == item2->address ? 0 :
+ item1->address > item2->address ? 1 : -1;
+}
+
+DwrLineRegs::DwrLineRegs (DwrSec *secp, char *dirName)
+{
+ // `dwarfdump -vv -l` shows a line section (.debug_line)
+ debug_lineSec = secp;
+ uint64_t stmt_offset = debug_lineSec->offset;
+ uint64_t next_cu_offset = debug_lineSec->ReadLength ();
+ uint64_t header_offset = debug_lineSec->offset;
+ debug_lineSec->size = next_cu_offset;
+ version = debug_lineSec->Get_16 ();
+ header_length = debug_lineSec->GetLong ();
+ opcode_start = debug_lineSec->offset + header_length;
+ minimum_instruction_length = debug_lineSec->Get_8 ();
+ op_index_register = 0;
+ if (version == 4)
+ maximum_operations_per_instruction = debug_lineSec->Get_8 ();
+ else
+ maximum_operations_per_instruction = 1;
+ default_is_stmt = debug_lineSec->Get_8 ();
+ is_stmt = (default_is_stmt != 0);
+ line_base = debug_lineSec->Get_8 ();
+ line_range = debug_lineSec->Get_8 ();
+ opcode_base = debug_lineSec->Get_8 ();
+ standard_opcode_length = (Dwarf_Small*) debug_lineSec->GetData (opcode_base - 1);
+
+ if (DUMP_DWR_LINE_REGS)
+ {
+ Dprintf (DUMP_DWR_LINE_REGS,
+ "\n.debug_line version=%d stmt_offset=0x%llx"
+ "header_offset=0x%llx size=%lld dirname='%s'\n"
+ " header_length=0x%llx opcode_start=0x%llx"
+ "minimum_instruction_length=%d default_is_stmt=%d\n"
+ " line_base=%d line_range=%d opcode_base=%d\n",
+ (int) version, (long long) stmt_offset,
+ (long long) header_offset,
+ (long long) (next_cu_offset - header_offset), STR (dirName),
+ (long long) header_length, (long long) opcode_start,
+ (int) minimum_instruction_length, (int) default_is_stmt,
+ (int) line_base, (int) line_range, (int) opcode_base);
+ if (standard_opcode_length == NULL)
+ Dprintf (DUMP_DWR_LINE_REGS, "ERROR: standard_opcode_length is NULL\n");
+ for (int i = 0, sz = standard_opcode_length ? opcode_base - 1 : 0;
+ i < sz; i++)
+ Dprintf (DUMP_DWR_LINE_REGS, " opcode[%2d] length %2d\n", i,
+ (int) standard_opcode_length[i]);
+ }
+
+ include_directories = new Vector<char *>;
+ include_directories->append (dirName);
+ while (true)
+ {
+ char *s = debug_lineSec->GetString (NULL);
+ if (s == NULL)
+ break;
+ include_directories->append (s);
+ }
+
+ file_names = new Vector<DwrFileName *>;
+ while (true)
+ {
+ char *s = debug_lineSec->GetString (NULL);
+ if (s == NULL)
+ break;
+ DwrFileName *fnp = new DwrFileName (s);
+ fnp->path = NULL;
+ fnp->fname = s;
+ fnp->dir_index = debug_lineSec->GetULEB128_32 ();
+ fnp->timestamp = debug_lineSec->GetULEB128 ();
+ fnp->file_size = debug_lineSec->GetULEB128 ();
+ file_names->append (fnp);
+ }
+ lines = NULL;
+ dump ();
+}
+
+DwrLineRegs::~DwrLineRegs ()
+{
+ Destroy (file_names);
+ Destroy (lines);
+ delete debug_lineSec;
+ delete include_directories;
+}
+
+void
+DwrLineRegs::dump ()
+{
+ if (!DUMP_DWR_LINE_REGS)
+ return;
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\ninclude_directories size=%lld\n"), (long long) VecSize (include_directories));
+ for (long i = 0, sz = VecSize (include_directories); i < sz; i++)
+ {
+ char *s = include_directories->get (i);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT (" %2lld %s\n"), (long long) i, STR (s));
+ }
+
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\nfile_names size=%lld\n"), (long long) VecSize (file_names));
+ for (long i = 0, sz = VecSize (file_names); i < sz; i++)
+ {
+ DwrFileName *fnp = file_names->get (i);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT (" %2lld %-40s dir_index=%4lld timestamp=%8lld file_size=%lld\n"),
+ (long long) i, STR (fnp->fname),
+ (long long) fnp->dir_index, (long long) fnp->timestamp, (long long) fnp->file_size);
+ }
+ if (lines)
+ lines->dump (fname);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\n\n"));
+}
+
+void
+DwrLineRegs::DoExtendedOpcode ()
+{
+ uint64_t size = debug_lineSec->GetULEB128 ();
+ if (size == 0)
+ {
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), NTXT ("ExtendedOpCode: size=0"));
+ return;
+ }
+ Dwarf_Small opcode = debug_lineSec->Get_8 ();
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), extended_opcode2str (opcode));
+ switch (opcode)
+ {
+ case DW_LNE_end_sequence:
+ end_sequence = true;
+ reset ();
+ break;
+ case DW_LNE_set_address:
+ address = debug_lineSec->GetADDR ();
+ break;
+ case DW_LNE_define_file:
+ // TODO, add file to file list
+ fname = debug_lineSec->GetString (NULL);
+ dir_index = debug_lineSec->GetULEB128 ();
+ timestamp = debug_lineSec->GetULEB128 ();
+ file_size = debug_lineSec->GetULEB128 ();
+ break;
+ default:
+ debug_lineSec->GetData (size - 1); // skip unknown opcode
+ break;
+ }
+}
+
+void
+DwrLineRegs::DoStandardOpcode (int opcode)
+{
+ switch (opcode)
+ {
+ case DW_LNS_copy:
+ basic_block = false;
+ EmitLine ();
+ break;
+ case DW_LNS_advance_pc:
+ address += debug_lineSec->GetULEB128 () * minimum_instruction_length;
+ break;
+ case DW_LNS_advance_line:
+ line += (int) debug_lineSec->GetSLEB128 ();
+ break;
+ case DW_LNS_set_file:
+ file = debug_lineSec->GetULEB128_32 ();
+ break;
+ case DW_LNS_set_column:
+ column = debug_lineSec->GetULEB128_32 ();
+ break;
+ case DW_LNS_negate_stmt:
+ is_stmt = -is_stmt;
+ break;
+ case DW_LNS_set_basic_block:
+ basic_block = true;
+ break;
+ case DW_LNS_const_add_pc:
+ address += ((255 - opcode_base) / line_range) * minimum_instruction_length;
+ break;
+ case DW_LNS_fixed_advance_pc:
+ address += debug_lineSec->Get_16 ();
+ break;
+ default: // skip unknown opcode/operands
+ debug_lineSec->GetData (standard_opcode_length ?
+ standard_opcode_length[opcode] : 1);
+ break;
+ }
+}
+
+void
+DwrLineRegs::DoSpecialOpcode (int opcode)
+{
+ int max_op_per_instr = maximum_operations_per_instruction == 0 ? 1
+ : maximum_operations_per_instruction;
+ int operation_advance = (opcode / line_range);
+ address += minimum_instruction_length * ((op_index_register + operation_advance) / max_op_per_instr);
+ op_index_register = (op_index_register + operation_advance) % max_op_per_instr;
+ line += line_base + (opcode % line_range);
+ basic_block = false;
+ EmitLine ();
+}
+
+void
+DwrLineRegs::reset ()
+{
+ dir_index = 0;
+ timestamp = 0;
+ file_size = 0;
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = (default_is_stmt != 0);
+ basic_block = false;
+ end_sequence = false;
+}
+
+void
+DwrLineRegs::EmitLine ()
+{
+ DwrLine *lnp = new DwrLine;
+
+ lnp->file = file;
+ lnp->line = line;
+ lnp->column = column;
+ lnp->address = address;
+ lines->append (lnp);
+ if ((file > 0) && (file < VecSize (file_names)))
+ {
+ DwrFileName *fnp = file_names->get (file);
+ fnp->isUsed = true;
+ }
+}
+
+Vector<DwrLine *> *
+DwrLineRegs::get_lines ()
+{
+ if (lines == NULL)
+ {
+ lines = new Vector<DwrLine *>;
+ debug_lineSec->offset = opcode_start;
+ reset ();
+ Dprintf (DUMP_DWR_LINE_REGS, "\n offset code address (file, line, column) stmt blck end_seq \n");
+ while (debug_lineSec->offset < debug_lineSec->size)
+ {
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("0x%08llx "),
+ (long long) debug_lineSec->offset);
+ Dwarf_Small opcode = debug_lineSec->Get_8 ();
+ if (opcode == 0)
+ DoExtendedOpcode ();
+ else if (opcode < opcode_base)
+ {
+ DoStandardOpcode (opcode);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), standard_opcode2str (opcode));
+ }
+ else
+ {
+ DoSpecialOpcode (opcode - opcode_base);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"),
+ special_opcode2str (opcode - opcode_base));
+ }
+ Dprintf (DUMP_DWR_LINE_REGS,
+ " 0x%08llx (%lld, %lld, %lld) %c %c %c\n",
+ (long long) address, (long long) file, (long long) line,
+ (long long) column, is_stmt ? 'T' : 'F',
+ basic_block ? 'T' : 'F', end_sequence ? 'T' : 'F');
+ }
+ lines->sort (LineRegsCmp);
+ if (DUMP_DWR_LINE_REGS)
+ lines->dump (fname);
+ }
+ return lines;
+}
+
+char *
+DwrLineRegs::getPath (int fn)
+{
+ fn--;
+ if ((fn >= VecSize (file_names)) || (fn < 0))
+ {
+ Dprintf (DEBUG_ERR_MSG, NTXT ("DwrLineRegs::getPath: fn=0x%lld file_names->size()=%lld\n"),
+ (long long) fn, (long long) VecSize (file_names));
+ return NULL;
+ }
+ DwrFileName *fnp = file_names->fetch (fn);
+ if (fnp->path)
+ return fnp->path;
+
+ char *dir = fnp->dir_index < include_directories->size () ?
+ include_directories->fetch (fnp->dir_index) : NULL;
+ if ((fnp->fname[0] == '/') || (dir == NULL) || (*dir == 0))
+ {
+ fnp->path = fnp->fname;
+ return fnp->path;
+ }
+
+ StringBuilder sb;
+ if (*dir != '/')
+ { // not absolute
+ char *s = include_directories->fetch (0);
+ sb.append (s);
+ sb.append ('/');
+ }
+ sb.append (dir);
+ sb.append ('/');
+ sb.append (fnp->fname);
+ fnp->path = canonical_path (sb.toString ());
+ return fnp->path;
+}
+
+DwrCU::DwrCU (Dwarf *_dwarf)
+{
+ dwarf = _dwarf;
+ cu_offset = dwarf->debug_infoSec->offset;
+ debug_infoSec = new DwrSec (dwarf->debug_infoSec, cu_offset);
+ next_cu_offset = debug_infoSec->ReadLength ();
+ if (next_cu_offset > debug_infoSec->sizeSec)
+ {
+ Dprintf (DEBUG_ERR_MSG,
+ "DwrCU::DwrCU: next_cu_offset(0x%llx) > debug_infoSec->sizeSec(%llx)\n",
+ (long long) next_cu_offset, (long long) debug_infoSec->sizeSec);
+ next_cu_offset = debug_infoSec->sizeSec;
+ }
+ debug_infoSec->size = next_cu_offset;
+ version = debug_infoSec->Get_16 ();
+ debug_abbrev_offset = debug_infoSec->GetLong ();
+ address_size = debug_infoSec->Get_8 ();
+ cu_header_offset = debug_infoSec->offset;
+ comp_dir = NULL;
+ module = NULL;
+ abbrevTable = NULL;
+ dwrInlinedSubrs = NULL;
+ srcFiles = NULL;
+ stmt_list_offset = 0;
+ dwrLineReg = NULL;
+ isMemop = false;
+ isGNU = false;
+ dwrTag.level = 0;
+
+ build_abbrevTable (dwarf->debug_abbrevSec, debug_abbrev_offset);
+#ifdef DEBUG
+ if (DUMP_DWARFLIB)
+ {
+ Dprintf (DUMP_DWARFLIB,
+ "CU_HEADER: header_offset = 0x%08llx %lld"
+ "next_header_offset=0x%08llx %lld\n"
+ " abbrev_offset = 0x%08llx %lld\n"
+ " unit_length = %lld\n"
+ " version = %d\n"
+ " address_size = %d\n"
+ " fmt64 = %s\n"
+ "debug_info: need_swap_endian=%s fmt64=%s addr32=%s\n",
+ (long long) cu_offset, (long long) cu_offset,
+ (long long) next_cu_offset, (long long) next_cu_offset,
+ (long long) debug_abbrev_offset, (long long) debug_abbrev_offset,
+ (long long) (next_cu_offset - cu_offset),
+ (int) version, (int) address_size,
+ debug_infoSec->fmt64 ? "true" : "false",
+ debug_infoSec->need_swap_endian ? "true" : "false",
+ debug_infoSec->fmt64 ? "true" : "false",
+ debug_infoSec->addr32 ? "true" : "false");
+ Dprintf (DUMP_DWARFLIB, "\n.debug_abbrev cnt=%d offset=0x%08llx %lld\n",
+ (int) VecSize (abbrevTable), (long long) debug_abbrev_offset,
+ (long long) debug_abbrev_offset);
+ for (int i = 1, sz = VecSize (abbrevTable); i < sz; i++)
+ {
+ DwrAbbrevTable *abbTbl = abbrevTable->get (i);
+ Dprintf (DUMP_DWARFLIB, NTXT ("%5d: %-30s %-20s offset=0x%08llx\n"),
+ (int) i, DwrCU::tag2str (abbTbl->tag),
+ abbTbl->hasChild ? "DW_children_yes" : "DW_children_no",
+ (long long) abbTbl->offset);
+ for (int i1 = abbTbl->firstAtForm; i1 < abbTbl->lastAtForm; i1++)
+ {
+ Dwr_Attr *atf = abbrevAtForm->get (i1);
+ Dprintf (DUMP_DWARFLIB, " %-30s %s\n",
+ DwrCU::at2str (atf->at_name),
+ DwrCU::form2str (atf->at_form));
+ }
+ }
+ }
+#endif
+}
+
+DwrCU::~DwrCU ()
+{
+ delete debug_infoSec;
+ delete abbrevTable;
+ delete abbrevAtForm;
+ Destroy (dwrInlinedSubrs);
+ delete srcFiles;
+ delete dwrLineReg;
+ free (comp_dir);
+}
+
+void
+DwrCU::build_abbrevTable (DwrSec *_debug_abbrevSec, uint64_t _offset)
+{
+ if (abbrevTable)
+ return;
+ DwrSec *debug_abbrevSec = new DwrSec (_debug_abbrevSec, _offset);
+ abbrevTable = new DbeArray <DwrAbbrevTable>(128);
+ abbrevAtForm = new DbeArray <Dwr_Attr>(512);
+ abbrevTable->allocate (1); // skip first
+ abbrevAtForm->allocate (1); // skip first
+ for (int i = 1; debug_abbrevSec->offset < debug_abbrevSec->size; i++)
+ {
+ DwrAbbrevTable abbTbl;
+ abbTbl.offset = debug_abbrevSec->offset;
+ abbTbl.code = debug_abbrevSec->GetULEB128_32 ();
+ if (abbTbl.code == 0)
+ break;
+ else if (i != abbTbl.code)
+ {
+ dwarf->elf->append_msg (CMSG_ERROR, GTXT ("%s: the abbreviations table is corrupted (%lld <--> %lld)\n"),
+ get_basename (dwarf->elf->get_location ()),
+ (long long) i, (long long) abbTbl.code);
+ break;
+ }
+ abbTbl.tag = debug_abbrevSec->GetULEB128_32 ();
+ abbTbl.hasChild = (DW_children_yes == debug_abbrevSec->Get_8 ());
+ abbTbl.firstAtForm = abbrevAtForm->size ();
+ while (debug_abbrevSec->offset < debug_abbrevSec->size)
+ {
+ Dwr_Attr atf;
+ atf.at_name = debug_abbrevSec->GetULEB128_32 ();
+ atf.at_form = debug_abbrevSec->GetULEB128_32 ();
+ if (atf.at_name == 0 && atf.at_form == 0)
+ break;
+ abbrevAtForm->append (atf);
+ }
+ abbTbl.lastAtForm = abbrevAtForm->size ();
+ abbrevTable->append (abbTbl);
+ }
+ delete debug_abbrevSec;
+}
+
+int
+DwrCU::set_die (Dwarf_Die die)
+{
+ if (die > 0)
+ debug_infoSec->offset = die;
+ if (debug_infoSec->offset < cu_header_offset
+ || debug_infoSec->offset >= debug_infoSec->size)
+ return DW_DLV_ERROR;
+ dwrTag.offset = debug_infoSec->offset;
+ dwrTag.die = debug_infoSec->offset - cu_offset;
+ dwrTag.num = debug_infoSec->GetULEB128_32 ();
+ if (dwrTag.num == 0)
+ return DW_DLV_NO_ENTRY;
+ dwrTag.abbrevAtForm = abbrevAtForm;
+ DwrAbbrevTable *abbTbl = abbrevTable->get (dwrTag.num);
+ if (abbTbl == NULL)
+ { // corrupt dwarf
+ dwarf->elf->append_msg (CMSG_ERROR, GTXT ("%s: the abbreviation code (%lld) does not match for the Dwarf entry (0x%llx)\n"),
+ get_basename (dwarf->elf->get_location ()),
+ (long long) dwrTag.num, (long long) dwrTag.offset);
+ return DW_DLV_ERROR;
+ }
+ dwrTag.tag = abbTbl->tag;
+ dwrTag.hasChild = abbTbl->hasChild;
+ dwrTag.firstAttribute = abbTbl->firstAtForm;
+ dwrTag.lastAttribute = abbTbl->lastAtForm;
+ for (int k = abbTbl->firstAtForm; k < abbTbl->lastAtForm; k++)
+ {
+ Dwr_Attr *atf = abbrevAtForm->get (k);
+ int at_form = atf->at_form;
+ if (at_form == DW_FORM_indirect)
+ at_form = debug_infoSec->GetULEB128_32 ();
+ switch (at_form)
+ {
+ case DW_FORM_addr:
+ atf->u.offset = (address_size == 4) ? debug_infoSec->GetADDR_32 ()
+ : debug_infoSec->GetADDR_64 ();
+ break;
+ case DW_FORM_flag:
+ atf->u.offset = debug_infoSec->Get_8 ();
+ break;
+ case DW_FORM_block:
+ atf->len = debug_infoSec->GetULEB128 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_block1:
+ atf->len = debug_infoSec->Get_8 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_block2:
+ atf->len = debug_infoSec->Get_16 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_block4:
+ atf->len = debug_infoSec->Get_32 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_ref1:
+ atf->u.offset = debug_infoSec->Get_8 ();
+ break;
+ case DW_FORM_ref2:
+ atf->u.offset = debug_infoSec->Get_16 ();
+ break;
+ case DW_FORM_ref4:
+ atf->u.offset = debug_infoSec->Get_32 ();
+ break;
+ case DW_FORM_ref8:
+ atf->u.offset = debug_infoSec->Get_64 ();
+ break;
+ case DW_FORM_ref_udata:
+ atf->u.offset = debug_infoSec->GetULEB128 ();
+ break;
+ case DW_FORM_data1:
+ atf->u.offset = debug_infoSec->Get_8 ();
+ break;
+ case DW_FORM_data2:
+ atf->u.offset = debug_infoSec->Get_16 ();
+ break;
+ case DW_FORM_data4:
+ atf->u.offset = debug_infoSec->Get_32 ();
+ break;
+ case DW_FORM_data8:
+ atf->u.offset = debug_infoSec->Get_64 ();
+ break;
+ case DW_FORM_string:
+ atf->u.str = debug_infoSec->GetString (&atf->len);
+ break;
+ case DW_FORM_strp:
+ atf->u.offset = debug_infoSec->GetRef ();
+ if (dwarf->debug_strSec == NULL)
+ {
+ atf->u.str = NULL;
+ atf->len = 0;
+ }
+ else
+ {
+ dwarf->debug_strSec->offset = atf->u.offset;
+ atf->u.str = dwarf->debug_strSec->GetString (&atf->len);
+ }
+ break;
+ case DW_FORM_sdata:
+ atf->u.val = debug_infoSec->GetSLEB128 ();
+ break;
+ case DW_FORM_udata:
+ atf->u.offset = debug_infoSec->GetULEB128 ();
+ break;
+ case DW_FORM_ref_addr:
+ atf->u.offset = debug_infoSec->GetADDR ();
+ break;
+ case DW_FORM_sec_offset:
+ atf->u.offset = debug_infoSec->GetRef ();
+ break;
+ case DW_FORM_exprloc:
+ atf->u.offset = debug_infoSec->GetULEB128 ();
+ debug_infoSec->offset += atf->u.offset;
+ break;
+ case DW_FORM_flag_present:
+ atf->u.val = 1;
+ break;
+ case DW_FORM_ref_sig8:
+ atf->u.offset = debug_infoSec->GetADDR_64 ();
+ break;
+ default:
+ DEBUG_CODE
+ {
+ Dprintf (1, "Attribute form 0x%llx (%lld) is not implemented\n",
+ (long long) atf->at_form, (long long) atf->at_form);
+ assert (0);
+ }
+ atf->u.str = NULL;
+ atf->len = 0;
+ break;
+ }
+ }
+ dwrTag.dump ();
+ return DW_DLV_OK;
+}
+
+static char *
+composePath (char *dname, char *fname)
+{
+ char *s;
+ if (*fname == '/' || dname == NULL)
+ s = dbe_sprintf (NTXT ("%s"), fname);
+ else
+ s = dbe_sprintf (NTXT ("%s/%s"), dname, fname);
+ return canonical_path (s);
+}
+
+Module *
+DwrCU::parse_cu_header (LoadObject *lo)
+{
+ // Is tag always DW_TAG_compile_unit?
+ if (dwrTag.tag != DW_TAG_compile_unit)
+ {
+ Dprintf (DEBUG_ERR_MSG,
+ "parse_cu_header: die=0x%llx tag=%lld is not DW_TAG_compile_unit\n",
+ (long long) cu_offset, (long long) dwrTag.tag);
+ return NULL;
+ }
+
+ char *name = Dwarf_string (DW_AT_name);
+ if (name == NULL)
+ name = NTXT ("UnnamedUnit");
+ stmt_list_offset = Dwarf_data (DW_AT_stmt_list);
+ comp_dir = dbe_strdup (Dwarf_string (DW_AT_comp_dir));
+ char *dir_name = comp_dir ? StrChr (comp_dir, ':') : NULL;
+ char *orig_name = Dwarf_string (DW_AT_SUN_original_name);
+ char *path = composePath (dir_name, orig_name ? orig_name : name);
+
+ module = dwarf->stabs->append_Module (lo, path);
+ free (path);
+ if (module == NULL)
+ return NULL;
+ module->hasDwarf = true;
+ if (orig_name)
+ module->linkerStabName = composePath (dir_name, name);
+ module->lang_code = Dwarf_lang ();
+ module->comp_flags = dbe_strdup (Dwarf_string (DW_AT_SUN_command_line));
+ if (module->comp_flags == NULL)
+ module->comp_flags = dbe_strdup (Dwarf_string (DW_AT_icc_flags));
+ module->comp_dir = dbe_strdup (dir_name);
+
+ char *obj_file = Dwarf_string (DW_AT_SUN_obj_file);
+ char *obj_dir = Dwarf_string (DW_AT_SUN_obj_dir);
+ if (obj_dir && obj_file)
+ {
+ // object information may not be available
+ dir_name = StrChr (obj_dir, ':');
+ path = composePath (dir_name, obj_file);
+ if (module->dot_o_file == NULL)
+ module->dot_o_file = module->createLoadObject (path);
+ }
+ else
+ path = dbe_strdup (dwarf->stabs->path);
+ module->set_name (path);
+ return module;
+}
+
+Dwr_Attr *
+Dwr_Tag::get_attr (Dwarf_Half attr)
+{
+ for (long i = firstAttribute; i < lastAttribute; i++)
+ {
+ Dwr_Attr *atf = abbrevAtForm->get (i);
+ if (atf->at_name == attr)
+ return atf;
+ }
+ return NULL;
+}
+
+char *
+DwrCU::Dwarf_string (Dwarf_Half attr)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ return dwrAttr ? dwrAttr->u.str : NULL;
+}
+
+uint64_t
+DwrCU::get_high_pc (uint64_t low_pc)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_high_pc);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_addr:
+ return dwrAttr->u.offset;
+ default:
+ return dwrAttr->u.offset + low_pc;
+ }
+ return 0;
+}
+
+Dwarf_Addr
+DwrCU::Dwarf_addr (Dwarf_Half attr)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_addr:
+ return dwrAttr->u.offset;
+ }
+ return 0;
+}
+
+DwrSec*
+DwrCU::Dwarf_block (Dwarf_Half attr)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr && dwrAttr->u.block)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return new DwrSec (dwrAttr->u.block, dwrAttr->len,
+ dwarf->elf->need_swap_endian,
+ dwarf->elf->elf_getclass () == ELFCLASS32);
+ }
+ return NULL;
+}
+
+int
+DwrCU::read_data_attr (Dwarf_Half attr, int64_t *retVal)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ case DW_FORM_sec_offset:
+ *retVal = dwrAttr->u.val;
+ return DW_DLV_OK;
+
+ }
+ return DW_DLV_ERROR;
+}
+
+int
+DwrCU::read_ref_attr (Dwarf_Half attr, int64_t *retVal)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_sec_offset:
+ case DW_FORM_exprloc:
+ case DW_FORM_ref_sig8:
+ *retVal = dwrAttr->u.val;
+ return DW_DLV_OK;
+ }
+ return DW_DLV_ERROR;
+}
+
+int64_t
+DwrCU::Dwarf_data (Dwarf_Half attr)
+{
+ int64_t retVal;
+ if (read_data_attr (attr, &retVal) == DW_DLV_OK)
+ return retVal;
+ return 0;
+}
+
+int64_t
+DwrCU::Dwarf_ref (Dwarf_Half attr)
+{
+ int64_t retVal;
+ if (read_ref_attr (attr, &retVal) == DW_DLV_OK)
+ return retVal;
+ return 0;
+}
+
+Dwarf_Addr
+DwrCU::Dwarf_location (Dwarf_Attribute attr)
+{
+ DwrSec *secp = Dwarf_block (attr);
+ if (secp)
+ {
+ DwrLocation loc;
+ DwrLocation *lp = dwr_get_location (secp, &loc);
+ delete secp;
+ if (lp)
+ return lp->lc_number;
+ }
+ return 0;
+}
+
+void
+DwrCU::map_dwarf_lines (Module *mod)
+{
+ DwrLineRegs *lineReg = get_dwrLineReg ();
+ long inlinedSubrCnt = VecSize (dwrInlinedSubrs);
+ if (isGNU && (inlinedSubrCnt > 0))
+ {
+ Function *func = NULL;
+ mod->inlinedSubr = (InlinedSubr *) malloc (inlinedSubrCnt
+ * sizeof (InlinedSubr));
+ for (long i = 0; i < inlinedSubrCnt; i++)
+ {
+ DwrInlinedSubr *inlinedSubr = dwrInlinedSubrs->get (i);
+ uint64_t low_pc;
+ Function *f = dwarf->stabs->map_PC_to_func (inlinedSubr->low_pc,
+ low_pc, mod->functions);
+ if (f == NULL)
+ continue;
+ if (func != f)
+ {
+ func = f;
+ func->inlinedSubrCnt = 0;
+ func->inlinedSubr = mod->inlinedSubr + i;
+ }
+ InlinedSubr *p = func->inlinedSubr + func->inlinedSubrCnt;
+ func->inlinedSubrCnt++;
+ int fileno = inlinedSubr->file - 1;
+ SourceFile *sf = ((fileno >= 0) && (fileno < VecSize (srcFiles))) ?
+ srcFiles->get (fileno) : dbeSession->get_Unknown_Source ();
+ p->dbeLine = sf->find_dbeline (inlinedSubr->line);
+ p->high_pc = inlinedSubr->high_pc - low_pc;
+ p->low_pc = inlinedSubr->low_pc - low_pc;
+ p->level = inlinedSubr->level;
+ p->func = NULL;
+ p->fname = NULL;
+ if (set_die (inlinedSubr->abstract_origin) == DW_DLV_OK)
+ p->fname = dbe_strdup (Dwarf_string (DW_AT_name));
+ if (p->fname)
+ p->func = Stabs::find_func (p->fname, mod->functions,
+ Stabs::is_fortran (mod->lang_code));
+ }
+ }
+ Vector<DwrLine *> *lines = lineReg->get_lines ();
+
+ Include *includes = new Include;
+ includes->new_src_file (mod->getMainSrc (), 0, NULL);
+ char *path = NULL;
+ SourceFile *cur_src = NULL;
+ Function *cur_func = NULL;
+ for (long i = 0, sz = VecSize (lines); i < sz; i++)
+ {
+ DwrLine *dwrLine = lines->get (i);
+ char *filename = dwrLineReg->getPath (dwrLine->file);
+ if (filename == NULL)
+ continue;
+ uint64_t pc = dwrLine->address;
+ int lineno = dwrLine->line;
+ if (path != filename)
+ {
+ path = filename;
+ char *name = StrChr (path, ':');
+ SourceFile *src = mod->setIncludeFile (name);
+ if (cur_src != src)
+ {
+ includes->new_src_file (src, lineno, cur_func);
+ cur_src = src;
+ }
+ }
+ uint64_t low_pc;
+ Function *func = dwarf->stabs->map_PC_to_func (pc, low_pc, mod->functions);
+ if (func && (func->module == mod))
+ {
+ if (func != cur_func)
+ {
+ if (cur_func)
+ while (cur_func->popSrcFile () != NULL)
+ ;
+ cur_func = func;
+ includes->push_src_files (cur_func);
+ }
+ cur_func->add_PC_info (pc - low_pc, lineno);
+ }
+ }
+ if (cur_func)
+ while (cur_func->popSrcFile ())
+ ;
+ delete includes;
+}
+
+DwrLineRegs *
+DwrCU::get_dwrLineReg ()
+{
+ if (dwrLineReg == NULL)
+ dwrLineReg = new DwrLineRegs (new DwrSec (dwarf->debug_lineSec,
+ stmt_list_offset), comp_dir);
+ return dwrLineReg;
+}
+
+void
+DwrCU::parse_inlined_subroutine (Dwarf_cnt *ctx)
+{
+ int64_t abstract_origin = Dwarf_ref (DW_AT_abstract_origin);
+ int fileno = (int) Dwarf_data (DW_AT_call_file);
+ int lineno = (int) Dwarf_data (DW_AT_call_line);
+ int level = ctx->inlinedSubr ? (ctx->inlinedSubr->level + 1) : 0;
+ DwrInlinedSubr *inlinedSubr_old = ctx->inlinedSubr;
+
+ if (dwrInlinedSubrs == NULL)
+ dwrInlinedSubrs = new Vector<DwrInlinedSubr*>;
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_ranges);
+ if (dwrAttr)
+ {
+ uint64_t ranges = Dwarf_ref (DW_AT_ranges);
+ if (dwarf->debug_rangesSec && (ranges < dwarf->debug_rangesSec->size))
+ {
+ dwarf->debug_rangesSec->offset = ranges;
+ for (;;)
+ {
+ uint64_t low_pc = dwarf->debug_rangesSec->GetADDR ();
+ uint64_t high_pc = dwarf->debug_rangesSec->GetADDR ();
+ if ((low_pc > 0) && (low_pc <= high_pc))
+ {
+ DwrInlinedSubr *p = new DwrInlinedSubr (abstract_origin,
+ low_pc, high_pc, fileno, lineno, level);
+ dwrInlinedSubrs->append (p);
+ ctx->inlinedSubr = p;
+ }
+ else
+ break;
+ }
+ }
+ }
+ else
+ {
+ uint64_t low_pc = Dwarf_addr (DW_AT_low_pc);
+ uint64_t high_pc = get_high_pc (low_pc);
+ if ((low_pc > 0) && (low_pc <= high_pc))
+ {
+ DwrInlinedSubr *p = new DwrInlinedSubr (abstract_origin, low_pc,
+ high_pc, fileno, lineno, level);
+ dwrInlinedSubrs->append (p);
+ ctx->inlinedSubr = p;
+ }
+ }
+ parseChild (ctx);
+ ctx->inlinedSubr = inlinedSubr_old;
+}
+
+
+//////////////////////////////////////////////////////////
+// class DwrInlinedSubr
+DwrInlinedSubr::DwrInlinedSubr (int64_t _abstract_origin, uint64_t _low_pc,
+ uint64_t _high_pc, int _file, int _line, int _level)
+{
+ abstract_origin = _abstract_origin;
+ low_pc = _low_pc;
+ high_pc = _high_pc;
+ file = _file;
+ line = _line;
+ level = _level;
+}
+
+void
+DwrInlinedSubr::dump ()
+{
+ Dprintf (DUMP_DWARFLIB,
+ " level=%d 0x%08llx [0x%08llx - 0x%08llx] file=%d line=%d\n",
+ (int) level, (long long) abstract_origin, (long long) low_pc,
+ (long long) high_pc, (int) file, (int) line);
+}
diff --git a/gprofng/src/DwarfLib.h b/gprofng/src/DwarfLib.h
new file mode 100644
index 0000000..95eff57
--- /dev/null
+++ b/gprofng/src/DwarfLib.h
@@ -0,0 +1,313 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DWARFLIB_H_
+#define _DWARFLIB_H_
+
+#include "dwarf2.h"
+
+class ElfReloc;
+class Dwr_type;
+class SourceFile;
+
+template <class ITEM> class Vector;
+template <class ITEM> class DbeArray;
+template <typename Key_t, typename Value_t> class DefaultMap;
+
+typedef uint64_t ULEB128;
+typedef int64_t SLEB128;
+typedef unsigned short Dwarf_Half;
+typedef unsigned char Dwarf_Small;
+typedef uint64_t Dwarf_Off;
+typedef uint64_t Dwarf_Addr;
+typedef uint64_t Dwarf_Unsigned;
+typedef int64_t Dwarf_Die;
+typedef int32_t Dwarf_Debug;
+typedef int32_t Dwarf_Attribute;
+
+
+class DwrSec
+{
+public:
+ DwrSec (unsigned char *_data, uint64_t _size, bool _need_swap_endian, bool _addr32);
+ DwrSec (DwrSec *secp, uint64_t _offset);
+ ~DwrSec ();
+ unsigned char Get_8 ();
+ unsigned short Get_16 ();
+ uint32_t Get_32 ();
+ uint64_t Get_64 ();
+ uint64_t GetRef ();
+ uint64_t GetADDR ();
+ uint64_t GetADDR_32 ();
+ uint64_t GetADDR_64 ();
+ uint64_t GetLong ();
+ uint64_t ReadLength ();
+ SLEB128 GetSLEB128 ();
+ ULEB128 GetULEB128 ();
+ char *GetString (uint64_t *lenp);
+ char *GetData (uint64_t len);
+ void dump (char *msg);
+
+ inline uint32_t
+ GetULEB128_32 ()
+ {
+ return (uint32_t) GetULEB128 ();
+ }
+
+ bool
+ inRange (uint64_t left, uint64_t right)
+ {
+ return (offset >= left) && (offset < right);
+ };
+
+ ElfReloc *reloc;
+ uint64_t sizeSec;
+ uint64_t size;
+ uint64_t offset;
+ bool fmt64;
+ bool addr32;
+ bool need_swap_endian;
+
+private:
+ bool isCopy;
+ unsigned char *data;
+ bool bounds_violation (uint64_t sz);
+};
+
+class DwrFileName
+{
+public:
+ DwrFileName (char *_fname);
+ ~DwrFileName ();
+ uint64_t timestamp;
+ uint64_t file_size;
+ int dir_index;
+ char *fname;
+ char *path;
+ bool isUsed;
+};
+
+class DwrLine
+{
+public:
+ DwrLine ();
+ ~DwrLine ();
+ uint64_t address;
+ uint32_t file;
+ uint32_t line;
+ uint32_t column;
+};
+
+class DwrInlinedSubr
+{
+public:
+ DwrInlinedSubr (int64_t _abstract_origin, uint64_t _low_pc, uint64_t _high_pc,
+ int _file, int _line, int _level);
+ void dump ();
+ int64_t abstract_origin;
+ uint64_t low_pc;
+ uint64_t high_pc;
+ int file;
+ int line;
+ int level;
+};
+
+class DwrLineRegs
+{
+public:
+ DwrLineRegs (DwrSec *_secp, char *dirName);
+ ~DwrLineRegs ();
+ char *getPath (int fn);
+ Vector<DwrLine *> *get_lines ();
+ void dump ();
+
+ Vector<DwrFileName *> *file_names;
+
+private:
+ void DoExtendedOpcode ();
+ void DoStandardOpcode (int opcode);
+ void DoSpecialOpcode (int opcode);
+ void EmitLine ();
+ void reset ();
+
+ char *fname;
+ uint64_t dir_index;
+ uint64_t timestamp;
+ uint64_t file_size;
+ uint64_t address;
+ uint32_t file;
+ uint32_t line;
+ uint32_t column;
+ Dwarf_Half version;
+ uint64_t op_index_register;
+ Dwarf_Small maximum_operations_per_instruction;
+ Dwarf_Small minimum_instruction_length;
+ Dwarf_Small default_is_stmt;
+ Dwarf_Small line_range;
+ Dwarf_Small opcode_base;
+ signed char line_base;
+ bool is_stmt;
+ bool basic_block;
+ bool end_sequence;
+ Vector<DwrLine *> *lines;
+ Vector<char *> *include_directories;
+ Dwarf_Small *standard_opcode_length;
+ DwrSec *debug_lineSec;
+ uint64_t header_length;
+ uint64_t opcode_start;
+};
+
+typedef struct Dwr_Attr
+{
+ union
+ {
+ char *str;
+ unsigned char *block;
+ uint64_t offset;
+ int64_t val;
+ } u;
+ uint64_t len; // length of u.str
+ int at_form;
+ int at_name;
+} Dwr_Attr;
+
+typedef struct Dwr_Tag
+{
+public:
+ Dwr_Attr *get_attr (Dwarf_Half attr);
+ void dump ();
+
+ DbeArray<Dwr_Attr> *abbrevAtForm;
+ int64_t die;
+ int64_t offset;
+ int firstAttribute;
+ int lastAttribute;
+ int tag;
+ int hasChild;
+ int num;
+ int level;
+} Dwr_Tag;
+
+enum
+{
+ DW_DLV_OK,
+ DW_DLV_NO_ENTRY,
+ DW_DLV_ERROR,
+ DW_DLV_BAD_ELF,
+ DW_DLV_NO_DWARF,
+ DW_DLV_WRONG_ARG
+};
+
+typedef struct DwrLocation
+{
+ uint64_t offset;
+ uint64_t lc_number;
+ uint64_t lc_number2;
+ uint32_t op;
+} DwrLocation;
+
+typedef struct DwrAbbrevTable
+{
+ int64_t offset;
+ int firstAtForm;
+ int lastAtForm;
+ int code;
+ int tag;
+ bool hasChild;
+} DwrAbbrevTable;
+
+class Dwarf_cnt
+{
+public:
+ Dwarf_cnt ();
+ int64_t cu_offset;
+ int64_t parent;
+ int64_t size;
+ Module *module;
+ char *name;
+ Function *func;
+ Function *fortranMAIN;
+ datatype_t *dtype;
+ DwrInlinedSubr *inlinedSubr;
+ DefaultMap <int64_t, Dwr_type*> *dwr_types;
+ int level;
+
+ Dwr_type *get_dwr_type (int64_t cu_die_offset);
+ Dwr_type *put_dwr_type (int64_t cu_die_offset, int tag);
+ Dwr_type *put_dwr_type (Dwr_Tag *dwrTag);
+};
+
+class DwrCU
+{
+public:
+ DwrCU (Dwarf *_dwarf);
+ ~DwrCU ();
+ Module *parse_cu_header (LoadObject *lo);
+ void parseChild (Dwarf_cnt *ctx);
+ void read_hwcprof_info (Dwarf_cnt *ctx);
+ void map_dwarf_lines (Module *mod);
+ int set_die (Dwarf_Die die);
+ DwrLineRegs *get_dwrLineReg ();
+
+ static char *at2str (int tag);
+ static char *form2str (int tag);
+ static char *tag2str (int tag);
+
+ uint64_t cu_header_offset;
+ uint64_t cu_offset;
+ uint64_t next_cu_offset;
+ Vector<DwrInlinedSubr*> *dwrInlinedSubrs;
+ Vector<SourceFile *> *srcFiles;
+ bool isMemop;
+ bool isGNU;
+
+private:
+ void build_abbrevTable (DwrSec *debug_abbrevSec, uint64_t stmt_list_offset);
+ Function *append_Function (Dwarf_cnt *ctx);
+ void parse_inlined_subroutine (Dwarf_cnt *ctx);
+ uint64_t get_low_pc ();
+ uint64_t get_high_pc (uint64_t low_pc);
+ DwrLocation *dwr_get_location (DwrSec *secp, DwrLocation *lp);
+ int read_data_attr (Dwarf_Half attr, int64_t *retVal);
+ int read_ref_attr (Dwarf_Half attr, int64_t *retVal);
+ char *get_linkage_name ();
+ char *Dwarf_string (Dwarf_Half attr);
+ int64_t Dwarf_data (Dwarf_Half attr);
+ int64_t Dwarf_ref (Dwarf_Half attr);
+ DwrSec *Dwarf_block (Dwarf_Half attr);
+ Dwarf_Addr Dwarf_addr (Dwarf_Half attr);
+ Dwarf_Addr Dwarf_location (Dwarf_Attribute attr);
+ Sp_lang_code Dwarf_lang ();
+
+ Dwarf *dwarf;
+ DwrSec *debug_infoSec;
+ uint64_t debug_abbrev_offset;
+ uint64_t stmt_list_offset; // offset in .debug_line section (DW_AT_stmt_list)
+ char *comp_dir; // compilation directory (DW_AT_comp_dir)
+ Module *module;
+ Dwarf_Half version;
+ Dwarf_Small address_size;
+ Dwr_Tag dwrTag;
+ DwrLineRegs *dwrLineReg;
+ DbeArray<DwrAbbrevTable> *abbrevTable;
+ DbeArray<Dwr_Attr> *abbrevAtForm;
+};
+
+#endif /* _DWARFLIB_H_ */
diff --git a/gprofng/src/Elf.cc b/gprofng/src/Elf.cc
new file mode 100644
index 0000000..4117cf2
--- /dev/null
+++ b/gprofng/src/Elf.cc
@@ -0,0 +1,1138 @@
+/* Copyright (C) 2021 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 <unistd.h>
+
+#include "util.h"
+#include "bfd.h"
+#include "elf-bfd.h"
+#include "Elf.h"
+#include "Map.h"
+#include "StringBuilder.h"
+#include "DbeFile.h"
+
+typedef uint32_t Elf32_Word;
+typedef uint32_t Elf64_Word;
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Xword;
+typedef int32_t Elf32_Sword;
+typedef int64_t Elf64_Sxword;
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+// Ancillary entry
+typedef struct
+{
+ Elf32_Word a_tag; /* how to interpret value */
+ union
+ {
+ Elf32_Word a_val;
+ Elf32_Addr a_ptr;
+ } a_un;
+} Elf32_Ancillary;
+
+struct S_Elf64_Ancillary
+{
+ Elf64_Xword a_tag; /* how to interpret value */
+ union
+ {
+ Elf64_Xword a_val;
+ Elf64_Addr a_ptr;
+ } a_un;
+};
+
+/* Dynamic section entry. */
+typedef struct
+{
+ Elf32_Sword d_tag; /* Dynamic entry type */
+
+ union
+ {
+ Elf32_Word d_val; /* Integer value */
+ Elf32_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf32_Dyn;
+
+struct S_Elf64_Dyn
+{
+ Elf64_Sxword d_tag; /* Dynamic entry type */
+
+ union
+ {
+ Elf64_Xword d_val; /* Integer value */
+ Elf64_Addr d_ptr; /* Address value */
+ } d_un;
+};
+
+
+// Symbol table
+typedef struct
+{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info; /* bind, type: ELF_32_ST_... */
+ unsigned char st_other;
+ Elf32_Half st_shndx; /* SHN_... */
+} Elf32_Sym;
+
+typedef struct
+{
+ Elf64_Word st_name;
+ unsigned char st_info; /* bind, type: ELF_64_ST_... */
+ unsigned char st_other;
+ Elf64_Half st_shndx; /* SHN_... */
+ Elf64_Addr st_value;
+ Elf64_Xword st_size;
+} Elf64_Sym;
+
+
+// Relocation
+typedef struct
+{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info; /* sym, type: ELF32_R_... */
+} Elf32_Rel;
+
+typedef struct
+{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info; /* sym, type: ELF32_R_... */
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+typedef struct
+{
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info; /* sym, type: ELF64_R_... */
+} Elf64_Rel;
+
+typedef struct
+{
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info; /* sym, type: ELF64_R_... */
+ Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+int Elf::bfd_status = -1;
+
+void
+Elf::elf_init ()
+{
+ if (bfd_status == -1)
+ bfd_status = bfd_init ();
+}
+
+Elf::Elf (char *filename) : DbeMessages (), Data_window (filename)
+{
+ ehdrp = NULL;
+ data = NULL;
+ ancillary_files = NULL;
+ elfSymbols = NULL;
+ gnu_debug_file = NULL;
+ dbeFile = NULL;
+ abfd = NULL;
+ if (bfd_status != BFD_INIT_MAGIC)
+ {
+ status = ELF_ERR_CANT_OPEN_FILE;
+ return;
+ }
+ abfd = bfd_openr (filename, NULL);
+ if (abfd == NULL)
+ {
+ status = ELF_ERR_CANT_OPEN_FILE;
+ return;
+ }
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ bfd_close (abfd);
+ abfd = NULL;
+ status = ELF_ERR_CANT_OPEN_FILE;
+ return;
+ }
+ ehdrp = elf_getehdr ();
+ if (ehdrp == NULL)
+ {
+ bfd_close (abfd);
+ abfd = NULL;
+ status = ELF_ERR_BAD_ELF_FORMAT;
+ return;
+ }
+ elf_class = ehdrp->e_ident[EI_CLASS];
+ elf_datatype = ehdrp->e_ident[EI_DATA];
+
+ if (not_opened ())
+ {
+ status = ELF_ERR_CANT_OPEN_FILE;
+ return;
+ }
+ status = ELF_ERR_NONE;
+
+#if ARCH(SPARC)
+ need_swap_endian = is_Intel ();
+#else
+ need_swap_endian = !is_Intel ();
+#endif
+
+ analyzerInfo = 0;
+ SUNW_ldynsym = 0;
+ gnuLink = 0;
+ stab = 0;
+ stabStr = 0;
+ stabIndex = 0;
+ stabIndexStr = 0;
+ stabExcl = 0;
+ stabExclStr = 0;
+ symtab = 0;
+ dynsym = 0;
+ info = 0;
+ plt = 0;
+ dwarf = false;
+
+ for (unsigned int sec = 1; sec < elf_getehdr ()->e_shnum; sec++)
+ {
+ char *name = get_sec_name (sec);
+ if (name == NULL)
+ continue;
+ if (streq (name, NTXT (".stab")))
+ stab = sec;
+ else if (streq (name, NTXT (".stabstr")))
+ stabStr = sec;
+ else if (streq (name, NTXT (".stab.index")))
+ stabIndex = sec;
+ else if (streq (name, NTXT (".stab.indexstr")))
+ stabIndexStr = sec;
+ else if (streq (name, NTXT (".stab.excl")))
+ stabExcl = sec;
+ else if (streq (name, NTXT (".stab.exclstr")))
+ stabExclStr = sec;
+ else if (streq (name, NTXT (".gnu_debuglink")))
+ gnuLink = sec;
+ else if (streq (name, NTXT (".__analyzer_info")))
+ analyzerInfo = sec;
+ else if (streq (name, NTXT (".info")))
+ info = true;
+ else if (streq (name, NTXT (".plt")))
+ plt = sec;
+ else if (streq (name, NTXT (".SUNW_ldynsym")))
+ SUNW_ldynsym = sec;
+ else if (streq (name, NTXT (".dynsym")))
+ dynsym = sec;
+ else if (streq (name, NTXT (".symtab")))
+ symtab = sec;
+ else if (strncmp (name, NTXT (".debug"), 6) == 0)
+ dwarf = true;
+ }
+ if (fd != -1)
+ {
+ close (fd);
+ fd = -1;
+ }
+}
+
+Elf::~Elf ()
+{
+ if (data)
+ {
+ for (int i = 0; i < (int) ehdrp->e_shnum; i++)
+ {
+ Elf_Data *p = data[i];
+ if (p && !mmap_on_file && (p->d_flags & SHF_SUNW_ABSENT) == 0)
+ free (p->d_buf);
+ delete p;
+ }
+ free (data);
+ }
+ if (ancillary_files)
+ {
+ ancillary_files->destroy ();
+ delete ancillary_files;
+ }
+ delete elfSymbols;
+ delete gnu_debug_file;
+ delete dbeFile;
+ if (abfd)
+ bfd_close (abfd);
+}
+
+Elf_Internal_Ehdr *
+Elf::elf_getehdr ()
+{
+ if (ehdrp == NULL && abfd)
+ ehdrp = elf_elfheader (abfd);
+ return ehdrp;
+}
+
+Elf_Internal_Phdr *
+Elf::get_phdr (unsigned int ndx)
+{
+ if (ehdrp == NULL || ndx >= ehdrp->e_phnum)
+ return NULL;
+ return &(elf_tdata (abfd)->phdr[ndx]);
+}
+
+Elf_Internal_Shdr *
+Elf::get_shdr (unsigned int ndx)
+{
+ if (ehdrp == NULL || ndx >= ehdrp->e_shnum)
+ return NULL;
+ return elf_elfsections (abfd)[ndx];
+}
+
+Elf64_Dyn *
+Elf::elf_getdyn (Elf_Internal_Phdr *phdr, unsigned int ndx, Elf64_Dyn *pdyn)
+{
+ if (elf_getclass () == ELFCLASS32)
+ {
+ if (ndx * sizeof (Elf32_Dyn) >= phdr->p_filesz)
+ return NULL;
+ Elf32_Dyn *hdr = (Elf32_Dyn*) bind (phdr->p_offset + ndx * sizeof (Elf32_Dyn),
+ sizeof (Elf32_Dyn));
+ if (hdr == NULL)
+ return NULL;
+ pdyn->d_tag = decode (hdr->d_tag);
+ pdyn->d_un.d_val = decode (hdr->d_un.d_val);
+ }
+ else
+ {
+ if (ndx * sizeof (Elf64_Dyn) >= phdr->p_filesz)
+ return NULL;
+ Elf64_Dyn *hdr = (Elf64_Dyn*) bind (phdr->p_offset + ndx * sizeof (Elf64_Dyn),
+ sizeof (Elf64_Dyn));
+ if (hdr == NULL)
+ return NULL;
+ pdyn->d_tag = decode (hdr->d_tag);
+ pdyn->d_un.d_val = decode (hdr->d_un.d_val);
+ }
+ return pdyn;
+}
+
+unsigned
+Elf::elf_version (unsigned ver)
+{
+ // We compile locally, no need to check the version
+ return ver;
+}
+
+Elf *
+Elf::elf_begin (char *fname, Elf_status *stp)
+{
+ if (fname == NULL)
+ {
+ if (stp)
+ *stp = ELF_ERR_CANT_OPEN_FILE;
+ return NULL;
+ }
+ Elf *elf = new Elf (fname);
+ if (stp)
+ *stp = elf->status;
+ if (elf->status != ELF_ERR_NONE)
+ {
+ delete elf;
+ return NULL;
+ }
+#if DEBUG
+ if (DUMP_ELF_SEC)
+ {
+ char *str = elf->dump ();
+ fprintf (stderr, NTXT ("%s\n\n"), str);
+ free (str);
+ }
+#endif /* DEBUG */
+ return elf;
+}
+
+unsigned int
+Elf::elf_get_sec_num (const char *name)
+{
+ if (name == NULL || ehdrp == NULL)
+ return 0;
+ for (unsigned int sec = 1; sec < ehdrp->e_shnum; sec++)
+ {
+ Elf_Internal_Shdr *shdr = get_shdr (sec);
+ if (shdr == NULL)
+ continue;
+ char *sname = elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
+ if (sname != NULL && strcmp (name, sname) == 0)
+ return sec;
+ }
+ return 0;
+}
+
+char *
+Elf::get_sec_name (unsigned int sec)
+{
+ Elf_Internal_Shdr *shdr = get_shdr (sec);
+ if (ehdrp == NULL || shdr == NULL)
+ return NULL;
+ return elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
+}
+
+Elf_Data *
+Elf::elf_getdata (unsigned int sec)
+{
+ if (data == NULL)
+ {
+ data = (Elf_Data **) malloc (ehdrp->e_shnum * sizeof (Elf_Data *));
+ for (int i = 0; i < (int) ehdrp->e_shnum; i++)
+ data[i] = NULL;
+ }
+ Elf_Data *edta = data[sec];
+ if (edta == NULL)
+ {
+ Elf_Internal_Shdr *shdr = get_shdr (sec);
+ if (shdr == NULL)
+ return NULL;
+ edta = new Elf_Data;
+ data[sec] = edta;
+ if ((shdr->sh_flags & SHF_SUNW_ABSENT) != 0)
+ {
+ char *sname = get_sec_name (sec);
+ for (int i = 0, sz = VecSize(ancillary_files); i < sz; i++)
+ {
+ Elf *ancElf = ancillary_files->fetch (i);
+ int secNum = sec;
+ if (dbe_strcmp (sname, ancElf->get_sec_name (sec)) != 0)
+ {
+ append_msg (CMSG_WARN,
+ "Warning: the section #%d (%s) is mismatch in ancillary file '%s')\n",
+ sec, STR (sname), STR (ancElf->fname));
+ secNum = ancElf->elf_get_sec_num (sname);
+ }
+ if (secNum > 0)
+ {
+ Elf_Data *ed = ancElf->elf_getdata (secNum);
+ if (ed && ed->d_buf)
+ {
+ *edta = *ed;
+ edta->d_flags |= SHF_SUNW_ABSENT;
+ return edta;
+ }
+ }
+ }
+ }
+ edta->d_buf = get_data (shdr->sh_offset, (size_t) shdr->sh_size, NULL);
+ edta->d_flags = shdr->sh_flags;
+ edta->d_size = ((edta->d_buf == NULL) || (shdr->sh_type == SHT_NOBITS)) ? 0 : shdr->sh_size;
+ edta->d_off = shdr->sh_offset;
+ edta->d_align = shdr->sh_addralign;
+ }
+ return edta;
+}
+
+int64_t
+Elf::elf_checksum ()
+{
+ if (ehdrp == NULL)
+ return 0;
+ int64_t chk = 0;
+ for (unsigned int ndx = 0; ndx < ehdrp->e_phnum; ndx++)
+ {
+ Elf_Internal_Phdr *phdr = get_phdr (ndx);
+ if (phdr == NULL)
+ continue;
+ if (phdr->p_type == PT_DYNAMIC)
+ {
+ Elf64_Dyn edyn;
+ for (unsigned int i = 0; elf_getdyn (phdr, i, &edyn) != NULL; i++)
+ {
+ if (!edyn.d_tag)
+ break;
+ if (edyn.d_tag == DT_CHECKSUM)
+ {
+ chk = edyn.d_un.d_val;
+ break;
+ }
+ }
+ }
+ }
+ return normalize_checksum (chk);
+}
+
+uint64_t
+Elf::get_baseAddr ()
+{
+ uint64_t addr = 0;
+ for (unsigned int pnum = 0; pnum < elf_getehdr ()->e_phnum; pnum++)
+ {
+ Elf_Internal_Phdr *phdr = get_phdr (pnum);
+ if (phdr->p_type == PT_LOAD && phdr->p_flags == (PF_R | PF_X))
+ {
+ if (addr == 0)
+ addr = phdr->p_vaddr;
+ else
+ {
+ addr = 0;
+ break;
+ }
+ }
+ }
+ return addr;
+}
+
+char *
+Elf::elf_strptr (unsigned int sec, uint64_t off)
+{
+ Elf_Data *edta = elf_getdata (sec);
+ if (edta && edta->d_buf && edta->d_size > off)
+ return ((char *) edta->d_buf) + off;
+ return NULL;
+}
+
+Elf_Internal_Sym *
+Elf::elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst)
+{
+ if (dst == NULL || edta == NULL)
+ return NULL;
+ if (elf_getclass () == ELFCLASS32)
+ {
+ if (edta->d_size <= ndx * sizeof (Elf32_Sym))
+ return NULL;
+ Elf32_Sym *hdr = (Elf32_Sym*) bind (edta->d_off + ndx * sizeof (Elf32_Sym), sizeof (Elf32_Sym));
+ if (hdr == NULL)
+ return NULL;
+ dst->st_name = decode (hdr->st_name);
+ dst->st_value = decode (hdr->st_value);
+ dst->st_size = decode (hdr->st_size);
+ dst->st_info = ELF64_ST_INFO (ELF32_ST_BIND (decode (hdr->st_info)),
+ ELF32_ST_TYPE (decode (hdr->st_info)));
+ dst->st_other = decode (hdr->st_other);
+ dst->st_shndx = decode (hdr->st_shndx);
+ }
+ else
+ {
+ if (edta->d_size <= ndx * sizeof (Elf64_Sym))
+ return NULL;
+ Elf64_Sym *hdr = (Elf64_Sym*) bind (edta->d_off + ndx * sizeof (Elf64_Sym),
+ sizeof (Elf64_Sym));
+ if (hdr == NULL)
+ return NULL;
+ dst->st_name = decode (hdr->st_name);
+ dst->st_value = decode (hdr->st_value);
+ dst->st_size = decode (hdr->st_size);
+ dst->st_info = decode (hdr->st_info);
+ dst->st_other = decode (hdr->st_other);
+ dst->st_shndx = decode (hdr->st_shndx);
+ }
+ return dst;
+}
+
+Elf_Internal_Rela *
+Elf::elf_getrel (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst)
+{
+ if (dst == NULL || edta == NULL || edta->d_buf == NULL)
+ return NULL;
+ if (elf_getclass () == ELFCLASS32)
+ {
+ Elf32_Rel *rel = ((Elf32_Rel *) edta->d_buf) + ndx;
+ dst->r_offset = decode (rel->r_offset);
+ dst->r_info = ELF64_R_INFO (ELF32_R_SYM (decode (rel->r_info)),
+ ELF32_R_TYPE (decode (rel->r_info)));
+ }
+ else
+ {
+ Elf64_Rel *rel = ((Elf64_Rel *) edta->d_buf) + ndx;
+ dst->r_offset = decode (rel->r_offset);
+ dst->r_info = decode (rel->r_info);
+ }
+ return dst;
+}
+
+Elf_Internal_Rela *
+Elf::elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst)
+{
+ if (dst == NULL || edta == NULL || edta->d_buf == NULL)
+ return NULL;
+ if (elf_getclass () == ELFCLASS32)
+ {
+ Elf32_Rela *rela = ((Elf32_Rela *) edta->d_buf) + ndx;
+ dst->r_offset = decode (rela->r_offset);
+ dst->r_addend = decode (rela->r_addend);
+ dst->r_info = ELF64_R_INFO (ELF32_R_SYM (decode (rela->r_info)),
+ ELF32_R_TYPE (decode (rela->r_info)));
+ }
+ else
+ {
+ Elf64_Rela *rela = ((Elf64_Rela *) edta->d_buf) + ndx;
+ dst->r_offset = decode (rela->r_offset);
+ dst->r_addend = decode (rela->r_addend);
+ dst->r_info = decode (rela->r_info);
+ }
+ return dst;
+}
+
+Elf64_Ancillary *
+Elf::elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst)
+{
+ if (dst == NULL || edta == NULL || edta->d_buf == NULL)
+ return NULL;
+ if (elf_getclass () == ELFCLASS32)
+ {
+ Elf32_Ancillary *p = ((Elf32_Ancillary *) edta->d_buf) + ndx;
+ dst->a_tag = decode (p->a_tag);
+ dst->a_un.a_val = decode (p->a_un.a_val);
+ }
+ else
+ {
+ Elf64_Ancillary *p = ((Elf64_Ancillary *) edta->d_buf) + ndx;
+ dst->a_tag = decode (p->a_tag);
+ dst->a_un.a_val = decode (p->a_un.a_val);
+ }
+ return dst;
+}
+
+Elf *
+Elf::get_related_file (const char *lo_name, const char *nm)
+{
+ DbeFile *df;
+ if (*nm == '/')
+ {
+ df = new DbeFile (nm);
+ df->filetype |= (DbeFile::F_FILE | DbeFile::F_DEBUG_FILE);
+ }
+ else
+ {
+ char *bname = get_basename (lo_name);
+ char *fnm = dbe_sprintf ("%.*s/%s", (int) (bname - lo_name), lo_name, nm);
+ df = new DbeFile (fnm);
+ df->filetype |= (DbeFile::F_FILE | DbeFile::F_DEBUG_FILE);
+ free (fnm);
+ }
+ Dprintf (DEBUG_STABS, "get_related_file: %s -> '%s'\n", nm, df->get_name ());
+ Elf_status st = ELF_ERR_CANT_OPEN_FILE;
+ Elf *elf = elf_begin (df->get_location (), &st);
+ if (elf)
+ {
+ elf->dbeFile = df;
+ return elf;
+ }
+ switch (st)
+ {
+ case ELF_ERR_CANT_OPEN_FILE:
+ append_msg (CMSG_ERROR, GTXT ("Cannot open file `%s'"), df->get_name ());
+ break;
+ case ELF_ERR_BAD_ELF_FORMAT:
+ default:
+ append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"),
+ df->get_name ());
+ break;
+ }
+ delete df;
+ return NULL;
+}
+
+Elf *
+Elf::find_ancillary_files (char *lo_name)
+{
+ // read the .gnu_debuglink and .SUNW_ancillary seections
+ if (gnu_debug_file)
+ return gnu_debug_file;
+ unsigned int sec = elf_get_sec_num (NTXT (".gnu_debuglink"));
+ if (sec > 0)
+ {
+ Elf_Data *dp = elf_getdata (sec);
+ if (dp)
+ {
+ gnu_debug_file = get_related_file (lo_name, (char *) (dp->d_buf));
+ if (gnu_debug_file)
+ return gnu_debug_file;
+ }
+ }
+
+ sec = elf_get_sec_num (NTXT (".SUNW_ancillary"));
+ if (sec > 0)
+ {
+ Elf_Internal_Shdr *shdr = get_shdr (sec);
+ uint64_t check_sum = 0;
+ char *ancName = NULL;
+ if (shdr)
+ {
+ Elf_Data *dp = elf_getdata (sec);
+ for (int i = 0, sz = (int) (shdr->sh_size / shdr->sh_entsize);
+ i < sz; i++)
+ {
+ Elf64_Ancillary anc;
+ if (elf_getancillary (dp, i, &anc) == NULL
+ || anc.a_tag == ANC_SUNW_NULL)
+ break;
+ if (anc.a_tag == ANC_SUNW_MEMBER)
+ ancName = elf_strptr (shdr->sh_link, anc.a_un.a_ptr);
+ else if (anc.a_tag == ANC_SUNW_CHECKSUM)
+ {
+ if (i == 0)
+ {
+ check_sum = anc.a_un.a_val;
+ continue;
+ }
+ if (check_sum == anc.a_un.a_val)
+ ancName = NULL;
+ if (ancName)
+ {
+ Elf *ancElf = get_related_file (lo_name, ancName);
+ if (ancElf == NULL)
+ continue;
+ int ancSec = ancElf->elf_get_sec_num (".SUNW_ancillary");
+ if (ancSec > 0)
+ {
+ Elf_Internal_Shdr *ancHdr = ancElf->get_shdr (ancSec);
+ if (ancHdr)
+ {
+ Elf_Data *anc_dp = ancElf->elf_getdata (ancSec);
+ Elf64_Ancillary anc1;
+ if (ancElf->elf_getancillary (anc_dp, 0, &anc1)
+ && (anc1.a_tag == ANC_SUNW_CHECKSUM) &&
+ anc1.a_un.a_val == anc.a_un.a_val)
+ {
+ if (ancillary_files == NULL)
+ ancillary_files = new Vector<Elf*>(2);
+ ancillary_files->append (ancElf);
+ }
+ else
+ append_msg (CMSG_WARN, GTXT ("Load Object: '%s' (checksum Ox%lld). The .anc file '%s' has checksum Ox%llx"),
+ STR (fname), (long long) check_sum,
+ STR (ancElf->dbeFile->get_location ()),
+ (long long) anc1.a_un.a_val);
+ }
+ }
+ ancName = NULL;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+char*
+Elf::get_location ()
+{
+ return dbeFile ? dbeFile->get_location () : fname;
+}
+
+#define RET_S(x) if (t == x) return (char *) #x
+
+static char *
+get_elf_class_name (int t)
+{
+ RET_S (ELFCLASSNONE);
+ RET_S (ELFCLASS32);
+ RET_S (ELFCLASS64);
+ return NTXT ("ELFCLASS_UNKNOWN");
+}
+
+static char *
+get_elf_data_name (int t)
+{
+ RET_S (ELFDATANONE);
+ RET_S (ELFDATA2LSB);
+ RET_S (ELFDATA2MSB);
+ return NTXT ("ELFDATA_UNKNOWN");
+}
+
+static char *
+get_elf_osabi_name (int t)
+{
+ RET_S (ELFOSABI_NONE);
+ RET_S (ELFOSABI_HPUX);
+ RET_S (ELFOSABI_NETBSD);
+ RET_S (ELFOSABI_LINUX);
+ RET_S (ELFOSABI_SOLARIS);
+ RET_S (ELFOSABI_AIX);
+ RET_S (ELFOSABI_IRIX);
+ RET_S (ELFOSABI_FREEBSD);
+ RET_S (ELFOSABI_TRU64);
+ RET_S (ELFOSABI_MODESTO);
+ RET_S (ELFOSABI_OPENBSD);
+ return NTXT ("ELFOSABI_UNKNOWN");
+}
+
+static char *
+get_elf_etype_name (int t)
+{
+ RET_S (ET_NONE);
+ RET_S (ET_REL);
+ RET_S (ET_EXEC);
+ RET_S (ET_DYN);
+ RET_S (ET_CORE);
+ RET_S (ET_LOPROC);
+ RET_S (ET_HIPROC);
+ return NTXT ("ETYPE_UNKNOWN");
+}
+
+static char *
+get_elf_ptype_name (int t)
+{
+ RET_S (PT_NULL);
+ RET_S (PT_LOAD);
+ RET_S (PT_DYNAMIC);
+ RET_S (PT_INTERP);
+ RET_S (PT_NOTE);
+ RET_S (PT_SHLIB);
+ RET_S (PT_PHDR);
+ RET_S (PT_TLS);
+ RET_S (PT_LOOS);
+ RET_S (PT_GNU_EH_FRAME);
+ RET_S (PT_GNU_EH_FRAME);
+ RET_S (PT_HIOS);
+ RET_S (PT_LOPROC);
+ RET_S (PT_HIPROC);
+ return NTXT ("PTYPE_UNKNOWN");
+}
+
+static char *
+get_elf_shtype_name (unsigned int t)
+{
+ RET_S (SHT_NULL);
+ RET_S (SHT_PROGBITS);
+ RET_S (SHT_SYMTAB);
+ RET_S (SHT_STRTAB);
+ RET_S (SHT_RELA);
+ RET_S (SHT_HASH);
+ RET_S (SHT_DYNAMIC);
+ RET_S (SHT_NOTE);
+ RET_S (SHT_NOBITS);
+ RET_S (SHT_REL);
+ RET_S (SHT_SHLIB);
+ RET_S (SHT_DYNSYM);
+ RET_S (SHT_INIT_ARRAY);
+ RET_S (SHT_FINI_ARRAY);
+ RET_S (SHT_PREINIT_ARRAY);
+ RET_S (SHT_GROUP);
+ RET_S (SHT_SYMTAB_SHNDX);
+ RET_S (SHT_LOOS);
+ RET_S (SHT_SUNW_verdef);
+ RET_S (SHT_SUNW_verneed);
+ RET_S (SHT_HIOS);
+ RET_S (SHT_LOPROC);
+ RET_S (SHT_HIPROC);
+ RET_S (SHT_LOUSER);
+ RET_S (SHT_HIUSER);
+ return NTXT ("SHTYPE_UNKNOWN");
+}
+
+static char *
+get_elf_machine_name (int t)
+{
+ RET_S (EM_NONE);
+ RET_S (EM_M32);
+ RET_S (EM_SPARC);
+ RET_S (EM_386);
+ RET_S (EM_68K);
+ RET_S (EM_88K);
+ RET_S (EM_860);
+ RET_S (EM_MIPS);
+ RET_S (EM_S370);
+ RET_S (EM_MIPS_RS3_LE);
+ RET_S (EM_SPARC32PLUS);
+ RET_S (EM_960);
+ RET_S (EM_PPC);
+ RET_S (EM_PPC64);
+ RET_S (EM_V800);
+ RET_S (EM_FR20);
+ RET_S (EM_RH32);
+ RET_S (EM_RCE);
+ RET_S (EM_ARM);
+ RET_S (EM_ALPHA);
+ RET_S (EM_SH);
+ RET_S (EM_SPARCV9);
+ RET_S (EM_TRICORE);
+ RET_S (EM_ARC);
+ RET_S (EM_H8_300);
+ RET_S (EM_H8_300H);
+ RET_S (EM_H8S);
+ RET_S (EM_H8_500);
+ RET_S (EM_IA_64);
+ RET_S (EM_MIPS_X);
+ RET_S (EM_COLDFIRE);
+ RET_S (EM_68HC12);
+ RET_S (EM_MMA);
+ RET_S (EM_PCP);
+ RET_S (EM_NCPU);
+ RET_S (EM_NDR1);
+ RET_S (EM_STARCORE);
+ RET_S (EM_ME16);
+ RET_S (EM_ST100);
+ RET_S (EM_TINYJ);
+ RET_S (EM_X86_64);
+ RET_S (EM_PDSP);
+ RET_S (EM_FX66);
+ RET_S (EM_ST9PLUS);
+ RET_S (EM_ST7);
+ RET_S (EM_68HC16);
+ RET_S (EM_68HC11);
+ RET_S (EM_68HC08);
+ RET_S (EM_68HC05);
+ RET_S (EM_SVX);
+ RET_S (EM_ST19);
+ RET_S (EM_VAX);
+ RET_S (EM_CRIS);
+ RET_S (EM_JAVELIN);
+ RET_S (EM_FIREPATH);
+ RET_S (EM_ZSP);
+ RET_S (EM_MMIX);
+ RET_S (EM_HUANY);
+ RET_S (EM_PRISM);
+ RET_S (EM_AVR);
+ RET_S (EM_FR30);
+ RET_S (EM_D10V);
+ RET_S (EM_D30V);
+ RET_S (EM_V850);
+ RET_S (EM_M32R);
+ RET_S (EM_MN10300);
+ RET_S (EM_MN10200);
+ RET_S (EM_PJ);
+ RET_S (EM_OPENRISC);
+ RET_S (EM_XTENSA);
+ return NTXT ("ELFMACHINE_UNKNOWN");
+}
+
+static char *
+get_elf_version_name (int t)
+{
+ RET_S (EV_NONE);
+ RET_S (EV_CURRENT);
+ return NTXT ("VERSION_UNKNOWN");
+}
+
+static char *
+get_elf_ancillary_tag (int t)
+{
+ RET_S (ANC_SUNW_NULL);
+ RET_S (ANC_SUNW_CHECKSUM);
+ RET_S (ANC_SUNW_MEMBER);
+ RET_S (ANC_SUNW_NUM);
+ return NTXT ("ANCILLARY_TAG_UNKNOWN");
+}
+
+#define ADD_S(x) if ((f & (x)) == (x)) { sb->append(' '); sb->append(#x); f &= ~(x); }
+
+static void
+dump_sh_flags (StringBuilder *sb, long long flags)
+{
+ long long f = flags;
+ if (f != 0)
+ {
+ sb->append (NTXT (" ["));
+ ADD_S (SHF_WRITE)
+ ADD_S (SHF_ALLOC)
+ ADD_S (SHF_EXECINSTR)
+ ADD_S (SHF_MERGE)
+ ADD_S (SHF_STRINGS)
+ ADD_S (SHF_INFO_LINK)
+ ADD_S (SHF_LINK_ORDER)
+ ADD_S (SHF_OS_NONCONFORMING)
+ ADD_S (SHF_GROUP)
+ ADD_S (SHF_TLS)
+ ADD_S (SHF_SUNW_ABSENT)
+ ADD_S (SHF_EXCLUDE)
+ if (f != 0 && f != flags)
+ sb->appendf (NTXT (" 0x%llx"), (long long) f);
+ sb->append (NTXT (" ]"));
+ }
+ sb->append (NTXT ("\n"));
+}
+
+static void
+dump_p_flags (StringBuilder *sb, long long flags)
+{
+ long long f = flags;
+ if (f != 0)
+ {
+ sb->append (NTXT (" ["));
+ ADD_S (PF_X)
+ ADD_S (PF_W)
+ ADD_S (PF_R)
+ ADD_S (PF_MASKPROC)
+ if (f != 0 && f != flags)
+ sb->appendf (NTXT (" 0x%llx"), (long long) f);
+ sb->append (NTXT (" ]"));
+ }
+ sb->append (NTXT ("\n"));
+}
+
+char *
+Elf::dump ()
+{
+ StringBuilder sb;
+ sb.sprintf (NTXT ("ELF Header: %s\n"), fname ? fname : GTXT ("(unknown)"));
+ if (ehdrp == NULL)
+ {
+ sb.appendf (GTXT ("\n\n Cannot read Elf header\n"));
+ return sb.toString ();
+ }
+ sb.appendf (NTXT (" %-15s "), NTXT ("e_ident"));
+ for (int i = 0; i < EI_NIDENT; i++)
+ sb.appendf (NTXT ("%x"), ehdrp->e_ident[i]);
+ sb.append (NTXT ("\n"));
+ char *fmt0 = NTXT (" %-15s %10lld ( %s )\n");
+ char *fmt1 = NTXT (" %-15s 0x%08llx ( %lld )\n");
+ char *fmt2 = NTXT (" %-15s 0x%08llx");
+ sb.appendf (fmt0, NTXT ("EI_CLASS"), (long long) ehdrp->e_ident[EI_CLASS],
+ get_elf_class_name (ehdrp->e_ident[EI_CLASS]));
+ sb.appendf (fmt0, NTXT ("EI_DATA"), (long long) ehdrp->e_ident[EI_DATA],
+ get_elf_data_name (ehdrp->e_ident[EI_DATA]));
+ sb.appendf (fmt0, NTXT ("EI_OSABI"), (long long) ehdrp->e_ident[EI_OSABI],
+ get_elf_osabi_name (ehdrp->e_ident[EI_OSABI]));
+ sb.appendf (fmt0, NTXT ("e_type"), (long long) ehdrp->e_type,
+ get_elf_etype_name (ehdrp->e_type));
+ sb.appendf (fmt0, NTXT ("e_machine"), (long long) ehdrp->e_machine,
+ get_elf_machine_name (ehdrp->e_machine));
+ sb.appendf (fmt0, NTXT ("e_version"), (long long) ehdrp->e_version,
+ get_elf_version_name (ehdrp->e_version));
+ sb.appendf (fmt1, NTXT ("e_entry"), (long long) ehdrp->e_entry,
+ (long long) ehdrp->e_entry);
+ sb.appendf (fmt1, NTXT ("e_phoff"), (long long) ehdrp->e_phoff,
+ (long long) ehdrp->e_phoff);
+ sb.appendf (fmt1, NTXT ("e_shoff"), (long long) ehdrp->e_shoff,
+ (long long) ehdrp->e_shoff);
+ sb.appendf (fmt1, NTXT ("e_flags"), (long long) ehdrp->e_flags,
+ (long long) ehdrp->e_flags);
+ sb.appendf (fmt1, NTXT ("e_ehsize"), (long long) ehdrp->e_ehsize,
+ (long long) ehdrp->e_ehsize);
+ sb.appendf (fmt1, NTXT ("e_phentsize"), (long long) ehdrp->e_phentsize,
+ (long long) ehdrp->e_phentsize);
+ sb.appendf (fmt1, NTXT ("e_phnum"), (long long) ehdrp->e_phnum,
+ (long long) ehdrp->e_phnum);
+ sb.appendf (fmt1, NTXT ("e_shentsize"), (long long) ehdrp->e_shentsize,
+ (long long) ehdrp->e_shentsize);
+ sb.appendf (fmt1, NTXT ("e_shnum"), (long long) ehdrp->e_shnum,
+ (long long) ehdrp->e_shnum);
+ sb.appendf (fmt1, NTXT ("e_shstrndx"), (long long) ehdrp->e_shstrndx,
+ (long long) ehdrp->e_shstrndx);
+
+ for (unsigned int i = 0; i < ehdrp->e_phnum; i++)
+ {
+ sb.appendf (NTXT ("\nProgram Header[%d]:\n"), i);
+ Elf_Internal_Phdr *phdr = get_phdr (i);
+ if (phdr == NULL)
+ {
+ sb.appendf (NTXT (" ERROR: get_phdr(%d) failed\n"), i);
+ continue;
+ }
+ sb.appendf (fmt0, "p_type", (long long) phdr->p_type,
+ get_elf_ptype_name (phdr->p_type));
+ sb.appendf (fmt2, "p_flags", (long long) phdr->p_flags);
+ dump_p_flags (&sb, phdr->p_flags);
+ sb.appendf (fmt1, "p_offset", (long long) phdr->p_offset,
+ (long long) phdr->p_offset);
+ sb.appendf (fmt1, "p_vaddr", (long long) phdr->p_vaddr,
+ (long long) phdr->p_vaddr);
+ sb.appendf (fmt1, "p_paddr", (long long) phdr->p_paddr,
+ (long long) phdr->p_paddr);
+ sb.appendf (fmt1, "p_filesz", (long long) phdr->p_filesz,
+ (long long) phdr->p_filesz);
+ sb.appendf (fmt1, "p_memsz", (long long) phdr->p_memsz,
+ (long long) phdr->p_memsz);
+ sb.appendf (fmt1, "p_align", (long long) phdr->p_align,
+ (long long) phdr->p_align);
+ }
+
+ for (unsigned int i = 1; i < ehdrp->e_shnum; i++)
+ {
+ sb.appendf (NTXT ("\nSection Header[%d]:\n"), i);
+ Elf_Internal_Shdr *shdr = get_shdr (i);
+ if (shdr == NULL)
+ {
+ sb.appendf (NTXT (" ERROR: get_shdr(%d) failed\n"), i);
+ continue;
+ }
+ char *s = get_sec_name (i);
+ sb.appendf (fmt0, "sh_name", (long long) shdr->sh_name,
+ s ? s : NTXT ("NULL"));
+ sb.appendf (fmt0, "sh_type", (long long) shdr->sh_type,
+ get_elf_shtype_name (shdr->sh_type));
+ sb.appendf (fmt2, "sh_flags", (long long) shdr->sh_flags);
+ dump_sh_flags (&sb, shdr->sh_flags);
+ sb.appendf (fmt1, "sh_addr", (long long) shdr->sh_addr,
+ (long long) shdr->sh_addr);
+ sb.appendf (fmt1, "sh_offset", (long long) shdr->sh_offset,
+ (long long) shdr->sh_offset);
+ sb.appendf (fmt1, "sh_size", (long long) shdr->sh_size,
+ (long long) shdr->sh_size);
+ sb.appendf (fmt1, "sh_link", (long long) shdr->sh_link,
+ (long long) shdr->sh_link);
+ sb.appendf (fmt1, "sh_info", (long long) shdr->sh_info,
+ (long long) shdr->sh_info);
+ sb.appendf (fmt1, "sh_addralign", (long long) shdr->sh_addralign,
+ (long long) shdr->sh_addralign);
+ sb.appendf (fmt1, "sh_entsize", (long long) shdr->sh_entsize,
+ (long long) shdr->sh_entsize);
+ }
+
+ for (unsigned int i = 1; i < ehdrp->e_shnum; i++)
+ {
+ Elf_Internal_Shdr *shdr = get_shdr (i);
+ if (shdr == NULL)
+ continue;
+ char *secName = get_sec_name (i);
+ if (secName == NULL)
+ continue;
+ if (strcmp (NTXT (".SUNW_ancillary"), secName) == 0)
+ {
+ sb.appendf (NTXT ("\nSection[%d]: %s\n"), i, secName);
+ Elf_Data *dp = elf_getdata (i);
+ for (int j = 0, cnt = (int) (shdr->sh_size / shdr->sh_entsize);
+ j < cnt; j++)
+ {
+ Elf64_Ancillary anc;
+ if (elf_getancillary (dp, j, &anc) == NULL)
+ break;
+ sb.appendf (NTXT ("%10d %-20s 0x%08llx %6lld"), j,
+ get_elf_ancillary_tag ((int) anc.a_tag),
+ (long long) anc.a_un.a_ptr, (long long) anc.a_un.a_ptr);
+ if (anc.a_tag == ANC_SUNW_MEMBER)
+ sb.appendf (NTXT (" %s\n"), STR (elf_strptr (shdr->sh_link, anc.a_un.a_ptr)));
+ else
+ sb.append (NTXT ("\n"));
+ }
+ }
+ }
+ return sb.toString ();
+}
+
+void
+Elf::dump_elf_sec ()
+{
+ if (!DUMP_ELF_SEC)
+ return;
+ if (ehdrp == NULL)
+ return;
+ Dprintf (DUMP_ELF_SEC, "======= DwarfLib::dump_elf_sec\n"
+ " N |type|flags| sh_addr | sh_offset | sh_size | sh_link |"
+ " sh_info | sh_addralign | sh_entsize | sh_name | name\n");
+ for (unsigned int sec = 1; sec < ehdrp->e_shnum; sec++)
+ {
+ Elf_Internal_Shdr *shdr = get_shdr (sec);
+ if (shdr == NULL)
+ continue;
+ char *name = elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
+ Dprintf (DUMP_ELF_SEC, "%3d:%3d |%4d |%9lld | %9lld |%8lld |%8lld |"
+ "%8lld |%14d |%11lld | %6lld %s\n",
+ sec, (int) shdr->sh_type, (int) shdr->sh_flags,
+ (long long) shdr->sh_addr, (long long) shdr->sh_offset,
+ (long long) shdr->sh_size, (long long) shdr->sh_link,
+ (long long) shdr->sh_info,
+ (int) shdr->sh_addralign, (long long) shdr->sh_entsize,
+ (long long) shdr->sh_name, name ? name : NTXT ("NULL"));
+ }
+ Dprintf (DUMP_ELF_SEC, NTXT ("\n"));
+}
diff --git a/gprofng/src/Elf.h b/gprofng/src/Elf.h
new file mode 100644
index 0000000..3648b88
--- /dev/null
+++ b/gprofng/src/Elf.h
@@ -0,0 +1,170 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _Elf_h_
+#define _Elf_h_
+
+#include <string.h>
+#include "ansidecl.h"
+#include "bfd.h"
+#include "elf/common.h"
+#include "elf/internal.h"
+
+#include "Data_window.h"
+#include "Emsg.h"
+
+class Symbol;
+class DbeFile;
+template <class ITEM> class Vector;
+template <typename Key_t, typename Value_t> class Map;
+
+#define GELF_R_SYM(info) ((info)>>32)
+#define GELF_ST_TYPE(info) ((info) & 0xf)
+#define GELF_ST_BIND(info) ((info) >> 4)
+#define GELF_R_TYPE(info) ((((uint64_t)(info))<<56)>>56)
+
+#define SHF_SUNW_ABSENT 0x00200000 /* section data not present */
+
+// Ancillary values.
+#define ANC_SUNW_NULL 0
+#define ANC_SUNW_CHECKSUM 1 /* elf checksum */
+#define ANC_SUNW_MEMBER 2 /* name of ancillary group object */
+#define ANC_SUNW_NUM 3
+
+
+typedef struct S_Elf64_Dyn Elf64_Dyn;
+typedef struct S_Elf64_Ancillary Elf64_Ancillary;
+
+typedef struct
+{
+ void *d_buf;
+ uint64_t d_flags;
+ uint64_t d_size;
+ uint64_t d_off; // offset into section
+ uint64_t d_align; // alignment in section
+} Elf_Data;
+
+class Elf : public DbeMessages, public Data_window
+{
+public:
+ enum Elf_status
+ {
+ ELF_ERR_NONE,
+ ELF_ERR_CANT_OPEN_FILE,
+ ELF_ERR_CANT_MMAP,
+ ELF_ERR_BIG_FILE,
+ ELF_ERR_BAD_ELF_FORMAT,
+ ELF_ERR_READ_FILE
+ };
+
+ Elf (char *_fname);
+ ~Elf ();
+
+ static void elf_init ();
+ static unsigned elf_version (unsigned ver);
+ static Elf *elf_begin (char *_fname, Elf_status *stp = NULL);
+
+ unsigned int elf_get_sec_num (const char *sec_name);
+ char *get_sec_name (unsigned int sec);
+ Elf_Internal_Ehdr *elf_getehdr ();
+ Elf_Internal_Phdr *get_phdr (unsigned int ndx);
+ Elf_Internal_Shdr *get_shdr (unsigned int ndx);
+ Elf64_Dyn *elf_getdyn (Elf_Internal_Phdr *phdr, unsigned int ndx, Elf64_Dyn *pdyn);
+ Elf_Data *elf_getdata (unsigned int sec);
+ int64_t elf_checksum ();
+ uint64_t get_baseAddr();
+ char *elf_strptr (unsigned int sec, uint64_t off);
+ Elf_Internal_Sym *elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst);
+ Elf_Internal_Rela *elf_getrel (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst);
+ Elf_Internal_Rela *elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst);
+ Elf64_Ancillary *elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst);
+ Elf *find_ancillary_files (char *lo_name); // read the .gnu_debuglink and .SUNW_ancillary seections
+ char *get_location ();
+ char *dump ();
+ void dump_elf_sec ();
+
+ static inline int64_t
+ normalize_checksum (int64_t chk)
+ {
+ return (chk == 0xffffffff || chk == -1) ? 0 : chk;
+ };
+
+ inline bool
+ is_Intel ()
+ {
+ return elf_datatype == ELFDATA2LSB;
+ };
+
+ inline int
+ elf_getclass ()
+ {
+ return elf_class;
+ };
+
+ inline int
+ elf_getdatatype ()
+ {
+ return elf_datatype;
+ };
+
+ Elf_status status;
+ Vector<Elf*> *ancillary_files;
+ Elf *gnu_debug_file;
+ DbeFile *dbeFile;
+ Map<const char*, Symbol*> *elfSymbols;
+ unsigned int gnuLink, analyzerInfo, SUNW_ldynsym, stab, stabStr, symtab, dynsym;
+ unsigned int stabIndex, stabIndexStr, stabExcl, stabExclStr, info, plt;
+ bool dwarf;
+
+protected:
+ Elf *get_related_file (const char *lo_name, const char *nm);
+ int elf_class;
+ int elf_datatype;
+ Elf_Internal_Ehdr *ehdrp;
+ Elf_Data **data;
+ bfd *abfd;
+ static int bfd_status;
+};
+
+
+class ElfReloc
+{
+public:
+ struct Sreloc
+ {
+ long long offset;
+ long long value;
+ int stt_type;
+ };
+
+ static ElfReloc *get_elf_reloc (Elf *elf, char *sec_name, ElfReloc *rlc);
+ ElfReloc (Elf *_elf);
+ ~ElfReloc ();
+ long long get_reloc_addr (long long offset);
+ void dump ();
+ void dump_rela_debug_sec (int sec);
+
+private:
+ Elf *elf;
+ Vector<Sreloc *> *reloc;
+ int cur_reloc_ind;
+};
+
+#endif
diff --git a/gprofng/src/Emsg.cc b/gprofng/src/Emsg.cc
new file mode 100644
index 0000000..11bad97
--- /dev/null
+++ b/gprofng/src/Emsg.cc
@@ -0,0 +1,614 @@
+/* Copyright (C) 2021 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 <stdarg.h>
+
+#include "util.h"
+#include "Emsg.h"
+#include "StringBuilder.h"
+
+// The Emsg, experiment message, has as objects I18N'd messages
+// in a structure suitable for attaching to and fetching
+// from a queue of such messages. It is intended to
+// be used for collector errors, collector warnings, parser
+// errors, and er_archive errors that are encountered when
+// reading an experiment
+
+// ----------------------- Message --------------------------
+
+Emsg::Emsg (Cmsg_warn w, const char *i18n_text)
+{
+ warn = w;
+ flavor = 0;
+ par = NULL;
+ text = strdup (i18n_text);
+ next = NULL;
+}
+
+Emsg::Emsg (Cmsg_warn w, StringBuilder& sb)
+{
+ warn = w;
+ flavor = 0;
+ par = NULL;
+ text = sb.toString ();
+ next = NULL;
+}
+
+Emsg::Emsg (Cmsg_warn w, int f, const char *param)
+{
+ char *type;
+ warn = w;
+ flavor = f;
+ if (param != NULL)
+ par = dbe_strdup (param);
+ else
+ par = dbe_strdup ("");
+ next = NULL;
+
+ // determine type
+ switch (warn)
+ {
+ case CMSG_WARN:
+ type = GTXT ("*** Collector Warning");
+ break;
+ case CMSG_ERROR:
+ type = GTXT ("*** Collector Error");
+ break;
+ case CMSG_FATAL:
+ type = GTXT ("*** Collector Fatal Error");
+ break;
+ case CMSG_COMMENT:
+ type = GTXT ("Comment");
+ break;
+ case CMSG_PARSER:
+ type = GTXT ("*** Log Error");
+ break;
+ case CMSG_ARCHIVE:
+ type = GTXT ("*** Archive Error");
+ break;
+ default:
+ type = GTXT ("*** Internal Error");
+ break;
+ };
+
+ // now convert the message to its I18N'd string
+ switch (flavor)
+ {
+ case COL_ERROR_NONE:
+ text = dbe_sprintf (GTXT ("%s: No error"), type);
+ break;
+ case COL_ERROR_ARGS2BIG:
+ text = dbe_sprintf (GTXT ("%s: Data argument too long"), type);
+ break;
+ case COL_ERROR_BADDIR:
+ text = dbe_sprintf (GTXT ("%s: Bad experiment directory name"), type);
+ break;
+ case COL_ERROR_ARGS:
+ text = dbe_sprintf (GTXT ("%s: Data argument format error `%s'"), type, par);
+ break;
+ case COL_ERROR_PROFARGS:
+ text = dbe_sprintf (GTXT ("%s: [UNUSED] Bad clock-profiling argument"), type);
+ break;
+ case COL_ERROR_SYNCARGS:
+ text = dbe_sprintf (GTXT ("%s: [UNUSED] Bad synchronization tracing argument"), type);
+ break;
+ case COL_ERROR_HWCARGS:
+ text = dbe_sprintf (GTXT ("%s: Bad hardware counter profiling argument"), type);
+ break;
+ case COL_ERROR_DIRPERM:
+ text = dbe_sprintf (GTXT ("%s: Experiment directory is not writeable; check umask and permissions"), type);
+ break;
+ case COL_ERROR_NOMSACCT:
+ text = dbe_sprintf (GTXT ("%s: Turning on microstate accounting failed"), type);
+ break;
+ case COL_ERROR_PROFINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing clock-profiling failed"), type);
+ break;
+ case COL_ERROR_SYNCINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing synchronization tracing failed"), type);
+ break;
+ case COL_ERROR_HWCINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing hardware counter profiling failed -- %s"), type, par);
+ break;
+ case COL_ERROR_HWCFAIL:
+ text = dbe_sprintf (GTXT ("%s: HW counter data collection failed; likely cause is that another process preempted the counters"), type);
+ break;
+ case COL_ERROR_EXPOPEN:
+ text = dbe_sprintf (GTXT ("%s: Experiment initialization failed, %s"), type, par);
+ break;
+ case COL_ERROR_SIZELIM:
+ text = dbe_sprintf (GTXT ("%s: Experiment size limit exceeded, writing %s"), type, par);
+ break;
+ case COL_ERROR_SYSINFO:
+ text = dbe_sprintf (GTXT ("%s: system name can not be determined"), type);
+ break;
+ case COL_ERROR_OVWOPEN:
+ text = dbe_sprintf (GTXT ("%s: Can't open overview %s"), type, par);
+ break;
+ case COL_ERROR_OVWWRITE:
+ text = dbe_sprintf (GTXT ("%s: Can't write overview %s"), type, par);
+ break;
+ case COL_ERROR_OVWREAD:
+ text = dbe_sprintf (GTXT ("%s: Can't read overview data for %s"), type, par);
+ break;
+ case COL_ERROR_NOZMEM:
+ text = dbe_sprintf (GTXT ("%s: Open of /dev/zero failed: %s"), type, par);
+ break;
+ case COL_ERROR_NOZMEMMAP:
+ text = dbe_sprintf (GTXT ("%s: Mmap of /dev/zero failed: %s"), type, par);
+ break;
+ case COL_ERROR_NOHNDL:
+ text = dbe_sprintf (GTXT ("%s: Out of data handles for %s"), type, par);
+ break;
+ case COL_ERROR_FILEOPN:
+ text = dbe_sprintf (GTXT ("%s: Open failed %s"), type, par);
+ break;
+ case COL_ERROR_FILETRNC:
+ text = dbe_sprintf (GTXT ("%s: Truncate failed for file %s"), type, par);
+ break;
+ case COL_ERROR_FILEMAP:
+ text = dbe_sprintf (GTXT ("%s: Mmap failed %s"), type, par);
+ break;
+ case COL_ERROR_HEAPINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing heap tracing failed"), type);
+ break;
+ case COL_ERROR_DISPINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing SIGPROF dispatcher failed"), type);
+ break;
+ case COL_ERROR_ITMRINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing interval timer failed; %s"), type, par);
+ break;
+ case COL_ERROR_SMPLINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing periodic sampling failed"), type);
+ break;
+ case COL_ERROR_MPIINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing MPI tracing failed"), type);
+ break;
+ case COL_ERROR_JAVAINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing Java profiling failed"), type);
+ break;
+ case COL_ERROR_LINEINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing descendant process lineage failed"), type);
+ break;
+ case COL_ERROR_NOSPACE:
+ text = dbe_sprintf (GTXT ("%s: Out of disk space writing `%s'"), type, par);
+ break;
+ case COL_ERROR_ITMRRST:
+ text = dbe_sprintf (GTXT ("%s: Resetting interval timer failed: %s"), type, par);
+ break;
+ case COL_ERROR_MKDIR:
+ text = dbe_sprintf (GTXT ("%s: Unable to create directory `%s'"), type, par);
+ break;
+ case COL_ERROR_JVM2NEW:
+ text = dbe_sprintf (GTXT ("%s: JVM version with JVMTI requires more recent release of the performance tools; please upgrade"), type);
+ break;
+ case COL_ERROR_JVMNOTSUPP:
+ text = dbe_sprintf (GTXT ("%s: JVM version does not support JVMTI; no java profiling is available"), type);
+ break;
+ case COL_ERROR_JVMNOJSTACK:
+ text = dbe_sprintf (GTXT ("%s: JVM version does not support java callstacks; java mode data will not be recorded"), type);
+ break;
+ case COL_ERROR_DYNOPEN:
+ text = dbe_sprintf (GTXT ("%s: Can't open dyntext file `%s'"), type, par);
+ break;
+ case COL_ERROR_DYNWRITE:
+ text = dbe_sprintf (GTXT ("%s: Can't write dyntext file `%s'"), type, par);
+ break;
+ case COL_ERROR_MAPOPEN:
+ text = dbe_sprintf (GTXT ("%s: Can't open map file `%s'"), type, par);
+ break;
+ case COL_ERROR_MAPREAD:
+ text = dbe_sprintf (GTXT ("%s: Can't read map file `%s'"), type, par);
+ break;
+ case COL_ERROR_MAPWRITE:
+ text = dbe_sprintf (GTXT ("%s: Can't write map file"), type);
+ break;
+ case COL_ERROR_RESOLVE:
+ text = dbe_sprintf (GTXT ("%s: Can't resolve map file `%s'"), type, par);
+ break;
+ case COL_ERROR_OMPINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing OpenMP tracing failed"), type);
+ break;
+ case COL_ERROR_DURATION_INIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing experiment-duration setting to `%s' failed"), type, par);
+ break;
+ case COL_ERROR_RDTINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing RDT failed"), type);
+ break;
+ case COL_ERROR_GENERAL:
+ if (strlen (par))
+ text = dbe_sprintf (GTXT ("%s: %s"), type, par);
+ else
+ text = dbe_sprintf (GTXT ("%s: General error"), type);
+ break;
+ case COL_ERROR_EXEC_FAIL:
+ text = dbe_sprintf (GTXT ("%s: Exec of process failed"), type);
+ break;
+ case COL_ERROR_THR_MAX:
+ text = dbe_sprintf (GTXT ("%s: Thread count exceeds maximum (%s); set SP_COLLECTOR_NUMTHREADS for higher value"), type, par);
+ break;
+ case COL_ERROR_IOINIT:
+ text = dbe_sprintf (GTXT ("%s: Initializing IO tracing failed"), type);
+ break;
+ case COL_ERROR_NODATA:
+ text = dbe_sprintf (GTXT ("%s: No data was recorded in the experiment"), type);
+ break;
+ case COL_ERROR_DTRACE_FATAL:
+ text = dbe_sprintf (GTXT ("%s: Fatal error reported from DTrace -- %s"), type, par);
+ break;
+ case COL_ERROR_MAPSEEK:
+ text = dbe_sprintf (GTXT ("%s: Seek error on map file `%s'"), type, par);
+ break;
+ case COL_ERROR_UNEXP_FOUNDER:
+ text = dbe_sprintf (GTXT ("%s: Unexpected value for founder `%s'"), type, par);
+ break;
+ case COL_ERROR_LOG_OPEN:
+ text = dbe_sprintf (GTXT ("%s: Failure to open log file"), type);
+ break;
+ case COL_ERROR_TSD_INIT:
+ text = dbe_sprintf (GTXT ("%s: TSD could not be initialized"), type);
+ break;
+ case COL_ERROR_UTIL_INIT:
+ text = dbe_sprintf (GTXT ("%s: libcol_util.c initialization failed"), type);
+ break;
+ case COL_ERROR_MAPCACHE:
+ text = dbe_sprintf (GTXT ("%s: Unable to cache mappings; internal error (`%s')"), type, par);
+ break;
+ case COL_WARN_NONE:
+ text = dbe_sprintf (GTXT ("%s: No warning"), type);
+ break;
+ case COL_WARN_FSTYPE:
+ text = dbe_sprintf (GTXT ("%s: Experiment was written to a filesystem of type `%s'; data may be distorted"), type, par);
+ break;
+ case COL_WARN_PROFRND:
+ text = dbe_sprintf (GTXT ("%s: Profiling interval was changed from requested %s (microsecs.) used"), type, par);
+ break;
+ case COL_WARN_SIZELIM:
+ text = dbe_sprintf (GTXT ("%s: Experiment size limit exceeded"), type);
+ break;
+ case COL_WARN_SIGPROF:
+ text = dbe_sprintf (GTXT ("%s: SIGPROF handler was changed (%s) during the run; profile data may be unreliable"), type, par);
+ break;
+ case COL_WARN_SMPLADJ:
+ text = dbe_sprintf (GTXT ("%s: Periodic sampling rate adjusted %s microseconds"), type, par);
+ break;
+ case COL_WARN_ITMROVR:
+ text = dbe_sprintf (GTXT ("%s: Application's attempt to set interval timer period to %s was ignored; its behavior may be changed"), type, par);
+ break;
+ case COL_WARN_ITMRREP:
+ text = dbe_sprintf (GTXT ("%s: Collection interval timer period was changed (%s); profile data may be unreliable"), type, par);
+ break;
+ case COL_WARN_SIGEMT:
+ text = dbe_sprintf (GTXT ("%s: SIGEMT handler was changed during the run; profile data may be unreliable"), type);
+ break;
+ case COL_WARN_CPCBLK:
+ text = dbe_sprintf (GTXT ("%s: libcpc access blocked for hardware counter profiling"), type);
+ break;
+ case COL_WARN_VFORK:
+ text = dbe_sprintf (GTXT ("%s: vfork(2) replaced by %s; execution may be affected"), type, par);
+ break;
+ case COL_WARN_EXECENV:
+ text = dbe_sprintf (GTXT ("%s: exec environment augmented with %s missing collection variables"), type, par);
+ break;
+ case COL_WARN_SAMPSIGUSED:
+ text = dbe_sprintf (GTXT ("%s: target installed handler for sample signal %s; samples may be lost"), type, par);
+ break;
+ case COL_WARN_PAUSESIGUSED:
+ text = dbe_sprintf (GTXT ("%s: target installed handler for pause/resume signal %s; data may be lost or unexpected"),
+ type, par);
+ break;
+ case COL_WARN_CPCNOTRESERVED:
+ text = dbe_sprintf (GTXT ("%s: unable to reserve HW counters; data may be distorted by other users of the counters"), type);
+ break;
+ case COL_WARN_LIBTHREAD_T1: /* par contains the aslwpid... do we want to report it? */
+ text = dbe_sprintf (GTXT ("%s: application ran with a libthread version that may distort data; see collect(1) man page"), type);
+ break;
+ case COL_WARN_SIGMASK:
+ text = dbe_sprintf (GTXT ("%s: Blocking %s ignored while in use for collection"), type, par);
+ break;
+ case COL_WARN_NOFOLLOW:
+ text = dbe_sprintf (GTXT ("%s: Following disabled for uncollectable target (%s)"), type, par);
+ break;
+ case COL_WARN_RISKYFOLLOW:
+ text = dbe_sprintf (GTXT ("%s: Following unqualified target may be unreliable (%s)"), type, par);
+ break;
+ case COL_WARN_IDCHNG:
+ text = dbe_sprintf (GTXT ("%s: Imminent process ID change (%s) may result in an inconsistent experiment"), type, par);
+ break;
+ case COL_WARN_OLDJAVA:
+ text = dbe_sprintf (GTXT ("%s: Java profiling requires JVM version 1.4.2_02 or later"), type);
+ break;
+ case COL_WARN_ITMRPOVR:
+ text = dbe_sprintf (GTXT ("%s: Collector reset application's profile timer %s; application behavior may be changed"), type, par);
+ break;
+ case COL_WARN_NO_JAVA_HEAP:
+ text = dbe_sprintf (GTXT ("%s: Java heap profiling is not supported by JVMTI; disabled "), type);
+ break;
+ case COL_WARN_RDT_PAUSE_NOMEM:
+ text = dbe_sprintf (GTXT ("%s: Data race detection paused at %s because of running out of internal memory"), type, par);
+ break;
+ case COL_WARN_RDT_RESUME:
+ text = dbe_sprintf (GTXT ("%s: Data race detection resumed"), type);
+ break;
+ case COL_WARN_RDT_THROVER:
+ text = dbe_sprintf (GTXT ("%s: Too many concurrent/created threads; accesses with thread IDs above limit are not checked"), type);
+ break;
+ case COL_WARN_THR_PAUSE_RESUME:
+ text = dbe_sprintf (GTXT ("%s: The collector_thread_pause/collector_thread_resume APIs are deprecated, and will be removed in a future release"), type);
+ break;
+ case COL_WARN_NOPROF_DATA:
+ text = dbe_sprintf (GTXT ("%s: No profile data recorded in experiment"), type);
+ break;
+ case COL_WARN_LONG_FSTAT:
+ text = dbe_sprintf (GTXT ("%s: Long fstat call -- %s"), type, par);
+ break;
+ case COL_WARN_LONG_READ:
+ text = dbe_sprintf (GTXT ("%s: Long read call -- %s"), type, par);
+ break;
+ case COL_WARN_LINUX_X86_APICID:
+ text = dbe_sprintf (GTXT ("%s: Linux libc sched_getcpu() not found; using x86 %s IDs rather than CPU IDs"), type, par);
+ break;
+
+ case COL_COMMENT_NONE:
+ text = dbe_sprintf (GTXT ("%s"), par);
+ break;
+ case COL_COMMENT_CWD:
+ text = dbe_sprintf (GTXT ("Initial execution directory `%s'"), par);
+ break;
+ case COL_COMMENT_ARGV:
+ text = dbe_sprintf (GTXT ("Argument list `%s'"), par);
+ break;
+ case COL_COMMENT_MAYASSNAP:
+ text = dbe_sprintf (GTXT ("Mayas snap file `%s'"), par);
+ break;
+
+ case COL_COMMENT_LINEFORK:
+ text = dbe_sprintf (GTXT ("Target fork: %s"), par);
+ break;
+ case COL_COMMENT_LINEEXEC:
+ text = dbe_sprintf (GTXT ("Target exec: %s"), par);
+ break;
+ case COL_COMMENT_LINECOMBO:
+ text = dbe_sprintf (GTXT ("Target fork/exec: %s"), par);
+ break;
+ case COL_COMMENT_FOXSNAP:
+ text = dbe_sprintf (GTXT ("Fox snap file `%s'"), par);
+ break;
+ case COL_COMMENT_ROCKSNAP:
+ text = dbe_sprintf (GTXT ("Rock simulator snap file `%s'"), par);
+ break;
+ case COL_COMMENT_BITINSTRDATA:
+ text = dbe_sprintf (GTXT ("Bit instrument data file `%s'"), par);
+ break;
+ case COL_COMMENT_BITSNAP:
+ text = dbe_sprintf (GTXT ("Bit snap file `%s'"), par);
+ break;
+ case COL_COMMENT_SIMDSPSNAP:
+ text = dbe_sprintf (GTXT ("Simulator dataspace profiling snap file `%s'"), par);
+ break;
+ case COL_COMMENT_HWCADJ:
+ text = dbe_sprintf (GTXT ("%s: HWC overflow interval adjusted: %s"), type, par);
+ break;
+ case COL_WARN_APP_NOT_READY:
+ text = dbe_sprintf (GTXT ("*** Collect: %s"), par);
+ break;
+ case COL_WARN_RDT_DL_TERMINATE:
+ text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process terminated"), type);
+ break;
+ case COL_WARN_RDT_DL_TERMINATE_CORE:
+ text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process terminated and core dumped"), type);
+ break;
+ case COL_WARN_RDT_DL_CONTINUE:
+ text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process allowed to continue"), type);
+ break;
+ default:
+ text = dbe_sprintf (GTXT ("%s: Number %d (\"%s\")"), type, flavor, par);
+ break;
+ };
+}
+
+Emsg::~Emsg ()
+{
+ free (par);
+ free (text);
+}
+
+// ----------------------- Message Queue --------------------
+Emsgqueue::Emsgqueue (char *_qname)
+{
+ first = NULL;
+ last = NULL;
+ qname = strdup (_qname);
+}
+
+Emsgqueue::~Emsgqueue ()
+{
+ free (qname);
+ clear ();
+}
+
+Emsg *
+Emsgqueue::find_msg (Cmsg_warn w, char *msg)
+{
+ for (Emsg *m = first; m; m = m->next)
+ if (m->get_warn () == w && strcmp (m->get_msg (), msg) == 0)
+ return m;
+ return NULL;
+}
+
+Emsg *
+Emsgqueue::append (Cmsg_warn w, char *msg)
+{
+ Emsg *m = find_msg (w, msg);
+ if (m)
+ return m;
+ m = new Emsg (w, msg);
+ append (m);
+ return m;
+}
+
+// Append a single message to a queue
+void
+Emsgqueue::append (Emsg* m)
+{
+ m->next = NULL;
+ if (last == NULL)
+ {
+ first = m;
+ last = m;
+ }
+ else
+ {
+ last->next = m;
+ last = m;
+ }
+}
+
+// Append a queue of messages to a queue
+void
+Emsgqueue::appendqueue (Emsgqueue* mq)
+{
+ Emsg *m = mq->first;
+ if (m == NULL)
+ return;
+ if (last == NULL)
+ first = m;
+ else
+ last->next = m;
+ // now find the new last
+ while (m->next != NULL)
+ m = m->next;
+ last = m;
+}
+
+Emsg *
+Emsgqueue::fetch (void)
+{
+ return first;
+}
+
+// Empty the queue, deleting all messages
+void
+Emsgqueue::clear (void)
+{
+ Emsg *pp;
+ Emsg *p = first;
+ while (p != NULL)
+ {
+ pp = p;
+ p = p->next;
+ delete pp;
+ }
+ first = NULL;
+ last = NULL;
+}
+
+// Mark the queue empty, without deleting the messages --
+// used when the messages have been requeued somewhere else
+void
+Emsgqueue::mark_clear (void)
+{
+ first = NULL;
+ last = NULL;
+}
+
+DbeMessages::DbeMessages ()
+{
+ msgs = NULL;
+}
+
+DbeMessages::~DbeMessages ()
+{
+ if (msgs)
+ {
+ msgs->destroy ();
+ delete msgs;
+ }
+}
+
+Emsg *
+DbeMessages::get_error ()
+{
+ for (int i = msgs ? msgs->size () - 1 : -1; i >= 0; i--)
+ {
+ Emsg *msg = msgs->get (i);
+ if (msg->get_warn () == CMSG_ERROR)
+ return msg;
+ }
+ return NULL;
+}
+
+void
+DbeMessages::remove_msg (Emsg *msg)
+{
+ for (int i = 0, sz = msgs ? msgs->size () : 0; i < sz; i++)
+ if (msg == msgs->get (i))
+ {
+ msgs->remove (i);
+ delete msg;
+ return;
+ }
+}
+
+Emsg *
+DbeMessages::append_msg (Cmsg_warn w, const char *fmt, ...)
+{
+ char buffer[256];
+ size_t buf_size;
+ Emsg *msg;
+ va_list vp;
+
+ va_start (vp, fmt);
+ buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
+ va_end (vp);
+ if (buf_size < sizeof (buffer))
+ msg = new Emsg (w, buffer);
+ else
+ {
+ va_start (vp, fmt);
+ char *buf = (char *) malloc (buf_size);
+ vsnprintf (buf, buf_size, fmt, vp);
+ va_end (vp);
+ msg = new Emsg (w, buf);
+ free (buf);
+ }
+
+ if (msgs == NULL)
+ msgs = new Vector<Emsg*>();
+ msgs->append (msg);
+ Dprintf (DEBUG_ERR_MSG, NTXT ("Warning: %s\n"), msg->get_msg ());
+ return msg;
+}
+
+void
+DbeMessages::append_msgs (Vector<Emsg*> *lst)
+{
+ if (lst && (lst->size () != 0))
+ {
+ if (msgs == NULL)
+ msgs = new Vector<Emsg*>();
+ for (int i = 0, sz = lst->size (); i < sz; i++)
+ {
+ Emsg *m = lst->fetch (i);
+ msgs->append (new Emsg (m->get_warn (), m->get_msg ()));
+ }
+ }
+}
diff --git a/gprofng/src/Emsg.h b/gprofng/src/Emsg.h
new file mode 100644
index 0000000..f1d47c5
--- /dev/null
+++ b/gprofng/src/Emsg.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _EMSG_H
+#define _EMSG_H
+
+#include "Emsgnum.h"
+#include "vec.h"
+
+//
+// The Emsg, experiment message, has as objects I18N'd messages
+// in a structure suitable for attaching to and fetching
+// from a queue of such messages. It is intended to
+// be used for collector errors, collector warnings, parser
+// errors, and er_archive errors that are encountered when
+// reading an experiment
+
+class Emsg;
+class Emsgqueue;
+class StringBuilder;
+
+typedef enum
+{
+ CMSG_WARN = 0,
+ CMSG_ERROR,
+ CMSG_FATAL,
+ CMSG_COMMENT,
+ CMSG_PARSER,
+ CMSG_ARCHIVE
+} Cmsg_warn;
+
+class Emsg
+{
+public:
+ friend class Emsgqueue;
+
+ Emsg (Cmsg_warn w, const char *i18n_text);
+ Emsg (Cmsg_warn w, StringBuilder& sb);
+ Emsg (Cmsg_warn w, int f, const char *param);
+ ~Emsg ();
+
+ char *
+ get_msg ()
+ {
+ return text;
+ };
+
+ Cmsg_warn
+ get_warn ()
+ {
+ return warn;
+ };
+
+ Emsg *next; // next message in a queue
+
+protected:
+ Cmsg_warn warn; // error/warning/...
+ int flavor; // the message flavor
+ char *par; // the input parameter string
+ char *text; // The I18N text of the message
+};
+
+class Emsgqueue
+{
+public:
+ Emsgqueue (char *);
+ ~Emsgqueue ();
+
+ void append (Emsg*);
+ Emsg *append (Cmsg_warn w, char *msg);
+ Emsg *find_msg (Cmsg_warn w, char *msg);
+ void appendqueue (Emsgqueue*);
+ Emsg *fetch (void);
+ void clear (void); // empty the queue
+ void mark_clear (void); // mark the queue empty, without touching messages
+
+protected:
+ Emsg *first;
+ Emsg *last;
+ char *qname;
+};
+
+class DbeMessages
+{
+public:
+ DbeMessages ();
+ ~DbeMessages ();
+ Vector<Emsg*> *msgs;
+ void remove_msg (Emsg *msg);
+ Emsg *get_error ();
+ Emsg *append_msg (Cmsg_warn w, const char *fmt, ...);
+ void append_msgs (Vector<Emsg*> *lst);
+};
+
+#endif /* _EMSG_H */
diff --git a/gprofng/src/Emsgnum.h b/gprofng/src/Emsgnum.h
new file mode 100644
index 0000000..cef8332
--- /dev/null
+++ b/gprofng/src/Emsgnum.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _EMSGNUM_H
+#define _EMSGNUM_H
+
+// Define numerical codes for all messages and warnings
+
+#define COL_ERROR_NONE 0 /* OK */
+#define COL_ERROR_ARGS2BIG 1 /* data descriptor too long */
+#define COL_ERROR_BADDIR 2 /* experiment directory error */
+#define COL_ERROR_ARGS 3 /* data descriptor format error */
+#define COL_ERROR_PROFARGS 4 /* clock profile parameter error */
+#define COL_ERROR_SYNCARGS 5 /* synctrace parameter error */
+#define COL_ERROR_HWCARGS 6 /* HWC profile parameter error */
+#define COL_ERROR_DIRPERM 7 /* experiment directory not writable */
+#define COL_ERROR_NOMSACCT 8 /* failed to turn on microstate accounting */
+#define COL_ERROR_PROFINIT 9 /* failed to initialize profiling */
+#define COL_ERROR_SYNCINIT 10 /* failed to initialize synchronization tracing */
+#define COL_ERROR_HWCINIT 11 /* failed to initialize HWC profiling */
+#define COL_ERROR_HWCFAIL 12 /* HWC profiling failed during run */
+#define COL_ERROR_EXPOPEN 13 /* Experiment initialization failed */
+#define COL_ERROR_SIZELIM 14 /* Experiment exceeded size limit */
+#define COL_ERROR_SYSINFO 15 /* uname call failed */
+#define COL_ERROR_OVWOPEN 16 /* Opening the overview file failed */
+#define COL_ERROR_OVWWRITE 17 /* Writing the overview file failed */
+#define COL_ERROR_OVWREAD 18 /* Reading the overview data failed */
+#define COL_ERROR_NOZMEM 19 /* Unable to open /dev/zero */
+#define COL_ERROR_NOZMEMMAP 20 /* Unable to map /dev/zero */
+#define COL_ERROR_NOHNDL 21 /* No more handles available for data */
+#define COL_ERROR_FILEOPN 22 /* Unable to open file */
+#define COL_ERROR_FILETRNC 23 /* Unable to truncate file */
+#define COL_ERROR_FILEMAP 24 /* Unable to mmap file */
+#define COL_ERROR_HEAPINIT 25 /* Unable to install heap tracing */
+#define COL_ERROR_DISPINIT 26 /* Failed to install dispatcher */
+#define COL_ERROR_ITMRINIT 27 /* Failed to install interval timer */
+#define COL_ERROR_SMPLINIT 28 /* Failed to initialize periodic sampling */
+#define COL_ERROR_MPIINIT 29 /* Failed to initialize MPI tracing */
+#define COL_ERROR_JAVAINIT 30 /* Failed to initialize Java profiling */
+#define COL_ERROR_LINEINIT 31 /* Failed to initialize lineage tracing */
+#define COL_ERROR_NOSPACE 32 /* Ran out of disk space writing file */
+#define COL_ERROR_ITMRRST 33 /* Failed to reset interval timer */
+#define COL_ERROR_MKDIR 34 /* Failed to create (sub)directory */
+#define COL_ERROR_JVM2NEW 35 /* JVM is too new for us to cope (JVMTI interface) */
+#define COL_ERROR_JVMNOTSUPP 36 /* JVM does not support profiling (no JVMTI interface) */
+#define COL_ERROR_JVMNOJSTACK 37 /* JVM does not support java stack unwind */
+#define COL_ERROR_DYNOPEN 38 /* Unable to open dyntext file */
+#define COL_ERROR_DYNWRITE 39 /* Unable to write dyntext file */
+#define COL_ERROR_MAPOPEN 40 /* Unable to open map file */
+#define COL_ERROR_MAPREAD 41 /* Unable to read map file */
+#define COL_ERROR_MAPWRITE 42 /* Unable to write map file */
+#define COL_ERROR_RESOLVE 43 /* Unable to resolve map file */
+#define COL_ERROR_OMPINIT 44 /* Failure to initialize OpenMP tracing */
+#define COL_ERROR_DURATION_INIT 45 /* Failure to initialize -t (duration) processing */
+#define COL_ERROR_RDTINIT 46 /* Unable to install RDT */
+#define COL_ERROR_GENERAL 47 /* General error */
+#define COL_ERROR_EXEC_FAIL 48 /* Can't exec the process */
+#define COL_ERROR_THR_MAX 49 /* More threads than are supported */
+#define COL_ERROR_IOINIT 50 /* failed to initialize IO tracing */
+#define COL_ERROR_NODATA 51 /* No data recorded in experiment */
+#define COL_ERROR_DTRACE_FATAL 52 /* Fatal error from er_kernel DTrace code */
+#define COL_ERROR_MAPSEEK 53 /* Error on seek of map file */
+#define COL_ERROR_UNEXP_FOUNDER 54 /* Unexpected value for SP_COLLECTOR_FOUNDER */
+#define COL_ERROR_LOG_OPEN 55 /* Failure to open log.xml file */
+#define COL_ERROR_TSD_INIT 56 /* TSD could not be initialized */
+#define COL_ERROR_UTIL_INIT 57 /* libcol_util.c could not be initialized */
+#define COL_ERROR_MAPCACHE 58 /* Unable to cache mappings */
+
+#define COL_WARN_NONE 200 /* just a note, not a real warning */
+#define COL_WARN_FSTYPE 201 /* Writing to a potentially-distorting file system */
+#define COL_WARN_PROFRND 202 /* Profile interval rounded */
+#define COL_WARN_SIZELIM 203 /* Size limit specified */
+#define COL_WARN_SIGPROF 204 /* SIGPROF handler replaced */
+#define COL_WARN_SMPLADJ 205 /* Periodic sampling rate adjusted */
+#define COL_WARN_ITMROVR 206 /* Application interval timer resetting prevented */
+#define COL_WARN_ITMRREP 207 /* Collection interval timer found to have been overridden */
+#define COL_WARN_SIGEMT 208 /* SIGEMT handler replaced */
+#define COL_WARN_CPCBLK 209 /* libcpc access blocked */
+#define COL_WARN_VFORK 210 /* vfork(2) switched to fork1(2) */
+#define COL_WARN_EXECENV 211 /* incomplete exec environment */
+#define COL_WARN_SAMPSIGUSED 212 /* target installed handler for sample signal */
+#define COL_WARN_PAUSESIGUSED 213 /* target installed handler for pause signal */
+#define COL_WARN_CPCNOTRESERVED 214 /* unable to reserve HW counters for kernel profiling */
+#define COL_WARN_LIBTHREAD_T1 215 /* collection with classic libthread */
+#define COL_WARN_SIGMASK 216 /* profiling signal masking overridden */
+#define COL_WARN_NOFOLLOW 217 /* descendant following disabled */
+#define COL_WARN_RISKYFOLLOW 218 /* descendant following unqualified */
+#define COL_WARN_IDCHNG 219 /* process ID change requested */
+#define COL_WARN_OLDJAVA 220 /* Java profiling requires JVM version 1.4.2_02 or later */
+#define COL_WARN_ITMRPOVR 221 /* Overriding app-set interval timer */
+#define COL_WARN_NO_JAVA_HEAP 222 /* Java heap tracing not supported (JVM 1.5) */
+#define COL_WARN_RDT_PAUSE_NOMEM 223 /* RDT paused because of running out of memory */
+#define COL_WARN_RDT_RESUME 224 /* RDT resumed */
+#define COL_WARN_RDT_THROVER 225 /* RDT: too many threads */
+#define COL_WARN_THR_PAUSE_RESUME 226 /* use of thread pause/resume API is deprecateds */
+#define COL_WARN_APP_NOT_READY 227 /* Application is not instrumented for RDT */
+#define COL_WARN_RDT_DL_TERMINATE 228 /* RDT: terminate execution on actual deadlock */
+#define COL_WARN_RDT_DL_TERMINATE_CORE 229 /* RDT: dump core and terminate execution on actual deadlock */
+#define COL_WARN_RDT_DL_CONTINUE 230 /* RDT: continue execution on actual deadlock */
+#define COL_WARN_NOPROF_DATA 231 /* No profile data recorded in experiment */
+#define COL_WARN_LONG_FSTAT 232 /* fstat call on /proc/self/map took > 200 ms. */
+#define COL_WARN_LONG_READ 233 /* read call on /proc/self/map took > 200 ms. */
+#define COL_WARN_LINUX_X86_APICID 234 /* using x86 APIC IDs rather than Linux sched_getcpu() */
+
+#define COL_COMMENT_NONE 400 /* no comment */
+#define COL_COMMENT_CWD 401 /* initial execution directory */
+#define COL_COMMENT_ARGV 402 /* arguments */
+#define COL_COMMENT_MAYASSNAP 403 /* Mayas snap file name */
+#define COL_COMMENT_LINEFORK 404 /* process fork'd */
+#define COL_COMMENT_LINEEXEC 405 /* process exec'd */
+#define COL_COMMENT_LINECOMBO 406 /* process combo fork/exec */
+#define COL_COMMENT_FOXSNAP 407 /* Fox snap file name */
+#define COL_COMMENT_ROCKSNAP 408 /* Rock simulator snap file name */
+#define COL_COMMENT_BITINSTRDATA 409 /* Bit instrdata file name */
+#define COL_COMMENT_BITSNAP 410 /* Bit snap file name */
+#define COL_COMMENT_SIMDSPSNAP 411 /* Simulator dataspace profiling snap file name */
+#define COL_COMMENT_HWCADJ 412 /* HWC overflow interval adjusted */
+#endif /* _EMSGNUM_H */
diff --git a/gprofng/src/ExpGroup.cc b/gprofng/src/ExpGroup.cc
new file mode 100644
index 0000000..0ad269a
--- /dev/null
+++ b/gprofng/src/ExpGroup.cc
@@ -0,0 +1,163 @@
+/* Copyright (C) 2021 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 "ExpGroup.h"
+#include "Experiment.h"
+#include "LoadObject.h"
+#include "DbeSession.h"
+
+//////////////////////////////////////////////////////////
+// class ExpGroup
+
+int ExpGroup::phaseCompareIdx = 0;
+
+ExpGroup::ExpGroup (char *nm)
+{
+ name = dbe_strdup (nm);
+ canonical_path (name);
+ exps = new Vector<Experiment*>;
+ founder = NULL;
+ groupId = 0;
+ phaseCompareIdx++;
+ loadObjs = NULL;
+ loadObjsMap = NULL;
+}
+
+ExpGroup::~ExpGroup ()
+{
+ phaseCompareIdx++;
+ free (name);
+ delete exps;
+ delete loadObjs;
+ delete loadObjsMap;
+}
+
+void
+ExpGroup::append (Experiment *exp)
+{
+ for (int i = 0, sz = exps->size (); i < sz; i++)
+ {
+ Experiment *e = exps->fetch (i);
+ if (exp == e)
+ return;
+ }
+ exps->append (exp);
+ if (exps->size () == 1)
+ founder = exp;
+}
+
+void
+ExpGroup::drop_experiment (Experiment *exp)
+{
+ for (int i = 0, sz = exps->size (); i < sz; i++)
+ {
+ Experiment *e = exps->fetch (i);
+ if (exp == e)
+ {
+ exps->remove (i);
+ break;
+ }
+ }
+ if (founder == exp)
+ founder = NULL;
+}
+
+Vector<Experiment*> *
+ExpGroup::get_founders ()
+{
+ Vector<Experiment*> *expList = NULL;
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ if (exp->founder_exp == NULL)
+ {
+ if (expList == NULL)
+ expList = new Vector<Experiment*>;
+ expList->append (exp);
+ }
+ }
+ return expList;
+}
+
+void
+ExpGroup::create_list_of_loadObjects ()
+{
+ if (loadObjs == NULL)
+ {
+ loadObjs = new Vector<LoadObject*>();
+ loadObjsMap = new DefaultMap<LoadObject*, int>();
+ for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+ {
+ Experiment *exp = exps->fetch (i);
+ for (int i1 = 0, sz1 = VecSize(exp->loadObjs); i1 < sz1; i1++)
+ {
+ LoadObject *lo = exp->loadObjs->fetch (i1);
+ if (!loadObjsMap->get (lo))
+ {
+ loadObjs->append (lo);
+ loadObjsMap->put (lo, loadObjs->size ());
+ }
+ }
+ }
+ }
+}
+
+LoadObject *
+ExpGroup::get_comparable_loadObject (LoadObject *lo)
+{
+ create_list_of_loadObjects ();
+ if (loadObjsMap->get (lo))
+ return lo;
+ if ((lo->flags & SEG_FLAG_EXE) != 0)
+ if (dbeSession->expGroups->size () == dbeSession->nexps ())
+ for (int i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+ {
+ LoadObject *lobj = loadObjs->fetch (i);
+ if ((lobj->flags & SEG_FLAG_EXE) != 0)
+ return lobj;
+ }
+
+ long first_ind = -1;
+ char *bname = get_basename (lo->get_pathname ());
+ for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+ {
+ LoadObject *lobj = loadObjs->get (i);
+ if (lobj->comparable_objs == NULL
+ && strcmp (bname, get_basename (lobj->get_pathname ())) == 0)
+ {
+ if (lo->platform == lobj->platform)
+ {
+ if ((lo->flags & SEG_FLAG_DYNAMIC) != 0)
+ {
+ if (dbe_strcmp (lo->firstExp->uarglist,
+ lobj->firstExp->uarglist) == 0)
+ return lobj;
+ }
+ else
+ return lobj;
+ }
+ if (first_ind == -1)
+ first_ind = i;
+ }
+ }
+ return first_ind == -1 ? NULL : loadObjs->get (first_ind);
+}
diff --git a/gprofng/src/ExpGroup.h b/gprofng/src/ExpGroup.h
new file mode 100644
index 0000000..b3c9422
--- /dev/null
+++ b/gprofng/src/ExpGroup.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _EXPGROUP_H
+#define _EXPGROUP_H
+
+#include "vec.h"
+#include "Map.h"
+
+class Experiment;
+class LoadObject;
+
+class ExpGroup
+{
+public:
+ ExpGroup (char *nm);
+ ~ExpGroup ();
+ void append (Experiment *exp);
+ void drop_experiment (Experiment *exp);
+ Vector<Experiment*> *get_founders ();
+ void create_list_of_loadObjects ();
+ LoadObject *get_comparable_loadObject (LoadObject *lo);
+
+ Vector<Experiment*> *exps;
+ Vector<LoadObject*> *loadObjs;
+ Map <LoadObject*, int> *loadObjsMap;
+ Experiment *founder;
+ char *name;
+ int groupId;
+ static int phaseCompareIdx;
+};
+
+#endif /* _EXPGROUP_H */
diff --git a/gprofng/src/Exp_Layout.cc b/gprofng/src/Exp_Layout.cc
new file mode 100644
index 0000000..dfe1432
--- /dev/null
+++ b/gprofng/src/Exp_Layout.cc
@@ -0,0 +1,422 @@
+/* Copyright (C) 2021 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 "CallStack.h"
+#include "DbeSession.h"
+#include "Exp_Layout.h"
+#include "Experiment.h"
+#include "Function.h"
+#include "Table.h"
+#include "dbe_types.h"
+#include "util.h"
+
+/*
+ * PrUsage is a class which wraps access to the values of prusage
+ * system structure. It was expanded to 64 bit entities in 2.7
+ * (experiment version 6 & 7).
+ */
+PrUsage::PrUsage ()
+{
+ pr_tstamp = pr_create = pr_term = pr_rtime = (hrtime_t) 0;
+ pr_utime = pr_stime = pr_ttime = pr_tftime = pr_dftime = (hrtime_t) 0;
+ pr_kftime = pr_ltime = pr_slptime = pr_wtime = pr_stoptime = (hrtime_t) 0;
+
+ pr_minf = pr_majf = pr_nswap = pr_inblk = pr_oublk = 0;
+ pr_msnd = pr_mrcv = pr_sigs = pr_vctx = pr_ictx = pr_sysc = pr_ioch = 0;
+}
+
+/*
+ * Resource usage. /proc/<pid>/usage /proc/<pid>/lwp/<lwpid>/lwpusage
+ */
+struct timestruc_32
+{ /* v8 timestruc_t */
+ uint32_t tv_sec; /* seconds */
+ uint32_t tv_nsec; /* and nanoseconds */
+};
+
+typedef struct ana_prusage
+{
+ id_t pr_lwpid; /* lwp id. 0: process or defunct */
+ int pr_count; /* number of contributing lwps */
+ timestruc_32 pr_tstamp; /* current time stamp */
+ timestruc_32 pr_create; /* process/lwp creation time stamp */
+ timestruc_32 pr_term; /* process/lwp termination time stamp */
+ timestruc_32 pr_rtime; /* total lwp real (elapsed) time */
+ timestruc_32 pr_utime; /* user level cpu time */
+ timestruc_32 pr_stime; /* system call cpu time */
+ timestruc_32 pr_ttime; /* other system trap cpu time */
+ timestruc_32 pr_tftime; /* text page fault sleep time */
+ timestruc_32 pr_dftime; /* data page fault sleep time */
+ timestruc_32 pr_kftime; /* kernel page fault sleep time */
+ timestruc_32 pr_ltime; /* user lock wait sleep time */
+ timestruc_32 pr_slptime; /* all other sleep time */
+ timestruc_32 pr_wtime; /* wait-cpu (latency) time */
+ timestruc_32 pr_stoptime; /* stopped time */
+ timestruc_32 filltime[6]; /* filler for future expansion */
+ uint32_t pr_minf; /* minor page faults */
+ uint32_t pr_majf; /* major page faults */
+ uint32_t pr_nswap; /* swaps */
+ uint32_t pr_inblk; /* input blocks */
+ uint32_t pr_oublk; /* output blocks */
+ uint32_t pr_msnd; /* messages sent */
+ uint32_t pr_mrcv; /* messages received */
+ uint32_t pr_sigs; /* signals received */
+ uint32_t pr_vctx; /* voluntary context switches */
+ uint32_t pr_ictx; /* involuntary context switches */
+ uint32_t pr_sysc; /* system calls */
+ uint32_t pr_ioch; /* chars read and written */
+ uint32_t filler[10]; /* filler for future expansion */
+} raw_prusage_32;
+
+uint64_t
+PrUsage::bind32Size ()
+{
+ uint64_t bindSize = sizeof (raw_prusage_32);
+ return bindSize;
+}
+
+#define timestruc2hr(x) ((hrtime_t)(x).tv_sec*NANOSEC + (hrtime_t)(x).tv_nsec)
+
+PrUsage *
+PrUsage::bind32 (void *p, bool need_swap_endian)
+{
+ if (p == NULL)
+ return NULL;
+ raw_prusage_32 pu, *tmp = (raw_prusage_32*) p;
+ if (need_swap_endian)
+ {
+ pu = *tmp;
+ tmp = &pu;
+ SWAP_ENDIAN (pu.pr_tstamp.tv_sec);
+ SWAP_ENDIAN (pu.pr_tstamp.tv_nsec);
+ SWAP_ENDIAN (pu.pr_create.tv_sec);
+ SWAP_ENDIAN (pu.pr_create.tv_nsec);
+ SWAP_ENDIAN (pu.pr_term.tv_sec);
+ SWAP_ENDIAN (pu.pr_term.tv_nsec);
+ SWAP_ENDIAN (pu.pr_rtime.tv_sec);
+ SWAP_ENDIAN (pu.pr_rtime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_utime.tv_sec);
+ SWAP_ENDIAN (pu.pr_utime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_stime.tv_sec);
+ SWAP_ENDIAN (pu.pr_stime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_ttime.tv_sec);
+ SWAP_ENDIAN (pu.pr_ttime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_tftime.tv_sec);
+ SWAP_ENDIAN (pu.pr_tftime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_dftime.tv_sec);
+ SWAP_ENDIAN (pu.pr_dftime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_kftime.tv_sec);
+ SWAP_ENDIAN (pu.pr_kftime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_ltime.tv_sec);
+ SWAP_ENDIAN (pu.pr_ltime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_slptime.tv_sec);
+ SWAP_ENDIAN (pu.pr_slptime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_wtime.tv_sec);
+ SWAP_ENDIAN (pu.pr_wtime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_stoptime.tv_sec);
+ SWAP_ENDIAN (pu.pr_stoptime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_minf);
+ SWAP_ENDIAN (pu.pr_majf);
+ SWAP_ENDIAN (pu.pr_nswap);
+ SWAP_ENDIAN (pu.pr_inblk);
+ SWAP_ENDIAN (pu.pr_oublk);
+ SWAP_ENDIAN (pu.pr_msnd);
+ SWAP_ENDIAN (pu.pr_mrcv);
+ SWAP_ENDIAN (pu.pr_sigs);
+ SWAP_ENDIAN (pu.pr_vctx);
+ SWAP_ENDIAN (pu.pr_ictx);
+ SWAP_ENDIAN (pu.pr_sysc);
+ SWAP_ENDIAN (pu.pr_ioch);
+ }
+ pr_tstamp = timestruc2hr (tmp->pr_tstamp);
+ pr_create = timestruc2hr (tmp->pr_create);
+ pr_term = timestruc2hr (tmp->pr_term);
+ pr_rtime = timestruc2hr (tmp->pr_rtime);
+ pr_utime = timestruc2hr (tmp->pr_utime);
+ pr_stime = timestruc2hr (tmp->pr_stime);
+ pr_ttime = timestruc2hr (tmp->pr_ttime);
+ pr_tftime = timestruc2hr (tmp->pr_tftime);
+ pr_dftime = timestruc2hr (tmp->pr_dftime);
+ pr_kftime = timestruc2hr (tmp->pr_kftime);
+ pr_ltime = timestruc2hr (tmp->pr_ltime);
+ pr_slptime = timestruc2hr (tmp->pr_slptime);
+ pr_wtime = timestruc2hr (tmp->pr_wtime);
+ pr_stoptime = timestruc2hr (tmp->pr_stoptime);
+ pr_minf = tmp->pr_minf;
+ pr_majf = tmp->pr_majf;
+ pr_nswap = tmp->pr_nswap;
+ pr_inblk = tmp->pr_inblk;
+ pr_oublk = tmp->pr_oublk;
+ pr_msnd = tmp->pr_msnd;
+ pr_mrcv = tmp->pr_mrcv;
+ pr_sigs = tmp->pr_sigs;
+ pr_vctx = tmp->pr_vctx;
+ pr_ictx = tmp->pr_ictx;
+ pr_sysc = tmp->pr_sysc;
+ pr_ioch = tmp->pr_ioch;
+ return this;
+}
+
+struct timestruc_64
+{ /* 64-bit timestruc_t */
+ uint64_t tv_sec; /* seconds */
+ uint64_t tv_nsec; /* and nanoseconds */
+};
+
+typedef struct
+{
+ id_t pr_lwpid; /* lwp id. 0: process or defunct */
+ int pr_count; /* number of contributing lwps */
+ timestruc_64 pr_tstamp; /* current time stamp */
+ timestruc_64 pr_create; /* process/lwp creation time stamp */
+ timestruc_64 pr_term; /* process/lwp termination time stamp */
+ timestruc_64 pr_rtime; /* total lwp real (elapsed) time */
+ timestruc_64 pr_utime; /* user level cpu time */
+ timestruc_64 pr_stime; /* system call cpu time */
+ timestruc_64 pr_ttime; /* other system trap cpu time */
+ timestruc_64 pr_tftime; /* text page fault sleep time */
+ timestruc_64 pr_dftime; /* data page fault sleep time */
+ timestruc_64 pr_kftime; /* kernel page fault sleep time */
+ timestruc_64 pr_ltime; /* user lock wait sleep time */
+ timestruc_64 pr_slptime; /* all other sleep time */
+ timestruc_64 pr_wtime; /* wait-cpu (latency) time */
+ timestruc_64 pr_stoptime; /* stopped time */
+ timestruc_64 filltime[6]; /* filler for future expansion */
+ uint64_t pr_minf; /* minor page faults */
+ uint64_t pr_majf; /* major page faults */
+ uint64_t pr_nswap; /* swaps */
+ uint64_t pr_inblk; /* input blocks */
+ uint64_t pr_oublk; /* output blocks */
+ uint64_t pr_msnd; /* messages sent */
+ uint64_t pr_mrcv; /* messages received */
+ uint64_t pr_sigs; /* signals received */
+ uint64_t pr_vctx; /* voluntary context switches */
+ uint64_t pr_ictx; /* involuntary context switches */
+ uint64_t pr_sysc; /* system calls */
+ uint64_t pr_ioch; /* chars read and written */
+ uint64_t filler[10]; /* filler for future expansion */
+} raw_prusage_64;
+
+uint64_t
+PrUsage::bind64Size ()
+{
+ uint64_t bindSize = sizeof (raw_prusage_64);
+ return bindSize;
+}
+
+PrUsage *
+PrUsage::bind64 (void *p, bool need_swap_endian)
+{
+ if (p == NULL)
+ {
+ return NULL;
+ }
+ raw_prusage_64 pu, *tmp = (raw_prusage_64*) p;
+ if (need_swap_endian)
+ {
+ pu = *tmp;
+ tmp = &pu;
+ SWAP_ENDIAN (pu.pr_tstamp.tv_sec);
+ SWAP_ENDIAN (pu.pr_tstamp.tv_nsec);
+ SWAP_ENDIAN (pu.pr_create.tv_sec);
+ SWAP_ENDIAN (pu.pr_create.tv_nsec);
+ SWAP_ENDIAN (pu.pr_term.tv_sec);
+ SWAP_ENDIAN (pu.pr_term.tv_nsec);
+ SWAP_ENDIAN (pu.pr_rtime.tv_sec);
+ SWAP_ENDIAN (pu.pr_rtime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_utime.tv_sec);
+ SWAP_ENDIAN (pu.pr_utime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_stime.tv_sec);
+ SWAP_ENDIAN (pu.pr_stime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_ttime.tv_sec);
+ SWAP_ENDIAN (pu.pr_ttime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_tftime.tv_sec);
+ SWAP_ENDIAN (pu.pr_tftime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_dftime.tv_sec);
+ SWAP_ENDIAN (pu.pr_dftime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_kftime.tv_sec);
+ SWAP_ENDIAN (pu.pr_kftime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_ltime.tv_sec);
+ SWAP_ENDIAN (pu.pr_ltime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_slptime.tv_sec);
+ SWAP_ENDIAN (pu.pr_slptime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_wtime.tv_sec);
+ SWAP_ENDIAN (pu.pr_wtime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_stoptime.tv_sec);
+ SWAP_ENDIAN (pu.pr_stoptime.tv_nsec);
+ SWAP_ENDIAN (pu.pr_minf);
+ SWAP_ENDIAN (pu.pr_majf);
+ SWAP_ENDIAN (pu.pr_nswap);
+ SWAP_ENDIAN (pu.pr_inblk);
+ SWAP_ENDIAN (pu.pr_oublk);
+ SWAP_ENDIAN (pu.pr_msnd);
+ SWAP_ENDIAN (pu.pr_mrcv);
+ SWAP_ENDIAN (pu.pr_sigs);
+ SWAP_ENDIAN (pu.pr_vctx);
+ SWAP_ENDIAN (pu.pr_ictx);
+ SWAP_ENDIAN (pu.pr_sysc);
+ SWAP_ENDIAN (pu.pr_ioch);
+ }
+
+ pr_tstamp = timestruc2hr (tmp->pr_tstamp);
+ pr_create = timestruc2hr (tmp->pr_create);
+ pr_term = timestruc2hr (tmp->pr_term);
+ pr_rtime = timestruc2hr (tmp->pr_rtime);
+ pr_utime = timestruc2hr (tmp->pr_utime);
+ pr_stime = timestruc2hr (tmp->pr_stime);
+ pr_ttime = timestruc2hr (tmp->pr_ttime);
+ pr_tftime = timestruc2hr (tmp->pr_tftime);
+ pr_dftime = timestruc2hr (tmp->pr_dftime);
+ pr_kftime = timestruc2hr (tmp->pr_kftime);
+ pr_ltime = timestruc2hr (tmp->pr_ltime);
+ pr_slptime = timestruc2hr (tmp->pr_slptime);
+ pr_wtime = timestruc2hr (tmp->pr_wtime);
+ pr_stoptime = timestruc2hr (tmp->pr_stoptime);
+ pr_minf = tmp->pr_minf;
+ pr_majf = tmp->pr_majf;
+ pr_nswap = tmp->pr_nswap;
+ pr_inblk = tmp->pr_inblk;
+ pr_oublk = tmp->pr_oublk;
+ pr_msnd = tmp->pr_msnd;
+ pr_mrcv = tmp->pr_mrcv;
+ pr_sigs = tmp->pr_sigs;
+ pr_vctx = tmp->pr_vctx;
+ pr_ictx = tmp->pr_ictx;
+ pr_sysc = tmp->pr_sysc;
+ pr_ioch = tmp->pr_ioch;
+ return this;
+}
+
+Vector<long long> *
+PrUsage::getMstateValues ()
+{
+ const PrUsage *prusage = this;
+ Vector<long long> *states = new Vector<long long>;
+ states->store (0, prusage->pr_utime);
+ states->store (1, prusage->pr_stime);
+ states->store (2, prusage->pr_ttime);
+ states->store (3, prusage->pr_tftime);
+ states->store (4, prusage->pr_dftime);
+ states->store (5, prusage->pr_kftime);
+ states->store (6, prusage->pr_ltime);
+ states->store (7, prusage->pr_slptime);
+ states->store (8, prusage->pr_wtime);
+ states->store (9, prusage->pr_stoptime);
+ assert (LMS_NUM_SOLARIS_MSTATES == states->size ());
+ return states;
+}
+
+void* CommonPacket::jvm_overhead = NULL;
+
+CommonPacket::CommonPacket ()
+{
+ for (int i = 0; i < NTAGS; i++)
+ tags[i] = 0;
+ tstamp = 0;
+ jthread_TBR = NULL;
+ frinfo = 0;
+ leafpc = 0;
+ nat_stack = NULL;
+ user_stack = NULL;
+}
+
+int
+CommonPacket::cmp (const void *a, const void *b)
+{
+ if ((*(CommonPacket **) a)->tstamp > (*(CommonPacket **) b)->tstamp)
+ return 1;
+ else if ((*(CommonPacket **) a)->tstamp < (*(CommonPacket **) b)->tstamp)
+ return -1;
+ else
+ return 0;
+}
+
+void *
+CommonPacket::getStack (VMode view_mode)
+{
+ if (view_mode == VMODE_MACHINE)
+ return nat_stack;
+ else if (view_mode == VMODE_USER)
+ {
+ if (jthread_TBR == JTHREAD_NONE || (jthread_TBR && jthread_TBR->is_system ()))
+ return jvm_overhead;
+ }
+ else if (view_mode == VMODE_EXPERT)
+ {
+ Histable *hist = CallStack::getStackPC (user_stack, 0);
+ if (hist->get_type () == Histable::INSTR)
+ {
+ DbeInstr *instr = (DbeInstr*) hist;
+ if (instr->func == dbeSession->get_JUnknown_Function ())
+ return nat_stack;
+ }
+ else if (hist->get_type () == Histable::LINE)
+ {
+ DbeLine *line = (DbeLine *) hist;
+ if (line->func == dbeSession->get_JUnknown_Function ())
+ return nat_stack;
+ }
+ }
+ return user_stack;
+}
+
+Histable *
+CommonPacket::getStackPC (int n, VMode view_mode)
+{
+ return CallStack::getStackPC (getStack (view_mode), n);
+}
+
+Vector<Histable*> *
+CommonPacket::getStackPCs (VMode view_mode)
+{
+ return CallStack::getStackPCs (getStack (view_mode));
+}
+
+void *
+getStack (VMode view_mode, DataView *dview, long idx)
+{
+ void *stack = NULL;
+ if (view_mode == VMODE_MACHINE)
+ stack = dview->getObjValue (PROP_MSTACK, idx);
+ else if (view_mode == VMODE_USER)
+ stack = dview->getObjValue (PROP_USTACK, idx);
+ else if (view_mode == VMODE_EXPERT)
+ stack = dview->getObjValue (PROP_XSTACK, idx);
+ return stack;
+}
+
+int
+stackSize (VMode view_mode, DataView *dview, long idx)
+{
+ return CallStack::stackSize (getStack (view_mode, dview, idx));
+}
+
+Histable *
+getStackPC (int n, VMode view_mode, DataView *dview, long idx)
+{
+ return CallStack::getStackPC (getStack (view_mode, dview, idx), n);
+}
+
+Vector<Histable*> *
+getStackPCs (VMode view_mode, DataView *dview, long idx)
+{
+ return CallStack::getStackPCs (getStack (view_mode, dview, idx));
+}
diff --git a/gprofng/src/Exp_Layout.h b/gprofng/src/Exp_Layout.h
new file mode 100644
index 0000000..c5fbe4c
--- /dev/null
+++ b/gprofng/src/Exp_Layout.h
@@ -0,0 +1,158 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _EXP_LAYOUT_H
+#define _EXP_LAYOUT_H
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "dbe_types.h"
+#include "gp-experiment.h"
+#include "data_pckts.h"
+#include "ABS.h"
+#include "Data_window.h"
+#include "Histable.h"
+#include "vec.h"
+
+class PrUsage
+{
+public:
+ PrUsage ();
+ PrUsage *bind32 (void *p, bool need_swap_endian);
+ PrUsage *bind64 (void *p, bool need_swap_endian);
+ static uint64_t bind32Size ();
+ static uint64_t bind64Size ();
+ Vector<long long> * getMstateValues ();
+
+ hrtime_t pr_tstamp;
+ hrtime_t pr_create;
+ hrtime_t pr_term;
+ hrtime_t pr_rtime;
+
+ // the following correspond to PROP_MSTATE LMS_* offsets; see newMstateVec()
+ hrtime_t pr_utime;
+ hrtime_t pr_stime;
+ hrtime_t pr_ttime;
+ hrtime_t pr_tftime;
+ hrtime_t pr_dftime;
+ hrtime_t pr_kftime;
+ hrtime_t pr_ltime;
+ hrtime_t pr_slptime;
+ hrtime_t pr_wtime;
+ hrtime_t pr_stoptime;
+
+ uint64_t pr_minf;
+ uint64_t pr_majf;
+ uint64_t pr_nswap;
+ uint64_t pr_inblk;
+ uint64_t pr_oublk;
+ uint64_t pr_msnd;
+ uint64_t pr_mrcv;
+ uint64_t pr_sigs;
+ uint64_t pr_vctx;
+ uint64_t pr_ictx;
+ uint64_t pr_sysc;
+ uint64_t pr_ioch;
+};
+
+class DataView;
+extern void *getStack (VMode, DataView*, long);
+extern int stackSize (VMode, DataView*, long);
+extern Histable *getStackPC (int, VMode, DataView*, long);
+extern Vector<Histable*> *getStackPCs (VMode, DataView*, long);
+
+class CommonPacket // use only for RacePacket, please
+{
+public:
+ CommonPacket ();
+ void *getStack (VMode);
+ Histable *getStackPC (int, VMode);
+ Vector<Histable*>*getStackPCs (VMode);
+ static int cmp (const void *a, const void *b);
+
+ enum Tag_type { LWP, THR, CPU };
+ static const int NTAGS = 3;
+ uint32_t tags[NTAGS]; // lwp_id, thr_id, cpu_id
+ hrtime_t tstamp;
+ struct JThread *jthread_TBR; // pointer to JThread or NULL
+ uint64_t frinfo; // frame info
+ Vaddr leafpc; // raw leaf PC if availabe
+ void *nat_stack; // native stack
+ void *user_stack; // user stack (Java, OMP, etc.)
+ static void *jvm_overhead;
+};
+
+class FramePacket
+{
+public:
+ int
+ stackSize (bool java = false)
+ {
+ return java ? jstack->size () / 2 : stack->size ();
+ }
+
+ Vaddr
+ getFromStack (int n)
+ {
+ return stack->fetch (n);
+ }
+
+ Vaddr
+ getMthdFromStack (int n)
+ {
+ return jstack->fetch (2 * n + 1);
+ }
+
+ int
+ getBciFromStack (int n)
+ {
+ return (int) jstack->fetch (2 * n);
+ }
+
+ bool
+ isLeafMark (int n)
+ {
+ return stack->fetch (n) == (Vaddr) SP_LEAF_CHECK_MARKER;
+ }
+
+ bool
+ isTruncatedStack (bool java = false)
+ {
+ return java ? jtruncated : truncated == (Vaddr) SP_TRUNC_STACK_MARKER;
+ }
+
+ bool
+ isFailedUnwindStack ()
+ {
+ return truncated == (Vaddr) SP_FAILED_UNWIND_MARKER;
+ }
+ uint32_t omp_state; // OpenMP thread state
+ uint32_t mpi_state; // MPI state
+ uint64_t omp_cprid; // OpenMP parallel region id (omptrace)
+ Vector<Vaddr> *stack;
+ Vaddr truncated;
+ Vector<Vaddr> *jstack;
+ bool jtruncated;
+ Vector<Vaddr> *ompstack;
+ Vaddr omptruncated;
+};
+
+#endif /* _EXP_LAYOUT_H */
diff --git a/gprofng/src/Experiment.cc b/gprofng/src/Experiment.cc
new file mode 100644
index 0000000..a23c10c
--- /dev/null
+++ b/gprofng/src/Experiment.cc
@@ -0,0 +1,6961 @@
+/* Copyright (C) 2021 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 <errno.h>
+#include <utime.h>
+#include <alloca.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <set>
+
+#include "util.h"
+#include "CacheMap.h"
+#include "DbeFile.h"
+#include "DbeCacheMap.h"
+#include "DefaultHandler.h"
+#include "DefaultMap2D.h"
+#include "Emsg.h"
+#include "Elf.h"
+#include "SAXParser.h"
+#include "SAXParserFactory.h"
+#include "StringBuilder.h"
+#include "DbeSession.h"
+#include "DbeThread.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataStream.h"
+#include "Expression.h"
+#include "Function.h"
+#include "HeapMap.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "Ovw_data.h"
+#include "PRBTree.h"
+#include "Sample.h"
+#include "SegMem.h"
+#include "StringMap.h"
+#include "UserLabel.h"
+#include "Table.h"
+#include "dbe_types.h"
+#include "FileData.h"
+#include "cc_libcollector.h"
+#include "ExpGroup.h"
+
+int nPush;
+int nPop;
+int pushCnt;
+int popCnt;
+int pushCnt3;
+int popCnt3;
+
+struct Experiment::UIDnode
+{
+ uint64_t uid;
+ uint64_t val;
+ UIDnode *next;
+};
+
+struct Experiment::RawFramePacket
+{
+ uint64_t uid;
+ UIDnode *uidn;
+ UIDnode *uidj;
+ UIDnode *omp_uid;
+ uint32_t omp_state;
+};
+
+static hrtime_t
+parseTStamp (const char *s)
+{
+ hrtime_t ts = (hrtime_t) 0;
+ ts = (hrtime_t) atoi (s) * NANOSEC;
+ s = strchr (s, '.');
+ if (s != NULL)
+ ts += (hrtime_t) atoi (s + 1);
+ return ts;
+}
+
+class Experiment::ExperimentFile
+{
+public:
+
+ enum
+ {
+ EF_NOT_OPENED,
+ EF_OPENED,
+ EF_CLOSED,
+ EF_FAILURE
+ };
+
+ ExperimentFile (Experiment *_exp, const char *_fname);
+ ~ExperimentFile ();
+
+ bool open (bool new_open = false);
+
+ char *
+ get_name ()
+ {
+ return fname;
+ }
+
+ inline int
+ get_status ()
+ {
+ return ef_status;
+ }
+
+ char *fgets ();
+ void close ();
+
+ FILE *fh;
+
+private:
+ Experiment *exp;
+ char *fname;
+ off64_t offset;
+ int bufsz, ef_status;
+ char *buffer;
+};
+
+class Experiment::ExperimentHandler : public DefaultHandler
+{
+public:
+
+ ExperimentHandler (Experiment *_exp);
+ ~ExperimentHandler ();
+
+ void
+ startDocument () { }
+ void endDocument ();
+ void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
+ void endElement (char *uri, char *localName, char *qName);
+ void characters (char *ch, int start, int length);
+
+ void
+ ignorableWhitespace (char*, int, int) { }
+ void
+ error (SAXParseException *e);
+
+private:
+
+ enum Element
+ {
+ EL_NONE,
+ EL_EXPERIMENT,
+ EL_COLLECTOR,
+ EL_SETTING,
+ EL_PROCESS,
+ EL_SYSTEM,
+ EL_EVENT,
+ EL_PROFILE,
+ EL_DATAPTR,
+ EL_PROFDATA,
+ EL_PROFPCKT,
+ EL_FIELD,
+ EL_CPU,
+ EL_STATE,
+ EL_FREQUENCY,
+ EL_POWERM,
+ EL_DTRACEFATAL
+ };
+
+ static int toInt (Attributes *attrs, const char *atr);
+ static char*toStr (Attributes *attrs, const char *atr);
+ void pushElem (Element);
+ void popElem ();
+
+ Experiment *exp;
+ Element curElem;
+ Vector<Element> *stack;
+ Module *dynfuncModule;
+ DataDescriptor *dDscr;
+ PacketDescriptor *pDscr;
+ PropDescr *propDscr;
+ char *text;
+ Cmsg_warn mkind;
+ int mnum;
+ int mec;
+};
+
+
+// HTableSize is the size of smemHTable and instHTable
+// omazur: both HTableSize and the hash function haven't been tuned;
+static const int HTableSize = 8192;
+
+//-------------------------------------------------- Experiment file handler
+
+Experiment::ExperimentFile::ExperimentFile (Experiment *_exp, const char *_fname)
+{
+ exp = _exp;
+ fh = NULL;
+ bufsz = 0;
+ buffer = NULL;
+ ef_status = EF_NOT_OPENED;
+ offset = 0;
+ fname = dbe_sprintf (NTXT ("%s/%s"), exp->expt_name, _fname);
+}
+
+Experiment::ExperimentFile::~ExperimentFile ()
+{
+ close ();
+ free (buffer);
+ free (fname);
+}
+
+bool
+Experiment::ExperimentFile::open (bool new_open)
+{
+ if (fh == NULL)
+ {
+ fh = fopen64 (fname, NTXT ("r"));
+ if (fh == NULL)
+ {
+ ef_status = EF_FAILURE;
+ return false;
+ }
+ ef_status = EF_OPENED;
+ if (new_open)
+ offset = 0;
+ if (offset != 0)
+ fseeko64 (fh, offset, SEEK_SET);
+ }
+ return true;
+}
+
+char *
+Experiment::ExperimentFile::fgets ()
+{
+ if (bufsz == 0)
+ {
+ bufsz = 1024;
+ buffer = (char *) malloc (bufsz);
+ if (buffer == NULL)
+ return NULL;
+ buffer[bufsz - 1] = (char) 1; // sentinel
+ }
+ char *res = ::fgets (buffer, bufsz, fh);
+ if (res == NULL)
+ return NULL;
+ while (buffer[bufsz - 1] == (char) 0)
+ {
+ int newsz = bufsz + 1024;
+ char *newbuf = (char *) malloc (newsz);
+ if (newbuf == NULL)
+ return NULL;
+ memcpy (newbuf, buffer, bufsz);
+ free (buffer);
+ buffer = newbuf;
+ buffer[newsz - 1] = (char) 1; // sentinel
+ // we don't care about fgets result here
+ ::fgets (buffer + bufsz - 1, newsz - bufsz + 1, fh);
+ bufsz = newsz;
+ }
+ return buffer;
+}
+
+void
+Experiment::ExperimentFile::close ()
+{
+ if (fh)
+ {
+ offset = ftello64 (fh);
+ fclose (fh);
+ ef_status = EF_CLOSED;
+ fh = NULL;
+ }
+}
+
+
+//-------------------------------------------------- Experiment XML parser
+int
+Experiment::ExperimentHandler::toInt (Attributes *attrs, const char *atr)
+{
+ const char *str = attrs->getValue (atr);
+ return str ? atoi (str) : 0;
+}
+
+char *
+Experiment::ExperimentHandler::toStr (Attributes *attrs, const char *atr)
+{
+ const char *str = attrs->getValue (atr);
+ return dbe_strdup (str ? str : NTXT (""));
+}
+
+Experiment::ExperimentHandler::ExperimentHandler (Experiment *_exp)
+{
+ exp = _exp;
+ stack = new Vector<Element>;
+ pushElem (EL_NONE);
+ dynfuncModule = NULL;
+ dDscr = NULL;
+ pDscr = NULL;
+ propDscr = NULL;
+ text = NULL;
+ mkind = (Cmsg_warn) - 1; // CMSG_NONE
+ mnum = -1;
+ mec = -1;
+}
+
+Experiment::ExperimentHandler::~ExperimentHandler ()
+{
+ delete stack;
+ free (text);
+}
+
+void
+Experiment::ExperimentHandler::endDocument ()
+{
+ { // SP_TAG_STATE should be used to describe states, but it isn't
+ // let's do it here:
+ DataDescriptor *dd = exp->getDataDescriptor (DATA_HEAP);
+ if (dd != NULL)
+ {
+ PropDescr *prop = dd->getProp (PROP_HTYPE);
+ if (prop != NULL)
+ {
+ char * stateNames [HEAPTYPE_LAST] = HEAPTYPE_STATE_STRINGS;
+ char * stateUNames[HEAPTYPE_LAST] = HEAPTYPE_STATE_USTRINGS;
+ for (int ii = 0; ii < HEAPTYPE_LAST; ii++)
+ prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ }
+ }
+ dd = exp->getDataDescriptor (DATA_IOTRACE);
+ if (dd != NULL)
+ {
+ PropDescr *prop = dd->getProp (PROP_IOTYPE);
+ if (prop != NULL)
+ {
+ char * stateNames [IOTRACETYPE_LAST] = IOTRACETYPE_STATE_STRINGS;
+ char * stateUNames[IOTRACETYPE_LAST] = IOTRACETYPE_STATE_USTRINGS;
+ for (int ii = 0; ii < IOTRACETYPE_LAST; ii++)
+ prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ }
+ }
+ }
+}
+
+void
+Experiment::ExperimentHandler::pushElem (Element elem)
+{
+ curElem = elem;
+ stack->append (curElem);
+}
+
+void
+Experiment::ExperimentHandler::popElem ()
+{
+ stack->remove (stack->size () - 1);
+ curElem = stack->fetch (stack->size () - 1);
+}
+
+void
+Experiment::ExperimentHandler::startElement (char*, char*, char *qName, Attributes *attrs)
+{
+ DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
+ if (strcmp (qName, SP_TAG_EXPERIMENT) == 0)
+ {
+ pushElem (EL_EXPERIMENT);
+ const char *str = attrs->getValue (NTXT ("version"));
+ if (str != NULL)
+ {
+ int major = atoi (str);
+ str = strchr (str, '.');
+ int minor = str ? atoi (str + 1) : 0;
+ exp->exp_maj_version = major;
+ exp->exp_min_version = minor;
+ if (major != SUNPERF_VERNUM || minor != SUNPERF_VERNUM_MINOR)
+ {
+ // not the current version, see if we support some earlier versions
+ if (major < 12)
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("*** Error: experiment %s version %d.%d is not supported;\nuse the version of the tools that recorded the experiment to read it"),
+ exp->get_expt_name (), major, minor);
+ // exp->errorq->append( new Emsg(CMSG_FATAL, sb) );
+ exp->status = FAILURE;
+ exp->obsolete = 1;
+ throw new SAXException (sb.toString ());
+ }
+ }
+ }
+ }
+ else if (strcmp (qName, SP_TAG_COLLECTOR) == 0)
+ pushElem (EL_COLLECTOR);
+ else if (strcmp (qName, SP_TAG_SETTING) == 0)
+ {
+ int found = 0;
+ pushElem (EL_SETTING);
+ const char *str = attrs->getValue (SP_JCMD_LIMIT);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.limit = atoi (str);
+ }
+ str = attrs->getValue (SP_JCMD_BLKSZ);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->blksz = strtol (str, NULL, 0);
+ }
+ str = attrs->getValue (SP_JCMD_STACKBASE);
+ if (str)
+ {
+ found = 1;
+ exp->stack_base = strtoull (str, NULL, 0);
+ }
+ str = attrs->getValue (SP_JCMD_HWC_DEFAULT);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->hwc_default = true;
+ }
+ str = attrs->getValue (SP_JCMD_NOIDLE);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->commentq->append (new Emsg (CMSG_COMMENT,
+ GTXT ("*** Note: experiment does not have events from idle CPUs")));
+ }
+ str = attrs->getValue (SP_JCMD_FAKETIME);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->timelineavail = false;
+ exp->commentq->append (new Emsg (CMSG_COMMENT,
+ GTXT ("*** Note: experiment does not have timestamps; timeline unavailable")));
+ }
+ str = attrs->getValue (SP_JCMD_DELAYSTART);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.start_delay = strdup (str);
+ }
+ str = attrs->getValue (SP_JCMD_TERMINATE);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.terminate = strdup (str);
+ }
+ str = attrs->getValue (SP_JCMD_PAUSE_SIG);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.pause_sig = strdup (str);
+ }
+ str = attrs->getValue (SP_JCMD_SAMPLE_PERIOD);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.sample_periodic = 1;
+ exp->coll_params.sample_timer = atoi (str);
+ }
+ str = attrs->getValue (SP_JCMD_SAMPLE_SIG);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.sample_sig = str;
+ }
+ str = attrs->getValue (SP_JCMD_SRCHPATH);
+ if (str != NULL)
+ {
+ found = 1;
+ StringBuilder sb;
+ sb.sprintf (GTXT ("Search path: %s"), str);
+ exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ dbeSession->add_classpath ((char*) str);
+ }
+ str = attrs->getValue (SP_JCMD_LINETRACE);
+ if (str != NULL)
+ {
+ found = 1;
+ exp->coll_params.linetrace = strdup (str);
+ }
+
+ str = attrs->getValue (SP_JCMD_COLLENV);
+ if (str != NULL)
+ {
+ found = 1;
+ StringBuilder sb;
+ sb.sprintf (GTXT (" Data collection environment variable: %s"), str);
+ exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (found == 0)
+ {
+ int nattr = attrs->getLength ();
+ if (nattr != 0)
+ {
+ fprintf (stderr, "XXX Unexpected setting found; %d attributes:\n",
+ nattr);
+ for (int k = 0; k < nattr; k++)
+ {
+ const char *qn = attrs->getQName (k);
+ const char *vl = attrs->getValue (k);
+ fprintf (stderr, "XXX %s = %s\n", qn, vl);
+ }
+ }
+ }
+ // END OF CODE FOR "setting"
+ }
+ else if (strcmp (qName, SP_TAG_SYSTEM) == 0)
+ {
+ pushElem (EL_SYSTEM);
+ const char *str = attrs->getValue (NTXT ("hostname"));
+ if (str != NULL)
+ exp->hostname = strdup (str);
+ str = attrs->getValue (NTXT ("os"));
+ if (str != NULL)
+ {
+ exp->os_version = strdup (str);
+ /* For Linux experiments expect sparse thread ID's */
+ if (strncmp (str, NTXT ("SunOS"), 5) != 0)
+ exp->sparse_threads = true;
+ }
+ str = attrs->getValue (NTXT ("arch"));
+ if (str != NULL)
+ {
+ if (strcmp (str, "i86pc") == 0 || strcmp (str, "i686") == 0
+ || strcmp (str, "x86_64") == 0)
+ exp->platform = Intel;
+ else if (strcmp (str, "aarch64") == 0)
+ exp->platform = Aarch64;
+ else
+ exp->platform = Sparc;
+ exp->need_swap_endian = (DbeSession::platform == Sparc) ?
+ (exp->platform != Sparc) : (exp->platform == Sparc);
+ exp->architecture = strdup (str);
+ }
+ str = attrs->getValue (NTXT ("pagesz"));
+ if (str != NULL)
+ exp->page_size = atoi (str);
+ str = attrs->getValue (NTXT ("npages"));
+ if (str != NULL)
+ exp->npages = atoi (str);
+ }
+ else if (strcmp (qName, SP_TAG_POWERM) == 0)
+ pushElem (EL_POWERM);
+ else if (strcmp (qName, SP_TAG_FREQUENCY) == 0)
+ {
+ pushElem (EL_FREQUENCY);
+ const char *str = attrs->getValue (NTXT ("clk"));
+ if (str != NULL)
+ exp->set_clock (atoi (str));
+ // check for frequency_scaling or turbo_mode recorded from libcollector under dbx
+ str = attrs->getValue (NTXT ("frequency_scaling"));
+ const char *str2 = attrs->getValue (NTXT ("turbo_mode"));
+ if (str != NULL || str2 != NULL)
+ exp->varclock = 1;
+ }
+ else if (strcmp (qName, SP_TAG_CPU) == 0)
+ {
+ pushElem (EL_CPU);
+ exp->ncpus++;
+ const char *str = attrs->getValue (NTXT ("clk"));
+ if (str != NULL)
+ {
+ int clk = atoi (str);
+ if (exp->maxclock == 0)
+ {
+ exp->minclock = clk;
+ exp->maxclock = clk;
+ }
+ else
+ {
+ if (clk < exp->minclock)
+ exp->minclock = clk;
+ if (clk > exp->maxclock)
+ exp->maxclock = clk;
+ }
+ exp->clock = clk;
+ }
+ // check for frequency_scaling or turbo_mode
+ str = attrs->getValue (NTXT ("frequency_scaling"));
+ const char *str2 = attrs->getValue (NTXT ("turbo_mode"));
+ if (str != NULL || str2 != NULL)
+ exp->varclock = 1;
+ }
+ else if (strcmp (qName, SP_TAG_PROCESS) == 0)
+ {
+ pushElem (EL_PROCESS);
+ const char *str = attrs->getValue (NTXT ("wsize"));
+ if (str != NULL)
+ {
+ int wsz = atoi (str);
+ if (wsz == 32)
+ exp->wsize = W32;
+ else if (wsz == 64)
+ exp->wsize = W64;
+ }
+ str = attrs->getValue (NTXT ("pid"));
+ if (str != NULL)
+ exp->pid = atoi (str);
+ str = attrs->getValue (NTXT ("ppid"));
+ if (str != NULL)
+ exp->ppid = atoi (str);
+ str = attrs->getValue (NTXT ("pgrp"));
+ if (str != NULL)
+ exp->pgrp = atoi (str);
+ str = attrs->getValue (NTXT ("sid"));
+ if (str != NULL)
+ exp->sid = atoi (str);
+ str = attrs->getValue (NTXT ("cwd"));
+ if (str != NULL)
+ exp->ucwd = strdup (str);
+ str = attrs->getValue (NTXT ("pagesz"));
+ if (str != NULL)
+ exp->page_size = atoi (str);
+ }
+ else if (strcmp (qName, SP_TAG_EVENT) == 0)
+ { // Start code for event
+ pushElem (EL_EVENT);
+ hrtime_t ts = (hrtime_t) 0;
+ const char *str = attrs->getValue (NTXT ("tstamp"));
+ if (str != NULL)
+ ts = parseTStamp (str);
+ str = attrs->getValue (NTXT ("kind"));
+ if (str != NULL)
+ {
+ if (strcmp (str, SP_JCMD_RUN) == 0)
+ {
+ exp->broken = 0;
+ exp->exp_start_time = ts;
+ str = attrs->getValue (NTXT ("time"));
+ if (str != NULL)
+ exp->start_sec = atol (str);
+ str = attrs->getValue (NTXT ("pid"));
+ if (str != NULL)
+ exp->pid = atoi (str);
+ str = attrs->getValue (NTXT ("ppid"));
+ if (str != NULL)
+ exp->ppid = atoi (str);
+ str = attrs->getValue (NTXT ("pgrp"));
+ if (str != NULL)
+ exp->pgrp = atoi (str);
+ str = attrs->getValue (NTXT ("sid"));
+ if (str != NULL)
+ exp->sid = atoi (str);
+ exp->status = Experiment::INCOMPLETE;
+ }
+ else if (strcmp (str, SP_JCMD_ARCHIVE) == 0)
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("er_archive run: XXXXXXX"));
+ exp->pprocq->append (new Emsg (CMSG_WARN, sb));
+ }
+ else if (strcmp (str, SP_JCMD_SAMPLE) == 0)
+ {
+ exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
+ str = attrs->getValue (NTXT ("id"));
+ int id = str ? atoi (str) : -1;
+ char *label = dbe_strdup (attrs->getValue (NTXT ("label")));
+ exp->process_sample_cmd (NULL, ts, id, label);
+ }
+ else if (strcmp (str, SP_JCMD_EXIT) == 0)
+ {
+ // don't treat EXIT as an event w.r.t. last_event and non_paused_time
+ exp->status = Experiment::SUCCESS;
+ }
+ else if (strcmp (str, SP_JCMD_CERROR) == 0)
+ {
+ mkind = CMSG_ERROR;
+ str = attrs->getValue (NTXT ("id"));
+ if (str != NULL)
+ {
+ mnum = atoi (str);
+ }
+ str = attrs->getValue (NTXT ("ec"));
+ if (str != NULL)
+ {
+ mec = atoi (str);
+ }
+ }
+ else if (strcmp (str, SP_JCMD_CWARN) == 0)
+ {
+ mkind = CMSG_WARN;
+ str = attrs->getValue (NTXT ("id"));
+ if (str != NULL)
+ mnum = atoi (str);
+ }
+ else if (strcmp (str, SP_JCMD_COMMENT) == 0)
+ {
+ mkind = CMSG_COMMENT;
+ str = attrs->getValue (NTXT ("id"));
+ if (str != NULL)
+ mnum = atoi (str);
+ str = attrs->getValue (NTXT ("text"));
+ if (str != NULL)
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("*** Note: %s"), str);
+ exp->commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ }
+ else if (strcmp (str, SP_JCMD_DESC_START) == 0)
+ {
+ char *variant = toStr (attrs, NTXT ("variant"));
+ char *lineage = toStr (attrs, NTXT ("lineage"));
+ int follow = toInt (attrs, NTXT ("follow"));
+ char *msg = toStr (attrs, NTXT ("msg"));
+ exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg);
+ }
+ else if (strcmp (str, SP_JCMD_DESC_STARTED) == 0)
+ {
+ char *variant = toStr (attrs, NTXT ("variant"));
+ char *lineage = toStr (attrs, NTXT ("lineage"));
+ int follow = toInt (attrs, NTXT ("follow"));
+ char *msg = toStr (attrs, NTXT ("msg"));
+ exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg);
+ }
+ else if (strcmp (str, SP_JCMD_EXEC_START) == 0)
+ {
+ // if successful, acts like experiment termination - no "exit" entry will follow
+ exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
+ char *variant = toStr (attrs, NTXT ("variant"));
+ char *lineage = toStr (attrs, NTXT ("lineage"));
+ int follow = toInt (attrs, NTXT ("follow"));
+ char *msg = toStr (attrs, NTXT ("msg"));
+ exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg);
+ exp->exec_started = true;
+ }
+ else if (strcmp (str, SP_JCMD_EXEC_ERROR) == 0)
+ {
+ exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
+ char *variant = toStr (attrs, NTXT ("variant"));
+ char *lineage = toStr (attrs, NTXT ("lineage"));
+ int follow = toInt (attrs, NTXT ("follow"));
+ char *msg = toStr (attrs, NTXT ("msg"));
+ exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg);
+ exp->exec_started = false;
+ }
+ else if (strcmp (str, SP_JCMD_JTHRSTART) == 0)
+ {
+ char *name = dbe_strdup (attrs->getValue (NTXT ("name")));
+ char *grpname = dbe_strdup (attrs->getValue (NTXT ("grpname")));
+ char *prntname = dbe_strdup (attrs->getValue (NTXT ("prntname")));
+ str = attrs->getValue (NTXT ("tid"));
+ uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("jthr"));
+ Vaddr jthr = str ? strtoull (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("jenv"));
+ Vaddr jenv = str ? strtoull (str, NULL, 0) : 0;
+ exp->process_jthr_start_cmd (NULL, name, grpname, prntname, tid, jthr, jenv, ts);
+ }
+ else if (strcmp (str, SP_JCMD_JTHREND) == 0)
+ {
+ str = attrs->getValue (NTXT ("tid"));
+ uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("jthr"));
+ Vaddr jthr = str ? strtoull (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("jenv"));
+ Vaddr jenv = str ? strtoull (str, NULL, 0) : 0;
+ exp->process_jthr_end_cmd (NULL, tid, jthr, jenv, ts);
+ }
+ else if (strcmp (str, SP_JCMD_GCEND) == 0)
+ {
+ if (exp->getDataDescriptor (DATA_GCEVENT) == NULL)
+ exp->newDataDescriptor (DATA_GCEVENT);
+ exp->process_gc_end_cmd (ts);
+ }
+ else if (strcmp (str, SP_JCMD_GCSTART) == 0)
+ {
+ if (exp->getDataDescriptor (DATA_GCEVENT) == NULL)
+ exp->newDataDescriptor (DATA_GCEVENT);
+ exp->process_gc_start_cmd (ts);
+ }
+ else if (strcmp (str, SP_JCMD_PAUSE) == 0)
+ {
+ if (exp->resume_ts != MAX_TIME)
+ {
+ // data collection was active
+ hrtime_t delta = ts - exp->resume_ts;
+ exp->non_paused_time += delta;
+ exp->resume_ts = MAX_TIME; // collection is paused
+ }
+ StringBuilder sb;
+ str = attrs->getValue (NTXT ("name"));
+ if (str == NULL)
+ sb.sprintf (GTXT ("Pause: %ld.%09ld"), (long) (ts / NANOSEC),
+ (long) (ts % NANOSEC));
+ else
+ sb.sprintf (GTXT ("Pause (%s): %ld.%09ld"), str,
+ (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+ exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ else if (strcmp (str, SP_JCMD_RESUME) == 0)
+ {
+ if (exp->resume_ts == MAX_TIME)
+ // data collection was paused
+ exp->resume_ts = ts; // remember start time
+ StringBuilder sb;
+ sb.sprintf (GTXT ("Resume: %ld.%09ld"), (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+ exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ if (exp->exp_start_time == ZERO_TIME)
+ exp->exp_start_time = ts;
+ }
+ else if (strcmp (str, SP_JCMD_THREAD_PAUSE) == 0)
+ {
+ str = attrs->getValue (NTXT ("tid"));
+ uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+ StringBuilder sb;
+ sb.sprintf (GTXT ("Thread %llu pause: %ld.%09ld"), (unsigned long long) tid,
+ (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+ exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ else if (strcmp (str, SP_JCMD_THREAD_RESUME) == 0)
+ {
+ str = attrs->getValue (NTXT ("tid"));
+ uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+ StringBuilder sb;
+ sb.sprintf (GTXT ("Thread %llu resume: %ld.%09ld"), (unsigned long long) tid,
+ (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+ exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ else if (strcmp (str, NTXT ("map")) == 0)
+ {
+ ts += exp->exp_start_time;
+ str = attrs->getValue (NTXT ("vaddr"));
+ Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("size"));
+ int msize = str ? atoi (str) : 0;
+ str = attrs->getValue (NTXT ("foffset"));
+ int64_t offset = str ? strtoll (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("modes"));
+ int64_t modes = str ? strtoll (str, NULL, 0) : 0;
+ str = attrs->getValue (NTXT ("chksum"));
+ int64_t chksum = 0;
+ if (str)
+ chksum = Elf::normalize_checksum (strtoll (str, NULL, 0));
+ char *name = (char *) attrs->getValue (NTXT ("name"));
+ str = attrs->getValue (NTXT ("object"));
+ if (strcmp (str, NTXT ("segment")) == 0)
+ {
+ if (strcmp (name, NTXT ("LinuxKernel")) == 0)
+ exp->process_Linux_kernel_cmd (ts);
+ else
+ exp->process_seg_map_cmd (NULL, ts, vaddr, msize, 0,
+ offset, modes, chksum, name);
+ }
+ else if (strcmp (str, NTXT ("function")) == 0)
+ {
+ exp->process_fn_load_cmd (dynfuncModule, name, vaddr, msize, ts);
+ dynfuncModule = NULL;
+ }
+ else if (strcmp (str, NTXT ("dynfunc")) == 0)
+ {
+ if (dynfuncModule == NULL)
+ {
+ dynfuncModule = dbeSession->createModule (exp->get_dynfunc_lo (DYNFUNC_SEGMENT), name);
+ dynfuncModule->flags |= MOD_FLAG_UNKNOWN;
+ dynfuncModule->set_file_name (dbe_strdup (dynfuncModule->getMainSrc ()->get_name ()));
+ }
+ (void) exp->create_dynfunc (dynfuncModule,
+ (char*) attrs->getValue (NTXT ("funcname")), vaddr, msize);
+ }
+ else if (strcmp (str, NTXT ("jcm")) == 0)
+ {
+ str = attrs->getValue (NTXT ("methodId"));
+ Vaddr mid = str ? strtoull (str, NULL, 0) : 0;
+ exp->process_jcm_load_cmd (NULL, mid, vaddr, msize, ts);
+ }
+ }
+ else if (strcmp (str, NTXT ("unmap")) == 0)
+ {
+ ts += exp->exp_start_time;
+ str = attrs->getValue (NTXT ("vaddr"));
+ Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0;
+ exp->process_seg_unmap_cmd (NULL, ts, vaddr);
+ }
+ }
+ // end of code for event
+ }
+ else if (strcmp (qName, SP_TAG_PROFILE) == 0)
+ {
+ pushElem (EL_PROFILE);
+ const char *str = attrs->getValue (NTXT ("name"));
+ if (str == NULL)
+ return;
+ if (strcmp (str, NTXT ("profile")) == 0)
+ {
+ exp->coll_params.profile_mode = 1;
+ str = attrs->getValue (NTXT ("numstates"));
+ if (str != NULL)
+ exp->coll_params.lms_magic_id = atoi (str);
+ str = attrs->getValue (NTXT ("ptimer"));
+ if (str != NULL)
+ exp->coll_params.ptimer_usec = atoi (str); // microseconds
+
+ PropDescr *mstate_prop = NULL;
+ char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS;
+ char * stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS;
+ {
+ dDscr = exp->newDataDescriptor (DATA_CLOCK);
+ PropDescr *prop = new PropDescr (PROP_MSTATE, NTXT ("MSTATE"));
+ prop->uname = dbe_strdup (GTXT ("Thread state"));
+ prop->vtype = TYPE_UINT32;
+ // (states added below)
+ dDscr->addProperty (prop);
+ mstate_prop = prop;
+
+ prop = new PropDescr (PROP_NTICK, NTXT ("NTICK"));
+ prop->uname = dbe_strdup (GTXT ("Number of Profiling Ticks"));
+ prop->vtype = TYPE_UINT32;
+ dDscr->addProperty (prop);
+ }
+
+ switch (exp->coll_params.lms_magic_id)
+ {
+ case LMS_MAGIC_ID_SOLARIS:
+ exp->register_metric (Metric::CP_TOTAL);
+ exp->register_metric (Metric::CP_TOTAL_CPU);
+ exp->register_metric (Metric::CP_LMS_USER);
+ exp->register_metric (Metric::CP_LMS_SYSTEM);
+ exp->register_metric (Metric::CP_LMS_TRAP);
+ exp->register_metric (Metric::CP_LMS_DFAULT);
+ exp->register_metric (Metric::CP_LMS_TFAULT);
+ exp->register_metric (Metric::CP_LMS_KFAULT);
+ exp->register_metric (Metric::CP_LMS_STOPPED);
+ exp->register_metric (Metric::CP_LMS_WAIT_CPU);
+ exp->register_metric (Metric::CP_LMS_SLEEP);
+ exp->register_metric (Metric::CP_LMS_USER_LOCK);
+ for (int ii = 0; ii < LMS_NUM_SOLARIS_MSTATES; ii++)
+ mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ break;
+ case LMS_MAGIC_ID_ERKERNEL_KERNEL:
+ exp->register_metric (Metric::CP_KERNEL_CPU);
+ {
+ int ii = LMS_KERNEL_CPU;
+ mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ }
+ break;
+ case LMS_MAGIC_ID_ERKERNEL_USER:
+ exp->register_metric (Metric::CP_TOTAL_CPU);
+ exp->register_metric (Metric::CP_LMS_USER);
+ exp->register_metric (Metric::CP_LMS_SYSTEM);
+ {
+ int ii = LMS_KERNEL_CPU;
+ mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ ii = LMS_USER;
+ mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ ii = LMS_SYSTEM;
+ mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ }
+ break;
+ case LMS_MAGIC_ID_LINUX:
+ exp->register_metric (Metric::CP_TOTAL_CPU);
+ {
+ int ii = LMS_LINUX_CPU;
+ mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ }
+ break;
+ default:
+ // odd
+ break;
+ }
+ }
+ else if (strcmp (str, NTXT ("heaptrace")) == 0)
+ {
+ exp->coll_params.heap_mode = 1;
+ exp->leaklistavail = true;
+ exp->heapdataavail = true;
+ exp->register_metric (Metric::HEAP_ALLOC_BYTES);
+ exp->register_metric (Metric::HEAP_ALLOC_CNT);
+ exp->register_metric (Metric::HEAP_LEAK_BYTES);
+ exp->register_metric (Metric::HEAP_LEAK_CNT);
+ dDscr = exp->newDataDescriptor (DATA_HEAP);
+ }
+ else if (strcmp (str, NTXT ("iotrace")) == 0)
+ {
+ exp->coll_params.io_mode = 1;
+ exp->iodataavail = true;
+ exp->register_metric (Metric::IO_READ_TIME);
+ exp->register_metric (Metric::IO_READ_BYTES);
+ exp->register_metric (Metric::IO_READ_CNT);
+ exp->register_metric (Metric::IO_WRITE_TIME);
+ exp->register_metric (Metric::IO_WRITE_BYTES);
+ exp->register_metric (Metric::IO_WRITE_CNT);
+ exp->register_metric (Metric::IO_OTHER_TIME);
+ exp->register_metric (Metric::IO_OTHER_CNT);
+ exp->register_metric (Metric::IO_ERROR_TIME);
+ exp->register_metric (Metric::IO_ERROR_CNT);
+ dDscr = exp->newDataDescriptor (DATA_IOTRACE);
+ }
+ else if (strcmp (str, NTXT ("synctrace")) == 0)
+ {
+ exp->coll_params.sync_mode = 1;
+ str = attrs->getValue (NTXT ("threshold"));
+ if (str != NULL)
+ exp->coll_params.sync_threshold = atoi (str);
+ str = attrs->getValue (NTXT ("scope"));
+ if (str != NULL)
+ exp->coll_params.sync_scope = atoi (str);
+ else // Should only happen with old experiments; use the old default
+ exp->coll_params.sync_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA;
+ exp->register_metric (Metric::SYNC_WAIT_TIME);
+ exp->register_metric (Metric::SYNC_WAIT_COUNT);
+ dDscr = exp->newDataDescriptor (DATA_SYNCH);
+ }
+ else if (strcmp (str, NTXT ("omptrace")) == 0)
+ {
+ exp->coll_params.omp_mode = 1;
+ dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW);
+ }
+ else if (strcmp (str, NTXT ("hwcounter")) == 0)
+ {
+ str = attrs->getValue (NTXT ("cpuver"));
+ int cpuver = str ? atoi (str) : 0;
+ char *counter = dbe_strdup (attrs->getValue (NTXT ("hwcname")));
+ char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name"))); // may not be present
+ str = attrs->getValue (NTXT ("interval"));
+ int interval = str ? atoi (str) : 0;
+ str = attrs->getValue (NTXT ("tag"));
+ int tag = str ? atoi (str) : 0;
+ str = attrs->getValue (NTXT ("memop"));
+ int i_tpc = str ? atoi (str) : 0;
+ char *modstr = dbe_strdup (attrs->getValue (NTXT ("modstr")));
+ exp->process_hwcounter_cmd (NULL, cpuver, counter, int_name, interval, tag, i_tpc, modstr);
+ dDscr = exp->newDataDescriptor (DATA_HWC);
+ }
+ else if (strcmp (str, NTXT ("hwsimctr")) == 0)
+ {
+ int cpuver = toInt (attrs, NTXT ("cpuver"));
+ char *hwcname = dbe_strdup (attrs->getValue (NTXT ("hwcname")));
+ char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name")));
+ char *metric = dbe_strdup (attrs->getValue (NTXT ("metric")));
+ int reg = toInt (attrs, NTXT ("reg_num"));
+ int interval = toInt (attrs, NTXT ("interval"));
+ int timecvt = toInt (attrs, NTXT ("timecvt"));
+ int i_tpc = toInt (attrs, NTXT ("memop"));
+ int tag = toInt (attrs, NTXT ("tag"));
+ exp->process_hwsimctr_cmd (NULL, cpuver, hwcname, int_name, metric, reg,
+ interval, timecvt, i_tpc, tag);
+ dDscr = exp->newDataDescriptor (DATA_HWC);
+ }
+ else if (strcmp (str, NTXT ("dversion")) == 0)
+ exp->dversion = dbe_strdup (attrs->getValue (NTXT ("version")));
+ else if (strcmp (str, NTXT ("jprofile")) == 0)
+ {
+ exp->has_java = true;
+ str = attrs->getValue (NTXT ("jversion"));
+ if (str != NULL)
+ exp->jversion = strdup (str);
+ }
+ else if (strcmp (str, NTXT ("datarace")) == 0)
+ {
+ exp->coll_params.race_mode = 1;
+ exp->racelistavail = true;
+ str = attrs->getValue (NTXT ("scheme"));
+ exp->coll_params.race_stack = str ? atoi (str) : 0;
+ exp->register_metric (Metric::RACCESS);
+ dDscr = exp->newDataDescriptor (DATA_RACE);
+ }
+ else if (strcmp (str, NTXT ("deadlock")) == 0)
+ {
+ exp->coll_params.deadlock_mode = 1;
+ exp->deadlocklistavail = true;
+ exp->register_metric (Metric::DEADLOCKS);
+ dDscr = exp->newDataDescriptor (DATA_DLCK);
+ }
+ }
+ /* XXX -- obsolete tag, but is still written to experiments */
+ else if (strcmp (qName, SP_TAG_DATAPTR) == 0)
+ {
+ pushElem (EL_DATAPTR);
+ return;
+ }
+ else if (strcmp (qName, SP_TAG_PROFDATA) == 0)
+ {
+ pushElem (EL_PROFDATA);
+ // SS12 HWC experiments are not well structured
+ const char *fname = attrs->getValue (NTXT ("fname"));
+ if (fname && strcmp (fname, SP_HWCNTR_FILE) == 0)
+ dDscr = exp->newDataDescriptor (DATA_HWC);
+ }
+ else if (strcmp (qName, SP_TAG_PROFPCKT) == 0)
+ {
+ pushElem (EL_PROFPCKT);
+ const char *str = attrs->getValue (NTXT ("kind")); // see Pckt_type
+ int kind = str ? atoi (str) : -1;
+ if (kind < 0)
+ return;
+ if (exp->coll_params.omp_mode == 1)
+ {
+ if (kind == OMP_PCKT)
+ dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW);
+ else if (kind == OMP2_PCKT)
+ dDscr = exp->newDataDescriptor (DATA_OMP2, DDFLAG_NOSHOW);
+ else if (kind == OMP3_PCKT)
+ dDscr = exp->newDataDescriptor (DATA_OMP3, DDFLAG_NOSHOW);
+ else if (kind == OMP4_PCKT)
+ dDscr = exp->newDataDescriptor (DATA_OMP4, DDFLAG_NOSHOW);
+ else if (kind == OMP5_PCKT)
+ dDscr = exp->newDataDescriptor (DATA_OMP5, DDFLAG_NOSHOW);
+ }
+ pDscr = exp->newPacketDescriptor (kind, dDscr);
+ return;
+ }
+ else if (strcmp (qName, SP_TAG_FIELD) == 0)
+ {
+ pushElem (EL_FIELD);
+ if (pDscr != NULL)
+ {
+ const char *name = attrs->getValue (NTXT ("name"));
+ if (name == NULL)
+ return;
+ int propID = dbeSession->registerPropertyName (name);
+ propDscr = new PropDescr (propID, name);
+ FieldDescr *fldDscr = new FieldDescr (propID, name);
+
+ const char *str = attrs->getValue (NTXT ("type"));
+ if (str)
+ {
+ if (strcmp (str, NTXT ("INT32")) == 0)
+ fldDscr->vtype = TYPE_INT32;
+ else if (strcmp (str, NTXT ("UINT32")) == 0)
+ fldDscr->vtype = TYPE_UINT32;
+ else if (strcmp (str, NTXT ("INT64")) == 0)
+ fldDscr->vtype = TYPE_INT64;
+ else if (strcmp (str, NTXT ("UINT64")) == 0)
+ fldDscr->vtype = TYPE_UINT64;
+ else if (strcmp (str, NTXT ("STRING")) == 0)
+ fldDscr->vtype = TYPE_STRING;
+ else if (strcmp (str, NTXT ("DOUBLE")) == 0)
+ fldDscr->vtype = TYPE_DOUBLE;
+ else if (strcmp (str, NTXT ("DATE")) == 0)
+ {
+ fldDscr->vtype = TYPE_DATE;
+ const char *fmt = attrs->getValue (NTXT ("format"));
+ fldDscr->format = strdup (fmt ? fmt : "");
+ }
+ }
+ propDscr->vtype = fldDscr->vtype;
+
+ // TYPE_DATE is converted to TYPE_UINT64 in propDscr
+ if (fldDscr->vtype == TYPE_DATE)
+ propDscr->vtype = TYPE_UINT64;
+
+ // Fix some types until they are fixed in libcollector
+ if (propID == PROP_VIRTPC || propID == PROP_PHYSPC)
+ {
+ if (fldDscr->vtype == TYPE_INT32)
+ propDscr->vtype = TYPE_UINT32;
+ else if (fldDscr->vtype == TYPE_INT64)
+ propDscr->vtype = TYPE_UINT64;
+ }
+
+ // The following props get mapped to 32-bit values in readPacket
+ if (propID == PROP_CPUID || propID == PROP_THRID
+ || propID == PROP_LWPID)
+ propDscr->vtype = TYPE_UINT32; // override experiment property
+
+ str = attrs->getValue (NTXT ("uname"));
+ if (str)
+ propDscr->uname = strdup (PTXT ((char*) str));
+ str = attrs->getValue (NTXT ("noshow"));
+ if (str && atoi (str) != 0)
+ propDscr->flags |= PRFLAG_NOSHOW;
+
+ if (dDscr == NULL)
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("*** Error: data parsing failed. Log file is corrupted."));
+ exp->warnq->append (new Emsg (CMSG_ERROR, sb));
+ throw new SAXException (sb.toString ());
+ }
+
+ dDscr->addProperty (propDscr);
+ str = attrs->getValue (NTXT ("offset"));
+ if (str)
+ fldDscr->offset = atoi (str);
+ pDscr->addField (fldDscr);
+ }
+ }
+ else if (strcmp (qName, SP_TAG_STATE) == 0)
+ {
+ pushElem (EL_STATE);
+ if (propDscr != NULL)
+ {
+ const char *str = attrs->getValue (NTXT ("value"));
+ int value = str ? atoi (str) : -1;
+ str = attrs->getValue (NTXT ("name"));
+ const char *ustr = attrs->getValue (NTXT ("uname"));
+ propDscr->addState (value, str, ustr);
+ }
+ }
+ else if (strcmp (qName, SP_TAG_DTRACEFATAL) == 0)
+ pushElem (EL_DTRACEFATAL);
+ else
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("*** Warning: unrecognized element %s"), qName);
+ exp->warnq->append (new Emsg (CMSG_WARN, sb));
+ pushElem (EL_NONE);
+ }
+}
+
+void
+Experiment::ExperimentHandler::characters (char *ch, int start, int length)
+{
+ switch (curElem)
+ {
+ case EL_COLLECTOR:
+ exp->cversion = dbe_strndup (ch + start, length);
+ break;
+ case EL_PROCESS:
+ exp->process_arglist_cmd (NULL, dbe_strndup (ch + start, length));
+ break;
+ case EL_EVENT:
+ free (text);
+ text = dbe_strndup (ch + start, length);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+Experiment::ExperimentHandler::endElement (char*, char*, char*)
+{
+ if (curElem == EL_EVENT && mkind >= 0 && mnum >= 0)
+ {
+ char *str;
+ if (mec > 0)
+ str = dbe_sprintf ("%s -- %s", text != NULL ? text : "", strerror (mec));
+ else
+ str = dbe_sprintf ("%s", text != NULL ? text : "");
+ Emsg *msg = new Emsg (mkind, mnum, str);
+ if (mkind == CMSG_WARN)
+ {
+ if (mnum != COL_WARN_FSTYPE
+ || dbeSession->check_ignore_fs_warn () == false)
+ exp->warnq->append (msg);
+ else
+ exp->commentq->append (msg);
+ }
+ else if (mkind == CMSG_ERROR || mkind == CMSG_FATAL)
+ exp->errorq->append (msg);
+ else if (mkind == CMSG_COMMENT)
+ exp->commentq->append (msg);
+ else
+ delete msg;
+ mkind = (Cmsg_warn) - 1;
+ mnum = -1;
+ mec = -1;
+ }
+ else if (curElem == EL_PROFILE)
+ dDscr = NULL;
+ else if (curElem == EL_PROFPCKT)
+ pDscr = NULL;
+ else if (curElem == EL_FIELD)
+ propDscr = NULL;
+ free (text);
+ text = NULL;
+ popElem ();
+}
+
+void
+Experiment::ExperimentHandler::error (SAXParseException *e)
+{
+ StringBuilder sb;
+ sb.sprintf (GTXT ("%s at line %d, column %d"),
+ e->getMessage (), e->getLineNumber (), e->getColumnNumber ());
+ char *msg = sb.toString ();
+ SAXException *e1 = new SAXException (msg);
+ free (msg);
+ throw ( e1);
+}
+
+//-------------------------------------------------- Experiment
+
+Experiment::Experiment ()
+{
+ groupId = 0;
+ userExpId = expIdx = -1;
+ founder_exp = NULL;
+ baseFounder = NULL;
+ children_exps = new Vector<Experiment*>;
+ loadObjs = new Vector<LoadObject*>;
+ loadObjMap = new StringMap<LoadObject*>(128, 128);
+ sourcesMap = NULL;
+
+ // Initialize configuration information.
+ status = FAILURE;
+ start_sec = 0;
+ mtime = 0;
+ hostname = NULL;
+ username = NULL;
+ architecture = NULL;
+ os_version = NULL;
+ uarglist = NULL;
+ utargname = NULL;
+ ucwd = NULL;
+ cversion = NULL;
+ dversion = NULL;
+ jversion = NULL;
+ exp_maj_version = 0;
+ exp_min_version = 0;
+ platform = Unknown;
+ wsize = Wnone;
+ page_size = 4096;
+ npages = 0;
+ stack_base = 0xf0000000;
+ broken = 1;
+ obsolete = 0;
+ hwc_bogus = 0;
+ hwc_lost_int = 0;
+ hwc_scanned = 0;
+ hwc_default = false;
+ invalid_packet = 0;
+
+ // clear HWC event stats
+ dsevents = 0;
+ dsnoxhwcevents = 0;
+
+ memset (&coll_params, 0, sizeof (coll_params));
+ ncpus = 0;
+ minclock = 0;
+ maxclock = 0;
+ clock = 0;
+ varclock = 0;
+ exec_started = false;
+ timelineavail = true;
+ leaklistavail = false;
+ heapdataavail = false;
+ iodataavail = false;
+ dataspaceavail = false;
+ ifreqavail = false;
+ racelistavail = false;
+ deadlocklistavail = false;
+ ompavail = false;
+ tiny_threshold = -1;
+ pid = 0;
+ ppid = 0;
+ pgrp = 0;
+ sid = 0;
+
+ gc_duration = ZERO_TIME;
+ exp_start_time = ZERO_TIME; // not known. Wall-clock hrtime (not zero based)
+ last_event = ZERO_TIME; // not known. Wall-clock hrtime (not zero based)
+ non_paused_time = 0; // 0 non-paused time (will sum as experiment is processed)
+ resume_ts = 0; // by default, collection is "resumed" (not paused) from time=0
+ need_swap_endian = false;
+ exp_rel_start_time_set = false;
+ exp_rel_start_time = ZERO_TIME;
+ has_java = false;
+ hex_field_width = 8;
+ hw_cpuver = CPUVER_UNDEFINED;
+ machinemodel = NULL;
+ expt_name = NULL;
+ arch_name = NULL;
+ fndr_arch_name = NULL;
+ logFile = NULL;
+
+ dataDscrs = new Vector<DataDescriptor*>;
+ for (int i = 0; i < DATA_LAST; ++i)
+ dataDscrs->append (NULL);
+
+ pcktDscrs = new Vector<PacketDescriptor*>;
+ blksz = PROFILE_BUFFER_CHUNK;
+ jthreads = new Vector<JThread*>;
+ jthreads_idx = new Vector<JThread*>;
+ gcevents = new Vector<GCEvent*>;
+ gcevent_last_used = (GCEvent *) NULL;
+ heapUnmapEvents = new Vector<UnmapChunk*>;
+ cstack = NULL;
+ cstackShowHide = NULL;
+ frmpckts = new Vector<RawFramePacket*>;
+ typedef DefaultMap2D<uint32_t, hrtime_t, uint64_t> OmpMap0;
+ mapPRid = new OmpMap0 (OmpMap0::Interval);
+ typedef DefaultMap2D<uint32_t, hrtime_t, void*> OmpMap;
+ mapPReg = new OmpMap (OmpMap::Interval);
+ mapTask = new OmpMap (OmpMap::Interval);
+ openMPdata = NULL;
+ archiveMap = NULL;
+ nnodes = 0;
+ nchunks = 0;
+ chunks = 0;
+ uidHTable = NULL;
+ uidnodes = new Vector<UIDnode*>;
+ mrecs = new Vector<MapRecord*>;
+ samples = new Vector<Sample*>;
+ sample_last_used = (Sample *) NULL;
+ first_sample_label = (char*) NULL;
+ fDataMap = NULL;
+ vFdMap = NULL;
+ resolveFrameInfo = true;
+ discardTiny = false;
+ init ();
+}
+
+Experiment::~Experiment ()
+{
+ fini ();
+ free (coll_params.linetrace);
+ for (int i = 0; i < MAX_HWCOUNT; i++)
+ {
+ free (coll_params.hw_aux_name[i]);
+ free (coll_params.hw_username[i]);
+ }
+ free (hostname);
+ free (username);
+ free (architecture);
+ free (os_version);
+ free (uarglist);
+ free (utargname);
+ free (ucwd);
+ free (cversion);
+ free (dversion);
+ free (jversion);
+ delete logFile;
+ free (expt_name);
+ free (arch_name);
+ free (fndr_arch_name);
+ delete jthreads_idx;
+ delete cstack;
+ delete cstackShowHide;
+ delete mapPRid;
+ delete mapPReg;
+ delete mapTask;
+ delete openMPdata;
+ destroy_map (DbeFile *, archiveMap);
+ delete[] uidHTable;
+ delete uidnodes;
+ delete mrecs;
+ delete children_exps;
+ delete loadObjs;
+ delete loadObjMap;
+ delete sourcesMap;
+ free (first_sample_label);
+ free (machinemodel);
+
+ dataDscrs->destroy ();
+ delete dataDscrs;
+ pcktDscrs->destroy ();
+ delete pcktDscrs;
+ jthreads->destroy ();
+ delete jthreads;
+ gcevents->destroy ();
+ delete gcevents;
+ heapUnmapEvents->destroy ();
+ delete heapUnmapEvents;
+ frmpckts->destroy ();
+ delete frmpckts;
+ samples->destroy ();
+ delete samples;
+ delete fDataMap;
+ delete vFdMap;
+
+ for (long i = 0; i < nchunks; i++)
+ delete[] chunks[i];
+ delete[] chunks;
+}
+
+void
+Experiment::init_cache ()
+{
+ if (smemHTable)
+ return;
+ smemHTable = new SegMem*[HTableSize];
+ instHTable = new DbeInstr*[HTableSize];
+ for (int i = 0; i < HTableSize; i++)
+ {
+ smemHTable[i] = NULL;
+ instHTable[i] = NULL;
+ }
+ uidHTable = new UIDnode*[HTableSize];
+ for (int i = 0; i < HTableSize; i++)
+ uidHTable[i] = NULL;
+
+ cstack = CallStack::getInstance (this);
+ cstackShowHide = CallStack::getInstance (this);
+}
+
+void
+Experiment::init ()
+{
+ userLabels = NULL;
+ seg_items = new Vector<SegMem*>;
+ maps = new PRBTree ();
+ jmaps = NULL; // used by JAVA_CLASSES only
+ jmidHTable = NULL;
+ smemHTable = NULL;
+ instHTable = NULL;
+ min_thread = (uint64_t) - 1;
+ max_thread = 0;
+ thread_cnt = 0;
+ min_lwp = (uint64_t) - 1;
+ max_lwp = 0;
+ lwp_cnt = 0;
+ min_cpu = (uint64_t) - 1;
+ max_cpu = 0;
+ cpu_cnt = 0;
+
+ commentq = new Emsgqueue (NTXT ("commentq"));
+ runlogq = new Emsgqueue (NTXT ("runlogq"));
+ errorq = new Emsgqueue (NTXT ("errorq"));
+ warnq = new Emsgqueue (NTXT ("warnq"));
+ notesq = new Emsgqueue (NTXT ("notesq"));
+ pprocq = new Emsgqueue (NTXT ("pprocq"));
+ ifreqq = NULL;
+
+ metrics = new Vector<BaseMetric*>;
+ tagObjs = new Vector<Vector<Histable*>*>;
+ tagObjs->store (PROP_THRID, new Vector<Histable*>);
+ tagObjs->store (PROP_LWPID, new Vector<Histable*>);
+ tagObjs->store (PROP_CPUID, new Vector<Histable*>);
+ tagObjs->store (PROP_EXPID, new Vector<Histable*>);
+ sparse_threads = false;
+}
+
+void
+Experiment::fini ()
+{
+ seg_items->destroy ();
+ delete seg_items;
+ delete maps;
+ delete jmaps;
+ delete[] smemHTable;
+ delete[] instHTable;
+ delete jmidHTable;
+ delete commentq;
+ delete runlogq;
+ delete errorq;
+ delete warnq;
+ delete notesq;
+ delete pprocq;
+ if (ifreqq != NULL)
+ {
+ delete ifreqq;
+ ifreqq = NULL;
+ }
+
+ int index;
+ BaseMetric *mtr;
+ Vec_loop (BaseMetric*, metrics, index, mtr)
+ {
+ dbeSession->drop_metric (mtr);
+ }
+ delete metrics;
+ tagObjs->fetch (PROP_THRID)->destroy ();
+ tagObjs->fetch (PROP_LWPID)->destroy ();
+ tagObjs->fetch (PROP_CPUID)->destroy ();
+ tagObjs->fetch (PROP_EXPID)->destroy ();
+ tagObjs->destroy ();
+ delete tagObjs;
+}
+
+// These are the data files which can be read in parallel
+// for multiple sub-experiments.
+// Postpone calling resolve_frame_info()
+void
+Experiment::read_experiment_data (bool read_ahead)
+{
+
+ read_frameinfo_file ();
+ if (read_ahead)
+ {
+ resolveFrameInfo = false;
+ (void) get_profile_events ();
+ resolveFrameInfo = true;
+ }
+}
+
+Experiment::Exp_status
+Experiment::open_epilogue ()
+{
+
+ // set up mapping for tagObj(PROP_EXPID)
+ (void) mapTagValue (PROP_EXPID, userExpId);
+
+ post_process ();
+ if (last_event != ZERO_TIME)
+ { // if last_event is known
+ StringBuilder sb;
+ hrtime_t ts = last_event - exp_start_time;
+ sb.sprintf (GTXT ("Experiment Ended: %ld.%09ld\nData Collection Duration: %ld.%09ld"),
+ (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+ (long) (non_paused_time / NANOSEC),
+ (long) (non_paused_time % NANOSEC));
+ runlogq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // Check for incomplete experiment, and inform the user
+ if (status == INCOMPLETE)
+ {
+ if (exec_started == true)
+ // experiment ended with the exec, not abnormally
+ status = SUCCESS;
+ else
+ {
+ char * cmnt = GTXT ("*** Note: experiment was not closed");
+ commentq->append (new Emsg (CMSG_COMMENT, cmnt));
+ // runlogq->append(new Emsg(CMSG_COMMENT, cmnt));
+ }
+ }
+ // write a descriptive header for the experiment
+ write_header ();
+ return status;
+}
+
+Experiment::Exp_status
+Experiment::open (char *path)
+{
+
+ // Find experiment directory
+ if (find_expdir (path) != SUCCESS)
+ // message will have been queued and status set
+ return status;
+
+ // Get creation time for experiment
+ struct stat64 st;
+ if (dbe_stat (path, &st) == 0)
+ mtime = st.st_mtime;
+
+ // Read the warnings file
+ read_warn_file ();
+
+ // Open the log file
+ read_log_file ();
+ if (status == SUCCESS && last_event // last event is initialized
+ && (last_event - exp_start_time) / 1000000 < tiny_threshold)
+ {
+ // Process "tiny_threshold" (SP_ANALYZER_DISCARD_TINY_EXPERIMENTS)
+ // At this point, we've only processed log.xml.
+ // Note: if an experiment terminated abnormally, last_event will not yet
+ // represent events from clock profiling and other metrics.
+ // Other events will often have timestamps after the last log.xml entry.
+ discardTiny = true;
+ return status;
+ }
+ if (status == FAILURE)
+ {
+ if (logFile->get_status () == ExperimentFile::EF_FAILURE)
+ {
+ Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment cannot be read"));
+ errorq->append (m);
+ }
+ else if (fetch_errors () == NULL)
+ {
+ if (broken == 1)
+ {
+ Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log does not show target starting"));
+ errorq->append (m);
+ }
+ else
+ {
+ Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment could not be parsed"));
+ errorq->append (m);
+ }
+ }
+ return status;
+ }
+ init_cache ();
+ if (varclock != 0)
+ {
+ StringBuilder sb;
+ sb.sprintf (
+ GTXT ("*** Warning: system has variable clock frequency, which may cause variable execution times and inaccurate conversions of cycle counts into time."));
+ warnq->append (new Emsg (CMSG_WARN, sb));
+ }
+
+ // Read the notes file
+ read_notes_file ();
+ read_labels_file ();
+ read_archives ();
+
+ // The log file shows experiment started
+ read_java_classes_file ();
+
+ read_map_file ();
+
+ // Dyntext file has to be processed after loadobjects file
+ // as we need to be able to map (vaddr,ts) to dynamic functions.
+ read_dyntext_file ();
+
+ // Read the overview file and create samples.
+ // Profiling data hasn't been read yet so we may have
+ // events after the last recorded sample.
+ // We'll create a fake sample to cover all those
+ // events later.
+ read_overview_file ();
+
+ // Check if instruction frequency data is available
+ read_ifreq_file ();
+
+ // Check if OMP data is available
+ read_omp_file ();
+
+ return status;
+}
+
+/* XXX -- update() is a no-op now, but may be needed for auto-update */
+Experiment::Exp_status
+Experiment::update ()
+{
+ return status;
+}
+
+void
+Experiment::append (LoadObject *lo)
+{
+ loadObjs->append (lo);
+ char *obj_name = lo->get_pathname ();
+ char *bname = get_basename (obj_name);
+ loadObjMap->put (obj_name, lo);
+ loadObjMap->put (bname, lo);
+ if (lo->flags & SEG_FLAG_EXE)
+ loadObjMap->put (COMP_EXE_NAME, lo);
+}
+
+void
+Experiment::read_notes_file ()
+{
+ Emsg *m;
+
+ // Open log file:
+ char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
+ FILE *f = fopen (fname, NTXT ("r"));
+ free (fname);
+ if (f == NULL)
+ return;
+ if (!dbeSession->is_interactive ())
+ {
+ m = new Emsg (CMSG_COMMENT, NTXT ("Notes:"));
+ notesq->append (m);
+ }
+
+ while (1)
+ {
+ char str[MAXPATHLEN];
+ char *e = fgets (str, ((int) sizeof (str)) - 1, f);
+ if (e == NULL)
+ {
+ if (!dbeSession->is_interactive ())
+ {
+ m = new Emsg (CMSG_COMMENT,
+ "============================================================");
+ notesq->append (m);
+ }
+ break;
+ }
+ size_t i = strlen (str);
+ if (i > 0 && str[i - 1] == '\n')
+ // remove trailing nl
+ str[i - 1] = 0;
+ m = new Emsg (CMSG_COMMENT, str);
+ notesq->append (m);
+ }
+ (void) fclose (f);
+}
+
+int
+Experiment::save_notes (char* text, bool handle_file)
+{
+ if (handle_file)
+ {
+ FILE *fnotes;
+ char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
+ fnotes = fopen (fname, NTXT ("w"));
+ free (fname);
+ if (fnotes != NULL)
+ {
+ (void) fprintf (fnotes, NTXT ("%s"), text);
+ fclose (fnotes);
+ }
+ else
+ return 1; // Cannot write file
+ }
+ notesq->clear ();
+ Emsg *m = new Emsg (CMSG_COMMENT, text);
+ notesq->append (m);
+
+ return 0;
+}
+
+int
+Experiment::delete_notes (bool handle_file)
+{
+ if (handle_file)
+ {
+ char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
+ if (unlink (fname) != 0)
+ {
+ free (fname);
+ return 1; // Cannot delete file
+ }
+ free (fname);
+ }
+ notesq->clear ();
+ return 0;
+}
+
+int
+Experiment::read_warn_file ()
+{
+ int local_status = SUCCESS;
+
+ ExperimentFile *warnFile = new ExperimentFile (this, SP_WARN_FILE);
+ if (warnFile == NULL)
+ return FAILURE;
+ if (!warnFile->open ())
+ {
+ delete warnFile;
+ return FAILURE;
+ }
+ SAXParserFactory *factory = SAXParserFactory::newInstance ();
+ SAXParser *saxParser = factory->newSAXParser ();
+ DefaultHandler *dh = new ExperimentHandler (this);
+ try
+ {
+ saxParser->parse ((File*) warnFile->fh, dh);
+ }
+ catch (SAXException *e)
+ {
+ // Fatal error in the parser
+ StringBuilder sb;
+ sb.sprintf (NTXT ("%s: %s"), SP_WARN_FILE, e->getMessage ());
+ char *str = sb.toString ();
+ Emsg *m = new Emsg (CMSG_FATAL, str);
+ errorq->append (m);
+ local_status = FAILURE;
+ delete e;
+ }
+ delete warnFile;
+ delete dh;
+ delete saxParser;
+ delete factory;
+
+ return local_status;
+}
+
+int
+Experiment::read_log_file ()
+{
+ if (logFile == NULL)
+ logFile = new ExperimentFile (this, SP_LOG_FILE);
+ if (!logFile->open ())
+ {
+ status = FAILURE;
+ return status;
+ }
+
+ SAXParserFactory *factory = SAXParserFactory::newInstance ();
+ SAXParser *saxParser = factory->newSAXParser ();
+ DefaultHandler *dh = new ExperimentHandler (this);
+ try
+ {
+ saxParser->parse ((File*) logFile->fh, dh);
+ }
+ catch (SAXException *e)
+ {
+ // Fatal error in the parser
+ StringBuilder sb;
+ if (obsolete == 1)
+ sb.sprintf (NTXT ("%s"), e->getMessage ());
+ else
+ sb.sprintf (NTXT ("%s: %s"), SP_LOG_FILE, e->getMessage ());
+ char *str = sb.toString ();
+ Emsg *m = new Emsg (CMSG_FATAL, str);
+ errorq->append (m);
+ status = FAILURE;
+ delete e;
+ }
+ logFile->close ();
+ dbeSession->register_metric (GTXT ("IPC"), GTXT ("Instructions Per Cycle"),
+ NTXT ("insts/cycles"));
+ dbeSession->register_metric (GTXT ("CPI"), GTXT ("Cycles Per Instruction"),
+ NTXT ("cycles/insts"));
+ dbeSession->register_metric (GTXT ("K_IPC"),
+ GTXT ("Kernel Instructions Per Cycle"),
+ NTXT ("K_insts/K_cycles"));
+ dbeSession->register_metric (GTXT ("K_CPI"),
+ GTXT ("Kernel Cycles Per Instruction"),
+ NTXT ("K_cycles/K_insts"));
+
+ delete dh;
+ delete saxParser;
+ delete factory;
+
+ return status;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// class Experiment::ExperimentLabelsHandler
+//
+
+class Experiment::ExperimentLabelsHandler : public DefaultHandler
+{
+public:
+
+ ExperimentLabelsHandler (Experiment *_exp)
+ {
+ exp = _exp;
+ }
+
+ ~ExperimentLabelsHandler () { };
+ void startDocument () { }
+ void endDocument () { }
+ void endElement (char * /*uri*/, char * /*localName*/, char * /*qName*/) { }
+ void characters (char * /*ch*/, int /*start*/, int /*length*/) { }
+ void ignorableWhitespace (char*, int, int) { }
+ void error (SAXParseException * /*e*/) { }
+
+ void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
+
+private:
+
+ inline const char *
+ s2s (const char *s)
+ {
+ return s ? s : "NULL";
+ }
+
+ Experiment *exp;
+ char *hostname;
+ hrtime_t time, tstamp;
+};
+
+void
+Experiment::ExperimentLabelsHandler::startElement (char*, char*, char *qName,
+ Attributes *attrs)
+{
+ DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
+ if (qName == NULL || strcmp (qName, NTXT ("id")) != 0)
+ return;
+ char *name = NULL, *all_times = NULL, *comment = NULL, *hostName = NULL;
+ long startSec = 0;
+ // long tm_zone = 0;
+ hrtime_t startHrtime = (hrtime_t) 0;
+ long long lbl_ts = 0;
+ int relative = 0;
+ timeval start_tv;
+ start_tv.tv_usec = start_tv.tv_sec = 0;
+ for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++)
+ {
+ const char *qn = attrs->getQName (i);
+ const char *vl = attrs->getValue (i);
+ if (strcmp (qn, NTXT ("name")) == 0)
+ name = dbe_xml2str (vl);
+ else if (strcmp (qn, NTXT ("cmd")) == 0)
+ all_times = dbe_xml2str (vl);
+ else if (strcmp (qn, NTXT ("comment")) == 0)
+ comment = dbe_xml2str (vl);
+ else if (strcmp (qn, NTXT ("relative")) == 0)
+ relative = atoi (vl);
+ else if (strcmp (qn, NTXT ("hostname")) == 0)
+ hostName = dbe_xml2str (vl);
+ else if (strcmp (qn, NTXT ("time")) == 0)
+ startSec = atol (vl);
+ else if (strcmp (qn, NTXT ("tstamp")) == 0)
+ startHrtime = parseTStamp (vl);
+ else if (strcmp (qn, NTXT ("lbl_ts")) == 0)
+ {
+ if (*vl == '-')
+ lbl_ts = -parseTStamp (vl + 1);
+ else
+ lbl_ts = parseTStamp (vl);
+ }
+ }
+ if (name == NULL || hostName == NULL || (all_times == NULL && comment == NULL))
+ {
+ free (name);
+ free (hostName);
+ free (all_times);
+ free (comment);
+ return;
+ }
+ UserLabel *lbl = new UserLabel (name);
+ lbl->comment = comment;
+ lbl->hostname = hostName;
+ lbl->start_sec = startSec;
+ lbl->start_hrtime = startHrtime;
+ exp->userLabels->append (lbl);
+ if (all_times)
+ {
+ lbl->all_times = all_times;
+ lbl->start_tv = start_tv;
+ lbl->relative = relative;
+ if (relative == UserLabel::REL_TIME)
+ lbl->atime = lbl_ts;
+ else
+ { // relative == UserLabel::CUR_TIME
+ long long delta = 0;
+ if (exp->hostname && strcmp (lbl->hostname, exp->hostname) == 0)
+ delta = lbl_ts + (lbl->start_hrtime - exp->exp_start_time);
+ else
+ for (int i = 0; i < exp->userLabels->size (); i++)
+ {
+ UserLabel *firstLbl = exp->userLabels->fetch (i);
+ if (strcmp (lbl->hostname, firstLbl->hostname) == 0)
+ {
+ delta = lbl_ts + (lbl->start_hrtime - firstLbl->start_hrtime) +
+ ((long long) (firstLbl->start_sec - exp->start_sec)) * NANOSEC;
+ break;
+ }
+ }
+ lbl->atime = delta > 0 ? delta : 0;
+ }
+ }
+}
+
+static int
+sortUserLabels (const void *a, const void *b)
+{
+ UserLabel *l1 = *((UserLabel **) a);
+ UserLabel *l2 = *((UserLabel **) b);
+ int v = dbe_strcmp (l1->name, l2->name);
+ if (v != 0)
+ return v;
+ if (l1->atime < l2->atime)
+ return -1;
+ else if (l1->atime > l2->atime)
+ return 1;
+ if (l1->id < l2->id)
+ return -1;
+ else if (l1->id > l2->id)
+ return 1;
+ return 0;
+}
+
+static char *
+append_string (char *s, char *str)
+{
+ if (s == NULL)
+ return dbe_strdup (str);
+ char *new_s = dbe_sprintf (NTXT ("%s %s"), s, str);
+ free (s);
+ return new_s;
+}
+
+void
+Experiment::read_labels_file ()
+{
+ ExperimentFile *fp = new ExperimentFile (this, SP_LABELS_FILE);
+ if (!fp->open ())
+ {
+ delete fp;
+ return;
+ }
+ userLabels = new Vector<UserLabel*>();
+ SAXParserFactory *factory = SAXParserFactory::newInstance ();
+ SAXParser *saxParser = factory->newSAXParser ();
+ DefaultHandler *dh = new ExperimentLabelsHandler (this);
+ try
+ {
+ saxParser->parse ((File*) fp->fh, dh);
+ }
+ catch (SAXException *e)
+ {
+ // Fatal error in the parser
+ StringBuilder sb;
+ sb.sprintf (NTXT ("%s: %s"), SP_LABELS_FILE, e->getMessage ());
+ char *str = sb.toString ();
+ Emsg *m = new Emsg (CMSG_FATAL, str);
+ errorq->append (m);
+ delete e;
+ }
+ fp->close ();
+ delete fp;
+ delete dh;
+ delete saxParser;
+ delete factory;
+
+ userLabels->sort (sortUserLabels);
+ UserLabel::dump ("After sortUserLabels:", userLabels);
+ UserLabel *ulbl = NULL;
+ for (int i = 0, sz = userLabels->size (); i < sz; i++)
+ {
+ UserLabel *lbl = userLabels->fetch (i);
+ if (ulbl == NULL)
+ ulbl = new UserLabel (lbl->name);
+ else if (dbe_strcmp (lbl->name, ulbl->name) != 0)
+ { // new Label
+ ulbl->register_user_label (groupId);
+ if (ulbl->expr == NULL)
+ delete ulbl;
+ ulbl = new UserLabel (lbl->name);
+ }
+ if (lbl->all_times)
+ {
+ if (strncmp (lbl->all_times, NTXT ("start"), 5) == 0)
+ {
+ if (!ulbl->start_f)
+ {
+ ulbl->start_f = true;
+ ulbl->timeStart = lbl->atime;
+ }
+ }
+ else
+ { // stop
+ if (!ulbl->start_f)
+ continue;
+ ulbl->all_times = append_string (ulbl->all_times, lbl->all_times);
+ ulbl->stop_f = true;
+ ulbl->timeStop = lbl->atime;
+ ulbl->gen_expr ();
+ }
+ }
+ if (lbl->comment != NULL)
+ ulbl->comment = append_string (ulbl->comment, lbl->comment);
+ }
+ if (ulbl)
+ {
+ ulbl->register_user_label (groupId);
+ if (ulbl->expr == NULL)
+ delete ulbl;
+ }
+ Destroy (userLabels);
+}
+
+void
+Experiment::read_archives ()
+{
+ if (founder_exp)
+ return;
+ char *allocated_str = NULL;
+ char *nm = get_arch_name ();
+ DIR *exp_dir = opendir (nm);
+ if (exp_dir == NULL)
+ {
+ if (founder_exp == NULL)
+ {
+ // Check if the user uses a subexperiment only
+ nm = dbe_sprintf (NTXT ("%s/../%s"), expt_name, SP_ARCHIVES_DIR);
+ exp_dir = opendir (nm);
+ if (exp_dir == NULL)
+ {
+ free (nm);
+ return;
+ }
+ allocated_str = nm;
+ }
+ else
+ return;
+ }
+
+ StringBuilder sb;
+ sb.append (nm);
+ sb.append ('/');
+ int dlen = sb.length ();
+ free (allocated_str);
+ archiveMap = new StringMap<DbeFile *>();
+
+ struct dirent *entry = NULL;
+ while ((entry = readdir (exp_dir)) != NULL)
+ {
+ char *dname = entry->d_name;
+ if (dname[0] == '.'
+ && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))
+ // skip links to ./ or ../
+ continue;
+ sb.setLength (dlen);
+ sb.append (dname);
+ char *fnm = sb.toString ();
+ DbeFile *df = new DbeFile (fnm);
+ df->set_location (fnm);
+ df->filetype |= DbeFile::F_FILE;
+ df->inArchive = true;
+ df->experiment = this;
+ archiveMap->put (dname, df);
+ free (fnm);
+ }
+ closedir (exp_dir);
+}
+
+static char *
+gen_file_name (const char *packet_name, const char *src_name)
+{
+ char *fnm, *bname = get_basename (packet_name);
+ if (bname == packet_name)
+ fnm = dbe_strdup (src_name);
+ else
+ fnm = dbe_sprintf ("%.*s%s", (int) (bname - packet_name),
+ packet_name, src_name);
+
+ // convert "java.lang.Object/Integer.java" => "java/lang/Object/Integer.java"
+ bname = get_basename (fnm);
+ for (char *s = fnm; s < bname; s++)
+ if (*s == '.')
+ *s = '/';
+ return fnm;
+}
+
+static char *
+get_jlass_name (const char *nm)
+{
+ // Convert "Ljava/lang/Object;" => "java/lang/Object.class"
+ if (*nm == 'L')
+ {
+ size_t len = strlen (nm);
+ if (nm[len - 1] == ';')
+ return dbe_sprintf ("%.*s.class", (int) (len - 2), nm + 1);
+ }
+ return dbe_strdup (nm);
+}
+
+static char *
+get_jmodule_name (const char *nm)
+{
+ // convert "Ljava/lang/Object;" => "java.lang.Object"
+ if (*nm == 'L')
+ {
+ size_t len = strlen (nm);
+ if (nm[len - 1] == ';')
+ {
+ char *mname = dbe_sprintf (NTXT ("%.*s"), (int) (len - 2), nm + 1);
+ for (char *s = mname; *s; s++)
+ if (*s == '/')
+ *s = '.';
+ return mname;
+ }
+ }
+ return dbe_strdup (nm);
+}
+
+LoadObject *
+Experiment::get_j_lo (const char *className, const char *fileName)
+{
+ char *class_name = get_jlass_name (className);
+ Dprintf (DUMP_JCLASS_READER,
+ "Experiment::get_j_lo: className='%s' class_name='%s' fileName='%s'\n",
+ STR (className), STR (class_name), STR (fileName));
+ LoadObject *lo = loadObjMap->get (class_name);
+ if (lo == NULL)
+ {
+ lo = createLoadObject (class_name, fileName);
+ lo->type = LoadObject::SEG_TEXT;
+ lo->mtime = (time_t) 0;
+ lo->size = 0;
+ lo->set_platform (Java, wsize);
+ lo->dbeFile->filetype |= DbeFile::F_FILE | DbeFile::F_JAVACLASS;
+ append (lo);
+ Dprintf (DUMP_JCLASS_READER,
+ "Experiment::get_j_lo: creates '%s' location='%s'\n",
+ STR (lo->get_name ()), STR (lo->dbeFile->get_location (false)));
+ }
+ free (class_name);
+ return lo;
+}
+
+Module *
+Experiment::get_jclass (const char *className, const char *fileName)
+{
+ LoadObject *lo = get_j_lo (className, NULL);
+ char *mod_name = get_jmodule_name (className);
+ Module *mod = lo->find_module (mod_name);
+ if (mod == NULL)
+ {
+ mod = dbeSession->createClassFile (mod_name);
+ mod->loadobject = lo;
+ if (strcmp (fileName, NTXT ("<Unknown>")) != 0)
+ mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
+ else
+ mod->set_file_name (dbe_strdup (fileName));
+ lo->append_module (mod);
+ mod_name = NULL;
+ }
+ else if (mod->file_name && (strcmp (mod->file_name, "<Unknown>") == 0)
+ && strcmp (fileName, "<Unknown>") != 0)
+ mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
+ Dprintf (DUMP_JCLASS_READER,
+ "Experiment::get_jclass: class_name='%s' mod_name='%s' fileName='%s'\n",
+ mod->loadobject->get_pathname (), mod->get_name (), mod->file_name);
+ free (mod_name);
+ return mod;
+}
+
+#define ARCH_STRLEN(s) ( ( strlen(s) + 4 ) & ~0x3 )
+
+int
+Experiment::read_java_classes_file ()
+{
+ char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_JCLASSES_FILE);
+ Data_window *dwin = new Data_window (data_file_name);
+ free (data_file_name);
+ if (dwin->not_opened ())
+ {
+ delete dwin;
+ return INCOMPLETE;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+ jmaps = new PRBTree ();
+ jmidHTable = new DbeCacheMap<unsigned long long, JMethod>;
+
+ hrtime_t cur_loaded = 0;
+ Module *cur_mod = NULL;
+ for (int64_t offset = 0;;)
+ {
+ CM_Packet *cpkt = (CM_Packet*) dwin->bind (offset, sizeof (CM_Packet));
+ if (cpkt == NULL)
+ break;
+ uint16_t v16 = (uint16_t) cpkt->tsize;
+ size_t cpktsize = dwin->decode (v16);
+ cpkt = (CM_Packet*) dwin->bind (offset, cpktsize);
+ if ((cpkt == NULL) || (cpktsize == 0))
+ {
+ char *buf = dbe_sprintf (GTXT ("archive file malformed %s"),
+ arch_name);
+ errorq->append (new Emsg (CMSG_ERROR, buf));
+ free (buf);
+ break;
+ }
+ v16 = (uint16_t) cpkt->type;
+ v16 = dwin->decode (v16);
+ switch (v16)
+ {
+ case ARCH_JCLASS:
+ {
+ ARCH_jclass *ajcl = (ARCH_jclass*) cpkt;
+ uint64_t class_id = dwin->decode (ajcl->class_id);
+ char *className = ((char*) ajcl) + sizeof (*ajcl);
+ char *fileName = className + ARCH_STRLEN (className);
+ Dprintf (DUMP_JCLASS_READER,
+ "read_java_classes_file: ARCH_JCLASS(Ox%x)"
+ "class_id=Ox%llx className='%s' fileName='%s' \n",
+ (int) v16, (long long) class_id, className, fileName);
+ cur_mod = NULL;
+ if (*className == 'L')
+ { // Old libcollector generated '[' (one array dimension).
+ cur_mod = get_jclass (className, fileName);
+ cur_loaded = dwin->decode (ajcl->tstamp);
+ jmaps->insert (class_id, cur_loaded, cur_mod);
+ }
+ break;
+ }
+ case ARCH_JCLASS_LOCATION:
+ {
+ ARCH_jclass_location *ajcl = (ARCH_jclass_location *) cpkt;
+ uint64_t class_id = dwin->decode (ajcl->class_id);
+ char *className = ((char*) ajcl) + sizeof (*ajcl);
+ char *fileName = className + ARCH_STRLEN (className);
+ Dprintf (DUMP_JCLASS_READER,
+ "read_java_classes_file: ARCH_JCLASS_LOCATION(Ox%x)"
+ "class_id=Ox%llx className='%s' fileName='%s' \n",
+ (int) v16, (long long) class_id, className, fileName);
+ get_j_lo (className, fileName);
+ break;
+ }
+ case ARCH_JMETHOD:
+ {
+ if (cur_mod == NULL)
+ break;
+ ARCH_jmethod *ajmt = (ARCH_jmethod*) cpkt;
+ uint64_t method_id = dwin->decode (ajmt->method_id);
+ char *s_name = ((char*) ajmt) + sizeof (*ajmt);
+ char *s_signature = s_name + ARCH_STRLEN (s_name);
+ char *fullname = dbe_sprintf ("%s.%s", cur_mod->get_name (), s_name);
+ Dprintf (DUMP_JCLASS_READER,
+ "read_java_classes_file: ARCH_JMETHOD(Ox%x) "
+ "method_id=Ox%llx name='%s' signature='%s' fullname='%s'\n",
+ (int) v16, (long long) method_id, s_name,
+ s_signature, fullname);
+ JMethod *jmthd = cur_mod->find_jmethod (fullname, s_signature);
+ if (jmthd == NULL)
+ {
+ jmthd = dbeSession->createJMethod ();
+ jmthd->size = (unsigned) - 1; // unknown until later (maybe)
+ jmthd->module = cur_mod;
+ jmthd->set_signature (s_signature);
+ jmthd->set_name (fullname);
+ cur_mod->functions->append (jmthd);
+ cur_mod->loadobject->functions->append (jmthd);
+ Dprintf (DUMP_JCLASS_READER,
+ "read_java_classes_file: ARCH_JMETHOD CREATE fullname=%s\n",
+ fullname);
+ }
+ jmaps->insert (method_id, cur_loaded, jmthd);
+ free (fullname);
+ break;
+ }
+ default:
+ Dprintf (DUMP_JCLASS_READER,
+ "read_java_classes_file: type=Ox%x (%d) cpktsize=%d\n",
+ (int) v16, (int) v16, (int) cpktsize);
+ break; // ignore unknown packets
+ }
+ offset += cpktsize;
+ }
+ delete dwin;
+ return SUCCESS;
+}
+
+void
+Experiment::read_map_file ()
+{
+ ExperimentFile *mapFile = new ExperimentFile (this, SP_MAP_FILE);
+ if (!mapFile->open ())
+ {
+ delete mapFile;
+ return;
+ }
+
+ SAXParserFactory *factory = SAXParserFactory::newInstance ();
+ SAXParser *saxParser = factory->newSAXParser ();
+ DefaultHandler *dh = new ExperimentHandler (this);
+ try
+ {
+ saxParser->parse ((File*) mapFile->fh, dh);
+ }
+ catch (SAXException *e)
+ {
+ // Fatal error in the parser
+ StringBuilder sb;
+ sb.sprintf (NTXT ("%s: %s"), SP_MAP_FILE, e->getMessage ());
+ char *str = sb.toString ();
+ Emsg *m = new Emsg (CMSG_FATAL, str);
+ errorq->append (m);
+ status = FAILURE;
+ free (str);
+ delete e;
+ }
+ delete mapFile;
+ delete dh;
+ delete saxParser;
+ delete factory;
+
+ for (int i = 0, sz = mrecs ? mrecs->size () : 0; i < sz; i++)
+ {
+ MapRecord *mrec = mrecs->fetch (i);
+ SegMem *smem, *sm_lo, *sm_hi;
+ switch (mrec->kind)
+ {
+ case MapRecord::LOAD:
+ smem = new SegMem;
+ smem->base = mrec->base;
+ smem->size = mrec->size;
+ smem->load_time = mrec->ts;
+ smem->unload_time = MAX_TIME;
+ smem->obj = mrec->obj;
+ smem->set_file_offset (mrec->foff);
+ seg_items->append (smem); // add to the master list
+
+ // Check if the new segment overlaps other active segments
+ sm_lo = (SegMem*) maps->locate (smem->base, smem->load_time);
+ if (sm_lo && sm_lo->base + sm_lo->size > smem->base)
+ {
+ // check to see if it is a duplicate record: same address and size, and
+ if ((smem->base == sm_lo->base) && (smem->size == sm_lo->size))
+ {
+ // addresses and sizes match, check name
+ if (strstr (smem->obj->get_name (), sm_lo->obj->get_name ()) != NULL
+ || strstr (sm_lo->obj->get_name (), smem->obj->get_name ()) != NULL)
+ // this is a duplicate; just move on the the next map record
+ continue;
+ fprintf (stderr,
+ GTXT ("*** Warning: Segment `%s' loaded with same address, size as `%s' [0x%llx-0x%llx]\n"),
+ smem->obj->get_name (), sm_lo->obj->get_name (),
+ sm_lo->base, sm_lo->base + sm_lo->size);
+ }
+
+ // Not a duplicate; implicitly unload the old one
+ // Note: implicit unloading causes high <Unknown>
+ // when such overlapping is bogus
+ StringBuilder sb;
+ sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
+ smem->obj->get_name (), smem->base, smem->base + smem->size,
+ sm_lo->obj->get_name (), sm_lo->base, sm_lo->base + sm_lo->size);
+ warnq->append (new Emsg (CMSG_WARN, sb));
+ }
+
+ // now look for other segments with which this might overlap
+ sm_hi = (SegMem*) maps->locate_up (smem->base, smem->load_time);
+ while (sm_hi && sm_hi->base < smem->base + smem->size)
+ {
+
+ // Note: implicit unloading causes high <Unknown> when such overlapping is bogus
+ // maps->remove( sm_hi->base, smem->load_time );
+ StringBuilder sb;
+ sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
+ smem->obj->get_name (), smem->base,
+ smem->base + smem->size, sm_hi->obj->get_name (),
+ sm_hi->base, sm_hi->base + sm_hi->size);
+ warnq->append (new Emsg (CMSG_WARN, sb));
+ sm_hi = (SegMem*) maps->locate_up (sm_hi->base + sm_hi->size,
+ smem->load_time);
+ }
+
+ maps->insert (smem->base, smem->load_time, smem);
+ break;
+ case MapRecord::UNLOAD:
+ smem = (SegMem*) maps->locate (mrec->base, mrec->ts);
+ if (smem && smem->base == mrec->base)
+ {
+ smem->unload_time = mrec->ts;
+ maps->remove (mrec->base, mrec->ts);
+ }
+ break;
+ }
+ }
+ mrecs->destroy ();
+
+ // See if there are comments or warnings for a load object;
+ // if so, queue them to Experiment
+ for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+ {
+ LoadObject *lo = loadObjs->get (i);
+ for (Emsg *m = lo->fetch_warnings (); m; m = m->next)
+ warnq->append (m->get_warn (), m->get_msg ());
+ for (Emsg *m = lo->fetch_comments (); m; m = m->next)
+ commentq->append (m->get_warn (), m->get_msg ());
+ }
+}
+
+void
+Experiment::read_frameinfo_file ()
+{
+ init_cache ();
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading CallStack Data: %s"), base_name);
+ read_data_file ("data." SP_FRINFO_FILE, msg);
+ free (msg);
+ frmpckts->sort (frUidCmp);
+ uidnodes->sort (uidNodeCmp);
+}
+
+void
+Experiment::read_omp_preg ()
+{
+ // Parallel region descriptions
+ DataDescriptor *pregDdscr = getDataDescriptor (DATA_OMP4);
+ if (pregDdscr == NULL)
+ return;
+ DataView *pregData = pregDdscr->createView ();
+ pregData->sort (PROP_CPRID); // omptrace PROP_CPRID
+
+ // OpenMP enter parreg events
+ DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
+ if (dDscr == NULL || dDscr->getSize () == 0)
+ {
+ delete pregData;
+ return;
+ }
+
+ char *idxname = NTXT ("OMP_preg");
+ delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Parallel Region"),
+ NTXT ("CPRID"), NULL, NULL);
+ int idxtype = dbeSession->findIndexSpaceByName (idxname);
+ if (idxtype < 0)
+ {
+ delete pregData;
+ return;
+ }
+ ompavail = true;
+
+ // Pre-create parallel region with id == 0
+ Histable *preg0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
+ preg0->set_name (dbe_strdup (GTXT ("Implicit OpenMP Parallel Region")));
+
+ // Take care of the progress bar
+ char *msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
+ get_basename (expt_name));
+ theApplication->set_progress (0, msg);
+ free (msg);
+ long deltaReport = 1000;
+ long nextReport = 0;
+ long errors_found = 0;
+ Vector<Histable*> pregs;
+
+ long size = dDscr->getSize ();
+ for (long i = 0; i < size; ++i)
+ {
+ if (i == nextReport)
+ {
+ int percent = (int) (i * 100 / size);
+ if (percent > 0)
+ theApplication->set_progress (percent, NULL);
+ nextReport += deltaReport;
+ }
+
+ uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+ hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+ uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); // omptrace CPRID
+ mapPRid->put (thrid, tstamp, cprid);
+
+ pregs.reset ();
+ /*
+ * We will use 2 pointers to make sure there is no loop.
+ * First pointer "curpreg" goes to the next element,
+ * second pointer "curpreg_loop_control" goes to the next->next element.
+ * If these pointers have the same value - there is a loop.
+ */
+ uint64_t curpreg_loop_control = cprid;
+ Datum tval_loop_control;
+ if (curpreg_loop_control != 0)
+ {
+ tval_loop_control.setUINT64 (curpreg_loop_control);
+ long idx = pregData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
+ if (idx < 0)
+ curpreg_loop_control = 0;
+ else
+ curpreg_loop_control = pregData->getLongValue (PROP_PPRID, idx);
+ }
+ for (uint64_t curpreg = cprid; curpreg != 0;)
+ {
+ Histable *val = NULL;
+ Datum tval;
+ tval.setUINT64 (curpreg);
+ long idx = pregData->getIdxByVals (&tval, DataView::REL_EQ);
+ if (idx < 0)
+ break;
+ /*
+ * Check if there is a loop
+ */
+ if (0 != curpreg_loop_control)
+ {
+ if (curpreg == curpreg_loop_control)
+ {
+ errors_found++;
+ if (1 == errors_found)
+ {
+ Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP regions; data may not be correct."));
+ warnq->append (m);
+ }
+ break;
+ }
+ }
+ uint64_t pragmapc = pregData->getLongValue (PROP_PRPC, idx);
+ DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
+ if (instr == NULL)
+ {
+ break;
+ }
+ val = instr;
+ DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
+ if (dbeline->lineno > 0)
+ {
+ if (instr->func->usrfunc)
+ dbeline = dbeline->sourceFile->find_dbeline
+ (instr->func->usrfunc, dbeline->lineno);
+ dbeline->set_flag (DbeLine::OMPPRAGMA);
+ val = dbeline;
+ }
+ val = dbeSession->createIndexObject (idxtype, val);
+ pregs.append (val);
+
+ curpreg = pregData->getLongValue (PROP_PPRID, idx);
+ /*
+ * Update curpreg_loop_control
+ */
+ if (0 != curpreg_loop_control)
+ {
+ tval_loop_control.setUINT64 (curpreg_loop_control);
+ idx = pregData->getIdxByVals
+ (&tval_loop_control, DataView::REL_EQ);
+ if (idx < 0)
+ curpreg_loop_control = 0;
+ else
+ {
+ curpreg_loop_control = pregData->getLongValue
+ (PROP_PPRID, idx);
+ tval_loop_control.setUINT64 (curpreg_loop_control);
+ idx = pregData->getIdxByVals
+ (&tval_loop_control, DataView::REL_EQ);
+ if (idx < 0)
+ curpreg_loop_control = 0;
+ else
+ curpreg_loop_control = pregData->getLongValue
+ (PROP_PPRID, idx);
+ }
+ }
+ }
+ pregs.append (preg0);
+ void *prstack = cstack->add_stack (&pregs);
+ mapPReg->put (thrid, tstamp, prstack);
+ }
+ theApplication->set_progress (0, NTXT (""));
+ delete pregData;
+}
+
+void
+Experiment::read_omp_task ()
+{
+ // Task description
+ DataDescriptor *taskDataDdscr = getDataDescriptor (DATA_OMP5);
+ if (taskDataDdscr == NULL)
+ return;
+
+ //7035272: previously, DataView was global; now it's local...is this OK?
+ DataView *taskData = taskDataDdscr->createView ();
+ taskData->sort (PROP_TSKID); // omptrace PROP_TSKID
+
+ // OpenMP enter task events
+ DataDescriptor *dDscr = getDataDescriptor (DATA_OMP3);
+ if (dDscr == NULL || dDscr->getSize () == 0)
+ {
+ delete taskData;
+ return;
+ }
+
+ char *idxname = NTXT ("OMP_task");
+ // delete a possible error message. Ugly.
+ delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Task"), NTXT ("TSKID"), NULL, NULL);
+ int idxtype = dbeSession->findIndexSpaceByName (idxname);
+ if (idxtype < 0)
+ {
+ delete taskData;
+ return;
+ }
+ ompavail = true;
+
+ // Pre-create task with id == 0
+ Histable *task0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
+ task0->set_name (dbe_strdup (GTXT ("OpenMP Task from Implicit Parallel Region")));
+
+ // Take care of the progress bar
+ char *msg = dbe_sprintf (GTXT ("Processing OpenMP Task Data: %s"), get_basename (expt_name));
+ theApplication->set_progress (0, msg);
+ free (msg);
+ long deltaReport = 1000;
+ long nextReport = 0;
+
+ Vector<Histable*> tasks;
+ long size = dDscr->getSize ();
+ long errors_found = 0;
+ for (long i = 0; i < size; ++i)
+ {
+ if (i == nextReport)
+ {
+ int percent = (int) (i * 100 / size);
+ if (percent > 0)
+ theApplication->set_progress (percent, NULL);
+ nextReport += deltaReport;
+ }
+
+ uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+ hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+ uint64_t tskid = dDscr->getLongValue (PROP_TSKID, i); //omptrace TSKID
+ tasks.reset ();
+ /*
+ * We will use 2 pointers to make sure there is no loop.
+ * First pointer "curtsk" goes to the next element,
+ * second pointer "curtsk_loop_control" goes to the next->next element.
+ * If these pointers have the same value - there is a loop.
+ */
+ uint64_t curtsk_loop_control = tskid;
+ Datum tval_loop_control;
+ if (curtsk_loop_control != 0)
+ {
+ tval_loop_control.setUINT64 (curtsk_loop_control);
+ long idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
+ if (idx < 0)
+ curtsk_loop_control = 0;
+ else
+ curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
+ }
+ for (uint64_t curtsk = tskid; curtsk != 0;)
+ {
+ Histable *val = NULL;
+
+ Datum tval;
+ tval.setUINT64 (curtsk);
+ long idx = taskData->getIdxByVals (&tval, DataView::REL_EQ);
+ if (idx < 0)
+ break;
+ /*
+ * Check if there is a loop
+ */
+ if (0 != curtsk_loop_control)
+ {
+ if (curtsk == curtsk_loop_control)
+ {
+ errors_found++;
+ if (1 == errors_found)
+ {
+ Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP tasks; data may not be correct."));
+ warnq->append (m);
+ }
+ break;
+ }
+ }
+ uint64_t pragmapc = taskData->getLongValue (PROP_PRPC, idx);
+ DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
+ if (instr == NULL)
+ break;
+ val = instr;
+ DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
+ if (dbeline->lineno > 0)
+ {
+ if (instr->func->usrfunc)
+ dbeline = dbeline->sourceFile->find_dbeline
+ (instr->func->usrfunc, dbeline->lineno);
+ dbeline->set_flag (DbeLine::OMPPRAGMA);
+ val = dbeline;
+ }
+ val = dbeSession->createIndexObject (idxtype, val);
+ tasks.append (val);
+
+ curtsk = taskData->getLongValue (PROP_PTSKID, idx);
+ /*
+ * Update curtsk_loop_control
+ */
+ if (0 != curtsk_loop_control)
+ {
+ tval_loop_control.setUINT64 (curtsk_loop_control);
+ idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
+ if (idx < 0)
+ curtsk_loop_control = 0;
+ else
+ {
+ curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
+ tval_loop_control.setUINT64 (curtsk_loop_control);
+ idx = taskData->getIdxByVals (&tval_loop_control,
+ DataView::REL_EQ);
+ if (idx < 0)
+ curtsk_loop_control = 0;
+ else
+ curtsk_loop_control = taskData->getLongValue (PROP_PTSKID,
+ idx);
+ }
+ }
+ }
+ tasks.append (task0);
+ void *tskstack = cstack->add_stack (&tasks);
+ mapTask->put (thrid, tstamp, tskstack);
+ }
+ theApplication->set_progress (0, NTXT (""));
+ delete taskData;
+}
+
+void
+Experiment::read_omp_file ()
+{
+ // DATA_OMP2 table is common between OpenMP 2.5 and 3.0 profiling
+ DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
+ if (dDscr == NULL)
+ return;
+ if (dDscr->getSize () == 0)
+ {
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading OpenMP Data: %s"), base_name);
+ read_data_file (SP_OMPTRACE_FILE, msg);
+ free (msg);
+
+ // OpenMP fork events
+ dDscr = getDataDescriptor (DATA_OMP);
+ long sz = dDscr->getSize ();
+ if (sz > 0)
+ {
+ // progress bar
+ msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
+ base_name);
+ theApplication->set_progress (0, msg);
+ free (msg);
+ long deltaReport = 5000;
+ long nextReport = 0;
+ for (int i = 0; i < sz; ++i)
+ {
+ if (i == nextReport)
+ {
+ int percent = (int) (i * 100 / sz);
+ if (percent > 0)
+ theApplication->set_progress (percent, NULL);
+ nextReport += deltaReport;
+ }
+ uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+ hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+ uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
+ mapPRid->put (thrid, tstamp, cprid);
+ }
+ theApplication->set_progress (0, NTXT (""));
+
+ ompavail = true;
+ openMPdata = dDscr->createView ();
+ openMPdata->sort (PROP_CPRID); // omptrace PROP_CPRID
+
+ // thread enters parreg events
+ dDscr = getDataDescriptor (DATA_OMP2);
+ sz = dDscr->getSize ();
+
+ // progress bar
+ msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
+ base_name);
+ theApplication->set_progress (0, msg);
+ free (msg);
+ deltaReport = 5000;
+ nextReport = 0;
+
+ for (int i = 0; i < sz; ++i)
+ {
+ if (i == nextReport)
+ {
+ int percent = (int) (i * 100 / sz);
+ if (percent > 0)
+ theApplication->set_progress (percent, NULL);
+ nextReport += deltaReport;
+ }
+ uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+ hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+ uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
+ mapPRid->put (thrid, tstamp, cprid);
+ }
+ theApplication->set_progress (0, NTXT (""));
+ }
+ else
+ {
+ read_omp_preg ();
+ read_omp_task ();
+ }
+ if (ompavail && coll_params.profile_mode)
+ {
+ dbeSession->status_ompavail = 1;
+ register_metric (Metric::OMP_WORK);
+ register_metric (Metric::OMP_WAIT);
+ register_metric (Metric::OMP_OVHD);
+ if (coll_params.lms_magic_id == LMS_MAGIC_ID_SOLARIS)
+ register_metric (Metric::OMP_MASTER_THREAD);
+ }
+ }
+}
+
+void
+Experiment::read_ifreq_file ()
+{
+ char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_IFREQ_FILE);
+ FILE *f = fopen (fname, NTXT ("r"));
+ free (fname);
+ if (f == NULL)
+ {
+ ifreqavail = false;
+ return;
+ }
+ ifreqavail = true;
+ ifreqq = new Emsgqueue (NTXT ("ifreqq"));
+
+ while (1)
+ {
+ Emsg *m;
+ char str[MAXPATHLEN];
+ char *e = fgets (str, ((int) sizeof (str)) - 1, f);
+ if (e == NULL)
+ {
+ // end the list from the experiment
+ m = new Emsg (CMSG_COMMENT,
+ GTXT ("============================================================"));
+ ifreqq->append (m);
+ break;
+ }
+ // get the string
+ size_t i = strlen (str);
+ if (i > 0 && str[i - 1] == '\n')
+ // remove trailing nl
+ str[i - 1] = 0;
+ // and append it
+ m = new Emsg (CMSG_COMMENT, str);
+ ifreqq->append (m);
+ }
+ (void) fclose (f);
+}
+
+Experiment *
+Experiment::getBaseFounder ()
+{
+ if (baseFounder)
+ return baseFounder;
+ Experiment *founder = this;
+ Experiment *parent = founder->founder_exp;
+ while (parent)
+ {
+ founder = parent;
+ parent = founder->founder_exp;
+ }
+ baseFounder = founder;
+ return baseFounder;
+}
+
+hrtime_t
+Experiment::getRelativeStartTime ()
+{
+ if (exp_rel_start_time_set)
+ return exp_rel_start_time;
+ Experiment *founder = getBaseFounder ();
+ hrtime_t child_start = this->getStartTime ();
+ hrtime_t founder_start = founder->getStartTime ();
+ exp_rel_start_time = child_start - founder_start;
+ if (child_start == 0 && founder_start)
+ exp_rel_start_time = 0; // when descendents have incomplete log.xml
+ exp_rel_start_time_set = true;
+ return exp_rel_start_time;
+}
+
+DataDescriptor *
+Experiment::get_raw_events (int data_id)
+{
+ DataDescriptor *dDscr;
+ switch (data_id)
+ {
+ case DATA_CLOCK:
+ dDscr = get_profile_events ();
+ break;
+ case DATA_SYNCH:
+ dDscr = get_sync_events ();
+ break;
+ case DATA_HWC:
+ dDscr = get_hwc_events ();
+ break;
+ case DATA_HEAP:
+ dDscr = get_heap_events ();
+ break;
+ case DATA_HEAPSZ:
+ dDscr = get_heapsz_events ();
+ break;
+ case DATA_IOTRACE:
+ dDscr = get_iotrace_events ();
+ break;
+ case DATA_RACE:
+ dDscr = get_race_events ();
+ break;
+ case DATA_DLCK:
+ dDscr = get_deadlock_events ();
+ break;
+ case DATA_SAMPLE:
+ dDscr = get_sample_events ();
+ break;
+ case DATA_GCEVENT:
+ dDscr = get_gc_events ();
+ break;
+ default:
+ dDscr = NULL;
+ break;
+ }
+ return dDscr;
+}
+
+int
+Experiment::base_data_id (int data_id)
+{
+ switch (data_id)
+ {
+ case DATA_HEAPSZ:
+ return DATA_HEAP; // DATA_HEAPSZ DataView is based on DATA_HEAP's DataView
+ default:
+ break;
+ }
+ return data_id;
+}
+
+DataView *
+Experiment::create_derived_data_view (int data_id, DataView *dview)
+{
+ // dview contains filtered packets
+ switch (data_id)
+ {
+ case DATA_HEAPSZ:
+ return create_heapsz_data_view (dview);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+DataDescriptor *
+Experiment::get_profile_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_CLOCK);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () == 0)
+ {
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading Profile Data: %s"), base_name);
+ read_data_file (SP_PROFILE_FILE, msg);
+ free (msg);
+ add_evt_time_to_profile_events (dDscr);
+ resolve_frame_info (dDscr);
+ }
+ else if (!dDscr->isResolveFrInfoDone ())
+ resolve_frame_info (dDscr);
+ return dDscr;
+}
+
+void
+Experiment::add_evt_time_to_profile_events (DataDescriptor *dDscr)
+{
+ if (coll_params.lms_magic_id != LMS_MAGIC_ID_SOLARIS)
+ return;
+
+ DataView *dview = dDscr->createView ();
+ dview->sort (PROP_THRID, PROP_TSTAMP);
+
+ // add PROP_EVT_TIME
+ PropDescr* tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
+ tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
+ tmp_propDscr->vtype = TYPE_INT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ long sz = dview->getSize ();
+ long long ptimer_usec = get_params ()->ptimer_usec;
+ for (long i = 0; i < sz; i++)
+ {
+ int next_sample;
+ int jj;
+ {
+ hrtime_t this_tstamp = dview->getLongValue (PROP_TSTAMP, i);
+ long this_thrid = dview->getLongValue (PROP_THRID, i);
+ for (jj = i + 1; jj < sz; jj++)
+ {
+ hrtime_t tmp_tstamp = dview->getLongValue (PROP_TSTAMP, jj);
+ if (tmp_tstamp != this_tstamp)
+ break;
+ long tmp_thrid = dview->getLongValue (PROP_THRID, jj);
+ if (tmp_thrid != this_thrid)
+ break;
+ }
+ next_sample = jj;
+ }
+
+ long nticks = 0;
+ for (jj = i; jj < next_sample; jj++)
+ nticks += dview->getLongValue (PROP_NTICK, jj);
+ if (nticks <= 1)
+ continue; // no duration
+
+ nticks--;
+ hrtime_t duration = ptimer_usec * 1000LL * nticks; // nanoseconds
+ for (jj = i; jj < next_sample; jj++)
+ dview->setValue (PROP_EVT_TIME, jj, duration);
+ i = jj - 1;
+ }
+ delete dview;
+}
+
+DataDescriptor *
+Experiment::get_sync_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_SYNCH);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () > 0)
+ return dDscr;
+
+ // fetch data
+ {
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading Synctrace Data: %s"), base_name);
+ read_data_file (SP_SYNCTRACE_FILE, msg);
+ free (msg);
+ resolve_frame_info (dDscr);
+ }
+
+ // check for PROP_EVT_TIME
+ PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
+ if (tmp_propDscr)
+ return dDscr;
+
+ // add PROP_EVT_TIME
+ tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
+ tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
+ tmp_propDscr->vtype = TYPE_INT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ long sz = dDscr->getSize ();
+ for (long i = 0; i < sz; i++)
+ {
+ uint64_t event_duration = dDscr->getLongValue (PROP_TSTAMP, i);
+ event_duration -= dDscr->getLongValue (PROP_SRQST, i);
+ dDscr->setValue (PROP_EVT_TIME, i, event_duration);
+ }
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_hwc_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_HWC);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () == 0)
+ {
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading HW Profile Data: %s"), base_name);
+
+ // clear HWC event stats
+ dsevents = 0;
+ dsnoxhwcevents = 0;
+ read_data_file (SP_HWCNTR_FILE, msg);
+ free (msg);
+ resolve_frame_info (dDscr);
+
+ // describe the HW counters in PropDescr
+ PropDescr *prop = dDscr->getProp (PROP_HWCTAG);
+ if (prop)
+ {
+ Collection_params *cparam = get_params ();
+ if (cparam->hw_mode != 0)
+ for (int aux = 0; aux < MAX_HWCOUNT; aux++)
+ if (cparam->hw_aux_name[aux])
+ {
+ const char* cmdname = cparam->hw_aux_name[aux];
+ const char* uname = cparam->hw_username[aux];
+ prop->addState (aux, cmdname, uname);
+ }
+ }
+ else
+ assert (0);
+
+ double dserrrate = 100.0 * ((double) dsnoxhwcevents) / ((double) dsevents);
+ if ((dsevents > 0) && (dserrrate > 10.0))
+ {
+ // warn the user that rate is high
+ StringBuilder sb;
+ if (dbeSession->check_ignore_no_xhwcprof ())
+ sb.sprintf (
+ GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that were accepted\n without verification; data may be incorrect or misleading\n recompile with -xhwcprof and rerecord to get better data\n"),
+ base_name, dserrrate, (long long) dsnoxhwcevents,
+ (long long) dsevents);
+ else
+ sb.sprintf (
+ GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that could not be verified\n recompile with -xhwcprof and rerecord to get better data\n"),
+ base_name, dserrrate, (long long) dsnoxhwcevents,
+ (long long) dsevents);
+ errorq->append (new Emsg (CMSG_WARN, sb));
+ }
+
+ // see if we've scanned the data
+ if (hwc_scanned == 0)
+ {
+ // no, scan the packets to see how many are bogus, or represent lost interrupts
+ long hwc_cnt = 0;
+
+ // loop over the packets, counting the bad ones
+ if (hwc_bogus != 0 || hwc_lost_int != 0)
+ {
+ // hwc counter data had bogus packets and/or packets reflecting lost interrupts
+ double bogus_rate = 100. * (double) hwc_bogus / (double) hwc_cnt;
+ if (bogus_rate > 5.)
+ {
+ StringBuilder sb;
+ sb.sprintf (
+ GTXT ("WARNING: Too many invalid HW counter profile events (%ld/%ld = %3.2f%%) in experiment %d (`%s'); data may be unreliable"),
+ (long) hwc_bogus, (long) hwc_cnt, bogus_rate,
+ (int) userExpId, base_name);
+ Emsg *m = new Emsg (CMSG_WARN, sb);
+ warnq->append (m);
+ }
+ hwc_scanned = 1;
+ }
+ }
+ }
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_iotrace_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_IOTRACE);
+ if (dDscr == NULL)
+ return NULL;
+
+ if (dDscr->getSize () > 0)
+ return dDscr;
+
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading IO Trace Data: %s"), base_name);
+ read_data_file (SP_IOTRACE_FILE, msg);
+ free (msg);
+
+ if (dDscr->getSize () == 0)
+ return dDscr;
+ resolve_frame_info (dDscr);
+
+ // check for PROP_EVT_TIME
+ PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
+ if (tmp_propDscr)
+ return dDscr;
+
+ // add PROP_EVT_TIME
+ tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
+ tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
+ tmp_propDscr->vtype = TYPE_INT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ // add PROP_IOVFD
+ tmp_propDscr = new PropDescr (PROP_IOVFD, "IOVFD");
+ tmp_propDscr->uname = dbe_strdup (GTXT ("Virtual File Descriptor"));
+ tmp_propDscr->vtype = TYPE_INT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ delete fDataMap;
+ fDataMap = new DefaultMap<int64_t, FileData*>;
+
+ delete vFdMap;
+ vFdMap = new DefaultMap<int, int64_t>;
+
+ static int64_t virtualFd = 0;
+
+ FileData *fData;
+ virtualFd += 10;
+ fData = fDataMap->get (VIRTUAL_FD_STDIN);
+ if (fData == NULL)
+ {
+ fData = new FileData (STDIN_FILENAME);
+ fData->setVirtualFd (VIRTUAL_FD_STDIN);
+ fData->id = VIRTUAL_FD_STDIN;
+ fData->setFileDes (STDIN_FD);
+ fDataMap->put (VIRTUAL_FD_STDIN, fData);
+ vFdMap->put (STDIN_FD, VIRTUAL_FD_STDIN);
+ }
+
+ fData = fDataMap->get (VIRTUAL_FD_STDOUT);
+ if (fData == NULL)
+ {
+ fData = new FileData (STDOUT_FILENAME);
+ fData->setVirtualFd (VIRTUAL_FD_STDOUT);
+ fData->id = VIRTUAL_FD_STDOUT;
+ fData->setFileDes (STDOUT_FD);
+ fDataMap->put (VIRTUAL_FD_STDOUT, fData);
+ vFdMap->put (STDOUT_FD, VIRTUAL_FD_STDOUT);
+ }
+
+ fData = fDataMap->get (VIRTUAL_FD_STDERR);
+ if (fData == NULL)
+ {
+ fData = new FileData (STDERR_FILENAME);
+ fData->setVirtualFd (VIRTUAL_FD_STDERR);
+ fData->id = VIRTUAL_FD_STDERR;
+ fData->setFileDes (STDERR_FD);
+ fDataMap->put (VIRTUAL_FD_STDERR, fData);
+ vFdMap->put (STDERR_FD, VIRTUAL_FD_STDERR);
+ }
+
+ fData = fDataMap->get (VIRTUAL_FD_OTHERIO);
+ if (fData == NULL)
+ {
+ fData = new FileData (OTHERIO_FILENAME);
+ fData->setVirtualFd (VIRTUAL_FD_OTHERIO);
+ fData->id = VIRTUAL_FD_OTHERIO;
+ fData->setFileDes (OTHERIO_FD);
+ fDataMap->put (VIRTUAL_FD_OTHERIO, fData);
+ }
+
+ DataView *dview = dDscr->createView ();
+ dview->sort (PROP_TSTAMP);
+ long sz = dview->getSize ();
+ for (long i = 0; i < sz; i++)
+ {
+ hrtime_t event_duration = dview->getLongValue (PROP_TSTAMP, i);
+ hrtime_t event_start = dview->getLongValue (PROP_IORQST, i);
+ if (event_start > 0)
+ event_duration -= event_start;
+ else
+ event_duration = 0;
+ dview->setValue (PROP_EVT_TIME, i, event_duration);
+
+ int32_t fd = -1;
+ int64_t vFd = VIRTUAL_FD_NONE;
+ char *fName = NULL;
+ int32_t origFd = -1;
+ StringBuilder *sb = NULL;
+ FileData *fDataOrig = NULL;
+ FileSystem_type fsType;
+
+ IOTrace_type ioType = (IOTrace_type) dview->getIntValue (PROP_IOTYPE, i);
+ switch (ioType)
+ {
+ case READ_TRACE:
+ case WRITE_TRACE:
+ case READ_TRACE_ERROR:
+ case WRITE_TRACE_ERROR:
+ fd = dview->getIntValue (PROP_IOFD, i);
+ vFd = vFdMap->get (fd);
+ if (vFd == 0 || vFd == VIRTUAL_FD_NONE
+ || (fData = fDataMap->get (vFd)) == NULL)
+ {
+ fData = new FileData (UNKNOWNFD_FILENAME);
+ fData->setVirtualFd (virtualFd);
+ fData->setFsType ("N/A");
+ fData->setFileDes (fd);
+ fDataMap->put (virtualFd, fData);
+ vFdMap->put (fd, virtualFd);
+ vFd = virtualFd;
+ virtualFd++;
+ }
+ dview->setValue (PROP_IOVFD, i, vFd);
+ break;
+ case OPEN_TRACE:
+ fName = NULL;
+ sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
+ if (sb != NULL && sb->length () > 0)
+ fName = sb->toString ();
+ fd = dview->getIntValue (PROP_IOFD, i);
+ origFd = dview->getIntValue (PROP_IOOFD, i);
+ fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
+
+ if (fName != NULL)
+ {
+ fData = new FileData (fName);
+ fDataMap->put (virtualFd, fData);
+ vFdMap->put (fd, virtualFd);
+ fData->setFileDes (fd);
+ fData->setFsType (fsType);
+ fData->setVirtualFd (virtualFd);
+ vFd = virtualFd;
+ virtualFd++;
+ }
+ else if (origFd > 0)
+ {
+ vFd = vFdMap->get (origFd);
+ if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error I/O tracing: (open) cannot get the virtual file descriptor, fd=%d origFd=%d\n",
+ fd, origFd);
+ continue;
+ }
+ else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error IO tracing: (open) cannot get original FileData object, fd=%d origFd=%d\n",
+ fd, origFd);
+ continue;
+ }
+ else
+ {
+ fName = fDataOrig->getFileName ();
+ fData = new FileData (fName);
+ fData->setFileDes (fd);
+ fData->setFsType (fDataOrig->getFsType ());
+ fData->setVirtualFd (virtualFd);
+ fDataMap->put (virtualFd, fData);
+ vFdMap->put (fd, virtualFd);
+ vFd = virtualFd;
+ virtualFd++;
+ }
+ }
+ else if (fd >= 0)
+ {
+ vFd = vFdMap->get (fd);
+ if (vFd == 0 || vFd == VIRTUAL_FD_NONE
+ || (fData = fDataMap->get (vFd)) == NULL)
+ {
+ fData = new FileData (UNKNOWNFD_FILENAME);
+ fData->setVirtualFd (virtualFd);
+ fData->setFsType ("N/A");
+ fData->setFileDes (fd);
+ fDataMap->put (virtualFd, fData);
+ vFdMap->put (fd, virtualFd);
+ vFd = virtualFd;
+ virtualFd++;
+ }
+ }
+ else
+ {
+ Dprintf (DEBUG_IO,
+ NTXT ("*** Error IO tracing: (open) unknown open IO type, fd=%d origFd=%d\n"), fd, origFd);
+ continue;
+ }
+
+ dview->setValue (PROP_IOVFD, i, vFd);
+ break;
+
+ case OPEN_TRACE_ERROR:
+ fName = NULL;
+
+ sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
+ if (sb != NULL && sb->length () > 0)
+ fName = sb->toString ();
+ fd = dview->getIntValue (PROP_IOFD, i);
+ origFd = dview->getIntValue (PROP_IOOFD, i);
+ fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
+
+ if (fName != NULL)
+ {
+ fData = new FileData (fName);
+ fDataMap->put (virtualFd, fData);
+ fData->setFileDes (fd);
+ fData->setFsType (fsType);
+ fData->setVirtualFd (virtualFd);
+ vFd = virtualFd;
+ virtualFd++;
+ }
+ else if (origFd > 0)
+ {
+ vFd = vFdMap->get (origFd);
+ if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error IO tracing: (open error) cannot get the virtual file descriptor, fd=%d origFd=%d\n",
+ fd, origFd);
+ continue;
+ }
+ else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error IO tracing: (open error) cannot get original FileData object, fd=%d origFd=%d\n",
+ fd, origFd);
+ continue;
+ }
+ else
+ {
+ fName = fDataOrig->getFileName ();
+ fData = new FileData (fName);
+ fData->setFileDes (fd);
+ fData->setFsType (fDataOrig->getFsType ());
+ fData->setVirtualFd (virtualFd);
+ fDataMap->put (virtualFd, fData);
+ vFd = virtualFd;
+ virtualFd++;
+ }
+ }
+
+ dview->setValue (PROP_IOVFD, i, vFd);
+ break;
+
+ case CLOSE_TRACE:
+ case CLOSE_TRACE_ERROR:
+ fd = dview->getIntValue (PROP_IOFD, i);
+ vFd = vFdMap->get (fd);
+ if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error IO tracing: (close) cannot get the virtual file descriptor, fd=%d\n",
+ fd);
+ continue;
+ }
+ fData = fDataMap->get (vFd);
+ if (fData == NULL)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error IO tracing: (close) cannot get the FileData object, fd=%d\n",
+ fd);
+ continue;
+ }
+
+ vFdMap->put (fd, VIRTUAL_FD_NONE);
+ dview->setValue (PROP_IOVFD, i, vFd);
+ break;
+
+ case OTHERIO_TRACE:
+ case OTHERIO_TRACE_ERROR:
+ vFd = VIRTUAL_FD_OTHERIO;
+ fData = fDataMap->get (vFd);
+ if (fData == NULL)
+ {
+ Dprintf (DEBUG_IO,
+ "*** Error IO tracing: (other IO) cannot get the FileData object\n");
+ continue;
+ }
+
+ dview->setValue (PROP_IOVFD, i, vFd);
+ break;
+ case IOTRACETYPE_LAST:
+ break;
+ }
+ }
+
+ delete dview;
+
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_heap_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () > 0)
+ return dDscr;
+
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading Heap Trace Data: %s"), base_name);
+ read_data_file (SP_HEAPTRACE_FILE, msg);
+ free (msg);
+
+ if (dDscr->getSize () == 0)
+ return dDscr;
+ resolve_frame_info (dDscr);
+
+ // Match FREE to MALLOC
+ PropDescr *prop = new PropDescr (PROP_HLEAKED, NTXT ("HLEAKED"));
+ prop->uname = dbe_strdup (GTXT ("Bytes Leaked"));
+ prop->vtype = TYPE_UINT64;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
+ prop->uname = dbe_strdup (GTXT ("Heap Memory Usage"));
+ prop->vtype = TYPE_UINT64;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_HFREED, NTXT ("HFREED"));
+ prop->uname = dbe_strdup (GTXT ("Bytes Freed"));
+ prop->vtype = TYPE_UINT64;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"));
+ prop->uname = dbe_strdup (GTXT ("Net Bytes Allocated"));
+ prop->vtype = TYPE_INT64;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"));
+ prop->uname = dbe_strdup (GTXT ("Net Bytes Leaked"));
+ prop->vtype = TYPE_UINT64;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"));
+ prop->vtype = TYPE_INT64;
+ prop->flags = DDFLAG_NOSHOW;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"));
+ prop->vtype = TYPE_UINT64;
+ prop->flags = DDFLAG_NOSHOW;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"));
+ prop->vtype = TYPE_OBJ;
+ prop->flags = DDFLAG_NOSHOW;
+ dDscr->addProperty (prop);
+
+ prop = new PropDescr (PROP_TSTAMP2, NTXT ("TSTAMP2"));
+ prop->uname = dbe_strdup (GTXT ("End Timestamp (nanoseconds)"));
+ prop->vtype = TYPE_UINT64;
+ prop->flags = DDFLAG_NOSHOW;
+ dDscr->addProperty (prop);
+
+ DataView *dview = dDscr->createView ();
+ dview->sort (PROP_TSTAMP);
+
+ // Keep track of memory usage
+ Size memoryUsage = 0;
+
+ HeapMap *heapmap = new HeapMap ();
+ long sz = dview->getSize ();
+ for (long i = 0; i < sz; i++)
+ {
+
+ Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
+ Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
+ Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
+ Size hsize = dview->getULongValue (PROP_HSIZE, i);
+ hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
+
+ switch (mtype)
+ {
+ case MALLOC_TRACE:
+ dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
+ if (vaddr)
+ {
+ dview->setValue (PROP_HLEAKED, i, hsize);
+ heapmap->allocate (vaddr, i + 1);
+
+ // Increase heap size
+ memoryUsage += hsize;
+ dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+ }
+ break;
+
+ case FREE_TRACE:
+ if (vaddr)
+ {
+ long idx = heapmap->deallocate (vaddr) - 1;
+ if (idx >= 0)
+ {
+ // Decrease heap size
+ Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
+ memoryUsage -= leaked;
+ dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+
+ Size alloc = dview->getLongValue (PROP_HSIZE, idx);
+ // update allocation
+ dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
+ dview->setValue (PROP_TSTAMP2, idx, tstamp);
+ dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
+ // update this event
+ dview->setValue (PROP_HFREED, i, alloc);
+ }
+ }
+ break;
+
+ case REALLOC_TRACE:
+ dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
+ if (ovaddr)
+ {
+ long idx = heapmap->deallocate (ovaddr) - 1;
+ if (idx >= 0)
+ {
+ // Decrease heap size
+ Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
+ memoryUsage -= leaked;
+ dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+
+ Size alloc = dview->getLongValue (PROP_HSIZE, idx);
+ // update allocation
+ dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
+ dview->setValue (PROP_TSTAMP2, idx, tstamp);
+ dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
+ // update this event
+ dview->setValue (PROP_HFREED, i, alloc);
+ }
+ }
+ if (vaddr)
+ {
+ dview->setValue (PROP_HLEAKED, i, hsize);
+ heapmap->allocate (vaddr, i + 1);
+
+ // Increase heap size
+ memoryUsage += hsize;
+ dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+ }
+ break;
+ case MMAP_TRACE:
+ case MUNMAP_TRACE:
+ // Adjust the size to be multiple of page_size
+ //hsize = (( hsize - 1 ) / page_size + 1 ) * page_size;
+ if (vaddr)
+ {
+ UnmapChunk *list;
+ if (mtype == MMAP_TRACE)
+ {
+ dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
+ dview->setValue (PROP_HLEAKED, i, hsize);
+ list = heapmap->mmap (vaddr, hsize, i);
+
+ // Increase heap size
+ memoryUsage += hsize;
+ dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+ }
+ else
+ { // MUNMAP_TRACE
+ list = heapmap->munmap (vaddr, hsize);
+
+ // Set allocation size to zero
+ // Note: We're currently reusing PROP_HSIZE to mean allocation size
+ // If we ever need to save the original HSIZE, we'll need to
+ // create a new PROP_* to represent event allocation size
+ //
+ // For now, tuck the original size away as HOVADDR
+ dview->setValue (PROP_HOVADDR, i, (uint64_t) hsize);
+ dview->setValue (PROP_HSIZE, i, (uint64_t) 0);
+ }
+ Size total_freed = 0;
+ while (list)
+ {
+ long idx = list->val;
+ total_freed += list->size;
+ Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
+
+ // Decrease heap size
+ memoryUsage -= list->size;
+ dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+
+ Size leak_update = leaked - list->size;
+ // update allocation
+ dview->setValue (PROP_HLEAKED, idx, leak_update);
+ // update allocation's list of frees
+ {
+ UnmapChunk *copy = new UnmapChunk;
+ heapUnmapEvents->append (copy);
+ copy->val = dview->getIdByIdx (i);
+ copy->size = list->size;
+ copy->next = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, idx);
+ dview->setObjValue (PROP_VOIDP_OBJ, idx, copy);
+ }
+ if (leak_update <= 0)
+ if (leak_update == 0)
+ dview->setValue (PROP_TSTAMP2, idx, tstamp);
+ UnmapChunk *t = list;
+ list = list->next;
+ delete t;
+ }
+ // update this event
+ if (total_freed)
+ // only need to write value if it is non-zero
+ dview->setValue (PROP_HFREED, i, total_freed);
+ }
+ break;
+ // ignoring HEAPTYPE_LAST, which will never be recorded
+ case HEAPTYPE_LAST:
+ break;
+ }
+ }
+ delete heapmap;
+ delete dview;
+
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_heapsz_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_HEAPSZ);
+ if (dDscr)
+ return dDscr;
+ dDscr = get_heap_events (); // derived from DATA_HEAP
+ if (dDscr == NULL)
+ return NULL;
+ dDscr = newDataDescriptor (DATA_HEAPSZ, 0, dDscr);
+ return dDscr;
+}
+
+static void
+update_heapsz_packet (std::set<long> &pkt_id_set, DataView *dview,
+ long alloc_pkt_id, int64_t net_alloc, uint64_t leaks)
+{
+ // pkt_id_set: set is updated to include packet
+ // alloc_pkt_id: data descriptor id (NOT dview idx)
+ // net_alloc: adjustment to net allocation for this packet (note: signed value)
+ // leaks: leak bytes to attribute to alloc_pkt_id
+ std::pair < std::set<long>::iterator, bool> ret;
+ ret = pkt_id_set.insert (alloc_pkt_id); // add to set
+ bool new_to_set = ret.second; // was not in set
+ if (!new_to_set)
+ {
+ // Has been seen before, update values
+ net_alloc += dview->getDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id);
+ if (leaks)
+ {
+ uint64_t old = dview->getDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id);
+ if (old != 0)
+ leaks = old;
+ }
+ }
+ dview->setDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id, net_alloc);
+ dview->setDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id, leaks);
+}
+
+DataView *
+Experiment::create_heapsz_data_view (DataView *heap_dview)
+{
+ // heap_dview has DATA_HEAP _filtered_ packets.
+ // This creates, populates, and returns DATA_HEAPSZ DataView
+ DataDescriptor *dDscr = get_heapsz_events ();
+ if (dDscr == NULL)
+ return NULL;
+ std::set<long> pkt_id_set;
+ DataView *dview = heap_dview;
+ long sz = dview->getSize ();
+ for (long i = 0; i < sz; i++)
+ {
+ int64_t hsize = (int64_t) dview->getULongValue (PROP_HSIZE, i);
+ uint64_t leaks = dview->getULongValue (PROP_HLEAKED, i);
+ long alloc_pkt_id = dview->getIdByIdx (i);
+ update_heapsz_packet (pkt_id_set, dview, alloc_pkt_id, hsize, leaks);
+
+ // linked free
+ UnmapChunk *mmap_frees = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, i); // mmap metadata
+ if (mmap_frees)
+ {
+ // mmap: all frees associated with this packet
+ while (mmap_frees)
+ {
+ long free_pkt_id = mmap_frees->val;
+ int64_t free_sz = mmap_frees->size;
+ update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -free_sz, 0);
+ mmap_frees = mmap_frees->next;
+ }
+ }
+ else
+ {
+ // malloc: check for associated free
+ long free_pkt_id = dview->getLongValue (PROP_DDSCR_LNK, i) - 1;
+ if (free_pkt_id >= 0)
+ update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -hsize, 0);
+ }
+ }
+
+ // create a new DataView based on the filtered-in and associated free events
+ std::set<long>::iterator it;
+ DataView *heapsz_dview = dDscr->createExtManagedView ();
+ for (it = pkt_id_set.begin (); it != pkt_id_set.end (); ++it)
+ {
+ long ddscr_pkt_id = *it;
+ heapsz_dview->appendDataDescriptorId (ddscr_pkt_id);
+ }
+ compute_heapsz_data_view (heapsz_dview);
+ return heapsz_dview;
+}
+
+void
+Experiment::compute_heapsz_data_view (DataView *heapsz_dview)
+{
+ DataView *dview = heapsz_dview;
+
+ // Keep track of memory usage
+ int64_t currentAllocs = 0;
+ Size currentLeaks = 0;
+ dview->sort (PROP_TSTAMP);
+ long sz = dview->getSize ();
+ for (long i = 0; i < sz; i++)
+ {
+ int64_t net_alloc = dview->getLongValue (PROP_HCUR_NET_ALLOC, i);
+ currentAllocs += net_alloc;
+ dview->setValue (PROP_HCUR_ALLOCS, i, currentAllocs);
+
+ Size leaks = dview->getULongValue (PROP_HCUR_LEAKS, i);
+ currentLeaks += leaks;
+ dview->setValue (PROP_HCUR_LEAKS, i, currentLeaks);
+ }
+}
+
+void
+Experiment::DBG_memuse (Sample * s)
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
+ if (dDscr == NULL || dDscr->getSize () == 0)
+ return;
+
+ DataView *dview = dDscr->createView ();
+ dview->sort (PROP_TSTAMP);
+ hrtime_t ts1 = s->get_start_time ();
+ hrtime_t ts2 = s->get_end_time ();
+
+ HeapMap *heapmap = new HeapMap ();
+ long sz = dview->getSize ();
+ Size maxSize = 0;
+ Size curSize = 0;
+ hrtime_t maxTime = 0;
+ for (long i = 0; i < sz; i++)
+ {
+ hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
+ if (tstamp < ts1)
+ continue;
+ if (tstamp >= ts2)
+ break;
+
+ Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
+ Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
+ Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
+ switch (mtype)
+ {
+ case REALLOC_TRACE:
+ break;
+ case MALLOC_TRACE:
+ ovaddr = 0;
+ break;
+ case FREE_TRACE:
+ ovaddr = vaddr;
+ vaddr = 0;
+ break;
+ default:
+ vaddr = 0;
+ ovaddr = 0;
+ break;
+ }
+ if (ovaddr)
+ {
+ long idx = heapmap->deallocate (ovaddr) - 1;
+ if (idx >= 0)
+ curSize -= dview->getULongValue (PROP_HSIZE, idx);
+ }
+ if (vaddr)
+ {
+ heapmap->allocate (vaddr, i + 1);
+ curSize += dview->getULongValue (PROP_HSIZE, i);
+ if (curSize > maxSize)
+ {
+ maxSize = curSize;
+ maxTime = tstamp;
+ }
+ }
+ }
+ printf ("SAMPLE=%s (id=%d) MEMUSE=%lld TSTAMP=%lld\n", s->get_start_label (),
+ s->get_number (), maxSize, maxTime - getStartTime ());
+ delete dview;
+ delete heapmap;
+}
+
+void
+Experiment::DBG_memuse (const char *sname)
+{
+ for (int i = 0; i < samples->size (); ++i)
+ {
+ Sample *sample = samples->fetch (i);
+ if (streq (sname, sample->get_start_label ()))
+ {
+ DBG_memuse (sample);
+ break;
+ }
+ }
+}
+
+DataDescriptor *
+Experiment::get_race_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_RACE);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () == 0)
+ {
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading Race Data: %s"), base_name);
+ read_data_file (SP_RACETRACE_FILE, msg);
+ free (msg);
+ resolve_frame_info (dDscr);
+ }
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_deadlock_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_DLCK);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () == 0)
+ {
+ char *base_name = get_basename (expt_name);
+ char *msg = dbe_sprintf (GTXT ("Loading Deadlocks Data: %s"), base_name);
+ read_data_file (SP_DEADLOCK_FILE, msg);
+ free (msg);
+ resolve_frame_info (dDscr);
+ }
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_sample_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_SAMPLE);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () > 0)
+ return dDscr;
+
+ // read_overview_file(); //YXXX do this here at some point instead of:
+ PropDescr *tmp_propDscr;
+ tmp_propDscr = new PropDescr (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
+ tmp_propDscr->uname = NULL;
+ tmp_propDscr->vtype = TYPE_OBJ;
+ dDscr->addProperty (tmp_propDscr);
+
+ tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
+ tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
+ tmp_propDscr->vtype = TYPE_UINT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ tmp_propDscr = new PropDescr (PROP_SAMPLE, NTXT ("SAMPLE"));
+ tmp_propDscr->uname = dbe_strdup ("Sample number");
+ tmp_propDscr->vtype = TYPE_UINT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+ tmp_propDscr->uname = dbe_strdup ("Event duration");
+ tmp_propDscr->vtype = TYPE_UINT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ long ssize = samples->size ();
+ for (long ii = 0; ii < ssize; ii++)
+ {
+ Sample * sample = samples->fetch (ii);
+ long recn = dDscr->addRecord ();
+ hrtime_t sduration = sample->get_end_time () - sample->get_start_time ();
+ dDscr->setObjValue (PROP_SMPLOBJ, recn, sample);
+ dDscr->setValue (PROP_SAMPLE, recn, sample->get_number ());
+ dDscr->setValue (PROP_TSTAMP, recn, sample->get_end_time ());
+ dDscr->setValue (PROP_EVT_TIME, recn, sduration);
+ }
+ return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_gc_events ()
+{
+ DataDescriptor *dDscr = getDataDescriptor (DATA_GCEVENT);
+ if (dDscr == NULL)
+ return NULL;
+ if (dDscr->getSize () > 0)
+ return dDscr;
+
+ // read_overview_file(); //YXXX do this here at some point instead of:
+ PropDescr *tmp_propDscr;
+ tmp_propDscr = new PropDescr (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
+ tmp_propDscr->uname = NULL;
+ tmp_propDscr->vtype = TYPE_OBJ;
+ dDscr->addProperty (tmp_propDscr);
+
+ tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
+ tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
+ tmp_propDscr->vtype = TYPE_UINT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ tmp_propDscr = new PropDescr (PROP_GCEVENT, NTXT ("GCEVENT"));
+ tmp_propDscr->uname = dbe_strdup ("GCEvent number");
+ tmp_propDscr->vtype = TYPE_UINT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+ tmp_propDscr->uname = dbe_strdup ("Event duration");
+ tmp_propDscr->vtype = TYPE_UINT64;
+ dDscr->addProperty (tmp_propDscr);
+
+ long ssize = gcevents->size ();
+ for (long ii = 0; ii < ssize; ii++)
+ {
+ GCEvent * gcevent = gcevents->fetch (ii);
+ long recn = dDscr->addRecord ();
+ hrtime_t sduration = gcevent->end - gcevent->start;
+ dDscr->setObjValue (PROP_GCEVENTOBJ, recn, gcevent);
+ dDscr->setValue (PROP_GCEVENT, recn, gcevent->id);
+ dDscr->setValue (PROP_TSTAMP, recn, gcevent->end);
+ dDscr->setValue (PROP_EVT_TIME, recn, sduration);
+ }
+ return dDscr;
+}
+
+void
+Experiment::update_last_event (hrtime_t ts/*wall_ts*/)
+{
+ if (last_event == ZERO_TIME)
+ {
+ // not yet initialized
+ last_event = ts;
+ }
+ if (last_event - exp_start_time < ts - exp_start_time)
+ // compare deltas to avoid hrtime_t wrap
+ last_event = ts;
+}
+
+void
+Experiment::write_header ()
+{
+ StringBuilder sb;
+
+ // write commentary to the experiment, describing the parameters
+ if (dbeSession->ipc_mode || dbeSession->rdt_mode)
+ {
+ // In GUI: print start time at the beginning
+ char *start_time = ctime (&start_sec);
+ if (start_time != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT ("Experiment started %s"), start_time);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ }
+ // write message with target arglist
+ if (uarglist != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT ("\nTarget command (%s): '%s'"),
+ (wsize == W32 ? "32-bit" : "64-bit"), uarglist);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ sb.setLength (0);
+ sb.sprintf (GTXT ("Process pid %d, ppid %d, pgrp %d, sid %d"),
+ pid, ppid, pgrp, sid);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+
+ // add comment for user name, if set
+ if (username != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT ("User: `%s'"), username);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // add comment for current working directory
+ if (ucwd != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT ("Current working directory: %s"), ucwd);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // add comment for collector version string
+ if (cversion != NULL)
+ {
+ char *wstring;
+ switch (wsize)
+ {
+ case Wnone:
+ wstring = NTXT ("?");
+ break;
+ case W32:
+ wstring = GTXT ("32-bit");
+ break;
+ case W64:
+ wstring = GTXT ("64-bit");
+ break;
+ default:
+ wstring = NTXT ("??");
+ break;
+ }
+ sb.setLength (0);
+ sb.sprintf (GTXT ("Collector version: `%s'; experiment version %d.%d (%s)"),
+ cversion, exp_maj_version, exp_min_version, wstring);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // add comment for driver version string (er_kernel)
+ if (dversion != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT ("Kernel driver version: `%s'"), dversion);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ if (jversion != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT ("JVM version: `%s'"), jversion);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // add comment for hostname, parameters
+ if (hostname == NULL)
+ hostname = dbe_strdup (GTXT ("unknown"));
+ if (os_version == NULL)
+ os_version = dbe_strdup (GTXT ("unknown"));
+ if (architecture == NULL)
+ architecture = dbe_strdup (GTXT ("unknown"));
+ sb.setLength (0);
+ sb.sprintf (GTXT ("Host `%s', OS `%s', page size %d, architecture `%s'"),
+ hostname, os_version, page_size, architecture);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+
+ sb.setLength (0);
+ if (maxclock != minclock)
+ {
+ clock = maxclock;
+ sb.sprintf (
+ GTXT (" %d CPUs, with clocks ranging from %d to %d MHz.; max of %d MHz. assumed"),
+ ncpus, minclock, maxclock, clock);
+ }
+ else
+ sb.sprintf (GTXT (" %d CPU%s, clock speed %d MHz."),
+ ncpus, (ncpus == 1 ? NTXT ("") : "s"), clock);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+
+ // add comment for machine memory size
+ if (page_size > 0 && npages > 0)
+ {
+ long long memsize = ((long long) npages * page_size) / (1024 * 1024);
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Memory: %d pages @ %d = %lld MB."),
+ npages, page_size, memsize);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // add comment for machine memory size
+ if (machinemodel != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Machine model: %s"), machinemodel);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+
+ // add comment for start time
+ char *p = ctime (&start_sec);
+ sb.setLength (0);
+ if (p != NULL)
+ sb.sprintf (GTXT ("Experiment started %s"), p);
+ else
+ sb.sprintf (GTXT ("\nExperiment start not recorded"));
+ write_coll_params ();
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ commentq->appendqueue (runlogq);
+ runlogq->mark_clear ();
+}
+
+void
+Experiment::write_coll_params ()
+{
+ StringBuilder sb;
+
+ // now write the various collection parameters as comments
+ sb.setLength (0);
+ sb.append (GTXT ("Data collection parameters:"));
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ if (coll_params.profile_mode == 1)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Clock-profiling, interval = %d microsecs."),
+ (int) (coll_params.ptimer_usec));
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.sync_mode == 1)
+ {
+ sb.setLength (0);
+ char *scope_str = NTXT ("");
+ switch (coll_params.sync_scope)
+ {
+ case 0:
+ scope_str = GTXT ("Native- and Java-APIs");
+ break;
+ case SYNCSCOPE_JAVA:
+ scope_str = GTXT ("JAVA-APIs");
+ break;
+ case SYNCSCOPE_NATIVE:
+ scope_str = GTXT ("Native-APIs");
+ break;
+ case SYNCSCOPE_JAVA | SYNCSCOPE_NATIVE:
+ scope_str = GTXT ("Native- and Java-APIs");
+ break;
+ }
+ if (coll_params.sync_threshold < 0)
+ sb.sprintf (GTXT (" Synchronization tracing, threshold = %d microsecs. (calibrated); %s"),
+ -coll_params.sync_threshold, scope_str);
+ else
+ sb.sprintf (GTXT (" Synchronization tracing, threshold = %d microsecs.; %s"),
+ coll_params.sync_threshold, scope_str);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.heap_mode == 1)
+ {
+ sb.setLength (0);
+ sb.append (GTXT (" Heap tracing"));
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.io_mode == 1)
+ {
+ sb.setLength (0);
+ sb.append (GTXT (" IO tracing"));
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.race_mode == 1)
+ {
+ sb.setLength (0);
+ char *race_stack_name;
+ switch (coll_params.race_stack)
+ {
+ case 0:
+ race_stack_name = GTXT ("dual-stack");
+ break;
+ case 1:
+ race_stack_name = GTXT ("single-stack");
+ break;
+ case 2:
+ race_stack_name = GTXT ("leaf");
+ break;
+ default:
+ abort ();
+ }
+ sb.sprintf (GTXT (" Datarace detection, %s"), race_stack_name);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.deadlock_mode == 1)
+ {
+ sb.setLength (0);
+ sb.append (GTXT (" Deadlock detection"));
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.hw_mode == 1)
+ {
+ sb.setLength (0);
+ if (hwc_default == true)
+ sb.append (GTXT (" HW counter-profiling (default); counters:"));
+ else
+ sb.append (GTXT (" HW counter-profiling; counters:"));
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ for (int i = 0; i < MAX_HWCOUNT; i++)
+ {
+ if (!coll_params.hw_aux_name[i])
+ continue;
+ sb.setLength (0);
+ sb.sprintf (GTXT (" %s, tag %d, interval %d, memop %d"),
+ coll_params.hw_aux_name[i], i,
+ coll_params.hw_interval[i], coll_params.hw_tpc[i]);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ }
+ if (coll_params.sample_periodic == 1)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Periodic sampling, %d secs."),
+ coll_params.sample_timer);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.limit != 0)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Experiment size limit, %d"),
+ coll_params.limit);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.linetrace != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Follow descendant processes from: %s"),
+ coll_params.linetrace);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.pause_sig != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Pause signal %s"), coll_params.pause_sig);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.sample_sig != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Sample signal %s"), coll_params.sample_sig);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.start_delay != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Data collection delay start %s seconds"), coll_params.start_delay);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ if (coll_params.terminate != NULL)
+ {
+ sb.setLength (0);
+ sb.sprintf (GTXT (" Data collection termination after %s seconds"), coll_params.terminate);
+ commentq->append (new Emsg (CMSG_COMMENT, sb));
+ }
+ // add a blank line after data description
+ commentq->append (new Emsg (CMSG_COMMENT, NTXT ("")));
+}
+
+
+/*
+ * Raw packet processing
+ */
+static int
+check_mstate (char *ptr, PacketDescriptor *pDscr, int arg)
+{
+ switch (arg)
+ {
+ case PROP_UCPU:
+ case PROP_SCPU:
+ case PROP_TRAP:
+ case PROP_TFLT:
+ case PROP_DFLT:
+ case PROP_KFLT:
+ case PROP_ULCK:
+ case PROP_TSLP:
+ case PROP_WCPU:
+ case PROP_TSTP:
+ break;
+ default:
+ return 0;
+ }
+ Vector<FieldDescr*> *fields = pDscr->getFields ();
+ for (int i = 0, sz = fields->size (); i < sz; i++)
+ {
+ FieldDescr *fDscr = fields->fetch (i);
+ if (fDscr->propID == arg)
+ return *((int*) (ptr + fDscr->offset));
+ }
+ return 0;
+}
+
+#define PACKET_ALIGNMENT 4
+
+uint64_t
+Experiment::readPacket (Data_window *dwin, Data_window::Span *span)
+{
+ Common_packet *rcp = (Common_packet *) dwin->bind (span,
+ sizeof (CommonHead_packet));
+ uint16_t v16;
+ uint64_t size = 0;
+ if (rcp)
+ {
+ if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
+ {
+ invalid_packet++;
+ size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
+ return size;
+ }
+ v16 = (uint16_t) rcp->tsize;
+ size = dwin->decode (v16);
+ if (size == 0)
+ {
+ size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
+ return size;
+ }
+ rcp = (Common_packet *) dwin->bind (span, size);
+ }
+ if (rcp == NULL)
+ return 0;
+
+ if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
+ {
+ invalid_packet++;
+ size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
+ return size;
+ }
+ v16 = (uint16_t) rcp->type;
+ uint32_t rcptype = dwin->decode (v16);
+ if (rcptype == EMPTY_PCKT)
+ return size;
+ if (rcptype == FRAME_PCKT)
+ {
+ RawFramePacket *fp = new RawFramePacket;
+ fp->uid = dwin->decode (((Frame_packet*) rcp)->uid);
+ fp->uidn = NULL;
+ fp->uidj = NULL;
+ fp->omp_uid = NULL;
+ fp->omp_state = 0;
+ char *ptr = (char*) rcp + dwin->decode (((Frame_packet*) rcp)->hsize);
+ if ((((long) ptr) % PACKET_ALIGNMENT) != 0)
+ {
+ invalid_packet++;
+ delete fp;
+ return size;
+ }
+ v16 = (uint16_t) ((Frame_packet*) rcp)->tsize;
+ char *end = (char*) rcp + dwin->decode (v16);
+ for (; ptr < end;)
+ {
+ Common_info *cinfo = (Common_info*) ptr;
+ uint32_t hsize = dwin->decode (cinfo->hsize);
+ if (hsize == 0 || ptr + hsize > end)
+ break;
+ int kind = dwin->decode (cinfo->kind);
+ bool compressed = false;
+ if (kind & COMPRESSED_INFO)
+ {
+ compressed = true;
+ kind &= ~COMPRESSED_INFO;
+ }
+ switch (kind)
+ {
+ case STACK_INFO:
+ {
+ char *stack = ptr + sizeof (Stack_info);
+ size_t stack_size = hsize - sizeof (Stack_info);
+ uint64_t uidn = dwin->decode (((Stack_info*) cinfo)->uid);
+ if (stack_size <= 0)
+ {
+ fp->uidn = get_uid_node (uidn);
+ break;
+ }
+ uint64_t link_uid = (uint64_t) 0;
+ if (compressed)
+ {
+ stack_size -= sizeof (uint64_t);
+ unsigned char *s = (unsigned char*) (stack + stack_size);
+ int shift = 0;
+ for (size_t i = 0; i<sizeof (link_uid); i++)
+ {
+ link_uid |= (uint64_t) * s++ << shift;
+ shift += 8;
+ }
+ }
+ if (wsize == W32)
+ fp->uidn = add_uid (dwin, uidn,
+ (int) (stack_size / sizeof (uint32_t)),
+ (uint32_t*) stack, link_uid);
+ else
+ fp->uidn = add_uid (dwin, uidn,
+ (int) (stack_size / sizeof (uint64_t)),
+ (uint64_t*) stack, link_uid);
+ break;
+ }
+ case JAVA_INFO:
+ {
+ char *stack = ptr + sizeof (Java_info);
+ size_t stack_size = hsize - sizeof (Java_info);
+ uint64_t uidj = dwin->decode (((Java_info*) cinfo)->uid);
+ if (stack_size <= 0)
+ {
+ fp->uidj = get_uid_node (uidj);
+ break;
+ }
+
+ uint64_t link_uid = (uint64_t) 0;
+ if (compressed)
+ {
+ stack_size -= sizeof (uint64_t);
+ unsigned char *s = (unsigned char*) (stack + stack_size);
+ int shift = 0;
+ for (size_t i = 0; i<sizeof (link_uid); i++)
+ {
+ link_uid |= (uint64_t) * s++ << shift;
+ shift += 8;
+ }
+ }
+ if (wsize == W32)
+ fp->uidj = add_uid (dwin, uidj,
+ (int) (stack_size / sizeof (uint32_t)),
+ (uint32_t*) stack, link_uid);
+ else
+ {
+ // bug 6909545: garbage in 64-bit JAVA_INFO
+ char *nstack = (char*) malloc (stack_size);
+ char *dst = nstack;
+ char *srcmax = stack + stack_size - sizeof (uint64_t);
+ for (char *src = stack; src <= srcmax;)
+ {
+ int64_t val = dwin->decode (*(int32_t*) src);
+ *(uint64_t*) dst = dwin->decode (val);
+ src += sizeof (uint64_t);
+ dst += sizeof (uint64_t);
+ if (src > srcmax)
+ {
+ fprintf (stderr, "er_print: Experiment::readPacket: Error in data: src=%llx greater than %llx\n",
+ (long long) src, (long long) srcmax);
+ break;
+ }
+ *(uint64_t*) dst = *(uint64_t*) src;
+ src += sizeof (uint64_t);
+ dst += sizeof (uint64_t);
+ }
+ fp->uidj = add_uid (dwin, uidj,
+ (int) (stack_size / sizeof (uint64_t)),
+ (uint64_t*) nstack, link_uid);
+ free (nstack);
+ }
+ break;
+ }
+ case OMP_INFO:
+ fp->omp_state = dwin->decode (((OMP_info*) ptr)->omp_state);
+ break;
+ case OMP2_INFO:
+ {
+ uint64_t omp_uid = dwin->decode (((OMP2_info*) ptr)->uid);
+ fp->omp_uid = get_uid_node (omp_uid);
+ fp->omp_state = dwin->decode (((OMP2_info*) ptr)->omp_state);
+ break;
+ }
+ default:
+ break;
+ }
+ ptr += hsize;
+ }
+ frmpckts->append (fp);
+ return size;
+ }
+ else if (rcptype == UID_PCKT)
+ {
+ Uid_packet *uidp = (Uid_packet*) rcp;
+ uint64_t uid = dwin->decode (uidp->uid);
+ char *arr_bytes = (char*) (uidp + 1);
+ v16 = (uint16_t) rcp->tsize;
+ size_t arr_length = dwin->decode (v16) - sizeof (Uid_packet);
+ if (arr_length <= 0)
+ return size;
+ uint64_t link_uid = (uint64_t) 0;
+ if (dwin->decode (uidp->flags) & COMPRESSED_INFO)
+ {
+ arr_length -= sizeof (uint64_t);
+ unsigned char *s = (unsigned char*) (arr_bytes + arr_length);
+ int shift = 0;
+ for (size_t i = 0; i<sizeof (link_uid); i++)
+ {
+ link_uid |= (uint64_t) * s++ << shift;
+ shift += 8;
+ }
+ }
+ if (wsize == W32)
+ add_uid (dwin, uid, (int) (arr_length / sizeof (uint32_t)),
+ (uint32_t*) arr_bytes, link_uid);
+ else
+ add_uid (dwin, uid, (int) (arr_length / sizeof (uint64_t)),
+ (uint64_t*) arr_bytes, link_uid);
+ return size;
+ }
+
+ PacketDescriptor *pcktDescr = getPacketDescriptor (rcptype);
+ if (pcktDescr == NULL)
+ return size;
+ DataDescriptor *dataDescr = pcktDescr->getDataDescriptor ();
+ if (dataDescr == NULL)
+ return size;
+
+ /* omazur: TBR START -- old experiment */
+ if (rcptype == PROF_PCKT)
+ {
+ // For backward compatibility with older SS12 experiments
+ int numstates = get_params ()->lms_magic_id; // ugly, for old experiments
+ if (numstates > LMS_NUM_SOLARIS_MSTATES)
+ numstates = LMS_NUM_SOLARIS_MSTATES;
+ for (int i = 0; i < numstates; i++)
+ if (check_mstate ((char*) rcp, pcktDescr, PROP_UCPU + i))
+ readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, PROP_UCPU + i,
+ size);
+ }
+ else
+ readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, 0, size);
+ return size;
+}
+
+void
+Experiment::readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
+ DataDescriptor *dDscr, int arg, uint64_t pktsz)
+{
+ union Value
+ {
+ uint32_t val32;
+ uint64_t val64;
+ } *v;
+
+ long recn = dDscr->addRecord ();
+ Vector<FieldDescr*> *fields = pDscr->getFields ();
+ int sz = fields->size ();
+ for (int i = 0; i < sz; i++)
+ {
+ FieldDescr *field = fields->fetch (i);
+ v = (Value*) (ptr + field->offset);
+ if (field->propID == arg)
+ {
+ dDscr->setValue (PROP_NTICK, recn, dwin->decode (v->val32));
+ dDscr->setValue (PROP_MSTATE, recn, (uint32_t) (field->propID - PROP_UCPU));
+ }
+ if (field->propID == PROP_THRID || field->propID == PROP_LWPID
+ || field->propID == PROP_CPUID)
+ {
+ uint64_t tmp64 = 0;
+ switch (field->vtype)
+ {
+ case TYPE_INT32:
+ case TYPE_UINT32:
+ tmp64 = dwin->decode (v->val32);
+ break;
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ tmp64 = dwin->decode (v->val64);
+ break;
+ case TYPE_STRING:
+ case TYPE_DOUBLE:
+ case TYPE_OBJ:
+ case TYPE_DATE:
+ case TYPE_BOOL:
+ case TYPE_ENUM:
+ case TYPE_LAST:
+ case TYPE_NONE:
+ break;
+ }
+ uint32_t tag = mapTagValue ((Prop_type) field->propID, tmp64);
+ dDscr->setValue (field->propID, recn, tag);
+ }
+ else
+ {
+ switch (field->vtype)
+ {
+ case TYPE_INT32:
+ case TYPE_UINT32:
+ dDscr->setValue (field->propID, recn, dwin->decode (v->val32));
+ break;
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ dDscr->setValue (field->propID, recn, dwin->decode (v->val64));
+ break;
+ case TYPE_STRING:
+ {
+ int len = (int) (pktsz - field->offset);
+ if ((len > 0) && (ptr[field->offset] != 0))
+ {
+ StringBuilder *sb = new StringBuilder ();
+ sb->append (ptr + field->offset, 0, len);
+ dDscr->setObjValue (field->propID, recn, sb);
+ }
+ break;
+ }
+ // ignoring the following cases (why?)
+ case TYPE_DOUBLE:
+ case TYPE_OBJ:
+ case TYPE_DATE:
+ case TYPE_BOOL:
+ case TYPE_ENUM:
+ case TYPE_LAST:
+ case TYPE_NONE:
+ break;
+ }
+ }
+ }
+}
+
+#define PROG_BYTE 102400 // update progress bar every PROG_BYTE bytes
+
+void
+Experiment::read_data_file (const char *fname, const char *msg)
+{
+ Data_window::Span span;
+ off64_t total_len, remain_len;
+ char *progress_bar_msg;
+ int progress_bar_percent = -1;
+
+ char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, fname);
+ Data_window *dwin = new Data_window (data_file_name);
+ // Here we can call stat(data_file_name) to get file size,
+ // and call a function to reallocate vectors for clock profiling data
+ free (data_file_name);
+ if (dwin->not_opened ())
+ {
+ delete dwin;
+ return;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+
+ span.offset = 0;
+ span.length = dwin->get_fsize ();
+ total_len = remain_len = span.length;
+ progress_bar_msg = dbe_sprintf (NTXT ("%s %s"), NTXT (" "), msg);
+ invalid_packet = 0;
+ for (;;)
+ {
+ uint64_t pcktsz = readPacket (dwin, &span);
+ if (pcktsz == 0)
+ break;
+ // Update progress bar
+ if ((span.length <= remain_len) && (remain_len > 0))
+ {
+ int percent = (int) (100 * (total_len - remain_len) / total_len);
+ if (percent > progress_bar_percent)
+ {
+ progress_bar_percent += 10;
+ theApplication->set_progress (percent, progress_bar_msg);
+ }
+ remain_len -= PROG_BYTE;
+ }
+ span.length -= pcktsz;
+ span.offset += pcktsz;
+ }
+ delete dwin;
+
+ if (invalid_packet)
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("WARNING: There are %d invalid packet(s) in the %s file"),
+ invalid_packet, fname);
+ Emsg *m = new Emsg (CMSG_WARN, sb);
+ warnq->append (m);
+ }
+
+ theApplication->set_progress (0, NTXT (""));
+ free (progress_bar_msg);
+}
+
+int
+Experiment::read_overview_file ()
+{
+ char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_OVERVIEW_FILE);
+ Data_window *dwin = new Data_window (data_file_name);
+ free (data_file_name);
+ if (dwin->not_opened ())
+ {
+ delete dwin;
+ return 0;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+ newDataDescriptor (DATA_SAMPLE);
+
+ Data_window::Span span;
+ span.offset = 0;
+ span.length = dwin->get_fsize ();
+
+ PrUsage *data = NULL, *data_prev = NULL;
+ Sample *sample;
+ int sample_number = 1;
+
+ int64_t prDataSize;
+ if (wsize == W32)
+ prDataSize = PrUsage::bind32Size ();
+ else
+ prDataSize = PrUsage::bind64Size ();
+
+ while (span.length > 0)
+ {
+ data_prev = data;
+ data = new PrUsage ();
+
+ void *dw = dwin->bind (&span, prDataSize);
+ if ((dw == NULL) || (prDataSize > span.length))
+ {
+ Emsg *m = new Emsg (CMSG_ERROR, GTXT ("Warning: overview data file can't be read"));
+ warnq->append (m);
+ status = FAILURE;
+ delete dwin;
+ return status;
+ }
+
+ if (wsize == W32)
+ data->bind32 (dw, need_swap_endian);
+ else
+ data->bind64 (dw, need_swap_endian);
+ span.length -= prDataSize;
+ span.offset += prDataSize;
+
+ // Skip the first packet
+ if (data_prev == NULL)
+ continue;
+ if (sample_number > samples->size ())
+ { // inconsistent log/overview
+ sample = new Sample (sample_number);
+ char * label = GTXT ("<unknown>");
+ sample->start_label = dbe_strdup (label);
+ sample->end_label = dbe_strdup (label);
+ samples->append (sample);
+ }
+ else
+ sample = samples->fetch (sample_number - 1);
+ sample_number++;
+ sample->start_time = data_prev->pr_tstamp + 1;
+ sample->end_time = data->pr_tstamp;
+ sample->prusage = data_prev;
+
+ data_prev->pr_rtime = data->pr_rtime - data_prev->pr_rtime;
+ data_prev->pr_utime = data->pr_utime - data_prev->pr_utime;
+ data_prev->pr_stime = data->pr_stime - data_prev->pr_stime;
+ data_prev->pr_ttime = data->pr_ttime - data_prev->pr_ttime;
+ data_prev->pr_tftime = data->pr_tftime - data_prev->pr_tftime;
+ data_prev->pr_dftime = data->pr_dftime - data_prev->pr_dftime;
+ data_prev->pr_kftime = data->pr_kftime - data_prev->pr_kftime;
+ data_prev->pr_ltime = data->pr_ltime - data_prev->pr_ltime;
+ data_prev->pr_slptime = data->pr_slptime - data_prev->pr_slptime;
+ data_prev->pr_wtime = data->pr_wtime - data_prev->pr_wtime;
+ data_prev->pr_stoptime = data->pr_stoptime - data_prev->pr_stoptime;
+ data_prev->pr_minf = data->pr_minf - data_prev->pr_minf;
+ data_prev->pr_majf = data->pr_majf - data_prev->pr_majf;
+ data_prev->pr_nswap = data->pr_nswap - data_prev->pr_nswap;
+ data_prev->pr_inblk = data->pr_inblk - data_prev->pr_inblk;
+ data_prev->pr_oublk = data->pr_oublk - data_prev->pr_oublk;
+ data_prev->pr_msnd = data->pr_msnd - data_prev->pr_msnd;
+ data_prev->pr_mrcv = data->pr_mrcv - data_prev->pr_mrcv;
+ data_prev->pr_sigs = data->pr_sigs - data_prev->pr_sigs;
+ data_prev->pr_vctx = data->pr_vctx - data_prev->pr_vctx;
+ data_prev->pr_ictx = data->pr_ictx - data_prev->pr_ictx;
+ data_prev->pr_sysc = data->pr_sysc - data_prev->pr_sysc;
+ data_prev->pr_ioch = data->pr_ioch - data_prev->pr_ioch;
+ sample->get_usage (); // force validation
+ }
+
+ for (long smpNum = samples->size (); smpNum >= sample_number; smpNum--)
+ {
+ // overview file was truncated
+ sample = samples->remove (smpNum - 1);
+ delete sample;
+ }
+
+ if (data)
+ {
+ // Update last_event so that getEndTime() covers
+ // all loadobjects, too.
+ update_last_event (data->pr_tstamp);
+ delete data;
+ }
+ delete dwin;
+ return SUCCESS;
+}
+
+int
+Experiment::uidNodeCmp (const void *a, const void *b)
+{
+ UIDnode *nd1 = *(UIDnode**) a;
+ UIDnode *nd2 = *(UIDnode**) b;
+ if (nd1->uid == nd2->uid)
+ return 0;
+ return nd1->uid < nd2->uid ? -1 : 1;
+}
+
+static uint64_t
+funcAddr (uint32_t val)
+{
+ if (val == (uint32_t) SP_LEAF_CHECK_MARKER)
+ return (uint64_t) SP_LEAF_CHECK_MARKER;
+ if (val == (uint32_t) SP_TRUNC_STACK_MARKER)
+ return (uint64_t) SP_TRUNC_STACK_MARKER;
+ if (val == (uint32_t) SP_FAILED_UNWIND_MARKER)
+ return (uint64_t) SP_FAILED_UNWIND_MARKER;
+ return val;
+}
+
+Experiment::UIDnode *
+Experiment::add_uid (Data_window *dwin, uint64_t uid, int size,
+ uint32_t *array, uint64_t link_uid)
+{
+ if (uid == (uint64_t) 0)
+ return NULL;
+ uint64_t val = funcAddr (dwin->decode (array[0]));
+ UIDnode *node = NULL;
+ UIDnode *res = get_uid_node (uid, val);
+ UIDnode *next = res;
+ for (int i = 0; i < size; i++)
+ {
+ val = funcAddr (dwin->decode (array[i]));
+ if (next == NULL)
+ {
+ next = get_uid_node ((uint64_t) 0, val);
+ if (node != NULL)
+ node->next = next;
+ }
+ node = next;
+ next = node->next;
+ if (node->val == 0)
+ node->val = val;
+ else if (node->val != val) // Algorithmic error (should never happen)
+ node->val = (uint64_t) SP_LEAF_CHECK_MARKER;
+ }
+ if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
+ node->next = get_uid_node (link_uid);
+ return res;
+}
+
+Experiment::UIDnode *
+Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid)
+{
+ if (uid == (uint64_t) 0)
+ return NULL;
+ UIDnode *node = NULL;
+ uint64_t val = dwin->decode (array[0]);
+ UIDnode *res = get_uid_node (uid, val);
+ UIDnode *next = res;
+ for (int i = 0; i < size; i++)
+ {
+ val = dwin->decode (array[i]);
+ if (next == NULL)
+ {
+ next = get_uid_node ((uint64_t) 0, val);
+ if (node != NULL)
+ node->next = next;
+ }
+ node = next;
+ next = node->next;
+ if (node->val == (uint64_t) 0)
+ node->val = val;
+ else if (node->val != val) // Algorithmic error (should never happen)
+ node->val = (uint64_t) - 1;
+ }
+ if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
+ node->next = get_uid_node (link_uid);
+ return res;
+}
+
+Experiment::UIDnode *
+Experiment::new_uid_node (uint64_t uid, uint64_t val)
+{
+#define NCHUNKSTEP 1024
+ if (nnodes >= nchunks * CHUNKSZ)
+ {
+ // Reallocate Node chunk array
+ UIDnode** old_chunks = chunks;
+ chunks = new UIDnode*[nchunks + NCHUNKSTEP];
+ memcpy (chunks, old_chunks, nchunks * sizeof (UIDnode*));
+ nchunks += NCHUNKSTEP;
+ delete[] old_chunks;
+ // Clean future pointers
+ memset (&chunks[nchunks - NCHUNKSTEP], 0, NCHUNKSTEP * sizeof (UIDnode*));
+ }
+
+ if (NULL == chunks[nnodes / CHUNKSZ]) // Allocate new chunk for nodes.
+ chunks[nnodes / CHUNKSZ] = new UIDnode[CHUNKSZ];
+ UIDnode *node = &chunks[nnodes / CHUNKSZ][nnodes % CHUNKSZ];
+ node->uid = uid;
+ node->val = val;
+ node->next = NULL;
+ nnodes++;
+ return node;
+}
+
+Experiment::UIDnode *
+Experiment::get_uid_node (uint64_t uid, uint64_t val)
+{
+ int hash = (((int) uid) >> 4) & (HTableSize - 1);
+ if (uid != (uint64_t) 0)
+ {
+ UIDnode *node = uidHTable[hash];
+ if (node && node->uid == uid)
+ return node;
+ }
+ UIDnode *node = new_uid_node (uid, val);
+ if (uid != (uint64_t) 0)
+ {
+ uidHTable[hash] = node;
+ uidnodes->append (node);
+ }
+ return node;
+}
+
+Experiment::UIDnode *
+Experiment::get_uid_node (uint64_t uid)
+{
+ if (uid == (uint64_t) 0)
+ return NULL;
+ int hash = (((int) uid) >> 4) & (HTableSize - 1);
+ UIDnode *node = uidHTable[hash];
+ if (node && node->uid == uid)
+ return node;
+ node = new_uid_node (uid, (uint64_t) 0);
+ node->next = node;
+ return node;
+}
+
+Experiment::UIDnode *
+Experiment::find_uid_node (uint64_t uid)
+{
+ int hash = (((int) uid) >> 4) & (HTableSize - 1);
+ UIDnode *node = uidHTable[hash];
+ if (node && node->uid == uid)
+ return node;
+ int lt = 0;
+ int rt = uidnodes->size () - 1;
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ node = uidnodes->fetch (md);
+ if (node->uid < uid)
+ lt = md + 1;
+ else if (node->uid > uid)
+ rt = md - 1;
+ else
+ {
+ uidHTable[hash] = node;
+ return node;
+ }
+ }
+ return NULL;
+}
+
+int
+Experiment::frUidCmp (const void *a, const void *b)
+{
+ RawFramePacket *fp1 = *(RawFramePacket**) a;
+ RawFramePacket *fp2 = *(RawFramePacket**) b;
+ if (fp1->uid == fp2->uid)
+ return 0;
+ return fp1->uid < fp2->uid ? -1 : 1;
+}
+
+Experiment::RawFramePacket *
+Experiment::find_frame_packet (uint64_t uid)
+{
+ int lt = 0;
+ int rt = frmpckts->size () - 1;
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ RawFramePacket *fp = frmpckts->fetch (md);
+ if (fp->uid < uid)
+ lt = md + 1;
+ else if (fp->uid > uid)
+ rt = md - 1;
+ else
+ return fp;
+ }
+
+ return NULL;
+}
+
+#define FRINFO_CACHEOPT_SIZE_LIMIT 4000000
+#define FRINFO_PIPELINE_SIZE_LIMIT 500000
+#define FRINFO_PIPELINE_NUM_STAGES 3
+
+// Pipelined execution of resolve_frame_info() and add_stack().
+// Since this is the largest time consuming part of loading an experiment (especially
+// so for large java experiments) - executing this part as a 3 stage pipeline can
+// give significant performance gain - and this concept can be aggressively applied
+// to enhance the gain further in future. The three stages are:
+// Phase 1: resolve_frame_info()
+// Phase 2: first part of add_stack() where the native stack is built
+// Phase 3: second part og add_stack() where the java stack is built
+// Phase 4: insert the native and java stacks into the stack map
+// The main thread operates in the first Phase and the other stages are
+// operated by a ssplib sequential queue - The threads working on the queues run concurrently
+// with each other and with the main thread. But within a particular queue, jobs are
+// executed sequentially
+
+
+// This is the second phase of the pipeline of resolve_frame_info and add_stack
+// It works on a chunk of iterations (size CSTCTX_CHUNK_SZ) and invokes add_stack()
+// for each one of them
+
+void
+Experiment::resolve_frame_info (DataDescriptor *dDscr)
+{
+ if (!resolveFrameInfo)
+ return;
+ if (NULL == cstack)
+ return;
+ dDscr->setResolveFrInfoDone ();
+
+ // Check for TSTAMP
+ int propID = dbeSession->getPropIdByName (NTXT ("TSTAMP"));
+ Data *dataTStamp = dDscr->getData (propID);
+ if (dataTStamp == NULL)
+ return;
+
+ propID = dbeSession->getPropIdByName (NTXT ("FRINFO"));
+ Data *dataFrinfo = dDscr->getData (propID);
+
+ propID = dbeSession->getPropIdByName (NTXT ("THRID"));
+ Data *dataThrId = dDscr->getData (propID);
+
+ // We can get frame info either by FRINFO or by [THRID,STKIDX]
+ if (dataFrinfo == NULL)
+ return;
+
+ char *propName = NTXT ("MSTACK");
+ propID = dbeSession->getPropIdByName (propName);
+ PropDescr *prMStack = new PropDescr (propID, propName);
+ prMStack->uname = dbe_strdup (GTXT ("Machine Call Stack"));
+ prMStack->vtype = TYPE_OBJ;
+ dDscr->addProperty (prMStack);
+
+ propName = NTXT ("USTACK");
+ propID = dbeSession->getPropIdByName (propName);
+ PropDescr *prUStack = new PropDescr (propID, propName);
+ prUStack->uname = dbe_strdup (GTXT ("User Call Stack"));
+ prUStack->vtype = TYPE_OBJ;
+ dDscr->addProperty (prUStack);
+
+ propName = NTXT ("XSTACK");
+ propID = dbeSession->getPropIdByName (propName);
+ PropDescr *prXStack = new PropDescr (propID, propName);
+ prXStack->uname = dbe_strdup (GTXT ("Expert Call Stack"));
+ prXStack->vtype = TYPE_OBJ;
+ dDscr->addProperty (prXStack);
+
+ propName = NTXT ("HSTACK");
+ propID = dbeSession->getPropIdByName (propName);
+ PropDescr *prHStack = new PropDescr (propID, propName);
+ prHStack->uname = dbe_strdup (GTXT ("ShowHide Call Stack"));
+ prHStack->vtype = TYPE_OBJ;
+ dDscr->addProperty (prHStack);
+
+ if (has_java)
+ {
+ propName = NTXT ("JTHREAD");
+ propID = dbeSession->getPropIdByName (propName);
+ PropDescr *prJThread = new PropDescr (propID, propName);
+ prJThread->uname = dbe_strdup (GTXT ("Java Thread"));
+ prJThread->vtype = TYPE_OBJ;
+ dDscr->addProperty (prJThread);
+ }
+
+ if (ompavail)
+ {
+ PropDescr *prop = new PropDescr (PROP_OMPSTATE, NTXT ("OMPSTATE"));
+ prop->uname = dbe_strdup (GTXT ("OpenMP state"));
+ prop->vtype = TYPE_UINT32;
+ char * stateNames [OMP_LAST_STATE] = OMP_THR_STATE_STRINGS;
+ char * stateUNames[OMP_LAST_STATE] = OMP_THR_STATE_USTRINGS;
+ for (int ii = 0; ii < OMP_LAST_STATE; ii++)
+ prop->addState (ii, stateNames[ii], stateUNames[ii]);
+ dDscr->addProperty (prop);
+
+ // add PROP_CPRID to profiling data (not same as omptrace's PROP_CPRID)
+ prop = dDscr->getProp (PROP_CPRID);
+ if (prop)
+ {
+ VType_type type = prop->vtype;
+ assert (type == TYPE_OBJ); //see 7040526
+ }
+ prop = new PropDescr (PROP_CPRID, NTXT ("CPRID")); //profiling PROP_CPRID
+ prop->uname = dbe_strdup (GTXT ("OpenMP parallel region"));
+ prop->vtype = TYPE_OBJ;
+ dDscr->addProperty (prop);
+
+ // add PROP_TSKID to profiling data (not same as omptrace's PROP_TSKID)
+ prop = dDscr->getProp (PROP_TSKID);
+ if (prop)
+ {
+ VType_type type = prop->vtype;
+ assert (type == TYPE_OBJ); //see 7040526
+ }
+ prop = new PropDescr (PROP_TSKID, NTXT ("TSKID")); //profiling PROP_TSKID
+ prop->uname = dbe_strdup (GTXT ("OpenMP task"));
+ prop->vtype = TYPE_OBJ;
+ dDscr->addProperty (prop);
+ }
+ char *progress_bar_msg = dbe_sprintf (NTXT ("%s %s: %s"), NTXT (" "),
+ GTXT ("Processing CallStack Data"),
+ get_basename (expt_name));
+ int progress_bar_percent = -1;
+ long deltaReport = 5000;
+ long nextReport = 0;
+
+ long size = dDscr->getSize ();
+ // bool resolve_frinfo_pipelined = size > FRINFO_PIPELINE_SIZE_LIMIT && !ompavail;
+ bool resolve_frinfo_pipelined = false;
+
+ Map<uint64_t, uint64_t> *nodeCache = NULL;
+ Map<uint64_t, uint64_t> *frameInfoCache = NULL;
+ if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL)
+ {
+ frameInfoCache = new CacheMap<uint64_t, uint64_t>;
+ nodeCache = new CacheMap<uint64_t, uint64_t>;
+ }
+
+ pushCnt = popCnt = pushCnt3 = popCnt3 = 0;
+ nPush = nPop = 0;
+
+ FramePacket *fp = NULL;
+ // DbeThreadPool * threadPool = new DbeThreadPool(5);
+ fp = new FramePacket;
+ fp->stack = new Vector<Vaddr>;
+ fp->jstack = new Vector<Vaddr>;
+ fp->ompstack = new Vector<Vaddr>;
+ fp->omp_state = 0;
+ fp->mpi_state = 0;
+
+ // piggyback on post-processing to calculate exp->last_event
+ const hrtime_t _exp_start_time = getStartTime (); // wall clock time
+ hrtime_t exp_duration = getLastEvent () == ZERO_TIME ? 0
+ : getLastEvent () - _exp_start_time; // zero-based
+
+ int missed_fi = 0;
+ int total_fi = 0;
+
+ for (long i = 0; i < size; i++)
+ {
+ if (i == nextReport)
+ {
+ int percent = (int) (i * 100 / size);
+ if (percent > progress_bar_percent)
+ {
+ progress_bar_percent += 10;
+ theApplication->set_progress (percent, progress_bar_msg);
+ }
+ nextReport += deltaReport;
+ }
+
+ uint32_t thrid = (uint32_t) dataThrId->fetchInt (i);
+ hrtime_t tstamp = (hrtime_t) dataTStamp->fetchLong (i);
+
+ // piggyback on post-processing to calculate exp->last_event
+ {
+ hrtime_t relative_timestamp = tstamp - _exp_start_time;
+ if (exp_duration < relative_timestamp)
+ exp_duration = relative_timestamp;
+ }
+ uint64_t frinfo = (uint64_t) dataFrinfo->fetchLong (i);
+
+ RawFramePacket *rfp = NULL;
+ if (frinfo)
+ {
+ // CacheMap does not work with NULL key
+ if (frameInfoCache != NULL)
+ rfp = (RawFramePacket *) frameInfoCache->get (frinfo);
+ }
+ if (rfp == 0)
+ {
+ rfp = find_frame_packet (frinfo);
+ if (rfp != 0)
+ {
+ if (frameInfoCache != NULL)
+ frameInfoCache->put (frinfo, (uint64_t) rfp);
+ }
+ else
+ missed_fi++;
+ total_fi++;
+ }
+
+ // Process OpenMP properties
+ if (ompavail)
+ {
+ fp->omp_state = rfp ? rfp->omp_state : 0;
+ dDscr->setValue (PROP_OMPSTATE, i, fp->omp_state);
+
+ fp->omp_cprid = mapPRid->get (thrid, tstamp, mapPRid->REL_EQLE);
+ void *omp_preg = mapPReg->get (thrid, tstamp, mapPReg->REL_EQLE);
+ if (!omp_preg)
+ {
+ char *idxname = NTXT ("OMP_preg");
+ int idxtype = dbeSession->findIndexSpaceByName (idxname);
+ if (idxtype != -1)
+ {
+ Histable *preg0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
+ if (preg0)
+ {
+ Vector<Histable*> pregs;
+ pregs.append (preg0);
+ omp_preg = cstack->add_stack (&pregs);
+ mapPReg->put (thrid, tstamp, omp_preg);
+ }
+ }
+ }
+ dDscr->setObjValue (PROP_CPRID, i, omp_preg); //profiling PROP_CPRID
+ void *omp_task = mapTask->get (thrid, tstamp, mapTask->REL_EQLE);
+ if (!omp_task)
+ {
+ char *idxname = NTXT ("OMP_task");
+ int idxtype = dbeSession->findIndexSpaceByName (idxname);
+ if (idxtype != -1)
+ {
+ Histable *task0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
+ if (task0)
+ {
+ Vector<Histable*> tasks;
+ tasks.append (task0);
+ omp_task = cstack->add_stack (&tasks);
+ mapTask->put (thrid, tstamp, omp_task);
+ }
+ }
+ }
+ dDscr->setObjValue (PROP_TSKID, i, omp_task); //profiling PROP_TSKID
+ }
+ else
+ {
+ fp->omp_state = 0;
+ fp->omp_cprid = 0;
+ }
+
+ // Construct the native stack
+ fp->stack->reset ();
+ Vaddr leafpc = dDscr->getULongValue (PROP_LEAFPC, i);
+ if (leafpc)
+ fp->stack->append (leafpc);
+ UIDnode *node = rfp ? rfp->uidn : NULL;
+ while (node)
+ {
+ if (node->next == node)
+ // this node contains link_uid
+ node = find_uid_node (node->uid);
+ else
+ {
+ fp->stack->append (node->val);
+ node = node->next;
+ }
+ }
+ fp->truncated = 0;
+ int last = fp->stack->size () - 1;
+ if (last >= 0)
+ {
+ switch (fp->stack->fetch (last))
+ {
+ case SP_TRUNC_STACK_MARKER:
+ fp->truncated = (Vaddr) SP_TRUNC_STACK_MARKER;
+ fp->stack->remove (last);
+ break;
+ case SP_FAILED_UNWIND_MARKER:
+ fp->truncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
+ fp->stack->remove (last);
+ break;
+ }
+ }
+
+ // Construct the Java stack
+ fp->jstack->reset ();
+ node = rfp ? rfp->uidj : NULL;
+ while (node)
+ {
+ if (node->next == node)
+ {
+ // this node contains link_uid
+ UIDnode *n = NULL;
+ if (node->uid)
+ {
+ // CacheMap does not work with NULL key
+ if (nodeCache != NULL)
+ n = (UIDnode *) nodeCache->get (node->uid);
+ }
+ if (n == NULL)
+ {
+ n = find_uid_node (node->uid);
+ if (n != NULL)
+ {
+ if (nodeCache != NULL)
+ nodeCache->put (node->uid, (uint64_t) n);
+ }
+ }
+ node = n;
+ }
+ else
+ {
+ fp->jstack->append (node->val);
+ node = node->next;
+ }
+ }
+ fp->jtruncated = false;
+ last = fp->jstack->size () - 1;
+ if (last >= 1 && fp->jstack->fetch (last) == SP_TRUNC_STACK_MARKER)
+ {
+ fp->jtruncated = true;
+ fp->jstack->remove (last);
+ fp->jstack->remove (last - 1);
+ }
+
+ // Construct the OpenMP stack
+ if (ompavail)
+ {
+ fp->ompstack->reset ();
+ if (rfp && rfp->omp_uid)
+ {
+ if (leafpc)
+ fp->ompstack->append (leafpc);
+ node = rfp->omp_uid;
+ while (node)
+ {
+ if (node->next == node)
+ // this node contains link_uid
+ node = find_uid_node (node->uid);
+ else
+ {
+ fp->ompstack->append (node->val);
+ node = node->next;
+ }
+ }
+ fp->omptruncated = false;
+ last = fp->ompstack->size () - 1;
+ if (last >= 0)
+ {
+ switch (fp->ompstack->fetch (last))
+ {
+ case SP_TRUNC_STACK_MARKER:
+ fp->omptruncated = (Vaddr) SP_TRUNC_STACK_MARKER;
+ fp->ompstack->remove (last);
+ break;
+ case SP_FAILED_UNWIND_MARKER:
+ fp->omptruncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
+ fp->ompstack->remove (last);
+ break;
+ }
+ }
+ }
+ }
+ cstack->add_stack (dDscr, i, fp, NULL);
+ }
+
+ // piggyback on post-processing to calculate exp->last_event
+ {
+ hrtime_t exp_end_time = _exp_start_time + exp_duration;
+ update_last_event (exp_end_time);
+ }
+
+ if (missed_fi > 0)
+ {
+ StringBuilder sb;
+ sb.sprintf (
+ GTXT ("*** Warning: %d frameinfo packets are missing from total of %d when resolving %s."),
+ missed_fi, total_fi, dDscr->getName ());
+ warnq->append (new Emsg (CMSG_WARN, sb));
+ }
+
+ // threadPool->wait_group();
+ // delete threadPool;
+ theApplication->set_progress (0, NTXT (""));
+ free (progress_bar_msg);
+ if (!resolve_frinfo_pipelined && fp != NULL)
+ {
+ delete fp->ompstack;
+ delete fp->jstack;
+ delete fp->stack;
+ delete fp;
+ }
+ delete frameInfoCache;
+ frameInfoCache = NULL;
+ delete nodeCache;
+ nodeCache = NULL;
+}
+
+void
+Experiment::post_process ()
+{
+ // update non_paused_time after final update to "last_event"
+ if (resume_ts != MAX_TIME && last_event)
+ {
+ hrtime_t ts = last_event - exp_start_time;
+ hrtime_t delta = ts - resume_ts;
+ non_paused_time += delta;
+ resume_ts = MAX_TIME; // collection is paused
+ }
+
+ // GC: prune events outside of experiment duration, calculate GC duration, update indices
+ int index;
+ GCEvent * gcevent;
+ gc_duration = ZERO_TIME;
+ if (gcevents != NULL)
+ {
+ // delete events that finish before exp_start_time or start after last_event
+ for (int ii = 0; ii < gcevents->size ();)
+ {
+ gcevent = gcevents->fetch (ii);
+ if (gcevent->end - exp_start_time < 0
+ || last_event - gcevent->start < 0)
+ delete gcevents->remove (ii);
+ else
+ ii++;
+ }
+ }
+ Vec_loop (GCEvent*, gcevents, index, gcevent)
+ {
+ gcevent->id = index + 1; // renumber to account for any deleted events
+ if (gcevent->start - exp_start_time < 0 || gcevent->start == ZERO_TIME)
+ // truncate events that start before experiment start
+ gcevent->start = exp_start_time;
+ if (last_event - gcevent->end < 0)
+ // truncate events that end after experiment end
+ gcevent->end = last_event;
+ gc_duration += gcevent->end - gcevent->start;
+ }
+}
+
+Experiment::Exp_status
+Experiment::find_expdir (char *path)
+{
+ // This function checks that the experiment directory
+ // is of the proper form, and accessible
+ struct stat64 sbuf;
+
+ // Save the name
+ expt_name = dbe_strdup (path);
+
+ // Check that the name ends in .er
+ size_t i = strlen (path);
+ if (i > 0 && path[i - 1] == '/')
+ path[--i] = '\0';
+
+ if (i < 4 || strcmp (&path[i - 3], NTXT (".er")) != 0)
+ {
+ Emsg *m = new Emsg (CMSG_FATAL,
+ GTXT ("*** Error: not a valid experiment name"));
+ errorq->append (m);
+ status = FAILURE;
+ return FAILURE;
+ }
+
+ // Check if new directory structure (i.e., no pointer file)
+ if (dbe_stat (path, &sbuf))
+ {
+ Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: experiment not found"));
+ errorq->append (m);
+ status = FAILURE;
+ return FAILURE;
+ }
+ if (S_ISDIR (sbuf.st_mode) == 0)
+ {
+ // ignore pointer-file experiments
+ Emsg *m = new Emsg (CMSG_FATAL,
+ GTXT ("*** Error: experiment was recorded with an earlier version, and can not be read"));
+ errorq->append (m);
+ obsolete = 1;
+ status = FAILURE;
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+void
+Experiment::purge ()
+{
+ // This routine will purge all of the caches of releasable storage.
+ for (int i = 0; i < dataDscrs->size (); ++i)
+ {
+ DataDescriptor *dataDscr = dataDscrs->fetch (i);
+ if (dataDscr == NULL)
+ continue;
+ dataDscr->reset ();
+ }
+ delete cstack;
+ delete cstackShowHide;
+ cstack = CallStack::getInstance (this);
+ cstackShowHide = CallStack::getInstance (this);
+}
+
+void
+Experiment::resetShowHideStack ()
+{
+ delete cstackShowHide;
+ cstackShowHide = CallStack::getInstance (this);
+}
+
+#define GET_INT_VAL(v, s, len) \
+ for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
+
+static int
+dir_name_cmp (const void *a, const void *b)
+{
+ char *s1 = *((char **) a);
+ char *s2 = *((char **) b);
+ while (*s1)
+ {
+ if (isdigit (*s1) && isdigit (*s2))
+ {
+ int v1, v2, len1, len2;
+ GET_INT_VAL (v1, s1, len1);
+ GET_INT_VAL (v2, s2, len2);
+ if (v1 != v2)
+ return v1 - v2;
+ if (len1 != len2)
+ return len2 - len1;
+ continue;
+ }
+ if (*s1 != *s2)
+ break;
+ s1++;
+ s2++;
+ }
+ return *s1 - *s2;
+}
+
+Vector<char*> *
+Experiment::get_descendants_names ()
+{
+ char *dir_name = get_expt_name ();
+ if (dir_name == NULL)
+ return NULL;
+ DIR *exp_dir = opendir (dir_name);
+ if (exp_dir == NULL)
+ return NULL;
+ Vector<char*> *exp_names = new Vector<char*>();
+ for (struct dirent *entry = readdir (exp_dir); entry;
+ entry = readdir (exp_dir))
+ {
+ if (entry->d_name[0] == '_' || strncmp (entry->d_name, "M_r", 3) == 0)
+ {
+ char *dpath = dbe_sprintf (NTXT ("%s/%s"), dir_name, entry->d_name);
+ struct stat64 sbuf;
+ if (dbe_stat (dpath, &sbuf) == 0 && S_ISDIR (sbuf.st_mode))
+ exp_names->append (dpath);
+ else
+ free (dpath);
+ }
+ }
+ closedir (exp_dir);
+ if (exp_names->size () == 0)
+ {
+ delete exp_names;
+ return NULL;
+ }
+ exp_names->sort (dir_name_cmp);
+ return exp_names;
+}
+
+bool
+Experiment::create_dir (char *dname)
+{
+ if (mkdir (dname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
+ {
+ return true;
+ }
+ struct stat64 sbuf;
+ if (dbe_stat (dname, &sbuf) != 0 || S_ISDIR (sbuf.st_mode) == 0)
+ {
+ char *buf = dbe_sprintf (GTXT ("Unable to create directory `%s'\n"),
+ dname);
+ errorq->append (new Emsg (CMSG_ERROR, buf));
+ free (buf);
+ return false;
+ }
+ return true;
+}
+
+char *
+Experiment::get_arch_name ()
+{
+ if (arch_name == NULL)
+ {
+ // Determine the master experiment directory.
+ // omazur: should do it in a less hacky way. XXXX
+ char *ptr = strstr_r (expt_name, DESCENDANT_EXPT_KEY);
+ ptr = ptr ? ptr + 3 : expt_name + strlen (expt_name);
+ arch_name = dbe_sprintf (NTXT ("%.*s/%s"), (int) (ptr - expt_name),
+ expt_name, SP_ARCHIVES_DIR);
+ }
+ return arch_name;
+}
+
+char *
+Experiment::get_fndr_arch_name ()
+{
+ if (fndr_arch_name == NULL)
+ // Determine the founder experiment directory.
+ fndr_arch_name = dbe_strdup (get_arch_name ());
+ return fndr_arch_name;
+}
+
+enum
+{
+ HASH_NAME_LEN = 11 // (64 / 6 + 1) = 11
+};
+
+static char *
+get_hash_string (char buf[HASH_NAME_LEN + 1], uint64_t hash)
+{
+ static const char *har =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+ for (int i = 0; i < HASH_NAME_LEN; i++)
+ {
+ buf[i] = har[hash & 0x3f];
+ hash = hash >> 6;
+ }
+ buf[HASH_NAME_LEN] = 0;
+ return buf;
+}
+
+char *
+Experiment::getNameInArchive (const char *fname, bool archiveFile)
+{
+ char *aname = get_archived_name (fname, archiveFile);
+ char *ret = dbe_sprintf (NTXT ("%s/%s"), get_arch_name (), aname);
+ free (aname);
+ return ret;
+}
+
+#define MAX_ARCHIVE_FILENAME_LEN (256 - HASH_NAME_LEN - 2)
+
+char *
+Experiment::get_archived_name (const char *fname, bool archiveFile)
+{
+ char *bname = get_basename (fname);
+
+ // dirname_hash:
+ char dirnameHash[HASH_NAME_LEN + 1];
+ // Treat "a.out" and "./a.out" equally
+ uint64_t hash = bname != fname ? crc64 (fname, bname - fname)
+ : crc64 (NTXT ("./"), 2);
+ get_hash_string (dirnameHash, hash);
+
+ char *ret;
+ long bname_len = dbe_sstrlen (bname);
+ if (bname_len > MAX_ARCHIVE_FILENAME_LEN)
+ {
+ char basenameHash[HASH_NAME_LEN + 1];
+ hash = crc64 (bname, bname_len);
+ get_hash_string (basenameHash, hash);
+ ret = dbe_sprintf ("%.*s%c%s_%s",
+ MAX_ARCHIVE_FILENAME_LEN - HASH_NAME_LEN - 1,
+ bname, archiveFile ? '.' : '_',
+ dirnameHash, basenameHash);
+ }
+ else
+ ret = dbe_sprintf ("%s%c%s", bname, archiveFile ? '.' : '_', dirnameHash);
+ return ret;
+}
+
+char *
+Experiment::checkFileInArchive (const char *fname, bool archiveFile)
+{
+ if (archiveMap)
+ {
+ char *aname = get_archived_name (fname, archiveFile);
+ DbeFile *df = archiveMap->get (aname);
+ free (aname);
+ if (df)
+ return strdup (df->get_location ());
+ return NULL;
+ }
+ if (founder_exp)
+ return founder_exp->checkFileInArchive (fname, archiveFile);
+ return NULL;
+}
+
+
+// Comparing SegMem
+
+static int
+SegMemCmp (const void *a, const void *b)
+{
+ SegMem *item1 = *((SegMem **) a);
+ SegMem *item2 = *((SegMem **) b);
+ return item1->unload_time > item2->unload_time ? 1 :
+ item1->unload_time == item2->unload_time ? 0 : -1;
+}
+
+SegMem*
+Experiment::update_ts_in_maps (Vaddr addr, hrtime_t ts)
+{
+ Vector<SegMem *> *segMems = (Vector<SegMem *> *) maps->values ();
+ if (!segMems->is_sorted ())
+ {
+ Dprintf (DEBUG_MAPS, NTXT ("update_ts_in_maps: segMems.size=%lld\n"), (long long) segMems->size ());
+ segMems->sort (SegMemCmp);
+ }
+ for (int i = 0, sz = segMems ? segMems->size () : 0; i < sz; i++)
+ {
+ SegMem *sm = segMems->fetch (i);
+ if (ts < sm->unload_time)
+ {
+ for (; i < sz; i++)
+ {
+ sm = segMems->fetch (i);
+ if ((addr >= sm->base) && (addr < sm->base + sm->size))
+ {
+ Dprintf (DEBUG_MAPS,
+ "update_ts_in_maps: old:%u.%09u -> %u.%09u addr=0x%08llx size=%lld\n",
+ (unsigned) (sm->load_time / NANOSEC),
+ (unsigned) (sm->load_time % NANOSEC),
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ (unsigned long long) sm->base, (long long) sm->size);
+ maps->remove (sm->base, sm->load_time);
+ sm->load_time = ts;
+ maps->insert (sm->base, ts, sm);
+ return sm;
+ }
+ }
+ }
+ }
+ Dprintf (DEBUG_MAPS, "update_ts_in_maps: NOT FOUND %u.%09u addr=0x%08llx\n",
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ (unsigned long long) addr);
+ return NULL;
+}
+
+DbeInstr*
+Experiment::map_Vaddr_to_PC (Vaddr addr, hrtime_t ts)
+{
+ // Look up in the hash table first
+ int hash = (((int) addr) >> 8) & (HTableSize - 1);
+ SegMem *si = smemHTable[hash];
+ if (si == NULL || addr < si->base || addr >= si->base + si->size
+ || ts < si->load_time || ts >= si->unload_time)
+ {
+ // Not in the hash table
+ si = (SegMem*) maps->locate (addr, ts);
+ if (si == NULL || addr < si->base || addr >= si->base + si->size
+ || ts < si->load_time || ts >= si->unload_time)
+ {
+ si = update_ts_in_maps (addr, ts);
+ if (si == NULL)
+ return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, addr);
+ }
+ smemHTable[hash] = si;
+ }
+
+ // Calculate the file offset of 'addr'
+ uint64_t f_offset = si->get_file_offset () + (addr - si->base);
+
+ DbeInstr *instr;
+ if (si->obj->get_type () == Histable::LOADOBJECT)
+ {
+ LoadObject *lo = (LoadObject*) si->obj;
+ lo->sync_read_stabs ();
+ instr = lo->find_dbeinstr (f_offset);
+ }
+ else
+ {
+ int hash2 = ((((int) addr) & 0xFFFC00) | (((int) f_offset) >> 2))
+ & (HTableSize - 1);
+ instr = instHTable[hash2];
+ if (instr == NULL || instr->func != si->obj || instr->addr != f_offset)
+ {
+ // Not in the hash table
+ Function *fp = (Function *) si->obj;
+ instr = fp->find_dbeinstr (0, f_offset);
+ instHTable[hash2] = instr;
+ }
+ }
+ if (!instr->func->isUsed)
+ {
+ instr->func->isUsed = true;
+ instr->func->module->isUsed = true;
+ instr->func->module->loadobject->isUsed = true;
+ }
+ return instr;
+}
+
+Sample *
+Experiment::map_event_to_Sample (hrtime_t ts)
+{
+ Sample *sample;
+ int index;
+
+ // Check if the last used sample is the right one,
+ // if not then find it.
+ if (sample_last_used && ts >= sample_last_used->start_time
+ && ts <= sample_last_used->end_time)
+ return sample_last_used;
+
+ Vec_loop (Sample*, samples, index, sample)
+ {
+ if ((ts >= sample->start_time) &&
+ (ts <= sample->end_time))
+ {
+ sample_last_used = sample;
+ return sample;
+ }
+ }
+ return (Sample*) NULL;
+}
+
+GCEvent *
+Experiment::map_event_to_GCEvent (hrtime_t ts)
+{
+ GCEvent *gcevent;
+ int index;
+
+ // Check if the last used sample is the right one,
+ // if not then find it.
+ if (gcevent_last_used && ts >= gcevent_last_used->start
+ && ts <= gcevent_last_used->end)
+ return gcevent_last_used;
+ Vec_loop (GCEvent*, gcevents, index, gcevent)
+ {
+ if ((ts >= gcevent->start) &&
+ (ts <= gcevent->end))
+ {
+ gcevent_last_used = gcevent;
+ return gcevent;
+ }
+ }
+ return (GCEvent*) NULL;
+}
+
+DbeInstr*
+Experiment::map_jmid_to_PC (Vaddr mid, int bci, hrtime_t ts)
+{
+ if (mid == 0 || jmaps == NULL)
+ // special case: no Java stack was recorded, bci - error code
+ return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, bci);
+
+ JMethod *jmthd = jmidHTable->get (mid);
+ if (jmthd == NULL)
+ {
+ jmthd = (JMethod *) jmaps->locate_exact_match (mid, ts);
+ if (jmthd)
+ jmidHTable->put (mid, jmthd);
+ }
+ if (jmthd == NULL || jmthd->get_type () != Histable::FUNCTION)
+ return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, (uint64_t) mid);
+ return jmthd->find_dbeinstr (0, bci);
+}
+
+Emsg *
+Experiment::fetch_comments ()
+{
+ return commentq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_runlogq ()
+{
+ return runlogq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_errors ()
+{
+ return errorq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_warnings ()
+{
+ return warnq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_notes ()
+{
+ return notesq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_ifreq ()
+{
+ return ifreqq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_pprocq ()
+{
+ return pprocq->fetch ();
+}
+
+int
+Experiment::read_dyntext_file ()
+{
+ char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_DYNTEXT_FILE);
+ Data_window *dwin = new Data_window (data_file_name);
+ if (dwin->not_opened ())
+ {
+ free (data_file_name);
+ delete dwin;
+ return 1;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+
+ Function *fp = NULL;
+ char *progress_msg = NULL; // Message for the progress bar
+ for (int64_t offset = 0;;)
+ {
+ DT_common *cpckt = (DT_common *) dwin->bind (offset, sizeof (DT_common));
+ if (cpckt == NULL)
+ break;
+ size_t cpcktsize = dwin->decode (cpckt->size);
+ cpckt = (DT_common *) dwin->bind (offset, cpcktsize);
+ if (cpckt == NULL)
+ break;
+ switch (dwin->decode (cpckt->type))
+ {
+ case DT_HEADER:
+ {
+ DT_header *hdr = (DT_header*) cpckt;
+ hrtime_t ts = dwin->decode (hdr->time) + exp_start_time;
+ SegMem *si = (SegMem*) maps->locate (dwin->decode (hdr->vaddr), ts);
+ fp = si ? (Function *) si->obj : NULL;
+ if (fp && (fp->get_type () != Histable::FUNCTION
+ || !(fp->flags & FUNC_FLAG_DYNAMIC)))
+ fp = NULL;
+ break;
+ }
+ case DT_CODE:
+ if (fp)
+ {
+ fp->img_fname = data_file_name;
+ fp->img_offset = offset + sizeof (DT_common);
+ if ((platform != Intel) && (platform != Amd64))
+ { //ARCH(SPARC)
+ // Find out 'save' instruction address for SPARC
+ char *ptr = ((char*) cpckt) + sizeof (DT_common);
+ size_t img_size = cpcktsize - sizeof (DT_common);
+ for (size_t i = 0; i < img_size; i += 4)
+ if (ptr[i] == (char) 0x9d && ptr[i + 1] == (char) 0xe3)
+ {
+ fp->save_addr = i;
+ break;
+ }
+ }
+ }
+ break;
+ case DT_SRCFILE:
+ if (fp)
+ {
+ char *srcname = dbe_strndup (((char*) cpckt) + sizeof (DT_common),
+ cpcktsize - sizeof (DT_common));
+ LoadObject *ds = fp->module ? fp->module->loadobject : NULL;
+ assert (ds != NULL);
+ Module *mod = dbeSession->createModule (ds, NULL);
+ mod->set_file_name (srcname);
+ //}
+ if (fp->module)
+ {
+ // It's most likely (unknown). Remove fp from it.
+ long idx = fp->module->functions->find (fp);
+ if (idx >= 0)
+ fp->module->functions->remove (idx);
+ }
+ fp->module = mod;
+ mod->functions->append (fp);
+ }
+ break;
+ case DT_LTABLE:
+ if (fp)
+ {
+ DT_lineno *ltab = (DT_lineno*) ((char*) cpckt + sizeof (DT_common));
+ size_t sz = (cpcktsize - sizeof (DT_common)) / sizeof (DT_lineno);
+ if (sz <= 0)
+ break;
+ // Take care of the progress bar
+ static int percent = 0;
+ static long deltaReport = sz / 100; // 1000;
+ static long nextReport = 0;
+ static long progress_count = 0;
+ fp->pushSrcFile (fp->getDefSrc (), 0);
+ for (size_t i = 0; i < sz; i++)
+ {
+ int lineno = dwin->decode (ltab[i].lineno);
+ if (fp->usrfunc != NULL)
+ {
+ // Update progress bar
+ if (dbeSession->is_interactive ())
+ {
+ if (progress_count == nextReport)
+ {
+ if (percent < 99)
+ {
+ percent++;
+ if (NULL == progress_msg)
+ {
+ progress_msg = dbe_sprintf (GTXT ("Processing Dynamic Text: %s"),
+ get_basename (expt_name));
+ }
+ theApplication->set_progress (percent, progress_msg);
+ nextReport += deltaReport;
+ }
+ }
+ progress_count++;
+ }
+ DbeLine *dbeline = fp->usrfunc->mapPCtoLine (lineno, NULL);
+ lineno = dbeline != NULL ? dbeline->lineno : -1;
+ }
+ fp->add_PC_info (dwin->decode (ltab[i].offset), lineno);
+ }
+ fp->popSrcFile ();
+ }
+ break;
+ default:
+ // skip unknown records
+ break;
+ }
+ offset += cpcktsize;
+ }
+ free (progress_msg);
+ free (data_file_name);
+ delete dwin;
+ return 0;
+}
+
+uint32_t
+Experiment::mapTagValue (Prop_type prop, uint64_t value)
+{
+ Vector<Histable*> *objs = tagObjs->fetch (prop);
+ int lt = 0;
+ int rt = objs->size () - 1;
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ Other *obj = (Other*) objs->fetch (md);
+ if (obj->value64 < value)
+ lt = md + 1;
+ else if (obj->value64 > value)
+ rt = md - 1;
+ else
+ return obj->tag;
+ }
+
+ uint32_t tag;
+ if (sparse_threads && (prop == PROP_THRID || prop == PROP_LWPID))
+ tag = objs->size () + 1; // "+ 1" related to 7038295
+ else
+ tag = (int) value; // truncation; See 6788767
+
+ Other *obj = new Other ();
+ obj->value64 = value;
+ obj->tag = tag;
+ if (lt == objs->size ())
+ objs->append (obj);
+ else
+ objs->insert (lt, obj);
+
+ // Update min and max tags
+ if (prop == PROP_LWPID)
+ {
+ if ((uint64_t) tag < min_lwp)
+ min_lwp = (uint64_t) tag;
+ if ((uint64_t) tag > max_lwp)
+ max_lwp = (uint64_t) tag;
+ lwp_cnt++;
+ }
+ else if (prop == PROP_THRID)
+ {
+ if ((uint64_t) tag < min_thread)
+ min_thread = (uint64_t) tag;
+ if ((uint64_t) tag > max_thread)
+ max_thread = (uint64_t) tag;
+ thread_cnt++;
+ }
+ else if (prop == PROP_CPUID)
+ {
+ // On Solaris 8, we don't get CPU id -- don't change
+ if (value != (uint64_t) - 1)
+ {//YXXX is this related only to solaris 8?
+ if ((uint64_t) tag < min_cpu)
+ min_cpu = (uint64_t) tag;
+ if ((uint64_t) tag > max_cpu)
+ max_cpu = (uint64_t) tag;
+ }
+ cpu_cnt++;
+ }
+ return obj->tag;
+}
+
+Vector<Histable*> *
+Experiment::getTagObjs (Prop_type prop)
+{
+ return tagObjs->fetch (prop);
+}
+
+Histable *
+Experiment::getTagObj (Prop_type prop, uint32_t tag)
+{
+ Vector<Histable*> *objs = tagObjs->fetch (prop);
+ if (objs == NULL)
+ return NULL;
+ for (int i = 0; i < objs->size (); i++)
+ {
+ Other *obj = (Other*) objs->fetch (i);
+ if (obj->tag == tag)
+ return obj;
+ }
+ return NULL;
+}
+
+JThread *
+Experiment::map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp)
+{
+ if (!has_java)
+ return JTHREAD_DEFAULT;
+ int lt = 0;
+ int rt = jthreads_idx->size () - 1;
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ JThread *jthread = jthreads_idx->fetch (md);
+ if (jthread->tid < tid)
+ lt = md + 1;
+ else if (jthread->tid > tid)
+ rt = md - 1;
+ else
+ {
+ for (; jthread; jthread = jthread->next)
+ if (tstamp >= jthread->start && tstamp < jthread->end)
+ return jthread;
+ break;
+ }
+ }
+
+ return JTHREAD_NONE;
+}
+
+JThread*
+Experiment::get_jthread (uint32_t tid)
+{
+ if (!has_java)
+ return JTHREAD_DEFAULT;
+ int lt = 0;
+ int rt = jthreads_idx->size () - 1;
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ JThread *jthread = jthreads_idx->fetch (md);
+ if (jthread->tid < tid)
+ lt = md + 1;
+ else if (jthread->tid > tid)
+ rt = md - 1;
+ else
+ {
+ JThread *jthread_first = jthread;
+ while ((jthread = jthread->next) != NULL)
+ if (!jthread->is_system () &&
+ jthread->jthr_id < jthread_first->jthr_id)
+ jthread_first = jthread;
+ return jthread_first;
+ }
+ }
+
+ return JTHREAD_NONE;
+}
+
+// SS12 experiment
+DataDescriptor *
+Experiment::newDataDescriptor (int data_id, int flags,
+ DataDescriptor *master_dDscr)
+{
+ DataDescriptor *dataDscr = NULL;
+ if (data_id >= 0 && data_id < dataDscrs->size ())
+ {
+ dataDscr = dataDscrs->fetch (data_id);
+ if (dataDscr != NULL)
+ return dataDscr;
+ }
+
+ assert (data_id >= 0 && data_id < DATA_LAST);
+ const char *nm = get_prof_data_type_name (data_id);
+ const char *uname = get_prof_data_type_uname (data_id);
+
+ if (master_dDscr)
+ dataDscr = new DataDescriptor (data_id, nm, uname, master_dDscr);
+ else
+ dataDscr = new DataDescriptor (data_id, nm, uname, flags);
+ dataDscrs->store (data_id, dataDscr);
+ return dataDscr;
+}
+
+Vector<DataDescriptor*> *
+Experiment::getDataDescriptors ()
+{
+ Vector<DataDescriptor*> *result = new Vector<DataDescriptor*>;
+ for (int i = 0; i < dataDscrs->size (); ++i)
+ {
+ DataDescriptor *dd;
+ dd = get_raw_events (i); // force data fetch
+ if (dd != NULL)
+ result->append (dd);
+ }
+ return result;
+}
+
+DataDescriptor *
+Experiment::getDataDescriptor (int data_id)
+{
+ if (data_id < 0 || data_id >= dataDscrs->size ())
+ return NULL;
+ return dataDscrs->fetch (data_id);
+}
+
+PacketDescriptor *
+Experiment::newPacketDescriptor (int kind, DataDescriptor *dDscr)
+{
+ PacketDescriptor *pDscr = new PacketDescriptor (dDscr);
+ pcktDscrs->store (kind, pDscr);
+ return pDscr;
+}
+
+PacketDescriptor *
+Experiment::getPacketDescriptor (int kind)
+{
+ if (kind < 0 || kind >= pcktDscrs->size ())
+ return NULL;
+ return pcktDscrs->fetch (kind);
+}
+
+void
+Experiment::set_clock (int clk)
+{
+ if (clk > 0)
+ {
+ if (maxclock < clk)
+ {
+ maxclock = clk;
+ clock = maxclock;
+ }
+ if (minclock == 0 || minclock > clk)
+ minclock = clk;
+ }
+}
+
+bool
+JThread::is_system ()
+{
+ if (group_name == NULL)
+ return false;
+ return strcmp (group_name, NTXT ("system")) == 0;
+}
+
+void
+Experiment::dump_stacks (FILE *outfile)
+{
+ cstack->print (outfile);
+}
+
+void
+Experiment::dump_map (FILE *outfile)
+{
+ int index;
+ SegMem *s;
+ fprintf (outfile, GTXT ("Experiment %s\n"), get_expt_name ());
+ fprintf (outfile, GTXT ("Address Size (hex) Load time Unload time Checksum Name\n"));
+ Vec_loop (SegMem*, seg_items, index, s)
+ {
+ timestruc_t load;
+ timestruc_t unload;
+ hr2timestruc (&load, (s->load_time - exp_start_time));
+ if (load.tv_nsec < 0)
+ {
+ load.tv_sec--;
+ load.tv_nsec += NANOSEC;
+ }
+ if (s->unload_time == MAX_TIME)
+ {
+ unload.tv_sec = 0;
+ unload.tv_nsec = 0;
+ }
+ else
+ hr2timestruc (&unload, (s->unload_time - exp_start_time));
+ if (load.tv_nsec < 0)
+ {
+ load.tv_sec--;
+ load.tv_nsec += NANOSEC;
+ }
+ fprintf (outfile,
+ "0x%08llx %8lld (0x%08llx) %5ld.%09ld %5ld.%09ld \"%s\"\n",
+ s->base, s->size, s->size, load.tv_sec, load.tv_nsec,
+ unload.tv_sec, unload.tv_nsec, s->obj->get_name ());
+ }
+ fprintf (outfile, NTXT ("\n"));
+}
+
+/**
+ * Copy file to archive
+ * @param name
+ * @param aname
+ * @param hide_msg
+ * @return 0 - success, 1 - error
+ */
+int
+Experiment::copy_file_to_archive (const char *name, const char *aname, int hide_msg)
+{
+ errno = 0;
+ int fd_w = open64 (aname, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ if (fd_w == -1)
+ {
+ if (errno == EEXIST)
+ return 0;
+ fprintf (stderr, GTXT ("er_archive: unable to copy `%s': %s\n"),
+ name, STR (strerror (errno)));
+ return 1;
+ }
+
+ if (dbe_stat_file (name, NULL) != 0)
+ {
+ fprintf (stderr, GTXT ("er_archive: cannot access file `%s': %s\n"),
+ name, STR (strerror (errno)));
+ close (fd_w);
+ return 1;
+ }
+
+ int fd_r = open64 (name, O_RDONLY);
+ if (fd_r == -1)
+ {
+ fprintf (stderr, GTXT ("er_archive: unable to open `%s': %s\n"),
+ name, strerror (errno));
+ close (fd_w);
+ unlink (aname);
+ return 1;
+ }
+
+ if (!hide_msg)
+ fprintf (stderr, GTXT ("Copying `%s' to `%s'\n"), name, aname);
+ bool do_unlink = false;
+ for (;;)
+ {
+ unsigned char buf[65536];
+ int n, n1;
+ n = (int) read (fd_r, (void *) buf, sizeof (buf));
+ if (n <= 0)
+ break;
+ n1 = (int) write (fd_w, buf, n);
+ if (n != n1)
+ {
+ fprintf (stderr, GTXT ("er_archive: unable to write %d bytes to `%s': %s\n"),
+ n, aname, STR (strerror (errno)));
+ do_unlink = true;
+ break;
+ }
+ }
+ close (fd_w);
+
+ struct stat64 s_buf;
+ if (fstat64 (fd_r, &s_buf) == 0)
+ {
+ struct utimbuf u_buf;
+ u_buf.actime = s_buf.st_atime;
+ u_buf.modtime = s_buf.st_mtime;
+ utime (aname, &u_buf);
+ }
+ close (fd_r);
+ if (do_unlink)
+ {
+ if (!hide_msg)
+ fprintf (stderr, GTXT ("er_archive: remove %s\n"), aname);
+ unlink (aname);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Copy file to common archive
+ * Algorithm:
+ * Calculate checksum
+ * Generate file name to be created in common archive
+ * Check if it is not in common archive yet
+ * Copy file to the common archive directory if it is not there yet
+ * Create symbolic link: "aname" -> "caname", where "caname" is the name in common archive
+ * @param name - original file name
+ * @param aname - file name in experiment archive
+ * @param common_archive - common archive directory
+ * @return 0 - success, 1 - error
+ */
+int
+Experiment::copy_file_to_common_archive (const char *name, const char *aname,
+ int hide_msg,
+ const char *common_archive,
+ int relative_path)
+{
+ if (!name || !aname || !common_archive)
+ {
+ if (!name)
+ fprintf (stderr, GTXT ("er_archive: Internal error: file name is NULL\n"));
+ if (!aname)
+ fprintf (stderr, GTXT ("er_archive: Internal error: file name in archive is NULL\n"));
+ if (!common_archive)
+ fprintf (stderr, GTXT ("er_archive: Internal error: path to common archive is NULL\n"));
+ return 1;
+ }
+ // Check if file is already archived
+ if (dbe_stat (aname, NULL) == 0)
+ return 0; // File is already archived
+ // Generate full path to common archive directory
+ char *cad = NULL;
+ char *abs_aname = NULL;
+ if ((common_archive[0] != '/') || (aname[0] != '/'))
+ {
+ long size = pathconf (NTXT ("."), _PC_PATH_MAX);
+ if (size < 0)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(\".\", _PC_PATH_MAX) failed\n"));
+ return 1;
+ }
+ char *buf = (char *) malloc ((size_t) size);
+ if (buf == NULL)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+ return 1;
+ }
+ char *ptr = getcwd (buf, (size_t) size);
+ if (ptr == NULL)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: cannot determine current directory\n"));
+ free (buf);
+ return 1;
+ }
+ if (common_archive[0] != '/')
+ cad = dbe_sprintf (NTXT ("%s/%s"), ptr, common_archive);
+ else
+ cad = dbe_strdup (common_archive);
+ if (aname[0] != '/')
+ abs_aname = dbe_sprintf (NTXT ("%s/%s"), ptr, aname);
+ else
+ abs_aname = dbe_strdup (aname);
+ free (buf);
+ }
+ else
+ {
+ cad = dbe_strdup (common_archive);
+ abs_aname = dbe_strdup (aname);
+ }
+ // Calculate checksum
+ char * errmsg = NULL;
+ uint32_t crcval = get_cksum (name, &errmsg);
+ if (0 == crcval)
+ { // error
+ free (cad);
+ free (abs_aname);
+ if (NULL != errmsg)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: %s\n"), errmsg);
+ free (errmsg);
+ return 1;
+ }
+ fprintf (stderr,
+ GTXT ("er_archive: Fatal error: get_cksum(%s) returned %d\n"),
+ name, crcval);
+ return 1;
+ }
+ // Generate file name to be created in common archive
+ char *fname = get_basename (name);
+ char *abs_caname = dbe_sprintf (NTXT ("%s/%u_%s"), cad, crcval, fname);
+ if (abs_caname == NULL)
+ {
+ free (cad);
+ free (abs_aname);
+ fprintf (stderr,
+ GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+ return 1;
+ }
+ // Check if full name is not too long
+ long len = dbe_sstrlen (abs_caname);
+ long max = pathconf (cad, _PC_PATH_MAX);
+ if ((max < 0) || (len <= 0))
+ { // unknown error
+ fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_PATH_MAX) failed\n"),
+ cad);
+ free (abs_caname);
+ free (cad);
+ free (abs_aname);
+ return 1;
+ }
+ if (len >= max)
+ {
+ // Try to truncate the name
+ if ((len - max) <= dbe_sstrlen (fname))
+ {
+ // Yes, we can do it
+ abs_caname[max - 1] = 0;
+ if (!hide_msg)
+ fprintf (stderr, GTXT ("er_archive: file path is too long - truncated:%s\n"),
+ abs_caname);
+ }
+ }
+ // Check if file name is not too long
+ char *cafname = get_basename (abs_caname);
+ len = dbe_sstrlen (cafname);
+ max = pathconf (cad, _PC_NAME_MAX);
+ if ((max < 0) || (len <= 0))
+ { // unknown error
+ fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_NAME_MAX) failed\n"),
+ cad);
+ free (abs_caname);
+ free (cad);
+ free (abs_aname);
+ return 1;
+ }
+ if (len >= max)
+ {
+ // Try to truncate the name
+ if ((len - max) <= dbe_sstrlen (fname))
+ {
+ // Yes, we can do it
+ cafname[max - 1] = 0;
+ if (!hide_msg)
+ fprintf (stderr, GTXT ("er_archive: file name is too long - truncated:%s\n"),
+ abs_caname);
+ }
+ }
+ // Copy file to the common archive directory if it is not there yet
+ int res = 0;
+ if (dbe_stat_file (abs_caname, NULL) != 0)
+ {
+ // Use temporary file to avoid synchronization problems
+ char *t = dbe_sprintf ("%s/archive_%llx", cad, (unsigned long long) gethrtime());
+ free (cad);
+ // Copy file to temporary file
+ res = copy_file_to_archive (name, t, hide_msg); // hide messages
+ if (res != 0)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to temporary file: %s\n"),
+ name, t);
+ unlink (t);
+ free (t);
+ free (abs_caname);
+ free (abs_aname);
+ return 1;
+ }
+ // Set read-only permissions
+ struct stat64 statbuf;
+ if (0 == dbe_stat_file (name, &statbuf))
+ {
+ mode_t mask = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ mode_t mode = statbuf.st_mode & mask;
+ chmod (t, mode);
+ }
+ // Try to rename temporary file "t" to "abs_caname"
+ // res = link(t, abs_caname); // link() fails on some f/s - use rename()
+ res = rename (t, abs_caname);
+ if (res != 0)
+ {
+ if (errno != EEXIST)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: rename(%s, %s) returned error: %d\n"),
+ t, abs_caname, res);
+ unlink (t);
+ free (t);
+ free (abs_caname);
+ free (abs_aname);
+ return 1;
+ }
+ // File "abs_caname" is already there - continue
+ }
+ unlink (t);
+ free (t);
+ }
+ else
+ free (cad);
+ char *lname = NULL;
+ if (relative_path)
+ {
+ if (common_archive[0] != '/' && aname[0] != '/')
+ {
+ // compare one relative path to another and find common beginning
+ char *rel_caname = dbe_sprintf ("%s/%s", common_archive, cafname);
+ if (rel_caname == NULL)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+ return 1;
+ }
+ lname = get_relative_link (rel_caname, aname);
+ free (rel_caname);
+ }
+ else
+ {
+ if (abs_aname == NULL)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+ return 1;
+ }
+ lname = get_relative_link (abs_caname, abs_aname);
+ }
+ }
+ else // absolute path
+ lname = dbe_strdup (abs_caname);
+ free (abs_aname);
+ if (lname == NULL)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+ return 1;
+ }
+ // Create symbolic link: aname -> lname
+ if (dbe_stat_file (abs_caname, NULL) == 0)
+ {
+ res = symlink (lname, aname);
+ if (res != 0)
+ {
+ fprintf (stderr, GTXT ("er_archive: Fatal error: symlink(%s, %s) returned error: %d (errno=%s)\n"),
+ lname, aname, res, strerror (errno));
+ free (abs_caname);
+ free (lname);
+ return 1;
+ }
+ if (!hide_msg)
+ fprintf (stderr, GTXT ("Created symbolic link %s to file in common archive: %s\n"),
+ aname, lname);
+ }
+ else
+ {
+ fprintf (stderr, GTXT ("er_archive: Internal error: file does not exist in common archive: %s\n"),
+ abs_caname);
+ res = 1;
+ }
+ free (abs_caname);
+ free (lname);
+ return res;
+}
+
+/**
+ * Copy file to archive
+ * @param name
+ * @param aname
+ * @param hide_msg
+ * @param common_archive
+ * @return 0 - success
+ */
+int
+Experiment::copy_file (char *name, char *aname, int hide_msg, char *common_archive, int relative_path)
+{
+ if (common_archive)
+ {
+ if (0 == copy_file_to_common_archive (name, aname, hide_msg,
+ common_archive, relative_path))
+ return 0;
+ // Error. For now - fatal error. Message is already printed.
+ fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to common archive %s\n"),
+ name, common_archive);
+ return 1;
+ }
+ return (copy_file_to_archive (name, aname, hide_msg));
+}
+
+LoadObject *
+Experiment::createLoadObject (const char *path, uint64_t chksum)
+{
+ LoadObject *lo = dbeSession->createLoadObject (path, chksum);
+ if (lo->firstExp == NULL)
+ lo->firstExp = this;
+ return lo;
+}
+
+LoadObject *
+Experiment::createLoadObject (const char *path, const char *runTimePath)
+{
+ DbeFile *df = findFileInArchive (path, runTimePath);
+ if (df && (df->get_stat () == NULL))
+ df = NULL; // No access to file
+ LoadObject *lo = dbeSession->createLoadObject (path, runTimePath, df);
+ if (df && (lo->dbeFile->get_location (false) == NULL))
+ {
+ lo->dbeFile->set_location (df->get_location ());
+ lo->dbeFile->inArchive = df->inArchive;
+ lo->dbeFile->sbuf = df->sbuf;
+ lo->dbeFile->experiment = df->experiment;
+ lo->firstExp = df->experiment;
+ }
+ if (lo->firstExp == NULL)
+ {
+ lo->firstExp = this;
+ lo->dbeFile->experiment = this;
+ }
+ return lo;
+}
+
+SourceFile *
+Experiment::get_source (const char *path)
+{
+ if (founder_exp && (founder_exp != this))
+ return founder_exp->get_source (path);
+ if (sourcesMap == NULL)
+ sourcesMap = new StringMap<SourceFile*>(1024, 1024);
+ if (strncmp (path, NTXT ("./"), 2) == 0)
+ path += 2;
+ SourceFile *sf = sourcesMap->get (path);
+ if (sf)
+ return sf;
+ char *fnm = checkFileInArchive (path, false);
+ if (fnm)
+ {
+ sf = new SourceFile (path);
+ dbeSession->append (sf);
+ DbeFile *df = sf->dbeFile;
+ df->set_location (fnm);
+ df->inArchive = true;
+ df->check_access (fnm); // init 'sbuf'
+ df->sbuf.st_mtime = 0; // Don't check timestamps
+ free (fnm);
+ }
+ else
+ sf = dbeSession->createSourceFile (path);
+ sourcesMap->put (path, sf);
+ return sf;
+}
+
+Vector<Histable*> *
+Experiment::get_comparable_objs ()
+{
+ update_comparable_objs ();
+ if (comparable_objs || dbeSession->expGroups->size () <= 1)
+ return comparable_objs;
+ comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
+ for (long i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->get (i);
+ if (groupId == gr->groupId)
+ {
+ comparable_objs->append (this);
+ continue;
+ }
+ Histable *h = NULL;
+ for (long i1 = 0, sz1 = gr->exps ? gr->exps->size () : 0; i1 < sz1; i1++)
+ {
+ Experiment *exp = gr->exps->get (i1);
+ if ((exp->comparable_objs == NULL) && (dbe_strcmp (utargname, exp->utargname) == 0))
+ {
+ exp->phaseCompareIdx = phaseCompareIdx;
+ h = exp;
+ h->comparable_objs = comparable_objs;
+ break;
+ }
+ }
+ comparable_objs->append (h);
+ }
+ dump_comparable_objs ();
+ return comparable_objs;
+}
+
+DbeFile *
+Experiment::findFileInArchive (const char *fname)
+{
+ if (archiveMap)
+ {
+ char *aname = get_archived_name (fname);
+ DbeFile *df = archiveMap->get (aname);
+ free (aname);
+ return df;
+ }
+ if (founder_exp)
+ return founder_exp->findFileInArchive (fname);
+ return NULL;
+}
+
+DbeFile *
+Experiment::findFileInArchive (const char *className, const char *runTimePath)
+{
+ DbeFile *df = NULL;
+ if (runTimePath)
+ {
+ const char *fnm = NULL;
+ if (strncmp (runTimePath, NTXT ("zip:"), 4) == 0)
+ fnm = runTimePath + 4;
+ else if (strncmp (runTimePath, NTXT ("jar:file:"), 9) == 0)
+ fnm = runTimePath + 9;
+ if (fnm)
+ {
+ const char *s = strchr (fnm, '!');
+ if (s)
+ {
+ char *s1 = dbe_strndup (fnm, s - fnm);
+ df = findFileInArchive (s1);
+ free (s1);
+ }
+ else
+ df = findFileInArchive (fnm);
+ if (df)
+ df->filetype |= DbeFile::F_JAR_FILE;
+ }
+ else if (strncmp (runTimePath, NTXT ("file:"), 5) == 0)
+ {
+ fnm = runTimePath + 5;
+ df = findFileInArchive (fnm);
+ }
+ else
+ df = findFileInArchive (runTimePath);
+ }
+ if (df == NULL)
+ df = findFileInArchive (className);
+ return df;
+}
diff --git a/gprofng/src/Experiment.h b/gprofng/src/Experiment.h
new file mode 100644
index 0000000..41c44e4
--- /dev/null
+++ b/gprofng/src/Experiment.h
@@ -0,0 +1,689 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _EEXPERIMENT_H
+#define _EEXPERIMENT_H
+
+// The experiment class is responsible for managing all the data
+// for an individual experiment
+
+#include "Metric.h"
+#include "Histable.h"
+#include "Stats_data.h"
+#include "DefaultMap.h"
+#include "HeapMap.h"
+
+class Data_window;
+class DbeFile;
+class CallStack;
+class JMethod;
+class Sample;
+class SegMem;
+class LoadObject;
+class SourceFile;
+class UserLabel;
+class PRBTree;
+class Emsg;
+class Emsgqueue;
+struct JThread;
+struct GCEvent;
+class FileData;
+class Module;
+class Experiment;
+template <class ITEM> class Vector;
+
+#define JTHREAD_DEFAULT ((JThread*)0)
+#define JTHREAD_NONE ((JThread*)-1)
+
+// When we perform the pipelined optimization on resolve_frame_info() and add_stack()
+// this is the number of iterations one phase works on before passing on the work to
+// the next phase
+
+#define CSTCTX_CHUNK_SZ 10000
+#define PIPELINE_QUEUE_SZ_HI 8
+#define PIPELINE_QUEUE_SZ_LOW 2
+
+// the add_stack_ctx structure contains the intermediate state (context) after
+// CSTCTX_CHUNK_SZ number of iterations to pass on the work to another thread to
+// operate on the next stage
+typedef struct
+{
+ Vector<DbeInstr*> *natpcs;
+ Vector<Histable*> *jpcs;
+ long idx;
+ FramePacket *frp;
+ hrtime_t tstamp;
+ uint32_t thrid;
+ bool last_ctx;
+} cstk_ctx;
+
+// To minimize threadpool overhead, the granularity of a job submitted is made larger:
+// containing a chunk of iterations (of size CSTCTX_CHUNK_SZ)
+typedef struct
+{
+ cstk_ctx* cstCtxAr[CSTCTX_CHUNK_SZ];
+ int last_idx;
+ long idx_begin;
+ long idx_end;
+ DataDescriptor *dDscr;
+ Experiment *exp;
+ void *cstk;
+} cstk_ctx_chunk;
+
+class Experiment : public Histable, public DbeMessages
+{
+public:
+
+ enum Exp_status
+ {
+ SUCCESS,
+ INCOMPLETE,
+ FAILURE
+ };
+
+ Experiment ();
+ virtual ~Experiment ();
+
+ virtual Histable_type
+ get_type ()
+ {
+ return EXPERIMENT;
+ };
+ virtual Vector<Histable*> *get_comparable_objs ();
+
+ int groupId;
+ Experiment *founder_exp; // parent of this experiment
+ Vector<Experiment*> *children_exps; // children of this experiment
+
+ // Configuration Information
+ char *hostname; // Hosthame (e.g. mymachine)
+ long start_sec; // Starting timeval secs.
+ char *username; // name of person performing the test
+ char *architecture; // Architecture name ("sun4")
+ Platform_t platform; // Sparc,Sparcv9,Intel
+ WSize_t wsize; // word size: may be w32 or w64
+ int clock; // CPU clock frequency, Mhz
+ int varclock; // Set if CPU clock frequency can change: turbo-mode
+ int maxclock; // max. CPU clock frequency on MP machine
+ int minclock; // min. CPU clock frequency on MP machine
+ int ncpus; // count of CPUs where expt was recorded
+ int hw_cpuver; // CPU version from libcpc
+ char *machinemodel; // machine model of machine on which experiment was recorded
+ char *os_version; // Operating system name
+ int page_size; // Page size (bytes)
+ int npages; // Number of page size
+ int exp_maj_version; // major version number of current experiment
+ int exp_min_version; // minor version number of current experiment
+ int hex_field_width; // number of digits in hex form of address
+ // for current experiment, i.e. 8 for 32bit addresses
+ int broken; // If SP_JCMD_RUN line not seen
+ int obsolete; // If pointer file experiment detected
+ bool hwc_default; // True if HW counters were enabled by default
+ int hwc_bogus; // Count of bogus HWC packets
+ int hwc_lost_int; // Count of packets reflecting lost interrupt
+ int hwc_scanned; // If the HWC packets have been scanned
+ int invalid_packet; // Count of invalid packets
+ bool exec_started; // True if exec was called, and exec error not yet seen
+ bool dataspaceavail; // True if dataspace data is in the experiment
+ bool leaklistavail; // True if leaklist data is in the experiment
+ bool heapdataavail; // True if heap data is in the experiment
+ bool racelistavail; // true if there are race events in the experiment
+ bool iodataavail; // true if there are io events in the experiment
+ bool deadlocklistavail; // true if there are deadlock events in the experiment
+ bool timelineavail; // true if there are valid timestamps in the experiment
+ bool ifreqavail; // True if instruction-frequency data is in the experiment
+ bool ompavail; // true if there is OpenMP data in the experiment
+ bool has_java;
+ char *uarglist; // argv[] array, as a string
+ char *utargname; // basename of argv[0] extracted from uarglist
+ char *ucwd; // working directory
+ char *cversion; // collector version string
+ char *dversion; // driver version string (er_kernel)
+ char *jversion; // Java version string (java profiling)
+
+ // Open the named experiment record and process log file
+ Exp_status open (char *directory_name);
+
+ // Update experiment (read and process new data)
+ Exp_status update ();
+
+ // Returns collector parameters for the current sample selection
+ Collection_params *
+ get_params ()
+ {
+ return &coll_params;
+ }
+
+ Exp_status
+ get_status ()
+ {
+ return status;
+ }
+
+ // Returns the number of samples. For use by FilterNumeric
+ int
+ nsamples ()
+ {
+ return samples->size ();
+ }
+
+ // Release any releasable memory.
+ void purge ();
+
+ void resetShowHideStack ();
+ int save_notes (char*, bool);
+ int delete_notes (bool);
+ Experiment *getBaseFounder (); // returns topmost founder or this if no descendents
+
+ hrtime_t
+ getStartTime ()
+ {
+ return exp_start_time;
+ }
+ hrtime_t getRelativeStartTime (); // delta between start and founder's start
+
+ hrtime_t
+ getWallStartSec ()
+ {
+ return start_sec;
+ }
+
+ hrtime_t
+ getLastEvent ()
+ {
+ if (last_event != ZERO_TIME)
+ return last_event;
+ return exp_start_time;
+ }
+
+ hrtime_t
+ getGCDuration ()
+ {
+ return gc_duration;
+ }
+
+ int
+ getPID ()
+ {
+ return pid;
+ }
+
+ int
+ getUserExpId ()
+ {
+ return userExpId;
+ }
+
+ int
+ getExpIdx ()
+ {
+ return expIdx;
+ }
+
+ void
+ setExpIdx (int idx)
+ {
+ expIdx = idx;
+ }
+
+ void
+ setUserExpId (int idx)
+ {
+ userExpId = idx;
+ }
+
+ void
+ setTinyThreshold (int limit)
+ {
+ tiny_threshold = limit;
+ }
+
+ bool
+ isDiscardedTinyExperiment ()
+ {
+ return discardTiny;
+ }
+
+ Exp_status open_epilogue ();
+ void read_experiment_data (bool read_ahead);
+ static int copy_file_to_archive (const char *name, const char *aname, int hide_msg);
+ static int copy_file_to_common_archive (const char *name, const char *aname,
+ int hide_msg, const char *common_archive, int relative_path = 0);
+ static int copy_file (char *name, char *aname, int hide_msg,
+ char *common_archive = NULL, int relative_path = 0);
+
+ // get_raw_events()
+ // action: get unfiltered packets, loading them if required
+ // parameters: data_id (see ProfData_type)
+ DataDescriptor *get_raw_events (int data_id);
+ Vector<DataDescriptor*> *getDataDescriptors ();
+
+ // Some DATA_* types are derived from others, e.g. DATA_HEAPSZ is derived from DATA_HEAP
+ // The following hooks support derived DataViews
+ int base_data_id (int data_id); // returns base data_id type (ProfData_type DATA_*)
+ DataView *create_derived_data_view (int data_id, DataView *dview);
+
+ Vector<BaseMetric*>*
+ get_metric_list ()
+ {
+ return metrics;
+ }
+
+ char *
+ get_expt_name ()
+ {
+ return expt_name; // Return the pathname to the experiment
+ };
+
+ Vector<char*> *get_descendants_names ();
+ char *get_fndr_arch_name ();
+ char *get_arch_name ();
+ char *getNameInArchive (const char *fname, bool archiveFile = false);
+ char *checkFileInArchive (const char *fname, bool archiveFile = false);
+ DbeFile *findFileInArchive (const char *className, const char *runTimePath);
+ DbeFile *findFileInArchive (const char *fname);
+ bool create_dir (char *dname);
+
+ Vaddr
+ ret_stack_base ()
+ {
+ return stack_base;
+ };
+
+ // Map a virtual address to a PC pair
+ DbeInstr *map_Vaddr_to_PC (Vaddr addr, hrtime_t ts);
+ DbeInstr *map_jmid_to_PC (Vaddr mid, int lineno, hrtime_t ts);
+ Sample *map_event_to_Sample (hrtime_t ts);
+ GCEvent *map_event_to_GCEvent (hrtime_t ts);
+
+ DataView *
+ getOpenMPdata ()
+ {
+ return openMPdata;
+ }
+
+ time_t
+ get_mtime ()
+ {
+ return mtime;
+ }
+
+ Emsg *fetch_comments (void); // fetch the queue of comment messages
+ Emsg *fetch_runlogq (void); // fetch the queue of run log messages
+ Emsg *fetch_errors (void); // fetch the queue of error messages
+ Emsg *fetch_warnings (void); // fetch the queue of warning messages
+ Emsg *fetch_notes (void); // fetch the queue of notes messages
+ Emsg *fetch_ifreq (void); // fetch the queue of ifreq messages
+ Emsg *fetch_pprocq (void); // fetch the queue of post-processing messages
+
+ // message queues
+ Emsgqueue *commentq; // comments for the experiment header
+ Emsgqueue *runlogq; // used temporarily; after log file processing,
+ // messages are appended to the commentq
+ Emsgqueue *errorq; // error messages
+ Emsgqueue *warnq; // warning messages
+ Emsgqueue *notesq; // user-written notes messages
+ Emsgqueue *pprocq; // postprocessing messages
+ Emsgqueue *ifreqq; // Instruction frequency data, from count experiment
+ Map<const char*, LoadObject*> *loadObjMap;
+ Vector<LoadObject*> *loadObjs;
+ void append (LoadObject *lo);
+ LoadObject *createLoadObject (const char *path, uint64_t chksum = 0);
+ LoadObject *createLoadObject (const char *path, const char *runTimePath);
+ SourceFile *get_source (const char *path);
+ void set_clock (int clk);
+
+ CallStack *
+ callTree ()
+ {
+ return cstack;
+ }
+
+ CallStack *
+ callTreeShowHide ()
+ {
+ return cstackShowHide;
+ }
+
+ uint32_t mapTagValue (Prop_type, uint64_t value);
+ Histable *getTagObj (Prop_type, uint32_t idx);
+ Vector<Histable*> *getTagObjs (Prop_type);
+
+ JThread *map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp);
+ JThread *get_jthread (uint32_t tid);
+
+ Vector<JThread*> *
+ get_jthreads ()
+ {
+ return jthreads;
+ }
+
+ Vector<GCEvent*> *
+ get_gcevents ()
+ {
+ return gcevents;
+ }
+
+ bool need_swap_endian;
+ Collection_params coll_params; // Collection params
+
+ // Ranges for threads, lwps, cpu
+ uint64_t min_thread;
+ uint64_t max_thread;
+ uint64_t thread_cnt;
+ uint64_t min_lwp;
+ uint64_t max_lwp;
+ uint64_t lwp_cnt;
+ uint64_t min_cpu;
+ uint64_t max_cpu;
+ uint64_t cpu_cnt;
+ uint64_t dsevents; // count of dataspace events
+ uint64_t dsnoxhwcevents; /* count of ds events that could be be validated
+ * because of no branch target info */
+
+ PacketDescriptor *newPacketDescriptor (int kind, DataDescriptor *dDscr);
+ PacketDescriptor *getPacketDescriptor (int kind);
+
+ // debugging aids -- dump_stacks, dump_map
+ void dump_stacks (FILE *);
+ void dump_map (FILE *);
+
+ // These methods are used in nightly performance regression testing
+ void DBG_memuse (Sample *);
+ void DBG_memuse (const char *sname);
+ void init_cache ();
+
+ DefaultMap<int64_t, FileData*> *
+ getFDataMap ()
+ {
+ return fDataMap;
+ }
+ CallStack *cstack;
+
+protected:
+
+ Exp_status status; // Error status
+ Vector<SegMem*> *seg_items; // Master list of seg_items
+ CallStack *cstackShowHide;
+ PRBTree *maps; // All maps in (Vaddr,time)
+
+ hrtime_t gc_duration; // wall-clock hrtime of total GC intervals
+ hrtime_t exp_start_time; // wall-clock hrtime at exp start
+ hrtime_t last_event; // wall-clock hrtime of last known sample or log.xml entry
+ hrtime_t non_paused_time; // sum of periods where data collection is active (not paused)
+ hrtime_t resume_ts; // tracks log.xml start/resume times
+ void update_last_event (hrtime_t ts /*wall time (not 0-based)*/);
+
+ char *expt_name; // name of experiment
+ char *arch_name; // <experiment>/archive
+ char *fndr_arch_name; // <founder_experiment>/archive
+ //TBR? hrtime_t sample_time; // total of sample durations
+ int yyparse (); // Allow yyparse actions to access
+ Vaddr stack_base; // Stack base
+
+ // Write experiment header to comment queue
+ void write_header ();
+ void write_coll_params ();
+
+ Exp_status find_expdir (char *directory_name);
+
+ // Invoke the parser to process a file.
+ void read_data_file (const char*, const char*);
+ int read_log_file ();
+ void read_labels_file ();
+ void read_notes_file ();
+ void read_archives ();
+ int read_java_classes_file ();
+ void read_map_file ();
+ int read_overview_file ();
+ int read_dyntext_file ();
+ void read_omp_file ();
+ void read_omp_preg ();
+ void read_omp_task ();
+ void read_ifreq_file ();
+ void read_frameinfo_file ();
+
+ // Functions to process the log and loadobjects file entries
+ // They are deliberately made virtual to overload them
+ // in er_export.
+ virtual int process_arglist_cmd (char *, char *);
+ virtual int process_desc_start_cmd (char *, hrtime_t, char *, char *, int, char *);
+ virtual int process_desc_started_cmd (char *, hrtime_t, char *, char *, int, char *);
+ virtual int process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr, int fsize, hrtime_t ts);
+ virtual int process_fn_unload_cmd (char *, Vaddr, hrtime_t);
+ virtual int process_hwcounter_cmd (char *, int, char *, char *, int, int, int, char *);
+ virtual int process_hwsimctr_cmd (char *, int, char *, char *, char*, int, int, int, int, int);
+ virtual int process_jcm_load_cmd (char*, Vaddr, Vaddr, int, hrtime_t);
+ virtual int process_jcm_unload_cmd (char*, Vaddr, hrtime_t);
+ virtual int process_Linux_kernel_cmd (hrtime_t);
+ virtual int process_jthr_end_cmd (char *, uint64_t, Vaddr, Vaddr, hrtime_t);
+ virtual int process_jthr_start_cmd (char *, char *, char *, char *, uint64_t, Vaddr, Vaddr, hrtime_t);
+ virtual int process_gc_end_cmd (hrtime_t);
+ virtual int process_gc_start_cmd (hrtime_t);
+ virtual int process_sample_cmd (char *, hrtime_t, int id, char *lbl);
+ virtual int process_sample_sig_cmd (char *, int);
+ virtual int process_seg_map_cmd (char *, hrtime_t, Vaddr, int, int, int64_t, int64_t, int64_t, char *);
+ virtual int process_seg_unmap_cmd (char *, hrtime_t, Vaddr);
+
+ // creation time for experiment
+ time_t mtime;
+ hrtime_t exp_rel_start_time; // start of exp. relative to founder
+ bool exp_rel_start_time_set;
+ Vector<UserLabel*> *userLabels; // List of er_labels
+ int userExpId; // user value for EXPID
+ int expIdx; // DbeSession exp identifier
+ PRBTree *jmaps; // JAVA_CLASSES: (id,time)->Histable
+ Experiment* baseFounder; // outermost experiment (null until lazily computed)
+
+ // Represents a file in experiment
+ class ExperimentFile;
+
+ // XML handler to parse various experiment files
+ class ExperimentHandler;
+ class ExperimentLabelsHandler;
+
+ uint64_t readPacket (Data_window *dwin, Data_window::Span *span);
+ void readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
+ DataDescriptor *dDscr, int arg, uint64_t pktsz);
+
+ // read data
+ DataDescriptor *get_profile_events ();
+ DataDescriptor *get_sync_events ();
+ DataDescriptor *get_hwc_events ();
+ DataDescriptor *get_heap_events ();
+ DataDescriptor *get_heapsz_events ();
+ DataDescriptor *get_iotrace_events ();
+ DataDescriptor *get_race_events ();
+ DataDescriptor *get_deadlock_events ();
+ DataDescriptor *get_sample_events ();
+ DataDescriptor *get_gc_events ();
+ DataDescriptor *getDataDescriptor (int data_id);
+ DataDescriptor *newDataDescriptor (int data_id, int flags = 0,
+ DataDescriptor *master_dDscr = NULL);
+
+ // Frame info data structures and methods
+ struct UIDnode;
+ struct RawFramePacket;
+
+ Vector<RawFramePacket*>*frmpckts; // frame info data
+ static int frUidCmp (const void*, const void*);
+ RawFramePacket *find_frame_packet (uint64_t uid);
+
+ static const int CHUNKSZ = 16384;
+ long nnodes;
+ long nchunks;
+ UIDnode **chunks;
+ UIDnode **uidHTable;
+ Vector<UIDnode*> *uidnodes;
+ bool resolveFrameInfo;
+ bool discardTiny;
+ int tiny_threshold; /* optimize away tiny experiments which ran
+ * for less than specified time (ms): default 0 */
+
+ static int uidNodeCmp (const void *a, const void *b);
+ UIDnode *add_uid (Data_window *dwin, uint64_t uid, int size, uint32_t *array, uint64_t link_uid);
+ UIDnode *add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid);
+ UIDnode *new_uid_node (uint64_t uid, uint64_t val);
+ UIDnode *get_uid_node (uint64_t uid, uint64_t val);
+ UIDnode *get_uid_node (uint64_t uid);
+ UIDnode *find_uid_node (uint64_t uid);
+
+ ExperimentFile *logFile;
+
+ // Data descriptors
+ Vector<DataDescriptor*> *dataDscrs;
+ Vector<PacketDescriptor*> *pcktDscrs;
+ long blksz; // binary data file block size
+
+ // Processed data packets
+ DataView *openMPdata; // OMP fork events
+
+ // Map events to OpenMP parallel regions and tasks
+ Map2D<uint32_t, hrtime_t, uint64_t> *mapPRid;
+ Map2D<uint32_t, hrtime_t, void*> *mapPReg;
+ Map2D<uint32_t, hrtime_t, void*> *mapTask;
+
+ // Archive content
+ Map<const char*, DbeFile *> *archiveMap;
+ Map<const char*, SourceFile*>*sourcesMap;
+
+ void init ();
+ void fini ();
+ void post_process ();
+ void constructJavaStack (FramePacket *, UIDnode *, Map<uint64_t, uint64_t> *);
+ void resolve_frame_info (DataDescriptor*);
+ void cleanup_cstk_ctx_chunk ();
+ void register_metric (Metric::Type type);
+ void register_metric (Hwcentry *ctr, const char* aux, const char* username);
+
+ Sample *sample_last_used;
+ GCEvent *gcevent_last_used;
+ char *first_sample_label;
+ Module *get_jclass (const char *className, const char *fileName);
+ LoadObject *get_j_lo (const char *className, const char *fileName);
+
+ Vector<BaseMetric*> *metrics;
+ Vector<JThread*> *jthreads; // master list of Java threads
+ Vector<JThread*> *jthreads_idx; // index in the master list
+ Vector<GCEvent*> *gcevents;
+ Vector<UnmapChunk*> *heapUnmapEvents;
+ Vector<Sample*> *samples; // Array of Sample pointers
+
+ DefaultMap<int64_t, FileData*> *fDataMap; // list of FileData objects using the virtual File descriptor as the key
+ DefaultMap<int, int64_t> *vFdMap; // list of virtual file descrptors using the file descriptor as the key
+
+ Vector<Vector<Histable*>*> *tagObjs; // tag objects
+ bool sparse_threads;
+
+ SegMem **smemHTable; // hash table for SegMem's
+ DbeInstr **instHTable; // hash table for DbeInstr
+ Map<unsigned long long, JMethod*> *jmidHTable; // hash table for jmid
+
+ // identity of target process
+ int pid;
+ int ppid;
+ int pgrp;
+ int sid;
+
+ // Map file processing related data
+ struct MapRecord
+ {
+
+ enum
+ {
+ LOAD, UNLOAD
+ } kind;
+ Histable *obj;
+ Vaddr base;
+ Size size;
+ hrtime_t ts;
+ uint64_t foff;
+ };
+
+ void mrec_insert (MapRecord *mrec);
+ SegMem *update_ts_in_maps (Vaddr addr, hrtime_t ts);
+ int read_warn_file ();
+ LoadObject *get_dynfunc_lo (const char *loName);
+ Function *create_dynfunc (Module *mod, char *fname, int64_t vaddr, int64_t fsize);
+ char *get_archived_name (const char *fname, bool archiveFile = false);
+
+ Vector<MapRecord*> *mrecs;
+
+private:
+ void add_evt_time_to_profile_events (DataDescriptor *dDscr);
+ DataView *create_heapsz_data_view (DataView *heap_dview);
+ void compute_heapsz_data_view (DataView *heapsz_dview);
+};
+
+struct JThread
+{
+ JThread *next;
+ char *name;
+ char *group_name;
+ char *parent_name;
+ uint32_t tid; // system thread id
+ Vaddr jthr; // recorded Java thread id
+ Vaddr jenv; // recorded JNIEnv id
+ uint32_t jthr_id; // internal JThread object id
+ hrtime_t start;
+ hrtime_t end;
+
+ JThread ()
+ {
+ name = NULL;
+ group_name = NULL;
+ parent_name = NULL;
+ }
+
+ ~JThread ()
+ {
+ free (name);
+ free (group_name);
+ free (parent_name);
+ }
+ bool is_system ();
+};
+
+struct GCEvent
+{
+
+ GCEvent ()
+ {
+ id = -1;
+ }
+
+ ~GCEvent () { }
+
+ hrtime_t start;
+ hrtime_t end;
+ int id;
+};
+
+class ExperimentLoadCancelException
+{
+public:
+
+ ExperimentLoadCancelException () { };
+
+ ~ExperimentLoadCancelException () { };
+};
+
+
+#endif /* _EEXPERIMENT_H */
diff --git a/gprofng/src/Expression.cc b/gprofng/src/Expression.cc
new file mode 100644
index 0000000..49c94a8
--- /dev/null
+++ b/gprofng/src/Expression.cc
@@ -0,0 +1,1279 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include "CallStack.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "DataObject.h"
+#include "Exp_Layout.h"
+#include "Experiment.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Expression.h"
+#include "Function.h"
+#include "Histable.h"
+#include "Sample.h"
+#include "Table.h"
+
+//////////////////////////////////////////////////////////
+// class Expression::Context
+
+static const uint64_t INDXOBJ_EXPGRID_SHIFT = 60;
+static const uint64_t INDXOBJ_EXPID_SHIFT = 32;
+
+Expression::Context::Context (DbeView *_dbev, Experiment *_exp)
+{
+ dbev = _dbev;
+ exp = _exp;
+ dview = NULL;
+ eventId = 0;
+}
+
+Expression::Context::Context (DbeView *_dbev, Experiment *_exp,
+ DataView *_dview, long _eventId)
+{
+ dbev = _dbev;
+ exp = _exp;
+ dview = _dview;
+ eventId = _eventId;
+}
+
+//////////////////////////////////////////////////////////
+// class Expression
+Expression::Expression (OpCode _op, uint64_t _v)
+{
+ op = _op;
+ v = Value (_v);
+ arg0 = NULL;
+ arg1 = NULL;
+}
+
+Expression::Expression (OpCode _op, const Expression *_arg0,
+ const Expression *_arg1)
+{
+ op = _op;
+ v = Value ();
+ arg0 = NULL;
+ arg1 = NULL;
+ if (_arg0)
+ arg0 = _arg0->copy ();
+ if (_arg1)
+ arg1 = _arg1->copy ();
+}
+
+Expression::~Expression ()
+{
+ delete arg0;
+ delete arg1;
+}
+
+Expression::Expression (const Expression &rhs)
+{
+ op = rhs.op;
+ arg0 = NULL;
+ arg1 = NULL;
+ if (rhs.arg0)
+ arg0 = rhs.arg0->copy ();
+ if (rhs.arg1)
+ arg1 = rhs.arg1->copy ();
+ v = Value (rhs.v);
+ fixupValues ();
+}
+
+Expression::Expression (const Expression *rhs)
+{
+ arg0 = NULL;
+ arg1 = NULL;
+ copy (rhs);
+}
+
+void
+Expression::copy (const Expression *rhs)
+{
+ op = rhs->op;
+ delete arg0;
+ delete arg1;
+ arg0 = NULL;
+ arg1 = NULL;
+ if (rhs->arg0)
+ arg0 = rhs->arg0->copy ();
+ if (rhs->arg1)
+ arg1 = rhs->arg1->copy ();
+ v = Value (rhs->v);
+ fixupValues ();
+}
+
+Expression &
+Expression::operator= (const Expression &rhs)
+{
+ if (this == &rhs)
+ return *this;
+ copy (&rhs);
+ return *this;
+}
+
+void
+Expression::fixupValues ()
+{
+ if (v.next)
+ {
+ assert (arg0 && v.next == &(arg0->v));
+ v.next = &(arg0->v);
+ }
+}
+
+bool
+Expression::getVal (int propId, Context *ctx)
+{
+ v.val = 0;
+ v.next = NULL;
+ int origPropId = propId;
+ switch (propId)
+ {
+ default:
+ {
+ if (!ctx->dview)
+ return false;
+ PropDescr *propDscr = ctx->dview->getProp (propId);
+ if (!propDscr)
+ return false;
+ switch (propDscr->vtype)
+ {
+ case TYPE_INT32:
+ v.val = ctx->dview->getIntValue (propId, ctx->eventId);
+ break;
+ case TYPE_UINT32:
+ v.val = (uint32_t) ctx->dview->getIntValue (propId, ctx->eventId); //prevent sign extension
+ break;
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ v.val = ctx->dview->getLongValue (propId, ctx->eventId);
+ break;
+ case TYPE_OBJ:
+ // YM: not sure if we should allow this
+ v.val = (long long) ctx->dview->getObjValue (propId, ctx->eventId);
+ break;
+ case TYPE_STRING:
+ case TYPE_DOUBLE:
+ default:
+ return false; // Weird, programming error?
+ }
+ break;
+ }
+ case PROP_FREQ_MHZ:
+ if (ctx->exp && ctx->exp->clock)
+ v.val = ctx->exp->clock;
+ else
+ return false;
+ break;
+ case PROP_PID:
+ if (ctx->exp == NULL)
+ return false;
+ v.val = ctx->exp->getPID ();
+ break;
+ case PROP_EXPID:
+ if (ctx->exp == NULL)
+ return false;
+ v.val = ctx->exp->getUserExpId ();
+ break;
+ case PROP_EXPID_CMP:
+ if (ctx->exp == NULL)
+ return false;
+ else
+ {
+ Experiment *exp = ctx->exp;
+ if (ctx->dbev && ctx->dbev->comparingExperiments ())
+ exp = (Experiment *) exp->get_compare_obj ();
+ v.val = exp->getUserExpId ();
+ }
+ break;
+ case PROP_EXPGRID:
+ if (ctx->exp == NULL)
+ return false;
+ v.val = ctx->exp->groupId;
+ break;
+ case PROP_NTICK_USEC:
+ if (ctx->exp == NULL)
+ return false;
+ if (ctx->dview && ctx->dview->getProp (PROP_NTICK))
+ v.val = ctx->dview->getIntValue (PROP_NTICK, ctx->eventId)
+ * ctx->exp->get_params ()->ptimer_usec;
+ else
+ return false;
+ break;
+ case PROP_ATSTAMP:
+ case PROP_ETSTAMP:
+ if (ctx->exp == NULL)
+ return false;
+ if (ctx->dview && ctx->dview->getProp (PROP_TSTAMP))
+ v.val = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+ else
+ return false;
+ if (propId == PROP_ATSTAMP)
+ break; // absolute time, no adjustments
+ // propId==PROP_ETSTAMP
+ // calculate relative time from start of this experiment
+ v.val -= ctx->exp->getStartTime ();
+ break;
+ case PROP_TSTAMP:
+ case PROP_TSTAMP_LO:
+ case PROP_TSTAMP_HI:
+ {
+ if (ctx->exp == NULL)
+ return false;
+ if (!(ctx->dview && ctx->dview->getProp (PROP_TSTAMP)))
+ return false;
+ hrtime_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+ // compute relative time from start of founder experiment
+ v.val = tstamp - ctx->exp->getStartTime ()
+ + ctx->exp->getRelativeStartTime ();
+ if (propId == PROP_TSTAMP)
+ break;
+ if (ctx->dview->getProp (PROP_EVT_TIME))
+ {
+ hrtime_t delta = ctx->dview->getLongValue (PROP_EVT_TIME, ctx->eventId);
+ if (propId == PROP_TSTAMP_LO)
+ {
+ if (delta > 0)
+ { // positive delta means TSTAMP is at end
+ // TSTAMP_LO = TSTAMP-delta
+ v.val -= delta;
+ break;
+ }
+ break;
+ }
+ else
+ { // PROP_TSTAMP_HI
+ if (delta < 0)
+ { // negative delta means TSTAMP is at start
+ // TSTAMP_HI = TSTAMP+(-delta)
+ v.val -= delta;
+ break;
+ }
+ break;
+ }
+ }
+ else if (ctx->dview->getProp (PROP_TSTAMP2))
+ {
+ if (propId == PROP_TSTAMP_HI)
+ {
+ hrtime_t tstamp2 = ctx->dview->getLongValue (PROP_TSTAMP2,
+ ctx->eventId);
+ if (tstamp2 == 0)
+ break; // if not initialized, event does not have duration
+ if (tstamp2 == MAX_TIME)
+ tstamp2 = ctx->exp->getLastEvent ();
+ hrtime_t delta = tstamp2 - tstamp;
+ if (delta >= 0)
+ {
+ v.val += delta;
+ break;
+ }
+ break; // weird, delta should not be negative
+ }
+ break; // PROP_TSTAMP_LO, no modification needed
+ }
+ break; // should never be hit
+ }
+ case PROP_IOHEAPBYTES:
+ {
+ propId = PROP_IONBYTE;
+ if (ctx->dview == NULL)
+ return false;
+ if (!ctx->dview->getProp (propId))
+ { // has property?
+ propId = PROP_HSIZE;
+ if (!ctx->dview->getProp (propId))
+ return false;
+ }
+ v.val = ctx->dview->getLongValue (propId, ctx->eventId);
+ break;
+ }
+ case PROP_SAMPLE_MAP:
+ {
+ if (ctx->exp == NULL)
+ return false;
+ if (ctx->dview == NULL)
+ return false;
+ if (ctx->dview->getProp (PROP_SAMPLE))
+ v.val = ctx->dview->getIntValue (PROP_SAMPLE, ctx->eventId);
+ else
+ { // does not have property, convert to time.
+ uint64_t tstamp;
+ tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+ Sample *sample = ctx->exp->map_event_to_Sample (tstamp);
+ v.val = sample ? sample->get_number () : -1;
+ }
+ break;
+ }
+ case PROP_GCEVENT_MAP:
+ {
+ if (ctx->exp == NULL)
+ return false;
+ if (ctx->dview == NULL)
+ return false;
+ if (ctx->dview->getProp (PROP_GCEVENT))
+ v.val = ctx->dview->getIntValue (PROP_GCEVENT, ctx->eventId);
+ else
+ { // does not have property, convert to time.
+ uint64_t tstamp;
+ tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+ GCEvent *gcevent = ctx->exp->map_event_to_GCEvent (tstamp);
+ v.val = gcevent ? gcevent->id : 0;
+ }
+ break;
+ }
+ case PROP_LEAF:
+ {
+ if (ctx->dview == NULL)
+ return false;
+ VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
+ int prop_id;
+ if (vmode == VMODE_MACHINE)
+ prop_id = PROP_MSTACK;
+ else if (vmode == VMODE_EXPERT)
+ prop_id = PROP_XSTACK;
+ else
+ prop_id = PROP_USTACK;
+ if (!ctx->dview->getProp (prop_id))
+ return false;
+ Histable *obj = CallStack::getStackPC (ctx->dview->getObjValue (prop_id, ctx->eventId), 0);
+ Function *func = (Function*) obj->convertto (Histable::FUNCTION);
+ v.val = func->id; // LEAF
+ break;
+ }
+ case PROP_STACKID:
+ {
+ VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
+ if (vmode == VMODE_MACHINE)
+ propId = PROP_MSTACK;
+ else if (vmode == VMODE_EXPERT)
+ propId = PROP_XSTACK;
+ else
+ propId = PROP_USTACK;
+ if (ctx->dview == NULL)
+ return false;
+ if (!ctx->dview->getProp (propId))
+ return false;
+ v.val = (long) ctx->dview->getObjValue (propId, ctx->eventId);
+ break;
+ }
+ case PROP_STACKL:
+ case PROP_STACKI:
+ case PROP_STACK:
+ {
+ VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
+ if (vmode == VMODE_MACHINE)
+ propId = PROP_MSTACK;
+ else if (vmode == VMODE_EXPERT)
+ propId = PROP_XSTACK;
+ else
+ propId = PROP_USTACK;
+ }
+ // no break;
+ case PROP_MSTACKL:
+ case PROP_XSTACKL:
+ case PROP_USTACKL:
+ case PROP_MSTACKI:
+ case PROP_XSTACKI:
+ case PROP_USTACKI:
+ switch (propId)
+ {
+ case PROP_MSTACKL:
+ case PROP_MSTACKI:
+ propId = PROP_MSTACK;
+ break;
+ case PROP_XSTACKL:
+ case PROP_XSTACKI:
+ propId = PROP_XSTACK;
+ break;
+ case PROP_USTACKL:
+ case PROP_USTACKI:
+ propId = PROP_USTACK;
+ break;
+ default:
+ break;
+ }
+ // no break;
+ case PROP_MSTACK:
+ case PROP_XSTACK:
+ case PROP_USTACK:
+ {
+ if (ctx->dview == NULL)
+ return false;
+ if (!ctx->dview->getProp (propId))
+ return false;
+ bool hide_mode = !ctx->dbev->isShowAll ()
+ || ctx->dbev->isFilterHideMode ();
+ Expression *cur = this;
+ for (CallStackNode *stack = (CallStackNode *)
+ ctx->dview->getObjValue (propId, ctx->eventId);
+ stack; stack = stack->get_ancestor ())
+ {
+ Histable *hist = stack->get_instr ();
+ if (origPropId == PROP_STACK || origPropId == PROP_MSTACK
+ || origPropId == PROP_XSTACK || origPropId == PROP_USTACK)
+ {
+ cur->v.val = hist->convertto (Histable::FUNCTION)->id;
+ cur->v.fn = cur->v.val;
+ }
+ else if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL
+ || origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL)
+ {
+ cur->v.val = hist->convertto (Histable::LINE)->id;
+ if (hide_mode)
+ cur->v.fn = hist->convertto (Histable::FUNCTION)->id;
+ else
+ cur->v.fn = 0;
+ }
+ else if (origPropId == PROP_STACKI || origPropId == PROP_MSTACKI
+ || origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI)
+ {
+ cur->v.val = hist->convertto (Histable::INSTR)->id;
+ if (hide_mode)
+ cur->v.fn = hist->convertto (Histable::FUNCTION)->id;
+ else
+ cur->v.fn = 0;
+ }
+ if (cur->arg1 == NULL)
+ cur->arg1 = new Expression (OP_NONE, (uint64_t) 0);
+ if (stack->get_ancestor () == NULL)
+ {
+ if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL
+ || origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL
+ || origPropId == PROP_STACKI || origPropId == PROP_MSTACKI
+ || origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI)
+ {
+ cur->v.next = NULL;
+ continue;
+ }
+ }
+ cur->v.next = &cur->arg1->v;
+ cur = cur->arg1;
+ }
+ if (origPropId == PROP_STACK || origPropId == PROP_MSTACK
+ || origPropId == PROP_XSTACK || origPropId == PROP_USTACK)
+ {
+ cur->v.val = dbeSession->get_Total_Function ()->id;
+ cur->v.fn = cur->v.val;
+ cur->v.next = NULL;
+ }
+ break;
+ }
+ case PROP_DOBJ:
+ {
+ if (ctx->dview == NULL)
+ return false;
+ if (!ctx->dview->getProp (PROP_DOBJ))
+ return false;
+ DataObject *dobj = (DataObject*)
+ ctx->dview->getObjValue (PROP_DOBJ, ctx->eventId);
+ if (dobj != NULL)
+ {
+ Expression *cur = this;
+ for (;;)
+ {
+ cur->v.val = dobj->id;
+ dobj = dobj->parent;
+ if (dobj == NULL)
+ break;
+ if (cur->arg1 == NULL)
+ cur->arg1 = new Expression (OP_NONE, (uint64_t) 0);
+ cur->v.next = &cur->arg1->v;
+ cur = cur->arg1;
+ }
+ cur->v.next = NULL;
+ }
+ break;
+ }
+ case PROP_CPRID:
+ case PROP_TSKID:
+ {
+ if (ctx->dview == NULL)
+ return false;
+ if (!ctx->dview->getProp (propId))
+ return false;
+ CallStackNode *ompstack = (CallStackNode *)
+ ctx->dview->getObjValue (propId, ctx->eventId);
+ Histable *hobj = ompstack->get_instr ();
+ if (hobj != NULL)
+ v.val = hobj->id;
+ break;
+ }
+ case PROP_JTHREAD:
+ {
+ if (ctx->exp == NULL)
+ return false;
+ if (ctx->dview == NULL)
+ return false;
+ if (!ctx->dview->getProp (propId))
+ return false;
+ uint64_t tstamp;
+ tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+ uint32_t thrid;
+ uint64_t jthr_id = 0;
+ thrid = ctx->dview->getIntValue (PROP_THRID, ctx->eventId);
+ JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp);
+ if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT)
+ {
+ jthr_id = jthread->jthr_id;
+ uint64_t grid = ctx->exp->groupId;
+ uint64_t expid = ctx->exp->getUserExpId ();
+ v.val = (grid << INDXOBJ_EXPGRID_SHIFT) |
+ (expid << INDXOBJ_EXPID_SHIFT) | jthr_id;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+bool
+Expression::bEval (Context *ctx)
+{
+ uint64_t v0, v1;
+ switch (op)
+ {
+ case OP_DEG:
+ if (!arg1->bEval (ctx))
+ return false;
+ if (arg1->v.val < 0)
+ {
+ v.val = 0;
+ return true;
+ }
+ if (!arg0->bEval (ctx))
+ {
+ return false;
+ }
+ v0 = arg0->v.val;
+ v1 = arg1->v.val;
+ for (v.val = 1; v1 > 0; v1--)
+ v.val *= v0;
+ return true;
+ case OP_MUL:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val * arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_DIV:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v1 = arg1->v.val;
+ v.val = (v1 == 0) ? 0 : (arg0->v.val / v1);
+ return true;
+ }
+ return false;
+ case OP_REM:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v1 = arg1->v.val;
+ v.val = (v1 == 0) ? 0 : (arg0->v.val % v1);
+ return true;
+ }
+ return false;
+ case OP_ADD:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val + arg1->v.val;
+ // DBFIXME LIBRARY VISIBILITY
+ // hack to pass v.fn value to new expression for leaf filters USTACK+0
+ v.fn = arg0->v.fn + arg1->v.fn;
+ return true;
+ }
+ return false;
+ case OP_MINUS:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val - arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_LS:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val << arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_RS:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val >> arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_LT:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val < arg1->v.val ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_LE:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val <= arg1->v.val ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_GT:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val > arg1->v.val ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_GE:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val >= arg1->v.val ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_EQ:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val == arg1->v.val ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_NE:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val != arg1->v.val ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_BITAND:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val & arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_BITXOR:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val ^ arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_BITOR:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v.val = arg0->v.val | arg1->v.val;
+ return true;
+ }
+ return false;
+ case OP_AND:
+ if (arg0->bEval (ctx))
+ {
+ if (arg0->v.val == 0)
+ {
+ v.val = 0;
+ return true;
+ }
+ if (arg1->bEval (ctx))
+ {
+ v.val = arg1->v.val == 0 ? 0 : 1;
+ return true;
+ }
+ return false;
+ }
+ if (arg1->bEval (ctx) && arg1->v.val == 0)
+ {
+ v.val = 0;
+ return true;
+ }
+ return false;
+ case OP_OR:
+ if (arg0->bEval (ctx))
+ {
+ if (arg0->v.val != 0)
+ {
+ v.val = 1;
+ return true;
+ }
+ if (arg1->bEval (ctx))
+ {
+ v.val = arg1->v.val == 0 ? 0 : 1;
+ return true;
+ }
+ return false;
+ }
+ if (arg1->bEval (ctx) && arg1->v.val != 0)
+ {
+ v.val = 1;
+ return true;
+ }
+ return false;
+ case OP_NEQV:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v0 = arg0->v.val;
+ v1 = arg1->v.val;
+ v.val = (v0 == 0 && v1 != 0) || (v0 != 0 && v1 == 0) ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_EQV:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ v0 = arg0->v.val;
+ v1 = arg1->v.val;
+ v.val = (v0 == 0 && v1 == 0) || (v0 != 0 && v1 != 0) ? 1 : 0;
+ return true;
+ }
+ return false;
+ case OP_QWE:
+ if (arg0->bEval (ctx))
+ {
+ if (arg0->v.val != 0)
+ {
+ if (arg1->arg0->bEval (ctx))
+ {
+ v.val = arg1->arg0->v.val;
+ return true;
+ }
+ }
+ else
+ {
+ if (arg1->arg1->bEval (ctx))
+ {
+ v.val = arg1->arg1->v.val;
+ return true;
+ }
+ }
+ }
+ return false;
+ case OP_COMMA:
+ if (arg0->bEval (ctx))
+ {
+ v.next = &arg0->v;
+ if (arg1->bEval (ctx))
+ {
+ v.val = arg1->v.val;
+ return true;
+ }
+ }
+ return false;
+ case OP_IN:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ for (Value *s = &arg0->v; s; s = s->next)
+ {
+ bool found = false;
+ for (Value *t = &arg1->v; t; t = t->next)
+ {
+ if (t->val == s->val)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ v.val = 0;
+ return true;
+ }
+ }
+ v.val = 1;
+ return true;
+ }
+ return false;
+ case OP_SOMEIN:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ for (Value *s = &arg0->v; s; s = s->next)
+ {
+ for (Value *t = &arg1->v; t; t = t->next)
+ {
+ if (t->val == s->val)
+ {
+ v.val = 1;
+ return true;
+ }
+ }
+ }
+ v.val = 0;
+ return true;
+ }
+ return false;
+ case OP_ORDRIN:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ for (Value *t0 = &arg1->v; t0; t0 = t0->next)
+ {
+ bool found = true;
+ for (Value *s = &arg0->v, *t = t0; s; s = s->next, t = t->next)
+ {
+ if (t == NULL || t->val != s->val)
+ {
+ found = false;
+ break;
+ }
+ }
+ if (found)
+ {
+ v.val = 1;
+ return true;
+ }
+ }
+ v.val = 0;
+ return true;
+ }
+ return false;
+ // LIBRARY_VISIBILITY
+ case OP_LIBRARY_IN:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ for (Value *s = &arg0->v; s; s = s->next)
+ {
+ bool found = false;
+ uint64_t objId = s->val;
+ Histable *obj = dbeSession->findObjectById (objId);
+ bool libraryFound = false;
+ Function *fn;
+ if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+ {
+ fn = (Function *) obj;
+ if (fn->isHideFunc)
+ // this belongss to a loadobject in hide/library mode
+ libraryFound = true;
+ }
+
+ if (libraryFound)
+ {
+ uint64_t lo_id = fn->module->loadobject->id;
+ for (Value *t = &arg1->v; t; t = t->next)
+ {
+ uint64_t t_id = t->fn;
+ Histable *obj2 = dbeSession->findObjectById (t_id);
+ if (obj2 != NULL
+ && obj2->get_type () == Histable::FUNCTION)
+ {
+ Function *func2 = (Function *) obj2;
+ uint64_t lo_id2 = func2->module->loadobject->id;
+ if (lo_id2 == lo_id)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Not a loadobject
+ for (Value *t = &arg1->v; t; t = t->next)
+ {
+ if (t->val == s->val)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ v.val = 0;
+ return true;
+ }
+ }
+ v.val = 1;
+ return true;
+ }
+ return false;
+ case OP_LIBRARY_SOMEIN:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ for (Value *s = &arg0->v; s; s = s->next)
+ {
+ uint64_t objId = s->val;
+ Histable *obj = dbeSession->findObjectById (objId);
+ bool libraryFound = false;
+ Function *fn;
+ if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+ {
+ fn = (Function *) obj;
+ if (fn->isHideFunc)
+ // this belongs to a loadobject in hide/library mode
+ libraryFound = true;
+ }
+
+ if (libraryFound)
+ {
+ uint64_t lo_id = fn->module->loadobject->id;
+ for (Value *t = &arg1->v; t; t = t->next)
+ {
+ uint64_t t_id = t->fn;
+ Histable *obj2 = dbeSession->findObjectById (t_id);
+ if (obj2 != NULL && obj2->get_type () == Histable::FUNCTION)
+ {
+ Function *func2 = (Function *) obj2;
+ uint64_t lo_id2 = func2->module->loadobject->id;
+ if (lo_id2 == lo_id)
+ {
+ v.val = 1;
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (Value *t = &arg1->v; t; t = t->next)
+ if (t->val == s->val)
+ {
+ v.val = 1;
+ return true;
+ }
+ }
+ }
+ v.val = 0;
+ return true;
+ }
+ return false;
+ case OP_LIBRARY_ORDRIN:
+ if (arg0->bEval (ctx) && arg1->bEval (ctx))
+ {
+ for (Value *t0 = &arg1->v; t0; t0 = t0->next)
+ {
+ bool found = true;
+ Value *t = t0;
+ for (Value *s = &arg0->v; s; s = s->next)
+ {
+ // start comparing s->val with t->val
+ // if matches move on to s->next and t->next
+ uint64_t objId = s->val;
+ Histable *obj = dbeSession->findObjectById (objId);
+ bool libraryFound = false;
+ Function *fn;
+ if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+ {
+ fn = (Function *) obj;
+ if (fn->isHideFunc)
+ libraryFound = true;
+ }
+ if (libraryFound)
+ {
+ // s->val is from a loadobject
+ // check if t->val is a func whose loadobject matches s->val
+ uint64_t lo_id = fn->module->loadobject->id;
+ uint64_t t_id = t->fn;
+ Histable *obj2 = dbeSession->findObjectById (t_id);
+ if (obj2 != NULL
+ && obj2->get_type () == Histable::FUNCTION)
+ {
+ Function *func2 = (Function *) obj2;
+ uint64_t lo_id2 = func2->module->loadobject->id;
+ if (lo_id2 != lo_id)
+ {
+ // no match
+ found = false;
+ break;
+ }
+ else
+ {
+ // t->val is a func whose loadobject matches s->val
+ while (t != NULL && lo_id2 == lo_id)
+ {
+ // skip frames with same load object
+ t = t->next;
+ t_id = t->fn;
+ obj2 = dbeSession->findObjectById (t_id);
+ if (obj2 != NULL
+ && obj2->get_type () == Histable::FUNCTION)
+ {
+ func2 = (Function *) obj2;
+ lo_id2 = func2->module->loadobject->id;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (t == NULL || t->val != s->val)
+ {
+ found = false;
+ break;
+ }
+ t = t->next;
+ }
+ }
+ if (found)
+ {
+ v.val = 1;
+ return true;
+ }
+ }
+ v.val = 0;
+ return true;
+ }
+ return false;
+ case OP_BITNOT:
+ if (arg0->bEval (ctx))
+ {
+ v.val = ~arg0->v.val;
+ return true;
+ }
+ return false;
+ case OP_NOT:
+ if (arg0->bEval (ctx))
+ {
+ v.val = !arg0->v.val;
+ return true;
+ }
+ return false;
+ case OP_NUM:
+ return true;
+ case OP_NAME:
+ if (ctx && arg0->bEval (ctx) && getVal ((int) arg0->v.val, ctx))
+ return true;
+ return false;
+ case OP_FUNC:
+ // FNAME is completely processed by pEval for now
+ v.val = 0;
+ return true;
+ case OP_HASPROP:
+ if (!ctx || !ctx->dview)
+ return false; // can't be resolved (occurs during pEval() )
+ else if (arg0->op != OP_NAME || !arg0->arg0)
+ return false; // weird, wrong arg type
+ else
+ {
+ int propId = (int) arg0->arg0->v.val;
+ if (ctx->dview->getProp (propId))
+ v.val = 1;
+ else
+ v.val = 0;
+ return true;
+ }
+ case OP_FILE:
+ // FILENAME is completely processed by pEval for now
+ v.val = 0;
+ return true;
+ case OP_JAVA:
+ //JGROUP & JPARENT is completely processed by pEval for now
+ v.val = 0;
+ return true;
+ case OP_COLON:
+ return false; // OK for arg1 of OP_QWE
+ default:
+#ifdef IPC_LOG
+ fprintf (stderr, "INTERNAL ERROR: Expression::eval op=%d\n", op);
+#endif
+ return false;
+ }
+ return false;
+}
+
+Expression *
+Expression::pEval (Context *ctx) // partial evaluation (dview may be NULL)
+{
+ Expression *res = NULL;
+ switch (op)
+ {
+ case OP_FUNC:
+ {
+ Vector<Histable*> *objs = NULL;
+ if (arg0->v.val == FUNC_FNAME)
+ {
+ Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA;
+ objs = (Vector<Histable*>*)dbeSession->match_func_names ((char*) arg1->v.val, nfmt);
+ }
+ else if (arg0->v.val == FUNC_DNAME)
+ objs = (Vector<Histable*>*)dbeSession->match_dobj_names ((char*) arg1->v.val);
+ Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
+ res = cur;
+ int i = objs ? objs->size () - 1 : -1;
+ for (; i >= 0; i--)
+ {
+ cur->v.val = objs->fetch (i)->id;
+ if (i == 0)
+ break;
+ cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
+ cur->v.next = &cur->arg0->v;
+ cur = cur->arg0;
+ }
+ cur->v.next = NULL;
+ if (objs)
+ delete objs;
+ break;
+ }
+ case OP_JAVA:
+ {
+ Vector<JThread*> *objs = NULL;
+ Vector<uint64_t> *grids = NULL;
+ Vector<uint64_t> *expids = NULL;
+ if (arg0->v.val == JAVA_JGROUP)
+ objs = dbeSession->match_java_threads ((char*) arg1->v.val, 0, grids,
+ expids);
+ else if (arg0->v.val == JAVA_JPARENT)
+ objs = dbeSession->match_java_threads ((char*) arg1->v.val, 1, grids,
+ expids);
+ Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
+ res = cur;
+ int i = objs ? objs->size () - 1 : -1;
+ for (; i >= 0; i--)
+ {
+ uint64_t jthr_id = 0;
+ JThread *jthread = (JThread *) (objs->fetch (i));
+ jthr_id = jthread->jthr_id;
+ uint64_t grid = grids->fetch (i);
+ uint64_t expid = expids->fetch (i);
+ cur->v.val = (grid << INDXOBJ_EXPGRID_SHIFT) |
+ (expid << INDXOBJ_EXPID_SHIFT) | jthr_id;
+ if (i == 0)
+ break;
+ cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
+ cur->v.next = &cur->arg0->v;
+ cur = cur->arg0;
+ }
+ cur->v.next = NULL;
+ delete objs;
+ delete grids;
+ delete expids;
+ break;
+ }
+ case OP_FILE:
+ {
+ Vector<Histable*> *objs = NULL;
+ Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA;
+ if (ctx)
+ objs = (Vector<Histable*>*)dbeSession->match_file_names ((char*) arg1->v.val, nfmt);
+ Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
+ res = cur;
+ int i = objs ? objs->size () - 1 : -1;
+ for (; i >= 0; i--)
+ {
+ cur->v.val = objs->fetch (i)->id;
+ if (i == 0)
+ break;
+ cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
+ cur->v.next = &cur->arg0->v;
+ cur = cur->arg0;
+ }
+ cur->v.next = NULL;
+ if (objs)
+ delete objs;
+ break;
+ }
+ case OP_NUM:
+ case OP_COMMA:
+ res = copy ();
+ break;
+ case OP_IN:
+ case OP_SOMEIN:
+ case OP_ORDRIN:
+ {
+ // LIBRARY_VISIBILITY:
+ // Evaluate the arg0 of OP_IN, OP_SOMEIN, OP_ORDRIN to see if it has any library/loadobject
+ // Change it to OP_LIBRARY_IN, OP_LIBRARY_SOMEIN or OP_LIBRARY_ORDRIN respectively
+ if (dbeSession->is_lib_visibility_used () && (arg0->hasLoadObject ()
+ || arg1->hasLoadObject ()))
+ {
+ OpCode new_op;
+ switch (op)
+ {
+ case OP_IN:
+ new_op = OP_LIBRARY_IN;
+ break;
+ case OP_SOMEIN:
+ new_op = OP_LIBRARY_SOMEIN;
+ break;
+ case OP_ORDRIN:
+ new_op = OP_LIBRARY_ORDRIN;
+ break;
+ default:
+ new_op = op; // Should never reach here
+ break;
+ }
+ if (arg1->hasLoadObject ())
+ res = new Expression (new_op, arg1 ? arg1->pEval (ctx) : NULL,
+ arg0 ? arg0->pEval (ctx) : NULL);
+ else
+ res = new Expression (new_op, arg0 ? arg0->pEval (ctx) : NULL,
+ arg1 ? arg1->pEval (ctx) : NULL);
+ res->v = v;
+ ctx->dbev->setFilterHideMode ();
+ return res;
+ }
+ }
+ // no break; if no loadobjects found fall thru to the default case
+ default:
+ if (bEval (ctx))
+ {
+ res = new Expression (OP_NUM, v.val);
+ break;
+ }
+ res = new Expression (op, arg0 ? arg0->pEval (ctx) : NULL,
+ arg1 ? arg1->pEval (ctx) : NULL);
+ res->v = v;
+ break;
+ }
+ return res;
+}
+
+bool
+Expression::verifyObjectInExpr (Histable *obj)
+{
+ uint64_t id = ((uint64_t) obj->id);
+ if (op == OP_NUM && v.val == id)
+ return true;
+ bool inArg0 = false;
+ bool inArg1 = false;
+ if (arg0 != NULL)
+ inArg0 = arg0->verifyObjectInExpr (obj);
+ if (inArg0)
+ return true;
+ if (arg1 != NULL)
+ inArg1 = arg1->verifyObjectInExpr (obj);
+ if (inArg1)
+ return true;
+ return false;
+}
+
+bool
+Expression::hasLoadObject ()
+{
+ if (op == OP_NUM)
+ {
+ uint64_t id = v.val;
+ Histable *obj = dbeSession->findObjectById (id);
+ if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+ {
+ Function *func = (Function *) obj;
+ if (func->isHideFunc)
+ return true;
+ }
+ }
+ if (arg0 && arg0->hasLoadObject ())
+ return true;
+ if (arg1 && arg1->hasLoadObject ())
+ return true;
+ return false;
+}
diff --git a/gprofng/src/Expression.h b/gprofng/src/Expression.h
new file mode 100644
index 0000000..7542853
--- /dev/null
+++ b/gprofng/src/Expression.h
@@ -0,0 +1,180 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _EXPRESSION_H
+#define _EXPRESSION_H
+
+#include <inttypes.h>
+
+class Experiment;
+class DataView;
+class DbeView;
+class Histable;
+
+class Expression
+{
+public:
+
+ class Context
+ {
+ public:
+ Context (DbeView *_dbev, Experiment *_exp = 0);
+ Context (DbeView *_dbev, Experiment *_exp, DataView *_dview, long _eventId);
+
+ ~Context () { };
+
+ void
+ put (DataView *d, long id)
+ {
+ dview = d;
+ eventId = id;
+ };
+
+ void
+ put (Experiment *_exp)
+ {
+ exp = _exp;
+ };
+
+ Experiment *exp;
+ DataView *dview;
+ DbeView *dbev;
+ long eventId;
+ };
+
+ enum OpCode
+ {
+ OP_NONE,
+ OP_QWE,
+ OP_COLON,
+ OP_OR,
+ OP_AND,
+ OP_NOT,
+ OP_EQV,
+ OP_NEQV,
+ OP_BITOR,
+ OP_BITAND,
+ OP_BITXOR,
+ OP_BITNOT,
+ OP_EQ,
+ OP_NE,
+ OP_LT,
+ OP_GT,
+ OP_LE,
+ OP_GE,
+ OP_LS,
+ OP_RS,
+ OP_ADD,
+ OP_MINUS,
+ OP_MUL,
+ OP_DIV,
+ OP_REM,
+ OP_DEG,
+ OP_COMMA,
+ OP_IN,
+ OP_SOMEIN,
+ OP_ORDRIN,
+ OP_NUM,
+ OP_NAME,
+ OP_FUNC,
+ OP_FILE,
+ OP_JAVA,
+ OP_HASPROP,
+ OP_LIBRARY_IN,
+ OP_LIBRARY_SOMEIN,
+ OP_LIBRARY_ORDRIN
+ };
+
+ enum FuncCode
+ {
+ FUNC_FNAME,
+ FUNC_DNAME
+ };
+
+ enum JavaCode
+ {
+ JAVA_JGROUP,
+ JAVA_JPARENT
+ };
+
+ Expression (OpCode, const Expression*, const Expression* = 0);
+ Expression (OpCode, uint64_t);
+ Expression (const Expression &rhs);
+ Expression (const Expression *rhs);
+ Expression &operator= (const Expression &rhs);
+ ~Expression ();
+
+ Expression *
+ copy () const
+ {
+ return new Expression (this);
+ }
+ void copy (const Expression *rhs);
+
+ uint64_t
+ eval (Context *ctx)
+ {
+ return bEval (ctx) ? v.val : 0;
+ };
+
+ bool
+ passes (Context *ctx)
+ {
+ return bEval (ctx) ? v.val != 0 : true;
+ };
+
+ bool
+ complete ()
+ {
+ return op == OP_NUM;
+ };
+
+ bool verifyObjectInExpr (Histable *obj);
+ Expression *
+ pEval (Context *ctx); // Partial evaluation to simplify expression
+
+private:
+
+ struct Value
+ {
+
+ Value (uint64_t _val = 0, Value *_next = 0) : val (_val), next (_next)
+ {
+ fn = 0;
+ }
+ uint64_t val;
+ uint64_t fn;
+ Value *next;
+ };
+
+ bool getVal (int propId, Context *ctx);
+ bool bEval (Context *ctx);
+
+ bool hasLoadObject ();
+ void fixupValues ();
+
+ OpCode op;
+ Value v;
+ Expression *arg0;
+ Expression *arg1;
+};
+
+
+#endif /* _EXPRESSION_H */
diff --git a/gprofng/src/FileData.cc b/gprofng/src/FileData.cc
new file mode 100644
index 0000000..7a941f5
--- /dev/null
+++ b/gprofng/src/FileData.cc
@@ -0,0 +1,400 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include <string.h>
+
+#include "util.h"
+#include "FileData.h"
+
+void
+FileData::init ()
+{
+ readTime = 0;
+ writeTime = 0;
+ otherTime = 0;
+ errorTime = 0;
+ readBytes = 0;
+ writeBytes = 0;
+ readCnt = 0;
+ writeCnt = 0;
+ otherCnt = 0;
+ errorCnt = 0;
+ wSlowestBytes = 0;
+ wSmallestBytes = _10TB;
+ wLargestBytes = 0;
+ w0KB1KBCnt = 0;
+ w1KB8KBCnt = 0;
+ w8KB32KBCnt = 0;
+ w32KB128KBCnt = 0;
+ w128KB256KBCnt = 0;
+ w256KB512KBCnt = 0;
+ w512KB1000KBCnt = 0;
+ w1000KB10MBCnt = 0;
+ w10MB100MBCnt = 0;
+ w100MB1GBCnt = 0;
+ w1GB10GBCnt = 0;
+ w10GB100GBCnt = 0;
+ w100GB1TBCnt = 0;
+ w1TB10TBCnt = 0;
+ rSlowestBytes = 0;
+ rSmallestBytes = _10TB;
+ rLargestBytes = 0;
+ r0KB1KBCnt = 0;
+ r1KB8KBCnt = 0;
+ r8KB32KBCnt = 0;
+ r32KB128KBCnt = 0;
+ r128KB256KBCnt = 0;
+ r256KB512KBCnt = 0;
+ r512KB1000KBCnt = 0;
+ r1000KB10MBCnt = 0;
+ r10MB100MBCnt = 0;
+ r100MB1GBCnt = 0;
+ r1GB10GBCnt = 0;
+ r10GB100GBCnt = 0;
+ r100GB1TBCnt = 0;
+ r1TB10TBCnt = 0;
+}
+
+FileData::FileData (const char *fName)
+{
+ fileName = dbe_strdup (fName);
+ fileDesList = new Vector<int>;
+ virtualFds = new Vector<int64_t>;
+ virtualFd = -1;
+ fileDes = -1;
+ fsType[0] = '\0';
+ histType = Histable::IOACTVFD;
+ init ();
+}
+
+FileData::FileData (FileData *fData)
+{
+ fileName = dbe_strdup (fData->fileName);
+ fileDesList = new Vector<int>;
+ Vector<int> *fdList = fData->fileDesList;
+ int fd;
+ if (fdList != NULL)
+ for (int i = 0; i < fdList->size (); i++)
+ if ((fd = fdList->fetch (i)) == -1)
+ fileDesList->append (fd);
+
+ virtualFds = new Vector<int64_t>;
+ Vector<int64_t> *vfds = fData->virtualFds;
+ int64_t vfd;
+ if (vfds != NULL)
+ for (int i = 0; i < vfds->size (); i++)
+ if ((vfd = vfds->fetch (i)) == -1)
+ virtualFds->append (vfd);
+ virtualFd = fData->virtualFd;
+ fileDes = fData->fileDes;
+ histType = fData->histType;
+
+ for (int i = 0; i < FSTYPESZ; i++)
+ fsType[i] = fData->fsType[i];
+
+ readTime = fData->readTime;
+ writeTime = fData->writeTime;
+ otherTime = fData->otherTime;
+ errorTime = fData->errorTime;
+ readBytes = fData->readBytes;
+ writeBytes = fData->writeBytes;
+ readCnt = fData->readCnt;
+ writeCnt = fData->writeCnt;
+ otherCnt = fData->otherCnt;
+ errorCnt = fData->errorCnt;
+ wSlowestBytes = fData->wSlowestBytes;
+ wSmallestBytes = fData->wSmallestBytes;
+ wLargestBytes = fData->wLargestBytes;
+ w0KB1KBCnt = fData->w0KB1KBCnt;
+ w1KB8KBCnt = fData->w1KB8KBCnt;
+ w8KB32KBCnt = fData->w8KB32KBCnt;
+ w32KB128KBCnt = fData->w32KB128KBCnt;
+ w128KB256KBCnt = fData->w128KB256KBCnt;
+ w256KB512KBCnt = fData->w256KB512KBCnt;
+ w512KB1000KBCnt = fData->w512KB1000KBCnt;
+ w1000KB10MBCnt = fData->w1000KB10MBCnt;
+ w10MB100MBCnt = fData->w10MB100MBCnt;
+ w100MB1GBCnt = fData->w100MB1GBCnt;
+ w1GB10GBCnt = fData->w1GB10GBCnt;
+ w10GB100GBCnt = fData->w10GB100GBCnt;
+ w100GB1TBCnt = fData->w100GB1TBCnt;
+ w1TB10TBCnt = fData->w1TB10TBCnt;
+ rSlowestBytes = fData->rSlowestBytes;
+ rSmallestBytes = fData->rSmallestBytes;
+ rLargestBytes = fData->rLargestBytes;
+ r0KB1KBCnt = fData->r0KB1KBCnt;
+ r1KB8KBCnt = fData->r1KB8KBCnt;
+ r8KB32KBCnt = fData->r8KB32KBCnt;
+ r32KB128KBCnt = fData->r32KB128KBCnt;
+ r128KB256KBCnt = fData->r128KB256KBCnt;
+ r256KB512KBCnt = fData->r256KB512KBCnt;
+ r512KB1000KBCnt = fData->r512KB1000KBCnt;
+ r1000KB10MBCnt = fData->r1000KB10MBCnt;
+ r10MB100MBCnt = fData->r10MB100MBCnt;
+ r100MB1GBCnt = fData->r100MB1GBCnt;
+ r1GB10GBCnt = fData->r1GB10GBCnt;
+ r10GB100GBCnt = fData->r10GB100GBCnt;
+ r100GB1TBCnt = fData->r100GB1TBCnt;
+ r1TB10TBCnt = fData->r1TB10TBCnt;
+}
+
+FileData::~FileData ()
+{
+ free (fileName);
+ delete fileDesList;
+ delete virtualFds;
+}
+
+void
+FileData::setVirtualFds (int64_t vfd)
+{
+ for (int i = 0; i < virtualFds->size (); i++)
+ if (vfd == virtualFds->fetch (i))
+ return;
+ virtualFds->append (vfd);
+}
+
+void
+FileData::setFileDesList (int fd)
+{
+ for (int i = 0; i < fileDesList->size (); i++)
+ if (fd == fileDesList->fetch (i))
+ return;
+ fileDesList->append (fd);
+}
+
+void
+FileData::setFsType (const char* fst)
+{
+ size_t len = strlen (fst);
+ if (len > 0 && len < FSTYPESZ)
+ snprintf (fsType, sizeof (fsType), NTXT ("%s"), fst);
+ else
+ snprintf (fsType, sizeof (fsType), GTXT ("error"));
+}
+
+Histable*
+FileData::convertto (Histable_type type, Histable*)
+{
+ return (type == histType ? this : NULL);
+}
+
+char*
+FileData::get_name (Histable::NameFormat /*_nfmt*/)
+{
+ if (histType == Histable::IOACTVFD)
+ {
+ if (!streq (fileName, NTXT ("<Total>")))
+ {
+ if (fileDes >= 0)
+ return dbe_sprintf (GTXT ("%s (IOVFD=%lld, FD=%d)"), fileName,
+ (long long) virtualFd, (int) fileDes);
+ return dbe_sprintf (GTXT ("%s (IOVFD=%lld)"), fileName,
+ (long long) virtualFd);
+ }
+ else
+ return fileName;
+ }
+ else if (histType == Histable::IOACTFILE)
+ {
+ if (!streq (fileName, NTXT ("<Total>")))
+ {
+ if (!streq (fsType, NTXT ("N/A")))
+ return dbe_sprintf (GTXT ("%s (FS=%s)"), fileName, fsType);
+ return fileName;
+ }
+ return fileName;
+ }
+ return fileName;
+}
+
+char*
+FileData::get_raw_name (Histable::NameFormat /*_nfmt*/)
+{
+ return fileName;
+}
+
+void
+FileData::setFsType (FileSystem_type fst)
+{
+ const char *fsName;
+ switch (fst)
+ {
+ case ZFS_TYPE:
+ fsName = "zfs";
+ break;
+ case NFS_TYPE:
+ fsName = "nfs";
+ break;
+ case UFS_TYPE:
+ fsName = "ufs";
+ break;
+ case UDFS_TYPE:
+ fsName = "udfs";
+ break;
+ case LOFS_TYPE:
+ fsName = "lofs";
+ break;
+ case VXFS_TYPE:
+ fsName = "vxfs";
+ break;
+ case TMPFS_TYPE:
+ fsName = "tmpfs";
+ break;
+ case PCFS_TYPE:
+ fsName = "pcfs";
+ break;
+ case HSFS_TYPE:
+ fsName = "hsfs";
+ break;
+ case PROCFS_TYPE:
+ fsName = "procfs";
+ break;
+ case FIFOFS_TYPE:
+ fsName = "fifofs";
+ break;
+ case SWAPFS_TYPE:
+ fsName = "swapfs";
+ break;
+ case CACHEFS_TYPE:
+ fsName = "cachefs";
+ break;
+ case AUTOFS_TYPE:
+ fsName = "autofs";
+ break;
+ case SPECFS_TYPE:
+ fsName = "specfs";
+ break;
+ case SOCKFS_TYPE:
+ fsName = "sockfs";
+ break;
+ case FDFS_TYPE:
+ fsName = "fdfs";
+ break;
+ case MNTFS_TYPE:
+ fsName = "mntfs";
+ break;
+ case NAMEFS_TYPE:
+ fsName = "namefs";
+ break;
+ case OBJFS_TYPE:
+ fsName = "objfs";
+ break;
+ case SHAREFS_TYPE:
+ fsName = "sharefs";
+ break;
+ case EXT2FS_TYPE:
+ fsName = "ext2";
+ break;
+ case EXT3FS_TYPE:
+ fsName = "ext3";
+ break;
+ case EXT4FS_TYPE:
+ fsName = "ext4";
+ break;
+ case UNKNOWNFS_TYPE:
+ fsName = "N/A";
+ break;
+ default:
+ fsName = "N/A";
+ break;
+ }
+ setFsType (fsName);
+}
+
+void
+FileData::setWriteStat (hrtime_t wt, int64_t nb)
+{
+ if (wSlowestBytes < wt)
+ wSlowestBytes = wt;
+ if (nb != 0 && wSmallestBytes > nb)
+ wSmallestBytes = nb;
+ if (wLargestBytes < nb)
+ wLargestBytes = nb;
+ if (nb >= 0 && nb <= _1KB)
+ w0KB1KBCnt++;
+ else if (nb <= _8KB)
+ w1KB8KBCnt++;
+ else if (nb <= _32KB)
+ w8KB32KBCnt++;
+ else if (nb <= _128KB)
+ w32KB128KBCnt++;
+ else if (nb <= _256KB)
+ w128KB256KBCnt++;
+ else if (nb <= _512KB)
+ w256KB512KBCnt++;
+ else if (nb <= _1000KB)
+ w512KB1000KBCnt++;
+ else if (nb <= _10MB)
+ w1000KB10MBCnt++;
+ else if (nb <= _100MB)
+ w10MB100MBCnt++;
+ else if (nb <= _1GB)
+ w100MB1GBCnt++;
+ else if (nb <= _10GB)
+ w1GB10GBCnt++;
+ else if (nb <= _100GB)
+ w10GB100GBCnt++;
+ else if (nb <= _1TB)
+ w100GB1TBCnt++;
+ else if (nb <= _10TB)
+ w1TB10TBCnt++;
+}
+
+void
+FileData::setReadStat (hrtime_t rt, int64_t nb)
+{
+ if (rSlowestBytes < rt)
+ rSlowestBytes = rt;
+ if (nb != 0 && rSmallestBytes > nb)
+ rSmallestBytes = nb;
+ if (rLargestBytes < nb)
+ rLargestBytes = nb;
+ if (nb >= 0 && nb <= _1KB)
+ r0KB1KBCnt++;
+ else if (nb <= _8KB)
+ r1KB8KBCnt++;
+ else if (nb <= _32KB)
+ r8KB32KBCnt++;
+ else if (nb <= _128KB)
+ r32KB128KBCnt++;
+ else if (nb <= _256KB)
+ r128KB256KBCnt++;
+ else if (nb <= _512KB)
+ r256KB512KBCnt++;
+ else if (nb <= _1000KB)
+ r512KB1000KBCnt++;
+ else if (nb <= _10MB)
+ r1000KB10MBCnt++;
+ else if (nb <= _100MB)
+ r10MB100MBCnt++;
+ else if (nb <= _1GB)
+ r100MB1GBCnt++;
+ else if (nb <= _10GB)
+ r1GB10GBCnt++;
+ else if (nb <= _100GB)
+ r10GB100GBCnt++;
+ else if (nb <= _1TB)
+ r100GB1TBCnt++;
+ else if (nb <= _10TB)
+ r1TB10TBCnt++;
+}
diff --git a/gprofng/src/FileData.h b/gprofng/src/FileData.h
new file mode 100644
index 0000000..67de689
--- /dev/null
+++ b/gprofng/src/FileData.h
@@ -0,0 +1,522 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _FILEDATA_H
+#define _FILEDATA_H
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+#include "vec.h"
+#include "data_pckts.h"
+#include "Histable.h"
+
+#define FSTYPESZ 16
+
+#define VIRTUAL_FD_TOTAL 0
+#define VIRTUAL_FD_STDIN 1
+#define VIRTUAL_FD_STDOUT 2
+#define VIRTUAL_FD_STDERR 3
+#define VIRTUAL_FD_OTHERIO 4
+#define VIRTUAL_FD_NONE -1
+
+#define STDIN_FD 0
+#define STDOUT_FD 1
+#define STDERR_FD 2
+#define OTHERIO_FD -1
+
+#define OTHERIO_FILENAME "<Other IO activity>"
+#define STDIN_FILENAME "<stdin>"
+#define STDOUT_FILENAME "<stdout>"
+#define STDERR_FILENAME "<stderr>"
+#define TOTAL_FILENAME NTXT("<Total>")
+#define UNKNOWNFD_FILENAME "<pipe(), socket(), or other fds>"
+
+#define _1KB 1024
+#define _8KB 8192
+#define _32KB 32768
+#define _128KB 131072
+#define _256KB 262144
+#define _512KB 524288
+#define _1000KB 1048576
+#define _10MB 10485760
+#define _100MB 104857600
+#define _1GB 1073741824
+#define _10GB 10737418240
+#define _100GB 107374182400
+#define _1TB 1099511627776
+#define _10TB 10995116277760
+
+class FileData : public Histable
+{
+ friend class IOActivity;
+public:
+ FileData (const char *fName);
+ FileData (FileData *fData);
+ ~FileData ();
+
+ virtual char *get_name (Histable::NameFormat nfmt);
+ virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+ char *get_raw_name (Histable::NameFormat nfmt);
+ void setFsType (FileSystem_type fst);
+ void setFsType (const char* fst);
+
+ virtual Histable_type
+ get_type ()
+ {
+ return histType;
+ };
+
+ virtual uint64_t
+ get_addr ()
+ {
+ return virtualFd;
+ };
+
+ uint64_t
+ get_index ()
+ {
+ return virtualFd;
+ };
+
+ void init ();
+
+ char *
+ getFileName ()
+ {
+ return fileName;
+ }
+
+ void
+ addReadEvent (hrtime_t rt, int64_t nb)
+ {
+ readTime += rt;
+ readBytes += nb;
+ readCnt++;
+ }
+
+ hrtime_t
+ getReadTime ()
+ {
+ return readTime;
+ }
+
+ int64_t
+ getReadBytes ()
+ {
+ return readBytes;
+ }
+
+ int32_t
+ getReadCnt ()
+ {
+ return readCnt;
+ }
+
+ void
+ addWriteEvent (hrtime_t wt, int64_t nb)
+ {
+ writeTime += wt;
+ writeBytes += nb;
+ writeCnt++;
+ }
+
+ hrtime_t
+ getWriteTime ()
+ {
+ return writeTime;
+ }
+
+ int64_t
+ getWriteBytes ()
+ {
+ return writeBytes;
+ }
+
+ int32_t
+ getWriteCnt ()
+ {
+ return writeCnt;
+ }
+
+ void
+ addOtherEvent (hrtime_t ot)
+ {
+ otherTime += ot;
+ otherCnt++;
+ }
+
+ hrtime_t
+ getOtherTime ()
+ {
+ return otherTime;
+ }
+
+ int32_t
+ getOtherCnt ()
+ {
+ return otherCnt;
+ }
+
+ void
+ addErrorEvent (hrtime_t er)
+ {
+ errorTime += er;
+ errorCnt++;
+ }
+
+ hrtime_t
+ getErrorTime ()
+ {
+ return errorTime;
+ }
+
+ int32_t
+ getErrorCnt ()
+ {
+ return errorCnt;
+ }
+
+ void setFileDesList (int fd);
+
+ Vector<int> *
+ getFileDesList ()
+ {
+ return fileDesList;
+ }
+
+ void
+ setFileDes (int fd)
+ {
+ fileDes = fd;
+ }
+
+ int32_t
+ getFileDes ()
+ {
+ return fileDes;
+ }
+
+ void setVirtualFds (int64_t vfd);
+
+ Vector<int64_t> *
+ getVirtualFds ()
+ {
+ return virtualFds;
+ }
+
+ char *
+ getFsType ()
+ {
+ return fsType;
+ }
+
+ void
+ setVirtualFd (int64_t vFd)
+ {
+ virtualFd = vFd;
+ }
+
+ int64_t
+ getVirtualFd ()
+ {
+ return virtualFd;
+ }
+
+ void
+ setHistType (Histable::Type hType)
+ {
+ histType = hType;
+ }
+
+ Histable::Type
+ getHistType ()
+ {
+ return histType;
+ }
+
+ void setWriteStat (hrtime_t wt, int64_t nb);
+
+ hrtime_t
+ getWSlowestBytes ()
+ {
+ return wSlowestBytes;
+ }
+
+ int64_t
+ getWSmallestBytes ()
+ {
+ return wSmallestBytes;
+ }
+
+ int64_t
+ getWLargestBytes ()
+ {
+ return wLargestBytes;
+ }
+
+ int32_t
+ getW0KB1KBCnt ()
+ {
+ return w0KB1KBCnt;
+ }
+
+ int32_t
+ getW1KB8KBCnt ()
+ {
+ return w1KB8KBCnt;
+ }
+
+ int32_t
+ getW8KB32KBCnt ()
+ {
+ return w8KB32KBCnt;
+ }
+
+ int32_t
+ getW32KB128KBCnt ()
+ {
+ return w32KB128KBCnt;
+ }
+
+ int32_t
+ getW128KB256KBCnt ()
+ {
+ return w128KB256KBCnt;
+ }
+
+ int32_t
+ getW256KB512KBCnt ()
+ {
+ return w256KB512KBCnt;
+ }
+
+ int32_t
+ getW512KB1000KBCnt ()
+ {
+ return w512KB1000KBCnt;
+ }
+
+ int32_t
+ getW1000KB10MBCnt ()
+ {
+ return w1000KB10MBCnt;
+ }
+
+ int32_t
+ getW10MB100MBCnt ()
+ {
+ return w10MB100MBCnt;
+ }
+
+ int32_t
+ getW100MB1GBCnt ()
+ {
+ return w100MB1GBCnt;
+ }
+
+ int32_t
+ getW1GB10GBCnt ()
+ {
+ return w1GB10GBCnt;
+ }
+
+ int32_t
+ getW10GB100GBCnt ()
+ {
+ return w10GB100GBCnt;
+ }
+
+ int32_t
+ getW100GB1TBCnt ()
+ {
+ return w100GB1TBCnt;
+ }
+
+ int32_t
+ getW1TB10TBCnt ()
+ {
+ return w1TB10TBCnt;
+ }
+
+ void setReadStat (hrtime_t rt, int64_t nb);
+
+ hrtime_t
+ getRSlowestBytes ()
+ {
+ return rSlowestBytes;
+ }
+
+ int64_t
+ getRSmallestBytes ()
+ {
+ return rSmallestBytes;
+ }
+
+ int64_t
+ getRLargestBytes ()
+ {
+ return rLargestBytes;
+ }
+
+ int32_t
+ getR0KB1KBCnt ()
+ {
+ return r0KB1KBCnt;
+ }
+
+ int32_t
+ getR1KB8KBCnt ()
+ {
+ return r1KB8KBCnt;
+ }
+
+ int32_t
+ getR8KB32KBCnt ()
+ {
+ return r8KB32KBCnt;
+ }
+
+ int32_t
+ getR32KB128KBCnt ()
+ {
+ return r32KB128KBCnt;
+ }
+
+ int32_t
+ getR128KB256KBCnt ()
+ {
+ return r128KB256KBCnt;
+ }
+
+ int32_t
+ getR256KB512KBCnt ()
+ {
+ return r256KB512KBCnt;
+ }
+
+ int32_t
+ getR512KB1000KBCnt ()
+ {
+ return r512KB1000KBCnt;
+ }
+
+ int32_t
+ getR1000KB10MBCnt ()
+ {
+ return r1000KB10MBCnt;
+ }
+
+ int32_t
+ getR10MB100MBCnt ()
+ {
+ return r10MB100MBCnt;
+ }
+
+ int32_t
+ getR100MB1GBCnt ()
+ {
+ return r100MB1GBCnt;
+ }
+
+ int32_t
+ getR1GB10GBCnt ()
+ {
+ return r1GB10GBCnt;
+ }
+
+ int32_t
+ getR10GB100GBCnt ()
+ {
+ return r10GB100GBCnt;
+ }
+
+ int32_t
+ getR100GB1TBCnt ()
+ {
+ return r100GB1TBCnt;
+ }
+
+ int32_t
+ getR1TB10TBCnt ()
+ {
+ return r1TB10TBCnt;
+ }
+
+private:
+ char *fileName; // File name
+ hrtime_t readTime; // The Total time for read operations;
+ hrtime_t writeTime; // The Total time for write operations;
+ hrtime_t otherTime; // The Total time for other IO operations;
+ hrtime_t errorTime; // The Total time for failed IO operations;
+ int64_t readBytes; //The total bytes read
+ int64_t writeBytes; //The total bytes written
+ int32_t readCnt; // The read count
+ int32_t writeCnt; // The write count
+ int32_t otherCnt; // The other IO count
+ int32_t errorCnt; // The failed IO count
+ Vector<int> *fileDesList; // The list of file descriptors
+ Vector<int64_t> *virtualFds; // The list of file virtual descriptors
+ char fsType[FSTYPESZ]; // The file system type
+ int64_t virtualFd; // The virtual file descriptor
+ int32_t fileDes; // The file descriptor
+ Histable::Type histType; // The Histable type: IOACTFILE, IOACTVFD, ...
+
+ // Write statistics
+ hrtime_t wSlowestBytes;
+ int64_t wSmallestBytes;
+ int64_t wLargestBytes;
+ int32_t w0KB1KBCnt;
+ int32_t w1KB8KBCnt;
+ int32_t w8KB32KBCnt;
+ int32_t w32KB128KBCnt;
+ int32_t w128KB256KBCnt;
+ int32_t w256KB512KBCnt;
+ int32_t w512KB1000KBCnt;
+ int32_t w1000KB10MBCnt;
+ int32_t w10MB100MBCnt;
+ int32_t w100MB1GBCnt;
+ int32_t w1GB10GBCnt;
+ int32_t w10GB100GBCnt;
+ int32_t w100GB1TBCnt;
+ int32_t w1TB10TBCnt;
+
+ // Read statistics
+ hrtime_t rSlowestBytes;
+ int64_t rSmallestBytes;
+ int64_t rLargestBytes;
+ int32_t r0KB1KBCnt;
+ int32_t r1KB8KBCnt;
+ int32_t r8KB32KBCnt;
+ int32_t r32KB128KBCnt;
+ int32_t r128KB256KBCnt;
+ int32_t r256KB512KBCnt;
+ int32_t r512KB1000KBCnt;
+ int32_t r1000KB10MBCnt;
+ int32_t r10MB100MBCnt;
+ int32_t r100MB1GBCnt;
+ int32_t r1GB10GBCnt;
+ int32_t r10GB100GBCnt;
+ int32_t r100GB1TBCnt;
+ int32_t r1TB10TBCnt;
+};
+
+#endif
diff --git a/gprofng/src/Filter.cc b/gprofng/src/Filter.cc
new file mode 100644
index 0000000..34eda0d
--- /dev/null
+++ b/gprofng/src/Filter.cc
@@ -0,0 +1,514 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "Filter.h"
+#include "util.h"
+#include "i18n.h"
+#include "data_pckts.h"
+#include "StringBuilder.h"
+#include "Experiment.h"
+
+
+// ========================================================================
+// Subclass: FilterNumeric
+// Public Methods
+
+FilterNumeric::FilterNumeric (Experiment *_exp, const char *_cmd,
+ const char *_name)
+{
+ exp = _exp;
+ cmd = dbe_strdup (_cmd);
+ name = dbe_strdup (_name);
+ pattern = NULL;
+ status = NULL;
+ items = NULL;
+ prop_name = NULL;
+ first = (uint64_t) - 1;
+ last = (uint64_t) - 1;
+ nselected = 0;
+ nitems = 0;
+}
+
+FilterNumeric::~FilterNumeric ()
+{
+ free (cmd);
+ free (name);
+ free (pattern);
+ free (status);
+ Destroy (items);
+}
+
+// sets min and max for this filter; should be called when the range is
+// known -- that comes after the first PathTree build, in the current
+// sequence of things
+void
+FilterNumeric::set_range (uint64_t findex, uint64_t lindex, uint64_t total)
+{
+ if (first == findex && last == lindex)
+ return;
+ first = findex;
+ last = lindex;
+ nitems = total;
+ nselected = nitems;
+ if (pattern)
+ {
+ free (pattern);
+ pattern = NULL;
+ }
+ if (status)
+ {
+ free (status);
+ status = NULL;
+ }
+}
+
+void
+FilterNumeric::update_range ()
+{
+ if (exp == NULL)
+ return;
+ if (streq (cmd, NTXT ("sample")))
+ set_range (1, (uint64_t) exp->nsamples (), exp->nsamples ());
+ else if (streq (cmd, NTXT ("thread")))
+ set_range (exp->min_thread, exp->max_thread, exp->thread_cnt);
+ else if (streq (cmd, NTXT ("LWP")))
+ set_range (exp->min_lwp, exp->max_lwp, exp->lwp_cnt);
+ else if (streq (cmd, NTXT ("cpu")))
+ {
+ if (exp->min_cpu != (uint64_t) - 1)
+ set_range (exp->min_cpu, exp->max_cpu, exp->cpu_cnt);
+ }
+}
+
+// get_advanced_filter -- returns a string matching the current setting
+char *
+FilterNumeric::get_advanced_filter ()
+{
+ if (items == NULL)
+ return NULL;
+ if (items->size () == 0)
+ return dbe_strdup (NTXT ("0"));
+
+ StringBuilder sb;
+ if (items->size () > 1)
+ sb.append ('(');
+ for (int i = 0; i < items->size (); i++)
+ {
+ RangePair *rp = items->fetch (i);
+ if (i > 0)
+ sb.append (NTXT (" || "));
+ sb.append ('(');
+ sb.append (prop_name);
+ if (rp->first == rp->last)
+ {
+ sb.append (NTXT ("=="));
+ sb.append ((long long) rp->first);
+ }
+ else
+ {
+ sb.append (NTXT (">="));
+ sb.append ((long long) rp->first);
+ sb.append (NTXT (" && "));
+ sb.append (prop_name);
+ sb.append (NTXT ("<="));
+ sb.append ((long long) rp->last);
+ }
+ sb.append (')');
+ }
+ if (items->size () > 1)
+ sb.append (')');
+ return sb.toString ();
+}
+
+
+// get_pattern -- returns a string matching the current setting
+
+char *
+FilterNumeric::get_pattern ()
+{
+ update_range ();
+ if (pattern)
+ return pattern;
+ StringBuilder sb;
+ if (items == NULL)
+ {
+ if (last == (uint64_t) - 1 && last == first)
+ // neither set; data not available
+ sb.append (GTXT ("(data not recorded)"));
+ else
+ sb.append (GTXT ("all"));
+ }
+ else if (items->size () == 0)
+ sb.append (GTXT ("none"));
+ else
+ {
+ for (int i = 0; i < items->size (); i++)
+ {
+ RangePair *rp = items->fetch (i);
+ if (i > 0)
+ sb.append (',');
+ sb.append ((long long) rp->first);
+ if (rp->first != rp->last)
+ {
+ sb.append ('-');
+ sb.append ((long long) rp->last);
+ }
+ }
+ }
+ pattern = sb.toString ();
+ return pattern;
+}
+
+char *
+FilterNumeric::get_status ()
+{
+ update_range ();
+ if (status == NULL)
+ update_status ();
+ return dbe_strdup (status);
+}
+
+// set_pattern -- set the filter to a new pattern
+// set error true/false if there was or was not an error parsing string
+// Returns true/false if the filter changed, implying a rebuild of data
+bool
+FilterNumeric::set_pattern (char *str, bool *error)
+{
+ update_range ();
+ // save the old filter
+ Vector<RangePair *> *olditems = items;
+ *error = false;
+ if (strcmp (str, NTXT ("all")) == 0)
+ // if all, leave items NULL
+ items = NULL;
+ else if (strcmp (str, NTXT ("none")) == 0)
+ // if none, leave items as a zero-length vector
+ items = new Vector<RangePair *>(0);
+ else
+ {
+ uint64_t val, val2;
+ char *s = str;
+ char *nexts = s;
+ items = NULL;
+ for (bool done = false; done == false;)
+ {
+ // tokenize the string
+ // Does it start with a "-" ?
+ if (*nexts == '-')
+ val = first; // yes, set val to first, and see what follows
+ else
+ {
+ // it must start with a number
+ val = get_next_number (s, &nexts, error);
+ if (*error == true)
+ break;
+ }
+
+ // look at the next character
+ switch (*nexts)
+ {
+ case ',':
+ s = ++nexts;
+ *error = include_range (val, val);
+ if (*error == true)
+ done = true;
+ break;
+ case '-':
+ s = ++nexts;
+ if (*nexts == ',' || *nexts == '\0')
+ val2 = last;
+ else
+ {
+ val2 = get_next_number (s, &nexts, error);
+ if (*error == true)
+ {
+ done = true;
+ break;
+ }
+ }
+ if (val > val2)
+ {
+ *error = true;
+ done = true;
+ break;
+ }
+ *error = include_range (val, val2);
+ if (*error == true)
+ {
+ done = true;
+ break;
+ }
+ if (*nexts == ',')
+ {
+ s = ++nexts;
+ break;
+ }
+ if (*nexts == '\0')
+ {
+ done = true;
+ break;
+ }
+ break;
+ case '\0':
+ *error = include_range (val, val);
+ done = true;
+ break;
+ default:
+ *error = true;
+ done = true;
+ break;
+ }
+ }
+ // if there was a parser error leave old setting
+ if (*error == true)
+ {
+ if (items)
+ {
+ items->destroy ();
+ delete items;
+ }
+ items = olditems;
+ return false;
+ }
+ }
+
+ if (first != (uint64_t) - 1 && last != (uint64_t) - 1)
+ {
+ for (long i = VecSize (items) - 1; i >= 0; i--)
+ {
+ RangePair *rp = items->get (i);
+ if ((rp->first > last) || (rp->last < first))
+ {
+ delete rp;
+ items->remove (i);
+ continue;
+ }
+ if (rp->first < first)
+ rp->first = first;
+ if (rp->last > last)
+ rp->last = last;
+ }
+ if (VecSize (items) == 1)
+ {
+ RangePair *rp = items->get (0);
+ if ((rp->first == first) && (rp->last == last))
+ {
+ // All, leave items NULL
+ items->destroy ();
+ delete items;
+ items = NULL;
+ }
+ }
+ }
+
+ // no error, delete the old setting
+ if (olditems != NULL)
+ {
+ olditems->destroy ();
+ delete olditems;
+ }
+
+ bool changed;
+ // regenerate the pattern
+ if (pattern == NULL)
+ changed = true;
+ else
+ {
+ char *oldpattern = pattern;
+ pattern = NULL; // to force a recompute with new values
+ (void) get_pattern ();
+ changed = strcmp (pattern, oldpattern) != 0;
+ free (oldpattern);
+ }
+ return changed;
+}
+
+//================================================================
+// Protected methods
+
+// set_status -- regenerate the status line, describing the current setting
+void
+FilterNumeric::update_status ()
+{
+ // regenerate the status line
+ free (status);
+ nselected = 0;
+ if (items == NULL)
+ {
+ if (last == (uint64_t) - 1 && last == first)
+ // neither set; data not available
+ status = dbe_sprintf (GTXT ("(data not recorded)"));
+ else if (first == (uint64_t) - 1 || last == (uint64_t) - 1)
+ // range was not set
+ status = dbe_sprintf (GTXT ("(all)"));
+ else
+ // range was set, compute percentage
+ status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
+ (long long) nitems, (long long) first,
+ (long long) last);
+ }
+ else
+ {
+ // some are selected
+ int index;
+ RangePair *rp;
+ Vec_loop (RangePair *, items, index, rp)
+ {
+ nselected += rp->last - rp->first + 1;
+ }
+ if (last == (uint64_t) - 1)
+ // range was not set
+ status = dbe_sprintf (GTXT ("(%lld items selected)"),
+ (long long) nselected);
+ else
+ // range was set
+ status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
+ (long long) nitems, (long long) first,
+ (long long) last);
+ }
+}
+
+// Add a range to the filter; called from set_pattern for each index,
+// or index pair
+bool
+FilterNumeric::include_range (uint64_t findex, uint64_t lindex)
+{
+ int index;
+ RangePair *rp;
+ if (findex > lindex)
+ return true;
+
+ bool done = false;
+ if (items == NULL)
+ items = new Vector<RangePair *>(0);
+
+ Vec_loop (RangePair *, items, index, rp)
+ {
+ if (findex < rp->first)
+ {
+ // Case where the new pair starts before the old
+ if (lindex + 1 < rp->first)
+ {
+ // this pair comes cleanly in front of the current item
+ RangePair *rp2 = new RangePair ();
+ rp2->first = findex;
+ rp2->last = lindex;
+ items->insert (index, rp2);
+ done = true;
+ break;
+ }
+ // This new one extends the previous from the front
+ rp->first = findex;
+chkextend:
+ if (lindex <= rp->last)
+ {
+ // but does not extend the back
+ done = true;
+ break;
+ }
+ // extend this one out
+ rp->last = lindex;
+
+ // does it go into the next range?
+ if (index == items->size () - 1)
+ {
+ // this is the last range, so it does not
+ done = true;
+ break;
+ }
+ RangePair *next = items->fetch (index + 1);
+ if (lindex + 1 < next->first)
+ {
+ // no extension, we're done
+ done = true;
+ break;
+ }
+ // it does extend the next one
+ next->first = rp->first;
+ rp = next;
+ // remove the current one, promoting next
+ items->remove (index);
+ goto chkextend;
+ }
+ else if (findex > rp->last + 1)
+ // the new one is completely beyond the current
+ continue;
+ else
+ {
+ // the new one may start at or after the current, but it
+ // extends it out; set the current
+ // this pair overlaps the current item
+ // rp-> first is OK -- it's equal or less than findex
+ goto chkextend;
+ }
+ }
+
+ if (done != true)
+ {
+ // fall through -- append to list
+ rp = new RangePair ();
+ rp->first = findex;
+ rp->last = lindex;
+ items->append (rp);
+ }
+
+ return false;
+}
+
+// Scan the filter to see if the number given is filtered in or out
+// return true if number is in, false if it's out
+bool
+FilterNumeric::is_selected (uint64_t number)
+{
+ int index;
+ RangePair *rp;
+ if (items == NULL)
+ return true;
+ if (items->size () == 0)
+ return false;
+
+ Vec_loop (RangePair *, items, index, rp)
+ {
+ if (number >= rp->first && number <= rp->last)
+ return true;
+ }
+ return false;
+}
+
+// get_next_number
+// Called from parser to extract a number from the current string position
+// Sets fail true if there was an error, false otherwise
+// returns the number as parsed
+uint64_t
+FilterNumeric::get_next_number (char *s, char **e, bool *fail)
+{
+ errno = 0;
+ *fail = false;
+ uint64_t val = strtoll (s, e, 10);
+ if (errno == EINVAL)
+ *fail = true;
+ return (val);
+}
diff --git a/gprofng/src/Filter.h b/gprofng/src/Filter.h
new file mode 100644
index 0000000..1338218
--- /dev/null
+++ b/gprofng/src/Filter.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _FILTER_H
+#define _FILTER_H
+
+// A sample selection specifies a set of samples the user is interested in
+// viewing as a whole.
+
+#include "vec.h"
+#include "data_pckts.h"
+
+class Experiment;
+
+class FilterNumeric
+{
+public:
+ FilterNumeric (Experiment *, const char *, const char *);
+ ~FilterNumeric ();
+
+ // set or update the range of items first and last
+ void set_range (uint64_t findex, uint64_t lindex, uint64_t total);
+
+ // Return a string representation of the current ranges
+ // E.g. "1-5,7,9,10,12-13,73"
+ char *get_pattern ();
+
+ // Return a string for the current status: %, range, ...
+ // E.g. "100%" "100% [1-7]" "25% [1-4]"
+ char *get_status ();
+
+ char *get_advanced_filter ();
+
+ // Sets selection according to the string representation
+ // See above for return values and error handling
+ bool set_pattern (char *, bool *);
+
+ // Return true if "number" is included in selection
+ bool is_selected (uint64_t number);
+
+ char *
+ get_cmd ()
+ {
+ return cmd;
+ };
+
+ char *
+ get_name ()
+ {
+ return name;
+ };
+
+ uint64_t
+ nelem ()
+ {
+ return nitems;
+ };
+
+ char *prop_name; // name in advanced filter
+
+private:
+
+ typedef struct
+ {
+ uint64_t first;
+ uint64_t last;
+ } RangePair;
+
+ void update_status ();
+ void update_range ();
+
+ // Include "range" in selection
+ bool include_range (uint64_t findex, uint64_t lindex);
+
+ // Parse a number from the string
+ uint64_t get_next_number (char *s, char **e, bool *fail);
+
+ // Data
+ Vector<RangePair *> *items; // sorted array of items
+ uint64_t nselected;
+ uint64_t nitems;
+
+ Experiment *exp;
+ char *cmd;
+ char *name;
+ char *pattern;
+ char *status;
+
+ // First and Last items in selection
+ uint64_t first;
+ uint64_t last;
+};
+
+#endif /* _FILTER_H */
diff --git a/gprofng/src/FilterExp.h b/gprofng/src/FilterExp.h
new file mode 100644
index 0000000..b186af1
--- /dev/null
+++ b/gprofng/src/FilterExp.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _FILTEREXP_H
+#define _FILTEREXP_H
+
+#include "Expression.h"
+
+class FilterExp
+{
+public:
+
+ FilterExp (Expression *_expr, Expression::Context *_ctx, bool _noParFilter) :
+ expr (_expr), ctx (_ctx), noParFilter (_noParFilter) { };
+
+ ~FilterExp ()
+ {
+ delete ctx;
+ }
+
+ bool
+ passes ()
+ {
+ return expr ? expr->passes (ctx) : true;
+ }
+
+ void
+ put (DataView *dview, long eventId)
+ {
+ ctx->put (dview, eventId);
+ }
+
+ Expression *expr;
+ Expression::Context *ctx;
+ bool noParFilter;
+};
+
+
+#endif /* _FILTEREXP_H */
diff --git a/gprofng/src/FilterSet.cc b/gprofng/src/FilterSet.cc
new file mode 100644
index 0000000..29dc437
--- /dev/null
+++ b/gprofng/src/FilterSet.cc
@@ -0,0 +1,106 @@
+/* Copyright (C) 2021 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 "Experiment.h"
+#include "StringBuilder.h"
+#include "FilterSet.h"
+#include "Filter.h"
+#include "i18n.h"
+
+FilterSet::FilterSet (DbeView *_dbev, Experiment *_exp)
+{
+ dbev = _dbev;
+ exp = _exp;
+ enbl = false;
+ dfilter = new Vector<FilterNumeric *>;
+ FilterNumeric *f;
+ f = new FilterNumeric (exp, "sample", GTXT ("Samples"));
+ f->prop_name = NTXT ("SAMPLE_MAP");
+ dfilter->append (f);
+ f = new FilterNumeric (exp, "thread", GTXT ("Threads"));
+ f->prop_name = NTXT ("THRID");
+ dfilter->append (f);
+ f = new FilterNumeric (exp, "LWP", GTXT ("LWPs"));
+ f->prop_name = NTXT ("LWPID");
+ dfilter->append (f);
+ f = new FilterNumeric (exp, "cpu", GTXT ("CPUs"));
+ f->prop_name = NTXT ("CPUID");
+ dfilter->append (f);
+ f = new FilterNumeric (exp, "gcevent", GTXT ("GCEvents"));
+ f->prop_name = NTXT ("GCEVENT_MAP");
+ dfilter->append (f); // must add new numeric below
+}
+
+FilterSet::~FilterSet ()
+{
+ dfilter->destroy ();
+ delete dfilter;
+}
+
+FilterNumeric *
+FilterSet::get_filter (int index)
+{
+ if (index < dfilter->size () && index >= 0)
+ return dfilter->fetch (index);
+ return NULL;
+}
+
+char *
+FilterSet::get_advanced_filter ()
+{
+ StringBuilder sb;
+ bool filtrIsFalse = false;
+
+ if (get_enabled ())
+ {
+ Vector<FilterNumeric*> *filts = get_all_filters ();
+ if (filts == NULL)
+ return NULL;
+ for (int i = 0; i < filts->size (); i++)
+ {
+ FilterNumeric *f = filts->fetch (i);
+ if (f == NULL)
+ continue;
+ char *s = f->get_advanced_filter ();
+ if (s == NULL)
+ continue;
+ if (streq (s, NTXT ("0")))
+ {
+ free (s);
+ sb.setLength (0);
+ filtrIsFalse = true;
+ break;
+ }
+ if (sb.length () != 0)
+ sb.append (NTXT (" && "));
+ sb.append (s);
+ free (s);
+ }
+ }
+ else
+ filtrIsFalse = true;
+ if (filtrIsFalse)
+ sb.append ('0');
+ else if (sb.length () == 0)
+ return NULL;
+ return sb.toString ();
+}
+
diff --git a/gprofng/src/FilterSet.h b/gprofng/src/FilterSet.h
new file mode 100644
index 0000000..6908565
--- /dev/null
+++ b/gprofng/src/FilterSet.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _FILTERSET_H
+#define _FILTERSET_H
+
+#include "dbe_types.h"
+#include "vec.h"
+
+class Experiment;
+class FilterNumeric;
+class DbeView;
+
+#define SAMPLE_FILTER_IDX 0
+#define THREAD_FILTER_IDX 1
+#define LWP_FILTER_IDX 2
+#define CPU_FILTER_IDX 3
+
+class FilterSet
+{
+public:
+
+ FilterSet (DbeView *_dbev, Experiment *_exp);
+ ~FilterSet ();
+ char *get_advanced_filter ();
+ FilterNumeric *get_filter (int);
+
+ bool
+ get_enabled ()
+ {
+ return enbl;
+ }
+
+ void
+ set_enabled (bool b)
+ {
+ enbl = b;
+ }
+
+ Vector<FilterNumeric*> *
+ get_all_filters ()
+ {
+ return dfilter;
+ }
+
+private:
+
+ DbeView *dbev;
+ Experiment *exp;
+ bool enbl;
+ Vector<FilterNumeric*> *dfilter;
+};
+
+#endif /* _FILTERSET_H */
+
diff --git a/gprofng/src/Function.cc b/gprofng/src/Function.cc
new file mode 100644
index 0000000..b0e4a8f
--- /dev/null
+++ b/gprofng/src/Function.cc
@@ -0,0 +1,1160 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "demangle.h"
+#include "util.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Settings.h"
+#include "DbeFile.h"
+#include "DbeView.h"
+
+struct SrcInfo
+{
+ DbeLine *src_line;
+ SrcInfo *included_from;
+ SrcInfo *next;
+};
+
+struct PCInfo
+{
+ int64_t offset;
+ int64_t size;
+ SrcInfo *src_info;
+};
+
+Function::Function (uint64_t _id)
+{
+ id = _id;
+ instr_id = id << 32;
+ derivedNode = NULL;
+ module = NULL;
+ line_first = line_last = -1;
+ isOutlineFunction = false;
+ name = NULL;
+ mangled_name = NULL;
+ match_name = NULL;
+ comparable_name = NULL;
+ img_fname = NULL;
+ img_offset = 0;
+ chksum = 0;
+ flags = 0;
+ size = 0;
+ save_addr = FUNC_NO_SAVE;
+ linetab = NULL;
+ def_source = NULL;
+ indexStabsLink = NULL;
+ elfSym = NULL;
+ sources = NULL;
+ instrs = new Vector<DbeInstr*>;
+ addrs = NULL;
+ name_buf = NULL;
+ current_name_format = Histable::NA;
+ curr_srcinfo = NULL;
+ curr_srcfile = NULL;
+ srcinfo_list = NULL;
+ defaultDbeLine = NULL;
+ usrfunc = NULL;
+ alias = NULL;
+ instHTable = NULL;
+ addrIndexHTable = NULL;
+ isUsed = false;
+ isHideFunc = false;
+ inlinedSubr = NULL;
+ inlinedSubrCnt = 0;
+}
+
+Function::~Function ()
+{
+ free (mangled_name);
+ free (match_name);
+ free (comparable_name);
+ free (name_buf);
+ Destroy (linetab);
+ Destroy (instrs);
+
+ while (srcinfo_list)
+ {
+ SrcInfo *t = srcinfo_list;
+ srcinfo_list = t->next;
+ delete t;
+ }
+ delete sources;
+ delete addrs;
+ delete[] instHTable;
+ delete[] addrIndexHTable;
+ if (indexStabsLink)
+ // Remove a link to the current function
+ indexStabsLink->indexStabsLink = NULL;
+}
+
+char *
+Function::get_name (NameFormat nfmt)
+{
+ if (nfmt == Histable::NA)
+ {
+ DbeView *dbeView = dbeSession->getView (0);
+ if (dbeView)
+ nfmt = dbeView->get_name_format ();
+ }
+ if (name_buf && (nfmt == current_name_format || nfmt == Histable::NA))
+ return name_buf;
+ free (name_buf);
+ current_name_format = nfmt;
+
+ bool soname_fmt = Histable::soname_fmt (nfmt);
+ int fname_fmt = Histable::fname_fmt (nfmt);
+ if (fname_fmt == Histable::MANGLED)
+ name_buf = strdup (mangled_name);
+ else
+ {
+ if (module && module->is_fortran ()
+ && (streq (name, "MAIN") || streq (name, "MAIN_")))
+ name_buf = strdup (match_name);
+ else
+ name_buf = strdup (name);
+
+ if (fname_fmt == Histable::SHORT)
+ {
+ int i = get_paren (name_buf);
+ if (i != -1)
+ name_buf[i] = (char) 0;
+ }
+ }
+ if (soname_fmt)
+ {
+ char *fname = dbe_sprintf (NTXT ("%s [%s]"), name_buf, module->loadobject->get_name ());
+ free (name_buf);
+ name_buf = fname;
+ }
+ return name_buf;
+}
+
+uint64_t
+Function::get_addr ()
+{
+ LoadObject *lo = module ? module->loadobject : NULL;
+ int seg_idx = lo ? lo->seg_idx : -1;
+ return MAKE_ADDRESS (seg_idx, img_offset);
+}
+
+Histable *
+Function::convertto (Histable_type type, Histable *obj)
+{
+ Histable *res = NULL;
+ SourceFile *source = (SourceFile*) obj;
+ switch (type)
+ {
+ case INSTR:
+ res = find_dbeinstr (0, 0);
+ break;
+ case LINE:
+ {
+ // mapPCtoLine will implicitly read line info if necessary
+ res = mapPCtoLine (0, source);
+ break;
+ }
+ case FUNCTION:
+ res = this;
+ break;
+ case SOURCEFILE:
+ res = def_source;
+ break;
+ default:
+ assert (0);
+ }
+ return res;
+}
+
+void
+Function::set_name (char *string)
+{
+ if (string == NULL)
+ return;
+ set_mangled_name (string);
+
+ // strip away any globalization prefix, and save result for matching
+ char *mname = string;
+ if (strncmp (string, "$X", 2) == 0 || strncmp (string, ".X", 2) == 0)
+ {
+ // name was globalized
+ char *n = strchr (string + 2, (int) '.');
+ if (n != NULL)
+ mname = n + 1;
+ }
+ set_match_name (mname);
+ name = NULL;
+ if (module)
+ {
+ if (name == NULL && *match_name == '_')
+ {
+ int flag = DMGL_PARAMS;
+ if (module->lang_code == Sp_lang_java)
+ flag |= DMGL_JAVA;
+ name = cplus_demangle (match_name, flag);
+ }
+ }
+ if (name == NULL) // got demangled string
+ name = dbe_strdup (match_name);
+ set_comparable_name (name);
+}
+
+void
+Function::set_mangled_name (const char *string)
+{
+ if (string)
+ {
+ free (mangled_name);
+ mangled_name = dbe_strdup (string);
+ }
+}
+
+void
+Function::set_match_name (const char *string)
+{
+ if (string)
+ {
+ free (match_name);
+ match_name = dbe_strdup (string);
+ }
+}
+
+void
+Function::set_comparable_name (const char *string)
+{
+ if (string)
+ {
+ free (comparable_name);
+ comparable_name = dbe_strdup (string);
+
+ // remove blanks from comparable_name
+ for (char *s = comparable_name, *s1 = comparable_name;;)
+ {
+ if (*s == 0)
+ {
+ *s1 = 0;
+ break;
+ }
+ else if (*s != ' ')
+ {
+ *s1 = *s;
+ s1++;
+ }
+ s++;
+ }
+ }
+}
+
+// This function looks at the name of a function, and determines whether
+// or not it may be a derived function -- outline, mtask, or clone --
+// If it is, it writes the function name as demangled,
+// and sets a pointer to the function from which it was derived
+void
+Function::findDerivedFunctions ()
+
+{
+ MPFuncTypes ftype;
+ int index;
+ Function *fitem;
+ unsigned long long line_no;
+ char *namefmt;
+ char *subname = mangled_name;
+ char *demname;
+
+ // see if we've already done this
+ if ((flags & FUNC_FLAG_RESDER) != 0)
+ return;
+
+ // set flag for future
+ flags = flags | FUNC_FLAG_RESDER;
+ if (module == NULL)
+ return;
+ if (*subname != '_' || subname[1] != '$') // Not a specially named function
+ return;
+
+ // look for the current versions of naming
+ if (strncmp (subname + 2, NTXT ("d1"), 2) == 0) // doall function
+ ftype = MPF_DOALL;
+ else if (strncmp (subname + 2, "p1", 2) == 0) // parallel region function
+ ftype = MPF_PAR;
+ else if (strncmp (subname + 2, "l1", 2) == 0) // single thread loop setup
+ ftype = MPF_DOALL;
+ else if (strncmp (subname + 2, "s1", 2) == 0) // parallel section function
+ ftype = MPF_SECT;
+ else if (strncmp (subname + 2, "t1", 2) == 0) // task function
+ ftype = MPF_TASK;
+ else if (strncmp (subname + 2, "o1", 2) == 0) // outline function
+ {
+ ftype = MPF_OUTL;
+ isOutlineFunction = true;
+ }
+ else if (strncmp (subname + 2, "c1", 2) == 0) // clone function
+ ftype = MPF_CLONE;
+ else // Not an encoded name, just return
+ return;
+
+ // we know it's one of the above prefixes
+ char *sub = dbe_strdup (name + 4); // starting with base-26 number
+ char *p = sub;
+
+ // skip the base-26 number, and extract the line number
+ while (isalpha ((int) (*p)) != 0 && *p != 0)
+ p++;
+ line_no = atoll (p);
+
+ // skip past the number to to the .
+ while (*p != '.' && *p != 0)
+ p++;
+ if (*p == 0)
+ {
+ // can't be right
+ free (sub);
+ return;
+ }
+ // skip the trailing .
+ p++;
+ subname = p;
+ bool foundmatch = false;
+
+ // Find the function from which it is derived -- the one that matched subname
+ Vec_loop (Function*, module->functions, index, fitem)
+ {
+ if (streq (subname, fitem->mangled_name))
+ { // found it
+ foundmatch = true;
+ usrfunc = fitem;
+
+ // set the derived node
+ if ((fitem->flags & FUNC_FLAG_RESDER) == 0)
+ // ensure that it, too, is resolved if derived
+ fitem->findDerivedFunctions ();
+
+ // Build a demangled name
+ switch (ftype)
+ {
+ case MPF_OUTL:
+ isOutlineFunction = true;
+ namefmt = GTXT ("%s -- outline code from line %lld [%s]");
+ derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
+ break;
+ case MPF_PAR:
+ namefmt = GTXT ("%s -- OMP parallel region from line %lld [%s]");
+ break;
+ case MPF_DOALL:
+ namefmt = GTXT ("%s -- Parallel loop from line %lld [%s]");
+ break;
+ case MPF_SECT:
+ namefmt = GTXT ("%s -- OMP sections from line %lld [%s]");
+ break;
+ case MPF_CLONE:
+ // Note that clones are handled differently -- no line number and
+ // clones are NOT shown as called from the original
+ // so after constructing the name, just return
+ // later, establish link from clone to parent
+ demname = dbe_sprintf (GTXT ("%s -- cloned version [%s]"),
+ fitem->get_name (), name);
+ free (name);
+ // set the name to the demangled version
+ name = demname;
+ free (sub);
+ derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
+ return;
+ case MPF_TASK:
+ namefmt = GTXT ("%s -- OMP task from line %lld [%s]");
+ break;
+ default:
+ free (sub);
+ return;
+
+ }
+
+ // Finally, construct the demangled name
+ demname = dbe_sprintf (namefmt, fitem->get_name (), line_no, name);
+ free (name);
+ name = demname;
+ setLineFirst ((int) line_no);
+ break;
+ }
+ }
+
+ if (foundmatch == false && ftype == MPF_OUTL)
+ {
+ // Even if derived node was not found, we can demangle
+ demname = dbe_sprintf (GTXT ("%s -- outline code [%s]"), subname,
+ mangled_name);
+ free (name);
+ name = demname;
+ }
+ free (sub);
+}
+
+SrcInfo *
+Function::new_srcInfo ()
+{
+ SrcInfo *t = new SrcInfo ();
+ t->next = srcinfo_list;
+ srcinfo_list = t;
+ return t;
+}
+
+void
+Function::pushSrcFile (SourceFile* source, int /*lineno*/)
+{
+ // create new file stack
+ if (curr_srcfile == NULL)
+ {
+ curr_srcfile = source;
+ return;
+ }
+
+ SrcInfo *src_info = new_srcInfo ();
+ // In the ideal world, we need a DbeLine(III) here,
+ // but right now it would make us later believe that there are
+ // instructions generated for #include lines. To avoid that,
+ // we ask for a DbeLine(II).
+ src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/);
+ if (src_info->src_line)
+ {
+ src_info->included_from = curr_srcinfo;
+ curr_srcinfo = src_info;
+ }
+ curr_srcfile = source;
+ setSource ();
+}
+
+SourceFile *
+Function::popSrcFile ()
+{
+ if (curr_srcinfo != NULL)
+ {
+ curr_srcfile = curr_srcinfo->src_line->sourceFile;
+ curr_srcinfo = curr_srcinfo->included_from;
+ }
+ else
+ curr_srcfile = NULL;
+ return curr_srcfile;
+}
+
+void
+Function::copy_PCInfo (Function *from)
+{
+ if (line_first <= 0)
+ line_first = from->line_first;
+ if (line_last <= 0)
+ line_last = from->line_last;
+ if (def_source == NULL)
+ def_source = from->def_source;
+ for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++)
+ {
+ PCInfo *pcinf = from->linetab->fetch (i);
+ DbeLine *dbeLine = pcinf->src_info->src_line;
+ add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile);
+ }
+}
+
+void
+Function::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src)
+{
+ if (lineno <= 0 || size < 0 || offset >= (uint64_t) size)
+ return;
+ if (cur_src == NULL)
+ cur_src = curr_srcfile ? curr_srcfile : def_source;
+ if (linetab == NULL)
+ linetab = new Vector<PCInfo*>;
+
+ int left = 0;
+ int right = linetab->size () - 1;
+ DbeLine *dbeline;
+ while (left <= right)
+ {
+ int x = (left + right) / 2;
+ PCInfo *pcinf = linetab->fetch (x);
+ uint64_t pcinf_offset = ((uint64_t) pcinf->offset);
+ if (offset == pcinf_offset)
+ {
+ dbeline = cur_src->find_dbeline (this, lineno);
+ dbeline->init_Offset (offset);
+ pcinf->src_info->src_line = dbeline;
+ // Ignore duplicate offset
+ return;
+ }
+ else if (offset > pcinf_offset)
+ left = x + 1;
+ else
+ right = x - 1;
+ }
+ PCInfo *pcinfo = new PCInfo;
+ pcinfo->offset = offset;
+
+ // Form new SrcInfo
+ SrcInfo *srcInfo = new_srcInfo ();
+ dbeline = cur_src->find_dbeline (this, lineno);
+ dbeline->init_Offset (offset);
+ srcInfo->src_line = dbeline;
+ // For now don't build included_from list.
+ // We need better compiler support for that.
+ //srcInfo->included_from = curr_srcinfo;
+ srcInfo->included_from = NULL;
+ pcinfo->src_info = srcInfo;
+
+ // Update the size of the current line in both structures:
+ // current PCInfo and corresponding DbeLine.
+ if (left < linetab->size ())
+ pcinfo->size = linetab->fetch (left)->offset - offset;
+ else
+ pcinfo->size = size - offset;
+ pcinfo->src_info->src_line->size += pcinfo->size;
+
+ // If not the first line, update the size of the previous line
+ if (left > 0)
+ {
+ PCInfo *pcinfo_prev = linetab->fetch (left - 1);
+ int64_t delta = (offset - pcinfo_prev->offset) - pcinfo_prev->size;
+ pcinfo_prev->size += delta;
+ pcinfo_prev->src_info->src_line->size += delta;
+ }
+
+ linetab->insert (left, pcinfo);
+ if (cur_src == def_source)
+ {
+ if (line_first <= 0)
+ setLineFirst (lineno);
+ if (line_last <= 0 || lineno > line_last)
+ line_last = lineno;
+ }
+}
+
+PCInfo *
+Function::lookup_PCInfo (uint64_t offset)
+{
+ module->read_stabs ();
+ if (linetab == NULL)
+ linetab = new Vector<PCInfo*>;
+
+ int left = 0;
+ int right = linetab->size () - 1;
+ while (left <= right)
+ {
+ int x = (left + right) / 2;
+ PCInfo *pcinfo = linetab->fetch (x);
+ if (offset >= ((uint64_t) pcinfo->offset))
+ {
+ if (offset < (uint64_t) (pcinfo->offset + pcinfo->size))
+ return pcinfo;
+ left = x + 1;
+ }
+ else
+ right = x - 1;
+ }
+ return NULL;
+}
+
+DbeInstr*
+Function::mapLineToPc (DbeLine *dbeLine)
+{
+ if (dbeLine && linetab)
+ {
+ DbeLine *dbl = dbeLine->dbeline_base;
+ for (int i = 0, sz = linetab->size (); i < sz; i++)
+ {
+ PCInfo *pcinfo = linetab->get (i);
+ if (pcinfo->src_info
+ && (pcinfo->src_info->src_line->dbeline_base == dbl))
+ {
+ DbeInstr *dbeInstr = find_dbeinstr (PCLineFlag, pcinfo->offset);
+ if (dbeInstr)
+ {
+ dbeInstr->lineno = dbeLine->lineno;
+ return dbeInstr;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+DbeLine*
+Function::mapPCtoLine (uint64_t addr, SourceFile *src)
+{
+ PCInfo *pcinfo = lookup_PCInfo (addr);
+ if (pcinfo == NULL)
+ {
+ if (defaultDbeLine == NULL)
+ defaultDbeLine = getDefSrc ()->find_dbeline (this, 0);
+ return defaultDbeLine;
+ }
+ DbeLine *dbeline = pcinfo->src_info->src_line;
+
+ // If source-context is not specified return the line
+ // from which this pc has been generated.
+ if (src == NULL)
+ return dbeline;
+ if (dbeline->sourceFile == src)
+ return dbeline->dbeline_base;
+ return src->find_dbeline (this, 0);
+}
+
+DbeInstr *
+Function::find_dbeinstr (int flag, uint64_t addr)
+{
+ DbeInstr *instr;
+
+ enum
+ {
+ FuncInstHTableSize = 128
+ };
+
+ int hash = (((int) addr) >> 2) & (FuncInstHTableSize - 1);
+ if (instHTable == NULL)
+ {
+ if (size > 2048)
+ {
+ instHTable = new DbeInstr*[FuncInstHTableSize];
+ for (int i = 0; i < FuncInstHTableSize; i++)
+ instHTable[i] = NULL;
+ }
+ }
+ else
+ {
+ instr = instHTable[hash];
+ if (instr && instr->addr == addr && instr->flags == flag)
+ return instr;
+ }
+
+ int left = 0;
+ int right = instrs->size () - 1;
+ while (left <= right)
+ {
+ int index = (left + right) / 2;
+ instr = instrs->fetch (index);
+ if (addr < instr->addr)
+ right = index - 1;
+ else if (addr > instr->addr)
+ left = index + 1;
+ else
+ {
+ if (flag == instr->flags)
+ {
+ if (instHTable)
+ instHTable[hash] = instr;
+ return instr;
+ }
+ else if (flag < instr->flags)
+ right = index - 1;
+ else
+ left = index + 1;
+ }
+ }
+
+ // None found, create a new one
+ instr = new DbeInstr (instr_id++, flag, this, addr);
+ instrs->insert (left, instr);
+ if (instHTable)
+ instHTable[hash] = instr;
+ return instr;
+}
+
+// LIBRARY_VISIBILITY
+DbeInstr *
+Function::create_hide_instr (DbeInstr *instr)
+{
+ DbeInstr *new_instr = new DbeInstr (instr_id++, 0, this, instr->addr);
+ return new_instr;
+}
+
+uint64_t
+Function::find_previous_addr (uint64_t addr)
+{
+ if (addrs == NULL)
+ {
+ addrs = module->getAddrs (this);
+ if (addrs == NULL)
+ return addr;
+ }
+
+ int index = -1, not_found = 1;
+
+ enum
+ {
+ FuncAddrIndexHTableSize = 128
+ };
+ int hash = (((int) addr) >> 2) & (FuncAddrIndexHTableSize - 1);
+ if (addrIndexHTable == NULL)
+ {
+ if (size > 2048)
+ {
+ addrIndexHTable = new int[FuncAddrIndexHTableSize];
+ for (int i = 0; i < FuncAddrIndexHTableSize; i++)
+ addrIndexHTable[i] = -1;
+ }
+ }
+ else
+ {
+ index = addrIndexHTable[hash];
+ if (index >= 0 && addrs->fetch (index) == addr)
+ not_found = 0;
+ }
+
+ int left = 0;
+ int right = addrs->size () - 1;
+ while (not_found && left <= right)
+ {
+ index = (left + right) / 2;
+ uint64_t addr_test = addrs->fetch (index);
+ if (addr < addr_test)
+ right = index - 1;
+ else if (addr > addr_test)
+ left = index + 1;
+ else
+ {
+ if (addrIndexHTable)
+ addrIndexHTable[hash] = index;
+ not_found = 0;
+ }
+ }
+ if (not_found)
+ return addr;
+ if (index > 0)
+ index--;
+ return addrs->fetch (index);
+}
+
+void
+Function::setSource ()
+{
+ SourceFile *sf = module->getIncludeFile ();
+ if (sf == NULL)
+ sf = getDefSrc ();
+ if (def_source == NULL)
+ setDefSrc (sf);
+ if (sf == def_source)
+ return;
+ if (sources == NULL)
+ {
+ sources = new Vector<SourceFile*>;
+ sources->append (def_source);
+ sources->append (sf);
+ }
+ else if (sources->find (sf) < 0)
+ sources->append (sf);
+}
+
+void
+Function::setDefSrc (SourceFile *sf)
+{
+ if (sf)
+ {
+ def_source = sf;
+ if (line_first > 0)
+ add_PC_info (0, line_first, def_source);
+ }
+}
+
+void
+Function::setLineFirst (int lineno)
+{
+ if (lineno > 0)
+ {
+ line_first = lineno;
+ if (line_last <= 0)
+ line_last = lineno;
+ if (def_source)
+ add_PC_info (0, line_first, def_source);
+ }
+}
+
+Vector<SourceFile*> *
+Function::get_sources ()
+{
+ if (module)
+ module->read_stabs ();
+ if (sources == NULL)
+ {
+ sources = new Vector<SourceFile*>;
+ sources->append (getDefSrc ());
+ }
+ return sources;
+}
+
+SourceFile*
+Function::getDefSrc ()
+{
+ if (module)
+ module->read_stabs ();
+ if (def_source == NULL)
+ setDefSrc (module->getMainSrc ());
+ return def_source;
+}
+
+char *
+Function::getDefSrcName ()
+{
+ SourceFile *sf = getDefSrc ();
+ if (sf)
+ return sf->dbeFile->getResolvedPath ();
+ if (module)
+ return module->file_name;
+ sf = dbeSession->get_Unknown_Source ();
+ return sf->get_name ();
+}
+
+#define cmpValue(a, b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1)
+
+int
+Function::func_cmp (Function *func, SourceFile *srcContext)
+{
+ if (def_source != func->def_source)
+ {
+ if (srcContext == NULL)
+ srcContext = getDefSrc ();
+ if (def_source == srcContext)
+ return -1;
+ if (func->def_source == srcContext)
+ return 1;
+ return cmpValue (img_offset, func->img_offset);
+ }
+
+ if (line_first == func->line_first)
+ return cmpValue (img_offset, func->img_offset);
+ if (line_first <= 0)
+ {
+ if (func->line_first > 0)
+ return 1;
+ return cmpValue (img_offset, func->img_offset);
+ }
+ if (func->line_first <= 0)
+ return -1;
+ return cmpValue (line_first, func->line_first);
+}
+
+Vector<Histable*> *
+Function::get_comparable_objs ()
+{
+ update_comparable_objs ();
+ if (comparable_objs || dbeSession->expGroups->size () <= 1 || module == NULL)
+ return comparable_objs;
+ if (module == NULL || module->loadobject == NULL)
+ return NULL;
+ Vector<Histable*> *comparableModules = module->get_comparable_objs ();
+ if (comparableModules == NULL)
+ {
+ return NULL;
+ }
+ comparable_objs = new Vector<Histable*>(comparableModules->size ());
+ for (long i = 0, sz = comparableModules->size (); i < sz; i++)
+ {
+ Function *func = NULL;
+ comparable_objs->store (i, func);
+ Module *mod = (Module*) comparableModules->fetch (i);
+ if (mod == NULL)
+ continue;
+ if (mod == module)
+ func = this;
+ else
+ {
+ for (long i1 = 0, sz1 = VecSize (mod->functions); i1 < sz1; i1++)
+ {
+ Function *f = mod->functions->get (i1);
+ if ((f->comparable_objs == NULL)
+ && (strcmp (f->comparable_name, comparable_name) == 0))
+ {
+ func = f;
+ func->comparable_objs = comparable_objs;
+ break;
+ }
+ }
+ }
+ comparable_objs->store (i, func);
+ }
+ Vector<Histable*> *comparableLoadObjs =
+ module->loadobject->get_comparable_objs ();
+ if (VecSize (comparableLoadObjs) == VecSize (comparable_objs))
+ {
+ for (long i = 0, sz = VecSize (comparableLoadObjs); i < sz; i++)
+ {
+ LoadObject *lo = (LoadObject *) comparableLoadObjs->get (i);
+ Function *func = (Function *) comparable_objs->get (i);
+ if (func || (lo == NULL))
+ continue;
+ if (module->loadobject == lo)
+ func = this;
+ else
+ {
+ for (long i1 = 0, sz1 = VecSize (lo->functions); i1 < sz1; i1++)
+ {
+ Function *f = lo->functions->fetch (i1);
+ if ((f->comparable_objs == NULL)
+ && (strcmp (f->comparable_name, comparable_name) == 0))
+ {
+ func = f;
+ func->comparable_objs = comparable_objs;
+ break;
+ }
+ }
+ }
+ comparable_objs->store (i, func);
+ }
+ }
+ dump_comparable_objs ();
+ return comparable_objs;
+}
+
+JMethod::JMethod (uint64_t _id) : Function (_id)
+{
+ mid = 0LL;
+ addr = (Vaddr) 0;
+ signature = NULL;
+ jni_function = NULL;
+}
+
+JMethod::~JMethod ()
+{
+ free (signature);
+}
+
+uint64_t
+JMethod::get_addr ()
+{
+ if (addr != (Vaddr) 0)
+ return addr;
+ else
+ return Function::get_addr ();
+}
+
+typedef struct
+{
+ size_t used_in;
+ size_t used_out;
+} MethodField;
+
+static void
+write_buf (char* buf, char* str)
+{
+ while ((*buf++ = *str++));
+}
+
+/** Translate one field from the nane buffer.
+ * return how many chars were read from name and how many bytes were used in buf.
+ */
+static MethodField
+translate_method_field (const char* name, char* buf)
+{
+ MethodField out, t;
+ switch (*name)
+ {
+ case 'L':
+ name++;
+ out.used_in = 1;
+ out.used_out = 0;
+ while (*name != ';')
+ {
+ *buf = *name++;
+ if (*buf == '/')
+ *buf = '.';
+ buf++;
+ out.used_in++;
+ out.used_out++;
+ }
+ out.used_in++; /* the ';' is also used. */
+ break;
+ case 'Z':
+ write_buf (buf, NTXT ("boolean"));
+ out.used_out = 7;
+ out.used_in = 1;
+ break;
+ case 'B':
+ write_buf (buf, NTXT ("byte"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case 'C':
+ write_buf (buf, NTXT ("char"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case 'S':
+ write_buf (buf, NTXT ("short"));
+ out.used_out = 5;
+ out.used_in = 1;
+ break;
+ case 'I':
+ write_buf (buf, NTXT ("int"));
+ out.used_out = 3;
+ out.used_in = 1;
+ break;
+ case 'J':
+ write_buf (buf, NTXT ("long"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case 'F':
+ write_buf (buf, NTXT ("float"));
+ out.used_out = 5;
+ out.used_in = 1;
+ break;
+ case 'D':
+ write_buf (buf, NTXT ("double"));
+ out.used_out = 6;
+ out.used_in = 1;
+ break;
+ case 'V':
+ write_buf (buf, NTXT ("void"));
+ out.used_out = 4;
+ out.used_in = 1;
+ break;
+ case '[':
+ t = translate_method_field (name + 1, buf);
+ write_buf (buf + t.used_out, NTXT ("[]"));
+ out.used_out = t.used_out + 2;
+ out.used_in = t.used_in + 1;
+ break;
+ default:
+ out.used_out = 0;
+ out.used_in = 0;
+ }
+ return out;
+}
+
+/**
+ * translate method name to full method signature
+ * into the output buffer (buf).
+ * ret_type - true for printing result type
+ */
+static bool
+translate_method (char* mname, char *signature, bool ret_type, char* buf)
+{
+ MethodField p;
+ size_t l;
+ int first = 1;
+ if (signature == NULL)
+ return false;
+
+ const char *c = strchr (signature, ')');
+ if (c == NULL)
+ return false;
+ if (ret_type)
+ {
+ p = translate_method_field (++c, buf);
+ buf += p.used_out;
+ *buf++ = ' ';
+ }
+
+ l = strlen (mname);
+ memcpy (buf, mname, l + 1);
+ buf += l;
+ // *buf++ = ' '; // space before ()
+ *buf++ = '(';
+
+ c = signature + 1;
+ while (*c != ')')
+ {
+ if (!first)
+ {
+ *buf++ = ',';
+ *buf++ = ' ';
+ }
+ first = 0;
+ p = translate_method_field (c, buf);
+ c += p.used_in;
+ buf += p.used_out;
+ }
+
+ *buf++ = ')';
+ *buf = '\0';
+ return true;
+}
+
+void
+JMethod::set_name (char *string)
+{
+ if (string == NULL)
+ return;
+ set_mangled_name (string);
+
+ char buf[MAXDBUF];
+ *buf = '\0';
+ if (translate_method (string, signature, false, buf))
+ {
+ name = dbe_strdup (buf); // got translated string
+ Dprintf (DUMP_JCLASS_READER,
+ "JMethod::set_name: true name=%s string=%s signature=%s\n",
+ STR (name), STR (string), STR (signature));
+ }
+ else
+ {
+ name = dbe_strdup (string);
+ Dprintf (DUMP_JCLASS_READER,
+ "JMethod::set_name: false name=%s signature=%s\n",
+ STR (name), STR (signature));
+ }
+ set_match_name (name);
+ set_comparable_name (name);
+}
+
+bool
+JMethod::jni_match (Function *func)
+{
+ if (func == NULL || (func->flags & FUNC_NOT_JNI) != 0)
+ return false;
+ if (jni_function == func)
+ return true;
+
+ char *fname = func->get_name ();
+ if ((func->flags & FUNC_JNI_CHECKED) == 0)
+ {
+ func->flags |= FUNC_JNI_CHECKED;
+ if (strncmp (func->get_name (), NTXT ("Java_"), 5) != 0)
+ {
+ func->flags |= FUNC_NOT_JNI;
+ return false;
+ }
+ }
+
+ char *d = name;
+ char *s = fname + 5;
+ while (*d && *d != '(' && *d != ' ')
+ {
+ if (*d == '.')
+ {
+ if (*s++ != '_')
+ return false;
+ d++;
+ }
+ else if (*d == '_')
+ {
+ if (*s++ != '_')
+ return false;
+ if (*s++ != '1')
+ return false;
+ d++;
+ }
+ else if (*d++ != *s++)
+ return false;
+ }
+ jni_function = func;
+ return true;
+}
diff --git a/gprofng/src/Function.h b/gprofng/src/Function.h
new file mode 100644
index 0000000..b0a856b
--- /dev/null
+++ b/gprofng/src/Function.h
@@ -0,0 +1,222 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_FUNCTION_H
+#define _DBE_FUNCTION_H
+
+// A Function object represents an individual function in a .o file.
+
+#include "util.h"
+#include "Histable.h"
+#include "SourceFile.h"
+
+class Module;
+class Symbol;
+class InlinedSubr;
+struct SrcInfo;
+struct PCInfo;
+template <class ITEM> class Vector;
+
+const uint64_t FUNC_NO_SAVE = (uint64_t) - 1;
+const uint64_t FUNC_ROOT = (uint64_t) - 2;
+
+enum
+{
+ FUNC_FLAG_PLT = 1,
+ FUNC_FLAG_DYNAMIC = 2,
+ FUNC_FLAG_RESDER = 4, // set if derived function resolution has been done
+ FUNC_FLAG_NO_OFFSET = 8, // set if disassembly should not show offset from function
+ FUNC_FLAG_SIMULATED = 16, // not a real function like <Total>, <Unknown>, etc.
+ FUNC_FLAG_NATIVE = 32, // no byte code for JMethod
+ FUNC_NOT_JNI = 64, // a function name is not "Java_..."
+ FUNC_JNI_CHECKED = 128 // already checked for "Java_..."
+};
+
+const int MAXDBUF = 32768; // the longest demangled name handled
+
+class Function : public Histable
+{
+public:
+
+ enum MPFuncTypes
+ {
+ MPF_DOALL,
+ MPF_PAR,
+ MPF_SECT,
+ MPF_TASK,
+ MPF_CLONE,
+ MPF_OUTL
+ };
+
+ Function (uint64_t _id);
+ virtual ~Function ();
+
+ virtual uint64_t get_addr ();
+ virtual char *get_name (NameFormat = NA);
+ virtual Vector<Histable*> *get_comparable_objs ();
+ virtual void set_name (char *); // Set the demangled name
+ virtual Histable *convertto (Histable_type type, Histable *obj = NULL);
+
+ virtual Histable_type
+ get_type ()
+ {
+ return FUNCTION;
+ };
+
+ virtual int64_t
+ get_size ()
+ {
+ return size;
+ };
+
+ void set_comparable_name (const char *string);
+ void set_mangled_name (const char *string);
+ void set_match_name (const char *string);
+
+ // Find any derived functions, and set their derivedNode
+ void findDerivedFunctions ();
+ void findKrakatoaDerivedFunctions ();
+ void add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src = NULL);
+ void pushSrcFile (SourceFile* source, int lineno);
+ SourceFile *popSrcFile ();
+ int func_cmp (Function *func, SourceFile *srcContext = NULL);
+ void copy_PCInfo (Function *f);
+ DbeLine *mapPCtoLine (uint64_t addr, SourceFile *src = NULL);
+ DbeInstr *mapLineToPc (DbeLine *dbeLine);
+ DbeInstr *find_dbeinstr (int flag, uint64_t addr);
+ DbeInstr *create_hide_instr (DbeInstr *instr);
+ uint64_t find_previous_addr (uint64_t addr);
+ SourceFile *getDefSrc ();
+ char *getDefSrcName ();
+ void setDefSrc (SourceFile *sf);
+ void setLineFirst (int lineno);
+ Vector<SourceFile*> *get_sources ();
+
+ char *
+ get_mangled_name ()
+ {
+ return mangled_name;
+ }
+
+ char *
+ get_match_name ()
+ {
+ return match_name;
+ }
+
+ inline Function *
+ cardinal ()
+ {
+ return alias ? alias : this;
+ }
+
+ unsigned int flags; // FUNC_FLAG_*
+ Module *module; // pointer to module containing source
+ int line_first; // range of line numbers for function
+ int line_last;
+ int64_t size; // size of the function in bytes
+ uint64_t save_addr; // used for detection of leaf routines
+ DbeInstr *derivedNode; // If derived from another function
+ bool isOutlineFunction; // if outline (save assumed)
+ unsigned int chksum; // check sum of instructions
+ char *img_fname; // file containing function image
+ uint64_t img_offset; // file offset of the image
+ SourceFile *curr_srcfile;
+ DbeLine *defaultDbeLine;
+ Function *usrfunc; // User function
+ Function *alias;
+ bool isUsed;
+ bool isHideFunc;
+ SourceFile *def_source;
+ Function *indexStabsLink; // correspondent function for the .o file
+ Symbol *elfSym;
+ InlinedSubr *inlinedSubr;
+ int inlinedSubrCnt;
+
+private:
+ DbeInstr **instHTable; // hash table for DbeInstr
+ int *addrIndexHTable; // hash table for addrs index
+ void setSource ();
+ PCInfo *lookup_PCInfo (uint64_t offset);
+ SrcInfo *new_srcInfo ();
+
+ char *mangled_name;
+ char *match_name; // mangled name, with globalization stripped
+ char *comparable_name; // demangled name, with globalization and blanks stripped
+ char *name_buf;
+ NameFormat current_name_format;
+ Vector<PCInfo*> *linetab;
+ Vector<DbeInstr*> *instrs;
+ Vector<uint64_t> *addrs;
+ uint64_t instr_id;
+ Vector<SourceFile*> *sources;
+ SrcInfo *curr_srcinfo; // the current source stack of the function
+ SrcInfo *srcinfo_list; // master list for SrcInfo
+};
+
+class JMethod : public Function
+{
+public:
+ JMethod (uint64_t _id);
+ virtual ~JMethod ();
+ virtual void set_name (char *);
+ virtual uint64_t get_addr ();
+
+ void
+ set_addr (Vaddr _addr)
+ {
+ addr = _addr;
+ }
+
+ uint64_t
+ get_mid ()
+ {
+ return mid;
+ }
+
+ void
+ set_mid (uint64_t _mid)
+ {
+ mid = _mid;
+ }
+
+ char *
+ get_signature ()
+ {
+ return signature;
+ }
+
+ void
+ set_signature (const char *s)
+ {
+ signature = dbe_strdup (s);
+ }
+
+ // Returns true if func's name matches method's as its JNI implementation
+ bool jni_match (Function *func);
+
+private:
+ uint64_t mid;
+ Vaddr addr;
+ char *signature;
+ Function *jni_function;
+};
+
+#endif /* _DBE_FUNCTION_H */
diff --git a/gprofng/src/HashMap.h b/gprofng/src/HashMap.h
new file mode 100644
index 0000000..f66a6fe
--- /dev/null
+++ b/gprofng/src/HashMap.h
@@ -0,0 +1,435 @@
+/* Copyright (C) 2021 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. */
+
+// java.util.HashMap
+
+#ifndef _DBE_HASHMAP_H
+#define _DBE_HASHMAP_H
+
+#include "vec.h"
+#include "util.h"
+#include "StringBuilder.h"
+#include "Histable.h"
+#include "MemObject.h"
+
+template <typename Key_t> inline int get_hash_code (Key_t a);
+template <typename Key_t> inline bool is_equals (Key_t a, Key_t b);
+template <typename Key_t> inline Key_t copy_key (Key_t a);
+template <typename Key_t> inline void delete_key (Key_t a);
+
+// Specialization for char*
+template<> inline int
+get_hash_code (char *a)
+{
+ return (int) (crc64 (a, strlen (a)) & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (char *a, char *b)
+{
+ return dbe_strcmp (a, b) == 0;
+}
+
+template<> inline char *
+copy_key (char *a)
+{
+ return dbe_strdup (a);
+}
+
+template<> inline void
+delete_key (char *a)
+{
+ return free (a);
+}
+
+template<> inline int
+get_hash_code (uint64_t a)
+{
+ return (int) (a & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (uint64_t a, uint64_t b)
+{
+ return a == b;
+}
+
+template<> inline uint64_t
+copy_key (uint64_t a)
+{
+ return a;
+}
+
+template<> inline void
+delete_key (uint64_t a)
+{
+ a = a;
+}
+
+template<> inline int
+get_hash_code (Histable* a)
+{
+ return (int) (a->id & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (Histable* a, Histable* b)
+{
+ return a == b;
+}
+
+template<> inline Histable*
+copy_key (Histable* a)
+{
+ return a;
+}
+
+template<> inline void
+delete_key (Histable* a)
+{
+ a->id = a->id;
+}
+
+template<> inline int
+get_hash_code (MemObj* a)
+{
+ return (int) (a->id & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (MemObj* a, MemObj* b)
+{
+ return a == b;
+}
+
+template<> inline MemObj*
+copy_key (MemObj* a)
+{
+ return a;
+}
+
+template<> inline void
+delete_key (MemObj* a)
+{
+ a->id = a->id;
+}
+
+template <typename Key_t, typename Value_t>
+class HashMap
+{
+public:
+ HashMap (int initialCapacity = 0);
+
+ ~HashMap ()
+ {
+ clear ();
+ delete vals;
+ delete[] hashTable;
+ }
+
+ Value_t put (Key_t key, Value_t val);
+ Value_t get (Key_t key);
+ Value_t get (Key_t key, Value_t val); // Create a new map if key is not here
+ void clear ();
+ Value_t remove (Key_t);
+ Vector<Value_t> *values (Key_t key); // Return a list of values for 'key'
+
+ bool
+ containsKey (Key_t key)
+ {
+ Value_t p = get (key);
+ return p != NULL;
+ };
+
+ Vector<Value_t> *
+ values ()
+ {
+ return vals;
+ }
+
+ void
+ reset ()
+ {
+ clear ();
+ }
+
+ int
+ get_phaseIdx ()
+ {
+ return phaseIdx;
+ }
+
+ void
+ set_phaseIdx (int phase)
+ {
+ if (phase == 0) clear ();
+ phaseIdx = phase;
+ }
+ char *dump ();
+
+private:
+
+ enum
+ {
+ HASH_SIZE = 511,
+ MAX_HASH_SIZE = 1048575
+ };
+
+ typedef struct Hash
+ {
+ Key_t key;
+ Value_t val;
+ struct Hash *next;
+ } Hash_t;
+
+ void resize ();
+
+ int
+ hashCode (Key_t key)
+ {
+ return get_hash_code (key) % hash_sz;
+ }
+
+ bool
+ equals (Key_t a, Key_t b)
+ {
+ return is_equals (a, b);
+ }
+
+ Key_t
+ copy (Key_t key)
+ {
+ return copy_key (key);
+ }
+
+ Hash_t **hashTable;
+ Vector<Value_t> *vals;
+ int phaseIdx;
+ int hash_sz;
+ int nelem;
+};
+
+template <typename Key_t, typename Value_t>
+HashMap<Key_t, Value_t>
+::HashMap (int initialCapacity)
+{
+ if (initialCapacity > 0)
+ vals = new Vector<Value_t>(initialCapacity);
+ else
+ vals = new Vector<Value_t>();
+ phaseIdx = 0;
+ nelem = 0;
+ hash_sz = HASH_SIZE;
+ hashTable = new Hash_t*[hash_sz];
+ for (int i = 0; i < hash_sz; i++)
+ hashTable[i] = NULL;
+}
+
+template <typename Key_t, typename Value_t>
+void
+HashMap<Key_t, Value_t>::clear ()
+{
+ vals->reset ();
+ phaseIdx = 0;
+ nelem = 0;
+ for (int i = 0; i < hash_sz; i++)
+ {
+ Hash_t *next;
+ for (Hash_t *p = hashTable[i]; p; p = next)
+ {
+ next = p->next;
+ delete_key (p->key);
+ delete p;
+ }
+ hashTable[i] = NULL;
+ }
+}
+
+template <typename Key_t, typename Value_t>
+void
+HashMap<Key_t, Value_t>::resize ()
+{
+ int old_hash_sz = hash_sz;
+ hash_sz = old_hash_sz * 2 + 1;
+ Hash_t **old_hash_table = hashTable;
+ hashTable = new Hash_t*[hash_sz];
+ for (int i = 0; i < hash_sz; i++)
+ hashTable[i] = NULL;
+ nelem = 0;
+ for (int i = 0; i < old_hash_sz; i++)
+ {
+ if (old_hash_table[i] != NULL)
+ {
+ Hash_t *old_p;
+ Hash_t *p = old_hash_table[i];
+ while (p != NULL)
+ {
+ put (p->key, p->val);
+ old_p = p;
+ p = p->next;
+ delete old_p;
+ }
+ }
+ }
+ delete[] old_hash_table;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::get (Key_t key)
+{
+ int hash_code = hashCode (key);
+ for (Hash_t *p = hashTable[hash_code]; p; p = p->next)
+ if (equals (key, p->key))
+ return p->val;
+ return NULL;
+}
+
+template <typename Key_t, typename Value_t>
+Vector<Value_t> *
+HashMap<Key_t, Value_t>::values (Key_t key)
+{
+ Vector<Value_t> *list = new Vector<Value_t>();
+ int hash_code = hashCode (key);
+ for (Hash_t *p = hashTable[hash_code]; p; p = p->next)
+ {
+ if (equals (key, p->key))
+ list->append (p->val);
+ }
+ return list;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::get (const Key_t key, Value_t val)
+{
+ int hash_code = hashCode (key);
+ Hash_t *p, *first = NULL;
+ for (p = hashTable[hash_code]; p; p = p->next)
+ {
+ if (equals (key, p->key))
+ {
+ if (first == NULL)
+ first = p;
+ if (val == p->val)
+ return first->val; // Always return the first value
+ }
+ }
+ vals->append (val);
+ p = new Hash_t ();
+ p->val = val;
+ p->key = copy (key);
+ if (first)
+ {
+ p->next = first->next;
+ first->next = p;
+ return first->val; // Always return the first value
+ }
+ else
+ {
+ p->next = hashTable[hash_code];
+ hashTable[hash_code] = p;
+ return val;
+ }
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::remove (Key_t key)
+{
+ int hash_code = hashCode (key);
+ Value_t val = NULL;
+ for (Hash_t *prev = NULL, *p = hashTable[hash_code]; p != NULL;)
+ {
+ if (equals (key, p->key))
+ {
+ if (prev == NULL)
+ hashTable[hash_code] = p->next;
+ else
+ prev->next = p->next;
+ if (val == NULL)
+ val = p->val;
+ delete_key (p->key);
+ delete p;
+ }
+ else
+ {
+ prev = p;
+ p = p->next;
+ }
+ }
+ return val;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+ int hash_code = hashCode (key);
+ vals->append (val);
+ for (Hash_t *p = hashTable[hash_code]; p != NULL; p = p->next)
+ {
+ if (equals (key, p->key))
+ {
+ Value_t v = p->val;
+ p->val = val;
+ return v;
+ }
+ }
+ Hash_t *p = new Hash_t ();
+ p->val = val;
+ p->key = copy (key);
+ p->next = hashTable[hash_code];
+ hashTable[hash_code] = p;
+ nelem++;
+ if (nelem == hash_sz)
+ resize ();
+ return val;
+}
+
+template <typename Key_t, typename Value_t>
+char *
+HashMap<Key_t, Value_t>::dump ()
+{
+ StringBuilder sb;
+ char buf[128];
+ snprintf (buf, sizeof (buf), "HashMap: size=%d ##########\n", vals->size ());
+ sb.append (buf);
+ for (int i = 0; i < hash_sz; i++)
+ {
+ if (hashTable[i] == NULL)
+ continue;
+ snprintf (buf, sizeof (buf), "%3d:", i);
+ sb.append (buf);
+ char *s = NTXT (" ");
+ for (Hash_t *p = hashTable[i]; p; p = p->next)
+ {
+ sb.append (s);
+ s = NTXT (" ");
+ sb.append (p->key);
+ snprintf (buf, sizeof (buf), " --> 0x%p '%s'\n",
+ p->val, p->val->get_name ());
+ sb.append (buf);
+ }
+ }
+ return sb.toString ();
+}
+
+#endif // _DBE_HASHMAP_H
diff --git a/gprofng/src/HeapActivity.cc b/gprofng/src/HeapActivity.cc
new file mode 100644
index 0000000..943183d
--- /dev/null
+++ b/gprofng/src/HeapActivity.cc
@@ -0,0 +1,408 @@
+/* Copyright (C) 2021 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 "DbeSession.h"
+#include "HeapData.h"
+#include "StringBuilder.h"
+#include "i18n.h"
+#include "util.h"
+#include "HeapActivity.h"
+#include "MetricList.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "DbeView.h"
+#include "Exp_Layout.h"
+#include "i18n.h"
+
+HeapActivity::HeapActivity (DbeView *_dbev)
+{
+ dbev = _dbev;
+ hDataTotal = NULL;
+ hDataObjs = NULL;
+ hDataObjsCallStack = NULL;
+ hasCallStack = false;
+ hDataCalStkMap = NULL;
+ hist_data_callstack_all = NULL;
+}
+
+void
+HeapActivity::reset ()
+{
+ delete hDataTotal;
+ hDataTotal = NULL;
+ delete hDataObjsCallStack;
+ hDataObjsCallStack = NULL;
+ hasCallStack = false;
+ hDataObjs = NULL;
+ delete hDataCalStkMap;
+ hDataCalStkMap = NULL;
+ hist_data_callstack_all = NULL;
+}
+
+void
+HeapActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
+ Histable::Type hType, bool empty)
+{
+ int mIndex;
+ Metric *mtr;
+ Hist_data::HistItem *hi;
+ HeapData *hData = NULL;
+ if (hDataTotal == NULL)
+ {
+ hDataTotal = new HeapData (TOTAL_HEAPNAME);
+ hDataTotal->setHistType (hType);
+ hDataTotal->setStackId (TOTAL_STACK_ID);
+ hDataTotal->id = 0;
+ }
+
+ hData = new HeapData (hDataTotal);
+ hData->setHistType (hType);
+ hi = hist_data->append_hist_item (hData);
+
+ Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+ {
+ if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+ continue;
+
+ Metric::Type mtype = mtr->get_type ();
+ ValueTag vType = mtr->get_vtype ();
+
+ hist_data->total->value[mIndex].tag = vType;
+ hi->value[mIndex].tag = vType;
+ switch (mtype)
+ {
+ case BaseMetric::HEAP_ALLOC_BYTES:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
+ hi->value[mIndex].ll = hDataTotal->getAllocBytes ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::HEAP_ALLOC_CNT:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
+ hi->value[mIndex].ll = hDataTotal->getAllocCnt ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::HEAP_LEAK_BYTES:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
+ hi->value[mIndex].ll = hDataTotal->getLeakBytes ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::HEAP_LEAK_CNT:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
+ hi->value[mIndex].ll = hDataTotal->getLeakCnt ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+HeapActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
+{
+ int mIndex;
+ Metric *mtr;
+ Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+ {
+ if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+ continue;
+
+ Metric::Type mtype = mtr->get_type ();
+ ValueTag vType = mtr->get_vtype ();
+
+ hist_data->total->value[mIndex].tag = vType;
+ switch (mtype)
+ {
+ case BaseMetric::HEAP_ALLOC_BYTES:
+ hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
+ break;
+ case BaseMetric::HEAP_ALLOC_CNT:
+ hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
+ break;
+ case BaseMetric::HEAP_LEAK_BYTES:
+ hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
+ break;
+ case BaseMetric::HEAP_LEAK_CNT:
+ hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+HeapActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
+ Hist_data::Mode mode, Histable *selObj)
+{
+
+ Hist_data::HistItem *hi = NULL;
+
+ int numObjs = hDataObjs->size ();
+ int numMetrics = mlist->get_items ()->size ();
+ for (int i = 0; i < numObjs; i++)
+ {
+ HeapData *hData = hDataObjs->fetch (i);
+ if (mode == Hist_data::ALL)
+ hi = hist_data->append_hist_item (hData);
+ else if (mode == Hist_data::SELF)
+ {
+ if (hData->id == selObj->id)
+ hi = hist_data->append_hist_item (hData);
+ else
+ continue;
+ }
+
+ for (int mIndex = 0; mIndex < numMetrics; mIndex++)
+ {
+ Metric *mtr = mlist->get_items ()->fetch (mIndex);
+ if (!mtr->is_visible () && !mtr->is_tvisible ()
+ && !mtr->is_pvisible ())
+ continue;
+
+ Metric::Type mtype = mtr->get_type ();
+ ValueTag vType = mtr->get_vtype ();
+ hi->value[mIndex].tag = vType;
+ switch (mtype)
+ {
+ case BaseMetric::HEAP_ALLOC_BYTES:
+ hi->value[mIndex].ll = hData->getAllocBytes ();
+ break;
+ case BaseMetric::HEAP_ALLOC_CNT:
+ hi->value[mIndex].ll = hData->getAllocCnt ();
+ break;
+ case BaseMetric::HEAP_LEAK_BYTES:
+ hi->value[mIndex].ll = hData->getLeakBytes ();
+ break;
+ case BaseMetric::HEAP_LEAK_CNT:
+ hi->value[mIndex].ll = hData->getLeakCnt ();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+Hist_data *
+HeapActivity::compute_metrics (MetricList *mlist, Histable::Type type,
+ Hist_data::Mode mode, Histable *selObj)
+{
+ // it's already there, just return it
+ if (mode == Hist_data::ALL && type == Histable::HEAPCALLSTACK
+ && hist_data_callstack_all != NULL)
+ return hist_data_callstack_all;
+
+ bool has_data = false;
+ Hist_data *hist_data = NULL;
+ VMode viewMode = dbev->get_view_mode ();
+ switch (type)
+ {
+ case Histable::HEAPCALLSTACK:
+ if (!hasCallStack) // It is not computed yet
+ computeCallStack (type, viewMode);
+
+ // computeCallStack() creates hDataObjsCallStack
+ // hDataObjsCallStack contains the list of call stack objects
+ if (hDataObjsCallStack != NULL)
+ {
+ hDataObjs = hDataObjsCallStack;
+ has_data = true;
+ }
+ else
+ has_data = false;
+
+ if (has_data && mode == Hist_data::ALL && hist_data_callstack_all == NULL)
+ {
+ hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
+ hist_data = hist_data_callstack_all;
+ }
+ else if (has_data)
+ hist_data = new Hist_data (mlist, type, mode, false);
+ else
+ {
+ hist_data = new Hist_data (mlist, type, mode, false);
+ createHistItemTotals (hist_data, mlist, type, true);
+ return hist_data;
+ }
+ break;
+ default:
+ fprintf (stderr,
+ "HeapActivity cannot process data due to wrong Histable (type=%d) \n",
+ type);
+ abort ();
+ }
+
+ if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
+ createHistItemTotals (hist_data, mlist, type, false);
+ else
+ computeHistTotals (hist_data, mlist);
+ computeHistData (hist_data, mlist, mode, selObj);
+
+ // Determine by which metric to sort if any
+ bool rev_sort = mlist->get_sort_rev ();
+ int sort_ind = -1;
+ int nmetrics = mlist->get_items ()->size ();
+
+ for (int mind = 0; mind < nmetrics; mind++)
+ if (mlist->get_sort_ref_index () == mind)
+ sort_ind = mind;
+
+ hist_data->sort (sort_ind, rev_sort);
+ hist_data->compute_minmax ();
+
+ return hist_data;
+}
+
+void
+HeapActivity::computeCallStack (Histable::Type type, VMode viewMode)
+{
+ bool has_data = false;
+ reset ();
+ uint64_t stackIndex = 0;
+ HeapData *hData = NULL;
+
+ delete hDataCalStkMap;
+ hDataCalStkMap = new DefaultMap<uint64_t, HeapData*>;
+
+ delete hDataTotal;
+ hDataTotal = new HeapData (TOTAL_HEAPNAME);
+ hDataTotal->setHistType (type);
+
+ // There is no call stack for total, use the index for id
+ hDataTotal->id = stackIndex++;
+
+ // get the list of io events from DbeView
+ int numExps = dbeSession->nexps ();
+
+ for (int k = 0; k < numExps; k++)
+ {
+ // Investigate the performance impact of processing the heap events twice.
+ // This is a 2*n performance issue
+ dbev->get_filtered_events (k, DATA_HEAPSZ);
+
+ DataView *heapPkts = dbev->get_filtered_events (k, DATA_HEAP);
+ if (heapPkts == NULL)
+ continue;
+
+ Experiment *exp = dbeSession->get_exp (k);
+ long sz = heapPkts->getSize ();
+ int pid = 0;
+ int userExpId = 0;
+ if (sz > 0)
+ {
+ pid = exp->getPID ();
+ userExpId = exp->getUserExpId ();
+ }
+ for (long i = 0; i < sz; ++i)
+ {
+ uint64_t nByte = heapPkts->getULongValue (PROP_HSIZE, i);
+ uint64_t stackId = (uint64_t) getStack (viewMode, heapPkts, i);
+ Heap_type heapType = (Heap_type) heapPkts->getIntValue (PROP_HTYPE, i);
+ uint64_t leaked = heapPkts->getULongValue (PROP_HLEAKED, i);
+ int64_t heapSize = heapPkts->getLongValue (PROP_HCUR_ALLOCS, i);
+ hrtime_t packetTimestamp = heapPkts->getLongValue (PROP_TSTAMP, i);
+ hrtime_t timestamp = packetTimestamp - exp->getStartTime () +
+ exp->getRelativeStartTime ();
+
+ switch (heapType)
+ {
+ case MMAP_TRACE:
+ case MALLOC_TRACE:
+ case REALLOC_TRACE:
+ if (stackId != 0)
+ {
+ hData = hDataCalStkMap->get (stackId);
+ if (hData == NULL)
+ {
+ char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
+ (unsigned long long) stackId);
+ hData = new HeapData (stkName);
+ hDataCalStkMap->put (stackId, hData);
+ hData->id = (int64_t) stackId;
+ hData->setStackId (stackIndex);
+ stackIndex++;
+ hData->setHistType (type);
+ }
+ }
+ else
+ continue;
+
+ hData->addAllocEvent (nByte);
+ hDataTotal->addAllocEvent (nByte);
+ hDataTotal->setAllocStat (nByte);
+ hDataTotal->setPeakMemUsage (heapSize, hData->getStackId (),
+ timestamp, pid, userExpId);
+ if (leaked > 0)
+ {
+ hData->addLeakEvent (leaked);
+ hDataTotal->addLeakEvent (leaked);
+ hDataTotal->setLeakStat (leaked);
+ }
+ break;
+ case MUNMAP_TRACE:
+ case FREE_TRACE:
+ if (hData == NULL)
+ hData = new HeapData (TOTAL_HEAPNAME);
+ hDataTotal->setPeakMemUsage (heapSize, hData->getStackId (),
+ timestamp, pid, userExpId);
+ break;
+ case HEAPTYPE_LAST:
+ break;
+ }
+ has_data = true;
+ }
+ }
+
+ if (has_data)
+ {
+ hDataObjsCallStack = hDataCalStkMap->values ()->copy ();
+ hasCallStack = true;
+ }
+}
diff --git a/gprofng/src/HeapActivity.h b/gprofng/src/HeapActivity.h
new file mode 100644
index 0000000..582b0b7
--- /dev/null
+++ b/gprofng/src/HeapActivity.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _HEAPACTIVITY_H
+#define _HEAPACTIVITY_H
+
+
+#include <stdio.h>
+
+#include "vec.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Metric.h"
+#include "HeapData.h"
+#include "DefaultMap.h"
+#include "dbe_types.h"
+
+class Experiment;
+class Expression;
+class DataView;
+class DbeView;
+
+class HeapActivity
+{
+public:
+
+ HeapActivity (DbeView *_dbev);
+
+ ~HeapActivity ()
+ {
+ this->reset ();
+ }
+
+ void reset (void);
+ Hist_data *compute_metrics (MetricList *, Histable::Type,
+ Hist_data::Mode, Histable*);
+
+private:
+
+ void computeCallStack (Histable::Type, VMode viewMode);
+ void createHistItemTotals (Hist_data *, MetricList *, Histable::Type, bool);
+ void computeHistTotals (Hist_data *, MetricList *);
+ void computeHistData (Hist_data *, MetricList *, Hist_data::Mode, Histable *);
+
+ Vector<HeapData*> *hDataObjs;
+ Vector<HeapData*> *hDataObjsCallStack;
+ bool hasCallStack;
+ HeapData *hDataTotal;
+
+ // list of HeapData objects using the stack id as the key
+ DefaultMap<uint64_t, HeapData*> *hDataCalStkMap;
+
+ // the cached data for mode=Hist_Data::ALL
+ Hist_data *hist_data_callstack_all;
+
+ DbeView *dbev;
+};
+
+#endif /* _HEAPACTIVITY_H */
diff --git a/gprofng/src/HeapData.cc b/gprofng/src/HeapData.cc
new file mode 100644
index 0000000..5f001ad
--- /dev/null
+++ b/gprofng/src/HeapData.cc
@@ -0,0 +1,284 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include <string.h>
+
+#include "util.h"
+#include "HeapData.h"
+
+void
+HeapData::init ()
+{
+ allocBytes = 0;
+ leakBytes = 0;
+ allocCnt = 0;
+ leakCnt = 0;
+ stackId = 0;
+ histType = Histable::HEAPCALLSTACK;
+ peakMemUsage = 0;
+ timestamp = 0;
+ pid = 0;
+ userExpId = 0;
+ aSmallestBytes = _10TB;
+ aLargestBytes = 0;
+ a0KB1KBCnt = 0;
+ a1KB8KBCnt = 0;
+ a8KB32KBCnt = 0;
+ a32KB128KBCnt = 0;
+ a128KB256KBCnt = 0;
+ a256KB512KBCnt = 0;
+ a512KB1000KBCnt = 0;
+ a1000KB10MBCnt = 0;
+ a10MB100MBCnt = 0;
+ a100MB1GBCnt = 0;
+ a1GB10GBCnt = 0;
+ a10GB100GBCnt = 0;
+ a100GB1TBCnt = 0;
+ a1TB10TBCnt = 0;
+
+ lSmallestBytes = _10TB;
+ lLargestBytes = 0;
+ l0KB1KBCnt = 0;
+ l1KB8KBCnt = 0;
+ l8KB32KBCnt = 0;
+ l32KB128KBCnt = 0;
+ l128KB256KBCnt = 0;
+ l256KB512KBCnt = 0;
+ l512KB1000KBCnt = 0;
+ l1000KB10MBCnt = 0;
+ l10MB100MBCnt = 0;
+ l100MB1GBCnt = 0;
+ l1GB10GBCnt = 0;
+ l10GB100GBCnt = 0;
+ l100GB1TBCnt = 0;
+ l1TB10TBCnt = 0;
+}
+
+HeapData::HeapData (char *sName)
+{
+ stackName = dbe_strdup (sName);
+ peakStackIds = new Vector<uint64_t>;
+ peakTimestamps = new Vector<hrtime_t>;
+ init ();
+}
+
+HeapData::HeapData (HeapData *hData)
+{
+ stackName = dbe_strdup (hData->stackName);
+ stackId = hData->stackId;
+ histType = hData->histType;
+ allocBytes = hData->allocBytes;
+ leakBytes = hData->leakBytes;
+ allocCnt = hData->allocCnt;
+ leakCnt = hData->leakCnt;
+ peakMemUsage = hData->peakMemUsage;
+ timestamp = hData->timestamp;
+ pid = hData->getPid ();
+ userExpId = hData->getUserExpId ();
+ peakStackIds = new Vector<uint64_t>;
+ Vector<uint64_t> *sIds = hData->peakStackIds;
+ uint64_t sId;
+ if (sIds != NULL)
+ for (int i = 0; i < sIds->size (); i++)
+ {
+ sId = sIds->fetch (i);
+ peakStackIds->append (sId);
+ }
+
+ peakTimestamps = new Vector<hrtime_t>;
+ Vector<hrtime_t> *pts = hData->peakTimestamps;
+ hrtime_t ts;
+ if (pts != NULL)
+ for (int i = 0; i < pts->size (); i++)
+ {
+ ts = pts->fetch (i);
+ peakTimestamps->append (ts);
+ }
+
+ aSmallestBytes = hData->aSmallestBytes;
+ aLargestBytes = hData->aLargestBytes;
+ a0KB1KBCnt = hData->a0KB1KBCnt;
+ a1KB8KBCnt = hData->a1KB8KBCnt;
+ a8KB32KBCnt = hData->a8KB32KBCnt;
+ a32KB128KBCnt = hData->a32KB128KBCnt;
+ a128KB256KBCnt = hData->a128KB256KBCnt;
+ a256KB512KBCnt = hData->a256KB512KBCnt;
+ a512KB1000KBCnt = hData->a512KB1000KBCnt;
+ a1000KB10MBCnt = hData->a1000KB10MBCnt;
+ a10MB100MBCnt = hData->a10MB100MBCnt;
+ a100MB1GBCnt = hData->a100MB1GBCnt;
+ a1GB10GBCnt = hData->a1GB10GBCnt;
+ a10GB100GBCnt = hData->a10GB100GBCnt;
+ a100GB1TBCnt = hData->a100GB1TBCnt;
+ a1TB10TBCnt = hData->a1TB10TBCnt;
+
+ lSmallestBytes = hData->lSmallestBytes;
+ lLargestBytes = hData->lLargestBytes;
+ l0KB1KBCnt = hData->l0KB1KBCnt;
+ l1KB8KBCnt = hData->l1KB8KBCnt;
+ l8KB32KBCnt = hData->l8KB32KBCnt;
+ l32KB128KBCnt = hData->l32KB128KBCnt;
+ l128KB256KBCnt = hData->l128KB256KBCnt;
+ l256KB512KBCnt = hData->l256KB512KBCnt;
+ l512KB1000KBCnt = hData->l512KB1000KBCnt;
+ l1000KB10MBCnt = hData->l1000KB10MBCnt;
+ l10MB100MBCnt = hData->l10MB100MBCnt;
+ l100MB1GBCnt = hData->l100MB1GBCnt;
+ l1GB10GBCnt = hData->l1GB10GBCnt;
+ l10GB100GBCnt = hData->l10GB100GBCnt;
+ l100GB1TBCnt = hData->l100GB1TBCnt;
+ l1TB10TBCnt = hData->l1TB10TBCnt;
+}
+
+HeapData::~HeapData ()
+{
+ free (stackName);
+ delete peakStackIds;
+ delete peakTimestamps;
+}
+
+Histable*
+HeapData::convertto (Histable_type type, Histable*)
+{
+ return type == histType ? this : NULL;
+}
+
+char*
+HeapData::get_name (Histable::NameFormat /*_nfmt*/)
+{
+ return stackName;
+}
+
+char*
+HeapData::get_raw_name (Histable::NameFormat /*_nfmt*/)
+{
+ return stackName;
+}
+
+void
+HeapData::set_name (char* _name)
+{
+ free (stackName);
+ stackName = dbe_strdup (_name);
+}
+
+void
+HeapData::setPeakMemUsage (int64_t pmu, uint64_t sId, hrtime_t ts, int procId, int uei)
+{
+ if (peakMemUsage < pmu)
+ {
+ peakMemUsage = pmu;
+ peakStackIds->reset ();
+ peakStackIds->append (sId);
+ peakTimestamps->reset ();
+ peakTimestamps->append (ts);
+ pid = procId;
+ userExpId = uei;
+ }
+ else if (peakMemUsage == pmu)
+ {
+ for (int i = 0; i < peakStackIds->size (); i++)
+ {
+ uint64_t curSId = peakStackIds->fetch (i);
+ if (curSId == sId)
+ return;
+ }
+ peakStackIds->append (sId);
+ peakTimestamps->append (ts);
+ pid = procId;
+ userExpId = uei;
+ }
+}
+
+void
+HeapData::setAllocStat (int64_t nb)
+{
+ if (aSmallestBytes > nb)
+ aSmallestBytes = nb;
+ if (aLargestBytes < nb)
+ aLargestBytes = nb;
+ if (nb >= 0 && nb <= _1KB)
+ a0KB1KBCnt++;
+ else if (nb <= _8KB)
+ a1KB8KBCnt++;
+ else if (nb <= _32KB)
+ a8KB32KBCnt++;
+ else if (nb <= _128KB)
+ a32KB128KBCnt++;
+ else if (nb <= _256KB)
+ a128KB256KBCnt++;
+ else if (nb <= _512KB)
+ a256KB512KBCnt++;
+ else if (nb <= _1000KB)
+ a512KB1000KBCnt++;
+ else if (nb <= _10MB)
+ a1000KB10MBCnt++;
+ else if (nb <= _100MB)
+ a10MB100MBCnt++;
+ else if (nb <= _1GB)
+ a100MB1GBCnt++;
+ else if (nb <= _10GB)
+ a1GB10GBCnt++;
+ else if (nb <= _100GB)
+ a10GB100GBCnt++;
+ else if (nb <= _1TB)
+ a100GB1TBCnt++;
+ else if (nb <= _10TB)
+ a1TB10TBCnt++;
+}
+
+void
+HeapData::setLeakStat (int64_t nb)
+{
+ if (lSmallestBytes > nb)
+ lSmallestBytes = nb;
+ if (lLargestBytes < nb)
+ lLargestBytes = nb;
+ if (nb >= 0 && nb <= _1KB)
+ l0KB1KBCnt++;
+ else if (nb <= _8KB)
+ l1KB8KBCnt++;
+ else if (nb <= _32KB)
+ l8KB32KBCnt++;
+ else if (nb <= _128KB)
+ l32KB128KBCnt++;
+ else if (nb <= _256KB)
+ l128KB256KBCnt++;
+ else if (nb <= _512KB)
+ l256KB512KBCnt++;
+ else if (nb <= _1000KB)
+ l512KB1000KBCnt++;
+ else if (nb <= _10MB)
+ l1000KB10MBCnt++;
+ else if (nb <= _100MB)
+ l10MB100MBCnt++;
+ else if (nb <= _1GB)
+ l100MB1GBCnt++;
+ else if (nb <= _10GB)
+ l1GB10GBCnt++;
+ else if (nb <= _100GB)
+ l10GB100GBCnt++;
+ else if (nb <= _1TB)
+ l100GB1TBCnt++;
+ else if (nb <= _10TB)
+ l1TB10TBCnt++;
+}
diff --git a/gprofng/src/HeapData.h b/gprofng/src/HeapData.h
new file mode 100644
index 0000000..7ff68e9
--- /dev/null
+++ b/gprofng/src/HeapData.h
@@ -0,0 +1,450 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _HEAPDATA_H
+#define _HEAPDATA_H
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+#include "vec.h"
+#include "data_pckts.h"
+#include "Histable.h"
+
+#define TOTAL_HEAPNAME NTXT("<Total>")
+#define TOTAL_STACK_ID 0
+#define _1KB 1024
+#define _8KB 8192
+#define _32KB 32768
+#define _128KB 131072
+#define _256KB 262144
+#define _512KB 524288
+#define _1000KB 1048576
+#define _10MB 10485760
+#define _100MB 104857600
+#define _1GB 1073741824
+#define _10GB 10737418240
+#define _100GB 107374182400
+#define _1TB 1099511627776
+#define _10TB 10995116277760
+
+class HeapData : public Histable
+{
+ friend class HeapActivity;
+public:
+ HeapData (char *sName);
+ HeapData (HeapData *hData);
+ ~HeapData ();
+ char *get_raw_name (Histable::NameFormat nfmt);
+ void init ();
+ void setStackName (char* sName);
+ void setPeakMemUsage (int64_t pmu, uint64_t sId, hrtime_t ts, int procId, int uei);
+
+ virtual char *get_name (Histable::NameFormat nfmt);
+ virtual void set_name (char * _name);
+ virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+ virtual Histable_type
+ get_type ()
+ {
+ return histType;
+ }
+
+ virtual uint64_t
+ get_addr ()
+ {
+ return stackId;
+ }
+
+ uint64_t
+ get_index ()
+ {
+ return stackId;
+ }
+
+ char *
+ getStackName ()
+ {
+ return stackName;
+ }
+
+ void
+ addAllocEvent (uint64_t nb)
+ {
+ allocBytes += nb;
+ allocCnt++;
+ }
+
+ uint64_t
+ getAllocBytes ()
+ {
+ return allocBytes;
+ }
+
+ int32_t
+ getAllocCnt ()
+ {
+ return allocCnt;
+ }
+
+ void
+ addLeakEvent (uint64_t nb)
+ {
+ leakBytes += nb;
+ leakCnt++;
+ }
+
+ uint64_t
+ getLeakBytes ()
+ {
+ return leakBytes;
+ }
+
+ int32_t
+ getLeakCnt ()
+ {
+ return leakCnt;
+ }
+
+ void
+ setStackId (uint64_t sId)
+ {
+ stackId = sId;
+ }
+
+ uint64_t
+ getStackId ()
+ {
+ return stackId;
+ }
+
+ void
+ setTimestamp (hrtime_t ts)
+ {
+ timestamp = ts;
+ }
+
+ hrtime_t
+ getTimestamp ()
+ {
+ return timestamp;
+ }
+
+ void
+ setHistType (Histable::Type hType)
+ {
+ histType = hType;
+ }
+
+ Histable::Type
+ getHistType ()
+ {
+ return histType;
+ }
+
+ int64_t
+ getPeakMemUsage ()
+ {
+ return peakMemUsage;
+ }
+
+ Vector<uint64_t> *
+ getPeakStackIds ()
+ {
+ return peakStackIds;
+ }
+
+ Vector<hrtime_t> *
+ getPeakTimestamps ()
+ {
+ return peakTimestamps;
+ }
+
+ void
+ setPid (int procId)
+ {
+ pid = procId;
+ }
+
+ int
+ getPid ()
+ {
+ return pid;
+ }
+
+ void
+ setUserExpId (int uei)
+ {
+ userExpId = uei;
+ }
+
+ int
+ getUserExpId ()
+ {
+ return userExpId;
+ }
+
+ void setAllocStat (int64_t nb);
+
+ int64_t
+ getASmallestBytes ()
+ {
+ return aSmallestBytes;
+ }
+
+ int64_t
+ getALargestBytes ()
+ {
+ return aLargestBytes;
+ }
+
+ int32_t
+ getA0KB1KBCnt ()
+ {
+ return a0KB1KBCnt;
+ }
+
+ int32_t
+ getA1KB8KBCnt ()
+ {
+ return a1KB8KBCnt;
+ }
+
+ int32_t
+ getA8KB32KBCnt ()
+ {
+ return a8KB32KBCnt;
+ }
+
+ int32_t
+ getA32KB128KBCnt ()
+ {
+ return a32KB128KBCnt;
+ }
+
+ int32_t
+ getA128KB256KBCnt ()
+ {
+ return a128KB256KBCnt;
+ }
+
+ int32_t
+ getA256KB512KBCnt ()
+ {
+ return a256KB512KBCnt;
+ }
+
+ int32_t
+ getA512KB1000KBCnt ()
+ {
+ return a512KB1000KBCnt;
+ }
+
+ int32_t
+ getA1000KB10MBCnt ()
+ {
+ return a1000KB10MBCnt;
+ }
+
+ int32_t
+ getA10MB100MBCnt ()
+ {
+ return a10MB100MBCnt;
+ }
+
+ int32_t
+ getA100MB1GBCnt ()
+ {
+ return a100MB1GBCnt;
+ }
+
+ int32_t
+ getA1GB10GBCnt ()
+ {
+ return a1GB10GBCnt;
+ }
+
+ int32_t
+ getA10GB100GBCnt ()
+ {
+ return a10GB100GBCnt;
+ }
+
+ int32_t
+ getA100GB1TBCnt ()
+ {
+ return a100GB1TBCnt;
+ }
+
+ int32_t
+ getA1TB10TBCnt ()
+ {
+ return a1TB10TBCnt;
+ }
+
+ void setLeakStat (int64_t nb);
+
+ int64_t
+ getLSmallestBytes ()
+ {
+ return lSmallestBytes;
+ }
+
+ int64_t
+ getLLargestBytes ()
+ {
+ return lLargestBytes;
+ }
+
+ int32_t
+ getL0KB1KBCnt ()
+ {
+ return l0KB1KBCnt;
+ }
+
+ int32_t
+ getL1KB8KBCnt ()
+ {
+ return l1KB8KBCnt;
+ }
+
+ int32_t
+ getL8KB32KBCnt ()
+ {
+ return l8KB32KBCnt;
+ }
+
+ int32_t
+ getL32KB128KBCnt ()
+ {
+ return l32KB128KBCnt;
+ }
+
+ int32_t
+ getL128KB256KBCnt ()
+ {
+ return l128KB256KBCnt;
+ }
+
+ int32_t
+ getL256KB512KBCnt ()
+ {
+ return l256KB512KBCnt;
+ }
+
+ int32_t
+ getL512KB1000KBCnt ()
+ {
+ return l512KB1000KBCnt;
+ }
+
+ int32_t
+ getL1000KB10MBCnt ()
+ {
+ return l1000KB10MBCnt;
+ }
+
+ int32_t
+ getL10MB100MBCnt ()
+ {
+ return l10MB100MBCnt;
+ }
+
+ int32_t
+ getL100MB1GBCnt ()
+ {
+ return l100MB1GBCnt;
+ }
+
+ int32_t
+ getL1GB10GBCnt ()
+ {
+ return l1GB10GBCnt;
+ }
+
+ int32_t
+ getL10GB100GBCnt ()
+ {
+ return l10GB100GBCnt;
+ }
+
+ int32_t
+ getL100GB1TBCnt ()
+ {
+ return l100GB1TBCnt;
+ }
+
+ int32_t
+ getL1TB10TBCnt ()
+ {
+ return l1TB10TBCnt;
+ }
+
+private:
+ char *stackName; // stack name
+ uint64_t allocBytes; // The total bytes allocated
+ uint64_t leakBytes; // The total bytes leaked
+ int32_t allocCnt; // The alloc count
+ int32_t leakCnt; // The leak count
+ Histable::Type histType; // The Histable type: HEAPCALLSTACK
+ int64_t peakMemUsage; // Keep track of peak memory usage
+ uint64_t stackId;
+ Vector<uint64_t> *peakStackIds; // The peak memory usage stack ids
+ hrtime_t timestamp;
+ Vector<hrtime_t> *peakTimestamps; // The peak data
+ int pid; // The process id
+ int userExpId; // The experiment id
+
+ int64_t aSmallestBytes;
+ int64_t aLargestBytes;
+ int32_t a0KB1KBCnt;
+ int32_t a1KB8KBCnt;
+ int32_t a8KB32KBCnt;
+ int32_t a32KB128KBCnt;
+ int32_t a128KB256KBCnt;
+ int32_t a256KB512KBCnt;
+ int32_t a512KB1000KBCnt;
+ int32_t a1000KB10MBCnt;
+ int32_t a10MB100MBCnt;
+ int32_t a100MB1GBCnt;
+ int32_t a1GB10GBCnt;
+ int32_t a10GB100GBCnt;
+ int32_t a100GB1TBCnt;
+ int32_t a1TB10TBCnt;
+
+ int64_t lSmallestBytes;
+ int64_t lLargestBytes;
+ int32_t l0KB1KBCnt;
+ int32_t l1KB8KBCnt;
+ int32_t l8KB32KBCnt;
+ int32_t l32KB128KBCnt;
+ int32_t l128KB256KBCnt;
+ int32_t l256KB512KBCnt;
+ int32_t l512KB1000KBCnt;
+ int32_t l1000KB10MBCnt;
+ int32_t l10MB100MBCnt;
+ int32_t l100MB1GBCnt;
+ int32_t l1GB10GBCnt;
+ int32_t l10GB100GBCnt;
+ int32_t l100GB1TBCnt;
+ int32_t l1TB10TBCnt;
+};
+
+#endif
diff --git a/gprofng/src/HeapMap.cc b/gprofng/src/HeapMap.cc
new file mode 100644
index 0000000..8e6c009
--- /dev/null
+++ b/gprofng/src/HeapMap.cc
@@ -0,0 +1,325 @@
+/* Copyright (C) 2021 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 "HeapMap.h"
+
+#define HEAPCHUNKSZ 1024 // number of HeapObj's in a chunk
+#define HEAPCHAINS 9192 // number of address-based chains
+#define hash(x) (((x) >> 6) % HEAPCHAINS)
+
+typedef struct HeapObj
+{
+ uint64_t addr;
+ uint64_t size;
+ long val;
+ HeapObj *next;
+} HeapObj;
+
+typedef struct HeapChunk
+{
+ void *addr;
+ HeapChunk *next;
+} HeapChunk;
+
+HeapMap::HeapMap ()
+{
+ chunks = NULL;
+ empty = NULL;
+ chain = new HeapObj*[HEAPCHAINS];
+ for (int i = 0; i < HEAPCHAINS; i++)
+ chain[i] = NULL;
+
+ mmaps = new HeapObj;
+ mmaps->addr = (uint64_t) 0;
+ mmaps->size = (uint64_t) 0;
+ mmaps->val = -1;
+ mmaps->next = NULL;
+}
+
+HeapMap::~HeapMap ()
+{
+ // free up all the chunks
+ HeapChunk *c = chunks;
+ while (c != NULL)
+ {
+ HeapChunk *next = c->next;
+ delete c;
+ c = next;
+ }
+ delete[] chain;
+ delete mmaps;
+}
+
+void
+HeapMap::allocate (uint64_t addr, long val)
+{
+ // get a HeapObj, and set it up for the allocated block
+ HeapObj *incoming = getHeapObj ();
+ incoming->addr = addr;
+ incoming->val = val;
+ incoming->next = NULL;
+
+ // determine which chain the block belongs on
+ int ichain = (int) hash (addr);
+
+ // if this is the first, just set it up and return
+ if (chain[ichain] == NULL)
+ {
+ chain[ichain] = incoming;
+ return;
+ }
+ // chain is non-empty -- find the slot for this one
+ // chain is maintained in reverse address order
+ HeapObj *prev = NULL;
+ HeapObj *next = chain[ichain];
+
+ for (;;)
+ {
+ if ((next == NULL) || (next->addr < incoming->addr))
+ {
+ // we've found the spot
+ incoming->next = next;
+ if (prev == NULL)
+ chain[ichain] = incoming;
+ else
+ prev->next = incoming;
+ return;
+ }
+ if (next->addr == incoming->addr)
+ {
+ // error -- two blocks with same address active
+ // ignore the new one
+ releaseHeapObj (incoming);
+ return;
+ }
+ // not yet, keep looking
+ prev = next;
+ next = next->next;
+ }
+}
+
+long
+HeapMap::deallocate (uint64_t addr)
+{
+ int ichain = (int) hash (addr);
+ HeapObj *cur = chain[ichain];
+ HeapObj *prev = NULL;
+ while (cur != NULL)
+ {
+ if (cur->addr == addr)
+ {
+ // we've found the block
+ long val = cur->val;
+
+ // delete the block from the chain
+ if (prev == NULL)
+ chain[ichain] = cur->next;
+ else
+ prev->next = cur->next;
+ releaseHeapObj (cur);
+ return val;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+
+ // block not found
+ return 0;
+}
+
+void
+HeapMap::allocateChunk ()
+{
+ // allocate the memory
+ HeapChunk *c = new HeapChunk;
+ HeapObj *newc = new HeapObj[HEAPCHUNKSZ];
+
+ // set up the chunk, and queue it for destructor's use
+ c->addr = (void *) newc;
+ c->next = chunks;
+ chunks = c;
+
+ // Initialize the HeapObj's in the chunk to one chain
+ // last entry is left NULL, terminating the chain
+ for (int i = 0; i < (HEAPCHUNKSZ - 1); i++)
+ newc[i].next = newc + i + 1;
+ newc[HEAPCHUNKSZ - 1].next = NULL;
+
+ // put that chain on the empty queue
+ empty = newc;
+}
+
+HeapObj *
+HeapMap::getHeapObj ()
+{
+ if (empty == NULL)
+ allocateChunk ();
+ HeapObj *ret = empty;
+ empty = ret->next;
+ return ret;
+}
+
+void
+HeapMap::releaseHeapObj (HeapObj *obj)
+{
+ obj->next = empty;
+ empty = obj;
+}
+
+UnmapChunk*
+HeapMap::mmap (uint64_t addr, int64_t size, long val)
+{
+ HeapObj *incoming = getHeapObj ();
+ incoming->addr = addr;
+ incoming->size = size;
+ incoming->val = val;
+ incoming->next = NULL;
+ UnmapChunk* list = process (incoming, addr, size);
+ return list;
+}
+
+UnmapChunk*
+HeapMap::munmap (uint64_t addr, int64_t size)
+{
+ UnmapChunk* list = process (NULL, addr, size);
+ return list;
+}
+
+UnmapChunk*
+HeapMap::process (HeapObj *obj, uint64_t addr, int64_t size)
+{
+ // Some graphics are used to clarify the alignment of mmap regions
+ // obj, shown as consecutive pages: "NNNNNN"
+ // cur, shown as consecutive pages: "CCCCCC"
+
+ // Find the first overlap, start of N is before end of C. Examples:
+ // CCCCC
+ // NNNNN
+ // or
+ // CCCCC
+ // NNN
+ // or
+ // CCCCC
+ // NNNNN
+ // or
+ // CCCCC
+ // NNNNNNN
+ HeapObj *prev = mmaps;
+ HeapObj *cur = prev->next;
+ while (cur)
+ {
+ if (addr < cur->addr + cur->size)
+ break;
+ prev = cur;
+ cur = prev->next;
+ }
+
+ // None found
+ if (cur == NULL)
+ {
+ prev->next = obj;
+ return NULL;
+ }
+
+ UnmapChunk* list = NULL;
+ if (addr > cur->addr)
+ {
+ if (cur->addr + cur->size <= addr + size)
+ {
+ // Process overlap on the left (low side) of new allocation
+ // New range: N-start to C-end (gets freed below)
+ prev = cur;
+ cur = getHeapObj ();
+ cur->addr = addr;
+ cur->size = prev->addr + prev->size - addr;
+ cur->val = prev->val;
+ cur->next = prev->next;
+
+ // Truncate range: C-start to N-start
+ prev->size = addr - prev->addr;
+ }
+ else
+ {
+ // Process new allocation that fits completely within old allocation
+ // New range: N-start to N-end (freed below)
+ int64_t c_end = cur->addr + cur->size;
+ prev = cur;
+ cur = getHeapObj ();
+ cur->addr = addr;
+ cur->size = size;
+ cur->val = prev->val;
+ cur->next = prev->next;
+
+ // Truncate range: C-start to N-start
+ prev->size = addr - prev->addr;
+
+ // New range: N-end to C-end.
+ HeapObj *next = getHeapObj ();
+ next->addr = addr + size;
+ next->size = c_end - next->addr;
+ next->val = cur->val;
+ next->next = cur->next;
+ cur->next = next;
+ }
+ }
+
+ // Process all full overlaps.
+ // Copy details of cur to UnmapChunk list, remove cur from mmaps
+ while (cur && cur->addr + cur->size <= addr + size)
+ {
+
+ UnmapChunk* uc = new UnmapChunk;
+ uc->val = cur->val;
+ uc->size = cur->size;
+ uc->next = list;
+ list = uc;
+
+ HeapObj *t = cur;
+ cur = cur->next;
+ releaseHeapObj (t);
+ }
+
+ if (cur && cur->addr < addr + size)
+ {
+ // Process the last overlap (right side of new allocation)
+ // Copy details of cur to UnmapChunk list
+ UnmapChunk* uc = new UnmapChunk;
+ uc->val = cur->val;
+ uc->size = addr + size - cur->addr;
+ uc->next = list;
+ list = uc;
+
+ // Truncate left side of cur
+ cur->size -= uc->size;
+ cur->addr = addr + size;
+ }
+
+ // Insert new allocation
+ if (obj)
+ {
+ prev->next = obj;
+ obj->next = cur;
+ }
+ else
+ prev->next = cur;
+ return list;
+}
diff --git a/gprofng/src/HeapMap.h b/gprofng/src/HeapMap.h
new file mode 100644
index 0000000..c46129d
--- /dev/null
+++ b/gprofng/src/HeapMap.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _HEAPMAP_H
+#define _HEAPMAP_H
+
+#include "dbe_types.h"
+#include "vec.h"
+
+struct HeapObj;
+struct HeapChunk;
+
+typedef struct UnmapChunk
+{
+ long val;
+ int64_t size;
+ UnmapChunk *next;
+} UnmapChunk;
+
+class HeapMap
+{
+public:
+ HeapMap ();
+ ~HeapMap ();
+ void allocate (uint64_t addr, long val);
+ long deallocate (uint64_t addr);
+ UnmapChunk *mmap (uint64_t addr, int64_t size, long val);
+ UnmapChunk *munmap (uint64_t addr, int64_t size);
+
+private:
+ void allocateChunk ();
+ HeapObj *getHeapObj ();
+ void releaseHeapObj (HeapObj*);
+ UnmapChunk *process (HeapObj *obj, uint64_t addr, int64_t size);
+
+ HeapChunk *chunks;
+ HeapObj *empty;
+ HeapObj **chain;
+ HeapObj *mmaps;
+};
+
+#endif /* _HEAPMAP_H */
diff --git a/gprofng/src/Hist_data.cc b/gprofng/src/Hist_data.cc
new file mode 100644
index 0000000..4412203
--- /dev/null
+++ b/gprofng/src/Hist_data.cc
@@ -0,0 +1,1886 @@
+/* Copyright (C) 2021 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 <assert.h>
+
+#include "util.h"
+#include "DefaultMap.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "MemObject.h"
+#include "IndexObject.h"
+#include "MetricList.h"
+#include "Metric.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Settings.h"
+#include "StringBuilder.h"
+#include "ExpGroup.h"
+#include "PathTree.h"
+#include "DbeView.h"
+#include "FileData.h"
+
+Hist_data::HistItem::HistItem (long n)
+{
+ obj = NULL;
+ type = 0;
+ size = n;
+ value = new TValue[n];
+ memset (value, 0, sizeof (TValue) * n);
+}
+
+Hist_data::HistItem::~HistItem ()
+{
+ for (long i = 0; i < size; i++)
+ if (value[i].tag == VT_LABEL)
+ free (value[i].l);
+ delete[] value;
+}
+
+long
+Hist_data::size ()
+{
+ // If the data values have not been computed, do so
+ // Return the total number of items
+ return hist_items->size ();
+}
+
+Hist_data::HistItem *
+Hist_data::fetch (long index)
+{
+ return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL;
+}
+
+int
+Hist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype,
+ long ind, Hist_data *hdata)
+{
+ // Sort the data depending upon order and type
+ int result = 0;
+ Histable::Type type = hi_1->obj->get_type ();
+ if (stype == ALPHA)
+ {
+ if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ
+ && type != Histable::IOACTVFD && type != Histable::IOACTFILE
+ && type != Histable::IOCALLSTACK)
+ {
+ char *nm1 = hi_1->obj->get_name ();
+ char *nm2 = hi_2->obj->get_name ();
+ if (nm1 != NULL && nm2 != NULL)
+ result = strcoll (nm1, nm2);
+ }
+ else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD
+ || type == Histable::IOACTFILE)
+ {
+ uint64_t idx1, idx2;
+ idx1 = ((FileData *) (hi_1->obj))->get_index ();
+ idx2 = ((FileData *) (hi_2->obj))->get_index ();
+ if (idx1 < idx2)
+ result = -1;
+ else if (idx1 > idx2)
+ result = 1;
+ else
+ result = 0;
+ }
+ else
+ {
+ // for memory and index objects, "alphabetic" is really by index
+ // <Total> has index -2, and always comes first
+ // <Unknown> has index -1, and always comes second.
+ uint64_t i1, i2;
+ bool needsStringCompare = false;
+ if (type == Histable::MEMOBJ)
+ {
+ i1 = ((MemObj *) (hi_1->obj))->get_index ();
+ i2 = ((MemObj *) (hi_2->obj))->get_index ();
+ }
+ else if (type == Histable::INDEXOBJ)
+ {
+ i1 = ((IndexObject *) (hi_1->obj))->get_index ();
+ i2 = ((IndexObject *) (hi_2->obj))->get_index ();
+ needsStringCompare =
+ ((IndexObject *) (hi_1->obj))->requires_string_sort ();
+ }
+ else
+ abort ();
+ if (i1 == (uint64_t) - 2)
+ result = -1;
+ else if (i2 == (uint64_t) - 2)
+ result = 1;
+ else if (i1 == (uint64_t) - 1)
+ result = -1;
+ else if (i2 == (uint64_t) - 1)
+ result = 1;
+ else if (needsStringCompare)
+ {
+ char *nm1 = hi_1->obj->get_name ();
+ char *nm2 = hi_2->obj->get_name ();
+ if (nm1 != NULL && nm2 != NULL)
+ {
+ char nm1_lead = nm1[0];
+ char nm2_lead = nm2[0];
+ // put "(unknown)" and friends at end of list
+ if (nm1_lead == '(' && nm1_lead != nm2_lead)
+ result = 1;
+ else if (nm2_lead == '(' && nm1_lead != nm2_lead)
+ result = -1;
+ else
+ result = strcoll (nm1, nm2);
+ }
+ }
+ if (result == 0)
+ { // matches, resolve by index
+ if (i1 < i2)
+ result = -1;
+ else if (i1 > i2)
+ result = 1;
+ }
+ }
+ }
+ else if (stype == AUX)
+ {
+ switch (type)
+ {
+ case Histable::INSTR:
+ {
+ DbeInstr *instr1 = (DbeInstr*) hi_1->obj;
+ DbeInstr *instr2 = (DbeInstr*) hi_2->obj;
+ result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0;
+ break;
+ }
+ case Histable::LINE:
+ {
+ DbeLine *dbl1 = (DbeLine*) hi_1->obj;
+ DbeLine *dbl2 = (DbeLine*) hi_2->obj;
+ result = dbl1->line_cmp (dbl2);
+ }
+ break;
+ default:
+ assert (0);
+ }
+ }
+ else if (stype == VALUE)
+ {
+ Metric *m = hdata->get_metric_list ()->get (ind);
+ if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
+ {
+ TValue v1, v2;
+ int first_ind = hdata->hist_metrics[ind].indFirstExp;
+ if ((m->get_visbits () & VAL_DELTA) != 0)
+ {
+ v1.make_delta (hi_1->value + ind, hi_1->value + first_ind);
+ v2.make_delta (hi_2->value + ind, hi_2->value + first_ind);
+ }
+ else
+ {
+ v1.make_ratio (hi_1->value + ind, hi_1->value + first_ind);
+ v2.make_ratio (hi_2->value + ind, hi_2->value + first_ind);
+ }
+ result = v1.compare (&v2);
+ }
+ else
+ result = hi_1->value[ind].compare (hi_2->value + ind);
+ }
+ return result;
+}
+
+int
+Hist_data::sort_compare_all (const void *a, const void *b, const void *arg)
+{
+ HistItem *hi_1 = *((HistItem **) a);
+ HistItem *hi_2 = *((HistItem **) b);
+
+ Hist_data *hdata = (Hist_data*) arg;
+ int result = sort_compare (hi_1, hi_2, hdata->sort_type, hdata->sort_ind, hdata);
+ if (hdata->sort_order == DESCEND)
+ result = -result;
+
+ // Use the name as the 2d sort key (always ASCEND)
+ // except for MemoryObjects and IndexObjects, where the index is used
+ // For the Alphabetic sort
+ if (result == 0)
+ {
+ result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL);
+ if (result == 0)
+ {
+ for (long i = 0, sz = hdata->metrics->size (); i < sz; i++)
+ {
+ Metric *m = hdata->metrics->get (i);
+ if (m->get_type () != Metric::ONAME)
+ {
+ result = sort_compare (hi_1, hi_2, VALUE, i, hdata);
+ if (result != 0)
+ {
+ if (hdata->sort_order == DESCEND)
+ result = -result;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Use the address as the 3d sort key
+ // ( FUNCTION only, always ASCEND )
+ if (result == 0 && hi_1->obj->get_type () == Histable::FUNCTION)
+ {
+ Function *f1 = (Function*) hi_1->obj;
+ Function *f2 = (Function*) hi_2->obj;
+ if (f1->get_addr () < f2->get_addr ())
+ result = -1;
+ else if (f1->get_addr () > f2->get_addr ())
+ result = 1;
+ }
+
+ // Use the Histable id (ID of function, line, etc.) as the 4th sort key
+ // Note that IDs are not guaranteed to be stable,
+ if (result == 0)
+ {
+ if (hi_1->obj->id < hi_2->obj->id)
+ result = -1;
+ else if (hi_1->obj->id > hi_2->obj->id)
+ result = 1;
+ }
+
+ if (result == 0)
+ return result; // shouldn't happen in most cases; line allows for breakpoint
+ if (hdata->rev_sort)
+ result = -result;
+ return result;
+}
+
+int
+Hist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg)
+{
+ assert ((a != (const void *) NULL));
+ assert ((b != (const void *) NULL));
+ HistItem *hi_1 = *((HistItem **) a);
+ HistItem *hi_2 = *((HistItem **) b);
+ DataObject * dobj1 = (DataObject *) (hi_1->obj);
+ DataObject * dobj2 = (DataObject *) (hi_2->obj);
+ DataObject * parent1 = dobj1->parent;
+ DataObject * parent2 = dobj2->parent;
+
+ Hist_data *hdata = (Hist_data*) arg;
+
+ // are the two items members of the same object?
+ if (parent1 == parent2)
+ {
+ // yes
+ if (parent1)
+ {
+ // and they have real parents...
+ if (parent1->get_typename ())
+ { // element
+ // use dobj1/dobj2 offset for sorting
+ uint64_t off1 = dobj1->get_offset ();
+ uint64_t off2 = dobj2->get_offset ();
+ if (off1 < off2)
+ return -1;
+ if (off1 > off2)
+ return 1;
+ return 0;
+ }
+ }
+ }
+ else
+ { // parents differ
+ if (parent1)
+ {
+ if (parent1 == dobj2)
+ // sorting an object and its parent: parent always first
+ return 1;
+ dobj1 = parent1;
+ }
+ if (parent2)
+ {
+ if (parent2 == dobj1)
+ return -1;
+ dobj2 = parent2;
+ }
+ }
+ // Either two unknowns, or two scalars, or two parents
+ hi_1 = hdata->hi_map->get (dobj1);
+ hi_2 = hdata->hi_map->get (dobj2);
+ return sort_compare_all ((const void*) &hi_1, (const void*) &hi_2, hdata);
+}
+
+Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type,
+ Hist_data::Mode _mode, bool _viewowned)
+{
+ hist_items = new Vector<HistItem*>;
+ metrics = _metrics;
+ nmetrics = metrics->get_items ()->size ();
+ type = _type;
+ mode = _mode;
+ gprof_item = new_hist_item (NULL);
+ viewowned = _viewowned;
+ sort_ind = -1;
+ rev_sort = false;
+
+ Histable *tobj = new Other;
+ tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
+ minimum = new_hist_item (tobj);
+
+ tobj = new Other;
+ tobj->name = dbe_strdup (NTXT (""));
+ maximum = new_hist_item (tobj);
+
+ tobj = new Other;
+ tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx"));
+ maximum_inc = new_hist_item (tobj);
+
+ tobj = new Other;
+ tobj->name = dbe_strdup (NTXT ("<Total>"));
+ total = new_hist_item (tobj);
+
+ tobj = new Other;
+ tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX"));
+ threshold = new_hist_item (tobj);
+
+ hi_map = new HashMap<Histable*, HistItem*>;
+ callsite_mark = new DefaultMap<Histable*, int>;
+ hist_metrics = new Metric::HistMetric[metrics->size ()];
+ for (long i = 0, sz = metrics->size (); i < sz; i++)
+ {
+ Metric::HistMetric *h = hist_metrics + i;
+ h->init ();
+ Metric *m = metrics->get (i);
+ if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO)))
+ h->indFirstExp =
+ metrics->get_listorder (m->get_cmd (),
+ m->get_subtype (), "EXPGRID==1");
+ if (m->is_tvisible () && m->get_type () == BaseMetric::HWCNTR
+ && m->get_dependent_bm ())
+ h->indTimeVal =
+ metrics->get_listorder (m->get_dependent_bm ()->get_cmd (),
+ m->get_subtype (), m->get_expr_spec ());
+ }
+ status = NO_DATA;
+}
+
+Hist_data::~Hist_data ()
+{
+ delete[] hist_metrics;
+ if (hist_items)
+ {
+ hist_items->destroy ();
+ delete hist_items;
+ hist_items = NULL;
+ }
+ if (gprof_item)
+ {
+ delete gprof_item;
+ gprof_item = NULL;
+ }
+ if (maximum)
+ {
+ delete maximum->obj;
+ delete maximum;
+ maximum = NULL;
+ }
+ if (maximum_inc)
+ {
+ delete maximum_inc->obj;
+ delete maximum_inc;
+ maximum_inc = NULL;
+ }
+ if (minimum)
+ {
+ delete minimum->obj;
+ delete minimum;
+ minimum = NULL;
+ }
+ if (total)
+ {
+ delete total->obj;
+ delete total;
+ total = NULL;
+ }
+ if (threshold)
+ {
+ delete threshold->obj;
+ delete threshold;
+ threshold = NULL;
+ }
+ delete metrics;
+ delete hi_map;
+ delete callsite_mark;
+}
+
+void
+Hist_data::dump (char *msg, FILE *f)
+{
+ fprintf (f, " Hist_data dump: %s\n", msg);
+ fprintf (f, " %d=%d metrics\n", (int) nmetrics, (int) metrics->size ());
+ for (int i = 0; i < nmetrics; i++)
+ {
+ Metric *m = metrics->get_items ()->fetch (i);
+ char *s = m->get_expr_spec ();
+ fprintf (f, " %4d %15s %4d %15s\n", i, m->get_mcmd (0),
+ m->get_id (), s ? s : "(NULL)");
+ }
+
+ fprintf (f, NTXT (" HistItem listing\n"));
+ int n = hist_items->size ();
+ for (int j = -1; j < n; j++)
+ {
+ HistItem *hi;
+ if (j < 0)
+ {
+ hi = total;
+ fprintf (f, NTXT (" total"));
+ }
+ else
+ {
+ hi = hist_items->fetch (j);
+ fprintf (f, NTXT ("%30s"), hi->obj->get_name ());
+ }
+ for (int i = 0; i < nmetrics; i++)
+ {
+ char *stmp = hi->value[i].l;
+ switch (hi->value[i].tag)
+ {
+ case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s);
+ break;
+ case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i);
+ break;
+ case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
+ break;
+ case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f);
+ break;
+ case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d);
+ break;
+ case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
+ break;
+ case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)");
+ break;
+ case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
+ break;
+ case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p);
+ break;
+ case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
+ break;
+ default: fprintf (f, NTXT (" "));
+ break;
+ }
+ }
+ fprintf (f, NTXT ("\n"));
+ }
+}
+
+void
+Hist_data::sort (long ind, bool reverse)
+{
+ if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort)
+ // there's no change to the sorting
+ return;
+
+ if (mode == MODL)
+ {
+ sort_type = AUX;
+ sort_order = ASCEND;
+ }
+ else
+ {
+ if (ind == -1)
+ return;
+ Metric::Type mtype = metrics->get_items ()->fetch (ind)->get_type ();
+ sort_type = mtype == Metric::ONAME ? ALPHA : VALUE;
+ sort_order = (mtype == Metric::ONAME || mtype == Metric::ADDRESS) ?
+ ASCEND : DESCEND;
+ sort_ind = ind;
+ rev_sort = reverse;
+ }
+
+ if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
+ hist_items->sort ((CompareFunc) sort_compare_dlayout, this);
+ else
+ hist_items->sort ((CompareFunc) sort_compare_all, this);
+
+ // ensure that <Total> comes first/last
+ char *tname = NTXT ("<Total>");
+ for (int i = 0; i < hist_items->size (); ++i)
+ {
+ HistItem *hi = hist_items->fetch (i);
+ char *name = hi->obj->get_name ();
+ if (name != NULL && streq (name, tname))
+ {
+ int idx0 = rev_sort ? hist_items->size () - 1 : 0;
+ if (i != idx0)
+ {
+ hist_items->remove (i);
+ hist_items->insert (idx0, hi);
+ }
+ break;
+ }
+ }
+}
+
+void
+Hist_data::resort (MetricList *mlist)
+{
+ if (mlist->get_type () != metrics->get_type ())
+ if (metrics->get_type () == MET_CALL)
+ // wrong type of list -- internal error
+ abort ();
+
+ // get the new sort order
+ int ind = mlist->get_sort_ref_index ();
+ bool reverse = mlist->get_sort_rev ();
+ sort (ind, reverse);
+}
+
+void
+Hist_data::compute_minmax ()
+{
+ HistItem *hi;
+ int index;
+
+ for (int mind = 0; mind < nmetrics; mind++)
+ {
+ Metric *mtr = metrics->get_items ()->fetch (mind);
+ if (mtr->get_subtype () == Metric::STATIC)
+ continue;
+ if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+ continue;
+ ValueTag vtype = mtr->get_vtype2 ();
+
+ switch (vtype)
+ {
+ case VT_INT:
+ minimum->value[mind].tag = VT_INT;
+ minimum->value[mind].i = 0;
+ maximum->value[mind].tag = VT_INT;
+ maximum->value[mind].i = 0;
+ maximum_inc->value[mind].tag = VT_INT;
+ maximum_inc->value[mind].i = 0;
+
+ Vec_loop (HistItem *, hist_items, index, hi)
+ {
+ if (metrics->get_type () == MET_SRCDIS
+ && callsite_mark->get (hi->obj))
+ {
+ if (hi->value[mind].i > maximum_inc->value[mind].i)
+ maximum_inc->value[mind].i = hi->value[mind].i;
+ // ignore ones that has inclusive time for src/dis view
+ }
+ else if (hi->value[mind].i > maximum->value[mind].i)
+ maximum->value[mind].i = hi->value[mind].i;
+ if (hi->value[mind].i < minimum->value[mind].i)
+ minimum->value[mind].i = hi->value[mind].i;
+ }
+ break;
+ case VT_DOUBLE:
+ minimum->value[mind].tag = VT_DOUBLE;
+ minimum->value[mind].d = 0.0;
+ maximum->value[mind].tag = VT_DOUBLE;
+ maximum->value[mind].d = 0.0;
+ maximum_inc->value[mind].tag = VT_DOUBLE;
+ maximum_inc->value[mind].d = 0.0;
+ Vec_loop (HistItem*, hist_items, index, hi)
+ {
+ if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
+ {
+ if (hi->value[mind].d > maximum_inc->value[mind].d)
+ {
+ maximum_inc->value[mind].d = hi->value[mind].d;
+ maximum_inc->value[mind].sign = hi->value[mind].sign;
+ }
+ // ignore ones that has inclusive time for src/dis view
+ }
+ else
+ {
+ if (hi->value[mind].d > maximum->value[mind].d)
+ {
+ maximum->value[mind].d = hi->value[mind].d;
+ maximum->value[mind].sign = hi->value[mind].sign;
+ }
+ if (hi->value[mind].d < minimum->value[mind].d)
+ {
+ minimum->value[mind].d = hi->value[mind].d;
+ minimum->value[mind].sign = hi->value[mind].sign;
+ }
+ }
+ }
+ break;
+ case VT_LLONG:
+ case VT_ULLONG:
+ case VT_ADDRESS:
+ minimum->value[mind].tag = vtype;
+ minimum->value[mind].ll = 0;
+ maximum->value[mind].tag = vtype;
+ maximum->value[mind].ll = 0;
+ maximum_inc->value[mind].tag = vtype;
+ maximum_inc->value[mind].ll = 0;
+ Vec_loop (HistItem*, hist_items, index, hi)
+ {
+ if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
+ {
+ if (hi->value[mind].ll > maximum_inc->value[mind].ll)
+ {
+ maximum_inc->value[mind].ll = hi->value[mind].ll;
+ maximum_inc->value[mind].sign = hi->value[mind].sign;
+ }
+ // ignore ones that has inclusive time for src/dis view
+ }
+ else
+ {
+ if (hi->value[mind].ll > maximum->value[mind].ll)
+ {
+ maximum->value[mind].ll = hi->value[mind].ll;
+ maximum->value[mind].sign = hi->value[mind].sign;
+ }
+ if (hi->value[mind].ll < minimum->value[mind].ll)
+ {
+ minimum->value[mind].ll = hi->value[mind].ll;
+ minimum->value[mind].sign = hi->value[mind].sign;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+Hist_data::HistItem *
+Hist_data::new_hist_item (Histable *obj)
+{
+ long sz = get_metric_list ()->size ();
+ HistItem *hi = new HistItem (sz);
+ hi->obj = obj;
+
+ // We precalculate all metrics as integer values
+ // and convert them to appropriate types later.
+ for (long i = 0; i < sz; i++)
+ {
+ hi->value[i].tag = VT_INT;
+ hi->value[i].i = 0;
+ }
+ return hi;
+}
+
+Hist_data::HistItem *
+Hist_data::new_hist_item (Histable *obj, int itype, TValue *value)
+{
+ long sz = get_metric_list ()->size ();
+ HistItem *hi = new HistItem (sz);
+ hi->obj = obj;
+ hi->type = itype;
+ if (value)
+ for (long i = 0; i < sz; i++)
+ hi->value[i] = value[i];
+
+ return hi;
+}
+
+Hist_data::HistItem *
+Hist_data::find_hist_item (Histable *obj)
+{
+ if (obj == NULL)
+ return NULL;
+ return hi_map->get (obj);
+}
+
+Hist_data::HistItem *
+Hist_data::append_hist_item (Histable *obj)
+{
+ if (obj == NULL)
+ return NULL;
+ HistItem *hi = hi_map->get (obj);
+ if (hi == NULL)
+ {
+ hi = new_hist_item (obj);
+ hist_items->append (hi);
+ hi_map->put (obj, hi);
+ }
+ if (status == NO_DATA)
+ status = SUCCESS;
+ return hi;
+}
+
+void
+Hist_data::append_hist_item (HistItem *hi)
+{
+ hist_items->append (hi);
+}
+
+bool
+Hist_data::above_threshold (HistItem* hi)
+{
+ bool mark = false;
+ int index;
+ Metric *mitem;
+
+ Vec_loop (Metric*, metrics->get_items (), index, mitem)
+ {
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ switch (hi->value[index].tag)
+ {
+ case VT_DOUBLE:
+ if (hi->value[index].d > threshold->value[index].d)
+ mark = true;
+ break;
+ case VT_INT:
+ if (hi->value[index].i > threshold->value[index].i)
+ mark = true;
+ break;
+ case VT_LLONG:
+ if (hi->value[index].ll > threshold->value[index].ll)
+ mark = true;
+ break;
+ case VT_ULLONG:
+ if (hi->value[index].ull > threshold->value[index].ull)
+ mark = true;
+ break;
+ // ignoring the following cases (why?)
+ case VT_SHORT:
+ case VT_FLOAT:
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ break;
+ }
+ }
+ return mark;
+}
+
+void
+Hist_data::set_threshold (double proportion)
+{
+ int index;
+ Metric *mitem;
+ Vec_loop (Metric*, metrics->get_items (), index, mitem)
+ {
+ TValue *thresh = &threshold->value[index];
+ TValue *mtotal = &total->value[index];
+ thresh->tag = mitem->get_vtype ();
+
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ switch (thresh->tag)
+ {
+ case VT_INT:
+ thresh->i = (int) (proportion * (double) mtotal->i);
+ break;
+ case VT_DOUBLE:
+ thresh->d = proportion * mtotal->d;
+ break;
+ case VT_LLONG:
+ case VT_ULLONG:
+ thresh->ull = (unsigned long long) (proportion * (double) mtotal->ll);
+ break;
+ case VT_SHORT:
+ case VT_FLOAT:
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ break;
+ }
+ }
+}
+
+double
+Hist_data::get_percentage (double value, int mindex)
+{
+ double total_value;
+ if (value == 0.0)
+ return 0.0;
+
+ // Get the total value of this sample set.
+ // The value must be greater than 0.
+ total_value = total->value[mindex].to_double ();
+
+ // Find out what percentage of the total value this item is.
+ // Make sure we don't divide by zero.
+ if (total_value == 0.0)
+ return 0.0;
+ return value / total_value;
+}
+
+int
+Hist_data::print_label (FILE *out_file, Metric::HistMetric *hist_metric,
+ int space)
+{
+ int name_offset = 0;
+ StringBuilder sb, sb1, sb2, sb3;
+ if (space > 0)
+ {
+ char *fmt = NTXT ("%*s");
+ sb.appendf (fmt, space, NTXT (""));
+ sb1.appendf (fmt, space, NTXT (""));
+ sb2.appendf (fmt, space, NTXT (""));
+ sb3.appendf (fmt, space, NTXT (""));
+ }
+ for (int i = 0; i < nmetrics; i++)
+ {
+ Metric *m = metrics->get (i);
+ Metric::HistMetric *hm = &hist_metric[i];
+ int len = hm->width;
+ char *fmt = NTXT ("%-*s");
+ if ((i > 0) && (m->get_type () == Metric::ONAME))
+ {
+ name_offset = sb1.length ();
+ fmt = NTXT (" %-*s");
+ len--;
+ }
+ sb.appendf (fmt, len, m->legend ? m->legend : NTXT (""));
+ sb1.appendf (fmt, len, hm->legend1);
+ sb2.appendf (fmt, len, hm->legend2);
+ sb3.appendf (fmt, len, hm->legend3);
+ }
+ sb.trim ();
+ if (sb.length () != 0)
+ {
+ sb.toFileLn (out_file);
+ }
+ sb1.toFileLn (out_file);
+ sb2.toFileLn (out_file);
+ sb3.toFileLn (out_file);
+ return name_offset;
+}
+
+void
+Hist_data::print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit)
+{
+ StringBuilder sb;
+ int cnt = VecSize (hist_items);
+ if (cnt > limit && limit > 0)
+ cnt = limit;
+ for (int i = 0; i < cnt; i++)
+ {
+ sb.setLength (0);
+ print_row (&sb, i, hist_metric, NTXT (" "));
+ sb.toFileLn (out_file);
+ }
+}
+
+static void
+append_str (StringBuilder *sb, char *s, size_t len, int vis_bits)
+{
+ if ((vis_bits & VAL_RATIO) != 0)
+ {
+ if (*s != 'N') // Nan
+ sb->appendf (NTXT ("x "));
+ else
+ sb->appendf (NTXT (" "));
+ sb->appendf (NTXT ("%*s"), (int) (len - 2), s);
+ }
+ else
+ sb->appendf (NTXT ("%*s"), (int) len, s);
+}
+
+void
+Hist_data::print_row (StringBuilder *sb, int row, Metric::HistMetric *hmp, char *mark)
+{
+ TValue res;
+ char buf[256];
+ // Print only a list of user's metrics. ( nmetrics <= mlist->size() )
+ for (long i = 0; i < nmetrics; i++)
+ {
+ // Print only a list of user's metrics.
+ Metric *m = metrics->get (i);
+ if (!m->is_any_visible ())
+ continue;
+ Metric::HistMetric *hm = hmp + i;
+ int len = sb->length ();
+ if (m->is_tvisible ())
+ {
+ TValue *v = get_value (&res, hist_metrics[i].indTimeVal, row);
+ char *s = v->to_str (buf, sizeof (buf));
+ append_str (sb, s, hm->maxtime_width, m->get_visbits ());
+ }
+ if (m->is_visible ())
+ {
+ TValue *v = get_value (&res, i, row);
+ char *s = v->to_str (buf, sizeof (buf));
+ if (m->get_type () == BaseMetric::ONAME)
+ {
+ sb->append (mark);
+ if (i + 1 == nmetrics)
+ sb->appendf (NTXT ("%s"), s);
+ else
+ sb->appendf (NTXT ("%-*s "), (int) hm->maxvalue_width, s);
+ continue;
+ }
+ else
+ {
+ if (len != sb->length ())
+ sb->append (' ');
+ append_str (sb, s, hm->maxvalue_width, m->get_visbits ());
+ }
+ }
+ if (m->is_pvisible ())
+ {
+ if (len != sb->length ())
+ sb->append (' ');
+ long met_ind = i;
+ if (m->is_tvisible () && !m->is_visible ())
+ met_ind = hist_metrics[i].indTimeVal;
+ TValue *v = get_real_value (&res, met_ind, row);
+ double percent = get_percentage (v->to_double (), met_ind);
+ if (percent == 0.0)
+ // adjust to change format from xx.yy%
+ sb->append (NTXT (" 0. "));
+ else
+ // adjust format below to change format from xx.yy%
+ sb->appendf (NTXT ("%6.2f"), (100.0 * percent));
+ }
+ len = sb->length () - len;
+ if (hm->width > len && i + 1 != nmetrics)
+ sb->appendf (NTXT ("%*s"), (int) (hm->width - len), NTXT (" "));
+ }
+}
+
+TValue *
+Hist_data::get_real_value (TValue *res, int met_index, int row)
+{
+ HistItem *hi = hist_items->get (row);
+ Metric *m = metrics->get (met_index);
+ if (m->get_type () == BaseMetric::ONAME)
+ {
+ res->l = dbe_strdup (hi->obj->get_name ());
+ res->tag = VT_LABEL;
+ return res;
+ }
+ return hi->value + met_index;
+}
+
+TValue *
+Hist_data::get_value (TValue *res, int met_index, int row)
+{
+ HistItem *hi = hist_items->get (row);
+ Metric *m = metrics->get (met_index);
+ if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
+ {
+ int ind = hist_metrics[met_index].indFirstExp;
+ if ((m->get_visbits () & VAL_DELTA) != 0)
+ res->make_delta (hi->value + met_index, hi->value + ind);
+ else
+ res->make_ratio (hi->value + met_index, hi->value + ind);
+ return res;
+ }
+ return get_real_value (res, met_index, row);
+}
+
+TValue *
+Hist_data::get_value (TValue *res, int met_index, HistItem *hi)
+{
+ Metric *m = metrics->get (met_index);
+ if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
+ {
+ int ind = hist_metrics[met_index].indFirstExp;
+ if ((m->get_visbits () & VAL_DELTA) != 0)
+ res->make_delta (hi->value + met_index, hi->value + ind);
+ else
+ res->make_ratio (hi->value + met_index, hi->value + ind);
+ return res;
+ }
+ if (m->get_type () == BaseMetric::ONAME)
+ {
+ res->l = dbe_strdup (hi->obj->get_name ());
+ res->tag = VT_LABEL;
+ return res;
+ }
+ return hi->value + met_index;
+}
+
+Metric::HistMetric *
+Hist_data::get_histmetrics ()
+{
+ // find the width for each column.
+ for (long i = 0, sz = metrics->size (); i < sz; i++)
+ {
+ Metric *m = metrics->get (i);
+ Metric::HistMetric *hm = hist_metrics + i;
+ if (m->is_value_visible ())
+ {
+ TValue res;
+ for (long i1 = 0, sz1 = VecSize(hist_items); i1 < sz1; i1++)
+ {
+ TValue *v = get_value (&res, i, i1);
+ long len = v->get_len ();
+ if (hm->maxvalue_width < len)
+ hm->maxvalue_width = len;
+ }
+ if ((m->get_visbits () & VAL_RATIO) != 0)
+ hm->maxvalue_width += 2; // "x "
+ }
+ }
+
+ for (long i = 0, sz = metrics->size (); i < sz; i++)
+ {
+ Metric *m = metrics->get (i);
+ Metric::HistMetric *hm = hist_metrics + i;
+ if (m->is_time_visible ())
+ // take a value from depended metric
+ hm->maxtime_width = hist_metrics[hm->indTimeVal].maxvalue_width;
+ m->legend_width (hm, 2);
+ }
+ return hist_metrics;
+}
+
+void
+Hist_data::update_total (Hist_data::HistItem *new_total)
+{
+ for (long i = 0, sz = metrics->size (); i < sz; i++)
+ total->value[i] = new_total->value[i];
+}
+
+void
+Hist_data::update_max (Metric::HistMetric *hm_tmp)
+{
+ Metric::HistMetric *hms = get_histmetrics ();
+ for (int i = 0; i < nmetrics; i++)
+ {
+ Metric::HistMetric *hm = hms + i;
+ Metric::HistMetric *hm1 = hm_tmp + i;
+ if (hm1->maxtime_width < hm->maxtime_width)
+ hm1->maxtime_width = hm->maxtime_width;
+ if (hm1->maxvalue_width < hm->maxvalue_width)
+ hm1->maxvalue_width = hm->maxvalue_width;
+ }
+}
+
+void
+Hist_data::update_legend_width (Metric::HistMetric *hm_tmp)
+{
+ for (int i = 0; i < nmetrics; i++)
+ {
+ Metric *m = metrics->get (i);
+ m->legend_width (hm_tmp + i, 2);
+ }
+}
+
+void
+Metric::HistMetric::update_max (Metric::HistMetric *hm)
+{
+ if (maxtime_width < hm->maxtime_width)
+ maxtime_width = hm->maxtime_width;
+ if (maxvalue_width < hm->maxvalue_width)
+ maxvalue_width = hm->maxvalue_width;
+}
+
+void
+Metric::HistMetric::init ()
+{
+ width = 0;
+ maxvalue_width = 0;
+ maxtime_width = 0;
+ legend1[0] = 0;
+ legend2[0] = 0;
+ legend3[0] = 0;
+ indFirstExp = -1;
+ indTimeVal = -1;
+}
+
+size_t
+Hist_data::value_maxlen (int mindex)
+{
+ size_t maxlen = maximum->value[mindex].get_len ();
+ size_t minlen = minimum->value[mindex].get_len ();
+ // minlen can be bigger than maxlen only for negative value
+ return minlen > maxlen ? minlen : maxlen;
+}
+
+size_t
+Hist_data::time_len (TValue *value, int clock)
+{
+ TValue tm_value;
+ tm_value.tag = VT_DOUBLE;
+ tm_value.sign = value->sign;
+ tm_value.d = 1.e-6 * value->ll / clock;
+ return tm_value.get_len ();
+}
+
+size_t
+Hist_data::time_maxlen (int mindex, int clock)
+{
+ size_t maxlen = time_len (&(maximum->value[mindex]), clock);
+ size_t minlen = time_len (&(minimum->value[mindex]), clock);
+ // minlen can be bigger than maxlen only for negative value
+ return minlen > maxlen ? minlen : maxlen;
+}
+
+size_t
+Hist_data::name_len (HistItem *item)
+{
+ char *name = item->obj->get_name ();
+ return strlen (name);
+}
+
+size_t
+Hist_data::name_maxlen ()
+{
+ size_t res = 0;
+ for (long i = 0; i < size (); i++)
+ {
+ HistItem *hi = fetch (i);
+ size_t len = name_len (hi);
+ if (res < len)
+ res = len;
+ }
+ return res;
+}
+
+// Returns vector of object ids for the vector of selections
+// returns NULL if no valid selections
+Vector<uint64_t> *
+Hist_data::get_object_indices (Vector<int> *selections)
+{
+ // if no selections, return NULL
+ if (selections == NULL || selections->size () == 0)
+ return NULL;
+
+ Vector<uint64_t> *indices = new Vector<uint64_t>;
+ for (long i = 0, sz = selections->size (); i < sz; i++)
+ {
+ int sel = selections->get (i);
+ HistItem *hi = hist_items->get (sel);
+ if (hi == NULL || hi->obj == NULL)
+ continue;
+ Vector<Histable*> *v = hi->obj->get_comparable_objs ();
+ for (long i1 = 0, sz1 = v ? v->size () : 0; i1 < sz1; i1++)
+ {
+ Histable *h1 = v->get (i1);
+ if (h1 && (indices->find_r (h1->id) < 0))
+ indices->append (h1->id);
+ }
+ if (indices->find_r (hi->obj->id) < 0)
+ indices->append (hi->obj->id);
+ }
+ return indices;
+}
+
+DbeInstr::DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr)
+{
+ id = _id;
+ flags = _flags;
+ addr = _addr;
+ func = _func;
+ img_offset = addr + func->img_offset;
+ lineno = -1;
+ size = 0;
+ current_name_format = NA;
+ isUsed = false;
+ inlinedInd = -1;
+}
+
+int
+DbeInstr::pc_cmp (DbeInstr *instr2)
+{
+ int result = 0;
+ if (instr2 == NULL)
+ return -1;
+
+ // All PC's with the Line flag go to the
+ // end of the list. See Module::init_index()
+ if (flags & PCLineFlag)
+ {
+ if (instr2->flags & PCLineFlag)
+ {
+ if (addr < instr2->addr)
+ result = -1;
+ else if (addr > instr2->addr)
+ result = 1;
+ else
+ result = 0;
+ }
+ else
+ result = 1;
+ }
+ else if (instr2->flags & PCLineFlag)
+ result = -1;
+ else if (func == instr2->func)
+ {
+ if (size == 0)
+ {
+ if (addr < instr2->addr)
+ result = -1;
+ else if (addr == instr2->addr)
+ result = 0;
+ else if (addr >= instr2->addr + instr2->size)
+ result = 1;
+ else
+ result = 0;
+ }
+ else if (instr2->size == 0)
+ {
+ if (addr > instr2->addr)
+ result = 1;
+ else if (addr + size <= instr2->addr)
+ result = -1;
+ else
+ result = 0;
+ }
+ else if (addr < instr2->addr)
+ result = -1;
+ else if (addr > instr2->addr)
+ result = 1;
+ else
+ result = 0;
+
+ if (result == 0)
+ {
+ if (flags & PCTrgtFlag)
+ {
+ if (!(instr2->flags & PCTrgtFlag))
+ result = -1;
+ }
+ else if (instr2->flags & PCTrgtFlag)
+ result = 1;
+ }
+ }
+ else
+ result = func->func_cmp (instr2->func);
+ return result;
+}
+
+char *
+DbeInstr::get_name (NameFormat nfmt)
+{
+ if (name && (nfmt == current_name_format || nfmt == Histable::NA))
+ return name;
+
+ free (name);
+ name = NULL;
+ current_name_format = nfmt;
+ char *fname = func->get_name (nfmt);
+
+ if (func->flags & FUNC_FLAG_NO_OFFSET)
+ name = dbe_strdup (fname);
+ else if (addr == (uint64_t) - 1
+ && func != dbeSession->get_JUnknown_Function ())
+ // We use three heuristics above to recognize this special case.
+ // Once the original problem with bci == -1 is fixed, we don't
+ // need it any more.
+ name = dbe_sprintf (GTXT ("<Function %s: HotSpot-compiled leaf instructions>"),
+ fname);
+ else if (addr == (uint64_t) - 3)
+ name = dbe_sprintf (GTXT ("%s <Java native method>"), fname);
+ else
+ {
+ char buf[64], *typetag = NTXT (""), *alloc_typetag = NULL;
+ StringBuilder sb;
+ sb.append (fname);
+ if (func != dbeSession->get_JUnknown_Function ())
+ {
+ if (addr <= 0xFFFFFFFFU)
+ snprintf (buf, sizeof (buf), " + 0x%08X", (unsigned int) addr);
+ else
+ snprintf (buf, sizeof (buf), " + 0x%016llX",
+ (unsigned long long) addr);
+ }
+ else
+ {
+ char *subname;
+ switch ((long int) addr)
+ {
+ case -1:
+ subname = GTXT ("agent error");
+ break;
+ case -2:
+ subname = GTXT ("GC active");
+ break;
+ case -3:
+ subname = GTXT ("unknown non-Java frame");
+ break;
+ case -4:
+ subname = GTXT ("unwalkable non-Java frame");
+ break;
+ case -5:
+ subname = GTXT ("unknown Java frame");
+ break;
+ case -6:
+ subname = GTXT ("unwalkable Java frame");
+ break;
+ case -7:
+ subname = GTXT ("unknown thread state");
+ break;
+ case -8:
+ subname = GTXT ("thread in exit");
+ break;
+ case -9:
+ subname = GTXT ("deopt in process ticks");
+ break;
+ case -10:
+ subname = GTXT ("safepoint synchronizing ticks");
+ break;
+ default:
+ subname = GTXT ("unexpected error");
+ break;
+ }
+ snprintf (buf, sizeof (buf), "<%s (%d)>", subname, (int) addr);
+ }
+ sb.append (buf);
+ if (flags & PCTrgtFlag)
+ // annotate synthetic instruction
+ sb.append ('*'); // special distinguishing marker
+
+ DbeLine *dbeline = mapPCtoLine (NULL);
+ char *str = NULL;
+ if (dbeline && dbeline->lineno > 0)
+ str = strrchr (dbeline->get_name (nfmt), ',');
+ if (str)
+ sb.append (str);
+ if (strlen (typetag) > 0)
+ { // include padding for alignment
+ do
+ {
+ sb.append (' ');
+ }
+ while (sb.length () < 40);
+ sb.append (typetag);
+ delete alloc_typetag;
+ }
+ if (inlinedInd >= 0)
+ add_inlined_info (&sb);
+ name = sb.toString ();
+ }
+ return name;
+}
+
+DbeLine*
+DbeInstr::mapPCtoLine (SourceFile *sf)
+{
+ if (inlinedInd == -1)
+ {
+ inlinedInd = -2;
+ for (int i = 0; i < func->inlinedSubrCnt; i++)
+ {
+ InlinedSubr *p = func->inlinedSubr + i;
+ if (p->level == 0)
+ {
+ if (addr < p->low_pc)
+ break;
+ if (p->contains (addr))
+ {
+ inlinedInd = i;
+ break;
+ }
+ }
+ }
+ }
+ if (inlinedInd >= 0)
+ {
+ DbeLine *dl = func->inlinedSubr[inlinedInd].dbeLine;
+ return dl->sourceFile->find_dbeline (func, dl->lineno);
+ }
+ return func->mapPCtoLine (addr, sf);
+}
+
+void
+DbeInstr::add_inlined_info (StringBuilder *sb)
+{
+ do
+ {
+ sb->append (' ');
+ }
+ while (sb->length () < 40);
+ sb->append (NTXT ("<-- "));
+
+ InlinedSubr *last = NULL;
+ for (int i = inlinedInd; i < func->inlinedSubrCnt; i++)
+ {
+ InlinedSubr *p = func->inlinedSubr + i;
+ if (p->level == 0 && i > inlinedInd)
+ break;
+ if (!p->contains (addr))
+ continue;
+ if (last)
+ {
+ if (last->fname)
+ {
+ sb->append (last->fname);
+ sb->append (' ');
+ }
+ DbeLine *dl = p->dbeLine;
+ sb->appendf (NTXT ("%s:%lld <-- "), get_basename (dl->sourceFile->get_name ()), (long long) dl->lineno);
+ }
+ last = p;
+ }
+ if (last)
+ {
+ if (last->fname)
+ {
+ sb->append (last->fname);
+ sb->append (' ');
+ }
+ }
+ DbeLine *dl = func->mapPCtoLine (addr, NULL);
+ sb->appendf ("%s:%lld ", get_basename (dl->sourceFile->get_name ()),
+ (long long) dl->lineno);
+}
+
+char *
+DbeInstr::get_descriptor ()
+{
+ char *typetag = NTXT ("");
+ if ((flags & PCTrgtFlag) == 0) // not synthetic instruction
+ { // use memop descriptor, if available
+ Module *mod = func->module;
+ if (mod->hwcprof && mod->infoList)
+ {
+ long i;
+ inst_info_t *info = NULL;
+ Vec_loop (inst_info_t*, mod->infoList, i, info)
+ {
+ if (info->offset == func->img_offset + addr) break;
+ }
+ if (info)
+ {
+ long t;
+ datatype_t *dtype = NULL;
+ Vec_loop (datatype_t*, mod->datatypes, t, dtype)
+ {
+ if (dtype->datatype_id == info->memop->datatype_id)
+ break;
+ }
+ if (dtype && dtype->dobj)
+ typetag = dtype->dobj->get_name ();
+ }
+ }
+ }
+ return dbe_strdup (typetag);
+}
+
+int64_t
+DbeInstr::get_size ()
+{
+ // Function *func = (Function*)dbeSession->get_hobj( pc );
+ // Module *mod = func ? func->module : NULL;
+ // return mod ? mod->instrSize( func->img_offset + addr ) : 0;
+ return size;
+}
+
+uint64_t
+DbeInstr::get_addr ()
+{
+ return func->get_addr () + addr;
+}
+
+Histable *
+DbeInstr::convertto (Type type, Histable *obj)
+{
+ Histable *res = NULL;
+ SourceFile *source = (SourceFile*) obj;
+ switch (type)
+ {
+ case INSTR:
+ res = this;
+ break;
+ case LINE:
+ res = mapPCtoLine (source);
+ break;
+ case SOURCEFILE:
+ res = mapPCtoLine (source);
+ if (res)
+ res = ((DbeLine*) res)->sourceFile;
+ break;
+ case FUNCTION:
+ res = func;
+ break;
+ default:
+ assert (0);
+ }
+ return res;
+}
+
+char *
+DbeEA::get_name (NameFormat)
+{
+ if (name == NULL)
+ // generate one
+ name = dbe_strdup (dbeSession->localized_SP_UNKNOWN_NAME);
+ return name;
+}
+
+Histable *
+DbeEA::convertto (Type type, Histable *obj)
+{
+ Histable *res = NULL;
+ assert (obj == NULL);
+ switch (type)
+ {
+ case EADDR:
+ res = this;
+ break;
+ case DOBJECT:
+ res = dobj;
+ break;
+ default:
+ assert (0);
+ }
+ return res;
+}
+
+DbeLine::DbeLine (Function *_func, SourceFile *sf, int _lineno)
+{
+ func = _func;
+ lineno = _lineno;
+ sourceFile = sf;
+ id = sf->id + _lineno;
+ offset = 0;
+ size = 0;
+ flags = 0;
+ include = NULL;
+ dbeline_func_next = NULL;
+ dbeline_base = this;
+ current_name_format = Histable::NA;
+}
+
+DbeLine::~DbeLine ()
+{
+ delete dbeline_func_next;
+}
+
+int
+DbeLine::line_cmp (DbeLine *dbl)
+{
+ return lineno - dbl->lineno;
+}
+
+void
+DbeLine::init_Offset (uint64_t p_offset)
+{
+ if (offset == 0)
+ offset = p_offset;
+ if (dbeline_base && dbeline_base->offset == 0)
+ dbeline_base->offset = p_offset;
+}
+
+char *
+DbeLine::get_name (NameFormat nfmt)
+{
+ char *srcname = NULL, *basename, *fname;
+
+ if (func == NULL)
+ {
+ if (name)
+ return name;
+ srcname = sourceFile->get_name ();
+ basename = get_basename (srcname);
+ name = dbe_sprintf (GTXT ("line %u in \"%s\""), lineno, basename);
+ return name;
+ }
+
+ if (name && (nfmt == current_name_format || nfmt == Histable::NA))
+ return name;
+
+ current_name_format = nfmt;
+ free (name);
+ fname = func->get_name (nfmt);
+ if (func->flags & (FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET))
+ {
+ name = dbe_strdup (fname);
+ return name;
+ }
+
+ if (sourceFile)
+ srcname = sourceFile->get_name ();
+ if (!srcname || strlen (srcname) == 0)
+ srcname = func->getDefSrcName ();
+ basename = get_basename (srcname);
+
+ if (lineno != 0)
+ {
+ if (sourceFile == func->getDefSrc ())
+ name = dbe_sprintf (GTXT ("%s, line %u in \"%s\""), fname, lineno,
+ basename);
+ else
+ name = dbe_sprintf (GTXT ("%s, line %u in alternate source context \"%s\""),
+ fname, lineno, basename);
+ }
+ else if (sourceFile == NULL || (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
+ name = dbe_sprintf (GTXT ("<Function: %s, instructions without line numbers>"),
+ fname);
+ else
+ name = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
+ fname, basename);
+ return name;
+}
+
+int64_t
+DbeLine::get_size ()
+{
+ return size;
+}
+
+uint64_t
+DbeLine::get_addr ()
+{
+ if (func == NULL && dbeline_func_next == NULL)
+ return (uint64_t) 0;
+ Function *f = func ? func : dbeline_func_next->func;
+ return f->get_addr () + offset;
+}
+
+Histable *
+DbeLine::convertto (Type type, Histable *obj)
+{
+ Histable *res = NULL;
+ switch (type)
+ {
+ case INSTR:
+ {
+ Function *f = (Function *) convertto (FUNCTION, NULL);
+ if (f)
+ res = f->find_dbeinstr (0, offset);
+ break;
+ }
+ case LINE:
+ res = dbeline_base;
+ break;
+ case FUNCTION:
+ if (func)
+ {
+ res = func;
+ break;
+ }
+ else
+ {
+ int not_found = 1;
+ for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
+ {
+ Function *f = dl->func;
+ not_found = (obj == NULL // XXXX pass dbeview as Histable*
+ || ((DbeView*) obj)->get_path_tree ()->get_func_nodeidx (f) == 0);
+ if (f && f->def_source == sourceFile && (!not_found))
+ {
+ res = f;
+ break;
+ }
+ }
+ if (res == NULL && dbeline_func_next)
+ {
+ for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
+ {
+ Function *f = dl->func;
+ if (f && f->def_source == sourceFile)
+ {
+ res = f;
+ break;
+ }
+ }
+ }
+ if (res == NULL && dbeline_func_next)
+ res = dbeline_func_next->func;
+ }
+ break;
+ case SOURCEFILE:
+ res = (include) ? include : sourceFile;
+ break;
+ default:
+ assert (0);
+ }
+ return res;
+}
+
+CStack_data::CStack_data (MetricList *_metrics)
+{
+ metrics = _metrics;
+ total = new_cstack_item ();
+ cstack_items = new Vector<CStack_item*>;
+}
+
+CStack_data::CStack_item::CStack_item (long n)
+{
+ stack = NULL;
+ count = 0;
+ val = 0;
+ value = new TValue[n];
+ memset (value, 0, sizeof (TValue) * n);
+}
+
+CStack_data::CStack_item::~CStack_item ()
+{
+ delete stack;
+ delete[] value;
+}
+
+CStack_data::CStack_item *
+CStack_data::new_cstack_item ()
+{
+ int nmetrics = metrics->get_items ()->size ();
+ CStack_item *item = new CStack_item (nmetrics);
+
+ // We precalculate all metrics as integer values
+ // and convert them to appropriate types later.
+ for (int i = 0; i < nmetrics; i++)
+ item->value[i].tag = metrics->get_items ()->fetch (i)->get_vtype ();
+ return item;
+}
+
+HistableFile::HistableFile ()
+{
+ dbeFile = NULL;
+ isUsed = false;
+}
+
+Histable::Histable ()
+{
+ name = NULL;
+ id = 0;
+ comparable_objs = NULL;
+ phaseCompareIdx = -1;
+}
+
+Histable::~Histable ()
+{
+ delete_comparable_objs ();
+ free (name);
+}
+
+void
+Histable::delete_comparable_objs ()
+{
+ if (comparable_objs)
+ {
+ Vector<Histable*> *v = comparable_objs;
+ for (int i = 0; i < v->size (); i++)
+ {
+ Histable *h = v->fetch (i);
+ if (h)
+ {
+ h->comparable_objs = NULL;
+ h->phaseCompareIdx = phaseCompareIdx;
+ }
+ }
+ delete v;
+ }
+}
+
+void
+Histable::update_comparable_objs ()
+{
+ if (phaseCompareIdx != ExpGroup::phaseCompareIdx)
+ {
+ phaseCompareIdx = ExpGroup::phaseCompareIdx;
+ delete_comparable_objs ();
+ }
+}
+
+Vector<Histable*> *
+Histable::get_comparable_objs ()
+{
+ return comparable_objs;
+}
+
+Histable *
+Histable::get_compare_obj ()
+{
+ Vector<Histable*> *v = get_comparable_objs ();
+ for (long i = 0, sz = VecSize (v); i < sz; i++)
+ {
+ Histable *h = v->get (i);
+ if (h)
+ return h;
+ }
+ return this;
+}
+
+#define CASE_S(x) case x: return (char *) #x
+
+char *
+Histable::type_to_string ()
+{
+ switch (get_type ())
+ {
+ CASE_S (INSTR);
+ CASE_S (LINE);
+ CASE_S (FUNCTION);
+ CASE_S (MODULE);
+ CASE_S (LOADOBJECT);
+ CASE_S (EADDR);
+ CASE_S (MEMOBJ);
+ CASE_S (INDEXOBJ);
+ CASE_S (PAGE);
+ CASE_S (DOBJECT);
+ CASE_S (SOURCEFILE);
+ CASE_S (EXPERIMENT);
+ CASE_S (OTHER);
+ default:
+ break;
+ }
+ return NTXT ("ERROR");
+}
+
+void
+Histable::dump_comparable_objs ()
+{
+ Dprintf (DEBUG_COMPARISON,
+ "# Histable::dump_comparable_objs type=%s(%d) 0x%lx id=%lld %s\n",
+ type_to_string (), get_type (), (unsigned long) this, (long long) id,
+ STR (get_name ()));
+ for (int i = 0, sz = comparable_objs ? comparable_objs->size () : 0; i < sz; i++)
+ {
+ Histable *h = comparable_objs->fetch (i);
+ Dprintf (DEBUG_COMPARISON, " %d type=%s(%d) 0x%lx id=%lld %s\n", i,
+ h ? h->type_to_string () : "", h ? h->get_type () : -1,
+ (unsigned long) h, (long long) (h ? h->id : 0),
+ h ? STR (h->get_name ()) : NTXT (""));
+ }
+}
+
+char *
+Histable::dump ()
+{
+ StringBuilder sb;
+ sb.appendf (sizeof (long) == 32
+ ? " 0x%08lx : type=%s(%d) id=%lld %s"
+ : " 0x%016lx : type=%s(%d) id=%lld %s",
+ (unsigned long) this, type_to_string (), get_type (),
+ (long long) id, STR (get_name ()));
+ switch (get_type ())
+ {
+ case INSTR:
+ {
+ DbeInstr *o = (DbeInstr *) this;
+ sb.appendf (sizeof (long) == 32
+ ? " func=0x%08lx lineno=%lld"
+ : " func=0x%016lx lineno=%lld",
+ (unsigned long) o->func, (long long) o->lineno);
+ break;
+ }
+ case LINE:
+ {
+ DbeLine *o = (DbeLine *) this;
+ sb.appendf (sizeof (long) == 32
+ ? " func=0x%08lx sourceFile=0x%08lx lineno=%lld"
+ : " func=0x%016lx sourceFile=0x%016lx lineno=%lld",
+ (unsigned long) o->func, (unsigned long) o->sourceFile,
+ (long long) o->lineno);
+ break;
+ }
+ default:
+ break;
+ }
+ return sb.toString ();
+}
diff --git a/gprofng/src/Hist_data.h b/gprofng/src/Hist_data.h
new file mode 100644
index 0000000..c5f7281
--- /dev/null
+++ b/gprofng/src/Hist_data.h
@@ -0,0 +1,292 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _HIST_DATA_H
+#define _HIST_DATA_H
+
+// A Hist_data object is used to obtain data used for constructing
+// a histogram display.
+
+#include <sys/types.h>
+
+#include <vec.h>
+#include <Map.h>
+#include <HashMap.h>
+
+#include "dbe_structs.h"
+#include "Histable.h"
+#include "DerivedMetrics.h"
+
+class DbeLine;
+class MetricList;
+
+class Hist_data
+{
+public:
+ friend class DbeView;
+ friend class er_print_histogram;
+ friend class PathTree;
+ friend class DataSpace;
+ friend class MemorySpace;
+ friend class IOActivity;
+ friend class HeapActivity;
+
+ // HistItem contains all the data about a single histogram item.
+ struct HistItem
+ {
+ HistItem (long n);
+ ~HistItem ();
+ Histable *obj; // info on the object
+ int type; // annotated src/dis: type
+ TValue *value; // numeric values
+ long size;
+ };
+
+ enum Hist_status
+ {
+ SUCCESS = 0,
+ NO_DATA
+ };
+
+ enum Mode
+ {
+ ALL,
+ CALLERS,
+ CALLEES,
+ SELF,
+ MODL,
+ LAYOUT,
+ DETAIL
+ };
+
+ enum Sort_order
+ {
+ ASCEND,
+ DESCEND
+ };
+
+ enum Sort_type
+ {
+ ALPHA,
+ VALUE,
+ AUX
+ };
+
+ Hist_data (MetricList *, Histable::Type, Mode, bool _viewowned = false);
+
+ virtual ~Hist_data ();
+ void dump (char *msg, FILE *f);
+
+ Hist_status
+ get_status (void)
+ {
+ return status;
+ }
+
+ // Return the view ownership flag
+ bool
+ isViewOwned (void)
+ {
+ return viewowned;
+ }
+
+ // Return the total number of items
+ long size (void);
+
+ // Append a new HistItem for the specified Histable
+ HistItem *append_hist_item (Histable *obj);
+ void append_hist_item (HistItem *hi);
+ TValue *get_real_value (TValue *res, int met_index, int row);
+ TValue *get_value (TValue *res, int met_index, int row);
+ TValue *get_value (TValue *res, int met_index, HistItem *hi);
+ void print_row (StringBuilder *sb, int row, Metric::HistMetric *hist_metric, char *mark);
+ void print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit);
+ int print_label (FILE *out_file, Metric::HistMetric *hist_metric, int space);
+ void update_total (Hist_data::HistItem *new_total);
+ void update_max (Metric::HistMetric *hm_tmp);
+ void update_legend_width (Metric::HistMetric *hm_tmp);
+
+ // Find an existing HistItem
+ HistItem *find_hist_item (Histable *obj);
+
+ // sort the data
+ void sort (long ind, bool reverse);
+
+ // resort the data, if metric sort or direction has changed
+ void resort (MetricList *mlist);
+
+ // compute minima and maxima
+ void compute_minmax (void);
+
+ // fetch() takes a hist item index and returns a ptr to the item
+ HistItem *fetch (long index);
+
+ HistItem *
+ get_maximums (void)
+ {
+ return maximum;
+ }
+
+ HistItem *
+ get_maximums_inc (void)
+ {
+ return maximum_inc;
+ }
+
+ HistItem *
+ get_minimums (void)
+ {
+ return minimum;
+ }
+
+ HistItem *
+ get_totals (void)
+ {
+ return total;
+ }
+
+ Vector<HistItem*> *
+ get_hist_items (void)
+ {
+ return hist_items;
+ }
+
+ void
+ set_status (Hist_status st)
+ {
+ status = st;
+ }
+
+ MetricList *
+ get_metric_list (void)
+ {
+ return metrics;
+ }
+
+ Map<Histable*, int> *
+ get_callsite_mark ()
+ {
+ return callsite_mark;
+ }
+
+ Metric::HistMetric *get_histmetrics ();
+ void set_threshold (double proportion);
+ bool above_threshold (HistItem *hi);
+ double get_percentage (double value, int mindex);
+ size_t value_maxlen (int mindex); // Return the drawing length
+ size_t time_len (TValue *value, int clock);
+ size_t time_maxlen (int mindex, int clock);
+ size_t name_len (HistItem *item);
+ size_t name_maxlen ();
+ HistItem *new_hist_item (Histable *obj, int itype, TValue *value);
+ HistItem *update_hist_item (HistItem *hi, TValue *value);
+ Vector<uint64_t> *get_object_indices (Vector<int> *selections);
+
+private:
+
+ Metric::HistMetric *hist_metrics;
+ Vector<HistItem*> *hist_items; // Actual histogram values
+ HashMap<Histable*, HistItem*>*hi_map; // map: Histable -> HistItem
+ Map<Histable*, int>*callsite_mark;
+ Hist_status status;
+ int nmetrics; // number of metrics
+ MetricList *metrics;
+ Histable::Type type;
+ Sort_order sort_order;
+ Sort_type sort_type;
+ int sort_ind;
+ bool rev_sort; // true if sort is reversed
+
+ Mode mode;
+ HistItem *gprof_item; // used for gprof-style info
+ Histable *spontaneous;
+
+ // Private state variables
+ HistItem *maximum;
+ HistItem *minimum;
+ HistItem *maximum_inc;
+ HistItem *total;
+ HistItem *threshold;
+
+ // Perform the sort operation with this function
+ static int sort_compare_all (const void *a, const void *b, const void *arg);
+ static int sort_compare_dlayout (const void *a, const void *b, const void *arg);
+ static int sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype,
+ long ind, Hist_data *hdata);
+
+ // Allocate a new structure of dynamic size
+ HistItem *new_hist_item (Histable *obj);
+
+ // Flag indicating whether or not the Hist_data structure
+ // is owned by a DbeView, which has responsibility for
+ // deleting it, or not, in which case the last user deletes it.
+ // XXX this is very ugly, and arises from the inconsistent handling
+ // XXX of the Hist_data structure in various bits of code.
+ bool viewowned;
+};
+
+// This structure is destined to merge with Hist_data.
+// We currently use it to present callstack data such as
+// leak and allocation lists.
+
+class DbeInstr;
+
+struct CStack_data
+{
+
+ struct CStack_item
+ {
+ CStack_item (long n);
+ ~CStack_item ();
+ long count;
+ int64_t val;
+ Vector<DbeInstr*> *stack;
+ TValue *value; // numeric values
+ };
+
+ Vector<CStack_item*> *cstack_items;
+ CStack_item *total;
+
+ CStack_item *new_cstack_item ();
+ CStack_data (MetricList *);
+
+ long
+ size ()
+ {
+ return cstack_items->size ();
+ }
+
+ CStack_item *
+ fetch (long i)
+ {
+ return cstack_items->fetch (i);
+ }
+
+ ~CStack_data ()
+ {
+ cstack_items->destroy ();
+ delete cstack_items;
+ delete total;
+ }
+
+ MetricList *metrics;
+};
+
+#endif /* _HIST_DATA_H */
diff --git a/gprofng/src/Histable.h b/gprofng/src/Histable.h
new file mode 100644
index 0000000..c4cf854
--- /dev/null
+++ b/gprofng/src/Histable.h
@@ -0,0 +1,333 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _HISTABLE_H
+#define _HISTABLE_H
+
+//
+// The Histable class hierarchy is used to build up a representation of
+// the codeobjects (functions, modules, loadObjects, etc.) that make up the
+// text address space of a program. The hierarchy is as follows:
+//
+// Histable (public)
+// LoadObject (public)
+// Module (public)
+// Function (public)
+//
+// Dataobjects are objects from the data address space of a program.
+// The reason for calling the base class "Histable" is because these
+// objects are all valid objects for computing histograms on.
+
+// A Histable object represents an object in the program text or data.
+
+#include "dbe_structs.h"
+#include "Emsg.h"
+#include "Expression.h"
+
+class DataObject;
+class Function;
+class SourceFile;
+class DbeFile;
+class DbeLine;
+template <class ITEM> class Vector;
+
+class Histable
+{
+ friend class Hist_data;
+public:
+
+ enum Type
+ {
+ INSTR, LINE, FUNCTION, MODULE, LOADOBJECT,
+ EADDR, MEMOBJ, INDEXOBJ, PAGE, DOBJECT,
+ SOURCEFILE, IOACTFILE, IOACTVFD, IOCALLSTACK,
+ HEAPCALLSTACK, EXPERIMENT, OTHER
+ };
+
+ // NameFormat for functions and function based objects
+
+ enum NameFormat
+ {
+ NA, LONG, SHORT, MANGLED, SONAME = 0x10
+ };
+
+ static NameFormat
+ make_fmt (int fnfmt, bool sofmt = false)
+ {
+ return (NameFormat) (sofmt ? fnfmt | SONAME : fnfmt);
+ }
+
+ static int
+ fname_fmt (NameFormat fmt)
+ {
+ return (fmt & ~SONAME);
+ }
+
+ static bool
+ soname_fmt (NameFormat fmt)
+ {
+ return (fmt & SONAME);
+ }
+
+ Histable ();
+ char *dump ();
+
+ virtual ~Histable ();
+
+ virtual char *
+ get_name (NameFormat = NA)
+ {
+ return name; // Return the name of the object
+ }
+
+ virtual void
+ set_name (char * _name)
+ {
+ name = _name;
+ }
+
+ virtual void set_name_from_context (Expression::Context *) { }
+ virtual Type get_type () = 0;
+
+ virtual int64_t
+ get_size ()
+ {
+ return 0;
+ }
+
+ virtual uint64_t
+ get_addr ()
+ {
+ return 0ULL;
+ }
+
+ virtual Vector<Histable*> *get_comparable_objs ();
+ Histable *get_compare_obj ();
+
+ virtual Histable *
+ convertto (Type, Histable* = NULL)
+ {
+ return this;
+ }
+
+ Vector<Histable*> *comparable_objs;
+ int64_t id; // A unique id of this object, within its specific Type
+
+protected:
+ char *name; // Object name
+ int phaseCompareIdx;
+ void update_comparable_objs ();
+ void dump_comparable_objs ();
+ char *type_to_string ();
+ void delete_comparable_objs ();
+};
+
+typedef Histable::Type Histable_type;
+
+// An Other object represents some random histable object
+class Other : public Histable
+{
+public:
+
+ virtual Type
+ get_type ()
+ {
+ return OTHER;
+ }
+
+ uint64_t value64;
+ uint32_t tag;
+};
+
+// DbeInstr represents an instruction.
+//
+// Used by Analyzer for: Disassembly, PCs, Timeline, and Event tabs.
+//
+class DbeInstr : public Histable
+{
+public:
+ DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr);
+
+ virtual Type
+ get_type ()
+ {
+ return INSTR;
+ }
+
+ virtual char *get_name (NameFormat = NA);
+ virtual int64_t get_size ();
+ virtual uint64_t get_addr ();
+ virtual Histable *convertto (Type type, Histable *obj = NULL);
+ DbeLine *mapPCtoLine (SourceFile *sf);
+ void add_inlined_info (StringBuilder *sb);
+ char *get_descriptor ();
+ int pc_cmp (DbeInstr *instr2);
+
+ uint64_t addr;
+ uint64_t img_offset; // file offset of the image
+ int flags;
+ Function *func;
+ int lineno;
+ int inlinedInd;
+ int64_t size;
+ bool isUsed;
+
+private:
+ NameFormat current_name_format;
+};
+
+class DbeEA : public Histable
+{
+public:
+
+ DbeEA (DataObject *_dobj, Vaddr _eaddr)
+ {
+ dobj = _dobj;
+ eaddr = _eaddr;
+ };
+
+ virtual Type
+ get_type ()
+ {
+ return EADDR;
+ };
+
+ virtual int64_t
+ get_size ()
+ {
+ return 1;
+ };
+
+ virtual uint64_t
+ get_addr ()
+ {
+ return eaddr;
+ };
+
+ virtual char *get_name (NameFormat = NA);
+ virtual Histable *convertto (Type type, Histable *obj = NULL);
+
+ DataObject *dobj;
+ Vaddr eaddr;
+};
+
+// DbeLine represents a line in a source file.
+//
+// For each top-level DbeLine instance, there are three DbeLine subtypes:
+//
+// A The top-level DbeLine is associated with a sourceFile & lineno, but
+// not any particular function. This form of DbeLine is used
+// to represent Analyzer Source tab lines.
+//
+// B Function-specific lines, those associated with a function in addition
+// to the the sourceFile & lineno, are stored in a linked list.
+// (see "dbeline_func_next").
+// This subtype is used to differentiate a line found in #included source
+// that is referenced by multiple functions.
+// It is used in the Analyzer Lines tab.
+//
+// C Function-specific "lines" that don't have line number info are referenced
+// from each linked-list element's "dbeline_func_pseudo" field.
+// This subtype is needed when a binary doesn't identify line numbers.
+// It is used in the Analyzer Lines tab.
+//
+// When the user switches views between tabs, a selected object in the old
+// tab must be translated to an approprate object in the new tab.
+// When switching to the Source Tab, the top-level DbeLine (dbeline_base)
+// should be used.
+// When switching to the Lines Tab, a function-specific dbeline_func_*
+// should be used.
+//
+
+class DbeLine : public Histable
+{
+public:
+
+ enum Flag
+ {
+ OMPPRAGMA = 1
+ };
+
+ DbeLine (Function *_func, SourceFile *sf, int _lineno);
+ virtual ~DbeLine ();
+ virtual char *get_name (NameFormat = NA);
+ virtual int64_t get_size ();
+ virtual uint64_t get_addr ();
+ virtual Histable *convertto (Type type, Histable *obj = NULL);
+
+ void init_Offset (uint64_t p_offset);
+ int line_cmp (DbeLine *dbl);
+
+ virtual Type
+ get_type ()
+ {
+ return LINE;
+ }
+
+ void
+ set_flag (Flag flag)
+ {
+ flags |= flag;
+ }
+
+ bool
+ is_set (Flag flag)
+ {
+ return (flags & flag) != 0;
+ }
+
+ Function *func; // note: will be NULL in the base (head) dbeline
+ int lineno;
+ int64_t size;
+ SourceFile *sourceFile; // Default source file
+ SourceFile *include; // included source file or NULL
+
+ DbeLine *dbeline_base;
+ // Head of list, a dbeline associated with sourceFile & lineno, but not func:
+ // dbeline_base->lineno: non-zero
+ // dbeline_base->sourceFile: non-null
+ // dbeline_base->func: NULL
+ // dbeline_base->dbeline_base: this
+ // dbeline_base->dbeline_func_next: first func-specific dbeline
+
+ DbeLine *dbeline_func_next;
+ // If non-null, pointer to a function-specific dbeline where:
+ // dbeline_func_next->lineno: same as dbeline_base->lineno
+ // dbeline_func_next->sourceFile: same as dbeline_base->sourceFile
+ // dbeline_func_next->func: pointer to unique function
+ // dbeline_func_next->dbeline_base: head of the linked list.
+ // dbeline_func_next->dbeline_func_next: next function-specific dbeline.
+
+private:
+ int current_name_format;
+ int64_t offset;
+ int flags;
+};
+
+class HistableFile : public Histable, public DbeMessages
+{
+public:
+ HistableFile ();
+
+ bool isUsed;
+ DbeFile *dbeFile;
+};
+
+#endif /* _HISTABLE_H */
diff --git a/gprofng/src/IOActivity.cc b/gprofng/src/IOActivity.cc
new file mode 100644
index 0000000..401cab5
--- /dev/null
+++ b/gprofng/src/IOActivity.cc
@@ -0,0 +1,825 @@
+/* Copyright (C) 2021 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 "DbeSession.h"
+#include "FileData.h"
+#include "StringBuilder.h"
+#include "i18n.h"
+#include "util.h"
+#include "IOActivity.h"
+#include "MetricList.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "DbeView.h"
+#include "Exp_Layout.h"
+#include "i18n.h"
+
+IOActivity::IOActivity (DbeView *_dbev)
+{
+ dbev = _dbev;
+ fDataHash = NULL;
+ fDataTotal = NULL;
+ fDataObjs = NULL;
+ fDataObjsFile = NULL;
+ hasFile = false;
+ fDataObjsVfd = NULL;
+ hasVfd = false;
+ fDataObjsCallStack = NULL;
+ hasCallStack = false;
+ fDataCalStkMap = NULL;
+ fDataVfdMap = NULL;
+ hist_data_file_all = NULL;
+ hist_data_vfd_all = NULL;
+ hist_data_callstack_all = NULL;
+}
+
+void
+IOActivity::reset ()
+{
+ int numExps = dbeSession->nexps ();
+ FileData *fData = NULL;
+ DefaultMap<int64_t, FileData*>* fDataMap;
+ for (int k = 0; k < numExps; k++)
+ {
+ Experiment *exp = dbeSession->get_exp (k);
+ fDataMap = exp->getFDataMap ();
+ if (fDataMap == NULL)
+ continue;
+
+ fDataObjs = fDataMap->values ();
+ if (fDataObjs == NULL)
+ continue;
+ int numFiles = fDataObjs->size ();
+ for (int j = 0; j < numFiles; j++)
+ {
+ fData = fDataObjs->fetch (j);
+ fData->init ();
+ }
+ }
+
+ delete fDataHash;
+ fDataHash = NULL;
+ delete fDataTotal;
+ fDataTotal = NULL;
+
+ delete fDataObjsFile;
+ fDataObjsFile = NULL;
+ hasFile = false;
+
+ delete fDataObjsVfd;
+ fDataObjsVfd = NULL;
+ hasVfd = false;
+
+ delete fDataObjsCallStack;
+ fDataObjsCallStack = NULL;
+ hasCallStack = false;
+
+ delete fDataObjs;
+ fDataObjs = NULL;
+ delete fDataCalStkMap;
+ fDataCalStkMap = NULL;
+ delete fDataVfdMap;
+ fDataVfdMap = NULL;
+
+ // These three pointers are deleted by DbeView
+ // They are named iofile_data, iovfd_data, and iocs_data
+ hist_data_file_all = NULL;
+ hist_data_vfd_all = NULL;
+ hist_data_callstack_all = NULL;
+}
+
+void
+IOActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
+ Histable::Type hType, bool empty)
+{
+ int mIndex;
+ Metric *mtr;
+ Hist_data::HistItem *hi;
+ FileData *fData = NULL;
+
+ if (fDataTotal == NULL)
+ {
+ fDataTotal = new FileData (TOTAL_FILENAME);
+ fDataTotal->setHistType (hType);
+ fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
+ fDataTotal->id = 0;
+ }
+
+ fData = new FileData (fDataTotal);
+ fData->setHistType (hType);
+ hi = hist_data->append_hist_item (fData);
+ Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+ {
+ if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+ continue;
+
+ Metric::Type mtype = mtr->get_type ();
+ ValueTag vType = mtr->get_vtype ();
+ hist_data->total->value[mIndex].tag = vType;
+ hi->value[mIndex].tag = vType;
+ double prec = (double) NANOSEC;
+ switch (mtype)
+ {
+ case BaseMetric::IO_READ_BYTES:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
+ hi->value[mIndex].ll = fDataTotal->getReadBytes ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::IO_READ_CNT:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
+ hi->value[mIndex].ll = fDataTotal->getReadCnt ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::IO_READ_TIME:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getReadTime () / prec;
+ hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+ }
+ else
+ {
+ hist_data->total->value[mIndex].d = 0.0;
+ hi->value[mIndex].d = 0.0;
+ }
+ break;
+ case BaseMetric::IO_WRITE_BYTES:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
+ hi->value[mIndex].ll = fDataTotal->getWriteBytes ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::IO_WRITE_CNT:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
+ hi->value[mIndex].ll = fDataTotal->getWriteCnt ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::IO_WRITE_TIME:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getWriteTime () / prec;
+ hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+ }
+ else
+ {
+ hist_data->total->value[mIndex].d = 0.0;
+ hi->value[mIndex].d = 0.0;
+ }
+ break;
+ case BaseMetric::IO_OTHER_CNT:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
+ hi->value[mIndex].ll = fDataTotal->getOtherCnt ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::IO_OTHER_TIME:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getOtherTime () / prec;
+ hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+ }
+ else
+ {
+ hist_data->total->value[mIndex].d = 0.0;
+ hi->value[mIndex].d = 0.0;
+ }
+ break;
+ case BaseMetric::IO_ERROR_CNT:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
+ hi->value[mIndex].ll = fDataTotal->getErrorCnt ();
+ }
+ else
+ {
+ hist_data->total->value[mIndex].ll = 0;
+ hi->value[mIndex].ll = 0;
+ }
+ break;
+ case BaseMetric::IO_ERROR_TIME:
+ if (!empty)
+ {
+ hist_data->total->value[mIndex].d = (double) fDataTotal->getErrorTime () / prec;
+ hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+ }
+ else
+ {
+ hist_data->total->value[mIndex].d = 0.0;
+ hi->value[mIndex].d = 0.0;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+IOActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
+{
+ int mIndex;
+ Metric *mtr;
+ Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+ {
+ if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+ continue;
+
+ Metric::Type mtype = mtr->get_type ();
+ ValueTag vType = mtr->get_vtype ();
+ hist_data->total->value[mIndex].tag = vType;
+ double prec = (double) NANOSEC;
+ switch (mtype)
+ {
+ case BaseMetric::IO_READ_BYTES:
+ hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
+ break;
+ case BaseMetric::IO_READ_CNT:
+ hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
+ break;
+ case BaseMetric::IO_READ_TIME:
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getReadTime () / prec;
+ break;
+ case BaseMetric::IO_WRITE_BYTES:
+ hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
+ break;
+ case BaseMetric::IO_WRITE_CNT:
+ hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
+ break;
+ case BaseMetric::IO_WRITE_TIME:
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getWriteTime () / prec;
+ break;
+ case BaseMetric::IO_OTHER_CNT:
+ hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
+ break;
+ case BaseMetric::IO_OTHER_TIME:
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getOtherTime () / prec;
+ break;
+ case BaseMetric::IO_ERROR_CNT:
+ hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
+ break;
+ case BaseMetric::IO_ERROR_TIME:
+ hist_data->total->value[mIndex].d =
+ (double) fDataTotal->getErrorTime () / prec;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+IOActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
+ Hist_data::Mode mode, Histable *selObj)
+{
+
+ Hist_data::HistItem *hi = NULL;
+ int numObjs = fDataObjs->size ();
+ int numMetrics = mlist->get_items ()->size ();
+
+ for (int i = 0; i < numObjs; i++)
+ {
+ FileData *fData = fDataObjs->fetch (i);
+ if (mode == Hist_data::ALL)
+ hi = hist_data->append_hist_item (fData);
+ else if (mode == Hist_data::SELF)
+ {
+ if (fData->id == selObj->id)
+ hi = hist_data->append_hist_item (fData);
+ else
+ continue;
+ }
+
+ for (int mIndex = 0; mIndex < numMetrics; mIndex++)
+ {
+ Metric *mtr = mlist->get_items ()->fetch (mIndex);
+ if (!mtr->is_visible () && !mtr->is_tvisible ()
+ && !mtr->is_pvisible ())
+ continue;
+
+ Metric::Type mtype = mtr->get_type ();
+ ValueTag vType = mtr->get_vtype ();
+ hi->value[mIndex].tag = vType;
+
+ double prec = (double) NANOSEC;
+ switch (mtype)
+ {
+ case BaseMetric::IO_READ_BYTES:
+ hi->value[mIndex].ll = fData->getReadBytes ();
+ break;
+ case BaseMetric::IO_READ_CNT:
+ hi->value[mIndex].ll = fData->getReadCnt ();
+ break;
+ case BaseMetric::IO_READ_TIME:
+ hi->value[mIndex].d = (double) fData->getReadTime () / prec;
+ break;
+ case BaseMetric::IO_WRITE_BYTES:
+ hi->value[mIndex].ll = fData->getWriteBytes ();
+ break;
+ case BaseMetric::IO_WRITE_CNT:
+ hi->value[mIndex].ll = fData->getWriteCnt ();
+ break;
+ case BaseMetric::IO_WRITE_TIME:
+ hi->value[mIndex].d = (double) fData->getWriteTime () / prec;
+ break;
+ case BaseMetric::IO_OTHER_CNT:
+ hi->value[mIndex].ll = fData->getOtherCnt ();
+ break;
+ case BaseMetric::IO_OTHER_TIME:
+ hi->value[mIndex].d = (double) fData->getOtherTime () / prec;
+ break;
+ case BaseMetric::IO_ERROR_CNT:
+ hi->value[mIndex].ll = fData->getErrorCnt ();
+ break;
+ case BaseMetric::IO_ERROR_TIME:
+ hi->value[mIndex].d = (double) fData->getErrorTime () / prec;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+Hist_data *
+IOActivity::compute_metrics (MetricList *mlist, Histable::Type type,
+ Hist_data::Mode mode, Histable *selObj)
+{
+
+ // it's already there, just return it
+ if (mode == Hist_data::ALL)
+ {
+ if (type == Histable::IOACTFILE && hist_data_file_all)
+ return hist_data_file_all;
+ else if (type == Histable::IOACTVFD && hist_data_vfd_all)
+ return hist_data_vfd_all;
+ else if (type == Histable::IOCALLSTACK && hist_data_callstack_all)
+ return hist_data_callstack_all;
+ }
+
+ bool has_data = false;
+ Hist_data *hist_data = NULL;
+ VMode viewMode = dbev->get_view_mode ();
+
+ switch (type)
+ {
+ case Histable::IOACTVFD:
+ if (!hasVfd)
+ computeData (type);
+
+ // computeData() creates fDataObjsVfd
+ // fDataObjsVfd contains the list of vfd objects
+ if (fDataObjsVfd != NULL)
+ {
+ // fDataObjs is used in other methods
+ fDataObjs = fDataObjsVfd;
+ has_data = true;
+ }
+ else
+ has_data = false;
+
+ if (has_data && mode == Hist_data::ALL && hist_data_vfd_all == NULL)
+ {
+ hist_data_vfd_all = new Hist_data (mlist, type, mode, true);
+ hist_data = hist_data_vfd_all;
+ }
+ else if (has_data)
+ hist_data = new Hist_data (mlist, type, mode, false);
+ else
+ {
+ hist_data = new Hist_data (mlist, type, mode, false);
+ createHistItemTotals (hist_data, mlist, type, true);
+ return hist_data;
+ }
+ break;
+ case Histable::IOACTFILE:
+ if (!hasFile)
+ computeData (type);
+
+ // computeData() creates fDataObjsFile
+ // fDataObjsFile contains the list of file objects
+ if (fDataObjsFile != NULL)
+ {
+ fDataObjs = fDataObjsFile;
+ has_data = true;
+ }
+ else
+ has_data = false;
+
+ if (has_data && mode == Hist_data::ALL && hist_data_file_all == NULL)
+ {
+ hist_data_file_all = new Hist_data (mlist, type, mode, true);
+ hist_data = hist_data_file_all;
+ }
+ else if (has_data)
+ hist_data = new Hist_data (mlist, type, mode, false);
+ else
+ {
+ hist_data = new Hist_data (mlist, type, mode, false);
+ createHistItemTotals (hist_data, mlist, type, true);
+ return hist_data;
+ }
+ break;
+ case Histable::IOCALLSTACK:
+ if (!hasCallStack)
+ computeCallStack (type, viewMode);
+
+ // computeCallStack() creates fDataObjsCallStack
+ // fDataObjsCallStack contains the list of call stack objects
+ if (fDataObjsCallStack != NULL)
+ {
+ fDataObjs = fDataObjsCallStack;
+ has_data = true;
+ }
+ else
+ has_data = false;
+
+ if (has_data && (mode == Hist_data::ALL) && (hist_data_callstack_all == NULL))
+ {
+ hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
+ hist_data = hist_data_callstack_all;
+ }
+ else if (has_data)
+ hist_data = new Hist_data (mlist, type, mode, false);
+ else
+ {
+ hist_data = new Hist_data (mlist, type, mode, false);
+ createHistItemTotals (hist_data, mlist, type, true);
+ return hist_data;
+ }
+ break;
+ default:
+ fprintf (stderr,
+ "IOActivity cannot process data due to wrong Histable (type=%d) \n",
+ type);
+ abort ();
+ }
+
+ if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
+ createHistItemTotals (hist_data, mlist, type, false);
+ else
+ computeHistTotals (hist_data, mlist);
+ computeHistData (hist_data, mlist, mode, selObj);
+
+ // Determine by which metric to sort if any
+ bool rev_sort = mlist->get_sort_rev ();
+ int sort_ind = -1;
+ int nmetrics = mlist->get_items ()->size ();
+ for (int mind = 0; mind < nmetrics; mind++)
+ if (mlist->get_sort_ref_index () == mind)
+ sort_ind = mind;
+
+ hist_data->sort (sort_ind, rev_sort);
+ hist_data->compute_minmax ();
+ return hist_data;
+}
+
+void
+IOActivity::computeData (Histable::Type type)
+{
+ bool has_iodata = false;
+ reset ();
+ int64_t histableId = 0; // It is used by fDataAggr only
+ // fData uses vfd for histable id
+
+ fDataHash = new HashMap<char*, FileData*>;
+ FileData *fData = NULL;
+ FileData *fDataAggr = NULL;
+
+ fDataTotal = new FileData (TOTAL_FILENAME);
+ fDataTotal->setHistType (type);
+ fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
+ fDataTotal->id = histableId++;
+
+ FileData *fDataStdin = new FileData (STDIN_FILENAME);
+ fDataStdin->setFileDes (STDIN_FD);
+ fDataStdin->setHistType (type);
+ fDataStdin->setFsType ("N/A");
+ fDataStdin->id = histableId++;
+
+ FileData *fDataStdout = new FileData (STDOUT_FILENAME);
+ fDataStdout->setFileDes (STDOUT_FD);
+ fDataStdout->setHistType (type);
+ fDataStdout->setFsType ("N/A");
+ fDataStdout->id = histableId++;
+
+ FileData *fDataStderr = new FileData (STDERR_FILENAME);
+ fDataStderr->setFileDes (STDERR_FD);
+ fDataStderr->setHistType (type);
+ fDataStderr->setFsType ("N/A");
+ fDataStderr->id = histableId++;
+
+ FileData *fDataOtherIO = new FileData (OTHERIO_FILENAME);
+ fDataOtherIO->setFileDes (OTHERIO_FD);
+ fDataOtherIO->setHistType (type);
+ fDataOtherIO->setFsType ("N/A");
+ fDataOtherIO->id = histableId++;
+
+ DefaultMap<int64_t, FileData*>* fDataMap;
+ fDataObjsFile = NULL;
+ fDataObjsVfd = NULL;
+
+ // get the list of io events from DbeView
+ int numExps = dbeSession->nexps ();
+
+ for (int k = 0; k < numExps; k++)
+ {
+ DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
+ if (ioPkts == NULL || ioPkts->getSize () <= 0)
+ continue;
+ Experiment *exp = dbeSession->get_exp (k);
+ fDataMap = exp->getFDataMap ();
+ if (fDataMap == NULL)
+ continue;
+ delete fDataVfdMap;
+ fDataVfdMap = new DefaultMap<long, FileData*>;
+
+ long sz = ioPkts->getSize ();
+ for (long i = 0; i < sz; ++i)
+ {
+ hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
+ int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
+ IOTrace_type ioType = (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
+ int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
+ if (vFd >= 0)
+ {
+ fData = fDataMap->get (vFd);
+ if (fData == NULL)
+ continue;
+ }
+ else
+ continue;
+
+ if (fDataVfdMap->get (vFd) == NULL)
+ fDataVfdMap->put (vFd, fData);
+
+ switch (ioType)
+ {
+ case READ_TRACE:
+ fData->addReadEvent (event_duration, nByte);
+ // Set the Histable id for IOVFD
+ fData->id = fData->getVirtualFd ();
+ fDataTotal->addReadEvent (event_duration, nByte);
+ fDataTotal->setReadStat (event_duration, nByte);
+ break;
+ case WRITE_TRACE:
+ fData->addWriteEvent (event_duration, nByte);
+ // Set the Histable id for IOVFD
+ fData->id = fData->getVirtualFd ();
+ fDataTotal->addWriteEvent (event_duration, nByte);
+ fDataTotal->setWriteStat (event_duration, nByte);
+ break;
+ case OPEN_TRACE:
+ fData->addOtherEvent (event_duration);
+ // Set the Histable id for IOVFD
+ fData->id = fData->getVirtualFd ();
+ fDataTotal->addOtherEvent (event_duration);
+ break;
+ case CLOSE_TRACE:
+ case OTHERIO_TRACE:
+ fData->addOtherEvent (event_duration);
+ // Set the Histable id for IOVFD
+ fData->id = fData->getVirtualFd ();
+ fDataTotal->addOtherEvent (event_duration);
+ break;
+ case READ_TRACE_ERROR:
+ case WRITE_TRACE_ERROR:
+ case OPEN_TRACE_ERROR:
+ case CLOSE_TRACE_ERROR:
+ case OTHERIO_TRACE_ERROR:
+ fData->addErrorEvent (event_duration);
+ // Set the Histable id for IOVFD
+ fData->id = fData->getVirtualFd ();
+ fDataTotal->addErrorEvent (event_duration);
+ break;
+
+ case IOTRACETYPE_LAST:
+ break;
+ }
+
+ if (type == Histable::IOACTFILE)
+ {
+ fDataAggr = fDataHash->get (fData->getFileName ());
+ if (fDataAggr == NULL)
+ {
+ bool setInfo = false;
+ if (vFd == VIRTUAL_FD_STDIN)
+ fDataAggr = fDataStdin;
+ else if (vFd == VIRTUAL_FD_STDOUT)
+ fDataAggr = fDataStdout;
+ else if (vFd == VIRTUAL_FD_STDERR)
+ fDataAggr = fDataStderr;
+ else if (vFd == VIRTUAL_FD_OTHERIO)
+ fDataAggr = fDataOtherIO;
+ else
+ {
+ fDataAggr = new FileData (fData->getFileName ());
+ setInfo = true;
+ }
+ fDataHash->put (fData->getFileName (), fDataAggr);
+
+ if (setInfo)
+ {
+ fDataAggr->setFsType (fData->getFsType ());
+ fDataAggr->setHistType (type);
+ // Set the Histable id for aggregated file name
+ fDataAggr->id = histableId;
+ fDataAggr->setVirtualFd (histableId);
+ histableId++;
+ }
+ }
+
+ fDataAggr->setFileDesList (fData->getFileDes ());
+ fDataAggr->setVirtualFds (fData->getVirtualFd ());
+ switch (ioType)
+ {
+ case READ_TRACE:
+ fDataAggr->addReadEvent (event_duration, nByte);
+ break;
+ case WRITE_TRACE:
+ fDataAggr->addWriteEvent (event_duration, nByte);
+ break;
+ case OPEN_TRACE:
+ fDataAggr->addOtherEvent (event_duration);
+ break;
+ case CLOSE_TRACE:
+ case OTHERIO_TRACE:
+ fDataAggr->addOtherEvent (event_duration);
+ break;
+ case READ_TRACE_ERROR:
+ case WRITE_TRACE_ERROR:
+ case OPEN_TRACE_ERROR:
+ case CLOSE_TRACE_ERROR:
+ case OTHERIO_TRACE_ERROR:
+ fDataAggr->addErrorEvent (event_duration);
+ break;
+ case IOTRACETYPE_LAST:
+ break;
+ }
+ }
+ has_iodata = true;
+ }
+ if (sz > 0)
+ {
+ if (fDataObjsVfd == NULL)
+ fDataObjsVfd = new Vector<FileData*>;
+ fDataObjsVfd->addAll (fDataVfdMap->values ());
+ hasVfd = true;
+ }
+ }
+ if (has_iodata && type == Histable::IOACTFILE)
+ {
+ fDataObjsFile = fDataHash->values ()->copy ();
+ hasFile = true;
+ }
+}
+
+void
+IOActivity::computeCallStack (Histable::Type type, VMode viewMode)
+{
+ bool has_data = false;
+ int64_t stackIndex = 0;
+ FileData *fData = NULL;
+ delete fDataCalStkMap;
+ fDataCalStkMap = new DefaultMap<void*, FileData*>;
+ delete fDataTotal;
+ fDataTotal = new FileData (TOTAL_FILENAME);
+ fDataTotal->setHistType (type);
+
+ // There is no call stack for total, use the index for id
+ fDataTotal->id = stackIndex++;
+
+ // get the list of io events from DbeView
+ int numExps = dbeSession->nexps ();
+ for (int k = 0; k < numExps; k++)
+ {
+ DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
+ if (ioPkts == NULL || ioPkts->getSize () <= 0)
+ continue;
+ long sz = ioPkts->getSize ();
+ for (long i = 0; i < sz; ++i)
+ {
+ hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
+ int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
+ void *stackId = getStack (viewMode, ioPkts, i);
+ IOTrace_type ioType =
+ (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
+ int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
+
+ if (stackId != NULL && vFd > 0)
+ {
+ fData = fDataCalStkMap->get (stackId);
+ if (fData == NULL)
+ {
+ char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
+ (unsigned long long) stackId);
+ fData = new FileData (stkName);
+ fDataCalStkMap->put (stackId, fData);
+ fData->id = (int64_t) stackId;
+ fData->setVirtualFd (stackIndex);
+ stackIndex++;
+ fData->setHistType (type);
+ }
+ }
+ else
+ continue;
+
+ switch (ioType)
+ {
+ case READ_TRACE:
+ fData->addReadEvent (event_duration, nByte);
+ fDataTotal->addReadEvent (event_duration, nByte);
+ fDataTotal->setReadStat (event_duration, nByte);
+ break;
+ case WRITE_TRACE:
+ fData->addWriteEvent (event_duration, nByte);
+ fDataTotal->addWriteEvent (event_duration, nByte);
+ fDataTotal->setWriteStat (event_duration, nByte);
+ break;
+ case OPEN_TRACE:
+ fData->addOtherEvent (event_duration);
+ fDataTotal->addOtherEvent (event_duration);
+ break;
+ case CLOSE_TRACE:
+ case OTHERIO_TRACE:
+ fData->addOtherEvent (event_duration);
+ fDataTotal->addOtherEvent (event_duration);
+ break;
+ case READ_TRACE_ERROR:
+ case WRITE_TRACE_ERROR:
+ case OPEN_TRACE_ERROR:
+ fData->addErrorEvent (event_duration);
+ fDataTotal->addErrorEvent (event_duration);
+ break;
+ case CLOSE_TRACE_ERROR:
+ case OTHERIO_TRACE_ERROR:
+ fData->addErrorEvent (event_duration);
+ fDataTotal->addErrorEvent (event_duration);
+ break;
+ case IOTRACETYPE_LAST:
+ break;
+ }
+ has_data = true;
+ }
+ }
+ if (has_data)
+ {
+ fDataObjsCallStack = fDataCalStkMap->values ()->copy ();
+ hasCallStack = true;
+ }
+}
diff --git a/gprofng/src/IOActivity.h b/gprofng/src/IOActivity.h
new file mode 100644
index 0000000..35c4517
--- /dev/null
+++ b/gprofng/src/IOActivity.h
@@ -0,0 +1,86 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _IOACTIVITY_H
+#define _IOACTIVITY_H
+
+
+#include <stdio.h>
+
+#include "vec.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Metric.h"
+#include "FileData.h"
+#include "DefaultMap.h"
+#include "dbe_types.h"
+
+class Experiment;
+class Expression;
+class DataView;
+class DbeView;
+
+class IOActivity
+{
+public:
+
+ IOActivity (DbeView *_dbev);
+ void reset (void);
+ Hist_data *compute_metrics (MetricList *, Histable::Type, Hist_data::Mode,
+ Histable*);
+
+ ~IOActivity ()
+ {
+ this->reset ();
+ }
+
+private:
+ void computeData (Histable::Type);
+ void computeCallStack (Histable::Type, VMode viewMode);
+ void createHistItemTotals (Hist_data *, MetricList *, Histable::Type, bool);
+ void computeHistTotals (Hist_data *, MetricList *);
+ void computeHistData (Hist_data *, MetricList *, Hist_data::Mode, Histable *);
+
+ Vector<FileData*> *fDataObjs;
+ Vector<FileData*> *fDataObjsFile;
+ Vector<FileData*> *fDataObjsVfd;
+ Vector<FileData*> *fDataObjsCallStack;
+ bool hasFile;
+ bool hasVfd;
+ bool hasCallStack;
+ HashMap<char*, FileData*> *fDataHash;
+ FileData *fDataTotal;
+
+ // list of FileData objects using the stack id as the key
+ DefaultMap<void*, FileData*> *fDataCalStkMap;
+
+ // list of FileData objects using the VFD as the key
+ DefaultMap<long, FileData*> *fDataVfdMap;
+
+ // the cached data for mode=Hist_Data::ALL
+ Hist_data *hist_data_file_all;
+ Hist_data *hist_data_vfd_all;
+ Hist_data *hist_data_callstack_all;
+ Hist_data *hist_data_callstack;
+
+ DbeView *dbev;
+};
+
+#endif /* _IOACTIVITY_H */
diff --git a/gprofng/src/IndexMap2D.h b/gprofng/src/IndexMap2D.h
new file mode 100644
index 0000000..0f68a3a
--- /dev/null
+++ b/gprofng/src/IndexMap2D.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * Index Map2D implementation.
+ *
+ * Index Map2D is dynamic two dimensional array
+ */
+
+#ifndef _DBE_INDEXMAP2D_H
+#define _DBE_INDEXMAP2D_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map2D.h>
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+class IndexMap2D : public Map2D<Key1_t, Key2_t, Value_t>
+{
+public:
+
+ IndexMap2D ();
+ ~IndexMap2D ();
+
+ void put (Key1_t key1, Key2_t key2, Value_t val);
+ Value_t get (Key1_t key1, Key2_t key2);
+ Value_t get (Key1_t key1, Key2_t key2,
+ typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel);
+ Value_t remove (Key1_t key1, Key2_t key2);
+
+private:
+
+ Vector<Vector<Value_t>*> *map1;
+};
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+IndexMap2D<Key1_t, Key2_t, Value_t>::IndexMap2D ()
+{
+ map1 = new Vector<Vector<Value_t>*>;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+IndexMap2D<Key1_t, Key2_t, Value_t>::~IndexMap2D ()
+{
+ map1->destroy ();
+ delete map1;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+void
+IndexMap2D<Key1_t, Key2_t, Value_t>::put (Key1_t key1, Key2_t key2, Value_t val)
+{
+ if (key1 < 0 || key2 < 0)
+ return;
+ Vector<Value_t> *map2 = NULL;
+ if (key1 < map1->size ())
+ map2 = map1->fetch ((int) key1);
+ if (map2 == NULL)
+ {
+ map2 = new Vector<Value_t>;
+ map1->store ((int) key1, map2);
+ }
+ map2->store ((int) key2, val);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+IndexMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2)
+{
+ if (key1 < 0 || key1 >= map1->size () || key2 < 0)
+ return (Value_t) 0;
+ Vector<Value_t> *map2 = map1->fetch ((int) key1);
+ if (map2 == NULL || key2 >= map2->size ())
+ return (Value_t) 0;
+ return map2->fetch ((int) key2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+IndexMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2,
+ typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel)
+{
+ if (rel != Map2D<Key1_t, Key2_t, Value_t>::REL_EQEQ)
+ return (Value_t) 0;
+ return get (key1, key2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+IndexMap2D<Key1_t, Key2_t, Value_t>::remove (Key1_t key1, Key2_t key2)
+{
+ if (key1 < 0 || key1 >= map1->size () || key2 < 0)
+ return (Value_t) 0;
+ Vector<Value_t> *map2 = map1->fetch ((int) key1);
+ if (map2 == NULL || key2 >= map2->size ())
+ return (Value_t) 0;
+ Value_t res = map2->fetch ((int) key2);
+ map2->store ((int) key2, (Value_t) 0);
+ return res;
+}
+
+#endif
diff --git a/gprofng/src/IndexObject.cc b/gprofng/src/IndexObject.cc
new file mode 100644
index 0000000..a7c8a37
--- /dev/null
+++ b/gprofng/src/IndexObject.cc
@@ -0,0 +1,554 @@
+/* Copyright (C) 2021 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 <Histable *> *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 <Histable *> *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 ("<No Data>"));
+ }
+ }
+ 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 ("<No Data>"));
+ }
+ 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 ("<Unknown>"));
+ 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 ("<Unknown>"), (unsigned long long) id);
+ }
+ else if (strcasecmp (indexObj->name, NTXT ("Memory_lgrp")) == 0)
+ {
+ if (id == 0)
+ sb.append (GTXT ("<Unknown>"));
+ 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);
+}
diff --git a/gprofng/src/IndexObject.h b/gprofng/src/IndexObject.h
new file mode 100644
index 0000000..23f21d3
--- /dev/null
+++ b/gprofng/src/IndexObject.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _INDEXOBJECT_H
+#define _INDEXOBJECT_H
+
+#include "Histable.h"
+#include "Expression.h"
+
+class IndexObject : public Histable
+{
+public:
+ IndexObject (int _indextype, uint64_t _index);
+ IndexObject (int _indextype, Histable *_obj);
+ bool requires_string_sort (); // name column should be sorted using name text
+
+ virtual Histable_type
+ get_type ()
+ {
+ return INDEXOBJ;
+ }
+
+ virtual char *get_name (NameFormat = NA);
+ virtual void set_name (char*);
+ virtual void set_name_from_context (Expression::Context *);
+ virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+ virtual uint64_t
+ get_addr ()
+ {
+ return id;
+ }
+
+ uint64_t
+ get_index ()
+ {
+ return id;
+ }
+
+ Histable *
+ get_obj ()
+ {
+ return obj;
+ }
+
+ // for use in index object definitions
+ static const uint64_t INDXOBJ_EXPGRID_SHIFT = 60;
+ static const uint64_t INDXOBJ_EXPID_SHIFT = 32;
+ static const uint64_t INDXOBJ_PAYLOAD_SHIFT = 0;
+ static const uint64_t INDXOBJ_EXPGRID_MASK =
+ ((1LLU << (64 - INDXOBJ_EXPGRID_SHIFT)) - 1);
+ static const uint64_t INDXOBJ_EXPID_MASK =
+ ((1LLU << (INDXOBJ_EXPGRID_SHIFT - INDXOBJ_EXPID_SHIFT)) - 1);
+ static const uint64_t INDXOBJ_PAYLOAD_MASK =
+ ((1LLU << (INDXOBJ_EXPID_SHIFT - INDXOBJ_PAYLOAD_SHIFT)) - 1);
+
+private:
+
+ int indextype;
+ Histable *obj;
+ bool nameIsFinal;
+};
+
+typedef enum IndexObjTypes
+{
+ INDEX_THREADS = 0,
+ INDEX_CPUS,
+ INDEX_SAMPLES,
+ INDEX_GCEVENTS,
+ INDEX_SECONDS,
+ INDEX_PROCESSES,
+ INDEX_EXPERIMENTS,
+ INDEX_BYTES,
+ INDEX_DURATION,
+ INDEX_LAST // never used; marks the count of precompiled items
+} IndexObjTypes_t;
+
+class IndexObjType_t
+{
+public:
+ IndexObjType_t ();
+ ~IndexObjType_t ();
+ int type;
+ char *name; // used as input
+ char *i18n_name; // used for output
+ char *index_expr_str;
+ Expression *index_expr;
+ char mnemonic;
+ char *short_description;
+ char *long_description;
+ MemObjType_t *memObj;
+};
+
+#endif /* _INDEXOBJECT_H */
diff --git a/gprofng/src/IntervalMap.h b/gprofng/src/IntervalMap.h
new file mode 100644
index 0000000..8c20474
--- /dev/null
+++ b/gprofng/src/IntervalMap.h
@@ -0,0 +1,194 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * Interval Map implementation.
+ *
+ * Interval Map makes the following assumptions:
+ * - if duplicate keys, the last one will be stored
+ * - <TBC>
+ */
+#ifndef _DBE_INTERVALMAP_H
+#define _DBE_INTERVALMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+
+template <typename Key_t, typename Value_t>
+class IntervalMap : public Map<Key_t, Value_t>
+{
+public:
+
+ IntervalMap ();
+ ~IntervalMap ();
+ void put (Key_t key, Value_t val);
+ Value_t get (Key_t key);
+ Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
+ Value_t remove (Key_t key);
+
+private:
+
+ struct Entry
+ {
+ Key_t key;
+ Value_t val;
+ };
+
+ static const int CHUNK_SIZE;
+
+ int entries;
+ int nchunks;
+ Entry **chunks;
+ Vector<Entry*> *index;
+};
+
+template <typename Key_t, typename Value_t>
+const int IntervalMap<Key_t, Value_t>::CHUNK_SIZE = 16384;
+
+template <typename Key_t, typename Value_t>
+IntervalMap<Key_t, Value_t>::IntervalMap ()
+{
+ entries = 0;
+ nchunks = 0;
+ chunks = NULL;
+ index = new Vector<Entry*>;
+}
+
+template <typename Key_t, typename Value_t>
+IntervalMap<Key_t, Value_t>::~IntervalMap ()
+{
+ for (int i = 0; i < nchunks; i++)
+ delete[] chunks[i];
+ delete[] chunks;
+ delete index;
+}
+
+template <typename Key_t, typename Value_t>
+void
+IntervalMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+ int lo = 0;
+ int hi = entries - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ Entry *entry = index->fetch (md);
+ int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+ if (cmp < 0)
+ lo = md + 1;
+ else if (cmp > 0)
+ hi = md - 1;
+ else
+ {
+ entry->val = val;
+ return;
+ }
+ }
+
+ if (entries >= nchunks * CHUNK_SIZE)
+ {
+ nchunks++;
+ // Reallocate Entry chunk array
+ Entry **new_chunks = new Entry*[nchunks];
+ for (int i = 0; i < nchunks - 1; i++)
+ new_chunks[i] = chunks[i];
+ delete chunks;
+ chunks = new_chunks;
+
+ // Allocate new chunk for entries.
+ chunks[nchunks - 1] = new Entry[CHUNK_SIZE];
+ }
+ Entry *entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE];
+ entry->key = key;
+ entry->val = val;
+ index->insert (lo, entry);
+ entries++;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+IntervalMap<Key_t, Value_t>::get (Key_t key)
+{
+ return get (key, Map<Key_t, Value_t>::REL_EQ);
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+IntervalMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel)
+{
+ int lo = 0;
+ int hi = entries - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ Entry *entry = index->fetch (md);
+ int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+ switch (rel)
+ {
+ case Map<Key_t, Value_t>::REL_LT:
+ if (cmp < 0)
+ lo = md + 1;
+ else
+ hi = md - 1;
+ break;
+ case Map<Key_t, Value_t>::REL_GT:
+ if (cmp <= 0)
+ lo = md + 1;
+ else
+ hi = md - 1;
+ break;
+ case Map<Key_t, Value_t>::REL_LE:
+ case Map<Key_t, Value_t>::REL_GE:
+ case Map<Key_t, Value_t>::REL_EQ:
+ if (cmp < 0)
+ lo = md + 1;
+ else if (cmp > 0)
+ hi = md - 1;
+ else
+ return entry->val;
+ break;
+ }
+ }
+ switch (rel)
+ {
+ case Map<Key_t, Value_t>::REL_LT:
+ case Map<Key_t, Value_t>::REL_LE:
+ return hi >= 0 ? index->fetch (hi)->val : (Value_t) 0;
+ case Map<Key_t, Value_t>::REL_GT:
+ case Map<Key_t, Value_t>::REL_GE:
+ return lo < entries ? index->fetch (lo)->val : (Value_t) 0;
+ case Map<Key_t, Value_t>::REL_EQ:
+ break;
+ }
+ return (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+IntervalMap<Key_t, Value_t>::remove (Key_t)
+{
+ // Not implemented
+ if (1)
+ assert (0);
+ return (Value_t) 0;
+}
+
+#endif
diff --git a/gprofng/src/LoadObject.cc b/gprofng/src/LoadObject.cc
new file mode 100644
index 0000000..d9ce3e8
--- /dev/null
+++ b/gprofng/src/LoadObject.cc
@@ -0,0 +1,1242 @@
+/* Copyright (C) 2021 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 <errno.h>
+
+#include "util.h"
+#include "StringBuilder.h"
+#include "Application.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "Module.h"
+#include "ClassFile.h"
+#include "Stabs.h"
+#include "LoadObject.h"
+#include "dbe_types.h"
+#include "DbeFile.h"
+#include "ExpGroup.h"
+
+enum
+{
+ LO_InstHTableSize = 4096,
+ HTableSize = 1024
+};
+
+LoadObject *
+LoadObject::create_item (const char *nm, int64_t chksum)
+{
+ LoadObject *lo = new LoadObject (nm);
+ lo->checksum = chksum;
+ dbeSession->append (lo);
+ return lo;
+}
+
+LoadObject *
+LoadObject::create_item (const char *nm, const char *_runTimePath, DbeFile *df)
+{
+ LoadObject *lo = new LoadObject (nm);
+ lo->runTimePath = dbe_strdup (_runTimePath);
+ lo->dbeFile->orig_location = dbe_strdup (_runTimePath);
+ if (df)
+ {
+ if ((df->filetype & DbeFile::F_JAR_FILE) != 0)
+ {
+ if (lo->dbeFile->find_in_jar_file (nm, df->get_jar_file ()))
+ {
+ lo->dbeFile->inArchive = df->inArchive;
+ lo->dbeFile->container = df;
+ }
+ }
+ else
+ {
+ lo->dbeFile->set_location (df->get_location ());
+ lo->dbeFile->sbuf = df->sbuf;
+ lo->dbeFile->inArchive = df->inArchive;
+ }
+ }
+ dbeSession->append (lo);
+ return lo;
+}
+
+LoadObject::LoadObject (const char *loname)
+{
+ flags = 0;
+ size = 0;
+ type = SEG_UNKNOWN;
+ isReadStabs = false;
+ need_swap_endian = false;
+ instHTable = new DbeInstr*[LO_InstHTableSize];
+ for (int i = 0; i < LO_InstHTableSize; i++)
+ instHTable[i] = NULL;
+
+ functions = new Vector<Function*>;
+ funcHTable = new Function*[HTableSize];
+ for (int i = 0; i < HTableSize; i++)
+ funcHTable[i] = NULL;
+
+ seg_modules = new Vector<Module*>;
+ modules = new HashMap<char*, Module*>;
+ platform = Unknown;
+ noname = dbeSession->createUnknownModule (this);
+ modules->put (noname->get_name (), noname);
+ pathname = NULL;
+ arch_name = NULL;
+ runTimePath = NULL;
+ objStabs = NULL;
+ firstExp = NULL;
+ seg_modules_map = NULL;
+ comp_funcs = NULL;
+ warnq = new Emsgqueue (NTXT ("lo_warnq"));
+ commentq = new Emsgqueue (NTXT ("lo_commentq"));
+ elf_lo = NULL;
+ elf_inited = false;
+ checksum = 0;
+ isUsed = false;
+ h_function = NULL;
+ h_instr = NULL;
+
+ char *nm = (char *) loname;
+ if (strncmp (nm, NTXT ("./"), 2) == 0)
+ nm += 2;
+ set_name (nm);
+ dbeFile = new DbeFile (nm);
+ dbeFile->filetype |= DbeFile::F_LOADOBJ | DbeFile::F_FILE;
+}
+
+LoadObject::~LoadObject ()
+{
+ delete seg_modules_map;
+ delete functions;
+ delete[] instHTable;
+ delete[] funcHTable;
+ delete seg_modules;
+ delete modules;
+ delete elf_lo;
+ free (pathname);
+ free (arch_name);
+ free (runTimePath);
+ delete objStabs;
+ delete warnq;
+ delete commentq;
+ delete h_instr;
+}
+
+Elf *
+LoadObject::get_elf ()
+{
+ if (elf_lo == NULL)
+ {
+ if (dbeFile->get_need_refind ())
+ elf_inited = false;
+ if (elf_inited)
+ return NULL;
+ elf_inited = true;
+ char *fnm = dbeFile->get_location ();
+ if (fnm == NULL)
+ {
+ append_msg (CMSG_ERROR, GTXT ("Cannot find file: `%s'"),
+ dbeFile->get_name ());
+ return NULL;
+ }
+ Elf::Elf_status st = Elf::ELF_ERR_CANT_OPEN_FILE;
+ elf_lo = Elf::elf_begin (fnm, &st);
+ if (elf_lo == NULL)
+ switch (st)
+ {
+ case Elf::ELF_ERR_CANT_OPEN_FILE:
+ append_msg (CMSG_ERROR, GTXT ("Cannot open ELF file `%s'"), fnm);
+ break;
+ case Elf::ELF_ERR_BAD_ELF_FORMAT:
+ default:
+ append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"),
+ fnm);
+ break;
+ }
+ }
+ return elf_lo;
+}
+
+Stabs *
+LoadObject::openDebugInfo (char *fname, Stabs::Stab_status *stp)
+{
+ if (objStabs == NULL)
+ {
+ if (fname == NULL)
+ return NULL;
+ objStabs = new Stabs (fname, get_pathname ());
+ Stabs::Stab_status st = objStabs->get_status ();
+ if ((st == Stabs::DBGD_ERR_NONE) && (checksum != 0))
+ {
+ Elf *elf = get_elf ();
+ if (elf && (checksum != elf->elf_checksum ()))
+ {
+ char *buf = dbe_sprintf (GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"),
+ fname);
+ commentq->append (new Emsg (CMSG_ERROR, buf));
+ delete buf;
+ st = Stabs::DBGD_ERR_CHK_SUM;
+ }
+ }
+ if (stp)
+ *stp = st;
+ if (st != Stabs::DBGD_ERR_NONE)
+ {
+ delete objStabs;
+ objStabs = NULL;
+ }
+ }
+ return objStabs;
+}
+
+uint64_t
+LoadObject::get_addr ()
+{
+ return MAKE_ADDRESS (seg_idx, 0);
+}
+
+bool
+LoadObject::compare (const char *_path, int64_t _checksum)
+{
+ return _checksum == checksum && dbe_strcmp (_path, get_pathname ()) == 0;
+}
+
+int
+LoadObject::compare (const char *_path, const char *_runTimePath, DbeFile *df)
+{
+ int ret = 0;
+ if (dbe_strcmp (_path, get_pathname ()) != 0)
+ return ret;
+ ret |= CMP_PATH;
+ if (_runTimePath)
+ {
+ if (dbe_strcmp (_runTimePath, runTimePath) != 0)
+ return ret;
+ ret |= CMP_RUNTIMEPATH;
+ }
+ if (df && dbeFile->compare (df))
+ ret |= CMP_CHKSUM;
+ return ret;
+}
+
+void
+LoadObject::set_platform (Platform_t pltf, int wsz)
+{
+ switch (pltf)
+ {
+ case Sparc:
+ case Sparcv9:
+ case Sparcv8plus:
+ platform = (wsz == W64) ? Sparcv9 : Sparc;
+ break;
+ case Intel:
+ case Amd64:
+ platform = (wsz == W64) ? Amd64 : Intel;
+ break;
+ default:
+ platform = pltf;
+ break;
+ }
+};
+
+void
+LoadObject::set_name (char *string)
+{
+ char *p;
+ pathname = dbe_strdup (string);
+
+ p = get_basename (pathname);
+ if (p[0] == '<')
+ name = dbe_strdup (p);
+ else // set a short name to "<basename>"
+ name = dbe_sprintf (NTXT ("<%s>"), p);
+}
+
+void
+LoadObject::dump_functions (FILE *out)
+{
+ int index;
+ Function *fitem;
+ char *sname, *mname;
+ if (platform == Java)
+ {
+ JMethod *jmthd;
+ Vector<JMethod*> *jmethods = (Vector<JMethod*>*)functions;
+ Vec_loop (JMethod*, jmethods, index, jmthd)
+ {
+ fprintf (out, "id %6llu, @0x%llx sz-%lld %s (module = %s)\n",
+ (unsigned long long) jmthd->id, (long long) jmthd->get_mid (),
+ (long long) jmthd->size, jmthd->get_name (),
+ jmthd->module ? jmthd->module->file_name : noname->file_name);
+ }
+ }
+ else
+ {
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (fitem->alias && fitem->alias != fitem)
+ fprintf (out, "id %6llu, @0x%llx - %s == alias of '%s'\n",
+ (ull_t) fitem->id, (ull_t) fitem->img_offset,
+ fitem->get_name (), fitem->alias->get_name ());
+ else
+ {
+ mname = fitem->module ? fitem->module->file_name : noname->file_name;
+ sname = fitem->getDefSrcName ();
+ fprintf (out,
+ "id %6llu, @0x%llx - 0x%llx [save 0x%llx] o-%lld sz-%lld %s (module = %s)",
+ (ull_t) fitem->id, (ull_t) fitem->img_offset,
+ (ull_t) (fitem->img_offset + fitem->size),
+ (ull_t) fitem->save_addr, (ull_t) fitem->img_offset,
+ (ll_t) fitem->size, fitem->get_name (), mname);
+ if (sname && !streq (sname, mname))
+ fprintf (out, " (Source = %s)", sname);
+ fprintf (out, "\n");
+ }
+ }
+ }
+}
+
+int
+LoadObject::get_index (Function *func)
+{
+ Function *fp;
+ uint64_t offset;
+ int x;
+ int left = 0;
+ int right = functions->size () - 1;
+ offset = func->img_offset;
+ while (left <= right)
+ {
+ x = (left + right) / 2;
+ fp = functions->fetch (x);
+
+ if (left == right)
+ {
+ if (offset >= fp->img_offset + fp->size)
+ return -1;
+ if (offset >= fp->img_offset)
+ return x;
+ return -1;
+ }
+ if (offset < fp->img_offset)
+ right = x - 1;
+ else if (offset >= fp->img_offset + fp->size)
+ left = x + 1;
+ else
+ return x;
+ }
+ return -1;
+}
+
+char *
+LoadObject::get_alias (Function *func)
+{
+ Function *fp, *alias;
+ int index, nsize;
+ static char buf[1024];
+ if (func->img_offset == 0 || func->alias == NULL)
+ return NULL;
+ int fid = get_index (func);
+ if (fid == -1)
+ return NULL;
+
+ nsize = functions->size ();
+ alias = func->alias;
+ for (index = fid; index < nsize; index++)
+ {
+ fp = functions->fetch (index);
+ if (fp->alias != alias)
+ {
+ fid = index;
+ break;
+ }
+ }
+
+ *buf = '\0';
+ for (index--; index >= 0; index--)
+ {
+ fp = functions->fetch (index);
+ if (fp->alias != alias)
+ break;
+ if (fp != alias)
+ {
+ size_t len = strlen (buf);
+ if (*buf != '\0')
+ {
+ snprintf (buf + len, sizeof (buf) - len, NTXT (", "));
+ len = strlen (buf);
+ }
+ snprintf (buf + len, sizeof (buf) - len, "%s", fp->get_name ());
+ }
+ }
+ return buf;
+}
+
+DbeInstr*
+LoadObject::find_dbeinstr (uint64_t file_off)
+{
+ int hash = (((int) file_off) >> 2) & (LO_InstHTableSize - 1);
+ DbeInstr *instr = instHTable[hash];
+ if (instr && instr->img_offset == file_off)
+ return instr;
+ Function *fp = find_function (file_off);
+ if (fp == NULL)
+ fp = dbeSession->get_Unknown_Function ();
+ uint64_t func_off = file_off - fp->img_offset;
+ instr = fp->find_dbeinstr (0, func_off);
+ instHTable[hash] = instr;
+ return instr;
+}
+
+Function *
+LoadObject::find_function (uint64_t foff)
+{
+ // Look up in the hash table
+ int hash = (((int) foff) >> 6) & (HTableSize - 1);
+ Function *func = funcHTable[hash];
+ if (func && foff >= func->img_offset && foff < func->img_offset + func->size)
+ return func->alias ? func->alias : func;
+
+ // Use binary search
+ func = NULL;
+ int left = 0;
+ int right = functions->size () - 1;
+ while (left <= right)
+ {
+ int x = (left + right) / 2;
+ Function *fp = functions->fetch (x);
+ assert (fp != NULL);
+
+ if (foff < fp->img_offset)
+ right = x - 1;
+ else if (foff >= fp->img_offset + fp->size)
+ left = x + 1;
+ else
+ {
+ func = fp;
+ break;
+ }
+ }
+
+ // Plug the hole with a static function
+ char *func_name = NULL;
+ Size low_bound = 0, high_bound = 0;
+ if (func == NULL)
+ {
+ int last = functions->size () - 1;
+ uint64_t usize = (uint64_t) size;
+ if (foff >= usize)
+ {
+ // Cannot map to this LoadObject. Probably LoadObject was changed.
+ if (last >= 0 && functions->fetch (last)->img_offset == usize)
+ {
+ // Function is already created
+ func = functions->fetch (last);
+ if (func->size < 0 || (uint64_t) func->size < foff - usize)
+ func->size = foff - usize;
+ }
+ else
+ {
+ low_bound = size;
+ high_bound = foff;
+ func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) -- no functions found"),
+ low_bound, name);
+ }
+ }
+ else if (last < 0)
+ {
+ low_bound = 0;
+ high_bound = size;
+ func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) -- no functions found"),
+ low_bound, name);
+ }
+ else if (foff < functions->fetch (0)->img_offset)
+ {
+ low_bound = 0;
+ high_bound = functions->fetch (0)->img_offset;
+ }
+ else
+ {
+ Function *fp = functions->fetch (last);
+ if (foff >= fp->img_offset + fp->size)
+ {
+ low_bound = fp->img_offset + fp->size;
+ high_bound = size;
+ }
+ else
+ {
+ fp = functions->fetch (left);
+ if (foff >= fp->img_offset + fp->size)
+ {
+ low_bound = fp->img_offset + fp->size;
+ high_bound = functions->fetch (left + 1)->img_offset;
+ }
+ else
+ {
+ Function *fp1 = functions->fetch (left - 1);
+ low_bound = fp1->img_offset + fp1->size;
+ high_bound = fp->img_offset;
+ }
+ }
+ }
+ }
+
+ if (func == NULL)
+ {
+ func = dbeSession->createFunction ();
+ func->size = (unsigned) (high_bound - low_bound);
+ func->module = noname;
+ func->img_fname = get_pathname ();
+ func->img_offset = (off_t) low_bound;
+ noname->functions->append (func); // unordered
+ if (func_name == NULL)
+ func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"), low_bound,
+ name);
+ func->set_name (func_name);
+ free (func_name);
+
+ // now insert the function
+ functions->insert (left, func);
+ }
+
+ // Update the hash table
+ funcHTable[hash] = func;
+ return func->alias ? func->alias : func;
+}
+
+static void
+fixFuncAlias (Vector<Function*> *SymLst)
+{
+ int ind, i, k;
+ int64_t len, bestLen, maxSize;
+ Function *sym, *bestAlias;
+
+ // XXXX it is a clone of Stabs::fixSymtabAlias()
+ ind = SymLst->size () - 1;
+ for (i = 0; i < ind; i++)
+ {
+ bestAlias = SymLst->fetch (i);
+ if (bestAlias->img_offset == 0) // Ignore this bad symbol
+ continue;
+ sym = SymLst->fetch (i + 1);
+ if (bestAlias->img_offset != sym->img_offset)
+ {
+ if (bestAlias->size == 0
+ || sym->img_offset < bestAlias->img_offset + bestAlias->size)
+ bestAlias->size = (int) (sym->img_offset - bestAlias->img_offset);
+ continue;
+ }
+
+ // Find a "best" alias
+ bestLen = strlen (bestAlias->get_name ());
+ maxSize = bestAlias->size;
+ for (k = i + 1; k <= ind; k++)
+ {
+ sym = SymLst->fetch (k);
+ if (bestAlias->img_offset != sym->img_offset)
+ { // no more aliases
+ if ((maxSize == 0) ||
+ (sym->img_offset < bestAlias->img_offset + maxSize))
+ maxSize = sym->img_offset - bestAlias->img_offset;
+ break;
+ }
+ if (maxSize < sym->size)
+ maxSize = sym->size;
+ len = strlen (sym->get_name ());
+ if (len < bestLen)
+ {
+ bestAlias = sym;
+ bestLen = len;
+ }
+ }
+ for (; i < k; i++)
+ {
+ sym = SymLst->fetch (i);
+ sym->alias = bestAlias;
+ sym->size = maxSize;
+ }
+ i--;
+ }
+}
+
+void
+LoadObject::post_process_functions ()
+{
+ if (flags & SEG_FLAG_DYNAMIC || platform == Java)
+ return;
+
+ char *msg = GTXT ("Processing Load Object Data");
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (1, msg);
+
+ // First sort the functions
+ functions->sort (func_compare);
+ fixFuncAlias (functions);
+
+ Module *mitem;
+ int index;
+ Vec_loop (Module*, seg_modules, index, mitem)
+ {
+ mitem->functions->sort (func_compare);
+ }
+
+ // Find any derived functions, and set their derivedNode
+ Function *fitem;
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (dbeSession->is_interactive () && index % 5000 == 0)
+ {
+ int percent = (int) (100.0 * index / functions->size ());
+ theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+ }
+ fitem->findDerivedFunctions ();
+ }
+
+ // 4987698: get the alias name for MAIN_
+ fitem = find_function (NTXT ("MAIN_"));
+ if (fitem)
+ fitem->module->read_stabs ();
+ fitem = find_function (NTXT ("@plt"));
+ if (fitem)
+ fitem->flags |= FUNC_FLAG_PLT;
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (0, NTXT (""));
+}
+
+int
+LoadObject::func_compare (const void *p1, const void *p2)
+{
+ Function *f1 = *(Function **) p1;
+ Function *f2 = *(Function **) p2;
+ if (f1->img_offset != f2->img_offset)
+ return f1->img_offset > f2->img_offset ? 1 : -1;
+
+ // annotated source not available for weak symbols.
+ if ((f1->module->flags & MOD_FLAG_UNKNOWN) != 0)
+ {
+ if ((f2->module->flags & MOD_FLAG_UNKNOWN) == 0)
+ return -1;
+ }
+ else if ((f2->module->flags & MOD_FLAG_UNKNOWN) != 0)
+ return 1;
+ return strcoll (f1->get_name (), f2->get_name ());
+}
+
+Function *
+LoadObject::find_function (char *fname)
+{
+ Function *fitem;
+ int index;
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (strcmp (fitem->get_name (), fname) == 0)
+ return fitem;
+ }
+ return (Function *) NULL;
+}
+
+Function *
+LoadObject::find_function (char *fname, unsigned int chksum)
+{
+ Function *fitem;
+ int index;
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ if (fitem->chksum == chksum && strcmp (fitem->get_name (), fname) == 0)
+ return fitem;
+ }
+ return (Function *) NULL;
+}
+
+Module *
+LoadObject::find_module (char *mname)
+{
+ for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++)
+ {
+ Module *module = seg_modules->fetch (i);
+ if (strcmp (module->get_name (), mname) == 0)
+ return module;
+ }
+ return (Module *) NULL;
+}
+
+LoadObject::Arch_status
+LoadObject::sync_read_stabs ()
+{
+ Arch_status st = ARCHIVE_SUCCESS;
+ if (!isReadStabs)
+ {
+ aquireLock ();
+ if (!isReadStabs)
+ {
+ st = read_stabs ();
+ post_process_functions ();
+ isReadStabs = true;
+ }
+ releaseLock ();
+ }
+ return st;
+}
+
+LoadObject::Arch_status
+LoadObject::read_stabs ()
+{
+ if ((dbeFile->filetype & DbeFile::F_FICTION) != 0)
+ return ARCHIVE_SUCCESS;
+ Arch_status stabs_status = ARCHIVE_ERR_OPEN;
+ if (platform == Java)
+ {
+ Module *cf = NULL;
+ for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++)
+ {
+ Module *mod = seg_modules->fetch (i);
+ if (mod->dbeFile
+ && (mod->dbeFile->filetype & DbeFile::F_JAVACLASS) != 0)
+ {
+ cf = mod;
+ break;
+ }
+ }
+ if (cf)
+ {
+ int status = cf->readFile ();
+ switch (status)
+ {
+ case Module::AE_OK:
+ stabs_status = ARCHIVE_SUCCESS;
+ break;
+ case Module::AE_NOSTABS:
+ stabs_status = ARCHIVE_NO_STABS;
+ break;
+ case Module::AE_NOTREAD:
+ default:
+ stabs_status = ARCHIVE_ERR_OPEN;
+ break;
+ }
+ }
+ }
+ else if (strchr (pathname, '`'))
+ return ARCHIVE_SUCCESS;
+ else
+ {
+ Arch_status st = ARCHIVE_WRONG_ARCH;
+ Elf *elf = get_elf ();
+ if (elf == NULL)
+ {
+ if (read_archive () == 0)
+ st = ARCHIVE_SUCCESS;
+ else
+ {
+ char *msg = dbe_sprintf (GTXT ("*** Warning: Can't open file: %s"),
+ dbeFile->get_name ());
+ warnq->append (new Emsg (CMSG_ERROR, msg));
+ delete msg;
+ }
+ }
+ else if (checksum != 0 && checksum != elf->elf_checksum ())
+ {
+ if (read_archive () == 0)
+ st = ARCHIVE_SUCCESS;
+ else
+ {
+ char *msg = dbe_sprintf (
+ GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"),
+ dbeFile->get_location ());
+ commentq->append (new Emsg (CMSG_ERROR, msg));
+ delete msg;
+ }
+ }
+ if (st == ARCHIVE_SUCCESS) // An old archive is used
+ return st;
+
+ Stabs::Stab_status status = Stabs::DBGD_ERR_CANT_OPEN_FILE;
+ char *location = dbeFile->get_location (true);
+ if (location == NULL)
+ return ARCHIVE_ERR_OPEN;
+
+ if (openDebugInfo (location, &status))
+ {
+ status = objStabs->read_archive (this);
+ isRelocatable = objStabs->is_relocatable ();
+ size = objStabs->get_textsz ();
+ platform = objStabs->get_platform ();
+ wsize = objStabs->get_class ();
+ }
+
+ switch (status)
+ {
+ case Stabs::DBGD_ERR_NONE:
+ stabs_status = ARCHIVE_SUCCESS;
+ break;
+ case Stabs::DBGD_ERR_CANT_OPEN_FILE:
+ stabs_status = ARCHIVE_ERR_OPEN;
+ break;
+ case Stabs::DBGD_ERR_BAD_ELF_LIB:
+ case Stabs::DBGD_ERR_BAD_ELF_FORMAT:
+ stabs_status = ARCHIVE_BAD_STABS;
+ break;
+ case Stabs::DBGD_ERR_NO_STABS:
+ stabs_status = ARCHIVE_NO_STABS;
+ break;
+ case Stabs::DBGD_ERR_NO_DWARF:
+ stabs_status = ARCHIVE_NO_DWARF;
+ break;
+ default:
+ stabs_status = ARCHIVE_BAD_STABS;
+ break;
+ }
+ }
+ return stabs_status;
+}
+
+#define ARCH_STRLEN(s) ((strlen(s) + 4) & ~0x3 )
+
+static int
+offsetCmp (const void *a, const void *b)
+{
+ uint32_t o1 = ((inst_info_t *) a)->offset;
+ uint32_t o2 = ((inst_info_t *) b)->offset;
+ return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+int
+LoadObject::read_archive ()
+{
+ if (arch_name == NULL)
+ return 1;
+ Module *mod = NULL;
+ Function *func = NULL;
+ char *buf;
+ Data_window *dwin = new Data_window (arch_name);
+ if (dwin->not_opened ())
+ {
+ delete dwin;
+ buf = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s: %s"),
+ arch_name, strerror (errno));
+ warnq->append (new Emsg (CMSG_ERROR, buf));
+ delete buf;
+ return 1;
+ }
+ dwin->need_swap_endian = need_swap_endian;
+
+ // Prevent reading earlier archive files, which didn't support versioning.
+ int64_t offset = 0;
+ ARCH_common *cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common));
+ uint16_t v16;
+ if (cpkt)
+ {
+ v16 = (uint16_t) cpkt->type;
+ if (dwin->decode (v16) != ARCH_SEGMENT)
+ cpkt = NULL;
+ }
+ if (cpkt == NULL)
+ {
+ buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name);
+ warnq->append (new Emsg (CMSG_WARN, buf));
+ delete buf;
+ return 1;
+ }
+
+ char *msg = NULL;
+ unsigned long long pointer_invalid = 0;
+ for (int64_t last_offset = -5000;;)
+ {
+ cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common));
+ if (cpkt == NULL)
+ break;
+ v16 = (uint16_t) cpkt->size;
+ uint32_t cpktsize = dwin->decode (v16);
+ cpkt = (ARCH_common*) dwin->bind (offset, cpktsize);
+ if ((cpkt == NULL) || (cpktsize == 0))
+ {
+ buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name);
+ warnq->append (new Emsg (CMSG_WARN, buf));
+ delete buf;
+ break;
+ }
+
+ // Update the progress bar
+ if (dbeSession->is_interactive () && ((offset - last_offset) >= 5000))
+ {
+ last_offset = offset;
+ int percent = (int) (100.0 * offset / dwin->get_fsize ());
+ if (msg == NULL)
+ msg = dbe_sprintf (GTXT ("Reading Load Object Data: %s"), name);
+ theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+ }
+ char *ptr = (char *) cpkt;
+ v16 = (uint16_t) cpkt->type;
+ switch (dwin->decode (v16))
+ {
+ case ARCH_SEGMENT:
+ {
+ ARCH_segment *aseg = (ARCH_segment*) cpkt;
+ if (dwin->decode (aseg->version) != ARCH_VERSION)
+ {
+ buf = dbe_sprintf (GTXT ("Archive file version mismatch for %s"), arch_name);
+ warnq->append (new Emsg (CMSG_ERROR, buf));
+ delete buf;
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (0, "");
+ return 1;
+ }
+ if (size == 0)
+ size = dwin->decode (aseg->textsz);
+ Platform_t pltf = (Platform_t) dwin->decode (aseg->platform);
+ if (pltf != Unknown)
+ {
+ platform = pltf; // override if known
+ wsize = (platform == Sparcv9 || platform == Amd64) ? W64 : W32;
+ }
+ break;
+ }
+ case ARCH_MSG:
+ {
+ ARCH_message *amsg = (ARCH_message*) cpkt;
+ buf = status_str ((Arch_status) dwin->decode (amsg->errcode));
+ commentq->append (new Emsg (CMSG_ARCHIVE, buf));
+ free (buf);
+ break;
+ }
+ case ARCH_INF:
+ {
+ ARCH_info *ainf = (ARCH_info*) cpkt;
+ Emsg *m = new Emsg (CMSG_ARCHIVE, (char*) (ainf + 1));
+ commentq->append (m);
+ break;
+ }
+ case ARCH_MODULE:
+ {
+ ARCH_module *amod = (ARCH_module*) cpkt;
+ char *str = ((char*) amod) + sizeof (ARCH_module);
+ if (streq (str, SP_UNKNOWN_NAME) &&
+ streq (str + ARCH_STRLEN (str), SP_UNKNOWN_NAME))
+ {
+ mod = noname;
+ break;
+ }
+ mod = dbeSession->createModule (this, str);
+ mod->lang_code = (Sp_lang_code) dwin->decode (amod->lang_code);
+ mod->fragmented = dwin->decode (amod->fragmented);
+ str += ARCH_STRLEN (str);
+ mod->set_file_name (dbe_strdup (str));
+ modules->put (get_basename (str), mod);
+ break;
+ }
+ case ARCH_FUNCTION:
+ {
+ if (mod == NULL)
+ break;
+ ARCH_function *afnc = (ARCH_function*) cpkt;
+ func = dbeSession->createFunction ();
+ func->img_offset = dwin->decode (afnc->offset);
+ func->size = dwin->decode (afnc->size);
+ func->save_addr = dwin->decode (afnc->save_addr)
+ - dwin->decode (afnc->offset);
+ func->module = mod;
+ func->set_name (((char*) afnc) + sizeof (ARCH_function));
+ mod->functions->append (func);
+ functions->append (func);
+ break;
+ }
+ case ARCH_LDINSTR:
+ if (mod == NULL)
+ break;
+ Dprintf (DEBUG_LOADOBJ, "LDINSTR list for %s\n", mod->get_name ());
+ if (mod->infoList == NULL)
+ mod->infoList = new Vector<inst_info_t*>;
+ for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+ (char*) mp < ptr + cpktsize; mp++)
+ {
+ memop_info_t *memop = new memop_info_t;
+ memop->offset = dwin->decode (mp->offset);
+ memop->id = dwin->decode (mp->id);
+ memop->signature = dwin->decode (mp->signature);
+ memop->datatype_id = dwin->decode (mp->datatype_id);
+ mod->ldMemops.append (memop);
+
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_LD;
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ mod->infoList->incorporate (instop, offsetCmp);
+ Dprintf (DEBUG_LOADOBJ,
+ "ld: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+ memop->offset, memop->id, memop->signature,
+ memop->datatype_id);
+ }
+ Dprintf (DEBUG_LOADOBJ, "LDINSTR list of %lld for %s\n",
+ (long long) mod->ldMemops.size (), mod->get_name ());
+ break;
+ case ARCH_STINSTR:
+ if (mod == NULL)
+ break;
+ Dprintf (DEBUG_LOADOBJ, NTXT ("STINSTR list for %s\n"), mod->get_name ());
+ if (mod->infoList == NULL)
+ mod->infoList = new Vector<inst_info_t*>;
+ for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+ ((char *) mp) < ptr + cpktsize; mp++)
+ {
+ memop_info_t *memop = new memop_info_t;
+ memop->offset = dwin->decode (mp->offset);
+ memop->id = dwin->decode (mp->id);
+ memop->signature = dwin->decode (mp->signature);
+ memop->datatype_id = dwin->decode (mp->datatype_id);
+ mod->stMemops.append (memop);
+
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_ST;
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ mod->infoList->incorporate (instop, offsetCmp);
+ Dprintf (DEBUG_LOADOBJ,
+ "st: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+ memop->offset, memop->id, memop->signature,
+ memop->datatype_id);
+ }
+ Dprintf (DEBUG_LOADOBJ, "STINSTR list of %lld for %s\n",
+ (long long) mod->stMemops.size (), mod->get_name ());
+ break;
+ case ARCH_PREFETCH:
+ if (mod == NULL)
+ break;
+ Dprintf (DEBUG_LOADOBJ, "PFINSTR list for %s\n", mod->get_name ());
+ if (mod->infoList == NULL)
+ mod->infoList = new Vector<inst_info_t*>;
+ for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+ ((char*) mp) < ptr + cpkt->size; mp++)
+ {
+ memop_info_t *memop = new memop_info_t;
+ memop->offset = dwin->decode (mp->offset);
+ memop->id = dwin->decode (mp->id);
+ memop->signature = dwin->decode (mp->signature);
+ memop->datatype_id = dwin->decode (mp->datatype_id);
+ mod->pfMemops.append (memop);
+
+ inst_info_t *instop = new inst_info_t;
+ instop->type = CPF_INSTR_TYPE_PREFETCH;
+ instop->offset = memop->offset;
+ instop->memop = memop;
+ mod->infoList->incorporate (instop, offsetCmp);
+ Dprintf (DEBUG_LOADOBJ,
+ "pf: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+ memop->offset, memop->id, memop->signature,
+ memop->datatype_id);
+ }
+ Dprintf (DEBUG_LOADOBJ, "PFINSTR list of %lld for %s\n",
+ (long long) mod->pfMemops.size (), mod->get_name ());
+ break;
+ case ARCH_BRTARGET:
+ if (mod == NULL)
+ break;
+ for (target_info_t *tp = (target_info_t*) (ptr + sizeof (ARCH_aninfo));
+ ((char*) tp) < ptr + cpkt->size; tp++)
+ {
+ target_info_t *bTarget = new target_info_t;
+ bTarget->offset = dwin->decode (tp->offset);
+ mod->bTargets.append (bTarget);
+ }
+ Dprintf (DEBUG_LOADOBJ, "BRTARGET list of %lld for %s\n",
+ (long long) mod->infoList->size (), mod->get_name ());
+ break;
+ default:
+ /* Check if the prointer is valid - should be even. */
+ pointer_invalid = (unsigned long long) (offset + cpktsize) & 1;
+ break; // ignore unknown packets
+ }
+ if (pointer_invalid)
+ break;
+ offset += cpktsize;
+ }
+ delete msg;
+ delete dwin;
+
+ if (dbeSession->is_interactive ())
+ theApplication->set_progress (0, NTXT (""));
+ return 0;
+}
+
+char *
+LoadObject::status_str (Arch_status rv, char */*arg*/)
+{
+ switch (rv)
+ {
+ case ARCHIVE_SUCCESS:
+ case ARCHIVE_EXIST:
+ return NULL;
+ case ARCHIVE_BAD_STABS:
+ return dbe_sprintf (GTXT ("Error: unable to read symbol table of %s"),
+ name);
+ case ARCHIVE_ERR_SEG:
+ return dbe_sprintf (GTXT ("Error: unable to read load object file %s"),
+ pathname);
+ case ARCHIVE_ERR_OPEN:
+ return dbe_sprintf (GTXT ("Error: unable to open file %s"),
+ pathname);
+ case ARCHIVE_ERR_MAP:
+ return dbe_sprintf (GTXT ("Error: unable to map file %s"),
+ pathname);
+ case ARCHIVE_WARN_CHECKSUM:
+ return dbe_sprintf (GTXT ("Note: checksum differs from that recorded in experiment for %s"),
+ name);
+ case ARCHIVE_WARN_MTIME:
+ return dbe_sprintf (GTXT ("Warning: last-modified time differs from that recorded in experiment for %s"),
+ name);
+ case ARCHIVE_WARN_HOST:
+ return dbe_sprintf (GTXT ("Try running er_archive -F on the experiment, on the host where it was recorded"));
+ case ARCHIVE_ERR_VERSION:
+ return dbe_sprintf (GTXT ("Error: Wrong version of archive for %s"),
+ pathname);
+ case ARCHIVE_NO_STABS:
+ return dbe_sprintf (GTXT ("Note: no stabs or dwarf information in %s"),
+ name);
+ case ARCHIVE_WRONG_ARCH:
+#if ARCH(SPARC)
+ return dbe_sprintf (GTXT ("Error: file %s is built for Intel, and can't be read on SPARC"),
+ name);
+#else
+ return dbe_sprintf (GTXT ("Error: file %s is built for SPARC, and can't be read on Intel"),
+ name);
+#endif
+ case ARCHIVE_NO_LIBDWARF:
+ return dbe_strdup (GTXT ("Warning: no libdwarf found to read DWARF symbol tables"));
+ case ARCHIVE_NO_DWARF:
+ return dbe_sprintf (GTXT ("Note: no DWARF symbol table in %s"), name);
+ default:
+ return dbe_sprintf (GTXT ("Warning: unexpected archive error %d"),
+ (int) rv);
+ }
+}
+
+uint32_t
+LoadObject::get_checksum ()
+{
+ char *errmsg = NULL;
+ uint32_t crcval = get_cksum (pathname, &errmsg);
+ if (0 == crcval && errmsg)
+ {
+ warnq->append (new Emsg (CMSG_ERROR, errmsg));
+ free (errmsg);
+ }
+ return crcval;
+}
+
+static char*
+get_module_map_key (Module *mod)
+{
+ return mod->lang_code == Sp_lang_java ? mod->get_name () : mod->file_name;
+}
+
+Module *
+LoadObject::get_comparable_Module (Module *mod)
+{
+ if (mod->loadobject == this)
+ return mod;
+ if (get_module_map_key (mod) == NULL)
+ return NULL;
+ if (seg_modules_map == NULL)
+ {
+ seg_modules_map = new HashMap<char*, Module*>;
+ for (int i = 0; i < seg_modules->size (); i++)
+ {
+ Module *m = seg_modules->fetch (i);
+ char *key = get_module_map_key (m);
+ if (key)
+ {
+ seg_modules_map->put (m->file_name, m);
+ char *bname = get_basename (key);
+ if (bname != key)
+ seg_modules_map->put (bname, m);
+ }
+ }
+ }
+
+ char *key = get_module_map_key (mod);
+ Module *cmpMod = seg_modules_map->get (key);
+ if (cmpMod && cmpMod->comparable_objs == NULL)
+ return cmpMod;
+ char *bname = get_basename (key);
+ if (bname != key)
+ {
+ cmpMod = seg_modules_map->get (bname);
+ if (cmpMod && cmpMod->comparable_objs == NULL)
+ return cmpMod;
+ }
+ return NULL;
+}
+
+Vector<Histable*> *
+LoadObject::get_comparable_objs ()
+{
+ update_comparable_objs ();
+ if (comparable_objs || dbeSession->expGroups->size () <= 1)
+ return comparable_objs;
+ comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
+ for (int i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
+ {
+ ExpGroup *gr = dbeSession->expGroups->fetch (i);
+ Histable *h = gr->get_comparable_loadObject (this);
+ comparable_objs->append (h);
+ if (h)
+ h->comparable_objs = comparable_objs;
+ }
+ dump_comparable_objs ();
+ return comparable_objs;
+}
+
+void
+LoadObject::append_module (Module *mod)
+{
+ seg_modules->append (mod);
+ if (seg_modules_map == NULL)
+ seg_modules_map = new HashMap<char*, Module*>;
+ char *key = get_module_map_key (mod);
+ if (key)
+ {
+ seg_modules_map->put (key, mod);
+ char *bname = get_basename (key);
+ if (bname != key)
+ seg_modules_map->put (bname, mod);
+ }
+}
+
+// LIBRARY_VISIBILITY
+Function *
+LoadObject::get_hide_function ()
+{
+ if (h_function == NULL)
+ h_function = dbeSession->create_hide_function (this);
+ return h_function;
+}
+
+DbeInstr *
+LoadObject::get_hide_instr (DbeInstr *instr)
+{
+ if (h_instr == NULL)
+ {
+ Function *hf = get_hide_function ();
+ h_instr = hf->create_hide_instr (instr);
+ }
+ return h_instr;
+}
diff --git a/gprofng/src/LoadObject.h b/gprofng/src/LoadObject.h
new file mode 100644
index 0000000..0c997e3
--- /dev/null
+++ b/gprofng/src/LoadObject.h
@@ -0,0 +1,210 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _LOADOBJECT_H
+#define _LOADOBJECT_H
+
+// A Segment object represents a segment of the program text.
+
+#include "Histable.h"
+#include "Stabs.h"
+#include "DbeLock.h"
+
+#define JAVA_COMPILED_METHODS "JAVA_COMPILED_METHODS"
+#define DYNFUNC_SEGMENT "DYNAMIC_FUNCTIONS"
+#define SEG_FLAG_DYNAMIC 0x01
+#define SEG_FLAG_JVM 0x02
+#define SEG_FLAG_OMP 0x04
+#define SEG_FLAG_EXE 0x08
+#define SEG_FLAG_REORDER 0x10
+
+/* Hash name for all comparable executions */
+#define COMP_EXE_NAME "<COMP_EXE_NAME>"
+
+class Emsg;
+class Elf;
+class Experiment;
+class Function;
+class Module;
+template <typename Key_t, typename Value_t> class HashMap;
+template <typename Key_t, typename Value_t> class Map;
+template <class ITEM> class Vector;
+
+enum
+{
+ CMP_PATH = 1,
+ CMP_RUNTIMEPATH = 2,
+ CMP_CHKSUM = 4
+};
+
+class LoadObject : public HistableFile, public DbeLock
+{
+public:
+
+ // The various segments types.
+ enum seg_type
+ {
+ SEG_TEXT,
+ SEG_DATA,
+ SEG_BSS,
+ SEG_HEAP,
+ SEG_STACK,
+ SEG_DEVICE,
+ SEG_UNKNOWN
+ };
+
+ // These codes are stored in *.archive files
+ enum Arch_status
+ {
+ ARCHIVE_SUCCESS,
+ ARCHIVE_EXIST,
+ ARCHIVE_BAD_STABS,
+ ARCHIVE_ERR_SEG,
+ ARCHIVE_ERR_OPEN,
+ ARCHIVE_ERR_MAP,
+ ARCHIVE_WARN_MTIME,
+ ARCHIVE_WARN_HOST,
+ ARCHIVE_ERR_VERSION,
+ ARCHIVE_NO_STABS,
+ ARCHIVE_WRONG_ARCH,
+ ARCHIVE_NO_LIBDWARF,
+ ARCHIVE_NO_DWARF,
+ ARCHIVE_WARN_CHECKSUM
+ };
+
+ LoadObject (const char *loname);
+
+ static LoadObject *create_item (const char *nm, int64_t chksum);
+ static LoadObject *create_item (const char *nm, const char *_runTimePath, DbeFile *df);
+
+ virtual ~LoadObject ();
+ virtual void set_name (char *string);
+ virtual uint64_t get_addr ();
+ virtual Vector<Histable*> *get_comparable_objs ();
+
+ virtual Histable_type
+ get_type ()
+ {
+ return LOADOBJECT;
+ };
+
+ virtual int64_t
+ get_size ()
+ {
+ return size;
+ }
+
+ char *
+ get_pathname ()
+ {
+ return pathname;
+ }
+
+ void
+ set_archname (char *aname)
+ {
+ free (arch_name);
+ arch_name = aname;
+ }
+
+ bool
+ is_relocatable ()
+ {
+ return isRelocatable;
+ }
+
+ bool compare (const char *nm, int64_t _checksum);
+ int compare (const char *_path, const char *_runTimePath, DbeFile *df);
+ void set_platform (Platform_t pltf, int wsz);
+ void dump_functions (FILE *);
+ int get_index (Function *func);
+ char *get_alias (Function *func);
+ DbeInstr *find_dbeinstr (uint64_t file_off);
+ Function *find_function (uint64_t offset);
+ Function *find_function (char *fname);
+ Function *find_function (char *fname, unsigned int chksum);
+ Module *find_module (char *mname);
+ Module *get_comparable_Module (Module *mod);
+ void append_module (Module *mod);
+ Elf *get_elf ();
+ Stabs *openDebugInfo (char *fname, Stabs::Stab_status *stp = NULL);
+ Arch_status read_stabs ();
+ Arch_status sync_read_stabs ();
+ void post_process_functions ();
+ char *status_str (Arch_status rv, char *arg = NULL);
+ Function *get_hide_function ();
+ DbeInstr *get_hide_instr (DbeInstr *instr);
+ uint32_t get_checksum ();
+
+ Emsg *
+ fetch_warnings (void) // fetch the queue of warning messages
+ {
+ return warnq->fetch ();
+ }
+
+ Emsg *
+ fetch_comments (void) // fetch the queue of comment messages
+ {
+ return commentq->fetch ();
+ }
+
+ unsigned int flags; // SEG_FLAG_*
+ bool isReadStabs;
+ bool need_swap_endian;
+ int seg_idx; // for compatibility (ADDRESS)
+ seg_type type;
+ int64_t size; // size of loadobject in bytes
+ int64_t max_size; // Maximum size of loadobject in bytes
+ int64_t min_size; // Min size of loadobject in bytes.
+ Vector<Function*> *functions; // Ordered list of functions
+ Vector<Module*> *seg_modules; // list of modules
+ HashMap<char*, Module*> *modules;
+ Module *noname; // Module pointer to unknown name
+ Platform_t platform; // Sparc, Sparcv9, Intel
+ WSize_t wsize; // word size: 32,64
+ Stabs *objStabs;
+ HashMap<char*, Function*> *comp_funcs; // list of comparable functions
+ Experiment *firstExp;
+ char *runTimePath;
+ time_t mtime; // file timestamp (in seconds)
+ int64_t checksum; // file checksum
+
+private:
+ Elf *elf_lo;
+ bool elf_inited;
+ DbeInstr **instHTable; // hash table for DbeInstr
+ char *pathname; // User name of object file
+ ino64_t inode; // inode number of segment file
+ bool isRelocatable; // is relocatable .o
+ char *arch_name; // .archive name
+ Emsgqueue *warnq;
+ Emsgqueue *commentq;
+ Function **funcHTable; // hash table for functions
+ Function *h_function; // hide pseudo function
+ DbeInstr *h_instr; // hide pseudo instr
+ HashMap<char*, Module*> *seg_modules_map; // to find a comparable module
+
+ static int func_compare (const void *p1, const void *p2);
+ int read_archive ();
+ void init_datatypes ();
+ void update_datatypes (Module*, Vaddr, uint32_t datatype_id);
+};
+
+#endif /* _LOADOBJECT_H */
diff --git a/gprofng/src/MachineModel.cc b/gprofng/src/MachineModel.cc
new file mode 100644
index 0000000..15f493a
--- /dev/null
+++ b/gprofng/src/MachineModel.cc
@@ -0,0 +1,317 @@
+/* Copyright (C) 2021 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 <string.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "DbeSession.h"
+#include "Command.h"
+#include "Application.h"
+#include "MemorySpace.h"
+#include "i18n.h"
+
+#define MAXARGS 20
+
+static const char *LIBNAME = "../lib/analyzer/lib/machinemodels";
+
+char *
+DbeSession::find_mach_model (char *name)
+{
+ // Read current working directory to see if it's there
+ if (name[0] == '/')
+ {
+ // Absolute path given
+ char *path = dbe_sprintf (NTXT ("%s.ermm"), name);
+ if (access (path, R_OK | F_OK) == 0)
+ return path;
+ free (path);
+ // Don't try anywhere else
+ return NULL;
+ }
+
+ char *path = dbe_sprintf (NTXT ("./%s.ermm"), name);
+ if (access (path, R_OK | F_OK) == 0)
+ return path;
+ free (path);
+
+
+ // Read the user's home directory to see if it's there
+ char *home = getenv (NTXT ("HOME"));
+ if (home != NULL)
+ {
+ path = dbe_sprintf (NTXT ("%s/%s.ermm"), home, name);
+ if (access (path, R_OK | F_OK) == 0)
+ return path;
+ free (path);
+ }
+ if (strchr (name, (int) '/') != NULL)
+ // name has a slash; don't look in system installation directory
+ return NULL;
+
+ // Read system installation directory to see if it's there
+ path = dbe_sprintf ("%s/%s/%s.ermm", theApplication->get_run_dir (),
+ LIBNAME, name);
+ if (access (path, R_OK | F_OK) == 0)
+ return path;
+ free (path);
+ return NULL;
+}
+
+// Handle the definitions from a machinemodel file
+// Return value is NULL if it was OK, or an error message if not
+char *
+DbeSession::load_mach_model (char *_name)
+{
+ CmdType cmd_type;
+ int arg_count, cparam;
+ char *cmd, *end_cmd;
+ char *arglist[MAXARGS];
+ char *ret = NULL;
+ char *path = NULL;
+ FILE *fptr = NULL;
+
+ // Does name have .ermm suffix? If so, strip it away
+ char *name = dbe_strdup (_name);
+ size_t len = strlen (name);
+ if (len > 5 && strcmp (name + len - 5, ".ermm") == 0)
+ name[len - 5] = 0;
+
+ if ((mach_model_loaded != NULL) && (strcmp (name, mach_model_loaded) == 0))
+ {
+ ret = dbe_sprintf (GTXT ("Machine model %s is already loaded\n"), name);
+ free (name);
+ return ret;
+ }
+ else if (mach_model_loaded == NULL && len == 0)
+ {
+ ret = dbe_sprintf (GTXT ("No Machine model is loaded\n"));
+ free (name);
+ return ret;
+ }
+
+ if (len != 0)
+ {
+ // zero-length just means unload any previously loaded model; only look if non-zero
+ path = find_mach_model (name);
+ if (path == NULL)
+ {
+ ret = dbe_sprintf (GTXT ("Machine model %s not found\n"), name);
+ free (name);
+ return ret;
+ }
+ fptr = fopen (path, NTXT ("r"));
+ if (fptr == NULL)
+ {
+ ret = dbe_sprintf (GTXT ("Open of Machine model %s, file %s failed\n"), name, path);
+ free (path);
+ free (name);
+ return ret;
+ }
+ }
+
+ // We are now committed to make the new machine model the loaded one;
+ // Delete any MemoryObjects from any previously loaded machinemodel
+ if (dbeSession->mach_model_loaded != NULL)
+ {
+ Vector <char *> *oldobjs = MemorySpace::getMachineModelMemObjs
+ (dbeSession->mach_model_loaded);
+ for (int i = 0; i < oldobjs->size (); i++)
+ MemorySpace::mobj_delete (oldobjs->fetch (i));
+ delete oldobjs;
+ free (mach_model_loaded);
+ }
+ if (len == 0)
+ {
+ mach_model_loaded = NULL;
+ free (name);
+ // and there's no "loading" to do; just return
+ return NULL;
+ }
+ else
+ mach_model_loaded = name;
+
+ int line_no = 0;
+ end_cmd = NULL;
+
+ while (!feof (fptr))
+ {
+ char *script = read_line (fptr);
+ if (script == NULL)
+ continue;
+
+ line_no++;
+ strtok (script, NTXT ("\n"));
+
+ // extract the command
+ cmd = strtok (script, NTXT (" \t"));
+ if (cmd == NULL || *cmd == '#' || *cmd == '\n')
+ {
+ free (script);
+ continue;
+ }
+
+ char *remainder = strtok (NULL, NTXT ("\n"));
+ // now extract the arguments
+ int nargs = 0;
+ for (;;)
+ {
+ if (nargs >= MAXARGS)
+ {
+ ret = dbe_sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
+ MAXARGS, cmd, line_no);
+ continue;
+ }
+
+ char *nextarg = strtok (remainder, NTXT ("\n"));
+
+ if (nextarg == NULL || *nextarg == '#')
+ // either the end of the line, or a comment indicator
+ break;
+ arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
+ remainder = end_cmd;
+ if (remainder == NULL)
+ break;
+
+ // skip any blanks or tabs to get to next argument
+ while ((*remainder == ' ') || (*remainder == '\t'))
+ remainder++;
+ }
+
+ cmd_type = Command::get_command (cmd, arg_count, cparam);
+ // check for extra arguments
+ if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
+ ret = dbe_sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"),
+ cmd, line_no);
+ if (nargs < arg_count)
+ {
+ ret = dbe_sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"),
+ cmd, line_no);
+
+ // ignore this command
+ free (script);
+ continue;
+ }
+
+ switch (cmd_type)
+ {
+ case INDXOBJDEF:
+ {
+ char *err = dbeSession->indxobj_define (arglist[0], NULL,
+ arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL,
+ (nargs >= 4) ? PTXT (arglist[3]) : NULL);
+ if (err != NULL)
+ ret = dbe_sprintf (GTXT (" %s: line %d `%s %s %s'\n"),
+ err, line_no, cmd, arglist[0], arglist[1]);
+ break;
+ }
+ case COMMENT:
+ // ignore the line
+ break;
+ default:
+ {
+ // unexpected command in a machinemodel file
+ ret = dbe_sprintf (GTXT ("Unexpected command in machinemodel file %s on line %d: `%.64s'\n"),
+ path, line_no, cmd);
+ break;
+ }
+ }
+ free (script);
+ }
+ fclose (fptr);
+ return ret;
+}
+
+Vector<char*> *
+DbeSession::list_mach_models ()
+{
+ Vector<char*> *model_names = new Vector<char*>();
+
+ // Open the current directory to read the entries there
+ DIR *dir = opendir (NTXT ("."));
+ if (dir != NULL)
+ {
+ struct dirent *entry = NULL;
+ while ((entry = readdir (dir)) != NULL)
+ {
+ size_t len = strlen (entry->d_name);
+ if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
+ continue;
+ char *model = dbe_strdup (entry->d_name);
+
+ // remove the .ermm suffix
+ model[len - 5] = 0;
+
+ // add to vector
+ model_names->append (dbe_strdup (model));
+ }
+ closedir (dir);
+ }
+
+ // Read the user's home directory to list the models there
+ char *home = getenv ("HOME");
+ if (home != NULL)
+ {
+ dir = opendir (home);
+ if (dir != NULL)
+ {
+ struct dirent *entry = NULL;
+ while ((entry = readdir (dir)) != NULL)
+ {
+ size_t len = strlen (entry->d_name);
+ if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
+ continue;
+ char *model = dbe_strdup (entry->d_name);
+
+ // remove the .ermm suffix
+ model[len - 5] = 0;
+
+ // add to vector
+ model_names->append (dbe_strdup (model));
+ }
+ closedir (dir);
+ }
+ }
+
+ // Read system installation directory to list the models there
+ char *sysdir = dbe_sprintf ("%s/%s", theApplication->get_run_dir (), LIBNAME);
+
+ dir = opendir (sysdir);
+ if (dir != NULL)
+ {
+ struct dirent *entry = NULL;
+ while ((entry = readdir (dir)) != NULL)
+ {
+ size_t len = strlen (entry->d_name);
+ if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
+ continue;
+ char *model = dbe_strdup (entry->d_name);
+
+ // remove the .ermm suffix
+ model[len - 5] = 0;
+
+ // add to vector
+ model_names->append (dbe_strdup (model));
+ }
+ closedir (dir);
+ }
+ return model_names;
+}
diff --git a/gprofng/src/Makefile.am b/gprofng/src/Makefile.am
new file mode 100644
index 0000000..b874b5b
--- /dev/null
+++ b/gprofng/src/Makefile.am
@@ -0,0 +1,202 @@
+## Process this file with automake to generate Makefile.in
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I . -I .. -I ../..
+
+CCSOURCES = \
+ Application.cc \
+ BaseMetric.cc \
+ BaseMetricTreeNode.cc \
+ CallStack.cc \
+ CatchOutOfMemory.cc \
+ ClassFile.cc \
+ Command.cc \
+ CompCom.cc \
+ DataObject.cc \
+ DataSpace.cc \
+ Data_window.cc \
+ DataStream.cc \
+ DbeApplication.cc \
+ DbeFile.cc \
+ DbeJarFile.cc \
+ DbeLock.cc \
+ DbeSession.cc \
+ DbeThread.cc \
+ DbeView.cc \
+ DerivedMetrics.cc \
+ Disasm.cc \
+ Dwarf.cc \
+ DwarfLib.cc \
+ Elf.cc \
+ Emsg.cc \
+ Experiment.cc \
+ Exp_Layout.cc \
+ ExpGroup.cc \
+ Expression.cc \
+ FileData.cc \
+ Filter.cc \
+ FilterSet.cc \
+ Function.cc \
+ HeapMap.cc \
+ HeapData.cc \
+ HeapActivity.cc \
+ Hist_data.cc \
+ IndexObject.cc \
+ IOActivity.cc \
+ LoadObject.cc \
+ MachineModel.cc \
+ MemObject.cc \
+ MemorySpace.cc \
+ Metric.cc \
+ MetricList.cc \
+ Module.cc \
+ Ovw_data.cc \
+ PRBTree.cc \
+ PathTree.cc \
+ PreviewExp.cc \
+ Print.cc \
+ SAXParserFactory.cc \
+ Sample.cc \
+ Settings.cc \
+ SourceFile.cc \
+ Stabs.cc \
+ Stats_data.cc \
+ StringBuilder.cc \
+ Table.cc \
+ QLParser.tab.cc \
+ dbe_collctrl.cc \
+ i18n.cc \
+ parse.cc \
+ UserLabel.cc \
+ util.cc \
+ Dbe.cc \
+ $(NULL)
+
+CSOURCES = \
+ dbe_hwcdrv.c \
+ dbe_hwcfuncs.c \
+ dbe_hwctable.c \
+ dbe_memmgr.c \
+ gethrtime.c \
+ $(NULL)
+
+LIBGPROFNG = libgprofng.la
+
+AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -DLOCALEDIR=\"@localedir@\" -I.. -I$(srcdir) \
+ -I$(srcdir)/../common \
+ -I$(srcdir)/../../include -I$(srcdir)/../../opcodes \
+ -I../../bfd -I$(srcdir)/../../bfd
+AM_CFLAGS = $(GPROFNG_CFLAGS) $(PTHREAD_CFLAGS) -Wno-switch \
+ -Wno-format-truncation
+AM_CXXFLAGS = $(AM_CFLAGS)
+
+man_MANS = gprofng.1 \
+ gp-archive.1 \
+ gp-collect-app.1 \
+ gp-display-src.1 \
+ gp-display-text.1
+
+MAINTAINERCLEANFILES = $(man_MANS)
+
+EXTRA_DIST = $(man_MANS)
+
+
+lib_LTLIBRARIES = $(LIBGPROFNG)
+libgprofng_la_SOURCES = $(CCSOURCES) $(CSOURCES)
+libgprofng_la_LDFLAGS = -version-info 0:0:0
+libgprofng_la_LIBADD = $(top_builddir)/../opcodes/libopcodes.la \
+ $(top_builddir)/../bfd/libbfd.la \
+ $(GPROFNG_LIBADD) \
+ $(PTHREAD_LIBS) -ldl
+
+dbedir = $(prefix)/etc
+dbe_DATA = $(srcdir)/gprofng.rc
+
+
+bin_PROGRAMS = gp-archive gp-collect-app gprofng gp-display-text gp-display-src
+
+gp_archive_SOURCES = gp-archive.cc ArchiveExp.cc
+gp_archive_LDADD = $(LIBGPROFNG)
+
+gp_collect_app_SOURCES = gp-collect-app.cc checks.cc envsets.cc count.cc
+gp_collect_app_LDADD = $(LIBGPROFNG)
+
+gprofng_SOURCES = gprofng.cc
+gprofng_LDADD = $(LIBGPROFNG)
+
+gp_display_src_SOURCES = gp-display-src.cc
+gp_display_src_LDADD = $(LIBGPROFNG)
+
+gp_display_text_SOURCES = gp-display-text.cc ipc.cc ipcio.cc
+gp_display_text_LDADD = $(LIBGPROFNG)
+
+
+if BUILD_MAN
+
+# The man pages depend on the version number and on a help2man include file.
+common_mandeps = $(top_srcdir)/../bfd/version.m4
+
+# Use -o so that the `missing' program can infer the output file.
+# Embolden subcommand names in the output, and include a SEE ALSO.
+# Arrange to regenerate the output if we have help2man, but leave the
+# disted output there otherwise.
+# Some extra annoying complexity is in place so that people without
+# help2man dno't accidentally overwrite the manpage.
+
+INFO_PAGE = "gprofng"
+MANUAL = "User Commands"
+TEXT_GPROFNG = "the driver for the gprofng tool suite"
+TEXT_GP_ARCHIVE = "archive gprofng experiment data"
+TEXT_GP_COLLECT_APP = "collect performance data for the target application"
+TEXT_GP_DISPLAY_SRC = "display the source code, optionally interleaved with the disassembly of the target object"
+TEXT_GP_DISPLAY_TEXT = "display the performance data in plain text format"
+
+HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
+H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
+ | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
+ | sed 's/Limitations:/.SH LIMITATIONS/'
+
+gprofng.1: $(srcdir)/gprofng.cc $(common_mandeps) | ./gprofng$(EXEEXT)
+ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+ --name=$(TEXT_GPROFNG) ./gprofng$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-archive.1: $(srcdir)/gp-archive.cc $(common_mandeps) | ./gp-archive$(EXEEXT)
+ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+ --name=$(TEXT_GP_ARCHIVE) ./gp-archive$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-collect-app.1: $(srcdir)/gp-collect-app.cc $(common_mandeps) | ./gp-collect-app$(EXEEXT)
+ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+ --name=$(TEXT_GP_COLLECT_APP) ./gp-collect-app$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-display-src.1: $(srcdir)/gp-display-src.cc $(srcdir)/Command.cc \
+ $(common_mandeps) | ./gp-display-src$(EXEEXT)
+ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+ --name=$(TEXT_GP_DISPLAY_SRC) ./gp-display-src$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-display-text.1: $(srcdir)/gp-display-text.cc $(srcdir)/Command.cc \
+ $(common_mandeps) | ./gp-display-text$(EXEEXT)
+ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+ --name=$(TEXT_GP_DISPLAY_TEXT) ./gp-display-text$(EXEEXT) $(H2M_FILTER) > $@
+
+endif
+
+# Distribution involves building the binaries to generate the manpage,
+# so ensure that the necessary libraries are built at dist time.
+dist-hook: $(LIBGPROFNG)
+
diff --git a/gprofng/src/Makefile.in b/gprofng/src/Makefile.in
new file mode 100644
index 0000000..f21671d
--- /dev/null
+++ b/gprofng/src/Makefile.in
@@ -0,0 +1,1171 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = gp-archive$(EXEEXT) gp-collect-app$(EXEEXT) \
+ gprofng$(EXEEXT) gp-display-text$(EXEEXT) \
+ gp-display-src$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
+ $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+ $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
+ $(top_srcdir)/../config/enable.m4 \
+ $(top_srcdir)/../config/ax_pthread.m4 \
+ $(top_srcdir)/config/bison.m4 $(top_srcdir)/../bfd/version.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(dbedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgprofng_la_DEPENDENCIES = $(top_builddir)/../opcodes/libopcodes.la \
+ $(top_builddir)/../bfd/libbfd.la $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__objects_1 = Application.lo BaseMetric.lo BaseMetricTreeNode.lo \
+ CallStack.lo CatchOutOfMemory.lo ClassFile.lo Command.lo \
+ CompCom.lo DataObject.lo DataSpace.lo Data_window.lo \
+ DataStream.lo DbeApplication.lo DbeFile.lo DbeJarFile.lo \
+ DbeLock.lo DbeSession.lo DbeThread.lo DbeView.lo \
+ DerivedMetrics.lo Disasm.lo Dwarf.lo DwarfLib.lo Elf.lo \
+ Emsg.lo Experiment.lo Exp_Layout.lo ExpGroup.lo Expression.lo \
+ FileData.lo Filter.lo FilterSet.lo Function.lo HeapMap.lo \
+ HeapData.lo HeapActivity.lo Hist_data.lo IndexObject.lo \
+ IOActivity.lo LoadObject.lo MachineModel.lo MemObject.lo \
+ MemorySpace.lo Metric.lo MetricList.lo Module.lo Ovw_data.lo \
+ PRBTree.lo PathTree.lo PreviewExp.lo Print.lo \
+ SAXParserFactory.lo Sample.lo Settings.lo SourceFile.lo \
+ Stabs.lo Stats_data.lo StringBuilder.lo Table.lo \
+ QLParser.tab.lo dbe_collctrl.lo i18n.lo parse.lo UserLabel.lo \
+ util.lo Dbe.lo
+am__objects_2 = dbe_hwcdrv.lo dbe_hwcfuncs.lo dbe_hwctable.lo \
+ dbe_memmgr.lo gethrtime.lo
+am_libgprofng_la_OBJECTS = $(am__objects_1) $(am__objects_2)
+libgprofng_la_OBJECTS = $(am_libgprofng_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgprofng_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgprofng_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+PROGRAMS = $(bin_PROGRAMS)
+am_gp_archive_OBJECTS = gp-archive.$(OBJEXT) ArchiveExp.$(OBJEXT)
+gp_archive_OBJECTS = $(am_gp_archive_OBJECTS)
+gp_archive_DEPENDENCIES = $(LIBGPROFNG)
+am_gp_collect_app_OBJECTS = gp-collect-app.$(OBJEXT) checks.$(OBJEXT) \
+ envsets.$(OBJEXT) count.$(OBJEXT)
+gp_collect_app_OBJECTS = $(am_gp_collect_app_OBJECTS)
+gp_collect_app_DEPENDENCIES = $(LIBGPROFNG)
+am_gp_display_src_OBJECTS = gp-display-src.$(OBJEXT)
+gp_display_src_OBJECTS = $(am_gp_display_src_OBJECTS)
+gp_display_src_DEPENDENCIES = $(LIBGPROFNG)
+am_gp_display_text_OBJECTS = gp-display-text.$(OBJEXT) ipc.$(OBJEXT) \
+ ipcio.$(OBJEXT)
+gp_display_text_OBJECTS = $(am_gp_display_text_OBJECTS)
+gp_display_text_DEPENDENCIES = $(LIBGPROFNG)
+am_gprofng_OBJECTS = gprofng.$(OBJEXT)
+gprofng_OBJECTS = $(am_gprofng_OBJECTS)
+gprofng_DEPENDENCIES = $(LIBGPROFNG)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(libgprofng_la_SOURCES) $(gp_archive_SOURCES) \
+ $(gp_collect_app_SOURCES) $(gp_display_src_SOURCES) \
+ $(gp_display_text_SOURCES) $(gprofng_SOURCES)
+DIST_SOURCES = $(libgprofng_la_SOURCES) $(gp_archive_SOURCES) \
+ $(gp_collect_app_SOURCES) $(gp_display_src_SOURCES) \
+ $(gp_display_text_SOURCES) $(gprofng_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+DATA = $(dbe_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp \
+ $(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_SUBDIRS = @BUILD_SUBDIRS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPECT = @EXPECT@
+FGREP = @FGREP@
+GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
+GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
+GPROFNG_LIBADD = @GPROFNG_LIBADD@
+GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
+GREP = @GREP@
+HELP2MAN = @HELP2MAN@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA = @JAVA@
+JAVAC = @JAVAC@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gprofng_cflags = @gprofng_cflags@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+jdk_inc = @jdk_inc@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I . -I .. -I ../..
+CCSOURCES = \
+ Application.cc \
+ BaseMetric.cc \
+ BaseMetricTreeNode.cc \
+ CallStack.cc \
+ CatchOutOfMemory.cc \
+ ClassFile.cc \
+ Command.cc \
+ CompCom.cc \
+ DataObject.cc \
+ DataSpace.cc \
+ Data_window.cc \
+ DataStream.cc \
+ DbeApplication.cc \
+ DbeFile.cc \
+ DbeJarFile.cc \
+ DbeLock.cc \
+ DbeSession.cc \
+ DbeThread.cc \
+ DbeView.cc \
+ DerivedMetrics.cc \
+ Disasm.cc \
+ Dwarf.cc \
+ DwarfLib.cc \
+ Elf.cc \
+ Emsg.cc \
+ Experiment.cc \
+ Exp_Layout.cc \
+ ExpGroup.cc \
+ Expression.cc \
+ FileData.cc \
+ Filter.cc \
+ FilterSet.cc \
+ Function.cc \
+ HeapMap.cc \
+ HeapData.cc \
+ HeapActivity.cc \
+ Hist_data.cc \
+ IndexObject.cc \
+ IOActivity.cc \
+ LoadObject.cc \
+ MachineModel.cc \
+ MemObject.cc \
+ MemorySpace.cc \
+ Metric.cc \
+ MetricList.cc \
+ Module.cc \
+ Ovw_data.cc \
+ PRBTree.cc \
+ PathTree.cc \
+ PreviewExp.cc \
+ Print.cc \
+ SAXParserFactory.cc \
+ Sample.cc \
+ Settings.cc \
+ SourceFile.cc \
+ Stabs.cc \
+ Stats_data.cc \
+ StringBuilder.cc \
+ Table.cc \
+ QLParser.tab.cc \
+ dbe_collctrl.cc \
+ i18n.cc \
+ parse.cc \
+ UserLabel.cc \
+ util.cc \
+ Dbe.cc \
+ $(NULL)
+
+CSOURCES = \
+ dbe_hwcdrv.c \
+ dbe_hwcfuncs.c \
+ dbe_hwctable.c \
+ dbe_memmgr.c \
+ gethrtime.c \
+ $(NULL)
+
+LIBGPROFNG = libgprofng.la
+AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -DLOCALEDIR=\"@localedir@\" -I.. -I$(srcdir) \
+ -I$(srcdir)/../common \
+ -I$(srcdir)/../../include -I$(srcdir)/../../opcodes \
+ -I../../bfd -I$(srcdir)/../../bfd
+
+AM_CFLAGS = $(GPROFNG_CFLAGS) $(PTHREAD_CFLAGS) -Wno-switch \
+ -Wno-format-truncation
+
+AM_CXXFLAGS = $(AM_CFLAGS)
+man_MANS = gprofng.1 \
+ gp-archive.1 \
+ gp-collect-app.1 \
+ gp-display-src.1 \
+ gp-display-text.1
+
+MAINTAINERCLEANFILES = $(man_MANS)
+EXTRA_DIST = $(man_MANS)
+lib_LTLIBRARIES = $(LIBGPROFNG)
+libgprofng_la_SOURCES = $(CCSOURCES) $(CSOURCES)
+libgprofng_la_LDFLAGS = -version-info 0:0:0
+libgprofng_la_LIBADD = $(top_builddir)/../opcodes/libopcodes.la \
+ $(top_builddir)/../bfd/libbfd.la \
+ $(GPROFNG_LIBADD) \
+ $(PTHREAD_LIBS) -ldl
+
+dbedir = $(prefix)/etc
+dbe_DATA = $(srcdir)/gprofng.rc
+gp_archive_SOURCES = gp-archive.cc ArchiveExp.cc
+gp_archive_LDADD = $(LIBGPROFNG)
+gp_collect_app_SOURCES = gp-collect-app.cc checks.cc envsets.cc count.cc
+gp_collect_app_LDADD = $(LIBGPROFNG)
+gprofng_SOURCES = gprofng.cc
+gprofng_LDADD = $(LIBGPROFNG)
+gp_display_src_SOURCES = gp-display-src.cc
+gp_display_src_LDADD = $(LIBGPROFNG)
+gp_display_text_SOURCES = gp-display-text.cc ipc.cc ipcio.cc
+gp_display_text_LDADD = $(LIBGPROFNG)
+
+# The man pages depend on the version number and on a help2man include file.
+@BUILD_MAN_TRUE@common_mandeps = $(top_srcdir)/../bfd/version.m4
+
+# Use -o so that the `missing' program can infer the output file.
+# Embolden subcommand names in the output, and include a SEE ALSO.
+# Arrange to regenerate the output if we have help2man, but leave the
+# disted output there otherwise.
+# Some extra annoying complexity is in place so that people without
+# help2man dno't accidentally overwrite the manpage.
+@BUILD_MAN_TRUE@INFO_PAGE = "gprofng"
+@BUILD_MAN_TRUE@MANUAL = "User Commands"
+@BUILD_MAN_TRUE@TEXT_GPROFNG = "the driver for the gprofng tool suite"
+@BUILD_MAN_TRUE@TEXT_GP_ARCHIVE = "archive gprofng experiment data"
+@BUILD_MAN_TRUE@TEXT_GP_COLLECT_APP = "collect performance data for the target application"
+@BUILD_MAN_TRUE@TEXT_GP_DISPLAY_SRC = "display the source code, optionally interleaved with the disassembly of the target object"
+@BUILD_MAN_TRUE@TEXT_GP_DISPLAY_TEXT = "display the performance data in plain text format"
+@BUILD_MAN_TRUE@HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
+@BUILD_MAN_TRUE@H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
+@BUILD_MAN_TRUE@ | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
+@BUILD_MAN_TRUE@ | sed 's/Limitations:/.SH LIMITATIONS/'
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgprofng.la: $(libgprofng_la_OBJECTS) $(libgprofng_la_DEPENDENCIES) $(EXTRA_libgprofng_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgprofng_la_LINK) -rpath $(libdir) $(libgprofng_la_OBJECTS) $(libgprofng_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+gp-archive$(EXEEXT): $(gp_archive_OBJECTS) $(gp_archive_DEPENDENCIES) $(EXTRA_gp_archive_DEPENDENCIES)
+ @rm -f gp-archive$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gp_archive_OBJECTS) $(gp_archive_LDADD) $(LIBS)
+
+gp-collect-app$(EXEEXT): $(gp_collect_app_OBJECTS) $(gp_collect_app_DEPENDENCIES) $(EXTRA_gp_collect_app_DEPENDENCIES)
+ @rm -f gp-collect-app$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gp_collect_app_OBJECTS) $(gp_collect_app_LDADD) $(LIBS)
+
+gp-display-src$(EXEEXT): $(gp_display_src_OBJECTS) $(gp_display_src_DEPENDENCIES) $(EXTRA_gp_display_src_DEPENDENCIES)
+ @rm -f gp-display-src$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gp_display_src_OBJECTS) $(gp_display_src_LDADD) $(LIBS)
+
+gp-display-text$(EXEEXT): $(gp_display_text_OBJECTS) $(gp_display_text_DEPENDENCIES) $(EXTRA_gp_display_text_DEPENDENCIES)
+ @rm -f gp-display-text$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gp_display_text_OBJECTS) $(gp_display_text_LDADD) $(LIBS)
+
+gprofng$(EXEEXT): $(gprofng_OBJECTS) $(gprofng_DEPENDENCIES) $(EXTRA_gprofng_DEPENDENCIES)
+ @rm -f gprofng$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gprofng_OBJECTS) $(gprofng_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Application.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArchiveExp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BaseMetric.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BaseMetricTreeNode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CallStack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CatchOutOfMemory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClassFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Command.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompCom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataSpace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataStream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data_window.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dbe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeApplication.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeJarFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeLock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeSession.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeThread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeView.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DerivedMetrics.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Disasm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dwarf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DwarfLib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Elf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Emsg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ExpGroup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Exp_Layout.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Experiment.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Expression.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileData.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Filter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FilterSet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Function.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeapActivity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeapData.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeapMap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Hist_data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IOActivity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IndexObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LoadObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MachineModel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemorySpace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metric.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetricList.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Module.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Ovw_data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PRBTree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PathTree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PreviewExp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QLParser.tab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SAXParserFactory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Sample.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Settings.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SourceFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stabs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stats_data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StringBuilder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UserLabel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checks.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/count.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_collctrl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_hwcdrv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_hwcfuncs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_hwctable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_memmgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/envsets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gethrtime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-archive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-collect-app.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-display-src.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-display-text.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gprofng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i18n.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(man_MANS)'; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.1[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-dbeDATA: $(dbe_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dbe_DATA)'; test -n "$(dbedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dbedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dbedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(dbedir)" || exit $$?; \
+ done
+
+uninstall-dbeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dbe_DATA)'; test -n "$(dbedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(dbedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) $(DATA)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(dbedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dbeDATA install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-dbeDATA \
+ uninstall-libLTLIBRARIES uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool cscopelist-am ctags ctags-am dist-hook distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dbeDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-dbeDATA \
+ uninstall-libLTLIBRARIES uninstall-man uninstall-man1
+
+.PRECIOUS: Makefile
+
+
+@BUILD_MAN_TRUE@gprofng.1: $(srcdir)/gprofng.cc $(common_mandeps) | ./gprofng$(EXEEXT)
+@BUILD_MAN_TRUE@ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@ --name=$(TEXT_GPROFNG) ./gprofng$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-archive.1: $(srcdir)/gp-archive.cc $(common_mandeps) | ./gp-archive$(EXEEXT)
+@BUILD_MAN_TRUE@ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@ --name=$(TEXT_GP_ARCHIVE) ./gp-archive$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-collect-app.1: $(srcdir)/gp-collect-app.cc $(common_mandeps) | ./gp-collect-app$(EXEEXT)
+@BUILD_MAN_TRUE@ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@ --name=$(TEXT_GP_COLLECT_APP) ./gp-collect-app$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-display-src.1: $(srcdir)/gp-display-src.cc $(srcdir)/Command.cc \
+@BUILD_MAN_TRUE@ $(common_mandeps) | ./gp-display-src$(EXEEXT)
+@BUILD_MAN_TRUE@ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@ --name=$(TEXT_GP_DISPLAY_SRC) ./gp-display-src$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-display-text.1: $(srcdir)/gp-display-text.cc $(srcdir)/Command.cc \
+@BUILD_MAN_TRUE@ $(common_mandeps) | ./gp-display-text$(EXEEXT)
+@BUILD_MAN_TRUE@ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@ --name=$(TEXT_GP_DISPLAY_TEXT) ./gp-display-text$(EXEEXT) $(H2M_FILTER) > $@
+
+# Distribution involves building the binaries to generate the manpage,
+# so ensure that the necessary libraries are built at dist time.
+dist-hook: $(LIBGPROFNG)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gprofng/src/Map.h b/gprofng/src/Map.h
new file mode 100644
index 0000000..530dcfc
--- /dev/null
+++ b/gprofng/src/Map.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_MAP_H
+#define _DBE_MAP_H
+
+#include "vec.h"
+
+template <typename Key_t, typename Value_t>
+class Map
+{
+public:
+
+ enum Relation
+ {
+ REL_LT,
+ REL_LE,
+ REL_EQ,
+ REL_GE,
+ REL_GT
+ };
+
+ virtual ~Map () { };
+ virtual void put (Key_t key, Value_t val) = 0;
+ virtual Value_t get (Key_t key) = 0;
+ virtual Value_t get (Key_t key, Relation rel) = 0;
+ virtual Value_t remove (Key_t key) = 0;
+
+ virtual Vector<Key_t> *
+ keySet ()
+ {
+ return NULL;
+ }
+
+ virtual Vector<Value_t> *
+ values ()
+ {
+ return NULL;
+ }
+};
+
+#define destroy_map(t, p) if (p) { Vector<t> *v = p->values (); Destroy (v); delete p; }
+
+#endif
diff --git a/gprofng/src/Map2D.h b/gprofng/src/Map2D.h
new file mode 100644
index 0000000..41b2be2
--- /dev/null
+++ b/gprofng/src/Map2D.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_MAP2D_H
+#define _DBE_MAP2D_H
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+class Map2D
+{
+public:
+
+ enum MapType
+ {
+ Default,
+ Interval
+ };
+
+ // Relation for the first key is always EQUAL
+ enum Relation
+ {
+ REL_EQLT,
+ REL_EQLE,
+ REL_EQEQ,
+ REL_EQGE,
+ REL_EQGT
+ };
+
+ virtual ~Map2D () { };
+ virtual void put (Key1_t key1, Key2_t key2, Value_t val) = 0;
+ virtual Value_t get (Key1_t key1, Key2_t key2) = 0;
+ virtual Value_t get (Key1_t key1, Key2_t key2, Relation rel) = 0;
+ virtual Value_t remove (Key1_t key1, Key2_t key2) = 0;
+
+};
+
+#endif
diff --git a/gprofng/src/MemObject.cc b/gprofng/src/MemObject.cc
new file mode 100644
index 0000000..d207a99
--- /dev/null
+++ b/gprofng/src/MemObject.cc
@@ -0,0 +1,44 @@
+/* Copyright (C) 2021 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 "Exp_Layout.h"
+#include "MemObject.h"
+#include "DataSpace.h"
+#include "ABS.h"
+#include "Dbe.h"
+#include "i18n.h"
+
+MemObj::MemObj (uint64_t _index, char *_name)
+{
+ id = _index;
+ name = _name;
+}
+
+MemObj::~MemObj ()
+{
+ free (name);
+}
+
+Histable *
+MemObj::convertto (Histable_type type, Histable*)
+{
+ return type == MEMOBJ ? this : NULL;
+}
diff --git a/gprofng/src/MemObject.h b/gprofng/src/MemObject.h
new file mode 100644
index 0000000..6bc459f
--- /dev/null
+++ b/gprofng/src/MemObject.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _MEMOBJECT_H
+#define _MEMOBJECT_H
+
+#include "Histable.h"
+#include "util.h"
+
+class MemObj : public Histable
+{
+public:
+ friend class MemorySpace;
+
+ MemObj (uint64_t _index, char *_name);
+ ~MemObj ();
+
+ virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+ virtual Histable_type
+ get_type ()
+ {
+ return MEMOBJ;
+ }
+
+ virtual char *
+ get_name (NameFormat = NA)
+ {
+ return dbe_strdup (name);
+ }
+
+ virtual uint64_t
+ get_addr ()
+ {
+ return id;
+ }
+
+ uint64_t
+ get_index ()
+ {
+ return id;
+ }
+};
+
+#endif /* _MEMOBJECT_H */
diff --git a/gprofng/src/MemorySpace.cc b/gprofng/src/MemorySpace.cc
new file mode 100644
index 0000000..3f7c78d
--- /dev/null
+++ b/gprofng/src/MemorySpace.cc
@@ -0,0 +1,452 @@
+/* Copyright (C) 2021 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 <ctype.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "MetricList.h"
+#include "MemObject.h"
+#include "PathTree.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "MemorySpace.h"
+#include "Table.h"
+#include "IndexObject.h"
+
+MemObjType_t::MemObjType_t ()
+{
+ type = -1;
+ name = NULL;
+ index_expr = NULL;
+ machmodel = NULL;
+ mnemonic = 0;
+ short_description = NULL;
+ long_description = NULL;
+}
+
+MemObjType_t::~MemObjType_t ()
+{
+ free (name);
+ free (index_expr);
+ free (machmodel);
+ free (short_description);
+ free (long_description);
+}
+
+MemorySpace::MemorySpace (DbeView *_dbev, int _mstype)
+{
+ char *mname;
+ dbev = _dbev;
+ phaseIdx = -1;
+
+ // set up the MemoryObject information
+ objs = new HashMap<uint64_t, MemObj*>;
+ mstype = _mstype;
+ msindex_exp = NULL;
+ msname = NULL;
+ msindex_exp_str = NULL;
+
+ // find the memory space in the table
+ MemObjType_t *mot = findMemSpaceByIndex (mstype);
+ if (mot)
+ {
+ msname = dbe_strdup (mot->name);
+ if (mot->index_expr != NULL)
+ {
+ msindex_exp_str = dbe_strdup (mot->index_expr);
+ msindex_exp = dbeSession->ql_parse (msindex_exp_str);
+ if (msindex_exp == NULL)
+ // this was checked when the definition was created
+ abort ();
+ }
+ }
+
+ // create the Total and Unknown objects
+ mname = dbe_strdup (NTXT ("<Total>"));
+ total_memobj = createMemObject ((uint64_t) - 2, mname);
+ mname = dbe_strdup (GTXT ("<Unknown>"));
+ unk_memobj = createMemObject ((uint64_t) - 1, mname);
+ hist_data_all = NULL;
+ selected_mo_index = (uint64_t) - 3;
+ sel_ind = -1;
+}
+
+MemorySpace::~MemorySpace ()
+{
+ reset ();
+ delete objs;
+ free (msname);
+ free (msindex_exp);
+ free (msindex_exp_str);
+}
+
+void
+MemorySpace::reset ()
+{
+ if (hist_data_all != NULL)
+ {
+ delete hist_data_all;
+ hist_data_all = NULL;
+ }
+ // do not clear the selected object's index
+ // selected_mo_index = (uint64_t)-3;
+
+ // destroy any existing objects, but keep the vector
+ // Now that we have a hashmap, which has its own vector,
+ // safe to delete and reallocate
+ delete objs;
+ objs = new HashMap<uint64_t, MemObj*>;
+}
+
+// find a memory object by its memory-object index
+int
+MemorySpace::findMemObject (uint64_t indx)
+{
+ int index;
+ Hist_data::HistItem *hi;
+ if (indx == (uint64_t) - 3)
+ return -1;
+
+ Vec_loop (Hist_data::HistItem *, hist_data_all->hist_items, index, hi)
+ {
+ if (((uint64_t) ((MemObj *) hi->obj)->id) == indx)
+ return index;
+ }
+ // object does not exist; filter change eliminated it, for example
+ return -1;
+}
+
+// find the object referenced in the packet
+MemObj *
+MemorySpace::lookupMemObject (Experiment *exp, DataView *packets, long i)
+{
+ uint64_t idx;
+ uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
+ if (va == ABS_UNSUPPORTED)
+ // return NULL, to ignore the record
+ return NULL;
+ if (va < ABS_CODE_RANGE)
+ // The va is not valid, rather, it's an error code
+ // return the <Unknown> object
+ return unk_memobj;
+
+ Expression::Context ctx (dbev, exp, packets, i);
+ idx = msindex_exp->eval (&ctx);
+ if (idx == (uint64_t) - 1)
+ return unk_memobj;
+
+ // do a binary search for the memory object
+ MemObj *res = objs->get (idx);
+ if (res == NULL)
+ {
+ res = createMemObject (idx, NULL);
+ objs->put (idx, res);
+ }
+ else
+ return res;
+
+ // recompute range
+ if (idx < idx_min)
+ idx_min = idx;
+ if (idx > idx_max)
+ idx_max = idx;
+ return res;
+}
+
+MemObj *
+MemorySpace::createMemObject (uint64_t index, char *moname)
+{
+ MemObj *res;
+ char *name;
+ if (moname != NULL)
+ {
+ res = new MemObj (index, moname);
+ return res;
+ }
+
+ // Custom memory objects
+ // The memory_page_size is defined in the machine model file such
+ // as ./machinemodels/t4.ermm.
+ // Most users prefer to look at the hexadecimal version of virtual
+ // addresses. Display only the hexadecimal version of virtual addresses
+ // for all machine model views with an exception of virtual page size.
+ if (dbe_strcmp (msname, NTXT ("Memory_page_size")) == 0)
+ name = dbe_sprintf (NTXT ("%s 0x%16.16llx (%llu)"), msname,
+ (long long) index, (unsigned long long) index);
+ else if (dbe_strcmp (msname, NTXT ("Memory_in_home_lgrp")) == 0)
+ name = dbe_sprintf (NTXT ("%s: %s"), msname,
+ index == 1 ? GTXT ("True") : index == 0 ? GTXT ("False")
+ : GTXT ("<Unknown>"));
+ else if (dbe_strcmp (msname, NTXT ("Memory_lgrp")) == 0)
+ name = dbe_sprintf (NTXT ("%s %llu"), msname, (unsigned long long) index);
+ else
+ name = dbe_sprintf (NTXT ("%s 0x%16.16llx"), msname, (long long) index);
+
+ res = new MemObj (index, name);
+ return res;
+}
+
+
+static Vector<MemObjType_t*> dyn_memobj_vec;
+static Vector<MemObjType_t*> *dyn_memobj = &dyn_memobj_vec;
+static Vector<int> *ordlist;
+
+// Static function to get a vector of custom memory object definitions
+
+Vector<void*> *
+MemorySpace::getMemObjects ()
+{
+ MemObjType_t *mot;
+ int ii;
+ int size = dyn_memobj->size ();
+ Vector<int> *indx = new Vector<int>(size);
+ Vector<char*> *name = new Vector<char*>(size);
+ Vector<char> *mnemonic = new Vector<char>(size);
+ Vector<char*> *formula = new Vector<char*>(size);
+ Vector<char*> *machmodel = new Vector<char*>(size);
+ Vector<int> *order = new Vector<int>(size);
+ Vector<char*> *sdesc = new Vector<char*>(size);
+ Vector<char*> *ldesc = new Vector<char*>(size);
+
+ if (size > 0)
+ {
+ Vec_loop (MemObjType_t *, dyn_memobj, ii, mot)
+ {
+ indx->store (ii, mot->type);
+ order->store (ii, ii);
+ name->store (ii, dbe_strdup (mot->name));
+ formula->store (ii, dbe_strdup (mot->index_expr));
+ mnemonic->store (ii, mot->mnemonic);
+ sdesc->store (ii, mot->short_description == NULL ? NULL
+ : dbe_strdup (mot->short_description));
+ ldesc->store (ii, mot->long_description == NULL ? NULL
+ : dbe_strdup (mot->long_description));
+ if (mot->machmodel == NULL)
+ machmodel->store (ii, NULL);
+ else
+ machmodel->store (ii, dbe_strdup (mot->machmodel));
+ }
+ }
+ Vector<void*> *res = new Vector<void*>(8);
+ res->store (0, indx);
+ res->store (1, name);
+ res->store (2, mnemonic);
+ res->store (3, formula);
+ res->store (4, machmodel);
+ res->store (5, order);
+ res->store (6, sdesc);
+ res->store (7, ldesc);
+ return (res);
+}
+
+// Static function to set order of memory object tabs
+void
+MemorySpace::set_MemTabOrder (Vector<int> *orders)
+{
+ int size = orders->size ();
+ ordlist = new Vector<int>(size);
+ for (int i = 0; i < size; i++)
+ ordlist->store (i, orders->fetch (i));
+}
+
+// Static function to define a new memory object type
+char *
+MemorySpace::mobj_define (char *mname, char *mindex_exp, char *_machmodel,
+ char *short_description, char *long_description)
+{
+ MemObjType_t *mot;
+
+ if (mname == NULL)
+ return dbe_strdup (GTXT ("No memory object name has been specified."));
+ if (isalpha ((int) (mname[0])) == 0)
+ return dbe_sprintf (GTXT ("Memory Object type name %s does not begin with an alphabetic character"),
+ mname);
+ char *p = mname;
+ while (*p != 0)
+ {
+ if (isalnum ((int) (*p)) == 0 && *p != '_')
+ return dbe_sprintf (GTXT ("Memory Object type name %s contains a non-alphanumeric character"),
+ mname);
+ p++;
+ }
+
+ mot = findMemSpaceByName (mname);
+ if (mot != NULL)
+ {
+ if (strcmp (mot->index_expr, mindex_exp) == 0)
+ // It's a redefinition, but the new definition is the same
+ return NULL;
+ return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+ mname);
+ }
+
+ // make sure the name is not in use
+ if (dbeSession->findIndexSpaceByName (mname) >= 0)
+ return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+ mname);
+
+ if (mindex_exp == NULL || *mindex_exp == 0)
+ return dbe_strdup (GTXT ("No index-expr has been specified."));
+
+ // verify that the index expression parses correctly
+ Expression *e = dbeSession->ql_parse (mindex_exp);
+ if (e == NULL)
+ return dbe_sprintf (GTXT ("Memory Object index expression is invalid: %s"),
+ mindex_exp);
+ delete e;
+
+ // It's OK, create the new table entry
+ char *s = dbeSession->indxobj_define (mname, NULL, mindex_exp,
+ short_description, long_description);
+ if (s)
+ return s;
+ IndexObjType_t *indObj = dbeSession->findIndexSpace (mname);
+
+ mot = new MemObjType_t;
+ mot->type = indObj->type;
+ indObj->memObj = mot;
+ mot->name = dbe_strdup (mname);
+ mot->index_expr = dbe_strdup (mindex_exp);
+ mot->mnemonic = MemorySpace::pickMnemonic (mname);
+ mot->machmodel = dbe_strdup (_machmodel);
+ mot->short_description = dbe_strdup (short_description);
+ mot->long_description = dbe_strdup (long_description);
+
+ // add it to the list
+ dyn_memobj->append (mot);
+
+ // tell the session
+ if (dbeSession != NULL)
+ dbeSession->mobj_define (mot);
+ return NULL;
+}
+
+// Static function to delete a new memory object type
+
+char *
+MemorySpace::mobj_delete (char *mname)
+{
+ if (mname == NULL)
+ return dbe_strdup (GTXT ("No memory object name has been specified.\n"));
+
+ // search the dynamic types
+ for (long idx = 0, sz = VecSize (dyn_memobj); idx < sz; idx++)
+ {
+ MemObjType_t *mt = dyn_memobj->get (idx);
+ if (strcasecmp (mt->name, mname) == 0)
+ {
+ // delete it from the vector
+ mt = dyn_memobj->remove (idx);
+ delete mt;
+ dbeSession->removeIndexSpaceByName (mname);
+ return NULL;
+ }
+ }
+ return dbe_sprintf (GTXT ("Memory object `%s' is not defined.\n"), mname);
+}
+
+// Static function to get a list of memory object names from a machine model
+
+Vector <char*> *
+MemorySpace::getMachineModelMemObjs (char *mname)
+{
+ Vector <char *> *ret = new Vector <char *> ();
+ if (mname == NULL)
+ return ret;
+
+ // search the memory objects
+ int idx;
+ MemObjType_t *mt;
+ Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
+ {
+ if (mt->machmodel != NULL && strcmp (mt->machmodel, mname) == 0)
+ {
+ char *n = dbe_strdup (mt->name);
+ ret->append (n);
+ }
+ }
+ return ret;
+}
+
+char
+MemorySpace::pickMnemonic (char *name)
+{
+ return name[0];
+}
+
+void
+MemorySpace::get_filter_keywords (Vector <void*> *res)
+{
+ Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
+ Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+ Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
+ Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+ Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+ Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
+ Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+
+ char *vtypeNames[] = VTYPE_TYPE_NAMES;
+ for (int i = 0, sz = dyn_memobj ? dyn_memobj->size () : 0; i < sz; i++)
+ {
+ MemObjType_t *obj = dyn_memobj->fetch (i);
+ kwCategory->append (dbe_strdup (NTXT ("FK_MEMOBJ")));
+ kwCategoryI18N->append (dbe_strdup (GTXT ("Memory Object Definitions")));
+ kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
+ kwKeyword->append (dbe_strdup (obj->name));
+ kwFormula->append (dbe_strdup (obj->index_expr));
+ kwDescription->append (NULL);
+ kwEnumDescs->append (NULL);
+ }
+}
+
+MemObjType_t *
+MemorySpace::findMemSpaceByName (const char *mname)
+{
+ int idx;
+ MemObjType_t *mt;
+
+ // search the dynamic types
+ Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
+ {
+ if (strcasecmp (mt->name, mname) == 0)
+ return mt;
+ }
+ return NULL;
+}
+
+MemObjType_t *
+MemorySpace::findMemSpaceByIndex (int index)
+{
+ int idx;
+ MemObjType_t *mt;
+
+ // search the dynamic types
+ Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
+ {
+ if (mt->type == index)
+ return mt;
+ }
+ return NULL;
+}
diff --git a/gprofng/src/MemorySpace.h b/gprofng/src/MemorySpace.h
new file mode 100644
index 0000000..7d02e5e
--- /dev/null
+++ b/gprofng/src/MemorySpace.h
@@ -0,0 +1,113 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _MEMORYSPACE_H
+#define _MEMORYSPACE_H
+
+#include <stdio.h>
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "Exp_Layout.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Metric.h"
+#include "HashMap.h"
+
+class Experiment;
+class Expression;
+class DataView;
+class DbeView;
+class MemObj;
+
+class MemObjType_t
+{
+public:
+ MemObjType_t ();
+ ~MemObjType_t ();
+ int type;
+ char *name;
+ char *index_expr;
+ char *machmodel;
+ char mnemonic;
+ char *short_description;
+ char *long_description;
+};
+
+class MemorySpace
+{
+public:
+
+ MemorySpace (DbeView *_dbev, int subtype);
+ ~MemorySpace ();
+
+ void reset (void);
+
+ int
+ getMemObjType (void)
+ {
+ return mstype;
+ }
+
+ char *
+ getMemObjTypeName (void)
+ {
+ return msname;
+ }
+
+ Expression *
+ getMemObjDef (void)
+ {
+ return msindex_exp;
+ }
+
+ // static members, used to define or fetch the various MemorySpaces
+ static void get_filter_keywords (Vector <void*> *res);
+ static Vector<void*> *getMemObjects (void);
+ static void set_MemTabOrder (Vector<int> *);
+ static char *mobj_define (char *, char *, char *, char *, char *);
+ static char *mobj_delete (char *);
+ static MemObjType_t *findMemSpaceByName (const char *mname);
+ static MemObjType_t *findMemSpaceByIndex (int index);
+ static char pickMnemonic (char *name);
+ static Vector<char *> *getMachineModelMemObjs (char *);
+
+private:
+ HashMap<uint64_t, MemObj*> *objs;
+ int findMemObject (uint64_t indx);
+ MemObj *lookupMemObject (Experiment *exp, DataView*, long);
+ MemObj *createMemObject (uint64_t, char *moname);
+
+ int mstype; // type of this memory space
+ char *msname; // name of this memory space
+ Expression *msindex_exp; // index-expression for this memory space
+ char *msindex_exp_str; // string for index-expression
+ Hist_data *hist_data_all; // the cached data for mode=Hist_Data::ALL
+ uint64_t selected_mo_index; // which page, cacheline, etc.
+ int sel_ind; // index of selected object in list
+ DbeView *dbev;
+ int phaseIdx;
+ uint64_t idx_min;
+ uint64_t idx_max;
+ MemObj *unk_memobj;
+ MemObj *total_memobj;
+};
+
+#endif /* _MEMORYSPACE_H */
diff --git a/gprofng/src/Metric.cc b/gprofng/src/Metric.cc
new file mode 100644
index 0000000..3b026ff
--- /dev/null
+++ b/gprofng/src/Metric.cc
@@ -0,0 +1,1660 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <strings.h>
+#include <limits.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Expression.h"
+#include "Metric.h"
+
+Metric::Metric (BaseMetric *item, SubType st) : BaseMetric (*item)
+{
+ name = NULL;
+ abbr = NULL;
+ abbr_unit = NULL;
+ baseMetric = item;
+ set_subtype (st);
+ visbits = VAL_NA;
+ if (item->get_type () == DERIVED)
+ visbits = VAL_VALUE;
+}
+
+Metric::Metric (const Metric& item) : BaseMetric (item)
+{
+ baseMetric = item.baseMetric;
+ subtype = item.subtype;
+ name = dbe_strdup (item.name);
+ abbr = dbe_strdup (item.abbr);
+ abbr_unit = dbe_strdup (item.abbr_unit);
+ visbits = item.visbits;
+}
+
+Metric::~Metric ()
+{
+ free (name);
+ free (abbr);
+ free (abbr_unit);
+}
+
+// Note that BaseMetric::get_vtype() has the base value type.
+// Here, we get the value type for the displayed metric,
+// which may be different if comparison is used.
+
+ValueTag
+Metric::get_vtype2 ()
+{
+ ValueTag vtype = get_vtype ();
+ if (visbits & VAL_DELTA)
+ {
+ switch (vtype)
+ {
+ case VT_ULLONG: return VT_LLONG;
+ default: return vtype;
+ }
+ }
+ if (visbits & VAL_RATIO)
+ {
+ switch (vtype)
+ {
+ case VT_INT:
+ case VT_LLONG:
+ case VT_ULLONG:
+ case VT_FLOAT:
+ case VT_DOUBLE: return VT_DOUBLE;
+ default: return vtype;
+ }
+ }
+ return vtype;
+}
+
+void
+Metric::set_subtype (SubType st)
+{
+ subtype = st;
+ free (name);
+ free (abbr);
+ free (abbr_unit);
+ name = NULL;
+ abbr = NULL;
+ abbr_unit = NULL;
+
+ switch (get_type ())
+ {
+ case CP_LMS_USER:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive User CPU Time"));
+ abbr = dbe_strdup (GTXT ("Excl. User CPU"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive User CPU Time"));
+ abbr = dbe_strdup (GTXT ("Incl. User CPU"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed User CPU Time"));
+ abbr = dbe_strdup (GTXT ("Attr. User CPU"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_USER metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ abort ();
+ }
+ break;
+
+ case CP_LMS_WAIT_CPU:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Wait CPU Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Wait CPU"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Wait CPU Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Wait CPU"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Wait CPU Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Wait CPU"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_WAIT_CPU metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_USER_LOCK:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive User Lock Time"));
+ abbr = dbe_strdup (GTXT ("Excl. User Lock"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive User Lock Time"));
+ abbr = dbe_strdup (GTXT ("Incl. User Lock"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed User Lock Time"));
+ abbr = dbe_strdup (GTXT ("Attr. User Lock"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_USER_LOCK metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_SYSTEM:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive System CPU Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Sys. CPU"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive System CPU Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Sys. CPU"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed System CPU Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Sys. CPU"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_SYSTEM metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case SYNC_WAIT_TIME:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Sync Wait Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Sync Wait"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Sync Wait Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Sync Wait"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Sync Wait Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Sync Wait"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected LWT metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_TFAULT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Text Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Text Fault"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Text Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Text Fault"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Text Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Text Fault"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_TFAULT metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_DFAULT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Data Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Data Fault"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Data Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Data Fault"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Data Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Data Fault"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_DFAULT metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_KERNEL_CPU:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Kernel CPU Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Kernel CPU"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Kernel CPU Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Kernel CPU"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Kernel CPU Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Kernel CPU"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_KERNEL_CPU metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case HWCNTR:
+ {
+ char *sstr, *estr1, *estr2;
+ if (get_hw_ctr () == NULL)
+ abort ();
+ sstr = get_username ();
+ if (st == EXCLUSIVE)
+ {
+ estr1 = GTXT ("Exclusive ");
+ estr2 = GTXT ("Excl. ");
+ }
+ else if (st == INCLUSIVE)
+ {
+ estr1 = GTXT ("Inclusive ");
+ estr2 = GTXT ("Incl. ");
+ }
+ else if (st == ATTRIBUTED)
+ {
+ estr1 = GTXT ("Attributed ");
+ estr2 = GTXT ("Attr. ");
+ }
+ else if (st == DATASPACE)
+ {
+ estr1 = GTXT ("Data-derived ");
+ estr2 = GTXT ("Data. ");
+ }
+ else
+ {
+ estr1 = dbe_sprintf (GTXT ("Unexpected hwc %s metric subtype %d"),
+ get_aux (), st);
+ estr2 = dbe_strdup (NTXT ("??"));
+ }
+ name = dbe_sprintf (NTXT ("%s%s"), estr1, sstr);
+ abbr = dbe_sprintf (NTXT ("%s%s"), estr2, sstr);
+ break;
+ }
+
+ case DERIVED:
+ {
+ switch (st)
+ {
+ case EXCLUSIVE:
+ name = dbe_sprintf (GTXT ("Exclusive %s"), get_username ());
+ abbr = dbe_sprintf (GTXT ("Excl. %s"), get_cmd ());
+ break;
+ case INCLUSIVE:
+ name = dbe_sprintf (GTXT ("Inclusive %s"), get_username ());
+ abbr = dbe_sprintf (GTXT ("Incl. %s"), get_cmd ());
+ break;
+ case ATTRIBUTED:
+ name = dbe_sprintf (GTXT ("Attributed %s"), get_username ());
+ abbr = dbe_sprintf (GTXT ("Attr. %s"), get_cmd ());
+ break;
+ default:
+ name = dbe_sprintf (GTXT ("Unexpected derived %s metric subtype %d"),
+ get_username (), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ break;
+ }
+ break;
+ }
+
+ case OMP_MASTER_THREAD:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Master Thread Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Master Thread"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Master Thread Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Master Thread"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Master Thread Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Master Thread"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected Master Thread metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_TOTAL:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Total Thread Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Total Thread"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Total Thread Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Total Thread"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Total Thread Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Total Thread"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected TOTAL metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case SYNC_WAIT_COUNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Sync Wait Count"));
+ abbr = dbe_strdup (GTXT ("Excl. Sync Wait Count"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Sync Wait Count"));
+ abbr = dbe_strdup (GTXT ("Incl. Sync Wait Count"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Sync Wait Count"));
+ abbr = dbe_strdup (GTXT ("Attr. Sync Wait Count"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected LWCNT metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_TOTAL_CPU:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Total CPU Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Total CPU"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Total CPU Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Total CPU"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Total CPU Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Total CPU"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected TOTAL_CPU metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case CP_LMS_TRAP:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Trap CPU Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Trap CPU"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Trap CPU Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Trap CPU"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Trap CPU Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Trap CPU"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_TRAP metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_KFAULT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Kernel Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Kernel Page Fault"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Kernel Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Kernel Page Fault"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Kernel Page Fault Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Kernel Page Fault"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_KFAULT metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_SLEEP:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Sleep Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Sleep"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Sleep Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Sleep"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Sleep Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Sleep"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_SLEEP metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case CP_LMS_STOPPED:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Stopped Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Stopped"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Stopped Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Stopped"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Stopped Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Stopped"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected CP_LMS_STOPPED metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case HEAP_ALLOC_BYTES:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Bytes Allocated"));
+ abbr = dbe_strdup (GTXT ("Excl. Bytes Allocated"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Bytes Allocated"));
+ abbr = dbe_strdup (GTXT ("Incl. Bytes Allocated"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Bytes Allocated"));
+ abbr = dbe_strdup (GTXT ("Attr. Bytes Allocated"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected BYTES_MALLOCD metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case HEAP_ALLOC_CNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Allocations"));
+ abbr = dbe_strdup (GTXT ("Excl. Allocations"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Allocations"));
+ abbr = dbe_strdup (GTXT ("Incl. Allocations"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Allocations"));
+ abbr = dbe_strdup (GTXT ("Attr. Allocations"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected MALLOCS metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case HEAP_LEAK_BYTES:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Bytes Leaked"));
+ abbr = dbe_strdup (GTXT ("Excl. Bytes Leaked"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Bytes Leaked"));
+ abbr = dbe_strdup (GTXT ("Incl. Bytes Leaked"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Bytes Leaked"));
+ abbr = dbe_strdup (GTXT ("Attr. Bytes Leaked"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected BYTES_LEAKED metric subtype %d"),
+ st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case HEAP_LEAK_CNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Leaks"));
+ abbr = dbe_strdup (GTXT ("Excl. Leaks"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Leaks"));
+ abbr = dbe_strdup (GTXT ("Incl. Leaks"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Leaks"));
+ abbr = dbe_strdup (GTXT ("Attr. Leaks"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected LEAKS metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_READ_BYTES:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Read Bytes"));
+ abbr = dbe_strdup (GTXT ("Excl. Read Bytes"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Read Bytes"));
+ abbr = dbe_strdup (GTXT ("Incl. Read Bytes"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Read Bytes"));
+ abbr = dbe_strdup (GTXT ("Attr. Read Bytes"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected READ_BYTES metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_WRITE_BYTES:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Write Bytes"));
+ abbr = dbe_strdup (GTXT ("Excl. Write Bytes"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Write Bytes"));
+ abbr = dbe_strdup (GTXT ("Incl. Write Bytes"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Write Bytes"));
+ abbr = dbe_strdup (GTXT ("Attr. Write Bytes"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected WRITE_BYTES metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_READ_CNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Read Count"));
+ abbr = dbe_strdup (GTXT ("Excl. Read Count"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Read Count"));
+ abbr = dbe_strdup (GTXT ("Incl. Read Count"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Read Count"));
+ abbr = dbe_strdup (GTXT ("Attr. Read Count"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected READCNT metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_WRITE_CNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Write Count"));
+ abbr = dbe_strdup (GTXT ("Excl. Write Count"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Write Count"));
+ abbr = dbe_strdup (GTXT ("Incl. Write Count"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Write Count"));
+ abbr = dbe_strdup (GTXT ("Attr. Write Count"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected WRITECNT metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_OTHER_CNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Other I/O Count"));
+ abbr = dbe_strdup (GTXT ("Excl. Other I/O Count"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Other I/O Count"));
+ abbr = dbe_strdup (GTXT ("Incl. Other I/O Count"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Other I/O Count"));
+ abbr = dbe_strdup (GTXT ("Attr. Other I/O Count"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OTHERIOCNT metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_ERROR_CNT:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive I/O Error Count"));
+ abbr = dbe_strdup (GTXT ("Excl. I/O Error Count"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive I/O Error Count"));
+ abbr = dbe_strdup (GTXT ("Incl. I/O Error Count"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed I/O Error Count"));
+ abbr = dbe_strdup (GTXT ("Attr. I/O Error Count"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected IOERRORCNT metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_READ_TIME:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Read Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Read Time"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Read Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Read Time"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Read Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Read Time"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected READ_TIME metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_WRITE_TIME:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Write Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Write Time"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Write Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Write Time"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Write Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Write Time"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected WRITE_TIME metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_OTHER_TIME:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Other I/O Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Other I/O Time"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Other I/O Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Other I/O Time"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Other I/O Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Other I/O Time"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OTHERIO_TIME metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case IO_ERROR_TIME:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive I/O Error Time"));
+ abbr = dbe_strdup (GTXT ("Excl. I/O Error Time"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive I/O Error Time"));
+ abbr = dbe_strdup (GTXT ("Incl. I/O Error Time"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed I/O Error Time"));
+ abbr = dbe_strdup (GTXT ("Attr. I/O Error Time"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected IOERROR_TIME metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+
+ case SIZES:
+ name = dbe_strdup (GTXT ("Size"));
+ abbr = dbe_strdup (GTXT ("Size"));
+ abbr_unit = dbe_strdup (GTXT ("bytes"));
+ break;
+
+ case ADDRESS:
+ name = dbe_strdup (GTXT ("PC Address"));
+ abbr = dbe_strdup (GTXT ("PC Addr."));
+ break;
+
+ case ONAME:
+ name = dbe_strdup (GTXT ("Name"));
+ abbr = dbe_strdup (GTXT ("Name"));
+ break;
+
+ case OMP_NONE:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Non-OpenMP Time"));
+ abbr = dbe_strdup (GTXT ("Excl. Non-OMP"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Non-OpenMP Time"));
+ abbr = dbe_strdup (GTXT ("Incl. Non-OMP"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Non-OpenMP Time"));
+ abbr = dbe_strdup (GTXT ("Attr. Non-OMP"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected Non-OpenMP metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_OVHD:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Overhead Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP ovhd."));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Overhead Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP ovhd."));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Overhead Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP ovhd."));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Overhead metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_WORK:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Work Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP Work"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Work Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP Work"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Work Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP Work"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Work metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_IBAR:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Implicit Barrier Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP i-barr."));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Implicit Barrier Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP i-barr."));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Implicit Barrier Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP i-barr."));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Implicit Barrier metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_EBAR:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Explicit Barrier Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP e-barr."));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Explicit Barrier Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP e-barr."));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Explicit Barrier Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP e-barr."));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Explicit Barrier metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_WAIT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Wait Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP Wait"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Wait Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP Wait"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Wait Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP Wait"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Wait metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_SERL:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Serial Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP serl"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Serial Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP serl"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Serial Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP serl"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Slave Idle metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_RDUC:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Reduction Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP rduc"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Reduction Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP rduc"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Reduction Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP rduc"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Reduction metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_LKWT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Lock Wait Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP lkwt"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Lock Wait Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP lkwt"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Lock Wait Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP lkwt"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Lock Wait metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_CTWT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Critical Section Wait Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP ctwt"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Critical Section Wait Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP ctwt"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Critical Section Wait Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP ctwt"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Critical Section Wait metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_ODWT:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Ordered Section Wait Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP odwt"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Ordered Section Wait Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP odwt"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Ordered Section Wait Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP odwt"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Ordered Section Wait metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_MSTR:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Master Serial Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP ser."));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Master Serial Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP ser."));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Master Serial Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP ser."));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Master Serial metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_SNGL:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Single Region Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP sngl"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Single Region Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP sngl"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Single Region Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP sngl"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Single Region metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case OMP_ORDD:
+ abbr_unit = dbe_strdup (GTXT ("sec."));
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive OpenMP Ordered Region Time"));
+ abbr = dbe_strdup (GTXT ("Excl. OMP ordd"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive OpenMP Ordered Region Time"));
+ abbr = dbe_strdup (GTXT ("Incl. OMP ordd"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed OpenMP Ordered Region Time"));
+ abbr = dbe_strdup (GTXT ("Attr. OMP ordd"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected OpenMP Ordered Region metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case RACCESS:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Race Accesses"));
+ abbr = dbe_strdup (GTXT ("Excl. Race Accesses"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Race Accesses"));
+ abbr = dbe_strdup (GTXT ("Incl. Race Accesses"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Race Accesses"));
+ abbr = dbe_strdup (GTXT ("Attr. Race Accesses"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected Race Access metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ case DEADLOCKS:
+ if (st == EXCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Exclusive Deadlocks"));
+ abbr = dbe_strdup (GTXT ("Excl. Deadlocks"));
+ }
+ else if (st == INCLUSIVE)
+ {
+ name = dbe_strdup (GTXT ("Inclusive Deadlocks"));
+ abbr = dbe_strdup (GTXT ("Incl. Deadlocks"));
+ }
+ else if (st == ATTRIBUTED)
+ {
+ name = dbe_strdup (GTXT ("Attributed Deadlocks"));
+ abbr = dbe_strdup (GTXT ("Attr. Deadlocks"));
+ }
+ else
+ {
+ name = dbe_sprintf (GTXT ("Unexpected Deadlocks metric subtype %d"), st);
+ abbr = dbe_strdup (NTXT ("??"));
+ }
+ break;
+ default:
+ abort ();
+ }
+} //Metric::set_subtype
+
+static bool
+is_width_ok (int lines, size_t width, size_t *tlen, int last)
+{
+ size_t len = 0;
+ for (int i = 0; i <= last; i++)
+ {
+ if (len != 0)
+ len++;
+ if (len + tlen[i] > width)
+ {
+ if (--lines == 0)
+ return false;
+ len = 0;
+ }
+ len += tlen[i];
+ }
+ return true;
+}
+
+void
+Metric::legend_width (HistMetric *hitem, int gap)
+{
+ size_t tlen[MAX_LEN];
+ char *tok[MAX_LEN], buf[MAX_LEN], unit[MAX_LEN];
+ hitem->width = hitem->maxtime_width;
+ if (hitem->maxvalue_width > 0)
+ {
+ if (hitem->width > 0)
+ hitem->width++;
+ hitem->width += hitem->maxvalue_width;
+ }
+ if (is_pvisible ())
+ {
+ if (hitem->width > 0)
+ {
+ hitem->width++;
+ }
+ hitem->width += 6; // adjust to change format from xx.yy%
+ }
+ snprintf (buf, sizeof (buf), "%s", get_abbr ());
+ size_t max_len = hitem->width;
+ if (legend)
+ {
+ size_t legend_len = strlen (legend);
+ if (max_len < legend_len)
+ max_len = legend_len;
+ }
+ tok[0] = buf;
+ int last = 0;
+ for (int i = 0;; i++)
+ {
+ if (buf[i] == ' ')
+ {
+ buf[i] = '\0';
+ while (buf[i + 1] == ' ')
+ i++;
+ tlen[last] = strlen (tok[last]);
+ if (max_len < tlen[last])
+ max_len = tlen[last];
+ last++;
+ tok[last] = buf + i + 1;
+ }
+ else if (buf[i] == '\0')
+ {
+ tlen[last] = strlen (tok[last]);
+ if (max_len < tlen[last])
+ max_len = tlen[last];
+ if (tlen[last] == 0 && last > 0)
+ last--;
+ break;
+ }
+ }
+
+ *unit = '\0'; // get the extra unit tokens
+ int max_lines = 3;
+ if (is_tvisible ())
+ {
+ char *s = GTXT ("sec.");
+ if ((get_visbits () & VAL_DELTA) != 0)
+ s = GTXT ("delta");
+ else if ((get_visbits () & VAL_RATIO) != 0)
+ s = GTXT ("ratio");
+ long len = strlen (s);
+ if (hitem->maxtime_width < len)
+ {
+ hitem->width += len - hitem->maxtime_width;
+ hitem->maxtime_width = len;
+ }
+ snprintf (unit, sizeof (unit), "%*s", (int) hitem->maxtime_width, s);
+ }
+ if (is_visible ())
+ {
+ char *s = NTXT ("");
+ if (!is_tvisible ())
+ {
+ if ((get_visbits () & VAL_DELTA) != 0)
+ s = GTXT ("delta");
+ else if ((get_visbits () & VAL_RATIO) != 0)
+ s = GTXT ("ratio");
+ else if ((get_value_styles () & VAL_TIMEVAL) != 0 && !is_time_val ())
+ s = GTXT ("sec.");
+ }
+ long len = strlen (s);
+ if (hitem->maxvalue_width < len)
+ {
+ hitem->width += len - hitem->maxvalue_width;
+ hitem->maxvalue_width = len;
+ }
+ if (*unit)
+ {
+ max_lines = 2;
+ len = strlen (unit);
+ snprintf (unit + len, sizeof (unit) - len, " %*s",
+ (int) hitem->maxvalue_width, s);
+ }
+ else
+ snprintf (unit, sizeof (unit), "%*s", (int) hitem->maxvalue_width, s);
+ }
+ if (is_pvisible ())
+ {
+ max_lines = 2;
+ if (*unit)
+ {
+ size_t len = strlen (unit);
+ snprintf (unit + len, sizeof (unit) - len, GTXT (" %%"));
+ }
+ else
+ snprintf (unit, sizeof (unit), GTXT (" %%"));
+ }
+ for (size_t i = strlen (unit); i > 0;)
+ { // remove trailing spaces
+ i--;
+ if (unit[i] != ' ')
+ break;
+ unit[i] = 0;
+ }
+
+ if (*unit)
+ {
+ last++;
+ tlen[last] = strlen (unit);
+ tok[last] = unit;
+ if (max_len < tlen[last])
+ max_len = tlen[last];
+ if (max_lines == 3 && *unit == ' ')
+ {
+ char *str = unit;
+ while (*str == ' ')
+ str++;
+ tlen[last] = strlen (str);
+ tok[last] = str;
+ }
+ }
+
+ int last1 = max_lines == 3 ? last : last - 1;
+ while (!is_width_ok (max_lines, max_len, tlen, last1))
+ max_len++;
+ hitem->width = max_len + gap;
+
+ char *legends[3];
+ legends[0] = hitem->legend1;
+ legends[1] = hitem->legend2;
+ legends[2] = hitem->legend3;
+ for (int i = 0, ind = 0; i < 3; i++)
+ {
+ char *str = legends[i];
+ *str = 0;
+ for (; ind <= last; ind++)
+ {
+ if (*unit && (ind == last))
+ {
+ // Try to put 'unit' in 'legend3'
+ if (i != 2)
+ {
+ tok[last] = unit; // restore a formated 'unit'
+ break;
+ }
+ }
+ size_t len = strlen (str);
+ if (len != 0)
+ {
+ if (len + 1 + tlen[ind] > max_len)
+ break;
+ snprintf (str + len, MAX_LEN - len, NTXT (" %s"), tok[ind]);
+ }
+ else
+ {
+ if (len + tlen[ind] > max_len)
+ break;
+ snprintf (str + len, MAX_LEN - len, NTXT ("%s"), tok[ind]);
+ }
+ }
+ }
+}
+
+int
+Metric::get_real_visbits ()
+{
+ int v = visbits;
+ if (!is_time_val () && (visbits & (VAL_TIMEVAL | VAL_VALUE)) != 0)
+ {
+ v &= ~(VAL_TIMEVAL | VAL_VALUE);
+ v |= (get_value_styles () & (VAL_TIMEVAL | VAL_VALUE));
+ }
+ return v;
+}
+
+char *
+Metric::get_vis_string (int vis)
+{
+ char *vis_str;
+ if (subtype == STATIC)
+ vis_str = NTXT ("");
+ else
+ {
+ int v;
+ if (is_time_val ())
+ v = vis & (VAL_TIMEVAL | VAL_VALUE | VAL_PERCENT);
+ else
+ {
+ v = vis & VAL_PERCENT;
+ if ((vis & (VAL_TIMEVAL | VAL_VALUE)) != 0)
+ v |= (get_value_styles () & (VAL_TIMEVAL | VAL_VALUE));
+ }
+ switch (v)
+ {
+ case VAL_TIMEVAL:
+ vis_str = NTXT (".");
+ break;
+ case VAL_VALUE:
+ vis_str = NTXT ("+");
+ break;
+ case VAL_TIMEVAL | VAL_VALUE:
+ vis_str = NTXT (".+");
+ break;
+ case VAL_PERCENT:
+ vis_str = NTXT ("%");
+ break;
+ case VAL_TIMEVAL | VAL_PERCENT:
+ vis_str = NTXT (".%");
+ break;
+ case VAL_VALUE | VAL_PERCENT:
+ vis_str = NTXT ("+%");
+ break;
+ case VAL_TIMEVAL | VAL_VALUE | VAL_PERCENT:
+ vis_str = NTXT (".+%");
+ break;
+ default:
+ vis_str = NTXT ("!");
+ break;
+ }
+ }
+ return vis_str;
+}
+
+char *
+Metric::get_vis_str ()
+{
+ char *vis_str = NULL;
+ if (visbits == -1)
+ {
+ // unitialized, return all possible with a trailing -
+ if (subtype == STATIC)
+ vis_str = NTXT (".-");
+ else if (is_time_val ())
+ vis_str = NTXT (".+%-");
+ else
+ vis_str = NTXT (".%-");
+ }
+ else
+ vis_str = get_vis_string (get_real_visbits ());
+ return vis_str;
+}
+
+void
+Metric::set_dmetrics_visbits (int dmetrics_visbits)
+{
+ visbits = VAL_NA; // clear global state
+
+ // process the "show" bits
+ int _visbits = dmetrics_visbits & ~VAL_HIDE_ALL;
+ assert (_visbits != -1);
+ if (_visbits == 0)
+ return; // done. (Ignore VAL_HIDE_ALL since there's nothing to hide.)
+ if (get_subtype () == STATIC)
+ // percent, time value not applicable
+ visbits = VAL_VALUE;
+ else
+ {
+ // now or in the bits, but manage . and + according to the is_time_val setting
+ if (is_time_val () == 0)
+ {
+ if ((_visbits & VAL_VALUE) || (_visbits & VAL_TIMEVAL))
+ visbits |= VAL_VALUE;
+ }
+ else
+ visbits |= (_visbits & (VAL_VALUE | VAL_TIMEVAL));
+ visbits |= (_visbits & (VAL_PERCENT | VAL_RATIO | VAL_DELTA));
+ }
+ // process the "hide" bit
+ if (dmetrics_visbits & VAL_HIDE_ALL)
+ visbits |= VAL_HIDE_ALL;
+}
+
+void
+Metric::set_vvisible (bool set)
+{
+ if (set)
+ {
+ visbits |= VAL_VALUE;
+ visbits &= ~VAL_HIDE_ALL;
+ }
+ else
+ visbits &= ~VAL_VALUE;
+}
+
+void
+Metric::set_tvisible (bool set)
+{
+ if (set)
+ {
+ visbits |= VAL_TIMEVAL;
+ visbits &= ~VAL_HIDE_ALL;
+ }
+ else
+ visbits &= ~VAL_TIMEVAL;
+}
+
+void
+Metric::set_pvisible (bool set)
+{
+ if (set)
+ {
+ visbits |= VAL_PERCENT;
+ visbits &= ~VAL_HIDE_ALL;
+ }
+ else
+ visbits &= ~VAL_PERCENT;
+}
+
+char *
+Metric::get_mcmd (bool allPossible)
+{
+ char *sc = NTXT (""); // subtype == STATIC
+ char *hide;
+ char *vis = get_vis_string (allPossible ? get_value_styles ()
+ : get_real_visbits ());
+ if (subtype == INCLUSIVE)
+ sc = NTXT ("i");
+ else if (subtype == EXCLUSIVE)
+ sc = NTXT ("e");
+ else if (subtype == ATTRIBUTED)
+ sc = NTXT ("a");
+ else if (subtype == DATASPACE)
+ sc = NTXT ("d");
+ if (allPossible)
+ hide = NTXT ("");
+ else if (visbits == VAL_NA || (visbits & VAL_HIDE_ALL) != 0)
+ hide = NTXT ("!");
+ else
+ hide = NTXT ("");
+
+ char *mcmd = get_cmd ();
+ return dbe_sprintf (GTXT ("%s%s%s%s"), sc, hide, vis, mcmd);
+}
+
+char *
+Metric::dump ()
+{
+ int len = 4;
+ BaseMetric *bm = (BaseMetric *) this;
+ char *s = bm->dump ();
+ char *msg = dbe_sprintf ("%s\n%*c subtype=%d time_val=%d vis=%d tvis=%d"
+ " pvis=%d\n%*c abbr='%s' cmd='%s' name='%s'\n",
+ STR (s), len, ' ', get_subtype (), is_time_val (),
+ is_visible (), is_tvisible (), is_pvisible (),
+ len, ' ', STR (get_abbr ()), STR (get_cmd ()),
+ STR (get_name ()));
+ free (s);
+ return msg;
+}
+
diff --git a/gprofng/src/Metric.h b/gprofng/src/Metric.h
new file mode 100644
index 0000000..a2b3778
--- /dev/null
+++ b/gprofng/src/Metric.h
@@ -0,0 +1,188 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _METRIC_H
+#define _METRIC_H
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "enums.h"
+#include "BaseMetric.h"
+
+#define MAX_LEN 1024
+
+class Expression;
+
+// The metric class defines the metrics that are available. The metrics are
+// registered when the experiment's log file is read.
+class Metric : public BaseMetric
+{
+public:
+
+ typedef struct HistMetricS
+ {
+ int width;
+ int maxvalue_width;
+ int maxtime_width;
+ char legend1[MAX_LEN];
+ char legend2[MAX_LEN];
+ char legend3[MAX_LEN];
+ int indFirstExp; // only for -compare=[delta|ratio]
+ int indTimeVal; // only for HWC time-converted metrics
+ void update_max (struct HistMetricS *hm);
+ void init ();
+ } HistMetric;
+
+ Metric (const Metric& item); // copy constructor
+ Metric (BaseMetric *item, SubType st);
+ Metric (char *_name, SubType st); // for derived metrics
+ virtual ~Metric ();
+
+ char *get_mcmd (bool); // e.user, a.total, etc. NOTI18N
+ int get_real_visbits (); // methods for managing visibility
+ ValueTag get_vtype2 (); // takes comparison visbits into account
+ void set_dmetrics_visbits (int _dmetrics_visbits);
+
+ // fetch various fields from a Metric
+ SubType
+ get_subtype ()
+ {
+ return subtype;
+ }
+
+ char *
+ get_name ()
+ {
+ return name;
+ }
+
+ char *
+ get_abbr ()
+ {
+ return abbr;
+ }
+
+ char *
+ get_abbr_unit ()
+ {
+ return abbr_unit;
+ }
+
+ BaseMetric *
+ get_base_metric ()
+ {
+ return baseMetric;
+ }
+
+ int
+ get_visbits ()
+ {
+ return visbits;
+ }
+
+ void
+ set_raw_visbits (int _visbits)
+ {
+ visbits = _visbits;
+ }
+
+ void
+ clear_all_visbits ()
+ {
+ visbits = VAL_NA;
+ }
+
+ void
+ enable_all_visbits ()
+ {
+ visbits = get_value_styles ();
+ }
+
+
+#define VAL_IS_HIDDEN(n) ((n) == -1 || (n) == VAL_NA || ((n) & VAL_HIDE_ALL) != 0)
+
+ bool
+ is_any_visible ()
+ {
+ return !VAL_IS_HIDDEN (visbits)
+ && (visbits & (VAL_VALUE | VAL_TIMEVAL | VAL_PERCENT));
+ }
+
+ bool
+ is_value_visible ()
+ {
+ return (visbits & VAL_VALUE) != 0
+ || (!is_time_val () && (visbits & VAL_TIMEVAL) != 0);
+ }
+
+ bool
+ is_time_visible ()
+ {
+ return is_time_val () && (visbits & VAL_TIMEVAL) != 0;
+ }
+
+ bool
+ is_visible ()
+ {
+ return !VAL_IS_HIDDEN (visbits) && is_value_visible ();
+ }
+
+ bool
+ is_tvisible ()
+ {
+ return !VAL_IS_HIDDEN (visbits) && is_time_visible ();
+ }
+
+ bool
+ is_pvisible ()
+ {
+ return !VAL_IS_HIDDEN (visbits) && (visbits & VAL_PERCENT) != 0;
+ }
+
+ bool
+ is_time_val ()
+ {
+ int v = VAL_TIMEVAL | VAL_VALUE;
+ return (get_value_styles () & v) == v;
+ }
+
+ // per-bit handling of visbits
+ // Note: Forces VAL_HIDE_ALL to zero. Use only on temporary Metric objects.
+ void set_vvisible (bool set);
+ void set_tvisible (bool set);
+ void set_pvisible (bool set);
+
+ void set_subtype (SubType st);
+ void legend_width (HistMetric *hitem, int gap);
+ char *get_vis_str ();
+ char *get_vis_string (int vis);
+ char *dump ();
+
+
+private:
+ BaseMetric *baseMetric;
+ SubType subtype; // specific variant for this Metric
+ char *name;
+ char *abbr;
+ char *abbr_unit;
+ int visbits; // ValueType, e.g. VAL_VALUE|VAL_TIMEVAL
+};
+
+#endif /* _METRIC_H */
diff --git a/gprofng/src/MetricList.cc b/gprofng/src/MetricList.cc
new file mode 100644
index 0000000..7596524
--- /dev/null
+++ b/gprofng/src/MetricList.cc
@@ -0,0 +1,1075 @@
+/* Copyright (C) 2021 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 "Command.h"
+#include "DbeSession.h"
+#include "MetricList.h"
+#include "StringBuilder.h"
+
+// Build a metric reference list
+MetricList::MetricList (Vector<BaseMetric*> *base_metrics, MetricType _mtype)
+{
+ mtype = _mtype;
+ items = new Vector<Metric*>;
+ sort_ref_index = 0;
+ sort_reverse = false;
+
+ Metric *mitem;
+ // loop over the base_metrics, and add in all the appropriate subtypes
+ for (long i = 0, sz = base_metrics ? base_metrics->size () : 0; i < sz; i++)
+ {
+ BaseMetric *mtr = base_metrics->get (i);
+ if (mtr->is_internal ())
+ continue;
+ switch (mtype)
+ {
+ case MET_DATA:
+ if ((mtr->get_flavors () & BaseMetric::DATASPACE) != 0)
+ {
+ mitem = new Metric (mtr, BaseMetric::DATASPACE);
+ items->append (mitem);
+ }
+ break;
+
+ case MET_INDX:
+ {
+ if ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0
+ || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0)
+ {
+ int index2;
+ Metric *item2 = NULL;
+ bool found = false;
+ Vec_loop (Metric*, items, index2, item2)
+ {
+ if (item2->get_subtype () == BaseMetric::EXCLUSIVE
+ && dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == false)
+ {
+ mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+ items->append (mitem);
+ }
+ }
+ }
+ break;
+
+ case MET_CALL:
+ case MET_CALL_AGR:
+ if ((mtr->get_flavors () & BaseMetric::ATTRIBUTED) != 0)
+ {
+ mitem = new Metric (mtr, BaseMetric::ATTRIBUTED);
+ items->append (mitem);
+ }
+ // now fall through to add exclusive and inclusive
+
+ case MET_NORMAL:
+ case MET_COMMON:
+ if (mtr->get_flavors () & BaseMetric::EXCLUSIVE)
+ {
+ mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+ items->append (mitem);
+ }
+ if (mtr->get_flavors () & BaseMetric::INCLUSIVE)
+ {
+ mitem = new Metric (mtr, BaseMetric::INCLUSIVE);
+ items->append (mitem);
+ }
+ break;
+ case MET_SRCDIS:
+ if (mtr->get_flavors () & BaseMetric::INCLUSIVE)
+ {
+ mitem = new Metric (mtr, BaseMetric::INCLUSIVE);
+ items->append (mitem);
+ }
+ break;
+ case MET_IO:
+ {
+ if (mtr->get_packet_type () == DATA_IOTRACE
+ && ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0
+ || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0))
+ {
+ int index2;
+ Metric *item2 = NULL;
+ bool found = false;
+ Vec_loop (Metric*, items, index2, item2)
+ {
+ if (item2->get_subtype () == BaseMetric::EXCLUSIVE
+ && dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == false)
+ {
+ mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+ items->append (mitem);
+ }
+ }
+ }
+ break;
+ case MET_HEAP:
+ {
+ if (mtr->get_packet_type () == DATA_HEAP
+ && ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0
+ || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0))
+ {
+ int index2;
+ Metric *item2 = NULL;
+ bool found = false;
+ Vec_loop (Metric*, items, index2, item2)
+ {
+ if ((item2->get_subtype () == BaseMetric::EXCLUSIVE) &&
+ (dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == false)
+ {
+ mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+ items->append (mitem);
+ }
+ }
+ }
+ break;
+ }
+
+ // add the static
+ if (mtr->get_flavors () & BaseMetric::STATIC)
+ {
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ case MET_COMMON:
+ case MET_CALL:
+ case MET_CALL_AGR:
+ case MET_SRCDIS:
+ mitem = new Metric (mtr, BaseMetric::STATIC);
+ items->append (mitem);
+ break;
+ default:
+ if (mtr->get_type () == BaseMetric::ONAME)
+ {
+ mitem = new Metric (mtr, BaseMetric::STATIC);
+ items->append (mitem);
+ }
+ break;
+ }
+ }
+ }
+ // set all metrics visible
+ for (long i = 0, sz = items ? items->size () : 0; i < sz; i++)
+ items->get (i)->enable_all_visbits ();
+}
+
+// Constructor for an empty list -- items will be added one at a time
+MetricList::MetricList (MetricType _mtype)
+{
+ mtype = _mtype;
+ items = new Vector<Metric*>;
+ sort_ref_index = 0;
+ sort_reverse = false;
+}
+
+MetricList::~MetricList ()
+{
+ Destroy (items);
+}
+
+// Duplicate a metric list
+MetricList::MetricList (MetricList *old)
+{
+ mtype = old->mtype;
+
+ // get an empty vector
+ items = new Vector<Metric*>;
+ Metric *item;
+ Metric *nitem;
+ int index;
+ sort_ref_index = old->get_sort_ref_index ();
+ sort_reverse = old->get_sort_rev ();
+ Vec_loop (Metric*, old->items, index, item)
+ {
+ nitem = new Metric (*item);
+ items->append (nitem);
+ }
+}
+
+// set_metrics:
+// Sets the particular metric list, according to the metric spec
+// If fromRcFile, updates dbeSession->get_reg_metrics_tree() with new defaults.
+char *
+MetricList::set_metrics (const char *mspec, bool fromRcFile,
+ DerivedMetrics * /* derived_metrics */)
+{
+ BaseMetric::SubType subtypes[10];
+ int nsubtypes;
+ int dmetrics_vis; // literal translation of metrics/dmetrics %.+
+ bool parseOK = false;
+ char *errbuf;
+ Vector<Metric*> *old_items = items;
+ items = new Vector<Metric*>;
+ Vector<BaseMetric*> *base_items = dbeSession->get_base_reg_metrics ();
+
+ // and copy the input specification
+ char *buf = dbe_strdup (mspec);
+
+ // append metric items from parsing the string
+ for (char *mcmd = strtok (buf, NTXT (":")); mcmd != NULL;
+ mcmd = strtok (NULL, NTXT (":")))
+ {
+ // parse the single metric_spec, based on the type of list being constructed, into:
+ // a vector of SubTypes (any of [iead] or STATIC)
+ // a integer mask for the visibility bits
+ // and the string name of the base metric
+ // it might be "all", "any", or "hwc" or it should match a metric in the list
+ // it might also be "bit", meaning any bit-computed metric
+ char *mname = parse_metric_spec (mcmd, subtypes, &nsubtypes,
+ &dmetrics_vis, &parseOK);
+ if (!parseOK)
+ {
+ // error parsing the metric specification
+ // not from an rc file, it's an error
+ if (!fromRcFile)
+ {
+ delete base_items;
+ items->destroy ();
+ delete items;
+ items = old_items;
+ free (buf);
+ return mname;
+ }
+ continue;
+ }
+
+ // loop over subtypes requested
+ // set the visibility of and sort order according to the vis bits,
+ // and the order of encounter in the processing
+ int ret = add_matching_dmetrics (base_items, mname, subtypes, nsubtypes,
+ dmetrics_vis, fromRcFile);
+ if (ret != 0 && !fromRcFile)
+ {
+ if (ret == 1)
+ errbuf = dbe_sprintf (GTXT ("No data recorded to support metric specification: %s\n"),
+ mcmd);
+ else
+ errbuf = dbe_sprintf (GTXT ("Metric specification for `%s' has appeared before in %s"),
+ mcmd, mspec);
+ delete base_items;
+ items->destroy ();
+ delete items;
+ items = old_items;
+ free (buf);
+ return errbuf;
+ }
+ } // we've processed the entire spec
+
+ // update metric defaults
+ if (fromRcFile)
+ {
+ for (long i = 0, sz = items->size (); i < sz; i++)
+ {
+ Metric *m = items->get (i);
+ int visbits = m->get_visbits ();
+ BaseMetric::SubType subtype = m->get_subtype ();
+ BaseMetric *reg_bm = m->get_base_metric ();
+ reg_bm->set_default_visbits (subtype, visbits);
+ BaseMetricTreeNode *mtree = dbeSession->get_reg_metrics_tree ();
+ BaseMetricTreeNode *bmtnode = mtree->register_metric (m);
+ BaseMetric *tree_bm = bmtnode->get_BaseMetric ();
+ tree_bm->set_default_visbits (subtype, visbits);
+ }
+ }
+
+ // ensure that name is present, remove hidden metrics
+ nsubtypes = 1;
+ for (long i = items->size () - 1; i >= 0; i--)
+ {
+ Metric *m = items->fetch (i);
+ if (!m->is_any_visible ())
+ {
+ delete m;
+ items->remove (i);
+ continue;
+ }
+ if (m->get_type () == BaseMetric::ONAME)
+ nsubtypes = 0;
+ }
+
+ // did we get at least one valid match?
+ if (items->size () == 0 && !fromRcFile)
+ {
+ errbuf = dbe_sprintf (GTXT ("No valid metrics specified in `%s'\n"), mspec);
+ delete base_items;
+ items->destroy ();
+ delete items;
+ items = old_items;
+ free (buf);
+ return errbuf;
+ }
+
+ if (nsubtypes == 1)
+ {
+ subtypes[0] = BaseMetric::STATIC;
+ (void) add_matching_dmetrics (base_items, NTXT ("name"), subtypes, 1, VAL_VALUE, true);
+ }
+
+ // replace the old list of items, with the new set
+ if (old_items)
+ {
+ old_items->destroy ();
+ delete old_items;
+ }
+ set_fallback_sort ();
+ free (buf);
+ delete base_items;
+ return NULL;
+}
+
+void
+MetricList::set_fallback_sort ()
+{
+ // sort by first visible of the appropriate flavor
+ char *sortcmd = NULL;
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ case MET_COMMON:
+ sortcmd = NTXT ("ei.any:name");
+ break;
+ case MET_SRCDIS:
+ sortcmd = NTXT ("i.any:name");
+ break;
+ case MET_CALL:
+ case MET_CALL_AGR:
+ sortcmd = NTXT ("a.any:name");
+ break;
+ case MET_DATA:
+ sortcmd = NTXT ("d.any:name");
+ break;
+ case MET_INDX:
+ sortcmd = NTXT ("e.any:name");
+ break;
+ case MET_IO:
+ sortcmd = NTXT ("e.any:name");
+ break;
+ case MET_HEAP:
+ sortcmd = NTXT ("e.any:name");
+ break;
+ }
+ if (NULL != sortcmd)
+ (void) set_sort (sortcmd, true);
+}
+
+void
+MetricList::set_metrics (MetricList *mlist)
+{
+ // verify that the type is appropriate for the call
+ if (mtype == MET_NORMAL || mtype == MET_COMMON
+ || (mlist->mtype != MET_NORMAL && mlist->mtype != MET_COMMON))
+ abort ();
+
+ Vector<Metric*> *mlist_items = mlist->get_items ();
+ items->destroy ();
+ items->reset ();
+
+ int sort_ind = mlist->get_sort_ref_index ();
+ for (int i = 0, mlist_sz = mlist_items->size (); i < mlist_sz; i++)
+ {
+ Metric *mtr = mlist_items->fetch (i);
+ if (!mtr->is_any_visible ())
+ continue;
+
+ // Add a new Metric with probably a new sub_type to this->items:
+ // for MET_CALL and MET_CALL_AGR the matching entry to an e. or i. is itself
+ // for MET_DATA, the matching entry to an e. or i. is the d. metric
+ // for MET_INDX, the matching entry to an e. or i. is the e. metric
+ // for MET_IO, the matching entry to an e. or i. is the e. metric
+ // for MET_HEAP, the matching entry to an e. or i. is the e. metric
+ // Save static entries (SIZES and ADDRESS) only for MET_NORMAL, MET_CALL, MET_CALL_AGR, MET_SRCDIS
+ switch (mtr->get_type ())
+ {
+ case BaseMetric::SIZES:
+ case BaseMetric::ADDRESS:
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ case MET_COMMON:
+ case MET_CALL:
+ case MET_CALL_AGR:
+ case MET_SRCDIS:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+
+ BaseMetric::SubType st = mtr->get_subtype ();
+ if (st != BaseMetric::STATIC)
+ {
+ if (mtype == MET_CALL || mtype == MET_CALL_AGR)
+ {
+ if ((mtr->get_flavors () & BaseMetric::ATTRIBUTED) == 0)
+ continue;
+ st = BaseMetric::ATTRIBUTED;
+ }
+ else if (mtype == MET_DATA)
+ {
+ if ((mtr->get_flavors () & BaseMetric::DATASPACE) == 0)
+ continue;
+ st = BaseMetric::DATASPACE;
+ }
+ else if (mtype == MET_INDX)
+ {
+ if ((mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0)
+ continue;
+ st = BaseMetric::EXCLUSIVE;
+ }
+ else if (mtype == MET_IO)
+ {
+ if (mtr->get_packet_type () != DATA_IOTRACE ||
+ (mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0)
+ continue;
+ st = BaseMetric::EXCLUSIVE;
+ }
+ else if (mtype == MET_HEAP)
+ {
+ if (mtr->get_packet_type () != DATA_HEAP ||
+ (mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0)
+ continue;
+ st = BaseMetric::EXCLUSIVE;
+ }
+ else if (mtype == MET_SRCDIS)
+ {
+ if ((mtr->get_flavors () & BaseMetric::INCLUSIVE) == 0)
+ continue;
+ st = BaseMetric::INCLUSIVE;
+ }
+ }
+
+ bool found = false;
+ for (int i1 = 0, items_sz = items->size (); i1 < items_sz; i1++)
+ {
+ Metric *m1 = items->fetch (i1);
+ if (mtr->get_id () == m1->get_id () && st == m1->get_subtype ())
+ {
+ if (sort_ind == i)
+ sort_ind = i1;
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+ Metric *m = new Metric (*mtr);
+ m->set_subtype (st);
+ m->set_raw_visbits (mtr->get_visbits ());
+ if (sort_ind == i)
+ sort_ind = items->size ();
+ items->append (m);
+ }
+ if (sort_ind >= items->size ())
+ sort_ind = 0;
+ if (mtype == MET_IO)
+ sort_ind = 0;
+ if (mtype == MET_HEAP)
+ sort_ind = 0;
+ sort_ref_index = sort_ind;
+
+}
+
+
+// set_sort:
+// Sets the sort for the metric list to the first metric
+// in mspec that is present; if fromRcFile is false, then
+// only one metric may be specified. The requested sort
+// metric must be visible, or it won't be in the metric list
+
+char *
+MetricList::set_sort (const char *mspec, bool fromRcFile)
+{
+ char *mcmd;
+ BaseMetric::SubType subtypes[10];
+ int nsubtypes;
+ int vis;
+ bool parseOK = false;
+ bool reverse = false;
+ char buf[BUFSIZ];
+ char *list = buf;
+ char *mname;
+
+ // copy the input specification
+ snprintf (buf, sizeof (buf), NTXT ("%s"), mspec);
+ char *listp = list;
+ if (*listp == '-')
+ {
+ // reverse sort specified
+ reverse = true;
+ listp++;
+ }
+
+ // search for metric items from parsing the string
+ while ((mcmd = strtok (listp, NTXT (":"))) != NULL)
+ {
+ listp = NULL; // let strtok keep track
+
+ // parse the single metric_spec, based on the type of list being constructed, into:
+ // a vector of SubTypes (any of [iead] or STATIC)
+ // a integer mask for the visibility bits
+ // and the string name of the base metric
+ mname = parse_metric_spec (mcmd, subtypes, &nsubtypes, &vis, &parseOK);
+ if (!parseOK)
+ {
+ // error parsing the metric specification
+ // not from an rc file, it's an error
+ if (!fromRcFile)
+ return (mname);
+ continue;
+ }
+ if (VAL_IS_HIDDEN (vis))
+ continue;
+
+ // loop over subtypes requested to find metric
+ // add a metric of that subtype, with specified vis.bits
+ for (int i = 0; i < nsubtypes; i++)
+ {
+ // make sure the subtype is acceptable
+ if ((mtype == MET_CALL || mtype == MET_CALL_AGR)
+ && subtypes[i] != BaseMetric::ATTRIBUTED
+ && subtypes[i] != BaseMetric::STATIC)
+ return dbe_sprintf (GTXT ("Inclusive, Exclusive, or Data metrics cannot be specified for caller-callee sort: %s\n"),
+ mcmd);
+ if (mtype == MET_DATA && subtypes[i] != BaseMetric::DATASPACE
+ && subtypes[i] != BaseMetric::STATIC)
+ return dbe_sprintf (GTXT ("Inclusive, Exclusive, or Attributed metrics cannot be specified for data-derived sort: %s\n"),
+ mcmd);
+ if (mtype == MET_INDX && subtypes[i] != BaseMetric::EXCLUSIVE
+ && subtypes[i] != BaseMetric::STATIC)
+ return dbe_sprintf (GTXT ("Inclusive, Data or Attributed metrics cannot be specified for index sort: %s\n"),
+ mcmd);
+ if ((mtype == MET_NORMAL || mtype == MET_COMMON
+ || mtype == MET_SRCDIS)
+ && (subtypes[i] == BaseMetric::DATASPACE
+ || subtypes[i] == BaseMetric::ATTRIBUTED))
+ return dbe_sprintf (GTXT ("Data or Attributed metrics cannot be specified for sort: %s\n"), mcmd);
+ if (set_sort_metric (mname, subtypes[i], reverse))
+ return NULL;
+ }
+ // continue looking at entries
+ }
+
+ // not found on the list at all
+ switch (mtype)
+ {
+ case MET_NORMAL:
+ case MET_COMMON:
+ case MET_SRCDIS:
+ return dbe_sprintf (GTXT ("Invalid sort specification: %s\n"), mspec);
+ case MET_CALL:
+ case MET_CALL_AGR:
+ return dbe_sprintf (GTXT ("Invalid caller-callee sort specification: %s\n"),
+ mspec);
+ case MET_DATA:
+ return dbe_sprintf (GTXT ("Invalid data-derived sort specification: %s\n"),
+ mspec);
+ case MET_INDX:
+ return dbe_sprintf (GTXT ("Invalid index sort specification: %s\n"),
+ mspec);
+ case MET_IO:
+ return dbe_sprintf (GTXT ("Invalid I/O sort specification: %s\n"), mspec);
+ case MET_HEAP:
+ return dbe_sprintf (GTXT ("Invalid heap sort specification: %s\n"),
+ mspec);
+ }
+ return NULL;
+}
+
+// set_sort to the metric with the given visible index
+
+void
+MetricList::set_sort (int visindex, bool reverse)
+{
+ Metric *mitem;
+ if (visindex < items->size ())
+ {
+ mitem = items->fetch (visindex);
+ if (mitem->is_any_visible ())
+ {
+ sort_ref_index = visindex;
+ sort_reverse = reverse;
+ return;
+ }
+ }
+ set_fallback_sort ();
+}
+
+bool
+MetricList::set_sort_metric (char *mname, BaseMetric::SubType mst, bool reverse)
+{
+ bool any = false, hwc = false, bit = false;
+
+ // check keywords 'any', 'all', 'bit' and 'hwc'
+ if (!strcasecmp (mname, Command::ANY_CMD))
+ any = true;
+ else if (!strcasecmp (mname, Command::ALL_CMD))
+ any = true;
+ else if (!strcasecmp (mname, Command::HWC_CMD))
+ hwc = true;
+ else if (!strcasecmp (mname, Command::BIT_CMD))
+ bit = true;
+
+ for (int i = 0, items_sz = items->size (); i < items_sz; i++)
+ {
+ Metric *m = items->fetch (i);
+ if (mst == m->get_subtype ()
+ && (any || (hwc && m->get_type () == BaseMetric::HWCNTR)
+ || (bit && m->get_cmd ()
+ && strncmp (Command::BIT_CMD, m->get_cmd (),
+ strlen (Command::BIT_CMD)) == 0)
+ || dbe_strcmp (mname, m->get_cmd ()) == 0))
+ {
+ sort_ref_index = i;
+ sort_reverse = reverse;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Print to a file of a list of metrics from a supplied vector
+// Debug flag = 1, prints the short name and address of the list
+// Debug flag = 2, prints the details of the list
+void
+MetricList::print_metric_list (FILE *dis_file, char *leader, int debug)
+{
+ Metric *item;
+ int index;
+ char fmt_name[64];
+ fprintf (dis_file, NTXT ("%s"), leader);
+ if (items == NULL)
+ {
+ fprintf (dis_file, GTXT ("NULL metric list can not be printed; aborting"));
+ abort ();
+ }
+
+ if (items->size () == 0)
+ {
+ fprintf (dis_file, GTXT ("metric list is empty; aborting\n"));
+ abort ();
+ }
+
+ // if debugging, print list address and string, and sort name
+ if (debug != 0)
+ {
+ char *s = get_metrics ();
+ fprintf (dis_file, "\tmetriclist at 0x%lx: %s, %lld metrics; sort by %s\n",
+ (unsigned long) this, s, (long long) items->size (),
+ get_sort_name ());
+ free (s);
+ if (debug == 1)
+ return;
+ }
+
+ // Find the longest metric name & command
+ size_t max_len = 0;
+ size_t max_len2 = 0;
+
+ Vec_loop (Metric*, items, index, item)
+ {
+ // get the name
+ char *mn = item->get_name ();
+ size_t len = strlen (mn);
+ if (max_len < len)
+ max_len = len;
+
+ mn = item->get_mcmd (true);
+ len = strlen (mn);
+ if (max_len2 < len)
+ max_len2 = len;
+ free (mn);
+
+ }
+ if (debug == 2)
+ snprintf (fmt_name, sizeof (fmt_name), "%%%ds: %%-%ds", (int) max_len,
+ (int) max_len2);
+ else
+ snprintf (fmt_name, sizeof (fmt_name), "%%%ds: %%s", (int) max_len);
+
+ Vec_loop (Metric*, items, index, item)
+ {
+ char *mcmd = item->get_mcmd (true);
+ fprintf (dis_file, fmt_name, item->get_name (), mcmd);
+ free (mcmd);
+ if (debug == 2)
+ fprintf (dis_file, "\t[st %2d, VT %d, vis = %4s, T=%d, sort = %c]",
+ item->get_subtype (), item->get_vtype (),
+ item->get_vis_str (), item->is_time_val (),
+ sort_ref_index == index ? 'Y' : 'N');
+ fputc ('\n', dis_file);
+ }
+
+ fputc ('\n', dis_file);
+ fflush (dis_file);
+}
+
+// Return a string formatted from a vector of metrics
+// string is in the form suitable for a "metrics <string>" command
+char *
+MetricList::get_metrics ()
+{
+ Metric *item;
+ int index;
+ StringBuilder sb;
+ Vec_loop (Metric*, items, index, item)
+ {
+ if (sb.length () != 0)
+ sb.append (':');
+ char *mcmd = item->get_mcmd (false);
+ sb.append (mcmd);
+ free (mcmd);
+ }
+ return sb.toString ();
+}
+
+int
+MetricList::get_listorder (Metric *mtr)
+{
+ for (int i = 0, items_sz = items->size (); i < items_sz; i++)
+ {
+ Metric *m = items->fetch (i);
+ if (m->get_subtype () == mtr->get_subtype ()
+ && m->get_id () == mtr->get_id ())
+ return i;
+ }
+ return -1;
+}
+
+int
+MetricList::get_listorder (char *cmd, BaseMetric::SubType st, const char *expr)
+{
+ for (long i = 0, items_sz = items->size (); i < items_sz; i++)
+ {
+ Metric *m = items->fetch (i);
+ if (m->get_subtype () == st && dbe_strcmp (m->get_cmd (), cmd) == 0
+ && dbe_strcmp (m->get_expr_spec (), expr) == 0)
+ return (int) i;
+ }
+ return -1;
+}
+
+Metric *
+MetricList::find_metric_by_name (char *cmd)
+{
+ for (long i = 0, items_sz = items->size (); i < items_sz; i++)
+ {
+ Metric *m = items->fetch (i);
+ if (dbe_strcmp (m->get_cmd (), cmd) == 0)
+ return m;
+ }
+ return NULL;
+}
+
+// find a metric by name and subtype
+Metric *
+MetricList::find_metric (char *cmd, BaseMetric::SubType st)
+{
+ int i = get_listorder (cmd, st);
+ if (i < 0)
+ return NULL;
+ return items->fetch (i);
+}
+
+// Get the sort metric from a list; forces sort by first if not set
+Metric *
+MetricList::get_sort_metric ()
+{
+ int i = get_sort_ref_index ();
+ return i >= 0 ? items->fetch (i) : NULL;
+}
+
+char *
+MetricList::get_sort_name ()
+{
+ Metric *item = get_sort_metric ();
+ if (item == NULL)
+ return dbe_strdup (NTXT (""));
+ char *n = item->get_name ();
+ return sort_reverse ? dbe_sprintf ("-%s", n) : dbe_strdup (n);
+}
+
+char *
+MetricList::get_sort_cmd ()
+{
+ char *buf;
+ Metric *item = get_sort_metric ();
+ if (item == NULL)
+ return dbe_strdup (NTXT (""));
+ char *n = item->get_mcmd (false);
+ if (sort_reverse)
+ {
+ buf = dbe_sprintf (NTXT ("-%s"), n);
+ free (n);
+ }
+ else
+ buf = n;
+ return buf;
+}
+
+Metric *
+MetricList::append (BaseMetric *bm, BaseMetric::SubType st, int visbits)
+{
+ for (long i = 0, sz = items->size (); i < sz; i++)
+ {
+ Metric *m = items->get (i);
+ if (m->get_id () == bm->get_id () && m->get_subtype () == st)
+ return NULL;
+ }
+ Metric *met = new Metric (bm, st);
+ met->set_dmetrics_visbits (visbits);
+ items->append (met);
+ return met;
+}
+
+int
+MetricList::add_matching_dmetrics (Vector<BaseMetric*> *base_items,
+ char *mcmd, BaseMetric::SubType *_subtypes,
+ int nsubtypes, int dmetrics_visbits,
+ bool fromRcFile)
+{
+ bool any = false, hwc = false, bit = false;
+ int got_metric = 1;
+
+ // check keywords 'any', 'all', 'bit', and 'hwc'
+ if (!strcasecmp (mcmd, Command::ANY_CMD))
+ any = true;
+ else if (!strcasecmp (mcmd, Command::ALL_CMD))
+ any = true;
+ else if (!strcasecmp (mcmd, Command::HWC_CMD))
+ hwc = true;
+ else if (!strcasecmp (mcmd, Command::BIT_CMD))
+ bit = true;
+
+ BaseMetric::SubType *subtypes = _subtypes;
+ BaseMetric::SubType all_subtypes[2] =
+ { BaseMetric::EXCLUSIVE, BaseMetric::INCLUSIVE };
+
+ if (nsubtypes == 0 || (nsubtypes == 1 && subtypes[0] == BaseMetric::STATIC))
+ {
+ // user did not specify ei; treat as wildcard and supply both.
+ subtypes = all_subtypes;
+ nsubtypes = 2;
+ }
+
+ // scan the metrics to find all matches
+ for (int i = 0, base_sz = base_items->size (); i < base_sz; i++)
+ {
+ BaseMetric *item = base_items->fetch (i);
+ if (!(any || (hwc && item->get_type () == BaseMetric::HWCNTR)
+ || (bit && item->get_cmd ()
+ && strncmp (item->get_cmd (), Command::BIT_CMD,
+ strlen (Command::BIT_CMD)) == 0)
+ || dbe_strcmp (item->get_cmd (), mcmd) == 0))
+ continue;
+ if (item->is_internal ())
+ continue;
+ if (item->get_flavors () & BaseMetric::STATIC)
+ {
+ got_metric = 0;
+ int vis = item->get_type () != BaseMetric::ONAME ?
+ dmetrics_visbits : VAL_VALUE;
+ if (append (item, BaseMetric::STATIC, vis) == NULL && !fromRcFile)
+ return 2;
+ continue;
+ }
+
+ // special case for omp metrics: make visible only if
+ // omp data has been collected
+ if (!dbeSession->is_omp_available ()
+ && (strcasecmp (mcmd, "ompwork") == 0
+ || strcasecmp (mcmd, "ompwait") == 0))
+ continue;
+
+ for (int j = 0; j < nsubtypes; j++)
+ {
+ if (append (item, subtypes[j], dmetrics_visbits) == NULL
+ && !fromRcFile)
+ return 2;
+ }
+ got_metric = 0;
+ if (!(any || hwc || bit))
+ break;
+ }
+ return got_metric;
+}
+
+// parse a single metric specification, to give:
+// a vector of subtypes, and a count of the number of them
+// an integer visibility
+// return the string for the metric name
+
+char *
+MetricList::parse_metric_spec (char *mcmd, BaseMetric::SubType *subtypes,
+ int *nsubtypes, int *dmetrics_visb, bool *isOK)
+{
+ size_t len_vtype;
+ int index;
+ int vis;
+ bool got_e, got_i, got_a, got_d;
+ char *str = mcmd;
+ char *str2;
+
+ *isOK = true;
+
+ // For dynamic metrics, each keyword is of the form <flavor><visibility><metric-name>
+ // For static metrics, each keyword is of the form [<visibility>]<metric-name>
+ // <flavor> can be either "i" for inclusive or "e" for exclusive
+ // <visibility> can be any combination of "." (to show the metric as a time),
+ // "%" (to show it as a percentage), "+" (to show it as a count), and "!" (turn off the metric)
+
+ // find subtype
+ index = 0;
+ size_t len_subtype = strspn (str, NTXT ("eiad"));
+ str2 = str + len_subtype;
+
+ // find vis
+ if (len_subtype == 0)
+ {
+ // only a . or ! is possible if no subtypes
+ len_vtype = strspn (str2, NTXT (".!"));
+ vis = VAL_VALUE;
+ }
+ else
+ {
+ len_vtype = strspn (str2, NTXT (".+%!"));
+ vis = VAL_NA;
+ }
+
+ // if no visibility bits, there can't be a subtype
+ if (len_vtype == 0)
+ len_subtype = 0;
+
+ if (len_subtype == 0)
+ {
+ // must be a static metric
+ subtypes[index++] = BaseMetric::STATIC;
+ vis = VAL_VALUE;
+ }
+ else
+ {
+ // figure out which subtypes are specified
+ got_e = got_i = got_a = got_d = false;
+ for (size_t i = 0; i < len_subtype; i++)
+ {
+ str += len_subtype;
+ if (mcmd[i] == 'e')
+ { // exclusive
+ if (mtype == MET_DATA)
+ {
+ *isOK = false;
+ return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for data metrics\n"),
+ mcmd);
+ }
+ if (!got_e)
+ {
+ got_e = true;
+ subtypes[index++] = BaseMetric::EXCLUSIVE;
+ }
+ }
+ else if (mcmd[i] == 'i')
+ { // inclusive
+ if (mtype == MET_DATA)
+ {
+ *isOK = false;
+ return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for data metrics\n"),
+ mcmd);
+ }
+ if (mtype == MET_INDX)
+ {
+ *isOK = false;
+ return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for index metrics\n"),
+ mcmd);
+ }
+ if (!got_i)
+ {
+ got_i = true;
+ subtypes[index++] = BaseMetric::INCLUSIVE;
+ }
+ }
+ else if (mcmd[i] == 'a')
+ { // attributed
+ if (mtype != MET_CALL && mtype != MET_CALL_AGR)
+ {
+ *isOK = false;
+ return dbe_sprintf (GTXT ("Invalid metric specification: %s applicable for caller-callee metrics only\n"),
+ mcmd);
+ }
+ if (!got_a)
+ {
+ got_a = true;
+ subtypes[index++] = BaseMetric::ATTRIBUTED;
+ }
+ }
+ else if (mcmd[i] == 'd')
+ { // data-space
+ if (mtype != MET_DATA)
+ {
+ *isOK = false;
+ return dbe_sprintf (GTXT ("Invalid metric specification: %s applicable for data-derived metrics only\n"),
+ mcmd);
+ }
+ if (!got_d)
+ {
+ got_d = true;
+ subtypes[index++] = BaseMetric::DATASPACE;
+ }
+ }
+ }
+ }
+ *nsubtypes = index;
+
+ // now determine the visiblity bits
+ if (len_vtype > 0)
+ {
+ for (size_t i = 0; i < len_vtype; i++)
+ {
+ if (str2[i] == '+')
+ vis = (vis | VAL_VALUE);
+ else if (str2[i] == '.')
+ vis = (vis | VAL_TIMEVAL);
+ else if (str2[i] == '%')
+ vis = (vis | VAL_PERCENT);
+ else if (str2[i] == '!')
+ vis = (vis | VAL_HIDE_ALL);
+ }
+ }
+ *dmetrics_visb = vis;
+ return mcmd + len_subtype + len_vtype;
+}
diff --git a/gprofng/src/MetricList.h b/gprofng/src/MetricList.h
new file mode 100644
index 0000000..b8486c1
--- /dev/null
+++ b/gprofng/src/MetricList.h
@@ -0,0 +1,163 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _METRICLIST_H
+#define _METRICLIST_H
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "enums.h"
+#include "Metric.h"
+#include "DerivedMetrics.h"
+#include <stdio.h>
+
+//
+// The MetricList class is used to manage a list of metrics
+
+class MetricList
+{
+public:
+
+ MetricList (Vector<BaseMetric*> *base_metrics, MetricType type);
+ MetricList (MetricList *old);
+ MetricList (MetricType _mtype);
+ ~MetricList ();
+
+ // Methods concerning a list of metrics
+ // set metrics -- text, caller-callee, data, and index flavors
+ // flavor depends on mtype in the list
+ // returns NULL if OK, or an error string if not
+ // always returns NULL if fromRcFile is TRUE
+ char *set_metrics (const char *metric_cmd, bool fromRcFile, DerivedMetrics *derived_metrics);
+
+ // update the caller-callee or dataspace metrics to match normal metrics
+ // It is assumed that this->mtype is MET_CALL, MET_DATA, or MET_INDX and
+ // that metrics_list->mtype is MET_NORMAL
+ void set_metrics (MetricList *metrics_list);
+
+ // produce a string for the metrics from a vector
+ char *get_metrics ();
+
+ // set the sort metric for a list from a metric string
+ // returns NULL if OK, or an error string if not
+ char *set_sort (const char *metric_cmd, bool fromRcFile);
+
+ // set the sort metric for a list from the first visible index
+ void set_fallback_sort ();
+
+ // set the sort metric for a list from a visible index
+ void set_sort (int visindex, bool reverse);
+
+ char *get_sort_name (); // get the name of the sort metric from a vector
+
+ bool
+ get_sort_rev () // get the boolean reverse for the sort metric
+ {
+ return sort_reverse;
+ }
+
+ void
+ set_sort_rev (bool v)
+ {
+ sort_reverse = v;
+ }
+
+ int
+ get_sort_ref_index ()
+ {
+ return sort_ref_index;
+ }
+
+ void
+ set_sort_ref_index (int ind)
+ {
+ sort_ref_index = ind;
+ }
+
+ bool set_sort_metric (char *metric_cmd, BaseMetric::SubType mst, bool reverse);
+ Metric *find_metric (char *cmd, BaseMetric::SubType st);
+ Metric *find_metric_by_name (char *cmd);
+ int get_listorder (char *cmd, BaseMetric::SubType st, const char *expr = NULL);
+ int get_listorder (Metric *mtr);
+ Metric *get_sort_metric (); // get the sort metric from a vector
+ char *get_sort_cmd (); // get the command name of the sort metric
+
+ MetricType
+ get_type ()
+ {
+ return mtype;
+ }
+
+ Vector<Metric*> *
+ get_items () // get the vector of metrics from the list
+ {
+ return items;
+ }
+
+ Metric *
+ get (long i)
+ {
+ return items->get (i);
+ }
+
+ void
+ put (long i, Metric *m)
+ {
+ items->put (i, m);
+ }
+
+ void
+ append (Metric *m)
+ {
+ items->append (m);
+ }
+
+ long
+ size ()
+ {
+ return items ? items->size () : 0;
+ }
+
+ Metric *append (BaseMetric *bm, BaseMetric::SubType st, int visbits);
+
+ // produce a list of all metrics from a vector
+ void print_metric_list (FILE *dis_file, char *leader, int debug);
+
+ // Add any and all matching metrics to the growing list
+ // return value is zero for OK, 1 for no match
+ int add_matching_dmetrics (Vector<BaseMetric*> *base_items, char *cmd,
+ BaseMetric::SubType *subtypes, int nsubtypes,
+ int dmetrics_vis, // literal translation of dmetrics +. etc.
+ bool fromRcFile);
+
+private:
+ // parse a metric specification substring, based on type of list
+ char *parse_metric_spec (char *cmd, BaseMetric::SubType *subtypes,
+ int *nsubtypes, int *dmetrics_visb, bool *isOK);
+
+ Vector<Metric*> *items;
+ MetricType mtype;
+
+ // the sort reference index
+ int sort_ref_index;
+ bool sort_reverse;
+};
+
+#endif /* _METRICLIST_H */
diff --git a/gprofng/src/Module.cc b/gprofng/src/Module.cc
new file mode 100644
index 0000000..1e61b42
--- /dev/null
+++ b/gprofng/src/Module.cc
@@ -0,0 +1,1840 @@
+/* Copyright (C) 2021 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 <unistd.h>
+#include <ar.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "DbeView.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "ClassFile.h"
+#include "LoadObject.h"
+#include "Disasm.h"
+#include "CompCom.h"
+#include "Dwarf.h"
+#include "DbeFile.h"
+#include "PathTree.h"
+#include "Elf.h"
+
+Module::Module ()
+{
+ lang_code = Sp_lang_unknown;
+ flags = 0;
+ status = AE_NOTREAD;
+ openSourceFlag = AE_NOTREAD;
+ hexVisible = false;
+ disPath = NULL;
+ stabsPath = NULL;
+ stabsTmp = NULL;
+ disName = NULL;
+ stabsName = NULL;
+ indexStabsLink = NULL;
+ file_name = NULL;
+ functions = new Vector<Function*>;
+ loadobject = NULL;
+ dot_o_file = NULL;
+ main_source = dbeSession->get_Unknown_Source ();
+ srcContext = main_source;
+ includes = new Vector<SourceFile*>;
+ includes->append (main_source);
+ curr_inc = NULL;
+ fragmented = 0;
+ hwcprof = 0;
+ hdrOffset = 0;
+ hasDwarf = false;
+ hasStabs = false;
+ readStabs = false;
+ comComs = NULL;
+ infoList = NULL;
+ datatypes = NULL;
+ objStabs = NULL;
+ disasm = NULL;
+ comp_flags = NULL;
+ comp_dir = NULL;
+ linkerStabName = NULL;
+ disMTime = (time_t) 0;
+ stabsMTime = (time_t) 0;
+ real_timestamp = 0;
+ curr_timestamp = 0;
+ src_items = NULL;
+ dis_items = NULL;
+ data_items = NULL;
+ cur_dbev = NULL;
+ maximum = NULL;
+ maximum_inc = NULL;
+ empty = NULL;
+ inlinedSubr = NULL;
+}
+
+Module::~Module ()
+{
+ removeStabsTmp ();
+ delete includes;
+ if (comComs != NULL)
+ {
+ comComs->destroy ();
+ delete comComs;
+ }
+ free (comp_flags);
+ free (comp_dir);
+ free (linkerStabName);
+ free (disPath);
+ free (stabsPath);
+ free (disName);
+ free (stabsName);
+ delete functions;
+ free (file_name);
+ if (indexStabsLink)
+ // Remove a link to the current module
+ indexStabsLink->indexStabsLink = NULL;
+
+ if (dot_o_file)
+ {
+ delete dot_o_file->dbeFile;
+ delete dot_o_file;
+ }
+ delete src_items;
+ delete dis_items;
+ delete disasm;
+ free (inlinedSubr);
+ if (lang_code != Sp_lang_java)
+ delete dbeFile;
+
+}
+
+Stabs *
+Module::openDebugInfo ()
+{
+ setFile ();
+ objStabs = loadobject->openDebugInfo (disPath);
+ return objStabs;
+}
+
+void
+Module::removeStabsTmp ()
+{
+ // Remove temporary *.o (got from *.a) after reading Stabs
+ if (stabsTmp != NULL)
+ {
+ unlink (stabsTmp);
+ free (stabsTmp);
+ stabsTmp = NULL;
+ }
+}
+
+int64_t
+Module::get_size ()
+{
+ Function *fp;
+ int index;
+ int64_t result = 0;
+ Vec_loop (Function*, functions, index, fp)
+ {
+ result += fp->size;
+ }
+ return result;
+}
+
+bool
+Module::is_fortran ()
+{
+ return Stabs::is_fortran (lang_code);
+}
+
+SourceFile *
+Module::findSource (const char *fname, bool create)
+{
+ SourceFile *sf = NULL;
+ if (loadobject && loadobject->firstExp)
+ sf = loadobject->firstExp->get_source (fname);
+ if (sf == NULL)
+ sf = dbeSession->createSourceFile (fname);
+ for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
+ {
+ SourceFile *sf1 = includes->fetch (i);
+ if (sf == sf1)
+ return sf;
+ }
+ if (create)
+ {
+ if (includes == NULL)
+ includes = new Vector<SourceFile*>;
+ includes->append (sf);
+ return sf;
+ }
+ return NULL;
+}
+
+SourceFile *
+Module::setIncludeFile (char *includeFile)
+{
+ curr_inc = NULL;
+ if (includeFile)
+ curr_inc = findSource (includeFile, true);
+ return curr_inc;
+}
+
+char *
+Module::anno_str (char *fnm)
+{
+ char timebuf1[26], timebuf2[26];
+ const time_t real_time = (time_t) (unsigned int) real_timestamp;
+ const time_t curr_time = (time_t) (unsigned int) curr_timestamp;
+
+ switch (status)
+ {
+ case AE_OK:
+ case AE_NOTREAD:
+ return NULL;
+ case AE_NOSRC:
+ return dbe_sprintf (GTXT ("Source file `%s' not readable"),
+ fnm ? fnm : file_name);
+ case AE_NOOBJ:
+ if (lang_code == Sp_lang_java)
+ {
+ Emsg *emsg = get_error ();
+ if (emsg)
+ {
+ char *s = dbe_strdup (emsg->get_msg ());
+ remove_msg (emsg);
+ return s;
+ }
+ return dbe_sprintf (GTXT ("Object file `%s.class' not readable"),
+ name);
+ }
+ return dbe_sprintf (GTXT ("Object file `%s' not readable"), get_name ());
+ case AE_NOLOBJ:
+ if (lang_code == Sp_lang_java)
+ return dbe_sprintf (GTXT ("Object file `%s' not readable"),
+ dbeFile ? dbeFile->get_name () : name);
+ return dbe_sprintf (GTXT ("Object file `%s' not readable"), loadobject->get_pathname ());
+ case AE_NOSTABS:
+ return dbe_sprintf (GTXT ("Error reading line-number information in object `%s'; source annotation not available"),
+ stabsPath ? stabsPath : NTXT (""));
+ case AE_NOSYMTAB:
+ return dbe_sprintf (GTXT ("Error reading symbol table in object `%s'; disassembly annotation not available"),
+ disPath ? disPath : NTXT (""));
+ case AE_TIMESRC:
+ return dbe_sprintf (GTXT ("Warning! Source file `%s' is newer than the experiment data"),
+ main_source->dbeFile->getResolvedPath ());
+ case AE_TIMEDIS:
+ return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
+ disName ? disName : NTXT (""));
+ case AE_TIMESTABS:
+ return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
+ stabsName ? stabsName : NTXT (""));
+ case AE_TIMESTABS_DIFF:
+ snprintf (timebuf1, sizeof (timebuf1), NTXT ("%s"), ctime (&curr_time));
+ snprintf (timebuf2, sizeof (timebuf2), NTXT ("%s"), ctime (&real_time));
+ timebuf1[24] = timebuf2[24] = '\0';
+ return dbe_sprintf (GTXT ("Warning! Object file `%s' is not the same one that was linked into executable.\n"
+ "\tObject file: `%s'\n\tcompiled on: %s\n"
+ "\tExecutable contains object file compiled on: %s"),
+ getResolvedObjectPath (), getResolvedObjectPath (),
+ timebuf1, timebuf2);
+ case AE_OTHER:
+ default:
+ return dbe_strdup (GTXT ("Annotation computation error"));
+ }
+}//anno_str
+
+LoadObject *
+Module::createLoadObject (const char *lo_name)
+{
+ LoadObject *lo = new LoadObject (lo_name);
+ lo->dbeFile->filetype |= DbeFile::F_DOT_O;
+ return lo;
+}
+
+static bool
+tsIsNewer (time_t t1, time_t t2)
+{
+ return t1 != 0 && t2 != 0 && t1 < t2;
+}
+
+Module::Anno_Errors
+Module::checkTimeStamp (bool chkDis)
+{
+ /* Check the linked and the real object timestamps due to bug #4796329 */
+ if (real_timestamp && curr_timestamp && real_timestamp != curr_timestamp)
+ return AE_TIMESTABS_DIFF;
+
+ time_t srctime = main_source->getMTime ();
+ for (int index = 0; index < dbeSession->nexps (); index++)
+ {
+ time_t mtime = dbeSession->get_exp (index)->get_mtime ();
+ if (tsIsNewer (mtime, srctime))
+ return AE_TIMESRC;
+ if (tsIsNewer (mtime, stabsMTime))
+ return AE_TIMESTABS;
+ if (chkDis && tsIsNewer (mtime, disMTime))
+ return AE_TIMEDIS;
+ }
+ return AE_OK;
+}//checkTimeStamp
+
+static size_t
+get_ar_size (char *s, size_t len)
+{
+ size_t sz = 0;
+ for (size_t i = 0; i < len; i++)
+ {
+ if (s[i] < '0' || s[i] > '9')
+ break;
+ sz = sz * 10 + (s[i] - '0');
+ }
+ return sz;
+}
+
+static void
+dump_hdr_field (char *nm, char *s, size_t len)
+{
+ Dprintf (DEBUG_READ_AR, NTXT (" %s "), nm);
+ for (size_t i = 0; i < len; i++)
+ Dprintf (DEBUG_READ_AR, "%c", isprint (s[i]) ? s[i] : '?');
+ Dprintf (DEBUG_READ_AR, NTXT (" "));
+ for (size_t i = 0; i < len; i++)
+ Dprintf (DEBUG_READ_AR, NTXT (" %d"), s[i]);
+ Dprintf (DEBUG_READ_AR, NTXT (" \n"));
+}
+
+static void
+dump_ar_hdr (int lineNum, struct ar_hdr *hdr)
+{
+ if (DEBUG_READ_AR)
+ {
+ Dprintf (DEBUG_READ_AR, NTXT ("Module::read_ar %d\n"), lineNum);
+ dump_hdr_field (NTXT ("ar_name"), hdr->ar_name, sizeof (hdr->ar_name));
+ dump_hdr_field (NTXT ("ar_date"), hdr->ar_date, sizeof (hdr->ar_date));
+ dump_hdr_field (NTXT ("ar_uid"), hdr->ar_uid, sizeof (hdr->ar_uid));
+ dump_hdr_field (NTXT ("ar_gid"), hdr->ar_gid, sizeof (hdr->ar_gid));
+ dump_hdr_field (NTXT ("ar_mode"), hdr->ar_mode, sizeof (hdr->ar_mode));
+ dump_hdr_field (NTXT ("ar_size"), hdr->ar_size, sizeof (hdr->ar_size));
+ dump_hdr_field (NTXT ("ar_fmag"), hdr->ar_fmag, sizeof (hdr->ar_fmag));
+ }
+}
+
+bool
+Module::read_ar (int ar, int obj, char *obj_base)
+{
+ struct ar_hdr hdr; // Archive header
+ char magic[SARMAG]; // Magic string from archive
+ Dprintf (DEBUG_READ_AR, "Module::read_ar %d %p %s %s \n", __LINE__,
+ this, STR (obj_base), STR (get_name ()));
+ // Check the magic string
+ if ((read_from_file (ar, magic, SARMAG) != SARMAG)
+ || strncmp (magic, ARMAG, SARMAG))
+ return false;
+
+ // Read and skip the first file in the archive (index file to ld)
+ if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
+ return false;
+ DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
+ if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)), SEEK_CUR)
+ == -1)
+ return false;
+
+ // Read the string file where it keeps long file names (if exist)
+ if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
+ return false;
+ DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
+ char *longnames = NULL; // Area with names longer than ~13
+ size_t longnames_size = 0;
+ if (!strncmp (hdr.ar_name, NTXT ("//"), 2))
+ {
+ longnames_size = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
+ longnames = (char *) malloc (longnames_size + 1);
+ int64_t cnt = read_from_file (ar, longnames, longnames_size);
+ if (cnt != (int64_t) longnames_size)
+ {
+ free (longnames);
+ return false;
+ }
+ longnames[longnames_size] = 0;
+ }
+ else
+ // back out, no long file names
+ lseek (ar, -(sizeof (hdr)), SEEK_CUR);
+
+ // Search the ar for the object file name
+ char ar_buf[sizeof (hdr.ar_name) + 1];
+ ar_buf[sizeof (hdr.ar_name)] = 0;
+ while (1)
+ {
+ if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
+ break;
+ DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
+ char *ar_name;
+ if (hdr.ar_name[0] != '/')
+ { // Name is in the header
+ for (size_t i = 0; i < sizeof (hdr.ar_name); i++)
+ {
+ if (hdr.ar_name[i] == '/')
+ {
+ ar_buf[i] = 0;
+ break;
+ }
+ ar_buf[i] = hdr.ar_name[i];
+ }
+ ar_name = ar_buf;
+ }
+ else if (hdr.ar_name[1] == ' ')
+ { // Name is blank
+ ar_buf[0] = 0;
+ ar_name = ar_buf;
+ }
+ else
+ { // Name is in the string table
+ if (longnames == NULL)
+ break;
+ size_t offset = get_ar_size (hdr.ar_name + 1,
+ sizeof (hdr.ar_name) - 1);
+ if (offset >= longnames_size)
+ break;
+ for (size_t i = offset; i < longnames_size; i++)
+ {
+ if (longnames[i] == '/')
+ {
+ longnames[i] = 0;
+ break;
+ }
+ }
+ ar_name = longnames + offset;
+ }
+ Dprintf (DEBUG_READ_AR, "Module::read_ar %d ar_name=%s\n", __LINE__,
+ ar_name);
+
+ if (streq (ar_name, obj_base))
+ { // create object file
+ free (longnames);
+ for (size_t objsize = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
+ objsize > 0;)
+ {
+ char buf[MAXPATHLEN];
+ size_t n = objsize < sizeof (buf) ? objsize : sizeof (buf);
+ int64_t cnt = read_from_file (ar, buf, n);
+ if (cnt != (int64_t) n)
+ return false;
+ cnt = write (obj, buf, n);
+ if (cnt != (int64_t) n)
+ return false;
+ objsize -= n;
+ }
+ return true;
+ }
+ if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)),
+ SEEK_CUR) == -1)
+ break;
+ }
+ free (longnames);
+ return false;
+}
+
+static char *
+get_obj_name_from_lib (char *nm)
+{
+ char *base = strrchr (nm, '(');
+ if (base)
+ {
+ size_t last = strlen (base) - 1;
+ if (base[last] == ')')
+ return base;
+ }
+ return NULL;
+}
+
+bool
+Module::setFile ()
+{
+ if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0)
+ return true;
+ if ((loadobject->dbeFile->filetype & DbeFile::F_FICTION) != 0)
+ return false;
+ if ((flags & MOD_FLAG_UNKNOWN) != 0)
+ return true;
+
+ if (lang_code == Sp_lang_java)
+ {
+ if (dbeFile->get_need_refind ())
+ {
+ char *fnm = dbeFile->get_location ();
+ stabsPath = dbe_strdup (fnm);
+ stabsName = dbe_strdup (fnm);
+ disPath = dbe_strdup (fnm);
+ disName = dbe_strdup (fnm);
+ stabsMTime = dbeFile->sbuf.st_mtime;
+ }
+ return dbeFile->get_location () != NULL;
+ }
+
+ if (dbeFile == NULL)
+ {
+ char *objname = get_obj_name_from_lib (name);
+ if (objname)
+ {
+ // in the format of libpath(obj)
+ objname = dbe_strdup (objname + 1);
+ size_t last = strlen (objname) - 1;
+ objname[last] = '\0';
+ }
+ dbeFile = new DbeFile (objname ? objname : name);
+ free (objname);
+ dbeFile->filetype |= DbeFile::F_DOT_O;
+ }
+ if (dbeFile->get_need_refind ())
+ {
+ disMTime = (time_t) 0;
+ stabsMTime = (time_t) 0;
+ free (disName);
+ free (stabsName);
+ disName = NULL;
+ stabsName = NULL;
+
+ // Find the Executable/Shared-Object file of module
+ char *path = loadobject->dbeFile->get_location ();
+ if (path)
+ {
+ disPath = strdup (path);
+ disName = strdup (path);
+ disMTime = loadobject->dbeFile->sbuf.st_mtime;
+ }
+
+ char *objname = get_obj_name_from_lib (name);
+ if (objname)
+ {
+ // in the format of libpath(obj)
+ char *namebuf = dbe_strdup (name);
+ char *base = namebuf + (objname - name);
+ *base = '\0';
+ base++;
+ size_t last = strlen (base) - 1;
+ base[last] = '\0';
+ stabsTmp = dbeSession->get_tmp_file_name (base, false);
+ dbeSession->tmp_files->append (strdup (stabsTmp));
+
+ DbeFile *dbf = dbeSession->getDbeFile (namebuf,
+ DbeFile::F_DOT_A_LIB | DbeFile::F_FILE);
+ path = dbf->get_location ();
+ int ar = -1, obj = -1;
+ if (path != NULL)
+ {
+ ar = open64 (path, O_RDONLY | O_LARGEFILE);
+ if (ar != -1)
+ obj = open64 (stabsTmp, O_CREAT | O_WRONLY | O_LARGEFILE, 0600);
+ }
+ if (ar != -1 && obj != -1 && read_ar (ar, obj, base))
+ {
+ dbeFile->set_location (stabsTmp);
+ dbeFile->check_access (stabsTmp); // init 'sbuf'
+ dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
+ dbeFile->container = dbf;
+ stabsPath = strdup (stabsTmp);
+ stabsName = strdup (path);
+ stabsMTime = dbeFile->sbuf.st_mtime;
+ }
+ else
+ {
+ removeStabsTmp ();
+ objname = NULL;
+ }
+ if (ar != -1)
+ close (ar);
+ if (obj != -1)
+ close (obj);
+ free (namebuf);
+ }
+ if (objname == NULL)
+ {
+ path = dbeFile->get_location ();
+ if (path != NULL)
+ {
+ stabsPath = strdup (path);
+ stabsName = strdup (path);
+ stabsMTime = hasDwarf ? 0 : dbeFile->sbuf.st_mtime;
+ }
+ }
+
+ // First, try to access the symbol table of the module itself
+ // If failed, access the symbol table of the executable
+ if (stabsPath == NULL)
+ {
+ if (disPath == NULL)
+ return false;
+ stabsPath = strdup (disPath);
+ stabsName = strdup (disName);
+ stabsMTime = disMTime;
+ }
+ else if (disPath == NULL)
+ {
+ disPath = strdup (stabsPath);
+ disName = strdup (stabsName);
+ disMTime = stabsMTime;
+ }
+ }
+ return stabsPath != NULL;
+}
+
+// openStabs -- open mappings from PCs to source lines
+bool
+Module::openStabs (bool all)
+{
+ if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0
+ || (flags & MOD_FLAG_UNKNOWN) != 0)
+ return true;
+ if (loadobject->platform == Java)
+ {
+ setIncludeFile (NULL);
+ readFile ();
+ return ( status == AE_OK);
+ }
+ if (readStabs)
+ return true;
+
+ // Read Stabs info.
+ int64_t Inode = main_source->getInode ();
+ char *fname = strrchr (file_name, (int) '/');
+ char *mname = strrchr (main_source->get_name (), (int) '/');
+ if (fname && mname && !streq (fname, mname))
+ {
+ SourceFile *sf = findSource (file_name, false);
+ if (sf != NULL)
+ Inode = sf->getInode ();
+ }
+
+ comComs = new Vector<ComC*>;
+ Stabs *stabs = openDebugInfo ();
+ if (stabs == NULL)
+ return false;
+ int st = stabs->read_stabs (Inode, this, comComs, true);
+ if (!hasDwarf && hasStabs && !streq (stabsPath, disPath))
+ {
+ // Read stabs from .o file
+ if (dot_o_file == NULL)
+ {
+ if (dbeFile->get_location ())
+ {
+ dot_o_file = createLoadObject (dbeFile->get_name ());
+ dot_o_file->dbeFile->set_location (dbeFile->get_location ());
+ dot_o_file->dbeFile->sbuf = dbeFile->sbuf;
+ dot_o_file->dbeFile->container = dbeFile->container;
+ }
+ }
+ if (dot_o_file
+ && dot_o_file->sync_read_stabs () == LoadObject::ARCHIVE_SUCCESS)
+ {
+ Stabs *stabs_o = dot_o_file->objStabs;
+ if (stabs_o)
+ {
+ st = stabs_o->read_stabs (Inode, this,
+ comComs->size () > 0 ? NULL : comComs);
+ Elf *elf_o = stabs_o->openElf (false);
+ if (elf_o->dwarf)
+ stabs->read_dwarf_from_dot_o (this);
+ }
+ }
+ }
+ if (all)
+ read_hwcprof_info ();
+
+ readStabs = true;
+ return st == Stabs::DBGD_ERR_NONE;
+}
+
+char *
+Module::get_disasm (uint64_t inst_address, uint64_t end_address,
+ uint64_t start_address, uint64_t address, int64_t &inst_size)
+{
+ return disasm->get_disasm (inst_address, end_address, start_address,
+ address, inst_size);
+}
+
+void
+Module::read_stabs (bool all)
+{
+ if (openSourceFlag == AE_NOTREAD)
+ {
+ openSourceFlag = AE_OK;
+ if (lang_code == Sp_lang_java)
+ {
+ char *clpath = file_name;
+ if (clpath == NULL || strcmp (clpath, "<Unknown>") == 0)
+ clpath = ClassFile::get_java_file_name (name, false);
+ main_source = findSource (clpath, true);
+ main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
+ if (clpath != file_name)
+ free (clpath);
+ }
+ else
+ main_source = findSource (file_name, true);
+ if (setFile ())
+ openStabs (all);
+ }
+}
+
+bool
+Module::openDisPC ()
+{
+ if (disasm == NULL)
+ {
+ if (!(loadobject->flags & SEG_FLAG_DYNAMIC) && loadobject->platform != Java)
+ {
+ // Read Stabs & Symbol tables
+ if (openDebugInfo () == NULL)
+ return false;
+ if (!objStabs->read_symbols (functions))
+ return false;
+ }
+ disasm = new Disasm (loadobject->platform, objStabs);
+ }
+ return true;
+}
+
+static SourceFile *cmpSrcContext; // Use only for func_cmp
+
+static int
+func_cmp (const void *a, const void *b)
+{
+ Function *fp1 = *((Function **) a);
+ Function *fp2 = *((Function **) b);
+ return fp1->func_cmp (fp2, cmpSrcContext);
+}
+
+bool
+Module::computeMetrics (DbeView *dbev, Function *func, MetricList *metrics,
+ Histable::Type type, bool src_metric,
+ bool func_scope, SourceFile *source)
+{
+ name_idx = metrics->get_listorder (NTXT ("name"), Metric::STATIC);
+ if (name_idx < 0)
+ {
+ metrics->print_metric_list (stderr,
+ GTXT ("Fatal: no name metric in Module::computeMetrics mlist:\n"),
+ 1);
+ abort ();
+ }
+
+ // Now find the metrics for size and address, if present
+ size_index = metrics->get_listorder (NTXT ("size"), Metric::STATIC);
+ addr_index = metrics->get_listorder (NTXT ("address"), Metric::STATIC);
+
+ // free the old cached data for both src and disassembly
+ // If it's disassembly with visible source metrics, we use both
+ if (dis_items)
+ {
+ delete dis_items;
+ dis_items = NULL;
+ }
+ if (src_items)
+ {
+ delete src_items;
+ src_items = NULL;
+ }
+
+ // ask the DbeView to generate new data to be cached
+ if (src_metric || type == Histable::LINE)
+ {
+ Histable *obj = (func_scope) ? (Histable*) func : (Histable*)this;
+ if (lang_code == Sp_lang_java)
+ obj = func_scope ? (Histable *) func :
+ (source && source->get_type () == Histable::SOURCEFILE ?
+ (Histable *) source : (Histable *) this);
+ src_items = dbev->get_hist_data (metrics, Histable::LINE, 0,
+ Hist_data::MODL, obj, source);
+ }
+ if (type == Histable::INSTR)
+ dis_items = dbev->get_hist_data (metrics, Histable::INSTR, 0,
+ Hist_data::MODL,
+ func_scope ? (Histable*) func : (Histable*) this,
+ source);
+
+ Hist_data *cur_hist_data;
+ if (type == Histable::INSTR)
+ cur_hist_data = dis_items;
+ else
+ cur_hist_data = src_items;
+
+ Vector<Metric*> *items = cur_hist_data->get_metric_list ()->get_items ();
+ long sz = items->size ();
+ empty = new TValue[sz];
+ memset (empty, 0, sizeof (TValue) * sz);
+ for (long i = 0; i < sz; i++)
+ empty[i].tag = items->get (i)->get_vtype ();
+ return true;
+}
+
+// Method to get annotated source or disassembly for the module
+// or a function within it
+Hist_data *
+Module::get_data (DbeView *dbev, MetricList *mlist, Histable::Type type,
+ TValue *ftotal, SourceFile *srcFile, Function *func,
+ Vector<int> *marks, int threshold, int vis_bits,
+ int src_visible, bool hex_vis, bool func_scope,
+ bool /*src_only*/, Vector<int_pair_t> *marks2d,
+ Vector<int_pair_t> *marks2d_inc)
+{
+ cur_dbev = dbev;
+ srcContext = srcFile ? srcFile : main_source;
+ read_stabs ();
+ status = AE_OK;
+ dbev->warning_msg = NULL;
+ dbev->error_msg = NULL;
+ if (type == Histable::LINE)
+ {
+ if (!srcContext->readSource ())
+ {
+ status = AE_NOSRC;
+ dbev->error_msg = anno_str (srcContext->get_name ());
+ return NULL;
+ }
+ if (!computeMetrics (dbev, func, mlist, type, false, func_scope, srcContext))
+ {
+ status = AE_OTHER;
+ dbev->error_msg = anno_str ();
+ return NULL;
+ }
+ status = checkTimeStamp (false);
+ }
+ else
+ { // Histable::INSTR
+ Anno_Errors src_status = AE_OK;
+ if (!srcContext->readSource ())
+ {
+ src_status = AE_NOSRC;
+ dbev->error_msg = anno_str (srcContext->get_name ());
+ }
+ if (!setFile ())
+ status = AE_NOLOBJ;
+ else
+ {
+ if (!openStabs ())
+ src_status = AE_NOSTABS;
+ if (!openDisPC ())
+ status = AE_NOSYMTAB;
+ }
+ if (status != AE_OK)
+ {
+ dbev->error_msg = anno_str ();
+ return NULL;
+ }
+ if (src_status != AE_OK && func != NULL)
+ {
+ if (loadobject->platform == Java && (func->flags & FUNC_FLAG_NATIVE) != 0)
+ {
+ append_msg (CMSG_ERROR,
+ GTXT ("`%s' is a native method; byte code not available\n"),
+ func->get_name ());
+ status = AE_NOOBJ;
+ dbev->error_msg = anno_str ();
+ return NULL;
+ }
+ func_scope = true;
+ }
+ // get the disassembly-line metric data
+ if (!computeMetrics (dbev, func, mlist, type,
+ (src_visible & SRC_METRIC) != 0,
+ func_scope, srcContext))
+ {
+ status = AE_OTHER;
+ dbev->error_msg = anno_str ();
+ return NULL;
+ }
+ status = checkTimeStamp (true);
+ }
+ total = ftotal;
+
+ // initialize line number
+ init_line ();
+
+ // initialize data -- get duplicate metric list for the line texts
+ // pick up the metric list from the computed data
+ MetricList *nmlist = NULL;
+ if (type == Histable::INSTR)
+ {
+ mlist = dis_items->get_metric_list ();
+ nmlist = new MetricList (mlist);
+ data_items = new Hist_data (nmlist, Histable::INSTR, Hist_data::MODL);
+ data_items->set_status (dis_items->get_status ());
+ set_dis_data (func, vis_bits, dbev->get_cmpline_visible (),
+ src_visible, hex_vis, func_scope,
+ dbev->get_funcline_visible ());
+ }
+ else
+ {
+ mlist = src_items->get_metric_list ();
+ nmlist = new MetricList (mlist);
+ data_items = new Hist_data (nmlist, Histable::LINE, Hist_data::MODL);
+ data_items->set_status (src_items->get_status ());
+ set_src_data (func_scope ? func : NULL, vis_bits,
+ dbev->get_cmpline_visible (),
+ dbev->get_funcline_visible ());
+ }
+ data_items->compute_minmax ();
+
+ Metric *mitem;
+ int index;
+ Hist_data::HistItem *max_item;
+ TValue *value;
+ Hist_data::HistItem *max_item_inc;
+ TValue *value_inc;
+ double dthreshold = threshold / 100.0;
+
+ int sz = data_items->get_metric_list ()->get_items ()->size ();
+ maximum = new TValue[sz];
+ maximum_inc = new TValue[sz];
+ memset (maximum, 0, sizeof (TValue) * sz);
+ memset (maximum_inc, 0, sizeof (TValue) * sz);
+ max_item = data_items->get_maximums ();
+ max_item_inc = data_items->get_maximums_inc ();
+
+ Vec_loop (Metric*, data_items->get_metric_list ()->get_items (), index, mitem)
+ {
+ maximum_inc[index].tag = maximum[index].tag = mitem->get_vtype ();
+
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ if (!mitem->is_visible () && !mitem->is_tvisible ()
+ && !mitem->is_pvisible ())
+ continue;
+
+ value = &max_item->value[index];
+ value_inc = &max_item_inc->value[index];
+
+ double dthresh;
+ if (mitem->is_zeroThreshold () == true)
+ dthresh = 0;
+ else
+ dthresh = dthreshold;
+ switch (value->tag)
+ {
+ case VT_INT:
+ maximum[index].i = (int) (dthresh * (double) value->i);
+ maximum_inc[index].i = (int) (dthresh * (double) value_inc->i);
+ break;
+ case VT_DOUBLE:
+ maximum[index].d = dthresh * value->d;
+ maximum_inc[index].d = dthresh * value_inc->d;
+ break;
+ case VT_LLONG:
+ maximum[index].ll = (unsigned long long) (dthresh * (double) value->ll);
+ maximum_inc[index].ll = (unsigned long long)
+ (dthresh * (double) value_inc->ll);
+ break;
+ case VT_ULLONG:
+ maximum[index].ull = (unsigned long long)
+ (dthresh * (double) value->ull);
+ maximum_inc[index].ull = (unsigned long long)
+ (dthresh * (double) value_inc->ull);
+ break;
+ default:
+ // not needed for non-numerical metrics
+ break;
+ }
+ }
+
+ // mark all high values
+ for (int index1 = 0; index1 < data_items->size (); index1++)
+ {
+ Hist_data::HistItem *hi = data_items->fetch (index1);
+ int index2;
+ Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
+ {
+ bool mark = false;
+ if (mitem->get_subtype () == Metric::STATIC)
+ continue;
+ if (!mitem->is_visible () && !mitem->is_tvisible ()
+ && !mitem->is_pvisible ())
+ continue;
+
+ switch (hi->value[index2].tag)
+ {
+ case VT_DOUBLE:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].d > maximum_inc[index2].d)
+ mark = true;
+ break;
+ }
+ if (hi->value[index2].d > maximum[index2].d)
+ mark = true;
+ break;
+ case VT_INT:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].i > maximum_inc[index2].i)
+ mark = true;
+ break;
+ }
+ if (hi->value[index2].i > maximum[index2].i)
+ mark = true;
+ break;
+ case VT_LLONG:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].ll > maximum_inc[index2].ll)
+ mark = true;
+ break;
+ }
+ if (hi->value[index2].ll > maximum[index2].ll)
+ mark = true;
+ break;
+ case VT_ULLONG:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].ull > maximum_inc[index2].ull)
+ mark = true;
+ break;
+ }
+ if (hi->value[index2].ull > maximum[index2].ull)
+ mark = true;
+ break;
+ // ignoring the following cases (why?)
+ case VT_SHORT:
+ case VT_FLOAT:
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ break;
+ }
+ if (mark)
+ {
+ marks->append (index1);
+ break;
+ }
+ }
+ }
+
+ // mark all high values to marks2d
+ if (marks2d != NULL && marks2d_inc != NULL)
+ {
+ for (int index1 = 0; index1 < data_items->size (); index1++)
+ {
+ Hist_data::HistItem *hi = data_items->fetch (index1);
+ int index2;
+ Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
+ {
+ Metric::SubType subType = mitem->get_subtype ();
+ if (subType == Metric::STATIC)
+ continue;
+ if (!mitem->is_visible () && !mitem->is_tvisible ()
+ && !mitem->is_pvisible ())
+ continue;
+ switch (hi->value[index2].tag)
+ {
+ case VT_DOUBLE:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].d > maximum_inc[index2].d)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d_inc->append (pair);
+ }
+ break;
+ }
+ if (hi->value[index2].d > maximum[index2].d)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d->append (pair);
+ }
+ break;
+ case VT_INT:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].i > maximum_inc[index2].i)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d_inc->append (pair);
+ }
+ break;
+ }
+ if (hi->value[index2].i > maximum[index2].i)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d->append (pair);
+ }
+ break;
+ case VT_LLONG:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].ll > maximum_inc[index2].ll)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d_inc->append (pair);
+ }
+ break;
+ }
+ if (hi->value[index2].ll > maximum[index2].ll)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d->append (pair);
+ }
+ break;
+ case VT_ULLONG:
+ if (nmlist->get_type () == MET_SRCDIS
+ && data_items->get_callsite_mark ()->get (hi->obj))
+ {
+ if (hi->value[index2].ull > maximum_inc[index2].ull)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d_inc->append (pair);
+ }
+ break;
+ }
+ if (hi->value[index2].ull > maximum[index2].ull)
+ {
+ int_pair_t pair = {index1, index2};
+ marks2d->append (pair);
+ }
+ break;
+ case VT_SHORT:
+ case VT_FLOAT:
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ break;
+ }
+ }
+ }
+ }
+
+ // free memory used by Computing & Printing metrics
+ delete[] maximum;
+ delete[] maximum_inc;
+ delete[] empty;
+ maximum = NULL;
+ maximum_inc = NULL;
+ empty = NULL;
+ dbev->warning_msg = anno_str ();
+ return data_items;
+}
+
+Vector<uint64_t> *
+Module::getAddrs (Function *func)
+{
+ uint64_t start_address = func->img_offset;
+ uint64_t end_address = start_address + func->size;
+ int64_t inst_size = 0;
+
+ // initialize "disasm" if necessary
+ if (!openDisPC ())
+ return NULL;
+
+ Vector<uint64_t> *addrs = new Vector<uint64_t>;
+ for (uint64_t inst_address = start_address; inst_address < end_address;)
+ {
+ char *s = disasm->get_disasm (inst_address, end_address, start_address,
+ func->img_offset, inst_size);
+ free (s);
+ addrs->append (inst_address - start_address);
+ inst_address += inst_size;
+ if (inst_size == 0)
+ break;
+ }
+ return addrs;
+}
+
+void
+Module::init_line ()
+{
+ // initialize the compiler commentary data
+ cindex = 0;
+ if (comComs != NULL && comComs->size () > 0)
+ cline = comComs->fetch (cindex)->line;
+ else
+ cline = -1;
+
+ sindex = 0;
+ if (src_items && src_items->size () > 0)
+ sline = ((DbeLine*) src_items->fetch (0)->obj)->lineno;
+ else
+ sline = -1;
+
+ dindex = 0;
+ mindex = 0;
+ mline = -1;
+ if (dis_items && dis_items->size () > 0)
+ {
+ daddr = (DbeInstr*) dis_items->fetch (0)->obj;
+
+ // After sorting all HistItems with PCLineFlag appear
+ // at the end of the list. Find the first one.
+ for (mindex = dis_items->size () - 1; mindex >= 0; mindex--)
+ {
+ Hist_data::HistItem *item = dis_items->fetch (mindex);
+ if (!(((DbeInstr*) item->obj)->flags & PCLineFlag))
+ break;
+ mline = (unsigned) (((DbeInstr*) item->obj)->addr);
+ }
+ mindex++;
+ }
+ else
+ daddr = NULL;
+}
+
+void
+Module::set_src_data (Function *func, int vis_bits, int cmpline_visible,
+ int funcline_visible)
+{
+ Function *curr_func = NULL;
+
+ // start at the top of the file, and loop over all lines in the file (source context)
+ for (curline = 1; curline <= srcContext->getLineCount (); curline++)
+ {
+ // Before writing the line, see if there's compiler commentary to insert
+ if (cline == curline)
+ set_ComCom (vis_bits);
+
+ // Find out if we need to print zero metrics with the line
+ DbeLine *dbeline = srcContext->find_dbeline (NULL, curline);
+ Anno_Types type = AT_SRC_ONLY;
+ if (dbeline->dbeline_func_next)
+ {
+ if (func)
+ for (DbeLine *dl = dbeline->dbeline_func_next; dl; dl = dl->dbeline_func_next)
+ {
+ if (dl->func == func)
+ {
+ type = AT_SRC;
+ break;
+ }
+ }
+ else
+ type = AT_SRC;
+ }
+
+ if (funcline_visible)
+ { // show red lines
+ // is there a function index line to insert?
+ Function *func_next = NULL;
+ for (DbeLine *dl = dbeline; dl; dl = dl->dbeline_func_next)
+ {
+ Function *f = dl->func;
+ if (f && f->line_first == curline
+ && f->getDefSrc () == srcContext)
+ {
+ if (lang_code == Sp_lang_java
+ && (f->flags & FUNC_FLAG_DYNAMIC))
+ continue;
+ if (cur_dbev && cur_dbev->get_path_tree ()->get_func_nodeidx (f))
+ {
+ func_next = f;
+ break;
+ }
+ else if (func_next == NULL)
+ func_next = f;
+ }
+ }
+ if (func_next && curr_func != func_next)
+ {
+ curr_func = func_next;
+ char *func_name = curr_func->get_name ();
+ if (is_fortran () && streq (func_name, NTXT ("MAIN_")))
+ func_name = curr_func->get_match_name ();
+ Hist_data::HistItem *item =
+ src_items->new_hist_item (curr_func, AT_FUNC, empty);
+ item->value[name_idx].l = dbe_sprintf (GTXT ("<Function: %s>"),
+ func_name);
+ data_items->append_hist_item (item);
+ }
+ } // end of red line
+ set_src (type, dbeline); // add the source line
+ } // end of loop over source lines
+
+ // See if compiler flags are set; if so, append them
+ if (cmpline_visible && comp_flags)
+ {
+ Hist_data::HistItem *item = src_items->new_hist_item (NULL, AT_EMPTY,
+ empty);
+ item->value[name_idx].l = strdup (NTXT (""));
+ data_items->append_hist_item (item);
+ item = src_items->new_hist_item (NULL, AT_COM, empty);
+ item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
+ comp_flags);
+ data_items->append_hist_item (item);
+ }
+}
+
+void
+Module::set_dis_data (Function *func, int vis_bits, int cmpline_visible,
+ int src_visible, bool hex_vis, bool func_scope,
+ int funcline_visible)
+{
+ bool nextFile = false;
+
+ // initialize the source output, if any
+ curline = (srcContext->getLineCount () > 0) ? 1 : -1;
+ if (func)
+ nextFile = srcContext != func->getDefSrc ();
+ curr_inc = srcContext;
+
+ bool src_code = (src_visible & SRC_CODE);
+ Anno_Types src_type = (src_visible & SRC_METRIC) ? AT_SRC : AT_SRC_ONLY;
+
+ char *img_fname = func ? func->img_fname : NULL;
+
+ // Build a new Function list
+ Vector<Function*> *FuncLst = new Vector<Function*>;
+ if (func_scope)
+ {
+ if (func)
+ FuncLst->append (func);
+ }
+ else
+ {
+ for (int i = 0, sz = functions ? functions->size () : 0; i < sz; i++)
+ {
+ Function *fitem = functions->fetch (i);
+ if (fitem != fitem->cardinal ())
+ continue;
+ if (img_fname == NULL)
+ img_fname = fitem->img_fname;
+ if (fitem->img_fname == NULL || strcmp (fitem->img_fname, img_fname))
+ continue;
+ FuncLst->append (fitem);
+ }
+ }
+ if (FuncLst->size () == 0)
+ { // no function is good
+ delete FuncLst;
+ return;
+ }
+ cmpSrcContext = srcContext;
+ FuncLst->sort (func_cmp);
+
+ disasm->set_hex_visible (hex_vis);
+ for (int index = 0, sz = FuncLst->size (); index < sz; index++)
+ {
+ Function *fitem = FuncLst->fetch (index);
+ uint64_t start_address, end_address;
+ int64_t inst_size;
+ if (fitem->getDefSrc () != srcContext && curline > 0)
+ {
+ // now flush the left source line, if available
+ for (; curline <= srcContext->getLineCount (); curline++)
+ {
+ // see if there's a compiler comment line to dump
+ if (cline == curline)
+ set_ComCom (vis_bits);
+ if (src_code)
+ set_src (src_type, srcContext->find_dbeline (curline));
+ }
+ curline = -1;
+ }
+
+ curr_inc = NULL;
+ // disassemble one function
+ start_address = objStabs ?
+ objStabs->mapOffsetToAddress (fitem->img_offset) : 0;
+ end_address = start_address + fitem->size;
+ inst_size = 0;
+
+ disasm->set_addr_end (end_address);
+ if ((loadobject->flags & SEG_FLAG_DYNAMIC)
+ && loadobject->platform != Java)
+ disasm->set_img_name (img_fname);
+
+ for (uint64_t inst_address = start_address; inst_address < end_address;)
+ {
+ uint64_t address = inst_address - start_address;
+ DbeInstr *instr = fitem->find_dbeinstr (0, address);
+ DbeLine *dbeline = (DbeLine *) (instr->convertto (Histable::LINE));
+ if (instr->lineno == -1 && dbeline && dbeline->lineno > 0)
+ instr->lineno = dbeline->lineno;
+
+ // now write the unannotated source line, if available
+ if (curline > 0)
+ { // source is present
+ int lineno = curline - 1;
+ if (instr->lineno != -1)
+ {
+ if (dbeline && streq (dbeline->sourceFile->get_name (),
+ srcContext->get_name ()))
+ lineno = instr->lineno;
+ }
+ else if (curr_inc == NULL && srcContext == fitem->def_source
+ && fitem->line_first > 0)
+ lineno = fitem->line_first;
+
+ for (; curline <= lineno; curline++)
+ {
+ // see if there's a compiler comment line to dump
+ if (cline == curline)
+ set_ComCom (vis_bits);
+ if (mline == curline)
+ set_MPSlave ();
+ if (src_code)
+ set_src (src_type, srcContext->find_dbeline (curline));
+ if (curline >= srcContext->getLineCount ())
+ {
+ curline = -1;
+ break;
+ }
+ }
+ }
+
+ if (funcline_visible)
+ { // show red lines
+ if (!curr_inc || (dbeline && curr_inc != dbeline->sourceFile))
+ {
+ Hist_data::HistItem *item = dis_items->new_hist_item (dbeline, AT_FUNC, empty);
+ curr_inc = dbeline ? dbeline->sourceFile : srcContext;
+ char *str;
+ if (curr_inc != srcContext)
+ {
+ char *fileName = curr_inc->dbeFile->getResolvedPath ();
+ str = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
+ fitem->get_name (), fileName);
+ }
+ else
+ str = dbe_sprintf (GTXT ("<Function: %s>"),
+ fitem->get_name ());
+ item->value[name_idx].l = str;
+ data_items->append_hist_item (item);
+ }
+ }
+
+ char *dis_str = get_disasm (inst_address, end_address, start_address,
+ fitem->img_offset, inst_size);
+ if (inst_size == 0)
+ break;
+ else if (instr->size == 0)
+ instr->size = (unsigned int) inst_size;
+ inst_address += inst_size;
+
+ // stomp out control characters
+ for (size_t i = 0, len = strlen (dis_str); i < len; i++)
+ {
+ if (dis_str[i] == '\t')
+ dis_str[i] = ' ';
+ }
+
+ for (int i = 0; i < bTargets.size (); i++)
+ {
+ target_info_t *bTarget = bTargets.fetch (i);
+ if (bTarget->offset == fitem->img_offset + address)
+ {
+ // insert a new line for the bTarget
+ size_t colon = strcspn (dis_str, NTXT (":"));
+ char *msg = GTXT ("* <branch target>");
+ size_t len = colon + strlen (msg);
+ len = (len < 50) ? (50 - len) : 1;
+ char *new_dis_str = dbe_sprintf ("%.*s%s%*c <===----<<<",
+ (int) colon, dis_str, msg,
+ (int) len, ' ');
+ DbeInstr *bt = fitem->find_dbeinstr (PCTrgtFlag, address);
+ bt->lineno = instr->lineno;
+ bt->size = 0;
+ set_dis (bt, AT_DIS, nextFile, new_dis_str);
+ break;
+ }
+ }
+
+ // AnalyzerInfo/Datatype annotations
+ if (infoList != NULL)
+ {
+ inst_info_t *info = NULL;
+ int pinfo;
+ Vec_loop (inst_info_t*, infoList, pinfo, info)
+ {
+ if (info->offset == fitem->img_offset + address) break;
+ }
+ if (info != NULL)
+ { // got a matching memop
+ char typetag[400];
+ typetag[0] = '\0';
+ long t;
+ datatype_t *dtype = NULL;
+ Vec_loop (datatype_t*, datatypes, t, dtype)
+ {
+ if (dtype->datatype_id == info->memop->datatype_id)
+ break;
+ }
+ if (datatypes != NULL)
+ {
+ size_t len = strlen (typetag);
+ if (dtype == NULL || t == datatypes->size ())
+ snprintf (typetag + len, sizeof (typetag) - len, "%s",
+ PTXT (DOBJ_UNSPECIFIED));
+ else if (dtype->dobj == NULL)
+ snprintf (typetag + len, sizeof (typetag) - len, "%s",
+ PTXT (DOBJ_UNDETERMINED));
+ else
+ snprintf (typetag + len, sizeof (typetag) - len, "%s",
+ dtype->dobj->get_name ());
+ }
+ if (strlen (typetag) > 1)
+ {
+ char *new_dis_str;
+ new_dis_str = dbe_sprintf ("%-50s %s", dis_str, typetag);
+ free (dis_str);
+ dis_str = new_dis_str;
+ }
+ }
+ }
+ set_dis (instr, AT_DIS, nextFile, dis_str);
+ }
+ }
+
+ // now flush the left source line, if available
+ if (curline > 0)
+ { // source is present
+ for (; curline <= srcContext->getLineCount (); curline++)
+ {
+ // see if there's a compiler comment line to dump
+ if (cline == curline)
+ set_ComCom (vis_bits);
+
+ if (src_code)
+ set_src (src_type, srcContext->find_dbeline (curline));
+ }
+ }
+
+ // See if compiler flags are set; if so, append them
+ if (cmpline_visible && comp_flags)
+ {
+ Hist_data::HistItem *item = dis_items->new_hist_item (NULL, AT_EMPTY,
+ empty);
+ item->value[name_idx].l = dbe_strdup (NTXT (""));
+ data_items->append_hist_item (item);
+ item = dis_items->new_hist_item (NULL, AT_COM, empty);
+ item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
+ comp_flags);
+ data_items->append_hist_item (item);
+ }
+ delete FuncLst;
+}
+
+// set_src -- inserts one or more lines into the growing data list
+void
+Module::set_src (Anno_Types type, DbeLine *dbeline)
+{
+ Hist_data::HistItem *item;
+
+ // Flush items that are not represented in source
+ while (sline >= 0 && sline < curline)
+ {
+ item = src_items->fetch (sindex);
+ if (((DbeLine*) item->obj)->lineno > 0)
+ set_one (item, AT_QUOTE, item->obj->get_name ());
+
+ if (++sindex < src_items->size ()) // get next line with metrics
+ sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
+ else
+ sline = -1;
+ }
+
+ // write values in the metric fields for the given source line
+ if (curline == sline)
+ { // got metrics for this line
+ item = src_items->fetch (sindex);
+ if (((DbeLine*) item->obj)->lineno > 0)
+ set_one (item, AT_SRC, srcContext->getLine (curline));
+
+ if (++sindex < src_items->size ()) // get next line metric index
+ sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
+ else
+ sline = -1;
+ }
+ else
+ {
+ item = data_items->new_hist_item (dbeline, type, empty);
+ if (size_index != -1)
+ item->value[size_index].ll = dbeline->get_size ();
+ if (addr_index != -1)
+ item->value[addr_index].ll = dbeline->get_addr ();
+ item->value[name_idx].l = dbe_strdup (srcContext->getLine (curline));
+ data_items->append_hist_item (item);
+ }
+}
+
+void
+Module::set_dis (DbeInstr *instr, Anno_Types type, bool nextFile, char *dis_str)
+{
+ // Flush items that are not represented in disassembly
+ while (daddr && daddr->pc_cmp (instr) < 0)
+ {
+ if (!nextFile)
+ set_one (dis_items->fetch (dindex), AT_QUOTE, daddr->get_name ());
+ if (++dindex < dis_items->size ()) // get next line metric index
+ daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
+ else
+ daddr = NULL;
+ }
+
+ // Write values in the metric fields for the given pc index value
+ if (instr->inlinedInd >= 0)
+ {
+ StringBuilder sb;
+ sb.append (dis_str);
+ instr->add_inlined_info (&sb);
+ free (dis_str);
+ dis_str = sb.toString ();
+ }
+ if (daddr && daddr->pc_cmp (instr) == 0)
+ {
+ Hist_data::HistItem *item = data_items->new_hist_item (instr, type,
+ dis_items->fetch (dindex)->value);
+ item->value[name_idx].tag = VT_LABEL;
+ item->value[name_idx].l = dis_str;
+ data_items->append_hist_item (item);
+ if (dis_items->get_callsite_mark ()->get (dis_items->fetch (dindex)->obj))
+ data_items->get_callsite_mark ()->put (item->obj, 1);
+
+ if (++dindex < dis_items->size ()) // get next line metric index
+ daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
+ else
+ daddr = NULL;
+ }
+ else
+ {
+ // create a new item for this PC
+ Hist_data::HistItem *item = dis_items->new_hist_item (instr, type, empty);
+ if (size_index != -1)
+ item->value[size_index].ll = instr->size;
+ if (addr_index != -1)
+ item->value[addr_index].ll = instr->get_addr ();
+ item->value[name_idx].tag = VT_LABEL;
+ item->value[name_idx].l = dis_str;
+ data_items->append_hist_item (item);
+ }
+}
+
+void
+Module::set_MPSlave ()
+{
+ Hist_data::HistItem *item;
+ Function *fp;
+ int index;
+
+ // write the inclusive metrics for slave threads
+ while (mline == curline)
+ {
+ item = dis_items->fetch (mindex);
+ DbeInstr *instr = (DbeInstr *) item->obj;
+ Vec_loop (Function*, functions, index, fp)
+ {
+ if (fp->derivedNode == instr)
+ {
+ set_one (item, AT_QUOTE, (fp->isOutlineFunction) ?
+ GTXT ("<inclusive metrics for outlined functions>") :
+ GTXT ("<inclusive metrics for slave threads>"));
+ break;
+ }
+ }
+
+ mindex++;
+ if (mindex < dis_items->size ())
+ mline = (unsigned) ((DbeInstr*) (dis_items->fetch (mindex)->obj))->addr;
+ else
+ mline = -1;
+ }
+}//set_MPSlave
+
+void
+Module::set_one (Hist_data::HistItem *org_item, Anno_Types type,
+ const char *text)
+{
+ if (org_item == NULL)
+ return;
+ Hist_data::HistItem *item = data_items->new_hist_item (org_item->obj, type,
+ org_item->value);
+ item->value[name_idx].tag = VT_LABEL;
+ item->value[name_idx].l = dbe_strdup (text);
+ data_items->append_hist_item (item);
+ if (org_item != NULL && src_items != NULL
+ && src_items->get_callsite_mark ()->get (org_item->obj))
+ data_items->get_callsite_mark ()->put (item->obj, 1);
+}//set_one
+
+void
+Module::set_ComCom (int vis_bits)
+{
+ Hist_data::HistItem *item;
+ Function *func = dbeSession->get_Unknown_Function ();
+
+ if (vis_bits)
+ {
+ // precede the compiler commentary with a blank line
+ item = data_items->new_hist_item (func, AT_EMPTY, empty);
+ item->value[name_idx].l = dbe_strdup (NTXT (""));
+ data_items->append_hist_item (item);
+ }
+ while (cline == curline)
+ {
+ ComC *comm = comComs->fetch (cindex);
+ if (comm->visible & vis_bits)
+ {
+ // write the compiler commentary
+ item = data_items->new_hist_item (func, AT_COM, empty);
+ item->value[name_idx].l = dbe_strdup (comm->com_str);
+ data_items->append_hist_item (item);
+ }
+ if (++cindex < comComs->size ())
+ cline = comComs->fetch (cindex)->line;
+ else
+ cline = -1;
+ }
+}
+
+void
+Module::dump_dataobjects (FILE *out)
+{
+ int index;
+ datatype_t *dtype;
+ Vec_loop (datatype_t*, datatypes, index, dtype)
+ {
+ fprintf (out, NTXT ("[0x%08X,%6lld] %4d %6d %s "), dtype->datatype_id,
+ dtype->dobj ? dtype->dobj->id : 0LL,
+ dtype->memop_refs, dtype->event_data,
+ (dtype->dobj != NULL ? (dtype->dobj->get_name () ?
+ dtype->dobj->get_name () : "<NULL>") : "<no object>"));
+#if DEBUG
+ Histable* scope = dtype->dobj ? dtype->dobj->get_scope () : NULL;
+ if (scope != NULL)
+ {
+ switch (scope->get_type ())
+ {
+ case Histable::LOADOBJECT:
+ case Histable::FUNCTION:
+ fprintf (out, NTXT ("%s"), scope->get_name ());
+ break;
+ case Histable::MODULE:
+ {
+ char *filename = get_basename (scope->get_name ());
+ fprintf (out, NTXT ("%s"), filename);
+ break;
+ }
+ default:
+ fprintf (out, NTXT ("\tUnexpected scope %d:%s"),
+ scope->get_type (), scope->get_name ());
+ }
+ }
+#endif
+ fprintf (out, NTXT ("\n"));
+ }
+}
+
+void
+Module::set_name (char *str)
+{
+ free (name);
+ name = str;
+}
+
+void
+Module::read_hwcprof_info ()
+{
+ if (hwcprof == 0)
+ {
+ hwcprof = 1;
+ Stabs *stabs = openDebugInfo ();
+ if (stabs)
+ stabs->read_hwcprof_info (this);
+ }
+}
+
+void
+Module::reset_datatypes ()
+{
+ for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
+ {
+ datatype_t *t = datatypes->fetch (i);
+ t->event_data = 0;
+ }
+}
+
+DataObject *
+Module::get_dobj (uint32_t dtype_id)
+{
+ read_hwcprof_info ();
+ for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
+ {
+ datatype_t *t = datatypes->fetch (i);
+ if (t->datatype_id == dtype_id)
+ {
+ t->event_data++;
+ return t->dobj;
+ }
+ }
+ return NULL;
+}
+
+int
+Module::readFile ()
+{
+ return AE_OK;
+}
+
+Vector<Histable*> *
+Module::get_comparable_objs ()
+{
+ update_comparable_objs ();
+ if (comparable_objs || dbeSession->expGroups->size () <= 1 || loadobject == NULL)
+ return comparable_objs;
+ Vector<Histable*> *comparableLoadObjs = loadobject->get_comparable_objs ();
+ if (comparableLoadObjs == NULL)
+ return NULL;
+ comparable_objs = new Vector<Histable*>(comparableLoadObjs->size ());
+ for (int i = 0, sz = comparableLoadObjs->size (); i < sz; i++)
+ {
+ Module *mod = NULL;
+ LoadObject *lo = (LoadObject*) comparableLoadObjs->fetch (i);
+ if (lo)
+ {
+ mod = lo->get_comparable_Module (this);
+ if (mod)
+ mod->comparable_objs = comparable_objs;
+ }
+ comparable_objs->store (i, mod);
+ }
+ dump_comparable_objs ();
+ return comparable_objs;
+}
+
+JMethod *
+Module::find_jmethod (const char *nm, const char *sig)
+{
+ // Vladimir: Probably we should not use linear search
+ for (long i = 0, sz = VecSize (functions); i < sz; i++)
+ {
+ JMethod *jmthd = (JMethod*) functions->get (i);
+ char *jmt_name = jmthd->get_name (Histable::SHORT);
+ if (strcmp (jmt_name, nm) == 0
+ && strcmp (jmthd->get_signature (), sig) == 0)
+ return jmthd;
+ }
+ return NULL;
+}
diff --git a/gprofng/src/Module.h b/gprofng/src/Module.h
new file mode 100644
index 0000000..39c4322
--- /dev/null
+++ b/gprofng/src/Module.h
@@ -0,0 +1,284 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _MODULE_H
+#define _MODULE_H
+
+// A Module object represents a .o file that was used to build up a segement.
+// Its main function is to compute source and disassembly annotations
+// Text reordering and/or function outlining imply that a module may
+// not be contiguous.
+
+#include "Histable.h"
+#include "Hist_data.h"
+
+#define MOD_FLAG_UNKNOWN 0x01
+
+class LoadObject;
+class MetricList;
+class ComC;
+class Disasm;
+class Hist_data;
+class Stabs;
+class SourceFile;
+class DataObject;
+class JMethod;
+template <class ITEM> class Vector;
+
+class InlinedSubr
+{
+public:
+ InlinedSubr ();
+ DbeLine *dbeLine;
+ Function *func;
+ char *fname;
+ uint64_t low_pc;
+ uint64_t high_pc;
+ int level;
+
+ bool
+ contains (InlinedSubr *p)
+ {
+ return low_pc <= p->low_pc && high_pc >= p->high_pc;
+ }
+
+ bool
+ contains (uint64_t pc)
+ {
+ return low_pc <= pc && high_pc > pc;
+ }
+};
+
+class Module : public HistableFile
+{
+public:
+ // Annotated Source or Disassembly
+ enum Anno_Errors
+ {
+ AE_OK,
+ AE_NOTREAD,
+ AE_NOSRC,
+ AE_NOOBJ,
+ AE_NOLOBJ,
+ AE_NOSTABS,
+ AE_NOSYMTAB,
+ AE_TIMESRC,
+ AE_TIMEDIS,
+ AE_TIMESTABS,
+ AE_TIMESTABS_DIFF,
+ AE_OTHER
+ };
+
+ // The following enums are duplicated in Java
+ enum Anno_Types
+ {
+ AT_LIST = 0,
+ AT_SRC,
+ AT_SRC_ONLY,
+ AT_DIS,
+ AT_COM,
+ AT_QUOTE,
+ AT_FUNC,
+ AT_EMPTY,
+ AT_DIS_ONLY
+ };
+
+ Module ();
+ virtual ~Module ();
+ virtual int64_t get_size ();
+ virtual void set_name (char *str);
+ virtual Vector<Histable*> *get_comparable_objs ();
+ virtual int readFile ();
+
+ virtual Histable_type
+ get_type ()
+ {
+ return MODULE;
+ }
+
+ inline Anno_Errors
+ get_status ()
+ {
+ return status;
+ }
+
+ inline void
+ set_file_name (char *fnm)
+ {
+ free (file_name);
+ file_name = fnm;
+ }
+
+ // get error string
+ char *anno_str (char *fnm = NULL);
+
+ // generate annotated source/disassembly data
+ Hist_data *get_data (DbeView *dbev, MetricList *mlist,
+ Histable::Type type, TValue *ftotal, SourceFile *srcFile,
+ Function *func, Vector<int> *marks, int threshold,
+ int vis_bits, int src_visible, bool hex_visible,
+ bool func_scope, bool src_only,
+ Vector<int_pair_t> *marks2d = NULL,
+ Vector<int_pair_t> *marks2d_inc = NULL);
+
+ Vector<uint64_t> *getAddrs (Function *func);
+ SourceFile *setIncludeFile (char *includeFile);
+
+ SourceFile *
+ getIncludeFile ()
+ {
+ return curr_inc;
+ }
+
+ SourceFile *
+ getMainSrc ()
+ {
+ return main_source;
+ }
+
+ char *
+ getResolvedObjectPath ()
+ {
+ return stabsPath ? stabsPath : get_name ();
+ }
+
+ char *
+ getDebugPath ()
+ {
+ setFile ();
+ return stabsPath;
+ }
+
+ void read_stabs (bool all = true);
+ void dump_dataobjects (FILE *out);
+ DataObject *get_dobj (uint32_t dtype_id);
+ void reset_datatypes ();
+ void read_hwcprof_info ();
+ bool is_fortran ();
+ SourceFile *findSource (const char *fname, bool create);
+ bool openStabs (bool all = true);
+ LoadObject *createLoadObject (const char *lo_name);
+ JMethod *find_jmethod (const char *nm, const char *sig);
+
+ unsigned int flags; // flags used for marking traversals
+ Sp_lang_code lang_code; // What is source lang. in module
+ char *file_name; // Full path to actual source file
+ Vector<Function*> *functions; // Unordered list of functions
+ LoadObject *loadobject; // Parent loadobject
+ LoadObject *dot_o_file; // The .o file with debug information
+ unsigned fragmented; // -xF used when compiling module
+ int real_timestamp; // Linked timestamp from N_OPT stab
+ int curr_timestamp; // Current object timestamp from N_OPT stab
+ char *comp_flags; // compiler flags used to compile module
+ char *comp_dir; // directory used to compile module
+ char *linkerStabName; // Name from 'N_UNDF' stab
+ Stabs *objStabs; // stabs of object file
+ bool readStabs;
+ bool hasStabs;
+ bool hasDwarf;
+ uint64_t hdrOffset; // offset in .debug_info
+ unsigned hwcprof; // hwcprof info status
+ Vector<inst_info_t*> *infoList; // merged list
+ Vector<memop_info_t*> ldMemops; // load instructions
+ Vector<memop_info_t*> stMemops; // store instructions
+ Vector<memop_info_t*> pfMemops; // prefetch instructions
+ Vector<target_info_t*> bTargets; // branch targets
+ Vector<datatype_t*> *datatypes; // object type descriptors
+ Vector<SourceFile*> *includes;
+ Module *indexStabsLink; // correspondent module for the .o file
+ InlinedSubr *inlinedSubr;
+
+protected:
+ void removeStabsTmp (); // Remove temporary *.o (got from *.a)
+
+ // Check timestamp, warn users if src/dis/stabs later than exp.
+ Anno_Errors checkTimeStamp (bool chkDis);
+
+ // Set paths for reading Stabs and Symbols
+ bool read_ar (int ar, int obj, char *obj_base);
+ bool setFile ();
+
+ // Open appropriate symbol tables, construct set of PC ranges,
+ // and maps to source lines for each PC
+ Stabs *openDebugInfo ();
+
+ // Construct PC index table
+ bool openDisPC ();
+
+ // Compute data--scan data to compute metrics per-src-line/dis-line
+ bool computeMetrics (DbeView *dbev, Function *func, MetricList *mlist,
+ Histable::Type type, bool src_metric,
+ bool func_scope, SourceFile *source);
+ void init_line ();
+ void init_index (Hist_data *witems, int &wlindex, int &wmsize, int &wmindex);
+
+ void set_src_data (Function *func, int vis_bits, int cmpline_visible,
+ int funcline_visible);
+ void set_dis_data (Function *func, int vis_bits, int cmpline_visible,
+ int src_visible, bool hex_vis, bool func_scope,
+ int funcline_visible);
+ void set_src (Anno_Types type, DbeLine *dbeline);
+ void set_dis (DbeInstr *instr, Anno_Types type, bool nextFile, char *dis_str);
+ void set_MPSlave ();
+ void set_one (Hist_data::HistItem *org_item, Anno_Types type, const char *text);
+ void set_ComCom (int vis_bits);
+
+ virtual char *get_disasm (uint64_t inst_address, uint64_t end_address,
+ uint64_t start_address, uint64_t f_offset,
+ int64_t &inst_size);
+
+ Anno_Errors status;
+ Anno_Errors openSourceFlag;
+ bool hexVisible; // show hex code in disasm
+ time_t disMTime; // Creating time for disassembly
+ time_t stabsMTime; // Creating time for stabs
+ SourceFile *main_source;
+ SourceFile *curr_inc; // pointer to include file or NULL
+ SourceFile *srcContext;
+ Vector<ComC*> *comComs; // table of compiler comments
+ Disasm *disasm;
+ Hist_data *src_items;
+ Hist_data *dis_items;
+ Hist_data *data_items;
+ DbeView * cur_dbev;
+ TValue *total;
+ TValue *maximum;
+ TValue *maximum_inc;
+ TValue *empty;
+ int name_idx; // index of name metric in list for src/dis
+ int size_index; // index of size metric in list for src/dis
+ int addr_index; // index of address metric in list for src/dis
+
+ int curline; // line# of next source line to be processed
+ int cindex, cline; // index and src line of next compiler-comment
+ int sindex, sline; // index and src line of next item in src_items
+ int dindex;
+ DbeInstr *daddr; // pointer to next DbeInstr with metrics
+ int mindex; // MP index and src line of next metric-value
+ int mline; // MP line to be processed by source
+
+ char *disPath; // path for disassembly
+ char *stabsPath; // path for reading stabs
+ char *stabsTmp; // temporary *.o from *.a
+ char *disName; // library/path for disassembly
+ char *stabsName; // library/path for stabs
+};
+
+#endif /* _MODULE_H */
diff --git a/gprofng/src/Ovw_data.cc b/gprofng/src/Ovw_data.cc
new file mode 100644
index 0000000..2cd5718
--- /dev/null
+++ b/gprofng/src/Ovw_data.cc
@@ -0,0 +1,242 @@
+/* Copyright (C) 2021 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 <memory.h>
+#include <values.h>
+#include <assert.h>
+#include "Data_window.h"
+#include "Exp_Layout.h"
+#include "Table.h"
+#include "Ovw_data.h"
+#include "Sample.h"
+#include "data_pckts.h"
+#include "util.h"
+#include "i18n.h"
+
+void
+Ovw_data::sum (Ovw_data *data)
+{
+ Ovw_item data_totals = data->get_totals ();
+ if (totals == NULL)
+ {
+ totals = reset_item (new Ovw_item);
+ *totals = data_totals;
+ totals->start.tv_sec = totals->end.tv_sec = -1;
+ totals->start.tv_nsec = totals->end.tv_nsec = 0;
+ }
+ else
+ {
+ tsadd (&totals->duration, &data_totals.duration);
+ tsadd (&totals->tlwp, &data_totals.tlwp);
+ if (tstodouble (totals->duration) != 0)
+ totals->nlwp = tstodouble (totals->tlwp) / tstodouble (totals->duration);
+
+ for (int i = 0, size = totals->size; i < size; i++)
+ tsadd (&totals->values[i].t, &data_totals.values[i].t);
+ }
+}
+
+Ovw_data::Ovw_item *
+Ovw_data::reset_item (Ovw_data::Ovw_item *item)
+{
+ memset (item, 0, sizeof (*item));
+ return item;
+}
+
+Ovw_data::Ovw_item
+Ovw_data::get_totals ()
+{
+ // This routine will return the totals values for item in the sample.
+ // Compute maximums and totals only once, and save the result.
+ // On subsequent calls, just return the saved result.
+ // If maximums is NULL, then totals is also NULL
+ if (totals != NULL)
+ return *totals;
+
+ timestruc_t zero = {0, 0};
+ totals = reset_item (new Ovw_item);
+ totals->start.tv_sec = MAXINT; // new
+ totals->start.tv_nsec = MAXINT; // new
+ totals->start_label = totals->end_label = NTXT ("Total");
+ totals->type = VT_HRTIME;
+
+ int nsampsel = 0;
+ for (int index = 0; index < size (); index++)
+ {
+ Ovw_item item = fetch (index);
+ nsampsel++;
+
+ // Compute totals
+ for (int i = 0; i < OVW_NUMVALS + 1; i++)
+ tsadd (&totals->values[i].t, &item.values[i].t);
+
+ int_max (&totals->states, item.states);
+ tsadd (&totals->total.t, &item.total.t);
+ int_max (&totals->size, item.size);
+ tsadd (&totals->duration, &item.duration);
+ tsadd (&totals->tlwp, &item.tlwp);
+ totals->number += item.number;
+ if (tscmp (&totals->start, &item.start) > 0)
+ totals->start = item.start;
+ if (tscmp (&totals->end, &item.end) < 0)
+ totals->end = item.end;
+ }
+
+ if (totals->start.tv_sec == MAXINT && totals->start.tv_nsec == MAXINT)
+ totals->start = zero;
+ totals->nlwp = tstodouble (totals->tlwp) / tstodouble (totals->duration);
+
+ if (nsampsel == 0)
+ {
+ totals->size = OVW_NUMVALS + 1;
+ totals->start.tv_sec = totals->end.tv_sec = -1;
+ totals->start.tv_nsec = totals->end.tv_nsec = 0;
+ totals->nlwp = -1;
+ }
+ return *totals;
+}
+
+Ovw_data::Ovw_item
+Ovw_data::get_labels ()
+{
+ Ovw_item ovw_item;
+ Value *values;
+ memset (&ovw_item, 0, sizeof (Ovw_item));
+ values = &ovw_item.values[0];
+
+ char *stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS;
+ values[0].l = dbe_strdup (GTXT ("Leftover"));
+ values[OVW_LMS_USER + 1].l = stateUNames[LMS_USER];
+ values[OVW_LMS_SYSTEM + 1].l = stateUNames[LMS_SYSTEM];
+ values[OVW_LMS_WAIT_CPU + 1].l = stateUNames[LMS_WAIT_CPU];
+ values[OVW_LMS_USER_LOCK + 1].l = stateUNames[LMS_USER_LOCK];
+ values[OVW_LMS_TFAULT + 1].l = stateUNames[LMS_TFAULT];
+ values[OVW_LMS_DFAULT + 1].l = stateUNames[LMS_DFAULT];
+ values[OVW_LMS_KFAULT + 1].l = stateUNames[LMS_KFAULT];
+ values[OVW_LMS_SLEEP + 1].l = stateUNames[LMS_SLEEP];
+ values[OVW_LMS_STOPPED + 1].l = stateUNames[LMS_STOPPED];
+ values[OVW_LMS_TRAP + 1].l = stateUNames[LMS_TRAP];
+
+ ovw_item.size = OVW_NUMVALS + 1;
+ ovw_item.states = 0;
+ ovw_item.type = VT_LABEL;
+ return ovw_item;
+}
+
+Ovw_data::Ovw_data ()
+{
+ packets = NULL;
+ ovw_items = new Vector<Ovw_item*>;
+ totals = NULL;
+}
+
+Ovw_data::Ovw_data (DataView *_packets, hrtime_t exp_start)
+{
+ packets = _packets;
+ ovw_items = new Vector<Ovw_item*>;
+ totals = NULL;
+ long npackets = packets->getSize ();
+ for (long index = 0; index < npackets; index++)
+ {
+ Ovw_item *ovw_item = new Ovw_item;
+ memset (ovw_item, 0, sizeof (Ovw_item));
+ Sample *sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
+ extract_data (ovw_item, sample);
+ hr2timestruc (&ovw_item->start, sample->get_start_time () - exp_start);
+ hr2timestruc (&ovw_item->end, sample->get_end_time () - exp_start);
+ // No need to check for duration, as duration has to be > 0.
+ // If not, it would have been found out in yyparse.
+ tssub (&ovw_item->duration, &ovw_item->end, &ovw_item->start);
+ ovw_item->number = sample->get_number ();
+ ovw_item->start_label = sample->get_start_label ();
+ ovw_item->end_label = sample->get_end_label ();
+
+ int size = ovw_item->size;
+ for (int j = 0; j < size; j++)
+ tsadd (&ovw_item->tlwp, &ovw_item->values[j].t);
+ if (tstodouble (ovw_item->duration) != 0)
+ ovw_item->nlwp = tstodouble (ovw_item->tlwp) /
+ tstodouble (ovw_item->duration);
+ ovw_items->append (ovw_item);
+ }
+}
+
+Ovw_data::~Ovw_data ()
+{
+ ovw_items->destroy ();
+ delete ovw_items;
+ delete totals;
+}
+
+void
+Ovw_data::extract_data (Ovw_data::Ovw_item *ovw_item, Sample *sample)
+{
+ // This routine break out the data in "data" into buckets in "ovw_item"
+ int index;
+ int states;
+ timestruc_t sum, rtime;
+ timestruc_t zero = {0, 0};
+ Value *values;
+ PrUsage *prusage = sample->get_usage ();
+ if (prusage == NULL)
+ prusage = new PrUsage;
+
+ values = &ovw_item->values[0];
+ hr2timestruc (&values[OVW_LMS_USER + 1].t, prusage->pr_utime);
+ hr2timestruc (&values[OVW_LMS_SYSTEM + 1].t, prusage->pr_stime);
+ hr2timestruc (&values[OVW_LMS_WAIT_CPU + 1].t, prusage->pr_wtime);
+ hr2timestruc (&values[OVW_LMS_USER_LOCK + 1].t, prusage->pr_ltime);
+ hr2timestruc (&values[OVW_LMS_TFAULT + 1].t, prusage->pr_tftime);
+ hr2timestruc (&values[OVW_LMS_DFAULT + 1].t, prusage->pr_dftime);
+ hr2timestruc (&values[OVW_LMS_TRAP + 1].t, prusage->pr_ttime);
+ hr2timestruc (&values[OVW_LMS_KFAULT + 1].t, prusage->pr_kftime);
+ hr2timestruc (&values[OVW_LMS_SLEEP + 1].t, prusage->pr_slptime);
+ hr2timestruc (&values[OVW_LMS_STOPPED + 1].t, prusage->pr_stoptime);
+ ovw_item->size = OVW_NUMVALS + 1;
+
+ //XXX: Compute values[0] as rtime - sum_of(other_times)
+ sum = zero;
+ states = 0;
+ for (index = 1; index < ovw_item->size; index++)
+ {
+ if (values[index].t.tv_sec != 0 || values[index].t.tv_nsec != 0)
+ states++;
+ tsadd (&sum, &values[index].t);
+ }
+
+ // If the sum of all times is greater than rtime then adjust
+ // rtime to be equal to sum and also adjust the pr_rtime field
+ hr2timestruc (&rtime, prusage->pr_rtime);
+ if (tscmp (&sum, &rtime) > 0)
+ {
+ ovw_item->total.t = sum;
+ values[0].t = zero;
+ }
+ else
+ {
+ ovw_item->total.t = rtime;
+ tssub (&rtime, &rtime, &sum);
+ tsadd (&values[0].t, &rtime);
+ states++;
+ }
+ ovw_item->type = VT_HRTIME;
+ ovw_item->states = states;
+}
diff --git a/gprofng/src/Ovw_data.h b/gprofng/src/Ovw_data.h
new file mode 100644
index 0000000..0c3372c
--- /dev/null
+++ b/gprofng/src/Ovw_data.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _OVW_DATA_H
+#define _OVW_DATA_H
+
+// An Ovw_data object is used to supply data for constructing an overview
+// display.
+
+#include "dbe_structs.h"
+
+class Sample;
+class DataView;
+
+class Ovw_data
+{
+public:
+
+ enum OVW_LMS_STORAGE
+ {// in display order, not LMS_* order
+ // Note: use same display order of LMS_* in: er.rc, TimelineVariable.java,
+ // Ovw_data.h, BaseMetricTreeNode.cc and Experiment.cc metric registration
+ OVW_LMS_USER,
+ OVW_LMS_SYSTEM,
+ OVW_LMS_TRAP,
+ OVW_LMS_USER_LOCK,
+ OVW_LMS_DFAULT,
+ OVW_LMS_TFAULT,
+ OVW_LMS_KFAULT,
+ OVW_LMS_STOPPED,
+ OVW_LMS_WAIT_CPU,
+ OVW_LMS_SLEEP,
+ OVW_NUMVALS // must be last
+ };
+
+ // Ovw_item contains one slice of data
+ struct Ovw_item
+ {
+ Value values [OVW_NUMVALS + 1]; // Value list (value[0] is left over)
+ int states; // Number of non-zero states
+ Value total; // Total of all values
+ int size; // Number of values
+ timestruc_t start; // Start time of sample
+ timestruc_t duration; // Duration of sample
+ timestruc_t end; // End time of sample
+ timestruc_t tlwp; // Total LWP time
+ double nlwp; // Average number of LWPs
+ ValueTag type; // Type of value
+ int number; // Sample number
+ char *start_label; // Sample start label
+ char *end_label; // Sample end label
+ };
+
+ Ovw_data (DataView *, hrtime_t exp_start);
+ Ovw_data ();
+ ~Ovw_data ();
+ void sum (Ovw_data *data);
+ Ovw_item get_totals ();
+ Ovw_item get_labels ();
+
+ // zero out contents of Ovw_item
+ static Ovw_item *reset_item (Ovw_item *item);
+
+ int
+ size ()
+ {
+ return ovw_items->size ();
+ }
+
+ Ovw_item
+ fetch (int index)
+ {
+ return *ovw_items->fetch (index);
+ }
+
+private:
+ // Compute the values for "ovw_item" from "sample".
+ void extract_data (Ovw_item *ovw_item, Sample *sample);
+
+ Vector<Ovw_item*> *ovw_items;
+ Ovw_item *totals; // Item to cache totals
+ DataView *packets;
+};
+
+#endif /* _OVW_DATA_H */
diff --git a/gprofng/src/PRBTree.cc b/gprofng/src/PRBTree.cc
new file mode 100644
index 0000000..5046a91
--- /dev/null
+++ b/gprofng/src/PRBTree.cc
@@ -0,0 +1,480 @@
+/* Copyright (C) 2021 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. */
+
+// The Persistent Red-Black Tree
+//
+// Implementation is based on an algorithm described in
+// Sarnak, N., Tarjan, R., "Planar point location using
+// persistent search trees", in Communications of the ACM,
+// 1986, Vol.29, Number 7.
+//
+
+#include "config.h"
+#include <memory.h>
+#include <string.h>
+
+#include "vec.h"
+#include "PRBTree.h"
+
+#define ASSERT(x)
+
+#define IS_BLACK(x) ((x)==NULL || (x)->color == Black)
+#define IS_RED(x) ((x)!=NULL && (x)->color == Red)
+#define SET_BLACK(x) if(x) x->color = Black
+#define SET_RED(x) (x)->color = Red
+
+#define D_OPPOSITE(x) (((x)==Left) ? Right : Left )
+
+PRBTree::LMap::LMap (Key_t _key, void *_item)
+{
+ key = _key;
+ item = _item;
+ color = Red;
+ parent = NULL;
+ for (int i = 0; i < NPTRS; i++)
+ {
+ dir[i] = None;
+ chld[i] = NULL;
+ time[i] = 0;
+ }
+};
+
+PRBTree::LMap::LMap (const LMap& lm)
+{
+ key = lm.key;
+ item = lm.item;
+ color = lm.color;
+ parent = lm.parent;
+ for (int i = 0; i < NPTRS; i++)
+ {
+ dir[i] = None;
+ chld[i] = NULL;
+ time[i] = 0;
+ }
+};
+
+PRBTree::PRBTree ()
+{
+ roots = new Vector<LMap*>;
+ root = NULL;
+ times = new Vector<Time_t>;
+ rtts = (Time_t) 0;
+ curts = (Time_t) 0;
+ mlist = NULL;
+ vals = NULL;
+}
+
+PRBTree::~PRBTree ()
+{
+ while (mlist)
+ {
+ LMap *lm = mlist;
+ mlist = mlist->next;
+ delete lm;
+ }
+ delete times;
+ delete roots;
+ delete vals;
+}
+
+Vector<void *> *
+PRBTree::values ()
+{
+ if (vals == NULL)
+ {
+ vals = new Vector<void*>;
+ for (LMap *lm = mlist; lm; lm = lm->next)
+ vals->append (lm->item);
+ }
+ return vals;
+}
+
+PRBTree::LMap *
+PRBTree::rb_new_node (Key_t key, void *item)
+{
+ LMap *lm = new LMap (key, item);
+ lm->next = mlist;
+ mlist = lm;
+ return lm;
+}
+
+PRBTree::LMap *
+PRBTree::rb_new_node (LMap *lm)
+{
+ LMap *lmnew = new LMap (*lm);
+ lmnew->next = mlist;
+ mlist = lmnew;
+ return lmnew;
+}
+
+PRBTree::LMap *
+PRBTree::rb_child (LMap *lm, Direction d, Time_t ts)
+{
+ if (lm == NULL)
+ return NULL;
+ for (int i = 0; i < NPTRS; i++)
+ {
+ if (lm->time[i] > ts)
+ continue;
+ if (lm->dir[i] == d)
+ return lm->chld[i];
+ else if (lm->dir[i] == None)
+ break;
+ }
+ return NULL;
+}
+
+PRBTree::Direction
+PRBTree::rb_which_chld (LMap *lm)
+{
+ LMap *prnt = lm->parent;
+ if (prnt == NULL)
+ return None;
+ for (int i = 0; i < NPTRS; i++)
+ {
+ if (prnt->dir[i] == None)
+ break;
+ if (prnt->chld[i] == lm)
+ return (Direction) prnt->dir[i];
+ }
+ return None;
+}
+
+PRBTree::LMap *
+PRBTree::rb_neighbor (LMap *lm, Time_t ts)
+{
+ ASSERT (lm->dir[0] != None);
+ Direction d = D_OPPOSITE (lm->dir[0]);
+ LMap *y = NULL;
+ LMap *next = lm->chld[0];
+ while (next)
+ {
+ y = next;
+ next = rb_child (y, d, ts);
+ }
+ return y;
+}
+
+PRBTree::LMap *
+PRBTree::rb_copy_node (LMap *lm, Direction d)
+{
+ LMap *nlm = rb_new_node (lm);
+ rb_fix_chld (lm->parent, nlm, rb_which_chld (lm));
+ if (d == None)
+ {
+ d = Left;
+ rb_fix_chld (nlm, rb_child (lm, d, curts), d);
+ }
+
+ // copy the other child
+ Direction dd = D_OPPOSITE (d);
+ rb_fix_chld (nlm, rb_child (lm, dd, curts), dd);
+ return nlm;
+}
+
+PRBTree::LMap *
+PRBTree::rb_fix_chld (LMap *prnt, LMap *lm, Direction d)
+{
+
+ if (prnt == NULL)
+ {
+ // fixing root
+ ASSERT (d == None);
+ if (rtts == curts)
+ root = lm;
+ else
+ {
+ roots->append (root);
+ times->append (rtts);
+ root = lm;
+ rtts = curts;
+ }
+ if (lm != NULL)
+ lm->parent = prnt;
+ return prnt;
+ }
+
+ // If we already have a d-pointer at time curts, reuse it
+ for (int i = 0; prnt->time[i] == curts; i++)
+ {
+ if (prnt->dir[i] == d)
+ {
+ prnt->chld[i] = lm;
+ if (lm != NULL)
+ lm->parent = prnt;
+ return prnt;
+ }
+ }
+
+ if (prnt->dir[NPTRS - 1] != None)
+ prnt = rb_copy_node (prnt, d);
+ ASSERT (prnt->dir[NPTRS - 1] == None);
+
+ for (int i = NPTRS - 1; i > 0; i--)
+ {
+ prnt->dir[i] = prnt->dir[i - 1];
+ prnt->chld[i] = prnt->chld[i - 1];
+ prnt->time[i] = prnt->time[i - 1];
+ }
+ prnt->dir[0] = d;
+ prnt->chld[0] = lm;
+ prnt->time[0] = curts;
+ if (lm != NULL)
+ lm->parent = prnt;
+ return prnt;
+}
+
+PRBTree::LMap *
+PRBTree::rb_rotate (LMap *x, Direction d)
+{
+ Direction dd = D_OPPOSITE (d);
+ LMap *y = rb_child (x, dd, curts);
+ x = rb_fix_chld (x, rb_child (y, d, curts), dd);
+ rb_fix_chld (x->parent, y, rb_which_chld (x));
+ rb_fix_chld (y, x, d);
+ return x;
+}
+
+void
+PRBTree::rb_remove_fixup (LMap *x, LMap *prnt, Direction d0)
+{
+
+ while (IS_BLACK (x) && (x != root))
+ {
+ Direction d = (x == NULL) ? d0 : rb_which_chld (x);
+ Direction dd = D_OPPOSITE (d);
+ LMap *y = rb_child (prnt, dd, curts);
+ if (IS_RED (y))
+ {
+ SET_BLACK (y);
+ SET_RED (prnt);
+ prnt = rb_rotate (prnt, d);
+ y = rb_child (prnt, dd, curts);
+ }
+ LMap *y_d = rb_child (y, d, curts);
+ LMap *y_dd = rb_child (y, dd, curts);
+ if (IS_BLACK (y_d) && IS_BLACK (y_dd))
+ {
+ SET_RED (y);
+ x = prnt;
+ prnt = x->parent;
+ }
+ else
+ {
+ if (IS_BLACK (y_dd))
+ {
+ SET_BLACK (y_d);
+ SET_RED (y);
+ y = rb_rotate (y, dd);
+ prnt = y->parent->parent;
+ y = rb_child (prnt, dd, curts);
+ y_dd = rb_child (y, dd, curts);
+ }
+ y->color = prnt->color;
+ SET_BLACK (prnt);
+ SET_BLACK (y_dd);
+ prnt = rb_rotate (prnt, d);
+ break;
+ }
+ }
+ SET_BLACK (x);
+}
+
+PRBTree::LMap *
+PRBTree::rb_locate (Key_t key, Time_t ts, bool low)
+{
+ LMap *lm;
+ Direction d;
+ int i, lt, rt;
+ int tsz = times->size ();
+
+ if (ts >= rtts)
+ lm = root;
+ else
+ {
+ // exponential search
+ for (i = 1; i <= tsz; i = i * 2)
+ if (times->fetch (tsz - i) <= ts)
+ break;
+
+ if (i <= tsz)
+ {
+ lt = tsz - i;
+ rt = tsz - i / 2 - 1;
+ }
+ else
+ {
+ lt = 0;
+ rt = tsz - 1;
+ }
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ if (times->fetch (md) <= ts)
+ lt = md + 1;
+ else
+ rt = md - 1;
+ }
+ if (rt < 0)
+ return NULL;
+ lm = roots->fetch (rt);
+ }
+
+ LMap *last_lo = NULL;
+ LMap *last_hi = NULL;
+ while (lm != NULL)
+ {
+ if (key >= lm->key)
+ {
+ last_lo = lm;
+ d = Right;
+ }
+ else
+ {
+ last_hi = lm;
+ d = Left;
+ }
+ lm = rb_child (lm, d, ts);
+ }
+ return low ? last_lo : last_hi;
+}
+
+//==================================================== Public interface
+
+bool
+PRBTree::insert (Key_t key, Time_t ts, void *item)
+{
+ LMap *lm, *y;
+ Direction d, dd;
+ if (ts > curts)
+ curts = ts;
+ else if (ts < curts)
+ return false; // can only update the current tree
+
+ // Insert in the tree in the usual way
+ y = NULL;
+ d = None;
+ for (LMap *next = root; next;)
+ {
+ y = next;
+ if (key == y->key)
+ {
+ // copy the node with both children
+ lm = rb_copy_node (y, None);
+ // but use the new item
+ lm->item = item;
+ return true;
+ }
+ d = (key < y->key) ? Left : Right;
+ next = rb_child (y, d, curts);
+ }
+ lm = rb_new_node (key, item);
+ rb_fix_chld (y, lm, d);
+
+ // Rebalance the tree
+ while (IS_RED (lm->parent))
+ {
+ d = rb_which_chld (lm->parent);
+ dd = D_OPPOSITE (d);
+
+ y = rb_child (lm->parent->parent, dd, curts);
+ if (IS_RED (y))
+ {
+ SET_BLACK (lm->parent);
+ SET_BLACK (y);
+ SET_RED (lm->parent->parent);
+ lm = lm->parent->parent;
+ }
+ else
+ {
+ if (rb_which_chld (lm) == dd)
+ {
+ lm = lm->parent;
+ lm = rb_rotate (lm, d);
+ }
+ SET_BLACK (lm->parent);
+ SET_RED (lm->parent->parent);
+ rb_rotate (lm->parent->parent, dd);
+ }
+ }
+
+ // Color the root Black
+ SET_BLACK (root);
+ return true;
+}
+
+bool
+PRBTree::remove (Key_t key, Time_t ts)
+{
+ LMap *lm, *x, *y, *prnt;
+ if (ts > curts)
+ curts = ts;
+ else if (ts < curts)
+ return false; // can only update the current tree
+
+ lm = rb_locate (key, curts, true);
+ if (lm == NULL || lm->key != key)
+ return false;
+
+ if (rb_child (lm, Left, curts) && rb_child (lm, Right, curts))
+ y = rb_neighbor (lm, curts);
+ else
+ y = lm;
+
+ x = rb_child (y, Left, curts);
+ if (x == NULL)
+ x = rb_child (y, Right, curts);
+
+ if (y != lm)
+ {
+ lm = rb_copy_node (lm, None); // copied with children
+ lm->key = y->key;
+ lm->item = y->item;
+ }
+
+ Direction d = rb_which_chld (y);
+ prnt = rb_fix_chld (y->parent, x, d);
+ if (IS_BLACK (y))
+ rb_remove_fixup (x, prnt, d);
+ return true;
+}
+
+void *
+PRBTree::locate (Key_t key, Time_t ts)
+{
+ LMap *lm = rb_locate (key, ts, true);
+ return lm ? lm->item : NULL;
+}
+
+void *
+PRBTree::locate_up (Key_t key, Time_t ts)
+{
+ LMap *lm = rb_locate (key, ts, false);
+ return lm ? lm->item : NULL;
+}
+
+void *
+PRBTree::locate_exact_match (Key_t key, Time_t ts)
+{
+ LMap *lm = rb_locate (key, ts, true);
+ if (lm && key == lm->key)
+ return lm->item;
+ return NULL;
+}
diff --git a/gprofng/src/PRBTree.h b/gprofng/src/PRBTree.h
new file mode 100644
index 0000000..1a6f07f
--- /dev/null
+++ b/gprofng/src/PRBTree.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2021 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. */
+
+//
+// The Persistent Red-Black Tree
+//
+
+#ifndef _PRBTREE_H
+#define _PRBTREE_H
+
+#include "dbe_types.h"
+template <class ITEM> class Vector;
+
+// The number of pointers in a node must be set greater than 2.
+// The higher the number the faster the search seems to be and
+// the more memory the tree takes.
+#define NPTRS 5
+
+class PRBTree
+{
+public:
+
+ typedef Vaddr Key_t;
+ typedef hrtime_t Time_t;
+
+ PRBTree ();
+ ~PRBTree ();
+
+ bool insert (Key_t key, Time_t ts, void *item);
+ bool remove (Key_t key, Time_t ts);
+ void *locate (Key_t key, Time_t ts);
+ void *locate_exact_match (Key_t key, Time_t ts);
+ void *locate_up (Key_t key, Time_t ts);
+ Vector<void *> *values ();
+
+private:
+
+ enum Color
+ {
+ Red,
+ Black
+ };
+
+ enum Direction
+ {
+ None,
+ Left,
+ Right
+ };
+
+ struct LMap
+ {
+ Key_t key;
+ void *item;
+ LMap *parent;
+ LMap *chld[NPTRS];
+ Time_t time[NPTRS];
+ char dir[NPTRS];
+ char color;
+ LMap *next;
+
+ LMap (Key_t _key, void *_item);
+ LMap (const LMap& lm);
+ };
+ friend struct LMap;
+
+ LMap *mlist; // The master list of all nodes
+ Vector<LMap*> *roots;
+ Vector<Time_t> *times;
+ Vector<void *> *vals;
+ LMap *root;
+ Time_t rtts; // root timestamp
+ Time_t curts; // last update timestamp
+
+ LMap *rb_locate (Key_t key, Time_t ts, bool low);
+ LMap *rb_new_node (Key_t key, void *item);
+ LMap *rb_new_node (LMap *lm);
+ LMap *rb_copy_node (LMap *lm, Direction d);
+ LMap *rb_fix_chld (LMap *prnt, LMap *lm, Direction d);
+ LMap *rb_rotate (LMap *x, Direction d);
+ void rb_remove_fixup (LMap *x, LMap *prnt, Direction d0);
+
+ static LMap *rb_child (LMap *lm, Direction d, Time_t ts);
+ static Direction rb_which_chld (LMap *lm);
+ static LMap *rb_neighbor (LMap *lm, Time_t ts);
+
+};
+
+#endif /* _PRBTREE_H */
diff --git a/gprofng/src/PathTree.cc b/gprofng/src/PathTree.cc
new file mode 100644
index 0000000..798e55c
--- /dev/null
+++ b/gprofng/src/PathTree.cc
@@ -0,0 +1,2637 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "DefaultMap.h"
+#include "CacheMap.h"
+
+#include "DbeSession.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Emsg.h"
+#include "Experiment.h"
+#include "Expression.h"
+#include "Function.h"
+#include "Histable.h"
+#include "IndexObject.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "PathTree.h"
+#include "LoadObject.h"
+#include "Sample.h"
+#include "StringBuilder.h"
+#include "Table.h"
+
+// Define counts, rate for error warnings for statistical profiles
+#define MIN_PROF_CNT 100
+#define MAX_PROF_RATE 1000.
+
+#define NUM_DESCENDANTS(nd) ((nd)->descendants ? (nd)->descendants->size() : 0)
+#define IS_LEAF(nd) ((nd)->descendants == NULL)
+
+#ifdef DEBUG
+#define DBG(__func) __func
+#else
+#define DBG(__func)
+#endif
+
+void
+PathTree::construct (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType)
+{
+ dbev = _dbev;
+ indxtype = _indxtype;
+ pathTreeType = _pathTreeType;
+ status = 0;
+ nchunks = 0;
+ chunks = NULL;
+ nodes = 1; // don't use node 0
+ nslots = 0;
+ slots = NULL;
+ root_idx = 0;
+ root = NULL;
+ depth = 1;
+ dnodes = 0;
+ phaseIdx = -1;
+ nexps = 0;
+ total_obj = NULL;
+ indx_expr = NULL;
+ statsq = NULL;
+ warningq = NULL;
+ cancel_ok = 1;
+ ptree_internal = NULL;
+ ftree_internal = NULL;
+ ftree_needs_update = false;
+ depth_map = NULL;
+ init ();
+}
+
+PathTree::~PathTree ()
+{
+ fini ();
+ for (long i = 0; i < nchunks; i++)
+ delete[] chunks[i];
+ delete[] chunks;
+}
+
+void
+PathTree::init ()
+{
+ fn_map = new DefaultMap<Function*, NodeIdx>;
+ stack_prop = PROP_NONE;
+ desc_htable_size = 511;
+ desc_htable_nelem = 0;
+ descHT = new hash_node_t*[desc_htable_size];
+ for (int i = 0; i < desc_htable_size; i++)
+ descHT[i] = NULL;
+ pathMap = new CacheMap<uint64_t, NodeIdx>;
+ statsq = new Emsgqueue (NTXT ("statsq"));
+ warningq = new Emsgqueue (NTXT ("warningq"));
+ if (indxtype < 0)
+ {
+ Function *ftotal = dbeSession->get_Total_Function ();
+ if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE)
+ total_obj = ftotal;
+ else
+ total_obj = ftotal->find_dbeinstr (0, 0);
+ VMode view_mode = dbev->get_view_mode ();
+ if (view_mode == VMODE_MACHINE)
+ stack_prop = PROP_MSTACK;
+ else if (view_mode == VMODE_EXPERT)
+ stack_prop = PROP_XSTACK;
+ else if (view_mode == VMODE_USER)
+ {
+ stack_prop = PROP_USTACK;
+ if (dbeSession->is_omp_available ()
+ && pathTreeType == PATHTREE_INTERNAL_OMP)
+ stack_prop = PROP_XSTACK;
+ }
+ }
+ else
+ {
+ total_obj = new IndexObject (indxtype, (uint64_t) - 2);
+ total_obj->set_name (dbe_strdup (NTXT ("<Total>")));
+ char *idxname = dbeSession->getIndexSpaceName (indxtype);
+ if (streq (idxname, NTXT ("OMP_preg")))
+ stack_prop = PROP_CPRID;
+ else if (streq (idxname, NTXT ("OMP_task")))
+ stack_prop = PROP_TSKID;
+ else
+ indx_expr = dbeSession->getIndexSpaceExpr (indxtype);
+ }
+ root_idx = new_Node (0, total_obj, false);
+ root = NODE_IDX (root_idx);
+}
+
+void
+PathTree::fini ()
+{
+ // For each node free its descendants vector
+ // and reset the node list of its function
+ for (long i = 1; i < nodes; i++)
+ {
+ Node *node = NODE_IDX (i);
+ if (node->descendants)
+ delete node->descendants;
+ }
+ nodes = 1; // don't use node 0
+
+ for (int i = 0; i < nslots; i++)
+ {
+ int **tmp = slots[i].mvals;
+ for (long j = 0; j < nchunks; j++)
+ delete[] tmp[j];
+ delete[] tmp;
+ }
+ delete[] slots;
+ slots = NULL;
+ nslots = 0;
+ delete fn_map;
+ fn_map = NULL;
+ delete pathMap;
+ pathMap = NULL;
+ destroy (depth_map);
+ depth_map = NULL;
+ if (indxtype >= 0)
+ delete total_obj;
+
+ for (int i = 0; i < desc_htable_size; i++)
+ {
+ hash_node_t *p = descHT[i];
+ while (p)
+ {
+ hash_node_t *p1 = p;
+ p = p->next;
+ delete p1;
+ }
+ }
+ delete[] descHT;
+ delete statsq;
+ delete warningq;
+ depth = 1;
+ dnodes = 0;
+ phaseIdx = -1;
+ nexps = 0;
+ status = 0;
+}
+
+PtreePhaseStatus
+PathTree::reset ()
+{
+ if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE)
+ return NORMAL; // never process reset for ftree_internal.
+
+ if (dbeSession->is_omp_available () && dbev->get_view_mode () == VMODE_USER
+ && pathTreeType == PATHTREE_MAIN && ptree_internal == NULL)
+ ptree_internal = new PathTree (dbev, indxtype, PATHTREE_INTERNAL_OMP);
+
+ if (phaseIdx != dbev->getPhaseIdx ())
+ {
+ fini ();
+ init ();
+ phaseIdx = dbev->getPhaseIdx ();
+ ftree_needs_update = true;
+ }
+ for (; nexps < dbeSession->nexps (); nexps++)
+ {
+ ftree_needs_update = true;
+ if (add_experiment (nexps) == CANCELED)
+ return CANCELED;
+ }
+
+ // LIBRARY_VISIBILITY
+ if (dbev->isNewViewMode ())
+ dbev->resetNewViewMode ();
+ if (dbev->isShowHideChanged ())
+ dbev->resetShowHideChanged ();
+ return NORMAL;
+}
+
+int
+PathTree::allocate_slot (int id, ValueTag vtype)
+{
+
+ int i;
+ int slot_idx = find_slot (id);
+ if (slot_idx >= 0)
+ {
+ DBG (assert (slots[slot_idx].vtype == vtype));
+ return slot_idx;
+ }
+ slot_idx = nslots++;
+
+ Slot *old_slots = slots;
+ slots = new Slot[nslots];
+ for (i = 0; i < slot_idx; i++)
+ slots[i] = old_slots[i];
+ delete[] old_slots;
+
+ slots[slot_idx].id = id;
+ slots[slot_idx].vtype = vtype;
+ int **ip = new int*[nchunks];
+ for (i = 0; i < nchunks; i++)
+ ip[i] = NULL;
+ slots[slot_idx].mvals = ip;
+
+ return slot_idx;
+}
+
+void
+PathTree::allocate_slots (Slot *new_slots, int new_nslots)
+{
+ // duplicates new_slots
+
+ // if previously had more slots than currently requested, delete the data from those slots.
+ for (int i = new_nslots; i < nslots; i++)
+ {
+ int **tmp = slots[i].mvals;
+ for (long j = 0; j < nchunks; j++)
+ delete tmp[j];
+ delete tmp;
+ }
+ if (new_nslots == 0)
+ {
+ nslots = new_nslots;
+ delete[] slots;
+ slots = NULL;
+ return;
+ }
+
+ Slot *old_slots = slots;
+ slots = new Slot[new_nslots];
+ for (int i = 0; i < new_nslots; i++)
+ {
+ slots[i] = new_slots[i]; // pick up id and vtype
+ if (i < nslots)
+ slots[i].mvals = old_slots[i].mvals;
+ else
+ {
+ if (nchunks == 0)
+ slots[i].mvals = NULL;
+ else
+ {
+ int **ip = new int*[nchunks];
+ for (long j = 0; j < nchunks; j++)
+ ip[j] = NULL;
+ slots[i].mvals = ip;
+ }
+ }
+ }
+ nslots = new_nslots;
+ delete old_slots;
+}
+
+int
+PathTree::find_slot (int id)
+{
+ for (int i = 0; i < nslots; i++)
+ if (slots[i].id == id)
+ return i;
+ return -1;
+}
+
+PathTree::NodeIdx
+PathTree::new_Node (NodeIdx anc, Histable *instr, bool leaf)
+{
+ if (nodes >= nchunks * CHUNKSZ)
+ {
+ long idx = nchunks++;
+
+ // Reallocate Node chunk array
+ Node **old_chunks = chunks;
+ chunks = new Node*[nchunks];
+ for (long k = 0; k < idx; k++)
+ chunks[k] = old_chunks[k];
+ delete[] old_chunks;
+
+ // Reallocate metric value chunk arrays.
+ for (int i = 0; i < nslots; i++)
+ {
+ int **mvals = new int*[nchunks];
+ for (long k = 0; k < idx; k++)
+ {
+ mvals[k] = slots[i].mvals[k];
+ }
+ delete[] slots[i].mvals;
+ slots[i].mvals = mvals;
+ slots[i].mvals[idx] = NULL;
+ }
+
+ // Allocate new chunk for nodes.
+ // Note that we don't need to allocate new chunks
+ // for metric values at this point as we rely on
+ // lazy allocation.
+ //
+ allocate_chunk (chunks, idx);
+ }
+ NodeIdx node_idx = nodes++;
+ Node *node = NODE_IDX (node_idx);
+ node->ancestor = anc;
+ node->descendants = leaf ? (Vector<NodeIdx>*)NULL : new Vector<NodeIdx>(2);
+ node->instr = instr;
+ Function *func = (Function*) (instr->convertto (Histable::FUNCTION));
+ node->funclist = fn_map->get (func);
+ fn_map->put (func, node_idx);
+ return node_idx;
+}
+
+PathTree::NodeIdx
+PathTree::find_path (Experiment *exp, DataView *dview, long recIdx)
+{
+ if (indx_expr != NULL)
+ {
+ Expression::Context ctx (dbev, exp, dview, recIdx);
+ uint64_t idx = indx_expr->eval (&ctx);
+ Histable *cur_obj = dbeSession->createIndexObject (indxtype, idx);
+ cur_obj->set_name_from_context (&ctx);
+ NodeIdx dsc_idx = find_in_desc_htable (root_idx, cur_obj, true);
+ depth = 2;
+ return dsc_idx;
+ }
+
+ bool showAll = dbev->isShowAll ();
+ int t_stack_prop = stack_prop;
+ void *stackId = dview->getObjValue (t_stack_prop, recIdx);
+ NodeIdx node_idx;
+ if (stackId != NULL)
+ {
+ // pathMap does not work with NULL key
+ node_idx = pathMap->get ((uint64_t) stackId);
+ if (node_idx != 0)
+ return node_idx;
+ }
+ Vector<Histable*> *stack = (Vector<Histable*>*)CallStack::getStackPCs (stackId, !showAll);
+ int stack_size = stack->size ();
+ if (stack_size == 0)
+ return root_idx;
+
+ node_idx = root_idx;
+ int thisdepth = 1;
+
+ for (int i = stack_size - 1; i >= 0; i--)
+ {
+ bool leaf = (i == 0);
+ Histable *cur_addr = stack->fetch (i);
+
+ // bail out of loop if load object API-only is set
+ // and this is not the top frame
+ // This is now done in HSTACK if hide is set
+
+ Function *func = (Function*) cur_addr->convertto (Histable::FUNCTION);
+ if (func != NULL)
+ {
+ Module *mod = func->module;
+ LoadObject *lo = mod->loadobject;
+ int segx = lo->seg_idx;
+ if (showAll && dbev->get_lo_expand (segx) == LIBEX_API
+ && i != stack_size - 1)
+ leaf = true;
+ }
+
+ NodeIdx dsc_idx = find_desc_node (node_idx, cur_addr, leaf);
+ thisdepth++;
+ node_idx = dsc_idx;
+
+ // LIBEX_API processing might have set leaf to true
+ if (leaf)
+ break;
+ }
+ if (thisdepth > depth)
+ depth = thisdepth;
+ delete stack;
+ pathMap->put ((uint64_t) stackId, node_idx);
+ return node_idx;
+}
+
+static int
+desc_node_comp (const void *s1, const void *s2, const void *ptree)
+{
+ PathTree::NodeIdx t1, t2;
+ t1 = *(PathTree::NodeIdx *)s1;
+ t2 = *(PathTree::NodeIdx *)s2;
+ PathTree* Ptree = (PathTree *) ptree;
+ PathTree::Node *n1 = Ptree->NODE_IDX (t1);
+ PathTree::Node *n2 = Ptree->NODE_IDX (t2);
+ Histable *d1 = n1->instr;
+ Histable *d2 = n2->instr;
+ if (d1->id < d2->id)
+ return -1;
+ else if (d1->id > d2->id)
+ return +1;
+ else
+ return 0;
+}
+
+PathTree::NodeIdx
+PathTree::find_in_desc_htable (NodeIdx node_idx, Histable *instr, bool leaf)
+{
+ unsigned int hash_code = (unsigned int) instr->id % desc_htable_size;
+ Node *node = NODE_IDX (node_idx);
+ hash_node_t *p = NULL;
+ for (p = descHT[hash_code]; p; p = p->next)
+ {
+ Node *dsc = NODE_IDX (p->nd);
+ Histable *dinstr = dsc->instr;
+ if (dinstr->id == instr->id && leaf == IS_LEAF (dsc))
+ return p->nd;
+ }
+ // Not found
+ NodeIdx dsc_idx = new_Node (node_idx, instr, leaf);
+ node->descendants->append (dsc_idx);
+ p = new hash_node_t ();
+ p->nd = dsc_idx;
+ p->next = descHT[hash_code];
+ descHT[hash_code] = p;
+ desc_htable_nelem++;
+
+ // time to resize
+ if (desc_htable_nelem == desc_htable_size)
+ {
+ int old_htable_size = desc_htable_size;
+ desc_htable_size = old_htable_size * 2 + 1;
+ hash_node_t **old_htable = descHT;
+ descHT = new hash_node_t*[desc_htable_size];
+ for (int i = 0; i < desc_htable_size; i++)
+ descHT[i] = NULL;
+
+ for (int i = 0; i < old_htable_size; i++)
+ if (old_htable[i] != NULL)
+ {
+ hash_node *old_p;
+ hash_node_t *hash_p = old_htable[i];
+ while (hash_p != NULL)
+ {
+ hash_node_t *new_p = new hash_node_t ();
+ new_p->nd = hash_p->nd;
+ Node *dnode = NODE_IDX (hash_p->nd);
+ Histable *dnode_instr = dnode->instr;
+ hash_code = (unsigned int) dnode_instr->id % desc_htable_size;
+ new_p->next = descHT[hash_code];
+ descHT[hash_code] = new_p;
+ old_p = hash_p;
+ hash_p = hash_p->next;
+ delete old_p;
+ }
+ }
+ delete[] old_htable;
+ }
+ return dsc_idx;
+}
+
+PathTree::NodeIdx
+PathTree::find_desc_node (NodeIdx node_idx, Histable *instr, bool leaf)
+{
+ // Binary search. All nodes are ordered by Histable::id.
+
+ // We have a special case when two nodes with the same
+ // id value may co-exist: one representing a leaf node and
+ // another one representing a call site.
+ Node *node = NODE_IDX (node_idx);
+ int left = 0;
+ int right = NUM_DESCENDANTS (node) - 1;
+ while (left <= right)
+ {
+ int index = (left + right) / 2;
+ NodeIdx dsc_idx = node->descendants->fetch (index);
+ Node *dsc = NODE_IDX (dsc_idx);
+ Histable *dinstr = dsc->instr;
+ if (instr->id < dinstr->id)
+ right = index - 1;
+ else if (instr->id > dinstr->id)
+ left = index + 1;
+ else if (leaf == IS_LEAF (dsc))
+ return dsc_idx;
+ else if (leaf)
+ right = index - 1;
+ else
+ left = index + 1;
+ }
+
+ // None was found. Create one.
+ NodeIdx dsc_idx = new_Node (node_idx, instr, leaf);
+ node->descendants->insert (left, dsc_idx);
+ return dsc_idx;
+}
+
+PtreePhaseStatus
+PathTree::process_packets (Experiment *exp, DataView *packets, int data_type)
+{
+ Expression::Context ctx (dbev, exp);
+ char *progress_bar_msg = NULL;
+ int progress_bar_percent = -1;
+
+ Vector<BaseMetric*> *mlist = dbev->get_all_reg_metrics ();
+ Vector<BaseMetric*> mlist2;
+ StringBuilder stb;
+ for (int midx = 0, mlist_sz = mlist->size (); midx < mlist_sz; ++midx)
+ {
+ BaseMetric *mtr = mlist->fetch (midx);
+ if (mtr->get_packet_type () == data_type &&
+ (mtr->get_expr () == NULL || mtr->get_expr ()->passes (&ctx)))
+ {
+ Hwcentry *hwc = mtr->get_hw_ctr ();
+ if (hwc)
+ {
+ stb.setLength (0);
+ // XXX this should be done at metric registration
+ Collection_params *col_params = exp->get_params ();
+ for (int i = 0; i < MAX_HWCOUNT; i++)
+ {
+ // We may have duplicate counters in col_params,
+ // check for all (see 5081284).
+ if (dbe_strcmp (hwc->name, col_params->hw_aux_name[i]) == 0)
+ {
+ if (stb.length () != 0)
+ stb.append (NTXT ("||"));
+ stb.append (NTXT ("HWCTAG=="));
+ stb.append (i);
+ }
+ }
+ if (stb.length () == 0)
+ continue;
+ stb.append (NTXT ("&& ((HWCINT & "));
+ stb.append ((long long) HWCVAL_ERR_FLAG);
+ stb.append (NTXT (")==0)"));
+ char *s = stb.toString ();
+ mtr->set_cond_spec (s);
+ free (s);
+ }
+ ValueTag vtype = mtr->get_vtype ();
+ switch (vtype)
+ {
+ case VT_INT:
+ case VT_ULLONG:
+ case VT_LLONG:
+ break; // nothing to do
+ default:
+ vtype = VT_ULLONG; // ym: not sure when this would happen
+ break;
+ }
+ allocate_slot (mtr->get_id (), vtype);
+ mlist2.append (mtr);
+ }
+ }
+
+ Slot **mslots = new Slot*[mlist2.size ()];
+ for (int midx = 0, mlist_sz = mlist2.size (); midx < mlist_sz; ++midx)
+ {
+ BaseMetric *mtr = mlist2.fetch (midx);
+ int id = mtr->get_id ();
+ int slot_ind = find_slot (id);
+ mslots[midx] = SLOT_IDX (slot_ind);
+ }
+
+ for (long i = 0, packets_sz = packets->getSize (); i < packets_sz; ++i)
+ {
+ if (dbeSession->is_interactive ())
+ {
+ if (NULL == progress_bar_msg)
+ progress_bar_msg = dbe_sprintf (GTXT ("Processing Experiment: %s"),
+ get_basename (exp->get_expt_name ()));
+ int val = (int) (100 * i / packets_sz);
+ if (val > progress_bar_percent)
+ {
+ progress_bar_percent += 10;
+ if (theApplication->set_progress (val, progress_bar_msg)
+ && cancel_ok)
+ {
+ delete[] mslots;
+ return CANCELED;
+ }
+ }
+ }
+
+ NodeIdx path_idx = 0;
+ ctx.put (packets, i);
+
+ for (int midx = 0, mlist_sz = mlist2.size (); midx < mlist_sz; ++midx)
+ {
+ BaseMetric *mtr = mlist2.fetch (midx);
+ if (mtr->get_cond () != NULL && !mtr->get_cond ()->passes (&ctx))
+ continue;
+
+ int64_t mval = mtr->get_val ()->eval (&ctx);
+ if (mval == 0)
+ continue;
+ if (path_idx == 0)
+ path_idx = find_path (exp, packets, i);
+ NodeIdx node_idx = path_idx;
+ Slot *mslot = mslots[midx];
+ while (node_idx)
+ {
+ INCREMENT_METRIC (mslot, node_idx, mval);
+ node_idx = NODE_IDX (node_idx)->ancestor;
+ }
+ }
+ }
+ if (dbeSession->is_interactive ())
+ free (progress_bar_msg);
+ delete[] mslots;
+ if (indx_expr != NULL)
+ root->descendants->sort ((CompareFunc) desc_node_comp, this);
+ return NORMAL;
+}
+
+DataView *
+PathTree::get_filtered_events (int exp_index, int data_type)
+{
+ if (indx_expr != NULL)
+ {
+ IndexObjType_t *indexObj = dbeSession->getIndexSpace (indxtype);
+ if (indexObj->memObj && data_type != DATA_HWC)
+ return NULL;
+ }
+ return dbev->get_filtered_events (exp_index, data_type);
+}
+
+PtreePhaseStatus
+PathTree::add_experiment (int exp_index)
+{
+ StringBuilder sb;
+ char *expt_name;
+ char *base_name;
+ Emsg *m;
+ Experiment *experiment = dbeSession->get_exp (exp_index);
+ if (experiment->broken != 0)
+ return NORMAL;
+ status = 0;
+ expt_name = experiment->get_expt_name ();
+ base_name = get_basename (expt_name);
+
+ hrtime_t starttime = gethrtime ();
+ hrtime_t startvtime = gethrvtime ();
+
+ // Experiment::getEndTime was initially implemented as
+ // returning exp->last_event. To preserve the semantics
+ // new Experiment::getLastEvent() is used here.
+ hrtime_t tot_time = experiment->getLastEvent () - experiment->getStartTime ();
+
+ if (!dbev->isShowAll () && (dbev->isShowHideChanged ()
+ || dbev->isNewViewMode ()))
+ experiment->resetShowHideStack ();
+
+ // To report experiment index to the user,
+ // start numeration from 1, not 0
+ sb.sprintf (GTXT ("PathTree processing experiment %d (`%s'); duration %lld.%06lld"),
+ exp_index + 1, base_name,
+ tot_time / NANOSEC, (tot_time % NANOSEC / 1000));
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+
+ DataView *prof_packet = get_filtered_events (exp_index, DATA_CLOCK);
+ if (prof_packet && prof_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, prof_packet, DATA_CLOCK) == CANCELED)
+ return CANCELED;
+ long clock_cnt = prof_packet->getSize ();
+ double clock_rate;
+ if (tot_time != 0)
+ clock_rate = (double) clock_cnt / (double) tot_time * (double) NANOSEC;
+ else
+ clock_rate = (double) 0.;
+ if (experiment->timelineavail)
+ sb.sprintf (GTXT (" Processed %ld clock-profile events (%3.2f/sec.)"),
+ clock_cnt, clock_rate);
+ else
+ sb.sprintf (GTXT (" Processed %ld clock-profile events"), clock_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+
+ // check for statistical validity
+ if ((experiment->timelineavail == true)
+ && !dbev->get_filter_active () && (clock_cnt < MIN_PROF_CNT))
+ {
+ sb.sprintf (GTXT ("WARNING: too few clock-profile events (%ld) in experiment %d (`%s') for statistical validity"),
+ clock_cnt, exp_index + 1, base_name);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+ }
+
+ DataView *sync_packet = get_filtered_events (exp_index, DATA_SYNCH);
+ if (sync_packet && sync_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, sync_packet, DATA_SYNCH) == CANCELED)
+ return CANCELED;
+ long sync_cnt = sync_packet->getSize ();
+ sb.sprintf (GTXT (" Processed %ld synctrace events"), sync_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+
+ DataView *iotrace_packet = get_filtered_events (exp_index, DATA_IOTRACE);
+ if (iotrace_packet && iotrace_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, iotrace_packet, DATA_IOTRACE) == CANCELED)
+ return CANCELED;
+ long iotrace_cnt = iotrace_packet->getSize ();
+ sb.sprintf (GTXT (" Processed %ld IO trace events"), iotrace_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+
+ DataView *hwc_packet = get_filtered_events (exp_index, DATA_HWC);
+ if (hwc_packet && hwc_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, hwc_packet, DATA_HWC) == CANCELED)
+ return CANCELED;
+ long hwc_cnt = hwc_packet->getSize ();
+ double hwc_rate = (double) hwc_cnt / (double) tot_time * (double) NANOSEC;
+ if (experiment->timelineavail)
+ sb.sprintf (GTXT (" Processed %ld hwc-profile events (%3.2f/sec.)"),
+ hwc_cnt, hwc_rate);
+ else
+ sb.sprintf (GTXT (" Processed %ld hwc-profile events"), hwc_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+
+ // check for statistical validity
+ if (experiment->timelineavail && !dbev->get_filter_active () && (hwc_cnt < MIN_PROF_CNT))
+ {
+ sb.sprintf (GTXT ("WARNING: too few HW counter profile events (%ld) in experiment %d (`%s') for statistical validity"),
+ hwc_cnt, exp_index + 1, base_name);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+ }
+
+ DataView *heap_packet = get_filtered_events (exp_index, DATA_HEAP);
+ if (heap_packet && heap_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, heap_packet, DATA_HEAP) == CANCELED)
+ return CANCELED;
+ long heap_cnt = heap_packet->getSize ();
+ sb.sprintf (GTXT (" Processed %ld heaptrace events"), heap_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+
+ DataView *race_packet = get_filtered_events (exp_index, DATA_RACE);
+ if (race_packet && race_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, race_packet, DATA_RACE) == CANCELED)
+ return CANCELED;
+ long race_cnt = race_packet->getSize ();
+ sb.sprintf (GTXT (" Processed %ld race access events"), race_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+
+ DataView *deadlock_packet = get_filtered_events (exp_index, DATA_DLCK);
+ if (deadlock_packet && deadlock_packet->getSize () > 0)
+ {
+ if (process_packets (experiment, deadlock_packet, DATA_DLCK) == CANCELED)
+ return CANCELED;
+ long race_cnt = deadlock_packet->getSize ();
+ sb.sprintf (GTXT (" Processed %ld race access events"), race_cnt);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ }
+
+ hrtime_t pathtime = gethrtime () - starttime;
+ hrtime_t pathvtime = gethrvtime () - startvtime;
+ sb.sprintf (GTXT ("PathTree time = %lld.%06lld CPU-time %lld.%06lld\n"),
+ pathtime / NANOSEC, (pathtime % NANOSEC) / 1000,
+ pathvtime / NANOSEC, (pathvtime % NANOSEC) / 1000);
+ m = new Emsg (CMSG_COMMENT, sb);
+ statsq->append (m);
+ return NORMAL;
+}
+
+Hist_data *
+PathTree::compute_metrics (MetricList *mlist, Histable::Type type,
+ Hist_data::Mode mode, Vector<Histable*> *objs,
+ Histable *context, Vector<Histable*> *sel_objs,
+ PtreeComputeOption computeOpt)
+{
+ VMode view_mode = dbev->get_view_mode ();
+
+ // For displaying disassembly correctly in user mode with openmp
+ if (ptree_internal != NULL &&
+ (view_mode == VMODE_EXPERT ||
+ (view_mode == VMODE_USER && (type == Histable::INSTR
+ || (dbev->isOmpDisMode ()
+ && type == Histable::FUNCTION
+ && mode == Hist_data::CALLEES
+ && computeOpt == COMPUTEOPT_OMP_CALLEE))
+ )))
+ return ptree_internal->compute_metrics (mlist, type, mode, objs, context,
+ sel_objs);
+
+ PtreePhaseStatus resetStatus = reset ();
+
+ hist_data = new Hist_data (mlist, type, mode);
+ int nmetrics = mlist->get_items ()->size ();
+ int sort_ind = -1;
+ Hist_data::HistItem *hi;
+ int index;
+
+ if (status != 0 || resetStatus == CANCELED)
+ return hist_data;
+
+ hist_data->set_status (Hist_data::SUCCESS);
+ if (dbeSession->is_interactive () && mode != Hist_data::CALLEES)
+ theApplication->set_progress (0, GTXT ("Constructing Metrics"));
+
+ xlate = new int[nmetrics];
+ for (int mind = 0; mind < nmetrics; mind++)
+ {
+ Metric *mtr = mlist->get (mind);
+ xlate[mind] = find_slot (mtr->get_id ());
+ }
+
+ // Compute dynamic metrics
+ obj_list = new Histable*[depth];
+ if ((type == Histable::LINE || type == Histable::INSTR)
+ && mode == Hist_data::CALLERS)
+ node_list = new Node*[depth];
+ percent = 0;
+ ndone = 0;
+ if (mode == Hist_data::MODL)
+ {
+ Histable *obj = objs && objs->size () > 0 ? objs->fetch (0) : NULL;
+ if (obj != NULL)
+ {
+ switch (obj->get_type ())
+ {
+ case Histable::FUNCTION:
+ {
+ Vector<Function*> *funclist = new Vector<Function*>;
+ funclist->append ((Function*) obj);
+ get_metrics (funclist, context);
+ delete funclist;
+ break;
+ }
+ case Histable::MODULE:
+ {
+ Vector<Histable*> *comparableModules = obj->get_comparable_objs ();
+ if (comparableModules != NULL)
+ {
+ Vector<Function*> *functions = new Vector<Function*>;
+ for (int i = 0; i < comparableModules->size (); i++)
+ {
+ Module *mod = (Module*) comparableModules->fetch (i);
+ if (mod)
+ {
+ bool found = false;
+ for (int i1 = 0; i1 < i; i1++)
+ {
+ if (mod == comparableModules->fetch (i1))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ functions->addAll (mod->functions);
+ }
+ }
+ get_metrics (functions, context);
+ delete functions;
+ }
+ else
+ get_metrics (((Module*) obj)->functions, context);
+ break;
+ }
+ case Histable::SOURCEFILE:
+ get_metrics (((SourceFile *) obj)->get_functions (), context);
+ break;
+ default:
+ DBG (assert (0));
+ }
+ }
+ }
+ else if (mode == Hist_data::CALLERS)
+ {
+ if (objs && objs->size () > 0)
+ get_clr_metrics (objs);
+ }
+ else if (mode == Hist_data::CALLEES)
+ {
+ if (objs && objs->size () > 0)
+ get_cle_metrics (objs);
+ else // Special case: get root
+ get_cle_metrics (NULL);
+ }
+ else if (mode == Hist_data::SELF)
+ {
+ if (objs->size () == 1)
+ {
+ Histable *obj = objs->fetch (0);
+ if (obj != NULL)
+ {
+ if (obj->get_type () == Histable::LINE)
+ {
+ Vector<Function*> *funclist = new Vector<Function*>;
+ for (DbeLine *dl = (DbeLine*) obj->convertto (Histable::LINE);
+ dl; dl = dl->dbeline_func_next)
+ if (dl->func)
+ funclist->append (dl->func);
+
+ get_self_metrics (obj, funclist, sel_objs);
+ delete funclist;
+ }
+ else if (obj->get_type () == Histable::FUNCTION
+ || obj->get_type () == Histable::INSTR)
+ {
+ // Use shortcut for functions and oth.
+ if (context)
+ {
+ Vector<Function*> *funclist = NULL;
+ if (context->get_type () == Histable::MODULE)
+ funclist = ((Module*) context)->functions->copy ();
+ else
+ {
+ funclist = new Vector<Function*>;
+ funclist->append ((Function*) context);
+ }
+ get_self_metrics (obj, funclist, sel_objs);
+ delete funclist;
+ }
+ else
+ get_self_metrics (objs);
+ }
+ else
+ get_self_metrics (objs);
+ }
+ }
+ else
+ get_self_metrics (objs);
+ }
+ else // Hist_data::ALL
+ get_metrics (root_idx, 0);
+
+ delete[] obj_list;
+ if ((type == Histable::LINE || type == Histable::INSTR)
+ && mode == Hist_data::CALLERS)
+ delete[] node_list;
+
+ // Postprocess; find total
+ for (long mind = 0, sz = mlist->get_items ()->size (); mind < sz; mind++)
+ {
+ Metric *mtr = mlist->get_items ()->get (mind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ ValueTag vtype = mtr->get_vtype ();
+ hist_data->total->value[mind].tag = vtype;
+
+ switch (vtype)
+ {
+ // ignoring the following cases (why?)
+ case VT_SHORT:
+ case VT_FLOAT:
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ break;
+
+ case VT_INT:
+ // Calculate total as the sum of all values in hist_data for
+ // ATTRIBUTED metrics only. For all others, use root node values.
+ //
+ if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+ && subtype == Metric::ATTRIBUTED)
+ {
+ hist_data->total->value[mind].i = 0;
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ hist_data->total->value[mind].i += hi->value[mind].i;
+ }
+ if (mode == Hist_data::CALLEES)
+ hist_data->total->value[mind].i += hist_data->gprof_item->value[mind].i;
+ }
+ else if (xlate[mind] != -1)
+ ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]],
+ root_idx);
+ break;
+
+ case VT_LLONG:
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = vtype;
+ }
+
+ if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+ && subtype == Metric::ATTRIBUTED)
+ {
+ hist_data->total->value[mind].ll = 0;
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ hist_data->total->value[mind].ll += hi->value[mind].ll;
+ }
+ if (mode == Hist_data::CALLEES)
+ hist_data->total->value[mind].ll += hist_data->gprof_item->value[mind].ll;
+ }
+ else if (xlate[mind] != -1)
+ ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], root_idx);
+ break;
+
+ case VT_ULLONG:
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = vtype;
+ }
+ if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+ && subtype == Metric::ATTRIBUTED)
+ {
+ hist_data->total->value[mind].ull = 0;
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ hist_data->total->value[mind].ull += hi->value[mind].ull;
+ }
+ if (mode == Hist_data::CALLEES)
+ hist_data->total->value[mind].ull += hist_data->gprof_item->value[mind].ull;
+ }
+ else if (xlate[mind] != -1)
+ ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], root_idx);
+ break;
+
+ case VT_DOUBLE:
+ double prec = mtr->get_precision ();
+ ValueTag vt = (xlate[mind] != -1) ? slots[xlate[mind]].vtype : VT_INT;
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ double val = (vt == VT_LLONG ? hi->value[mind].ll :
+ (vt == VT_ULLONG ? hi->value[mind].ull
+ : hi->value[mind].i));
+ hi->value[mind].tag = vtype;
+ hi->value[mind].d = val / prec;
+ }
+
+ if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+ && subtype == Metric::ATTRIBUTED)
+ {
+ hist_data->total->value[mind].d = 0.0;
+ Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+ {
+ hist_data->total->value[mind].d += hi->value[mind].d;
+ }
+ if (mode == Hist_data::CALLEES)
+ hist_data->total->value[mind].d +=
+ (double) (vt == VT_LLONG ? hist_data->gprof_item->value[mind].ll :
+ (vt == VT_ULLONG ? hist_data->gprof_item->value[mind].ull :
+ hist_data->gprof_item->value[mind].i)) / prec;
+ }
+ else if (xlate[mind] != -1)
+ {
+ TValue& total = hist_data->total->value[mind];
+ ASN_METRIC_VAL (total, slots[xlate[mind]], root_idx);
+ double val = (vt == VT_LLONG ? total.ll :
+ (vt == VT_ULLONG ? total.ll : total.i));
+ total.d = val / prec;
+ }
+ break;
+ }
+ }
+ delete[] xlate;
+
+ // Determine by which metric to sort if any
+ bool rev_sort = mlist->get_sort_rev ();
+ for (long mind = 0, sz = mlist->get_items ()->size (); mind < sz; mind++)
+ {
+ Metric *mtr = mlist->get_items ()->get (mind);
+ if (mlist->get_sort_ref_index () == mind)
+ sort_ind = mind;
+
+ switch (mtr->get_type ())
+ {
+ case BaseMetric::SIZES:
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ Histable *h = mtr->get_comparable_obj (hi->obj);
+ hi->value[mind].tag = VT_LLONG;
+ hi->value[mind].ll = h ? h->get_size () : 0;
+ }
+ break;
+ case BaseMetric::ADDRESS:
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ Histable *h = mtr->get_comparable_obj (hi->obj);
+ hi->value[mind].tag = VT_ADDRESS;
+ hi->value[mind].ll = h ? h->get_addr () : 0;
+ }
+ break;
+ case BaseMetric::DERIVED:
+ {
+ Definition *def = mtr->get_definition ();
+ long *map = def->get_map ();
+ for (long i1 = 0, sz1 = hist_data->hist_items->size (); i1 < sz1; i1++)
+ {
+ /* Hist_data::HistItem * */hi = hist_data->hist_items->get (i1);
+ hi->value[mind].tag = VT_DOUBLE;
+ hi->value[mind].d = def->eval (map, hi->value);
+ }
+ hist_data->total->value[mind].tag = VT_DOUBLE;
+ hist_data->total->value[mind].d = def->eval (map, hist_data->total->value);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ hist_data->sort (sort_ind, rev_sort);
+ hist_data->compute_minmax ();
+ if (dbeSession->is_interactive () && mode != Hist_data::CALLERS)
+ theApplication->set_progress (0, GTXT (""));
+
+#if DEBUG_FTREE
+ if (ftree_hist_data)
+ {
+ bool matches = ftree_debug_match_hist_data (hist_data, ftree_hist_data);
+ if (!matches)
+ assert (false);
+ delete hist_data;
+ hist_data = ftree_hist_data; // return the debug version
+ }
+#endif
+ return hist_data;
+}
+
+#if DEBUG_FTREE
+bool
+PathTree::ftree_debug_match_hist_data (Hist_data *data /* ref */,
+ Hist_data *data_tmp)
+{
+ if (data->get_status () != Hist_data::SUCCESS)
+ {
+ DBG (assert (false));
+ return false;
+ }
+ if (data == NULL && data != data_tmp)
+ {
+ DBG (assert (false));
+ return false;
+ }
+
+ MetricList *mlist;
+ mlist = data->get_metric_list ();
+ MetricList *mlist_tmp;
+ mlist_tmp = data_tmp->get_metric_list ();
+ if (mlist->size () != mlist_tmp->size ())
+ {
+ DBG (assert (false));
+ return false;
+ }
+
+ // Get table size: count visible metrics
+ int nitems = data->size ();
+ if (data->size () != data_tmp->size ())
+ {
+ DBG (assert (false));
+ return false;
+ }
+
+ for (int i = 0; i < nitems; ++i)
+ {
+ Hist_data::HistItem *item = data->fetch (i);
+ Hist_data::HistItem *item_tmp = data_tmp->fetch (i);
+ if (item->obj->id != item_tmp->obj->id)
+ {
+ DBG (assert (false));
+ return false;
+ }
+ }
+
+ for (long i = 0, sz = mlist->size (); i < sz; i++)
+ {
+ long met_ind = i;
+ Metric *mitem = mlist->get (i);
+ Metric *mitem_tmp = mlist_tmp->get (i);
+
+ if (mitem->get_id () != mitem_tmp->get_id ())
+ {
+ DBG (assert (false));
+ return false;
+ }
+ if (mitem->get_visbits () != mitem_tmp->get_visbits ())
+ {
+ DBG (assert (false));
+ return false;
+ }
+ if (mitem->get_vtype () != mitem_tmp->get_vtype ())
+ {
+ DBG (assert (false));
+ return false;
+ }
+
+ if (!mitem->is_visible () && !mitem->is_tvisible ()
+ && !mitem->is_pvisible ())
+ continue;
+ // table->append(dbeGetTableDataOneColumn(data, i));
+ for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+ {
+ Metric *m = mitem;
+ TValue res;
+ TValue res_tmp;
+ TValue *v = data->get_value (&res, met_ind, row);
+ TValue *v_tmp = data_tmp->get_value (&res_tmp, met_ind, row);
+ if ((m->get_visbits () & VAL_RATIO) != 0)
+ {
+ if (v->tag != VT_LABEL)
+ {
+ if (v->to_double () != v_tmp->to_double ())
+ {
+ DBG (assert (false));
+ return false;
+ }
+ }
+ continue;
+ }
+ switch (m->get_vtype ())
+ {
+ case VT_DOUBLE:
+ {
+ double diff = v->d - v_tmp->d;
+ if (diff < 0) diff = -diff;
+ if (diff > 0.0001)
+ {
+ DBG (assert (false));
+ return false;
+ }
+ else
+ DBG (assert (true));
+ break;
+ }
+ case VT_INT:
+ if (v->i != v_tmp->i)
+ {
+ DBG (assert (false));
+ return false;
+ }
+ break;
+ case VT_ULLONG:
+ case VT_LLONG:
+ case VT_ADDRESS:
+ if (v->ll != v_tmp->ll)
+ {
+ DBG (assert (false));
+ return false;
+ }
+ break;
+
+ case VT_LABEL:
+ if (dbe_strcmp (v->l, v_tmp->l))
+ {
+ DBG (assert (false));
+ return false;
+ }
+ break;
+ default:
+ DBG (assert (false));
+ return false;
+ }
+ }
+ }
+ return true;
+}
+#endif
+
+Histable *
+PathTree::get_hist_func_obj (Node *node)
+{
+ LoadObject *lo;
+ Function *func;
+ func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+ // LIBRARY VISIBILITY
+ lo = func->module->loadobject;
+ if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+ return lo->get_hide_function ();
+ return get_compare_obj (func);
+}
+
+Histable *
+PathTree::get_hist_obj (Node *node, Histable* context)
+{
+ LoadObject *lo;
+ Function *func;
+ switch (hist_data->type)
+ {
+ case Histable::INSTR:
+ if (hist_data->mode == Hist_data::MODL)
+ {
+ if (node->instr->get_type () != Histable::INSTR)
+ return NULL;
+ }
+ else
+ {
+ // LIBRARY VISIBILITY
+ func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+ lo = func->module->loadobject;
+ if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+ return lo->get_hide_function ();
+ }
+ return node->instr;
+
+ case Histable::LINE:
+ if (hist_data->mode != Hist_data::MODL)
+ {
+ func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+ lo = func->module->loadobject;
+ // LIBRARY VISIBILITY
+ if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+ return lo->get_hide_function ();
+ }
+ // For openmp user mode - the stack is already made with dbelines,
+ // no need to convert it
+ if (node->instr->get_type () == Histable::LINE)
+ return node->instr;
+ return node->instr->convertto (Histable::LINE, context);
+
+ case Histable::FUNCTION:
+ if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE && node->ancestor != 0)
+ func = (Function*) node->instr;
+ else
+ func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+ lo = func->module->loadobject;
+ // LIBRARY VISIBILITY
+ if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+ return lo->get_hide_function ();
+ return get_compare_obj (func);
+ case Histable::MODULE:
+ func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+ return func->module;
+ case Histable::LOADOBJECT:
+ func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+ return func->module->loadobject;
+ case Histable::INDEXOBJ:
+ case Histable::MEMOBJ:
+ return node->instr;
+ default:
+ DBG (assert (0));
+ }
+ return NULL;
+}
+
+Histable *
+PathTree::get_compare_obj (Histable *obj)
+{
+ if (obj && dbev->comparingExperiments ())
+ obj = dbev->get_compare_obj (obj);
+ return obj;
+}
+
+void
+PathTree::get_metrics (NodeIdx node_idx, int dpth)
+{
+ Node *node = NODE_IDX (node_idx);
+ Histable *cur_obj = get_hist_obj (node);
+ obj_list[dpth] = cur_obj;
+
+ // Check for recursion (inclusive metrics)
+ int incl_ok = 1;
+ for (int i = dpth - 1; i >= 0; i--)
+ if (cur_obj == obj_list[i])
+ {
+ incl_ok = 0;
+ break;
+ }
+
+ // Check for leaf nodes (exclusive metrics)
+ int excl_ok = 0;
+ if (IS_LEAF (node) || node == NODE_IDX (root_idx))
+ excl_ok = 1;
+
+ // We shouldn't eliminate empty subtrees here because
+ // we create the list of hist items dynamically and want
+ // one for each object in the tree.
+ cur_obj = get_compare_obj (cur_obj);
+ Hist_data::HistItem *hi = hist_data->append_hist_item (cur_obj);
+ DBG (assert (hi != NULL));
+
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+
+ switch (subtype)
+ {
+ case Metric::INCLUSIVE:
+ if (incl_ok && hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ case Metric::EXCLUSIVE:
+ if (excl_ok && hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ // ignoring the following cases (why?)
+ case Metric::STATIC:
+ case Metric::ATTRIBUTED:
+ break;
+ case Metric::DATASPACE:
+ if (hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ }
+ }
+
+ if (dbeSession->is_interactive ())
+ {
+ ndone++;
+ int new_percent = 95 * ndone / nodes;
+ if (new_percent > percent)
+ {
+ percent = new_percent;
+ theApplication->set_progress (percent, NULL);
+ }
+ }
+
+ // Recursively process all descendants
+ int index;
+ int dsize = NUM_DESCENDANTS (node);
+ for (index = 0; index < dsize; index++)
+ get_metrics (node->descendants->fetch (index), dpth + 1);
+}
+
+void
+PathTree::get_clr_metrics (Vector<Histable*> *objs, NodeIdx node_idx,
+ int pmatch, int dpth)
+{
+ Node *node = NODE_IDX (node_idx);
+ Histable *cur_obj;
+ if (hist_data->type == Histable::LINE || hist_data->type == Histable::INSTR)
+ {
+ cur_obj = get_hist_func_obj (node);
+ node_list[dpth] = node;
+ }
+ else
+ cur_obj = get_hist_obj (node);
+ obj_list[dpth] = cur_obj;
+
+ bool match = false;
+ int nobj = objs->size ();
+ if (dpth + 1 >= nobj)
+ {
+ match = true;
+ for (int i = 0; i < nobj; ++i)
+ {
+ if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i])
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+
+ Hist_data::HistItem *hi = NULL;
+ Hist_data::HistItem *hi_adj = NULL;
+ if (match && dpth >= nobj)
+ {
+ if (hist_data->type == Histable::LINE
+ || hist_data->type == Histable::INSTR)
+ hi = hist_data->append_hist_item (get_hist_obj (node_list[dpth - nobj]));
+ else
+ hi = hist_data->append_hist_item (obj_list[dpth - nobj]);
+
+ if (pmatch >= 0 && pmatch >= nobj)
+ {
+ if (hist_data->type == Histable::LINE
+ || hist_data->type == Histable::INSTR)
+ hi_adj = hist_data->append_hist_item (get_hist_obj (
+ node_list[pmatch - nobj]));
+ else
+ hi_adj = hist_data->append_hist_item (obj_list[pmatch - nobj]);
+ }
+ }
+
+ if (hi != NULL)
+ {
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+
+ switch (subtype)
+ {
+ case Metric::ATTRIBUTED:
+ if (hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ if (hi_adj)
+ SUB_METRIC_VAL (hi_adj->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ case Metric::STATIC:
+ case Metric::EXCLUSIVE:
+ case Metric::INCLUSIVE:
+ case Metric::DATASPACE:
+ break;
+ }
+ }
+ }
+
+ // Recursively process all descendants
+ int dsize = NUM_DESCENDANTS (node);
+ for (int index = 0; index < dsize; index++)
+ get_clr_metrics (objs, node->descendants->fetch (index),
+ match ? dpth : pmatch, dpth + 1);
+}
+
+void
+PathTree::get_clr_metrics (Vector<Histable*> *objs)
+{
+ get_clr_metrics (objs, root_idx, -1, 0);
+}
+
+void
+PathTree::get_cle_metrics (Vector<Histable*> *objs, NodeIdx node_idx, int pcle,
+ int pmatch, int dpth)
+{
+ Node *node = NODE_IDX (node_idx);
+ Histable *cur_obj = get_hist_obj (node);
+ obj_list[dpth] = cur_obj;
+
+ bool match = false;
+ int nobj = objs->size ();
+ if (dpth + 1 >= nobj)
+ {
+ match = true;
+ for (int i = 0; i < nobj; ++i)
+ if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i])
+ {
+ match = false;
+ break;
+ }
+ }
+
+ Hist_data::HistItem *hi = NULL;
+ Hist_data::HistItem *hi_adj = NULL;
+ if (pmatch >= 0 && dpth == pmatch + 1)
+ hi = hist_data->append_hist_item (cur_obj);
+ if (match && IS_LEAF (node))
+ hi = hist_data->gprof_item;
+ if (pcle >= 0)
+ hi_adj = hist_data->append_hist_item (obj_list[pcle]);
+
+ if (hi != NULL)
+ {
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ if (subtype == Metric::ATTRIBUTED)
+ {
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ if (hi_adj)
+ SUB_METRIC_VAL (hi_adj->value[ind], slots[xlate[ind]], node_idx);
+ }
+ }
+ }
+
+ // Recursively process all descendants
+ int dsize = NUM_DESCENDANTS (node);
+ for (int index = 0; index < dsize; index++)
+ get_cle_metrics (objs, node->descendants->fetch (index),
+ pmatch >= 0 && dpth == pmatch + 1 ? dpth : pcle,
+ match ? dpth : pmatch, dpth + 1);
+}
+
+void
+PathTree::get_cle_metrics (Vector<Histable*> *objs, NodeIdx node_idx, int dpth)
+{
+ Node *node = NODE_IDX (node_idx);
+ Histable *cur_obj = get_hist_obj (node);
+ Hist_data::HistItem *hi = NULL;
+ if (NULL == objs) // Special case: get root
+ hi = hist_data->append_hist_item (cur_obj);
+ else
+ {
+ if (dpth == objs->size ())
+ hi = hist_data->append_hist_item (cur_obj);
+ else if (cur_obj == objs->fetch (dpth))
+ {
+ // Recursively process all descendants
+ int dsize = NUM_DESCENDANTS (node);
+ for (int index = 0; index < dsize; index++)
+ get_cle_metrics (objs, node->descendants->fetch (index), dpth + 1);
+ if (dpth == objs->size () - 1 && dsize == 0)
+ hi = hist_data->gprof_item;
+ }
+ }
+
+ if (hi != NULL)
+ {
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ if (subtype == Metric::ATTRIBUTED)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ }
+ }
+}
+
+void
+PathTree::ftree_reset ()
+{
+ if (pathTreeType == PATHTREE_MAIN && indxtype < 0)
+ {
+ reset ();
+ if (ftree_needs_update)
+ {
+ if (ftree_internal == NULL)
+ {
+ ftree_internal = new PathTree (dbev, indxtype,
+ PATHTREE_INTERNAL_FUNCTREE);
+ if (ftree_internal == NULL)
+ return;
+ }
+ ftree_internal->ftree_build (this);
+ ftree_needs_update = false;
+ }
+ }
+}
+
+void
+PathTree::ftree_build (PathTree * mstr)
+{
+ fini ();
+ init ();
+ allocate_slots (mstr->slots, mstr->nslots);
+ ftree_build (mstr, mstr->root_idx, root_idx);
+ depth = mstr->depth;
+ depth_map_build ();
+}
+
+#if DEBUG_FTREE // possibly TBR
+void
+PathTree::ftree_dump ()
+{
+ hrtime_t starttime, endtime;
+ int nmetrics = 1;
+ // int nmetrics = nslots;
+ for (int kk = 0; kk < nmetrics; kk++)
+ {
+ int id = slots[kk].id;
+ starttime = gethrtime ();
+ long nodecnt = 0;
+ for (int ii = 0; ii < depth; ii++)
+ {
+ Vector<Vector<void*>*> *tmp = (Vector<Vector<void*>*>*)get_ftree_level
+ (id, ii);
+ if (tmp == NULL)
+ continue;
+ long sz = tmp->get (0)->size ();
+ nodecnt += sz;
+#if 1
+ // fprintf(stderr, "... finished (%ld nodes)\n", sz);
+#else
+ Vector<NodeIdx> *nodeIdxList = (Vector<NodeIdx> *)tmp->get (0);
+ Vector<NodeIdx> *ancestorNodeIdxList = (Vector<NodeIdx> *)tmp->get (1);
+ Vector<uint64_t> *idList = (Vector<uint64_t> *)tmp->get (2);
+ Vector<uint64_t> *vals = (Vector<uint64_t> *)tmp->get (3);
+ for (int jj = 0; jj < sz; jj++)
+ fprintf (stderr, " ...%d:%d node=%ld, anc=%ld, id=%llu, val=%llu\n",
+ sz, jj, nodeIdxList->get (jj),
+ ancestorNodeIdxList->get (jj),
+ idList->get (jj), vals->get (jj));
+#endif
+ destroy (tmp);
+ }
+ endtime = gethrtime ();
+ fprintf (stderr, "====================== %ld nodes time=%llu\n",
+ nodecnt, (endtime - starttime) / 1000 / 1000);
+ }
+}
+#endif
+
+// ftree: translate mstr Histable::INSTR to Histable::FUNCTION
+void
+PathTree::ftree_build (PathTree *mstr, NodeIdx mstr_node_idx,
+ NodeIdx local_node_idx)
+{
+ // requires: slots, nslots
+ Node *mstr_node = mstr->NODE_IDX (mstr_node_idx);
+ int dsize = NUM_DESCENDANTS (mstr_node);
+
+ // Add metrics
+ for (int i = 0; i < nslots; i++)
+ {
+ if (i >= mstr->nslots)
+ continue; //weird
+ if (slots[i].vtype != mstr->slots[i].vtype)
+ continue; //weird
+ TValue val;
+ val.ll = 0;
+ mstr->ASN_METRIC_VAL (val, mstr->slots[i], mstr_node_idx);
+ int64_t mval;
+ switch (slots[i].vtype)
+ {
+ case VT_ULLONG:
+ case VT_LLONG:
+ mval = val.ll;
+ break;
+ case VT_INT:
+ mval = val.i;
+ break;
+ default:
+ mval = 0;
+ break;
+ }
+ if (mval)
+ {
+ Slot * mslot = SLOT_IDX (i);
+ if (mslot)
+ INCREMENT_METRIC (mslot, local_node_idx, mval);
+ }
+ }
+
+ // Recursively process all descendants
+ for (int index = 0; index < dsize; index++)
+ {
+ NodeIdx mstr_desc_node_idx = mstr_node->descendants->fetch (index);
+ Node *mstr_desc_node = mstr->NODE_IDX (mstr_desc_node_idx);
+ Function *func = (Function*) mstr_desc_node->instr->convertto (Histable::FUNCTION);
+ int mstr_desc_dsize = NUM_DESCENDANTS (mstr_desc_node);
+ bool leaf = (mstr_desc_dsize == 0);
+ NodeIdx local_desc_node_idx = find_desc_node (local_node_idx, func, leaf);
+ ftree_build (mstr, mstr_desc_node_idx, local_desc_node_idx);
+ }
+}
+
+void
+PathTree::depth_map_build ()
+{
+ destroy (depth_map);
+ depth_map = new Vector<Vector<NodeIdx>*>(depth);
+ if (depth)
+ {
+ depth_map->put (depth - 1, 0); // fill vector with nulls
+ depth_map_build (root_idx, 0);
+ }
+}
+
+void
+PathTree::depth_map_build (NodeIdx node_idx, int dpth)
+{
+ Node *node = NODE_IDX (node_idx);
+
+ Vector<NodeIdx> *node_idxs = depth_map->get (dpth);
+ if (node_idxs == NULL)
+ {
+ node_idxs = new Vector<NodeIdx>();
+ depth_map->store (dpth, node_idxs);
+ }
+ node_idxs->append (node_idx);
+
+ // Recursively process all descendants
+ int dsize = NUM_DESCENDANTS (node);
+ for (int index = 0; index < dsize; index++)
+ {
+ NodeIdx desc_node_idx = node->descendants->fetch (index);
+ depth_map_build (desc_node_idx, dpth + 1);
+ }
+}
+
+int
+PathTree::get_ftree_depth ()
+{ // external use only
+ ftree_reset ();
+ if (!ftree_internal)
+ return 0;
+ return ftree_internal->get_depth ();
+}
+
+Vector<Function*>*
+PathTree::get_ftree_funcs ()
+{ // external use only
+ ftree_reset ();
+ if (!ftree_internal)
+ return NULL;
+ return ftree_internal->get_funcs ();
+}
+
+Vector<Function*>*
+PathTree::get_funcs ()
+{
+ // get unique functions
+ if (fn_map == NULL)
+ return NULL;
+ return fn_map->keySet ();
+}
+
+Vector<void*>*
+PathTree::get_ftree_level (BaseMetric *bm, int dpth)
+{ // external use only
+ ftree_reset ();
+ if (!ftree_internal)
+ return NULL;
+ return ftree_internal->get_level (bm, dpth);
+}
+
+Vector<void*>*
+PathTree::get_level (BaseMetric *bm, int dpth)
+{
+ // Nodes at tree depth dpth
+ if (dpth < 0 || dpth >= depth)
+ return NULL;
+ if (depth_map == NULL)
+ return NULL;
+ Vector<NodeIdx> *node_idxs = depth_map->get (dpth);
+ return get_nodes (bm, node_idxs);
+}
+
+Vector<void*>*
+PathTree::get_ftree_node_children (BaseMetric *bm, NodeIdx node_idx)
+{ // external use only
+ ftree_reset ();
+ if (!ftree_internal)
+ return NULL;
+ return ftree_internal->get_node_children (bm, node_idx);
+}
+
+Vector<void*>*
+PathTree::get_node_children (BaseMetric *bm, NodeIdx node_idx)
+{
+ // Nodes that are children of node_idx
+ if (depth_map == NULL)
+ return NULL;
+ if (node_idx == 0) // special case for root
+ return get_nodes (bm, depth_map->get (0));
+ if (node_idx < 0 || node_idx >= nodes)
+ return NULL;
+ Node *node = NODE_IDX (node_idx);
+ if (node == NULL)
+ return NULL;
+ Vector<NodeIdx> *node_idxs = node->descendants;
+ return get_nodes (bm, node_idxs);
+}
+
+Vector<void*>*
+PathTree::get_nodes (BaseMetric *bm, Vector<NodeIdx> *node_idxs)
+{ // used for ftree
+ // capture info for node_idxs:
+ // node's idx
+ // node->ancestor idx
+ // node->instr->id
+ // mind metric value // in the future, could instead accept vector of mind
+ if (node_idxs == NULL)
+ return NULL;
+ long sz = node_idxs->size ();
+ if (sz <= 0)
+ return NULL;
+
+ bool calculate_metric = false;
+ ValueTag vtype;
+ int slot_idx;
+ double prec;
+ if (bm != NULL)
+ {
+ int mind = bm->get_id ();
+ slot_idx = find_slot (mind); // may be -1 (CPI and IPC)
+ prec = bm->get_precision ();
+ vtype = bm->get_vtype ();
+ }
+ else
+ {
+ slot_idx = -1;
+ prec = 1.0;
+ vtype = VT_INT;
+ }
+
+ if (slot_idx >= 0)
+ {
+ switch (vtype)
+ {
+ case VT_ULLONG:
+ case VT_LLONG:
+ case VT_INT:
+ if (slots[slot_idx].vtype == vtype)
+ calculate_metric = true;
+ else
+ DBG (assert (false));
+ break;
+ case VT_DOUBLE:
+ calculate_metric = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ Vector<void*> *results = new Vector<void*>(4);
+ if (!calculate_metric)
+ results->store (3, NULL);
+ else
+ {
+ // Code below cribbed from Dbe.cc:dbeGetTableDataV2Data.
+ // TBD: possibly create an intermediate HistData and instead call that routine
+ switch (vtype)
+ {
+ case VT_ULLONG:
+ case VT_LLONG:
+ {
+ Vector<long long> *vals = new Vector<long long>(sz);
+ for (long i = 0; i < sz; i++)
+ {
+ NodeIdx node_idx = node_idxs->get (i);
+ TValue val;
+ val.ll = 0;
+ ASN_METRIC_VAL (val, slots[slot_idx], node_idx);
+ vals->append (val.ll);
+ }
+ results->store (3, vals);
+ break;
+ }
+ case VT_DOUBLE:
+ {
+ Vector<double> *vals = new Vector<double>(sz);
+ TValue val;
+ val.tag = slots[slot_idx].vtype; // required for to_double();
+ for (long i = 0; i < sz; i++)
+ {
+ NodeIdx node_idx = node_idxs->get (i);
+ val.ll = 0;
+ ASN_METRIC_VAL (val, slots[slot_idx], node_idx);
+ double dval = val.to_double ();
+ dval /= prec;
+ vals->append (dval);
+ }
+ results->store (3, vals);
+ break;
+ }
+ case VT_INT:
+ {
+ Vector<int> *vals = new Vector<int>(sz);
+ for (long i = 0; i < sz; i++)
+ {
+ NodeIdx node_idx = node_idxs->get (i);
+ TValue val;
+ val.i = 0;
+ ASN_METRIC_VAL (val, slots[slot_idx], node_idx);
+ vals->append (val.i);
+ }
+ results->store (3, vals);
+ break;
+ }
+ default:
+ results->store (3, NULL);
+ break;
+ }
+ }
+
+ Vector<int> *nodeIdxList = new Vector<int>(sz);
+ Vector<int> *ancestorNodeIdxList = new Vector<int>(sz);
+ Vector<uint64_t> *idList = new Vector<uint64_t>(sz);
+ for (long i = 0; i < sz; i++)
+ {
+ NodeIdx node_idx = node_idxs->get (i);
+ Node *node = NODE_IDX (node_idx);
+ NodeIdx ancestor_idx = node->ancestor;
+ Histable *func = node->instr;
+ nodeIdxList->append (node_idx);
+ ancestorNodeIdxList->append (ancestor_idx);
+ idList->append (func->id);
+ }
+
+ results->store (0, nodeIdxList);
+ results->store (1, ancestorNodeIdxList);
+ results->store (2, idList);
+ return results;
+}
+
+void
+PathTree::get_cle_metrics (Vector<Histable*> *objs)
+{
+ if (NULL == objs || objs->fetch (0) == get_hist_obj (NODE_IDX (root_idx)))
+ // Call Tree optimization
+ get_cle_metrics (objs, root_idx, 0);
+ else
+ // General case
+ get_cle_metrics (objs, root_idx, -1, -1, 0);
+}
+
+void
+PathTree::get_metrics (Vector<Function*> *functions, Histable *context)
+{
+ Function *fitem;
+ int excl_ok, incl_ok;
+ NodeIdx node_idx;
+ Node *node, *anc;
+ int index;
+
+ Vec_loop (Function*, functions, index, fitem)
+ {
+ node_idx = fn_map->get (fitem);
+ for (; node_idx; node_idx = node->funclist)
+ {
+ node = NODE_IDX (node_idx);
+ Histable *h_obj = get_hist_obj (node, context);
+ if (h_obj == NULL)
+ continue;
+
+ // Check for recursion (inclusive metrics)
+ incl_ok = 1;
+ for (anc = NODE_IDX (node->ancestor); anc;
+ anc = NODE_IDX (anc->ancestor))
+ {
+ if (h_obj == get_hist_obj (anc, context))
+ {
+ incl_ok = 0;
+ break;
+ }
+ }
+
+ // Check for leaf nodes (exclusive metrics)
+ excl_ok = 0;
+ if (IS_LEAF (node))
+ excl_ok = 1;
+
+ h_obj = get_compare_obj (h_obj);
+ Hist_data::HistItem *hi = hist_data->append_hist_item (h_obj);
+
+ if (!excl_ok)
+ hist_data->get_callsite_mark ()->put (h_obj, 1);
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ if (subtype == Metric::INCLUSIVE && !incl_ok)
+ continue;
+ if (subtype == Metric::EXCLUSIVE && !excl_ok)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ }
+ }
+ }
+}
+
+void
+PathTree::get_self_metrics (Vector<Histable*> *objs, NodeIdx node_idx,
+ bool seen, int dpth)
+{
+ Node *node = NODE_IDX (node_idx);
+ Histable *cur_obj = get_hist_obj (node);
+ obj_list[dpth] = cur_obj;
+
+ bool match = false;
+ int nobj = objs->size ();
+ if (dpth + 1 >= nobj)
+ {
+ match = true;
+ for (int i = 0; i < nobj; ++i)
+ {
+ if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i])
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+
+ if (match)
+ {
+ Hist_data::HistItem *hi = hist_data->append_hist_item (cur_obj);
+ int incl_ok = !seen;
+ int excl_ok = 0;
+ if (IS_LEAF (node) || node == NODE_IDX (root_idx))
+ excl_ok = 1;
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ switch (subtype)
+ {
+ case Metric::INCLUSIVE:
+ if (incl_ok && hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ case Metric::EXCLUSIVE:
+ case Metric::ATTRIBUTED:
+ if (excl_ok && hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ case Metric::DATASPACE:
+ if (hi)
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ break;
+ // ignoring the following cases (why?)
+ case Metric::STATIC:
+ break;
+ }
+ }
+ }
+
+ if (dbeSession->is_interactive ())
+ {
+ ndone++;
+ int new_percent = 95 * ndone / nodes;
+ if (new_percent > percent)
+ {
+ percent = new_percent;
+ theApplication->set_progress (percent, NULL);
+ }
+ }
+
+ // Recursively process all descendants
+ int index;
+ int dsize = NUM_DESCENDANTS (node);
+ for (index = 0; index < dsize; index++)
+ get_self_metrics (objs, node->descendants->fetch (index),
+ seen || match, dpth + 1);
+}
+
+void
+PathTree::get_self_metrics (Vector<Histable*> *objs)
+{
+ get_self_metrics (objs, root_idx, false, 0);
+}
+
+void
+PathTree::get_self_metrics (Histable *obj, Vector<Function*> *funclist,
+ Vector<Histable*>* sel_objs)
+{
+ int excl_ok, incl_ok;
+ NodeIdx node_idx;
+ Node *node, *anc;
+
+ if (obj == NULL)
+ return;
+
+ SourceFile *src = NULL;
+ if (obj && obj->get_type () == Histable::LINE)
+ {
+ DbeLine *dbeline = (DbeLine*) obj;
+ src = dbeline->sourceFile;
+ }
+
+ Hist_data::HistItem *hi = hist_data->append_hist_item (obj);
+ for (int i = 0, sz = funclist ? funclist->size () : 0; i < sz; i++)
+ {
+ Function *fitem = (Function*) get_compare_obj (funclist->fetch (i));
+ node_idx = fn_map->get (fitem);
+ for (; node_idx; node_idx = node->funclist)
+ {
+ node = NODE_IDX (node_idx);
+ if (obj && obj->get_type () == Histable::LINE)
+ {
+ Histable *h = get_hist_obj (node, src);
+ if (h == NULL)
+ continue;
+ if (h->convertto (Histable::LINE) != obj->convertto (Histable::LINE))
+ continue;
+ }
+ else if (get_hist_obj (node, src) != obj)
+ continue;
+
+ // Check for recursion (inclusive metrics)
+ incl_ok = 1;
+ for (anc = NODE_IDX (node->ancestor); anc;
+ anc = NODE_IDX (anc->ancestor))
+ {
+ if (get_hist_obj (anc, src) == obj)
+ {
+ incl_ok = 0;
+ break;
+ }
+ if (sel_objs != NULL)
+ for (int k = 0; k < sel_objs->size (); k++)
+ if (sel_objs->fetch (k) == get_hist_obj (anc, src))
+ {
+ incl_ok = 0;
+ break;
+ }
+ }
+
+ // Check for leaf nodes (exclusive metrics)
+ excl_ok = 0;
+ if (IS_LEAF (node) || node == NODE_IDX (root_idx))
+ excl_ok = 1;
+
+ MetricList *mlist = hist_data->get_metric_list ();
+ for (long ind = 0, ind_sz = mlist->size (); ind < ind_sz; ind++)
+ {
+ if (xlate[ind] == -1)
+ continue;
+ Metric *mtr = mlist->get (ind);
+ Metric::SubType subtype = mtr->get_subtype ();
+ if (subtype == Metric::INCLUSIVE && !incl_ok)
+ continue;
+ if (subtype == Metric::EXCLUSIVE && !excl_ok)
+ continue;
+ if (subtype == Metric::ATTRIBUTED && !excl_ok)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+ continue;
+ ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+ }
+ }
+ }
+}
+
+Vector<Histable*> *
+PathTree::get_clr_instr (Histable * func)
+{
+ Vector<Histable*> * instrs = NULL;
+ if (func->get_type () != Histable::FUNCTION)
+ return NULL;
+ NodeIdx node_idx = fn_map->get ((Function*) func);
+ Node *node = NODE_IDX (node_idx);
+ if (node == NULL)
+ return new Vector<Histable*>();
+ int instr_num = 0;
+ for (; node; node = NODE_IDX (node->funclist))
+ instr_num++;
+ instrs = new Vector<Histable*>(instr_num);
+ node = NODE_IDX (node_idx);
+ Histable *instr = NODE_IDX (node->ancestor)->instr;
+ instr_num = 0;
+ instrs->store (instr_num, instr);
+ node = NODE_IDX (node->funclist);
+ for (; node; node = NODE_IDX (node->funclist))
+ {
+ instr = NODE_IDX (node->ancestor)->instr;
+ instr_num++;
+ instrs->store (instr_num, instr);
+ }
+ return instrs;
+}
+
+Vector<void*> *
+PathTree::get_cle_instr (Histable * func, Vector<Histable*>*&instrs)
+{
+ if (func->get_type () != Histable::FUNCTION)
+ return NULL;
+ NodeIdx node_idx = fn_map->get ((Function*) func);
+ Node *node = NODE_IDX (node_idx);
+ if (node == NULL)
+ {
+ instrs = new Vector<Histable*>();
+ return new Vector<void*>();
+ }
+ int instr_num = 0;
+ for (; node; node = NODE_IDX (node->funclist))
+ instr_num++;
+ instrs = new Vector<Histable*>(instr_num);
+ Vector<void*> *callee_info = new Vector<void*>(instr_num);
+ node = NODE_IDX (node_idx);
+ Histable *instr = node->instr;
+ instr_num = 0;
+ instrs->store (instr_num, instr);
+ int dec_num = 0;
+ NodeIdx dec_idx = 0;
+ if (NUM_DESCENDANTS (node) > 0)
+ {
+ Vector<Histable*> * callee_instrs = new Vector<Histable*>(node->descendants->size ());
+ Vec_loop (NodeIdx, node->descendants, dec_num, dec_idx)
+ {
+ Node * dec_node = NODE_IDX (dec_idx);
+ //XXXX Note: there can be more than one instrs in one leaf function
+ callee_instrs->store (dec_num, dec_node->instr);
+ }
+ callee_info->store (instr_num, callee_instrs);
+ }
+ else
+ callee_info->store (instr_num, NULL);
+ node = NODE_IDX (node->funclist);
+ for (; node; node = NODE_IDX (node->funclist))
+ {
+ instr = node->instr;
+ instr_num++;
+ instrs->store (instr_num, instr);
+ if (NUM_DESCENDANTS (node) > 0)
+ {
+ Vector<Histable*> * callee_instrs = new Vector<Histable*>(node->descendants->size ());
+ Vec_loop (NodeIdx, node->descendants, dec_num, dec_idx)
+ {
+ Node * dec_node = NODE_IDX (dec_idx);
+ //XXXX Note: there can be more than one instrs in one leaf function
+ callee_instrs->store (dec_num, dec_node->instr);
+ }
+ callee_info->store (instr_num, callee_instrs);
+ }
+ else
+ callee_info->store (instr_num, NULL);
+ }
+ return callee_info;
+}
+
+//
+//
+// The following methods are used for debugging purpose only.
+//
+//
+static int maxdepth;
+static int maxwidth;
+
+void
+PathTree::print (FILE *fd)
+{
+ (void) reset ();
+ fprintf (fd, NTXT ("n = %lld, dn = %lld, MD = %lld\n\n"),
+ (long long) nodes, (long long) dnodes, (long long) depth);
+ maxdepth = 0;
+ maxwidth = 0;
+ print (fd, root, 0);
+ fprintf (fd, NTXT ("md = %lld, mw = %lld\n"),
+ (long long) maxdepth, (long long) maxwidth);
+}
+
+void
+PathTree::print (FILE *fd, PathTree::Node *node, int lvl)
+{
+ const char *t;
+ char *n;
+ if (lvl + 1 > maxdepth)
+ maxdepth = lvl + 1;
+ for (int i = 0; i < lvl; i++)
+ fprintf (fd, NTXT ("-"));
+ Histable *instr = node->instr;
+ if (instr->get_type () == Histable::LINE)
+ {
+ t = "L";
+ n = ((DbeLine *) instr)->func->get_name ();
+ }
+ else if (instr->get_type () == Histable::INSTR)
+ {
+ t = "I";
+ n = ((DbeInstr *) instr)->func->get_name ();
+ }
+ else
+ {
+ t = "O";
+ n = instr->get_name ();
+ }
+ long long addr = (long long) instr->get_addr ();
+ fprintf (fd, NTXT ("%s %s (0x%08llx) -- ndesc = %lld\n"),
+ t, n, addr, (long long) (NUM_DESCENDANTS (node)));
+
+ // Recursively process all descendants
+ int dsize = NUM_DESCENDANTS (node);
+ if (dsize > maxwidth)
+ maxwidth = dsize;
+ for (int index = 0; index < dsize; index++)
+ print (fd, NODE_IDX (node->descendants->fetch (index)), lvl + 1);
+}
+
+void
+PathTree::printn (FILE *fd)
+{
+ int n = dbg_nodes (root);
+ fprintf (fd, GTXT ("Number of nodes: %d, total size: %d\n"), n, (int) (n * sizeof (Node)));
+}
+
+void
+PathTree::dumpNodes (FILE *fd, Histable *obj)
+{
+ const char *t;
+ char *n;
+ NodeIdx node_idx = fn_map->get ((Function*) obj);
+ Node *node = NODE_IDX (node_idx);
+ if (node == NULL)
+ {
+ fprintf (fd, GTXT ("No nodes associated with %s\n"), obj->get_name ());
+ return;
+ }
+ Histable *instr = node->instr;
+ for (; node; node = NODE_IDX (node->funclist))
+ {
+ instr = node->instr;
+ if (instr->get_type () == Histable::LINE)
+ {
+ t = "L";
+ n = ((DbeLine *) instr)->func->get_name ();
+ }
+ else if (instr->get_type () == Histable::INSTR)
+ {
+ t = "I";
+ n = ((DbeInstr *) instr)->func->get_name ();
+ }
+ else
+ {
+ t = "O";
+ n = instr->get_name ();
+ }
+ long long addr = (long long) instr->get_addr ();
+ if (addr <= 0xFFFFFFFFU)
+ fprintf (fd, NTXT ("0x%08x -- %s %s\n"), (uint32_t) addr, t, n);
+ else
+ fprintf (fd, NTXT ("0x%016llX -- %s %s\n"), addr, t, n);
+ }
+}
+
+int
+PathTree::dbg_nodes (PathTree::Node *node)
+{
+ int res = 1;
+ int dsize = NUM_DESCENDANTS (node);
+ for (int index = 0; index < dsize; index++)
+ res += dbg_nodes (NODE_IDX (node->descendants->fetch (index)));
+ return res;
+}
+
+static int mind_g;
+
+int
+leak_alloc_comp (const void *s1, const void *s2)
+{
+ // See Hist_data::sort_compare() for duplicate code
+ int result = 0;
+ CStack_data::CStack_item *t1, *t2;
+ t1 = *(CStack_data::CStack_item **)s1;
+ t2 = *(CStack_data::CStack_item **)s2;
+
+ switch (t1->value[mind_g].tag)
+ {
+ case VT_INT:
+ if (t1->value[mind_g].i < t2->value[mind_g].i)
+ result = -1;
+ else if (t1->value[mind_g].i > t2->value[mind_g].i)
+ result = 1;
+ else
+ result = 0;
+ break;
+ case VT_LLONG:
+ if (t1->value[mind_g].ll < t2->value[mind_g].ll)
+ result = -1;
+ else if (t1->value[mind_g].ll > t2->value[mind_g].ll)
+ result = 1;
+ else
+ result = 0;
+ break;
+ case VT_ULLONG:
+ if (t1->value[mind_g].ull < t2->value[mind_g].ull)
+ result = -1;
+ else if (t1->value[mind_g].ull > t2->value[mind_g].ull)
+ result = 1;
+ else
+ result = 0;
+ break;
+ // ignoring the following cases (why?)
+ case VT_SHORT:
+ case VT_FLOAT:
+ case VT_DOUBLE:
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_ADDRESS:
+ case VT_OFFSET:
+ break;
+ }
+ // Sort in descending order
+ return -result;
+}
+
+CStack_data *
+PathTree::get_cstack_data (MetricList *mlist)
+{
+ (void) reset ();
+ CStack_data *lam = new CStack_data (mlist);
+ int nmetrics = mlist->get_items ()->size ();
+ mind_g = -1;
+ xlate = new int[nmetrics];
+ for (int mind = 0; mind < nmetrics; mind++)
+ {
+ xlate[mind] = -1;
+ Metric *mtr = mlist->get_items ()->fetch (mind);
+ if (mlist->get_sort_ref_index () == mind)
+ mind_g = mind;
+ xlate[mind] = find_slot (mtr->get_id ());
+ }
+
+ // now fill in the actual data
+ obj_list = new Histable*[depth];
+ get_cstack_list (lam, root_idx, 0);
+ delete[] obj_list;
+
+ if (mind_g >= 0)
+ lam->cstack_items->sort (leak_alloc_comp);
+ delete[] xlate;
+ return lam;
+}
+
+void
+PathTree::get_cstack_list (CStack_data *lam, NodeIdx node_idx, int dpth)
+{
+
+ Node *node = NODE_IDX (node_idx);
+ obj_list[dpth] = node->instr;
+
+ CStack_data::CStack_item *item = NULL;
+ if (IS_LEAF (node))
+ item = lam->new_cstack_item ();
+ int nmetrics = lam->metrics->get_items ()->size ();
+ bool subtree_empty = true;
+
+ for (int mind = 0; mind < nmetrics; mind++)
+ {
+ if (xlate[mind] == -1)
+ continue;
+ if (IS_MVAL_ZERO (slots[xlate[mind]], node_idx))
+ continue;
+ else
+ subtree_empty = false;
+ if (item)
+ {
+ ADD_METRIC_VAL (item->value[mind], slots[xlate[mind]], node_idx);
+ ADD_METRIC_VAL (lam->total->value[mind], slots[xlate[mind]], node_idx);
+ }
+ }
+
+ if (subtree_empty)
+ {
+ delete item;
+ return;
+ }
+
+ if (item)
+ {
+ // Finish processing a leaf node
+ item->stack = new Vector<DbeInstr*>(dpth);
+ for (int i = 1; i <= dpth; i++)
+ item->stack->append ((DbeInstr*) obj_list[i]);
+ lam->cstack_items->append (item);
+ }
+ else
+ {
+ // Recursively process all descendants
+ int dsize = NUM_DESCENDANTS (node);
+ for (int index = 0; index < dsize; index++)
+ get_cstack_list (lam, node->descendants->fetch (index), dpth + 1);
+ }
+}
+
+Emsg *
+PathTree::fetch_stats ()
+{
+ if (statsq == NULL)
+ return NULL;
+ return statsq->fetch ();
+}
+
+void
+PathTree::delete_stats ()
+{
+ if (statsq != NULL)
+ {
+ delete statsq;
+ statsq = new Emsgqueue (NTXT ("statsq"));
+ }
+}
+
+Emsg *
+PathTree::fetch_warnings ()
+{
+ if (warningq == NULL)
+ return NULL;
+ return warningq->fetch ();
+}
+
+void
+PathTree::delete_warnings ()
+{
+ if (warningq != NULL)
+ {
+ delete warningq;
+ warningq = new Emsgqueue (NTXT ("warningq"));
+ }
+}
diff --git a/gprofng/src/PathTree.h b/gprofng/src/PathTree.h
new file mode 100644
index 0000000..dc3ad1f
--- /dev/null
+++ b/gprofng/src/PathTree.h
@@ -0,0 +1,405 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PATH_TREE_H
+#define _PATH_TREE_H
+
+#include <vec.h>
+#include <Map.h>
+
+#include "dbe_structs.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "Metric.h"
+
+typedef enum
+{
+ NORMAL = 0, CANCELED
+} PtreePhaseStatus;
+
+class PathTree
+{
+public:
+
+ PathTree (DbeView *_dbev, int _indxtype = -1)
+ {
+ construct (_dbev, _indxtype, PATHTREE_MAIN);
+ }
+
+ ~PathTree ();
+
+ static void make_deltas (int vtype, TValue *v1, TValue *v2);
+ static void make_ratios (int vtype, TValue *v1, TValue *v2);
+
+ typedef enum
+ {
+ COMPUTEOPT_NONE = 0,
+ COMPUTEOPT_OMP_CALLEE
+ } PtreeComputeOption;
+
+ Hist_data *compute_metrics (MetricList *, Histable::Type,
+ Hist_data::Mode, Vector<Histable*>*,
+ Histable*, Vector<Histable*>* sel_objs = NULL,
+ PtreeComputeOption flag = COMPUTEOPT_NONE);
+ // Get aggregated callstack data
+ CStack_data *get_cstack_data (MetricList *);
+
+ Vector<Histable*> *get_clr_instr (Histable *);
+ Vector<void*> *get_cle_instr (Histable *, Vector<Histable*>*&);
+
+ int
+ get_status ()
+ {
+ return status;
+ }
+
+ int
+ get_depth ()
+ {
+ return depth;
+ }
+
+ int
+ getStackProp ()
+ {
+ return stack_prop;
+ }
+
+ typedef long NodeIdx;
+
+ struct Node
+ {
+ inline void
+ reset ()
+ {
+ ancestor = 0;
+ descendants = NULL;
+ instr = NULL;
+ funclist = 0;
+ }
+
+ NodeIdx ancestor;
+ Vector<NodeIdx> *descendants;
+ Histable *instr;
+ NodeIdx funclist;
+ };
+
+ static const int CHUNKSZ = 16384;
+
+ inline Node *
+ NODE_IDX (NodeIdx idx)
+ {
+ return idx ? &chunks[idx / CHUNKSZ][idx % CHUNKSZ] : NULL;
+ }
+
+ // queue for messages (statistics for pathtree processing)
+ Emsg *fetch_stats (void); // fetch the queue of comment messages
+ void delete_stats (void); // delete the queue of stats messages
+ Emsg *fetch_warnings (void); // fetch the queue of warnings messages
+ void delete_warnings (void); // delete the queue of warnings messages
+
+ NodeIdx
+ get_func_nodeidx (Function * func)
+ {
+ return fn_map == NULL ? (NodeIdx) 0 : fn_map->get (func);
+ }
+
+ void print (FILE *);
+ void dumpNodes (FILE *, Histable *);
+
+ // flame charts functions - get values from ftree_internal
+ int get_ftree_depth (); // Depth of tree
+ Vector<void*>* get_ftree_level (BaseMetric *bm, int dpth);
+ Vector<void*>* get_ftree_node_children (BaseMetric *bm, NodeIdx node_idx);
+ Vector<Function*>* get_ftree_funcs ();
+ Vector<Function*>* get_funcs (); // Unique functions in tree
+
+private:
+
+ enum
+ {
+ MAX_DESC_HTABLE_SZ = 65535
+ };
+
+ typedef struct hash_node
+ {
+ NodeIdx nd;
+ struct hash_node *next;
+ } hash_node_t;
+
+ int desc_htable_size;
+ int desc_htable_nelem;
+ hash_node_t **descHT;
+
+ struct Slot
+ {
+ int id;
+ ValueTag vtype;
+ union
+ {
+ int **mvals;
+ int64_t **mvals64;
+ };
+ };
+
+ typedef enum
+ {
+ PATHTREE_MAIN = 0,
+ PATHTREE_INTERNAL_OMP,
+ PATHTREE_INTERNAL_FUNCTREE
+ } PathTreeType;
+
+ DbeView *dbev;
+ int indxtype;
+ int stack_prop;
+ Expression *indx_expr;
+ Histable *total_obj;
+ Map<Function*, NodeIdx> *fn_map;
+ Map<uint64_t, NodeIdx> *pathMap;
+ Map<uint64_t, uint64_t> *hideMap;
+ int status;
+ NodeIdx root_idx;
+ Node *root;
+ int depth;
+ long nodes;
+ long dnodes;
+ long nchunks;
+ Node **chunks;
+ int nslots;
+ Slot *slots;
+ int phaseIdx;
+ int nexps;
+ Emsgqueue *statsq;
+ Emsgqueue *warningq;
+ Hist_data *hist_data;
+ int percent;
+ int ndone;
+ Histable **obj_list;
+ Node **node_list;
+ int *xlate;
+ bool cancel_ok;
+ PathTreeType pathTreeType;
+ PathTree *ptree_internal;
+ PathTree *ftree_internal; // function-based pathtree
+ bool ftree_needs_update;
+ Vector<Vector<NodeIdx>*> *depth_map; // for each depth level, list of nodes
+
+ void init ();
+ void fini ();
+ PtreePhaseStatus reset ();
+ PtreePhaseStatus add_experiment (int);
+ PtreePhaseStatus process_packets (Experiment*, DataView*, int);
+ DataView *get_filtered_events (int exp_index, int data_type);
+ void construct (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType);
+
+ PathTree (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType)
+ {
+ construct (_dbev, _indxtype, _pathTreeType);
+ }
+
+ inline int *
+ allocate_chunk (int **p, NodeIdx idx)
+ {
+ int *res = new int[CHUNKSZ];
+ for (int i = 0; i < CHUNKSZ; i++)
+ res[i] = 0;
+ p[idx] = res;
+ return res;
+ };
+
+ inline int64_t *
+ allocate_chunk (int64_t **p, NodeIdx idx)
+ {
+ int64_t *res = new int64_t[CHUNKSZ];
+ for (int i = 0; i < CHUNKSZ; i++)
+ res[i] = 0;
+ p[idx] = res;
+ return res;
+ };
+
+ inline Node *
+ allocate_chunk (Node **p, NodeIdx idx)
+ {
+ Node *res = new Node[CHUNKSZ];
+ for (int i = 0; i < CHUNKSZ; i++)
+ res[i].reset ();
+ p[idx] = res;
+ return res;
+ };
+
+ inline bool
+ IS_MVAL_ZERO (Slot& slot, NodeIdx idx)
+ {
+ if (slot.vtype == VT_LLONG || slot.vtype == VT_ULLONG)
+ {
+ int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+ return tmp ? tmp[idx % CHUNKSZ] == 0 : true;
+ }
+ else
+ {
+ int *tmp = slot.mvals[idx / CHUNKSZ];
+ return tmp ? tmp[idx % CHUNKSZ] == 0 : true;
+ }
+ }
+
+ inline void
+ ASN_METRIC_VAL (TValue& v, Slot& slot, NodeIdx idx)
+ {
+ if (slot.vtype == VT_LLONG)
+ {
+ int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+ if (tmp)
+ v.ll = tmp[idx % CHUNKSZ];
+ }
+ else if (slot.vtype == VT_ULLONG)
+ {
+ uint64_t *tmp = (uint64_t *) slot.mvals64[idx / CHUNKSZ];
+ if (tmp)
+ v.ull = tmp[idx % CHUNKSZ];
+ }
+ else
+ {
+ int *tmp = slot.mvals[idx / CHUNKSZ];
+ if (tmp)
+ v.i = tmp[idx % CHUNKSZ];
+ }
+ }
+
+ inline void
+ ADD_METRIC_VAL (TValue& v, Slot& slot, NodeIdx idx)
+ {
+ if (slot.vtype == VT_LLONG)
+ {
+ int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+ if (tmp)
+ v.ll += tmp[idx % CHUNKSZ];
+ }
+ else if (slot.vtype == VT_ULLONG)
+ {
+ uint64_t *tmp = (uint64_t *) slot.mvals64[idx / CHUNKSZ];
+ if (tmp)
+ v.ull += tmp[idx % CHUNKSZ];
+ }
+ else
+ {
+ int *tmp = slot.mvals[idx / CHUNKSZ];
+ if (tmp) v.i += tmp[idx % CHUNKSZ];
+ }
+ }
+
+ inline void
+ SUB_METRIC_VAL (TValue& v, Slot& slot, NodeIdx idx)
+ {
+ if (slot.vtype == VT_LLONG)
+ {
+ int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+ if (tmp)
+ v.ll -= tmp[idx % CHUNKSZ];
+ }
+ else if (slot.vtype == VT_ULLONG)
+ {
+ uint64_t *tmp = (uint64_t *) slot.mvals64[idx / CHUNKSZ];
+ if (tmp)
+ v.ull -= tmp[idx % CHUNKSZ];
+ }
+ else
+ {
+ int *tmp = slot.mvals[idx / CHUNKSZ];
+ if (tmp)
+ v.i -= tmp[idx % CHUNKSZ];
+ }
+ }
+
+ inline void
+ INCREMENT_METRIC (Slot *slot, NodeIdx idx, int64_t val)
+ {
+ if (slot->vtype == VT_LLONG)
+ {
+ int64_t *tmp = slot->mvals64[idx / CHUNKSZ];
+ if (tmp == NULL)
+ tmp = allocate_chunk (slot->mvals64, idx / CHUNKSZ);
+ tmp[idx % CHUNKSZ] += val;
+ }
+ else if (slot->vtype == VT_ULLONG)
+ {
+ uint64_t *tmp = (uint64_t *) slot->mvals64[idx / CHUNKSZ];
+ if (tmp == NULL)
+ tmp = (uint64_t *) allocate_chunk (slot->mvals64, idx / CHUNKSZ);
+ tmp[idx % CHUNKSZ] += val;
+ }
+ else
+ {
+ int *tmp = slot->mvals[idx / CHUNKSZ];
+ if (tmp == NULL)
+ tmp = allocate_chunk (slot->mvals, idx / CHUNKSZ);
+ tmp[idx % CHUNKSZ] += (int) val;
+ }
+ }
+
+ inline Slot *
+ SLOT_IDX (int idx)
+ {
+ if (idx < 0 || idx >= nslots)
+ return NULL;
+ return &slots[idx];
+ }
+
+ int allocate_slot (int id, ValueTag vtype);
+ void allocate_slots (Slot *slots, int nslots);
+ int find_slot (int);
+ NodeIdx new_Node (NodeIdx, Histable*, bool);
+ NodeIdx find_path (Experiment*, DataView*, long);
+ NodeIdx find_desc_node (NodeIdx, Histable*, bool);
+ NodeIdx find_in_desc_htable (NodeIdx, Histable*, bool);
+ Histable *get_hist_obj (Node *, Histable* = NULL);
+ Histable *get_hist_func_obj (Node *);
+ Histable *get_compare_obj (Histable *obj);
+ void get_metrics (NodeIdx, int);
+ void get_metrics (Vector<Function*> *, Histable *);
+ void get_clr_metrics (Vector<Histable*>*, NodeIdx, int, int);
+ void get_clr_metrics (Vector<Histable*>*);
+ void get_cle_metrics (Vector<Histable*>*, NodeIdx, int, int, int);
+ void get_cle_metrics (Vector<Histable*>*, NodeIdx, int);
+ void get_cle_metrics (Vector<Histable*>*);
+ void get_self_metrics (Vector<Histable*>*, NodeIdx, bool, int);
+ void get_self_metrics (Vector<Histable*>*);
+ void get_self_metrics (Histable *, Vector<Function*> *funclist,
+ Vector<Histable*>* sel_objs = NULL);
+ void get_cstack_list (CStack_data *, NodeIdx, int);
+
+ // Generate PathTree based on Functions instead of Instructions // Used for flame chart
+ void ftree_reset ();
+ void ftree_build (PathTree *mstr);
+ void ftree_build (PathTree *mstr, NodeIdx mstr_node_idx, NodeIdx local_node_idx);
+ void depth_map_build ();
+ void depth_map_build (NodeIdx node_idx, int depth);
+ Vector<void*>* get_level (BaseMetric *bm, int dpth);
+ Vector<void*>* get_nodes (BaseMetric *bm, Vector<NodeIdx> *node_idxs);
+ Vector<void*>* get_node_children (BaseMetric *bm, NodeIdx node_idx);
+ bool ftree_debug_match_hist_data (Hist_data *data, Hist_data *data_tmp);
+ void ftree_dump ();
+
+ // Debugging functions
+ void print (FILE *, PathTree::Node*, int);
+ void printn (FILE *);
+ int dbg_nodes (PathTree::Node*);
+};
+
+#endif /* _PATH_TREE_H */
diff --git a/gprofng/src/PreviewExp.cc b/gprofng/src/PreviewExp.cc
new file mode 100644
index 0000000..553afd3
--- /dev/null
+++ b/gprofng/src/PreviewExp.cc
@@ -0,0 +1,113 @@
+/* Copyright (C) 2021 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 <stdio.h>
+
+#include "PreviewExp.h"
+#include "Data_window.h"
+#include "DbeSession.h"
+#include "Emsg.h"
+#include "Print.h"
+#include "i18n.h"
+
+PreviewExp::PreviewExp (): Experiment () { }
+
+PreviewExp::~PreviewExp () { }//~PreviewExp
+
+Experiment::Exp_status
+PreviewExp::experiment_open (char *path)
+{
+ // Find experiment directory
+ if ((status = find_expdir (path)) != SUCCESS)
+ {
+ size_t len = strlen (path);
+ is_group = ((len > 4) && !strcmp (&path[len - 4], NTXT (".erg")));
+ return status;
+ }
+ else
+ is_group = 0;
+
+ read_log_file ();
+ if (status == FAILURE)
+ return status;
+
+ if (status == INCOMPLETE && resume_ts != MAX_TIME)
+ // experiment is incomplete and "resumed" (non-paused)
+ // PreviewExp does not process all the packets, therefore...
+ // ... last_event does not reflect reality
+ // ... we don't know the duration or the end.
+ last_event = ZERO_TIME; // mark last_event as uninitialized
+
+ read_notes_file ();
+ return status;
+}
+
+Vector<char*> *
+PreviewExp::preview_info ()
+{
+ Vector<char*> *info = new Vector<char*>;
+ if (is_group)
+ info->append (GTXT ("Experiment Group"));
+ else
+ info->append (GTXT ("Experiment"));
+ info->append (expt_name);
+
+ if (status == FAILURE /* != SUCCESS */)
+ {
+ if (is_group)
+ {
+ Vector<char*> *grp_list = dbeSession->get_group_or_expt (expt_name);
+ for (int i = 0, grp_sz = grp_list->size (); i < grp_sz; i++)
+ {
+ char *nm = grp_list->fetch (i);
+ char *str = dbe_sprintf (GTXT ("Exp.#%d"), i + 1);
+ info->append (str);
+ info->append (nm);
+ }
+ delete grp_list;
+ }
+ else
+ {
+ info->append (GTXT ("Error message"));
+ info->append (mqueue_str (errorq, GTXT ("No errors\n")));
+ }
+ return info;
+ }
+ info->append (GTXT ("Experiment header"));
+ info->append (mqueue_str (commentq, GTXT ("Empty header\n")));
+ info->append (GTXT ("Error message"));
+ info->append (mqueue_str (errorq, GTXT ("No errors\n")));
+ info->append (GTXT ("Warning message"));
+ info->append (mqueue_str (warnq, GTXT ("No warnings\n")));
+ info->append (GTXT ("Notes"));
+ info->append (mqueue_str (notesq, GTXT ("\n")));
+ return info;
+}
+
+char *
+PreviewExp::mqueue_str (Emsgqueue *msgqueue, char *null_str)
+{
+ char *mesgs = pr_mesgs (msgqueue->fetch (), null_str, "");
+ char *last = mesgs + strlen (mesgs) - 1;
+ if (*last == '\n')
+ *last = '\0';
+ return mesgs;
+}
diff --git a/gprofng/src/PreviewExp.h b/gprofng/src/PreviewExp.h
new file mode 100644
index 0000000..8b7834a
--- /dev/null
+++ b/gprofng/src/PreviewExp.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PREVIEW_EXP_H
+#define _PREVIEW_EXP_H
+
+#include "Experiment.h"
+#include "vec.h"
+
+class PreviewExp : public Experiment
+{
+public:
+ PreviewExp ();
+ ~PreviewExp ();
+
+ virtual Exp_status experiment_open (char *path);
+
+ Vector<char*> *preview_info ();
+
+ char *
+ getArgList ()
+ {
+ return uarglist;
+ }
+
+private:
+ char *mqueue_str (Emsgqueue *msgqueue, char *null_str);
+
+ int is_group;
+};
+
+#endif /* ! _PREVIEW_EXP_H */
diff --git a/gprofng/src/Print.cc b/gprofng/src/Print.cc
new file mode 100644
index 0000000..d6662df
--- /dev/null
+++ b/gprofng/src/Print.cc
@@ -0,0 +1,3485 @@
+/* Copyright (C) 2021 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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <libintl.h>
+//#include <libgen.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "Dbe.h"
+#include "StringBuilder.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "Settings.h"
+#include "Print.h"
+#include "DbeView.h"
+#include "Experiment.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "Function.h"
+#include "DataSpace.h"
+#include "DataObject.h"
+#include "FilterExp.h"
+#include "LoadObject.h"
+#include "Emsg.h"
+#include "Table.h"
+#include "DbeFile.h"
+#include "CallStack.h"
+
+int
+er_print_common_display::open (Print_params *params)
+{
+ pr_params = *params;
+ pr_params.name = dbe_strdup (params->name);
+ if (params->dest == DEST_PRINTER)
+ {
+ tmp_file = dbeSession->get_tmp_file_name (NTXT ("print"), false);
+ dbeSession->tmp_files->append (strdup (tmp_file));
+ out_file = fopen (tmp_file, NTXT ("w"));
+ }
+ else if (params->dest == DEST_OPEN_FILE)
+ out_file = pr_params.openfile;
+ else
+ out_file = fopen (pr_params.name, NTXT ("w"));
+
+ if (out_file == NULL)
+ // Failure
+ return 1;
+ return 0;
+}
+
+bool
+er_print_common_display::print_output ()
+{
+ char *sys_call;
+ bool ret = true;
+ if (pr_params.dest != DEST_OPEN_FILE)
+ fclose (out_file);
+
+ if (pr_params.dest == DEST_PRINTER)
+ {
+ if (streq ((char *) pr_params.name, NTXT ("")))
+ sys_call = dbe_sprintf ("(/usr/bin/lp -c -n%d %s) 2>/dev/null 1>&2",
+ pr_params.ncopies, tmp_file);
+ else
+ sys_call = dbe_sprintf ("(/usr/bin/lp -c -d%s -n%d %s) 2>/dev/null 1>&2",
+ pr_params.name, pr_params.ncopies, tmp_file);
+ if (system (sys_call) != 0)
+ ret = false;
+ unlink (tmp_file);
+ free (sys_call);
+ }
+
+ return ret;
+}
+
+// Return the report. If the report size is greater than max, return truncated report
+// Allocates memory, so the caller should free this memory.
+
+char *
+er_print_common_display::get_output (int maxsize)
+{
+ off_t max = (off_t) maxsize;
+ if (out_file != (FILE *) NULL)
+ {
+ fclose (out_file); // close tmp_file
+ out_file = (FILE *) NULL;
+ }
+ struct stat sbuf;
+ int st = stat (tmp_file, &sbuf);
+ if (st == 0)
+ {
+ off_t sz = sbuf.st_size;
+ if (sz > max)
+ return dbe_sprintf (GTXT ("Error: report is too long.\n"));
+ if (sz <= 0)
+ return dbe_sprintf (GTXT ("Error: empty temporary file: %s\n"),
+ tmp_file);
+ max = sz;
+ }
+
+ FILE *f = fopen (tmp_file, "r");
+ if (f == NULL)
+ return dbe_sprintf (GTXT ("Error: cannot open temporary file: %s\n"),
+ tmp_file);
+ char *report = (char *) malloc (max);
+ if (report)
+ {
+ if (1 != fread (report, max - 1, 1, f))
+ {
+ fclose (f);
+ free (report);
+ return dbe_sprintf (GTXT ("Error: cannot read temporary file: %s\n"),
+ tmp_file);
+ }
+ report[max - 1] = 0;
+ }
+ fclose (f);
+ return report;
+}
+
+void
+er_print_common_display::header_dump (int exp_idx)
+{
+ if (load && (exp_idx == exp_idx1))
+ {
+ load = false;
+ print_load_object (out_file);
+ }
+ print_header (dbeSession->get_exp (exp_idx), out_file);
+}
+
+char *
+pr_load_objects (Vector<LoadObject*> *loadobjects, char *lead)
+{
+ int size, i;
+ LoadObject *lo;
+ Emsg *m;
+ char *msg;
+ StringBuilder sb;
+ char *lo_name;
+ size = loadobjects->size ();
+ for (i = 0; i < size; i++)
+ {
+ lo = loadobjects->fetch (i);
+ lo_name = lo->get_name ();
+ if (lo_name != NULL)
+ {
+ size_t len = strlen (lo_name);
+ if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+ continue;
+ }
+
+ // print the segment name
+ sb.append (lead);
+ sb.append (NTXT (" "));
+ sb.append (lo->get_name ());
+ sb.append (NTXT (" ("));
+ sb.append (lo->get_pathname ());
+ sb.append (NTXT (")\n"));
+
+ // and any warnings
+ m = lo->fetch_warnings ();
+ if (m != NULL)
+ {
+ msg = pr_mesgs (m, NULL, NTXT (" "));
+ sb.append (msg);
+ free (msg);
+ }
+ }
+ return sb.toString ();
+}
+
+char *
+pr_mesgs (Emsg *msg, const char *null_str, const char *lead)
+{
+ Emsg *m;
+ StringBuilder sb;
+ if (msg == NULL)
+ return dbe_strdup (null_str);
+ for (m = msg; m; m = m->next)
+ {
+ sb.append (lead);
+ sb.append (m->get_msg ());
+ sb.append (NTXT ("\n"));
+ }
+ return sb.toString ();
+}
+
+void
+print_load_object (FILE *out_file)
+{
+ Vector<LoadObject*> *loadobjects = dbeSession->get_text_segments ();
+ char *msg = pr_load_objects (loadobjects, NTXT ("\t"));
+ fprintf (out_file, GTXT ("Load Object Coverage:\n"));
+ fprintf (out_file, NTXT ("%s"), msg);
+ fprintf (out_file,
+ "----------------------------------------------------------------\n");
+ free (msg);
+ delete loadobjects;
+}
+
+void
+print_header (Experiment *exp, FILE *out_file)
+{
+ fprintf (out_file, GTXT ("Experiment: %s\n"), exp->get_expt_name ());
+ char *msg = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT (""));
+ fprintf (out_file, NTXT ("%s"), msg);
+ free (msg);
+
+ msg = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT (""));
+ fprintf (out_file, NTXT ("%s"), msg);
+ free (msg);
+
+ msg = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT (""));
+ fprintf (out_file, NTXT ("%s"), msg);
+ free (msg);
+
+ msg = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT (""));
+ fprintf (out_file, NTXT ("%s"), msg);
+ free (msg);
+
+ msg = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT (""));
+ fprintf (out_file, NTXT ("%s"), msg);
+ free (msg);
+}
+
+void
+get_width (Hist_data *data,
+ MetricList *metrics_list, Metric::HistMetric *hist_metric)
+{
+ Metric *mitem;
+ Metric::HistMetric *hitem;
+ int last_column;
+ int index;
+
+ // find the last visible column.
+ last_column = 0;
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
+ last_column = index;
+ }
+
+ // find the width for each column.
+
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ hitem = &hist_metric[index];
+
+ if (mitem->is_visible ())
+ {
+ if (mitem->get_vtype () == VT_LABEL)
+ {
+ if (index == last_column)
+ hitem->maxvalue_width = 0;
+ else
+ hitem->maxvalue_width = data->name_maxlen ();
+ // truncate names which will be too long
+ if (hitem->maxvalue_width > MAX_LEN - 3)
+ hitem->maxvalue_width = MAX_LEN - 3;
+ }
+ else if (mitem->get_vtype () == VT_ADDRESS)
+ {
+ hitem->maxvalue_width = data->value_maxlen (index);
+ if (hitem->maxvalue_width < 13)
+ hitem->maxvalue_width = 13;
+ }
+ else
+ hitem->maxvalue_width = data->value_maxlen (index);
+ }
+ else
+ hitem->maxvalue_width = 0;
+
+ if (mitem->is_tvisible ())
+ {
+ if (mitem->get_visbits () & VAL_RATIO)
+ hitem->maxtime_width = data->value_maxlen (index);
+ else
+ hitem->maxtime_width = data->time_maxlen (index,
+ dbeSession->get_clock (-1));
+ }
+ else
+ {
+ hitem->maxtime_width = 0;
+ }
+ }
+}
+
+void
+get_format (char **fmt_int, char **fmt_real0, char **fmt_real1,
+ MetricList *metrics_list, Metric::HistMetric *hist_metric,
+ int nspace)
+{
+ Metric *mitem;
+ Metric::HistMetric *hitem;
+ int index;
+ int visible, tvisible, pvisible;
+ size_t maxlen;
+ bool prev;
+ char numstr[MAX_LEN], pstr_int[MAX_LEN],
+ pstr_real0[MAX_LEN], pstr_real1[MAX_LEN];
+
+ // find the width for each column.
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ hitem = &hist_metric[index];
+ visible = mitem->is_visible ();
+ tvisible = mitem->is_tvisible ();
+ pvisible = mitem->is_pvisible ();
+ *pstr_int = *pstr_real0 = *pstr_real1 = '\0';
+
+ // Get 'Show Value' format
+ const char *sign = (mitem->get_visbits () & VAL_DELTA) ? "+" : "";
+ if (visible)
+ {
+ maxlen = hitem->maxvalue_width;
+ switch (mitem->get_vtype2 ())
+ {
+ case VT_DOUBLE:
+ if (mitem->get_visbits () & VAL_RATIO)
+ {
+ snprintf (numstr, sizeof (numstr), "x %%#%d.0lf ",
+ (int) (maxlen - 3));
+ snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+ snprintf (pstr_real1, sizeof (pstr_real1), "x%%s%%%d.3lf ",
+ (int) maxlen);
+ }
+ else
+ {
+ snprintf (numstr, sizeof (numstr), "%%#%s%d.0lf ", sign,
+ (int) (maxlen - 3));
+ snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+ snprintf (pstr_real1, sizeof (pstr_real1), "%%s%%%s%d.3lf ",
+ sign, (int) maxlen);
+ }
+ break;
+ case VT_INT:
+ snprintf (pstr_int, sizeof (pstr_int), "%%%s%dd ", sign,
+ (int) maxlen);
+ break;
+ case VT_LLONG:
+ snprintf (pstr_int, sizeof (pstr_int), "%%%s%dlld ", sign,
+ (int) maxlen);
+ break;
+ case VT_ULLONG:
+ snprintf (pstr_int, sizeof (pstr_int), "%%%s%dllu ", sign,
+ (int) maxlen);
+ break;
+ case VT_ADDRESS:
+ if (maxlen <= 13)
+ {
+ snprintf (pstr_int, sizeof (pstr_int), "%%%dd:0x%%08x", 2);
+ }
+ else
+ {
+ snprintf (pstr_int, sizeof (pstr_int), "%%%dd:0x%%08x",
+ (int) (maxlen - 13));
+ }
+ break;
+ case VT_FLOAT:
+ snprintf (numstr, sizeof (numstr), "%%#%d.0f ",
+ (int) (maxlen - 3));
+ snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+ snprintf (pstr_real1, sizeof (pstr_real1), "%%%d.3f ",
+ (int) maxlen);
+ break;
+ case VT_SHORT:
+ snprintf (pstr_int, sizeof (pstr_int), "%%%dhu ", (int) maxlen);
+ break;
+ case VT_LABEL:
+ if (maxlen == 0) // last column
+ snprintf (pstr_int, sizeof (pstr_int), NTXT ("%%s%%s"));
+ else if (maxlen + nspace >= MAX_LEN - 3)
+ snprintf (pstr_int, sizeof (pstr_int), NTXT ("%%s%%-%d.%ds "),
+ MAX_LEN - 7, MAX_LEN - 7);
+ else
+ snprintf (pstr_int, sizeof (pstr_int), NTXT ("%%s%%-%ds "),
+ (int) (maxlen + nspace));
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Get 'Show Time' format
+ if (tvisible)
+ {
+ maxlen = hitem->maxtime_width;
+ if (mitem->get_visbits () & VAL_RATIO)
+ {
+ snprintf (numstr, sizeof (numstr), " %%%s#%d.0lf ",
+ sign, (int) (maxlen - 3));
+ snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+ snprintf (pstr_real1, sizeof (pstr_real1), "%%s%%%s%d.3lf ",
+ sign, (int) maxlen);
+ }
+ else
+ {
+ snprintf (numstr, sizeof (numstr), "%%%s#%d.0lf ",
+ sign, (int) (maxlen - 3));
+ snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+ snprintf (pstr_real1, sizeof (pstr_real1), "%%s%%%s%d.3lf ",
+ sign, (int) maxlen);
+ }
+ }
+
+ // Copy format
+ if (*pstr_int)
+ fmt_int[index] = dbe_strdup (pstr_int);
+ else
+ fmt_int[index] = NULL;
+
+ if (*pstr_real0)
+ fmt_real0[index] = dbe_strdup (pstr_real0);
+ else
+ fmt_real0[index] = NULL;
+
+ if (*pstr_real1)
+ fmt_real1[index] = dbe_strdup (pstr_real1);
+ else
+ fmt_real1[index] = NULL;
+
+ // Set total width
+ hitem->width = 0;
+ if (hitem->maxvalue_width > 0)
+ {
+ hitem->width += hitem->maxvalue_width;
+ prev = true;
+ }
+ else
+ prev = false;
+
+ if (hitem->maxtime_width > 0)
+ {
+ if (prev)
+ hitem->width++;
+ hitem->width += hitem->maxtime_width;
+ prev = true;
+ }
+
+ if (pvisible)
+ {
+ if (prev)
+ hitem->width++;
+ hitem->width += 6; // adjust to change format from xx.yy%
+ }
+ if (visible || tvisible || pvisible)
+ mitem->legend_width (hitem, 2);
+ }
+}
+
+static char *
+delTrailingBlanks (char *s)
+{
+ for (int i = (int) strlen (s) - 1; i >= 0 && s[i] == ' '; i--)
+ s[i] = 0;
+ return s;
+}
+
+/**
+ * Print the 3-line header with column heads for the metrics
+ * Return offset of "Name" column (this is needed to print Callers-Callees)
+ */
+int
+print_label (FILE *out_file, MetricList *metrics_list,
+ Metric::HistMetric *hist_metric, int space)
+{
+ char line0[2 * MAX_LEN], line1[2 * MAX_LEN];
+ char line2[2 * MAX_LEN], line3[2 * MAX_LEN];
+ int name_offset = 0;
+ *line0 = *line1 = *line2 = *line3 = '\0';
+ Vector<Metric*> *mlist = metrics_list->get_items ();
+ for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++)
+ {
+ Metric *mitem = mlist->fetch (index);
+ if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
+ {
+ Metric::HistMetric *hitem = hist_metric + index;
+ char *fmt;
+ if (index > 0 && mitem->get_type () == Metric::ONAME)
+ {
+ fmt = NTXT (" %-*s");
+ name_offset = strlen (line1);
+ }
+ else
+ fmt = NTXT ("%-*s");
+ int width = (int) hitem->width;
+ size_t len = strlen (line1);
+ snprintf (line1 + len, sizeof (line1) - len, fmt, width,
+ hitem->legend1);
+ len = strlen (line2);
+ snprintf (line2 + len, sizeof (line2) - len, fmt, width,
+ hitem->legend2);
+ len = strlen (line3);
+ snprintf (line3 + len, sizeof (line3) - len, fmt, width,
+ hitem->legend3);
+ len = strlen (line0);
+ snprintf (line0 + len, sizeof (line0) - len, fmt, width,
+ mitem->legend ? mitem->legend : NTXT (""));
+ }
+ }
+ char *s = delTrailingBlanks (line0);
+ if (*s)
+ fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), s);
+ fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line1));
+ fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line2));
+ fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line3));
+ return name_offset;
+}
+
+static int
+print_one_visible (FILE *out_file, char *fmt_int, char *fmt_real0, char *fmt_real1,
+ TValue *value, int visbits)
+{
+ int nc = 0;
+ switch (value->tag)
+ {
+ case VT_DOUBLE:
+ if (value->d == 0.0)
+ nc = fprintf (out_file, fmt_real0);
+ else
+ {
+ if (visbits & VAL_RATIO)
+ {
+ if (value->d > 99.999)
+ nc = fprintf (out_file, fmt_real1, NTXT (">"), 99.999);
+ else
+ nc = fprintf (out_file, fmt_real1, NTXT (" "), value->d);
+ }
+ else
+ nc = fprintf (out_file, fmt_real1, NTXT (""), value->d);
+ }
+ break;
+ case VT_INT:
+ nc = fprintf (out_file, fmt_int, value->i);
+ break;
+ case VT_LLONG:
+ case VT_ULLONG:
+ nc = fprintf (out_file, fmt_int, value->ll);
+ break;
+ case VT_ADDRESS:
+ nc = fprintf (out_file, fmt_int, ADDRESS_SEG (value->ll),
+ ADDRESS_OFF (value->ll));
+ break;
+ case VT_FLOAT:
+ if (value->f == 0.0)
+ nc = fprintf (out_file, fmt_real0);
+ else
+ nc = fprintf (out_file, fmt_real1, value->f);
+ break;
+ case VT_SHORT:
+ nc = fprintf (out_file, fmt_int, value->s);
+ break;
+ // ignoring the following cases (why?)
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_OFFSET:
+ break;
+ }
+ return nc;
+}
+
+static int
+print_one_tvisible (FILE *out_file, char *fmt_real0, char *fmt_real1,
+ TValue *value, int visbits, int clock)
+{
+ int nc;
+ if (value->ll == 0LL)
+ nc = fprintf (out_file, fmt_real0);
+ else
+ {
+ if (visbits & VAL_RATIO)
+ {
+ if (value->d > 99.999)
+ nc = fprintf (out_file, fmt_real1, NTXT (">"), 99.999);
+ else
+ nc = fprintf (out_file, fmt_real1, NTXT (" "), value->d);
+ }
+ else
+ nc = fprintf (out_file, fmt_real1, "", 1.e-6 * value->ll / clock);
+ }
+ return nc;
+}
+
+static void
+print_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+ char **fmt_int, char **fmt_real0, char **fmt_real1,
+ MetricList *metrics_list, Metric::HistMetric *hist_metric,
+ char *mark, Histable::NameFormat nfmt)
+{
+ Metric *mitem;
+ Metric::HistMetric *hitem;
+ int index, nc, np, i;
+ int visible, tvisible, pvisible;
+ TValue *value;
+ double percent;
+
+ if (item->type == Module::AT_EMPTY)
+ {
+ fprintf (out_file, nl);
+ return;
+ }
+
+ // set name_is_Total
+ int name_is_Total = 0;
+
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ if (mitem->get_type () != Metric::ONAME)
+ continue;
+ name_is_Total = strcmp (item->obj->get_name (), GTXT ("<Total>")) == 0;
+ break;
+ }
+
+ np = 0;
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ visible = mitem->is_visible ();
+ tvisible = mitem->is_tvisible ();
+ pvisible = mitem->is_pvisible ();
+
+ // alignment
+ for (i = 0; i < np; i++)
+ fputc (' ', out_file);
+
+ hitem = &hist_metric[index];
+ nc = 0;
+ if (tvisible)
+ {
+ value = &(item->value[index]);
+ nc = print_one_tvisible (out_file, fmt_real0[index], fmt_real1[index],
+ value, mitem->get_visbits (),
+ dbeSession->get_clock (-1));
+ }
+ else
+ nc = 0;
+
+ if (visible)
+ {
+ if (mitem->get_vtype () == VT_LABEL)
+ {
+ value = &(item->value[index]);
+ if (value->tag == VT_OFFSET)
+ nc += fprintf (out_file, fmt_int[index], mark,
+ ((DataObject*) (item->obj))->get_offset_name ());
+ else
+ nc += fprintf (out_file, fmt_int[index], mark,
+ item->obj->get_name (nfmt));
+ }
+ else if (name_is_Total &&
+ (strcmp (mitem->get_username (), "Block Covered %") == 0
+ || strcmp (mitem->get_username (), "Instr Covered %") == 0))
+ {
+ char stmp[128];
+ snprintf (stmp, sizeof (stmp), fmt_int[index], 0);
+
+ /* and now blank that '0' out */
+ for (int ii = 0; ii < 128; ii++)
+ {
+ if (stmp[ii] != '0')
+ continue;
+ stmp[ii] = ' ';
+ break;
+ }
+ nc += fprintf (out_file, stmp);
+ }
+ else
+ nc += print_one_visible (out_file, fmt_int[index], fmt_real0[index],
+ fmt_real1[index], &(item->value[index]),
+ mitem->get_visbits ());
+ }
+
+ if (pvisible)
+ {
+ percent = data->get_percentage (item->value[index].to_double (), index);
+ if (percent == 0.0)
+ // adjust to change format from xx.yy%
+ nc += fprintf (out_file, NTXT ("%#4.0f "), 0.);
+ else
+ // adjust format below to change format from xx.yy%
+ nc += fprintf (out_file, NTXT ("%6.2f "), (100.0 * percent));
+ }
+ np = (int) (hitem->width - nc);
+ }
+ fprintf (out_file, nl);
+}
+
+void
+print_content (FILE *out_file, Hist_data *data,
+ char **fmt_int, char **fmt_real0, char **fmt_real1,
+ MetricList *metrics_list, Metric::HistMetric *hist_metric,
+ int limit, Histable::NameFormat nfmt)
+{
+ // printing contents.
+ for (int i = 0; i < limit; i++)
+ {
+ Hist_data::HistItem *item = data->fetch (i);
+ print_one (out_file, data, item, fmt_int, fmt_real0, fmt_real1,
+ metrics_list, hist_metric, NTXT (" "), nfmt);
+ }
+}
+
+er_print_histogram::er_print_histogram (DbeView *_dbev, Hist_data *data,
+ MetricList *metrics_list,
+ Print_mode disp_type, int limit,
+ char *sort_name, Histable *sobj,
+ bool show_load, bool show_header)
+{
+ hist_data = data;
+ mlist = metrics_list;
+ type = disp_type;
+ number_entries = limit;
+ sort_metric = sort_name;
+ sel_obj = sobj;
+ dbev = _dbev;
+ exp_idx1 = 0;
+ exp_idx2 = dbeSession->nexps () - 1;
+ load = show_load;
+ header = show_header;
+}
+
+void
+er_print_histogram::dump_list (int limit)
+{
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ StringBuilder sb;
+ char *title = NULL; // No title for some formats
+ enum PrintMode pm = dbev->get_printmode ();
+
+ // create a header line, except for delimiter-separated list output
+ if (pm != PM_DELIM_SEP_LIST)
+ {
+ if (hist_data->type == Histable::FUNCTION)
+ sb.append (GTXT ("Functions sorted by metric: "));
+ else if (hist_data->type == Histable::INSTR)
+ sb.append (GTXT ("PCs sorted by metric: "));
+ else if (hist_data->type == Histable::LINE)
+ sb.append (GTXT ("Lines sorted by metric: "));
+ else if (hist_data->type == Histable::DOBJECT)
+ sb.append (GTXT ("Dataobjects sorted by metric: "));
+ else
+ sb.append (GTXT ("Objects sorted by metric: "));
+ sb.append (sort_metric);
+ title = sb.toString ();
+ }
+
+ switch (pm)
+ {
+ case PM_TEXT:
+ {
+ Metric::HistMetric *hist_metric = hist_data->get_histmetrics ();
+ fprintf (out_file, NTXT ("%s\n\n"), title); //print title
+ hist_data->print_label (out_file, hist_metric, 0);
+ hist_data->print_content (out_file, hist_metric, limit);
+ fprintf (out_file, nl);
+ break;
+ }
+ case PM_HTML:
+ {
+ print_html_title (out_file, title);
+ print_html_label (out_file, mlist);
+ print_html_content (out_file, hist_data, mlist, limit, nfmt);
+ print_html_trailer (out_file);
+ break;
+ }
+ case PM_DELIM_SEP_LIST:
+ {
+ char delim = dbev->get_printdelimiter ();
+ print_delim_label (out_file, mlist, delim);
+ print_delim_content (out_file, hist_data, mlist, limit, nfmt, delim);
+ print_delim_trailer (out_file, delim);
+ break;
+ }
+ }
+ free (title);
+}
+
+void
+er_print_histogram::dump_annotated_dataobjects (Vector<int> *marks,
+ int ithreshold)
+{
+ Metric::HistMetric *hist_metric;
+ char **fmt_int, **fmt_real0, **fmt_real1;
+ int no_metrics = mlist->get_items ()->size ();
+ int name_index = -1;
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+ if (!dbeSession->is_datamode_available ())
+ fprintf (out_file,
+ GTXT ("No dataspace information recorded in experiments\n\n"));
+
+ Hist_data *layout_data = dbev->get_data_space ()->get_layout_data (hist_data, marks, ithreshold);
+
+ for (int mind = 0; mind < no_metrics; mind++)
+ if (mlist->get_items ()->fetch (mind)->get_type () == Metric::ONAME)
+ name_index = mind;
+
+ fmt_int = new char*[no_metrics];
+ fmt_real0 = new char*[no_metrics];
+ fmt_real1 = new char*[no_metrics];
+ hist_metric = new Metric::HistMetric[no_metrics];
+
+ // use new layout_data to set metric format
+ get_width (hist_data, mlist, hist_metric);
+ get_format (fmt_int, fmt_real0, fmt_real1, mlist, hist_metric, 0);
+ snprintf (hist_metric[name_index].legend2, MAX_LEN, GTXT ("* +offset .element"));
+ print_label (out_file, mlist, hist_metric, 3);
+ fprintf (out_file, nl);
+ for (long i = 0; i < layout_data->size (); i++)
+ {
+ Hist_data::HistItem* item = layout_data->fetch (i);
+ if (marks->find (i) != -1)
+ fprintf (out_file, NTXT ("## "));
+ else
+ fprintf (out_file, NTXT (" "));
+ print_one (out_file, layout_data, item, fmt_int, fmt_real0, fmt_real1,
+ mlist, hist_metric, NTXT (" "), nfmt);
+ }
+ fprintf (out_file, nl);
+
+ // free format strings.
+ for (int i = 0; i < no_metrics; i++)
+ {
+ free (fmt_int[i]);
+ free (fmt_real0[i]);
+ free (fmt_real1[i]);
+ }
+ delete[] fmt_int;
+ delete[] fmt_real0;
+ delete[] fmt_real1;
+ delete[] hist_metric;
+ delete layout_data;
+}
+
+void
+er_print_histogram::dump_detail (int limit)
+{
+ Histable *obj;
+ Hist_data *current_data;
+ Histable::Type htype;
+ TValue *values;
+ double dvalue, percent;
+ MetricList *prop_mlist = new MetricList (mlist);
+ Metric *mitem;
+ int index, i;
+ size_t max_len, len, smax_len, slen;
+ Vaddr pc;
+ Module *module;
+ LoadObject *loadobject;
+ char *sname, *oname, *lname, *alias, *mangle;
+ char fmt_name[MAX_LEN];
+ char fmt_elem[MAX_LEN];
+ char fmt_real1[MAX_LEN], fmt_real2[MAX_LEN];
+ char fmt_int1[MAX_LEN], fmt_int2[MAX_LEN];
+ char fmt_long1[MAX_LEN], fmt_long2[MAX_LEN], fmt_long3[MAX_LEN];
+ char fmt_int0[MAX_LEN], fmt_long0[MAX_LEN];
+ char numstr[MAX_LEN];
+
+ Histable::NameFormat nfmt = dbev->get_name_format ();
+
+ // Check max. length of metrics names
+ max_len = smax_len = 0;
+
+ Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+ {
+ mitem->set_vvisible (true);
+ if (mitem->get_vtype () == VT_LABEL)
+ continue;
+
+ if (mitem->get_subtype () != Metric::STATIC)
+ {
+ mitem->set_pvisible (true);
+ len = hist_data->value_maxlen (index);
+ if (max_len < len)
+ max_len = len;
+ slen = strlen (mitem->get_name ());
+ if (smax_len < slen)
+ smax_len = slen;
+ }
+ }
+
+ // now get the length of the other (non-performance-data) messages
+ if (hist_data->type == Histable::FUNCTION)
+ {
+ slen = strlen (GTXT ("Source File"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Object File"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Load Object"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Mangled Name"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Aliases"));
+ if (smax_len < slen)
+ smax_len = slen;
+ }
+ else if (hist_data->type == Histable::DOBJECT)
+ {
+ slen = strlen (GTXT ("Scope"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Type"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Member of"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Offset (bytes)"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Size (bytes)"));
+ if (smax_len < slen)
+ smax_len = slen;
+ slen = strlen (GTXT ("Elements"));
+ if (smax_len < slen)
+ smax_len = slen;
+ }
+ snprintf (fmt_name, sizeof (fmt_name), NTXT ("\t%%%ds: "), (int) smax_len);
+ snprintf (fmt_elem, sizeof (fmt_elem), NTXT ("\t%%%ds "), (int) smax_len);
+ snprintf (numstr, sizeof (numstr), "%%#%d.0lf ( %#1.0f %%%%%%%%)\n",
+ (int) (max_len - 3), 0.);
+ snprintf (fmt_real1, sizeof (fmt_real1), numstr, 0.0);
+ snprintf (fmt_real2, sizeof (fmt_real2), NTXT ("%%%d.3lf (%%5.1f%%%%)\n"),
+ (int) max_len);
+ snprintf (fmt_int0, sizeof (fmt_int0), NTXT ("%%%dd\n"), (int) max_len);
+ snprintf (numstr, sizeof (numstr), NTXT ("%%%dd ( %#1.0f %%%%%%%%)\n"),
+ (int) max_len, 0.);
+ snprintf (fmt_int1, sizeof (fmt_int1), numstr, 0);
+ snprintf (fmt_int2, sizeof (fmt_int2), NTXT ("%%%dd (%%5.1f%%%%)\n"),
+ (int) max_len);
+ snprintf (fmt_long0, sizeof (fmt_long0), NTXT ("%%%dllu\n"), (int) max_len);
+ snprintf (numstr, sizeof (numstr), NTXT ("%%%dd ( %#1.0f %%%%%%%%)\n"),
+ (int) max_len, 0.);
+ snprintf (fmt_long1, sizeof (fmt_long1), numstr, 0);
+ snprintf (fmt_long2, sizeof (fmt_long2), "%%%dllu (%%5.1f%%%%)\n",
+ (int) max_len);
+ snprintf (numstr, sizeof (numstr), NTXT ("\t%%%ds %%%%%dllu\n"),
+ (int) (smax_len + 1), (int) max_len);
+ snprintf (fmt_long3, sizeof (fmt_long3), numstr, GTXT ("Count:"));
+ snprintf (numstr, sizeof (numstr), "%%%dd ( %#1.0f %%%%%%%%) %%#%d.0lf\n",
+ (int) max_len, 0., (int) (max_len - 6));
+
+ // now loop over the objects
+ int num_printed_items = 0;
+ for (i = 0; i < hist_data->size (); i++)
+ {
+ if (hist_data->type == Histable::FUNCTION)
+ {
+ if (num_printed_items >= limit)
+ break;
+ obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj;
+ htype = obj->get_type ();
+
+ // ask the view for all the data for the object
+ // xxxxx may be expensive to rescan all packets via get_hist_data()
+ current_data = dbev->get_hist_data (prop_mlist,
+ htype, 0, Hist_data::SELF, obj);
+ if (current_data->size () == 0)
+ continue;
+ values = current_data->fetch (0)->value;
+ }
+ else
+ {
+ obj = hist_data->fetch (i)->obj;
+ DataObject *dobj = (DataObject*) obj;
+ if (sel_obj)
+ {
+ // print selected item and its members
+ if (sel_obj != obj
+ && (DataObject*) sel_obj != dobj->get_parent ())
+ // not a match, advance to next item
+ continue;
+ }
+ else if (num_printed_items >= limit)
+ break;
+ htype = obj->get_type ();
+ values = hist_data->fetch (i)->value;
+ current_data = hist_data;
+ }
+
+ if (num_printed_items)
+ // if this isn't the first one, add a blank line
+ fprintf (out_file, NTXT ("\n"));
+ num_printed_items++;
+
+ // Print full object name
+ if (htype != Histable::DOBJECT)
+ fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt));
+ else
+ {
+ DataObject *dobj = (DataObject*) obj;
+ if (!dobj->get_parent ())
+ fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt));
+ else
+ fprintf (out_file, NTXT (" %s\n"), obj->get_name (nfmt));
+ }
+
+ Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+ {
+ if (mitem->get_vtype () == VT_LABEL)
+ continue;
+ if (mitem->get_subtype () == Metric::STATIC
+ && htype == Histable::DOBJECT)
+ continue;
+ fprintf (out_file, fmt_name, mitem->get_name ());
+
+ if (mitem->get_value_styles () & VAL_PERCENT)
+ {
+ dvalue = values[index].to_double ();
+ switch (mitem->get_vtype ())
+ {
+ case VT_DOUBLE:
+ if (dvalue == 0.0)
+ fprintf (out_file, fmt_real1);
+ else
+ fprintf (out_file, fmt_real2, dvalue, 100.0
+ * current_data->get_percentage (dvalue, index));
+ break;
+ case VT_INT:
+ if (dvalue == 0.0)
+ fprintf (out_file, fmt_int1);
+ else
+ fprintf (out_file, fmt_int2, (int) dvalue, 100.0
+ * current_data->get_percentage (dvalue, index));
+ break;
+ case VT_LLONG:
+ case VT_ULLONG:
+ if (values[index].ll == 0LL)
+ {
+ if (mitem->is_time_val ())
+ {
+ fprintf (out_file, fmt_real1);
+ fprintf (out_file, fmt_long3, 0LL);
+ }
+ else
+ fprintf (out_file, fmt_long1);
+ }
+ else
+ {
+ percent = 100.0 *
+ current_data->get_percentage (dvalue, index);
+ if (mitem->is_time_val ())
+ {
+ dvalue /= 1.e+6 * dbeSession->get_clock (-1);
+ fprintf (out_file, fmt_real2, dvalue, percent);
+ fprintf (out_file, fmt_long3, values[index].ll);
+ }
+ else
+ fprintf (out_file, fmt_long2, values[index].ll,
+ percent);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (mitem->get_vtype ())
+ {
+ case VT_INT:
+ fprintf (out_file, fmt_int0, values[index].i);
+ break;
+ case VT_LLONG:
+ case VT_ULLONG:
+ fprintf (out_file, fmt_long0, values[index].ll);
+ break;
+ case VT_ADDRESS:
+ pc = values[index].ll;
+ fprintf (out_file, NTXT ("%u:0x%08x\n"), ADDRESS_SEG (pc),
+ ADDRESS_OFF (pc));
+ break;
+ case VT_DOUBLE:
+ if (values[index].d == 0.0)
+ fprintf (out_file, fmt_real1);
+ else
+ fprintf (out_file, "\t%*.3lf\n", (int) (max_len - 5), values[index].d);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // now add the descriptive information about the object
+ if (htype != Histable::DOBJECT)
+ {
+ Function *func = (Function*) obj->convertto (Histable::FUNCTION);
+ if (func && func->get_type () == Histable::FUNCTION)
+ {
+ // Print the source/object/load-object files & aliases
+ oname = lname = alias = NULL;
+ sname = func->getDefSrcName ();
+ mangle = func->get_mangled_name ();
+ if (mangle && streq (func->get_name (), mangle))
+ mangle = NULL;
+ module = func->module;
+ if (module)
+ {
+ oname = module->get_name ();
+ loadobject = module->loadobject;
+ if (loadobject)
+ {
+ lname = loadobject->get_pathname ();
+ alias = loadobject->get_alias (func);
+ }
+ }
+
+ if (htype == Histable::INSTR && dbeSession->is_datamode_available ())
+ alias = ((DbeInstr*) obj)->get_descriptor ();
+
+ fprintf (out_file, fmt_name, GTXT ("Source File"));
+ if (sname)
+ fprintf (out_file, NTXT ("%s"), sname);
+ fprintf (out_file, NTXT ("\n"));
+
+ fprintf (out_file, fmt_name, GTXT ("Object File"));
+ if (oname)
+ fprintf (out_file, NTXT ("%s"), oname);
+ fprintf (out_file, NTXT ("\n"));
+
+ fprintf (out_file, fmt_name, GTXT ("Load Object"));
+ if (lname)
+ fprintf (out_file, NTXT ("%s"), lname);
+ fprintf (out_file, NTXT ("\n"));
+
+ fprintf (out_file, fmt_name, GTXT ("Mangled Name"));
+ if (mangle)
+ fprintf (out_file, NTXT ("%s"), mangle);
+ fprintf (out_file, NTXT ("\n"));
+ fprintf (out_file, fmt_name, GTXT ("Aliases"));
+ if (alias)
+ fprintf (out_file, NTXT ("%s"), alias);
+ fprintf (out_file, NTXT ("\n"));
+ }
+ }
+ else
+ {
+ // Print the dataobject information
+ DataObject *dobj = (DataObject*) obj;
+ Histable *scope = dobj->get_scope ();
+
+ // print the scope
+ fprintf (out_file, fmt_name, GTXT ("Scope"));
+ if (!scope)
+ fprintf (out_file, GTXT ("(Global)\n"));
+ else switch (scope->get_type ())
+ {
+ case Histable::FUNCTION:
+ fprintf (out_file, NTXT ("%s(%s)\n"),
+ ((Function*) scope)->module->get_name (),
+ scope->get_name ());
+ break;
+ case Histable::LOADOBJECT:
+ case Histable::MODULE:
+ default:
+ fprintf (out_file, NTXT ("%s\n"), scope->get_name ());
+ }
+
+ // print the type name
+ fprintf (out_file, fmt_name, GTXT ("Type"));
+ if (dobj->get_typename ())
+ fprintf (out_file, NTXT ("%s\n"), dobj->get_typename ());
+ else
+ fprintf (out_file, GTXT ("(Synthetic)\n"));
+
+ // print the offset
+ if (dobj->get_offset () != -1)
+ {
+ if (dobj->get_parent ())
+ {
+ fprintf (out_file, fmt_name, GTXT ("Member of"));
+ fprintf (out_file, NTXT ("%s\n"), dobj->get_parent ()->get_name ());
+ }
+ fprintf (out_file, fmt_name, GTXT ("Offset (bytes)"));
+ fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_offset ());
+ }
+ // print the size
+ if (dobj->get_size ())
+ {
+ fprintf (out_file, fmt_name, GTXT ("Size (bytes)"));
+ fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_size ());
+ }
+ }
+ if (hist_data->type == Histable::FUNCTION)
+ delete current_data;
+ }
+ if (num_printed_items == 0 && sel_obj)
+ fprintf (stderr,
+ GTXT ("Error: Specified item `%s' had no recorded metrics.\n"),
+ sel_obj->get_name ());
+ delete prop_mlist;
+}
+
+static Metric::HistMetric *
+allocateHistMetric (int no_metrics)
+{
+ Metric::HistMetric *hist_metric = new Metric::HistMetric[no_metrics];
+ for (int i = 0; i < no_metrics; i++)
+ {
+ Metric::HistMetric *hm = &hist_metric[i];
+ hm->init ();
+ }
+ return hist_metric;
+}
+
+void
+er_print_histogram::dump_gprof (int limit)
+{
+ StringBuilder sb;
+ Histable *obj;
+ Hist_data *callers;
+ Hist_data *callees;
+ Hist_data *center;
+
+ int no_metrics = mlist->get_items ()->size ();
+ Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics);
+ for (int i = 0; i < limit; i++)
+ {
+ obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj;
+ callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLERS, obj);
+ callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLEES, obj);
+ center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::SELF, obj);
+ callers->update_max (hist_metric);
+ callees->update_max (hist_metric);
+ center->update_max (hist_metric);
+ callers->update_legend_width (hist_metric);
+ callers->print_label (out_file, hist_metric, 0);
+ callers->print_content (out_file, hist_metric, callers->size ());
+
+ if (center->size () > 0)
+ {
+ center->update_total (callers->get_totals ());
+ sb.setLength (0);
+ center->print_row (&sb, 0, hist_metric, NTXT ("*"));
+ sb.toFileLn (out_file);
+ }
+ callees->print_content (out_file, hist_metric, callees->size ());
+ fprintf (out_file, nl);
+ delete callers;
+ delete callees;
+ delete center;
+ }
+ delete[] hist_metric;
+}
+
+// dump an annotated file
+void
+dump_anno_file (FILE *fp, Histable::Type type, Module *module, DbeView *dbev,
+ MetricList *mlist, TValue *ftotal, const char *srcFile,
+ Function *func, Vector<int> *marks, int threshold, int vis_bits,
+ int src_visible, bool hex_visible, bool src_only)
+{
+ int no_metrics, lspace, mspace, tspace,
+ remain, mindex, next_mark, hidx,
+ index;
+ Metric *mitem;
+ char **fmt_int, **fmt_real0, **fmt_real1, buf[MAX_LEN];
+ Hist_data::HistItem *item;
+
+ SourceFile *srcContext = NULL;
+ bool func_scope = dbev == NULL ? false : dbev->get_func_scope ();
+ if (srcFile)
+ {
+ srcContext = module->findSource (srcFile, false);
+ if (srcContext == NULL)
+ {
+ Vector<SourceFile*> *includes = module->includes;
+ char *bname = get_basename (srcFile);
+ for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
+ {
+ SourceFile *sf = includes->fetch (i);
+ if (streq (get_basename (sf->get_name ()), bname))
+ {
+ srcContext = sf;
+ break;
+ }
+ }
+ }
+ if (func)
+ func_scope = true;
+ }
+ else if (func)
+ srcContext = func->getDefSrc ();
+
+ Hist_data *hdata = module->get_data (dbev, mlist, type, ftotal, srcContext,
+ func, marks, threshold, vis_bits,
+ src_visible, hex_visible,
+ func_scope, src_only);
+
+ if (hdata == NULL)
+ return;
+
+ // force the name metric to be invisible
+ MetricList *nmlist = hdata->get_metric_list ();
+ nmlist->find_metric (GTXT ("name"), Metric::STATIC)->clear_all_visbits ();
+ no_metrics = nmlist->get_items ()->size ();
+ fmt_int = new char*[no_metrics];
+ fmt_real0 = new char*[no_metrics];
+ fmt_real1 = new char*[no_metrics];
+ Metric::HistMetric *hist_metric = hdata->get_histmetrics ();
+
+ // lspace is for max line number that's inserted; use to set width
+ int max_lineno = 0;
+ Vec_loop (Hist_data::HistItem*, hdata, hidx, item)
+ {
+ if (!item->obj)
+ continue;
+ if (item->obj->get_type () == Histable::LINE
+ && ((DbeLine*) item->obj)->lineno > max_lineno)
+ max_lineno = ((DbeLine*) item->obj)->lineno;
+ else if (item->obj->get_type () == Histable::INSTR
+ && ((DbeInstr*) item->obj)->lineno > max_lineno)
+ max_lineno = ((DbeInstr*) item->obj)->lineno;
+ }
+
+ lspace = snprintf (buf, sizeof (buf), NTXT ("%d"), max_lineno);
+
+ // mspace is the space needed for all metrics, and the mark, if any
+ mspace = 0;
+ if (nmlist->get_items ()->size () > 0)
+ {
+ mspace = 3; // mark "## "
+ Vec_loop (Metric*, nmlist->get_items (), index, mitem)
+ {
+ if (mitem->is_visible () || mitem->is_tvisible ()
+ || mitem->is_pvisible ())
+ mspace += (int) hist_metric[index].width;
+ }
+ }
+ tspace = 0;
+ remain = (mspace + lspace + 3) % 8; // " " before, ". " after line#
+ if (remain)
+ { // tab alignment
+ tspace = 8 - remain;
+ mspace += tspace;
+ }
+ mindex = 0;
+ next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1;
+
+ // Print the header for this list
+ SourceFile *sf = srcContext ? srcContext : module->getMainSrc ();
+ char *src_name = sf->dbeFile->get_location_info ();
+ DbeFile *df = module->dbeFile;
+ if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
+ df = module->loadobject->dbeFile;
+ char *lo_name = df->get_location_info ();
+ char *dot_o_name = lo_name;
+ if (module->dot_o_file)
+ dot_o_name = module->dot_o_file->dbeFile->get_location_info ();
+ fprintf (fp, GTXT ("Source file: %s\nObject file: %s\nLoad Object: %s\n\n"),
+ src_name, dot_o_name, lo_name);
+
+ // Print metric labels
+ if (nmlist->get_items ()->size () != 0)
+ print_label (fp, nmlist, hist_metric, 3);
+
+ // determine the name metric (not printed as a metric, though)
+ int lind = nmlist->get_listorder (GTXT ("name"), Metric::STATIC);
+
+ // now loop over the data rows -- the lines in the annotated source/disasm,
+ // including index lines, compiler commentary, etc.
+ StringBuilder sb;
+ Vec_loop (Hist_data::HistItem*, hdata, hidx, item)
+ {
+ sb.setLength (0);
+ if (item->type == Module::AT_DIS || item->type == Module::AT_QUOTE
+ || item->type == Module::AT_SRC)
+ {
+ // does this line get a high-metric mark?
+ if (hidx == next_mark)
+ {
+ sb.append (NTXT ("## "));
+ mindex++;
+ next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1;
+ }
+ else
+ sb.append (NTXT (" "));
+
+ hdata->print_row (&sb, hidx, hist_metric, NTXT (" "));
+ sb.toFile (fp);
+ for (int i = sb.length (); i < mspace; i++)
+ {
+ fputc (' ', fp);
+ }
+ }
+ else
+ // this line does not get any metrics; insert blanks in lieu of them
+ for (int i = 0; i < mspace; i++)
+ fputc (' ', fp);
+
+ switch (item->type)
+ {
+ case Module::AT_SRC_ONLY:
+ if (item->obj == NULL)
+ fprintf (fp, NTXT ("%*s. "), lspace + 1, "?");
+ else
+ fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno);
+ break;
+
+ case Module::AT_SRC:
+ fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno);
+ break;
+ case Module::AT_FUNC:
+ case Module::AT_QUOTE:
+ fprintf (fp, NTXT ("%*c"), lspace + 3, ' ');
+ break;
+ case Module::AT_DIS:
+ case Module::AT_DIS_ONLY:
+ if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
+ fprintf (fp, "%*c[%*s] ", lspace + 3, ' ', lspace, "?");
+ else
+ fprintf (fp, "%*c[%*d] ", lspace + 3, ' ', lspace,
+ ((DbeInstr*) item->obj)->lineno);
+ break;
+ case Module::AT_COM:
+ case Module::AT_EMPTY:
+ break;
+
+ }
+ if (item->value[lind].l == NULL)
+ item->value[lind].l = dbe_strdup (GTXT ("INTERNAL ERROR: missing line text"));
+ fprintf (fp, NTXT ("%s\n"), item->value[lind].l);
+ }
+ delete[] fmt_int;
+ delete[] fmt_real0;
+ delete[] fmt_real1;
+ delete hdata;
+}
+
+void
+er_print_histogram::dump_annotated ()
+{
+ Vector<int> *marks = new Vector<int>;
+ Function *anno_func = (Function *) sel_obj;
+ Module *module = anno_func ? anno_func->module : NULL;
+
+ if (hist_data->type == Histable::DOBJECT)
+ dump_annotated_dataobjects (marks, number_entries); // threshold
+ else if (number_entries == 0)
+ // Annotated source
+ dump_anno_file (out_file, Histable::LINE, module, dbev, mlist,
+ hist_data->get_totals ()->value, NULL, anno_func, marks,
+ dbev->get_thresh_src (), dbev->get_src_compcom (),
+ dbev->get_src_visible (), dbev->get_hex_visible (), true);
+ else
+ // Annotated disassembly
+ dump_anno_file (out_file, Histable::INSTR, module, dbev, mlist,
+ hist_data->get_totals ()->value, NULL, anno_func, marks,
+ dbev->get_thresh_dis (), dbev->get_dis_compcom (),
+ dbev->get_src_visible (), dbev->get_hex_visible (), true);
+}
+
+void
+er_print_histogram::data_dump ()
+{
+ int limit;
+ if (hist_data->get_status () == Hist_data::SUCCESS)
+ {
+ if (sort_metric[0] == '\n')
+ { // csingle Callers-Callees entry
+ sort_metric++;
+ fprintf (out_file, NTXT ("%s\n\n"), sort_metric);
+ }
+ else if (!sel_obj && type != MODE_LIST)
+ {
+ if (hist_data->type == Histable::FUNCTION)
+ fprintf (out_file,
+ GTXT ("Functions sorted by metric: %s\n\n"), sort_metric);
+ else if (hist_data->type == Histable::DOBJECT)
+ fprintf (out_file, GTXT ("Dataobjects sorted by metric: %s\n\n"),
+ sort_metric);
+ else
+ fprintf (out_file,
+ GTXT ("Objects sorted by metric: %s\n\n"), sort_metric);
+ }
+ limit = hist_data->size ();
+ if ((number_entries > 0) && (number_entries < limit))
+ limit = number_entries;
+
+ switch (type)
+ {
+ case MODE_LIST:
+ dump_list (limit);
+ break;
+ case MODE_DETAIL:
+ dump_detail (limit);
+ break;
+ case MODE_GPROF:
+ dump_gprof (limit);
+ break;
+ case MODE_ANNOTATED:
+ dump_annotated ();
+ break;
+ }
+ }
+ else
+ fprintf (out_file, GTXT ("Get_Hist_data call failed %d\n"),
+ (int) hist_data->get_status ());
+}
+
+/*
+ * Class er_print_ctree to print functions call tree
+ */
+er_print_ctree::er_print_ctree (DbeView *_dbev, Vector<Histable*> *_cstack,
+ Histable *_sobj, int _limit)
+{
+ dbev = _dbev;
+ cstack = _cstack;
+ sobj = _sobj;
+ limit = _limit;
+ print_row = 0;
+ exp_idx1 = 0;
+ exp_idx2 = dbeSession->nexps () - 1;
+ load = false;
+ header = false;
+}
+
+void
+er_print_ctree::data_dump ()
+{
+ StringBuilder sb;
+ Hist_data::HistItem *total;
+ sb.append (GTXT ("Functions Call Tree. Metric: "));
+ char *s = dbev->getSort (MET_CALL_AGR);
+ sb.append (s);
+ free (s);
+ sb.toFileLn (out_file);
+ fprintf (out_file, NTXT ("\n"));
+ mlist = dbev->get_metric_list (MET_CALL_AGR);
+
+ // Change cstack: add sobj to the end of cstack
+ cstack->append (sobj);
+ Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::SELF, cstack);
+ Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLERS, cstack);
+ Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLEES, cstack);
+
+ // Restore cstack
+ int last = cstack->size () - 1;
+ cstack->remove (last);
+
+ // Prepare formats
+ int no_metrics = mlist->size ();
+
+ // calculate max. width using data from callers, callees, center
+ hist_metric = allocateHistMetric (no_metrics);
+ callers->update_max (hist_metric);
+ callees->update_max (hist_metric);
+ center->update_max (hist_metric);
+ callers->update_legend_width (hist_metric);
+ callers->print_label (out_file, hist_metric, 0); // returns Name column offset
+
+ print_row = 0;
+ // Pass real total to print_children()
+ total = center->get_totals ();
+ print_children (center, 0, sobj, NTXT (" "), total);
+
+ // Free memory
+ cstack->reset ();
+ delete callers;
+ delete callees;
+ delete center;
+ delete[] hist_metric;
+}
+
+/*
+ * Recursive method print_children prints Call Tree elements.
+ */
+void
+er_print_ctree::print_children (Hist_data *data, int index, Histable *my_obj,
+ char * prefix, Hist_data::HistItem *total)
+{
+ StringBuilder buf;
+ const char *P0 = "+-";
+ const char *P2 = " |";
+ const char *P1 = " ";
+
+ // If limit exceeded - return
+ ++print_row;
+ if (limit > 0 && print_row > limit)
+ return;
+
+ if (my_obj == NULL)
+ return; // should never happen
+
+ // Prepare prefix
+ buf.append (prefix);
+ if (buf.endsWith (P2))
+ {
+ int len = buf.length () - 1;
+ buf.setLength (len);
+ }
+ buf.append (P0);
+
+ // Change cstack: add my_obj to the end of cstack
+ cstack->append (my_obj);
+
+ // Print current node info
+ char * my_prefix = buf.toString ();
+
+ // Replace parent's total values with real total values
+ data->update_total (total); // Needed to to calculate percentage only
+ buf.setLength (0);
+ data->print_row (&buf, index, hist_metric, my_prefix);
+ buf.toFileLn (out_file);
+ free (my_prefix);
+
+ // Get children
+ Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLEES, cstack);
+ int nc = callees->size ();
+ if (nc > 0)
+ {
+ // Print children
+ Hist_data::HistItem *item;
+ Histable *ch_obj;
+ char *ch_prefix;
+ buf.setLength (0);
+ buf.append (prefix);
+ buf.append (P2);
+ ch_prefix = buf.toString ();
+ for (int i = 0; i < nc - 1; i++)
+ {
+ item = callees->fetch (i);
+ ch_obj = item->obj;
+ print_children (callees, i, ch_obj, ch_prefix, total);
+ }
+ free (ch_prefix);
+ buf.setLength (0);
+ buf.append (prefix);
+ buf.append (P1);
+ ch_prefix = buf.toString ();
+ item = callees->fetch (nc - 1);
+ ch_obj = item->obj;
+ print_children (callees, nc - 1, ch_obj, ch_prefix, total);
+ free (ch_prefix);
+ }
+
+ // Restore cstack
+ int last = cstack->size () - 1;
+ cstack->remove (last);
+ delete callees;
+ return;
+}
+
+er_print_gprof::er_print_gprof (DbeView *_dbev, Vector<Histable*> *_cstack)
+{
+ dbev = _dbev;
+ cstack = _cstack;
+ exp_idx1 = 0;
+ exp_idx2 = dbeSession->nexps () - 1;
+ load = false;
+ header = false;
+}
+
+void
+er_print_gprof::data_dump ()
+{
+ StringBuilder sb;
+ sb.append (GTXT ("Callers and callees sorted by metric: "));
+ char *s = dbev->getSort (MET_CALL);
+ sb.append (s);
+ free (s);
+ sb.toFileLn (out_file);
+ fprintf (out_file, NTXT ("\n"));
+
+ MetricList *mlist = dbev->get_metric_list (MET_CALL);
+ Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::SELF, cstack);
+ Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLERS, cstack);
+ Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+ Hist_data::CALLEES, cstack);
+
+ mlist = center->get_metric_list ();
+ int no_metrics = mlist->get_items ()->size ();
+
+ // update max. width for callers/callees/center function item
+ Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics);
+ callers->update_max (hist_metric);
+ callees->update_max (hist_metric);
+ center->update_max (hist_metric);
+
+ callers->update_legend_width (hist_metric);
+ int name_offset = callers->print_label (out_file, hist_metric, 0); // returns Name column offset
+ // Print Callers
+ sb.setLength (0);
+ for (int i = 0; i < name_offset; i++)
+ sb.append (NTXT ("="));
+ if (name_offset > 0)
+ sb.append (NTXT (" "));
+ char *line1 = sb.toString ();
+ char *line2;
+ if (callers->size () > 0)
+ line2 = GTXT ("Callers");
+ else
+ line2 = GTXT ("No Callers");
+ fprintf (out_file, NTXT ("%s%s\n"), line1, line2);
+ callers->print_content (out_file, hist_metric, callers->size ());
+
+ // Print Stack Fragment
+ line2 = GTXT ("Stack Fragment");
+ fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2);
+
+ for (long i = 0, last = cstack->size () - 1; i <= last; ++i)
+ {
+ sb.setLength (0);
+ if (i == last && center->size () > 0)
+ {
+ center->update_total (callers->get_totals ()); // Needed to to calculate percentage only
+ center->print_row (&sb, center->size () - 1, hist_metric, NTXT (" "));
+ }
+ else
+ {
+ for (int n = name_offset; n > 0; n--)
+ sb.append (NTXT (" "));
+ if (name_offset > 0)
+ sb.append (NTXT (" "));
+ sb.append (cstack->get (i)->get_name ());
+ }
+ sb.toFileLn (out_file);
+ }
+
+ // Print Callees
+ if (callees->size () > 0)
+ line2 = GTXT ("Callees");
+ else
+ line2 = GTXT ("No Callees");
+ fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2);
+ callees->print_content (out_file, hist_metric, callees->size ());
+ fprintf (out_file, nl);
+ free (line1);
+ delete callers;
+ delete callees;
+ delete center;
+ delete[] hist_metric;
+}
+
+er_print_leaklist::er_print_leaklist (DbeView *_dbev, bool show_leak,
+ bool show_alloca, int _limit)
+{
+ dbev = _dbev;
+ leak = show_leak;
+ alloca = show_alloca;
+ limit = _limit;
+}
+
+// Output routine for leak list only
+void
+er_print_leaklist::data_dump ()
+{
+ CStack_data *lam;
+ CStack_data::CStack_item *lae;
+ int index;
+ if (!dbeSession->is_leaklist_available ())
+ fprintf (out_file, GTXT ("No leak or allocation information recorded in experiments\n\n"));
+
+ MetricList *origmlist = dbev->get_metric_list (MET_NORMAL);
+ if (leak)
+ {
+ // make a copy of the metric list, and set metrics for leaks
+ MetricList *nmlist = new MetricList (origmlist);
+ nmlist->set_metrics ("e.heapleakbytes:e.heapleakcnt:name", true,
+ dbev->get_derived_metrics ());
+
+ // now make a compacted version of it to get the right indices
+ MetricList *mlist = new MetricList (nmlist);
+ delete nmlist;
+
+ // fetch the callstack data
+ lam = dbev->get_cstack_data (mlist);
+
+ // now print it
+ if (lam && lam->size () != 0)
+ {
+ fprintf (out_file, GTXT ("Summary Results: Distinct Leaks = %d, Total Instances = %lld, Total Bytes Leaked = %lld\n\n"),
+ (int) lam->size (), lam->total->value[1].ll,
+ lam->total->value[0].ll);
+
+ Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
+ {
+ fprintf (out_file,
+ GTXT ("Leak #%d, Instances = %lld, Bytes Leaked = %lld\n"),
+ index + 1, lae->value[1].ll, lae->value[0].ll);
+ if (lae->stack != NULL)
+ for (int i = lae->stack->size () - 1; i >= 0; i--)
+ {
+ DbeInstr *instr = lae->stack->fetch (i);
+ fprintf (out_file, NTXT (" %s\n"), instr->get_name ());
+ }
+ fprintf (out_file, NTXT ("\n"));
+ if (index + 1 == limit) break;
+ }
+ }
+ else
+ fprintf (out_file, GTXT ("No leak information\n\n"));
+ delete lam;
+ delete mlist;
+ }
+
+ if (alloca)
+ {
+ // make a copy of the metric list, and set metrics for leaks
+ MetricList *nmlist = new MetricList (origmlist);
+ nmlist->set_metrics ("e.heapallocbytes:e.heapalloccnt:name",
+ true, dbev->get_derived_metrics ());
+
+ // now make a compacted version of it to get the right indices
+ MetricList *mlist = new MetricList (nmlist);
+ delete nmlist;
+
+ // fetch the callstack data
+ lam = dbev->get_cstack_data (mlist);
+
+ // now print it
+ if (lam && lam->size () != 0)
+ {
+ fprintf (out_file, GTXT ("Summary Results: Distinct Allocations = %d, Total Instances = %lld, Total Bytes Allocated = %lld\n\n"),
+ (int) lam->size (), lam->total->value[1].ll,
+ lam->total->value[0].ll);
+ Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
+ {
+ fprintf (out_file, GTXT ("Allocation #%d, Instances = %lld, Bytes Allocated = %lld\n"),
+ index + 1, lae->value[1].ll, lae->value[0].ll);
+ if (lae->stack != NULL)
+ for (int i = lae->stack->size () - 1; i >= 0; i--)
+ {
+ DbeInstr *instr = lae->stack->fetch (i);
+ fprintf (out_file, NTXT (" %s\n"), instr->get_name ());
+ }
+ fprintf (out_file, NTXT ("\n"));
+ if (index + 1 == limit) break;
+ }
+ }
+ else
+ fprintf (out_file, GTXT ("No allocation information\n\n"));
+ delete lam;
+ delete mlist;
+ }
+}
+
+er_print_heapactivity::er_print_heapactivity (DbeView *_dbev,
+ Histable::Type _type,
+ bool _printStat, int _limit)
+{
+ dbev = _dbev;
+ type = _type;
+ printStat = _printStat;
+ limit = _limit;
+}
+
+void
+er_print_heapactivity::printCallStacks (Hist_data *hist_data)
+{
+ Hist_data::HistItem *hi;
+ HeapData *hData;
+ long stackId;
+ int size = hist_data->size ();
+ if (limit > 0 && limit < size)
+ size = limit;
+
+ Histable::NameFormat fmt = dbev->get_name_format ();
+ for (int i = 0; i < size; i++)
+ {
+ hi = hist_data->fetch (i);
+ hData = (HeapData*) hi->obj;
+ stackId = hData->id;
+ if (i != 0)
+ fprintf (out_file, NTXT ("\n"));
+
+ fprintf (out_file, NTXT ("%s\n"), hData->get_name (fmt));
+ if (hData->getAllocCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("Instances = %d "),
+ (int) (hData->getAllocCnt ()));
+ fprintf (out_file, GTXT ("Bytes Allocated = %lld\n"),
+ (long long) hData->getAllocBytes ());
+ }
+
+ if (hData->getLeakCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("Instances = %d "),
+ (int) (hData->getLeakCnt ()));
+ fprintf (out_file, GTXT ("Bytes Leaked = %lld\n"),
+ (long long) hData->getLeakBytes ());
+ }
+
+ // There is no stack trace for <Total>
+ if (i == 0)
+ continue;
+
+ // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack
+ Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId);
+ if (instrs != NULL)
+ {
+ int stSize = instrs->size ();
+ for (int j = 0; j < stSize; j++)
+ {
+ Histable *instr = instrs->fetch (j);
+ if (instr != NULL)
+ fprintf (out_file, NTXT (" %s\n"), instr->get_name ());
+ }
+ delete instrs;
+ }
+ }
+}
+
+void
+er_print_heapactivity::printStatistics (Hist_data *hist_data)
+{
+ Hist_data::HistItem *hi;
+ HeapData *hDataTotal;
+ hi = hist_data->fetch (0);
+ hDataTotal = (HeapData*) hi->obj;
+ Vector<hrtime_t> *pTimestamps;
+ if (hDataTotal->getPeakMemUsage () > 0)
+ {
+ fprintf (out_file, GTXT ("\nProcess With Highest Peak Memory Usage\n"));
+ fprintf (out_file,
+ "-------------------------------------------------------\n");
+ fprintf (out_file, GTXT ("Heap size bytes %lld\n"),
+ (long long) hDataTotal->getPeakMemUsage ());
+ fprintf (out_file, GTXT ("Experiment Id %d\n"),
+ (int) (hDataTotal->getUserExpId ()));
+ fprintf (out_file, GTXT ("Process Id %d\n"),
+ (int) (hDataTotal->getPid ()));
+ pTimestamps = hDataTotal->getPeakTimestamps ();
+ if (pTimestamps != NULL)
+ for (int i = 0; i < pTimestamps->size (); i++)
+ fprintf (out_file,
+ GTXT ("Time of peak %.3f (secs.)\n"),
+ (double) (pTimestamps->fetch (i) / (double) NANOSEC));
+ }
+
+ if (hDataTotal->getAllocCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("\nMemory Allocations Statistics\n"));
+ fprintf (out_file,
+ GTXT ("Allocation Size Range Allocations \n"));
+ fprintf (out_file,
+ "-------------------------------------------------------\n");
+ if (hDataTotal->getA0KB1KBCnt () > 0)
+ fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
+ hDataTotal->getA0KB1KBCnt ());
+ if (hDataTotal->getA1KB8KBCnt () > 0)
+ fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
+ hDataTotal->getA1KB8KBCnt ());
+ if (hDataTotal->getA8KB32KBCnt () > 0)
+ fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
+ hDataTotal->getA8KB32KBCnt ());
+ if (hDataTotal->getA32KB128KBCnt () > 0)
+ fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
+ hDataTotal->getA32KB128KBCnt ());
+ if (hDataTotal->getA128KB256KBCnt () > 0)
+ fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
+ hDataTotal->getA128KB256KBCnt ());
+ if (hDataTotal->getA256KB512KBCnt () > 0)
+ fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
+ hDataTotal->getA256KB512KBCnt ());
+ if (hDataTotal->getA512KB1000KBCnt () > 0)
+ fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
+ hDataTotal->getA512KB1000KBCnt ());
+ if (hDataTotal->getA1000KB10MBCnt () > 0)
+ fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
+ hDataTotal->getA1000KB10MBCnt ());
+ if (hDataTotal->getA10MB100MBCnt () > 0)
+ fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
+ hDataTotal->getA10MB100MBCnt ());
+ if (hDataTotal->getA100MB1GBCnt () > 0)
+ fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
+ hDataTotal->getA100MB1GBCnt ());
+ if (hDataTotal->getA1GB10GBCnt () > 0)
+ fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
+ hDataTotal->getA1GB10GBCnt ());
+ if (hDataTotal->getA10GB100GBCnt () > 0)
+ fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
+ hDataTotal->getA10GB100GBCnt ());
+ if (hDataTotal->getA100GB1TBCnt () > 0)
+ fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
+ hDataTotal->getA100GB1TBCnt ());
+ if (hDataTotal->getA1TB10TBCnt () > 0)
+ fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
+ hDataTotal->getA1TB10TBCnt ());
+ fprintf (out_file, GTXT ("\nSmallest allocation bytes %lld\n"),
+ (long long) hDataTotal->getASmallestBytes ());
+ fprintf (out_file, GTXT ("Largest allocation bytes %lld\n"),
+ (long long) hDataTotal->getALargestBytes ());
+ fprintf (out_file, GTXT ("Total allocations %d\n"),
+ hDataTotal->getAllocCnt ());
+ fprintf (out_file, GTXT ("Total bytes %lld\n"),
+ (long long) hDataTotal->getAllocBytes ());
+ }
+
+ if (hDataTotal->getLeakCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("\nMemory Leaks Statistics\n"));
+ fprintf (out_file,
+ GTXT ("Leak Size Range Leaks \n"));
+ fprintf (out_file,
+ "-------------------------------------------------------\n");
+ if (hDataTotal->getL0KB1KBCnt () > 0)
+ fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
+ hDataTotal->getL0KB1KBCnt ());
+ if (hDataTotal->getL1KB8KBCnt () > 0)
+ fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
+ hDataTotal->getL1KB8KBCnt ());
+ if (hDataTotal->getL8KB32KBCnt () > 0)
+ fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
+ hDataTotal->getL8KB32KBCnt ());
+ if (hDataTotal->getL32KB128KBCnt () > 0)
+ fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
+ hDataTotal->getL32KB128KBCnt ());
+ if (hDataTotal->getL128KB256KBCnt () > 0)
+ fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
+ hDataTotal->getL128KB256KBCnt ());
+ if (hDataTotal->getL256KB512KBCnt () > 0)
+ fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
+ hDataTotal->getL256KB512KBCnt ());
+ if (hDataTotal->getL512KB1000KBCnt () > 0)
+ fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
+ hDataTotal->getL512KB1000KBCnt ());
+ if (hDataTotal->getL1000KB10MBCnt () > 0)
+ fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
+ hDataTotal->getL1000KB10MBCnt ());
+ if (hDataTotal->getL10MB100MBCnt () > 0)
+ fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
+ hDataTotal->getL10MB100MBCnt ());
+ if (hDataTotal->getL100MB1GBCnt () > 0)
+ fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
+ hDataTotal->getL100MB1GBCnt ());
+ if (hDataTotal->getL1GB10GBCnt () > 0)
+ fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
+ hDataTotal->getL1GB10GBCnt ());
+ if (hDataTotal->getL10GB100GBCnt () > 0)
+ fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
+ hDataTotal->getL10GB100GBCnt ());
+ if (hDataTotal->getL100GB1TBCnt () > 0)
+ fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
+ hDataTotal->getL100GB1TBCnt ());
+ if (hDataTotal->getL1TB10TBCnt () > 0)
+ fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
+ hDataTotal->getL1TB10TBCnt ());
+ fprintf (out_file, GTXT ("\nSmallest leaked bytes %lld\n"),
+ (long long) hDataTotal->getLSmallestBytes ());
+ fprintf (out_file, GTXT ("Largest leaked bytes %lld\n"),
+ (long long) hDataTotal->getLLargestBytes ());
+ fprintf (out_file, GTXT ("Total leaked %d \n"),
+ hDataTotal->getLeakCnt ());
+ fprintf (out_file, GTXT ("Total bytes %lld\n"),
+ (long long) hDataTotal->getLeakBytes ());
+ }
+ fprintf (out_file, NTXT ("\n"));
+}
+
+void
+er_print_heapactivity::data_dump ()
+{
+ // get the list of heap events from DbeView
+ int numExps = dbeSession->nexps ();
+ if (!numExps)
+ {
+ fprintf (out_file,
+ GTXT ("There is no heap event information in the experiments\n"));
+ return;
+ }
+ MetricList *mlist = dbev->get_metric_list (MET_HEAP);
+ Hist_data *hist_data;
+ hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL);
+ if (printStat)
+ printStatistics (hist_data);
+ else
+ printCallStacks (hist_data);
+}
+
+er_print_ioactivity::er_print_ioactivity (DbeView *_dbev, Histable::Type _type,
+ bool _printStat, int _limit)
+{
+ dbev = _dbev;
+ type = _type;
+ printStat = _printStat;
+ limit = _limit;
+}
+
+void
+er_print_ioactivity::printCallStacks (Hist_data *hist_data)
+{
+ Hist_data::HistItem *hi;
+ FileData *fData;
+ long stackId;
+ int size = hist_data->size ();
+ if (limit > 0 && limit < size)
+ size = limit;
+
+ for (int i = 0; i < size; i++)
+ {
+ hi = hist_data->fetch (i);
+ fData = (FileData*) hi->obj;
+ stackId = fData->id;
+ if (i != 0)
+ fprintf (out_file, NTXT ("\n"));
+ fprintf (out_file, NTXT ("%s\n"), fData->getFileName ());
+ if (fData->getWriteCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("Write Time=%.6f (secs.) "),
+ (double) (fData->getWriteTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Write Bytes=%lld "),
+ (long long) fData->getWriteBytes ());
+ fprintf (out_file, GTXT ("Write Count=%d\n"),
+ (int) (fData->getWriteCnt ()));
+ }
+ if (fData->getReadCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("Read Time=%.6f (secs.) "),
+ (double) (fData->getReadTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Read Bytes=%lld "),
+ (long long) fData->getReadBytes ());
+ fprintf (out_file, GTXT ("Read Count=%d\n"),
+ (int) fData->getReadCnt ());
+ }
+ if (fData->getOtherCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("Other I/O Time=%.6f (secs.) "),
+ (double) (fData->getOtherTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Other I/O Count=%d\n"),
+ (int) (fData->getOtherCnt ()));
+ }
+ if (fData->getErrorCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("I/O Error Time=%.6f (secs.) "),
+ (double) (fData->getErrorTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("I/O Error Count=%d\n"),
+ (int) (fData->getErrorCnt ()));
+ }
+
+ // There is no stack trace for <Total>
+ if (i == 0)
+ continue;
+
+ // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack
+ Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId);
+ if (instrs != NULL)
+ {
+ int stSize = instrs->size ();
+ for (int j = 0; j < stSize; j++)
+ {
+ Histable *instr = instrs->fetch (j);
+ if (instr != NULL)
+ fprintf (out_file, " %s\n", instr->get_name ());
+ }
+ delete instrs;
+ }
+ }
+}
+
+void
+er_print_ioactivity::printStatistics (Hist_data *hist_data)
+{
+ Hist_data::HistItem *hi;
+ FileData *fDataTotal;
+
+ hi = hist_data->fetch (0);
+ fDataTotal = (FileData*) hi->obj;
+
+ if (fDataTotal->getWriteCnt () > 0)
+ {
+ fprintf (out_file,
+ GTXT ("\nWrite Statistics\n"));
+ fprintf (out_file,
+ GTXT ("I/O Size Range Write Calls \n"));
+ fprintf (out_file,
+ "-------------------------------------------------------\n");
+ if (fDataTotal->getW0KB1KBCnt () > 0)
+ fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
+ fDataTotal->getW0KB1KBCnt ());
+ if (fDataTotal->getW1KB8KBCnt () > 0)
+ fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
+ fDataTotal->getW1KB8KBCnt ());
+ if (fDataTotal->getW8KB32KBCnt () > 0)
+ fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
+ fDataTotal->getW8KB32KBCnt ());
+ if (fDataTotal->getW32KB128KBCnt () > 0)
+ fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
+ fDataTotal->getW32KB128KBCnt ());
+ if (fDataTotal->getW128KB256KBCnt () > 0)
+ fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
+ fDataTotal->getW128KB256KBCnt ());
+ if (fDataTotal->getW256KB512KBCnt () > 0)
+ fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
+ fDataTotal->getW256KB512KBCnt ());
+ if (fDataTotal->getW512KB1000KBCnt () > 0)
+ fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
+ fDataTotal->getW512KB1000KBCnt ());
+ if (fDataTotal->getW1000KB10MBCnt () > 0)
+ fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
+ fDataTotal->getW1000KB10MBCnt ());
+ if (fDataTotal->getW10MB100MBCnt () > 0)
+ fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
+ fDataTotal->getW10MB100MBCnt ());
+ if (fDataTotal->getW100MB1GBCnt () > 0)
+ fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
+ fDataTotal->getW100MB1GBCnt ());
+ if (fDataTotal->getW1GB10GBCnt () > 0)
+ fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
+ fDataTotal->getW1GB10GBCnt ());
+ if (fDataTotal->getW10GB100GBCnt () > 0)
+ fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
+ fDataTotal->getW10GB100GBCnt ());
+ if (fDataTotal->getW100GB1TBCnt () > 0)
+ fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
+ fDataTotal->getW100GB1TBCnt ());
+ if (fDataTotal->getW1TB10TBCnt () > 0)
+ fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
+ fDataTotal->getW1TB10TBCnt ());
+ fprintf (out_file,
+ GTXT ("\nLongest write %.6f (secs.)\n"),
+ (double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Smallest write bytes %lld\n"),
+ (long long) fDataTotal->getWSmallestBytes ());
+ fprintf (out_file, GTXT ("Largest write bytes %lld\n"),
+ (long long) fDataTotal->getWLargestBytes ());
+ fprintf (out_file,
+ GTXT ("Total time %.6f (secs.)\n"),
+ (double) (fDataTotal->getWriteTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Total calls %d\n"),
+ fDataTotal->getWriteCnt ());
+ fprintf (out_file, GTXT ("Total bytes %lld\n"),
+ (long long) fDataTotal->getWriteBytes ());
+ }
+
+ if (fDataTotal->getReadCnt () > 0)
+ {
+ fprintf (out_file,
+ GTXT ("\nRead Statistics\n"));
+ fprintf (out_file,
+ GTXT ("I/O Size Range Read Calls \n"));
+ fprintf (out_file,
+ "------------------------------------------------------\n");
+ if (fDataTotal->getR0KB1KBCnt () > 0)
+ fprintf (out_file, NTXT (" 0KB - 1KB %d\n"),
+ fDataTotal->getR0KB1KBCnt ());
+ if (fDataTotal->getR1KB8KBCnt () > 0)
+ fprintf (out_file, NTXT (" 1KB - 8KB %d\n"),
+ fDataTotal->getR1KB8KBCnt ());
+ if (fDataTotal->getR8KB32KBCnt () > 0)
+ fprintf (out_file, NTXT (" 8KB - 32KB %d\n"),
+ fDataTotal->getR8KB32KBCnt ());
+ if (fDataTotal->getR32KB128KBCnt () > 0)
+ fprintf (out_file, NTXT (" 32KB - 128KB %d\n"),
+ fDataTotal->getR32KB128KBCnt ());
+ if (fDataTotal->getR128KB256KBCnt () > 0)
+ fprintf (out_file, NTXT (" 128KB - 256KB %d\n"),
+ fDataTotal->getR128KB256KBCnt ());
+ if (fDataTotal->getR256KB512KBCnt () > 0)
+ fprintf (out_file, NTXT (" 256KB - 512KB %d\n"),
+ fDataTotal->getR256KB512KBCnt ());
+ if (fDataTotal->getR512KB1000KBCnt () > 0)
+ fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"),
+ fDataTotal->getR512KB1000KBCnt ());
+ if (fDataTotal->getR1000KB10MBCnt () > 0)
+ fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"),
+ fDataTotal->getR1000KB10MBCnt ());
+ if (fDataTotal->getR10MB100MBCnt () > 0)
+ fprintf (out_file, NTXT (" 10MB - 100MB %d\n"),
+ fDataTotal->getR10MB100MBCnt ());
+ if (fDataTotal->getR100MB1GBCnt () > 0)
+ fprintf (out_file, NTXT (" 100MB - 1GB %d\n"),
+ fDataTotal->getR100MB1GBCnt ());
+ if (fDataTotal->getR1GB10GBCnt () > 0)
+ fprintf (out_file, NTXT (" 1GB - 10GB %d\n"),
+ fDataTotal->getR1GB10GBCnt ());
+ if (fDataTotal->getR10GB100GBCnt () > 0)
+ fprintf (out_file, NTXT (" 10GB - 100GB %d\n"),
+ fDataTotal->getR10GB100GBCnt ());
+ if (fDataTotal->getR100GB1TBCnt () > 0)
+ fprintf (out_file, NTXT (" 100GB - 1TB %d\n"),
+ fDataTotal->getR100GB1TBCnt ());
+ if (fDataTotal->getR1TB10TBCnt () > 0)
+ fprintf (out_file, NTXT (" 1TB - 10TB %d\n"),
+ fDataTotal->getR1TB10TBCnt ());
+ fprintf (out_file,
+ GTXT ("\nLongest time %.6f (secs.)\n"),
+ (double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Smallest read bytes %lld\n"),
+ (long long) fDataTotal->getRSmallestBytes ());
+ fprintf (out_file, GTXT ("Largest read bytes %lld\n"),
+ (long long) fDataTotal->getRLargestBytes ());
+ fprintf (out_file,
+ GTXT ("Total time %.6f (secs.)\n"),
+ (double) (fDataTotal->getReadTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Total calls %d\n"),
+ fDataTotal->getReadCnt ());
+ fprintf (out_file, GTXT ("Total bytes %lld\n"),
+ (long long) fDataTotal->getReadBytes ());
+ }
+
+ if (fDataTotal->getOtherCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("\nOther I/O Statistics\n"));
+ fprintf (out_file,
+ "-----------------------------------------------------\n");
+ fprintf (out_file,
+ GTXT ("Total time %.6f (secs.)\n"),
+ (double) (fDataTotal->getOtherTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Total calls %d \n"),
+ fDataTotal->getOtherCnt ());
+ }
+ if (fDataTotal->getErrorCnt () > 0)
+ {
+ fprintf (out_file, GTXT ("\nI/O Error Statistics\n"));
+ fprintf (out_file,
+ "-----------------------------------------------------\n");
+ fprintf (out_file,
+ GTXT ("Total time %.6f (secs.)\n"),
+ (double) (fDataTotal->getErrorTime () / (double) NANOSEC));
+ fprintf (out_file, GTXT ("Total calls %d \n"),
+ fDataTotal->getErrorCnt ());
+ }
+ fprintf (out_file, NTXT ("\n"));
+}
+
+void
+er_print_ioactivity::data_dump ()
+{
+ // get the list of io events from DbeView
+ int numExps = dbeSession->nexps ();
+ if (!numExps)
+ {
+ fprintf (out_file,
+ GTXT ("There is no IO event information in the experiments\n"));
+ return;
+ }
+
+ MetricList *mlist = dbev->get_metric_list (MET_IO);
+ Hist_data *hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL);
+ if (type == Histable::IOCALLSTACK)
+ printCallStacks (hist_data);
+ else if (printStat)
+ printStatistics (hist_data);
+ else
+ {
+ Metric::HistMetric *hist_metric = hist_data->get_histmetrics ();
+ hist_data->print_label (out_file, hist_metric, 0);
+ hist_data->print_content (out_file, hist_metric, limit);
+ fprintf (out_file, nl);
+ }
+}
+
+er_print_experiment::er_print_experiment (DbeView *_dbev, int bgn_idx,
+ int end_idx, bool show_load,
+ bool show_header, bool show_stat,
+ bool show_over, bool show_odetail)
+{
+ dbev = _dbev;
+ exp_idx1 = bgn_idx;
+ exp_idx2 = end_idx;
+ load = show_load;
+ header = show_header;
+ stat = show_stat;
+ over = show_over;
+ odetail = show_odetail;
+}
+
+void
+er_print_experiment::data_dump ()
+{
+ int index, maxlen;
+
+ maxlen = 0;
+
+ if (stat)
+ {
+ snprintf (fmt1, sizeof (fmt1), NTXT ("%%50s"));
+ if (exp_idx2 > exp_idx1)
+ {
+ statistics_sum (maxlen);
+ fprintf (out_file, nl);
+ }
+
+ for (index = exp_idx1; index <= exp_idx2; index++)
+ statistics_dump (index, maxlen);
+ }
+ else if (over)
+ {
+ snprintf (fmt1, sizeof (fmt1), NTXT ("%%30s"));
+ if (exp_idx2 > exp_idx1)
+ {
+ overview_sum (maxlen);
+ fprintf (out_file, nl);
+ }
+
+ for (index = exp_idx1; index <= exp_idx2; index++)
+ overview_dump (index, maxlen);
+ }
+ else if (header)
+ for (index = exp_idx1; index <= exp_idx2; index++)
+ {
+ if (index != exp_idx1)
+ fprintf (out_file,
+ "----------------------------------------------------------------\n");
+ header_dump (index);
+ }
+}
+
+void
+er_print_experiment::overview_sum (int &maxlen)
+{
+ int index;
+ Ovw_data *sum_data = new Ovw_data ();
+ for (index = exp_idx1; index <= exp_idx2; index++)
+ {
+ Ovw_data *ovw_data = dbev->get_ovw_data (index);
+ if (ovw_data == NULL)
+ continue;
+ sum_data->sum (ovw_data);
+ delete ovw_data;
+ }
+
+ fprintf (out_file, GTXT ("<Sum across selected experiments>"));
+ fprintf (out_file, nl);
+ overview_summary (sum_data, maxlen);
+ fprintf (out_file, nl);
+ delete sum_data;
+}
+
+void
+er_print_experiment::overview_dump (int exp_idx, int &maxlen)
+{
+ Ovw_data *ovw_data;
+ Ovw_data::Ovw_item ovw_item_labels;
+ Ovw_data::Ovw_item ovw_item;
+ int index;
+ int size;
+
+ ovw_data = dbev->get_ovw_data (exp_idx);
+ if (ovw_data == NULL)
+ return;
+ if (pr_params.header)
+ header_dump (exp_idx);
+ else if (odetail)
+ fprintf (out_file, GTXT ("Experiment: %s\n"),
+ dbeSession->get_exp (exp_idx)->get_expt_name ());
+
+ overview_summary (ovw_data, maxlen);
+ if (!odetail)
+ {
+ delete ovw_data;
+ return;
+ }
+
+ //Get the collection params for the sample selection and display them.
+ fprintf (out_file, NTXT ("\n\n"));
+ fprintf (out_file, fmt1, GTXT ("Individual samples"));
+ fprintf (out_file, NTXT ("\n\n"));
+
+ size = ovw_data->size ();
+ ovw_item_labels = ovw_data->get_labels ();
+
+ for (index = 0; index < size; index++)
+ {
+ ovw_item = ovw_data->fetch (index);
+ fprintf (out_file, fmt1, GTXT ("Sample Number"));
+ fprintf (out_file, NTXT (": %d\n\n"), ovw_item.number);
+ overview_item (&ovw_item, &ovw_item_labels);
+ fprintf (out_file, nl);
+ }
+
+ delete ovw_data;
+}
+
+void
+er_print_experiment::overview_summary (Ovw_data *ovw_data, int &maxlen)
+{
+ char buf[128];
+ int len;
+ Ovw_data::Ovw_item totals;
+ Ovw_data::Ovw_item ovw_item_labels;
+ totals = ovw_data->get_totals ();
+ len = snprintf (buf, sizeof (buf), "%.3lf", tstodouble (totals.total.t));
+ if (maxlen < len)
+ maxlen = len;
+ snprintf (buf, sizeof (buf), NTXT ("%%#%d.0lf ( %#1.0f %%%%%%%%)"),
+ maxlen - 3, 0.);
+ snprintf (fmt2, sizeof (fmt2), NTXT ("%%%d.3lf"), maxlen);
+ snprintf (fmt3, sizeof (fmt3), buf, 0.0);
+ snprintf (fmt4, sizeof (fmt4), NTXT ("%%%d.3lf (%%5.1f%%%%)"), maxlen);
+ fprintf (out_file, fmt1, GTXT ("Aggregated statistics for selected samples"));
+ fprintf (out_file, NTXT ("\n\n"));
+
+ ovw_item_labels = ovw_data->get_labels ();
+ overview_item (&totals, &ovw_item_labels);
+}
+
+void
+er_print_experiment::overview_item (Ovw_data::Ovw_item *ovw_item,
+ Ovw_data::Ovw_item *ovw_item_labels)
+{
+ double start, end, total_value;
+ int index, size;
+ timestruc_t total_time = {0, 0};
+
+ start = tstodouble (ovw_item->start);
+ end = tstodouble (ovw_item->end);
+
+ fprintf (out_file, fmt1, GTXT ("Start Label"));
+ fprintf (out_file, NTXT (": "));
+ fprintf (out_file, NTXT ("%s"), ovw_item->start_label);
+ fprintf (out_file, nl);
+ fprintf (out_file, fmt1, GTXT ("End Label"));
+ fprintf (out_file, NTXT (": %s\n"), ovw_item->end_label);
+
+ fprintf (out_file, fmt1, GTXT ("Start Time (sec.)"));
+ fprintf (out_file, NTXT (": "));
+ if (start == -1.0)
+ fprintf (out_file, GTXT ("N/A"));
+ else
+ fprintf (out_file, fmt2, start);
+ fprintf (out_file, nl);
+ fprintf (out_file, fmt1, GTXT ("End Time (sec.)"));
+ fprintf (out_file, NTXT (": "));
+ if (end == -1.0)
+ fprintf (out_file, GTXT ("N/A"));
+ else
+ fprintf (out_file, fmt2, end);
+ fprintf (out_file, nl);
+ fprintf (out_file, fmt1, GTXT ("Duration (sec.)"));
+ fprintf (out_file, NTXT (": "));
+ fprintf (out_file, fmt2, tstodouble (ovw_item->duration));
+ fprintf (out_file, NTXT ("\n"));
+
+ size = ovw_item->size;
+ for (index = 0; index < size; index++)
+ tsadd (&total_time, &ovw_item->values[index].t);
+
+ total_value = tstodouble (total_time);
+ fprintf (out_file, fmt1, GTXT ("Total Thread Time (sec.)"));
+ fprintf (out_file, NTXT (": "));
+ fprintf (out_file, fmt2, tstodouble (ovw_item->tlwp));
+ fprintf (out_file, NTXT ("\n"));
+ fprintf (out_file, fmt1, GTXT ("Average number of Threads"));
+ fprintf (out_file, NTXT (": "));
+ if (tstodouble (ovw_item->duration) != 0)
+ fprintf (out_file, fmt2, ovw_item->nlwp);
+ else
+ fprintf (out_file, GTXT ("N/A"));
+ fprintf (out_file, NTXT ("\n\n"));
+ fprintf (out_file, fmt1, GTXT ("Process Times (sec.)"));
+ fprintf (out_file, NTXT (":\n"));
+ for (index = 1; index < size; index++)
+ {
+ overview_value (&ovw_item_labels->values[index], ovw_item_labels->type,
+ total_value);
+ overview_value (&ovw_item->values[index], ovw_item->type,
+ total_value);
+ fprintf (out_file, NTXT ("\n"));
+ }
+}
+
+void
+er_print_experiment::overview_value (Value *value, ValueTag value_tag,
+ double total_value)
+{
+ double dvalue;
+ switch (value_tag)
+ {
+ case VT_LABEL:
+ fprintf (out_file, fmt1, value->l);
+ fprintf (out_file, NTXT (": "));
+ break;
+ case VT_HRTIME:
+ dvalue = tstodouble (value->t);
+ if (dvalue == 0.0)
+ fprintf (out_file, fmt3, 0., 0.);
+ else
+ fprintf (out_file, fmt4, dvalue, 100.0 * dvalue / total_value);
+ break;
+ case VT_INT:
+ fprintf (out_file, NTXT ("%d"), value->i);
+ break;
+ default:
+ fprintf (out_file, fmt3);
+ }
+}
+
+void
+er_print_experiment::statistics_sum (int &maxlen)
+{
+ int index;
+ int size, len;
+ Stats_data *sum_data = new Stats_data ();
+ for (index = exp_idx1; index <= exp_idx2; index++)
+ {
+ Stats_data *stats_data = dbev->get_stats_data (index);
+ if (stats_data == NULL)
+ continue;
+ sum_data->sum (stats_data);
+ delete stats_data;
+ }
+
+ // get the maximum width of values
+ size = sum_data->size ();
+ for (index = 0; index < size; index++)
+ {
+ len = (int) sum_data->fetch (index).value.get_len ();
+ if (maxlen < len)
+ maxlen = len;
+ }
+
+ // print overview average
+ overview_sum (maxlen);
+
+ // print statistics data
+ snprintf (fmt2, sizeof (fmt2), NTXT (": %%%ds\n"), maxlen);
+ statistics_item (sum_data);
+ delete sum_data;
+}
+
+void
+er_print_experiment::statistics_dump (int exp_idx, int &maxlen)
+{
+ Stats_data *stats_data;
+ int index;
+ int size, len;
+ stats_data = dbev->get_stats_data (exp_idx);
+ if (stats_data == NULL)
+ return;
+ if (pr_params.header)
+ {
+ header_dump (exp_idx);
+ fprintf (out_file, nl);
+ }
+ else
+ fprintf (out_file, GTXT ("Experiment: %s\n"),
+ dbeSession->get_exp (exp_idx)->get_expt_name ());
+
+ // get the maximum width of values
+ size = stats_data->size ();
+ for (index = 0; index < size; index++)
+ {
+ len = (int) stats_data->fetch (index).value.get_len ();
+ if (maxlen < len)
+ maxlen = len;
+ }
+
+ // print overview average
+ overview_dump (exp_idx, maxlen);
+ fprintf (out_file, nl);
+
+ // print statistics data
+ snprintf (fmt2, sizeof (fmt2), NTXT (": %%%ds\n"), maxlen);
+ statistics_item (stats_data);
+ delete stats_data;
+}
+
+void
+er_print_experiment::statistics_item (Stats_data *stats_data)
+{
+ int size, index;
+ Stats_data::Stats_item stats_item;
+ char buf[256];
+ size = stats_data->size ();
+ for (index = 0; index < size; index++)
+ {
+ stats_item = stats_data->fetch (index);
+ fprintf (out_file, fmt1, stats_item.label);
+ fprintf (out_file, fmt2, stats_item.value.to_str (buf, sizeof (buf)));
+ }
+ fprintf (out_file, nl);
+}
+
+// Print annotated source or disassembly -- called by er_print only
+void
+print_anno_file (char *name, const char *sel, const char *srcFile,
+ bool isDisasm, FILE *dis_file, FILE *inp_file, FILE *out_file,
+ DbeView *dbev, bool xdefault)
+{
+ Histable *obj;
+ Function *func;
+ Module *module;
+ Vector<int> *marks;
+ Hist_data *hist_data;
+ char *errstr;
+ int index;
+ SourceFile *fitem;
+ int threshold;
+ int compcom_bits;
+ int src_visible;
+ bool hex_visible;
+ bool srcmetrics_visible;
+
+ if ((name == NULL) || (strlen (name) == 0))
+ {
+ fprintf (stderr, GTXT ("Error: No function or file has been specified.\n"));
+ return;
+ }
+
+ // find the function from the name
+ if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel,
+ Histable::FUNCTION, xdefault))
+ return;
+
+ if (obj != NULL)
+ {
+ // source or disassembly for <Total>, <Unknown>, or @plt
+ if (obj->get_type () != Histable::FUNCTION)
+ {
+ fprintf (stderr,
+ GTXT ("Error: %s is not a real function; no source or disassembly available.\n"),
+ name);
+ return;
+ }
+
+ func = (Function *) obj;
+ if (func->flags & FUNC_FLAG_SIMULATED)
+ {
+ fprintf (stderr,
+ GTXT ("Error: %s is not a real function; no source or disassembly available.\n"),
+ name);
+ return;
+ }
+ else if (dbev != NULL && isDisasm)
+ dbev->set_func_scope (true);
+
+ // function found, set module
+ module = func->module;
+ int ix = module->loadobject->seg_idx;
+ if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+ {
+ char *lo_name = module->loadobject->get_name ();
+ fprintf (stderr,
+ GTXT ("Error: No source or disassembly available for hidden object %s.\n"),
+ lo_name);
+ return;
+ }
+
+ if (srcFile)
+ {
+ Vector<SourceFile*> *sources = func->get_sources ();
+ bool found = false;
+ if (sources == NULL)
+ {
+ fitem = func->getDefSrc ();
+ found = (func->line_first > 0)
+ && strcmp (basename (srcFile),
+ basename (fitem->get_name ())) == 0;
+ }
+ else
+ {
+ Vec_loop (SourceFile*, sources, index, fitem)
+ {
+ if (strcmp (basename (srcFile), basename (fitem->get_name ())) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ fprintf (stderr, GTXT ("Error: Source file context %s does not contribute to function `%s'.\n"),
+ srcFile, name);
+ return;
+ }
+ }
+ }
+ else
+ {
+ // function not found
+ if (sel && strrchr (sel, ':'))
+ {
+ // 'sel' was "@seg_num:address" or "file_name:address"
+ fprintf (stderr,
+ GTXT ("Error: No function with given name `%s %s' found.\n"),
+ name, sel);
+ return;
+ }
+ // search for a file of that name
+ if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel,
+ Histable::MODULE, xdefault))
+ return;
+
+ if (obj == NULL)
+ { // neither function nor file found
+ fprintf (stderr, GTXT ("Error: No function or file with given name `%s' found.\n"),
+ name);
+ return;
+ }
+
+ func = NULL;
+ module = (Module *) obj;
+ int ix = module->loadobject->seg_idx;
+ if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+ {
+ char *lo_name = module->loadobject->get_name ();
+ fprintf (stderr, GTXT ("Error: No source or disassembly available for hidden object %s.\n"),
+ lo_name);
+ return;
+ }
+ if (name)
+ srcFile = name;
+ }
+
+ if (module == NULL || module->get_name () == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Object name not recorded in experiment\n"));
+ return;
+ }
+ module->read_stabs ();
+
+ if (!isDisasm && (module->file_name == NULL
+ || (module->flags & MOD_FLAG_UNKNOWN) != 0
+ || *module->file_name == 0))
+ {
+ fprintf (stderr, GTXT ("Error: Source location not recorded in experiment\n"));
+ return;
+ }
+
+ MetricList *metric_list = dbev->get_metric_list (MET_NORMAL);
+ int sort_ref_index = metric_list->get_sort_ref_index ();
+ if (isDisasm)
+ metric_list->set_sort_ref_index (-1);
+
+ // Ask DbeView to generate function-level data
+ // MSI: I think this is used only to get totals to compute percentages
+ hist_data = dbev->get_hist_data (metric_list, Histable::FUNCTION, 0,
+ Hist_data::ALL);
+ MetricList *nmlist = hist_data->get_metric_list ();
+ metric_list->set_sort_ref_index (sort_ref_index);
+ if (nmlist->get_items ()->size () != 0
+ && hist_data->get_status () != Hist_data::SUCCESS)
+ {
+ errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ if (errstr)
+ {
+ fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+ free (errstr);
+ }
+ return;
+ }
+
+ marks = new Vector<int>;
+ if (isDisasm)
+ {
+ threshold = dbev->get_thresh_dis ();
+ compcom_bits = dbev->get_dis_compcom ();
+ src_visible = dbev->get_src_visible ();
+ hex_visible = dbev->get_hex_visible ();
+ srcmetrics_visible = dbev->get_srcmetric_visible ();
+ }
+ else
+ {
+ threshold = dbev->get_thresh_src ();
+ compcom_bits = dbev->get_src_compcom ();
+ src_visible = SRC_NA;
+ hex_visible = false;
+ srcmetrics_visible = false;
+ }
+
+ dump_anno_file (out_file, isDisasm ? Histable::INSTR : Histable::LINE,
+ module, dbev, nmlist, hist_data->get_totals ()->value,
+ srcFile, func, marks, threshold, compcom_bits,
+ src_visible, hex_visible, srcmetrics_visible);
+
+ delete marks;
+
+ errstr = module->anno_str ();
+ if (errstr)
+ {
+ fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+ free (errstr);
+ }
+ delete hist_data;
+}
+
+void
+print_html_title (FILE *out_file, char *title)
+{
+ // This will print a header row for the report
+ fprintf (out_file, "<html><title>%s</title>\n", title);
+ fprintf (out_file, "<center><h3>%s</h3></center>\n", title);
+}
+
+void
+print_html_label (FILE *out_file, MetricList *metrics_list)
+{
+ int mlist_sz;
+
+ // This will print a header row for the metrics
+ Vector<Metric*> *mlist = metrics_list->get_items ();
+ mlist_sz = mlist->size ();
+
+ fprintf (out_file, "<style type=\"text/css\">\n");
+ fprintf (out_file, "<!--\nBODY\n");
+ fprintf (out_file, ".th_C { text-align:center; background-color:lightgoldenrodyellow; }\n");
+ fprintf (out_file, ".th_CG { text-align:center; background-color:#ffff33; }\n");
+ fprintf (out_file, ".th_L { text-align:left; background-color:lightgoldenrodyellow; }\n");
+ fprintf (out_file, ".th_LG { text-align:left; background-color:#ffff33; }\n");
+ fprintf (out_file, ".td_R { text-align:right; }\n");
+ fprintf (out_file, ".td_RG { text-align:right; background-color:#ffff33; }\n");
+ fprintf (out_file, ".td_L { text-align:left; }\n");
+ fprintf (out_file, ".td_LG { text-align:left; background-color:#ffff33; }\n");
+ fprintf (out_file, "-->\n</style>");
+ fprintf (out_file, "<center><table border=1 cellspacing=2>\n<tr>");
+
+ for (int index = 0; index < mlist_sz; index++)
+ {
+ Metric *mitem = mlist->fetch (index);
+ int ncols = 0;
+ if (mitem->is_visible ())
+ ncols++;
+ if (mitem->is_tvisible ())
+ ncols++;
+ if (mitem->is_pvisible ())
+ ncols++;
+ if (ncols == 0)
+ continue;
+ char *name = strdup (mitem->get_name ());
+ char *name2 = split_metric_name (name);
+ const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
+
+ // start the column, with colspan setting, legend, and sort metric indicator
+ if (ncols == 1)
+ {
+ if (mitem->get_vtype () == VT_LABEL)
+ // left-adjust the name metric
+ fprintf (out_file,
+ "<th class=\"th_L%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
+ style, mitem->legend == NULL ? "&nbsp;" : mitem->legend,
+ (index == metrics_list->get_sort_ref_index ()) ? "&nabla;" : "&nbsp;",
+ name, name2 == NULL ? "&nbsp;" : name2);
+ else
+ // but center the others
+ fprintf (out_file,
+ "<th class=\"th_C%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
+ style, mitem->legend == NULL ? "&nbsp;" : mitem->legend,
+ (index == metrics_list->get_sort_ref_index ()) ?
+ "&nabla;" : "&nbsp;",
+ name, name2 == NULL ? NTXT ("&nbsp;") : name2);
+ }
+ else
+ // name metric can't span columns
+ fprintf (out_file,
+ "<th colspan=%d class=\"th_C%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
+ ncols, style,
+ mitem->legend == NULL ? "&nbsp;" : mitem->legend,
+ index == metrics_list->get_sort_ref_index () ?
+ "&nabla;" : "&nbsp;",
+ name, name2 == NULL ? "&nbsp;" : name2);
+
+ free (name);
+ }
+
+ // end this row, start the units row
+ fprintf (out_file, NTXT ("</tr>\n<tr>"));
+
+ // now do the units row
+ for (int index = 0; index < mlist_sz; index++)
+ {
+ Metric *mitem = mlist->fetch (index);
+ const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
+
+ if (mitem->is_tvisible ())
+ fprintf (out_file, "<th class=\"th_C%s\">&nbsp;(%s)</th>", style,
+ GTXT ("sec."));
+ if (mitem->is_visible ())
+ {
+ if (mitem->get_abbr_unit () == NULL)
+ fprintf (out_file, "<th class=\"th_C%s\">&nbsp;</th>", style);
+ else
+ fprintf (out_file, "<th class=\"th_C%s\">(%s)</th>", style,
+ mitem->get_abbr_unit () == NULL ? "&nbsp;"
+ : mitem->get_abbr_unit ());
+ }
+ if (mitem->is_pvisible ())
+ fprintf (out_file, "<th class=\"th_C%s\">&nbsp;(%%)</th>", style);
+ }
+ fprintf (out_file, NTXT ("</tr>\n"));
+}
+
+void
+print_html_content (FILE *out_file, Hist_data *data, MetricList *metrics_list,
+ int limit, Histable::NameFormat nfmt)
+{
+ Hist_data::HistItem *item;
+
+ // printing contents.
+ for (int i = 0; i < limit; i++)
+ {
+ item = data->fetch (i);
+ print_html_one (out_file, data, item, metrics_list, nfmt);
+ }
+}
+
+void
+print_html_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+ MetricList *metrics_list, Histable::NameFormat nfmt)
+{
+ Metric *mitem;
+ int index;
+ int visible, tvisible, pvisible;
+ TValue *value;
+ double percent;
+
+ fprintf (out_file, NTXT ("<tr>"));
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ visible = mitem->is_visible ();
+ tvisible = mitem->is_tvisible ();
+ pvisible = mitem->is_pvisible ();
+ const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
+
+ if (tvisible)
+ {
+ value = &(item->value[index]);
+ if (value->ll == 0LL)
+ fprintf (out_file,
+ "<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
+ style);
+ else
+ fprintf (out_file, "<td class=\"td_R%s\"><tt>%4.3lf</tt></td>",
+ style, 1.e-6 * value->ll / dbeSession->get_clock (-1));
+ }
+
+ if (visible)
+ {
+ if (mitem->get_vtype () == VT_LABEL)
+ {
+ value = &(item->value[index]);
+ char *r;
+ if (value->tag == VT_OFFSET)
+ r = ((DataObject*) (item->obj))->get_offset_name ();
+ else
+ r = item->obj->get_name (nfmt);
+ char *n = html_ize_name (r);
+ fprintf (out_file, NTXT ("<td class=\"td_L%s\">%s</td>"), style, n);
+ free (n);
+ }
+ else
+ {
+ value = &(item->value[index]);
+ switch (value->tag)
+ {
+ case VT_DOUBLE:
+ if (value->d == 0.0)
+ fprintf (out_file,
+ "<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
+ style);
+ else
+ fprintf (out_file,
+ "<td class=\"td_R%s\"><tt>%4.3lf</tt></td>", style,
+ value->d);
+ break;
+ case VT_INT:
+ fprintf (out_file, "<td class=\"td_R%s\"><tt>%d</tt></td>",
+ style, value->i);
+ break;
+ case VT_LLONG:
+ fprintf (out_file, "<td class=\"td_R%s\"><tt>%lld</td></tt>",
+ style, value->ll);
+ break;
+ case VT_ULLONG:
+ fprintf (out_file, "<td class=\"td_R%s\"><tt>%llu</td></tt>",
+ style, value->ull);
+ break;
+ case VT_ADDRESS:
+ fprintf (out_file,
+ "<td class=\"td_R%s\"><tt>%u:0x%08x</tt></td>", style,
+ ADDRESS_SEG (value->ll), ADDRESS_OFF (value->ll));
+ break;
+ case VT_FLOAT:
+ if (value->f == 0.0)
+ fprintf (out_file,
+ "<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
+ style);
+ else
+ fprintf (out_file,
+ "<td class=\"td_R%s\"><tt>%4.3f</tt></td>",
+ style, value->f);
+ break;
+ case VT_SHORT:
+ fprintf (out_file, "<td class=\"td_R%s\"><tt>%d</tt></td>",
+ style, value->s);
+ break;
+ // ignoring the following cases (why?)
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_OFFSET:
+ break;
+ }
+ }
+ }
+
+ if (pvisible)
+ {
+ percent = data->get_percentage (item->value[index].to_double (), index);
+ if (percent == 0.0)
+ // adjust to change format from xx.yy%
+ fprintf (out_file, "<td class=\"td_R%s\">0.&nbsp;&nbsp;&nbsp;</td>",
+ style);
+ else
+ // adjust format below to change format from xx.yy%
+ fprintf (out_file, "<td class=\"td_R%s\">%3.2f</td>", style,
+ (100.0 * percent));
+ }
+ }
+ fprintf (out_file, NTXT ("</tr>\n"));
+}
+
+void
+print_html_trailer (FILE *out_file)
+{
+ fprintf (out_file, NTXT ("</table></center></html>\n"));
+}
+
+static char *
+del_delim (char *s)
+{
+ size_t len = strlen (s);
+ if (len > 0)
+ s[len - 1] = 0;
+ return s;
+}
+
+void
+print_delim_label (FILE *out_file, MetricList *metrics_list, char delim)
+{
+ char line0[2 * MAX_LEN], line1[2 * MAX_LEN];
+ char line2[2 * MAX_LEN], line3[2 * MAX_LEN];
+ size_t len;
+
+ // This will print four header rows for the metrics
+ line0[0] = 0;
+ line1[0] = 0;
+ line2[0] = 0;
+ line3[0] = 0;
+ Vector<Metric*> *mlist = metrics_list->get_items ();
+ for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++)
+ {
+ Metric *mitem = mlist->fetch (index);
+ if (!(mitem->is_visible () || mitem->is_tvisible ()
+ || mitem->is_pvisible ()))
+ continue;
+ char *name = strdup (mitem->get_name ());
+ char *name2 = split_metric_name (name);
+
+ if (mitem->is_tvisible ())
+ {
+ len = strlen (line0);
+ snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"),
+ mitem->legend == NULL ? NTXT ("") : mitem->legend, delim);
+ len = strlen (line1);
+ snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"),
+ name, delim);
+ len = strlen (line2);
+ snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"),
+ name2 == NULL ? NTXT ("") : name2, delim);
+ len = strlen (line3);
+ if (index == metrics_list->get_sort_ref_index ())
+ snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V %s\"%c"),
+ GTXT ("(sec.)"), delim);
+ else
+ snprintf (line3 + len, sizeof (line3) - len, NTXT ("\" %s\"%c"),
+ GTXT ("(sec.)"), delim);
+ }
+ if (mitem->is_visible ())
+ {
+ len = strlen (line0);
+ snprintf (line0 + len, sizeof (line0) - len, "\"%s\"%c",
+ mitem->legend == NULL ? "" : mitem->legend, delim);
+
+ len = strlen (line1);
+ snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c",
+ name, delim);
+
+ len = strlen (line2);
+ snprintf (line2 + len, sizeof (line2) - len, "\"%s\"%c",
+ name2 == NULL ? NTXT ("") : name2, delim);
+
+ len = strlen (line3);
+ char *au = mitem->get_abbr_unit ();
+
+ if (index == metrics_list->get_sort_ref_index ())
+ {
+ if (au == NULL)
+ snprintf (line3 + len, sizeof (line3) - len, "\"V \"%c", delim);
+ else
+ snprintf (line3 + len, sizeof (line3) - len, "\"V (%s)\"%c",
+ au, delim);
+ }
+ else
+ {
+ if (au == NULL)
+ snprintf (line3 + len, sizeof (line3) - len, "\" \"%c",
+ delim);
+ else
+ snprintf (line3 + len, sizeof (line3) - len, "\" (%s)\"%c",
+ au, delim);
+ }
+ }
+ if (mitem->is_pvisible ())
+ {
+ len = strlen (line0);
+ snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"),
+ mitem->legend == NULL ? NTXT ("") : mitem->legend, delim);
+
+ len = strlen (line1);
+ snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"),
+ name, delim);
+
+ len = strlen (line2);
+ snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"),
+ name2 == NULL ? NTXT ("") : name2, delim);
+
+ len = strlen (line3);
+ if (index == metrics_list->get_sort_ref_index ())
+ snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V %s\"%c"),
+ NTXT ("%%"), delim);
+ else
+ snprintf (line3 + len, sizeof (line3) - len, NTXT ("\" %s\"%c"),
+ NTXT ("%%"), delim);
+ }
+ free (name);
+ }
+ // now remove the trailing delimiter, and print the four lines
+ fprintf (out_file, NTXT ("%s\n"), del_delim (line0));
+ fprintf (out_file, NTXT ("%s\n"), del_delim (line1));
+ fprintf (out_file, NTXT ("%s\n"), del_delim (line2));
+ fprintf (out_file, NTXT ("%s\n"), del_delim (line3));
+}
+
+void
+print_delim_content (FILE *out_file, Hist_data *data, MetricList *metrics_list,
+ int limit, Histable::NameFormat nfmt, char delim)
+{
+ Hist_data::HistItem *item;
+ int i;
+
+ // printing contents.
+ for (i = 0; i < limit; i++)
+ {
+ item = data->fetch (i);
+ print_delim_one (out_file, data, item, metrics_list, nfmt, delim);
+ }
+}
+
+void
+print_delim_trailer (FILE */*out_file*/, char /*delim*/) { }
+
+// EUGENE does this function work properly when "-compare ratio" is used?
+// how about when the ratio is nonzero-divided-by-zero?
+// EUGENE actually, review this entire file
+
+void
+print_delim_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+ MetricList *metrics_list, Histable::NameFormat nfmt,
+ char delim)
+{
+ Metric *mitem;
+ int index;
+ int visible, tvisible, pvisible;
+ TValue *value;
+ double percent;
+ size_t len;
+
+ char line1[2 * MAX_LEN];
+ *line1 = 0;
+ Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+ {
+ visible = mitem->is_visible ();
+ tvisible = mitem->is_tvisible ();
+ pvisible = mitem->is_pvisible ();
+ if (tvisible)
+ {
+ value = &(item->value[index]);
+ len = strlen (line1);
+ if (value->ll == 0LL)
+ snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim);
+ else
+ snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c",
+ 1.e-6 * value->ll / dbeSession->get_clock (-1),
+ delim);
+ }
+
+ if (visible)
+ {
+ len = strlen (line1);
+ if (mitem->get_vtype () == VT_LABEL)
+ {
+ value = &(item->value[index]);
+ char *r;
+ if (value->tag == VT_OFFSET)
+ r = ((DataObject*) (item->obj))->get_offset_name ();
+ else
+ r = item->obj->get_name (nfmt);
+ char *p = csv_ize_name (r, delim);
+ snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c", p, delim);
+ free (p);
+ }
+ else
+ {
+ value = &(item->value[index]);
+ switch (value->tag)
+ {
+ case VT_DOUBLE:
+ if (value->d == 0.0)
+ snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c",
+ delim);
+ else
+ snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c",
+ value->d, delim);
+ break;
+ case VT_INT:
+ snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c",
+ value->i, delim);
+ break;
+ case VT_LLONG:
+ snprintf (line1 + len, sizeof (line1) - len, "\"%lld\"%c",
+ value->ll, delim);
+ break;
+ case VT_ULLONG:
+ snprintf (line1 + len, sizeof (line1) - len, "\"%llu\"%c",
+ value->ull, delim);
+ break;
+ case VT_ADDRESS:
+ snprintf (line1 + len, sizeof (line1) - len, "\"%u:0x%08x\"%c",
+ ADDRESS_SEG (value->ll),
+ ADDRESS_OFF (value->ll), delim);
+ break;
+ case VT_FLOAT:
+ if (value->f == 0.0)
+ snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c",
+ delim);
+ else
+ snprintf (line1 + len, sizeof (line1) - len, "\"%4.3f\"%c",
+ value->f, delim);
+ break;
+ case VT_SHORT:
+ snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c",
+ value->s, delim);
+ break;
+ // ignoring the following cases (why?)
+ case VT_HRTIME:
+ case VT_LABEL:
+ case VT_OFFSET:
+ break;
+ }
+ }
+ }
+
+ if (pvisible)
+ {
+ len = strlen (line1);
+ percent = data->get_percentage (item->value[index].to_double (), index);
+ if (percent == 0.0)
+ // adjust to change format from xx.yy%
+ snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim);
+ else
+ // adjust format below to change format from xx.yy%
+ snprintf (line1 + len, sizeof (line1) - len, "\"%3.2f\"%c",
+ (100.0 * percent), delim);
+ }
+ }
+ fprintf (out_file, NTXT ("%s\n"), del_delim (line1));
+}
+
+char *
+html_ize_name (char *name)
+{
+ StringBuilder sb;
+ for (size_t i = 0; i < strlen (name); i++)
+ {
+ switch (name[i])
+ {
+ case ' ': sb.append (NTXT ("&nbsp;"));
+ break;
+ case '"': sb.append (NTXT ("&quot;"));
+ break;
+ case '&': sb.append (NTXT ("&amp;"));
+ break;
+ case '<': sb.append (NTXT ("&lt;"));
+ break;
+ case '>': sb.append (NTXT ("&gt;"));
+ break;
+ default: sb.append (name[i]);
+ break;
+ }
+ }
+ char *ret = sb.toString ();
+ return ret;
+}
+
+char *
+csv_ize_name (char *name, char /*delim*/)
+{
+ StringBuilder sb;
+ for (size_t i = 0; i < strlen (name); i++)
+ sb.append (name[i]);
+ char *ret = sb.toString ();
+ return ret;
+}
+
+// Split a metric name into two parts, replacing a blank with
+// a zero and returning pointer to the rest of the string, or
+// leaving the string unchanged, and returning NULL;
+
+char *
+split_metric_name (char *name)
+{
+ // figure out the most even split of the name
+ size_t len = strlen (name);
+ char *middle = &name[len / 2];
+
+ // find the first blank
+ char *first = strchr (name, (int) ' ');
+ if (first == NULL) // no blanks
+ return NULL;
+ char *last = first;
+ char *p = first;
+ for (;;)
+ {
+ p = strchr (p + 1, (int) ' ');
+ if (p == NULL)
+ break;
+ if (p < middle)
+ {
+ first = p;
+ last = p;
+ }
+ else
+ {
+ last = p;
+ break;
+ }
+ }
+ // pick the better of the two
+ char *ret;
+ int f = (int) (middle - first);
+ int l = (int) (last - middle);
+ if ((first == last) || (f <= l))
+ {
+ *first = '\0';
+ ret = first + 1;
+ }
+ else
+ {
+ *last = '\0';
+ ret = last + 1;
+ }
+ return ret;
+}
diff --git a/gprofng/src/Print.h b/gprofng/src/Print.h
new file mode 100644
index 0000000..4bc6655
--- /dev/null
+++ b/gprofng/src/Print.h
@@ -0,0 +1,283 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PRINT_H
+#define _PRINT_H
+
+
+// Include files
+#include <stdio.h>
+#include <stdlib.h>
+#include "dbe_types.h"
+#include "Metric.h"
+#include "Hist_data.h"
+#include "Ovw_data.h"
+#include "Stats_data.h"
+#include "Emsg.h"
+#include "Exp_Layout.h"
+#include "DefaultMap.h"
+#include "FileData.h"
+#include "HeapData.h"
+#include "HashMap.h"
+
+const char nl[] = "\n";
+const char tab[] = "\t";
+
+// Printing options.
+enum Print_destination
+{
+ DEST_PRINTER = 0,
+ DEST_FILE = 1,
+ DEST_OPEN_FILE = 2
+};
+
+enum Print_mode
+{
+ MODE_LIST,
+ MODE_DETAIL,
+ MODE_GPROF,
+ MODE_ANNOTATED
+};
+
+struct Print_params
+{
+ Print_destination dest; // printer or file
+ char *name; // of printer or file
+ int ncopies; // # of copies
+ bool header; // print header first
+ FILE *openfile; // if destination is DEST_OPEN_FILE
+};
+
+class Experiment;
+class MetricList;
+class DbeView;
+class Stack_coverage;
+class Function;
+class LoadObject;
+
+// Class Definitions
+class er_print_common_display
+{
+public:
+ er_print_common_display ()
+ {
+ out_file = NULL;
+ pr_params.header = false;
+ }
+
+ virtual ~er_print_common_display () { }
+
+ // Open the file/printer to write to
+ int open (Print_params *);
+
+ void
+ set_out_file (FILE *o)
+ {
+ out_file = o;
+ pr_params.dest = DEST_FILE;
+ }
+
+ // Print the final output data. This function calls
+ // data_dump() to actually do the dumping of data.
+ bool print_output ();
+
+ // Print the output in the appropriate format.
+ virtual void data_dump () = 0;
+
+ void header_dump (int exp_idx);
+
+ // Return the report. If the report size is greater than max, return truncated report
+ // Allocates memory, so the caller should free this memory.
+ char *get_output (int max);
+
+protected:
+ DbeView *dbev;
+ FILE *out_file;
+ Print_params pr_params;
+ char *tmp_file;
+ int exp_idx1, exp_idx2;
+ bool load;
+ bool header;
+};
+
+class er_print_histogram : public er_print_common_display
+{
+public:
+ er_print_histogram (DbeView *dbv, Hist_data *data, MetricList *metrics_list,
+ Print_mode disp_type, int limit, char *sort_name,
+ Histable *sobj, bool show_load, bool show_header);
+ void data_dump ();
+
+private:
+ void dump_list (int limit);
+ void dump_detail (int limit);
+ void get_gprof_width (Metric::HistMetric *hist_metric, int limit);
+ void dump_gprof (int limit);
+ void dump_annotated_dataobjects (Vector<int> *marks, int threshold);
+ void dump_annotated ();
+
+ Stack_coverage *stack_cov;
+ Hist_data *hist_data;
+ MetricList *mlist;
+ Print_mode type;
+ int number_entries;
+ char *sort_metric;
+ Histable *sel_obj;
+};
+
+class er_print_ctree : public er_print_common_display
+{
+public:
+ er_print_ctree (DbeView *dbv, Vector<Histable*> *cstack, Histable *sobj,
+ int limit);
+ void data_dump ();
+ void print_children (Hist_data *data, int index, Histable *obj, char *prefix,
+ Hist_data::HistItem *total);
+
+private:
+ Vector<Histable*> *cstack;
+ Histable *sobj;
+ MetricList *mlist;
+ Metric::HistMetric *hist_metric;
+ char **fmt_int;
+ char **fmt_real0;
+ char **fmt_real1;
+ int limit;
+ int print_row;
+};
+
+class er_print_gprof : public er_print_common_display
+{
+public:
+ er_print_gprof (DbeView *dbv, Vector<Histable*> *cstack);
+ void data_dump ();
+private:
+ Vector<Histable*> *cstack;
+};
+
+class er_print_leaklist : public er_print_common_display
+{
+public:
+ er_print_leaklist (DbeView *dbv, bool show_leak,
+ bool show_alloca, int limit);
+ void data_dump ();
+
+private:
+ bool leak;
+ bool alloca;
+ int limit;
+};
+
+class er_print_heapactivity : public er_print_common_display
+{
+public:
+ er_print_heapactivity (DbeView *_dbev, Histable::Type _type,
+ bool _printStat, int _limit);
+ void data_dump ();
+
+private:
+ void printStatistics (Hist_data *hist_data);
+ void printCallStacks (Hist_data *hist_data);
+
+ Histable::Type type;
+ bool printStat;
+ int limit;
+};
+
+class er_print_ioactivity : public er_print_common_display
+{
+public:
+ er_print_ioactivity (DbeView *_dbev, Histable::Type _type,
+ bool _printStat, int _limit);
+ void data_dump ();
+
+private:
+ void printStatistics (Hist_data *hist_data);
+ void printCallStacks (Hist_data *hist_data);
+
+ Histable::Type type;
+ bool printStat;
+ int limit;
+};
+
+class er_print_experiment : public er_print_common_display
+{
+public:
+ er_print_experiment (DbeView *me, int bgn_idx, int end_idx, bool show_load,
+ bool show_header, bool show_stat, bool show_over, bool show_odetail);
+ void data_dump ();
+
+private:
+ char fmt1[32], fmt2[32], fmt3[32], fmt4[32];
+ // buffers shared by the following functions
+ void overview_sum (int &maxlen);
+ void overview_dump (int exp_idx, int &maxlen);
+ void overview_summary (Ovw_data *ovw_data, int &maxlen);
+ void overview_item (Ovw_data::Ovw_item *ovw_item,
+ Ovw_data::Ovw_item *ovw_item_labels);
+ void overview_value (Value *value, ValueTag value_tag,
+ double total_value);
+ void statistics_sum (int &maxlen);
+ void statistics_dump (int exp_idx, int &maxlen);
+ void statistics_item (Stats_data *stats_data);
+
+ bool stat;
+ bool over;
+ bool odetail;
+};
+
+// Print the header. Experiment name and the sample
+// selection, along with the percentage.
+char *pr_load_objects (Vector<LoadObject*> *loadobjects, char *lead);
+char *pr_samples (Experiment *exp);
+char *pr_mesgs (Emsg *msg, const char *null_str, const char *lead);
+void print_load_object (FILE *out_file);
+void print_header (Experiment *exp, FILE *out_file);
+
+// Print Function metrics
+void get_width (Hist_data *data, MetricList *metrics_list,
+ Metric::HistMetric *hist_metric);
+void get_format (char **fmt_int, char **fmt_real0, char **fmt_real1,
+ MetricList *metrics_list, Metric::HistMetric *hist_metric,
+ int nspace);
+int print_label (FILE *out_file, MetricList *metrics_list,
+ Metric::HistMetric *hist_metric, int space);
+void print_anno_file (char *name, const char *sel, const char *srcFile,
+ bool isDisasm, FILE *dis_file, FILE *inp_file,
+ FILE *out_file, DbeView *dbev, bool xdefault);
+void print_html_title (FILE *out_file, char *title);
+void print_html_label (FILE *out_file, MetricList *metrics_list);
+void print_html_content (FILE *out_file, Hist_data *d, MetricList *metrics_list,
+ int limit, Histable::NameFormat nfmt);
+void print_html_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+ MetricList *metrics_list, Histable::NameFormat nfmt);
+void print_html_trailer (FILE* out_file);
+char *html_ize_name (char *name);
+void print_delim_label (FILE *out_file, MetricList *metrics_list, char delim);
+void print_delim_content (FILE *out_file, Hist_data *data,
+ MetricList *metrics_list, int limit,
+ Histable::NameFormat nfmt, char delim);
+void print_delim_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+ MetricList *metrics_list, Histable::NameFormat nfmt, char delim);
+void print_delim_trailer (FILE* out_file, char delim);
+char *csv_ize_name (char *name, char delim);
+char *split_metric_name (char *name);
+
+#endif
diff --git a/gprofng/src/QLParser.h b/gprofng/src/QLParser.h
new file mode 100644
index 0000000..c4665e8
--- /dev/null
+++ b/gprofng/src/QLParser.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _QLPARSER_H
+#define _QLPARSER_H
+
+#include <sstream>
+#include <istream>
+#include <iostream>
+#include "Expression.h"
+
+/* This class contains parser inputs (a string, if non-NULL: if NULL, use cin),
+ and outputs (obtained via operator(), which resets the output
+ expression). The destructor deletes the returned expression to allow
+ exception throws on syntax error to clean up properly. */
+
+namespace QL
+{
+ struct Result
+ {
+ std::stringstream streamify;
+ public:
+ std::istream in;
+ Expression *out;
+
+ Result () : in (std::cin.rdbuf ()), out (NULL) { }
+ Result (const char *instr) : streamify (std::string (instr)),
+ in (streamify.rdbuf ()), out (NULL) { }
+
+ Expression *operator() ()
+ {
+ Expression *o = out;
+ out = NULL;
+ return o;
+ }
+
+ ~Result ()
+ {
+ delete out;
+ }
+ };
+};
+
+#endif /* _QLPARSER_H */
diff --git a/gprofng/src/QLParser.tab.cc b/gprofng/src/QLParser.tab.cc
new file mode 100644
index 0000000..4517b2e
--- /dev/null
+++ b/gprofng/src/QLParser.tab.cc
@@ -0,0 +1,1453 @@
+// A Bison parser, made by GNU Bison 3.7.5.
+
+// Skeleton implementation for Bison LALR(1) parsers in C++
+
+// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
+
+// 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 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+// As a special exception, you may create a larger work that contains
+// part or all of the Bison parser skeleton and distribute that work
+// under terms of your choice, so long as that work isn't itself a
+// parser generator using the skeleton or a modified version thereof
+// as a parser skeleton. Alternatively, if you modify or redistribute
+// the parser skeleton itself, you may (at your option) remove this
+// special exception, which will cause the skeleton and the resulting
+// Bison output files to be licensed under the GNU General Public
+// License without this special exception.
+
+// This special exception was added by the Free Software Foundation in
+// version 2.2 of Bison.
+
+// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+// especially those whose name start with YY_ or yy_. They are
+// private implementation details that can be changed or removed.
+
+// "%code top" blocks.
+#line 28 "QLParser.yy"
+
+#include <stdio.h>
+#include <string.h>
+#include <string>
+
+#line 45 "QLParser.tab.cc"
+
+
+
+
+#include "QLParser.tab.hh"
+
+
+// Unqualified %code blocks.
+#line 42 "QLParser.yy"
+
+namespace QL
+{
+ static QL::Parser::symbol_type yylex (QL::Result &result);
+}
+
+#line 61 "QLParser.tab.cc"
+
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> // FIXME: INFRINGES ON USER NAME SPACE.
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+
+// Whether we are compiled with exception support.
+#ifndef YY_EXCEPTIONS
+# if defined __GNUC__ && !defined __EXCEPTIONS
+# define YY_EXCEPTIONS 0
+# else
+# define YY_EXCEPTIONS 1
+# endif
+#endif
+
+
+
+// Enable debugging if requested.
+#if YYDEBUG
+
+// A pseudo ostream that takes yydebug_ into account.
+# define YYCDEBUG if (yydebug_) (*yycdebug_)
+
+# define YY_SYMBOL_PRINT(Title, Symbol) \
+ do { \
+ if (yydebug_) \
+ { \
+ *yycdebug_ << Title << ' '; \
+ yy_print_ (*yycdebug_, Symbol); \
+ *yycdebug_ << '\n'; \
+ } \
+ } while (false)
+
+# define YY_REDUCE_PRINT(Rule) \
+ do { \
+ if (yydebug_) \
+ yy_reduce_print_ (Rule); \
+ } while (false)
+
+# define YY_STACK_PRINT() \
+ do { \
+ if (yydebug_) \
+ yy_stack_print_ (); \
+ } while (false)
+
+#else // !YYDEBUG
+
+# define YYCDEBUG if (false) std::cerr
+# define YY_SYMBOL_PRINT(Title, Symbol) YY_USE (Symbol)
+# define YY_REDUCE_PRINT(Rule) static_cast<void> (0)
+# define YY_STACK_PRINT() static_cast<void> (0)
+
+#endif // !YYDEBUG
+
+#define yyerrok (yyerrstatus_ = 0)
+#define yyclearin (yyla.clear ())
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+#define YYRECOVERING() (!!yyerrstatus_)
+
+#line 50 "QLParser.yy"
+namespace QL {
+#line 135 "QLParser.tab.cc"
+
+ /// Build a parser object.
+ Parser::Parser (QL::Result &result_yyarg)
+#if YYDEBUG
+ : yydebug_ (false),
+ yycdebug_ (&std::cerr),
+#else
+ :
+#endif
+ result (result_yyarg)
+ {}
+
+ Parser::~Parser ()
+ {}
+
+ Parser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW
+ {}
+
+ /*---------------.
+ | symbol kinds. |
+ `---------------*/
+
+
+
+ // by_state.
+ Parser::by_state::by_state () YY_NOEXCEPT
+ : state (empty_state)
+ {}
+
+ Parser::by_state::by_state (const by_state& that) YY_NOEXCEPT
+ : state (that.state)
+ {}
+
+ void
+ Parser::by_state::clear () YY_NOEXCEPT
+ {
+ state = empty_state;
+ }
+
+ void
+ Parser::by_state::move (by_state& that)
+ {
+ state = that.state;
+ that.clear ();
+ }
+
+ Parser::by_state::by_state (state_type s) YY_NOEXCEPT
+ : state (s)
+ {}
+
+ Parser::symbol_kind_type
+ Parser::by_state::kind () const YY_NOEXCEPT
+ {
+ if (state == empty_state)
+ return symbol_kind::S_YYEMPTY;
+ else
+ return YY_CAST (symbol_kind_type, yystos_[+state]);
+ }
+
+ Parser::stack_symbol_type::stack_symbol_type ()
+ {}
+
+ Parser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that)
+ : super_type (YY_MOVE (that.state))
+ {
+ switch (that.kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.YY_MOVE_OR_COPY< Expression * > (YY_MOVE (that.value));
+ break;
+
+ default:
+ break;
+ }
+
+#if 201103L <= YY_CPLUSPLUS
+ // that is emptied.
+ that.state = empty_state;
+#endif
+ }
+
+ Parser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that)
+ : super_type (s)
+ {
+ switch (that.kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.move< Expression * > (YY_MOVE (that.value));
+ break;
+
+ default:
+ break;
+ }
+
+ // that is emptied.
+ that.kind_ = symbol_kind::S_YYEMPTY;
+ }
+
+#if YY_CPLUSPLUS < 201103L
+ Parser::stack_symbol_type&
+ Parser::stack_symbol_type::operator= (const stack_symbol_type& that)
+ {
+ state = that.state;
+ switch (that.kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.copy< Expression * > (that.value);
+ break;
+
+ default:
+ break;
+ }
+
+ return *this;
+ }
+
+ Parser::stack_symbol_type&
+ Parser::stack_symbol_type::operator= (stack_symbol_type& that)
+ {
+ state = that.state;
+ switch (that.kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.move< Expression * > (that.value);
+ break;
+
+ default:
+ break;
+ }
+
+ // that is emptied.
+ that.state = empty_state;
+ return *this;
+ }
+#endif
+
+ template <typename Base>
+ void
+ Parser::yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const
+ {
+ if (yymsg)
+ YY_SYMBOL_PRINT (yymsg, yysym);
+ }
+
+#if YYDEBUG
+ template <typename Base>
+ void
+ Parser::yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const
+ {
+ std::ostream& yyoutput = yyo;
+ YY_USE (yyoutput);
+ if (yysym.empty ())
+ yyo << "empty symbol";
+ else
+ {
+ symbol_kind_type yykind = yysym.kind ();
+ yyo << (yykind < YYNTOKENS ? "token" : "nterm")
+ << ' ' << yysym.name () << " (";
+ YY_USE (yykind);
+ yyo << ')';
+ }
+ }
+#endif
+
+ void
+ Parser::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym)
+ {
+ if (m)
+ YY_SYMBOL_PRINT (m, sym);
+ yystack_.push (YY_MOVE (sym));
+ }
+
+ void
+ Parser::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym)
+ {
+#if 201103L <= YY_CPLUSPLUS
+ yypush_ (m, stack_symbol_type (s, std::move (sym)));
+#else
+ stack_symbol_type ss (s, sym);
+ yypush_ (m, ss);
+#endif
+ }
+
+ void
+ Parser::yypop_ (int n)
+ {
+ yystack_.pop (n);
+ }
+
+#if YYDEBUG
+ std::ostream&
+ Parser::debug_stream () const
+ {
+ return *yycdebug_;
+ }
+
+ void
+ Parser::set_debug_stream (std::ostream& o)
+ {
+ yycdebug_ = &o;
+ }
+
+
+ Parser::debug_level_type
+ Parser::debug_level () const
+ {
+ return yydebug_;
+ }
+
+ void
+ Parser::set_debug_level (debug_level_type l)
+ {
+ yydebug_ = l;
+ }
+#endif // YYDEBUG
+
+ Parser::state_type
+ Parser::yy_lr_goto_state_ (state_type yystate, int yysym)
+ {
+ int yyr = yypgoto_[yysym - YYNTOKENS] + yystate;
+ if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
+ return yytable_[yyr];
+ else
+ return yydefgoto_[yysym - YYNTOKENS];
+ }
+
+ bool
+ Parser::yy_pact_value_is_default_ (int yyvalue)
+ {
+ return yyvalue == yypact_ninf_;
+ }
+
+ bool
+ Parser::yy_table_value_is_error_ (int yyvalue)
+ {
+ return yyvalue == yytable_ninf_;
+ }
+
+ int
+ Parser::operator() ()
+ {
+ return parse ();
+ }
+
+ int
+ Parser::parse ()
+ {
+ int yyn;
+ /// Length of the RHS of the rule being reduced.
+ int yylen = 0;
+
+ // Error handling.
+ int yynerrs_ = 0;
+ int yyerrstatus_ = 0;
+
+ /// The lookahead symbol.
+ symbol_type yyla;
+
+ /// The return value of parse ().
+ int yyresult;
+
+#if YY_EXCEPTIONS
+ try
+#endif // YY_EXCEPTIONS
+ {
+ YYCDEBUG << "Starting parse\n";
+
+
+ /* Initialize the stack. The initial state will be set in
+ yynewstate, since the latter expects the semantical and the
+ location values to have been already stored, initialize these
+ stacks with a primary value. */
+ yystack_.clear ();
+ yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla));
+
+ /*-----------------------------------------------.
+ | yynewstate -- push a new symbol on the stack. |
+ `-----------------------------------------------*/
+ yynewstate:
+ YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n';
+ YY_STACK_PRINT ();
+
+ // Accept?
+ if (yystack_[0].state == yyfinal_)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+ /*-----------.
+ | yybackup. |
+ `-----------*/
+ yybackup:
+ // Try to take a decision without lookahead.
+ yyn = yypact_[+yystack_[0].state];
+ if (yy_pact_value_is_default_ (yyn))
+ goto yydefault;
+
+ // Read a lookahead token.
+ if (yyla.empty ())
+ {
+ YYCDEBUG << "Reading a token\n";
+#if YY_EXCEPTIONS
+ try
+#endif // YY_EXCEPTIONS
+ {
+ symbol_type yylookahead (yylex (result));
+ yyla.move (yylookahead);
+ }
+#if YY_EXCEPTIONS
+ catch (const syntax_error& yyexc)
+ {
+ YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
+ error (yyexc);
+ goto yyerrlab1;
+ }
+#endif // YY_EXCEPTIONS
+ }
+ YY_SYMBOL_PRINT ("Next token is", yyla);
+
+ if (yyla.kind () == symbol_kind::S_YYerror)
+ {
+ // The scanner already issued an error message, process directly
+ // to error recovery. But do not keep the error token as
+ // lookahead, it is too special and may lead us to an endless
+ // loop in error recovery. */
+ yyla.kind_ = symbol_kind::S_YYUNDEF;
+ goto yyerrlab1;
+ }
+
+ /* If the proper action on seeing token YYLA.TYPE is to reduce or
+ to detect an error, take that action. */
+ yyn += yyla.kind ();
+ if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.kind ())
+ {
+ goto yydefault;
+ }
+
+ // Reduce or error.
+ yyn = yytable_[yyn];
+ if (yyn <= 0)
+ {
+ if (yy_table_value_is_error_ (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ // Count tokens shifted since error; after three, turn off error status.
+ if (yyerrstatus_)
+ --yyerrstatus_;
+
+ // Shift the lookahead token.
+ yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla));
+ goto yynewstate;
+
+
+ /*-----------------------------------------------------------.
+ | yydefault -- do the default action for the current state. |
+ `-----------------------------------------------------------*/
+ yydefault:
+ yyn = yydefact_[+yystack_[0].state];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+ /*-----------------------------.
+ | yyreduce -- do a reduction. |
+ `-----------------------------*/
+ yyreduce:
+ yylen = yyr2_[yyn];
+ {
+ stack_symbol_type yylhs;
+ yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]);
+ /* Variants are always initialized to an empty instance of the
+ correct type. The default '$$ = $1' action is NOT applied
+ when using variants. */
+ switch (yyr1_[yyn])
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ yylhs.value.emplace< Expression * > ();
+ break;
+
+ default:
+ break;
+ }
+
+
+
+ // Perform the reduction.
+ YY_REDUCE_PRINT (yyn);
+#if YY_EXCEPTIONS
+ try
+#endif // YY_EXCEPTIONS
+ {
+ switch (yyn)
+ {
+ case 2: // S: %empty
+#line 104 "QLParser.yy"
+ { result.out = new Expression (Expression::OP_NUM, (uint64_t) 1); }
+#line 577 "QLParser.tab.cc"
+ break;
+
+ case 3: // S: exp
+#line 105 "QLParser.yy"
+ { result.out = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 583 "QLParser.tab.cc"
+ break;
+
+ case 4: // exp: exp DEG exp
+#line 107 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_DEG, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 589 "QLParser.tab.cc"
+ break;
+
+ case 5: // exp: exp MUL exp
+#line 108 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_MUL, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 595 "QLParser.tab.cc"
+ break;
+
+ case 6: // exp: exp DIV exp
+#line 109 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_DIV, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 601 "QLParser.tab.cc"
+ break;
+
+ case 7: // exp: exp REM exp
+#line 110 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_REM, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 607 "QLParser.tab.cc"
+ break;
+
+ case 8: // exp: exp ADD exp
+#line 111 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_ADD, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 613 "QLParser.tab.cc"
+ break;
+
+ case 9: // exp: exp MINUS exp
+#line 112 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_MINUS, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 619 "QLParser.tab.cc"
+ break;
+
+ case 10: // exp: exp LS exp
+#line 113 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_LS, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 625 "QLParser.tab.cc"
+ break;
+
+ case 11: // exp: exp RS exp
+#line 114 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_RS, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 631 "QLParser.tab.cc"
+ break;
+
+ case 12: // exp: exp LT exp
+#line 115 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_LT, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 637 "QLParser.tab.cc"
+ break;
+
+ case 13: // exp: exp LE exp
+#line 116 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_LE, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 643 "QLParser.tab.cc"
+ break;
+
+ case 14: // exp: exp GT exp
+#line 117 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_GT, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 649 "QLParser.tab.cc"
+ break;
+
+ case 15: // exp: exp GE exp
+#line 118 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_GE, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 655 "QLParser.tab.cc"
+ break;
+
+ case 16: // exp: exp EQ exp
+#line 119 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_EQ, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 661 "QLParser.tab.cc"
+ break;
+
+ case 17: // exp: exp NE exp
+#line 120 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_NE, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 667 "QLParser.tab.cc"
+ break;
+
+ case 18: // exp: exp BITAND exp
+#line 121 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITAND, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 673 "QLParser.tab.cc"
+ break;
+
+ case 19: // exp: exp BITXOR exp
+#line 122 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITXOR, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 679 "QLParser.tab.cc"
+ break;
+
+ case 20: // exp: exp BITOR exp
+#line 123 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITOR, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 685 "QLParser.tab.cc"
+ break;
+
+ case 21: // exp: exp AND exp
+#line 124 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_AND, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 691 "QLParser.tab.cc"
+ break;
+
+ case 22: // exp: exp OR exp
+#line 125 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_OR, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 697 "QLParser.tab.cc"
+ break;
+
+ case 23: // exp: exp NEQV exp
+#line 126 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_NEQV, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 703 "QLParser.tab.cc"
+ break;
+
+ case 24: // exp: exp EQV exp
+#line 127 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_EQV, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 709 "QLParser.tab.cc"
+ break;
+
+ case 25: // exp: exp QWE exp COLON exp
+#line 128 "QLParser.yy"
+ { Expression colon = Expression (Expression::OP_COLON, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ());
+ yylhs.value.as < Expression * > () = new Expression (Expression::OP_QWE, yystack_[4].value.as < Expression * > (), &colon); }
+#line 716 "QLParser.tab.cc"
+ break;
+
+ case 26: // exp: exp COMMA exp
+#line 130 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_COMMA, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 722 "QLParser.tab.cc"
+ break;
+
+ case 27: // exp: exp IN exp
+#line 131 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_IN, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 728 "QLParser.tab.cc"
+ break;
+
+ case 28: // exp: exp SOME IN exp
+#line 132 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_SOMEIN, yystack_[3].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 734 "QLParser.tab.cc"
+ break;
+
+ case 29: // exp: exp ORDR IN exp
+#line 133 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_ORDRIN, yystack_[3].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 740 "QLParser.tab.cc"
+ break;
+
+ case 30: // exp: term
+#line 134 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 746 "QLParser.tab.cc"
+ break;
+
+ case 31: // term: MINUS term
+#line 136 "QLParser.yy"
+ { Expression num = Expression (Expression::OP_NUM, (uint64_t) 0);
+ yylhs.value.as < Expression * > () = new Expression (Expression::OP_MINUS, &num, yystack_[0].value.as < Expression * > ()); }
+#line 753 "QLParser.tab.cc"
+ break;
+
+ case 32: // term: NOT term
+#line 138 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_NOT, yystack_[0].value.as < Expression * > (), NULL); }
+#line 759 "QLParser.tab.cc"
+ break;
+
+ case 33: // term: BITNOT term
+#line 139 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITNOT, yystack_[0].value.as < Expression * > (), NULL); }
+#line 765 "QLParser.tab.cc"
+ break;
+
+ case 34: // term: "(" exp ")"
+#line 140 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (yystack_[1].value.as < Expression * > ()); }
+#line 771 "QLParser.tab.cc"
+ break;
+
+ case 35: // term: FNAME "(" QSTR ")"
+#line 141 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_FUNC, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 777 "QLParser.tab.cc"
+ break;
+
+ case 36: // term: HASPROP "(" "name" ")"
+#line 142 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_HASPROP, yystack_[1].value.as < Expression * > (), NULL); }
+#line 783 "QLParser.tab.cc"
+ break;
+
+ case 37: // term: JGROUP "(" QSTR ")"
+#line 143 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_JAVA, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 789 "QLParser.tab.cc"
+ break;
+
+ case 38: // term: JPARENT "(" QSTR ")"
+#line 144 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_JAVA, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 795 "QLParser.tab.cc"
+ break;
+
+ case 39: // term: FILEIOVFD "(" QSTR ")"
+#line 145 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (Expression::OP_FILE, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 801 "QLParser.tab.cc"
+ break;
+
+ case 40: // term: "number"
+#line 146 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 807 "QLParser.tab.cc"
+ break;
+
+ case 41: // term: "name"
+#line 147 "QLParser.yy"
+ { yylhs.value.as < Expression * > () = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 813 "QLParser.tab.cc"
+ break;
+
+
+#line 817 "QLParser.tab.cc"
+
+ default:
+ break;
+ }
+ }
+#if YY_EXCEPTIONS
+ catch (const syntax_error& yyexc)
+ {
+ YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
+ error (yyexc);
+ YYERROR;
+ }
+#endif // YY_EXCEPTIONS
+ YY_SYMBOL_PRINT ("-> $$ =", yylhs);
+ yypop_ (yylen);
+ yylen = 0;
+
+ // Shift the result of the reduction.
+ yypush_ (YY_NULLPTR, YY_MOVE (yylhs));
+ }
+ goto yynewstate;
+
+
+ /*--------------------------------------.
+ | yyerrlab -- here on detecting error. |
+ `--------------------------------------*/
+ yyerrlab:
+ // If not already recovering from an error, report this error.
+ if (!yyerrstatus_)
+ {
+ ++yynerrs_;
+ std::string msg = YY_("syntax error");
+ error (YY_MOVE (msg));
+ }
+
+
+ if (yyerrstatus_ == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ // Return failure if at end of input.
+ if (yyla.kind () == symbol_kind::S_YYEOF)
+ YYABORT;
+ else if (!yyla.empty ())
+ {
+ yy_destroy_ ("Error: discarding", yyla);
+ yyla.clear ();
+ }
+ }
+
+ // Else will try to reuse lookahead token after shifting the error token.
+ goto yyerrlab1;
+
+
+ /*---------------------------------------------------.
+ | yyerrorlab -- error raised explicitly by YYERROR. |
+ `---------------------------------------------------*/
+ yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and
+ the label yyerrorlab therefore never appears in user code. */
+ if (false)
+ YYERROR;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ yypop_ (yylen);
+ yylen = 0;
+ YY_STACK_PRINT ();
+ goto yyerrlab1;
+
+
+ /*-------------------------------------------------------------.
+ | yyerrlab1 -- common code for both syntax error and YYERROR. |
+ `-------------------------------------------------------------*/
+ yyerrlab1:
+ yyerrstatus_ = 3; // Each real token shifted decrements this.
+ // Pop stack until we find a state that shifts the error token.
+ for (;;)
+ {
+ yyn = yypact_[+yystack_[0].state];
+ if (!yy_pact_value_is_default_ (yyn))
+ {
+ yyn += symbol_kind::S_YYerror;
+ if (0 <= yyn && yyn <= yylast_
+ && yycheck_[yyn] == symbol_kind::S_YYerror)
+ {
+ yyn = yytable_[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ // Pop the current state because it cannot handle the error token.
+ if (yystack_.size () == 1)
+ YYABORT;
+
+ yy_destroy_ ("Error: popping", yystack_[0]);
+ yypop_ ();
+ YY_STACK_PRINT ();
+ }
+ {
+ stack_symbol_type error_token;
+
+
+ // Shift the error token.
+ error_token.state = state_type (yyn);
+ yypush_ ("Shifting", YY_MOVE (error_token));
+ }
+ goto yynewstate;
+
+
+ /*-------------------------------------.
+ | yyacceptlab -- YYACCEPT comes here. |
+ `-------------------------------------*/
+ yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+
+ /*-----------------------------------.
+ | yyabortlab -- YYABORT comes here. |
+ `-----------------------------------*/
+ yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+
+ /*-----------------------------------------------------.
+ | yyreturn -- parsing is finished, return the result. |
+ `-----------------------------------------------------*/
+ yyreturn:
+ if (!yyla.empty ())
+ yy_destroy_ ("Cleanup: discarding lookahead", yyla);
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ yypop_ (yylen);
+ YY_STACK_PRINT ();
+ while (1 < yystack_.size ())
+ {
+ yy_destroy_ ("Cleanup: popping", yystack_[0]);
+ yypop_ ();
+ }
+
+ return yyresult;
+ }
+#if YY_EXCEPTIONS
+ catch (...)
+ {
+ YYCDEBUG << "Exception caught: cleaning lookahead and stack\n";
+ // Do not try to display the values of the reclaimed symbols,
+ // as their printers might throw an exception.
+ if (!yyla.empty ())
+ yy_destroy_ (YY_NULLPTR, yyla);
+
+ while (1 < yystack_.size ())
+ {
+ yy_destroy_ (YY_NULLPTR, yystack_[0]);
+ yypop_ ();
+ }
+ throw;
+ }
+#endif // YY_EXCEPTIONS
+ }
+
+ void
+ Parser::error (const syntax_error& yyexc)
+ {
+ error (yyexc.what ());
+ }
+
+#if YYDEBUG || 0
+ const char *
+ Parser::symbol_name (symbol_kind_type yysymbol)
+ {
+ return yytname_[yysymbol];
+ }
+#endif // #if YYDEBUG || 0
+
+
+
+
+
+ const signed char Parser::yypact_ninf_ = -3;
+
+ const signed char Parser::yytable_ninf_ = -1;
+
+ const short
+ Parser::yypact_[] =
+ {
+ 0, 0, -3, -3, -2, 1, 8, 13, 14, 0,
+ 0, 0, 2, 142, -3, 50, 7, 15, 9, 11,
+ 12, -3, -3, -3, -3, 0, 6, 38, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -3, 21, 22, 48, 49, 51, 188, 0, 0,
+ 221, 96, 95, 95, 95, 95, 95, 95, 95, 141,
+ 141, 141, 141, 141, 141, 17, 17, 17, 17, 17,
+ 17, 17, 17, -3, -3, -3, -3, -3, 188, 188,
+ 0, 221
+ };
+
+ const signed char
+ Parser::yydefact_[] =
+ {
+ 2, 0, 40, 41, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3, 30, 0, 0, 0, 0, 0,
+ 0, 31, 32, 33, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 34, 0, 0, 0, 0, 0, 27, 0, 0,
+ 26, 0, 21, 22, 24, 23, 18, 20, 19, 16,
+ 17, 12, 14, 13, 15, 10, 11, 8, 9, 5,
+ 6, 7, 4, 35, 36, 37, 38, 39, 28, 29,
+ 0, 25
+ };
+
+ const signed char
+ Parser::yypgoto_[] =
+ {
+ -3, -3, -1, 4
+ };
+
+ const signed char
+ Parser::yydefgoto_[] =
+ {
+ 0, 12, 13, 14
+ };
+
+ const signed char
+ Parser::yytable_[] =
+ {
+ 15, 16, 24, 1, 17, 2, 3, 4, 5, 6,
+ 7, 18, 8, 21, 22, 23, 19, 20, 52, 58,
+ 54, 53, 55, 56, 57, 83, 84, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 9, 59, 85, 86, 51, 87, 0, 88, 89, 10,
+ 0, 11, 0, 25, 26, 27, 28, 0, 29, 0,
+ 0, 0, 30, 0, 31, 50, 32, 33, 34, 35,
+ 36, 0, 37, 0, 38, 0, 39, 0, 40, 91,
+ 41, 0, 42, 0, 43, 0, 44, 0, 45, 0,
+ 46, 0, 47, 0, 48, 0, 49, 0, 50, 25,
+ 26, 27, 28, 0, 29, 0, 90, 0, 30, 0,
+ 31, 0, 32, 33, 34, 35, 36, 37, 37, 38,
+ 38, 39, 39, 40, 40, 41, 41, 42, 42, 43,
+ 43, 44, 44, 45, 45, 46, 46, 47, 47, 48,
+ 48, 49, 49, 50, 50, 25, 26, 27, 28, 0,
+ 29, 0, 0, 0, 30, 0, 31, 0, 32, 33,
+ 34, 35, 36, -1, 37, -1, 38, -1, 39, -1,
+ 40, -1, 41, -1, 42, 43, 43, 44, 44, 45,
+ 45, 46, 46, 47, 47, 48, 48, 49, 49, 50,
+ 50, -1, -1, -1, 28, 0, 29, 0, 0, 0,
+ 30, 0, 31, 0, 32, 33, 34, 35, 36, 0,
+ 37, 0, 38, 0, 39, 0, 40, 0, 41, 0,
+ 42, 0, 43, 0, 44, 0, 45, 0, 46, 29,
+ 47, 0, 48, 30, 49, 31, 50, 32, 33, 34,
+ 35, 36, 0, 37, 0, 38, 0, 39, 0, 40,
+ 0, 41, 0, 42, 0, 43, 0, 44, 0, 45,
+ 0, 46, 0, 47, 0, 48, 0, 49, 0, 50
+ };
+
+ const signed char
+ Parser::yycheck_[] =
+ {
+ 1, 3, 0, 3, 3, 5, 6, 7, 8, 9,
+ 10, 3, 12, 9, 10, 11, 3, 3, 11, 13,
+ 11, 6, 11, 11, 25, 4, 4, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 50, 13, 4, 4, 4, 4, -1, 58, 59, 59,
+ -1, 61, -1, 13, 14, 15, 16, -1, 18, -1,
+ -1, -1, 22, -1, 24, 58, 26, 27, 28, 29,
+ 30, -1, 32, -1, 34, -1, 36, -1, 38, 90,
+ 40, -1, 42, -1, 44, -1, 46, -1, 48, -1,
+ 50, -1, 52, -1, 54, -1, 56, -1, 58, 13,
+ 14, 15, 16, -1, 18, -1, 20, -1, 22, -1,
+ 24, -1, 26, 27, 28, 29, 30, 32, 32, 34,
+ 34, 36, 36, 38, 38, 40, 40, 42, 42, 44,
+ 44, 46, 46, 48, 48, 50, 50, 52, 52, 54,
+ 54, 56, 56, 58, 58, 13, 14, 15, 16, -1,
+ 18, -1, -1, -1, 22, -1, 24, -1, 26, 27,
+ 28, 29, 30, 32, 32, 34, 34, 36, 36, 38,
+ 38, 40, 40, 42, 42, 44, 44, 46, 46, 48,
+ 48, 50, 50, 52, 52, 54, 54, 56, 56, 58,
+ 58, 13, 14, 15, 16, -1, 18, -1, -1, -1,
+ 22, -1, 24, -1, 26, 27, 28, 29, 30, -1,
+ 32, -1, 34, -1, 36, -1, 38, -1, 40, -1,
+ 42, -1, 44, -1, 46, -1, 48, -1, 50, 18,
+ 52, -1, 54, 22, 56, 24, 58, 26, 27, 28,
+ 29, 30, -1, 32, -1, 34, -1, 36, -1, 38,
+ -1, 40, -1, 42, -1, 44, -1, 46, -1, 48,
+ -1, 50, -1, 52, -1, 54, -1, 56, -1, 58
+ };
+
+ const signed char
+ Parser::yystos_[] =
+ {
+ 0, 3, 5, 6, 7, 8, 9, 10, 12, 50,
+ 59, 61, 64, 65, 66, 65, 3, 3, 3, 3,
+ 3, 66, 66, 66, 0, 13, 14, 15, 16, 18,
+ 22, 24, 26, 27, 28, 29, 30, 32, 34, 36,
+ 38, 40, 42, 44, 46, 48, 50, 52, 54, 56,
+ 58, 4, 11, 6, 11, 11, 11, 65, 13, 13,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 4, 4, 4, 4, 4, 65, 65,
+ 20, 65
+ };
+
+ const signed char
+ Parser::yyr1_[] =
+ {
+ 0, 63, 64, 64, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66
+ };
+
+ const signed char
+ Parser::yyr2_[] =
+ {
+ 0, 2, 0, 1, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 5, 3, 3, 4, 4,
+ 1, 2, 2, 2, 3, 4, 4, 4, 4, 4,
+ 1, 1
+ };
+
+
+#if YYDEBUG
+ // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ // First, the terminals, then, starting at \a YYNTOKENS, nonterminals.
+ const char*
+ const Parser::yytname_[] =
+ {
+ "\"end of file\"", "error", "\"invalid token\"", "\"(\"", "\")\"",
+ "\"number\"", "\"name\"", "FNAME", "HASPROP", "JGROUP", "JPARENT",
+ "QSTR", "FILEIOVFD", "IN", "SOME", "ORDR", "COMMA", "\",\"", "QWE",
+ "\"?\"", "COLON", "\":\"", "AND", "\"&&\"", "OR", "\"|\"", "EQV", "NEQV",
+ "BITAND", "BITOR", "BITXOR", "\"^\"", "EQ", "\"=\"", "NE", "\"!=\"",
+ "LT", "\"<\"", "GT", "\">\"", "LE", "\"<=\"", "GE", "\">=\"", "LS",
+ "\"<<\"", "RS", "\">>\"", "ADD", "\"+\"", "MINUS", "\"-\"", "MUL",
+ "\"*\"", "DIV", "\"/\"", "REM", "\"%\"", "DEG", "NOT", "\"!\"", "BITNOT",
+ "\"~\"", "$accept", "S", "exp", "term", YY_NULLPTR
+ };
+#endif
+
+
+#if YYDEBUG
+ const unsigned char
+ Parser::yyrline_[] =
+ {
+ 0, 104, 104, 105, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+ 123, 124, 125, 126, 127, 128, 130, 131, 132, 133,
+ 134, 136, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147
+ };
+
+ void
+ Parser::yy_stack_print_ () const
+ {
+ *yycdebug_ << "Stack now";
+ for (stack_type::const_iterator
+ i = yystack_.begin (),
+ i_end = yystack_.end ();
+ i != i_end; ++i)
+ *yycdebug_ << ' ' << int (i->state);
+ *yycdebug_ << '\n';
+ }
+
+ void
+ Parser::yy_reduce_print_ (int yyrule) const
+ {
+ int yylno = yyrline_[yyrule];
+ int yynrhs = yyr2_[yyrule];
+ // Print the symbols being reduced, and their result.
+ *yycdebug_ << "Reducing stack by rule " << yyrule - 1
+ << " (line " << yylno << "):\n";
+ // The symbols being reduced.
+ for (int yyi = 0; yyi < yynrhs; yyi++)
+ YY_SYMBOL_PRINT (" $" << yyi + 1 << " =",
+ yystack_[(yynrhs) - (yyi + 1)]);
+ }
+#endif // YYDEBUG
+
+
+#line 50 "QLParser.yy"
+} // QL
+#line 1210 "QLParser.tab.cc"
+
+#line 149 "QLParser.yy"
+
+
+namespace QL
+{
+ static Parser::symbol_type
+ unget_ret (std::istream &in, char c, Parser::symbol_type tok)
+ {
+ in.putback (c);
+ return tok;
+ }
+
+ static Expression *
+ processName (char *name)
+ {
+ int propID = dbeSession->getPropIdByName (name);
+ if (propID != PROP_NONE)
+ {
+ Expression *expr = new Expression (Expression::OP_NUM, (uint64_t) propID);
+ Expression *ret = new Expression (Expression::OP_NAME, expr);
+ delete expr;
+ return ret;
+ }
+
+ // If a name is not statically known try user defined objects
+ Expression *expr = dbeSession->findObjDefByName (name);
+ if (expr != NULL)
+ return expr->copy();
+
+ throw Parser::syntax_error ("Name not found");
+ }
+
+ static Parser::symbol_type
+ yylex (QL::Result &result)
+ {
+ int base = 0;
+ int c;
+
+ do
+ c = result.in.get ();
+ while (result.in && (c == ' ' || c == '\t'));
+ if (!result.in)
+ return Parser::make_YYEOF ();
+
+ switch (c)
+ {
+ case '\n': return Parser::make_YYEOF ();
+ case '(': return Parser::make_LPAR () ;
+ case ')': return Parser::make_RPAR ();
+ case ',': return Parser::make_COMMA ();
+ case '%': return Parser::make_REM ();
+ case '/': return Parser::make_DIV ();
+ case '*': return Parser::make_MUL ();
+ case '-': return Parser::make_MINUS ();
+ case '+': return Parser::make_ADD ();
+ case '~': return Parser::make_BITNOT ();
+ case '^': return Parser::make_BITXOR ();
+ case '?': return Parser::make_QWE ();
+ case ':': return Parser::make_COLON ();
+ case '|':
+ c = result.in.get ();
+ if (c == '|')
+ return Parser::make_OR ();
+ else
+ return unget_ret (result.in, c, Parser::make_BITOR ());
+ case '&':
+ c = result.in.get ();
+ if (c == '&')
+ return Parser::make_AND ();
+ else
+ return unget_ret (result.in, c, Parser::make_BITAND ());
+ case '!':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_NE ();
+ else
+ return unget_ret (result.in, c, Parser::make_NOT ());
+ case '=':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_EQ ();
+ else
+ throw Parser::syntax_error ("Syntax error after =");
+ case '<':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_LE ();
+ else if (c == '<')
+ return Parser::make_LS ();
+ else
+ return unget_ret (result.in, c, Parser::make_LT ());
+ case '>':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_GE ();
+ else if (c == '>')
+ return Parser::make_RS ();
+ else
+ return unget_ret (result.in, c, Parser::make_GT ());
+ case '"':
+ {
+ int maxsz = 16;
+ char *str = (char *) malloc (maxsz);
+ char *ptr = str;
+
+ for (;;)
+ {
+ c = result.in.get ();
+ if (!result.in)
+ {
+ free (str);
+ throw Parser::syntax_error ("Unclosed \"");
+ }
+
+ switch (c)
+ {
+ case '"':
+ *ptr = (char)0;
+ // XXX omazur: need new string type
+ return Parser::make_QSTR (new Expression (Expression::OP_NUM, (uint64_t) str));
+ case 0:
+ case '\n':
+ free (str);
+ throw Parser::syntax_error ("Multiline strings are not supported");
+ default:
+ if (ptr - str >= maxsz)
+ {
+ size_t len = ptr - str;
+ maxsz = maxsz > 8192 ? maxsz + 8192 : maxsz * 2;
+ char *new_s = (char *) realloc (str, maxsz);
+ str = new_s;
+ ptr = str + len;
+ }
+ *ptr++ = c;
+ }
+ }
+ }
+ default:
+ if (c == '0')
+ {
+ base = 8;
+ c = result.in.get ();
+ if ( c == 'x' )
+ {
+ base = 16;
+ c = result.in.get ();
+ }
+ }
+ else if (c >= '1' && c <='9')
+ base = 10;
+
+ if (base)
+ {
+ uint64_t lval = 0;
+ for (;;)
+ {
+ int digit = -1;
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ digit = c - '0';
+ break;
+ case '8': case '9':
+ if (base > 8)
+ digit = c - '0';
+ break;
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ if (base == 16)
+ digit = c - 'a' + 10;
+ break;
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ if (base == 16)
+ digit = c - 'A' + 10;
+ break;
+ }
+ if (digit == -1)
+ {
+ result.in.putback (c);
+ break;
+ }
+ lval = lval * base + digit;
+ c = result.in.get ();
+ }
+ return Parser::make_NUM (new Expression (Expression::OP_NUM, lval));
+ }
+
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+ {
+ char name[32]; // omazur XXX: accept any length
+ name[0] = (char)c;
+ for (size_t i = 1; i < sizeof (name); i++)
+ {
+ c = result.in.get ();
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || (c == '_'))
+ name[i] = c;
+ else
+ {
+ name[i] = (char)0;
+ result.in.putback (c);
+ break;
+ }
+ }
+
+ if (strcasecmp (name, NTXT ("IN")) == 0)
+ return Parser::make_IN ();
+ else if (strcasecmp (name, NTXT ("SOME")) == 0)
+ return Parser::make_SOME ();
+ else if (strcasecmp (name, NTXT ("ORDERED")) == 0)
+ return Parser::make_ORDR ();
+ else if (strcasecmp (name, NTXT ("TRUE")) == 0)
+ return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 1));
+ else if (strcasecmp (name, NTXT ("FALSE")) == 0)
+ return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 0));
+ else if (strcasecmp (name, NTXT ("FNAME")) == 0)
+ return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_FNAME));
+ else if (strcasecmp (name, NTXT ("HAS_PROP")) == 0)
+ return Parser::make_HASPROP ();
+ else if (strcasecmp (name, NTXT ("JGROUP")) == 0)
+ return Parser::make_JGROUP (new Expression (Expression::OP_NUM, Expression::JAVA_JGROUP));
+ else if (strcasecmp (name, NTXT ("JPARENT")) == 0 )
+ return Parser::make_JPARENT (new Expression (Expression::OP_NUM, Expression::JAVA_JPARENT));
+ else if (strcasecmp (name, NTXT ("DNAME")) == 0)
+ return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_DNAME));
+ else if (strcasecmp (name, NTXT ("FILEIOVFD")) == 0 )
+ return Parser::make_FILEIOVFD (new Expression (Expression::OP_NUM, (uint64_t) 0));
+
+ return Parser::make_NAME (processName (name));
+ }
+
+ throw Parser::syntax_error ("Syntax error");
+ }
+ }
+ void
+ Parser::error (const std::string &)
+ {
+ // do nothing for now
+ }
+}
+
diff --git a/gprofng/src/QLParser.tab.hh b/gprofng/src/QLParser.tab.hh
new file mode 100644
index 0000000..eaf2cb5
--- /dev/null
+++ b/gprofng/src/QLParser.tab.hh
@@ -0,0 +1,2038 @@
+// A Bison parser, made by GNU Bison 3.7.5.
+
+// Skeleton interface for Bison LALR(1) parsers in C++
+
+// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
+
+// 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 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+// As a special exception, you may create a larger work that contains
+// part or all of the Bison parser skeleton and distribute that work
+// under terms of your choice, so long as that work isn't itself a
+// parser generator using the skeleton or a modified version thereof
+// as a parser skeleton. Alternatively, if you modify or redistribute
+// the parser skeleton itself, you may (at your option) remove this
+// special exception, which will cause the skeleton and the resulting
+// Bison output files to be licensed under the GNU General Public
+// License without this special exception.
+
+// This special exception was added by the Free Software Foundation in
+// version 2.2 of Bison.
+
+
+/**
+ ** \file QLParser.tab.hh
+ ** Define the QL::parser class.
+ */
+
+// C++ LALR(1) parser skeleton written by Akim Demaille.
+
+// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+// especially those whose name start with YY_ or yy_. They are
+// private implementation details that can be changed or removed.
+
+#ifndef YY_YY_QLPARSER_TAB_HH_INCLUDED
+# define YY_YY_QLPARSER_TAB_HH_INCLUDED
+// "%code requires" blocks.
+#line 33 "QLParser.yy"
+
+#include "QLParser.h"
+#include "DbeSession.h"
+#include "Expression.h"
+#include "Table.h"
+#include "i18n.h"
+
+#line 57 "QLParser.tab.hh"
+
+# include <cassert>
+# include <cstdlib> // std::abort
+# include <iostream>
+# include <stdexcept>
+# include <string>
+# include <vector>
+
+#if defined __cplusplus
+# define YY_CPLUSPLUS __cplusplus
+#else
+# define YY_CPLUSPLUS 199711L
+#endif
+
+// Support move semantics when possible.
+#if 201103L <= YY_CPLUSPLUS
+# define YY_MOVE std::move
+# define YY_MOVE_OR_COPY move
+# define YY_MOVE_REF(Type) Type&&
+# define YY_RVREF(Type) Type&&
+# define YY_COPY(Type) Type
+#else
+# define YY_MOVE
+# define YY_MOVE_OR_COPY copy
+# define YY_MOVE_REF(Type) Type&
+# define YY_RVREF(Type) const Type&
+# define YY_COPY(Type) const Type&
+#endif
+
+// Support noexcept when possible.
+#if 201103L <= YY_CPLUSPLUS
+# define YY_NOEXCEPT noexcept
+# define YY_NOTHROW
+#else
+# define YY_NOEXCEPT
+# define YY_NOTHROW throw ()
+#endif
+
+// Support constexpr when possible.
+#if 201703 <= YY_CPLUSPLUS
+# define YY_CONSTEXPR constexpr
+#else
+# define YY_CONSTEXPR
+#endif
+
+#include <typeinfo>
+#ifndef YY_ASSERT
+# include <cassert>
+# define YY_ASSERT assert
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YY_USE(E) ((void) (E))
+#else
+# define YY_USE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+#line 50 "QLParser.yy"
+namespace QL {
+#line 192 "QLParser.tab.hh"
+
+
+
+
+ /// A Bison parser.
+ class Parser
+ {
+ public:
+#ifndef YYSTYPE
+ /// A buffer to store and retrieve objects.
+ ///
+ /// Sort of a variant, but does not keep track of the nature
+ /// of the stored data, since that knowledge is available
+ /// via the current parser state.
+ class semantic_type
+ {
+ public:
+ /// Type of *this.
+ typedef semantic_type self_type;
+
+ /// Empty construction.
+ semantic_type () YY_NOEXCEPT
+ : yybuffer_ ()
+ , yytypeid_ (YY_NULLPTR)
+ {}
+
+ /// Construct and fill.
+ template <typename T>
+ semantic_type (YY_RVREF (T) t)
+ : yytypeid_ (&typeid (T))
+ {
+ YY_ASSERT (sizeof (T) <= size);
+ new (yyas_<T> ()) T (YY_MOVE (t));
+ }
+
+#if 201103L <= YY_CPLUSPLUS
+ /// Non copyable.
+ semantic_type (const self_type&) = delete;
+ /// Non copyable.
+ self_type& operator= (const self_type&) = delete;
+#endif
+
+ /// Destruction, allowed only if empty.
+ ~semantic_type () YY_NOEXCEPT
+ {
+ YY_ASSERT (!yytypeid_);
+ }
+
+# if 201103L <= YY_CPLUSPLUS
+ /// Instantiate a \a T in here from \a t.
+ template <typename T, typename... U>
+ T&
+ emplace (U&&... u)
+ {
+ YY_ASSERT (!yytypeid_);
+ YY_ASSERT (sizeof (T) <= size);
+ yytypeid_ = & typeid (T);
+ return *new (yyas_<T> ()) T (std::forward <U>(u)...);
+ }
+# else
+ /// Instantiate an empty \a T in here.
+ template <typename T>
+ T&
+ emplace ()
+ {
+ YY_ASSERT (!yytypeid_);
+ YY_ASSERT (sizeof (T) <= size);
+ yytypeid_ = & typeid (T);
+ return *new (yyas_<T> ()) T ();
+ }
+
+ /// Instantiate a \a T in here from \a t.
+ template <typename T>
+ T&
+ emplace (const T& t)
+ {
+ YY_ASSERT (!yytypeid_);
+ YY_ASSERT (sizeof (T) <= size);
+ yytypeid_ = & typeid (T);
+ return *new (yyas_<T> ()) T (t);
+ }
+# endif
+
+ /// Instantiate an empty \a T in here.
+ /// Obsolete, use emplace.
+ template <typename T>
+ T&
+ build ()
+ {
+ return emplace<T> ();
+ }
+
+ /// Instantiate a \a T in here from \a t.
+ /// Obsolete, use emplace.
+ template <typename T>
+ T&
+ build (const T& t)
+ {
+ return emplace<T> (t);
+ }
+
+ /// Accessor to a built \a T.
+ template <typename T>
+ T&
+ as () YY_NOEXCEPT
+ {
+ YY_ASSERT (yytypeid_);
+ YY_ASSERT (*yytypeid_ == typeid (T));
+ YY_ASSERT (sizeof (T) <= size);
+ return *yyas_<T> ();
+ }
+
+ /// Const accessor to a built \a T (for %printer).
+ template <typename T>
+ const T&
+ as () const YY_NOEXCEPT
+ {
+ YY_ASSERT (yytypeid_);
+ YY_ASSERT (*yytypeid_ == typeid (T));
+ YY_ASSERT (sizeof (T) <= size);
+ return *yyas_<T> ();
+ }
+
+ /// Swap the content with \a that, of same type.
+ ///
+ /// Both variants must be built beforehand, because swapping the actual
+ /// data requires reading it (with as()), and this is not possible on
+ /// unconstructed variants: it would require some dynamic testing, which
+ /// should not be the variant's responsibility.
+ /// Swapping between built and (possibly) non-built is done with
+ /// self_type::move ().
+ template <typename T>
+ void
+ swap (self_type& that) YY_NOEXCEPT
+ {
+ YY_ASSERT (yytypeid_);
+ YY_ASSERT (*yytypeid_ == *that.yytypeid_);
+ std::swap (as<T> (), that.as<T> ());
+ }
+
+ /// Move the content of \a that to this.
+ ///
+ /// Destroys \a that.
+ template <typename T>
+ void
+ move (self_type& that)
+ {
+# if 201103L <= YY_CPLUSPLUS
+ emplace<T> (std::move (that.as<T> ()));
+# else
+ emplace<T> ();
+ swap<T> (that);
+# endif
+ that.destroy<T> ();
+ }
+
+# if 201103L <= YY_CPLUSPLUS
+ /// Move the content of \a that to this.
+ template <typename T>
+ void
+ move (self_type&& that)
+ {
+ emplace<T> (std::move (that.as<T> ()));
+ that.destroy<T> ();
+ }
+#endif
+
+ /// Copy the content of \a that to this.
+ template <typename T>
+ void
+ copy (const self_type& that)
+ {
+ emplace<T> (that.as<T> ());
+ }
+
+ /// Destroy the stored \a T.
+ template <typename T>
+ void
+ destroy ()
+ {
+ as<T> ().~T ();
+ yytypeid_ = YY_NULLPTR;
+ }
+
+ private:
+#if YY_CPLUSPLUS < 201103L
+ /// Non copyable.
+ semantic_type (const self_type&);
+ /// Non copyable.
+ self_type& operator= (const self_type&);
+#endif
+
+ /// Accessor to raw memory as \a T.
+ template <typename T>
+ T*
+ yyas_ () YY_NOEXCEPT
+ {
+ void *yyp = yybuffer_.yyraw;
+ return static_cast<T*> (yyp);
+ }
+
+ /// Const accessor to raw memory as \a T.
+ template <typename T>
+ const T*
+ yyas_ () const YY_NOEXCEPT
+ {
+ const void *yyp = yybuffer_.yyraw;
+ return static_cast<const T*> (yyp);
+ }
+
+ /// An auxiliary type to compute the largest semantic type.
+ union union_type
+ {
+ // "number"
+ // "name"
+ // FNAME
+ // JGROUP
+ // JPARENT
+ // QSTR
+ // FILEIOVFD
+ // exp
+ // term
+ char dummy1[sizeof (Expression *)];
+ };
+
+ /// The size of the largest semantic type.
+ enum { size = sizeof (union_type) };
+
+ /// A buffer to store semantic values.
+ union
+ {
+ /// Strongest alignment constraints.
+ long double yyalign_me;
+ /// A buffer large enough to store any of the semantic values.
+ char yyraw[size];
+ } yybuffer_;
+
+ /// Whether the content is built: if defined, the name of the stored type.
+ const std::type_info *yytypeid_;
+ };
+
+#else
+ typedef YYSTYPE semantic_type;
+#endif
+
+ /// Syntax errors thrown from user actions.
+ struct syntax_error : std::runtime_error
+ {
+ syntax_error (const std::string& m)
+ : std::runtime_error (m)
+ {}
+
+ syntax_error (const syntax_error& s)
+ : std::runtime_error (s.what ())
+ {}
+
+ ~syntax_error () YY_NOEXCEPT YY_NOTHROW;
+ };
+
+ /// Token kinds.
+ struct token
+ {
+ enum token_kind_type
+ {
+ L_YYEMPTY = -2,
+ L_YYEOF = 0, // "end of file"
+ L_YYerror = 256, // error
+ L_YYUNDEF = 257, // "invalid token"
+ L_LPAR = 258, // "("
+ L_RPAR = 259, // ")"
+ L_NUM = 260, // "number"
+ L_NAME = 261, // "name"
+ L_FNAME = 262, // FNAME
+ L_HASPROP = 263, // HASPROP
+ L_JGROUP = 264, // JGROUP
+ L_JPARENT = 265, // JPARENT
+ L_QSTR = 266, // QSTR
+ L_FILEIOVFD = 267, // FILEIOVFD
+ L_IN = 268, // IN
+ L_SOME = 269, // SOME
+ L_ORDR = 270, // ORDR
+ L_COMMA = 271, // COMMA
+ L_QWE = 273, // QWE
+ L_COLON = 275, // COLON
+ L_AND = 277, // AND
+ L_OR = 279, // OR
+ L_EQV = 281, // EQV
+ L_NEQV = 282, // NEQV
+ L_BITAND = 283, // BITAND
+ L_BITOR = 284, // BITOR
+ L_BITXOR = 285, // BITXOR
+ L_EQ = 287, // EQ
+ L_NE = 289, // NE
+ L_LT = 291, // LT
+ L_GT = 293, // GT
+ L_LE = 295, // LE
+ L_GE = 297, // GE
+ L_LS = 299, // LS
+ L_RS = 301, // RS
+ L_ADD = 303, // ADD
+ L_MINUS = 305, // MINUS
+ L_MUL = 307, // MUL
+ L_DIV = 309, // DIV
+ L_REM = 311, // REM
+ L_DEG = 313, // DEG
+ L_NOT = 314, // NOT
+ L_BITNOT = 316 // BITNOT
+ };
+ /// Backward compatibility alias (Bison 3.6).
+ typedef token_kind_type yytokentype;
+ };
+
+ /// Token kind, as returned by yylex.
+ typedef token::yytokentype token_kind_type;
+
+ /// Backward compatibility alias (Bison 3.6).
+ typedef token_kind_type token_type;
+
+ /// Symbol kinds.
+ struct symbol_kind
+ {
+ enum symbol_kind_type
+ {
+ YYNTOKENS = 63, ///< Number of tokens.
+ S_YYEMPTY = -2,
+ S_YYEOF = 0, // "end of file"
+ S_YYerror = 1, // error
+ S_YYUNDEF = 2, // "invalid token"
+ S_LPAR = 3, // "("
+ S_RPAR = 4, // ")"
+ S_NUM = 5, // "number"
+ S_NAME = 6, // "name"
+ S_FNAME = 7, // FNAME
+ S_HASPROP = 8, // HASPROP
+ S_JGROUP = 9, // JGROUP
+ S_JPARENT = 10, // JPARENT
+ S_QSTR = 11, // QSTR
+ S_FILEIOVFD = 12, // FILEIOVFD
+ S_IN = 13, // IN
+ S_SOME = 14, // SOME
+ S_ORDR = 15, // ORDR
+ S_COMMA = 16, // COMMA
+ S_17_ = 17, // ","
+ S_QWE = 18, // QWE
+ S_19_ = 19, // "?"
+ S_COLON = 20, // COLON
+ S_21_ = 21, // ":"
+ S_AND = 22, // AND
+ S_23_ = 23, // "&&"
+ S_OR = 24, // OR
+ S_25_ = 25, // "|"
+ S_EQV = 26, // EQV
+ S_NEQV = 27, // NEQV
+ S_BITAND = 28, // BITAND
+ S_BITOR = 29, // BITOR
+ S_BITXOR = 30, // BITXOR
+ S_31_ = 31, // "^"
+ S_EQ = 32, // EQ
+ S_33_ = 33, // "="
+ S_NE = 34, // NE
+ S_35_ = 35, // "!="
+ S_LT = 36, // LT
+ S_37_ = 37, // "<"
+ S_GT = 38, // GT
+ S_39_ = 39, // ">"
+ S_LE = 40, // LE
+ S_41_ = 41, // "<="
+ S_GE = 42, // GE
+ S_43_ = 43, // ">="
+ S_LS = 44, // LS
+ S_45_ = 45, // "<<"
+ S_RS = 46, // RS
+ S_47_ = 47, // ">>"
+ S_ADD = 48, // ADD
+ S_49_ = 49, // "+"
+ S_MINUS = 50, // MINUS
+ S_51_ = 51, // "-"
+ S_MUL = 52, // MUL
+ S_53_ = 53, // "*"
+ S_DIV = 54, // DIV
+ S_55_ = 55, // "/"
+ S_REM = 56, // REM
+ S_57_ = 57, // "%"
+ S_DEG = 58, // DEG
+ S_NOT = 59, // NOT
+ S_60_ = 60, // "!"
+ S_BITNOT = 61, // BITNOT
+ S_62_ = 62, // "~"
+ S_YYACCEPT = 63, // $accept
+ S_S = 64, // S
+ S_exp = 65, // exp
+ S_term = 66 // term
+ };
+ };
+
+ /// (Internal) symbol kind.
+ typedef symbol_kind::symbol_kind_type symbol_kind_type;
+
+ /// The number of tokens.
+ static const symbol_kind_type YYNTOKENS = symbol_kind::YYNTOKENS;
+
+ /// A complete symbol.
+ ///
+ /// Expects its Base type to provide access to the symbol kind
+ /// via kind ().
+ ///
+ /// Provide access to semantic value.
+ template <typename Base>
+ struct basic_symbol : Base
+ {
+ /// Alias to Base.
+ typedef Base super_type;
+
+ /// Default constructor.
+ basic_symbol ()
+ : value ()
+ {}
+
+#if 201103L <= YY_CPLUSPLUS
+ /// Move constructor.
+ basic_symbol (basic_symbol&& that)
+ : Base (std::move (that))
+ , value ()
+ {
+ switch (this->kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.move< Expression * > (std::move (that.value));
+ break;
+
+ default:
+ break;
+ }
+
+ }
+#endif
+
+ /// Copy constructor.
+ basic_symbol (const basic_symbol& that);
+
+ /// Constructors for typed symbols.
+#if 201103L <= YY_CPLUSPLUS
+ basic_symbol (typename Base::kind_type t)
+ : Base (t)
+ {}
+#else
+ basic_symbol (typename Base::kind_type t)
+ : Base (t)
+ {}
+#endif
+
+#if 201103L <= YY_CPLUSPLUS
+ basic_symbol (typename Base::kind_type t, Expression *&& v)
+ : Base (t)
+ , value (std::move (v))
+ {}
+#else
+ basic_symbol (typename Base::kind_type t, const Expression *& v)
+ : Base (t)
+ , value (v)
+ {}
+#endif
+
+ /// Destroy the symbol.
+ ~basic_symbol ()
+ {
+ clear ();
+ }
+
+ /// Destroy contents, and record that is empty.
+ void clear () YY_NOEXCEPT
+ {
+ // User destructor.
+ symbol_kind_type yykind = this->kind ();
+ basic_symbol<Base>& yysym = *this;
+ (void) yysym;
+ switch (yykind)
+ {
+ case symbol_kind::S_NUM: // "number"
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 682 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_NAME: // "name"
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 688 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_FNAME: // FNAME
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 694 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_JGROUP: // JGROUP
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 700 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_JPARENT: // JPARENT
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 706 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_QSTR: // QSTR
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 712 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 718 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_exp: // exp
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 724 "QLParser.tab.hh"
+ break;
+
+ case symbol_kind::S_term: // term
+#line 100 "QLParser.yy"
+ { delete yysym.value.template as < Expression * > (); }
+#line 730 "QLParser.tab.hh"
+ break;
+
+ default:
+ break;
+ }
+
+ // Value type destructor.
+switch (yykind)
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.template destroy< Expression * > ();
+ break;
+
+ default:
+ break;
+ }
+
+ Base::clear ();
+ }
+
+#if YYDEBUG || 0
+ /// The user-facing name of this symbol.
+ const char *name () const YY_NOEXCEPT
+ {
+ return Parser::symbol_name (this->kind ());
+ }
+#endif // #if YYDEBUG || 0
+
+
+ /// Backward compatibility (Bison 3.6).
+ symbol_kind_type type_get () const YY_NOEXCEPT;
+
+ /// Whether empty.
+ bool empty () const YY_NOEXCEPT;
+
+ /// Destructive move, \a s is emptied into this.
+ void move (basic_symbol& s);
+
+ /// The semantic value.
+ semantic_type value;
+
+ private:
+#if YY_CPLUSPLUS < 201103L
+ /// Assignment operator.
+ basic_symbol& operator= (const basic_symbol& that);
+#endif
+ };
+
+ /// Type access provider for token (enum) based symbols.
+ struct by_kind
+ {
+ /// Default constructor.
+ by_kind ();
+
+#if 201103L <= YY_CPLUSPLUS
+ /// Move constructor.
+ by_kind (by_kind&& that);
+#endif
+
+ /// Copy constructor.
+ by_kind (const by_kind& that);
+
+ /// The symbol kind as needed by the constructor.
+ typedef token_kind_type kind_type;
+
+ /// Constructor from (external) token numbers.
+ by_kind (kind_type t);
+
+ /// Record that this symbol is empty.
+ void clear () YY_NOEXCEPT;
+
+ /// Steal the symbol kind from \a that.
+ void move (by_kind& that);
+
+ /// The (internal) type number (corresponding to \a type).
+ /// \a empty when empty.
+ symbol_kind_type kind () const YY_NOEXCEPT;
+
+ /// Backward compatibility (Bison 3.6).
+ symbol_kind_type type_get () const YY_NOEXCEPT;
+
+ /// The symbol kind.
+ /// \a S_YYEMPTY when empty.
+ symbol_kind_type kind_;
+ };
+
+ /// Backward compatibility for a private implementation detail (Bison 3.6).
+ typedef by_kind by_type;
+
+ /// "External" symbols: returned by the scanner.
+ struct symbol_type : basic_symbol<by_kind>
+ {
+ /// Superclass.
+ typedef basic_symbol<by_kind> super_type;
+
+ /// Empty symbol.
+ symbol_type () {}
+
+ /// Constructor for valueless symbols, and symbols from each type.
+#if 201103L <= YY_CPLUSPLUS
+ symbol_type (int tok)
+ : super_type(token_type (tok))
+#else
+ symbol_type (int tok)
+ : super_type(token_type (tok))
+#endif
+ {
+ YY_ASSERT (tok == token::L_YYEOF
+ || (token::L_YYerror <= tok && tok <= token::L_RPAR)
+ || tok == token::L_HASPROP
+ || (token::L_IN <= tok && tok <= 317));
+ }
+#if 201103L <= YY_CPLUSPLUS
+ symbol_type (int tok, Expression * v)
+ : super_type(token_type (tok), std::move (v))
+#else
+ symbol_type (int tok, const Expression *& v)
+ : super_type(token_type (tok), v)
+#endif
+ {
+ YY_ASSERT ((token::L_NUM <= tok && tok <= token::L_FNAME)
+ || (token::L_JGROUP <= tok && tok <= token::L_FILEIOVFD));
+ }
+ };
+
+ /// Build a parser object.
+ Parser (QL::Result &result_yyarg);
+ virtual ~Parser ();
+
+#if 201103L <= YY_CPLUSPLUS
+ /// Non copyable.
+ Parser (const Parser&) = delete;
+ /// Non copyable.
+ Parser& operator= (const Parser&) = delete;
+#endif
+
+ /// Parse. An alias for parse ().
+ /// \returns 0 iff parsing succeeded.
+ int operator() ();
+
+ /// Parse.
+ /// \returns 0 iff parsing succeeded.
+ virtual int parse ();
+
+#if YYDEBUG
+ /// The current debugging stream.
+ std::ostream& debug_stream () const YY_ATTRIBUTE_PURE;
+ /// Set the current debugging stream.
+ void set_debug_stream (std::ostream &);
+
+ /// Type for debugging levels.
+ typedef int debug_level_type;
+ /// The current debugging level.
+ debug_level_type debug_level () const YY_ATTRIBUTE_PURE;
+ /// Set the current debugging level.
+ void set_debug_level (debug_level_type l);
+#endif
+
+ /// Report a syntax error.
+ /// \param msg a description of the syntax error.
+ virtual void error (const std::string& msg);
+
+ /// Report a syntax error.
+ void error (const syntax_error& err);
+
+#if YYDEBUG || 0
+ /// The user-facing name of the symbol whose (internal) number is
+ /// YYSYMBOL. No bounds checking.
+ static const char *symbol_name (symbol_kind_type yysymbol);
+#endif // #if YYDEBUG || 0
+
+
+ // Implementation of make_symbol for each symbol type.
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_YYEOF ()
+ {
+ return symbol_type (token::L_YYEOF);
+ }
+#else
+ static
+ symbol_type
+ make_YYEOF ()
+ {
+ return symbol_type (token::L_YYEOF);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_YYerror ()
+ {
+ return symbol_type (token::L_YYerror);
+ }
+#else
+ static
+ symbol_type
+ make_YYerror ()
+ {
+ return symbol_type (token::L_YYerror);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_YYUNDEF ()
+ {
+ return symbol_type (token::L_YYUNDEF);
+ }
+#else
+ static
+ symbol_type
+ make_YYUNDEF ()
+ {
+ return symbol_type (token::L_YYUNDEF);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_LPAR ()
+ {
+ return symbol_type (token::L_LPAR);
+ }
+#else
+ static
+ symbol_type
+ make_LPAR ()
+ {
+ return symbol_type (token::L_LPAR);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_RPAR ()
+ {
+ return symbol_type (token::L_RPAR);
+ }
+#else
+ static
+ symbol_type
+ make_RPAR ()
+ {
+ return symbol_type (token::L_RPAR);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_NUM (Expression * v)
+ {
+ return symbol_type (token::L_NUM, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_NUM (const Expression *& v)
+ {
+ return symbol_type (token::L_NUM, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_NAME (Expression * v)
+ {
+ return symbol_type (token::L_NAME, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_NAME (const Expression *& v)
+ {
+ return symbol_type (token::L_NAME, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_FNAME (Expression * v)
+ {
+ return symbol_type (token::L_FNAME, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_FNAME (const Expression *& v)
+ {
+ return symbol_type (token::L_FNAME, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_HASPROP ()
+ {
+ return symbol_type (token::L_HASPROP);
+ }
+#else
+ static
+ symbol_type
+ make_HASPROP ()
+ {
+ return symbol_type (token::L_HASPROP);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_JGROUP (Expression * v)
+ {
+ return symbol_type (token::L_JGROUP, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_JGROUP (const Expression *& v)
+ {
+ return symbol_type (token::L_JGROUP, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_JPARENT (Expression * v)
+ {
+ return symbol_type (token::L_JPARENT, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_JPARENT (const Expression *& v)
+ {
+ return symbol_type (token::L_JPARENT, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_QSTR (Expression * v)
+ {
+ return symbol_type (token::L_QSTR, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_QSTR (const Expression *& v)
+ {
+ return symbol_type (token::L_QSTR, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_FILEIOVFD (Expression * v)
+ {
+ return symbol_type (token::L_FILEIOVFD, std::move (v));
+ }
+#else
+ static
+ symbol_type
+ make_FILEIOVFD (const Expression *& v)
+ {
+ return symbol_type (token::L_FILEIOVFD, v);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_IN ()
+ {
+ return symbol_type (token::L_IN);
+ }
+#else
+ static
+ symbol_type
+ make_IN ()
+ {
+ return symbol_type (token::L_IN);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_SOME ()
+ {
+ return symbol_type (token::L_SOME);
+ }
+#else
+ static
+ symbol_type
+ make_SOME ()
+ {
+ return symbol_type (token::L_SOME);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_ORDR ()
+ {
+ return symbol_type (token::L_ORDR);
+ }
+#else
+ static
+ symbol_type
+ make_ORDR ()
+ {
+ return symbol_type (token::L_ORDR);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_COMMA ()
+ {
+ return symbol_type (token::L_COMMA);
+ }
+#else
+ static
+ symbol_type
+ make_COMMA ()
+ {
+ return symbol_type (token::L_COMMA);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_QWE ()
+ {
+ return symbol_type (token::L_QWE);
+ }
+#else
+ static
+ symbol_type
+ make_QWE ()
+ {
+ return symbol_type (token::L_QWE);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_COLON ()
+ {
+ return symbol_type (token::L_COLON);
+ }
+#else
+ static
+ symbol_type
+ make_COLON ()
+ {
+ return symbol_type (token::L_COLON);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_AND ()
+ {
+ return symbol_type (token::L_AND);
+ }
+#else
+ static
+ symbol_type
+ make_AND ()
+ {
+ return symbol_type (token::L_AND);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_OR ()
+ {
+ return symbol_type (token::L_OR);
+ }
+#else
+ static
+ symbol_type
+ make_OR ()
+ {
+ return symbol_type (token::L_OR);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_EQV ()
+ {
+ return symbol_type (token::L_EQV);
+ }
+#else
+ static
+ symbol_type
+ make_EQV ()
+ {
+ return symbol_type (token::L_EQV);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_NEQV ()
+ {
+ return symbol_type (token::L_NEQV);
+ }
+#else
+ static
+ symbol_type
+ make_NEQV ()
+ {
+ return symbol_type (token::L_NEQV);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_BITAND ()
+ {
+ return symbol_type (token::L_BITAND);
+ }
+#else
+ static
+ symbol_type
+ make_BITAND ()
+ {
+ return symbol_type (token::L_BITAND);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_BITOR ()
+ {
+ return symbol_type (token::L_BITOR);
+ }
+#else
+ static
+ symbol_type
+ make_BITOR ()
+ {
+ return symbol_type (token::L_BITOR);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_BITXOR ()
+ {
+ return symbol_type (token::L_BITXOR);
+ }
+#else
+ static
+ symbol_type
+ make_BITXOR ()
+ {
+ return symbol_type (token::L_BITXOR);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_EQ ()
+ {
+ return symbol_type (token::L_EQ);
+ }
+#else
+ static
+ symbol_type
+ make_EQ ()
+ {
+ return symbol_type (token::L_EQ);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_NE ()
+ {
+ return symbol_type (token::L_NE);
+ }
+#else
+ static
+ symbol_type
+ make_NE ()
+ {
+ return symbol_type (token::L_NE);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_LT ()
+ {
+ return symbol_type (token::L_LT);
+ }
+#else
+ static
+ symbol_type
+ make_LT ()
+ {
+ return symbol_type (token::L_LT);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_GT ()
+ {
+ return symbol_type (token::L_GT);
+ }
+#else
+ static
+ symbol_type
+ make_GT ()
+ {
+ return symbol_type (token::L_GT);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_LE ()
+ {
+ return symbol_type (token::L_LE);
+ }
+#else
+ static
+ symbol_type
+ make_LE ()
+ {
+ return symbol_type (token::L_LE);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_GE ()
+ {
+ return symbol_type (token::L_GE);
+ }
+#else
+ static
+ symbol_type
+ make_GE ()
+ {
+ return symbol_type (token::L_GE);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_LS ()
+ {
+ return symbol_type (token::L_LS);
+ }
+#else
+ static
+ symbol_type
+ make_LS ()
+ {
+ return symbol_type (token::L_LS);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_RS ()
+ {
+ return symbol_type (token::L_RS);
+ }
+#else
+ static
+ symbol_type
+ make_RS ()
+ {
+ return symbol_type (token::L_RS);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_ADD ()
+ {
+ return symbol_type (token::L_ADD);
+ }
+#else
+ static
+ symbol_type
+ make_ADD ()
+ {
+ return symbol_type (token::L_ADD);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_MINUS ()
+ {
+ return symbol_type (token::L_MINUS);
+ }
+#else
+ static
+ symbol_type
+ make_MINUS ()
+ {
+ return symbol_type (token::L_MINUS);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_MUL ()
+ {
+ return symbol_type (token::L_MUL);
+ }
+#else
+ static
+ symbol_type
+ make_MUL ()
+ {
+ return symbol_type (token::L_MUL);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_DIV ()
+ {
+ return symbol_type (token::L_DIV);
+ }
+#else
+ static
+ symbol_type
+ make_DIV ()
+ {
+ return symbol_type (token::L_DIV);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_REM ()
+ {
+ return symbol_type (token::L_REM);
+ }
+#else
+ static
+ symbol_type
+ make_REM ()
+ {
+ return symbol_type (token::L_REM);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_DEG ()
+ {
+ return symbol_type (token::L_DEG);
+ }
+#else
+ static
+ symbol_type
+ make_DEG ()
+ {
+ return symbol_type (token::L_DEG);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_NOT ()
+ {
+ return symbol_type (token::L_NOT);
+ }
+#else
+ static
+ symbol_type
+ make_NOT ()
+ {
+ return symbol_type (token::L_NOT);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_BITNOT ()
+ {
+ return symbol_type (token::L_BITNOT);
+ }
+#else
+ static
+ symbol_type
+ make_BITNOT ()
+ {
+ return symbol_type (token::L_BITNOT);
+ }
+#endif
+
+
+ private:
+#if YY_CPLUSPLUS < 201103L
+ /// Non copyable.
+ Parser (const Parser&);
+ /// Non copyable.
+ Parser& operator= (const Parser&);
+#endif
+
+
+ /// Stored state numbers (used for stacks).
+ typedef signed char state_type;
+
+ /// Compute post-reduction state.
+ /// \param yystate the current state
+ /// \param yysym the nonterminal to push on the stack
+ static state_type yy_lr_goto_state_ (state_type yystate, int yysym);
+
+ /// Whether the given \c yypact_ value indicates a defaulted state.
+ /// \param yyvalue the value to check
+ static bool yy_pact_value_is_default_ (int yyvalue);
+
+ /// Whether the given \c yytable_ value indicates a syntax error.
+ /// \param yyvalue the value to check
+ static bool yy_table_value_is_error_ (int yyvalue);
+
+ static const signed char yypact_ninf_;
+ static const signed char yytable_ninf_;
+
+ /// Convert a scanner token kind \a t to a symbol kind.
+ /// In theory \a t should be a token_kind_type, but character literals
+ /// are valid, yet not members of the token_type enum.
+ static symbol_kind_type yytranslate_ (int t);
+
+#if YYDEBUG || 0
+ /// For a symbol, its name in clear.
+ static const char* const yytname_[];
+#endif // #if YYDEBUG || 0
+
+
+ // Tables.
+ // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ // STATE-NUM.
+ static const short yypact_[];
+
+ // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ // Performed when YYTABLE does not specify something else to do. Zero
+ // means the default is an error.
+ static const signed char yydefact_[];
+
+ // YYPGOTO[NTERM-NUM].
+ static const signed char yypgoto_[];
+
+ // YYDEFGOTO[NTERM-NUM].
+ static const signed char yydefgoto_[];
+
+ // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ // positive, shift that token. If negative, reduce the rule whose
+ // number is the opposite. If YYTABLE_NINF, syntax error.
+ static const signed char yytable_[];
+
+ static const signed char yycheck_[];
+
+ // YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ // symbol of state STATE-NUM.
+ static const signed char yystos_[];
+
+ // YYR1[YYN] -- Symbol number of symbol that rule YYN derives.
+ static const signed char yyr1_[];
+
+ // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.
+ static const signed char yyr2_[];
+
+
+#if YYDEBUG
+ // YYRLINE[YYN] -- Source line where rule number YYN was defined.
+ static const unsigned char yyrline_[];
+ /// Report on the debug stream that the rule \a r is going to be reduced.
+ virtual void yy_reduce_print_ (int r) const;
+ /// Print the state stack on the debug stream.
+ virtual void yy_stack_print_ () const;
+
+ /// Debugging level.
+ int yydebug_;
+ /// Debug stream.
+ std::ostream* yycdebug_;
+
+ /// \brief Display a symbol kind, value and location.
+ /// \param yyo The output stream.
+ /// \param yysym The symbol.
+ template <typename Base>
+ void yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const;
+#endif
+
+ /// \brief Reclaim the memory associated to a symbol.
+ /// \param yymsg Why this token is reclaimed.
+ /// If null, print nothing.
+ /// \param yysym The symbol.
+ template <typename Base>
+ void yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const;
+
+ private:
+ /// Type access provider for state based symbols.
+ struct by_state
+ {
+ /// Default constructor.
+ by_state () YY_NOEXCEPT;
+
+ /// The symbol kind as needed by the constructor.
+ typedef state_type kind_type;
+
+ /// Constructor.
+ by_state (kind_type s) YY_NOEXCEPT;
+
+ /// Copy constructor.
+ by_state (const by_state& that) YY_NOEXCEPT;
+
+ /// Record that this symbol is empty.
+ void clear () YY_NOEXCEPT;
+
+ /// Steal the symbol kind from \a that.
+ void move (by_state& that);
+
+ /// The symbol kind (corresponding to \a state).
+ /// \a symbol_kind::S_YYEMPTY when empty.
+ symbol_kind_type kind () const YY_NOEXCEPT;
+
+ /// The state number used to denote an empty symbol.
+ /// We use the initial state, as it does not have a value.
+ enum { empty_state = 0 };
+
+ /// The state.
+ /// \a empty when empty.
+ state_type state;
+ };
+
+ /// "Internal" symbol: element of the stack.
+ struct stack_symbol_type : basic_symbol<by_state>
+ {
+ /// Superclass.
+ typedef basic_symbol<by_state> super_type;
+ /// Construct an empty symbol.
+ stack_symbol_type ();
+ /// Move or copy construction.
+ stack_symbol_type (YY_RVREF (stack_symbol_type) that);
+ /// Steal the contents from \a sym to build this.
+ stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym);
+#if YY_CPLUSPLUS < 201103L
+ /// Assignment, needed by push_back by some old implementations.
+ /// Moves the contents of that.
+ stack_symbol_type& operator= (stack_symbol_type& that);
+
+ /// Assignment, needed by push_back by other implementations.
+ /// Needed by some other old implementations.
+ stack_symbol_type& operator= (const stack_symbol_type& that);
+#endif
+ };
+
+ /// A stack with random access from its top.
+ template <typename T, typename S = std::vector<T> >
+ class stack
+ {
+ public:
+ // Hide our reversed order.
+ typedef typename S::iterator iterator;
+ typedef typename S::const_iterator const_iterator;
+ typedef typename S::size_type size_type;
+ typedef typename std::ptrdiff_t index_type;
+
+ stack (size_type n = 200)
+ : seq_ (n)
+ {}
+
+#if 201103L <= YY_CPLUSPLUS
+ /// Non copyable.
+ stack (const stack&) = delete;
+ /// Non copyable.
+ stack& operator= (const stack&) = delete;
+#endif
+
+ /// Random access.
+ ///
+ /// Index 0 returns the topmost element.
+ const T&
+ operator[] (index_type i) const
+ {
+ return seq_[size_type (size () - 1 - i)];
+ }
+
+ /// Random access.
+ ///
+ /// Index 0 returns the topmost element.
+ T&
+ operator[] (index_type i)
+ {
+ return seq_[size_type (size () - 1 - i)];
+ }
+
+ /// Steal the contents of \a t.
+ ///
+ /// Close to move-semantics.
+ void
+ push (YY_MOVE_REF (T) t)
+ {
+ seq_.push_back (T ());
+ operator[] (0).move (t);
+ }
+
+ /// Pop elements from the stack.
+ void
+ pop (std::ptrdiff_t n = 1) YY_NOEXCEPT
+ {
+ for (; 0 < n; --n)
+ seq_.pop_back ();
+ }
+
+ /// Pop all elements from the stack.
+ void
+ clear () YY_NOEXCEPT
+ {
+ seq_.clear ();
+ }
+
+ /// Number of elements on the stack.
+ index_type
+ size () const YY_NOEXCEPT
+ {
+ return index_type (seq_.size ());
+ }
+
+ /// Iterator on top of the stack (going downwards).
+ const_iterator
+ begin () const YY_NOEXCEPT
+ {
+ return seq_.begin ();
+ }
+
+ /// Bottom of the stack.
+ const_iterator
+ end () const YY_NOEXCEPT
+ {
+ return seq_.end ();
+ }
+
+ /// Present a slice of the top of a stack.
+ class slice
+ {
+ public:
+ slice (const stack& stack, index_type range)
+ : stack_ (stack)
+ , range_ (range)
+ {}
+
+ const T&
+ operator[] (index_type i) const
+ {
+ return stack_[range_ - i];
+ }
+
+ private:
+ const stack& stack_;
+ index_type range_;
+ };
+
+ private:
+#if YY_CPLUSPLUS < 201103L
+ /// Non copyable.
+ stack (const stack&);
+ /// Non copyable.
+ stack& operator= (const stack&);
+#endif
+ /// The wrapped container.
+ S seq_;
+ };
+
+
+ /// Stack type.
+ typedef stack<stack_symbol_type> stack_type;
+
+ /// The stack.
+ stack_type yystack_;
+
+ /// Push a new state on the stack.
+ /// \param m a debug message to display
+ /// if null, no trace is output.
+ /// \param sym the symbol
+ /// \warning the contents of \a s.value is stolen.
+ void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym);
+
+ /// Push a new look ahead token on the state on the stack.
+ /// \param m a debug message to display
+ /// if null, no trace is output.
+ /// \param s the state
+ /// \param sym the symbol (for its value and location).
+ /// \warning the contents of \a sym.value is stolen.
+ void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym);
+
+ /// Pop \a n symbols from the stack.
+ void yypop_ (int n = 1);
+
+ /// Constants.
+ enum
+ {
+ yylast_ = 279, ///< Last index in yytable_.
+ yynnts_ = 4, ///< Number of nonterminal symbols.
+ yyfinal_ = 24 ///< Termination state number.
+ };
+
+
+ // User arguments.
+ QL::Result &result;
+
+ };
+
+ inline
+ Parser::symbol_kind_type
+ Parser::yytranslate_ (int t)
+ {
+ // YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to
+ // TOKEN-NUM as returned by yylex.
+ static
+ const signed char
+ translate_table[] =
+ {
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62
+ };
+ // Last valid token kind.
+ const int code_max = 317;
+
+ if (t <= 0)
+ return symbol_kind::S_YYEOF;
+ else if (t <= code_max)
+ return YY_CAST (symbol_kind_type, translate_table[t]);
+ else
+ return symbol_kind::S_YYUNDEF;
+ }
+
+ // basic_symbol.
+ template <typename Base>
+ Parser::basic_symbol<Base>::basic_symbol (const basic_symbol& that)
+ : Base (that)
+ , value ()
+ {
+ switch (this->kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.copy< Expression * > (YY_MOVE (that.value));
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+
+
+ template <typename Base>
+ Parser::symbol_kind_type
+ Parser::basic_symbol<Base>::type_get () const YY_NOEXCEPT
+ {
+ return this->kind ();
+ }
+
+ template <typename Base>
+ bool
+ Parser::basic_symbol<Base>::empty () const YY_NOEXCEPT
+ {
+ return this->kind () == symbol_kind::S_YYEMPTY;
+ }
+
+ template <typename Base>
+ void
+ Parser::basic_symbol<Base>::move (basic_symbol& s)
+ {
+ super_type::move (s);
+ switch (this->kind ())
+ {
+ case symbol_kind::S_NUM: // "number"
+ case symbol_kind::S_NAME: // "name"
+ case symbol_kind::S_FNAME: // FNAME
+ case symbol_kind::S_JGROUP: // JGROUP
+ case symbol_kind::S_JPARENT: // JPARENT
+ case symbol_kind::S_QSTR: // QSTR
+ case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+ case symbol_kind::S_exp: // exp
+ case symbol_kind::S_term: // term
+ value.move< Expression * > (YY_MOVE (s.value));
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ // by_kind.
+ inline
+ Parser::by_kind::by_kind ()
+ : kind_ (symbol_kind::S_YYEMPTY)
+ {}
+
+#if 201103L <= YY_CPLUSPLUS
+ inline
+ Parser::by_kind::by_kind (by_kind&& that)
+ : kind_ (that.kind_)
+ {
+ that.clear ();
+ }
+#endif
+
+ inline
+ Parser::by_kind::by_kind (const by_kind& that)
+ : kind_ (that.kind_)
+ {}
+
+ inline
+ Parser::by_kind::by_kind (token_kind_type t)
+ : kind_ (yytranslate_ (t))
+ {}
+
+ inline
+ void
+ Parser::by_kind::clear () YY_NOEXCEPT
+ {
+ kind_ = symbol_kind::S_YYEMPTY;
+ }
+
+ inline
+ void
+ Parser::by_kind::move (by_kind& that)
+ {
+ kind_ = that.kind_;
+ that.clear ();
+ }
+
+ inline
+ Parser::symbol_kind_type
+ Parser::by_kind::kind () const YY_NOEXCEPT
+ {
+ return kind_;
+ }
+
+ inline
+ Parser::symbol_kind_type
+ Parser::by_kind::type_get () const YY_NOEXCEPT
+ {
+ return this->kind ();
+ }
+
+#line 50 "QLParser.yy"
+} // QL
+#line 2034 "QLParser.tab.hh"
+
+
+
+
+#endif // !YY_YY_QLPARSER_TAB_HH_INCLUDED
diff --git a/gprofng/src/QLParser.yy b/gprofng/src/QLParser.yy
new file mode 100644
index 0000000..689d0e1
--- /dev/null
+++ b/gprofng/src/QLParser.yy
@@ -0,0 +1,390 @@
+/* Copyright (C) 2021 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. */
+
+// To rebuild QLParser.tab.cc and QLParser.tab.hh, use bison 3.6 or newer:
+// cd gprofng/src && bison QLParser.yy
+
+// For "api.parser.class"
+%require "3.3"
+%language "C++"
+
+%code top {
+#include <stdio.h>
+#include <string.h>
+#include <string>
+}
+%code requires {
+#include "QLParser.h"
+#include "DbeSession.h"
+#include "Expression.h"
+#include "Table.h"
+#include "i18n.h"
+}
+
+%code
+{
+namespace QL
+{
+ static QL::Parser::symbol_type yylex (QL::Result &result);
+}
+}
+
+%defines
+%define api.namespace {QL}
+%define api.parser.class {Parser}
+%define api.token.constructor
+%define api.value.type variant
+// Later: api.value.automove
+%define api.token.prefix {L_}
+%define parse.assert
+%param {QL::Result &result}
+
+%start S
+
+%token LPAR "("
+ RPAR ")"
+ NUM "number"
+ NAME "name"
+ FNAME
+ HASPROP
+ JGROUP
+ JPARENT
+ QSTR
+ FILEIOVFD
+
+%nonassoc IN SOME ORDR
+%left COMMA ","
+%right QWE "?"
+ COLON ":"
+%left AND "&&"
+ OR "|"
+ EQV NEQV
+ BITAND BITOR
+ BITXOR "^"
+%nonassoc EQ "="
+ NE "!="
+ LT "<"
+ GT ">"
+ LE "<="
+ GE ">="
+%left LS "<<"
+ RS ">>"
+ ADD "+"
+ MINUS "-"
+ MUL "*"
+ DIV "/"
+ REM "%"
+%right DEG
+ NOT "!"
+ BITNOT "~"
+
+%type <Expression *> QSTR NUM NAME FNAME JGROUP JPARENT FILEIOVFD exp term
+
+%destructor { delete $$; } <*>;
+
+%%
+
+S: /* empty */ { result.out = new Expression (Expression::OP_NUM, (uint64_t) 1); }
+| exp { result.out = new Expression ($1); }
+
+exp: exp DEG exp { $$ = new Expression (Expression::OP_DEG, $1, $3); } /* dead? */
+ | exp MUL exp { $$ = new Expression (Expression::OP_MUL, $1, $3); }
+ | exp DIV exp { $$ = new Expression (Expression::OP_DIV, $1, $3); }
+ | exp REM exp { $$ = new Expression (Expression::OP_REM, $1, $3); }
+ | exp ADD exp { $$ = new Expression (Expression::OP_ADD, $1, $3); }
+ | exp MINUS exp { $$ = new Expression (Expression::OP_MINUS, $1, $3); }
+ | exp LS exp { $$ = new Expression (Expression::OP_LS, $1, $3); }
+ | exp RS exp { $$ = new Expression (Expression::OP_RS, $1, $3); }
+ | exp LT exp { $$ = new Expression (Expression::OP_LT, $1, $3); }
+ | exp LE exp { $$ = new Expression (Expression::OP_LE, $1, $3); }
+ | exp GT exp { $$ = new Expression (Expression::OP_GT, $1, $3); }
+ | exp GE exp { $$ = new Expression (Expression::OP_GE, $1, $3); }
+ | exp EQ exp { $$ = new Expression (Expression::OP_EQ, $1, $3); }
+ | exp NE exp { $$ = new Expression (Expression::OP_NE, $1, $3); }
+ | exp BITAND exp { $$ = new Expression (Expression::OP_BITAND, $1, $3); }
+ | exp BITXOR exp { $$ = new Expression (Expression::OP_BITXOR, $1, $3); }
+ | exp BITOR exp { $$ = new Expression (Expression::OP_BITOR, $1, $3); }
+ | exp AND exp { $$ = new Expression (Expression::OP_AND, $1, $3); }
+ | exp OR exp { $$ = new Expression (Expression::OP_OR, $1, $3); }
+ | exp NEQV exp { $$ = new Expression (Expression::OP_NEQV, $1, $3); } /* dead? */
+ | exp EQV exp { $$ = new Expression (Expression::OP_EQV, $1, $3); } /* dead? */
+ | exp QWE exp COLON exp { Expression colon = Expression (Expression::OP_COLON, $3, $5);
+ $$ = new Expression (Expression::OP_QWE, $1, &colon); }
+ | exp COMMA exp { $$ = new Expression (Expression::OP_COMMA, $1, $3); }
+ | exp IN exp { $$ = new Expression (Expression::OP_IN, $1, $3); }
+ | exp SOME IN exp { $$ = new Expression (Expression::OP_SOMEIN, $1, $4); }
+ | exp ORDR IN exp { $$ = new Expression (Expression::OP_ORDRIN, $1, $4); }
+ | term { $$ = new Expression ($1); }
+
+term: MINUS term { Expression num = Expression (Expression::OP_NUM, (uint64_t) 0);
+ $$ = new Expression (Expression::OP_MINUS, &num, $2); }
+ | NOT term { $$ = new Expression (Expression::OP_NOT, $2, NULL); }
+ | BITNOT term { $$ = new Expression (Expression::OP_BITNOT, $2, NULL); }
+ | LPAR exp RPAR { $$ = new Expression ($2); }
+ | FNAME LPAR QSTR RPAR { $$ = new Expression (Expression::OP_FUNC, $1, $3); }
+ | HASPROP LPAR NAME RPAR { $$ = new Expression (Expression::OP_HASPROP, $3, NULL); }
+ | JGROUP LPAR QSTR RPAR { $$ = new Expression (Expression::OP_JAVA, $1, $3); }
+ | JPARENT LPAR QSTR RPAR { $$ = new Expression (Expression::OP_JAVA, $1, $3); }
+ | FILEIOVFD LPAR QSTR RPAR { $$ = new Expression (Expression::OP_FILE, $1, $3); }
+ | NUM { $$ = new Expression ($1); }
+ | NAME { $$ = new Expression ($1); }
+
+%%
+
+namespace QL
+{
+ static Parser::symbol_type
+ unget_ret (std::istream &in, char c, Parser::symbol_type tok)
+ {
+ in.putback (c);
+ return tok;
+ }
+
+ static Expression *
+ processName (char *name)
+ {
+ int propID = dbeSession->getPropIdByName (name);
+ if (propID != PROP_NONE)
+ {
+ Expression *expr = new Expression (Expression::OP_NUM, (uint64_t) propID);
+ Expression *ret = new Expression (Expression::OP_NAME, expr);
+ delete expr;
+ return ret;
+ }
+
+ // If a name is not statically known try user defined objects
+ Expression *expr = dbeSession->findObjDefByName (name);
+ if (expr != NULL)
+ return expr->copy();
+
+ throw Parser::syntax_error ("Name not found");
+ }
+
+ static Parser::symbol_type
+ yylex (QL::Result &result)
+ {
+ int base = 0;
+ int c;
+
+ do
+ c = result.in.get ();
+ while (result.in && (c == ' ' || c == '\t'));
+ if (!result.in)
+ return Parser::make_YYEOF ();
+
+ switch (c)
+ {
+ case '\n': return Parser::make_YYEOF ();
+ case '(': return Parser::make_LPAR () ;
+ case ')': return Parser::make_RPAR ();
+ case ',': return Parser::make_COMMA ();
+ case '%': return Parser::make_REM ();
+ case '/': return Parser::make_DIV ();
+ case '*': return Parser::make_MUL ();
+ case '-': return Parser::make_MINUS ();
+ case '+': return Parser::make_ADD ();
+ case '~': return Parser::make_BITNOT ();
+ case '^': return Parser::make_BITXOR ();
+ case '?': return Parser::make_QWE ();
+ case ':': return Parser::make_COLON ();
+ case '|':
+ c = result.in.get ();
+ if (c == '|')
+ return Parser::make_OR ();
+ else
+ return unget_ret (result.in, c, Parser::make_BITOR ());
+ case '&':
+ c = result.in.get ();
+ if (c == '&')
+ return Parser::make_AND ();
+ else
+ return unget_ret (result.in, c, Parser::make_BITAND ());
+ case '!':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_NE ();
+ else
+ return unget_ret (result.in, c, Parser::make_NOT ());
+ case '=':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_EQ ();
+ else
+ throw Parser::syntax_error ("Syntax error after =");
+ case '<':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_LE ();
+ else if (c == '<')
+ return Parser::make_LS ();
+ else
+ return unget_ret (result.in, c, Parser::make_LT ());
+ case '>':
+ c = result.in.get ();
+ if (c == '=')
+ return Parser::make_GE ();
+ else if (c == '>')
+ return Parser::make_RS ();
+ else
+ return unget_ret (result.in, c, Parser::make_GT ());
+ case '"':
+ {
+ int maxsz = 16;
+ char *str = (char *) malloc (maxsz);
+ char *ptr = str;
+
+ for (;;)
+ {
+ c = result.in.get ();
+ if (!result.in)
+ {
+ free (str);
+ throw Parser::syntax_error ("Unclosed \"");
+ }
+
+ switch (c)
+ {
+ case '"':
+ *ptr = (char)0;
+ // XXX omazur: need new string type
+ return Parser::make_QSTR (new Expression (Expression::OP_NUM, (uint64_t) str));
+ case 0:
+ case '\n':
+ free (str);
+ throw Parser::syntax_error ("Multiline strings are not supported");
+ default:
+ if (ptr - str >= maxsz)
+ {
+ size_t len = ptr - str;
+ maxsz = maxsz > 8192 ? maxsz + 8192 : maxsz * 2;
+ char *new_s = (char *) realloc (str, maxsz);
+ str = new_s;
+ ptr = str + len;
+ }
+ *ptr++ = c;
+ }
+ }
+ }
+ default:
+ if (c == '0')
+ {
+ base = 8;
+ c = result.in.get ();
+ if ( c == 'x' )
+ {
+ base = 16;
+ c = result.in.get ();
+ }
+ }
+ else if (c >= '1' && c <='9')
+ base = 10;
+
+ if (base)
+ {
+ uint64_t lval = 0;
+ for (;;)
+ {
+ int digit = -1;
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ digit = c - '0';
+ break;
+ case '8': case '9':
+ if (base > 8)
+ digit = c - '0';
+ break;
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ if (base == 16)
+ digit = c - 'a' + 10;
+ break;
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ if (base == 16)
+ digit = c - 'A' + 10;
+ break;
+ }
+ if (digit == -1)
+ {
+ result.in.putback (c);
+ break;
+ }
+ lval = lval * base + digit;
+ c = result.in.get ();
+ }
+ return Parser::make_NUM (new Expression (Expression::OP_NUM, lval));
+ }
+
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+ {
+ char name[32]; // omazur XXX: accept any length
+ name[0] = (char)c;
+ for (size_t i = 1; i < sizeof (name); i++)
+ {
+ c = result.in.get ();
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || (c == '_'))
+ name[i] = c;
+ else
+ {
+ name[i] = (char)0;
+ result.in.putback (c);
+ break;
+ }
+ }
+
+ if (strcasecmp (name, NTXT ("IN")) == 0)
+ return Parser::make_IN ();
+ else if (strcasecmp (name, NTXT ("SOME")) == 0)
+ return Parser::make_SOME ();
+ else if (strcasecmp (name, NTXT ("ORDERED")) == 0)
+ return Parser::make_ORDR ();
+ else if (strcasecmp (name, NTXT ("TRUE")) == 0)
+ return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 1));
+ else if (strcasecmp (name, NTXT ("FALSE")) == 0)
+ return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 0));
+ else if (strcasecmp (name, NTXT ("FNAME")) == 0)
+ return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_FNAME));
+ else if (strcasecmp (name, NTXT ("HAS_PROP")) == 0)
+ return Parser::make_HASPROP ();
+ else if (strcasecmp (name, NTXT ("JGROUP")) == 0)
+ return Parser::make_JGROUP (new Expression (Expression::OP_NUM, Expression::JAVA_JGROUP));
+ else if (strcasecmp (name, NTXT ("JPARENT")) == 0 )
+ return Parser::make_JPARENT (new Expression (Expression::OP_NUM, Expression::JAVA_JPARENT));
+ else if (strcasecmp (name, NTXT ("DNAME")) == 0)
+ return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_DNAME));
+ else if (strcasecmp (name, NTXT ("FILEIOVFD")) == 0 )
+ return Parser::make_FILEIOVFD (new Expression (Expression::OP_NUM, (uint64_t) 0));
+
+ return Parser::make_NAME (processName (name));
+ }
+
+ throw Parser::syntax_error ("Syntax error");
+ }
+ }
+ void
+ Parser::error (const std::string &)
+ {
+ // do nothing for now
+ }
+}
+
diff --git a/gprofng/src/SAXParser.h b/gprofng/src/SAXParser.h
new file mode 100644
index 0000000..dde3e06
--- /dev/null
+++ b/gprofng/src/SAXParser.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * javax/xml/parsers/SAXParser.java
+ *
+ * Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _SAXParser_h
+#define _SAXParser_h
+
+class File;
+class DefaultHandler;
+class SAXException;
+
+class SAXParser
+{
+public:
+
+ virtual ~SAXParser () { }
+ virtual void reset () { }
+ virtual void parse (File*, DefaultHandler*) = 0;
+ virtual bool isNamespaceAware () = 0;
+ virtual bool isValidating () = 0;
+
+protected:
+
+ SAXParser () { }
+};
+
+#endif /* _SAXParser_h */
diff --git a/gprofng/src/SAXParserFactory.cc b/gprofng/src/SAXParserFactory.cc
new file mode 100644
index 0000000..7d9e851
--- /dev/null
+++ b/gprofng/src/SAXParserFactory.cc
@@ -0,0 +1,666 @@
+/* Copyright (C) 2021 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 <ctype.h>
+
+#include "util.h"
+#include "vec.h"
+#include "DefaultHandler.h"
+#include "SAXParser.h"
+#include "SAXParserFactory.h"
+#include "StringBuilder.h"
+
+/*
+ * Private implementation of Attributes
+ */
+class AttributesP : public Attributes
+{
+public:
+ AttributesP ();
+ ~AttributesP ();
+ int getLength ();
+ const char *getQName (int index);
+ const char *getValue (int index);
+ int getIndex (const char *qName);
+ const char *getValue (const char *qName);
+ void append (char *qName, char *value);
+
+private:
+ Vector<char*> *names;
+ Vector<char*> *values;
+};
+
+AttributesP::AttributesP ()
+{
+ names = new Vector<char*>;
+ values = new Vector<char*>;
+}
+
+AttributesP::~AttributesP ()
+{
+ Destroy (names);
+ Destroy (values);
+}
+
+int
+AttributesP::getLength ()
+{
+ return names->size ();
+}
+
+const char *
+AttributesP::getQName (int index)
+{
+ if (index < 0 || index >= names->size ())
+ return NULL;
+ return names->fetch (index);
+}
+
+const char *
+AttributesP::getValue (int index)
+{
+ if (index < 0 || index >= values->size ())
+ return NULL;
+ return values->fetch (index);
+}
+
+int
+AttributesP::getIndex (const char *qName)
+{
+ for (int idx = 0; idx < names->size (); idx++)
+ if (strcmp (names->fetch (idx), qName) == 0)
+ return idx;
+ return -1;
+}
+
+const char *
+AttributesP::getValue (const char *qName)
+{
+ for (int idx = 0; idx < names->size (); idx++)
+ if (strcmp (names->fetch (idx), qName) == 0)
+ return values->fetch (idx);
+ return NULL;
+}
+
+void
+AttributesP::append (char *qName, char *value)
+{
+ names->append (qName);
+ values->append (value);
+}
+
+/*
+ * Implementation of SAXException
+ */
+SAXException::SAXException ()
+{
+ message = strdup ("null");
+}
+
+SAXException::SAXException (const char *_message)
+{
+ if (_message == NULL)
+ message = strdup ("null");
+ else
+ message = strdup (_message);
+}
+
+SAXException::~SAXException ()
+{
+ free (message);
+}
+
+char *
+SAXException::getMessage ()
+{
+ return message;
+}
+
+/*
+ * SAXParseException
+ */
+SAXParseException::SAXParseException (char *message, int _lineNumber, int _columnNumber)
+: SAXException (message == NULL ? GTXT ("XML parse error") : message)
+{
+ lineNumber = _lineNumber;
+ columnNumber = _columnNumber;
+}
+
+/*
+ * Private implementation of SAXParser
+ */
+class SAXParserP : public SAXParser
+{
+public:
+ SAXParserP ();
+ ~SAXParserP ();
+ void reset ();
+ void parse (File*, DefaultHandler*);
+
+ bool
+ isNamespaceAware ()
+ {
+ return false;
+ }
+
+ bool
+ isValidating ()
+ {
+ return false;
+ }
+
+private:
+
+ static const int CH_EOF = -1;
+
+ void nextch ();
+ bool isWSpace ();
+ void skipWSpaces ();
+ void scanString (const char *str);
+ char *parseName ();
+ char *parseString ();
+ char *decodeString (char *str);
+ Attributes *parseAttributes ();
+ void parseTag ();
+ void parseDocument ();
+ void parsePart (int idx);
+
+ DefaultHandler *dh;
+ int bufsz;
+ char *buffer;
+ int cntsz;
+ int idx;
+ int curch;
+ int line;
+ int column;
+};
+
+SAXParserP::SAXParserP ()
+{
+ dh = NULL;
+ bufsz = 0x2000;
+ buffer = (char*) malloc (bufsz);
+ cntsz = 0;
+ idx = 0;
+ line = 1;
+ column = 0;
+}
+
+SAXParserP::~SAXParserP ()
+{
+ free (buffer);
+}
+
+void
+SAXParserP::reset ()
+{
+ dh = NULL;
+ bufsz = 8192;
+ buffer = (char*) realloc (buffer, bufsz);
+ cntsz = 0;
+ idx = 0;
+ line = 1;
+ column = 0;
+}
+
+void
+SAXParserP::parse (File *f, DefaultHandler *_dh)
+{
+ if (_dh == NULL)
+ return;
+ dh = _dh;
+ FILE *file = (FILE*) f;
+ int rem = bufsz;
+ cntsz = 0;
+ idx = 0;
+ for (;;)
+ {
+ int n = (int) fread (buffer + cntsz, 1, rem, file);
+ if (ferror (file) || n <= 0)
+ break;
+ cntsz += n;
+ if (feof (file))
+ break;
+ rem -= n;
+ if (rem == 0)
+ {
+ int oldbufsz = bufsz;
+ bufsz = bufsz >= 0x100000 ? bufsz + 0x100000 : bufsz * 2;
+ buffer = (char*) realloc (buffer, bufsz);
+ rem = bufsz - oldbufsz;
+ }
+ }
+ nextch ();
+ parseDocument ();
+}
+
+static int
+hex (char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return 10 + (c - 'a');
+ return -1;
+}
+
+void
+SAXParserP::nextch ()
+{
+ curch = idx >= cntsz ? CH_EOF : buffer[idx++];
+ if (curch == '\n')
+ {
+ line += 1;
+ column = 0;
+ }
+ else
+ column += 1;
+}
+
+bool
+SAXParserP::isWSpace ()
+{
+ return curch == ' ' || curch == '\t' || curch == '\n' || curch == '\r';
+}
+
+void
+SAXParserP::skipWSpaces ()
+{
+ while (isWSpace ())
+ nextch ();
+}
+
+void
+SAXParserP::scanString (const char *str)
+{
+ if (str == NULL || *str == '\0')
+ return;
+ for (;;)
+ {
+ if (curch == CH_EOF)
+ break;
+ else if (curch == *str)
+ {
+ const char *p = str;
+ for (;;)
+ {
+ p += 1;
+ nextch ();
+ if (*p == '\0')
+ return;
+ if (curch != *p)
+ break;
+ }
+ }
+ nextch ();
+ }
+}
+
+char *
+SAXParserP::parseName ()
+{
+ StringBuilder *name = new StringBuilder ();
+
+ if ((curch >= 'A' && curch <= 'Z') || (curch >= 'a' && curch <= 'z'))
+ {
+ name->append ((char) curch);
+ nextch ();
+ while (isalnum (curch) != 0 || curch == '_')
+ {
+ name->append ((char) curch);
+ nextch ();
+ }
+ }
+
+ char *res = name->toString ();
+ delete name;
+ return res;
+}
+
+/**
+ * Replaces encoded XML characters with original characters
+ * Attention: this method reuses the same string that is passed as the argument
+ * @param str
+ * @return str
+ */
+char *
+SAXParserP::decodeString (char * str)
+{
+ // Check if string has %22% and replace it with double quotes
+ // Also replace all other special combinations.
+ char *from = str;
+ char *to = str;
+ if (strstr (from, "%") || strstr (from, "&"))
+ {
+ int len = strlen (from);
+ for (int i = 0; i < len; i++)
+ {
+ int nch = from[i];
+ // Process &...; combinations
+ if (nch == '&' && i + 3 < len)
+ {
+ if (from[i + 2] == 't' && from[i + 3] == ';')
+ {
+ // check &lt; &gt;
+ if (from[i + 1] == 'l')
+ {
+ nch = '<';
+ i += 3;
+ }
+ else if (from[i + 1] == 'g')
+ {
+ nch = '>';
+ i += 3;
+ }
+ }
+ else if (i + 4 < len && from[i + 4] == ';')
+ {
+ // check &amp;
+ if (from[i + 1] == 'a' && from[i + 2] == 'm' && from[i + 3] == 'p')
+ {
+ nch = '&';
+ i += 4;
+ }
+ }
+ else if ((i + 5 < len) && (from[i + 5] == ';'))
+ {
+ // check &apos; &quot;
+ if (from[i + 1] == 'a' && from[i + 2] == 'p'
+ && from[i + 3] == 'o' && from[i + 4] == 's')
+ {
+ nch = '\'';
+ i += 5;
+ }
+ if (from[i + 1] == 'q' && from[i + 2] == 'u' && from[i + 3] == 'o' && from[i + 4] == 't')
+ {
+ nch = '"';
+ i += 5;
+ }
+ }
+ }
+ // Process %XX% combinations
+ if (nch == '%' && i + 3 < len && from[i + 3] == '%')
+ {
+ int ch = hex (from[i + 1]);
+ if (ch >= 0)
+ {
+ int ch2 = hex (from[i + 2]);
+ if (ch2 >= 0)
+ {
+ ch = ch * 16 + ch2;
+ nch = ch;
+ i += 3;
+ }
+ }
+ }
+ *to++ = (char) nch;
+ }
+ *to = '\0';
+ }
+ return str;
+}
+
+char *
+SAXParserP::parseString ()
+{
+ StringBuilder *str = new StringBuilder ();
+ int quote = '>';
+ if (curch == '"')
+ {
+ quote = curch;
+ nextch ();
+ }
+ for (;;)
+ {
+ if (curch == CH_EOF)
+ break;
+ if (curch == quote)
+ {
+ nextch ();
+ break;
+ }
+ str->append ((char) curch);
+ nextch ();
+ }
+
+ char *res = str->toString ();
+ // Decode XML characters
+ res = decodeString (res);
+ delete str;
+ return res;
+}
+
+Attributes *
+SAXParserP::parseAttributes ()
+{
+ AttributesP *attrs = new AttributesP ();
+
+ for (;;)
+ {
+ skipWSpaces ();
+ char *name = parseName ();
+ if (name == NULL || *name == '\0')
+ {
+ free (name);
+ break;
+ }
+ skipWSpaces ();
+ if (curch != '=')
+ {
+ SAXParseException *e = new SAXParseException (NULL, line, column);
+ dh->error (e);
+ scanString (">");
+ free (name);
+ return attrs;
+ }
+ nextch ();
+ skipWSpaces ();
+ char *value = parseString ();
+ attrs->append (name, value);
+ }
+ return attrs;
+}
+
+void
+SAXParserP::parseTag ()
+{
+ skipWSpaces ();
+ bool empty = false;
+ char *name = parseName ();
+ if (name == NULL || *name == '\0')
+ {
+ SAXParseException *e = new SAXParseException (NULL, line, column);
+ dh->error (e);
+ scanString (">");
+ free (name);
+ return;
+ }
+
+ Attributes *attrs = parseAttributes ();
+ if (curch == '/')
+ {
+ nextch ();
+ empty = true;
+ }
+ if (curch == '>')
+ nextch ();
+ else
+ {
+ empty = false;
+ SAXParseException *e = new SAXParseException (NULL, line, column);
+ dh->error (e);
+ scanString (">");
+ }
+ if (curch == CH_EOF)
+ {
+ free (name);
+ delete attrs;
+ return;
+ }
+ dh->startElement (NULL, NULL, name, attrs);
+ if (empty)
+ {
+ dh->endElement (NULL, NULL, name);
+ free (name);
+ delete attrs;
+ return;
+ }
+
+ StringBuilder *chars = new StringBuilder ();
+ bool wspaces = true;
+ for (;;)
+ {
+ if (curch == CH_EOF)
+ break;
+ else if (curch == '<')
+ {
+ if (chars->length () > 0)
+ {
+ char *str = chars->toString ();
+ // Decode XML characters
+ str = decodeString (str);
+ if (wspaces)
+ dh->ignorableWhitespace (str, 0, chars->length ());
+ else
+ dh->characters (str, 0, chars->length ());
+ free (str);
+ chars->setLength (0);
+ wspaces = true;
+ }
+ nextch ();
+ if (curch == '/')
+ {
+ nextch ();
+ char *ename = parseName ();
+ if (ename && *ename != '\0')
+ {
+ if (strcmp (name, ename) == 0)
+ {
+ skipWSpaces ();
+ if (curch == '>')
+ {
+ nextch ();
+ dh->endElement (NULL, NULL, name);
+ free (ename);
+ break;
+ }
+ SAXParseException *e = new SAXParseException (NULL, line, column);
+ dh->error (e);
+ }
+ else
+ {
+ SAXParseException *e = new SAXParseException (NULL, line, column);
+ dh->error (e);
+ }
+ scanString (">");
+ }
+ free (ename);
+ }
+ else
+ parseTag ();
+ }
+ else
+ {
+ if (!isWSpace ())
+ wspaces = false;
+ chars->append ((char) curch);
+ nextch ();
+ }
+ }
+
+ free (name);
+ delete attrs;
+ delete chars;
+ return;
+}
+
+void
+SAXParserP::parseDocument ()
+{
+ dh->startDocument ();
+ for (;;)
+ {
+ if (curch == CH_EOF)
+ break;
+ if (curch == '<')
+ {
+ nextch ();
+ if (curch == '?')
+ scanString ("?>");
+ else if (curch == '!')
+ scanString (">");
+ else
+ parseTag ();
+ }
+ else
+ nextch ();
+ }
+ dh->endDocument ();
+}
+
+/*
+ * Private implementation of SAXParserFactory
+ */
+class SAXParserFactoryP : public SAXParserFactory
+{
+public:
+ SAXParserFactoryP () { }
+ ~SAXParserFactoryP () { }
+ SAXParser *newSAXParser ();
+
+ void
+ setFeature (const char *, bool) { }
+
+ bool
+ getFeature (const char *)
+ {
+ return false;
+ }
+};
+
+SAXParser *
+SAXParserFactoryP::newSAXParser ()
+{
+ return new SAXParserP ();
+}
+
+/*
+ * SAXParserFactory
+ */
+const char *SAXParserFactory::DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory";
+
+SAXParserFactory *
+SAXParserFactory::newInstance ()
+{
+ return new SAXParserFactoryP ();
+}
+
+void
+DefaultHandler::dump_startElement (const char *qName, Attributes *attrs)
+{
+ fprintf (stderr, NTXT ("DefaultHandler::startElement qName='%s'\n"), STR (qName));
+ for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++)
+ {
+ const char *qn = attrs->getQName (i);
+ const char *vl = attrs->getValue (i);
+ fprintf (stderr, NTXT (" %d '%s' = '%s'\n"), i, STR (qn), STR (vl));
+ }
+}
diff --git a/gprofng/src/SAXParserFactory.h b/gprofng/src/SAXParserFactory.h
new file mode 100644
index 0000000..8e2c366
--- /dev/null
+++ b/gprofng/src/SAXParserFactory.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * javax/xml/parsers/SAXParserFactory.java
+ *
+ * Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _SAXParserFactory_h
+#define _SAXParserFactory_h
+
+class SAXParser;
+
+class SAXParserFactory
+{
+public:
+ static SAXParserFactory *newInstance ();
+
+ virtual ~SAXParserFactory () { }
+ virtual SAXParser *newSAXParser () = 0;
+ virtual void setFeature (const char *name, bool value) = 0;
+ virtual bool getFeature (const char *name) = 0;
+
+ void
+ setNamespaceAware (bool awareness)
+ {
+ namespaceAware = awareness;
+ }
+
+ void
+ setValidating (bool _validating)
+ {
+ validating = _validating;
+ }
+
+ bool
+ isNamespaceAware ()
+ {
+ return namespaceAware;
+ }
+
+ bool
+ isValidating ()
+ {
+ return validating;
+ }
+
+protected:
+ SAXParserFactory () { }
+
+private:
+ static const char *DEFAULT_PROPERTY_NAME;
+ bool validating;
+ bool namespaceAware;
+};
+
+#endif /* _SAXParserFactory_h */
diff --git a/gprofng/src/Sample.cc b/gprofng/src/Sample.cc
new file mode 100644
index 0000000..7c00334
--- /dev/null
+++ b/gprofng/src/Sample.cc
@@ -0,0 +1,94 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include "Sample.h"
+#include "util.h"
+#include "Exp_Layout.h"
+
+Sample::Sample (int num)
+{
+ number = num;
+ prusage = NULL;
+ start_time = end_time = 0;
+ start_label = end_label = NULL;
+ validated = false;
+}
+
+Sample::~Sample ()
+{
+ delete prusage;
+ free (start_label);
+ free (end_label);
+}
+
+PrUsage *
+Sample::get_usage ()
+{
+ if (validated == false)
+ {
+ validate_usage ();
+ validated = true;
+ }
+ return prusage;
+}
+
+void
+Sample::validate_usage ()
+{
+ if (prusage == NULL || validated)
+ return;
+ validated = true;
+
+ // Make sure that none of the times are negative, force to zero if so
+ if (prusage->pr_utime < 0)
+ prusage->pr_utime = 0;
+ if (prusage->pr_stime < 0)
+ prusage->pr_stime = 0;
+ if (prusage->pr_ttime < 0)
+ prusage->pr_ttime = 0;
+ if (prusage->pr_tftime < 0)
+ prusage->pr_tftime = 0;
+ if (prusage->pr_dftime < 0)
+ prusage->pr_dftime = 0;
+ if (prusage->pr_kftime < 0)
+ prusage->pr_kftime = 0;
+ if (prusage->pr_ltime < 0)
+ prusage->pr_ltime = 0;
+ if (prusage->pr_slptime < 0)
+ prusage->pr_slptime = 0;
+ if (prusage->pr_wtime < 0)
+ prusage->pr_wtime = 0;
+ if (prusage->pr_stoptime < 0)
+ prusage->pr_stoptime = 0;
+ if (prusage->pr_rtime < 0)
+ prusage->pr_rtime = 0;
+
+ // Now make sure that the sum of states is >= prusage->pr_rtime
+ hrtime_t sum = prusage->pr_utime + prusage->pr_stime + prusage->pr_ttime
+ + prusage->pr_tftime + prusage->pr_dftime + prusage->pr_kftime
+ + prusage->pr_ltime + prusage->pr_slptime + prusage->pr_wtime
+ + prusage->pr_stoptime;
+
+ sum = sum - prusage->pr_rtime;
+ if (sum < 0)// increment sleep time to make it match
+ prusage->pr_slptime = prusage->pr_slptime - sum;
+}
diff --git a/gprofng/src/Sample.h b/gprofng/src/Sample.h
new file mode 100644
index 0000000..312bdcc
--- /dev/null
+++ b/gprofng/src/Sample.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _SAMPLE_H
+#define _SAMPLE_H
+
+// A data Sample object represents a single sample's worth of data. This
+// object is private and is only used by Experiment and Sample_sel.
+
+#include "dbe_types.h"
+
+class PrUsage;
+
+class Sample
+{
+ friend class Experiment; // see post_process(), read_overview_file()
+public:
+ Sample (int num);
+ ~Sample ();
+ PrUsage *get_usage ();
+
+ char *
+ get_start_label ()
+ {
+ return start_label;
+ }
+
+ char *
+ get_end_label ()
+ {
+ return end_label;
+ }
+
+ hrtime_t
+ get_start_time ()
+ {
+ return start_time;
+ }
+
+ hrtime_t
+ get_end_time ()
+ {
+ return end_time;
+ }
+
+ int
+ get_number ()
+ {
+ return number;
+ }
+
+private:
+ void validate_usage (); // Make sure usage data is consistent
+ bool validated; // if validation performed
+ char *start_label; // sample start label
+ char *end_label; // sample end label
+ hrtime_t start_time; // sample start time
+ hrtime_t end_time; // sample end time
+ PrUsage *prusage; // process usage data
+ int number; // sample number
+};
+
+#endif /* _SAMPLE_H */
diff --git a/gprofng/src/SegMem.h b/gprofng/src/SegMem.h
new file mode 100644
index 0000000..fbfe727
--- /dev/null
+++ b/gprofng/src/SegMem.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _SEGMEM_H
+#define _SEGMEM_H
+
+#include "dbe_types.h"
+class Histable;
+
+class SegMem
+{
+public:
+
+ // The various segments types.
+ enum Seg_mode
+ {
+ READ,
+ WRITE,
+ EXEC,
+ UNKNOWN
+ };
+
+ void
+ set_file_offset (uint64_t fo)
+ {
+ file_offset = fo;
+ }
+
+ uint64_t
+ get_file_offset ()
+ {
+ return file_offset;
+ }
+
+ void
+ set_mode (Seg_mode sm)
+ {
+ mode = sm;
+ }
+
+ Seg_mode
+ get_mode ()
+ {
+ return mode;
+ }
+
+ Size size; // Size of this instance
+ Histable *obj; // Pointer to Segment/Function object
+ Vaddr base; // Base address
+ hrtime_t load_time;
+ hrtime_t unload_time;
+ Size page_size;
+
+private:
+ uint64_t file_offset;
+ Seg_mode mode;
+};
+
+#endif /* _SEGMEM_H */
diff --git a/gprofng/src/Settings.cc b/gprofng/src/Settings.cc
new file mode 100644
index 0000000..965b917
--- /dev/null
+++ b/gprofng/src/Settings.cc
@@ -0,0 +1,1586 @@
+/* Copyright (C) 2021 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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include "enums.h"
+#include "Settings.h"
+#include "DbeSession.h"
+#include "Command.h"
+#include "Application.h"
+#include "MemorySpace.h"
+#include "StringBuilder.h"
+#include "Table.h"
+#include "Emsg.h"
+#include "util.h"
+#include "i18n.h"
+
+// Commands for compiler commentary
+static const char *comp_cmd[] = {
+ NTXT ("basic"),
+ NTXT ("version"),
+ NTXT ("warn"),
+ NTXT ("parallel"),
+ NTXT ("query"),
+ NTXT ("loop"),
+ NTXT ("pipe"),
+ NTXT ("inline"),
+ NTXT ("memops"),
+ NTXT ("fe"),
+ NTXT ("codegen"),
+ NTXT ("src"),
+ NTXT ("asrc"),
+ NTXT ("nosrc"),
+ NTXT ("hex"),
+ NTXT ("nohex"),
+ NTXT ("threshold"),
+ NTXT ("cf")
+};
+
+static const int comp_vis[] = {
+ CCMV_BASIC,
+ CCMV_VER,
+ CCMV_WARN,
+ CCMV_PAR,
+ CCMV_QUERY,
+ CCMV_LOOP,
+ CCMV_PIPE,
+ CCMV_INLINE,
+ CCMV_MEMOPS,
+ CCMV_FE,
+ CCMV_CG,
+ COMP_SRC,
+ COMP_SRC_METRIC,
+ COMP_NOSRC,
+ COMP_HEX,
+ COMP_NOHEX,
+ COMP_THRESHOLD,
+ COMP_CMPLINE
+};
+
+const int comp_size = sizeof (comp_cmd) / sizeof (char *);
+
+// Commands for timeline
+typedef enum
+{
+ TLCMD_INVALID,
+ TLCMD_ENTITY_MODE,
+ TLCMD_ALIGN,
+ TLCMD_DEPTH
+} TLModeSubcommand;
+
+typedef struct
+{
+ const char * cmdText;
+ TLModeSubcommand cmdType;
+ int cmdId;
+} TLModeCmd;
+static const TLModeCmd tlmode_cmd[] = {
+ // MODE commands
+ {NTXT ("lwp"), TLCMD_ENTITY_MODE, PROP_LWPID},
+ {NTXT ("thread"), TLCMD_ENTITY_MODE, PROP_THRID},
+ {NTXT ("cpu"), TLCMD_ENTITY_MODE, PROP_CPUID},
+ {NTXT ("experiment"), TLCMD_ENTITY_MODE, PROP_EXPID},
+ // ALIGN commands
+ {NTXT ("root"), TLCMD_ALIGN, TLSTACK_ALIGN_ROOT},
+ {NTXT ("leaf"), TLCMD_ALIGN, TLSTACK_ALIGN_LEAF},
+ // DEPTH commands
+ {NTXT ("depth"), TLCMD_DEPTH, 0 /* don't care */}
+};
+
+static const int tlmode_size = sizeof (tlmode_cmd) / sizeof (TLModeCmd);
+
+// Constructor
+
+Settings::Settings (Application *_app)
+{
+ // Remember the application
+ app = _app;
+
+ // Clear all default strings
+ str_vmode = NULL;
+ str_en_desc = NULL;
+ str_datamode = NULL;
+ str_scompcom = NULL;
+ str_sthresh = NULL;
+ str_dcompcom = NULL;
+ str_dthresh = NULL;
+ str_dmetrics = NULL;
+ str_dsort = NULL;
+ str_tlmode = NULL;
+ str_tldata = NULL;
+ str_tabs = NULL;
+ str_rtabs = NULL;
+ str_search_path = NULL;
+ str_name_format = NULL;
+ str_limit = NULL;
+ str_printmode = NULL;
+ str_compare = NULL;
+ preload_libdirs = NULL;
+ pathmaps = new Vector<pathmap_t*>;
+ lo_expands = new Vector<lo_expand_t*>;
+ lo_expand_default = LIBEX_SHOW;
+ is_loexpand_default = true;
+ tabs_processed = false;
+
+ // set default-default values
+ name_format = Histable::NA;
+ view_mode = VMODE_USER;
+ en_desc = false;
+ en_desc_cmp = NULL;
+ en_desc_usr = NULL;
+ src_compcom = 2147483647;
+ dis_compcom = 2147483647;
+#define DEFAULT_SRC_DIS_THRESHOLD 75
+ threshold_src = DEFAULT_SRC_DIS_THRESHOLD;
+ threshold_dis = DEFAULT_SRC_DIS_THRESHOLD;
+ src_visible = true;
+ srcmetric_visible = false;
+ hex_visible = false;
+ cmpline_visible = true;
+ funcline_visible = true;
+ tldata = NULL;
+ tlmode = 0;
+ stack_align = 0;
+ stack_depth = 0;
+ limit = 0;
+ // print mode is initialized after the .rc files are read
+ print_delim = ',';
+ compare_mode = CMP_DISABLE;
+ machinemodel = NULL;
+ ignore_no_xhwcprof = false;
+ ignore_fs_warn = false;
+
+ // construct the master list of tabs
+ buildMasterTabList ();
+
+ indx_tab_state = new Vector<bool>;
+ indx_tab_order = new Vector<int>;
+ mem_tab_state = new Vector<bool>;
+ mem_tab_order = new Vector<int>;
+
+ // note that the .rc files are not read here, but later
+}
+
+// Constructor for duplicating an existing Settings class
+
+Settings::Settings (Settings * _settings)
+{
+ int index;
+ app = _settings->app;
+
+ // Copy all default strings
+ str_vmode = dbe_strdup (_settings->str_vmode);
+ str_en_desc = dbe_strdup (_settings->str_en_desc);
+ str_datamode = dbe_strdup (_settings->str_datamode);
+ str_scompcom = dbe_strdup (_settings->str_scompcom);
+ str_sthresh = dbe_strdup (_settings->str_sthresh);
+ str_dcompcom = dbe_strdup (_settings->str_dcompcom);
+ str_dthresh = dbe_strdup (_settings->str_dthresh);
+ str_dmetrics = dbe_strdup (_settings->str_dmetrics);
+ str_dsort = dbe_strdup (_settings->str_dsort);
+ str_tlmode = dbe_strdup (_settings->str_tlmode);
+ str_tldata = dbe_strdup (_settings->str_tldata);
+ str_tabs = dbe_strdup (_settings->str_tabs);
+ str_rtabs = dbe_strdup (_settings->str_rtabs);
+ str_search_path = dbe_strdup (_settings->str_search_path);
+ str_name_format = dbe_strdup (_settings->str_name_format);
+ str_limit = dbe_strdup (_settings->str_limit);
+ str_printmode = dbe_strdup (_settings->str_printmode);
+ str_compare = dbe_strdup (_settings->str_compare);
+ preload_libdirs = dbe_strdup (_settings->preload_libdirs);
+
+ // replicate the pathmap vector
+ pathmap_t *thismap;
+ pathmap_t *newmap;
+ pathmaps = new Vector<pathmap_t*>;
+
+ Vec_loop (pathmap_t*, _settings->pathmaps, index, thismap)
+ {
+ newmap = new pathmap_t;
+ newmap->old_prefix = dbe_strdup (thismap->old_prefix);
+ newmap->new_prefix = dbe_strdup (thismap->new_prefix);
+ pathmaps->append (newmap);
+ }
+
+ // replicate the lo_expand vector and default
+ lo_expand_t *this_lo_ex;
+ lo_expand_t *new_lo_ex;
+ lo_expand_default = _settings->lo_expand_default;
+ is_loexpand_default = _settings->is_loexpand_default;
+ lo_expands = new Vector<lo_expand_t*>;
+
+ Vec_loop (lo_expand_t*, _settings->lo_expands, index, this_lo_ex)
+ {
+ new_lo_ex = new lo_expand_t;
+ new_lo_ex->libname = dbe_strdup (this_lo_ex->libname);
+ new_lo_ex->expand = this_lo_ex->expand;
+ lo_expands->append (new_lo_ex);
+ }
+ tabs_processed = _settings->tabs_processed;
+
+ // Copy the various values from the _settings instance
+ name_format = _settings->name_format;
+ view_mode = _settings->view_mode;
+ en_desc = false;
+ en_desc_cmp = NULL;
+ en_desc_usr = NULL;
+ if (_settings->en_desc_usr)
+ set_en_desc (_settings->en_desc_usr, true);
+ src_compcom = _settings->src_compcom;
+ dis_compcom = _settings->dis_compcom;
+ threshold_src = _settings->threshold_src;
+ threshold_dis = _settings->threshold_dis;
+ src_visible = _settings->src_visible;
+ srcmetric_visible = _settings->srcmetric_visible;
+ hex_visible = _settings->hex_visible;
+ cmpline_visible = _settings->cmpline_visible;
+ funcline_visible = _settings->funcline_visible;
+ tldata = dbe_strdup (_settings->tldata);
+ tlmode = _settings->tlmode;
+ stack_align = _settings->stack_align;
+ stack_depth = _settings->stack_depth;
+ limit = _settings->limit;
+ print_mode = _settings->print_mode;
+ print_delim = _settings->print_delim;
+ compare_mode = _settings->compare_mode;
+ machinemodel = dbe_strdup (_settings->machinemodel);
+ ignore_no_xhwcprof = _settings->ignore_no_xhwcprof;
+ ignore_fs_warn = _settings->ignore_fs_warn;
+
+ // copy the tab list, too
+ tab_list = new Vector<DispTab*>;
+ DispTab *dsptab;
+
+ Vec_loop (DispTab*, _settings->tab_list, index, dsptab)
+ {
+ DispTab *ntab;
+ ntab = new DispTab (dsptab->type, dsptab->order, dsptab->visible, dsptab->cmdtoken);
+ ntab->setAvailability (dsptab->available);
+ tab_list->append (ntab);
+ }
+
+ // construct the master list of memory tabs & copy order
+ index = _settings->mem_tab_state->size ();
+ mem_tab_state = new Vector<bool>(index);
+ mem_tab_order = new Vector<int>(index);
+ for (int i = 0; i < index; i++)
+ {
+ mem_tab_state->append (false);
+ mem_tab_order->append (_settings->mem_tab_order->fetch (i));
+ }
+
+ // construct the master list of index tabs & copy order
+ index = _settings->indx_tab_state->size ();
+ indx_tab_state = new Vector<bool>(index);
+ indx_tab_order = new Vector<int>(index);
+ for (int i = 0; i < index; i++)
+ indx_tab_order->append (_settings->indx_tab_order->fetch (i));
+ set_IndxTabState (_settings->indx_tab_state);
+}
+
+Settings::~Settings ()
+{
+ for (int i = 0; i < pathmaps->size (); ++i)
+ {
+ pathmap_t *pmap = pathmaps->fetch (i);
+ free (pmap->old_prefix);
+ free (pmap->new_prefix);
+ delete pmap;
+ }
+ delete pathmaps;
+
+ for (int i = 0; i < lo_expands->size (); ++i)
+ {
+ lo_expand_t *lo_ex = lo_expands->fetch (i);
+ free (lo_ex->libname);
+ delete lo_ex;
+ }
+ delete lo_expands;
+
+ tab_list->destroy ();
+ delete tab_list;
+ delete indx_tab_state;
+ delete indx_tab_order;
+ delete mem_tab_state;
+ delete mem_tab_order;
+
+ free (str_vmode);
+ free (str_en_desc);
+ free (str_datamode);
+ free (str_scompcom);
+ free (str_sthresh);
+ free (str_dcompcom);
+ free (str_dthresh);
+ free (str_dmetrics);
+ free (str_dsort);
+ free (str_tlmode);
+ free (str_tldata);
+ free (str_tabs);
+ free (str_rtabs);
+ free (str_search_path);
+ free (str_name_format);
+ free (str_limit);
+ free (str_compare);
+ free (str_printmode);
+ free (preload_libdirs);
+ free (tldata);
+ free (en_desc_usr);
+ if (en_desc_cmp)
+ {
+ regfree (en_desc_cmp);
+ delete en_desc_cmp;
+ }
+}
+
+/**
+ * Read .er.rc file from the specified location
+ * @param path
+ * @return
+ */
+char *
+Settings::read_rc (char *path)
+{
+ StringBuilder sb;
+ Emsgqueue *commentq = new Emsgqueue (NTXT ("setting_commentq"));
+
+ // Check file name
+ if (NULL == path)
+ return dbe_strdup (GTXT ("Error: empty file name"));
+ bool override = true;
+ set_rc (path, true, commentq, override);
+ Emsg *msg = commentq->fetch ();
+ while (msg != NULL)
+ {
+ char *str = msg->get_msg ();
+ sb.append (str);
+ msg = msg->next;
+ }
+ return sb.toString ();
+}
+
+void
+Settings::read_rc (bool ipc_or_rdt_mode)
+{
+ bool override = false;
+
+ // Read file from the current working directory
+ char *rc_path = realpath (NTXT ("./.gprofng.rc"), NULL);
+ if (rc_path)
+ set_rc (rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode);
+
+ // Read file from the user's home directory
+ char *home = getenv (NTXT ("HOME"));
+ if (home)
+ {
+ char *strbuf = dbe_sprintf (NTXT ("%s/.gprofng.rc"), home);
+ char *home_rc_path = realpath (strbuf, NULL);
+ if (home_rc_path)
+ {
+ if (rc_path == NULL || strcmp (rc_path, home_rc_path) != 0)
+ set_rc (home_rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode);
+ free (home_rc_path);
+ }
+ free (strbuf);
+ }
+ free (rc_path);
+
+ // Read system-wide file
+ rc_path = dbe_sprintf (NTXT ("%s/../etc/gprofng.rc"), app->get_run_dir ());
+ if (access (rc_path, R_OK | F_OK) != 0)
+ {
+ StringBuilder sb;
+ sb.sprintf (GTXT ("Warning: Default gprofng.rc file (%s) missing; configuration error "), rc_path);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ app->get_comments_queue ()->append (m);
+ }
+ else
+ set_rc (rc_path, false, app->get_comments_queue (), override);
+ free (rc_path);
+ is_loexpand_default = true;
+ if (str_printmode == NULL)
+ {
+ // only if there's none set
+ print_mode = PM_TEXT;
+ str_printmode = dbe_strdup (NTXT ("text"));
+ }
+}
+
+
+// Handle various settings from reading the name .rc file
+// This function is called for each .rc file read, and, for
+// some settings, it accumulates the strings from the files.
+// For others, it accepts the first appearance for a setting in a
+// .rc file, and ignores subsequent appearances from other files.
+// Error messages are appended to the Emsgqueue specified by the caller
+
+#define MAXARGS 20
+
+void
+Settings::set_rc (const char *path, bool msg, Emsgqueue *commentq,
+ bool override, bool ipc_or_rdt_mode)
+{
+ CmdType cmd_type;
+ int arg_count, cparam;
+ char *cmd, *end_cmd, *strbuf;
+ char *arglist[MAXARGS];
+ StringBuilder sb;
+
+ FILE *fptr = fopen (path, NTXT ("r"));
+ if (fptr == NULL)
+ return;
+
+ if (msg)
+ {
+ sb.sprintf (GTXT ("Processed %s for default settings"), path);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+ }
+ int line_no = 0;
+ end_cmd = NULL;
+ while (!feof (fptr))
+ {
+ char *script = read_line (fptr);
+ if (script == NULL)
+ continue;
+ line_no++;
+ strtok (script, NTXT ("\n"));
+
+ // extract the command
+ cmd = strtok (script, NTXT (" \t"));
+ if (cmd == NULL || *cmd == '#' || *cmd == '\n')
+ {
+ free (script);
+ continue;
+ }
+ char *remainder = strtok (NULL, NTXT ("\n"));
+ // now extract the arguments
+ int nargs = 0;
+ for (;;)
+ {
+ if (nargs >= MAXARGS)
+ {
+ if (!msg)
+ {
+ msg = true; // suppress repeats of header
+ Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+ commentq->append (m);
+ }
+ sb.sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
+ MAXARGS, cmd, line_no);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+ break;
+ }
+
+ char *nextarg = strtok (remainder, NTXT ("\n"));
+ if (nextarg == NULL || *nextarg == '#')
+ break;
+ arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
+ remainder = end_cmd;
+ if (remainder == NULL)
+ break;
+ // skip any blanks or tabs to get to next argument
+ while (*remainder == ' ' || *remainder == '\t')
+ remainder++;
+ }
+ cmd_type = Command::get_command (cmd, arg_count, cparam);
+ // check for extra arguments
+ if ((cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF) && (nargs > arg_count))
+ {
+ if (!msg)
+ {
+ msg = true; // suppress repeats of header
+ Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+ commentq->append (m);
+ }
+ sb.sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"), cmd, line_no);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+ }
+ if (nargs < arg_count)
+ {
+ if (!msg)
+ {
+ msg = true; // suppress repeats of header
+ Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+ commentq->append (m);
+ }
+ sb.sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"),
+ cmd, line_no);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+
+ // ignore this command
+ free (script);
+ continue;
+ }
+ if (ipc_or_rdt_mode && (cmd_type != ADDPATH) && (cmd_type != PATHMAP))
+ {
+ free (script);
+ continue;
+ }
+ switch (cmd_type)
+ {
+ case SCOMPCOM:
+ if (!str_scompcom || override)
+ {
+ str_scompcom = dbe_strdup (arglist[0]);
+ proc_compcom (arglist[0], true, true);
+ }
+ break;
+ case STHRESH:
+ if (!str_sthresh || override)
+ {
+ str_sthresh = dbe_strdup (arglist[0]);
+ proc_thresh (arglist[0], true, true);
+ break;
+ }
+ break;
+ case DCOMPCOM:
+ if (!str_dcompcom || override)
+ {
+ str_dcompcom = dbe_strdup (arglist[0]);
+ proc_compcom (arglist[0], false, true);
+ }
+ break;
+ case COMPCOM:
+ // process as if it were for both source and disassembly
+ // note that if it is set, subsequent SCOMPCOM and DCOMPCOM
+ // will be ignored
+ if (!str_scompcom || override)
+ {
+ str_scompcom = dbe_strdup (arglist[0]);
+ proc_compcom (arglist[0], true, true);
+ }
+ if (!str_dcompcom || override)
+ {
+ str_dcompcom = dbe_strdup (arglist[0]);
+ proc_compcom (arglist[0], false, true);
+ }
+ break;
+ case DTHRESH:
+ if (!str_dthresh || override)
+ {
+ str_dthresh = dbe_strdup (arglist[0]);
+ proc_thresh (arglist[0], false, true);
+ }
+ break;
+ case DMETRICS:
+ // append new settings to old, if necessary
+ if (str_dmetrics)
+ {
+ char *name = strstr (str_dmetrics, ":name");
+ if (name == NULL)
+ strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]);
+ else
+ {
+ char * next = strstr (name + 1, ":");
+ if (next == NULL)
+ {
+ name[0] = '\0';
+ strbuf = dbe_sprintf ("%s:%s:name", str_dmetrics, arglist[0]);
+ }
+ else
+ strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]);
+ }
+ free (str_dmetrics);
+ str_dmetrics = strbuf;
+ }
+ else
+ str_dmetrics = dbe_strdup (arglist[0]);
+ break;
+ case DSORT:
+ // append new settings to old, if necessary
+ if (str_dsort)
+ {
+ strbuf = dbe_sprintf (NTXT ("%s:%s"), str_dsort, arglist[0]);
+ free (str_dsort);
+ str_dsort = strbuf;
+ }
+ else
+ str_dsort = dbe_strdup (arglist[0]);
+ break;
+ case TLMODE:
+ if (!str_tlmode || override)
+ {
+ str_tlmode = dbe_strdup (arglist[0]);
+ proc_tlmode (arglist[0], true);
+ }
+ break;
+ case TLDATA:
+ if (!str_tldata || override)
+ {
+ str_tldata = dbe_strdup (arglist[0]);
+ proc_tldata (arglist[0], true);
+ }
+ break;
+ case TABS:
+ if (!str_tabs || override)
+ // the string is processed later, after all .rc files are read
+ str_tabs = dbe_strdup (arglist[0]);
+ break;
+ case RTABS:
+ if (!str_rtabs || override)
+ // the string is processed later, after all .rc files are read
+ str_rtabs = dbe_strdup (arglist[0]);
+ break;
+ case ADDPATH:
+ if (str_search_path)
+ {
+ strbuf = dbe_sprintf (NTXT ("%s:%s"), str_search_path, arglist[0]);
+ free (str_search_path);
+ str_search_path = strbuf;
+ }
+ else
+ str_search_path = dbe_strdup (arglist[0]);
+ break;
+ case PATHMAP:
+ {
+ char *err = add_pathmap (pathmaps, arglist[0], arglist[1]);
+ free (err); // XXX error is not reported
+ break;
+ }
+ case LIBDIRS:
+ if (preload_libdirs == NULL)
+ preload_libdirs = dbe_strdup (arglist[0]);
+ break;
+ case NAMEFMT:
+ if (name_format == Histable::NA)
+ set_name_format (arglist[0]);
+ break;
+ case VIEWMODE:
+ if (!str_vmode || override)
+ {
+ str_vmode = dbe_strdup (arglist[0]);
+ set_view_mode (arglist[0], true);
+ }
+ break;
+ case EN_DESC:
+ if (!str_en_desc || override)
+ {
+ str_en_desc = dbe_strdup (arglist[0]);
+ set_en_desc (arglist[0], true);
+ }
+ break;
+ case LIMIT:
+ if (!str_limit || override)
+ {
+ str_limit = dbe_strdup (arglist[0]);
+ set_limit (arglist[0], true);
+ }
+ break;
+ case PRINTMODE:
+ if (!str_printmode || override)
+ set_printmode (arglist[0]);
+ break;
+ case COMPARE:
+ if (!str_compare || override)
+ {
+ char *s = arglist[0];
+ if (s)
+ str_compare = dbe_strdup (s);
+ else
+ s = NTXT ("");
+ if (strcasecmp (s, NTXT ("OFF")) == 0
+ || strcmp (s, NTXT ("0")) == 0)
+ set_compare_mode (CMP_DISABLE);
+ else if (strcasecmp (s, NTXT ("ON")) == 0
+ || strcmp (s, NTXT ("1")) == 0)
+ set_compare_mode (CMP_ENABLE);
+ else if (strcasecmp (s, NTXT ("DELTA")) == 0)
+ set_compare_mode (CMP_DELTA);
+ else if (strcasecmp (s, NTXT ("RATIO")) == 0)
+ set_compare_mode (CMP_RATIO);
+ else
+ {
+ sb.sprintf (GTXT (" .er.rc:%d The argument of 'compare' should be 'on', 'off', 'delta', or 'ratio'"),
+ (int) line_no);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+ }
+ }
+ break;
+
+ case INDXOBJDEF:
+ {
+ char *ret = dbeSession->indxobj_define (arglist[0], NULL, arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL, (nargs >= 4) ? PTXT (arglist[3]) : NULL);
+ if (ret != NULL)
+ {
+ sb.sprintf (GTXT (" %s: line %d `%s %s %s'\n"),
+ ret, line_no, cmd, arglist[0], arglist[1]);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+ }
+ break;
+ }
+#ifdef sparc
+ //XXX: should be conditional on the experiment ARCH, not dbe ARCH
+ case IGNORE_NO_XHWCPROF:
+ // ignore absence of -xhwcprof info for dataspace profiling
+ set_ignore_no_xhwcprof (true);
+ break;
+#endif // sparc
+ case IGNORE_FS_WARN:
+ // ignore file system warning in experiments
+ set_ignore_fs_warn (true);
+ break;
+ case OBJECT_SHOW:
+ // Add the named libraries to the lib_expands array
+ set_libexpand (arglist[0], LIBEX_SHOW, true);
+ break;
+ case OBJECT_HIDE:
+ // Add the named libraries to the lib_expands array
+ set_libexpand (arglist[0], LIBEX_HIDE, true);
+ break;
+ case OBJECT_API:
+ // Add the named libraries to the lib_expands array
+ set_libexpand (arglist[0], LIBEX_API, true);
+ break;
+ case COMMENT:
+ // ignore the line
+ break;
+ default:
+ {
+ // unexpected command in an rc file
+ if (!msg)
+ {
+ // if quiet, can remain so no longer
+ msg = true;
+ Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+ commentq->append (m);
+ }
+ sb.sprintf (GTXT (" Unrecognized .gprofng.rc command on line %d: `%.64s'"),
+ line_no, cmd);
+ Emsg *m = new Emsg (CMSG_COMMENT, sb);
+ commentq->append (m);
+ break;
+ }
+ }
+ free (script);
+ }
+ fclose (fptr);
+}
+
+Cmd_status
+Settings::set_view_mode (char *arg, bool rc)
+{
+ if (!strcasecmp (arg, NTXT ("user")))
+ view_mode = VMODE_USER;
+ else if (!strcasecmp (arg, NTXT ("expert")))
+ view_mode = VMODE_EXPERT;
+ else if (!strcasecmp (arg, NTXT ("machine")))
+ view_mode = VMODE_MACHINE;
+ else if (!rc)
+ return CMD_BAD_ARG;
+ return CMD_OK;
+}
+
+Cmd_status
+Settings::set_en_desc (char *arg, bool rc)
+{
+ regex_t *regex_desc = NULL;
+
+ // cases below should be similar to Coll_Ctrl::set_follow_mode() cases
+ if (!strcasecmp (arg, NTXT ("on")))
+ en_desc = true;
+ else if (!strcasecmp (arg, NTXT ("off")))
+ en_desc = false;
+ else if (arg[0] == '=' && arg[1] != 0)
+ {
+ // user has specified a string matching specification
+ int ercode;
+ { // compile regex_desc
+ char * str = dbe_sprintf (NTXT ("^%s$"), arg + 1);
+ regex_desc = new regex_t;
+ memset (regex_desc, 0, sizeof (regex_t));
+ ercode = regcomp (regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ free (str);
+ }
+ if (ercode)
+ {
+ // syntax error in parsing string
+ delete regex_desc;
+ if (!rc)
+ return CMD_BAD_ARG;
+ return CMD_OK;
+ }
+ en_desc = true;
+ }
+ else
+ {
+ if (!rc)
+ return CMD_BAD_ARG;
+ return CMD_OK;
+ }
+ free (en_desc_usr);
+ en_desc_usr = dbe_strdup (arg);
+ if (en_desc_cmp)
+ {
+ regfree (en_desc_cmp);
+ delete en_desc_cmp;
+ }
+ en_desc_cmp = regex_desc;
+ return CMD_OK;
+}
+
+// See if a descendant matches either the lineage or the executable name
+bool
+Settings::check_en_desc (const char *lineage, const char *targname)
+{
+ bool rc;
+ if (en_desc_cmp == NULL)
+ return en_desc; // no specification was set, use the binary on/off value
+ if (lineage == NULL) // user doesn't care about specification
+ return en_desc; // use the binary on/off specification
+ if (!regexec (en_desc_cmp, lineage, 0, NULL, 0))
+ rc = true; // this one matches user specification
+ else if (targname == NULL)
+ rc = false; //a NULL name does not match any expression
+ else if (!regexec (en_desc_cmp, targname, 0, NULL, 0))
+ rc = true; // this one matches the executable name
+ else
+ rc = false;
+ return rc;
+}
+
+char *
+Settings::set_limit (char *arg, bool)
+{
+ limit = (int) strtol (arg, (char **) NULL, 10);
+ return NULL;
+}
+
+char *
+Settings::set_printmode (char *arg)
+{
+ if (arg == NULL)
+ return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"),
+ NTXT ("printmode"), NTXT ("text"), NTXT ("html"));
+ if (strlen (arg) == 1)
+ {
+ print_mode = PM_DELIM_SEP_LIST;
+ print_delim = arg[0];
+ }
+ else if (!strcasecmp (arg, NTXT ("text")))
+ print_mode = PM_TEXT;
+ else if (!strcasecmp (arg, NTXT ("html")))
+ print_mode = PM_HTML;
+ else
+ return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"),
+ NTXT ("printmode"), NTXT ("text"), NTXT ("html"));
+ free (str_printmode);
+ str_printmode = dbe_strdup (arg);
+ return NULL;
+}
+
+Cmd_status
+Settings::proc_compcom (const char *cmd, bool isSrc, bool rc)
+{
+ int ck_compcom_bits, ck_threshold;
+ bool ck_hex_visible = false;
+ bool ck_src_visible = false;
+ bool ck_srcmetric_visible = false;
+ bool got_compcom_bits, got_threshold, got_src_visible, got_srcmetric_visible;
+ bool got_hex_visible, got;
+ int len, i;
+ char *mcmd, *param;
+ int flag, value = 0;
+ Cmd_status status;
+ char buf[BUFSIZ], *list;
+
+ if (cmd == NULL)
+ return CMD_BAD;
+ ck_compcom_bits = 0;
+ ck_threshold = 0;
+ got_compcom_bits = got_threshold = got_src_visible = false;
+ got_srcmetric_visible = got_hex_visible = false;
+ snprintf (buf, sizeof (buf), NTXT ("%s"), cmd);
+ list = buf;
+ while ((mcmd = strtok (list, NTXT (":"))) != NULL)
+ {
+ list = NULL;
+ // if "all" or "none"
+ if (!strcasecmp (mcmd, Command::ALL_CMD))
+ {
+ got_compcom_bits = true;
+ ck_compcom_bits = CCMV_ALL;
+ continue;
+ }
+ else if (!strcasecmp (mcmd, Command::NONE_CMD))
+ {
+ got_compcom_bits = true;
+ ck_compcom_bits = 0;
+ continue;
+ }
+
+ // Find parameter after '='
+ param = strchr (mcmd, '=');
+ if (param)
+ {
+ *param = '\0';
+ param++;
+ }
+ status = CMD_OK;
+ got = false;
+ flag = 0;
+ len = (int) strlen (mcmd);
+ for (i = 0; status == CMD_OK && i < comp_size; i++)
+ if (!strncasecmp (mcmd, comp_cmd[i], len))
+ {
+ if (got) // Ambiguous comp_com command
+ status = CMD_AMBIGUOUS;
+ else
+ {
+ got = true;
+ flag = comp_vis[i];
+ // Check argument
+ if (flag == COMP_THRESHOLD)
+ {
+ if (param == NULL)
+ status = CMD_BAD_ARG;
+ else
+ {
+ value = (int) strtol (param, &param, 10);
+ if (value < 0 || value > 100)
+ status = CMD_OUTRANGE;
+ }
+ }
+ else if (param != NULL)
+ status = CMD_BAD_ARG;
+ }
+ }
+
+ // Not valid comp_com command
+ if (!got)
+ status = CMD_INVALID;
+ if (status != CMD_OK)
+ {
+ if (!rc)
+ return status;
+ continue;
+ }
+
+ // Set bits
+ switch (flag)
+ {
+ case COMP_CMPLINE:
+ cmpline_visible = true;
+ break;
+ case COMP_FUNCLINE:
+ funcline_visible = true;
+ break;
+ case COMP_THRESHOLD:
+ got_threshold = true;
+ ck_threshold = value;
+ break;
+ case COMP_SRC:
+ got_src_visible = true;
+ ck_src_visible = true;
+ break;
+ case COMP_SRC_METRIC:
+ got_srcmetric_visible = true;
+ ck_srcmetric_visible = true;
+ got_src_visible = true;
+ ck_src_visible = true;
+ break;
+ case COMP_NOSRC:
+ got_src_visible = true;
+ ck_src_visible = false;
+ break;
+ case COMP_HEX:
+ got_hex_visible = true;
+ ck_hex_visible = true;
+ break;
+ case COMP_NOHEX:
+ got_hex_visible = true;
+ ck_hex_visible = false;
+ break;
+ case CCMV_BASIC:
+ got_compcom_bits = true;
+ ck_compcom_bits = CCMV_BASIC;
+ break;
+ default:
+ got_compcom_bits = true;
+ ck_compcom_bits |= flag;
+ }
+ }
+
+ // No error, update
+ if (got_compcom_bits)
+ {
+ if (isSrc)
+ src_compcom = ck_compcom_bits;
+ else
+ dis_compcom = ck_compcom_bits;
+ }
+ if (got_threshold)
+ {
+ if (isSrc)
+ threshold_src = ck_threshold;
+ else
+ threshold_dis = ck_threshold;
+ }
+ if (got_src_visible)
+ src_visible = ck_src_visible;
+ if (got_srcmetric_visible)
+ srcmetric_visible = ck_srcmetric_visible;
+ if (got_hex_visible)
+ hex_visible = ck_hex_visible;
+ return CMD_OK;
+}
+
+// Process a threshold setting
+Cmd_status
+Settings::proc_thresh (char *cmd, bool isSrc, bool rc)
+{
+ int value;
+ if (cmd == NULL)
+ value = DEFAULT_SRC_DIS_THRESHOLD; // the default
+ else
+ value = (int) strtol (cmd, &cmd, 10);
+ if (value < 0 || value > 100)
+ {
+ if (!rc)
+ return CMD_OUTRANGE;
+ value = DEFAULT_SRC_DIS_THRESHOLD;
+ }
+ if (isSrc)
+ threshold_src = value;
+ else
+ threshold_dis = value;
+ return CMD_OK;
+}
+
+// return any error string from processing visibility settings
+char *
+Settings::get_compcom_errstr (Cmd_status status, const char *cmd)
+{
+ int i;
+ StringBuilder sb;
+ switch (status)
+ {
+ case CMD_BAD:
+ sb.append (GTXT ("No commentary classes has been specified."));
+ break;
+ case CMD_AMBIGUOUS:
+ sb.append (GTXT ("Ambiguous commentary classes: "));
+ break;
+ case CMD_BAD_ARG:
+ sb.append (GTXT ("Invalid argument for commentary classes: "));
+ break;
+ case CMD_OUTRANGE:
+ sb.append (GTXT ("Out of range commentary classes argument: "));
+ break;
+ case CMD_INVALID:
+ sb.append (GTXT ("Invalid commentary classes: "));
+ break;
+ case CMD_OK:
+ break;
+ }
+ if (cmd)
+ sb.append (cmd);
+ sb.append (GTXT ("\nAvailable commentary classes: "));
+ for (i = 0; i < comp_size; i++)
+ {
+ sb.append (comp_cmd[i]);
+ if (i == comp_size - 1)
+ sb.append (NTXT ("=#\n"));
+ else
+ sb.append (NTXT (":"));
+ }
+ return sb.toString ();
+}
+
+// Process a timeline-mode setting
+Cmd_status
+Settings::proc_tlmode (char *cmd, bool rc)
+{
+ bool got_tlmode, got_stack_align, got_stack_depth, got;
+ int ck_tlmode = 0, ck_stack_align = 0, ck_stack_depth = 0;
+ int len, i;
+ char *mcmd, *param;
+ int cmd_id, value = 0;
+ TLModeSubcommand cmd_type;
+ Cmd_status status;
+ char buf[BUFSIZ], *list;
+ if (cmd == NULL)
+ return CMD_BAD;
+ got_tlmode = got_stack_align = got_stack_depth = false;
+ snprintf (buf, sizeof (buf), NTXT ("%s"), cmd);
+ list = buf;
+ while ((mcmd = strtok (list, NTXT (":"))) != NULL)
+ {
+ list = NULL;
+
+ // Find parameter after '='
+ param = strchr (mcmd, '=');
+ if (param)
+ {
+ *param = '\0';
+ param++;
+ }
+ status = CMD_OK;
+ got = false;
+ cmd_id = 0;
+ cmd_type = TLCMD_INVALID;
+ len = (int) strlen (mcmd);
+ for (i = 0; status == CMD_OK && i < tlmode_size; i++)
+ {
+ if (!strncasecmp (mcmd, tlmode_cmd[i].cmdText, len))
+ {
+ if (got) // Ambiguous timeline mode
+ status = CMD_AMBIGUOUS;
+ else
+ {
+ got = true;
+ cmd_type = tlmode_cmd[i].cmdType;
+ cmd_id = tlmode_cmd[i].cmdId;
+
+ // Check argument
+ if (cmd_type == TLCMD_DEPTH)
+ {
+ if (param == NULL)
+ status = CMD_BAD_ARG;
+ else
+ {
+ value = (int) strtol (param, &param, 10);
+ if (value <= 0 || value > 256)
+ status = CMD_OUTRANGE;
+ }
+ }
+ else if (param != NULL)
+ status = CMD_BAD_ARG;
+ }
+ }
+ }
+
+ // Not valid timeline mode
+ if (!got)
+ status = CMD_INVALID;
+ if (status != CMD_OK)
+ {
+ if (!rc)
+ return status;
+ continue;
+ }
+
+ // Set bits
+ switch (cmd_type)
+ {
+ case TLCMD_ENTITY_MODE:
+ got_tlmode = true;
+ ck_tlmode = cmd_id;
+ break;
+ case TLCMD_ALIGN:
+ got_stack_align = true;
+ ck_stack_align = cmd_id;
+ break;
+ case TLCMD_DEPTH:
+ got_stack_depth = true;
+ ck_stack_depth = value;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // No error, update
+ if (got_tlmode)
+ tlmode = ck_tlmode;
+ if (got_stack_align)
+ stack_align = ck_stack_align;
+ if (got_stack_depth)
+ stack_depth = ck_stack_depth;
+ return CMD_OK;
+}
+
+// Process timeline data specification
+Cmd_status
+Settings::proc_tldata (const char *cmd, bool /* if true, ignore any error */)
+{
+ free (tldata);
+ tldata = dbe_strdup (cmd); // let GUI parse it
+ return CMD_OK;
+}
+
+void
+Settings::set_tldata (const char* _tldata_str)
+{
+ free (tldata);
+ tldata = dbe_strdup (_tldata_str);
+}
+
+char*
+Settings::get_tldata ()
+{
+ return dbe_strdup (tldata);
+}
+
+Cmd_status
+Settings::set_name_format (char *arg)
+{
+ char *colon = strchr (arg, ':');
+ size_t arg_len = (colon) ? (colon - arg) : strlen (arg);
+ Histable::NameFormat fname_fmt = Histable::NA;
+ if (!strncasecmp (arg, NTXT ("long"), arg_len))
+ fname_fmt = Histable::LONG;
+ else if (!strncasecmp (arg, NTXT ("short"), arg_len))
+ fname_fmt = Histable::SHORT;
+ else if (!strncasecmp (arg, NTXT ("mangled"), arg_len))
+ fname_fmt = Histable::MANGLED;
+ else
+ return CMD_BAD_ARG;
+
+ bool soname_fmt = false;
+ if (colon && (colon + 1))
+ {
+ colon++;
+ if (!strcasecmp (colon, NTXT ("soname")))
+ soname_fmt = true;
+ else if (!strcasecmp (colon, NTXT ("nosoname")))
+ soname_fmt = false;
+ else
+ return CMD_BAD_ARG;
+ }
+ name_format = Histable::make_fmt (fname_fmt, soname_fmt);
+ return CMD_OK;
+}
+
+void
+Settings::buildMasterTabList ()
+{
+ tab_list = new Vector<DispTab*>;
+ int i = -1;
+
+ // Add tabs for all the known reports
+ tab_list->append (new DispTab (DSP_DEADLOCKS, i, false, DEADLOCK_EVNTS));
+ tab_list->append (new DispTab (DSP_FUNCTION, i, false, FUNCS));
+ tab_list->append (new DispTab (DSP_TIMELINE, i, false, TIMELINE));
+ tab_list->append (new DispTab (DSP_CALLTREE, i, false, CALLTREE));
+ tab_list->append (new DispTab (DSP_CALLFLAME, i, false, CALLFLAME));
+ tab_list->append (new DispTab (DSP_DUALSOURCE, i, false, DUALSOURCE));
+ tab_list->append (new DispTab (DSP_SOURCE_DISASM, i, false, SOURCEDISAM));
+ tab_list->append (new DispTab (DSP_SOURCE, i, false, SOURCE));
+ tab_list->append (new DispTab (DSP_LINE, i, false, HOTLINES));
+ tab_list->append (new DispTab (DSP_DISASM, i, false, DISASM));
+ tab_list->append (new DispTab (DSP_PC, i, false, HOTPCS));
+ tab_list->append (new DispTab (DSP_LEAKLIST, i, false, LEAKS));
+ tab_list->append (new DispTab (DSP_IOACTIVITY, i, false, IOACTIVITY));
+ tab_list->append (new DispTab (DSP_HEAPCALLSTACK, i, false, HEAP));
+ tab_list->append (new DispTab (DSP_IFREQ, i, false, IFREQ));
+ tab_list->append (new DispTab (DSP_CALLER, i, false, GPROF));
+ tab_list->append (new DispTab (DSP_STATIS, i, false, STATISTICS));
+ tab_list->append (new DispTab (DSP_EXP, i, false, HEADER));
+}
+
+// Update tablist based on data availability
+void
+Settings::updateTabAvailability ()
+{
+ int index;
+ DispTab *dsptab;
+
+ Vec_loop (DispTab*, tab_list, index, dsptab)
+ {
+ if (dsptab->type == DSP_DATAOBJ)
+ dsptab->setAvailability (dbeSession->is_datamode_available ());
+ else if (dsptab->type == DSP_DLAYOUT)
+ dsptab->setAvailability (dbeSession->is_datamode_available ());
+ else if (dsptab->type == DSP_LEAKLIST)
+ dsptab->setAvailability (false);
+ else if (dsptab->type == DSP_IOACTIVITY)
+ dsptab->setAvailability (dbeSession->is_iodata_available ());
+ else if (dsptab->type == DSP_HEAPCALLSTACK)
+ dsptab->setAvailability (dbeSession->is_heapdata_available ());
+ else if (dsptab->type == DSP_TIMELINE)
+ dsptab->setAvailability (dbeSession->is_timeline_available ());
+ else if (dsptab->type == DSP_IFREQ)
+ dsptab->setAvailability (dbeSession->is_ifreq_available ());
+ else if (dsptab->type == DSP_RACES)
+ dsptab->setAvailability (dbeSession->is_racelist_available ());
+ else if (dsptab->type == DSP_DEADLOCKS)
+ dsptab->setAvailability (dbeSession->is_deadlocklist_available ());
+ else if (dsptab->type == DSP_DUALSOURCE)
+ dsptab->setAvailability (dbeSession->is_racelist_available ()
+ || dbeSession->is_deadlocklist_available ());
+ }
+}
+
+// Process a tab setting
+Cmd_status
+Settings::proc_tabs (bool _rdtMode)
+{
+ int arg_cnt, cparam;
+ int count = 0;
+ int index;
+ DispTab *dsptab;
+ char *cmd;
+ if (tabs_processed == true)
+ return CMD_OK;
+ tabs_processed = true;
+ if (_rdtMode == true)
+ {
+ if (str_rtabs == NULL)
+ str_rtabs = strdup ("header");
+ cmd = str_rtabs;
+ }
+ else
+ {
+ if (str_tabs == NULL)
+ str_tabs = strdup ("header");
+ cmd = str_tabs;
+ }
+ if (strcmp (cmd, NTXT ("none")) == 0)
+ return CMD_OK;
+ Vector <char *> *tokens = split_str (cmd, ':');
+ for (long j = 0, sz = VecSize (tokens); j < sz; j++)
+ {
+ char *tabname = tokens->get (j);
+ // search for this tab command token
+ CmdType c = Command::get_command (tabname, arg_cnt, cparam);
+ if (c == INDXOBJ)
+ {
+ // set the bit for this subtype
+ indx_tab_state->store (cparam, true);
+ indx_tab_order->store (cparam, count++);
+ }
+ else
+ {
+ // search for this tab type in the regular tabs
+ Vec_loop (DispTab*, tab_list, index, dsptab)
+ {
+ if (dsptab->cmdtoken == c)
+ {
+ dsptab->visible = true;
+ dsptab->order = count++;
+ break;
+ }
+ }
+ }
+ free (tabname);
+ }
+ delete tokens;
+ return CMD_OK;
+}
+
+void
+Settings::set_MemTabState (Vector<bool>*selected)
+{
+ if (selected->size () == 0)
+ return;
+ for (int j = 0; j < mem_tab_state->size (); j++)
+ mem_tab_state->store (j, selected->fetch (j));
+}
+
+// define a new memory object type
+
+void
+Settings::mobj_define (MemObjType_t */* mobj */, bool state)
+{
+ if (mem_tab_state->size () == 0)
+ state = true;
+ mem_tab_state->append (state);
+ mem_tab_order->append (-1);
+}
+
+void
+Settings::set_IndxTabState (Vector<bool>*selected)
+{
+ for (int j = 0; j < selected->size (); j++)
+ indx_tab_state->store (j, selected->fetch (j));
+}
+
+// define a new index object type
+void
+Settings::indxobj_define (int type, bool state)
+{
+ indx_tab_state->store (type, state);
+ indx_tab_order->store (type, -1);
+}
+
+void
+Settings::set_pathmaps (Vector<pathmap_t*> *newPathMap)
+{
+ if (pathmaps)
+ {
+ pathmaps->destroy ();
+ delete pathmaps;
+ }
+ pathmaps = newPathMap;
+}
+
+static char *
+get_canonical_name (const char *fname)
+{
+ char *nm = dbe_strdup (fname);
+ for (size_t len = strlen (nm); (len > 0) && (nm[len - 1] == '/'); len--)
+ nm[len - 1] = 0;
+ return nm;
+}
+
+char *
+Settings::add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to)
+{
+ // Check for errors
+ if (from == NULL || to == NULL)
+ return dbe_strdup (GTXT ("Pathmap can have neither from nor to as NULL\n"));
+ if (strcmp (from, to) == 0)
+ return dbe_strdup (GTXT ("Pathmap from must differ from to\n"));
+ char *old_prefix = get_canonical_name (from);
+ char *new_prefix = get_canonical_name (to);
+
+ // Check the pathmap list
+ for (int i = 0, sz = v->size (); i < sz; i++)
+ {
+ pathmap_t *pmp = v->get (i);
+ if ((strcmp (pmp->old_prefix, old_prefix) == 0) &&(strcmp (pmp->new_prefix, new_prefix) == 0))
+ {
+ char *s = dbe_sprintf (GTXT ("Pathmap from `%s' to `%s' already exists\n"), old_prefix, new_prefix);
+ free (old_prefix);
+ free (new_prefix);
+ return s;
+ }
+ }
+ // construct a map for this pair
+ pathmap_t *thismap = new pathmap_t;
+ thismap->old_prefix = old_prefix;
+ thismap->new_prefix = new_prefix;
+ v->append (thismap);
+ return NULL;
+}
+
+// Set all shared object expands back to .rc file defaults,
+// as stored in the DbeSession Settings
+bool
+Settings::set_libdefaults ()
+{
+ // See if this is unchanged
+ if (is_loexpand_default == true)
+ return false; // no change
+
+ // replicate the DbeSession's lo_expand vector and default settings
+ lo_expand_t *this_lo_ex;
+ lo_expand_t *new_lo_ex;
+ int index;
+ lo_expand_default = dbeSession->get_settings ()->lo_expand_default;
+ lo_expands = new Vector<lo_expand_t*>;
+ Vec_loop (lo_expand_t*, dbeSession->get_settings ()->lo_expands, index, this_lo_ex)
+ {
+ new_lo_ex = new lo_expand_t;
+ new_lo_ex->libname = dbe_strdup (this_lo_ex->libname);
+ new_lo_ex->expand = this_lo_ex->expand;
+ lo_expands->append (new_lo_ex);
+ }
+ is_loexpand_default = true;
+ return true;
+}
+
+bool
+Settings::set_libexpand (char *cov, enum LibExpand expand, bool rc)
+{
+ int index;
+ lo_expand_t *loe;
+ bool change = false;
+ if (cov == NULL || !strcasecmp (cov, Command::ALL_CMD))
+ { // set all libraries
+ // set the default
+ if (lo_expand_default != expand)
+ {
+ lo_expand_default = expand;
+ change = true;
+ is_loexpand_default = false;
+ }
+
+ // and force any explicit settings to match, too
+ Vec_loop (lo_expand_t*, lo_expands, index, loe)
+ {
+ if (loe->expand != expand)
+ {
+ loe->expand = expand;
+ change = true;
+ is_loexpand_default = false;
+ }
+ }
+
+ }
+ else
+ { // parsing coverage
+ Vector <char *> *tokens = split_str (cov, ',');
+ for (long j = 0, sz = VecSize (tokens); j < sz; j++)
+ {
+ char *lo_name = tokens->get (j);
+ char *newname = get_basename (lo_name);
+ bool found = false;
+ Vec_loop (lo_expand_t*, lo_expands, index, loe)
+ {
+ if (strcmp (loe->libname, newname) == 0)
+ {
+ if (loe->expand != expand)
+ {
+ if (rc == false)
+ {
+ loe->expand = expand;
+ change = true;
+ is_loexpand_default = false;
+ }
+ }
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false)
+ {
+ // construct a map for this pair
+ lo_expand_t *thisloe;
+ thisloe = new lo_expand_t;
+ thisloe->libname = dbe_strdup (newname);
+ thisloe->expand = expand;
+ change = true;
+ is_loexpand_default = false;
+
+ // add it to the vector
+ lo_expands->append (thisloe);
+ }
+ free (lo_name);
+ }
+ delete tokens;
+ }
+ return change;
+}
+
+enum LibExpand
+Settings::get_lo_setting (char *name)
+{
+ int index;
+ lo_expand_t *loe;
+ char *lo_name = get_basename (name);
+ Vec_loop (lo_expand_t*, lo_expands, index, loe)
+ {
+ if (strcmp (loe->libname, lo_name) == 0)
+ return loe->expand;
+ }
+ return lo_expand_default;
+}
diff --git a/gprofng/src/Settings.h b/gprofng/src/Settings.h
new file mode 100644
index 0000000..fc696e8
--- /dev/null
+++ b/gprofng/src/Settings.h
@@ -0,0 +1,425 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _SETTINGS_H
+#define _SETTINGS_H
+
+#include <stdio.h>
+#include <regex.h>
+
+#include "gp-defs.h"
+#include "Histable.h"
+#include "MemorySpace.h"
+#include "Metric.h"
+#include "dbe_types.h"
+#include "dbe_structs.h"
+#include "enums.h"
+#include "vec.h"
+
+class Emsgqueue;
+class Application;
+
+struct DispTab;
+
+// Settings object
+
+class Settings
+{
+public:
+ friend class DbeView;
+ friend class DbeSession;
+
+ Settings (Application *_app);
+ Settings (Settings *_settings);
+ virtual ~Settings ();
+ void read_rc (bool ipc_or_rdt_mode); // read all rc files
+ char *read_rc (char *path); // read rc file
+ void buildMasterTabList (); // build list of Tabs that can be invoked
+ void updateTabAvailability (); // update for datamode, leaklist
+ Cmd_status set_name_format (char *str); // from a string
+
+ Vector<DispTab*> *
+ get_TabList () // Get the list of tabs for this view
+ {
+ return tab_list;
+ }
+
+ Vector<bool> *
+ get_MemTabState () // Get the list and order of memory tabs for this view
+ {
+ return mem_tab_state;
+ }
+
+ Vector<int> *
+ get_MemTabOrder ()
+ {
+ return mem_tab_order;
+ }
+
+ // Set the list of memory tabs for this view
+ void set_MemTabState (Vector<bool>*sel);
+
+ // add a newly-defined memory object tab
+ void mobj_define (MemObjType_t *, bool state);
+
+ // add a newly-defined index object tab
+ void indxobj_define (int type, bool state);
+
+ Vector<bool> *
+ get_IndxTabState () // Get the list and order of index tabs for this view
+ {
+ return indx_tab_state;
+ }
+
+ Vector<int> *
+ get_IndxTabOrder ()
+ {
+ return indx_tab_order;
+ }
+
+ // Set the list of index tabs for this view
+ void set_IndxTabState (Vector<bool>*sel);
+
+ void
+ set_name_format (int fname_fmt, bool soname_fmt)
+ {
+ name_format = Histable::make_fmt (fname_fmt, soname_fmt);
+ }
+
+ Histable::NameFormat
+ get_name_format ()
+ {
+ return name_format;
+ }
+
+ // public methods for setting and accessing the settings
+ Cmd_status set_view_mode (char *str, bool rc); // from a string
+
+ void
+ set_view_mode (VMode mode)
+ {
+ view_mode = mode;
+ }
+
+ VMode
+ get_view_mode ()
+ {
+ return view_mode;
+ }
+
+ // set the en_desc expression/on/off
+ Cmd_status set_en_desc (char *str, bool rc); // from a string
+ // check if the lineage or the target name matches the en_desc expression
+ bool check_en_desc (const char *lineage, const char *targname);
+
+ char *set_limit (char *str, bool rc); // from a string
+
+ char *
+ set_limit (int _limit)
+ {
+ limit = _limit;
+ return NULL;
+ }
+
+ int
+ get_limit ()
+ {
+ return limit;
+ }
+
+ char *set_printmode (char *_pmode);
+
+ // processing compiler commentary visibility bits
+ Cmd_status proc_compcom (const char *cmd, bool isSrc, bool rc);
+
+ // return any error string from processing visibility settings
+ char *get_compcom_errstr (Cmd_status status, const char *cmd);
+
+ // methods for setting and getting strings, and individual settings
+
+ char *
+ get_str_scompcom ()
+ {
+ return str_scompcom;
+ }
+
+ char *
+ get_str_dcompcom ()
+ {
+ return str_dcompcom;
+ }
+
+ int
+ get_src_compcom ()
+ {
+ return src_compcom;
+ }
+
+ int
+ get_dis_compcom ()
+ {
+ return dis_compcom;
+ }
+
+ void
+ set_cmpline_visible (bool v)
+ {
+ cmpline_visible = v;
+ }
+
+ void
+ set_funcline_visible (bool v)
+ {
+ funcline_visible = v;
+ }
+
+ void
+ set_src_visible (int v)
+ {
+ src_visible = v;
+ }
+
+ int
+ get_src_visible ()
+ {
+ return src_visible;
+ }
+
+ void
+ set_srcmetric_visible (bool v)
+ {
+ srcmetric_visible = v;
+ }
+
+ bool
+ get_srcmetric_visible ()
+ {
+ return srcmetric_visible;
+ }
+
+ void
+ set_hex_visible (bool v)
+ {
+ hex_visible = v;
+ }
+
+ bool
+ get_hex_visible ()
+ {
+ return hex_visible;
+ }
+
+ // processing and accessing the threshold settings
+ Cmd_status proc_thresh (char *cmd, bool isSrc, bool rc);
+
+ int
+ get_thresh_src ()
+ {
+ return threshold_src;
+ }
+
+ int
+ get_thresh_dis ()
+ {
+ return threshold_dis;
+ }
+
+ // process a tlmode setting
+ Cmd_status proc_tlmode (char *cmd, bool rc);
+
+ void
+ set_tlmode (int _tlmode)
+ {
+ tlmode = _tlmode;
+ }
+
+ int
+ get_tlmode ()
+ {
+ return tlmode;
+ }
+
+ void
+ set_stack_align (int _stack_align)
+ {
+ stack_align = _stack_align;
+ }
+
+ int
+ get_stack_align ()
+ {
+ return stack_align;
+ }
+
+ void
+ set_stack_depth (int _stack_depth)
+ {
+ stack_depth = _stack_depth;
+ }
+
+ int
+ get_stack_depth ()
+ {
+ return stack_depth;
+ }
+
+ // process a tabs setting: called when the tab list is requested
+ Cmd_status proc_tabs (bool _rdtMode);
+
+ Cmd_status proc_tldata (const char *cmd, bool rc); // process a tldata setting
+ void set_tldata (const char* tldata_string);
+ char *get_tldata ();
+
+ char *
+ get_default_metrics ()
+ {
+ return str_dmetrics;
+ }
+
+ char *
+ get_default_sort ()
+ {
+ return str_dsort;
+ }
+
+ void
+ set_ignore_no_xhwcprof (bool v) // ignore no xhwcprof errors for dataspace
+ {
+ ignore_no_xhwcprof = v;
+ }
+
+ bool
+ get_ignore_no_xhwcprof ()
+ {
+ return ignore_no_xhwcprof;
+ }
+
+ void
+ set_ignore_fs_warn (bool v) // ignore filesystem warnings in experiments
+ {
+ ignore_fs_warn = v;
+ }
+
+ bool
+ get_ignore_fs_warn ()
+ {
+ return ignore_fs_warn;
+ }
+
+ // add a pathmap
+ static char *add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to);
+ void set_pathmaps (Vector<pathmap_t*> *newPathMap);
+
+ // add a LoadObject expansion setting
+ bool set_libexpand (char *, enum LibExpand, bool);
+ enum LibExpand get_lo_setting (char *);
+
+ // set LoadObject expansion defaults back to .rc specifications
+ bool set_libdefaults ();
+
+ void
+ set_compare_mode (int mode)
+ {
+ compare_mode = mode;
+ }
+
+ int
+ get_compare_mode ()
+ {
+ return compare_mode;
+ }
+
+ char *
+ get_machinemodel ()
+ {
+ return dbe_strdup (machinemodel);
+ }
+
+ char *preload_libdirs;
+
+protected: // data
+ Application *app;
+
+ // default strings from .rc file
+ char *str_vmode;
+ char *str_en_desc;
+ char *str_datamode;
+ char *str_scompcom;
+ char *str_sthresh;
+ char *str_dcompcom;
+ char *str_dthresh;
+ char *str_dmetrics;
+ char *str_dsort;
+ char *str_tlmode;
+ char *str_tldata;
+ char *str_tabs;
+ char *str_rtabs;
+ char *str_search_path;
+ char *str_name_format;
+ char *str_limit;
+ char *str_printmode;
+ char *str_compare;
+
+ bool tabs_processed;
+
+ // Processed settings
+ bool en_desc; // controls for reading descendant processes
+ char * en_desc_usr; // selective descendants: user specificaton
+ regex_t * en_desc_cmp; // selective descendants: compiled specification
+ Histable::NameFormat name_format; // long/short/mangled naming for C++/Java
+ VMode view_mode; // Java mode
+ int src_compcom; // compiler commentary visibility for anno-src
+ int dis_compcom; // compiler commentary visibility for anno-dis
+ int threshold_src; // threshold for anno-src
+ int threshold_dis; // threshold for anno-dis
+ int cmpline_visible; // show compile-line flags
+ int funcline_visible; // show compile-line flags
+ int src_visible; // show source in disasm
+ bool srcmetric_visible; // show metrics for source in disasm
+ bool hex_visible; // show hex code in disasm
+ char* tldata; // timeline data type string
+ int tlmode; // timeline mode for bars
+ int stack_align; // timeline stack alignment
+ int stack_depth; // timeline stack depth
+ int limit; // print limit
+ enum PrintMode print_mode;// print mode
+ char print_delim; // the delimiter, if print mode = PM_DELIM_SEP_LIST
+ int compare_mode; // compare mode
+
+ char *machinemodel; // machine model for Memory Objects
+
+ bool ignore_no_xhwcprof; // ignore no -xhwcprof data in dataspace
+ bool ignore_fs_warn; // ignore file-system recording warning
+
+ void set_rc (const char *path, bool msg, Emsgqueue *commentq,
+ bool override, bool ipc_or_rdt_mode = false);
+
+ Vector<DispTab*> *tab_list;
+ Vector<pathmap_t*> *pathmaps;
+ Vector<lo_expand_t*> *lo_expands;
+ enum LibExpand lo_expand_default;
+ bool is_loexpand_default;
+ Vector<bool> *mem_tab_state;
+ Vector<int> *mem_tab_order;
+ Vector<bool> *indx_tab_state;
+ Vector<int> *indx_tab_order;
+};
+
+#endif /* ! _SETTINGS_H */
diff --git a/gprofng/src/SourceFile.cc b/gprofng/src/SourceFile.cc
new file mode 100644
index 0000000..bd0a1f1
--- /dev/null
+++ b/gprofng/src/SourceFile.cc
@@ -0,0 +1,229 @@
+/* Copyright (C) 2021 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 <unistd.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "SourceFile.h"
+#include "DefaultMap.h"
+#include "DbeFile.h"
+#include "LoadObject.h"
+#include "Module.h"
+
+int SourceFile::curId = 0;
+
+SourceFile::SourceFile (const char *file_name)
+{
+ status = OS_NOTREAD;
+ srcLines = NULL;
+ srcInode = -1;
+ lines = NULL;
+ dbeLines = NULL;
+ functions = new DefaultMap<Function *, Function *>();
+ dbeFile = new DbeFile (file_name);
+ dbeFile->filetype |= DbeFile::F_SOURCE | DbeFile::F_FILE;
+ set_name ((char *) file_name);
+ srcMTime = (time_t) 0;
+ isTmpFile = false;
+ flags = 0;
+ read_stabs = false;
+ id = (uint64_t) ((Histable::SOURCEFILE << 24) + curId) << 32;
+ curId++;
+}
+
+SourceFile::~SourceFile ()
+{
+ destroy_map (DbeLine *, dbeLines);
+ delete functions;
+ delete dbeFile;
+ if (lines)
+ {
+ lines->destroy ();
+ delete lines;
+ }
+ if (srcLines)
+ {
+ free (srcLines->get (0));
+ delete srcLines;
+ }
+ if (isTmpFile)
+ unlink (name);
+}
+
+void
+SourceFile::set_name (char* _name)
+{
+ name = dbe_strdup (_name);
+}
+
+char*
+SourceFile::get_name (NameFormat)
+{
+ return name;
+}
+
+bool
+SourceFile::readSource ()
+{
+ if (srcLines)
+ return true;
+ status = OS_NOSRC;
+ char *location = dbeFile->get_location ();
+ if (location == NULL)
+ return false;
+ if (!isTmpFile)
+ srcMTime = dbeFile->sbuf.st_mtime;
+ srcInode = dbeFile->sbuf.st_ino;
+ size_t srcLen = dbeFile->sbuf.st_size;
+ int fd = open64 (location, O_RDONLY);
+ if (fd == -1)
+ {
+ status = OS_NOSRC;
+ return false;
+ }
+ char *srcMap = (char *) malloc (srcLen + 1);
+ int64_t sz = read_from_file (fd, srcMap, srcLen);
+ if (sz != (int64_t) srcLen)
+ append_msg (CMSG_ERROR, GTXT ("%s: Can read only %lld bytes instead %lld"),
+ location, (long long) sz, (long long) srcLen);
+ srcMap[sz] = 0;
+ close (fd);
+
+ // Count the number of lines in the file, converting <nl> to zero
+ srcLines = new Vector<char*>();
+ srcLines->append (srcMap);
+ for (int64_t i = 0; i < sz; i++)
+ {
+ if (srcMap[i] == '\r')
+ { // Window style
+ srcMap[i] = 0;
+ if (i + 1 < sz && srcMap[i + 1] != '\n')
+ srcLines->append (srcMap + i + 1);
+ }
+ else if (srcMap[i] == '\n')
+ {
+ srcMap[i] = '\0';
+ if (i + 1 < sz)
+ srcLines->append (srcMap + i + 1);
+ }
+ }
+ if (dbeLines)
+ {
+ Vector<DbeLine *> *v = dbeLines->values ();
+ for (long i = 0, sz1 = v ? v->size () : 0; i < sz1; i++)
+ {
+ DbeLine *p = v->get (i);
+ if (p->lineno >= srcLines->size ())
+ append_msg (CMSG_ERROR, GTXT ("Wrong line number %d. '%s' has only %d lines"),
+ p->lineno, dbeFile->get_location (), srcLines->size ());
+ }
+ delete v;
+ }
+ status = OS_OK;
+ return true;
+}
+
+char *
+SourceFile::getLine (int lineno)
+{
+ assert (srcLines != NULL);
+ if (lineno > 0 && lineno <= srcLines->size ())
+ return srcLines->get (lineno - 1);
+ return NTXT ("");
+}
+
+DbeLine *
+SourceFile::find_dbeline (Function *func, int lineno)
+{
+ if (lineno < 0 || (lineno == 0 && func == NULL))
+ return NULL;
+ DbeLine *dbeLine = NULL;
+ if (lines)
+ { // the source is available
+ if (lineno > lines->size ())
+ {
+ if (dbeLines)
+ dbeLine = dbeLines->get (lineno);
+ if (dbeLine == NULL)
+ append_msg (CMSG_ERROR,
+ GTXT ("Wrong line number %d. '%s' has only %d lines"),
+ lineno, dbeFile->get_location (), lines->size ());
+ }
+ else
+ {
+ dbeLine = lines->fetch (lineno);
+ if (dbeLine == NULL)
+ {
+ dbeLine = new DbeLine (NULL, this, lineno);
+ lines->store (lineno, dbeLine);
+ }
+ }
+ }
+ if (dbeLine == NULL)
+ { // the source is not yet read or lineno is wrong
+ if (dbeLines == NULL)
+ dbeLines = new DefaultMap<int, DbeLine *>();
+ dbeLine = dbeLines->get (lineno);
+ if (dbeLine == NULL)
+ {
+ dbeLine = new DbeLine (NULL, this, lineno);
+ dbeLines->put (lineno, dbeLine);
+ }
+ }
+
+ for (DbeLine *last = dbeLine;; last = last->dbeline_func_next)
+ {
+ if (last->func == func)
+ return last;
+ if (last->dbeline_func_next == NULL)
+ {
+ DbeLine *dl = new DbeLine (func, this, lineno);
+ if (functions->get (func) == NULL)
+ functions->put (func, func);
+ last->dbeline_func_next = dl;
+ dl->dbeline_base = dbeLine;
+ return dl;
+ }
+ }
+}
+
+Vector<Function *> *
+SourceFile::get_functions ()
+{
+ if (!read_stabs)
+ {
+ // Create all DbeLines for this Source
+ read_stabs = true;
+ Vector<LoadObject *> *lobjs = dbeSession->get_LoadObjects ();
+ for (long i = 0, sz = VecSize (lobjs); i < sz; i++)
+ {
+ LoadObject *lo = lobjs->get (i);
+ for (long i1 = 0, sz1 = VecSize (lo->seg_modules); i1 < sz1; i1++)
+ {
+ Module *mod = lo->seg_modules->get (i1);
+ mod->read_stabs ();
+ }
+ }
+ }
+ return functions->keySet ();
+}
diff --git a/gprofng/src/SourceFile.h b/gprofng/src/SourceFile.h
new file mode 100644
index 0000000..8e90682
--- /dev/null
+++ b/gprofng/src/SourceFile.h
@@ -0,0 +1,117 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _SOURCEFILE_H
+#define _SOURCEFILE_H
+
+#include "Histable.h"
+#include "Map.h"
+
+template <typename Key_t, typename Value_t> class Map;
+
+#define SOURCE_FLAG_UNKNOWN 0x01
+
+class SourceFile : public HistableFile
+{
+public:
+
+ enum OpenStatus
+ {
+ OS_OK,
+ OS_NOTREAD,
+ OS_NOSRC,
+ OS_TIMESRC
+ };
+
+ SourceFile (const char *file_name);
+ virtual ~SourceFile ();
+ virtual void set_name (char *);
+ virtual char *get_name (NameFormat = NA);
+
+ bool readSource ();
+ Vector<Function *> *get_functions ();
+ DbeLine *find_dbeline (Function *func, int lineno);
+ char *getLine (int lineno);
+
+ int
+ getLineCount ()
+ {
+ return srcLines ? srcLines->size () : 0;
+ }
+
+ ino64_t
+ getInode ()
+ {
+ return srcInode;
+ }
+
+ time_t
+ getMTime ()
+ {
+ return srcMTime;
+ }
+
+ void
+ setMTime (time_t tm)
+ {
+ srcMTime = tm;
+ }
+
+ bool
+ isTmp ()
+ {
+ return isTmpFile;
+ }
+
+ void
+ setTmp (bool set)
+ {
+ isTmpFile = set;
+ }
+
+ Histable_type
+ get_type ()
+ {
+ return SOURCEFILE;
+ }
+
+ DbeLine *
+ find_dbeline (int lineno)
+ {
+ return find_dbeline (NULL, lineno);
+ }
+
+ unsigned int flags;
+
+private:
+ static int curId; // object id
+ OpenStatus status;
+ ino64_t srcInode; // Inode number of source file
+ time_t srcMTime; // Creating time for source
+ Vector<char *> *srcLines; // array of pointers to lines in source
+ bool isTmpFile; // Temporary src file to be deleted
+
+ Vector<DbeLine*> *lines;
+ Map<int, DbeLine*> *dbeLines;
+ Map<Function *, Function *> *functions;
+ bool read_stabs;
+};
+
+#endif
diff --git a/gprofng/src/Stabs.cc b/gprofng/src/Stabs.cc
new file mode 100644
index 0000000..9f1247d
--- /dev/null
+++ b/gprofng/src/Stabs.cc
@@ -0,0 +1,2650 @@
+/* Copyright (C) 2021 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 <sys/param.h>
+
+#include "util.h"
+#include "Elf.h"
+#include "Dwarf.h"
+#include "stab.h"
+#include "DbeSession.h"
+#include "CompCom.h"
+#include "Stabs.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "Function.h"
+#include "info.h"
+#include "StringBuilder.h"
+#include "DbeFile.h"
+#include "StringMap.h"
+
+#define DISASM_REL_NONE 0 /* symtab search only */
+#define DISASM_REL_ONLY 1 /* relocation search only */
+#define DISASM_REL_TARG 2 /* relocatoin then symtab */
+
+///////////////////////////////////////////////////////////////////////////////
+// class StabReader
+class StabReader
+{
+public:
+ StabReader (Elf *_elf, Platform_t platform, int StabSec, int StabStrSec);
+ ~StabReader () { };
+ char *get_type_name (int t);
+ char *get_stab (struct stab *np, bool comdat);
+ void parse_N_OPT (Module *mod, char *str);
+ int stabCnt;
+ int stabNum;
+
+private:
+ Elf *elf;
+ char *StabData;
+ char *StabStrtab;
+ char *StabStrtabEnd;
+ int StrTabSize;
+ int StabEntSize;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// class Symbol
+
+class Symbol
+{
+public:
+ Symbol (Vector<Symbol*> *vec = NULL);
+
+ ~Symbol ()
+ {
+ free (name);
+ }
+
+ inline Symbol *
+ cardinal ()
+ {
+ return alias ? alias : this;
+ }
+
+ static void dump (Vector<Symbol*> *vec, char*msg);
+
+ Function *func;
+ Sp_lang_code lang_code;
+ uint64_t value; // st_value used in sym_name()
+ uint64_t save;
+ int64_t size;
+ uint64_t img_offset; // image offset in the ELF file
+ char *name;
+ Symbol *alias;
+ int local_ind;
+ int flags;
+ bool defined;
+};
+
+Symbol::Symbol (Vector<Symbol*> *vec)
+{
+ func = NULL;
+ lang_code = Sp_lang_unknown;
+ value = 0;
+ save = 0;
+ size = 0;
+ img_offset = 0;
+ name = NULL;
+ alias = NULL;
+ local_ind = -1;
+ flags = 0;
+ defined = false;
+ if (vec)
+ vec->append (this);
+}
+
+void
+Symbol::dump (Vector<Symbol*> *vec, char*msg)
+{
+ if (!DUMP_ELF_SYM || vec == NULL || vec->size () == 0)
+ return;
+ printf (NTXT ("======= Symbol::dump: %s =========\n"
+ " value | img_offset | flags|local_ind|\n"), msg);
+ for (int i = 0; i < vec->size (); i++)
+ {
+ Symbol *sp = vec->fetch (i);
+ printf (NTXT (" %3d %8lld |0x%016llx |%5d |%8d |%s\n"),
+ i, (long long) sp->value, (long long) sp->img_offset, sp->flags,
+ sp->local_ind, sp->name ? sp->name : NTXT ("NULL"));
+ }
+ printf (NTXT ("\n===== END of Symbol::dump: %s =========\n\n"), msg);
+}
+
+// end of class Symbol
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// class Reloc
+class Reloc
+{
+public:
+ Reloc ();
+ ~Reloc ();
+ uint64_t type;
+ uint64_t value;
+ uint64_t addend;
+ char *name;
+};
+
+Reloc::Reloc ()
+{
+ type = 0;
+ value = 0;
+ addend = 0;
+ name = NULL;
+}
+
+Reloc::~Reloc ()
+{
+ free (name);
+}
+// end of class Reloc
+///////////////////////////////////////////////////////////////////////////////
+
+enum
+{
+ SYM_PLT = 1 << 0,
+ SYM_UNDEF = 1 << 1
+};
+
+enum Section_type
+{
+ COMM1_SEC = 0x10000000,
+ COMM_SEC = 0x20000000,
+ INFO_SEC = 0x30000000,
+ LOOP_SEC = 0x40000000
+};
+
+struct cpf_stabs_t
+{
+ uint32_t type; // Archive::AnalyzerInfoType
+ uint32_t offset; // offset in .__analyzer_info
+ Module *module; // table for appropriate Module
+};
+
+static char *get_info_com (int type, int32_t copy_inout);
+static char *get_lp_com (unsigned hints, int parallel, char *dep);
+static int ComCmp (const void *a, const void *b);
+static ino64_t _src_inode = 0;
+static char *_src_name;
+
+// Comparing name
+static int
+SymNameCmp (const void *a, const void *b)
+{
+ Symbol *item1 = *((Symbol **) a);
+ Symbol *item2 = *((Symbol **) b);
+ return (item1->name == NULL) ? -1 :
+ (item2->name == NULL) ? 1 : strcmp (item1->name, item2->name);
+}
+
+// Comparing value: for sorting
+static int
+SymValueCmp (const void *a, const void *b)
+{
+ Symbol *item1 = *((Symbol **) a);
+ Symbol *item2 = *((Symbol **) b);
+ return (item1->value > item2->value) ? 1 :
+ (item1->value == item2->value) ? SymNameCmp (a, b) : -1;
+}
+
+// Comparing value: for searching (source name is always NULL)
+static int
+SymFindCmp (const void *a, const void *b)
+{
+ Symbol *item1 = *((Symbol **) a);
+ Symbol *item2 = *((Symbol **) b);
+ if (item1->value < item2->value)
+ return -1;
+ if (item1->value < item2->value + item2->size
+ || item1->value == item2->value) // item2->size == 0
+ return 0;
+ return 1;
+}
+
+// Comparing value for sorting. It is used only for searching aliases.
+static int
+SymImgOffsetCmp (const void *a, const void *b)
+{
+ Symbol *item1 = *((Symbol **) a);
+ Symbol *item2 = *((Symbol **) b);
+ return (item1->img_offset > item2->img_offset) ? 1 :
+ (item1->img_offset == item2->img_offset) ? SymNameCmp (a, b) : -1;
+}
+
+static int
+RelValueCmp (const void *a, const void *b)
+{
+ Reloc *item1 = *((Reloc **) a);
+ Reloc *item2 = *((Reloc **) b);
+ return (item1->value > item2->value) ? 1 :
+ (item1->value == item2->value) ? 0 : -1;
+}
+
+Stabs *
+Stabs::NewStabs (char *_path, char *lo_name)
+{
+ Stabs *stabs = new Stabs (_path, lo_name);
+ if (stabs->status != Stabs::DBGD_ERR_NONE)
+ {
+ delete stabs;
+ return NULL;
+ }
+ return stabs;
+}
+
+Stabs::Stabs (char *_path, char *_lo_name)
+{
+ path = dbe_strdup (_path);
+ lo_name = dbe_strdup (_lo_name);
+ SymLstByName = NULL;
+ pltSym = NULL;
+ SymLst = new Vector<Symbol*>;
+ RelLst = new Vector<Reloc*>;
+ RelPLTLst = new Vector<Reloc*>;
+ LocalLst = new Vector<Symbol*>;
+ LocalFile = new Vector<char*>;
+ LocalFileIdx = new Vector<int>;
+ last_PC_to_sym = NULL;
+ dwarf = NULL;
+ elfDbg = NULL;
+ elfDis = NULL;
+ stabsModules = NULL;
+ textsz = 0;
+ wsize = Wnone;
+ st_check_symtab = st_check_relocs = false;
+ status = DBGD_ERR_NONE;
+
+ if (openElf (false) == NULL)
+ return;
+ switch (elfDis->elf_getclass ())
+ {
+ case ELFCLASS32:
+ wsize = W32;
+ break;
+ case ELFCLASS64:
+ wsize = W64;
+ break;
+ }
+ isRelocatable = elfDis->elf_getehdr ()->e_type == ET_REL;
+ for (unsigned int pnum = 0; pnum < elfDis->elf_getehdr ()->e_phnum; pnum++)
+ {
+ Elf_Internal_Phdr *phdr = elfDis->get_phdr (pnum);
+ if (phdr->p_type == PT_LOAD && phdr->p_flags == (PF_R | PF_X))
+ {
+ if (textsz == 0)
+ textsz = phdr->p_memsz;
+ else
+ {
+ textsz = 0;
+ break;
+ }
+ }
+ }
+}
+
+Stabs::~Stabs ()
+{
+ delete pltSym;
+ delete SymLstByName;
+ Destroy (SymLst);
+ Destroy (RelLst);
+ Destroy (RelPLTLst);
+ Destroy (LocalFile);
+ delete elfDis;
+ delete dwarf;
+ delete LocalLst;
+ delete LocalFileIdx;
+ delete stabsModules;
+ free (path);
+ free (lo_name);
+}
+
+Elf *
+Stabs::openElf (char *fname, Stab_status &st)
+{
+ Elf::Elf_status elf_status;
+ Elf *elf = Elf::elf_begin (fname, &elf_status);
+ if (elf == NULL)
+ {
+ switch (elf_status)
+ {
+ case Elf::ELF_ERR_CANT_OPEN_FILE:
+ case Elf::ELF_ERR_CANT_MMAP:
+ case Elf::ELF_ERR_BIG_FILE:
+ st = DBGD_ERR_CANT_OPEN_FILE;
+ break;
+ case Elf::ELF_ERR_BAD_ELF_FORMAT:
+ default:
+ st = DBGD_ERR_BAD_ELF_FORMAT;
+ break;
+ }
+ return NULL;
+ }
+ if (elf->elf_version (EV_CURRENT) == EV_NONE)
+ {
+ // ELF library out of date
+ delete elf;
+ st = DBGD_ERR_BAD_ELF_LIB;
+ return NULL;
+ }
+
+ Elf_Internal_Ehdr *ehdrp = elf->elf_getehdr ();
+ if (ehdrp == NULL)
+ {
+ // check machine
+ delete elf;
+ st = DBGD_ERR_BAD_ELF_FORMAT;
+ return NULL;
+ }
+ switch (ehdrp->e_machine)
+ {
+ case EM_SPARC:
+ platform = Sparc;
+ break;
+ case EM_SPARC32PLUS:
+ platform = Sparcv8plus;
+ break;
+ case EM_SPARCV9:
+ platform = Sparcv9;
+ break;
+ case EM_386:
+ // case EM_486:
+ platform = Intel;
+ break;
+ case EM_X86_64:
+ platform = Amd64;
+ break;
+ case EM_AARCH64:
+ platform = Aarch64;
+ break;
+ default:
+ platform = Unknown;
+ break;
+ }
+ return elf;
+}
+
+Elf *
+Stabs::openElf (bool dbg_info)
+{
+ if (status != DBGD_ERR_NONE)
+ return NULL;
+ if (elfDis == NULL)
+ {
+ elfDis = openElf (path, status);
+ if (elfDis == NULL)
+ return NULL;
+ }
+ if (!dbg_info)
+ return elfDis;
+ if (elfDbg == NULL)
+ {
+ elfDbg = elfDis->find_ancillary_files (lo_name);
+ if (elfDbg == NULL)
+ elfDbg = elfDis;
+ }
+ return elfDbg;
+}
+
+bool
+Stabs::read_symbols (Vector<Function*> *functions)
+{
+ if (openElf (true) == NULL)
+ return false;
+ check_Symtab ();
+ check_Relocs ();
+ if (functions)
+ {
+ Function *fp;
+ int index;
+ Vec_loop (Function*, functions, index, fp)
+ {
+ fp->img_fname = path;
+ }
+ }
+ return true;
+}
+
+char *
+Stabs::sym_name (uint64_t target, uint64_t instr, int flag)
+{
+ long index;
+ if (flag == DISASM_REL_ONLY || flag == DISASM_REL_TARG)
+ {
+ Reloc *relptr = new Reloc;
+ relptr->value = instr;
+ index = RelLst->bisearch (0, -1, &relptr, RelValueCmp);
+ if (index >= 0)
+ {
+ delete relptr;
+ return RelLst->fetch (index)->name;
+ }
+ if (!is_relocatable ())
+ {
+ relptr->value = target;
+ index = RelPLTLst->bisearch (0, -1, &relptr, RelValueCmp);
+ if (index >= 0)
+ {
+ delete relptr;
+ return RelPLTLst->fetch (index)->name;
+ }
+ }
+ delete relptr;
+ }
+ if (flag == DISASM_REL_NONE || flag == DISASM_REL_TARG || !is_relocatable ())
+ {
+ Symbol *sptr;
+ sptr = map_PC_to_sym (target);
+ if (sptr && sptr->value == target)
+ return sptr->name;
+ }
+ return NULL;
+}
+
+Symbol *
+Stabs::map_PC_to_sym (uint64_t pc)
+{
+ if (pc == 0)
+ return NULL;
+ if (last_PC_to_sym && last_PC_to_sym->value <= pc
+ && last_PC_to_sym->value + last_PC_to_sym->size > pc)
+ return last_PC_to_sym;
+ Symbol *sym = new Symbol;
+ sym->value = pc;
+ long index = SymLst->bisearch (0, -1, &sym, SymFindCmp);
+ delete sym;
+ if (index >= 0)
+ {
+ last_PC_to_sym = SymLst->fetch (index)->cardinal ();
+ return last_PC_to_sym;
+ }
+ return NULL;
+}
+
+Function *
+Stabs::map_PC_to_func (uint64_t pc, uint64_t &low_pc, Vector<Function*> *functions)
+{
+ int index;
+ Function *func;
+ Symbol *sptr = map_PC_to_sym (pc);
+ if (sptr == NULL)
+ return NULL;
+ if (sptr->func)
+ {
+ low_pc = sptr->value;
+ return sptr->func;
+ }
+ if (functions)
+ {
+ Vec_loop (Function*, functions, index, func)
+ {
+ if (func->img_offset == sptr->img_offset)
+ {
+ sptr->func = func->cardinal ();
+ low_pc = sptr->value;
+ return sptr->func;
+ }
+ }
+ }
+ return NULL;
+}
+
+Stabs::Stab_status
+Stabs::read_stabs (ino64_t srcInode, Module *module, Vector<ComC*> *comComs,
+ bool readDwarf)
+{
+ if (module)
+ module->setIncludeFile (NULL);
+
+ if (openElf (true) == NULL)
+ return status;
+ check_Symtab ();
+
+ // read compiler commentary from .compcom1, .compcom,
+ // .info, .loops, and .loopview sections
+ if (comComs)
+ {
+ _src_inode = srcInode;
+ _src_name = module && module->file_name ? get_basename (module->file_name) : NULL;
+ if (!check_Comm (comComs))
+ // .loops, and .loopview are now in .compcom
+ check_Loop (comComs);
+
+ // should not read it after .info goes into .compcom
+ check_Info (comComs);
+ comComs->sort (ComCmp);
+ }
+
+ // get stabs info
+ Stab_status statusStabs = DBGD_ERR_NO_STABS;
+#define SRC_LINE_STABS(sec, secStr, comdat) \
+ if ((elfDbg->sec) && (elfDbg->secStr) && \
+ srcline_Stabs(module, elfDbg->sec, elfDbg->secStr, comdat) == DBGD_ERR_NONE) \
+ statusStabs = DBGD_ERR_NONE
+
+ SRC_LINE_STABS (stabExcl, stabExclStr, false);
+ SRC_LINE_STABS (stab, stabStr, false);
+ SRC_LINE_STABS (stabIndex, stabIndexStr, true);
+
+ // read Dwarf, if any sections found
+ if (elfDbg->dwarf && readDwarf)
+ {
+ openDwarf ()->srcline_Dwarf (module);
+ if (dwarf && dwarf->status == DBGD_ERR_NONE)
+ return DBGD_ERR_NONE;
+ }
+ return statusStabs;
+}
+
+static int
+ComCmp (const void *a, const void *b)
+{
+ ComC *item1 = *((ComC **) a);
+ ComC *item2 = *((ComC **) b);
+ return (item1->line > item2->line) ? 1 :
+ (item1->line < item2->line) ? -1 :
+ (item1->sec > item2->sec) ? 1 :
+ (item1->sec < item2->sec) ? -1 : 0;
+}
+
+static int
+check_src_name (char *srcName)
+{
+ if (_src_name && srcName && streq (_src_name, get_basename (srcName)))
+ return 1;
+ if (_src_inode == (ino64_t) - 1)
+ return 0;
+ DbeFile *dbeFile = dbeSession->getDbeFile (srcName, DbeFile::F_SOURCE);
+ char *path = dbeFile->get_location ();
+ return (path == NULL || dbeFile->sbuf.st_ino != _src_inode) ? 0 : 1;
+}
+
+bool
+Stabs::check_Comm (Vector<ComC*> *comComs)
+{
+ int sz = comComs->size ();
+ Elf *elf = openElf (true);
+ if (elf == NULL)
+ return false;
+
+ for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+ {
+ char *name = elf->get_sec_name (sec);
+ if (name == NULL)
+ continue;
+ Section_type sec_type;
+ if (streq (name, NTXT (".compcom")))
+ sec_type = COMM_SEC;
+ else if (streq (name, NTXT (".compcom1")))
+ sec_type = COMM1_SEC;
+ else
+ continue;
+
+ // find header, set messages id & visibility if succeed
+ CompComment *cc = new CompComment (elf, sec);
+ int cnt = cc->compcom_open ((CheckSrcName) check_src_name);
+ // process messages
+ for (int index = 0; index < cnt; index++)
+ {
+ int visible;
+ compmsg msg;
+ char *str = cc->compcom_format (index, &msg, visible);
+ if (str)
+ {
+ ComC *citem = new ComC;
+ citem->sec = sec_type + index;
+ citem->type = msg.msg_type;
+ citem->visible = visible;
+ citem->line = (msg.lineno < 1) ? 1 : msg.lineno;
+ citem->com_str = str;
+ comComs->append (citem);
+ }
+ }
+ delete cc;
+ }
+ return (sz != comComs->size ());
+}
+
+static int
+targetOffsetCmp (const void *a, const void *b)
+{
+ uint32_t o1 = ((target_info_t *) a)->offset;
+ uint32_t o2 = ((target_info_t *) b)->offset;
+ return (o1 >= o2);
+}
+
+void
+Stabs::check_AnalyzerInfo ()
+{
+ Elf *elf = openElf (true);
+ if ((elf == NULL) || (elf->analyzerInfo == 0))
+ {
+ Dprintf (DEBUG_STABS, NTXT ("Stabs::check_AnalyzerInfo: Null AnalyzerInfo section\n"));
+ return; // inappropriate, but ignored anyway
+ }
+ Elf_Data *data = elf->elf_getdata (elf->analyzerInfo);
+ int InfoSize = (int) data->d_size;
+ char *InfoData = (char *) data->d_buf;
+ int InfoAlign = (int) data->d_align;
+ AnalyzerInfoHdr h;
+ unsigned infoHdr_sz = sizeof (AnalyzerInfoHdr);
+ int table, entry;
+ int read = 0;
+ Module *mitem;
+ int index = 0;
+ if (InfoSize <= 0)
+ return;
+ uint64_t baseAddr = elf->get_baseAddr ();
+ Dprintf (DEBUG_STABS, NTXT ("Stabs::check_AnalyzerInfo size=%d @0x%lx (align=%d) base=0x%llx\n"),
+ InfoSize, (ul_t) InfoData, InfoAlign, (long long) baseAddr);
+ Dprintf (DEBUG_STABS, NTXT ("analyzerInfoMap has %lld entries\n"), (long long) analyzerInfoMap.size ());
+ if (analyzerInfoMap.size () == 0)
+ {
+ Dprintf (DEBUG_STABS, NTXT ("No analyzerInfoMap available!\n"));
+ return;
+ }
+
+ // verify integrity of analyzerInfoMap before reading analyzerInfo
+ unsigned count = 0;
+ Module *lastmod = NULL;
+ for (index = 0; index < analyzerInfoMap.size (); index++)
+ {
+ cpf_stabs_t map = analyzerInfoMap.fetch (index);
+ if (map.type > 3)
+ {
+ Dprintf (DEBUG_STABS, NTXT ("analyzerInfo contains table of unknown type %d for %s\n"),
+ map.type, map.module->get_name ());
+ return;
+ }
+ if (map.module != lastmod)
+ {
+ if (lastmod != NULL)
+ Dprintf (DEBUG_STABS, "analyzerInfo contains %d 0x0 offset tables for %s\n",
+ count, lastmod->get_name ());
+ count = 0;
+ }
+ count += (map.offset == 0x0); // only check for 0x0 tables for now
+ if (count > 4)
+ {
+ Dprintf (DEBUG_STABS, NTXT ("analyzerInfo contains too many 0x0 offset tables for %s\n"),
+ map.module->get_name ());
+ return;
+ }
+ lastmod = map.module;
+ }
+
+ index = 0;
+ while ((index < analyzerInfoMap.size ()) && (read < InfoSize))
+ {
+ for (table = 0; table < 3; table++)
+ { // memory operations (ld, st, prefetch)
+ // read the table header
+ memcpy ((void *) &h, (const void *) InfoData, infoHdr_sz);
+ InfoData += infoHdr_sz;
+ read += infoHdr_sz;
+
+ // use map for appropriate module
+ cpf_stabs_t map = analyzerInfoMap.fetch (index);
+ index++;
+ mitem = map.module;
+ Dprintf (DEBUG_STABS, "Table %d offset=0x%04x "
+ "text_labelref=0x%08llx entries=%d version=%d\n"
+ "itype %d offset=0x%04x module=%s\n", table, read,
+ (long long) (h.text_labelref - baseAddr), h.entries,
+ h.version, map.type, map.offset, map.module->get_name ());
+ // read the table entries
+ for (entry = 0; entry < h.entries; entry++)
+ {
+ memop_info_t *m = new memop_info_t;
+ unsigned memop_info_sz = sizeof (memop_info_t);
+ memcpy ((void *) m, (const void *) InfoData, memop_info_sz);
+ InfoData += memop_info_sz;
+ read += memop_info_sz;
+ m->offset += (uint32_t) (h.text_labelref - baseAddr);
+ Dprintf (DEBUG_STABS, NTXT ("%4d(%d): offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n"),
+ entry, table, m->offset, m->id, m->signature, m->datatype_id);
+ switch (table)
+ {
+ case CPF_INSTR_TYPE_LD:
+ mitem->ldMemops.append (m);
+ break;
+ case CPF_INSTR_TYPE_ST:
+ mitem->stMemops.append (m);
+ break;
+ case CPF_INSTR_TYPE_PREFETCH:
+ mitem->pfMemops.append (m);
+ break;
+ }
+ }
+ // following re-alignment should be redundant
+ //InfoData+=(read%InfoAlign); read+=(read%InfoAlign); // re-align
+ }
+ for (table = 3; table < 4; table++)
+ { // branch targets
+ memcpy ((void *) &h, (const void *) InfoData, infoHdr_sz);
+ InfoData += infoHdr_sz;
+ read += infoHdr_sz;
+
+ // use map for appropriate module
+ cpf_stabs_t map = analyzerInfoMap.fetch (index);
+ index++;
+ mitem = map.module;
+ Dprintf (DEBUG_STABS, "Table %d offset=0x%04x "
+ "text_labelref=0x%08llx entries=%d version=%d\n"
+ "itype %d offset=0x%04x module=%s\n", table, read,
+ (long long) (h.text_labelref - baseAddr), h.entries,
+ h.version, map.type, map.offset, map.module->get_name ());
+ for (entry = 0; entry < h.entries; entry++)
+ {
+ target_info_t *t = new target_info_t;
+ unsigned target_info_sz = sizeof (target_info_t);
+ memcpy ((void *) t, (const void *) InfoData, target_info_sz);
+ InfoData += target_info_sz;
+ read += target_info_sz;
+ t->offset += (uint32_t) (h.text_labelref - baseAddr);
+ Dprintf (DEBUG_STABS, NTXT ("%4d(%d): offset=0x%04x\n"), entry,
+ table, t->offset);
+ // the list of branch targets needs to be in offset sorted order
+ // and doing it here before archiving avoids the need to do it
+ // each time the archive is read.
+ mitem->bTargets.incorporate (t, targetOffsetCmp);
+ }
+ Dprintf (DEBUG_STABS, NTXT ("bTargets for %s has %lld items (last=0x%04x)\n"),
+ mitem->get_name (), (long long) mitem->bTargets.size (),
+ (mitem->bTargets.fetch (mitem->bTargets.size () - 1))->offset);
+ Dprintf (DEBUG_STABS, "read=%d at end of bTargets (InfoData=0x%lx)\n",
+ read, (ul_t) InfoData);
+ InfoData += (read % InfoAlign);
+ read += (read % InfoAlign); // re-align
+ Dprintf (DEBUG_STABS, "read=%d at end of bTargets (InfoData=0x%lx)\n",
+ read, (ul_t) InfoData);
+ }
+ Dprintf (DEBUG_STABS, "Stabs::check_AnalyzerInfo bytes read=%lld (index=%lld/%lld)\n",
+ (long long) read, (long long) index,
+ (long long) analyzerInfoMap.size ());
+ }
+}
+
+void
+Stabs::check_Info (Vector<ComC*> *comComs)
+{
+ Elf *elf = openElf (true);
+ if (elf == NULL || elf->info == 0)
+ return;
+ Elf_Data *data = elf->elf_getdata (elf->info);
+ uint64_t InfoSize = data->d_size;
+ char *InfoData = (char *) data->d_buf;
+ bool get_src = false;
+ for (int h_num = 0; InfoSize; h_num++)
+ {
+ if (InfoSize < sizeof (struct info_header))
+ return;
+ struct info_header *h = (struct info_header*) InfoData;
+ if (h->endian != '\0' || h->magic[0] != 'S' || h->magic[1] != 'U'
+ || h->magic[2] != 'N')
+ return;
+ if (h->len < InfoSize || h->len < sizeof (struct info_header) || (h->len & 3))
+ return;
+
+ char *fname = InfoData + sizeof (struct info_header);
+ InfoData += h->len;
+ InfoSize -= h->len;
+ get_src = check_src_name (fname);
+ for (uint32_t e_num = 0; e_num < h->cnt; ++e_num)
+ {
+ if (InfoSize < sizeof (struct entry_header))
+ return;
+ struct entry_header *e = (struct entry_header*) InfoData;
+ if (InfoSize < e->len)
+ return;
+ int32_t copy_inout = 0;
+ if (e->len > sizeof (struct entry_header))
+ if (e->type == F95_COPYINOUT)
+ copy_inout = *(int32_t*) (InfoData + sizeof (struct entry_header));
+ InfoData += e->len;
+ InfoSize -= e->len;
+ if (get_src)
+ {
+ ComC *citem = new ComC;
+ citem->sec = INFO_SEC + h_num;
+ citem->type = e->msgnum & 0xFFFFFF;
+ citem->visible = CCMV_ALL;
+ citem->line = e->line;
+ citem->com_str = get_info_com (citem->type, copy_inout);
+ comComs->append (citem);
+ }
+ }
+ if (get_src)
+ break;
+ }
+}
+
+static char *
+get_info_com (int type, int32_t copy_inout)
+{
+ switch (type)
+ {
+ case 1:
+ return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-in -- loop(s) inserted"),
+ copy_inout);
+ case 2:
+ return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-out -- loop(s) inserted"),
+ copy_inout);
+ case 3:
+ return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-in and a copy-out -- loops inserted"),
+ copy_inout);
+ case 4:
+ return dbe_strdup (GTXT ("Alignment of variables in common block may cause performance degradation"));
+ case 5:
+ return dbe_strdup (GTXT ("DO statement bounds lead to no executions of the loop"));
+ default:
+ return dbe_strdup (NTXT (""));
+ }
+}
+
+void
+Stabs::check_Loop (Vector<ComC*> *comComs)
+{
+ Elf *elf = openElf (true);
+ if (elf == NULL)
+ return;
+
+ StringBuilder sb;
+ for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+ {
+ char *name = elf->get_sec_name (sec);
+ if (name == NULL)
+ continue;
+ if (!streq (name, NTXT (".loops")) && !streq (name, NTXT (".loopview")))
+ continue;
+
+ Elf_Data *data = elf->elf_getdata (sec);
+ size_t LoopSize = (size_t) data->d_size, len;
+ char *LoopData = (char *) data->d_buf;
+ int remainder, i;
+ char src[2 * MAXPATHLEN], buf1[MAXPATHLEN], buf2[MAXPATHLEN];
+ char **dep_str = NULL;
+ bool get_src = false;
+ while ((LoopSize > 0) && !get_src &&
+ (strncmp (LoopData, NTXT ("Source:"), 7) == 0))
+ {
+ // The first three items in a .loops subsection are three strings.
+ // Source: ...
+ // Version: ...
+ // Number of loops: ...
+ sscanf (LoopData, NTXT ("%*s%s"), src);
+ len = strlen (LoopData) + 1;
+ LoopData += len;
+ LoopSize -= len;
+ sscanf (LoopData, NTXT ("%*s%*s%s"), buf1);
+ // double version = atof(buf1);
+ len = strlen (LoopData) + 1;
+ LoopData += len;
+ LoopSize -= len;
+ get_src = check_src_name (src);
+ sscanf (LoopData, NTXT ("%*s%*s%*s%s%s"), buf1, buf2);
+ int n_loop = atoi (buf1);
+ int n_depend = atoi (buf2);
+ len = strlen (LoopData) + 1;
+ LoopData += len;
+ LoopSize -= len;
+ if (get_src && (n_loop > 0))
+ {
+ dep_str = new char*[n_loop];
+ for (i = 0; i < n_loop; i++)
+ dep_str[i] = NULL;
+ }
+
+ // printf("Source: %s\nVersion: %f\nLoop#: %d\nDepend#: %d\n",
+ // src, version, n_loop, n_depend);
+
+ // Read in the strings that contain the list of variables that cause
+ // data dependencies inside of loops. Not every loop has such a list
+ // of variables.
+ //
+ // Example: if loop #54 has data dependencies caused by the
+ // variables named i, j and foo, then the string that represents
+ // this in the .loops section looks like this:
+ //
+ // .asciz "54:i.j.foo"
+ //
+ // The variable names are delimited with .
+ //
+ // For now, store these strings in an array, and add them into
+ // the loop structure when we read in the numeric loop info
+ // (that's what we read in next.)
+ //
+ // printf("\tDependenncies:\n");
+ for (i = 0; i < n_depend; i++)
+ {
+ len = strlen (LoopData) + 1;
+ LoopData += len;
+ LoopSize -= len;
+ if (dep_str != NULL)
+ {
+ char *dep_buf1 = dbe_strdup (LoopData);
+ char *ptr = strtok (dep_buf1, NTXT (":"));
+ if (ptr != NULL)
+ {
+ int index = atoi (ptr);
+ bool dep_first = true;
+ sb.setLength (0);
+ while ((ptr = strtok (NULL, NTXT (", "))) != NULL)
+ {
+ if (dep_first)
+ dep_first = false;
+ else
+ sb.append (NTXT (", "));
+ sb.append (ptr);
+ }
+ if (sb.length () > 0 && index < n_loop)
+ dep_str[index] = sb.toString ();
+ }
+ free (dep_buf1);
+ }
+ }
+
+ // Adjust Data pointer so that it is word aligned.
+ remainder = (int) (((unsigned long) LoopData) % 4);
+ if (remainder != 0)
+ {
+ len = 4 - remainder;
+ LoopData += len;
+ LoopSize -= len;
+ }
+
+ // Read in the loop info, one loop at a time.
+ for (i = 0; i < n_loop; i++)
+ {
+ int loopid = *((int *) LoopData);
+ LoopData += 4;
+ int line_no = *((int *) LoopData);
+ if (line_no < 1) // compiler has trouble on this
+ line_no = 1;
+ LoopData += 4;
+ // int nest = *((int *) LoopData);
+ LoopData += 4;
+ int parallel = *((int *) LoopData);
+ LoopData += 4;
+ unsigned hints = *((unsigned *) LoopData);
+ LoopData += 4;
+ // int count = *((int *) LoopData);
+ LoopData += 4;
+ LoopSize -= 24;
+ if (!get_src || (loopid >= n_loop))
+ continue;
+ ComC *citem = new ComC;
+ citem->sec = LOOP_SEC + i;
+ citem->type = hints;
+ citem->visible = CCMV_ALL;
+ citem->line = line_no;
+ citem->com_str = get_lp_com (hints, parallel, dep_str[loopid]);
+ comComs->append (citem);
+ }
+ if (dep_str)
+ {
+ for (i = 0; i < n_loop; i++)
+ free (dep_str[i]);
+ delete[] dep_str;
+ dep_str = NULL;
+ }
+ }
+ }
+}
+
+static char *
+get_lp_com (unsigned hints, int parallel, char *dep)
+{
+ StringBuilder sb;
+ if (parallel == -1)
+ sb.append (GTXT ("Loop below is serial, but parallelizable: "));
+ else if (parallel == 0)
+ sb.append (GTXT ("Loop below is not parallelized: "));
+ else
+ sb.append (GTXT ("Loop below is parallelized: "));
+ switch (hints)
+ {
+ case 0:
+ // No loop mesg will print
+ // strcat(com, GTXT("no hint available"));
+ break;
+ case 1:
+ sb.append (GTXT ("loop contains procedure call"));
+ break;
+ case 2:
+ sb.append (GTXT ("compiler generated two versions of this loop"));
+ break;
+ case 3:
+ {
+ StringBuilder sb_tmp;
+ sb_tmp.sprintf (GTXT ("the variable(s) \"%s\" cause a data dependency in this loop"),
+ dep ? dep : GTXT ("<Unknown>"));
+ sb.append (&sb_tmp);
+ }
+ break;
+ case 4:
+ sb.append (GTXT ("loop was significantly transformed during optimization"));
+ break;
+ case 5:
+ sb.append (GTXT ("loop may or may not hold enough work to be profitably parallelized"));
+ break;
+ case 6:
+ sb.append (GTXT ("loop was marked by user-inserted pragma"));
+ break;
+ case 7:
+ sb.append (GTXT ("loop contains multiple exits"));
+ break;
+ case 8:
+ sb.append (GTXT ("loop contains I/O, or other function calls, that are not MT safe"));
+ break;
+ case 9:
+ sb.append (GTXT ("loop contains backward flow of control"));
+ break;
+ case 10:
+ sb.append (GTXT ("loop may have been distributed"));
+ break;
+ case 11:
+ sb.append (GTXT ("two loops or more may have been fused"));
+ break;
+ case 12:
+ sb.append (GTXT ("two or more loops may have been interchanged"));
+ break;
+ default:
+ break;
+ }
+ return sb.toString ();
+}
+
+StabReader::StabReader (Elf *_elf, Platform_t platform, int StabSec, int StabStrSec)
+{
+ stabCnt = -1;
+ stabNum = 0;
+ if (_elf == NULL)
+ return;
+ elf = _elf;
+
+ // Get ELF data
+ Elf_Data *data = elf->elf_getdata (StabSec);
+ if (data == NULL)
+ return;
+ uint64_t stabSize = data->d_size;
+ StabData = (char *) data->d_buf;
+ Elf_Internal_Shdr *shdr = elf->get_shdr (StabSec);
+ if (shdr == NULL)
+ return;
+
+ // GCC bug: sh_entsize is 20 for 64 apps on Linux
+ StabEntSize = (platform == Amd64 || platform == Sparcv9) ? 12 : (unsigned) shdr->sh_entsize;
+ if (stabSize == 0 || StabEntSize == 0)
+ return;
+ data = elf->elf_getdata (StabStrSec);
+ if (data == NULL)
+ return;
+ shdr = elf->get_shdr (StabStrSec);
+ if (shdr == NULL)
+ return;
+ StabStrtab = (char *) data->d_buf;
+ StabStrtabEnd = StabStrtab + shdr->sh_size;
+ StrTabSize = 0;
+ stabCnt = (int) (stabSize / StabEntSize);
+}
+
+char *
+StabReader::get_stab (struct stab *np, bool comdat)
+{
+ struct stab *stbp = (struct stab *) (StabData + stabNum * StabEntSize);
+ stabNum++;
+ *np = *stbp;
+ np->n_desc = elf->decode (stbp->n_desc);
+ np->n_strx = elf->decode (stbp->n_strx);
+ np->n_value = elf->decode (stbp->n_value);
+ switch (np->n_type)
+ {
+ case N_UNDF:
+ case N_ILDPAD:
+ // Start of new stab section (or padding)
+ StabStrtab += StrTabSize;
+ StrTabSize = np->n_value;
+ }
+
+ char *str = NULL;
+ if (np->n_strx)
+ {
+ if (comdat && np->n_type == N_FUN && np->n_other == 1)
+ {
+ if (np->n_strx == 1)
+ StrTabSize++;
+ str = StabStrtab + StrTabSize;
+ // Each COMDAT string must be sized to find the next string:
+ StrTabSize += strlen (str) + 1;
+ }
+ else
+ str = StabStrtab + np->n_strx;
+ if (str >= StabStrtabEnd)
+ str = NULL;
+ }
+ if (DEBUG_STABS)
+ {
+ char buf[128];
+ char *s = get_type_name (np->n_type);
+ if (s == NULL)
+ {
+ snprintf (buf, sizeof (buf), NTXT ("n_type=%d"), np->n_type);
+ s = buf;
+ }
+ if (str)
+ {
+ Dprintf (DEBUG_STABS, NTXT ("%4d: .stabs \"%s\",%s,0x%x,0x%x,0x%x\n"),
+ stabNum - 1, str, s, (int) np->n_other, (int) np->n_desc,
+ (int) np->n_value);
+ }
+ else
+ Dprintf (DEBUG_STABS, NTXT ("%4d: .stabn %s,0x%x,0x%x,0x%x\n"),
+ stabNum - 1, s, (int) np->n_other, (int) np->n_desc,
+ (int) np->n_value);
+ }
+ return str;
+}
+
+void
+StabReader::parse_N_OPT (Module *mod, char *str)
+{
+ if (mod == NULL || str == NULL)
+ return;
+ for (char *s = str; 1; s++)
+ {
+ switch (*s)
+ {
+ case 'd':
+ if (s[1] == 'i' && s[2] == ';')
+ {
+ delete mod->dot_o_file;
+ mod->dot_o_file = NULL;
+ }
+ break;
+ case 's':
+ if ((s[1] == 'i' || s[1] == 'n') && s[2] == ';')
+ {
+ delete mod->dot_o_file;
+ mod->dot_o_file = NULL;
+ }
+ break;
+ }
+ s = strchr (s, ';');
+ if (s == NULL)
+ break;
+ }
+}
+
+Stabs::Stab_status
+Stabs::srcline_Stabs (Module *module, unsigned int StabSec,
+ unsigned int StabStrSec, bool comdat)
+{
+ StabReader *stabReader = new StabReader (openElf (true), platform, StabSec, StabStrSec);
+ int tot = stabReader->stabCnt;
+ if (tot < 0)
+ {
+ delete stabReader;
+ return DBGD_ERR_NO_STABS;
+ }
+ int n, lineno;
+ char *sbase, *n_so = NTXT (""), curr_src[2 * MAXPATHLEN];
+ Function *newFunc;
+ Sp_lang_code _lang_code = module->lang_code;
+ Vector<Function*> *functions = module->functions;
+ bool no_stabs = true;
+ *curr_src = '\0';
+ Function *func = NULL;
+ int phase = 0;
+ int stabs_level = 0;
+ int xline = 0;
+
+ // Find module
+ for (n = 0; n < tot; n++)
+ {
+ struct stab stb;
+ char *str = stabReader->get_stab (&stb, comdat);
+ if (stb.n_type == N_UNDF)
+ phase = 0;
+ else if (stb.n_type == N_SO)
+ {
+ if (str == NULL || *str == '\0')
+ continue;
+ if (phase == 0)
+ {
+ phase = 1;
+ n_so = str;
+ continue;
+ }
+ phase = 0;
+ sbase = str;
+ if (*str == '/')
+ {
+ if (streq (sbase, module->file_name))
+ break;
+ }
+ else
+ {
+ size_t last = strlen (n_so);
+ if (n_so[last - 1] == '/')
+ last--;
+ if (strncmp (n_so, module->file_name, last) == 0 &&
+ module->file_name[last] == '/' &&
+ streq (sbase, module->file_name + last + 1))
+ break;
+ }
+ }
+ }
+ if (n >= tot)
+ {
+ delete stabReader;
+ return DBGD_ERR_NO_STABS;
+ }
+
+ Include *includes = new Include;
+ includes->new_src_file (module->getMainSrc (), 0, NULL);
+ module->hasStabs = true;
+ *curr_src = '\0';
+ phase = 0;
+ for (n++; n < tot; n++)
+ {
+ struct stab stb;
+ char *str = stabReader->get_stab (&stb, comdat);
+ int n_desc = (int) ((unsigned short) stb.n_desc);
+ switch (stb.n_type)
+ {
+ case N_UNDF:
+ case N_SO:
+ case N_ENDM:
+ n = tot;
+ break;
+ case N_ALIAS:
+ if (str == NULL)
+ break;
+ if (is_fortran (_lang_code))
+ {
+ char *p = strchr (str, ':');
+ if (p && streq (p + 1, NTXT ("FMAIN")))
+ {
+ Function *afunc = find_func (NTXT ("MAIN"), functions, true);
+ if (afunc)
+ afunc->set_match_name (dbe_strndup (str, p - str));
+ break;
+ }
+ }
+ case N_FUN:
+ case N_OUTL:
+ if (str == NULL)
+ break;
+ if (*str == '@')
+ {
+ str++;
+ if (*str == '>' || *str == '<')
+ str++;
+ }
+ if (stabs_level != 0)
+ break;
+
+ // find address of the enclosed function
+ newFunc = find_func (str, functions, is_fortran (_lang_code));
+ if (newFunc == NULL)
+ break;
+ if (func)
+ while (func->popSrcFile ())
+ ;
+ func = newFunc;
+
+ // First line info to cover function from the beginning
+ lineno = xline + n_desc;
+ if (lineno > 0)
+ {
+ // Set the chain of includes for the new function
+ includes->push_src_files (func);
+ func->add_PC_info (0, lineno);
+ no_stabs = false;
+ }
+ break;
+ case N_ENTRY:
+ break;
+ case N_CMDLINE:
+ if (str && !module->comp_flags)
+ {
+ char *comp_flags = strchr (str, ';');
+ if (comp_flags)
+ {
+ module->comp_flags = dbe_strdup (comp_flags + 1);
+ module->comp_dir = dbe_strndup (str, comp_flags - str);
+ }
+ }
+ break;
+ case N_LBRAC:
+ stabs_level++;
+ break;
+ case N_RBRAC:
+ stabs_level--;
+ break;
+ case N_XLINE:
+ xline = n_desc << 16;
+ break;
+ case N_SLINE:
+ if (func == NULL)
+ break;
+ no_stabs = false;
+ lineno = xline + n_desc;
+ if (func->line_first <= 0)
+ {
+ // Set the chain of includes for the new function
+ includes->push_src_files (func);
+ func->add_PC_info (0, lineno);
+ break;
+ }
+ if (func->curr_srcfile == NULL)
+ includes->push_src_files (func);
+ if (func->line_first != lineno ||
+ !streq (curr_src, func->getDefSrc ()->get_name ()))
+ func->add_PC_info (stb.n_value, lineno);
+ break;
+ case N_OPT:
+ if ((str != NULL) && streq (str, NTXT ("gcc2_compiled.")))
+ _lang_code = Sp_lang_gcc;
+ switch (elfDbg->elf_getehdr ()->e_type)
+ {
+ case ET_EXEC:
+ case ET_DYN:
+ // set the real object timestamp from the executable's N_OPT stab
+ // due to bug #4796329
+ module->real_timestamp = stb.n_value;
+ break;
+ default:
+ module->curr_timestamp = stb.n_value;
+ break;
+ }
+ break;
+ case N_GSYM:
+ if ((str == NULL) || strncmp (str, NTXT ("__KAI_K"), 7))
+ break;
+ str += 7;
+ if (!strncmp (str, NTXT ("CC_"), 3))
+ _lang_code = Sp_lang_KAI_KCC;
+ else if (!strncmp (str, NTXT ("cc_"), 3))
+ _lang_code = Sp_lang_KAI_Kcc;
+ else if (!strncmp (str, NTXT ("PTS_"), 4) &&
+ (_lang_code != Sp_lang_KAI_KCC) &&
+ (_lang_code != Sp_lang_KAI_Kcc))
+ _lang_code = Sp_lang_KAI_KPTS;
+ break;
+ case N_BINCL:
+ includes->new_include_file (module->setIncludeFile (str), func);
+ break;
+ case N_EINCL:
+ includes->end_include_file (func);
+ break;
+ case N_SOL:
+ if (str == NULL)
+ break;
+ lineno = xline + n_desc;
+ if (lineno > 0 && func && func->line_first <= 0)
+ {
+ includes->push_src_files (func);
+ func->add_PC_info (0, lineno);
+ no_stabs = false;
+ }
+ if (streq (sbase, str))
+ {
+ module->setIncludeFile (NULL);
+ snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), module->file_name);
+ includes->new_src_file (module->getMainSrc (), lineno, func);
+ }
+ else
+ {
+ if (streq (sbase, get_basename (str)))
+ {
+ module->setIncludeFile (NULL);
+ snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), module->file_name);
+ includes->new_src_file (module->setIncludeFile (curr_src), lineno, func);
+ }
+ else
+ {
+ if (*str == '/')
+ snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), str);
+ else
+ {
+ size_t last = strlen (n_so);
+ if (last == 0 || n_so[last - 1] != '/')
+ snprintf (curr_src, sizeof (curr_src), NTXT ("%s/%s"), n_so, str);
+ else
+ snprintf (curr_src, sizeof (curr_src), NTXT ("%s%s"), n_so, str);
+ }
+ includes->new_src_file (module->setIncludeFile (curr_src), lineno, func);
+ }
+ }
+ break;
+ }
+ }
+ delete includes;
+ delete stabReader;
+ return no_stabs ? DBGD_ERR_NO_STABS : DBGD_ERR_NONE;
+}//srcline_Stabs
+
+static bool
+cmp_func_name (char *fname, size_t len, char *name, bool fortran)
+{
+ return (strncmp (name, fname, len) == 0
+ && (name[len] == 0
+ || (fortran && name[len] == '_' && name[len + 1] == 0)));
+}
+
+Function *
+Stabs::find_func (char *fname, Vector<Function*> *functions, bool fortran, bool inner_names)
+{
+ char *arg, *name;
+ Function *item;
+ int index;
+ size_t len;
+
+ len = strlen (fname);
+ arg = strchr (fname, ':');
+ if (arg != NULL)
+ {
+ if (arg[1] == 'P') // Prototype for function
+ return NULL;
+ len -= strlen (arg);
+ }
+
+ Vec_loop (Function*, functions, index, item)
+ {
+ name = item->get_mangled_name ();
+ if (cmp_func_name (fname, len, name, fortran))
+ return item->cardinal ();
+ }
+
+ if (inner_names)
+ {
+ // Dwarf subprograms may only have plain (non-linker) names
+ // Retry with inner names only
+
+ Vec_loop (Function*, functions, index, item)
+ {
+ name = strrchr (item->get_mangled_name (), '.');
+ if (!name) continue;
+ name++;
+ if (cmp_func_name (fname, len, name, fortran))
+ return item->cardinal ();
+ }
+ }
+ return NULL;
+}
+
+Map<const char*, Symbol*> *
+Stabs::get_elf_symbols ()
+{
+ Elf *elf = openElf (false);
+ if (elf->elfSymbols == NULL)
+ {
+ Map<const char*, Symbol*> *elfSymbols = new StringMap<Symbol*>(128, 128);
+ elf->elfSymbols = elfSymbols;
+ for (int i = 0, sz = SymLst ? SymLst->size () : 0; i < sz; i++)
+ {
+ Symbol *sym = SymLst->fetch (i);
+ elfSymbols->put (sym->name, sym);
+ }
+ }
+ return elf->elfSymbols;
+}
+
+void
+Stabs::read_dwarf_from_dot_o (Module *mod)
+{
+ Dprintf (DEBUG_STABS, NTXT ("stabsModules: %s\n"), STR (mod->get_name ()));
+ Vector<Module*> *mods = mod->dot_o_file->seg_modules;
+ char *bname = get_basename (mod->get_name ());
+ for (int i1 = 0, sz1 = mods ? mods->size () : 0; i1 < sz1; i1++)
+ {
+ Module *m = mods->fetch (i1);
+ Dprintf (DEBUG_STABS, NTXT (" MOD: %s\n"), STR (m->get_name ()));
+ if (dbe_strcmp (bname, get_basename (m->get_name ())) == 0)
+ {
+ mod->indexStabsLink = m;
+ m->indexStabsLink = mod;
+ break;
+ }
+ }
+ if (mod->indexStabsLink)
+ {
+ mod->dot_o_file->objStabs->openDwarf ()->srcline_Dwarf (mod->indexStabsLink);
+ Map<const char*, Symbol*> *elfSymbols = get_elf_symbols ();
+ Vector<Function*> *funcs = mod->indexStabsLink->functions;
+ for (int i1 = 0, sz1 = funcs ? funcs->size () : 0; i1 < sz1; i1++)
+ {
+ Function *f1 = funcs->fetch (i1);
+ Symbol *sym = elfSymbols->get (f1->get_mangled_name ());
+ if (sym == NULL)
+ continue;
+ Dprintf (DEBUG_STABS, NTXT (" Symbol: %s func=%p\n"), STR (sym->name), sym->func);
+ Function *f = sym->func;
+ if (f->indexStabsLink)
+ continue;
+ f->indexStabsLink = f1;
+ f1->indexStabsLink = f;
+ f->copy_PCInfo (f1);
+ }
+ }
+}
+
+Stabs::Stab_status
+Stabs::read_archive (LoadObject *lo)
+{
+ if (openElf (true) == NULL)
+ return status;
+ check_Symtab ();
+ if (elfDbg->dwarf)
+ openDwarf ()->archive_Dwarf (lo);
+
+ // get Module/Function lists from stabs info
+ Stab_status statusStabs = DBGD_ERR_NO_STABS;
+#define ARCHIVE_STABS(sec, secStr, comdat) \
+ if ((elfDbg->sec) != 0 && (elfDbg->secStr) != 0 && \
+ archive_Stabs(lo, elfDbg->sec, elfDbg->secStr, comdat) == DBGD_ERR_NONE) \
+ statusStabs = DBGD_ERR_NONE
+
+ // prefer index stabs (where they exist) since they're most appropriate
+ // for loadobjects and might have N_CPROF stabs for ABS/CPF
+ ARCHIVE_STABS (stabIndex, stabIndexStr, true);
+ ARCHIVE_STABS (stabExcl, stabExclStr, false);
+ ARCHIVE_STABS (stab, stabStr, false);
+
+ // Add all unassigned functions to the <unknown> module
+ Symbol *sitem, *alias;
+ int index;
+ Vec_loop (Symbol*, SymLst, index, sitem)
+ {
+ if (sitem->func || (sitem->size == 0) || (sitem->flags & SYM_UNDEF))
+ continue;
+ alias = sitem->alias;
+ if (alias)
+ {
+ if (alias->func == NULL)
+ {
+ alias->func = createFunction (lo, lo->noname, alias);
+ alias->func->alias = alias->func;
+ }
+ if (alias != sitem)
+ {
+ sitem->func = createFunction (lo, alias->func->module, sitem);
+ sitem->func->alias = alias->func;
+ }
+ }
+ else
+ sitem->func = createFunction (lo, lo->noname, sitem);
+ }
+ if (pltSym)
+ {
+ pltSym->func = createFunction (lo, lo->noname, pltSym);
+ pltSym->func->flags |= FUNC_FLAG_PLT;
+ }
+
+ // need Module association, so this must be done after handling Modules
+ check_AnalyzerInfo ();
+
+ if (dwarf && dwarf->status == DBGD_ERR_NONE)
+ return DBGD_ERR_NONE;
+ return statusStabs;
+}//read_archive
+
+Function *
+Stabs::createFunction (LoadObject *lo, Module *module, Symbol *sym)
+{
+ Function *func = dbeSession->createFunction ();
+ func->module = module;
+ func->img_fname = path;
+ func->img_offset = (off_t) sym->img_offset;
+ func->save_addr = sym->save;
+ func->size = (uint32_t) sym->size;
+ func->set_name (sym->name);
+ func->elfSym = sym;
+ module->functions->append (func);
+ lo->functions->append (func);
+ return func;
+}
+
+void
+Stabs::fixSymtabAlias ()
+{
+ int ind, i, k;
+ Symbol *sym, *bestAlias;
+ SymLst->sort (SymImgOffsetCmp);
+ ind = SymLst->size () - 1;
+ for (i = 0; i < ind; i++)
+ {
+ bestAlias = SymLst->fetch (i);
+ if (bestAlias->img_offset == 0) // Ignore this bad symbol
+ continue;
+ sym = SymLst->fetch (i + 1);
+ if (bestAlias->img_offset != sym->img_offset)
+ {
+ if ((bestAlias->size == 0) ||
+ (sym->img_offset < bestAlias->img_offset + bestAlias->size))
+ bestAlias->size = sym->img_offset - bestAlias->img_offset;
+ continue;
+ }
+
+ // Find a "best" alias
+ size_t bestLen = strlen (bestAlias->name);
+ int64_t maxSize = bestAlias->size;
+ for (k = i + 1; k <= ind; k++)
+ {
+ sym = SymLst->fetch (k);
+ if (bestAlias->img_offset != sym->img_offset)
+ { // no more aliases
+ if ((maxSize == 0) ||
+ (sym->img_offset < bestAlias->img_offset + maxSize))
+ maxSize = sym->img_offset - bestAlias->img_offset;
+ break;
+ }
+ if (maxSize < sym->size)
+ maxSize = sym->size;
+ size_t len = strlen (sym->name);
+ if (len < bestLen)
+ {
+ bestAlias = sym;
+ bestLen = len;
+ }
+ }
+ for (; i < k; i++)
+ {
+ sym = SymLst->fetch (i);
+ sym->alias = bestAlias;
+ sym->size = maxSize;
+ }
+ i--;
+ }
+}
+
+void
+Stabs::check_Symtab ()
+{
+ if (st_check_symtab)
+ return;
+ st_check_symtab = true;
+
+ Elf *elf = openElf (true);
+ if (elf == NULL)
+ return;
+ if (elfDis->plt != 0)
+ {
+ Elf_Internal_Shdr *shdr = elfDis->get_shdr (elfDis->plt);
+ if (shdr)
+ {
+ pltSym = new Symbol ();
+ pltSym->value = shdr->sh_addr;
+ pltSym->size = shdr->sh_size;
+ pltSym->img_offset = shdr->sh_offset;
+ pltSym->name = dbe_strdup (NTXT ("@plt"));
+ pltSym->flags |= SYM_PLT;
+ }
+ }
+ if (elf->symtab)
+ readSymSec (elf->symtab, elf);
+ else
+ {
+ readSymSec (elf->SUNW_ldynsym, elf);
+ readSymSec (elf->dynsym, elf);
+ }
+}
+
+void
+Stabs::readSymSec (unsigned int sec, Elf *elf)
+{
+ Symbol *sitem;
+ Sp_lang_code local_lcode;
+ if (sec == 0)
+ return;
+ // Get ELF data
+ Elf_Data *data = elf->elf_getdata (sec);
+ if (data == NULL)
+ return;
+ uint64_t SymtabSize = data->d_size;
+ Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+
+ if ((SymtabSize == 0) || (shdr->sh_entsize == 0))
+ return;
+ Elf_Data *data_str = elf->elf_getdata (shdr->sh_link);
+ if (data_str == NULL)
+ return;
+ char *Strtab = (char *) data_str->d_buf;
+
+ // read func symbolic table
+ for (unsigned int n = 0, tot = SymtabSize / shdr->sh_entsize; n < tot; n++)
+ {
+ Elf_Internal_Sym Sym;
+ elf->elf_getsym (data, n, &Sym);
+ const char *st_name = Sym.st_name < data_str->d_size ?
+ (Strtab + Sym.st_name) : NTXT ("no_name");
+ switch (GELF_ST_TYPE (Sym.st_info))
+ {
+ case STT_FUNC:
+ // Skip UNDEF symbols (bug 4817083)
+ if (Sym.st_shndx == 0)
+ {
+ if (Sym.st_value == 0)
+ break;
+ sitem = new Symbol (SymLst);
+ sitem->flags |= SYM_UNDEF;
+ if (pltSym)
+ sitem->img_offset = (uint32_t) (pltSym->img_offset +
+ Sym.st_value - pltSym->value);
+ }
+ else
+ {
+ Elf_Internal_Shdr *shdrp = elfDis->get_shdr (Sym.st_shndx);
+ if (shdrp == NULL)
+ break;
+ sitem = new Symbol (SymLst);
+ sitem->img_offset = (uint32_t) (shdrp->sh_offset +
+ Sym.st_value - shdrp->sh_addr);
+ }
+ sitem->size = Sym.st_size;
+ sitem->name = dbe_strdup (st_name);
+ sitem->value = is_relocatable () ? sitem->img_offset : Sym.st_value;
+ if (GELF_ST_BIND (Sym.st_info) == STB_LOCAL)
+ {
+ sitem->local_ind = LocalFile->size () - 1;
+ LocalLst->append (sitem);
+ }
+ break;
+ case STT_NOTYPE:
+ if (streq (st_name, NTXT ("gcc2_compiled.")))
+ {
+ sitem = new Symbol (SymLst);
+ sitem->lang_code = Sp_lang_gcc;
+ sitem->name = dbe_strdup (st_name);
+ sitem->local_ind = LocalFile->size () - 1;
+ LocalLst->append (sitem);
+ }
+ break;
+ case STT_OBJECT:
+ if (!strncmp (st_name, NTXT ("__KAI_KPTS_"), 11))
+ local_lcode = Sp_lang_KAI_KPTS;
+ else if (!strncmp (st_name, NTXT ("__KAI_KCC_"), 10))
+ local_lcode = Sp_lang_KAI_KCC;
+ else if (!strncmp (st_name, NTXT ("__KAI_Kcc_"), 10))
+ local_lcode = Sp_lang_KAI_Kcc;
+ else
+ break;
+ sitem = new Symbol (LocalLst);
+ sitem->lang_code = local_lcode;
+ sitem->name = dbe_strdup (st_name);
+ break;
+ case STT_FILE:
+ {
+ int last = LocalFile->size () - 1;
+ if (last >= 0 && LocalFileIdx->fetch (last) == LocalLst->size ())
+ {
+ // There were no local functions in the latest file.
+ free (LocalFile->get (last));
+ LocalFile->store (last, dbe_strdup (st_name));
+ }
+ else
+ {
+ LocalFile->append (dbe_strdup (st_name));
+ LocalFileIdx->append (LocalLst->size ());
+ }
+ break;
+ }
+ }
+ }
+ fixSymtabAlias ();
+ SymLst->sort (SymValueCmp);
+ get_save_addr (elf->need_swap_endian);
+ dump ();
+}//check_Symtab
+
+void
+Stabs::check_Relocs ()
+{
+ // We may have many relocation tables to process: .rela.text%foo,
+ // rela.text%bar, etc. On Intel, compilers generate .rel.text sections
+ // which have to be processed as well. A lot of rework is needed here.
+ Symbol *sptr = NULL;
+ if (st_check_relocs)
+ return;
+ st_check_relocs = true;
+
+ Elf *elf = openElf (false);
+ if (elf == NULL)
+ return;
+ for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+ {
+ bool use_rela, use_PLT;
+ char *name = elf->get_sec_name (sec);
+ if (name == NULL)
+ continue;
+ if (strncmp (name, NTXT (".rela.text"), 10) == 0)
+ {
+ use_rela = true;
+ use_PLT = false;
+ }
+ else if (streq (name, NTXT (".rela.plt")))
+ {
+ use_rela = true;
+ use_PLT = true;
+ }
+ else if (strncmp (name, NTXT (".rel.text"), 9) == 0)
+ {
+ use_rela = false;
+ use_PLT = false;
+ }
+ else if (streq (name, NTXT (".rel.plt")))
+ {
+ use_rela = false;
+ use_PLT = true;
+ }
+ else
+ continue;
+
+ Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+ if (shdr == NULL)
+ continue;
+
+ // Get ELF data
+ Elf_Data *data = elf->elf_getdata (sec);
+ if (data == NULL)
+ continue;
+ uint64_t ScnSize = data->d_size;
+ uint64_t EntSize = shdr->sh_entsize;
+ if ((ScnSize == 0) || (EntSize == 0))
+ continue;
+ int tot = (int) (ScnSize / EntSize);
+
+ // Get corresponding text section
+ Elf_Internal_Shdr *shdr_txt = elf->get_shdr (shdr->sh_info);
+ if (shdr_txt == NULL)
+ continue;
+ if (!(shdr_txt->sh_flags & SHF_EXECINSTR))
+ continue;
+
+ // Get corresponding symbol table section
+ Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link);
+ if (shdr_sym == NULL)
+ continue;
+ Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link);
+
+ // Get corresponding string table section
+ Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link);
+ if (data_str == NULL)
+ continue;
+ char *Strtab = (char*) data_str->d_buf;
+ for (int n = 0; n < tot; n++)
+ {
+ Elf_Internal_Sym sym;
+ Elf_Internal_Rela rela;
+ char *symName;
+ if (use_rela)
+ elf->elf_getrela (data, n, &rela);
+ else
+ {
+ // GElf_Rela is extended GElf_Rel
+ elf->elf_getrel (data, n, &rela);
+ rela.r_addend = 0;
+ }
+
+ int ndx = (int) GELF_R_SYM (rela.r_info);
+ elf->elf_getsym (data_sym, ndx, &sym);
+ switch (GELF_ST_TYPE (sym.st_info))
+ {
+ case STT_FUNC:
+ case STT_OBJECT:
+ case STT_NOTYPE:
+ if (sym.st_name == 0 || sym.st_name >= data_str->d_size)
+ continue;
+ symName = Strtab + sym.st_name;
+ break;
+ case STT_SECTION:
+ {
+ Elf_Internal_Shdr *secHdr = elf->get_shdr (sym.st_shndx);
+ if (secHdr == NULL)
+ continue;
+ if (sptr == NULL)
+ sptr = new Symbol;
+ sptr->value = secHdr->sh_offset + rela.r_addend;
+ long index = SymLst->bisearch (0, -1, &sptr, SymFindCmp);
+ if (index == -1)
+ continue;
+ Symbol *sp = SymLst->fetch (index);
+ if (sptr->value != sp->value)
+ continue;
+ symName = sp->name;
+ break;
+ }
+ default:
+ continue;
+ }
+ Reloc *reloc = new Reloc;
+ reloc->name = dbe_strdup (symName);
+ reloc->type = GELF_R_TYPE (rela.r_info);
+ reloc->value = use_PLT ? rela.r_offset
+ : rela.r_offset + shdr_txt->sh_offset;
+ reloc->addend = rela.r_addend;
+ if (use_PLT)
+ RelPLTLst->append (reloc);
+ else
+ RelLst->append (reloc);
+ }
+ }
+ delete sptr;
+ RelLst->sort (RelValueCmp);
+} //check_Relocs
+
+void
+Stabs::get_save_addr (bool need_swap_endian)
+{
+ if (elfDis->is_Intel ())
+ {
+ for (int j = 0, sz = SymLst ? SymLst->size () : 0; j < sz; j++)
+ {
+ Symbol *sitem = SymLst->fetch (j);
+ sitem->save = 0;
+ }
+ return;
+ }
+ for (int j = 0, sz = SymLst ? SymLst->size () : 0; j < sz; j++)
+ {
+ Symbol *sitem = SymLst->fetch (j);
+ sitem->save = FUNC_NO_SAVE;
+
+ // If an image offset is not known skip it.
+ // Works for artificial symbols like '@plt' as well.
+ if (sitem->img_offset == 0)
+ continue;
+
+ bool is_o7_moved = false;
+ int64_t off = sitem->img_offset;
+ for (int i = 0; i < sitem->size; i += 4)
+ {
+ unsigned int cmd;
+ if (elfDis->get_data (off, sizeof (cmd), &cmd) == NULL)
+ break;
+ if (need_swap_endian)
+ SWAP_ENDIAN (cmd);
+ off += sizeof (cmd);
+ if ((cmd & 0xffffc000) == 0x9de38000)
+ { // save %sp, ??, %sp
+ sitem->save = i;
+ break;
+ }
+ else if ((cmd & 0xc0000000) == 0x40000000 || // call ??
+ (cmd & 0xfff80000) == 0xbfc00000)
+ { // jmpl ??, %o7
+ if (!is_o7_moved)
+ {
+ sitem->save = FUNC_ROOT;
+ break;
+ }
+ }
+ else if ((cmd & 0xc1ffe01f) == 0x8010000f) // or %g0,%o7,??
+ is_o7_moved = true;
+ }
+ }
+}
+
+uint64_t
+Stabs::mapOffsetToAddress (uint64_t img_offset)
+{
+ Elf *elf = openElf (false);
+ if (elf == NULL)
+ return 0;
+ if (is_relocatable ())
+ return img_offset;
+ for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+ {
+ Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+ if (shdr == NULL)
+ continue;
+ if (img_offset >= (uint64_t) shdr->sh_offset
+ && img_offset < (uint64_t) (shdr->sh_offset + shdr->sh_size))
+ return shdr->sh_addr + (img_offset - shdr->sh_offset);
+ }
+ return 0;
+}
+
+Stabs::Stab_status
+Stabs::archive_Stabs (LoadObject *lo, unsigned int StabSec,
+ unsigned int StabStrSec, bool comdat)
+{
+ StabReader *stabReader = new StabReader (openElf (true), platform, StabSec, StabStrSec);
+ int tot = stabReader->stabCnt;
+ if (tot < 0)
+ {
+ delete stabReader;
+ return DBGD_ERR_NO_STABS;
+ }
+
+ char *sbase = NTXT (""), *arg, *fname, sname[2 * MAXPATHLEN];
+ int lastMod, phase, stabs_level, modCnt = 0;
+ Function *func = NULL;
+ Module *mod;
+#define INIT_MOD phase = 0; stabs_level = 0; *sname = '\0'; mod = NULL
+
+ bool updateStabsMod = false;
+ if (comdat && ((elfDbg->elf_getehdr ()->e_type == ET_EXEC) || (elfDbg->elf_getehdr ()->e_type == ET_DYN)))
+ {
+ if (stabsModules == NULL)
+ stabsModules = new Vector<Module*>();
+ updateStabsMod = true;
+ }
+ INIT_MOD;
+ lastMod = lo->seg_modules->size ();
+
+ for (int n = 0; n < tot; n++)
+ {
+ struct stab stb;
+ char *str = stabReader->get_stab (&stb, comdat);
+ switch (stb.n_type)
+ {
+ case N_FUN:
+ // Ignore a COMDAT function, if there are two or more modules in 'lo'
+ if (comdat && stb.n_other == 1 && modCnt > 1)
+ break;
+ case N_OUTL:
+ case N_ALIAS:
+ case N_ENTRY:
+ if (mod == NULL || str == NULL
+ || (stb.n_type != N_ENTRY && stabs_level != 0))
+ break;
+ if (*str == '@')
+ {
+ str++;
+ if (*str == '>' || *str == '<')
+ str++;
+ }
+
+ fname = dbe_strdup (str);
+ arg = strchr (fname, ':');
+ if (arg != NULL)
+ {
+ if (!strncmp (arg, NTXT (":P"), 2))
+ { // just prototype
+ free (fname);
+ break;
+ }
+ *arg = '\0';
+ }
+
+ func = append_Function (mod, fname);
+ free (fname);
+ break;
+ case N_CMDLINE:
+ if (str && mod)
+ {
+ char *comp_flags = strchr (str, ';');
+ if (comp_flags)
+ {
+ mod->comp_flags = dbe_strdup (comp_flags + 1);
+ mod->comp_dir = dbe_strndup (str, comp_flags - str);
+ }
+ }
+ break;
+ case N_LBRAC:
+ stabs_level++;
+ break;
+ case N_RBRAC:
+ stabs_level--;
+ break;
+ case N_UNDF:
+ INIT_MOD;
+ break;
+ case N_ENDM:
+ INIT_MOD;
+ break;
+ case N_OPT:
+ stabReader->parse_N_OPT (mod, str);
+ if (mod && (str != NULL) && streq (str, NTXT ("gcc2_compiled.")))
+ // Is it anachronism ?
+ mod->lang_code = Sp_lang_gcc;
+ break;
+ case N_GSYM:
+ if (mod && (str != NULL))
+ {
+ if (strncmp (str, NTXT ("__KAI_K"), 7))
+ break;
+ str += 7;
+ if (!strncmp (str, NTXT ("CC_"), 3))
+ mod->lang_code = Sp_lang_KAI_KCC;
+ else if (!strncmp (str, NTXT ("cc_"), 3))
+ mod->lang_code = Sp_lang_KAI_Kcc;
+ else if (!strncmp (str, NTXT ("PTS_"), 4) &&
+ (mod->lang_code != Sp_lang_KAI_KCC) &&
+ (mod->lang_code != Sp_lang_KAI_Kcc))
+ mod->lang_code = Sp_lang_KAI_KPTS;
+ }
+ break;
+ case N_SO:
+ if (str == NULL || *str == '\0')
+ {
+ INIT_MOD;
+ break;
+ }
+ if (phase == 0)
+ {
+ phase = 1;
+ sbase = str;
+ }
+ else
+ {
+ if (*str == '/')
+ sbase = str;
+ else
+ {
+ size_t last = strlen (sbase);
+ if (last == 0 || sbase[last - 1] != '/')
+ snprintf (sname, sizeof (sname), NTXT ("%s/%s"), sbase, str);
+ else
+ snprintf (sname, sizeof (sname), NTXT ("%s%s"), sbase, str);
+ sbase = sname;
+ }
+ mod = append_Module (lo, sbase, lastMod);
+ if (updateStabsMod)
+ stabsModules->append (mod);
+ mod->hasStabs = true;
+ modCnt++;
+ if ((mod->lang_code != Sp_lang_gcc) &&
+ (mod->lang_code != Sp_lang_KAI_KPTS) &&
+ (mod->lang_code != Sp_lang_KAI_KCC) &&
+ (mod->lang_code != Sp_lang_KAI_Kcc))
+ mod->lang_code = (Sp_lang_code) stb.n_desc;
+ *sname = '\0';
+ phase = 0;
+ }
+ break;
+ case N_OBJ:
+ if (str == NULL)
+ break;
+ if (phase == 0)
+ {
+ phase = 1;
+ sbase = str;
+ }
+ else
+ {
+ if (*str == '/')
+ sbase = str;
+ else
+ {
+ size_t last = strlen (sbase);
+ if (last == 0 || sbase[last - 1] != '/')
+ snprintf (sname, sizeof (sname), NTXT ("%s/%s"), sbase, str);
+ else
+ snprintf (sname, sizeof (sname), NTXT ("%s%s"), sbase, str);
+ sbase = sname;
+ }
+ if (mod && (mod->dot_o_file == NULL))
+ {
+ if (strcmp (sbase, NTXT ("/")) == 0)
+ mod->set_name (dbe_strdup (path));
+ else
+ {
+ mod->set_name (dbe_strdup (sbase));
+ mod->dot_o_file = mod->createLoadObject (sbase);
+ }
+ }
+ *sname = '\0';
+ phase = 0;
+ }
+ break;
+ case N_CPROF:
+ cpf_stabs_t map;
+ Dprintf (DEBUG_STABS, NTXT ("N_CPROF n_desc=%x n_value=0x%04x mod=%s\n"),
+ stb.n_desc, stb.n_value, (mod == NULL) ? NTXT ("???") : mod->get_name ());
+ map.type = stb.n_desc;
+ map.offset = stb.n_value;
+ map.module = mod;
+ analyzerInfoMap.append (map);
+ break;
+ }
+ }
+ delete stabReader;
+ return func ? DBGD_ERR_NONE : DBGD_ERR_NO_STABS;
+}
+
+Module *
+Stabs::append_Module (LoadObject *lo, char *name, int lastMod)
+{
+ Module *module;
+ int size;
+ Symbol *sitem;
+
+ if (lo->seg_modules != NULL)
+ {
+ size = lo->seg_modules->size ();
+ if (size < lastMod)
+ lastMod = size;
+ for (int i = 0; i < lastMod; i++)
+ {
+ module = lo->seg_modules->fetch (i);
+ if (module->linkerStabName && streq (module->linkerStabName, name))
+ return module;
+ }
+ }
+ module = dbeSession->createModule (lo, NULL);
+ module->set_file_name (dbe_strdup (name));
+ module->linkerStabName = dbe_strdup (module->file_name);
+
+ // Append all functions with 'local_ind == -1' to the module.
+ if (LocalLst->size () > 0)
+ {
+ sitem = LocalLst->fetch (0);
+ if (!sitem->defined && sitem->local_ind == -1)
+ // Append all functions with 'local_ind == -1' to the module.
+ append_local_funcs (module, 0);
+ }
+
+ // Append local func
+ char *basename = get_basename (name);
+ size = LocalFile->size ();
+ for (int i = 0; i < size; i++)
+ {
+ if (streq (basename, LocalFile->fetch (i)))
+ {
+ int local_ind = LocalFileIdx->fetch (i);
+ if (local_ind >= LocalLst->size ())
+ break;
+ sitem = LocalLst->fetch (local_ind);
+ if (!sitem->defined)
+ {
+ append_local_funcs (module, local_ind);
+ break;
+ }
+ }
+ }
+ return module;
+}
+
+void
+Stabs::append_local_funcs (Module *module, int first_ind)
+{
+ Symbol *sitem = LocalLst->fetch (first_ind);
+ int local_ind = sitem->local_ind;
+ int size = LocalLst->size ();
+ for (int i = first_ind; i < size; i++)
+ {
+ sitem = LocalLst->fetch (i);
+ if (sitem->local_ind != local_ind)
+ break;
+ sitem->defined = true;
+
+ // 3rd party compiled. e.g., Gcc or KAI compiled
+ if (sitem->lang_code != Sp_lang_unknown)
+ {
+ if (module->lang_code == Sp_lang_unknown)
+ module->lang_code = sitem->lang_code;
+ continue;
+ }
+ if (sitem->func)
+ continue;
+ Function *func = dbeSession->createFunction ();
+ sitem->func = func;
+ func->img_fname = path;
+ func->img_offset = (off_t) sitem->img_offset;
+ func->save_addr = (uint32_t) sitem->save;
+ func->size = (uint32_t) sitem->size;
+ func->module = module;
+ func->set_name (sitem->name);
+ module->functions->append (func);
+ module->loadobject->functions->append (func);
+ }
+}
+
+Function *
+Stabs::append_Function (Module *module, char *fname)
+{
+ Symbol *sitem, *sptr;
+ Function *func;
+ long sid, index;
+ char *name;
+ if (SymLstByName == NULL)
+ {
+ SymLstByName = SymLst->copy ();
+ SymLstByName->sort (SymNameCmp);
+ }
+ sptr = new Symbol;
+ if (module->lang_code == N_SO_FORTRAN || module->lang_code == N_SO_FORTRAN90)
+ {
+ char *fortran = dbe_sprintf (NTXT ("%s_"), fname); // FORTRAN name
+ sptr->name = fortran;
+ sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp);
+ if (sid == -1)
+ {
+ free (fortran);
+ sptr->name = fname;
+ sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp);
+ }
+ else
+ fname = fortran;
+ }
+ else
+ {
+ sptr->name = fname;
+ sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp);
+ }
+ sptr->name = NULL;
+ delete sptr;
+
+ if (sid == -1)
+ {
+ Vec_loop (Symbol*, SymLstByName, index, sitem)
+ {
+ if (strncmp (sitem->name, NTXT ("$X"), 2) == 0
+ || strncmp (sitem->name, NTXT (".X"), 2) == 0)
+ {
+ char *n = strchr (((sitem->name) + 2), (int) '.');
+ if (n != NULL)
+ name = n + 1;
+ else
+ name = sitem->name;
+ }
+ else
+ name = sitem->name;
+ if (name != NULL && fname != NULL && (strcmp (name, fname) == 0))
+ {
+ sid = index;
+ break;
+ }
+ }
+ }
+ if (sid != -1)
+ {
+ sitem = SymLstByName->fetch (sid);
+ if (sitem->alias)
+ sitem = sitem->alias;
+ if (sitem->func)
+ return sitem->func;
+ sitem->func = func = dbeSession->createFunction ();
+ func->img_fname = path;
+ func->img_offset = (off_t) sitem->img_offset;
+ func->save_addr = (uint32_t) sitem->save;
+ func->size = (uint32_t) sitem->size;
+ }
+ else
+ func = dbeSession->createFunction ();
+
+ func->module = module;
+ func->set_name (fname);
+ module->functions->append (func);
+ module->loadobject->functions->append (func);
+ return func;
+}
+
+Function *
+Stabs::append_Function (Module *module, char *linkerName, uint64_t pc)
+{
+ Dprintf (DEBUG_STABS, NTXT ("Stabs::append_Function: module=%s linkerName=%s pc=0x%llx\n"),
+ STR (module->get_name ()), STR (linkerName), (unsigned long long) pc);
+ long i;
+ Symbol *sitem = NULL, *sp;
+ Function *func;
+ sp = new Symbol;
+ if (pc)
+ {
+ sp->value = pc;
+ i = SymLst->bisearch (0, -1, &sp, SymFindCmp);
+ if (i != -1)
+ sitem = SymLst->fetch (i);
+ }
+
+ if (!sitem && linkerName)
+ {
+ if (SymLstByName == NULL)
+ {
+ SymLstByName = SymLst->copy ();
+ SymLstByName->sort (SymNameCmp);
+ }
+ sp->name = linkerName;
+ i = SymLstByName->bisearch (0, -1, &sp, SymNameCmp);
+ sp->name = NULL;
+ if (i != -1)
+ sitem = SymLstByName->fetch (i);
+ }
+ delete sp;
+
+ if (!sitem)
+ return NULL;
+ if (sitem->alias)
+ sitem = sitem->alias;
+ if (sitem->func)
+ return sitem->func;
+
+ sitem->func = func = dbeSession->createFunction ();
+ func->img_fname = path;
+ func->img_offset = (off_t) sitem->img_offset;
+ func->save_addr = (uint32_t) sitem->save;
+ func->size = (uint32_t) sitem->size;
+ func->module = module;
+ func->set_name (sitem->name); //XXXX ?? Now call it to set obj->name
+ module->functions->append (func);
+ module->loadobject->functions->append (func);
+ return func;
+}// Stabs::append_Function
+
+Dwarf *
+Stabs::openDwarf ()
+{
+ if (dwarf == NULL)
+ {
+ dwarf = new Dwarf (this);
+ check_Symtab ();
+ }
+ return dwarf;
+}
+
+void
+Stabs::read_hwcprof_info (Module *module)
+{
+ openDwarf ()->read_hwcprof_info (module);
+}
+
+void
+Stabs::dump ()
+{
+ if (!DUMP_ELF_SYM)
+ return;
+ printf (NTXT ("\n======= Stabs::dump: %s =========\n"), path ? path : NTXT ("NULL"));
+ int i, sz;
+ if (LocalFile)
+ {
+ sz = LocalFile->size ();
+ for (i = 0; i < sz; i++)
+ printf (" %3d: %5d '%s'\n", i, LocalFileIdx->fetch (i),
+ LocalFile->fetch (i));
+ }
+ Symbol::dump (SymLst, NTXT ("SymLst"));
+ Symbol::dump (LocalLst, NTXT ("LocalLst"));
+ printf (NTXT ("\n===== END of Stabs::dump: %s =========\n\n"),
+ path ? path : NTXT ("NULL"));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Class Include
+Include::Include ()
+{
+ stack = new Vector<SrcFileInfo*>;
+}
+
+Include::~Include ()
+{
+ Destroy (stack);
+}
+
+void
+Include::new_src_file (SourceFile *source, int lineno, Function *func)
+{
+ for (int index = stack->size () - 1; index >= 0; index--)
+ {
+ if (source == stack->fetch (index)->srcfile)
+ {
+ for (int i = stack->size () - 1; i > index; i--)
+ {
+ delete stack->remove (i);
+ if (func && func->line_first > 0)
+ func->popSrcFile ();
+ }
+ return;
+ }
+ }
+ if (func && func->line_first > 0)
+ func->pushSrcFile (source, lineno);
+
+ SrcFileInfo *sfinfo = new SrcFileInfo;
+ sfinfo->srcfile = source;
+ sfinfo->lineno = lineno;
+ stack->append (sfinfo);
+}
+
+void
+Include::push_src_files (Function *func)
+{
+ int index;
+ SrcFileInfo *sfinfo;
+
+ if (func->line_first <= 0 && stack->size () > 0)
+ {
+ sfinfo = stack->fetch (stack->size () - 1);
+ func->setDefSrc (sfinfo->srcfile);
+ }
+ Vec_loop (SrcFileInfo*, stack, index, sfinfo)
+ {
+ func->pushSrcFile (sfinfo->srcfile, sfinfo->lineno);
+ }
+}
+
+void
+Include::new_include_file (SourceFile *source, Function *func)
+{
+ if (stack->size () == 1 && stack->fetch (0)->srcfile == source)
+ // workaroud for gcc; gcc creates 'N_BINCL' stab for main source
+ return;
+ if (func && func->line_first > 0)
+ func->pushSrcFile (source, 0);
+
+ SrcFileInfo *sfinfo = new SrcFileInfo;
+ sfinfo->srcfile = source;
+ sfinfo->lineno = 0;
+ stack->append (sfinfo);
+}
+
+void
+Include::end_include_file (Function *func)
+{
+ int index = stack->size () - 1;
+ if (index > 0)
+ {
+ delete stack->remove (index);
+ if (func && func->line_first > 0)
+ func->popSrcFile ();
+ }
+}
+
+#define RET_S(x) if (t == x) return (char *) #x
+char *
+StabReader::get_type_name (int t)
+{
+ RET_S (N_UNDF);
+ RET_S (N_ABS);
+ RET_S (N_TEXT);
+ RET_S (N_DATA);
+ RET_S (N_BSS);
+ RET_S (N_COMM);
+ RET_S (N_FN);
+ RET_S (N_EXT);
+ RET_S (N_TYPE);
+ RET_S (N_GSYM);
+ RET_S (N_FNAME);
+ RET_S (N_FUN);
+ RET_S (N_OUTL);
+ RET_S (N_STSYM);
+ RET_S (N_TSTSYM);
+ RET_S (N_LCSYM);
+ RET_S (N_TLCSYM);
+ RET_S (N_MAIN);
+ RET_S (N_ROSYM);
+ RET_S (N_FLSYM);
+ RET_S (N_TFLSYM);
+ RET_S (N_PC);
+ RET_S (N_CMDLINE);
+ RET_S (N_OBJ);
+ RET_S (N_OPT);
+ RET_S (N_RSYM);
+ RET_S (N_SLINE);
+ RET_S (N_XLINE);
+ RET_S (N_ILDPAD);
+ RET_S (N_SSYM);
+ RET_S (N_ENDM);
+ RET_S (N_SO);
+ RET_S (N_MOD);
+ RET_S (N_EMOD);
+ RET_S (N_READ_MOD);
+ RET_S (N_ALIAS);
+ RET_S (N_LSYM);
+ RET_S (N_BINCL);
+ RET_S (N_SOL);
+ RET_S (N_PSYM);
+ RET_S (N_EINCL);
+ RET_S (N_ENTRY);
+ RET_S (N_SINCL);
+ RET_S (N_LBRAC);
+ RET_S (N_EXCL);
+ RET_S (N_USING);
+ RET_S (N_ISYM);
+ RET_S (N_ESYM);
+ RET_S (N_PATCH);
+ RET_S (N_CONSTRUCT);
+ RET_S (N_DESTRUCT);
+ RET_S (N_CODETAG);
+ RET_S (N_FUN_CHILD);
+ RET_S (N_RBRAC);
+ RET_S (N_BCOMM);
+ RET_S (N_TCOMM);
+ RET_S (N_ECOMM);
+ RET_S (N_XCOMM);
+ RET_S (N_ECOML);
+ RET_S (N_WITH);
+ RET_S (N_LENG);
+ RET_S (N_CPROF);
+ RET_S (N_BROWS);
+ RET_S (N_FUN_PURE);
+ RET_S (N_FUN_ELEMENTAL);
+ RET_S (N_FUN_RECURSIVE);
+ RET_S (N_FUN_AMD64_PARMDUMP);
+ RET_S (N_SYM_OMP_TLS);
+ RET_S (N_SO_AS);
+ RET_S (N_SO_C);
+ RET_S (N_SO_ANSI_C);
+ RET_S (N_SO_CC);
+ RET_S (N_SO_FORTRAN);
+ RET_S (N_SO_FORTRAN77);
+ RET_S (N_SO_PASCAL);
+ RET_S (N_SO_FORTRAN90);
+ RET_S (N_SO_JAVA);
+ RET_S (N_SO_C99);
+ return NULL;
+}
diff --git a/gprofng/src/Stabs.h b/gprofng/src/Stabs.h
new file mode 100644
index 0000000..1a7443a
--- /dev/null
+++ b/gprofng/src/Stabs.h
@@ -0,0 +1,160 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _STABS_H
+#define _STABS_H
+
+#include "dbe_structs.h"
+#include "vec.h"
+
+enum cpf_instr_type_t {
+ CPF_INSTR_TYPE_LD = 0, // profiled load instruction
+ CPF_INSTR_TYPE_ST, // profiled store instruction
+ CPF_INSTR_TYPE_PREFETCH, // profiled prefetch instruction
+ CPF_INSTR_TYPE_BRTARGET, // branch target
+ CPF_INSTR_TYPE_UNKNOWN, // unidentified instruction
+ CPF_INSTR_TYPE_NTYPES // total # of instr types
+};
+
+class Function;
+class LoadObject;
+class Module;
+class ComC;
+class Elf;
+class Dwarf;
+class Symbol;
+class Reloc;
+struct cpf_stabs_t;
+class SourceFile;
+template <typename Key_t, typename Value_t> class Map;
+
+class Include {
+ public:
+ typedef struct {
+ SourceFile *srcfile;
+ int lineno;
+ } SrcFileInfo;
+ Include();
+ ~Include();
+ void new_src_file(SourceFile *source, int lineno, Function *func = NULL);
+ void new_include_file(SourceFile *source, Function *func);
+ void end_include_file(Function *func);
+ void push_src_files(Function *func);
+
+ private:
+ Vector<SrcFileInfo*> *stack;
+};
+
+// Stabs object
+class Stabs {
+ public:
+
+ enum Stab_status {
+ DBGD_ERR_NONE,
+ DBGD_ERR_CANT_OPEN_FILE,
+ DBGD_ERR_BAD_ELF_LIB,
+ DBGD_ERR_BAD_ELF_FORMAT,
+ DBGD_ERR_NO_STABS,
+ DBGD_ERR_BAD_STABS,
+ DBGD_ERR_NO_DWARF,
+ DBGD_ERR_CHK_SUM
+ };
+
+ static Stabs *NewStabs(char *_path, char *lo_name);
+ Stabs(char *_path, char *_lo_name);
+ ~Stabs();
+
+ bool is_relocatable(){ return isRelocatable; }
+ long long get_textsz() { return textsz; }
+ Platform_t get_platform() { return platform; }
+ WSize_t get_class() { return wsize;}
+ Stab_status get_status() { return status;}
+
+ Stab_status read_stabs(ino64_t srcInode, Module *module, Vector<ComC*> *comComs, bool readDwarf = false);
+ Stab_status read_archive(LoadObject *lo);
+ bool read_symbols(Vector<Function*> *functions);
+ uint64_t mapOffsetToAddress(uint64_t img_offset);
+ char *sym_name(uint64_t target, uint64_t instr, int flag);
+ Elf *openElf (bool dbg_info = false);
+ void read_hwcprof_info(Module *module);
+ void dump();
+ void read_dwarf_from_dot_o(Module *mod);
+
+ static bool is_fortran(Sp_lang_code lc) { return (lc == Sp_lang_fortran) || (lc == Sp_lang_fortran90); }
+ static Function *find_func(char *fname, Vector<Function*> *functions, bool fortran, bool inner_names=false);
+ Module *append_Module(LoadObject *lo, char *name, int lastMod = 0);
+ Function *append_Function(Module *module, char *fname);
+ Function *append_Function(Module *module, char *linkerName, uint64_t pc);
+ Function *map_PC_to_func(uint64_t pc, uint64_t &low_pc, Vector<Function*> *functions);
+ char *path; // path to the object file
+ char *lo_name; // User name of load object
+
+ private:
+ Elf *elfDbg; // ELF with debug info
+ Elf *elfDis; // ELF for disasm
+ Stab_status status; // current stabs status
+
+ long long textsz; // text segment size
+ Platform_t platform; // Sparc, Sparcv9, Intel
+ WSize_t wsize; // word size: 32 or 64
+ bool isRelocatable;
+ Symbol *last_PC_to_sym;
+
+ Vector<cpf_stabs_t> analyzerInfoMap; // stabs->section mapping
+
+ bool check_Comm(Vector<ComC*> *comComs);
+ void check_Info(Vector<ComC*> *comComs);
+ void check_Loop(Vector<ComC*> *comComs);
+ void check_AnalyzerInfo();
+ void append_local_funcs(Module *module, int first_ind);
+ Stab_status srcline_Stabs (Module *module, unsigned int StabSec, unsigned int StabStrSec, bool comdat);
+ Stab_status archive_Stabs (LoadObject *lo, unsigned int StabSec, unsigned int StabStrSec, bool comdat);
+
+ // Interface with Elf Symbol Table
+ void check_Symtab();
+ void readSymSec(unsigned int sec, Elf *elf);
+ void check_Relocs();
+ void get_save_addr(bool need_swap_endian);
+ Symbol *map_PC_to_sym(uint64_t pc);
+ Symbol *pltSym;
+ Vector<Symbol*> *SymLst; // list of func symbols
+ Vector<Symbol*> *SymLstByName; // list of func symbols sorted by Name
+ Vector<Reloc*> *RelLst; // list of text relocations
+ Vector<Reloc*> *RelPLTLst; // list of PLT relocations
+ Vector<Symbol*> *LocalLst; // list of local func symbols
+ Vector<char*> *LocalFile; // list of local files
+ Vector<int> *LocalFileIdx; // start index in LocalLst
+
+ Elf *openElf(char *fname, Stab_status &st);
+ Map<const char*, Symbol*> *get_elf_symbols();
+ Dwarf *dwarf;
+
+ bool st_check_symtab, st_check_relocs;
+ Function *createFunction(LoadObject *lo, Module *module, Symbol *sym);
+ void fixSymtabAlias();
+
+ // Interface with dwarf
+ Dwarf *openDwarf();
+
+ Vector<Module*> *stabsModules;
+ static char *get_type_name(int t);
+};
+
+#endif /* _STABS_H */
diff --git a/gprofng/src/Stats_data.cc b/gprofng/src/Stats_data.cc
new file mode 100644
index 0000000..2595bc7
--- /dev/null
+++ b/gprofng/src/Stats_data.cc
@@ -0,0 +1,203 @@
+/* Copyright (C) 2021 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 <search.h> // For the tsearch stuff
+#include <assert.h>
+//#include <stdlib.h>
+#include "Table.h"
+#include "Sample.h"
+#include "Stats_data.h"
+#include "util.h"
+#include "i18n.h"
+
+//XXX: The fundamental problem with this package of routines is that
+//XXX: they should look a lot more like overview data. The result
+//XXX: is that it is not possible to share as much code as would
+//XXX: otherwise be possible.
+
+int
+Stats_data::size ()
+{
+ // Return the number of Stats_item values associated with "this".
+ if (stats_items == NULL)
+ return 0;
+ return stats_items->size ();
+}
+
+Stats_data::Stats_item
+Stats_data::fetch (int index)
+{
+ // Routine will return the "index"'th Stats_item associated with "this".
+ assert (index >= 0 && index < stats_items->size ());
+ return *(stats_items->fetch (index));
+}
+
+Stats_data::Stats_data ()
+{
+ // this constructor for use with sum()
+ packets = NULL;
+ stats_items = NULL;
+}
+
+Stats_data::Stats_data (DataView *_packets)
+{
+ packets = _packets;
+ stats_items = NULL;
+ compute_data (); // reads all data
+}
+
+Stats_data::~Stats_data ()
+{
+ if (stats_items)
+ {
+ stats_items->destroy ();
+ delete stats_items;
+ }
+}
+
+void
+Stats_data::sum (Stats_data *data)
+{
+ int index;
+ Stats_item *stats_item, *data_item;
+ if (stats_items == NULL)
+ {
+ stats_items = new Vector<Stats_item*>;
+ Vec_loop (Stats_item*, data->stats_items, index, data_item)
+ {
+ stats_item = create_stats_item (data_item->value.ll, data_item->label);
+ stats_items->append (stats_item);
+ }
+ }
+ else
+ {
+ Vec_loop (Stats_item*, data->stats_items, index, data_item)
+ {
+ stats_items->fetch (index)->value.ll += data_item->value.ll;
+ }
+ }
+}
+
+Stats_data::Stats_item *
+Stats_data::create_stats_item (long long v, char *l)
+{
+ Stats_data::Stats_item *st_it;
+ st_it = new Stats_data::Stats_item;
+ st_it->label = l;
+ st_it->value.sign = false;
+ st_it->value.ll = v;
+ st_it->value.tag = VT_LLONG;
+ return st_it;
+}
+
+PrUsage *
+Stats_data::fetchPrUsage (long index)
+{
+ // Return the data values corresponding to the "index"'th sample.
+ PrUsage *prusage;
+ if (packets->getSize () > 0)
+ {
+ Sample* sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
+ prusage = sample->get_usage ();
+ if (prusage != NULL)
+ return prusage;
+ }
+ return new PrUsage;
+}
+
+void
+Stats_data::compute_data ()
+{
+ Stats_data::Stats_item *stats_item;
+ PrUsage *tots, *temp;
+ stats_items = new Vector<Stats_data::Stats_item*>;
+
+ // Precomputation is needed.
+ long size = packets->getSize ();
+ tots = new PrUsage ();
+ for (long index = 0; index < size; index++)
+ {
+ temp = fetchPrUsage (index);
+ tots->pr_tstamp += temp->pr_tstamp;
+ tots->pr_create += temp->pr_create;
+ tots->pr_term += temp->pr_term;
+ tots->pr_rtime += temp->pr_rtime;
+ tots->pr_utime += temp->pr_utime;
+ tots->pr_stime += temp->pr_stime;
+ tots->pr_ttime += temp->pr_ttime;
+ tots->pr_tftime += temp->pr_tftime;
+ tots->pr_dftime += temp->pr_dftime;
+ tots->pr_kftime += temp->pr_kftime;
+ tots->pr_slptime += temp->pr_slptime;
+ tots->pr_ltime += temp->pr_ltime;
+ tots->pr_wtime += temp->pr_wtime;
+ tots->pr_stoptime += temp->pr_stoptime;
+ tots->pr_minf += temp->pr_minf;
+ tots->pr_majf += temp->pr_majf;
+ tots->pr_nswap += temp->pr_nswap;
+ tots->pr_inblk += temp->pr_inblk;
+ tots->pr_oublk += temp->pr_oublk;
+ tots->pr_msnd += temp->pr_msnd;
+ tots->pr_mrcv += temp->pr_mrcv;
+ tots->pr_sigs += temp->pr_sigs;
+ tots->pr_vctx += temp->pr_vctx;
+ tots->pr_ictx += temp->pr_ictx;
+ tots->pr_sysc += temp->pr_sysc;
+ tots->pr_ioch += temp->pr_ioch;
+ }
+ stats_item = create_stats_item ((long long) tots->pr_minf,
+ GTXT ("Minor Page Faults"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_majf,
+ GTXT ("Major Page Faults"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_nswap,
+ GTXT ("Process swaps"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_inblk,
+ GTXT ("Input blocks"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_oublk,
+ GTXT ("Output blocks"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_msnd,
+ GTXT ("Messages sent"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_mrcv,
+ GTXT ("Messages received"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_sigs,
+ GTXT ("Signals handled"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_vctx,
+ GTXT ("Voluntary context switches"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_ictx,
+ GTXT ("Involuntary context switches"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_sysc,
+ GTXT ("System calls"));
+ stats_items->append (stats_item);
+ stats_item = create_stats_item ((long long) tots->pr_ioch,
+ GTXT ("Characters of I/O"));
+ stats_items->append (stats_item);
+ delete tots;
+}
diff --git a/gprofng/src/Stats_data.h b/gprofng/src/Stats_data.h
new file mode 100644
index 0000000..2f6b6a7
--- /dev/null
+++ b/gprofng/src/Stats_data.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _STATS_DATA_H
+#define _STATS_DATA_H
+
+// A Stats_data object is used to obtain the data needed to display
+// a statistics display.
+
+#include "vec.h"
+#include "Exp_Layout.h"
+
+class DataView;
+
+class Stats_data
+{
+public:
+
+ struct Stats_item
+ {
+ char *label; // statistic label
+ TValue value; // statistic value
+ };
+
+ Stats_data ();
+ Stats_data (DataView *packets);
+ ~Stats_data ();
+ int size (); // Return the total number of items.
+ Stats_item fetch (int index);
+ void sum (Stats_data *data);
+
+private:
+
+ PrUsage * fetchPrUsage (long index);
+ void compute_data (); // Perform any initial computation.
+ Stats_data::Stats_item *create_stats_item (long long, char *);
+
+ Vector<Stats_item*> *stats_items; // Actual statistics values
+ DataView *packets;
+};
+
+#endif /* _STATS_DATA_H */
diff --git a/gprofng/src/StringBuilder.cc b/gprofng/src/StringBuilder.cc
new file mode 100644
index 0000000..a9656d9
--- /dev/null
+++ b/gprofng/src/StringBuilder.cc
@@ -0,0 +1,585 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <values.h>
+#include <stdarg.h>
+
+#include "gp-defs.h"
+#include "StringBuilder.h"
+#include "i18n.h"
+
+StringBuilder::StringBuilder ()
+{
+ count = 0;
+ maxCapacity = 16;
+ value = (char *) malloc (maxCapacity);
+ memset (value, 0, maxCapacity);
+}
+
+StringBuilder::StringBuilder (int capacity)
+{
+ count = 0;
+ maxCapacity = capacity;
+ value = (char *) malloc (maxCapacity);
+ memset (value, 0, maxCapacity);
+}
+
+StringBuilder::~StringBuilder ()
+{
+ free (value);
+}
+
+void
+StringBuilder::ensureCapacity (int minimumCapacity)
+{
+ if (minimumCapacity > maxCapacity)
+ expandCapacity (minimumCapacity);
+}
+
+void
+StringBuilder::expandCapacity (int minimumCapacity)
+{
+ int newCapacity = (maxCapacity + 1) * 2;
+ if (newCapacity < 0)
+ newCapacity = MAXINT;
+ else if (minimumCapacity > newCapacity)
+ newCapacity = minimumCapacity;
+ char *newValue = (char *) malloc (newCapacity);
+ maxCapacity = newCapacity;
+ memcpy (newValue, value, count);
+ memset (newValue + count, 0, maxCapacity - count);
+ free (value);
+ value = newValue;
+}
+
+void
+StringBuilder::trimToSize ()
+{
+ if (count < maxCapacity)
+ {
+ char *newValue = (char *) malloc (count);
+ maxCapacity = count;
+ memcpy (newValue, value, count);
+ free (value);
+ value = newValue;
+ }
+}
+
+void
+StringBuilder::trim ()
+{
+ while (count > 0)
+ {
+ if (value[count - 1] != ' ')
+ break;
+ count--;
+ }
+}
+
+void
+StringBuilder::setLength (int newLength)
+{
+ if (newLength < 0)
+ return;
+ if (newLength > maxCapacity)
+ expandCapacity (newLength);
+ if (count < newLength)
+ {
+ for (; count < newLength; count++)
+ value[count] = '\0';
+ }
+ else
+ count = newLength;
+}
+
+char
+StringBuilder::charAt (int index)
+{
+ if (index < 0 || index >= count)
+ return 0;
+ return value[index];
+}
+
+void
+StringBuilder::getChars (int srcBegin, int srcEnd, char dst[], int dstBegin)
+{
+ if (srcBegin < 0)
+ return;
+ if (srcEnd < 0 || srcEnd > count)
+ return;
+ if (srcBegin > srcEnd)
+ return;
+ memcpy (dst + dstBegin, value + srcBegin, srcEnd - srcBegin);
+}
+
+void
+StringBuilder::setCharAt (int index, char ch)
+{
+ if (index < 0 || index >= count)
+ return;
+ value[index] = ch;
+}
+
+StringBuilder *
+StringBuilder::append (StringBuilder *sb)
+{
+ if (sb == NULL)
+ return append (NTXT ("null"));
+ int len = sb->count;
+ int newcount = count + len;
+ if (newcount > maxCapacity)
+ expandCapacity (newcount);
+ sb->getChars (0, len, value, count);
+ count = newcount;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (const char str[])
+{
+ int len = (int) strlen (str);
+ int newCount = count + len;
+ if (newCount > maxCapacity)
+ expandCapacity (newCount);
+ memcpy (value + count, str, len);
+ count = newCount;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (const char str[], int offset, int len)
+{
+ int newCount = count + len;
+ if (newCount > maxCapacity)
+ expandCapacity (newCount);
+ memcpy (value + count, str + offset, len);
+ count = newCount;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (bool b)
+{
+ if (b)
+ append (NTXT ("true"));
+ else
+ append (NTXT ("false"));
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (char c)
+{
+ int newCount = count + 1;
+ if (newCount > maxCapacity)
+ {
+ expandCapacity (newCount);
+ }
+ value[count++] = c;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (int i)
+{
+ char buf[16];
+ snprintf (buf, sizeof (buf), NTXT ("%d"), i);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (unsigned int i)
+{
+ char buf[16];
+ snprintf (buf, sizeof (buf), NTXT ("%u"), i);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (long lng)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%ld"), lng);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (unsigned long lng)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%lu"), lng);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (long long lng)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%lld"), lng);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (unsigned long long lng)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%llu"), lng);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (float f)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%f"), (double) f);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::append (double d)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%f"), d);
+ append (buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::_delete (int start, int end)
+{
+ if (start < 0)
+ return this;
+ if (end > count)
+ end = count;
+ if (start > end)
+ return this;
+ int len = end - start;
+ if (len > 0)
+ {
+ memcpy (value + start, value + start + len, count - end);
+ count -= len;
+ }
+ return this;
+}
+
+StringBuilder *
+StringBuilder::deleteCharAt (int index)
+{
+ if (index < 0 || index >= count)
+ return this;
+ memcpy (value + index, value + index + 1, count - index - 1);
+ count--;
+ return this;
+}
+
+bool
+StringBuilder::endsWith (const char str[])
+{
+ if (str == NULL)
+ {
+ if (count == 0)
+ return true;
+ return false;
+ }
+ int len = (int) strlen (str);
+ if (len == 0)
+ return true;
+ int start = count - len;
+ if (start < 0)
+ return false;
+ int res = strncmp ((const char *) (value + start), str, len);
+ if (res != 0)
+ return false;
+ return true;
+}
+
+StringBuilder *
+StringBuilder::insert (int index, const char str[], int offset, int len)
+{
+ if (index < 0 || index > count)
+ return this;
+ if (offset < 0 || len < 0 || offset > ((int) strlen (str)) - len)
+ return this;
+ int newCount = count + len;
+ if (newCount > maxCapacity)
+ expandCapacity (newCount);
+ memcpy (value + index + len, value + index, count - index);
+ memcpy (value + index, str + offset, len);
+ count = newCount;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, const char str[])
+{
+ if (offset < 0 || offset > count)
+ return this;
+ int len = (int) strlen (str);
+ int newCount = count + len;
+ if (newCount > maxCapacity)
+ expandCapacity (newCount);
+ memcpy (value + offset + len, value + offset, count - offset);
+ memcpy (value + offset, str, len);
+ count = newCount;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, bool b)
+{
+ return insert (offset, b ? NTXT ("true") : NTXT ("false"));
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, char c)
+{
+ int newCount = count + 1;
+ if (newCount > maxCapacity)
+ expandCapacity (newCount);
+ memcpy (value + offset + 1, value + offset, count - offset);
+ value[offset] = c;
+ count = newCount;
+ return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, int i)
+{
+ char buf[16];
+ snprintf (buf, sizeof (buf), NTXT ("%d"), i);
+ insert (offset, buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, long l)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%ld"), l);
+ insert (offset, buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, float f)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%f"), (double) f);
+ insert (offset, buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, double d)
+{
+ char buf[32];
+ snprintf (buf, sizeof (buf), NTXT ("%f"), d);
+ insert (offset, buf);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::reverse ()
+{
+ int n = count - 1;
+ for (int j = (n - 1) >> 1; j >= 0; --j)
+ {
+ char temp = value[j];
+ char temp2 = value[n - j];
+ value[j] = temp2;
+ value[n - j] = temp;
+ }
+ return this;
+}
+
+//String *StringBuilder::toString();
+char *
+StringBuilder::toString ()
+{
+ char *str = (char *) malloc (count + 1);
+ memcpy (str, value, count);
+ str[count] = '\0';
+ return str;
+}
+
+void
+StringBuilder::toFile (FILE *fp)
+{
+ append ('\0');
+ count--;
+ fprintf (fp, NTXT ("%s"), value);
+}
+
+void
+StringBuilder::toFileLn (FILE *fp)
+{
+ trim ();
+ append ('\0');
+ count--;
+ fprintf (fp, NTXT ("%s\n"), value);
+}
+
+StringBuilder *
+StringBuilder::sprintf (const char *fmt, ...)
+{
+ int cnt;
+ setLength (0);
+
+ va_list vp;
+ va_start (vp, fmt);
+ cnt = vsnprintf (value, maxCapacity, fmt, vp);
+ va_end (vp);
+ if (cnt < maxCapacity)
+ {
+ count = cnt;
+ return this;
+ }
+
+ // Have to count the trailing zero
+ ensureCapacity (cnt + 1);
+ va_start (vp, fmt);
+ count = vsnprintf (value, maxCapacity, fmt, vp);
+ va_end (vp);
+ return this;
+}
+
+StringBuilder *
+StringBuilder::appendf (const char *fmt, ...)
+{
+ va_list vp;
+ va_start (vp, fmt);
+ int cnt = vsnprintf (value + count, maxCapacity - count, fmt, vp);
+ va_end (vp);
+ if (cnt + count < maxCapacity)
+ {
+ count += cnt;
+ return this;
+ }
+
+ // Have to count the trailing zero
+ ensureCapacity (count + cnt + 1);
+ va_start (vp, fmt);
+ count += vsnprintf (value + count, maxCapacity - count, fmt, vp);
+ va_end (vp);
+ return this;
+}
+
+int
+StringBuilder::indexOf (const char str[])
+{
+ return indexOf (str, 0);
+}
+
+int
+StringBuilder::indexOf (const char str[], int fromIndex)
+{
+ int len = (int) strlen (str);
+ if (fromIndex >= count)
+ return len == 0 ? count : -1;
+ if (fromIndex < 0)
+ fromIndex = 0;
+ if (len == 0)
+ return fromIndex;
+
+ char first = str[0];
+ int max = (count - len);
+
+ for (int i = fromIndex; i <= max; i++)
+ {
+ /* Look for first character. */
+ if (value[i] != first)
+ while (++i <= max && value[i] != first)
+ ;
+ /* Found first character, now look at the rest of v2 */
+ if (i <= max)
+ {
+ int j = i + 1;
+ int end = j + len - 1;
+ for (int k = 1; j < end && value[j] == str[k]; j++, k++)
+ ;
+ if (j == end) /* Found whole string. */
+ return i;
+ }
+ }
+ return -1;
+}
+
+int
+StringBuilder::lastIndexOf (const char str[])
+{
+ return lastIndexOf (str, count);
+}
+
+int
+StringBuilder::lastIndexOf (const char str[], int fromIndex)
+{
+ /*
+ * Check arguments; return immediately where possible. For
+ * consistency, don't check for null str.
+ */
+ int len = (int) strlen (str);
+ int rightIndex = count - len;
+ if (fromIndex < 0)
+ return -1;
+ if (fromIndex > rightIndex)
+ fromIndex = rightIndex;
+ /* Empty string always matches. */
+ if (len == 0)
+ return fromIndex;
+
+ int strLastIndex = len - 1;
+ char strLastChar = str[strLastIndex];
+ int min = len - 1;
+ int i = min + fromIndex;
+
+ while (true)
+ {
+ while (i >= min && value[i] != strLastChar)
+ i--;
+ if (i < min)
+ return -1;
+
+ int j = i - 1;
+ int start = j - (len - 1);
+ int k = strLastIndex - 1;
+ while (j > start)
+ {
+ if (value[j--] != str[k--])
+ {
+ i--;
+ break;
+ }
+ }
+ if (j == start)
+ return start + 1;
+ }
+}
+
diff --git a/gprofng/src/StringBuilder.h b/gprofng/src/StringBuilder.h
new file mode 100644
index 0000000..5fe1a51
--- /dev/null
+++ b/gprofng/src/StringBuilder.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * java/lang/StringBuilder
+ *
+ * Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _StringBuilder_h
+#define _StringBuilder_h
+
+class StringBuilder
+{
+public:
+ StringBuilder ();
+ StringBuilder (int capacity);
+ virtual ~StringBuilder ();
+
+ int
+ length ()
+ {
+ return count;
+ }
+
+ int
+ capacity ()
+ {
+ return maxCapacity;
+ }
+
+ bool endsWith (const char str[]);
+ void ensureCapacity (int minimumCapacity);
+ void expandCapacity (int minimumCapacity);
+ void trimToSize ();
+ void trim ();
+ void setLength (int newLength);
+ char charAt (int index);
+ void getChars (int srcBegin, int srcEnd, char dst[], int dstBegin);
+ void setCharAt (int index, char ch);
+ StringBuilder *append (StringBuilder *sb);
+ StringBuilder *append (const char str[]);
+ StringBuilder *append (const char str[], int offset, int len);
+ StringBuilder *append (bool b);
+ StringBuilder *append (char c);
+ StringBuilder *append (int i);
+ StringBuilder *append (unsigned int i);
+ StringBuilder *append (long lng);
+ StringBuilder *append (unsigned long i);
+ StringBuilder *append (long long lng);
+ StringBuilder *append (unsigned long long lng);
+ StringBuilder *append (float f);
+ StringBuilder *append (double d);
+ StringBuilder *_delete (int start, int end);
+ StringBuilder *deleteCharAt (int index);
+ StringBuilder *insert (int index, const char str[], int offset, int len);
+ StringBuilder *insert (int offset, const char str[]);
+ StringBuilder *insert (int offset, bool b);
+ StringBuilder *insert (int offset, char c);
+ StringBuilder *insert (int offset, int i);
+ StringBuilder *insert (int offset, long l);
+ StringBuilder *insert (int offset, float f);
+ StringBuilder *insert (int offset, double d);
+ StringBuilder *reverse ();
+ char *toString ();
+ void toFile (FILE *fp);
+ void toFileLn (FILE *fp);
+
+ // Not in Java
+ StringBuilder *appendf (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ StringBuilder *sprintf (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ int indexOf (const char str[]);
+ int indexOf (const char str[], int fromIndex);
+ int lastIndexOf (const char str[]);
+ int lastIndexOf (const char str[], int fromIndex);
+
+private:
+ char *value;
+ int count;
+ int maxCapacity;
+};
+
+#endif /* _StringBuilder_h */
diff --git a/gprofng/src/StringMap.h b/gprofng/src/StringMap.h
new file mode 100644
index 0000000..31898f4
--- /dev/null
+++ b/gprofng/src/StringMap.h
@@ -0,0 +1,238 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * String Map implementation.
+ */
+
+#ifndef _DBE_STRINGMAP_H
+#define _DBE_STRINGMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+#include <util.h>
+
+template <typename Value_t>
+class StringMap : public Map<const char*, Value_t>
+{
+public:
+
+ StringMap (int htable_size = 1024, int chunk_size = 16384);
+ ~StringMap ();
+ void clear ();
+ void put (const char *key, Value_t val);
+ Value_t get (const char *key);
+ Value_t get (const char *key, typename Map<const char*, Value_t>::Relation rel);
+ Value_t remove (const char*);
+ Vector<const char*> *keySet ();
+ Vector<Value_t> *values ();
+
+private:
+
+ static unsigned
+ hash (const char *key)
+ {
+ return (unsigned) crc64 (key, strlen (key));
+ }
+
+ struct Entry
+ {
+ char *key;
+ Value_t val;
+ };
+
+ int CHUNK_SIZE, HTABLE_SIZE;
+ int entries;
+ int nchunks;
+ Entry **chunks;
+ Vector<Entry*> *index;
+ Entry **hashTable;
+};
+
+template <typename Value_t>
+StringMap<Value_t>::StringMap (int htable_size, int chunk_size)
+{
+ HTABLE_SIZE = htable_size;
+ CHUNK_SIZE = chunk_size;
+ entries = 0;
+ nchunks = 0;
+ chunks = NULL;
+ index = new Vector<Entry*>;
+ hashTable = new Entry*[HTABLE_SIZE];
+ for (int i = 0; i < HTABLE_SIZE; i++)
+ hashTable[i] = NULL;
+}
+
+template <typename Value_t>
+StringMap<Value_t>::~StringMap ()
+{
+ for (int i = 0; i < entries; ++i)
+ {
+ Entry *entry = index->fetch (i);
+ free (entry->key);
+ }
+ for (int i = 0; i < nchunks; i++)
+ delete[] chunks[i];
+ delete[] chunks;
+ delete index;
+ delete[] hashTable;
+}
+
+template <typename Value_t>
+void
+StringMap<Value_t>::clear ()
+{
+ for (int i = 0; i < entries; ++i)
+ {
+ Entry *entry = index->fetch (i);
+ free (entry->key);
+ }
+ entries = 0;
+ index->reset ();
+ for (int i = 0; i < HTABLE_SIZE; i++)
+ hashTable[i] = NULL;
+}
+
+template <typename Value_t>
+void
+StringMap<Value_t>::put (const char *key, Value_t val)
+{
+ unsigned idx = hash (key) % HTABLE_SIZE;
+ Entry *entry = hashTable[idx];
+ if (entry && strcmp (entry->key, key) == 0)
+ {
+ entry->val = val;
+ return;
+ }
+ int lo = 0;
+ int hi = entries - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ entry = index->fetch (md);
+ int cmp = strcmp (entry->key, key);
+ if (cmp < 0)
+ lo = md + 1;
+ else if (cmp > 0)
+ hi = md - 1;
+ else
+ {
+ entry->val = val;
+ return;
+ }
+ }
+ if (entries >= nchunks * CHUNK_SIZE)
+ {
+ nchunks++;
+
+ // Reallocate Entry chunk array
+ Entry **new_chunks = new Entry*[nchunks];
+ for (int i = 0; i < nchunks - 1; i++)
+ new_chunks[i] = chunks[i];
+ delete[] chunks;
+ chunks = new_chunks;
+
+ // Allocate new chunk for entries.
+ chunks[nchunks - 1] = new Entry[CHUNK_SIZE];
+ }
+ entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE];
+ entry->key = strdup (key);
+ entry->val = val;
+ index->insert (lo, entry);
+ hashTable[idx] = entry;
+ entries++;
+}
+
+template <typename Value_t>
+Value_t
+StringMap<Value_t>::get (const char *key)
+{
+ unsigned idx = hash (key) % HTABLE_SIZE;
+ Entry *entry = hashTable[idx];
+ if (entry && strcmp (entry->key, key) == 0)
+ return entry->val;
+ int lo = 0;
+ int hi = entries - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ entry = index->fetch (md);
+ int cmp = strcmp (entry->key, key);
+ if (cmp < 0)
+ lo = md + 1;
+ else if (cmp > 0)
+ hi = md - 1;
+ else
+ {
+ hashTable[idx] = entry;
+ return entry->val;
+ }
+ }
+ return (Value_t) 0;
+}
+
+template <typename Value_t>
+Value_t
+StringMap<Value_t>::get (const char *key, typename Map<const char*,
+ Value_t>::Relation rel)
+{
+ if (rel != Map<const char*, Value_t>::REL_EQ)
+ return (Value_t) 0;
+ return get (key);
+}
+
+template <typename Value_t>
+Value_t
+StringMap<Value_t>::remove (const char*)
+{
+ // Not implemented
+ if (1)
+ assert (0);
+ return (Value_t) 0;
+}
+
+template <typename Value_t>
+Vector<Value_t> *
+StringMap<Value_t>::values ()
+{
+ Vector<Value_t> *vals = new Vector<Value_t>(entries);
+ for (int i = 0; i < entries; ++i)
+ {
+ Entry *entry = index->fetch (i);
+ vals->append (entry->val);
+ }
+ return vals;
+}
+
+template <typename Value_t>
+Vector<const char*> *
+StringMap<Value_t>::keySet ()
+{
+ Vector<const char*> *keys = new Vector<const char*>(entries);
+ for (int i = 0; i < entries; ++i)
+ {
+ Entry *entry = index->fetch (i);
+ keys->append (entry->key);
+ }
+ return keys;
+}
+
+#endif
diff --git a/gprofng/src/Table.cc b/gprofng/src/Table.cc
new file mode 100644
index 0000000..afe44bd
--- /dev/null
+++ b/gprofng/src/Table.cc
@@ -0,0 +1,1687 @@
+/* Copyright (C) 2021 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 <stdio.h>
+
+#include "IndexMap2D.h"
+#include "DbeSession.h"
+#include "FilterExp.h"
+#include "Table.h"
+#include "util.h"
+#include "i18n.h"
+
+char *
+get_prof_data_type_name (int t)
+{
+ switch (t)
+ {
+ case DATA_SAMPLE: return NTXT("PROFDATA_TYPE_SAMPLE");
+ case DATA_GCEVENT: return NTXT("PROFDATA_TYPE_GCEVENT");
+ case DATA_HEAPSZ: return NTXT("PROFDATA_TYPE_HEAPSZ");
+ case DATA_CLOCK: return NTXT("PROFDATA_TYPE_CLOCK");
+ case DATA_HWC: return NTXT("PROFDATA_TYPE_HWC");
+ case DATA_SYNCH: return NTXT("PROFDATA_TYPE_SYNCH");
+ case DATA_HEAP: return NTXT("PROFDATA_TYPE_HEAP");
+ case DATA_OMP: return NTXT("PROFDATA_TYPE_OMP");
+ case DATA_OMP2: return NTXT("PROFDATA_TYPE_OMP2");
+ case DATA_OMP3: return NTXT("PROFDATA_TYPE_OMP3");
+ case DATA_OMP4: return NTXT("PROFDATA_TYPE_OMP4");
+ case DATA_OMP5: return NTXT("PROFDATA_TYPE_OMP5");
+ case DATA_IOTRACE: return NTXT("PROFDATA_TYPE_IOTRACE");
+ default: abort ();
+ return NTXT ("PROFDATA_TYPE_ERROR");
+ }
+}
+
+char *
+get_prof_data_type_uname (int t)
+{
+ switch (t)
+ {
+ case DATA_SAMPLE: return GTXT("Process-wide Resource Utilization");
+ case DATA_GCEVENT: return GTXT("Java Garbage Collection Events");
+ case DATA_HEAPSZ: return GTXT("Heap Size");
+ case DATA_CLOCK: return GTXT("Clock Profiling");
+ case DATA_HWC: return GTXT("HW Counter Profiling");
+ case DATA_SYNCH: return GTXT("Synchronization Tracing");
+ case DATA_HEAP: return GTXT("Heap Tracing");
+ case DATA_OMP: return GTXT("OpenMP Profiling");
+ case DATA_OMP2: return GTXT("OpenMP Profiling");
+ case DATA_OMP3: return GTXT("OpenMP Profiling");
+ case DATA_OMP4: return GTXT("OpenMP Profiling");
+ case DATA_OMP5: return GTXT("OpenMP Profiling");
+ case DATA_IOTRACE: return GTXT("IO Tracing");
+ default: abort ();
+ return NTXT ("PROFDATA_TYPE_ERROR");
+ }
+}
+
+int assert_level = 0; // set to 1 to bypass problematic asserts
+
+#define ASSERT_SKIP (assert_level)
+
+/*
+ * class PropDescr
+ */
+
+PropDescr::PropDescr (int _propID, const char *_name)
+{
+ propID = _propID;
+ name = strdup (_name ? _name : NTXT (""));
+ uname = NULL;
+ vtype = TYPE_NONE;
+ flags = 0;
+ stateNames = NULL;
+ stateUNames = NULL;
+}
+
+PropDescr::~PropDescr ()
+{
+ free (name);
+ free (uname);
+ if (stateNames)
+ {
+ stateNames->destroy ();
+ delete stateNames;
+ }
+ if (stateUNames)
+ {
+ stateUNames->destroy ();
+ delete stateUNames;
+ }
+}
+
+void
+PropDescr::addState (int value, const char *stname, const char *stuname)
+{
+ if (value < 0 || stname == NULL)
+ return;
+ if (stateNames == NULL)
+ stateNames = new Vector<char*>;
+ stateNames->store (value, strdup (stname));
+ if (stateUNames == NULL)
+ stateUNames = new Vector<char*>;
+ stateUNames->store (value, strdup (stuname));
+}
+
+char *
+PropDescr::getStateName (int value)
+{
+ if (stateNames && value >= 0 && value < stateNames->size ())
+ return stateNames->fetch (value);
+ return NULL;
+}
+
+char *
+PropDescr::getStateUName (int value)
+{
+ if (stateUNames && value >= 0 && value < stateUNames->size ())
+ return stateUNames->fetch (value);
+ return NULL;
+}
+
+/*
+ * class FieldDescr
+ */
+
+FieldDescr::FieldDescr (int _propID, const char *_name)
+{
+ propID = _propID;
+ name = _name ? strdup (_name) : NULL;
+ offset = 0;
+ vtype = TYPE_NONE;
+ format = NULL;
+}
+
+FieldDescr::~FieldDescr ()
+{
+ free (name);
+ free (format);
+}
+
+/*
+ * class PacketDescriptor
+ */
+
+PacketDescriptor::PacketDescriptor (DataDescriptor *_ddscr)
+{
+ ddscr = _ddscr;
+ fields = new Vector<FieldDescr*>;
+}
+
+PacketDescriptor::~PacketDescriptor ()
+{
+ fields->destroy ();
+ delete fields;
+}
+
+void
+PacketDescriptor::addField (FieldDescr *fldDscr)
+{
+ if (fldDscr == NULL)
+ return;
+ fields->append (fldDscr);
+}
+
+/*
+ * class Data
+ */
+
+/* Check compatibility between Datum and Data */
+static void
+checkCompatibility (VType_type v1, VType_type v2)
+{
+ switch (v1)
+ {
+ case TYPE_NONE:
+ case TYPE_STRING:
+ case TYPE_DOUBLE:
+ case TYPE_OBJ:
+ case TYPE_DATE:
+ assert (v1 == v2);
+ break;
+ case TYPE_INT32:
+ case TYPE_UINT32:
+ assert (v2 == TYPE_INT32 ||
+ v2 == TYPE_UINT32);
+ break;
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ assert (v2 == TYPE_INT64 ||
+ v2 == TYPE_UINT64);
+ break;
+ default:
+ assert (0);
+ }
+}
+
+class DataINT32 : public Data
+{
+public:
+
+ DataINT32 ()
+ {
+ data = new Vector<int32_t>;
+ }
+
+ virtual
+ ~DataINT32 ()
+ {
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_INT32;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long i)
+ {
+ return (int) data->fetch (i);
+ }
+
+ virtual unsigned long long
+ fetchULong (long i)
+ {
+ return (unsigned long long) data->fetch (i);
+ }
+
+ virtual long long
+ fetchLong (long i)
+ {
+ return (long long) data->fetch (i);
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return dbe_sprintf (NTXT ("%d"), data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long i)
+ {
+ return (double) data->fetch (i);
+ }
+
+ virtual void *
+ fetchObject (long)
+ {
+ assert (ASSERT_SKIP);
+ return NULL;
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->i);
+ }
+
+ virtual void
+ setValue (long idx, uint64_t val)
+ {
+ data->store (idx, (int32_t) val);
+ }
+
+ virtual void
+ setObjValue (long, void*)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+
+ virtual int
+ cmpValues (long idx1, long idx2)
+ {
+ int32_t i1 = data->fetch (idx1);
+ int32_t i2 = data->fetch (idx2);
+ return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+ }
+
+ virtual int
+ cmpDatumValue (long idx, const Datum *val)
+ {
+ int32_t i1 = data->fetch (idx);
+ int32_t i2 = val->i;
+ return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+ }
+
+private:
+ Vector<int32_t> *data;
+};
+
+class DataUINT32 : public Data
+{
+public:
+
+ DataUINT32 ()
+ {
+ data = new Vector<uint32_t>;
+ }
+
+ virtual
+ ~DataUINT32 ()
+ {
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_UINT32;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long i)
+ {
+ return (int) data->fetch (i);
+ }
+
+ virtual unsigned long long
+ fetchULong (long i)
+ {
+ return (unsigned long long) data->fetch (i);
+ }
+
+ virtual long long
+ fetchLong (long i)
+ {
+ return (long long) data->fetch (i);
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return dbe_sprintf (NTXT ("%u"), data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long i)
+ {
+ return (double) data->fetch (i);
+ }
+
+ virtual void *
+ fetchObject (long)
+ {
+ assert (ASSERT_SKIP);
+ return NULL;
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->i);
+ }
+
+ virtual void
+ setValue (long idx, uint64_t val)
+ {
+ data->store (idx, (uint32_t) val);
+ }
+
+ virtual void
+ setObjValue (long, void*)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+
+ virtual int
+ cmpValues (long idx1, long idx2)
+ {
+ uint32_t u1 = data->fetch (idx1);
+ uint32_t u2 = data->fetch (idx2);
+ return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+ }
+
+ virtual int
+ cmpDatumValue (long idx, const Datum *val)
+ {
+ uint32_t u1 = data->fetch (idx);
+ uint32_t u2 = (uint32_t) val->i;
+ return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+ }
+
+private:
+ Vector<uint32_t> *data;
+};
+
+class DataINT64 : public Data
+{
+public:
+
+ DataINT64 ()
+ {
+ data = new Vector<int64_t>;
+ }
+
+ virtual
+ ~DataINT64 ()
+ {
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_INT64;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long i)
+ {
+ return (int) data->fetch (i);
+ }
+
+ virtual unsigned long long
+ fetchULong (long i)
+ {
+ return (unsigned long long) data->fetch (i);
+ }
+
+ virtual long long
+ fetchLong (long i)
+ {
+ return (long long) data->fetch (i);
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return dbe_sprintf (NTXT ("%lld"), (long long) data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long i)
+ {
+ return (double) data->fetch (i);
+ }
+
+ virtual void *
+ fetchObject (long)
+ {
+ assert (ASSERT_SKIP);
+ return NULL;
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->ll);
+ }
+
+ virtual void
+ setValue (long idx, uint64_t val)
+ {
+ data->store (idx, (int64_t) val);
+ }
+
+ virtual void
+ setObjValue (long, void*)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+
+ virtual int
+ cmpValues (long idx1, long idx2)
+ {
+ int64_t i1 = data->fetch (idx1);
+ int64_t i2 = data->fetch (idx2);
+ return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+ }
+
+ virtual int
+ cmpDatumValue (long idx, const Datum *val)
+ {
+ int64_t i1 = data->fetch (idx);
+ int64_t i2 = val->ll;
+ return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+ }
+
+private:
+ Vector<int64_t> *data;
+};
+
+class DataUINT64 : public Data
+{
+public:
+
+ DataUINT64 ()
+ {
+ data = new Vector<uint64_t>;
+ }
+
+ virtual
+ ~DataUINT64 ()
+ {
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_UINT64;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long i)
+ {
+ return (int) data->fetch (i);
+ }
+
+ virtual unsigned long long
+ fetchULong (long i)
+ {
+ return (unsigned long long) data->fetch (i);
+ }
+
+ virtual long long
+ fetchLong (long i)
+ {
+ return (long long) data->fetch (i);
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return dbe_sprintf (NTXT ("%llu"), (long long) data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long i)
+ {
+ return (double) data->fetch (i);
+ }
+
+ virtual void *
+ fetchObject (long)
+ {
+ assert (ASSERT_SKIP);
+ return NULL;
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->ll);
+ }
+
+ virtual void
+ setValue (long idx, uint64_t val)
+ {
+ data->store (idx, val);
+ }
+
+ virtual void
+ setObjValue (long, void*)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+
+ virtual int
+ cmpValues (long idx1, long idx2)
+ {
+ uint64_t u1 = data->fetch (idx1);
+ uint64_t u2 = data->fetch (idx2);
+ return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+ }
+
+ virtual int
+ cmpDatumValue (long idx, const Datum *val)
+ {
+ uint64_t u1 = data->fetch (idx);
+ uint64_t u2 = (uint64_t) val->ll;
+ return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+ }
+
+private:
+ Vector<uint64_t> *data;
+};
+
+class DataOBJECT : public Data
+{
+public:
+
+ DataOBJECT ()
+ {
+ dtype = TYPE_OBJ;
+ data = new Vector<void*>;
+ }
+
+ DataOBJECT (VType_type _dtype)
+ {
+ dtype = _dtype;
+ data = new Vector<void*>;
+ }
+
+ virtual
+ ~DataOBJECT ()
+ {
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return dtype;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long)
+ {
+ assert (ASSERT_SKIP);
+ return 0;
+ }
+
+ virtual unsigned long long
+ fetchULong (long)
+ {
+ assert (ASSERT_SKIP);
+ return 0LL;
+ }
+
+ virtual long long
+ fetchLong (long)
+ {
+ assert (ASSERT_SKIP);
+ return 0LL;
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return dbe_sprintf (NTXT ("%lu"), (unsigned long) data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long)
+ {
+ assert (ASSERT_SKIP);
+ return 0.0;
+ }
+
+ virtual void *
+ fetchObject (long i)
+ {
+ return data->fetch (i);
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->p);
+ }
+
+ virtual void
+ setValue (long, uint64_t)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+
+ virtual void
+ setObjValue (long idx, void *p)
+ {
+ data->store (idx, p);
+ }
+
+ virtual int
+ cmpValues (long, long)
+ {
+ return 0;
+ }
+
+ virtual int
+ cmpDatumValue (long, const Datum *)
+ {
+ return 0;
+ }
+
+private:
+ VType_type dtype;
+ Vector<void*> *data;
+};
+
+class DataSTRING : public Data
+{
+public:
+
+ DataSTRING ()
+ {
+ data = new Vector<char*>;
+ }
+
+ virtual
+ ~DataSTRING ()
+ {
+ data->destroy ();
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_STRING;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long)
+ {
+ return 0;
+ }
+
+ virtual unsigned long long
+ fetchULong (long)
+ {
+ return 0LL;
+ }
+
+ virtual long long
+ fetchLong (long)
+ {
+ return 0LL;
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return strdup (data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long)
+ {
+ return 0.0;
+ }
+
+ virtual void *
+ fetchObject (long i)
+ {
+ return data->fetch (i);
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->l);
+ }
+
+ virtual void
+ setValue (long, uint64_t)
+ {
+ return;
+ }
+
+ virtual void
+ setObjValue (long idx, void *p)
+ {
+ data->store (idx, (char*) p);
+ }
+
+ virtual int
+ cmpValues (long, long)
+ {
+ return 0;
+ }
+
+ virtual int
+ cmpDatumValue (long, const Datum *)
+ {
+ return 0;
+ }
+
+private:
+ Vector<char*> *data;
+};
+
+class DataDOUBLE : public Data
+{
+public:
+
+ DataDOUBLE ()
+ {
+ data = new Vector<double>;
+ }
+
+ virtual
+ ~DataDOUBLE ()
+ {
+ delete data;
+ }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_DOUBLE;
+ }
+
+ virtual void
+ reset ()
+ {
+ data->reset ();
+ }
+
+ virtual long
+ getSize ()
+ {
+ return data->size ();
+ }
+
+ virtual int
+ fetchInt (long i)
+ {
+ return (int) data->fetch (i);
+ }
+
+ virtual unsigned long long
+ fetchULong (long i)
+ {
+ return (unsigned long long) data->fetch (i);
+ }
+
+ virtual long long
+ fetchLong (long i)
+ {
+ return (long long) data->fetch (i);
+ }
+
+ virtual char *
+ fetchString (long i)
+ {
+ return dbe_sprintf (NTXT ("%f"), data->fetch (i));
+ }
+
+ virtual double
+ fetchDouble (long i)
+ {
+ return data->fetch (i);
+ }
+
+ virtual void
+ setDatumValue (long idx, const Datum *val)
+ {
+ data->store (idx, val->d);
+ }
+
+ virtual void
+ setValue (long idx, uint64_t val)
+ {
+ data->store (idx, (double) val);
+ }
+
+ virtual void
+ setObjValue (long, void*)
+ {
+ return;
+ }
+
+ virtual void *
+ fetchObject (long)
+ {
+ return NULL;
+ }
+
+ virtual int
+ cmpValues (long idx1, long idx2)
+ {
+ double d1 = data->fetch (idx1);
+ double d2 = data->fetch (idx2);
+ return d1 < d2 ? -1 : d1 > d2 ? 1 : 0;
+ }
+
+ virtual int
+ cmpDatumValue (long idx, const Datum *val)
+ {
+ double d1 = data->fetch (idx);
+ double d2 = val->d;
+ return d1 < d2 ? -1 : d1 > d2 ? 1 : 0;
+ }
+
+private:
+ Vector<double> *data;
+};
+
+Data *
+Data::newData (VType_type vtype)
+{
+ switch (vtype)
+ {
+ case TYPE_INT32:
+ return new DataINT32;
+ case TYPE_UINT32:
+ return new DataUINT32;
+ case TYPE_INT64:
+ return new DataINT64;
+ case TYPE_UINT64:
+ return new DataUINT64;
+ case TYPE_OBJ:
+ return new DataOBJECT;
+ case TYPE_STRING:
+ return new DataSTRING;
+ case TYPE_DOUBLE:
+ return new DataDOUBLE;
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * class DataDescriptor
+ */
+DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname,
+ int _flags)
+{
+ isMaster = true;
+ id = _id;
+ name = _name ? strdup (_name) : strdup (NTXT (""));
+ uname = _uname ? strdup (_uname) : strdup (NTXT (""));
+ flags = _flags;
+
+ // master data, shared with reference copies:
+ master_size = 0;
+ master_resolveFrameInfoDone = false;
+ props = new Vector<PropDescr*>;
+ data = new Vector<Data*>;
+ setsTBR = new Vector<Vector<long long>*>;
+
+ // master references point to self:
+ ref_size = &master_size;
+ ref_resolveFrameInfoDone = &master_resolveFrameInfoDone;
+}
+
+DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname,
+ DataDescriptor* dDscr)
+{
+ isMaster = false;
+ id = _id;
+ name = _name ? strdup (_name) : strdup (NTXT (""));
+ uname = _uname ? strdup (_uname) : strdup (NTXT (""));
+ flags = dDscr->flags;
+
+ // references point to master DataDescriptor
+ ref_size = &dDscr->master_size;
+ ref_resolveFrameInfoDone = &dDscr->master_resolveFrameInfoDone;
+ props = dDscr->props;
+ data = dDscr->data;
+ setsTBR = dDscr->setsTBR;
+
+ // data that should never be accessed in reference copy
+ master_size = -1;
+ master_resolveFrameInfoDone = false;
+}
+
+DataDescriptor::~DataDescriptor ()
+{
+ free (name);
+ free (uname);
+ if (!isMaster)
+ return;
+ props->destroy ();
+ delete props;
+ data->destroy ();
+ delete data;
+ setsTBR->destroy ();
+ delete setsTBR;
+}
+
+void
+DataDescriptor::reset ()
+{
+ if (!isMaster)
+ return;
+ for (int i = 0; i < data->size (); i++)
+ {
+ Data *d = data->fetch (i);
+ if (d != NULL)
+ d->reset ();
+ Vector<long long> *set = setsTBR->fetch (i);
+ if (set != NULL)
+ set->reset ();
+ }
+ master_size = 0;
+}
+
+PropDescr *
+DataDescriptor::getProp (int prop_id)
+{
+ for (int i = 0; i < props->size (); i++)
+ {
+ PropDescr *propDscr = props->fetch (i);
+ if (propDscr->propID == prop_id)
+ return propDscr;
+ }
+ return NULL;
+}
+
+Data *
+DataDescriptor::getData (int prop_id)
+{
+ if (prop_id < 0 || prop_id >= data->size ())
+ return NULL;
+ return data->fetch (prop_id);
+}
+
+void
+DataDescriptor::addProperty (PropDescr *propDscr)
+{
+ if (propDscr == NULL)
+ return;
+ if (propDscr->propID < 0)
+ return;
+ PropDescr *oldProp = getProp (propDscr->propID);
+ if (oldProp != NULL)
+ {
+ checkCompatibility (propDscr->vtype, oldProp->vtype); //YXXX depends on experiment correctness
+ delete propDscr;
+ return;
+ }
+ props->append (propDscr);
+ data->store (propDscr->propID, Data::newData (propDscr->vtype));
+ setsTBR->store (propDscr->propID, NULL);
+}
+
+long
+DataDescriptor::addRecord ()
+{
+ if (!isMaster)
+ return -1;
+ return master_size++;
+}
+
+static void
+checkEntity (Vector<long long> *set, long long val)
+{
+ // Binary search
+ int lo = 0;
+ int hi = set->size () - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ long long ent = set->fetch (md);
+ if (ent < val)
+ lo = md + 1;
+ else if (ent > val)
+ hi = md - 1;
+ else
+ return;
+ }
+ set->insert (lo, val);
+}
+
+void
+DataDescriptor::setDatumValue (int prop_id, long idx, const Datum *val)
+{
+ if (idx >= *ref_size)
+ return;
+ Data *d = getData (prop_id);
+ if (d != NULL)
+ {
+ VType_type datum_type = val->type;
+ VType_type data_type = d->type ();
+ checkCompatibility (datum_type, data_type);
+ d->setDatumValue (idx, val);
+ Vector<long long> *set = setsTBR->fetch (prop_id);
+ if (set != NULL)// Sets are maintained
+ checkEntity (set, d->fetchLong (idx));
+ }
+}
+
+void
+DataDescriptor::setValue (int prop_id, long idx, uint64_t val)
+{
+ if (idx >= *ref_size)
+ return;
+ Data *d = getData (prop_id);
+ if (d != NULL)
+ {
+ d->setValue (idx, val);
+ Vector<long long> *set = setsTBR->fetch (prop_id);
+ if (set != NULL)// Sets are maintained
+ checkEntity (set, d->fetchLong (idx));
+ }
+}
+
+void
+DataDescriptor::setObjValue (int prop_id, long idx, void *val)
+{
+ if (idx >= *ref_size)
+ return;
+ Data *d = getData (prop_id);
+ if (d != NULL)
+ d->setObjValue (idx, val);
+}
+
+DataView *
+DataDescriptor::createView ()
+{
+ return new DataView (this);
+}
+
+DataView *
+DataDescriptor::createImmutableView ()
+{
+ return new DataView (this, DataView::DV_IMMUTABLE);
+}
+
+DataView *
+DataDescriptor::createExtManagedView ()
+{
+ return new DataView (this, DataView::DV_EXT_MANAGED);
+}
+
+int
+DataDescriptor::getIntValue (int prop_id, long idx)
+{
+ Data *d = getData (prop_id);
+ if (d == NULL || idx >= d->getSize ())
+ return 0;
+ return d->fetchInt (idx);
+}
+
+unsigned long long
+DataDescriptor::getULongValue (int prop_id, long idx)
+{
+ Data *d = getData (prop_id);
+ if (d == NULL || idx >= d->getSize ())
+ return 0L;
+ return d->fetchULong (idx);
+}
+
+long long
+DataDescriptor::getLongValue (int prop_id, long idx)
+{
+ Data *d = getData (prop_id);
+ if (d == NULL || idx >= d->getSize ())
+ return 0L;
+ return d->fetchLong (idx);
+}
+
+void *
+DataDescriptor::getObjValue (int prop_id, long idx)
+{
+ Data *d = getData (prop_id);
+ if (d == NULL || idx >= d->getSize ())
+ return NULL;
+ return d->fetchObject (idx);
+}
+
+static int
+pcmp (const void *p1, const void *p2, const void *arg)
+{
+ long idx1 = *(long*) p1; // index1 into Data
+ long idx2 = *(long*) p2; // index2 into Data
+ for (Data **dsorted = (Data**) arg; *dsorted != DATA_SORT_EOL; dsorted++)
+ {
+ Data *data = *dsorted;
+ if (data == NULL)// sort property not in this data, skip this criteria
+ continue;
+ int res = data->cmpValues (idx1, idx2);
+ if (res)
+ return res;
+ }
+ // Provide stable sort
+ return idx1 < idx2 ? -1 : idx1 > idx2 ? 1 : 0;
+}
+
+Vector<long long> *
+DataDescriptor::getSet (int prop_id)
+{
+ if (prop_id < 0 || prop_id >= setsTBR->size ())
+ return NULL;
+ Vector<long long> *set = setsTBR->fetch (prop_id);
+ if (set != NULL)
+ return set;
+
+ Data *d = getData (prop_id);
+ if (d == NULL)
+ return NULL;
+ set = new Vector<long long>;
+ for (long i = 0; i<*ref_size; ++i)
+ checkEntity (set, d->fetchLong (i));
+ setsTBR->store (prop_id, set);
+
+ return set;
+}
+
+/*
+ * class DataView
+ */
+DataView::DataView (DataDescriptor *_ddscr)
+{
+ init (_ddscr, DV_NORMAL);
+}
+
+DataView::DataView (DataDescriptor *_ddscr, DataViewType _type)
+{
+ init (_ddscr, _type);
+}
+
+void
+DataView::init (DataDescriptor *_ddscr, DataViewType _type)
+{
+ ddscr = _ddscr;
+ type = _type;
+ switch (type)
+ {
+ case DV_IMMUTABLE:
+ ddsize = ddscr->getSize ();
+ index = NULL;
+ break;
+ case DV_NORMAL:
+ case DV_EXT_MANAGED:
+ ddsize = 0;
+ index = new Vector<long>;
+ break;
+ }
+ for (int ii = 0; ii < (MAX_SORT_DIMENSIONS + 1); ii++)
+ sortedBy[ii] = DATA_SORT_EOL;
+ filter = NULL;
+}
+
+DataView::~DataView ()
+{
+ delete filter;
+ delete index;
+}
+
+void
+DataView::appendDataDescriptorId (long pkt_id /* ddscr index */)
+{
+ if (type != DV_EXT_MANAGED)
+ return; // updates allowed only on externally managed DataViews
+ long curr_ddsize = ddscr->getSize ();
+ if (pkt_id < 0 || pkt_id >= curr_ddsize)
+ return; // error!
+ index->append (pkt_id);
+}
+
+void
+DataView::setDataDescriptorValue (int prop_id, long pkt_id, uint64_t val)
+{
+ ddscr->setValue (prop_id, pkt_id, val);
+}
+
+long long
+DataView::getDataDescriptorValue (int prop_id, long pkt_id)
+{
+ return ddscr->getLongValue (prop_id, pkt_id);
+}
+
+Vector<PropDescr*>*
+DataView::getProps ()
+{
+ return ddscr->getProps ();
+};
+
+PropDescr*
+DataView::getProp (int prop_id)
+{
+ return ddscr->getProp (prop_id);
+};
+
+void
+DataView::filter_in_chunks (fltr_dbe_ctx *dctx)
+{
+ Expression::Context *e_ctx = new Expression::Context (dctx->fltr->ctx->dbev, dctx->fltr->ctx->exp);
+ Expression *n_expr = dctx->fltr->expr->copy ();
+ bool noParFilter = dctx->fltr->noParFilter;
+ FilterExp *nFilter = new FilterExp (n_expr, e_ctx, noParFilter);
+ long iter = dctx->begin;
+ long end = dctx->end;
+ long orig_ddsize = dctx->orig_ddsize;
+ while (iter < end)
+ {
+ nFilter->put (dctx->tmpView, iter);
+ if (nFilter->passes ())
+ dctx->idxArr[iter - orig_ddsize] = 1;
+ iter += 1;
+ }
+ delete nFilter;
+}
+
+bool
+DataView::checkUpdate ()
+{
+ long newSize = ddscr->getSize ();
+ if (ddsize == newSize)
+ return false;
+ if (index == NULL)
+ return false;
+ if (type == DV_EXT_MANAGED)
+ return false;
+ bool updated = false;
+ if (filter)
+ {
+ DataView *tmpView = ddscr->createImmutableView ();
+ assert (tmpView->getSize () == newSize);
+ while (ddsize < newSize)
+ {
+ filter->put (tmpView, ddsize);
+ if (filter->passes ())
+ index->append (ddsize);
+ ddsize += 1;
+ }
+ delete tmpView;
+ return updated;
+ }
+ while (ddsize < newSize)
+ {
+ index->append (ddsize);
+ updated = true;
+ ddsize += 1;
+ }
+ return updated;
+}
+
+long
+DataView::getSize ()
+{
+ if (checkUpdate () && sortedBy[0] != DATA_SORT_EOL)
+ // note: after new filter is set, getSize() incurs cost of
+ // sorting even if caller isn't interested in sort
+ index->sort ((CompareFunc) pcmp, sortedBy);
+
+ if (index == NULL)
+ return ddscr->getSize ();
+ return index->size ();
+}
+
+void
+DataView::setDatumValue (int prop_id, long idx, const Datum *val)
+{
+ ddscr->setDatumValue (prop_id, getIdByIdx (idx), val);
+}
+
+void
+DataView::setValue (int prop_id, long idx, uint64_t val)
+{
+ ddscr->setValue (prop_id, getIdByIdx (idx), val);
+}
+
+void
+DataView::setObjValue (int prop_id, long idx, void *val)
+{
+ ddscr->setObjValue (prop_id, getIdByIdx (idx), val);
+}
+
+int
+DataView::getIntValue (int prop_id, long idx)
+{
+ return ddscr->getIntValue (prop_id, getIdByIdx (idx));
+}
+
+unsigned long long
+DataView::getULongValue (int prop_id, long idx)
+{
+ return ddscr->getULongValue (prop_id, getIdByIdx (idx));
+}
+
+long long
+DataView::getLongValue (int prop_id, long idx)
+{
+ return ddscr->getLongValue (prop_id, getIdByIdx (idx));
+}
+
+void *
+DataView::getObjValue (int prop_id, long idx)
+{
+ return ddscr->getObjValue (prop_id, getIdByIdx (idx));
+}
+
+void
+DataView::sort (const int props[], int prop_count)
+{
+ if (index == NULL)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+ assert (prop_count >= 0 && prop_count < MAX_SORT_DIMENSIONS);
+ bool sort_changed = false; // see if sort has changed...
+ for (int ii = 0; ii <= prop_count; ii++)
+ { // sortedBy size is prop_count+1
+ Data *data;
+ if (ii == prop_count)
+ data = DATA_SORT_EOL; // special end of array marker
+ else
+ data = ddscr->getData (props[ii]);
+ if (sortedBy[ii] != data)
+ {
+ sortedBy[ii] = data;
+ sort_changed = true;
+ }
+ }
+ if (!checkUpdate () && !sort_changed)
+ return;
+ index->sort ((CompareFunc) pcmp, sortedBy);
+}
+
+void
+DataView::sort (int prop0)
+{
+ sort (&prop0, 1);
+}
+
+void
+DataView::sort (int prop0, int prop1)
+{
+ int props[2] = {prop0, prop1};
+ sort (props, 2);
+}
+
+void
+DataView::sort (int prop0, int prop1, int prop2)
+{
+ int props[3] = {prop0, prop1, prop2};
+ sort (props, 3);
+}
+
+void
+DataView::setFilter (FilterExp *f)
+{
+ if (index == NULL)
+ {
+ assert (ASSERT_SKIP);
+ return;
+ }
+ delete filter;
+ filter = f;
+ index->reset ();
+ ddsize = 0;
+ checkUpdate ();
+}
+
+long
+DataView::getIdByIdx (long idx)
+{
+ if (index == NULL)
+ return idx;
+ return index->fetch (idx);
+}
+
+static int
+tvalcmp (long data_id, const Datum valColumns[], Data *sortedBy[])
+{
+ for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++)
+ {
+ if (sortedBy[ii] == DATA_SORT_EOL)
+ break;
+ Data *d = sortedBy[ii];
+ if (d == NULL)// property doesn't exist in data; compare always matches
+ continue;
+ const Datum *tvalue = &valColumns[ii];
+ int res = d->cmpDatumValue (data_id, tvalue);
+ if (res)
+ return res;
+ }
+ return 0;
+}
+
+static void
+checkSortTypes (const Datum valColumns[], Data *sortedBy[])
+{
+#ifndef NDEBUG
+ for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++)
+ {
+ if (sortedBy[ii] == DATA_SORT_EOL)
+ break;
+ Data *d = sortedBy[ii];
+ if (d == NULL)// property doesn't exist in data; compare always matches
+ continue;
+ VType_type datum_type = valColumns[ii].type;
+ VType_type data_type = d->type ();
+ checkCompatibility (datum_type, data_type);
+ }
+#endif
+}
+
+bool
+DataView::idxRootDimensionsMatch (long idx, const Datum valColumns[])
+{
+ // compares idx vs. valColumns[] - If all dimensions match
+ // (except sort leaf), then the leaf value is valid => return true.
+ // Otherwise, return false.
+ checkSortTypes (valColumns, sortedBy);
+ if (idx < 0 || idx >= index->size ()) // fell off end of array
+ return false;
+ long data_id = index->fetch (idx);
+
+ // we will check all dimensions for a match except the "leaf" dimension
+ for (int ii = 0; ii < (MAX_SORT_DIMENSIONS - 1); ii++)
+ {
+ if (sortedBy[ii + 1] == DATA_SORT_EOL)
+ break; // we are at leaf dimension, don't care about it's value
+ if (sortedBy[ii] == DATA_SORT_EOL)
+ break; // end of list
+ Data *d = sortedBy[ii];
+ if (d == NULL) // property doesn't exist in data; compare always matches
+ continue;
+ const Datum *tvalue = &valColumns[ii];
+ int res = d->cmpDatumValue (data_id, tvalue);
+ if (res)
+ return false;
+ }
+ return true;
+}
+
+long
+DataView::getIdxByVals (const Datum valColumns[], Relation rel)
+{
+ // checks sortedBy[] columns for match; relation only used on last column
+ return getIdxByVals (valColumns, rel, -1, -1);
+}
+
+long
+DataView::getIdxByVals (const Datum valColumns[], Relation rel,
+ long minIdx, long maxIdx)
+{
+ // checks sortedBy[] columns for match; relation only used on last column
+ checkSortTypes (valColumns, sortedBy);
+ if (index == NULL || sortedBy[0] == DATA_SORT_EOL)
+ return -1;
+
+ long lo;
+ if (minIdx < 0)
+ lo = 0;
+ else
+ lo = minIdx;
+
+ long hi;
+ if (maxIdx < 0 || maxIdx >= index->size ())
+ hi = index->size () - 1;
+ else
+ hi = maxIdx;
+
+ long md = -1;
+ while (lo <= hi)
+ {
+ md = (lo + hi) / 2;
+ int cmp = tvalcmp (index->fetch (md), valColumns, sortedBy);
+ if (cmp < 0)
+ {
+ lo = md + 1;
+ continue;
+ }
+ else if (cmp > 0)
+ {
+ hi = md - 1;
+ continue;
+ }
+
+ // cmp == 0, we have an exact match
+ switch (rel)
+ {
+ case REL_LT:
+ hi = md - 1; // continue searching
+ break;
+ case REL_GT:
+ lo = md + 1; // continue searching
+ break;
+ case REL_LTEQ:
+ case REL_GTEQ:
+ case REL_EQ:
+ // note: "md" may not be deterministic if multiple matches exist
+ return md; // a match => done.
+ }
+ }
+
+ // no exact match found
+ switch (rel)
+ {
+ case REL_LT:
+ case REL_LTEQ:
+ md = hi;
+ break;
+ case REL_GT:
+ case REL_GTEQ:
+ md = lo;
+ break;
+ case REL_EQ:
+ return -1;
+ }
+ if (idxRootDimensionsMatch (md, valColumns))
+ return md;
+ return -1;
+}
+
+void
+DataView::removeDbeViewIdx (long idx)
+{
+ index->remove (idx);
+}
+
diff --git a/gprofng/src/Table.h b/gprofng/src/Table.h
new file mode 100644
index 0000000..48ce06a
--- /dev/null
+++ b/gprofng/src/Table.h
@@ -0,0 +1,618 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _TABLE_H
+#define _TABLE_H
+
+#include "vec.h"
+#include "Map2D.h"
+
+#include "dbe_structs.h"
+
+class FilterExp;
+struct PropDescr;
+struct FieldDescr;
+class PacketDescriptor;
+class DataDescriptor;
+class DataView;
+
+// Note: order must match VTYPE_TYPE_NAMES, below
+
+enum VType_type
+{
+ TYPE_NONE,
+ TYPE_INT32,
+ TYPE_UINT32,
+ TYPE_INT64,
+ TYPE_UINT64,
+ TYPE_STRING,
+ TYPE_DOUBLE,
+ TYPE_OBJ,
+ TYPE_DATE, // Used in FieldDescr only, mapped to TYPE_UINT64 in PropDescr
+ TYPE_BOOL, // Used only to describe filter props
+ TYPE_ENUM, // Used only to describe filter props
+
+ TYPE_LAST
+};
+
+#define VTYPE_TYPE_NAMES \
+{ \
+ NTXT("NONE"), \
+ NTXT("INT32"), \
+ NTXT("UINT32"), \
+ NTXT("INT64"), \
+ NTXT("UINT64"), \
+ NTXT("STRING"), \
+ NTXT("DOUBLE"), \
+ NTXT("OBJECT"), \
+ NTXT("DATE"), \
+ NTXT("BOOL"), \
+ NTXT("ENUM") \
+}
+
+// Note: order must match PROFDATA_TYPE_NAMES and PROFDATA_TYPE_UNAMES, below
+
+enum ProfData_type
+{ // a.k.a "data_id" (not the same as Pckt_type "kind")
+ DATA_SAMPLE, // Traditional collect "Samples"
+ DATA_GCEVENT, // Java Garbage Collection events
+ DATA_HEAPSZ, // heap size tracking based on heap tracing data
+ DATA_CLOCK, // clock profiling data
+ DATA_HWC, // hardware counter profiling data
+ DATA_SYNCH, // synchronization tracing data
+ DATA_HEAP, // heap tracing data
+ DATA_MPI, // MPI tracing data
+ DATA_RACE, // data race detection data
+ DATA_DLCK, // deadlock detection data
+ DATA_OMP, // OpenMP profiling data (fork events)
+ DATA_OMP2, // OpenMP profiling data (enter thread events)
+ DATA_OMP3, // OpenMP profiling data (enter task events)
+ DATA_OMP4, // OpenMP profiling data (parreg descriptions)
+ DATA_OMP5, // OpenMP profiling data (task descriptions)
+ DATA_IOTRACE, // IO tracing data
+ DATA_LAST
+};
+
+extern char *get_prof_data_type_name (int t);
+extern char *
+get_prof_data_type_uname (int t);
+
+enum Prop_type
+{
+ PROP_NONE,
+ // commonly used properties (libcollector modules, er_print)
+ PROP_ATSTAMP, // hrtime_t, Filter: system HRT timestamp;
+ // "Absolute TSTAMP"
+ PROP_ETSTAMP, // hrtime_t, Filter: nanoseconds from subexperiment start;
+ // "subExperiment TSTAMP"
+ PROP_TSTAMP, // hrtime_t, Packet: system HRT timestamp
+ // Filter: nanoseconds from founder start
+ PROP_THRID, // mapped to uint32_t by readPacket
+ PROP_LWPID, // mapped to uint32_t by readPacket
+ PROP_CPUID, // mapped to uint32_t by readPacket
+ PROP_FRINFO, // uint64_t frinfo
+ PROP_EVT_TIME, // hrtime_t Filter: Time delta
+ // If TSTAMP taken at end of event, EVT_TIME will be positive
+ // If TSTAMP taken at start of event, EVT_TIME will be negative
+ // Note: clock and hwc profile events set EVT_TIME=0
+ // except Solaris Microstate events where NTICK>1:
+ // These will use EVT_TIME=(NTICK-1)*<tick duration>
+
+ // DATA_SAMPLE
+ PROP_SAMPLE, // uint64_t sample number
+ PROP_SMPLOBJ, // Sample*
+
+ // DATA_GCEVENT
+ PROP_GCEVENT, // uint64_t event id
+ PROP_GCEVENTOBJ, // GCEvent*
+
+ // DATA_CLOCK
+ PROP_MSTATE, // unsigned ProfilePacket::mstate
+ PROP_NTICK, // unsigned ProfilePacket::value
+ PROP_OMPSTATE, // int ProfilePacket::ompstate
+ PROP_MPISTATE, // int ProfilePacket::mpistate
+
+ // DATA_SAMPLE // see PrUsage class, see PROP_MSTATE - TBR?
+ PROP_UCPU,
+ PROP_SCPU,
+ PROP_TRAP,
+ PROP_TFLT,
+ PROP_DFLT,
+ PROP_KFLT,
+ PROP_ULCK,
+ PROP_TSLP,
+ PROP_WCPU,
+ PROP_TSTP,
+
+ // DATA_SYNCH
+ PROP_SRQST, // hrtime_t SyncPacket::requested
+ PROP_SOBJ, // Vaddr SyncPacket::objp
+
+ // DATA_HWC
+ PROP_HWCTAG, // uint32_t HWCntrPacket::tag;
+ PROP_HWCINT, // uint64_t HWCntrPacket::interval
+ PROP_VADDR, // Vaddr HWCntrPacket::dbeVA->eaddr
+ PROP_PADDR, // Vaddr HWCntrPacket::dbePA->eaddr
+ PROP_HWCDOBJ, // DataObject* HWCntrPacket::dobj
+ PROP_VIRTPC, // Vaddr HWCntrPacket::eventVPC
+ PROP_PHYSPC, // Vaddr HWCntrPacket::eventPPC
+ PROP_EA_PAGESIZE, // uint32_t HWCntrPacket::ea_pagesize
+ PROP_PC_PAGESIZE, // uint32_t HWCntrPacket::pc_pagesize
+ PROP_EA_LGRP, // uint32_t HWCntrPacket::ea_lgrp
+ PROP_PC_LGRP, // uint32_t HWCntrPacket::pc_lgrp
+ PROP_LWP_LGRP_HOME, // uint32_t HWCntrPacket::lwp_lgrp_home
+ PROP_PS_LGRP_HOME, // uint32_t HWCntrPacket::ps_lgrp_home
+ PROP_MEM_LAT, // uint64_t HWCntrPacket::latency
+ PROP_MEM_SRC, // uint64_t HWCntrPacket::data_source
+
+ // DATA_HEAP
+ PROP_HTYPE, // Heap_type HeapPacket::mtype
+ PROP_HSIZE, // Size HeapPacket::size (bytes alloc'd by this event)
+ PROP_HVADDR, // Vaddr HeapPacket::vaddr
+ PROP_HOVADDR, // Vaddr HeapPacket::ovaddr
+ PROP_HLEAKED, // Size HeapPacket::leaked (net bytes leaked)
+ PROP_HMEM_USAGE, // Size heap memory usage
+ PROP_HFREED, // Size (bytes freed by this event)
+ PROP_HCUR_ALLOCS, // int64_t (net allocations running total. Recomputed after each filter)
+ PROP_HCUR_NET_ALLOC, // int64_t (net allocation for this packet. Recomputed after each filter)
+ PROP_HCUR_LEAKS, // Size (net leaks running total. Recomputed after each filter)
+
+ // DATA_IOTRACE
+ PROP_IOTYPE, // IOTrace_type IOTracePacket::iotype
+ PROP_IOFD, // int32_t IOTracePacket::fd
+ PROP_IONBYTE, // Size_type IOTracePacket::nbyte
+ PROP_IORQST, // hrtime_t IOTracePacket::requested
+ PROP_IOOFD, // int32_t IOTracePacket::ofd
+ PROP_IOFSTYPE, // FileSystem_type IOTracePacket::fstype
+ PROP_IOFNAME, // char IOTracePacket::fname
+ PROP_IOVFD, // int32_t virtual file descriptor
+
+ // DATA_MPI
+ PROP_MPITYPE, // MPI_type MPIPacket::mpitype
+ PROP_MPISCOUNT, // Size MPIPacket::scount
+ PROP_MPISBYTES, // Size MPIPacket::sbytes
+ PROP_MPIRCOUNT, // Size MPIPacket::rcount
+ PROP_MPIRBYTES, // Size MPIPacket::rbytes
+
+ // DATA_OMP*
+ PROP_CPRID, // uint64_t (Note: not same as "PROP_CPRID" below)
+ PROP_PPRID, // uint64_t OMPPacket::omp_pprid
+ PROP_TSKID, // uint64_t (Note: not same as "PROP_CPRID" below)
+ PROP_PTSKID, // uint64_t OMPPacket::omp_ptskid
+ PROP_PRPC, // uint64_t OMPPacket::omp_prpc
+
+ // DATA_RACE
+ PROP_RTYPE, // Race_type RacePacket::rtype
+ PROP_RID, // uint32_t RacePacket::id
+ PROP_RVADDR, // Vaddr RacePacket::vaddr
+ PROP_RCNT, // uint32_t RacePacket::count
+ PROP_LEAFPC, // Vaddr CommonPacket::leafpc
+
+ // DATA_DLCK
+ PROP_DID, // uint32_t DeadlockPacket::id
+ PROP_DTYPE, // Deadlock_Lock_type DeadlockPacket::lock_type
+ PROP_DLTYPE, // Deadlock_type DeadlockPacket::dl_type
+ PROP_DVADDR, // Vaddr DeadlockPacket::lock_addr
+
+ // Synthetic properties (queries only)
+ PROP_STACKID,
+ PROP_STACK, // void* Generic; mapped to M, U, or XSTACK
+ PROP_MSTACK, // void* machine stack
+ PROP_USTACK, // void* user_stack
+ PROP_XSTACK, // void* expert_stack
+ PROP_HSTACK, // void* hide_stack
+ //PROP_CPRID, // void* (Note: not same as "PROP_CPRID" above)
+ //PROP_TSKID, // void* (Note: not same as "PROP_TSKID" above)
+ PROP_JTHREAD, // JThread* CommonPacket::jthread
+ PROP_LEAF, // uint64_t stack leaf function
+ PROP_DOBJ, // "DOBJ" DataObject*
+ PROP_SAMPLE_MAP, // Map events to SAMPLE using sample's time range
+ PROP_GCEVENT_MAP, // Map events to GCEVENT using gcevent's time range
+ PROP_PID, // int unix getpid()
+ PROP_EXPID, // int Experiment->getUserExpId(), AKA process number, >=1.
+ PROP_EXPID_CMP, // int "Comparable PROP_EXPID". In compare mode, if this
+ // process has been matched to another groups' process,
+ // returns PROP_EXPID of the matching process with the
+ // lowest PROP_EXPGRID value. Otherwise returns PROP_EXPID.
+ PROP_EXPGRID, // int Comparison group number. >=0, 0 is Baseline.
+ PROP_PARREG, // "PARREG" uint64_t (see 6436500) TBR?
+ PROP_TSTAMP_LO, // hrtime_t Filter: Event's low TSTAMP
+ PROP_TSTAMP_HI, // hrtime_t Filter: Event's high TSTAMP
+ PROP_TSTAMP2, // hrtime_t Filter: End TSTAMP (TSTAMP<=TSTAMP2)
+ PROP_FREQ_MHZ, // int frequency in MHZ (for converting HWC profiling cycles to time)
+ PROP_NTICK_USEC, // hrtime_t Clock profiling interval, microseconds (PROP_NTICK * Experiment->ptimer_usec)
+ PROP_IOHEAPBYTES, // Size PROP_HSIZE or PROP_IONBYTE
+ PROP_STACKL, // void* Generic; mapped to M, U, or XSTACK for DbeLine
+ PROP_MSTACKL, // void* machine stack
+ PROP_USTACKL, // void* user_stack
+ PROP_XSTACKL, // void* expert_stack
+ PROP_STACKI, // void* Generic; mapped to M, U, or XSTACK for DbeInstr
+ PROP_MSTACKI, // void* machine stack
+ PROP_USTACKI, // void* user_stack
+ PROP_XSTACKI, // void* expert_stack
+ PROP_DDSCR_LNK, // long long index into DataDescriptor table for a related event
+ PROP_VOIDP_OBJ, // void* pointer to object containing metadata
+ PROP_LAST
+};
+
+enum Prop_flag
+{
+ PRFLAG_NOSHOW = 0x40
+};
+
+struct PropDescr
+{
+ PropDescr (int propID, const char *name);
+ virtual ~PropDescr ();
+
+ void addState (int value, const char *stname, const char *stuname);
+ char *getStateName (int value);
+ char *getStateUName (int value);
+
+ int
+ getMaxState ()
+ {
+ return stateNames ? stateNames->size () : 0;
+ }
+
+ int propID;
+ char *name;
+ char *uname;
+ VType_type vtype;
+ int flags;
+
+private:
+ Vector<char*>*stateNames;
+ Vector<char*>*stateUNames;
+};
+
+struct FieldDescr
+{
+ FieldDescr (int propID, const char *name);
+ virtual ~FieldDescr ();
+
+ int propID;
+ char *name;
+ int offset;
+ VType_type vtype;
+ char *format;
+};
+
+class PacketDescriptor
+{
+public:
+ PacketDescriptor (DataDescriptor*);
+ virtual ~PacketDescriptor ();
+
+ DataDescriptor *
+ getDataDescriptor ()
+ {
+ return ddscr;
+ }
+
+ Vector<FieldDescr*> *
+ getFields ()
+ {
+ return fields;
+ }
+
+ void addField (FieldDescr*);
+
+private:
+ DataDescriptor *ddscr;
+ Vector<FieldDescr*> *fields;
+};
+
+struct Datum
+{
+
+ void
+ setUINT32 (uint32_t vv)
+ {
+ type = TYPE_UINT32;
+ i = vv;
+ }
+
+ void
+ setUINT64 (uint64_t vv)
+ {
+ type = TYPE_UINT64;
+ ll = vv;
+ }
+
+ void
+ setSTRING (char* vv)
+ {
+ type = TYPE_STRING;
+ l = vv;
+ }
+
+ void
+ setDOUBLE (double vv)
+ {
+ type = TYPE_DOUBLE;
+ d = vv;
+ }
+
+ void
+ setOBJ (void* vv)
+ {
+ type = TYPE_OBJ;
+ p = vv;
+ }
+
+ VType_type type;
+ union
+ {
+ int i;
+ double d;
+ char *l;
+ void *p;
+ unsigned long long ll;
+ };
+};
+
+class Data
+{
+public:
+ static Data *newData (VType_type);
+
+ virtual
+ ~Data () { }
+
+ virtual VType_type
+ type ()
+ {
+ return TYPE_NONE;
+ }
+ virtual void reset () = 0;
+ virtual long getSize () = 0;
+ virtual int fetchInt (long i) = 0;
+ virtual unsigned long long fetchULong (long i) = 0;
+ virtual long long fetchLong (long i) = 0;
+ virtual char *fetchString (long i) = 0;
+ virtual double fetchDouble (long i) = 0;
+ virtual void *fetchObject (long i) = 0;
+ virtual void setDatumValue (long, const Datum*) = 0;
+ virtual void setValue (long, uint64_t) = 0;
+ virtual void setObjValue (long, void*) = 0;
+ virtual int cmpValues (long idx1, long idx2) = 0;
+ virtual int cmpDatumValue (long idx, const Datum *val) = 0;
+};
+
+enum Data_flag
+{
+ DDFLAG_NOSHOW = 0x01
+};
+
+class DataDescriptor
+{
+ /*
+ * An instance of this class stores the data packets for a specific
+ * type of profiling, for example, clock profiling.
+ *
+ * Each packet consists of values for various properties.
+ * For example, a timestamp is a property which is accessed with PROP_TSTAMP.
+ *
+ * Ideally, DataDescriptor contents are considered immutable after the
+ * data is read in. setValue() should only be used during creation.
+ * - The packets are in fixed order. This allows DataDescriptor <pkt_id>
+ * to be treated as a stable handle.
+ * - Sorting/filtering is handled by the DataView class
+ * - In the future, if we need to add the ability to append new packets,
+ * we might add a flag to show when the class is immutable and/or appendible
+ */
+public:
+
+ DataDescriptor (int id, const char* name, const char* uname, int flags = 0); // master
+ DataDescriptor (int id, const char* name, const char* uname, DataDescriptor*); // reference copy
+ ~DataDescriptor ();
+
+ // packets' descriptions
+ int
+ getId ()
+ {
+ return id;
+ }
+
+ char *
+ getName ()
+ {
+ return name;
+ }
+
+ char *
+ getUName ()
+ {
+ return uname;
+ }
+
+ Vector<PropDescr*> *
+ getProps ()
+ {
+ return props; // packet properties
+ }
+ PropDescr *getProp (int prop_id); // packet property
+
+ long
+ getSize ()
+ {
+ return *ref_size; // number of packets
+ }
+
+ long
+ getFlags ()
+ {
+ return flags;
+ }
+
+ // class to provide sorting and filtering
+ DataView *createView ();
+ DataView *createImmutableView ();
+ DataView *createExtManagedView ();
+
+ // packet property values (<pkt_id> is stable packet handle)
+ int getIntValue (int prop_id, long pkt_id);
+ unsigned long long getULongValue (int prop_id, long pkt_id);
+ long long getLongValue (int prop_id, long pkt_id);
+ void *getObjValue (int prop_id, long pkt_id);
+ Vector<long long> *getSet (int prop_id); // list of sorted, unique values
+
+ // table creation/reset
+ void addProperty (PropDescr*); // add property to all packets
+ long addRecord (); // add packet
+ Data *getData (int prop_id); // get all packets
+ void setDatumValue (int prop_id, long pkt_id, const Datum *val);
+ void setValue (int prop_id, long pkt_id, uint64_t val);
+ void setObjValue (int prop_id, long pkt_id, void *val);
+ void reset (); // remove all packets (ym: TBR?)
+
+ void
+ setResolveFrInfoDone ()
+ {
+ *ref_resolveFrameInfoDone = true;
+ }
+
+ bool
+ isResolveFrInfoDone ()
+ {
+ return *ref_resolveFrameInfoDone;
+ }
+
+
+private:
+ bool isMaster;
+ int flags; // see Data_flag enum
+ int id;
+ char *name;
+ char *uname;
+
+ // the following should only be accessed if parent==NULL
+ long master_size;
+ bool master_resolveFrameInfoDone;
+
+ // the following point to the master DataDescriptor's fields
+ long *ref_size;
+ bool *ref_resolveFrameInfoDone;
+ Vector<PropDescr*> *props;
+ Vector<Data*> *data;
+ Vector<Vector<long long>*> *setsTBR; // Sets of unique values
+};
+
+typedef struct
+{
+ long begin;
+ long end;
+ long orig_ddsize;
+ DataView *tmpView;
+ long *idxArr;
+ FilterExp *fltr;
+} fltr_dbe_ctx;
+
+class DataView
+{
+ /*
+ * Provides sorting and filtering of DataDescriptor packets
+ */
+public:
+
+ enum Relation
+ {
+ REL_LT,
+ REL_LTEQ,
+ REL_EQ,
+ REL_GTEQ,
+ REL_GT
+ };
+
+ enum DataViewType
+ {
+ DV_NORMAL, // filterable, sortable
+ DV_IMMUTABLE, // reflects exact data in DataDescriptor
+ DV_EXT_MANAGED // sortable. index[] entries managed externally.
+ };
+
+ DataView (DataDescriptor*);
+ DataView (DataDescriptor*, DataViewType);
+ virtual ~DataView ();
+
+ Vector<PropDescr*> *getProps ();
+ PropDescr *getProp (int prop_id);
+ long getSize (); // number of post-filter packets
+
+ // packet property values accessed by sort index (not DataDescriptor pkt_id)
+ int getIntValue (int prop_id, long idx);
+ unsigned long long getULongValue (int prop_id, long idx);
+ long long getLongValue (int prop_id, long idx);
+ void *getObjValue (int prop_id, long idx);
+ long getIdByIdx (long idx); // returns DataDescriptor pkt_id
+
+ // define sort/filter
+ void sort (const int props[], int prop_count);
+ void sort (int prop);
+ void sort (int prop1, int prop2);
+ void sort (int prop1, int prop2, int prop3);
+ void setFilter (FilterExp*);
+
+ // search packets
+ // - sort must already be defined
+ // - requires the user to provide all properties used in current sort.
+ // - For a match, the all but the last sort property (the "leaf")
+ // must match exactly.
+ long getIdxByVals (const Datum valColumns[], Relation rel);
+ long getIdxByVals (const Datum valColumns[], Relation rel,
+ long minIdx, long maxIdx); //limit idx search range
+ bool idxRootDimensionsMatch (long idx, const Datum valColumns[]);
+ // packet at idx matches all non-leaf values in valColumns
+
+ // use during table creation, updates underlying DataDescriptor
+ void setDatumValue (int prop_id, long idx, const Datum *val);
+ void setValue (int prop_id, long idx, uint64_t val);
+ void setObjValue (int prop_id, long idx, void *val);
+
+ DataDescriptor *
+ getDataDescriptor ()
+ {
+ return ddscr;
+ }
+
+ void removeDbeViewIdx (long idx);
+
+ // for use with DV_EXT_MANAGED DataViews:
+ void appendDataDescriptorId (long pkt_id);
+ void setDataDescriptorValue (int prop_id, long pkt_id, uint64_t val);
+ long long getDataDescriptorValue (int prop_id, long pkt_id);
+
+private:
+ bool checkUpdate ();
+ void init (DataDescriptor*, DataViewType);
+
+ static void filter_in_chunks (fltr_dbe_ctx *dctx);
+ DataDescriptor *ddscr;
+ long ddsize;
+ Vector<long> *index; // sorted vector of data_id (index into dDscr)
+#define MAX_SORT_DIMENSIONS 10
+#define DATA_SORT_EOL ((Data *) -1) /* marks end of sortedBy[] array */
+ Data *sortedBy[MAX_SORT_DIMENSIONS + 1]; // columns for sort
+ FilterExp *filter;
+ DataViewType type;
+};
+
+#endif /* _TABLE_H */
diff --git a/gprofng/src/UserLabel.cc b/gprofng/src/UserLabel.cc
new file mode 100644
index 0000000..bdb9922
--- /dev/null
+++ b/gprofng/src/UserLabel.cc
@@ -0,0 +1,177 @@
+/* Copyright (C) 2021 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 <time.h>
+
+#include "DbeSession.h"
+#include "Expression.h"
+#include "StringBuilder.h"
+#include "util.h"
+#include "UserLabel.h"
+#include "debug.h"
+
+int UserLabel::last_id = 0;
+
+UserLabel::UserLabel (char *_name)
+{
+ name = dbe_strdup (_name);
+ comment = str_expr = all_times = hostname = NULL;
+ start_f = stop_f = false;
+ expr = NULL;
+ start_tv.tv_sec = 0;
+ start_tv.tv_usec = 0;
+ atime = timeStart = timeStop = start_sec = start_hrtime = 0;
+ relative = REL_TIME;
+ id = ++last_id;
+}
+
+UserLabel::~UserLabel ()
+{
+ free (name);
+ free (comment);
+ free (all_times);
+ free (hostname);
+ free (str_expr);
+ delete expr;
+}
+
+void
+UserLabel::gen_expr ()
+{
+ if (!start_f && !stop_f)
+ return;
+ StringBuilder sb;
+ sb.append ('(');
+ if (str_expr)
+ {
+ sb.append (str_expr);
+ sb.append (NTXT (" || ("));
+ }
+ if (start_f)
+ {
+ sb.append (NTXT ("TSTAMP"));
+ sb.append (NTXT (">="));
+ sb.append (timeStart);
+ if (stop_f)
+ {
+ sb.append (NTXT (" && "));
+ }
+ }
+ if (stop_f)
+ {
+ sb.append (NTXT ("TSTAMP"));
+ sb.append ('<');
+ sb.append (timeStop);
+ }
+ sb.append (')');
+ if (str_expr)
+ {
+ sb.append (')');
+ delete str_expr;
+ }
+ str_expr = sb.toString ();
+ start_f = stop_f = false;
+}
+
+void
+UserLabel::register_user_label (int groupId)
+{
+ gen_expr ();
+ if (str_expr)
+ {
+ char *old_str = str_expr;
+ str_expr = dbe_sprintf (NTXT ("(EXPGRID==%d && %s)"), groupId, old_str);
+ delete old_str;
+ UserLabel *ulbl = dbeSession->findUserLabel (name);
+ if (ulbl)
+ {
+ old_str = ulbl->str_expr;
+ ulbl->str_expr = dbe_sprintf (NTXT ("(%s || %s)"), old_str, str_expr);
+ delete old_str;
+ if (comment)
+ {
+ if (ulbl->comment)
+ {
+ old_str = ulbl->comment;
+ ulbl->comment = dbe_sprintf (NTXT ("%s; %s"), old_str, comment);
+ delete old_str;
+ }
+ else
+ ulbl->comment = dbe_strdup (comment);
+ }
+ delete ulbl->expr;
+ ulbl->expr = dbeSession->ql_parse (ulbl->str_expr);
+ }
+ else
+ {
+ expr = dbeSession->ql_parse (str_expr);
+ dbeSession->append (this);
+ }
+ }
+}
+
+char *
+UserLabel::dump ()
+{
+ StringBuilder sb;
+ sb.append (name);
+ if (str_expr)
+ {
+ sb.append (NTXT (" str_expr='"));
+ sb.append (str_expr);
+ sb.append ('\'');
+ }
+ if (all_times)
+ {
+ sb.append (NTXT (" atime="));
+ sb.append ((unsigned int) (atime / NANOSEC));
+ sb.append ('.');
+ char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("%09llu"), (unsigned long long) (atime % NANOSEC));
+ sb.append (buf);
+ sb.append (NTXT (" all_times='"));
+ sb.append (all_times);
+ sb.append ('\'');
+ }
+ if (comment)
+ {
+ sb.append (NTXT (" comment='"));
+ sb.append (comment);
+ sb.append ('\'');
+ }
+ return sb.toString ();
+}
+
+void
+UserLabel::dump (const char *msg, Vector<UserLabel*> *labels)
+{
+ if (!DUMP_USER_LABELS)
+ return;
+ if (msg)
+ fprintf (stderr, NTXT ("%s\n"), msg);
+ for (int i = 0, sz = labels ? labels->size () : 0; i < sz; i++)
+ {
+ UserLabel *lbl = labels->fetch (i);
+ char *s = lbl->dump ();
+ fprintf (stderr, NTXT ("%2d %s\n"), i, s);
+ delete s;
+ }
+}
diff --git a/gprofng/src/UserLabel.h b/gprofng/src/UserLabel.h
new file mode 100644
index 0000000..0cb37e4
--- /dev/null
+++ b/gprofng/src/UserLabel.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _USER_LABEL_H
+#define _USER_LABEL_H
+
+#include <time.h>
+#include "vec.h"
+
+class Expression;
+class StringBuilder;
+
+class UserLabel
+{
+public:
+
+ enum
+ {
+ REL_TIME = 0,
+ ABS_TIME = 1,
+ CUR_TIME = 2
+ };
+
+ UserLabel (char *_name);
+ ~UserLabel ();
+ void register_user_label (int groupId);
+ void gen_expr ();
+ char *dump ();
+ static void dump (const char *msg, Vector<UserLabel*> *labels);
+
+ char *name, *comment, *str_expr, *all_times, *hostname;
+ bool start_f, stop_f;
+ Expression *expr;
+ timeval start_tv;
+ long long atime, timeStart, timeStop, start_sec, start_hrtime;
+ int id, relative;
+
+private:
+ void gen_time_expr (StringBuilder *sb, long long hrtime, char *op);
+
+ static int last_id;
+};
+
+#endif
diff --git a/gprofng/src/checks.cc b/gprofng/src/checks.cc
new file mode 100644
index 0000000..105821e
--- /dev/null
+++ b/gprofng/src/checks.cc
@@ -0,0 +1,516 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+
+#include "gp-defs.h"
+#include "Elf.h"
+#include "collctrl.h"
+#include "i18n.h"
+#include "util.h"
+#include "collect.h"
+
+void
+collect::check_target (int argc, char **argv)
+{
+ char *next;
+ char *last = 0;
+ char *a;
+ char *ccret;
+ char **lasts = &last;
+ int tindex = targ_index;
+ int ret;
+ char *basename;
+ is_64 = false;
+
+ /* now check the executable */
+ nargs = argc - targ_index;
+ Exec_status rv = check_executable (argv[targ_index]);
+ switch (rv)
+ {
+ case EXEC_OK:
+ njargs = cc->get_java_arg_cnt ();
+ arglist = (char **) calloc (nargs + 5 + njargs, sizeof (char *));
+ jargs = cc->get_java_args ();
+
+ // store the first argument -- target name
+ ret = 0;
+ arglist[ret++] = argv[tindex++];
+ if (cc->get_java_mode () == 1)
+ {
+ // add any user-specified -J (Java) arguments
+ int length = (int) strlen (argv[targ_index]);
+ int is_java = 0;
+ if ((length >= 6) && strcmp (&argv[targ_index][length - 5], NTXT ("/java")) == 0)
+ is_java = 1;
+ else if ((length == 4) && strcmp (&argv[targ_index][0], NTXT ("java")) == 0)
+ is_java = 1;
+ if (njargs != 0 && is_java)
+ {
+ next = strtok_r (jargs, NTXT (" \t"), lasts);
+ arglist[ret++] = next;
+ for (;;)
+ {
+ next = strtok_r (NULL, NTXT (" \t"), lasts);
+ if (next == NULL)
+ break;
+ arglist[ret++] = next;
+ }
+ }
+ }
+
+ // copy the rest of the arguments
+ for (int i = 1; i < nargs; i++)
+ arglist[ret++] = argv[tindex++];
+ nargs = ret;
+ break;
+ case EXEC_IS_JAR:
+ // Preface the user-supplied argument list with
+ // the path to the java, the collector invocation,
+ // any -J java arguments provided, and "-jar".
+ ccret = cc->set_java_mode (NTXT ("on"));
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ exit (1);
+ }
+ njargs = cc->get_java_arg_cnt ();
+ arglist = (char **) calloc (nargs + 5 + njargs, sizeof (char *));
+ jargs = cc->get_java_args ();
+
+ a = find_java ();
+ if (a == NULL)
+ exit (1); // message was written
+ ret = 0;
+ arglist[ret++] = a;
+ // add any user-specified Java arguments
+ if (njargs != 0)
+ {
+ next = strtok_r (jargs, NTXT (" \t"), lasts);
+ arglist[ret++] = next;
+ for (;;)
+ {
+ next = strtok_r (NULL, NTXT (" \t"), lasts);
+ if (next == NULL)
+ break;
+ arglist[ret++] = next;
+ }
+ }
+ arglist[ret++] = NTXT ("-jar");
+ for (int i = 0; i < nargs; i++)
+ arglist[ret++] = argv[tindex++];
+ nargs = ret;
+ break;
+ case EXEC_IS_CLASSCLASS:
+ // remove the .class from the name
+ ret = (int) strlen (argv[targ_index]);
+ argv[targ_index][ret - 6] = 0;
+
+ // now fall through to the EXEC_IS_CLASS case
+ case EXEC_IS_CLASS:
+ // Preface the user-supplied argument list with
+ // the path to the java, the collector invocation,
+ // and any -J java arguments provided.
+ ccret = cc->set_java_mode (NTXT ("on"));
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ exit (1);
+ }
+ jargs = cc->get_java_args ();
+ njargs = cc->get_java_arg_cnt ();
+ arglist = (char **) calloc (nargs + 4 + njargs, sizeof (char *));
+
+ a = find_java ();
+ if (a == NULL)
+ exit (1); // message was written
+ ret = 0;
+ arglist[ret++] = a;
+ // add any user-specified Java arguments
+ if (njargs != 0)
+ {
+ next = strtok_r (jargs, NTXT (" \t"), lasts);
+ arglist[ret++] = next;
+ for (;;)
+ {
+ next = strtok_r (NULL, NTXT (" \t"), lasts);
+ if (next == NULL)
+ break;
+ arglist[ret++] = next;
+ }
+ }
+
+ // copy the remaining arguments to the new list
+ for (int i = 0; i < nargs; i++)
+ arglist[ret++] = argv[tindex++];
+ nargs = ret;
+ break;
+ case EXEC_ELF_NOSHARE:
+ case EXEC_OPEN_FAIL:
+ case EXEC_ELF_LIB:
+ case EXEC_ELF_HEADER:
+ case EXEC_ELF_ARCH:
+ case EXEC_ISDIR:
+ case EXEC_NOT_EXEC:
+ case EXEC_NOT_FOUND:
+ default:
+ /* something wrong; write a message */
+ char *errstr = status_str (rv, argv[targ_index]);
+ if (errstr)
+ {
+ dbe_write (2, "%s", errstr);
+ free (errstr);
+ }
+ exit (1);
+ }
+ cc->set_target (arglist[0]);
+
+ /* check the experiment */
+ char *ccwarn;
+ ccret = cc->check_expt (&ccwarn);
+ if (ccwarn != NULL)
+ {
+ writeStr (2, ccwarn);
+ free (ccwarn);
+ }
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ exit (1);
+ }
+ /* check if java, to see if -j flag was given */
+ if ((basename = strrchr (arglist[0], '/')) == NULL)
+ basename = arglist[0];
+ else
+ basename++;
+ if (strcmp (basename, NTXT ("java")) == 0)
+ {
+ /* the target's name is java; was java flag set? */
+ if ((jseen_global == 0) && (cc->get_java_mode () == 0))
+ {
+ char *cret = cc->set_java_mode (NTXT ("on"));
+ if (cret != NULL)
+ {
+ writeStr (2, cret);
+ exit (1);
+ }
+ }
+ }
+}
+
+collect::Exec_status
+collect::check_executable (char *target_name)
+{
+ char target_path[MAXPATHLEN];
+ struct stat64 statbuf;
+ if (target_name == NULL) // not set, but assume caller knows what it's doing
+ return EXEC_OK;
+ if (getenv ("GPROFNG_SKIP_VALIDATION")) // don't check target
+ return EXEC_OK;
+
+ // see if target exists and is not a directory
+ if ((dbe_stat (target_name, &statbuf) == 0) && ((statbuf.st_mode & S_IFMT) != S_IFDIR))
+ {
+ // target is found, check for access as executable
+ if (access (target_name, X_OK) != 0)
+ {
+ // not an executable, check for jar or class file
+ int i = (int) strlen (target_name);
+ if ((i >= 5) && strcmp (&target_name[i - 4], NTXT (".jar")) == 0)
+ {
+ // could be a jar file
+ // XXXX -- need better check for real jar file
+ cc->set_java_mode ("on");
+ return EXEC_IS_JAR;
+ }
+ if ((i >= 7) && strcmp (&target_name[i - 6], NTXT (".class")) == 0)
+ {
+ // could be a class file
+ // XXXX -- need better check for real class file
+ cc->set_java_mode (NTXT ("on"));
+ return EXEC_IS_CLASSCLASS;
+ }
+ // not a jar or class file, return not an executable
+ return EXEC_NOT_EXEC;
+ }
+ else // found, and it is executable. set the path to it
+ snprintf (target_path, sizeof (target_path), NTXT ("%s"), target_name);
+ }
+ else
+ {
+ // not found, look on path
+ char *exe_name = get_realpath (target_name);
+ if (access (exe_name, X_OK) == 0)
+ {
+ // target can't be located
+ // one last attempt: append .class to name, and see if we can find it
+ snprintf (target_path, sizeof (target_path), NTXT ("%s.class"), target_name);
+ if (dbe_stat (target_path, &statbuf) == 0)
+ {
+ // the file exists
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+ {
+ // this is a directory; that won't do.
+ return EXEC_ISDIR;
+ }
+ // say it's a class file
+ cc->set_java_mode (NTXT ("on"));
+ return EXEC_IS_CLASS;
+ }
+ return EXEC_NOT_FOUND;
+ }
+ snprintf (target_path, sizeof (target_path), NTXT ("%s"), exe_name);
+ delete exe_name;
+ }
+
+ // target_path is now the purported executable
+ // check for ELF library out of date
+ if (Elf::elf_version (EV_CURRENT) == EV_NONE)
+ return EXEC_ELF_LIB;
+ Elf *elf = Elf::elf_begin (target_path);
+ if (elf == NULL)
+ return EXEC_OK;
+ // do not by pass checking architectural match
+ collect::Exec_status exec_stat = check_executable_arch (elf);
+ if (exec_stat != EXEC_OK)
+ {
+ delete elf;
+ return exec_stat;
+ }
+ delete elf;
+ return EXEC_OK;
+}
+
+collect::Exec_status
+collect::check_executable_arch (Elf *elf)
+{
+ Elf_Internal_Ehdr *ehdrp = elf->elf_getehdr ();
+ if (ehdrp == NULL)
+ return EXEC_ELF_HEADER;
+ unsigned short machine = ehdrp->e_machine;
+
+ switch (machine)
+ {
+#if ARCH(SPARC)
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ break;
+ case EM_SPARCV9:
+ is_64 = true;
+ break;
+#elif ARCH(Intel)
+ case EM_X86_64:
+ {
+ is_64 = true;
+ // now figure out if the platform can run it
+ struct utsname unbuf;
+ int r = uname (&unbuf);
+ if (r == 0 && unbuf.machine && strstr (unbuf.machine, "_64") == NULL)
+ // machine can not run 64 bits, but this code is 64-bit
+ return EXEC_ELF_ARCH;
+ }
+ break;
+ case EM_386:
+ break;
+#elif ARCH(Aarch64)
+ case EM_AARCH64:
+ is_64 = true;
+ break;
+#endif
+ default:
+ return EXEC_ELF_ARCH;
+ }
+
+ // now check if target was built with shared libraries
+ int dynamic = 0;
+ for (unsigned cnt = 0; cnt < ehdrp->e_phnum; cnt++)
+ {
+ Elf_Internal_Phdr *phdrp = elf->get_phdr (cnt);
+ if (phdrp && phdrp->p_type == PT_DYNAMIC)
+ {
+ dynamic = 1;
+ break;
+ }
+ }
+ if (dynamic == 0)
+ {
+ // target is not a dynamic executable or shared object;
+ // can't record data
+ return EXEC_ELF_NOSHARE;
+ }
+ return EXEC_OK;
+}
+
+char *
+collect::status_str (Exec_status rv, char *target_name)
+{
+ switch (rv)
+ {
+ case EXEC_OK:
+ case EXEC_IS_JAR:
+ case EXEC_IS_CLASS:
+ case EXEC_IS_CLASSCLASS:
+ // supported flavors -- no error message
+ return NULL;
+ case EXEC_ELF_NOSHARE:
+ return dbe_sprintf (GTXT ("Target executable `%s' must be built with shared libraries\n"), target_name);
+ case EXEC_OPEN_FAIL:
+ return dbe_sprintf (GTXT ("Can't open target executable `%s'\n"), target_name);
+ case EXEC_ELF_LIB:
+ return strdup (GTXT ("Internal error: Not a working version of ELF library\n"));
+ case EXEC_ELF_HEADER:
+ return dbe_sprintf (GTXT ("Target `%s' is not a valid ELF executable\n"), target_name);
+ case EXEC_ELF_ARCH:
+ return dbe_sprintf (GTXT ("Target architecture of executable `%s' is not supported on this machine\n"), target_name);
+ case EXEC_ISDIR:
+ return dbe_sprintf (GTXT ("Target `%s' is a directory, not an executable\n"), target_name);
+ case EXEC_NOT_EXEC:
+ return dbe_sprintf (GTXT ("Target `%s' is not executable\n"), target_name);
+ case EXEC_NOT_FOUND:
+ return dbe_sprintf (GTXT ("Target `%s' not found\n"), target_name);
+ }
+ return NULL;
+}
+
+char *
+collect::find_java (void)
+{
+ char buf[MAXPATHLEN];
+ char *var = NULL;
+ Exec_status rv = EXEC_OK;
+
+ // first see if the user entered a -j argument
+ var = cc->get_java_path ();
+ if (var != NULL)
+ {
+ snprintf (buf, sizeof (buf), NTXT ("%s/bin/java"), var);
+ java_how = NTXT ("-j");
+ rv = check_executable (buf);
+ }
+ // then try JDK_HOME
+ if (java_how == NULL)
+ {
+ var = getenv (NTXT ("JDK_HOME"));
+ if ((var != NULL) && (strlen (var) > 0))
+ {
+ snprintf (buf, sizeof (buf), NTXT ("%s/bin/java"), var);
+ java_how = NTXT ("JDK_HOME");
+ rv = check_executable (buf);
+ }
+ }
+ // then try JAVA_PATH
+ if (java_how == NULL)
+ {
+ var = getenv (NTXT ("JAVA_PATH"));
+ if ((var != NULL) && (strlen (var) > 0))
+ {
+ snprintf (buf, sizeof (buf), NTXT ("%s/bin/java"), var);
+ java_how = NTXT ("JAVA_PATH");
+ rv = check_executable (buf);
+ }
+ }
+ // try the user's path
+ if (java_how == NULL)
+ {
+ snprintf (buf, sizeof (buf), NTXT ("java"));
+ rv = check_executable (buf);
+ if (rv == EXEC_OK)
+ java_how = NTXT ("PATH");
+ }
+ // finally, just try /usr/java -- system default
+ if (java_how == NULL)
+ {
+ snprintf (buf, sizeof (buf), NTXT ("/usr/java/bin/java"));
+ rv = check_executable (buf);
+ java_how = NTXT ("/usr/java/bin/java");
+ }
+
+ // we now have a nominal path to java, and how we chose it
+ // and we have rv set to the check_executable return
+ switch (rv)
+ {
+ case EXEC_OK:
+ java_path = strdup (buf);
+ if (verbose == 1)
+ dbe_write (2, GTXT ("Path to `%s' (set from %s) used for Java profiling\n"),
+ java_path, java_how);
+ return ( strdup (buf));
+ default:
+ dbe_write (2, GTXT ("Path to `%s' (set from %s) does not point to a JVM executable\n"),
+ buf, java_how);
+ break;
+ }
+ return NULL;
+}
+
+void
+collect::validate_config (int how)
+{
+ if (getenv (NTXT ("GPROFNG_SKIP_VALIDATION")) != NULL)
+ return;
+ char *cmd = dbe_sprintf (NTXT ("%s/perftools_validate"), run_dir);
+ if (access (cmd, X_OK) != 0)
+ {
+ if (how)
+ dbe_write (2, GTXT ("WARNING: Unable to validate system: `%s' could not be executed\n"), cmd);
+ return;
+ }
+ char *quiet = how == 0 ? NTXT ("") : NTXT ("-q"); // check collection, verbosely
+ char *buf;
+ if (cc->get_java_default () == 0 && java_path)
+ buf = dbe_sprintf (NTXT ("%s -c -j %s -H \"%s\" %s"), cmd, java_path, java_how, quiet);
+ else // not java mode -- don't check the java version
+ buf = dbe_sprintf (NTXT ("%s -c %s"), cmd, quiet);
+ free (cmd);
+
+ /* now run the command */
+ int ret = system (buf);
+ int status = WEXITSTATUS (ret);
+ if ((status & 0x1) != 0)
+ dbe_write (2, GTXT ("WARNING: Data collection may fail: system is not properly configured or is unsupported.\n"));
+ if ((status & 0x2) != 0)
+ dbe_write (2, GTXT ("WARNING: Java data collection may fail: J2SE[tm] version is unsupported.\n"));
+ free (buf);
+}
+
+void
+collect::validate_java (const char *jvm, const char *jhow, int q)
+{
+ char *cmd = dbe_sprintf (NTXT ("%s/perftools_ckjava"), run_dir);
+ if (access (cmd, X_OK) != 0)
+ {
+ dbe_write (2, GTXT ("WARNING: Unable to validate Java: `%s' could not be executed\n"), cmd);
+ return;
+ }
+ char *buf = dbe_sprintf (NTXT ("%s -j %s -H \"%s\" %s"), cmd, jvm, jhow,
+ (q == 1 ? "-q" : ""));
+ free (cmd);
+
+ /* now run the command */
+ int ret = system (buf);
+ int status = WEXITSTATUS (ret);
+ if (status != 0)
+ dbe_write (2, GTXT ("WARNING: Java data collection may fail: J2SE[tm] version is unsupported.\n"));
+ free (buf);
+}
diff --git a/gprofng/src/collctrl.cc b/gprofng/src/collctrl.cc
new file mode 100644
index 0000000..48c65ff
--- /dev/null
+++ b/gprofng/src/collctrl.cc
@@ -0,0 +1,3149 @@
+/* Copyright (C) 2021 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 <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <assert.h>
+#include <regex.h> /* regcomp() */
+
+#include "util.h"
+#include "libiberty.h"
+#include "collctrl.h"
+#include "hwcdrv.h"
+//#include "hwcfuncs.h"
+
+#define SP_GROUP_HEADER "#analyzer experiment group"
+#define DD_MAXPATHLEN (MAXPATHLEN * 4) /* large, to build up data descriptor */
+
+/* If the system doesn't provide strsignal, we get it defined in
+ libiberty but no declaration is supplied. */
+#if !defined (HAVE_STRSIGNAL) && !defined (strsignal)
+extern const char *strsignal (int);
+#endif
+
+// _SC_CPUID_MAX is not available on 2.6/2.7
+#ifndef _SC_CPUID_MAX
+#define _SC_CPUID_MAX 517
+#endif
+
+const char *get_fstype (char *);
+
+Coll_Ctrl::Coll_Ctrl (int _interactive, bool _defHWC, bool _kernelHWC)
+{
+ char hostname[MAXPATHLEN];
+ long ncpumax;
+ interactive = _interactive;
+ defHWC = _defHWC;
+ kernelHWC = _kernelHWC;
+
+ /* set this host's parameters */
+ gethostname (hostname, 1023);
+ node_name = strdup (hostname);
+ char *p = strchr (node_name, (int) '.');
+ if (p != NULL)
+ *p = 0;
+ default_stem = strdup ("test");
+
+ /* get CPU count and processor clock rate */
+ ncpumax = sysconf (_SC_CPUID_MAX);
+ if (ncpumax == -1)
+ {
+ ncpus = sysconf (_SC_NPROCESSORS_CONF);
+ /* add 2048 to count, since on some systems CPUID does not start at zero */
+ ncpumax = ncpus + 2048;
+ }
+ ncpus = 0;
+ cpu_clk_freq = 0;
+
+ // On Linux, read /proc/cpuinfo to get CPU count and clock rate
+ // Note that parsing is different on SPARC and x86
+#if defined(sparc)
+ FILE *procf = fopen ("/proc/cpuinfo", "r");
+ if (procf != NULL)
+ {
+ char temp[1024];
+ while (fgets (temp, (int) sizeof (temp), procf) != NULL)
+ {
+ if (strncmp (temp, "Cpu", 3) == 0 && temp[3] != '\0'
+ && strncmp ((strchr (temp + 1, 'C')) ? strchr (temp + 1, 'C')
+ : (temp + 4), "ClkTck", 6) == 0)
+ {
+ ncpus++;
+ char *val = strchr (temp, ':');
+ if (val)
+ {
+ unsigned long long freq;
+ sscanf (val + 2, "%llx", &freq);
+ cpu_clk_freq = (unsigned int) (((double) freq) / 1000000.0 + 0.5);
+ }
+ else
+ cpu_clk_freq = 0;
+ }
+ }
+ fclose (procf);
+ }
+
+#elif defined(__aarch64__)
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (cpu_clk_freq));
+ dbe_write (2, GTXT ("CPU clock frequency: %d\n"), cpu_clk_freq);
+
+#else
+ FILE *procf = fopen ("/proc/cpuinfo", "r");
+ if (procf != NULL)
+ {
+ char temp[1024];
+ while (fgets (temp, (int) sizeof (temp), procf) != NULL)
+ {
+ // x86 Linux
+ if (strncmp (temp, "processor", 9) == 0)
+ ncpus++;
+ else if (strncmp (temp, "cpu MHz", 7) == 0)
+ {
+ char *val = strchr (temp, ':');
+ cpu_clk_freq = val ? atoi (val + 1) : 0;
+ }
+ }
+ fclose (procf);
+ }
+#endif
+
+ /* check resolution of system clock */
+ sys_resolution = sysconf (_SC_CLK_TCK);
+ if (sys_resolution == 0)
+ sys_period = 10000;
+ else
+ sys_period = MICROSEC / (int) sys_resolution;
+
+ /* determine memory page size and number of pages */
+ npages = sysconf (_SC_PHYS_PAGES);
+ page_size = sysconf (_SC_PAGE_SIZE);
+
+ /* set default clock parameters */
+ hwcprof_enabled_cnt = 0; // must be set before calling determine_profile_params();
+ determine_profile_params (); // inits clk_params which is used by clock profiling AND HWCs
+ cpc_cpuver = CPUVER_UNDEFINED;
+
+ /* set default control values */
+ debug_mode = 0;
+#if defined(GPROFNG_JAVA_PROFILING)
+ java_mode = 1;
+#else
+ java_mode = 0;
+#endif
+ java_default = 1;
+ java_path = NULL;
+ java_args = NULL;
+ njava_args = 0;
+ follow_mode = FOLLOW_ON;
+ follow_default = 1;
+ follow_spec_usr = NULL;
+ follow_spec_cmp = NULL;
+ prof_idle = 1;
+ archive_mode = strdup ("on");
+ pauseresume_sig = 0;
+ sample_sig = 0;
+ uinterrupt = 0;
+ attach_pid = 0;
+ time_run = 0;
+ start_delay = 0;
+
+ /* clear the string pointers */
+ uexpt_name = NULL;
+ expt_name = NULL;
+ expt_dir = NULL;
+ base_name = NULL;
+ udir_name = NULL;
+ store_dir = NULL;
+ prev_store_dir = strdup ("");
+ store_ptr = NULL;
+ expt_group = NULL;
+ target_name = NULL;
+ data_desc = NULL;
+ lockname = NULL;
+ hwc_string = NULL;
+ project_home = NULL;
+ lockfd = -1;
+
+ /* set default data collection values */
+ enabled = 0;
+ opened = 0;
+ clkprof_enabled = 1;
+ clkprof_default = 1;
+ for (unsigned ii = 0; ii < MAX_PICS; ii++)
+ {
+ memset (&hwctr[ii], 0, sizeof (Hwcentry));
+ hwctr[ii].reg_num = -1;
+ }
+ hwcprof_default = 0;
+ if (defHWC == true)
+ {
+ setup_hwc ();
+ hwcprof_default = 1;
+ }
+ else // disable the default, and reset the counters
+ hwcprof_enabled_cnt = 0;
+ synctrace_enabled = 0;
+ synctrace_thresh = -1;
+ synctrace_scope = 0;
+ heaptrace_enabled = 0;
+ heaptrace_checkenabled = 0;
+ iotrace_enabled = 0;
+ count_enabled = 0;
+ Iflag = 0;
+ Nflag = 0;
+ sample_period = 1;
+ sample_default = 1;
+ size_limit = 0;
+ nofswarn = 0;
+ expno = 1;
+
+ // ensure that the default name is updated
+ // but don't print any message
+ (void) preprocess_names ();
+ (void) update_expt_name (false, false);
+}
+
+/* Copy constructor */
+Coll_Ctrl::Coll_Ctrl (Coll_Ctrl * cc)
+{
+ uinterrupt = 0;
+ interactive = cc->interactive;
+ defHWC = cc->defHWC;
+ kernelHWC = cc->kernelHWC;
+ node_name = strdup (cc->node_name);
+ default_stem = strdup (cc->default_stem);
+ ncpus = cc->ncpus;
+ cpu_clk_freq = cc->cpu_clk_freq;
+ npages = cc->npages;
+ page_size = cc->page_size;
+ cpc_cpuver = cc->cpc_cpuver;
+ debug_mode = cc->debug_mode;
+ java_mode = cc->java_mode;
+ java_default = cc->java_default;
+ java_path = NULL;
+ java_args = NULL;
+ njava_args = 0;
+ follow_mode = cc->follow_mode;
+ follow_default = cc->follow_default;
+ if (cc->follow_spec_usr)
+ {
+ follow_spec_usr = strdup (cc->follow_spec_usr);
+ follow_spec_cmp = strdup (cc->follow_spec_cmp);
+ }
+ else
+ {
+ follow_spec_usr = NULL;
+ follow_spec_cmp = NULL;
+ }
+ archive_mode = strdup (cc->archive_mode);
+ pauseresume_sig = cc->pauseresume_sig;
+ sample_sig = cc->sample_sig;
+ time_run = cc->time_run;
+ start_delay = cc->start_delay;
+ clk_params = cc->clk_params;
+ clkprof_enabled = cc->clkprof_enabled;
+ clkprof_default = cc->clkprof_default;
+ clkprof_timer = cc->clkprof_timer;
+ clkprof_timer_target = cc->clkprof_timer_target;
+
+ // copy HW counter information
+ hwcprof_default = cc->hwcprof_default;
+ hwcprof_enabled_cnt = cc->hwcprof_enabled_cnt;
+ if (cc->hwc_string != NULL)
+ hwc_string = strdup (cc->hwc_string);
+ else
+ hwc_string = NULL;
+ for (int i = 0; i < hwcprof_enabled_cnt; i++)
+ hwcentry_dup (&hwctr[i], &(cc->hwctr[i]));
+ project_home = cc->project_home ? strdup (cc->project_home) : NULL;
+ synctrace_enabled = cc->synctrace_enabled;
+ synctrace_thresh = cc->synctrace_thresh;
+ synctrace_scope = cc->synctrace_scope;
+ heaptrace_enabled = cc->heaptrace_enabled;
+ heaptrace_checkenabled = cc->heaptrace_checkenabled;
+ iotrace_enabled = cc->iotrace_enabled;
+ count_enabled = cc->count_enabled;
+ Iflag = cc->Iflag;
+ Nflag = cc->Nflag;
+ sample_period = cc->sample_period;
+ sample_default = cc->sample_default;
+ size_limit = cc->size_limit;
+ nofswarn = cc->nofswarn;
+
+ // these will get reset during preprocess_names()
+ expt_name = NULL;
+ expt_dir = NULL;
+ store_dir = NULL;
+ base_name = NULL;
+ expno = 1;
+
+ // these represent user settings
+ expt_group = NULL;
+ if (cc->expt_group != NULL)
+ expt_group = strdup (cc->expt_group);
+ uexpt_name = NULL;
+ if (cc->uexpt_name != NULL)
+ uexpt_name = strdup (cc->uexpt_name);
+ udir_name = NULL;
+ if (cc->udir_name != NULL)
+ udir_name = strdup (cc->udir_name);
+
+ /* clear the string pointers */
+ prev_store_dir = strdup ("");
+ store_ptr = NULL;
+ target_name = NULL;
+ data_desc = NULL;
+ lockname = NULL;
+ lockfd = -1;
+
+ /* set default data collection values */
+ enabled = cc->enabled;
+ opened = 0;
+ nofswarn = cc->nofswarn;
+ sys_resolution = cc->sys_resolution;
+ sys_period = cc->sys_period;
+
+ // ensure that the default name is updated
+ (void) preprocess_names ();
+ (void) update_expt_name (false, false);
+ build_data_desc ();
+}
+
+Coll_Ctrl::~Coll_Ctrl ()
+{
+ free (node_name);
+ free (expt_name);
+ free (expt_dir);
+ free (base_name);
+ free (udir_name);
+ free (store_dir);
+ free (store_ptr);
+ free (expt_group);
+ free (target_name);
+ free (data_desc);
+ free (lockname);
+ free (hwc_string);
+ free (project_home);
+ free (java_path);
+ hwcprof_enabled_cnt = 0;
+}
+
+/* set up the experiment */
+char *
+Coll_Ctrl::setup_experiment ()
+{
+ char *ret;
+ if (enabled == 0)
+ return NULL;
+ build_data_desc ();
+
+ /* create the experiment directory */
+ ret = create_exp_dir ();
+ if (ret != NULL)
+ return ret;
+
+ /* if an experiment-group, join it */
+ ret = join_group ();
+ if (ret != NULL)
+ {
+ remove_exp_dir ();
+ return ret;
+ }
+ /* all is OK, return 0 */
+ opened = 1;
+ return NULL;
+}
+
+void
+Coll_Ctrl::interrupt ()
+{
+ uinterrupt = 1;
+}
+
+char *
+Coll_Ctrl::enable_expt ()
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (cpu_clk_freq == 0)
+ return strdup (GTXT ("Can not determine CPU clock frequency.\n"));
+ if (sys_resolution == 0)
+ return strdup (GTXT ("System clock profile resolution can not be determined.\n"));
+ enabled = 1;
+ return NULL;
+}
+
+/* close the experiment */
+void
+Coll_Ctrl::close_expt ()
+{
+ opened = 0;
+ (void) update_expt_name (false, false);
+}
+
+/* close and delete the experiment */
+void
+Coll_Ctrl::delete_expt ()
+{
+ if (opened == 0)
+ return;
+ remove_exp_dir ();
+
+ /* The order of removing the directory and closing
+ * the experiment may seem unnatural, but it's not.
+ * We do need to update names when we close the experiment
+ * (actually Coll_Ctrl object) and we can't remove anything
+ * after that.
+ */
+ close_expt ();
+}
+
+// Check the experiment settings for consistency. Returns NULL if OK,
+// or an error message if there are invalid combinations of settings
+char *
+Coll_Ctrl::check_consistency ()
+{
+ /* check for Java arguments, but not Java profiling */
+ if (java_args != NULL && java_mode == 0)
+ return strdup (GTXT ("Java arguments can not be set if Java profiling is not enabled.\n"));
+
+ /* if count data, no other data is allowed */
+ if (count_enabled != 0
+ && ((clkprof_default != 1 && clkprof_enabled != 0)
+ || hwcprof_enabled_cnt != 0 || synctrace_enabled != 0
+ || heaptrace_enabled != 0 || iotrace_enabled != 0))
+ return strdup (GTXT ("Count data cannot be collected along with any other data.\n"));
+
+ /* if count data, various other options are not allowed */
+ if (count_enabled != 0
+ && ((java_mode != 0 && java_default != 1)
+ || java_args != NULL || debug_mode != 0
+ || (follow_mode != 0 && follow_default != 1)
+ || pauseresume_sig != 0 || sample_sig != 0
+ || (sample_default != 1 && sample_period != 0) || time_run != 0))
+ return strdup (GTXT ("Count data cannot be collected with any of -F -S -y -l -j -J -x -t .\n"));
+ /* if not count data, I and N options are not allowed */
+ if (count_enabled == 0 && (Iflag != 0 || Nflag != 0))
+ return strdup (GTXT ("-I or -N can only be specified with count data.\n"));
+ return NULL;
+}
+
+char *
+Coll_Ctrl::check_expt (char **warn)
+{
+ char *ret;
+ *warn = NULL;
+ ret = check_consistency ();
+ if (ret != NULL) /* something is wrong, return the error */
+ return ret;
+ /* check for heaptrace and java -- warn that it covers native allocations only */
+ if (heaptrace_enabled == 1 && java_mode == 1 && java_default == 0)
+ *warn = strdup (GTXT ("Note: Heap profiling will only trace native allocations, not Java allocations.\n"));
+
+ /* if no profiling data selected, warn the user */
+ if (clkprof_enabled == 0 && hwcprof_enabled_cnt == 0 && synctrace_enabled == 0
+ && heaptrace_enabled == 0 && iotrace_enabled == 0 && count_enabled == 0)
+ *warn = strdup (GTXT ("Warning: No function level data requested; only statistics will be collected.\n\n"));
+ build_data_desc ();
+
+ /* verify that the directory exists */
+ struct stat statbuf;
+ if (stat (store_dir, &statbuf) != 0)
+ return dbe_sprintf (GTXT ("Store directory %s is not accessible: %s\n"),
+ store_dir, strerror (errno));
+ if (access (store_dir, W_OK) != 0)
+ return dbe_sprintf (GTXT ("Store directory %s is not writeable: %s\n"),
+ store_dir, strerror (errno));
+
+ /* if an experiment-group, verify that it can be written */
+ ret = check_group ();
+ if (ret != NULL)
+ return ret;
+ return NULL;
+}
+
+char *
+Coll_Ctrl::show (int i)
+{
+ char UEbuf[4096];
+ UEbuf[0] = 0;
+ if (i == 0)
+ {
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("Collection parameters:\n"));
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT (" experiment enabled\n"));
+ }
+ if (target_name != NULL)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\ttarget = %s\n"), target_name);
+ if (uexpt_name != NULL)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tuser_expt_name = %s\n"), uexpt_name);
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\texpt_name = %s\n"),
+ ((expt_name != NULL) ? expt_name : NTXT ("<NULL>")));
+ if (udir_name != NULL)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdir_name = %s\n"), udir_name);
+ if (expt_group != NULL)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\texpt_group = %s\n"), expt_group);
+ if (debug_mode == 1)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdebug_mode enabled\n"));
+ if (clkprof_enabled != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tclock profiling enabled, %.3f millisec.\n"),
+ (double) (clkprof_timer) / 1000.);
+ if (synctrace_enabled != 0)
+ {
+ if (synctrace_thresh < 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tsynchronization tracing enabled, threshold: calibrate; "));
+ else if (synctrace_thresh == 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tsynchronization tracing enabled, threshold: all; "));
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tsynchronization tracing enabled, threshold: %d micros.; "), synctrace_thresh);
+ switch (synctrace_scope)
+ {
+ case SYNCSCOPE_NATIVE:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("Native-APIs\n"));
+ break;
+ case SYNCSCOPE_JAVA:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("Java-APIs\n"));
+ break;
+ case SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("Native- and Java-APIs\n"));
+ break;
+ default:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("ERR -- unexpected synctrace_scope %d\n"), synctrace_scope);
+ break;
+ }
+ }
+ if (hwcprof_enabled_cnt != 0)
+ {
+ char ctrbuf[MAXPATHLEN];
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\thardware counter profiling%s enabled:\n"),
+ (hwcprof_default == 1 ? GTXT (" (default)") : ""));
+ for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t %u. %s\n"), ii + 1,
+ hwc_hwcentry_specd_string (ctrbuf, MAXPATHLEN, &hwctr[ii]));
+ }
+ if (heaptrace_enabled != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\theap tracing enabled, %s\n"),
+ (heaptrace_checkenabled == 0 ? GTXT ("no checking") :
+ (heaptrace_checkenabled == 1 ? GTXT ("over/underrun checking") :
+ GTXT ("over/underrun checking and pattern storing"))));
+ if (iotrace_enabled != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tI/O tracing enabled\n"));
+ switch (count_enabled)
+ {
+ case 0:
+ break;
+ case 1:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tcount data enabled\n"));
+ break;
+ case -1:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tstatic count data will be generated (for a.out only)\n"));
+ break;
+ }
+ switch (follow_mode)
+ {
+ case FOLLOW_ON:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdescendant processes will be followed\n"));
+ break;
+ case FOLLOW_ALL:
+ if (follow_spec_usr && follow_spec_cmp)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\texperiments will be recorded for descendant processes that match pattern '%s'\n"),
+ follow_spec_usr);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdescendant processes will all be followed\n"));
+ break;
+ case FOLLOW_NONE:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdescendant processes will not be followed\n"));
+ break;
+ default:
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tfollowing descendant processes: <UNKNOWN>\n"));
+ break;
+ }
+ if (java_mode == 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tjava profiling disabled\n"));
+ if (pauseresume_sig != 0)
+ {
+ const char *buf = strsignal (pauseresume_sig);
+ if (buf != NULL)
+ {
+ if (pauseresume_pause == 1)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tpause-resume (delayed initialization) signal %s (%d) -- paused\n"), buf, pauseresume_sig);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tpause-resume (delayed initialization) signal %s (%d)\n"), buf, pauseresume_sig);
+ }
+ else
+ {
+ if (pauseresume_pause == 1)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tpause-resume (delayed initialization) signal %d -- paused\n"), pauseresume_sig);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tpause-resume (delayed initialization) signal %d\n"), pauseresume_sig);
+ }
+ }
+ if (sample_sig != 0)
+ {
+ const char *buf = strsignal (sample_sig);
+ if (buf != NULL)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tsample signal %s (%d)\n"), buf, sample_sig);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tsample signal %d\n"), sample_sig);
+ }
+ if (time_run != 0 || start_delay != 0)
+ {
+ if (start_delay != 0)
+ {
+ if (time_run != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdata-collection duration, %d-%d secs.\n"), start_delay, time_run);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdata-collection duration, %d- secs.\n"), start_delay);
+ }
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdata-collection duration, %d secs.\n"), time_run);
+ }
+ if (sample_period != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tperiodic sampling, %d secs.\n"), sample_period);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tno periodic sampling\n"));
+ if (size_limit != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\texperiment size limit %d MB.\n"), size_limit);
+ else
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tno experiment size limit set\n"));
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\texperiment archiving: -a %s\n"), archive_mode);
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\tdata descriptor: \"%s\"\n"),
+ ((data_desc != NULL) ? data_desc : NTXT ("<NULL>")));
+#if 0
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t expt_dir: %s\n"),
+ ((expt_dir != NULL) ? expt_dir : NTXT ("<NULL>")));
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t base_name: %s\n"),
+ ((base_name != NULL) ? base_name : NTXT ("<NULL>")));
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t store_dir: %s\n"),
+ ((store_dir != NULL) ? store_dir : NTXT ("<NULL>")));
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t store_ptr: %s\n"),
+ ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")));
+#endif
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t\thost: `%s', ncpus = %d, clock frequency %d MHz.\n"),
+ ((node_name != NULL) ? node_name : NTXT ("<NULL>")),
+ (int) ncpus, (int) cpu_clk_freq);
+ if (npages > 0)
+ {
+ long long memsize = ((long long) npages * (long long) page_size) / (1024 * 1024);
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("\t\tmemory: %ld pages @ %ld bytes = %lld MB.\n"),
+ npages, page_size, memsize);
+ }
+ return strdup (UEbuf);
+}
+
+#define MAX_COLLECT_ARGS 100
+
+char **
+Coll_Ctrl::get_collect_args ()
+{
+ char buf[DD_MAXPATHLEN];
+ char **p;
+ char **argv = (char **) calloc (MAX_COLLECT_ARGS, sizeof (char *));
+ if (argv == NULL) // poor way of dealing with calloc failure
+ abort ();
+ p = argv;
+ *p++ = strdup ("collect");
+ if (debug_mode == 1)
+ *p++ = strdup ("-x");
+ if (clkprof_enabled != 0)
+ {
+ *p++ = strdup ("-p");
+ snprintf (buf, sizeof (buf), "%du", clkprof_timer);
+ *p++ = strdup (buf);
+ }
+ if (hwcprof_enabled_cnt > 0)
+ {
+ *buf = 0;
+ *p++ = strdup ("-h");
+ for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+ {
+ char*rateString = hwc_rate_string (&hwctr[ii], 1); //"1" is for temporary goldfile compatibility. TBR YXXX!!
+ snprintf (buf + strlen (buf), sizeof (buf) - strlen (buf),
+ "%s%s,%s%s", ii ? "," : "", hwctr[ii].name,
+ rateString ? rateString : "",
+ (ii + 1 < hwcprof_enabled_cnt) ? "," : "");
+ free (rateString);
+ }
+ if (strlen (buf) + 1 >= sizeof (buf))
+ abort ();
+ *p++ = strdup (buf);
+ }
+ if (heaptrace_enabled != 0)
+ {
+ *p++ = strdup ("-H");
+ *p++ = strdup ("on");
+ }
+ if (iotrace_enabled != 0)
+ {
+ *p++ = strdup ("-i");
+ *p++ = strdup ("on");
+ }
+ if (synctrace_enabled != 0)
+ {
+ *p++ = strdup ("-s");
+ if (synctrace_thresh < 0)
+ *p++ = strdup ("calibrate");
+ else if (synctrace_thresh < 0)
+ *p++ = strdup ("all");
+ else
+ *p++ = dbe_sprintf ("%d", synctrace_thresh);
+ *p++ = dbe_sprintf (",%d", synctrace_scope);
+ }
+ if (follow_mode != 0)
+ {
+ *p++ = strdup ("-F");
+ char * fs = get_follow_usr_spec ();
+ if (fs)
+ *p++ = strdup (fs);
+ else
+ {
+ switch (get_follow_mode ())
+ {
+ case FOLLOW_ON:
+ *p++ = strdup ("on");
+ break;
+ case FOLLOW_ALL:
+ *p++ = strdup ("all");
+ break;
+ case FOLLOW_NONE:
+ default:
+ *p++ = strdup ("off");
+ break;
+ }
+ }
+ }
+ *p++ = strdup ("-a");
+ *p++ = strdup (get_archive_mode ());
+ if (java_mode != 0)
+ {
+ *p++ = strdup ("-j");
+ *p++ = strdup ("on");
+ }
+ if (pauseresume_sig != 0)
+ {
+ *p++ = strdup ("-y");
+ *p++ = dbe_sprintf ("%d%s", pauseresume_sig,
+ (pauseresume_pause == 0 ? ",r" : ""));
+ }
+ if (sample_sig != 0)
+ {
+ *p++ = strdup ("-l");
+ *p++ = dbe_sprintf ("%d", sample_sig);
+ }
+ if (sample_period != 0)
+ {
+ *p++ = strdup ("-S");
+ *p++ = dbe_sprintf ("%d", sample_period);
+ }
+ if (size_limit != 0)
+ {
+ *p++ = strdup ("-L");
+ *p++ = dbe_sprintf ("%d", size_limit);
+ }
+ if (expt_group != NULL)
+ {
+ *p++ = strdup ("-g");
+ *p++ = strdup (expt_group);
+ }
+ if (udir_name != 0)
+ {
+ *p++ = strdup ("-d");
+ *p++ = strdup (udir_name);
+ }
+ if (expt_name != 0)
+ {
+ *p++ = strdup ("-o");
+ *p++ = strdup (expt_name);
+ }
+ if (p - argv >= MAX_COLLECT_ARGS) // argument list too small -- fatal error
+ abort ();
+ return argv;
+}
+
+char *
+Coll_Ctrl::show_expt ()
+{
+ if (enabled == 0)
+ return NULL;
+ char UEbuf[4096];
+ UEbuf[0] = 0;
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("Creating experiment directory %s (Process ID: %ld) ...\n"),
+ ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")), (long) getpid ());
+ char *caller = getenv ("SP_COLLECTOR_FROM_GUI"); // Collector from GUI
+ if (caller != NULL) // Print non-localized message
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ NTXT ("\nCreating experiment directory %s (Process ID: %ld) ...\n"),
+ ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")), (long) getpid ());
+#if 0
+ char *fstype = get_fstype (store_dir);
+ if ((fstype != NULL) && (nofswarn == 0))
+ {
+ // only warn if clock or hwc profiling is turned on
+ if (clkprof_enabled || hwcprof_enabled_cnt != 0)
+ snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+ GTXT ("this experiment is being recorded to a file system \nof type \"%s\", which may distort the measured performance."),
+ fstype);
+ }
+#endif
+ return strdup (UEbuf);
+}
+
+void
+Coll_Ctrl::set_clk_params (int min, int res, int max, int hi, int norm, int lo)
+{
+ clk_params.min = min;
+ clk_params.res = res;
+ clk_params.max = max;
+ clk_params.hival = hi;
+ clk_params.normval = norm;
+ clk_params.lowval = lo;
+ set_clkprof_timer_target (clk_params.normval); // note: requires clk_params to be initialized!
+}
+
+char *
+Coll_Ctrl::reset_clkprof (int val)
+{
+ if (val != clkprof_timer)
+ {
+ // profiler has had to reset to a different value; warn user
+ char *msg = dbe_sprintf (
+ GTXT ("Warning: Clock profiling timer reset from %.3f millisec. to %.3f millisec. as required by profiling driver\n\n"),
+ (double) (clkprof_timer) / 1000., (double) (val) / 1000.);
+ adjust_clkprof_timer (val);
+ return msg;
+ }
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_clkprof (const char *string, char** warn)
+{
+ int ticks;
+ int nclkprof_timer;
+ int prevclkprof_enabled;
+ int prevclkprof_default;
+ *warn = NULL;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ /* if the first character is a +, warn user that it is no longer supported */
+ if (string[0] == '+')
+ return strdup (GTXT ("Warning: clock-based memoryspace and dataspace profiling is no longer supported\n"));
+ if (strcmp (string, "off") == 0)
+ {
+ clkprof_enabled = 0;
+ clkprof_default = 0;
+ return NULL;
+ }
+ else if (string == NULL || strcmp (string, "on") == 0)
+ nclkprof_timer = clk_params.normval;
+ else if (strcmp (string, "lo") == 0 || strcmp (string, "low") == 0)
+ nclkprof_timer = clk_params.lowval;
+ else if (strcmp (string, "hi") == 0 || strcmp (string, "high") == 0
+ || strcmp (string, "h") == 0)
+ nclkprof_timer = clk_params.hival;
+ else
+ {
+ /* the remaining string should be a number > 0 */
+ char *endchar = NULL;
+ double dval = strtod (string, &endchar);
+ if (*endchar == 'm' || *endchar == 0) /* user specified milliseconds */
+ dval = dval * 1000.;
+ else if (*endchar == 'u') /* user specified microseconds */
+ dval = dval;
+ else
+ return dbe_sprintf (GTXT ("Unrecognized clock-profiling interval `%s'\n"), string);
+ nclkprof_timer = (int) (dval + 0.5);
+ }
+ // we now have the proposed value; ensure it's within limits
+ if (nclkprof_timer <= 0)
+ return dbe_sprintf (GTXT ("Unrecognized clock-profiling interval `%s'\n"), string);
+
+ // Check consistency with experiment
+ prevclkprof_enabled = clkprof_enabled;
+ prevclkprof_default = clkprof_default;
+ clkprof_enabled = 1;
+ clkprof_default = 0;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ clkprof_default = prevclkprof_default;
+ clkprof_enabled = prevclkprof_enabled;
+ return ret;
+ }
+ int ref_nclkprof_timer = nclkprof_timer;
+
+ // check for minimum value
+ if (nclkprof_timer < clk_params.min)
+ {
+ /* value too small, use minimum value, with warning */
+ *warn = dbe_sprintf (
+ GTXT ("Warning: Clock profiling at %.3f millisec. interval is not supported on this system; minimum %.3f millisec. used\n"),
+ (double) (nclkprof_timer) / 1000., (double) (clk_params.min) / 1000.);
+ nclkprof_timer = clk_params.min;
+ }
+
+ // check for maximum value
+ if (nclkprof_timer > clk_params.max)
+ {
+ *warn = dbe_sprintf (
+ GTXT ("Clock profiling at %.3f millisec. interval is not supported on this system; maximum %.3f millisec. used\n"),
+ (double) (nclkprof_timer) / 1000., (double) (clk_params.max) / 1000.);
+ nclkprof_timer = clk_params.max;
+ }
+
+ /* see if setting is a multiple of the period */
+ if (nclkprof_timer > clk_params.res)
+ {
+ ticks = ((nclkprof_timer / clk_params.res) * clk_params.res);
+ if (ticks != nclkprof_timer)
+ {
+ /* no, we need to reset to a multiple */
+ *warn = dbe_sprintf (
+ GTXT ("Clock profile interval rounded from %.3f to %.3f (system resolution = %.3f) millisec."),
+ (double) (nclkprof_timer) / 1000., (double) (ticks) / 1000.,
+ (double) (clk_params.res) / 1000.);
+ nclkprof_timer = ticks;
+ }
+ }
+
+ // limit reference "target" rate. Target rate is also used for HWCS.
+ if (ref_nclkprof_timer > PROFINT_MAX)
+ ref_nclkprof_timer = PROFINT_MAX;
+ if (ref_nclkprof_timer < PROFINT_MIN)
+ ref_nclkprof_timer = PROFINT_MIN;
+ set_clkprof_timer_target (ref_nclkprof_timer);
+ adjust_clkprof_timer (nclkprof_timer);
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_synctrace (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ char *comma_p = NULL;
+ if (string == NULL)
+ {
+ /* no argument provided, use default: calibrate and native */
+ synctrace_enabled = 1;
+ synctrace_thresh = -1;
+ synctrace_scope = SYNCSCOPE_NATIVE;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ synctrace_enabled = 0;
+ return ret;
+ }
+ return NULL;
+ }
+ char *val = strdup (string);
+ /* see if there's a comma in the string */
+ char *next = strchr (val, (int) ',');
+ if (next != NULL)
+ {
+ /* remember where the comma was */
+ comma_p = next;
+
+ /* set the scope based on the characters following the comma */
+ synctrace_scope = 0;
+ next++;
+ while (*next != 0)
+ {
+ if (*next == 'n')
+ synctrace_scope |= SYNCSCOPE_NATIVE;
+ else if (*next == 'j')
+ synctrace_scope |= SYNCSCOPE_JAVA;
+ else
+ return dbe_sprintf (GTXT ("Unrecognized synchronization tracing threshold `%s'\n"), string);
+ next++;
+ }
+ if (synctrace_scope == 0)
+ synctrace_scope = SYNCSCOPE_NATIVE;
+ /* clear the comma for the threshold determination */
+ *comma_p = 0;
+ }
+ else /* no ",<scope>" -- default to native and Java */
+ synctrace_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA;
+ if (!strlen (val) || !strcmp (val, "calibrate") || !strcmp (val, "on"))
+ {
+ /* use default: calibrate and native */
+ synctrace_enabled = 1;
+ synctrace_thresh = -1;
+ free (val);
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ synctrace_enabled = 0;
+ return ret;
+ }
+ return NULL;
+ }
+ if (strcmp (val, "off") == 0)
+ {
+ synctrace_enabled = 0;
+ free (val);
+ return NULL;
+ }
+ if (strcmp (val, "all") == 0)
+ {
+ /* set to record all events */
+ synctrace_thresh = 0;
+ synctrace_enabled = 1;
+ char *ret = check_consistency ();
+ free (val);
+ if (ret != NULL)
+ {
+ synctrace_enabled = 0;
+ return ret;
+ }
+ return NULL;
+ }
+ /* the remaining string should be a number >= 0 */
+ char *endchar = NULL;
+ int tval = (int) strtol (val, &endchar, 0);
+ free (val);
+ if (*endchar != 0 || tval < 0)
+ {
+ /* invalid setting */
+ /* restore the comma, if it was zeroed out */
+ if (comma_p != NULL)
+ *comma_p = ',';
+ return dbe_sprintf (GTXT ("Unrecognized synchronization tracing threshold `%s'\n"), string);
+ }
+ synctrace_thresh = tval;
+ synctrace_enabled = 1;
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_heaptrace (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+ {
+ heaptrace_enabled = 1;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ heaptrace_enabled = 0;
+ return ret;
+ }
+ return NULL;
+ }
+ if (strcmp (string, "off") == 0)
+ {
+ heaptrace_enabled = 0;
+ return NULL;
+ }
+#if 0
+ if (strcmp (string, "check") == 0)
+ {
+ /* set to check for over/underruns */
+ heaptrace_checkenabled = 1;
+ heaptrace_enabled = 1;
+ return NULL;
+ }
+ if (strcmp (string, "clear") == 0)
+ {
+ /* set to check for over/underruns, and store patterns */
+ heaptrace_checkenabled = 2;
+ heaptrace_enabled = 1;
+ return NULL;
+ }
+#endif
+ return dbe_sprintf (GTXT ("Unrecognized heap tracing parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_iotrace (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+ {
+ iotrace_enabled = 1;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ iotrace_enabled = 0;
+ return ret;
+ }
+ return NULL;
+ }
+ if (strcmp (string, "off") == 0)
+ {
+ iotrace_enabled = 0;
+ return NULL;
+ }
+ return dbe_sprintf (GTXT ("Unrecognized I/O tracing parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_count (const char *string)
+{
+ int ret = -1;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0 || strcmp (string, "off") == 0)
+ {
+ count_enabled = 0;
+ ret = 0;
+ }
+ if (strcmp (string, "on") == 0)
+ {
+ count_enabled = 1;
+ char *cret = check_consistency ();
+ if (cret != NULL)
+ {
+ count_enabled = 0;
+ return cret;
+ }
+ ret = 0;
+ }
+ if (strcmp (string, "static") == 0)
+ {
+ count_enabled = -1;
+ char *cret = check_consistency ();
+ if (cret != NULL)
+ {
+ count_enabled = 0;
+ return cret;
+ }
+ ret = 0;
+ }
+ if (ret == 0)
+ {
+ if (count_enabled != 0)
+ {
+ /* ensure that sample period is 0, if set by default */
+ if (sample_default == 1)
+ sample_period = 0;
+ /* ensure that clock profiling is off, if set by default */
+ if (clkprof_default == 1)
+ {
+ clkprof_default = 0;
+ clkprof_enabled = 0;
+ }
+ if (hwcprof_default == 1)
+ hwcprof_default = 0;
+ }
+ return NULL;
+ }
+ return dbe_sprintf (GTXT ("Unrecognized count parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_time_run (const char *valarg)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (valarg == NULL) /* invalid setting */
+ return strdup (GTXT ("time parameter can not be NULL\n"));
+ /* the string should be a number >= 0 */
+ int prev_start_delay = start_delay;
+ int prev_time_run = time_run;
+ const char *endchar = valarg;
+ char *newchar = NULL;
+ int val = 0;
+ if (*endchar != '-')
+ {
+ val = (int) strtol (endchar, &newchar, 0);
+ endchar = newchar;
+ if (val < 0)
+ return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+ if (*endchar == 'm')
+ {
+ val = val * 60; /* convert to seconds */
+ endchar++;
+ }
+ else if (*endchar == 's') /* no conversion needed */
+ endchar++;
+ if (*endchar == 0)
+ {
+ time_run = val;
+ return NULL;
+ }
+ else if (*endchar != '-')
+ return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+ }
+ /* a second number is provided */
+ start_delay = val;
+ endchar++;
+ val = (int) strtol (endchar, &newchar, 0);
+ endchar = newchar;
+ if (val < 0)
+ {
+ start_delay = prev_start_delay;
+ return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+ }
+ if (*endchar == 'm')
+ {
+ val = val * 60; /* convert to seconds */
+ endchar++;
+ }
+ else if (*endchar == 's') /* no conversion needed */
+ endchar++;
+ if (*endchar != 0)
+ {
+ start_delay = prev_start_delay;
+ return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+ }
+ time_run = val;
+ if (time_run != 0 && start_delay >= time_run)
+ {
+ start_delay = prev_start_delay;
+ return dbe_sprintf (GTXT ("Invalid time parameter `%s': start time must be earlier than end time\n"), valarg);
+ }
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ start_delay = prev_start_delay;
+ time_run = prev_time_run;
+ return ret;
+ }
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_attach_pid (char *valarg)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (valarg == NULL)
+ return strdup (GTXT ("Specified PID can not be NULL\n"));
+
+ /* the string should be a number corresponding to an active process' pid */
+ char *endchar = NULL;
+ int val = (int) strtol (valarg, &endchar, 0);
+ if (*endchar != 0 || val < 0)
+ return dbe_sprintf (GTXT ("Invalid process pid `%s'\n"), valarg);
+ int prev_attach_pid = attach_pid;
+ attach_pid = val;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ attach_pid = prev_attach_pid;
+ return ret;
+ }
+ return NULL;
+}
+
+void
+Coll_Ctrl::free_hwc_fields (Hwcentry * tmpctr)
+{
+ if (tmpctr->name != NULL)
+ free (tmpctr->name);
+ if (tmpctr->int_name != NULL)
+ free (tmpctr->int_name);
+ memset (tmpctr, 0, sizeof (Hwcentry));
+ tmpctr->reg_num = -1;
+}
+
+void
+Coll_Ctrl::hwcentry_dup (Hwcentry *hnew, Hwcentry *_hwc)
+{
+ *hnew = *_hwc;
+ if (_hwc->name != NULL)
+ hnew->name = strdup (_hwc->name);
+ else
+ hnew->name = NULL;
+ if (_hwc->int_name != NULL)
+ hnew->int_name = strdup (_hwc->int_name);
+ else
+ hnew->int_name = NULL;
+ if (_hwc->metric != NULL)
+ hnew->metric = strdup (_hwc->metric);
+ else
+ hnew->metric = NULL;
+ if (_hwc->short_desc != NULL)
+ hnew->short_desc = strdup (_hwc->short_desc);
+ else
+ hnew->short_desc = NULL;
+ if (_hwc->reg_list != NULL)
+ {
+ hnew->reg_list = (regno_t*) malloc (sizeof (regno_t*) * MAX_PICS);
+ // poor way of dealing with malloc failure
+ if (hnew->reg_list)
+ {
+ for (int i = 0; i < MAX_PICS; i++)
+ {
+ hnew->reg_list[i] = _hwc->reg_list[i];
+ if (hnew->reg_list[i] == REGNO_ANY)
+ break;
+ }
+ }
+ }
+}
+
+// Routine to initialize the HWC tables, set up the default experiment, etc.
+void
+Coll_Ctrl::setup_hwc ()
+{
+ static bool is_hwc_setup = false;
+ if (is_hwc_setup == true)
+ return;
+ // try to set the default counters
+ is_hwc_setup = true;
+ set_hwcdefault ();
+}
+
+hrtime_t
+Coll_Ctrl::clkprof_timer_2_hwcentry_min_time (int target_clkprof_usec)
+{
+ hrtime_t hwc_nanosec;
+ if (target_clkprof_usec == clk_params.normval)
+ hwc_nanosec = HWCTIME_ON;
+ else if (target_clkprof_usec == clk_params.lowval)
+ hwc_nanosec = HWCTIME_LO;
+ else if (target_clkprof_usec == clk_params.hival)
+ hwc_nanosec = HWCTIME_HI;
+ else
+ hwc_nanosec = 1000LL * target_clkprof_usec; // nanoseconds
+ return hwc_nanosec;
+}
+
+void
+Coll_Ctrl::set_clkprof_timer_target (int microseconds)
+{
+ clkprof_timer = microseconds;
+ clkprof_timer_target = microseconds;
+ hrtime_t hwc_min_time_nanosec = clkprof_timer_2_hwcentry_min_time (microseconds);
+ for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+ {
+ hwctr[ii].min_time_default = hwc_min_time_nanosec;
+ hwc_update_val (&hwctr[ii]);
+ }
+}
+
+void
+Coll_Ctrl::adjust_clkprof_timer (int use)
+{
+ clkprof_timer = use;
+}
+
+/* set HWC counter set from a string */
+char * /* return an error string */
+Coll_Ctrl::set_hwcstring (const char *string, char **warnmsg)
+{
+ *warnmsg = NULL;
+ if (string == NULL || strcmp (string, "off") == 0)
+ {
+ hwcprof_enabled_cnt = 0;
+ return NULL;
+ }
+ setup_hwc ();
+ int old_cnt = hwcprof_enabled_cnt;
+ int old_hwcprof_default = hwcprof_default;
+
+ /* reset any previous count to zero */
+ hwcprof_enabled_cnt = 0;
+ char *ret = add_hwcstring (string, warnmsg);
+ if (ret != NULL)
+ {
+ // restore previous setting
+ hwcprof_enabled_cnt = old_cnt;
+ hwcprof_default = old_hwcprof_default;
+ }
+ return ret;
+}
+
+/* add additional HWC counters to counter set from string */
+char * /* return an error string */
+Coll_Ctrl::add_hwcstring (const char *string, char **warnmsg)
+{
+ *warnmsg = NULL;
+ if (string == NULL || strcmp (string, "off") == 0)
+ {
+ hwcprof_enabled_cnt = 0;
+ return NULL;
+ }
+ setup_hwc ();
+ int rc = 0;
+ int old_cnt = hwcprof_enabled_cnt;
+ int prev_cnt = hwcprof_enabled_cnt;
+ // int old_hwcprof_default = hwcprof_default;
+ char UEbuf[MAXPATHLEN * 5];
+ int UEsz;
+ Hwcentry tmpctr[MAX_PICS];
+ Hwcentry * ctrtable[MAX_PICS];
+ char *emsg;
+ char *wmsg;
+ UEbuf[0] = 0;
+ UEsz = sizeof (UEbuf);
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (hwcprof_default == 0)
+ {
+ /* Copy the counters already defined */
+ for (int ii = 0; ii < prev_cnt; ii++)
+ tmpctr[ii] = hwctr[ii];
+ }
+ else /* the previously-defined counters were defaulted; don't copy them */
+ prev_cnt = 0;
+
+ /* look up the CPU version */
+ cpc_cpuver = hwc_get_cpc_cpuver ();
+ if (string && *string)
+ {
+ /* lookup counters */
+ /* set up a pointer array */
+ for (unsigned ii = 0; ii < MAX_PICS; ii++)
+ ctrtable[ii] = &tmpctr[ii];
+ hrtime_t global_min_time = clkprof_timer_2_hwcentry_min_time (clkprof_timer_target);
+ rc = hwc_lookup (kernelHWC, global_min_time, string, &ctrtable[prev_cnt], MAX_PICS - prev_cnt, &emsg, &wmsg);
+ if (wmsg != NULL)
+ *warnmsg = wmsg;
+ if (rc < 0)
+ return emsg;
+ /* set count for sum of old and new counters */
+ rc = rc + prev_cnt;
+ }
+
+ /* even though the actual hwctr[] array is not updated, we can check consistency */
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ hwcprof_enabled_cnt = old_cnt;
+ return ret;
+ }
+
+ /* finally, validate the full counter set */
+ emsg = hwc_validate_ctrs (kernelHWC, ctrtable, rc);
+ if (emsg != NULL)
+ {
+ hwcprof_enabled_cnt = old_cnt;
+ return emsg;
+ }
+
+ /* success, update real counters and the string for them */
+ /* turn off the default */
+ hwcprof_default = 0;
+ hwcprof_enabled_cnt = rc;
+ free (hwc_string);
+ for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+ {
+ /* shallow copy of new counters */
+ hwctr[ii] = tmpctr[ii];
+ char *rateString = hwc_rate_string (&hwctr[ii], 0);
+ snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+ NTXT (",%s,%s"), hwctr[ii].name,
+ rateString ? rateString : "");
+ free (rateString);
+ }
+ /* now duplicate that string, skipping the leading comma */
+ hwc_string = strdup (&UEbuf[1]);
+ return NULL;
+}
+
+/* add default HWC counters to counter set with resolution (on, hi, or lo) */
+/* Note that the resultion will also be used to set the clock-profiling default */
+char * /* return an error string */
+Coll_Ctrl::add_default_hwcstring (const char *resolution, char **warnmsg, bool add, bool forKernel)
+{
+ setup_hwc ();
+ *warnmsg = NULL;
+ char *def_string = hwc_get_default_cntrs2 (forKernel, 1);
+ if (def_string == NULL)
+ {
+ /* no string defined, format and return an error message */
+ char cpuname[128];
+ hwc_get_cpuname (cpuname, sizeof (cpuname));
+ return dbe_sprintf (GTXT ("No default HW counter set is defined for %s\n"), cpuname);
+ }
+ int len = strlen (def_string);
+ if (len == 0)
+ {
+ /* string zero-length, meaning default counters can't be used */
+ char cpuname[128];
+ hwc_get_cpuname (cpuname, sizeof (cpuname));
+ return dbe_sprintf (GTXT ("HW counter set for %s cannot be loaded on this system\n"), cpuname);
+ }
+ /* allocate return string */
+ int retsize = 2 * len + 10;
+ char *ret = (char *) malloc (retsize);
+ if (ret == NULL)
+ return strdup (GTXT ("internal error formating HW counter set; malloc failed\n"));
+ *ret = 0;
+ char *retp = ret;
+ char *stringp = def_string;
+ int first = 1;
+ char *hwc_defaultx = strdup (def_string);
+
+ /* now massage the string in order to insert resolution for each counter */
+ for (;;)
+ {
+ /* find the next comma */
+ char * next;
+ char *nextp;
+ if (first == 1)
+ nextp = stringp;
+ else
+ nextp = stringp + 1;
+ first = 0;
+ if ((next = strchr (nextp, (int) ',')) != NULL)
+ {
+ if (next == nextp)
+ {
+ /* next counter is zero-length -- invalid string */
+ char cpuname[128];
+ hwc_get_cpuname (cpuname, sizeof (cpuname));
+ free (ret);
+ ret = dbe_sprintf (GTXT ("HW counter set for %s, \"%s\", format error\n"), cpuname, hwc_defaultx);
+ free (hwc_defaultx);
+ return ret;
+ }
+ /* another field found */
+ *next = 0;
+ char nextc = *(next + 1);
+ if ((nextc == 0) || (nextc == ','))
+ {
+ /* either ,, between fields, or string ends in comma */
+ /* append the string */
+ strncat (retp, stringp, (retsize - strlen (retp) - 1));
+ strncat (retp, ",", (retsize - strlen (retp) - 1));
+ strncat (retp, resolution, (retsize - strlen (retp) - 1));
+ if (nextc == 0) /* string ended in comma; we're done */
+ break;
+ }
+ else
+ {
+ /* string had only one comma between counter names; that's not valid */
+ char cpuname[128];
+ hwc_get_cpuname (cpuname, sizeof (cpuname));
+ free (ret);
+ ret = dbe_sprintf (GTXT ("HW counter set for %s, \"%s\", format error\n"), cpuname, hwc_defaultx);
+ free (hwc_defaultx);
+ return ret;
+ }
+ /* string had ,, between fields; move to next field */
+ stringp = next + 1;
+ if (* (stringp + 1) == 0) /* name ended in ,, -- we're done */
+ break;
+ continue;
+ }
+ else
+ {
+ /* no comma found, add the last counter and the comma and resolution */
+ strncat (retp, stringp, (retsize - strlen (retp) - 1));
+ strncat (retp, ",", (retsize - strlen (retp) - 1));
+ strncat (retp, resolution, (retsize - strlen (retp) - 1));
+ break;
+ }
+ }
+
+ /* we have now formatted the new string, with resolution inserted */
+ char *ccret;
+ if (add == true)
+ ccret = add_hwcstring (ret, warnmsg);
+ else
+ ccret = set_hwcstring (ret, warnmsg);
+ free (hwc_defaultx);
+ free (ret);
+
+ /* now set the clock-profiling timer, if on by default */
+ if (clkprof_default == 1)
+ {
+ if (strcmp (resolution, NTXT ("on")) == 0)
+ set_clkprof_timer_target (clk_params.normval);
+ else if (strcmp (resolution, NTXT ("lo")) == 0)
+ set_clkprof_timer_target (clk_params.lowval);
+ else if (strcmp (resolution, NTXT ("hi")) == 0)
+ set_clkprof_timer_target (clk_params.hival);
+ }
+ return ccret;
+}
+
+void
+Coll_Ctrl::set_hwcdefault ()
+{
+ char *string = hwc_get_default_cntrs2 (kernelHWC, 1);
+ if (string != NULL)
+ {
+ if (strlen (string) == 0)
+ hwcprof_default = 0;
+ else
+ {
+ char * warnmsg = NULL;
+ char *ccret = add_hwcstring (string, &warnmsg);
+ if (ccret != NULL)
+ {
+#if 0
+ /* set string to zero-length so that it won't be used again */
+ hwc_set_default_cntrs (kernelHWC, NTXT (""));
+#endif
+ hwcprof_default = 0;
+ }
+ else
+ hwcprof_default = 1;
+ }
+ free (string);
+ }
+ else
+ hwcprof_default = 0;
+}
+
+void
+Coll_Ctrl::disable_hwc ()
+{
+ hwcprof_enabled_cnt = 0;
+ hwcprof_default = 0;
+ free (hwc_string);
+ hwc_string = NULL;
+}
+
+char *
+Coll_Ctrl::set_sample_period (const char *string)
+{
+ int val;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strcmp (string, "on") == 0)
+ val = 1;
+ else if (strcmp (string, "off") == 0)
+ val = 0;
+ else
+ {
+ /* string should be a number > 0 */
+ char *endchar = NULL;
+ val = (int) strtol (string, &endchar, 0);
+ if (*endchar != 0 || val <= 0)
+ return dbe_sprintf (GTXT ("Unrecognized sample period `%s'\n"), string);
+ }
+ /* set that value */
+ int prev_sample_period = sample_period;
+ sample_period = val;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ sample_period = prev_sample_period;
+ return ret;
+ }
+ sample_default = 0;
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_size_limit (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0
+ || strcmp (string, "unlimited") == 0 || strcmp (string, "none") == 0)
+ {
+ size_limit = 0;
+ return NULL;
+ }
+ /* string should be a number >0; 0 is an error */
+ char *endchar = NULL;
+ int val = (int) strtol (string, &endchar, 0);
+ if (*endchar != 0 || val <= 0)
+ return dbe_sprintf (GTXT ("Unrecognized size limit `%s'\n"), string);
+ size_limit = val;
+ return 0;
+}
+
+void
+Coll_Ctrl::build_data_desc ()
+{
+ char spec[DD_MAXPATHLEN];
+ spec[0] = 0;
+
+ // Put sample sig before clock profiling. Dbx uses PROF
+ // for that purpose and we want it to be processed first.
+ if (project_home)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "P:%s;", project_home);
+ if (sample_sig != 0)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "g:%d;", sample_sig);
+ if (pauseresume_sig != 0)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "d:%d%s;", pauseresume_sig,
+ (pauseresume_pause == 1 ? "p" : ""));
+ if (clkprof_enabled == 1)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "p:%d;", clkprof_timer);
+ if (synctrace_enabled == 1)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "s:%d,%d;", synctrace_thresh, synctrace_scope);
+ if (heaptrace_enabled == 1)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "H:%d;", heaptrace_checkenabled);
+ if (iotrace_enabled == 1)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "i:;");
+ if (hwcprof_enabled_cnt > 0)
+ {
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "h:%s",
+ (hwcprof_default == true) ? "*" : "");
+ for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+ {
+ /* min_time is a "new" field.
+ *
+ * To help process_data_descriptor() in hwcfuncs.c parse
+ * the HWC portion of this string -- specifically, to
+ * recognize min_time when it's present and skip over
+ * when it's not -- we prepend 'm' to the min_time value.
+ *
+ * When we no longer worry about, say, an old dbx
+ * writing this string and a new libcollector looking for
+ * the min_time field, the 'm' character can be
+ * removed and process_data_descriptor() simplified.
+ */
+ hrtime_t min_time = hwctr[ii].min_time;
+ if (min_time == HWCTIME_TBD)
+ // user did not specify any value for overflow rate
+ min_time = hwctr[ii].min_time_default;
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec),
+ "%s%s:%s:%d:%d:m%lld:%d:%d:0x%x", ii ? "," : "",
+ strcmp (hwctr[ii].name, hwctr[ii].int_name) ? hwctr[ii].name : "",
+ hwctr[ii].int_name, hwctr[ii].reg_num, hwctr[ii].val,
+ min_time, ii, /*tag*/ hwctr[ii].timecvt, hwctr[ii].memop);
+ }
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), ";");
+ }
+ if ((time_run != 0) || (start_delay != 0))
+ {
+ if (start_delay != 0)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "t:%d:%d;", start_delay, time_run);
+ else
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "t:%d;", time_run);
+ }
+ if (sample_period != 0)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "S:%d;",
+ sample_period);
+ if (size_limit != 0)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "L:%d;",
+ size_limit);
+ if (java_mode != 0)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "j:%d;", (int) java_mode);
+ if (follow_mode != FOLLOW_NONE)
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "F:%d;", (int) follow_mode);
+ snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "a:%s;", archive_mode);
+ if (strlen (spec) + 1 >= sizeof (spec))
+ abort ();
+ free (data_desc);
+ data_desc = strdup (spec);
+}
+
+char *
+Coll_Ctrl::check_group ()
+{
+ char group_file[MAXPATHLEN];
+ if (expt_group == NULL)
+ return NULL;
+ // Is the group an relative path, with a store directory set?
+ if ((expt_group[0] == '/') || ((udir_name == NULL) || (udir_name[0] == '0')))
+ snprintf (group_file, sizeof (group_file), "%s", expt_group);
+ else // relative path, store directory; make group_file in that directory
+ snprintf (group_file, sizeof (group_file), "%s/%s", udir_name, expt_group);
+ // See if we can write the group file
+ int ret = access (group_file, W_OK);
+ if (ret != 0)
+ {
+ if (errno == ENOENT)
+ {
+ char *stmp = group_file;
+ char *dir = dirname (stmp);
+ ret = access (dir, W_OK);
+ if (ret != 0) // group file does not exist;
+ return dbe_sprintf (GTXT ("Directory (%s) for group file %s is not writeable: %s\n"),
+ dir, group_file, strerror (errno));
+ }
+ else
+ return dbe_sprintf (GTXT ("Group file %s is not writeable: %s\n"),
+ group_file, strerror (errno));
+ }
+ return NULL;
+}
+
+char *
+Coll_Ctrl::join_group ()
+{
+ int tries = 0;
+ int groupfd;
+ FILE *file;
+ char group_file[MAXPATHLEN];
+ struct stat statbuf;
+ struct flock flockbuf;
+ flockbuf.l_type = F_WRLCK;
+ flockbuf.l_whence = SEEK_SET;
+ flockbuf.l_start = 0;
+ flockbuf.l_len = 0;
+ if (expt_group == NULL)
+ return NULL;
+ // Is the group an relative path, with a store directory set?
+ if (expt_group[0] == '/' || udir_name == NULL || udir_name[0] == '0')
+ snprintf (group_file, sizeof (group_file), "%s", expt_group);
+ else // relative path, store directory; make group_file in that directory
+ snprintf (group_file, sizeof (group_file), "%s/%s", udir_name, expt_group);
+ for (;;)
+ {
+ tries++;
+ // try to open the group file
+ while ((groupfd = open (group_file, O_RDWR)) >= 0)
+ {
+ if (uinterrupt == 1)
+ {
+ close (groupfd);
+ return strdup (GTXT ("user interrupt\n"));
+ }
+ // it's opened, now lock it
+ if (fcntl (groupfd, F_SETLK, &flockbuf) != -1)
+ {
+ // we got the lock; check the file size
+ if (fstat (groupfd, &statbuf) != 0)
+ {
+ // can't stat the file -- give up
+ close (groupfd);
+ return dbe_sprintf (GTXT ("Can't fstat group file %s\n"), group_file);
+ }
+ if (statbuf.st_size == 0)
+ {
+ // size is zero: we got the lock just as someone
+ // else created the group file
+ // close the file and release the lock; try again
+ close (groupfd);
+ continue;
+ }
+ else
+ {
+ // size is non-zero, add our record
+ file = fdopen (groupfd, "a");
+ if (file == NULL)
+ {
+ close (groupfd);
+ return dbe_sprintf (GTXT ("Can't access group file %s\n"), group_file);
+ }
+ if (fprintf (file, "%s\n", store_ptr) <= 0)
+ {
+ fclose (file);
+ return dbe_sprintf (GTXT ("Can't update group file %s\n"), group_file);
+ }
+ // close the file, releasing our lock
+ fclose (file);
+ return NULL;
+ }
+ }
+ else
+ {
+ // can't get the lock, close the file and try again
+ close (groupfd);
+ if (uinterrupt == 1)
+ return strdup (GTXT ("user interrupt\n"));
+ if (tries == 11900)
+ return dbe_sprintf (GTXT ("Timed out: waiting for group file %s\n"), group_file);
+#if 0
+ if (tries % 500 == 0)
+ USR_WARN (GTXT ("Waiting for group file %s . . ."), group_file);
+#endif
+ usleep (10000U);
+ continue;
+ }
+ }
+ // If the error was not that the file did not exist, report it
+ if (errno != ENOENT)
+ return dbe_sprintf (GTXT ("Can't open group file %s: %s\n"),
+ group_file, strerror (errno));
+ // the file did not exist, try to create it
+ groupfd = open (group_file, O_CREAT | O_EXCL | O_RDWR, 0666);
+ if (groupfd < 0)
+ {
+ // we could not create the file
+ if (errno == EEXIST)
+ continue;
+ return dbe_sprintf (GTXT ("Can't create group file %s: %s\n"),
+ group_file, strerror (errno));
+ }
+ // we created the group file, now lock it, waiting for the lock
+ while (fcntl (groupfd, F_SETLKW, &flockbuf) == -1)
+ {
+ // we created the file, but couldn't lock it
+ if (errno != EINTR)
+ return dbe_sprintf (GTXT ("Unable to lock group file %s\n"), group_file);
+ }
+ // we created and locked the file, write to it
+ file = fdopen (groupfd, "a");
+ if (file == NULL)
+ {
+ close (groupfd);
+ return dbe_sprintf (GTXT ("Can't access group file %s\n"), group_file);
+ }
+ // write the header line
+ if (fprintf (file, "%s\n", SP_GROUP_HEADER) <= 0)
+ {
+ fclose (file);
+ return dbe_sprintf (GTXT ("Can't initialize group file %s\n"), group_file);
+ }
+ if (fprintf (file, "%s\n", store_ptr) <= 0)
+ {
+ fclose (file);
+ return dbe_sprintf (GTXT ("Can't update group file %s\n"), group_file);
+ }
+ // finally, close the file, releasing the lock
+ fclose (file);
+ return NULL;
+ }
+ // never reached
+}
+
+char *
+Coll_Ctrl::set_directory (char *dir, char **warn)
+{
+ struct stat statbuf;
+ *warn = NULL;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (stat (dir, &statbuf) != 0)
+ return dbe_sprintf (GTXT ("Can't set directory `%s': %s\n"),
+ dir, strerror (errno));
+ if (!S_ISDIR (statbuf.st_mode))
+ return dbe_sprintf (GTXT ("Can't set directory `%s': %s\n"),
+ dir, strerror (ENOTDIR));
+ free (udir_name);
+ udir_name = strdup (dir);
+
+ // Process new setting
+ *warn = preprocess_names ();
+ if ((uexpt_name != NULL) || (interactive != 0))
+ {
+ char *ret = update_expt_name (true, true);
+ if (ret != NULL)
+ {
+ if (*warn != NULL)
+ {
+ char *msg = dbe_sprintf ("%s%s", *warn, ret);
+ free (*warn);
+ free (ret);
+ *warn = msg;
+ }
+ else
+ *warn = ret;
+ }
+ }
+ else
+ (void) update_expt_name (false, false);
+ return NULL; // All is OK
+}
+
+int
+Coll_Ctrl::set_target (char* targetname)
+{
+ free (target_name);
+ target_name = NULL;
+ if (targetname != NULL)
+ target_name = strdup (targetname);
+ return 0;
+}
+
+void
+Coll_Ctrl::set_default_stem (const char* stem)
+{
+ default_stem = strdup (stem);
+ preprocess_names ();
+ (void) update_expt_name (false, false); // no warnings
+}
+
+char *
+Coll_Ctrl::set_expt (const char *ename, char **warn, bool overwriteExp)
+{
+ *warn = NULL;
+ if (ename == NULL)
+ {
+ free (uexpt_name);
+ uexpt_name = NULL;
+ return NULL;
+ }
+ char *exptname = canonical_path(strdup(ename));
+ size_t i = strlen (exptname);
+ if (i < 4 || strcmp (&exptname[i - 3], ".er") != 0)
+ {
+ free (exptname);
+ return dbe_sprintf (GTXT ("Experiment name `%s' must end in `.er'\n"),
+ ename);
+ }
+ // Name is OK
+ free (uexpt_name);
+ uexpt_name = exptname;
+ preprocess_names ();
+ char *err = update_expt_name (true, true, overwriteExp);
+ if (err != NULL)
+ return err;
+ if (overwriteExp)
+ {
+ char *nm = dbe_sprintf ("%s/%s", store_dir, base_name);
+ struct stat statbuf;
+ char *cmd = dbe_sprintf ("/bin/rm -rf %s >/dev/null 2>&1", nm);
+ system (cmd);
+ free (cmd);
+ if (stat (nm, &statbuf) == 0)
+ return dbe_sprintf (GTXT ("Cannot remove experiment `%s'\n"), nm);
+ if (errno != ENOENT)
+ return dbe_sprintf (GTXT ("Cannot remove experiment `%s'\n"), nm);
+ free (nm);
+ }
+ *warn = update_expt_name (true, false);
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_group (char *groupname)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (expt_group != NULL)
+ {
+ free (expt_group);
+ expt_group = NULL;
+ }
+ if (groupname == NULL)
+ {
+ // reset the name
+ preprocess_names ();
+ (void) update_expt_name (true, false);
+ return NULL;
+ }
+ int i = (int) strlen (groupname);
+ if (i < 5 || strcmp (&groupname[i - 4], ".erg") != 0)
+ return dbe_sprintf (GTXT ("Experiment group name `%s'must end in `.erg'\n"), groupname);
+ expt_group = strdup (groupname);
+ preprocess_names ();
+ (void) update_expt_name (true, false);
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_java_mode (const char *string)
+{
+ struct stat statbuf;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+ {
+#if defined(GPROFNG_JAVA_PROFILING)
+ int prev_java_mode = java_mode;
+ int prev_java_default = java_default;
+ java_mode = 1;
+ java_default = 0;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ java_mode = prev_java_mode;
+ java_default = prev_java_default;
+ return ret;
+ }
+ return NULL;
+#else
+ return strdup (GTXT ("gprofng was built without support for profiling Java applications\n"));
+#endif
+ }
+ if (strcmp (string, "off") == 0)
+ {
+ int prev_java_mode = java_mode;
+ int prev_java_default = java_default;
+ java_mode = 0;
+ java_default = 0;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ java_mode = prev_java_mode;
+ java_default = prev_java_default;
+ return ret;
+ }
+ free (java_path);
+ java_path = NULL;
+ return NULL;
+ }
+ /* any other value should be a path to Java installation directory */
+ if (stat (string, &statbuf) == 0)
+ {
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+ {
+ // it's a directory -- set the Java path to it
+ int prev_java_mode = java_mode;
+ int prev_java_default = java_default;
+ java_mode = 1;
+ java_default = 0;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ java_mode = prev_java_mode;
+ java_default = prev_java_default;
+ return ret;
+ }
+ return set_java_path (string);
+ }
+ }
+ return dbe_sprintf (GTXT ("Java-profiling parameter is neither \"on\", nor \"off\", nor is it a directory: `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_java_path (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ free (java_path);
+ java_path = strdup (string);
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_java_args (char *string)
+{
+ char *next;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ char *prev_java_args = java_args;
+ if (string == NULL || strlen (string) == 0)
+ java_args = strdup ("");
+ else
+ java_args = strdup (string);
+ // now count the number of Java arguments
+ for (next = java_args; *next; next++)
+ {
+ if (*next == ' ' || *next == '\t')
+ continue;
+ njava_args++;
+ for (++next; *next; next++)
+ if (*next == ' ' || *next == '\t')
+ break;
+ if (!*next)
+ break;
+ }
+ if (njava_args == 0)
+ java_args = NULL;
+ char *ret = check_consistency ();
+ if (ret != NULL)
+ {
+ java_args = prev_java_args;
+ return ret;
+ }
+ free (prev_java_args);
+ return NULL;
+}
+
+char *
+Coll_Ctrl::set_follow_mode (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ free (follow_spec_usr);
+ free (follow_spec_cmp);
+ follow_spec_usr = NULL;
+ follow_spec_cmp = NULL;
+ if (string == NULL || strlen (string) == 0 || strcmp (string, "all") == 0
+ || strcmp (string, "on") == 0)
+ {
+ follow_mode = FOLLOW_ON;
+ follow_default = 0;
+ return NULL;
+ }
+ if (strcmp (string, "off") == 0)
+ {
+ follow_mode = FOLLOW_NONE;
+ follow_default = 0;
+ return NULL;
+ }
+
+ /* compile regular expression if string starts with "=" */
+ if (string[0] == '=' && string[1] != 0)
+ {
+ // user has specified a string matching specification
+ regex_t regex_desc;
+ int ercode;
+ const char *userspec = &string[1];
+ size_t newstrlen = strlen (userspec) + 3;
+ char * str = (char *) malloc (newstrlen);
+ if (str)
+ {
+ snprintf (str, newstrlen, "^%s$", userspec);
+ assert (strlen (str) == newstrlen - 1);
+ ercode = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+ }
+ else
+ ercode = 1;
+ if (!ercode)
+ {
+ follow_spec_usr = strdup (string);
+ /* Ideally, follow_spec_cmp = [serialized regex_desc], */
+ /* so that libcollector wouldn't have to recompile it. */
+ /* For now, just copy the regular expression into follow_spec_cmp */
+ follow_spec_cmp = str;
+ follow_mode = FOLLOW_ALL;
+ follow_default = 0;
+ return NULL;
+ }
+ // syntax error in parsing string
+#if 0
+ char errbuf[256];
+ regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
+ fprintf (stderr, "Coll_Ctrl::set_follow_mode: regerror()=%s\n", errbuf);
+#endif
+ free (str);
+ }
+ return dbe_sprintf (GTXT ("Unrecognized follow-mode parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_prof_idle (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+ {
+ prof_idle = 1;
+ return NULL;
+ }
+ if (strcmp (string, "off") == 0)
+ {
+ prof_idle = 0;
+ return NULL;
+ }
+ return dbe_sprintf (GTXT ("Unrecognized profiling idle cpus parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_archive_mode (const char *string)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (string == NULL || strlen (string) == 0)
+ string = "on";
+ if (strcasecmp (string, "on") == 0 || strcasecmp (string, "off") == 0
+ || strcasecmp (string, "ldobjects") == 0
+ || strcasecmp (string, "usedldobjects") == 0
+ || strcasecmp (string, "src") == 0 || strcasecmp (string, "usedsrc") == 0
+ || strcasecmp (string, "all") == 0)
+ {
+ free (archive_mode);
+ archive_mode = strdup (string);
+ return NULL;
+ }
+ return dbe_sprintf (GTXT ("Unrecognized archive-mode parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_sample_signal (int value)
+{
+ const char *buf;
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (value == 0)
+ {
+ sample_sig = 0;
+ return NULL;
+ }
+ if (value == pauseresume_sig)
+ return report_signal_conflict (value);
+ if ((buf = strsignal (value)) != NULL)
+ sample_sig = value;
+ else
+ return dbe_sprintf (GTXT ("Invalid sample signal %d\n"), value);
+ return NULL;
+}
+
+/* find a signal by name */
+int
+Coll_Ctrl::find_sig (const char *string)
+{
+ int val;
+ char *signame_alloc = NULL;
+ const char *signame;
+ val = -1;
+ if (strcmp (string, "off") == 0)
+ return 0;
+ // see if the name begins with SIG
+ if (strncmp (string, "SIG", 3) != 0)
+ {
+ // no: add it
+ signame_alloc = (char *) malloc (strlen (string) + 3 + 1);
+ if (signame_alloc == NULL)
+ return -1;
+ strcpy (signame_alloc, "SIG");
+ strcpy (&signame_alloc[3], string);
+ signame = signame_alloc;
+ }
+ else
+ signame = string;
+
+ /* see if the string is a number */
+ char *endchar = NULL;
+ val = (int) strtol (signame, &endchar, 0);
+ if (*endchar != 0)
+ val = strtosigno (signame);
+ free (signame_alloc);
+ if (val == SIGKILL)
+ return -1;
+ return val;
+}
+
+char *
+Coll_Ctrl::set_pauseresume_signal (int value, int resume)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ if (value == 0)
+ {
+ pauseresume_sig = 0;
+ return NULL;
+ }
+ if (value == sample_sig)
+ return report_signal_conflict (value);
+ if (strsignal (value) != NULL)
+ {
+ pauseresume_sig = value;
+ pauseresume_pause = resume;
+ }
+ else
+ return dbe_sprintf (GTXT ("Invalid pause-resume (delayed initialization) signal %d\n"), value);
+ return NULL;
+}
+
+char *
+Coll_Ctrl::report_signal_conflict (int value)
+{
+ const char *xbuf = strsignal (value);
+ if (xbuf != NULL)
+ return dbe_sprintf (GTXT ("Signal %s (%d) can not be used for both sample and pause-resume (delayed initialization)\n"),
+ xbuf, value);
+ return dbe_sprintf (GTXT ("Signal %d can not be used for both sample and pause-resume (delayed initialization)\n"),
+ value);
+}
+
+char *
+Coll_Ctrl::set_debug_mode (int value)
+{
+ if (opened == 1)
+ return strdup (GTXT ("Experiment is active; command ignored.\n"));
+ debug_mode = value;
+ return NULL;
+}
+
+char *
+Coll_Ctrl::create_exp_dir ()
+{
+ int max = 4095; // 0xFFF - can be increased if it seems too low
+ for (int i = 0; i < max; i++)
+ {
+ if (mkdir (store_ptr,
+ S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0)
+ {
+ int err = errno;
+ if (err == EACCES)
+ return dbe_sprintf (GTXT ("Store directory %s is not writeable: %s\n"),
+ store_dir, strerror (err));
+ if (i + 1 >= max) // no more attempts
+ return dbe_sprintf (GTXT ("Unable to create directory `%s' -- %s\n%s: %d\n"),
+ store_ptr, strerror (err),
+ GTXT ("collect: Internal error: loop count achieved"),
+ max);
+ char *ermsg = update_expt_name (false, false, true);
+ if (ermsg != NULL)
+ {
+ char *msg = dbe_sprintf (GTXT ("Unable to create directory `%s' -- %s\n"),
+ store_ptr, ermsg);
+ free (ermsg);
+ return msg;
+ }
+ continue;
+ }
+ return NULL; // All is OK
+ }
+ return dbe_sprintf (GTXT ("Unable to create directory `%s'\n"), store_ptr);
+}
+
+char *
+Coll_Ctrl::get_exp_name (const char *stembase)
+{
+ expno = 1;
+ return dbe_sprintf ("%s.%d.er", stembase, expno);
+}
+
+char *
+Coll_Ctrl::preprocess_names ()
+{
+ char buf[MAXPATHLEN];
+ char msgbuf[MAXPATHLEN];
+ char *ret = NULL;
+
+ /* convert the experiment name and directory into store name/dir */
+ /* free the old strings */
+ if (store_dir != NULL)
+ {
+ free (store_dir);
+ store_dir = NULL;
+ }
+ if (expt_dir != NULL)
+ {
+ free (expt_dir);
+ expt_dir = NULL;
+ }
+ if (base_name != NULL)
+ {
+ free (base_name);
+ base_name = NULL;
+ }
+ if (expt_name != NULL)
+ {
+ free (expt_name);
+ expt_name = NULL;
+ }
+ expno = 1;
+ if (uexpt_name != NULL)
+ expt_name = strdup (uexpt_name);
+ else
+ {
+ // no user name -- pick a default
+ char *c;
+ char *stem;
+ char *stembase;
+ if (expt_group == NULL)
+ {
+ stem = strdup (default_stem);
+ stembase = stem;
+ }
+ else
+ {
+ stem = strdup (expt_group);
+ stem[strlen (stem) - 4] = 0;
+ stembase = stem;
+ // now remove any leading directory
+ for (int i = 0;; i++)
+ {
+ if (stem[i] == 0)
+ break;
+ if (stem[i] == '/')
+ stembase = &stem[i + 1];
+ }
+ if (strlen (stembase) == 0)
+ {
+ free (stem);
+ stem = strdup (default_stem);
+ stembase = stem;
+ }
+ }
+ c = get_exp_name (stembase);
+ expt_name = c;
+ free (stem);
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s"), expt_name);
+ if (buf[0] == '/')
+ {
+ // it's a full path name
+ if (udir_name != NULL)
+ {
+ snprintf (msgbuf, sizeof (msgbuf),
+ GTXT ("Warning: Experiment name is an absolute path; directory name %s ignored.\n"),
+ udir_name);
+ ret = strdup (msgbuf);
+ }
+ }
+
+ // now extract the directory and basename
+ int lastslash = 0;
+ for (int i = 0;; i++)
+ {
+ if (buf[i] == 0)
+ break;
+ if (buf[i] == '/')
+ lastslash = i;
+ }
+ expt_dir = strdup (buf);
+ if (lastslash != 0)
+ base_name = strdup (&buf[lastslash + 1]);
+ else
+ base_name = strdup (buf);
+ expt_dir[lastslash] = 0;
+ if (expt_dir[0] == '/')
+ store_dir = strdup (expt_dir);
+ else if ((udir_name == NULL) || (udir_name[0] == 0))
+ {
+ if (expt_dir[0] == 0)
+ store_dir = strdup (".");
+ else
+ store_dir = strdup (expt_dir);
+ }
+ else
+ {
+ /* udir_name is a non-empty string */
+ if (expt_dir[0] == 0)
+ store_dir = strdup (udir_name);
+ else
+ {
+ snprintf (buf, sizeof (buf), "%s/%s", udir_name, expt_dir);
+ store_dir = strdup (buf);
+ }
+ }
+ free (store_ptr);
+ if (strcmp (store_dir, ".") == 0)
+ store_ptr = strdup (base_name);
+ else
+ {
+ snprintf (buf, sizeof (buf), "%s/%s", store_dir, base_name);
+ store_ptr = strdup (buf);
+ }
+
+ // determine the file system type
+ if (strcmp (store_dir, prev_store_dir) != 0)
+ {
+ free (prev_store_dir);
+ prev_store_dir = strdup (store_dir);
+ const char *fstype = get_fstype (store_dir);
+ if (interactive && enabled && (fstype != NULL) && (nofswarn == 0))
+ {
+ snprintf (msgbuf, sizeof (msgbuf),
+ GTXT ("%sExperiment directory is set to a file system of type \"%s\",\n which may distort the measured performance;\n it is preferable to record to a local disk.\n"),
+ (ret == NULL ? "" : ret), fstype);
+ free (ret);
+ ret = strdup (msgbuf);
+ }
+ }
+ return ret;
+}
+
+char *
+Coll_Ctrl::update_expt_name (bool chgmsg, bool chkonly, bool newname)
+{
+ char *ret = NULL;
+ struct stat statbuf;
+ // make sure the name ends in .er
+ // set count to the length of the name
+ int count = (int) strlen (base_name);
+
+ // this should have been checked already, so we can abort
+ if (count < 4 || strcmp (&base_name[count - 3], ".er") != 0)
+ abort ();
+ int pcount = count - 4;
+ if (!newname)
+ { // check if old name can be used
+ char fullname[MAXPATHLEN];
+ snprintf (fullname, sizeof (fullname), "%s/%s", store_dir, base_name);
+ if (stat (fullname, &statbuf) != 0)
+ if (errno == ENOENT) // name does not exist, we can use it
+ return NULL;
+ }
+ else if (chkonly)
+ return NULL;
+
+ // current name will not work, update the name
+ DIR *dir;
+ struct dirent *dir_entry;
+
+ // see if there's a numeric field in front of the .er of the name
+ int digits = 0;
+ while (isdigit ((int) (base_name[pcount])) != 0)
+ {
+ pcount--;
+ if (pcount == 0) // name is of the form 12345.er; don't update it
+ return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
+ base_name);
+ digits++;
+ }
+ if (digits == 0) // name is of form xyz.er (or xyz..er); don't update it
+ return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
+ base_name);
+ if (base_name[pcount] != '.') // name is of form xyz123.er; don't update it
+ return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
+ base_name);
+ if (chkonly)
+ return NULL;
+
+ // save the name for a changed message
+ char *oldbase = strdup (base_name);
+
+ // the name is of the from prefix.nnn.er; extract the value of nnn
+ int version = atoi (&base_name[pcount + 1]);
+ if (newname) // do not try to use old name
+ version++;
+ int max_version = version - 1;
+
+ // terminate the base_name string after that . yielding "prefix."
+ base_name[pcount + 1] = 0;
+ if ((dir = opendir (store_dir)) == NULL)
+ {
+ // ignore error -- we'll hit it again later
+ free (oldbase);
+ return NULL;
+ }
+
+ // find the maximum version in the directory
+ // count is the number of characters before the number
+ //
+ while ((dir_entry = readdir (dir)) != NULL)
+ {
+ count = (int) strlen (dir_entry->d_name);
+ if ((count < 4) || (strcmp (&dir_entry->d_name[count - 3], ".er") != 0))
+ continue;
+ // check that the name is of the form prefix.nnn.er; if not, skip it
+ if (strncmp (base_name, dir_entry->d_name, pcount + 1) == 0)
+ {
+ // the "prefix." part matches, terminate the entry name before the .er
+ dir_entry->d_name[count - 3] = 0;
+ char *lastchar;
+ int dversion = (int) strtol (&dir_entry->d_name[pcount + 1], &lastchar, 10);
+
+ // if it did not end where the .er was, skip it
+ if (*lastchar != 0)
+ continue;
+ if (dversion > max_version)
+ max_version = dversion;
+ }
+ }
+
+ // we now have the maximum version determined
+ char newbase[MAXPATHLEN];
+ base_name[pcount + 1] = 0;
+ version = max_version + 1;
+ snprintf (newbase, sizeof (newbase), "%s%d.er", base_name, version);
+ if ((strcmp (oldbase, newbase) != 0) && chgmsg)
+ {
+ ret = dbe_sprintf (GTXT ("name %s is in use; changed to %s\n"),
+ oldbase, newbase);
+ free (oldbase);
+ }
+ else
+ free (oldbase);
+ free (base_name);
+ base_name = strdup (newbase);
+
+ // now, reset expt_name to reflect new setting
+ free (expt_name);
+ if (expt_dir[0] == 0)
+ expt_name = strdup (base_name);
+ else
+ expt_name = dbe_sprintf ("%s/%s", expt_dir, base_name);
+ free (store_ptr);
+ if (strcmp (store_dir, ".") == 0)
+ store_ptr = strdup (base_name);
+ else
+ store_ptr = dbe_sprintf ("%s/%s", store_dir, base_name);
+ closedir (dir);
+ return ret;
+}
+
+void
+Coll_Ctrl::remove_exp_dir ()
+{
+ if (store_ptr == NULL)
+ return;
+ rmdir (store_ptr);
+ free (store_ptr);
+ store_ptr = NULL;
+ return;
+}
+
+void
+Coll_Ctrl::determine_profile_params ()
+{
+ struct itimerval itimer;
+ struct itimerval otimer;
+ int period;
+ long nperiod;
+ struct sigaction act;
+ struct sigaction old_handler;
+ memset (&act, 0, sizeof (struct sigaction));
+ period = 997;
+
+ // set SIGPROF handler to SIG_IGN
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGPROF, &act, &old_handler) == -1)
+ {
+ /* couldn't set signal */
+ fprintf (stderr, GTXT ("Can't set SIGPROF: %s\n"), strerror (errno));
+ exit (1);
+ }
+
+ // set the timer to arbitrary resolution
+ itimer.it_interval.tv_sec = period / MICROSEC;
+ itimer.it_interval.tv_usec = period % MICROSEC;
+ itimer.it_value = itimer.it_interval;
+ setitimer (ITIMER_REALPROF, &itimer, &otimer);
+
+ // now reset the timer to turn it off
+ itimer.it_value.tv_sec = 0;
+ itimer.it_value.tv_usec = 0;
+ if (setitimer (ITIMER_REALPROF, &itimer, &otimer) == -1) // call failed
+ nperiod = -1;
+ else
+ nperiod = otimer.it_interval.tv_sec * MICROSEC + otimer.it_interval.tv_usec;
+
+ // check the returned value: is the what we asked for?
+ if (period == nperiod) // arbitrary precision is OK
+ set_clk_params (PROFINT_MIN, 1, PROFINT_MAX, PROFINT_HIGH, PROFINT_NORM, PROFINT_LOW);
+ else if (nperiod < 10000) // hi resolution allowed, but not arbitrary precision
+ set_clk_params ((int) nperiod, 1000, PROFINT_MAX, 1000, 10000, 100000);
+ else // low resolution only allowed
+ set_clk_params (10000, 10000, PROFINT_MAX, 1000, 10000, 100000);
+
+ // If old handler was default, ignore it; otherwise restore it
+ if (old_handler.sa_handler != SIG_DFL)
+ {
+ act.sa_handler = old_handler.sa_handler;
+ if (sigaction (SIGPROF, &act, &old_handler) == -1)
+ {
+ /* couldn't reset signal */
+ fprintf (stderr, GTXT ("Can't reset SIGPROF: %s\n"), strerror (errno));
+ exit (1);
+ }
+ }
+}
+
+const char *
+get_fstype (char *)
+{
+ /* On Linux, statvfs() doesn't return any information that seems to indicate
+ the filetype. The structure statvfs does not have any field/flag that
+ gives this information. Comparing the fields from
+ /usr/include/bits/statvfs.h:
+ unsigned long int f_fsid;
+ int __f_unused;
+ ^^^^ On Solaris, this is where f_basetype is
+ unsigned long int f_flag;
+ unsigned long int f_namemax;
+ XXX Need to revisit this XXX
+ */
+ return NULL; // no NFS warning on Linux for now
+}
+
+//========== Special functions to communicate with the Collector GUI ==========//
+
+/* Interface strings GUI <-> CLI */
+const char *ipc_str_exp_limit = "exp_limit";
+const char *ipc_str_time_limit = "time_limit";
+const char *ipc_str_arch_exp = "arch_exp";
+const char *ipc_str_descendant = "descendant";
+const char *ipc_str_clkprof = "clkprof";
+const char *ipc_str_hwcprof = "hwcprof";
+const char *ipc_str_hwc2_prof = "hwc2_prof";
+const char *ipc_str_javaprof = "javaprof";
+const char *ipc_str_sample = "sample";
+const char *ipc_str_sample_sig = "sample_sig";
+const char *ipc_str_pause_resume_sig = "pause_resume_sig";
+const char *ipc_str_synctrace = "synctrace";
+const char *ipc_str_heaptrace = "heaptrace";
+const char *ipc_str_iotrace = "iotrace";
+const char *ipc_str_count = "count";
+const char *ipc_str_prof_idle = "prof_idle"; // -x option
+// Standard answers
+const char *ipc_str_empty = "";
+const char *ipc_str_on = "on";
+const char *ipc_str_off = "off";
+const char *ipc_str_src = "src";
+const char *ipc_str_usedsrc = "usedsrc";
+const char *ipc_str_usedldobjects = "usedldobjects";
+const char *ipc_str_unlimited = "unlimited";
+const char *ipc_str_unknown_control = "Unknown control";
+const char *ipc_str_internal_error = "Internal error";
+
+/**
+ * Finds signal name
+ * @param signal
+ * @return NULL or signal name (pointer to allocated memory)
+ */
+char *
+Coll_Ctrl::find_signal_name (int signal)
+{
+ char *str_signal = NULL;
+ const char *buf = strsignal (signal);
+ if (buf != NULL)
+ str_signal = strdup (buf);
+ return str_signal;
+}
+
+/**
+ * Gets control's value
+ * @param control
+ * @return value
+ */
+char *
+Coll_Ctrl::get (char * control)
+{
+ int len = strlen (control);
+ if (!strncmp (control, ipc_str_exp_limit, len))
+ {
+ if ((size_limit > 0))
+ return dbe_sprintf ("%d", size_limit);
+ return strdup (ipc_str_unlimited);
+ }
+ if (!strncmp (control, ipc_str_time_limit, len))
+ {
+ if ((time_run != 0) || (start_delay != 0))
+ {
+ if (start_delay != 0)
+ {
+ if (time_run != 0)
+ return dbe_sprintf ("%ds-%ds", start_delay, start_delay + time_run);
+ return dbe_sprintf ("%ds-0s", start_delay);
+ }
+ return dbe_sprintf ("0s-%ds", time_run);
+ }
+ return strdup (ipc_str_unlimited);
+ }
+ if (strncmp (control, ipc_str_arch_exp, len) == 0)
+ return strdup (get_archive_mode ());
+ if (!strncmp (control, ipc_str_descendant, len))
+ {
+ switch (get_follow_mode ())
+ {
+ case FOLLOW_ON:
+ return strdup (ipc_str_on);
+ case FOLLOW_ALL:
+ return strdup (ipc_str_on);
+ case FOLLOW_NONE:
+ default:
+ return strdup (ipc_str_off);
+ }
+ }
+ if (!strncmp (control, ipc_str_prof_idle, len))
+ {
+ if (prof_idle == 0)
+ return strdup (ipc_str_off);
+ return strdup (ipc_str_on);
+ }
+ if (!strncmp (control, ipc_str_clkprof, len))
+ {
+ if (clkprof_default == 1 && clkprof_enabled == 1) // Default value
+ return strdup (ipc_str_empty);
+ if (clkprof_enabled == 0)
+ return strdup (ipc_str_off);
+ if ((clkprof_timer > 0))
+ return dbe_sprintf ("%d", clkprof_timer / 1000);
+ return strdup (ipc_str_internal_error);
+ }
+ if (!strncmp (control, ipc_str_hwcprof, len))
+ {
+ if (hwcprof_enabled_cnt == 0)
+ return strdup (ipc_str_off);
+ if (hwc_string != NULL)
+ return dbe_sprintf ("on\n%s", hwc_string);
+ return strdup (ipc_str_on); // XXX need more details?
+ }
+ if (!strncmp (control, ipc_str_javaprof, len))
+ {
+ if ((java_mode == 0))
+ return strdup (ipc_str_off);
+ return strdup (ipc_str_on);
+ }
+ if (!strncmp (control, ipc_str_sample, len))
+ {
+ if (sample_default == 1 && sample_period == 1) // Default value
+ return strdup (ipc_str_empty);
+ if (sample_period == 0)
+ return strdup (ipc_str_off);
+ if (sample_period > 0)
+ return dbe_sprintf ("%d", sample_period);
+ return strdup (ipc_str_internal_error);
+ }
+ if (!strncmp (control, ipc_str_sample_sig, len))
+ {
+ if ((sample_sig == 0))
+ return strdup (ipc_str_off);
+ char *str_signal = find_signal_name (sample_sig);
+ if (str_signal != NULL)
+ return str_signal;
+ return dbe_sprintf (GTXT ("Invalid sample signal %d\n"), sample_sig);
+ }
+ if (!strncmp (control, ipc_str_pause_resume_sig, len))
+ {
+ if (pauseresume_sig == 0)
+ return strdup (ipc_str_off);
+ char *str_signal = find_signal_name (pauseresume_sig);
+ if (str_signal != NULL)
+ return str_signal;
+ return dbe_sprintf (GTXT ("Invalid pause/resume signal %d\n"), pauseresume_sig);
+ }
+ if (!strncmp (control, ipc_str_synctrace, len))
+ {
+ if (synctrace_enabled == 0)
+ return strdup (ipc_str_off);
+ if (synctrace_thresh < 0)
+ return strdup ("on\nthreshold: calibrate");
+ if (synctrace_thresh == 0)
+ return strdup ("on\nthreshold: all");
+ return dbe_sprintf ("on\nthreshold: %d", synctrace_thresh);
+ }
+ if (!strncmp (control, ipc_str_heaptrace, len))
+ {
+ if ((heaptrace_enabled == 0))
+ return strdup (ipc_str_off);
+ return strdup (ipc_str_on);
+ }
+ if (!strncmp (control, ipc_str_iotrace, len))
+ {
+ if ((iotrace_enabled == 0))
+ return strdup (ipc_str_off);
+ return strdup (ipc_str_on);
+ }
+ if (!strncmp (control, ipc_str_count, len))
+ {
+ if ((count_enabled == 0))
+ return strdup (ipc_str_off);
+ if ((count_enabled < 0))
+ return strdup ("on\nstatic");
+ return strdup (ipc_str_on);
+ }
+ return strdup (ipc_str_unknown_control);
+}
+
+/**
+ * Resets control's value (restores the default value)
+ * @param control
+ * @param value
+ * @return error or warning or NULL (done)
+ */
+char *
+Coll_Ctrl::set (char * control, const char * value)
+{
+ char * ret;
+ char * warn = NULL;
+ int len = strlen (control);
+ if (!strncmp (control, ipc_str_exp_limit, len))
+ return set_size_limit (value);
+ if (!strncmp (control, ipc_str_time_limit, len))
+ return set_time_run (value);
+ if (!strncmp (control, ipc_str_arch_exp, len))
+ return set_archive_mode (value);
+ if (!strncmp (control, ipc_str_descendant, len))
+ return set_follow_mode (value);
+ if (!strncmp (control, ipc_str_prof_idle, len))
+ return set_prof_idle (value);
+ if (!strncmp (control, ipc_str_clkprof, len))
+ {
+ ret = set_clkprof (value, &warn);
+ if (ret == NULL)
+ {
+ if (warn != NULL)
+ return warn; // Warning
+ return NULL; // Done
+ }
+ return ret; // Error
+ }
+ if (!strncmp (control, ipc_str_hwcprof, len))
+ {
+ ret = set_hwcstring (value, &warn);
+ if (ret == NULL)
+ {
+ if (warn != NULL)
+ return warn; // Warning
+ return NULL; // Done
+ }
+ return ret; // Error
+ }
+ if (!strncmp (control, ipc_str_hwc2_prof, len))
+ {
+ ret = set_hwcstring (value, &warn);
+ if (ret == NULL)
+ {
+ if (warn != NULL)
+ return warn; // Warning
+ return NULL; // Done
+ }
+ return ret; // Error
+ }
+ if (!strncmp (control, ipc_str_javaprof, len))
+ return set_java_mode (value);
+ if (!strncmp (control, ipc_str_sample, len))
+ return set_sample_period (value);
+ if (!strncmp (control, ipc_str_sample_sig, len))
+ return set_sample_signal (find_sig (value));
+ if (!strncmp (control, ipc_str_pause_resume_sig, len))
+ {
+ char *str_signal = strdup (value);
+ char *str_state = strchr (str_signal, (int) '\n');
+ if (str_state != NULL)
+ {
+ *str_state = 0;
+ str_state++;
+ }
+ int signal = atoi (str_signal);
+ int state = 0;
+ if (str_state != NULL)
+ state = atoi (str_state);
+ free (str_signal);
+ return set_pauseresume_signal (signal, state);
+ }
+ if (!strncmp (control, ipc_str_synctrace, len))
+ return set_synctrace (value);
+ if (!strncmp (control, ipc_str_heaptrace, len))
+ return set_heaptrace (value);
+ if (!strncmp (control, ipc_str_iotrace, len))
+ return set_iotrace (value);
+ if (!strncmp (control, ipc_str_count, len))
+ return set_count (value);
+ return strdup (ipc_str_unknown_control);
+}
+
+/**
+ * Resets control's value (restores the default value)
+ * @param control
+ * @return error or NULL (done)
+ */
+char *
+Coll_Ctrl::unset (char * control)
+{
+ int len = strlen (control);
+ if (!strncmp (control, ipc_str_exp_limit, len))
+ size_limit = 0;
+ if (!strncmp (control, ipc_str_time_limit, len))
+ {
+ time_run = 0;
+ start_delay = 0;
+ }
+ if (!strncmp (control, ipc_str_arch_exp, len))
+ {
+ archive_mode = strdup ("on");
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_descendant, len))
+ {
+ follow_mode = FOLLOW_NONE;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_prof_idle, len))
+ {
+ prof_idle = 1;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_clkprof, len))
+ {
+ clkprof_default = 1;
+ clkprof_enabled = 1;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_hwcprof, len))
+ {
+ setup_hwc ();
+ set_hwcdefault ();
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_javaprof, len))
+ {
+ java_mode = 0;
+ java_default = 0;
+ free (java_path);
+ java_path = NULL;
+ free (java_args);
+ java_args = NULL;
+ }
+ if (!strncmp (control, ipc_str_sample, len))
+ {
+ sample_period = 1;
+ sample_default = 1;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_sample_sig, len))
+ {
+ sample_sig = 0;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_pause_resume_sig, len))
+ {
+ pauseresume_sig = 0;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_synctrace, len))
+ {
+ synctrace_enabled = 0;
+ synctrace_thresh = -1;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_heaptrace, len))
+ {
+ heaptrace_enabled = 0;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_iotrace, len))
+ {
+ iotrace_enabled = 0;
+ return NULL;
+ }
+ if (!strncmp (control, ipc_str_count, len))
+ {
+ count_enabled = 0;
+ Iflag = 0;
+ Nflag = 0;
+ return NULL;
+ }
+ return strdup (ipc_str_unknown_control);
+}
+
+void
+Coll_Ctrl::set_project_home (char *s)
+{
+ if (s)
+ project_home = strdup (s);
+}
diff --git a/gprofng/src/collctrl.h b/gprofng/src/collctrl.h
new file mode 100644
index 0000000..6555df7
--- /dev/null
+++ b/gprofng/src/collctrl.h
@@ -0,0 +1,405 @@
+/* Copyright (C) 2021 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. */
+
+/* This file describes the data structures used to control
+ * data collection; it is used by various commands in the MPMT
+ * tree, and is also shared with dbx. Care should be taken
+ * to ensure that both the mpmt and dbx builds continue.
+
+ * To remove any APIs or change any enum cases:
+ *
+ * 1. Make the changes in mpmt, and preserve the old APIs
+ * as scaffolding and any old enum values as #defines.
+ *
+ * 2. Add the new APIs and new cases to dbx, remove the
+ * old ones.
+ *
+ * 3. Remove the old API scaffolding and enum values here
+ *
+ */
+
+#ifndef _COLLCTRL_H
+#define _COLLCTRL_H
+
+#include "hwcentry.h"
+#include "cc_libcollector.h"
+
+/*---------------------------------------------------------------------------*/
+
+/* class */
+
+typedef struct {
+ int min;
+ int res;
+ int max;
+ int hival;
+ int normval;
+ int lowval;
+} clk_params_t;
+
+#define PROFINT_HIGH 997
+#define PROFINT_NORM 10007
+#define PROFINT_LOW 100003
+
+#define PROFINT_MIN 500
+#define PROFINT_MAX 1000000
+
+class Coll_Ctrl {
+public:
+
+ /* _interactive is 1 for dbx, 0 for collect */
+ Coll_Ctrl(int _interactive = 0, bool _defHWC = false, bool _kernelHWC = false);
+ ~Coll_Ctrl();
+
+ Coll_Ctrl(Coll_Ctrl *cc); /* constructor for duplicate */
+ char *check_expt(char **); /* check the experiment directory */
+ char *setup_experiment(); /* set up the experiment directory, etc. */
+ void close_expt();
+ void interrupt(); /* the user interrupts experiment */
+ void delete_expt();
+
+ /* enable/disable the experiment */
+ char *enable_expt();
+ void disable_expt() { enabled = 0; };
+ int isenabled() { return enabled; };
+
+ /* check for active experiment */
+ int isopened() { return opened; };
+
+ /* set the parameters for clock-profiling */
+ void set_clk_params(int min, int res, int max, int hi, int norm, int lo);
+ char *set_clkprof(const char *valptr, char **warn);
+ char *reset_clkprof(int val); /* called if profiler must reset value */
+ int get_sys_period() { return clk_params.min; };
+ int get_clk_min() { return clk_params.min; };
+ int get_clk_max() { return clk_params.max; };
+ int get_clk_res() { return clk_params.res; };
+ int get_clkprof_mode() { return clkprof_enabled; };
+ int get_clkprof_timer() { return clkprof_timer; };
+
+ /* set the parameters for synchronization tracing */
+ char *set_synctrace(const char *valptr);
+ int get_synctrace_mode() { return synctrace_enabled; };
+ int get_synctrace_thresh() { return synctrace_thresh; };
+ int get_synctrace_scope() { return synctrace_scope; };
+
+ /* set the parameters for heap tracing */
+ char *set_heaptrace(const char *);
+ int get_heaptrace_mode() { return heaptrace_enabled; };
+ int get_heaptrace_checkmode() { return heaptrace_checkenabled; };
+
+ /* set the parameters for I/O tracing */
+ char *set_iotrace(const char *);
+ int get_iotrace_mode() { return iotrace_enabled; };
+
+ /* set the parameters for HW counting */
+ void setup_hwc();
+ char *set_hwcstring(const char *str, char **warn);
+ char *add_hwcstring(const char *str, char **warn);
+ char *add_default_hwcstring(const char *str, char **warn, bool add, bool forKernel = false);
+ void set_hwcdefault();
+ void disable_hwc();
+ int get_hwc_cnt() { return hwcprof_enabled_cnt; };
+ int get_hwc_mode() { return hwcprof_enabled_cnt ? 1 : 0; };
+ char *get_hwc_string() { return hwc_string; };
+
+ Hwcentry *
+ get_hwc_entry (int n)
+ {
+ if (n < 0 || n >= hwcprof_enabled_cnt)
+ return 0;
+ return &hwctr[n];
+ };
+
+ void hwcentry_dup (Hwcentry *, Hwcentry *);
+ char *get_hwc_counter (int n) { return get_hwc_entry (n)->name; };
+
+ /* set the parameters for count data */
+ char *set_count (const char *);
+ int get_count () { return count_enabled; };
+ void set_Iflag () { Iflag = 1; };
+ void set_Nflag () { Nflag = 1; };
+
+ /* set time interval for attach with dbx timed collection */
+ /* also used for er_kernel */
+ char *set_time_run (const char *);
+ int get_time_run (void) { return time_run; };
+ int get_start_delay (void) { return start_delay; };
+
+ /* set pid for attach with dbx to collect data */
+ char *set_attach_pid (char *);
+ int get_attach_pid (void) { return attach_pid; };
+
+ /* set java mode, "on" = yes; "off" = no; anthing else implies
+ * yes, and is the path to the java to use
+ * java_mode is returned as zero for off, one for on
+ * java_default is returned as zero for explicitly set, one for defaulted on
+ */
+ char *set_java_mode (const char *);
+ int get_java_mode () { return java_mode; };
+ int get_java_default () { return java_default; };
+
+ /* setting Java path explicitly */
+ char *set_java_path (const char *);
+ char *get_java_path () { return java_path; };
+
+ /* set additional arguments for Java invocation */
+ char *set_java_args (char *);
+ char *get_java_args () { return java_args; };
+ int get_java_arg_cnt () { return njava_args; };
+
+ /* set load-object archive mode, 0 = no; other = yes */
+ char *set_archive_mode (const char *);
+ char *get_archive_mode () { return archive_mode; };
+
+ /* set follow-descendants mode, 0 = no; other = yes */
+ char *set_follow_mode (const char *);
+ Follow_type get_follow_mode () { return follow_mode; };
+ int get_follow_default () { return follow_default; };
+ char *get_follow_usr_spec () { return follow_spec_usr; };
+ char *get_follow_cmp_spec () { return follow_spec_cmp; };
+
+ /* set profile idle cpus mode, 1 = no; 0 = yes */
+ char *set_prof_idle (const char *);
+ int get_prof_idle () { return prof_idle; };
+
+ /* set debug more, 1 = yes; other = no */
+ /* if set, target will be set to halt at exit from exec */
+ char *set_debug_mode (int);
+ int get_debug_mode () { return debug_mode; };
+
+ /* find a signal from a string */
+ int find_sig (const char *);
+ /* find a signal name from a signal value */
+ char *find_signal_name (int signal);
+
+ /* set the pauseresume (delayed initialization) signal */
+ char *set_pauseresume_signal (int, int);
+ int get_pauseresume_signal () { return pauseresume_sig; };
+ int get_pauseresume_pause () { return pauseresume_pause; };
+
+ /* set the sample signal */
+ char *set_sample_signal (int);
+ int get_sample_signal () { return sample_sig; };
+
+ /* set the periodic sampling */
+ char *set_sample_period (const char *);
+ int get_sample_period (void) { return sample_period; };
+
+ /* set experiment size limit */
+ char *set_size_limit (const char *);
+ int get_size_limit (void) { return size_limit; };
+
+ /* naming methods */
+ /* set the target executable name */
+ int set_target (char *);
+ char *get_target () { return target_name; };
+
+ /* set the experiment name */
+ void set_default_stem (const char *);
+ char *set_expt (const char *, char **, bool);
+ char *get_expt () { return expt_name; };
+
+ /* set the experiment directory */
+ char *set_directory (char *, char **);
+
+ char *get_directory () { return udir_name ? udir_name : store_dir; };
+
+ /* return the real experiment ptr file name */
+ char *get_experiment () { return store_ptr; };
+ char *update_expt_name (bool verbose = true, bool ckonly = false, bool newname = false);
+
+ /* remove the experiment */
+ void remove_exp_dir ();
+
+ /* return the data descriptor */
+ char *
+ get_data_desc ()
+ {
+ return data_desc;
+ };
+
+ /* set the experiment group */
+ char *set_group (char *);
+ char *get_group () { return expt_group; };
+
+ /* return the experiment settings as a string */
+ char *show (int); /* full show */
+ char *show_expt (); /* short form */
+
+ /* return an argv array to compose a "collect" command from settings */
+ char **get_collect_args ();
+
+ /* determine characteristics of system */
+ char *get_node_name () { return node_name; };
+ long get_ncpus () { return ncpus; };
+ int get_cpu_clk_freq () { return cpu_clk_freq; };
+ int get_cpc_cpuver () { return cpc_cpuver; };
+
+ /* disable warning about non-local filesystems */
+ void set_nofswarn () { nofswarn = 1; };
+
+ //========== Special functions to communicate with the Collector GUI ==========//
+ char *get (char *); /* get control's value */
+ char *set (char *, const char *); /* set control's value */
+ char *unset (char *); /* reset control's value to its default */
+ void set_project_home (char *);
+
+private:
+ int interactive; /* 1 - dbx, 0 - collect */
+ bool defHWC; /* true if default HWC experiment should be run */
+ bool kernelHWC; /* T if default HWC counters are for kernel profiling */
+ int opened; /* T if an experiment is opened */
+ int enabled; /* T if an experiment is enabled */
+ volatile int uinterrupt; /* set if interrupt from user */
+
+ /* experiment/machine characteristics */
+ char *node_name; /* name of machine on which experiment is run */
+ long ncpus; /* number of online CPUs */
+ int cpu_clk_freq; /* chip clock (MHz.), as reported from processor_info */
+ int cpc_cpuver; /* chip version, as reported from libcpc */
+ long sys_resolution; /* system clock resolution */
+ int sys_period; /* profiling clock resolution on the system */
+ int sample_period; /* period for sampling, seconds */
+ int sample_default; /* if period for sampling set by default */
+ int size_limit; /* experiment size limit, MB */
+ long npages; /* number of pages configured */
+ long page_size; /* size of system page */
+ clk_params_t clk_params;
+
+ /* user specification of name */
+ /* user may specify both uexpt_name and udir_name
+ * if uexpt_name is absolute path, udir_name is ignored, with warning
+ * otherwise, udir_name is prepended to uexpt_name
+ *
+ * if uexpt_name is of the form: <dir>/zzzz.nnn.er, where nnn is numeric,
+ * nnn will be reset to one greater than the the highest experiment
+ * with a name of the same form.
+ */
+ char *default_stem; /* default stem for experiment name */
+ char *uexpt_name; /* suggested experiment name */
+ char *expt_name; /* experiment name, after defaulting */
+ char *expt_dir; /* directory part of suggested experiment name */
+ char *base_name; /* basename of suggested experiment name */
+ char *udir_name; /* user name of directory for data */
+
+ char *store_dir; /* directory to contain experiment dir. */
+ char *prev_store_dir; /* previously set store directory */
+ char *store_ptr; /* experiment pointer file */
+ char *expt_group; /* name of experiment group, if any */
+ char *project_home; /* argv[0] */
+
+ char *target_name; /* target executable name */
+ char *data_desc; /* string describing the data to be collected */
+ char *lockname; /* name of directory lock file */
+ int lockfd; /* fd of open lock file */
+
+ int nofswarn; /* if 1, don't warn of filesystem */
+ int expno; /* number in <stem>.<expno>.er */
+
+ /* T if an target is to be left for debugger attach */
+ int debug_mode;
+
+ /* clock-profiling controls */
+ /* T if clock-based profiling */
+ int clkprof_enabled;
+
+ /* T if on by default, rather than explicit setting */
+ int clkprof_default;
+
+ /* value for timer, microseconds. */
+ int clkprof_timer; // adjusted clock profiling interval
+ int clkprof_timer_target; // desired clock profiling interval
+
+ /* HW counter-profiling controls */
+ /* >0 if HW counter-based profiling */
+ int hwcprof_default;
+ int hwcprof_enabled_cnt;
+ char *hwc_string;
+ Hwcentry hwctr[MAX_PICS];
+
+ int synctrace_enabled; /* T if synchronization tracing */
+ /* sync trace threshold value, microsec. */
+ /* if 0, record all */
+ /* if <0, calibrate */
+ int synctrace_thresh;
+
+ /* sync trace scope -- a bit mask */
+ /* definitions in data_pckts.h */
+ int synctrace_scope;
+
+ int heaptrace_enabled; /* T if heap tracing */
+ /* if 0 no checking;
+ * if 1, check for over- and under-write
+ * if 2, also set patterns in malloc'd and free'd areas
+ */
+ int heaptrace_checkenabled;
+ int iotrace_enabled; /* T if I/O tracing */
+
+ /* count controls */
+ /* 1 if counting is enabled; -1 if count static is enabled */
+ int count_enabled;
+ int Iflag; /* specify bit output directory -- only with count_enabled */
+ int Nflag; /* specify bit library to ignore -- only with count_enabled */
+
+ /* pid, if -P <pid> is invoked for attach with dbx */
+ int attach_pid;
+
+ /* time_run -- non-zero if timed execution request (dbx/er_kernel) */
+ int time_run;
+ int start_delay;
+
+ /* T if Java profiling is requested */
+ int java_mode;
+ int java_default;
+ char *java_path;
+ char *java_args;
+ int njava_args;
+
+ /* whether/how following-descendants is requested */
+ Follow_type follow_mode;
+ int follow_default;
+ char *follow_spec_usr; // user's selective follow spec
+ char *follow_spec_cmp; // compiled selective follow spec
+ int prof_idle; // whether profiling idle cpus is requested
+ char *archive_mode; // how load-objects archiving is requested
+
+ // signals to control pause-resume (delayed initialization) and samples
+ int pauseresume_sig; // for pause-resume signal -- delayed initialization
+ int pauseresume_pause; // 1 if pauseresume and start paused; 0 if not
+ int sample_sig; // to trigger sample
+ char *report_signal_conflict (int);
+ char *check_consistency (); // check the experiment settings for consistency
+ void determine_profile_params ();
+ char *preprocess_names ();
+ char *get_exp_name (const char *);
+ char *create_exp_dir ();
+ void build_data_desc ();
+ char *check_group ();
+ char *join_group ();
+ void free_hwc_fields (Hwcentry *tmpctr);
+
+ // propagates clkprof_timer change to Hwcentry hwctr[]
+ void set_clkprof_timer_target (int microseconds);
+ void adjust_clkprof_timer (int microseconds);
+ hrtime_t clkprof_timer_2_hwcentry_min_time (int clkprof_microseconds);
+};
+
+#endif /* !_COLLCTRL_H */
diff --git a/gprofng/src/collect.h b/gprofng/src/collect.h
new file mode 100644
index 0000000..c500dee
--- /dev/null
+++ b/gprofng/src/collect.h
@@ -0,0 +1,156 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _COLLECT_H
+#define _COLLECT_H
+
+#include <Application.h>
+
+extern "C"
+{
+ typedef void (*SignalHandler)(int);
+}
+
+class Coll_Ctrl;
+class Elf;
+
+#define MAXLABELS 10 /* maximum number of -C arguments */
+#define STDEBUFSIZE 24000
+
+enum { MAX_LD_PRELOAD_TYPES = 3 };
+
+struct Process
+{
+ Process (pid_t _pid) : pid (_pid) { }
+ pid_t pid;
+};
+
+struct DtraceTool
+{
+ DtraceTool (char*);
+ ~DtraceTool ();
+
+ char *name; // Tool name as specified by -D flag
+ char *params; // Tool parameters
+ char *dfile; // Extracted d-script
+ char *mfile; // Extracted metadata file
+ char *ofile; // Output file
+ pid_t pid;
+};
+
+// collect object
+class collect : Application
+{
+public:
+ collect (int argc, char *argv[], char **envp);
+ virtual ~collect ();
+ void start (int argc, char *argv[]);
+ void writeStr (int f, const char *buf);
+
+ // the collector control class
+ Coll_Ctrl *cc;
+
+private:
+ enum Exec_status
+ {
+ EXEC_OK = 0, // found as runnable executable
+ EXEC_ELF_NOSHARE, // found, but built unshared
+ EXEC_IS_JAR, // found as a .jar file
+ EXEC_IS_CLASS, // found as a .class file but name missing .class
+ EXEC_IS_CLASSCLASS, // found as a .class file with explicit .class
+ EXEC_OPEN_FAIL, // could not be opened
+ EXEC_ELF_LIB, // internal error: bad elf library
+ EXEC_ELF_HEADER, // executable, with bad ELF header
+ EXEC_ELF_ARCH, // executable, but unrunnable architecture
+ EXEC_ISDIR, // a directory, not a file
+ EXEC_NOT_EXEC, // a file, but not executable
+ EXEC_NOT_FOUND // a directory, not a file
+ };
+
+ // override methods in base class
+ void usage ();
+ void short_usage ();
+ void show_hwc_usage ();
+ int check_args (int argc, char *argv[]);
+ void check_target (int, char **);
+ Exec_status check_executable (char *);
+ Exec_status check_executable_arch (Elf *);
+ char *status_str (Exec_status, char *);
+ int do_flag (const char *);
+ char *find_java (void);
+ char *java_path;
+ char *java_how;
+ int putenv_libcollector ();
+ int putenv_libcollector_ld_audits ();
+ int putenv_libcollector_ld_preloads ();
+ int putenv_libcollector_ld_misc ();
+ void add_ld_preload (const char *lib);
+ int putenv_ld_preloads ();
+ int putenv_memso ();
+ int env_strip (char *env, const char *str);
+ int putenv_purged_ld_preloads (const char *var);
+ int putenv_append (const char *var, const char *val);
+ void get_count_data ();
+ void prepare_dbx ();
+ int traceme (const char *file, char *const argv[]);
+ int checkflagterm (const char *);
+ void dupflagseen (char);
+ void dupflagseen (const char *);
+ void validate_config (int);
+ void validate_java (const char *, const char *, int);
+ int set_output ();
+ void reset_output ();
+
+ /* Logging warning messages */
+ char **collect_warnings;
+ int collect_warnings_idx;
+ void warn_open ();
+ void warn_close ();
+ void warn_write (const char *format, ...);
+ void warn_comment (const char *kind, int num, char *s = NULL, int len = 0);
+ char *warnfilename;
+ FILE *warn_file;
+
+ /* MPI experiment handling */
+ void setup_MPI_expt (); /* the founder experiment */
+ void write_MPI_founder_log ();
+ void close_MPI_founder_log (int, int);
+ void spawn_MPI_job (); /* run the MPI job */
+ void copy_collect_args (char ***); /* copy collect args for an MPI target */
+ int disabled;
+ int jseen_global; /* if -j flag was seen */
+ int verbose;
+ bool mem_so_me; /* if T, preload mem.so, not libcollector */
+ int origargc;
+ char **arglist;
+ char **origargv;
+ char **origenvp;
+ int targ_index; // index of name of target in origargv
+ bool is_64;
+ int nargs;
+ int njargs;
+ char *jargs;
+ int nlabels;
+ char *label[MAXLABELS];
+ char *sp_preload_list[MAX_LD_PRELOAD_TYPES + 1]; // +1 for NULL termination
+ char *sp_libpath_list[MAX_LD_PRELOAD_TYPES + 1]; // +1 for NULL termination
+};
+
+#endif /* ! _COLLECT_H */
diff --git a/gprofng/src/collector_module.h b/gprofng/src/collector_module.h
new file mode 100644
index 0000000..512af7a
--- /dev/null
+++ b/gprofng/src/collector_module.h
@@ -0,0 +1,223 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _COLLECTOR_MODULE_H
+#define _COLLECTOR_MODULE_H
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "gp-defs.h"
+
+struct stat;
+struct tm;
+
+#define COLLECTOR_MODULE_ERR ((CollectorModule)-1)
+
+/* ------- libc interface ----------------- */
+/* the fields in this structure are in alphabetical order.
+ * If you add any, please put it in the right place */
+typedef struct CollectorUtilFuncs
+{
+ int (*access)();
+ int (*atoi)(const char *nptr);
+ void *(*calloc)(size_t nelem, size_t elsize);
+ int (*clearenv)(void);
+ int (*close)(int);
+ int (*closedir)();
+ int (*execv)(const char *path, char *const argv[]);
+ void (*exit)(int status);
+ int (*fclose)(FILE *stream);
+ int (*fcntl)(int fd, int cmd, ...);
+ char *(*fgets)(char *s, int n, FILE *stream);
+ FILE *(*fopen)(const char *filename, const char *mode);
+ pid_t (*vfork)();
+ int (*fprintf)(FILE *stream, const char *format, ...);
+ void (*free)(void *ptr);
+ int (*fstat)(int fd, struct stat *buf);
+ int (*getcpuid)();
+ char *(*getcwd)(char *buf, size_t size);
+ char *(*getenv)(const char *name);
+ struct tm *(*gmtime_r)(const time_t *clock, struct tm *res);
+ int (*ioctl)(int d, int request, ...);
+ off_t (*lseek)(int fd, off_t offset, int whence);
+ void *(*malloc)(size_t size);
+ void *(*memset)(void *s1, int c, size_t n);
+ int (*mkdir)();
+ time_t (*mktime)(struct tm *timeptr);
+ void *(*mmap)(void *, size_t, int, int, int, off_t);
+ void *(*mmap64)();
+ int (*munmap)();
+ int (*open)(const char *, int, ...);
+ int (*open_bare)(const char *, int, ...);
+ DIR *(*opendir)();
+ int (*pclose)(FILE *stream);
+ FILE *(*popen)(const char *command, const char *mode);
+ int (*putenv)(char *string);
+ ssize_t (*pwrite)();
+ ssize_t (*pwrite64)();
+ ssize_t (*read)();
+ int (*setenv)(const char *name, const char *value, int overwrite);
+ int (*sigfillset)(sigset_t *set);
+ int (*sigprocmask)(int how, const sigset_t *set, sigset_t *oldset);
+ int (*snprintf)(char *str, size_t size, const char *format, ...);
+ int (*stack_getbounds)();
+ char *(*strchr)(const char *name, int c);
+ int (*strcmp)(const char *s1, const char *s2);
+ int (*strcpy)(const char *s1, const char *s2);
+ char *(*libc_strdup)(const char *s1); // Don't use "strdup" because it is a macro in gcc
+ char *(*strerror)(int errnum);
+ int (*strerror_r)(int errnum, char *strerrbuf, size_t buflen);
+ size_t (*strlcat)(char *dest, const char *src, size_t dstsize);
+ size_t (*strlcpy)(char *dest, const char *src, size_t dstsize);
+ size_t (*strlen)(const char *string);
+ int (*strncmp)(const char *s1, const char *s2, size_t n);
+ size_t (*strncpy)(char *dst, const char *src, size_t dstsize);
+ size_t (*strspn)(const char *s1, const char *s2);
+ char *(*strrchr)(const char *name, int c);
+ char *(*strstr)(const char *s1, const char *s2);
+ long int (*strtol)(const char *nptr, char **endptr, int base);
+ long long int (*strtoll)(const char *nptr, char **endptr, int base);
+ unsigned long int (*strtoul)(const char *nptr, char **endptr, int base);
+ unsigned long long int (*strtoull)(const char *nptr, char **endptr, int base);
+ int (*symlink)(const char *s1, const char *s2);
+ int (*syscall)(int number, ...);
+ long (*sysconf)(int name);
+ long (*sysinfo)(int command, char *buf, long count);
+ time_t (*time)(time_t *tloc);
+ int (*unsetenv)(const char *name);
+ int (*vsnprintf)(char *str, size_t size, const char *format, va_list ap);
+ pid_t (*waitpid)(pid_t pid, int *stat_loc, int options);
+ ssize_t (*write)();
+ double (*atof)();
+ void *n_a;
+} CollectorUtilFuncs;
+
+extern CollectorUtilFuncs __collector_util_funcs;
+extern int __collector_dlsym_guard;
+
+#define CALL_UTIL(x) __collector_util_funcs.x
+
+/* The following constants define the meaning of the "void *arg"
+ * argument of getFrameInfo().
+ */
+/* arg is a pointer to ucontext_t, walk the stack described by it */
+#define FRINFO_FROM_UC 1
+/* walk the current stack starting from the frame containing arg */
+#define FRINFO_FROM_STACK 2
+/* walk the current stack starting from the caller of the frame containing arg */
+#define FRINFO_FROM_STACK_ARG 3
+/* arg is a pc, process a stack containing just that pc */
+#define FRINFO_FROM_PC 4
+/* arg is of type CM_Array describing a stack image */
+#define FRINFO_FROM_ARRAY 5
+#define FRINFO_NO_OMP_INFO 0x80000000
+#define FRINFO_NO_WALK 0x40000000
+
+typedef struct CM_Array
+{
+ unsigned int length; /* in bytes, not including length */
+ void *bytes;
+} CM_Array;
+
+// Interface with libcollector.so:
+typedef enum
+{
+ SP_ORIGIN_FORK = -1,
+ SP_ORIGIN_LIBCOL_INIT = 0,
+ SP_ORIGIN_DBX_ATTACH = 1,
+ SP_ORIGIN_GENEXP = 2,
+ SP_ORIGIN_KERNEL = 3,
+ SP_ORIGIN_DTRACE = 4,
+ SP_ORIGIN_COLLECT = 5
+} sp_origin_t;
+
+struct Heap;
+struct Common_packet;
+struct CM_Packet;
+struct ModuleInterface;
+
+typedef long long HiResTime;
+typedef int CollectorModule;
+typedef unsigned long long FrameInfo;
+typedef struct CollectorInterface
+{
+ /* General services */
+ CollectorModule (*registerModule)(struct ModuleInterface*);
+ const char *(*getParams)();
+ const char *(*getExpDir)();
+ int (*writeLog)(char *format, ...);
+ FrameInfo (*getFrameInfo)(CollectorModule modl, HiResTime ts, int mode, void *arg);
+ FrameInfo (*getUID)(CM_Array *arg);
+ FrameInfo (*getUID2)(CM_Array *arg, FrameInfo uid);
+ int (*getStackTrace)(void *buf, int size, void *bptr, void *eptr, void *arg);
+ int (*writeMetaData)(CollectorModule modl, char *format, ...);
+
+ /* writeDataRecord ensures that the header is filled in, and then calls writeDataPacket */
+ int (*writeDataRecord)(CollectorModule modl, struct Common_packet *pckt);
+ int (*writeDataPacket)(CollectorModule modl, struct CM_Packet *pckt);
+ void (*write_sample)(char *name);
+ void (*get_progspec)(char *retstr, int tmp_sz, char *namestr, int name_sz);
+ int (*open_experiment)(const char *exp, const char *params, sp_origin_t origin);
+ HiResTime (*getHiResTime)();
+
+ /* Dynamic memory allocation service */
+ struct Heap *(*newHeap)();
+ void (*deleteHeap)(struct Heap *heap);
+ void *(*allocCSize)(struct Heap *heap, unsigned sz, int log);
+ void (*freeCSize)(struct Heap *heap, void *ptr, unsigned sz);
+ void *(*allocVSize)(struct Heap *heap, unsigned sz);
+ void *(*reallocVSize)(struct Heap *heap, void *ptr, unsigned newsz);
+
+ /* Thread specific data service */
+ unsigned (*createKey)(size_t sz, void (*init)(void*), void (*fini)(void*));
+ void *(*getKey)(unsigned key);
+
+ /* Debugging services */
+ void (*writeDebugInfo)(int, int, char *, ...) __attribute__ ((format (printf, 3, 4)));
+} CollectorInterface;
+
+typedef struct ModuleInterface
+{
+ char *description;
+ int (*initInterface)(CollectorInterface*);
+ int (*openExperiment)(const char *);
+ int (*startDataCollection)();
+ int (*stopDataCollection)();
+ int (*closeExperiment)();
+ int (*detachExperiment)(); /* called from fork-child before openExperiment() */
+} ModuleInterface;
+
+typedef CollectorModule (*RegModuleFunc)(ModuleInterface*);
+typedef void (*ModuleInitFunc)(CollectorInterface*);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ CollectorModule __collector_register_module (ModuleInterface *modint);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COLLECTOR_MODULE_H */
diff --git a/gprofng/src/comp_com.c b/gprofng/src/comp_com.c
new file mode 100644
index 0000000..486bd1a
--- /dev/null
+++ b/gprofng/src/comp_com.c
@@ -0,0 +1,3481 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <values.h>
+#include <assert.h>
+
+#include "comp_com.h"
+
+/*
+ * To add a new message _FORMAT_ please perform the following tasks:
+ * 1) Insert it into the list below, with the matching comment.
+ * The table is sorted by parameter type. In increasing order
+ * they are: String, Procedure, Variable, Loop, Region, Integer.
+ * 2) Insert the corresponding information into the following
+ * procedures in this file: ccm_num_params(), ccm_paramlist_index(),
+ * ccm_param_primtype(), and ccm_param_hightype().
+ * 3) If you are also creating a new high-type or primitive-type,
+ * extend the corresponding enum, update this comment and make sure
+ * to update any code in the analyzer, iropt, cg or ube that depends
+ * on knowing the limited set of types.
+ */
+
+typedef enum ccm_fmt {
+ CCMFMT_NONE, /* none */
+ CCMFMT_S1, /* s1 */
+ CCMFMT_S1S2, /* s1, s2 */
+ CCMFMT_S1L2, /* s1, l2 */
+ CCMFMT_S1L2VV3, /* s1, l2, v3, v4, ... */
+ CCMFMT_S1R2VV3, /* s1, r2, v3, v4, ... */
+ CCMFMT_S1X2, /* s1, x2 */
+ CCMFMT_P1, /* p1 */
+ CCMFMT_P1S2, /* p1, s2 */
+ CCMFMT_P1S2P3, /* p1, s2, p3 */
+ CCMFMT_P1S2P3I4, /* p1, s2, p3, i4 */
+ CCMFMT_P1S2I3, /* p1, s2, i3 */
+ CCMFMT_P1P2, /* p1, p2 */
+ CCMFMT_P1L2, /* p1, l2 */
+ CCMFMT_P1I2, /* p1, i2 */
+ CCMFMT_P1I2L3, /* p1, i2, l3 */
+ CCMFMT_P1I2LL3, /* p1, i2, l3, l4 ... */
+ CCMFMT_P1I2I3, /* p1, i2, i3 */
+ CCMFMT_PP1, /* p1, p2, ... */
+ CCMFMT_V1, /* v1 */
+ CCMFMT_V1V2, /* v1, v2 */
+ CCMFMT_V1L2, /* v1, l2 */
+ CCMFMT_VV1, /* v1, v2, ... */
+ CCMFMT_L1, /* l1 */
+ CCMFMT_L1S2, /* l1, s2 */
+ CCMFMT_L1S2L3, /* l1, s2, l3 */
+ CCMFMT_L1P2, /* l1, p2 */
+ CCMFMT_L1P2I3, /* l1, p2, i3 */
+ CCMFMT_L1PP2, /* l1, p2, p3, ... */
+ CCMFMT_L1VV2, /* l1, v2, v3, ... */
+ CCMFMT_L1L2, /* l1, l2 */
+ CCMFMT_L1L2L3, /* l1, l2, l3 */
+ CCMFMT_LL1, /* l1, l2, ... */
+ CCMFMT_L1R2, /* l1, r2 */
+ CCMFMT_L1I2, /* l1, i2 */
+ CCMFMT_L1I2L3, /* l1, i2, l3 */
+ CCMFMT_L1I2LL3, /* l1, i2, l3, l4, ... */
+ CCMFMT_L1I2I3L4, /* l1, i2, i3, l4 */
+ CCMFMT_L1I2I3I4I5, /* l1, i2, ..., i5 */
+ CCMFMT_L1I2I3I4I5I6I7, /* l1, i2, ..., i7 */
+ CCMFMT_L1I2I3I4I5I6I7I8I9, /* l1, i2, ..., i9 */
+ CCMFMT_L1II2, /* l1, i2, i3, ... */
+ CCMFMT_R1, /* r1 */
+ CCMFMT_R1VV2, /* r1, v2, v3, ... */
+ CCMFMT_I1, /* i1 */
+ CCMFMT_I1P2I3, /* i1, p2, i3 */
+ CCMFMT_I1V2, /* i1, v2 */
+ CCMFMT_I1V2V3, /* i1, v2, v3 */
+ CCMFMT_I1L2, /* i1, l2 */
+ CCMFMT_I1LL2, /* i1, l2, l3, ... */
+ CCMFMT_I1I2I3I4, /* i1, i2, i3, i4 */
+ CCMFMT_I1I2I3I4I5I6, /* i1, i2, ..., i6 */
+ CCMFMT_I1I2I3I4I5I6I7I8, /* i1, i2, ..., i8 */
+ CCMFMT_LAST
+} Ccm_Fmttype_t;
+
+/*
+ * Low- and high-level types for commentary parameters.
+ */
+
+typedef enum ccm_primtype
+{
+ CCM_PRIMTYPE_NONE,
+ CCM_PRIMTYPE_STRING,
+ CCM_PRIMTYPE_INTEGER,
+ CCM_PRIMTYPE_HEXSTRING
+} Ccm_Primtype_t;
+
+typedef enum ccm_hightype
+{
+ CCM_HITYPE_NONE,
+ CCM_HITYPE_STRING,
+ CCM_HITYPE_PROCEDURE,
+ CCM_HITYPE_VARIABLE,
+ CCM_HITYPE_LOOPTAG,
+ CCM_HITYPE_REGIONTAG,
+ CCM_HITYPE_HEXSTRING,
+ CCM_HITYPE_INTEGER
+} Ccm_Hitype_t;
+
+typedef struct ccm_attrs
+{
+ char *msg; /* I18N msg string */
+ const char *name; /* Print name for this message ID */
+ int32_t vis; /* Visibility bits */
+ Ccm_Fmttype_t fmt; /* Format type */
+} Ccm_Attr_t;
+
+static Ccm_Attr_t *ccm_attrs; /* Table of per-msg attributes */
+static nl_catd ccm_catd = (nl_catd) - 1; /* messages id */
+
+/*
+ * map COMPMSG_ID to table indices
+ */
+static int
+ccm_vis_index (COMPMSG_ID m)
+{
+ int32_t high = m >> 8;
+ int32_t low = m & 0xFF;
+ for (int i = 0; i < 24; i++, high >>= 1)
+ if (high <= 1)
+ return (i << 8) + low + 1;
+ return 0;
+}
+
+/*
+ * Return # parameters for this message; MAXINT for messages with
+ * parameter lists.
+ */
+static int
+ccm_num_params (COMPMSG_ID m)
+{
+ int vindex;
+ int res;
+ vindex = ccm_vis_index (m);
+ switch (ccm_attrs[vindex].fmt)
+ {
+ case CCMFMT_NONE:
+ res = 0;
+ break;
+ case CCMFMT_S1:
+ case CCMFMT_P1:
+ case CCMFMT_V1:
+ case CCMFMT_L1:
+ case CCMFMT_R1:
+ case CCMFMT_I1:
+ res = 1;
+ break;
+ case CCMFMT_S1S2:
+ case CCMFMT_S1L2:
+ case CCMFMT_S1X2:
+ case CCMFMT_P1S2:
+ case CCMFMT_P1P2:
+ case CCMFMT_P1L2:
+ case CCMFMT_P1I2:
+ case CCMFMT_V1V2:
+ case CCMFMT_V1L2:
+ case CCMFMT_L1S2:
+ case CCMFMT_L1P2:
+ case CCMFMT_L1L2:
+ case CCMFMT_L1R2:
+ case CCMFMT_L1I2:
+ case CCMFMT_I1V2:
+ case CCMFMT_I1L2:
+ res = 2;
+ break;
+ case CCMFMT_P1S2P3:
+ case CCMFMT_P1S2I3:
+ case CCMFMT_P1I2L3:
+ case CCMFMT_P1I2I3:
+ case CCMFMT_L1S2L3:
+ case CCMFMT_L1P2I3:
+ case CCMFMT_L1L2L3:
+ case CCMFMT_L1I2L3:
+ case CCMFMT_I1P2I3:
+ case CCMFMT_I1V2V3:
+ res = 3;
+ break;
+ case CCMFMT_P1S2P3I4:
+ case CCMFMT_L1I2I3L4:
+ case CCMFMT_I1I2I3I4:
+ res = 4;
+ break;
+ case CCMFMT_L1I2I3I4I5:
+ res = 5;
+ break;
+ case CCMFMT_I1I2I3I4I5I6:
+ res = 6;
+ break;
+ case CCMFMT_L1I2I3I4I5I6I7:
+ res = 7;
+ break;
+ case CCMFMT_I1I2I3I4I5I6I7I8:
+ res = 8;
+ break;
+ case CCMFMT_L1I2I3I4I5I6I7I8I9:
+ res = 9;
+ break;
+ case CCMFMT_S1L2VV3:
+ case CCMFMT_S1R2VV3:
+ case CCMFMT_PP1:
+ case CCMFMT_P1I2LL3:
+ case CCMFMT_VV1:
+ case CCMFMT_L1PP2:
+ case CCMFMT_L1VV2:
+ case CCMFMT_LL1:
+ case CCMFMT_L1I2LL3:
+ case CCMFMT_L1II2:
+ case CCMFMT_R1VV2:
+ case CCMFMT_I1LL2:
+ res = MAXINT;
+ break;
+ case CCMFMT_LAST:
+ default:
+ /* programming failure */
+ /* if(1) is hack to get around warning from C++ compiler */
+ if (1) assert (0);
+ break;
+ }
+ return res;
+}
+
+static int
+ccm_paramlist_index (COMPMSG_ID m)
+{
+ int res;
+ int vindex = ccm_vis_index (m);
+ switch (ccm_attrs[vindex].fmt)
+ {
+ case CCMFMT_NONE:
+ case CCMFMT_S1:
+ case CCMFMT_S1S2:
+ case CCMFMT_S1L2:
+ case CCMFMT_S1X2:
+ case CCMFMT_P1:
+ case CCMFMT_P1S2:
+ case CCMFMT_P1S2P3:
+ case CCMFMT_P1S2P3I4:
+ case CCMFMT_P1S2I3:
+ case CCMFMT_P1P2:
+ case CCMFMT_P1L2:
+ case CCMFMT_P1I2:
+ case CCMFMT_P1I2L3:
+ case CCMFMT_P1I2I3:
+ case CCMFMT_V1:
+ case CCMFMT_V1V2:
+ case CCMFMT_V1L2:
+ case CCMFMT_L1:
+ case CCMFMT_L1S2:
+ case CCMFMT_L1S2L3:
+ case CCMFMT_L1P2:
+ case CCMFMT_L1P2I3:
+ case CCMFMT_L1L2:
+ case CCMFMT_L1L2L3:
+ case CCMFMT_L1R2:
+ case CCMFMT_L1I2:
+ case CCMFMT_L1I2L3:
+ case CCMFMT_L1I2I3L4:
+ case CCMFMT_L1I2I3I4I5:
+ case CCMFMT_L1I2I3I4I5I6I7:
+ case CCMFMT_L1I2I3I4I5I6I7I8I9:
+ case CCMFMT_R1:
+ case CCMFMT_I1:
+ case CCMFMT_I1P2I3:
+ case CCMFMT_I1V2:
+ case CCMFMT_I1V2V3:
+ case CCMFMT_I1L2:
+ case CCMFMT_I1I2I3I4:
+ case CCMFMT_I1I2I3I4I5I6:
+ case CCMFMT_I1I2I3I4I5I6I7I8:
+ res = 0;
+ break;
+ case CCMFMT_PP1:
+ case CCMFMT_VV1:
+ case CCMFMT_LL1:
+ res = 1;
+ break;
+ case CCMFMT_L1PP2:
+ case CCMFMT_L1VV2:
+ case CCMFMT_L1II2:
+ case CCMFMT_R1VV2:
+ case CCMFMT_I1LL2:
+ res = 2;
+ break;
+ case CCMFMT_S1L2VV3:
+ case CCMFMT_S1R2VV3:
+ case CCMFMT_P1I2LL3:
+ case CCMFMT_L1I2LL3:
+ res = 3;
+ break;
+ case CCMFMT_LAST:
+ default:
+ /* programming failure */
+ /* if(1) is hack to get around warning from C++ compiler */
+ if (1) assert (0);
+ break;
+ }
+ return res;
+}
+
+static Ccm_Primtype_t
+ccm_param_primtype (COMPMSG_ID m, int param_idx)
+{
+ int vindex;
+ Ccm_Primtype_t res;
+ if (param_idx <= 0 || param_idx > ccm_num_params (m))
+ return CCM_PRIMTYPE_NONE;
+
+ res = CCM_PRIMTYPE_NONE; /* should always be updated */
+ vindex = ccm_vis_index (m);
+ switch (ccm_attrs[vindex].fmt)
+ {
+ /*
+ * Sort cases by:
+ * 1) # parameters
+ * 2) Strings before Integers
+ * 3) Enum tags
+ */
+ case CCMFMT_NONE:
+ /* programming failure */
+ /* if(1) is hack to get around warning from C++ compiler */
+ if (1)
+ assert (0);
+ break;
+ case CCMFMT_S1:
+ case CCMFMT_P1:
+ case CCMFMT_V1:
+ case CCMFMT_L1:
+ case CCMFMT_R1:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_I1:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_S1S2:
+ case CCMFMT_S1L2:
+ case CCMFMT_P1S2:
+ case CCMFMT_P1P2:
+ case CCMFMT_P1L2:
+ case CCMFMT_V1V2:
+ case CCMFMT_V1L2:
+ case CCMFMT_L1S2:
+ case CCMFMT_L1P2:
+ case CCMFMT_L1L2:
+ case CCMFMT_L1R2:
+ if (param_idx == 1 || param_idx == 2)
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_S1X2:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_PRIMTYPE_HEXSTRING;
+ break;
+ case CCMFMT_P1I2:
+ case CCMFMT_L1I2:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_I1V2:
+ case CCMFMT_I1L2:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_INTEGER;
+ else if (param_idx == 2)
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_P1S2P3:
+ case CCMFMT_L1S2L3:
+ case CCMFMT_L1L2L3:
+ if (param_idx >= 1 && param_idx <= 3)
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_P1S2I3:
+ case CCMFMT_L1P2I3:
+ if (param_idx == 1 || param_idx == 2)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 3)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_P1I2L3:
+ case CCMFMT_L1I2L3:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_P1I2I3:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 2 || param_idx == 3)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_I1V2V3:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_INTEGER;
+ else if (param_idx == 2 || param_idx == 3)
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_I1P2I3:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_PRIMTYPE_INTEGER;
+ else if (param_idx == 2)
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_L1I2I3L4:
+ if (param_idx == 1 || param_idx == 4)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 2 || param_idx == 3)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_P1S2P3I4:
+ if (param_idx >= 1 && param_idx <= 3)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx == 4)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_I1I2I3I4:
+ if (param_idx >= 1 && param_idx <= 4)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2I3I4I5:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx >= 2 && param_idx <= 5)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_I1I2I3I4I5I6:
+ if (param_idx >= 1 && param_idx <= 6)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2I3I4I5I6I7:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx >= 2 && param_idx <= 7)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_I1I2I3I4I5I6I7I8:
+ if (param_idx >= 1 && param_idx <= 8)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2I3I4I5I6I7I8I9:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else if (param_idx >= 2 && param_idx <= 9)
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_S1L2VV3:
+ case CCMFMT_S1R2VV3:
+ case CCMFMT_PP1:
+ case CCMFMT_VV1:
+ case CCMFMT_L1PP2:
+ case CCMFMT_L1VV2:
+ case CCMFMT_LL1:
+ case CCMFMT_R1VV2:
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_P1I2LL3:
+ case CCMFMT_L1I2LL3:
+ if (param_idx == 2)
+ res = CCM_PRIMTYPE_INTEGER;
+ else
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_L1II2:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_STRING;
+ else
+ res = CCM_PRIMTYPE_INTEGER;
+ break;
+ case CCMFMT_I1LL2:
+ if (param_idx == 1)
+ res = CCM_PRIMTYPE_INTEGER;
+ else
+ res = CCM_PRIMTYPE_STRING;
+ break;
+ case CCMFMT_LAST:
+ default:
+ /* programming failure */
+ /* if(1) is hack to get around warning from C++ compiler */
+ if (1)
+ assert (0);
+ break;
+ }
+ return res;
+}
+
+static Ccm_Hitype_t
+ccm_param_hightype (COMPMSG_ID m, int param_idx)
+{
+ int vindex;
+ Ccm_Hitype_t res;
+
+ if (param_idx <= 0 || param_idx > ccm_num_params (m))
+ return CCM_HITYPE_NONE;
+ res = CCM_HITYPE_NONE; /* should always be updated */
+ vindex = ccm_vis_index (m);
+ switch (ccm_attrs[vindex].fmt)
+ {
+ case CCMFMT_NONE:
+ /* programming failure */
+ /* if(1) is hack to get around warning from C++ compiler */
+ if (1)
+ assert (0);
+ break;
+ case CCMFMT_S1:
+ if (param_idx == 1)
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_S1S2:
+ if (param_idx == 1 || param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_S1L2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_S1L2VV3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_LOOPTAG;
+ else
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_S1R2VV3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_REGIONTAG;
+ else
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_S1X2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_STRING;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_HEXSTRING;
+ break;
+ case CCMFMT_P1:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ break;
+ case CCMFMT_P1S2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_P1S2P3:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_P1S2P3I4:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ else if (param_idx == 4)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_P1S2I3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ else if (param_idx == 3)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_P1P2:
+ if (param_idx == 1 || param_idx == 2)
+ res = CCM_HITYPE_PROCEDURE;
+ break;
+ case CCMFMT_P1L2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_P1I2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_P1I2L3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_INTEGER;
+ else if (param_idx == 3)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_P1I2I3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2 || param_idx == 3)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_P1I2LL3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_INTEGER;
+ else
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_PP1:
+ res = CCM_HITYPE_PROCEDURE;
+ break;
+ case CCMFMT_V1:
+ if (param_idx == 1)
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_V1V2:
+ if (param_idx == 1 || param_idx == 2)
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_V1L2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_VARIABLE;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_VV1:
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_L1:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_L1S2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_L1S2L3:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_STRING;
+ break;
+ case CCMFMT_L1P2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_PROCEDURE;
+ break;
+ case CCMFMT_L1P2I3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_PROCEDURE;
+ else if (param_idx == 3)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1PP2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else
+ res = CCM_HITYPE_PROCEDURE;
+ break;
+ case CCMFMT_L1VV2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_L1L2:
+ if (param_idx == 1 || param_idx == 2)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_L1L2L3:
+ if (param_idx >= 1 && param_idx <= 3)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_LL1:
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_L1R2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_REGIONTAG;
+ break;
+ case CCMFMT_L1I2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2L3:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2LL3:
+ if (param_idx == 2)
+ res = CCM_HITYPE_INTEGER;
+ else
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_L1I2I3L4:
+ if (param_idx == 1 || param_idx == 4)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx == 2 || param_idx == 3)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2I3I4I5:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx >= 2 && param_idx <= 5)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2I3I4I5I6I7:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx >= 2 && param_idx <= 7)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1I2I3I4I5I6I7I8I9:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else if (param_idx >= 2 && param_idx <= 9)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_L1II2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_LOOPTAG;
+ else
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_R1:
+ if (param_idx == 1)
+ res = CCM_HITYPE_REGIONTAG;
+ break;
+ case CCMFMT_R1VV2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_REGIONTAG;
+ else
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_I1:
+ if (param_idx == 1)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_I1P2I3:
+ if (param_idx == 1 || param_idx == 3)
+ res = CCM_HITYPE_INTEGER;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_PROCEDURE;
+ break;
+ case CCMFMT_I1V2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_INTEGER;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_I1V2V3:
+ if (param_idx == 1)
+ res = CCM_HITYPE_INTEGER;
+ else if (param_idx == 2 || param_idx == 3)
+ res = CCM_HITYPE_VARIABLE;
+ break;
+ case CCMFMT_I1L2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_INTEGER;
+ else if (param_idx == 2)
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_I1LL2:
+ if (param_idx == 1)
+ res = CCM_HITYPE_INTEGER;
+ else
+ res = CCM_HITYPE_LOOPTAG;
+ break;
+ case CCMFMT_I1I2I3I4:
+ if (param_idx >= 1 && param_idx <= 4)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_I1I2I3I4I5I6:
+ if (param_idx >= 1 && param_idx <= 6)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_I1I2I3I4I5I6I7I8:
+ if (param_idx >= 1 && param_idx <= 8)
+ res = CCM_HITYPE_INTEGER;
+ break;
+ case CCMFMT_LAST:
+ default:
+ /* programming failure */
+ /* if(1) is hack to get around warning from C++ compiler */
+ if (1)
+ assert (0);
+ break;
+ }
+ return res;
+}
+
+static void
+ccm_vis_init ()
+{
+ int size, vindex;
+ static int done = 0;
+ if (done)
+ return;
+ done = 1;
+ size = ccm_vis_index ((COMPMSG_ID) (CCMV_BASIC << 8));
+ ccm_attrs = (Ccm_Attr_t *) calloc (size, sizeof (Ccm_Attr_t));
+ if (ccm_attrs == NULL)
+ exit (1);
+ vindex = ccm_vis_index (CCM_MODDATE);
+ ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MODDATE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Source file %s, last modified on date %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1S2;
+
+ vindex = ccm_vis_index (CCM_COMPVER);
+ ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_COMPVER";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Component %s, version %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1S2;
+
+ vindex = ccm_vis_index (CCM_COMPDATE);
+ ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_COMPDATE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Compilation date %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_COMPOPT);
+ ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_COMPOPT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Compilation options %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_ACOMPOPT);
+ ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_ACOMPOPT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Actual Compilation options %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_VAR_ALIAS);
+ ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_VAR_ALIAS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variable %s aliased to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_V1V2;
+
+ vindex = ccm_vis_index (CCM_FBIRDIFF);
+ ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_FBIRDIFF";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Profile feedback data inconsistent with"
+ " intermediate representation file; check compiler"
+ " version, flags and source file");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_OPTRED_SWAP);
+ ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_OPTRED_SWAP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Optimization level for %s reduced from %d to"
+ " %d due to insufficient swap space");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2I3;
+
+ vindex = ccm_vis_index (CCM_OPTRED_CPLX);
+ ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_OPTRED_CPLX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Optimization level for %s reduced from %d to"
+ " %d due to program complexity");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2I3;
+
+ vindex = ccm_vis_index (CCM_UNKNOWN);
+ ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNKNOWN";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Unexpected compiler comment %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_CALL);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_CALL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it contains a"
+ " call to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_PAR_SER);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PAR_SER";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Both serial and parallel versions generated for"
+ " loop below");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_PAR_SER_VER);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PAR_SER_VER";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Both serial and parallel versions generated for"
+ " loop below; with parallel version used if %s,"
+ " serial otherwise");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_PAR_DRECTV);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PAR_DRECTV";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below parallelized by explicit user"
+ " directive");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_APAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_APAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below autoparallelized");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_AUTOPAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_AUTOPAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below autoparallelized; equivalent"
+ " explict directive is %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_DD);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_DD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below could not be parallelized because of a"
+ " data dependency on %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_DDA);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_DDA";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below could not be parallelized because of a"
+ " data dependency or aliasing of %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_ANONDD);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_ANONDD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below could not be parallelized because of"
+ " an anonymous data dependency");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_ANONDDA);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_ANONDDA";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below could not be parallelized because of"
+ " an anonymous data dependency or aliasing");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_PAR_WORK);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PAR_WORK";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below parallelized, but might not contain"
+ " enough work to be efficiently run in parallel");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_EXIT);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_EXIT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it contains"
+ " multiple exit points");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_STRNG);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_STRNG";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it contains a"
+ " strange flow of control");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_IO);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_IO";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it contains"
+ " I/O or other MT-unsafe calls");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_PAR_BODY_NAME);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PAR_BODY_NAME";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Parallel loop-body code is in function %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NLOOPIDX);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NLOOPIDX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because loop index"
+ " not found");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_DRECTV);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_DRECTV";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because of explicit"
+ " user directive");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NOTPROFIT);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NOTPROFIT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it was not"
+ " profitable to do so");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NEST);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NEST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it was"
+ " nested in a parallel loop");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NOAUTO);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NOAUTO";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because"
+ " autoparallelization is not enabled");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_PR_L_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PR_L_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Private variables in loop below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_SH_L_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_SH_L_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Shared variables in loop below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_TP_L_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_TP_L_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Threadprivate variables in loop below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_RV_L_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_RV_L_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Reduction variables in loop below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_IM_L_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IM_L_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Implicit variables in loop below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_PR_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PR_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Private variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_SH_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_SH_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Shared variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_TP_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_TP_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Threadprivate variables in OpenMP construct"
+ " below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_RV_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_RV_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Reduction variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_IM_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IM_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Implicit variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_IN_OMP);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_IN_OMP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below not parallelized because it is inside"
+ " an OpenMP region");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_FP_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_FP_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Firstprivate variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_LP_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LP_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Lastprivate variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_CP_O_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_CP_O_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Copyprivate variables in OpenMP construct below:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_PR_OAS_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PR_OAS_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as PRIVATE in OpenMP"
+ " construct below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_SH_OAS_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_SH_OAS_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as SHARED in OpenMP"
+ " construct below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_FP_OAS_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_FP_OAS_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as FIRSTPRIVATE in OpenMP"
+ " construct below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_LP_OAS_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LP_OAS_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as LASTPRIVATE in OpenMP"
+ " construct below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_RV_OAS_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_RV_OAS_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as REDUCTION in OpenMP"
+ " construct below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_FAIL_OAS_VAR);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_FAIL_OAS_VAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables cannot be autoscoped in OpenMP"
+ " construct below: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+ vindex = ccm_vis_index (CCM_SERIALIZE_OAS);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_SERIALIZE_OAS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "OpenMP parallel region below is serialized"
+ " because autoscoping has failed");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_UNPAR_CALL_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_CALL_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it contains calls"
+ " to: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1PP2;
+
+ vindex = ccm_vis_index (CCM_PAR_DRECTV_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PAR_DRECTV_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s parallelized by explicit user directive");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_APAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_APAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s autoparallelized");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_AUTOPAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_AUTOPAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s autoparallelized; equivalent"
+ " explict directive is %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1S2;
+
+ vindex = ccm_vis_index (CCM_UNPAR_DD_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_DD_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be parallelized because of"
+ " data dependences on: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+ vindex = ccm_vis_index (CCM_UNPAR_DDA_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_DDA_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be parallelized because of a"
+ " data dependence or aliasing of: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+ vindex = ccm_vis_index (CCM_UNPAR_ANONDD_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_ANONDD_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be parallelized because of an"
+ " anonymous data dependence");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_ANONDDA_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_ANONDDA_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be parallelized because of an"
+ " anonymous data dependence or aliasing");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_PAR_WORK_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PAR_WORK_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s parallelized, but might not contain"
+ " enough work to run efficiently in parallel");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_EXIT_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_EXIT_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it contains"
+ " multiple exit points");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_STRANGE_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_STRANGE_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it contains a"
+ " strange flow of control");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_IO_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_IO_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it contains"
+ " I/O or other MT-unsafe calls");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_PAR_BODY_NAME_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP;
+ ccm_attrs[vindex].name = "CCM_PAR_BODY_NAME_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s parallel loop-body code placed in"
+ " function %s along with %d inner loops");
+ ccm_attrs[vindex].fmt = CCMFMT_L1P2I3;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NLOOPIDX_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NLOOPIDX_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because loop index not"
+ " found");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_DRECTV_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_DRECTV_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because of explicit"
+ " user directive");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NOTPROFIT_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NOTPROFIT_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it was not"
+ " profitable to do so");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NEST_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NEST_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it was"
+ " nested within a parallel loop");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_UNPAR_NOAUTO_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNPAR_NOAUTO_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because"
+ " autoparallelization is not enabled");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_PR_L_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PR_L_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Private variables in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+ vindex = ccm_vis_index (CCM_SH_L_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_SH_L_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Shared variables in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+ vindex = ccm_vis_index (CCM_TP_L_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_TP_L_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Threadprivate variables in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+ vindex = ccm_vis_index (CCM_RV_L_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_RV_L_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Reduction variables of operator %s in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1L2VV3;
+
+ vindex = ccm_vis_index (CCM_IM_L_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IM_L_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Implicit variables in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+ vindex = ccm_vis_index (CCM_PR_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PR_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Private variables in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_SH_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_SH_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Shared variables in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_TP_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_TP_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Threadprivate variables in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_RV_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_RV_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Reduction variables of operator %s in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1R2VV3;
+
+ vindex = ccm_vis_index (CCM_IM_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IM_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Implicit variables in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_UNPAR_IN_OMP_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNPAR_IN_OMP_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s not parallelized because it is inside"
+ " OpenMP region %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1R2;
+
+ vindex = ccm_vis_index (CCM_FP_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_FP_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Firstprivate variables in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_LP_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LP_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Lastprivate variables in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_CP_O_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_CP_O_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Copyprivate variables in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_PR_OAS_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PR_OAS_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as PRIVATE in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_SH_OAS_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_SH_OAS_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as SHARED in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_FP_OAS_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_FP_OAS_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as FIRSTPRIVATE in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_LP_OAS_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LP_OAS_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as LASTPRIVATE in %s:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_RV_OAS_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_RV_OAS_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables autoscoped as REDUCTION of operator"
+ " %s in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1R2VV3;
+
+ vindex = ccm_vis_index (CCM_FAIL_OAS_VAR_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN;
+ ccm_attrs[vindex].name = "CCM_FAIL_OAS_VAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variables treated as shared because they cannot"
+ " be autoscoped in %s: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+ vindex = ccm_vis_index (CCM_SERIALIZE_OAS_2);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN;
+ ccm_attrs[vindex].name = "CCM_SERIALIZE_OAS_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s will be executed by a single thread because"
+ " autoscoping for some variables was not successful");
+ ccm_attrs[vindex].fmt = CCMFMT_R1;
+
+ vindex = ccm_vis_index (CCM_QPERMVEC);
+ ccm_attrs[vindex].vis = CCMV_QUERY | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_QPERMVEC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Is %s a permutation vector during execution of"
+ " %s?");
+ ccm_attrs[vindex].fmt = CCMFMT_V1L2;
+
+ vindex = ccm_vis_index (CCM_QEXPR);
+ ccm_attrs[vindex].vis = CCMV_QUERY | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_QEXPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Is expression %s true for %s?");
+ ccm_attrs[vindex].fmt = CCMFMT_S1L2;
+
+ vindex = ccm_vis_index (CCM_QSAFECALL);
+ ccm_attrs[vindex].vis = CCMV_QUERY | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_QSAFECALL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Is subroutine %s MP-safe as used in %s?");
+ ccm_attrs[vindex].fmt = CCMFMT_P1L2;
+
+ vindex = ccm_vis_index (CCM_LCOST);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LCOST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below estimated to cost %d cycles per"
+ " iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_UNROLL);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_UNROLL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below unrolled %d times");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_IMIX);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IMIX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below has %d loads, %d stores,"
+ " %d prefetches, %d FPadds, %d FPmuls, and"
+ " %d FPdivs per iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4I5I6;
+
+ vindex = ccm_vis_index (CCM_SPILLS);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_SPILLS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below required %d integer register spills,"
+ " %d FP register spills, and used"
+ " %d integer registers and %d FP registers");
+ ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4;
+
+ vindex = ccm_vis_index (CCM_LFISSION);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LFISSION";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below fissioned into %d loops");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_LPEEL);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LPEEL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below had iterations peeled off for better"
+ " unrolling and/or parallelization");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_LBLOCKED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LBLOCKED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below blocked by %d for improved cache"
+ " performance");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_LTILED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LTILED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below tiled for better performance");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_LUNRJAM);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LUNRJAM";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below unrolled and jammed");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_LWHILE2DO);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LWHILE2DO";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Bounds test for loop below moved to top of loop");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_L2CALL);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_L2CALL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below replaced by a call to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_LDEAD);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LDEAD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below deleted as dead code");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_LINTRCHNG);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LINTRCHNG";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below interchanged with loop on line %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_FUSEDTO);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_FUSEDTO";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below fused with loop on line %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_FUSEDFROM);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_FUSEDFROM";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop from line %d fused with loop below");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_VECINTRNSC);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_VECINTRNSC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below transformed to use calls to vector"
+ " intrinsic %s");
+ ccm_attrs[vindex].fmt = CCMFMT_PP1;
+
+ vindex = ccm_vis_index (CCM_LSTRIPMINE);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LSTRIPMINE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below strip-mined");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_LNEST2LOOPS);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LNEST2LOOPS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below collapsed with loop on line %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_LREVERSE);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LREVERSE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below has had its iteration direction"
+ " reversed");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_IMIX2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IMIX2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below has %d loads, %d stores,"
+ " %d prefetches, %d FPadds, %d FPmuls,"
+ " %d FPdivs, %d FPsubs, and %d FPsqrts per"
+ " iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4I5I6I7I8;
+
+ vindex = ccm_vis_index (CCM_LUNRFULL);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_LUNRFULL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below fully unrolled");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_ELIM_NOAMORTINST);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_ELIM_NOAMORTINST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below was eliminated as it contains no"
+ " non-amortizable instructions");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_COMP_DALIGN);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_COMP_DALIGN";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Performance of loop below could be improved"
+ " by compiling with -dalign");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_INTIMIX);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_INTIMIX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below has %d int-loads, %d int-stores,"
+ " %d alu-ops, %d muls, %d int-divs and"
+ " %d shifts per iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4I5I6;
+
+ vindex = ccm_vis_index (CCM_LMULTI_VERSION);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LMULTI_VERSION";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s multi-versioned. Specialized version"
+ " is %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1L2;
+
+ vindex = ccm_vis_index (CCM_LCOST_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LCOST_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s estimated to cost %d cycles per iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_UNROLL_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_UNROLL_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s unrolled %d times");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_IMIX_B);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_IMIX_B";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s has %d loads, %d stores,"
+ " %d prefetches, %d FPadds, %d FPmuls, and"
+ " %d FPdivs per iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7;
+
+ vindex = ccm_vis_index (CCM_SPILLS_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_SPILLS_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s required %d integer register spills,"
+ " %d FP register spills, and used"
+ " %d integer registers and %d FP registers");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5;
+
+ vindex = ccm_vis_index (CCM_LFISSION_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LFISSION_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s fissioned into %d loops, generating:"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2LL3;
+
+ vindex = ccm_vis_index (CCM_LFISSION_FRAG);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LFISSION_FRAG";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s contains code from lines: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1II2;
+
+ vindex = ccm_vis_index (CCM_LPEEL_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LPEEL_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s had iterations peeled off for better"
+ " unrolling and/or parallelization");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_LBLOCKED_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LBLOCKED_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s blocked by %d for improved memory"
+ " hierarchy performance, new inner loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2L3;
+
+ vindex = ccm_vis_index (CCM_LOUTER_UNROLL);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LOUTER_UNROLL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s is outer-unrolled %d times as part"
+ " of unroll and jam");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_LJAMMED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LJAMMED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "All %d copies of %s are fused together"
+ " as part of unroll and jam");
+ ccm_attrs[vindex].fmt = CCMFMT_I1L2;
+
+ vindex = ccm_vis_index (CCM_LWHILE2DO_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LWHILE2DO_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Bounds test for %s moved to top of loop");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_L2CALL_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_L2CALL_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s replaced by a call to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1P2;
+
+ vindex = ccm_vis_index (CCM_LDEAD_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LDEAD_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s deleted as dead code");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_LINTRCHNG_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LINTRCHNG_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s interchanged with %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1L2;
+
+ vindex = ccm_vis_index (CCM_LINTRCHNG_ORDER);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LINTRCHNG_ORDER";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "For loop nest below, the final order of loops"
+ " after interchanging and subsequent"
+ " transformations is: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_LL1;
+
+ vindex = ccm_vis_index (CCM_FUSED_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_FUSED_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s fused with %s, new loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+ vindex = ccm_vis_index (CCM_VECINTRNSC_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_VECINTRNSC_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s transformed to use calls to vector"
+ " intrinsics: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1PP2;
+
+ vindex = ccm_vis_index (CCM_LSTRIPMINE_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LSTRIPMINE_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s strip-mined by %d, new inner loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2L3;
+
+ vindex = ccm_vis_index (CCM_LNEST2LOOPS_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LNEST2LOOPS_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s collapsed with %s, new loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+ vindex = ccm_vis_index (CCM_LREVERSE_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LREVERSE_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s has had its iteration direction reversed");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_IMIX2_B);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_IMIX2_B";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s has %d loads, %d stores,"
+ " %d prefetches, %d FPadds, %d FPmuls,"
+ " %d FPdivs, %d FPsubs, and %d FPsqrts per"
+ " iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7I8I9;
+
+ vindex = ccm_vis_index (CCM_LUNRFULL_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LUNRFULL_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s fully unrolled");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_ELIM_NOAMORTINST_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_ELIM_NOAMORTINST_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s was eliminated as it contains no"
+ " non-amortizable instructions");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_COMP_DALIGN_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_COMP_DALIGN_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Performance of %s could be improved by"
+ " compiling with -dalign");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_INTIMIX_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INTIMIX_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s has %d int-loads, %d int-stores,"
+ " %d alu-ops, %d muls, %d int-divs and"
+ " %d shifts per iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7;
+
+ vindex = ccm_vis_index (CCM_OMP_REGION);
+ ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_OMP_REGION";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Source OpenMP region below has tag %s");
+ ccm_attrs[vindex].fmt = CCMFMT_R1;
+
+ vindex = ccm_vis_index (CCM_LMICROVECTORIZE);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LMICROVECTORIZE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s is micro-vectorized");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_LMULTI_VERSION_2);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LMULTI_VERSION_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s multi-versioned for %s."
+ " Specialized version is %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1S2L3;
+
+ vindex = ccm_vis_index (CCM_LCLONED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LCLONED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s cloned for %s. Clone is %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1S2L3;
+
+ vindex = ccm_vis_index (CCM_LUNSWITCHED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LUNSWITCHED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s is unswitched. New loops"
+ " are %s and %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+ vindex = ccm_vis_index (CCM_LRESWITCHED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LRESWITCHED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loops %s and %s and their surrounding"
+ " conditional code have been merged to"
+ " form loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+ vindex = ccm_vis_index (CCM_LSKEWBLOCKED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LSKEWBLOCKED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s skew-blocked by %d with slope"
+ " %d for improved memory hierarchy"
+ " performance, new inner loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2I3L4;
+
+ vindex = ccm_vis_index (CCM_IVSUB);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_IVSUB";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Induction variable substitution performed on %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_ONEITER_REPLACED);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_ONEITER_REPLACED";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s determined to have a trip count of 1;"
+ " converted to straight-line code");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_IMIX3_B);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_IMIX3_B";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s has %d loads, %d stores,"
+ " %d prefetches, %d FPadds, %d FPmuls,"
+ " %d FPmuladds, %d FPdivs, and %d FPsqrts per"
+ " iteration");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7I8I9;
+
+ vindex = ccm_vis_index (CCM_PIPELINE);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PIPELINE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below pipelined");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_PIPESTATS);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PIPESTATS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below scheduled with steady-state cycle"
+ " count = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_CALL);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_CALL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " calls");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INTCC);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INTCC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it sets"
+ " multiple integer condition codes.");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_MBAR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_MBAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains a"
+ " memory barrier instruction");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_MNMX);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_MNMX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " a minimum or a maximum operation");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_U2FLT);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_U2FLT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " an unsigned to float conversion");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_GOT);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_GOT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it sets the"
+ " Global Offset Table pointer");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_IDIV);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_IDIV";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " an integer divide");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_PRFTCH);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_PRFTCH";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " a prefetch operation");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_EXIT);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_EXIT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " an exit operation");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_REG);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_REG";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it contains"
+ " instructions that set the %%gsr or %%fsr register");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_UNS);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_UNS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it has an"
+ " unsigned loop counter");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_UNSUIT);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_UNSUIT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop was unsuitable for pipelining");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INTRINSIC);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INTRINSIC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined because it has an"
+ " intrinsic call to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_BIG);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_BIG";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined as it is too big");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INVINTPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INVINTPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined as it contains too"
+ " many loop invariant integers = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INVFLTPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INVFLTPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined as it contains too"
+ " many loop invariant floats = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INVDBLPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INVDBLPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined as it contains too"
+ " many loop invariant doubles = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_PIPE_SCHEDAFIPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFIPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below was adversely affected by high"
+ " integer register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_PIPE_SCHEDAFDPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFDPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below was adversely affected by high"
+ " double register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_PIPE_SCHEDAFFPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFFPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop below was adversely affected by high"
+ " float register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INTPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INTPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined due to high"
+ " integer register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_DBLPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_DBLPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined due to high"
+ " double register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_FLTPR);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_FLTPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop could not be pipelined due to high"
+ " float register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_PIPELINE_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PIPELINE_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s pipelined");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_PIPESTATS_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PIPESTATS_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s scheduled with steady-state cycle"
+ " count = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_CALL_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_CALL_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " calls");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INTCC_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INTCC_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it sets"
+ " multiple integer condition codes.");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_MBAR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_MBAR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " a memory barrier instruction");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_MNMX_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_MNMX_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " a minimum or a maximum operation");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_U2FLT_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_U2FLT_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " an unsigned to float conversion");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_GOT_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_GOT_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it sets the"
+ " Global Offset Table pointer");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_IDIV_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_IDIV_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " an integer divide");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_PRFTCH_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_PRFTCH_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " a prefetch operation");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_EXIT_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_EXIT_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " an exit operation");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_REG_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_REG_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " instructions that set the %%gsr or %%fsr register");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_UNS_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_UNS_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it has an"
+ " unsigned loop counter");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_UNSUIT_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_UNSUIT_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s is unsuitable for pipelining");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INTRINSIC_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INTRINSIC_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined because it contains"
+ " a call to intrinsic %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1P2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_BIG_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_BIG_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined as it is too big");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INVINTPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INVINTPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined as it contains too"
+ " many loop invariant integers = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INVFLTPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INVFLTPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined as it contains too"
+ " many loop invariant floats = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INVDBLPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INVDBLPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined as it contains too"
+ " many loop invariant doubles = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_PIPE_SCHEDAFIPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFIPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s was adversely affected by high"
+ " integer register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_PIPE_SCHEDAFDPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFDPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s was adversely affected by high"
+ " double register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_PIPE_SCHEDAFFPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFFPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s was adversely affected by high"
+ " float register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_INTPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_INTPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined due to high"
+ " integer register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_DBLPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_DBLPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined due to high"
+ " double register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_NOPIPE_FLTPR_2);
+ ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NOPIPE_FLTPR_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "%s could not be pipelined due to high"
+ " float register pressure = %d");
+ ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+ vindex = ccm_vis_index (CCM_INLINE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_INLINE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from source file %s into"
+ " the code for the following line");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+ vindex = ccm_vis_index (CCM_INLINE2);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_INLINE2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from source file %s into"
+ " inline copy of function %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+ vindex = ccm_vis_index (CCM_INLINE_TMPLT);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INLINE_TMPLT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from template file %s"
+ " into the code for the following line");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+ vindex = ccm_vis_index (CCM_INLINE_TMPLT2);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INLINE_TMPLT2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from template file %s"
+ " into inline copy of function %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+ vindex = ccm_vis_index (CCM_INLINE_OUT_COPY);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INLINE_OUT_COPY";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Out-of-line copy of inlined function %s from"
+ " source file %s generated");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+ vindex = ccm_vis_index (CCM_NINLINE_REC);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_REC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Recursive function %s inlined only up to"
+ " depth %d");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2;
+
+ vindex = ccm_vis_index (CCM_NINLINE_NEST);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_NEST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because inlining is"
+ " already nested too deeply");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CMPLX);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CMPLX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains"
+ " too many operations");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_FB);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_FB";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because the"
+ " profile-feedback execution count is too low");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_PAR);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_PAR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains"
+ " explicit parallel pragmas");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_OPT);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_OPT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is"
+ " compiled with optimization level <= 2");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_USR);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_USR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because either command"
+ " line option or source code pragma prohibited it,"
+ " or it's not safe to inline it");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_AUTO);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_AUTO";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because doing so"
+ " would make automatic storage for %s too large");
+ ccm_attrs[vindex].fmt = CCMFMT_P1P2;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALLS);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALLS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains"
+ " too many calls");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_ACTUAL);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_ACTUAL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it has more"
+ " actual parameters than formal parameters");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_FORMAL);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_FORMAL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it has more"
+ " formal parameters than actual parameters");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_TYPE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_TYPE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because formal"
+ " argument type does not match actual type");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_ATYPE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_ATYPE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because array formal"
+ " argument does not match reshaped array actual"
+ " argument type");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_RETTYPE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_RETTYPE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because return type"
+ " does not match");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_EXCPT);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_EXCPT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it"
+ " guarded by an exception handler");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_UNSAFE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_UNSAFE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it might be"
+ " unsafe (call alloca(), etc)");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_ALIAS);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_ALIAS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because inlining it"
+ " will make the alias analysis in the calling"
+ " function more conservative");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_FEMARK);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_FEMARK";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains"
+ " setjmp/longjmp, or indirect goto, etc");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_RAREX);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_RAREX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is known"
+ " to be rarely executed");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_CLONING);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_CLONING";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s from source file %s cloned,"
+ " creating cloned function %s; constant"
+ " parameters propagated to clone");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+ vindex = ccm_vis_index (CCM_INLINE_B);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INLINE_B";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from source file %s into"
+ " the code for the following line. %d loops"
+ " inlined");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2I3;
+
+ vindex = ccm_vis_index (CCM_INLINE2_B);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INLINE2_B";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from source file %s into"
+ " inline copy of function %s. %d loops inlined");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2P3I4;
+
+ vindex = ccm_vis_index (CCM_INLINE_LOOP);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_LOOP | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_INLINE_LOOP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Loop in function %s, line %d has"
+ " tag %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2L3;
+
+ vindex = ccm_vis_index (CCM_NINLINE_MULTIENTRY);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_MULTIENTRY";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it"
+ " contains an ENTRY statement");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_VARARGS);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_VARARGS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because variable"
+ " argument routines cannot be inlined");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_UNSEEN_BODY);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_UNSEEN_BODY";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because the compiler"
+ " has not seen the body of the function. Use"
+ " -xcrossfile or -xipo in order to inline it");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_UPLEVEL);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_UPLEVEL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is a"
+ " nested routine containing references to"
+ " variables defined in an outer function");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CMDLINE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CMDLINE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because either"
+ " -xinline or source code pragma prohibited it");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_CMPLX);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_CMPLX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because of the"
+ " complexity of the calling routine");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_LANG_MISMATCH);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_LANG_MISMATCH";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because it is in"
+ " a different language");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_RTN_WEAK);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_RTN_WEAK";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it"
+ " is marked weak");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_WEAKFILE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_WEAKFILE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because it is"
+ " in a different file and it contains a"
+ " call to a weak routine");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_TRYCATCH);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_TRYCATCH";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because it is"
+ " in a different file and contains an"
+ " explicit try/catch");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_REGP);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_REGP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because it would"
+ " cause excessive register pressure");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_RTN_REGP);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_RTN_REGP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it would"
+ " cause excessive register pressure");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_XPENSV);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_XPENSV";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because analysis"
+ " exceeds the compilation time limit");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_READONLYIR);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_READONLYIR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is in a file"
+ " specified as read-only by -xipo_archive=readonly"
+ " and it contains calls to static functions");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_THUNK);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_THUNK";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because it is in a"
+ " compiler-generated function that does not"
+ " permit inlining");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CALL_XTARGETS);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CALL_XTARGETS";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Indirect callsite has too many targets;"
+ " callsite marked do not inline");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NINLINE_SELFTAIL_RECURSIVE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_SELFTAIL_RECURSIVE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because"
+ " of a recursive tail-call to itself");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_PRAGMA);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_PRAGMA";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains"
+ " explicit parallel or alias pragmas");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CMPLX2);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CMPLX2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains too"
+ " many operations. Increase max_inst_hard in order"
+ " to inline it: -xinline_param=max_inst_hard:n");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_RARE);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_RARE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because the call"
+ " is rarely executed");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_PAR2);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_PAR2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is called"
+ " within a region guarded by an explicit"
+ " parallel pragmas");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_G_LIMIT);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_G_LIMIT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it would exceed"
+ " the permitted global code size growth limit. Try"
+ " to increase max_growth in order to inline it:"
+ " -xinline_param=max_growth:n");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_L_LIMIT);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_L_LIMIT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it would exceed"
+ " the maximum function size growth limit. Increase"
+ " max_function_inst in order to inline it:"
+ " -xinline_param=max_function_inst:n");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_REC2);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_REC2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Recursive function %s is inlined only up to"
+ " %d levels and up to %d size. Increase"
+ " max_recursive_deptha or max_recursive_inst in"
+ " order to inline it:"
+ " -xinline_param=max_recursive_depth:n,"
+ " -xinline_param=max_recursive_inst:n");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2I3;
+
+ vindex = ccm_vis_index (CCM_NINLINE_FB2);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_FB2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because the"
+ " profile-feedback execution count is too"
+ " low. Decrease min_counter in order to inline it:"
+ " -xinline_param:min_counter:n");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_CS_CMPLX);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_CS_CMPLX";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because called"
+ " function's size is too big. Increase"
+ " max_inst_soft in order to inline it:"
+ " -xinline_param=max_inst_soft:n");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_R_EXCPT);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_R_EXCPT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it contains"
+ " an exception handler");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_ASM);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_ASM";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because"
+ " it contains asm statements");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_R_READONLYIR);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_R_READONLYIR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is in a file"
+ " specified as read-only by -xipo_archive=readonly"
+ " and it is a static function");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_C_READONLYIR);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_C_READONLYIR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s not inlined because the calling"
+ " function is in a file specified as read-only"
+ " by -xipo_archive=readonly");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NINLINE_NEVERRETURN);
+ ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NINLINE_NEVERRETURN";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it"
+ " never returns");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_MPREFETCH);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MPREFETCH";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Prefetch of %s inserted");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_MPREFETCH_LD);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MPREFETCH_LD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Prefetch of %s inserted for load at %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+ vindex = ccm_vis_index (CCM_MPREFETCH_ST);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MPREFETCH_ST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Prefetch of %s inserted for store at %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+ vindex = ccm_vis_index (CCM_MPREFETCH_FB);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MPREFETCH_FB";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Prefetch of %s inserted based on feedback data");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_MPREFETCH_FB_LD);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MPREFETCH_FB_LD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Prefetch of %s inserted for load at %s based"
+ " on feedback data");
+ ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+ vindex = ccm_vis_index (CCM_MPREFETCH_FB_ST);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MPREFETCH_FB_ST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Prefetch of %s inserted for store at %s based"
+ " on feedback data");
+ ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+ vindex = ccm_vis_index (CCM_MLOAD);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MLOAD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Load below refers to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_MSTORE);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MSTORE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Store below refers to %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_MLOAD_P);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MLOAD_P";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Load below refers to %s, and was prefetched"
+ " at %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+ vindex = ccm_vis_index (CCM_MSTORE_P);
+ ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MSTORE_P";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Store below refers to %s, and was prefetched"
+ " at %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+ vindex = ccm_vis_index (CCM_COPYIN);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_COPYIN";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Parameter %d caused a copyin in the following"
+ " call");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_COPYOUT);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_COPYOUT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Parameter %d caused a copyout in the following"
+ " call");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_COPYINOUT);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_COPYINOUT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Parameter %d caused both a copyin and copyout"
+ " in the following call");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_PADDING);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_PADDING";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Padding of %d bytes inserted before"
+ " array %s");
+ ccm_attrs[vindex].fmt = CCMFMT_I1V2;
+
+ vindex = ccm_vis_index (CCM_PADCOMMON);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_PADCOMMON";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Padding of %d bytes inserted before"
+ " array %s in common block %s");
+ ccm_attrs[vindex].fmt = CCMFMT_I1V2V3;
+
+ vindex = ccm_vis_index (CCM_ALIGN_EQ);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_ALIGN_EQ";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Variable/array %s can not be double-aligned,"
+ " because it is equivalenced");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_ALIGN_PERF);
+ ccm_attrs[vindex].vis = CCMV_FE;
+ ccm_attrs[vindex].name = "CCM_ALIGN_PERF";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Alignment of variables in common block may cause"
+ " performance degradation");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_ALIGN_STRUCT);
+ ccm_attrs[vindex].vis = CCMV_FE;
+ ccm_attrs[vindex].name = "CCM_ALIGN_STRUCT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Alignment of component %s in numeric sequence"
+ " structure %s may cause performance degradation");
+ ccm_attrs[vindex].fmt = CCMFMT_S1S2;
+
+ vindex = ccm_vis_index (CCM_TMP_COPY);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TMP_COPY";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %s copied to a temporary");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_TMP_COPYM);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TMP_COPYM";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %s might be copied to a temporary;"
+ " runtime decision made");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_PROC_MISMATCH);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_PROC_MISMATCH";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %d to subprogram %s differs from"
+ " reference on line %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1P2I3;
+
+ vindex = ccm_vis_index (CCM_PROC_MISMATCH2);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_PROC_MISMATCH2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Scalar argument %d to subprogram %s is"
+ " referred to as an array on line %d");
+ ccm_attrs[vindex].fmt = CCMFMT_I1P2I3;
+
+ vindex = ccm_vis_index (CCM_PROC_MISMATCH3);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_PROC_MISMATCH3";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Return type/rank from subprogram %s differs"
+ " from return on line %d");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2;
+
+ vindex = ccm_vis_index (CCM_DO_EXPR);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_DO_EXPR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "DO statement bounds lead to no executions of the"
+ " loop");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_AUTO_BND);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_AUTO_BND";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "The bounds for automatic variable %s are not"
+ " available at all entry points; zero-length"
+ " variable might be allocated");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_LIT_PAD);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_LIT_PAD";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "The character string literal %s padded"
+ " to the length specified for the dummy argument");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_ARRAY_LOOP);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_ARRAY_LOOP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Array statement below generated a loop");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_ARRAY_LOOPNEST);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+ ccm_attrs[vindex].name = "CCM_ARRAY_LOOPNEST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Array statement below generated %d nested loops");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_ALIGN_PERF2);
+ ccm_attrs[vindex].vis = CCMV_FE;
+ ccm_attrs[vindex].name = "CCM_ALIGN_PERF2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Alignment of variable %s in common block %s"
+ " may cause a performance degradation");
+ ccm_attrs[vindex].fmt = CCMFMT_V1V2;
+
+ vindex = ccm_vis_index (CCM_ALIGN_PERF3);
+ ccm_attrs[vindex].vis = CCMV_FE;
+ ccm_attrs[vindex].name = "CCM_ALIGN_PERF3";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Alignment of variable %s in blank common may"
+ " cause a performance degradation");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_IO_LOOP_ARRAY);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_IO_LOOP_ARRAY";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "I/O implied do item below generated an array"
+ " section");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_TMPCONST);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_TMPCONST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Implicit invocation of class %s constructor for"
+ " temporary");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_TMPDEST);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_TMPDEST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Implicit invocation of class %s destructor for"
+ " temporary");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_DBL_CONST);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_DBL_CONST";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Double constant %s used in float expression");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_MINLINE);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MINLINE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s inlined from source file %s by"
+ " front-end");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+ vindex = ccm_vis_index (CCM_MINLINE2);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MINLINE2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s from source file %s inlined into"
+ " inline copy of method %s by front-end");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+ vindex = ccm_vis_index (CCM_MINLINE3);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MINLINE3";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it uses keyword"
+ " %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+ vindex = ccm_vis_index (CCM_MINLINE4);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+ ccm_attrs[vindex].name = "CCM_MINLINE4";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s not inlined because it is too"
+ " complex");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_TMP_COPYOUT);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TMP_COPYOUT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %s copied from a temporary");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_TMP_COPYOUTM);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TMP_COPYOUTM";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %s might be copied from a temporary;"
+ " runtime decision made");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_TMP_COPYINOUT);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TMP_COPYINOUT";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %s copied in and out of a temporary");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_TMP_COPYINOUTM);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TMP_COPYINOUTM";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Argument %s might be copied in and out of"
+ " a temporary; runtime decision made");
+ ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+ vindex = ccm_vis_index (CCM_ARRAY_LOOP_2);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_ARRAY_LOOP_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Array statement below generated loop %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_ARRAY_LOOPNEST_2);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_ARRAY_LOOPNEST_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Array statement below generated %d nested"
+ " loops: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_I1LL2;
+
+ vindex = ccm_vis_index (CCM_IO_LOOP_ARRAY_2);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_IO_LOOP_ARRAY_2";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "I/O implied do item below generated an array"
+ " section: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_USER_LOOP);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_USER_LOOP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Source loop below has tag %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_FOUND_LOOP);
+ ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_FOUND_LOOP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Discovered loop below has tag %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_MFUNCTION_LOOP);
+ ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_MFUNCTION_LOOP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Copy in M-function of loop below has tag %s");
+ ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+ vindex = ccm_vis_index (CCM_FSIMPLE);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_FSIMPLE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Transformations for fsimple=%d applied");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_STACK);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_STACK";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Function %s requires %d Mbytes of stack"
+ " storage");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2;
+
+ vindex = ccm_vis_index (CCM_TAILRECUR);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_TAILRECUR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Recursive tail call in %s optimized to jump to"
+ " entry point");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_TAILCALL);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+ ccm_attrs[vindex].name = "CCM_TAILCALL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to function %s was tail-call optimized");
+ ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+ vindex = ccm_vis_index (CCM_NI_EXIT_OR_PSEUDO);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_EXIT_OR_PSEUDO";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains the pseudo instruction %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_UNARY_OPC);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_UNARY_OPC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains the instruction opcode %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_NI_INT_LDD_ON_V9);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_INT_LDD_ON_V9";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains integer ldd instructions, which are"
+ " deprecated in the v9 architecture");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_LATE_INL_OPC);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_LATE_INL_OPC";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains the instruction opcode %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_IMM_OP);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_IMM_OP";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because the"
+ " relocation or immediate operand %s is not well"
+ " understood by the optimizer");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_STATELEAF);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_STATELEAF";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " references the state register %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_ASR_19);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_ASR_19";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because"
+ " %%asr19 is not supported in pre v8plus code");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_FSR_USE);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_FSR_USE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because"
+ " references to %%fsr can only be optimized when the"
+ " -iaopts flag is used");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_REGISTER);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_REGISTER";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " references the register %s");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+ vindex = ccm_vis_index (CCM_NI_NO_RET_VAL);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_NO_RET_VAL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " does not return the value declared");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_DELAY);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_DELAY";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains a non nop delay slot");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_SCALL);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_SCALL";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " calls a function which returns a structure");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_CASE_POSITION);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_CASE_POSITION";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Case block below was placed at position %d"
+ " based on execution frequency");
+ ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+ vindex = ccm_vis_index (CCM_CALL_WITH_CODE);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_CALL_WITH_CODE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Call to %s replaced with inline code. %d"
+ " loops created: %s");
+ ccm_attrs[vindex].fmt = CCMFMT_P1I2LL3;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_SP_ADDR);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_SP_ADDR";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains a %%sp+reg address");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_BAD_SP_USAGE);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_BAD_SP_USAGE";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " uses/defines the stack pointer in a non-load/store instruction");
+ ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+ vindex = ccm_vis_index (CCM_NI_MIXED_REG_TYPES);
+ ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+ ccm_attrs[vindex].name = "CCM_NI_MIXED_REG_TYPES";
+ ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+ "Template could not be early inlined because it"
+ " contains register %s used as both x-register and register pair");
+ ccm_attrs[vindex].fmt = CCMFMT_S1;
+}
diff --git a/gprofng/src/comp_com.h b/gprofng/src/comp_com.h
new file mode 100644
index 0000000..e410924
--- /dev/null
+++ b/gprofng/src/comp_com.h
@@ -0,0 +1,903 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _COMP_COM_H
+#define _COMP_COM_H
+
+#include <sys/types.h>
+#include <nl_types.h>
+
+/*
+ * This file describes format for the compiler-commentary
+ * section to be added to .o's and propagated to the a.out. It reflects
+ * information the compiler can expose to the user about his or her
+ * program. The section should be generated for all compiles where
+ * the user has specified -g on the compile line.
+ *
+ * In the analyzer, display of the messages will be governed by a user UI
+ * that sets a vis_bits bitmap, and matches it against a show_bits
+ * bitmap table, which is maintained separately from the producer
+ * code. For any message, if (vis_bits&show_bits) is non-zero, the
+ * message is shown. If zero, the message is not shown. A similar
+ * mechanism would be used for a stand-alone source or disassembly browser.
+ *
+ *
+ * The .compcom Section
+ * --------------------
+ * The section will be named ".compcom"; it is generated for each
+ * .o, and aggregated into a single section in the a.out. In that
+ * section, each .o's data is separate, and the tools will loop
+ * over the data for each .o in order to find the subsection for
+ * the particular .o being annotated.
+ *
+ *
+ * Since the header is fixed-length, and the total size of the section
+ * can be easily determined as:
+ *
+ * sizeof(stuct compcomhdr)
+ * + msgcount * sizeof(struct compmsg)
+ * + paramcount * sizeof(int32_t)
+ * + stringlen
+ *
+ * there is no need to have the size in the header.
+ */
+
+typedef struct
+{ /* Header describing the section */
+ int32_t srcname; /* index into strings of source file path */
+ int32_t version; /* a version number for the .compcom format */
+ int32_t msgcount; /* count of messages in the section */
+ int32_t paramcount; /* count of parameters in the section */
+ int32_t stringcount; /* count of strings in the section */
+ int32_t stringlen; /* count of total bytes in strings */
+} compcomhdr;
+
+/*
+ * The data for the .o after the header as:
+ *
+ * compmsg msgs[msgcount]; the array of messages
+ * int32_t param[paramcount]; the parameters used in the messages
+ * parameters are either integers or
+ * string-indices
+ * char msgstrings[stringlen]; the strings used in the messages
+ */
+
+/*
+ * Message Classes and Visualization Bits
+ * --------------------------------------
+ * Each of the messages above may belong to zero or more visualization
+ * classes, governed by a table using zero or more of the following symbolic
+ * names for the classes:
+ */
+typedef enum {
+CCMV_WANT = 0x000, /* High-priority RFE -- used only for human */
+ /* reading of message list */
+CCMV_UNIMPL = 0x000, /* Unimplemented -- used only for human */
+ /* reading of message list */
+CCMV_OBS = 0x000, /* Obsolete -- to be replaced by a different */
+ /* message with different parameters -- */
+ /* used only for human reading of message */
+ /* list */
+CCMV_VER = 0x001, /* Versioning messages */
+CCMV_WARN = 0x002, /* Warning messages */
+CCMV_PAR = 0x004, /* Parallelization messages */
+CCMV_QUERY = 0x008, /* Compiler queries */
+CCMV_LOOP = 0x010, /* Loop detail messages */
+CCMV_PIPE = 0x020, /* Pipelining messages */
+CCMV_INLINE = 0x040, /* Inlining information */
+CCMV_MEMOPS = 0x080, /* Messages concerning memory operations */
+CCMV_FE = 0x100, /* Front-end messages (all compilers) */
+CCMV_CG = 0x200, /* Code-generator messages (all compilers) */
+CCMV_BASIC = 0x400, /* for default messages */
+CCMV_ALL = 0x7FFFFFFF /* for all messages */
+} COMPCLASS_ID;
+
+typedef enum ccm_msgid
+{
+ /* Group: Versioning Messages */
+ /* All of these are global to the .o, and will */
+ /* have lineno = pcoffset = 0 */
+
+CCM_MODDATE=0x00100, /* Source file <s1>, last modified on date <s2> */
+CCM_COMPVER, /* Component <s1>, version <s2> */
+ /* [Emitted for each component of the compiler.] */
+CCM_COMPDATE, /* Compilation date <s1> */
+ /* [<s1> is an I18n string with the date and time] */
+CCM_COMPOPT, /* Compilation options <s1> */
+ /* [As specified by the user] */
+CCM_ACOMPOPT, /* Actual Compilation options <s1> */
+ /* [As expanded by the driver] */
+
+ /* Group: Warning Messages */
+CCM_VAR_ALIAS=0x00200, /* Variable <v1> aliased to <v2> */
+CCM_FBIRDIFF, /* Profile feedback data inconsistent with */
+ /* intermediate representation file; check compiler */
+ /* version, flags and source file */
+CCM_OPTRED_SWAP, /* Optimization level for <p1> reduced from <i2> to */
+ /* <i3> due to insufficient swap space */
+CCM_OPTRED_CPLX, /* Optimization level for <p1> reduced from <i2> to */
+ /* <i3> due to program complexity */
+CCM_UNKNOWN, /* Unexpected compiler comment <i1> */
+
+ /* Group: Parallelization Messages */
+CCM_UNPAR_CALL=0x00400, /* Loop below not parallelized because it contains a */
+ /* call to <p1> */
+
+ /* CCMV_WANT: Don't generate CCM_PAR_SER; always use CCM_PAR_SER_VER */
+CCM_PAR_SER, /* Both serial and parallel versions generated for */
+ /* loop below */
+CCM_PAR_SER_VER, /* Both serial and parallel versions generated for */
+ /* loop below; with parallel version used if <s1>, */
+ /* serial otherwise */
+CCM_PAR_DRECTV, /* Loop below parallelized by explicit user */
+ /* directive */
+CCM_APAR, /* Loop below autoparallelized */
+CCM_AUTOPAR, /* Loop below autoparallelized; equivalent */
+ /* explict directive is <s1> */
+CCM_UNPAR_DD, /* Loop below could not be parallelized because of a */
+ /* data dependency on <v1>, <v2>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_UNPAR_DDA, /* Loop below could not be parallelized because of a */
+ /* data dependency or aliasing of <v1>, <v2>, ... */
+CCM_UNPAR_ANONDD, /* Loop below could not be parallelized because of */
+ /* an anonymous data dependency */
+CCM_UNPAR_ANONDDA, /* Loop below could not be parallelized because of */
+ /* an anonymous data dependency or aliasing */
+CCM_PAR_WORK, /* Loop below parallelized, but might not contain */
+ /* enough work to be efficiently run in parallel */
+CCM_UNPAR_EXIT, /* Loop below not parallelized because it contains */
+ /* multiple exit points */
+CCM_UNPAR_STRNG, /* Loop below not parallelized because it contains a */
+ /* strange flow of control */
+CCM_UNPAR_IO, /* Loop below not parallelized because it contains */
+ /* I/O or other MT-unsafe calls */
+CCM_PAR_BODY_NAME, /* Parallel loop-body code is in function <p1> */
+CCM_UNPAR_NLOOPIDX, /* Loop below not parallelized because loop index */
+ /* not found */
+CCM_UNPAR_DRECTV, /* Loop below not parallelized because of explicit */
+ /* user directive */
+CCM_UNPAR_NOTPROFIT, /* Loop below not parallelized because it was not */
+ /* profitable to do so */
+CCM_UNPAR_NEST, /* Loop below not parallelized because it was */
+ /* nested in a parallel loop */
+CCM_UNPAR, /* Loop below not parallelized */
+CCM_UNPAR_NOAUTO, /* Loop below not parallelized because */
+ /* autoparallelization is not enabled */
+CCM_PR_L_VAR, /* Private variables in loop below: */
+ /* <v1>, <v2>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_SH_L_VAR, /* Shared variables in loop below: */
+ /* <v1>, <v2>, ... */
+CCM_TP_L_VAR, /* Threadprivate variables in loop below: */
+ /* <v1>, <v2>, ... */
+CCM_RV_L_VAR, /* Reduction variables in loop below: */
+ /* <v1>, <v2>, ... */
+CCM_IM_L_VAR, /* Implicit variables in loop below: */
+ /* <v1>, <v2>, ... */
+CCM_PR_O_VAR, /* Private variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_SH_O_VAR, /* Shared variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_TP_O_VAR, /* Threadprivate variables in OpenMP construct */
+ /* below: <v1>, <v2>, ... */
+CCM_RV_O_VAR, /* Reduction variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_IM_O_VAR, /* Implicit variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_UNPAR_IN_OMP, /* Loop below not parallelized because it is inside */
+ /* an OpenMP region */
+CCM_FP_O_VAR, /* Firstprivate variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_LP_O_VAR, /* Lastprivate variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_CP_O_VAR, /* Copyprivate variables in OpenMP construct below: */
+ /* <v1>, <v2>, ... */
+CCM_PR_OAS_VAR, /* Variables autoscoped as PRIVATE in OpenMP */
+ /* construct below: <v1>, <v2>, ... */
+CCM_SH_OAS_VAR, /* Variables autoscoped as SHARED in OpenMP */
+ /* construct below: <v1>, <v2>, ... */
+CCM_FP_OAS_VAR, /* Variables autoscoped as FIRSTPRIVATE in OpenMP */
+ /* construct below: <v1>, <v2>, ... */
+CCM_LP_OAS_VAR, /* Variables autoscoped as LASTPRIVATE in OpenMP */
+ /* construct below: <v1>, <v2>, ... */
+CCM_RV_OAS_VAR, /* Variables autoscoped as REDUCTION in OpenMP */
+ /* construct below: <v1>, <v2>, ... */
+CCM_FAIL_OAS_VAR, /* Variables cannot be autoscoped in OpenMP */
+ /* construct below: <v1>, <v2>, ... */
+CCM_SERIALIZE_OAS, /* OpenMP parallel region below is serialized */
+ /* because autoscoping has failed */
+CCM_UNPAR_CALL_2, /* <l1> not parallelized because it contains calls */
+ /* to: <p2>, <p3>, ... */
+CCM_PAR_DRECTV_2, /* <l1> parallelized by explicit user directive */
+CCM_APAR_2, /* <l1> autoparallelized */
+CCM_AUTOPAR_2, /* <l1> autoparallelized; equivalent */
+ /* explict directive is <s2> */
+CCM_UNPAR_DD_2, /* <l1> could not be parallelized because of */
+ /* data dependences on: <v2>, <v3>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_UNPAR_DDA_2, /* <l1> could not be parallelized because of a */
+ /* data dependence or aliasing of: <v2>, <v3>, ... */
+CCM_UNPAR_ANONDD_2, /* <l1> could not be parallelized because of an */
+ /* anonymous data dependence */
+CCM_UNPAR_ANONDDA_2, /* <l1> could not be parallelized because of an */
+ /* anonymous data dependence or aliasing */
+CCM_PAR_WORK_2, /* <l1> parallelized, but might not contain */
+ /* enough work to run efficiently in parallel */
+CCM_UNPAR_EXIT_2, /* <l1> not parallelized because it contains */
+ /* multiple exit points */
+CCM_UNPAR_STRANGE_2, /* <l1> not parallelized because it contains a */
+ /* strange flow of control */
+CCM_UNPAR_IO_2, /* <l1> not parallelized because it contains */
+ /* I/O or other MT-unsafe calls */
+CCM_PAR_BODY_NAME_2, /* <l1> parallel loop-body code placed in */
+ /* function <p2> along with <i3> inner loops */
+CCM_UNPAR_NLOOPIDX_2, /* <l1> not parallelized because loop index not */
+ /* found */
+CCM_UNPAR_DRECTV_2, /* <l1> not parallelized because of explicit */
+ /* user directive */
+CCM_UNPAR_NOTPROFIT_2, /* <l1> not parallelized because it was not */
+ /* profitable to do so */
+CCM_UNPAR_NEST_2, /* <l1> not parallelized because it was */
+ /* nested within a parallel loop */
+CCM_UNPAR_2, /* <l1> not parallelized */
+CCM_UNPAR_NOAUTO_2, /* <l1> not parallelized because */
+ /* autoparallelization is not enabled */
+CCM_PR_L_VAR_2, /* Private variables in <l1>: */
+ /* <v2>, <v3>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_SH_L_VAR_2, /* Shared variables in <l1>: */
+ /* <v2>, <v3>, ... */
+CCM_TP_L_VAR_2, /* Threadprivate variables in <l1>: */
+ /* <v2>, <v3>, ... */
+CCM_RV_L_VAR_2, /* Reduction variables of operator <s1> in <l2>: */
+ /* <v3>, <v4>, ... */
+CCM_IM_L_VAR_2, /* Implicit variables in <l1>: */
+ /* <v2>, <v3>, ... */
+CCM_PR_O_VAR_2, /* Private variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_SH_O_VAR_2, /* Shared variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_TP_O_VAR_2, /* Threadprivate variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_RV_O_VAR_2, /* Reduction variables of operator <s1> in <r2>: */
+ /* <v3>, <v4>, ... */
+CCM_IM_O_VAR_2, /* Implicit variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_UNPAR_IN_OMP_2, /* <l1> not parallelized because it is inside */
+ /* OpenMP region <r2> */
+CCM_FP_O_VAR_2, /* Firstprivate variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_LP_O_VAR_2, /* Lastprivate variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_CP_O_VAR_2, /* Copyprivate variables in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_PR_OAS_VAR_2, /* Variables autoscoped as PRIVATE in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_SH_OAS_VAR_2, /* Variables autoscoped as SHARED in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_FP_OAS_VAR_2, /* Variables autoscoped as FIRSTPRIVATE in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_LP_OAS_VAR_2, /* Variables autoscoped as LASTPRIVATE in <r1>: */
+ /* <v2>, <v3>, ... */
+CCM_RV_OAS_VAR_2, /* Variables autoscoped as REDUCTION of operator */
+ /* <s1> in <r2>: <v3>, <v4>, ... */
+CCM_FAIL_OAS_VAR_2, /* Variables treated as shared because they cannot */
+ /* be autoscoped in <r1>: <v2>, <v3>, ... */
+CCM_SERIALIZE_OAS_2, /* <r1> will be executed by a single thread because */
+ /* autoscoping for some variables was not successful */
+
+ /* Group: Parallelization Questions asked of the user */
+ /* How will the user answer these questions? */
+CCM_QPERMVEC=0x00800, /* Is <v1> a permutation vector during execution of */
+ /* <l2>? */
+CCM_QEXPR, /* Is expression <s1> true for <l2>? */
+CCM_QSAFECALL, /* Is subroutine <p1> MP-safe as used in <l2>? */
+
+ /* Group: Loop Optimization Messages */
+CCM_LCOST=0x01000, /* Loop below estimated to cost <i1> cycles per */
+ /* iteration */
+CCM_UNROLL, /* Loop below unrolled <i1> times */
+ /* CCMV_WANT: the next one should be replaced by CCM_IMIX2 */
+CCM_IMIX, /* Loop below has <i1> loads, <i2> stores, */
+ /* <i3> prefetches, <i4> FPadds, <i5> FPmuls, and */
+ /* <i6> FPdivs per iteration */
+CCM_SPILLS, /* Loop below required <i1> integer register spills, */
+ /* <i2> FP register spills, and used */
+ /* <i3> integer registers and <i4> FP registers */
+CCM_LFISSION, /* Loop below fissioned into <i1> loops */
+CCM_LPEEL, /* Loop below had iterations peeled off for better */
+ /* unrolling and/or parallelization */
+CCM_LBLOCKED, /* Loop below blocked by <i1> for improved cache */
+ /* performance */
+CCM_LTILED, /* Loop below tiled for better performance */
+CCM_LUNRJAM, /* Loop below unrolled and jammed */
+CCM_LWHILE2DO, /* Bounds test for loop below moved to top of loop */
+CCM_L2CALL, /* Loop below replaced by a call to <p1> */
+CCM_LDEAD, /* Loop below deleted as dead code */
+CCM_LINTRCHNG, /* Loop below interchanged with loop on line <i1> */
+CCM_FUSEDTO, /* Loop below fused with loop on line <i1> */
+CCM_FUSEDFROM, /* Loop from line <i1> fused with loop below */
+CCM_VECINTRNSC, /* Loop below transformed to use calls to vector */
+ /* intrinsic <p1>, <p2>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_LSTRIPMINE, /* Loop below strip-mined */
+CCM_LNEST2LOOPS, /* Loop below collapsed with loop on line <i1> */
+CCM_LREVERSE, /* Loop below has had its iteration direction */
+ /* reversed */
+CCM_IMIX2, /* Loop below has <i1> loads, <i2> stores, */
+ /* <i3> prefetches, <i4> FPadds, <i5> FPmuls, */
+ /* <i6> FPdivs, <i7> FPsubs, and <i8> FPsqrts per */
+ /* iteration */
+CCM_LUNRFULL, /* Loop below fully unrolled */
+CCM_ELIM_NOAMORTINST, /* Loop below was eliminated as it contains no */
+ /* non-amortizable instructions */
+CCM_COMP_DALIGN, /* Performance of loop below could be improved */
+ /* by compiling with -dalign */
+CCM_INTIMIX, /* Loop below has <i1> int-loads, <i2> int-stores, */
+ /* <i3> alu-ops, <i4> muls, <i5> int-divs and */
+ /* <i6> shifts per iteration */
+CCM_LMULTI_VERSION, /* <l1> multi-versioned. Specialized version */
+ /* is <l2> */
+CCM_LCOST_2, /* <l1> estimated to cost <i2> cycles per iteration */
+CCM_UNROLL_2, /* <l1> unrolled <i2> times */
+
+ /* CCMV_WANT: the next one should be replaced by CCM_IMIX2_B or CCM_IMIX3_B */
+CCM_IMIX_B, /* <l1> has <i2> loads, <i3> stores, */
+ /* <i4> prefetches, <i5> FPadds, <i6> FPmuls, and */
+ /* <i7> FPdivs per iteration */
+CCM_SPILLS_2, /* <l1> required <i2> integer register spills, */
+ /* <i3> FP register spills, and used */
+ /* <i4> integer registers and <i5> FP registers */
+CCM_LFISSION_2, /* <l1> fissioned into <i2> loops, generating: */
+ /* <l3>, <l4>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_LFISSION_FRAG, /* <l1> contains code from lines: <i2>, <i3>, ... */
+CCM_LPEEL_2, /* <l1> had iterations peeled off for better */
+ /* unrolling and/or parallelization */
+CCM_LBLOCKED_2, /* <l1> blocked by <i2> for improved memory */
+ /* hierarchy performance, new inner loop <l3> */
+CCM_LOUTER_UNROLL, /* <l1> is outer-unrolled <i2> times as part */
+ /* of unroll and jam */
+CCM_LJAMMED, /* All <i1> copies of <l2> are fused together */
+ /* as part of unroll and jam */
+CCM_LWHILE2DO_2, /* Bounds test for <l1> moved to top of loop */
+CCM_L2CALL_2, /* <l1> replaced by a call to <p2> */
+CCM_LDEAD_2, /* <l1> deleted as dead code */
+CCM_LINTRCHNG_2, /* <l1> interchanged with <l2> */
+CCM_LINTRCHNG_ORDER, /* For loop nest below, the final order of loops */
+ /* after interchanging and subsequent */
+ /* transformations is: <l1>, <l2>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_FUSED_2, /* <l1> fused with <l2>, new loop <l3> */
+CCM_VECINTRNSC_2, /* <l1> transformed to use calls to vector */
+ /* intrinsics: <p2>, <p3>, ... */
+CCM_LSTRIPMINE_2, /* <l1> strip-mined by <i2>, new inner loop <l3> */
+CCM_LNEST2LOOPS_2, /* <l1> collapsed with <l2>, new loop <l3> */
+CCM_LREVERSE_2, /* <l1> has had its iteration direction reversed */
+CCM_IMIX2_B, /* <l1> has <i2> loads, <i3> stores, */
+ /* <i4> prefetches, <i5> FPadds, <i6> FPmuls, */
+ /* <i7> FPdivs, <i8> FPsubs, and <i9> FPsqrts per */
+ /* iteration */
+CCM_LUNRFULL_2, /* <l1> fully unrolled */
+CCM_ELIM_NOAMORTINST_2, /* <l1> was eliminated as it contains no */
+ /* non-amortizable instructions */
+CCM_COMP_DALIGN_2, /* Performance of <l1> could be improved by */
+ /* compiling with -dalign */
+CCM_INTIMIX_2, /* <l1> has <i2> int-loads, <i3> int-stores, */
+ /* <i4> alu-ops, <i5> muls, <i6> int-divs and */
+ /* <i7> shifts per iteration */
+CCM_OMP_REGION, /* Source OpenMP region below has tag <r1> */
+CCM_LMICROVECTORIZE, /* <l1> is micro-vectorized */
+CCM_LMULTI_VERSION_2, /* <l1> multi-versioned for <s2>. */
+ /* Specialized version is <l3> */
+CCM_LCLONED, /* <l1> cloned for <s2>. Clone is <l3> */
+CCM_LUNSWITCHED, /* <l1> is unswitched. New loops */
+ /* are <l2> and <l3> */
+CCM_LRESWITCHED, /* Loops <l1> and <l2> and their surrounding */
+ /* conditional code have been merged to */
+ /* form loop <l3> */
+CCM_LSKEWBLOCKED, /* <l1> skew-blocked by <i2> with slope */
+ /* <i3> for improved memory hierarchy */
+ /* performance, new inner loop <l4> */
+CCM_IVSUB, /* Induction variable substitution performed on <l1> */
+CCM_ONEITER_REPLACED, /* <l1> determined to have a trip count of 1; */
+ /* converted to straight-line code */
+CCM_IMIX3_B, /* <l1> has <i2> loads, <i3> stores, */
+ /* <i4> prefetches, <i5> FPadds, <i6> FPmuls, */
+ /* <i7> FPmuladds, <i8> FPdivs, and <i9> FPsqrts per */
+ /* iteration */
+
+ /* Group: Pipelining Messages */
+CCM_PIPELINE=0x02000, /* Loop below pipelined */
+CCM_PIPESTATS, /* Loop below scheduled with steady-state cycle */
+ /* count = <i1> */
+CCM_NOPIPE_CALL, /* Loop could not be pipelined because it contains */
+ /* calls */
+CCM_NOPIPE_INTCC, /* Loop could not be pipelined because it sets */
+ /* multiple integer condition codes. */
+CCM_NOPIPE_MBAR, /* Loop could not be pipelined because it contains a */
+ /* memory barrier instruction */
+CCM_NOPIPE_MNMX, /* Loop could not be pipelined because it contains */
+ /* a minimum or a maximum operation */
+CCM_NOPIPE_U2FLT, /* Loop could not be pipelined because it contains */
+ /* an unsigned to float conversion */
+CCM_NOPIPE_GOT, /* Loop could not be pipelined because it sets the */
+ /* Global Offset Table pointer */
+CCM_NOPIPE_IDIV, /* Loop could not be pipelined because it contains */
+ /* an integer divide */
+CCM_NOPIPE_PRFTCH, /* Loop could not be pipelined because it contains */
+ /* a prefetch operation */
+CCM_NOPIPE_EXIT, /* Loop could not be pipelined because it contains */
+ /* an exit operation */
+CCM_NOPIPE_REG, /* Loop could not be pipelined because it contains */
+ /* instructions that set the %gsr or %fsr register */
+CCM_NOPIPE_UNS, /* Loop could not be pipelined because it has an */
+ /* unsigned loop counter */
+CCM_NOPIPE_UNSUIT, /* Loop was unsuitable for pipelining */
+CCM_NOPIPE_INTRINSIC, /* Loop could not be pipelined because it has an */
+ /* intrinsic call to <p1> */
+CCM_NOPIPE_BIG, /* Loop could not be pipelined as it is too big */
+CCM_NOPIPE_INVINTPR, /* Loop could not be pipelined as it contains too */
+ /* many loop invariant integers = <i1> */
+CCM_NOPIPE_INVFLTPR, /* Loop could not be pipelined as it contains too */
+ /* many loop invariant floats = <i1> */
+CCM_NOPIPE_INVDBLPR, /* Loop could not be pipelined as it contains too */
+ /* many loop invariant doubles = <i1> */
+CCM_PIPE_SCHEDAFIPR, /* Loop below was adversely affected by high */
+ /* integer register pressure = <i1> */
+CCM_PIPE_SCHEDAFDPR, /* Loop below was adversely affected by high */
+ /* double register pressure = <i1> */
+CCM_PIPE_SCHEDAFFPR, /* Loop below was adversely affected by high */
+ /* float register pressure = <i1> */
+CCM_NOPIPE_INTPR, /* Loop could not be pipelined due to high */
+ /* integer register pressure = <i1> */
+CCM_NOPIPE_DBLPR, /* Loop could not be pipelined due to high */
+ /* double register pressure = <i1> */
+CCM_NOPIPE_FLTPR, /* Loop could not be pipelined due to high */
+ /* float register pressure = <i1> */
+CCM_PIPELINE_2, /* <l1> pipelined */
+CCM_PIPESTATS_2, /* <l1> scheduled with steady-state cycle */
+ /* count = <i2> */
+CCM_NOPIPE_CALL_2, /* <l1> could not be pipelined because it contains */
+ /* calls */
+CCM_NOPIPE_INTCC_2, /* <l1> could not be pipelined because it sets */
+ /* multiple integer condition codes. */
+CCM_NOPIPE_MBAR_2, /* <l1> could not be pipelined because it contains */
+ /* a memory barrier instruction */
+CCM_NOPIPE_MNMX_2, /* <l1> could not be pipelined because it contains */
+ /* a minimum or a maximum operation */
+CCM_NOPIPE_U2FLT_2, /* <l1> could not be pipelined because it contains */
+ /* an unsigned to float conversion */
+CCM_NOPIPE_GOT_2, /* <l1> could not be pipelined because it sets the */
+ /* Global Offset Table pointer */
+CCM_NOPIPE_IDIV_2, /* <l1> could not be pipelined because it contains */
+ /* an integer divide */
+CCM_NOPIPE_PRFTCH_2, /* <l1> could not be pipelined because it contains */
+ /* a prefetch operation */
+CCM_NOPIPE_EXIT_2, /* <l1> could not be pipelined because it contains */
+ /* an exit operation */
+CCM_NOPIPE_REG_2, /* <l1> could not be pipelined because it contains */
+ /* instructions that set the %gsr or %fsr register */
+CCM_NOPIPE_UNS_2, /* <l1> could not be pipelined because it has an */
+ /* unsigned loop counter */
+CCM_NOPIPE_UNSUIT_2, /* <l1> is unsuitable for pipelining */
+CCM_NOPIPE_INTRINSIC_2, /* <l1> could not be pipelined because it contains */
+ /* a call to intrinsic <p2> */
+CCM_NOPIPE_BIG_2, /* <l1> could not be pipelined as it is too big */
+CCM_NOPIPE_INVINTPR_2, /* <l1> could not be pipelined as it contains too */
+ /* many loop invariant integers = <i2> */
+CCM_NOPIPE_INVFLTPR_2, /* <l1> could not be pipelined as it contains too */
+ /* many loop invariant floats = <i2> */
+CCM_NOPIPE_INVDBLPR_2, /* <l1> could not be pipelined as it contains too */
+ /* many loop invariant doubles = <i2> */
+CCM_PIPE_SCHEDAFIPR_2, /* <l1> was adversely affected by high */
+ /* integer register pressure = <i2> */
+CCM_PIPE_SCHEDAFDPR_2, /* <l1> was adversely affected by high */
+ /* double register pressure = <i2> */
+CCM_PIPE_SCHEDAFFPR_2, /* <l1> was adversely affected by high */
+ /* float register pressure = <i2> */
+CCM_NOPIPE_INTPR_2, /* <l1> could not be pipelined due to high */
+ /* integer register pressure = <i2> */
+CCM_NOPIPE_DBLPR_2, /* <l1> could not be pipelined due to high */
+ /* double register pressure = <i2> */
+CCM_NOPIPE_FLTPR_2, /* <l1> could not be pipelined due to high */
+ /* float register pressure = <i2> */
+
+ /* Group: Inlining Messages */
+CCM_INLINE=0x04000, /* Function <p1> inlined from source file <s2> into */
+ /* the code for the following line */
+CCM_INLINE2, /* Function <p1> inlined from source file <s2> into */
+ /* inline copy of function <p3> */
+CCM_INLINE_TMPLT, /* Function <p1> inlined from template file <s2> */
+ /* into the code for the following line */
+CCM_INLINE_TMPLT2, /* Function <p1> inlined from template file <s2> */
+ /* into inline copy of function <p3> */
+CCM_INLINE_OUT_COPY, /* Out-of-line copy of inlined function <p1> from */
+ /* source file <s2> generated */
+CCM_NINLINE_REC, /* Recursive function <p1> inlined only up to */
+ /* depth <i2> */
+CCM_NINLINE_NEST, /* Function <p1> not inlined because inlining is */
+ /* already nested too deeply */
+CCM_NINLINE_CMPLX, /* Function <p1> not inlined because it contains */
+ /* too many operations */
+CCM_NINLINE_FB, /* Function <p1> not inlined because the */
+ /* profile-feedback execution count is too low */
+CCM_NINLINE_PAR, /* Function <p1> not inlined because it contains */
+ /* explicit parallel pragmas */
+CCM_NINLINE_OPT, /* Function <p1> not inlined because it is */
+ /* compiled with optimization level <= 2 */
+CCM_NINLINE_USR, /* Function <p1> not inlined because either command */
+ /* line option or source code pragma prohibited it, */
+ /* or it's not safe to inline it */
+CCM_NINLINE_AUTO, /* Function <p1> not inlined because doing so */
+ /* would make automatic storage for <p2> too large */
+CCM_NINLINE_CALLS, /* Function <p1> not inlined because it contains */
+ /* too many calls */
+CCM_NINLINE_ACTUAL, /* Function <p1> not inlined because it has more */
+ /* actual parameters than formal parameters */
+CCM_NINLINE_FORMAL, /* Function <p1> not inlined because it has more */
+ /* formal parameters than actual parameters */
+CCM_NINLINE_TYPE, /* Function <p1> not inlined because formal */
+ /* argument type does not match actual type */
+CCM_NINLINE_ATYPE, /* Function <p1> not inlined because array formal */
+ /* argument does not match reshaped array actual */
+ /* argument type */
+CCM_NINLINE_RETTYPE, /* Function <p1> not inlined because return type */
+ /* does not match */
+CCM_NINLINE_EXCPT, /* Function <p1> not inlined because it */
+ /* guarded by an exception handler */
+CCM_NINLINE_UNSAFE, /* Function <p1> not inlined because it might be */
+ /* unsafe (call alloca(), etc) */
+CCM_NINLINE_ALIAS, /* Function <p1> not inlined because inlining it */
+ /* will make the alias analysis in the calling */
+ /* function more conservative */
+CCM_NINLINE_FEMARK, /* Function <p1> not inlined because it contains */
+ /* setjmp/longjmp, or indirect goto, etc */
+CCM_NINLINE_RAREX, /* Function <p1> not inlined because it is known */
+ /* to be rarely executed */
+CCM_CLONING, /* Function <p1> from source file <s2> cloned, */
+ /* creating cloned function <p3>; constant */
+ /* parameters propagated to clone */
+CCM_INLINE_B, /* Function <p1> inlined from source file <s2> into */
+ /* the code for the following line. <i3> loops */
+ /* inlined */
+CCM_INLINE2_B, /* Function <p1> inlined from source file <s2> into */
+ /* inline copy of function <p3>. <i4> loops inlined */
+CCM_INLINE_LOOP, /* Loop in function <p1>, line <i2> has */
+ /* tag <l3> */
+CCM_NINLINE_MULTIENTRY, /* Function <p1> not inlined because it */
+ /* contains an ENTRY statement */
+CCM_NINLINE_VARARGS, /* Function <p1> not inlined because variable */
+ /* argument routines cannot be inlined */
+CCM_NINLINE_UNSEEN_BODY, /* Function <p1> not inlined because the compiler */
+ /* has not seen the body of the function. Use */
+ /* -xcrossfile or -xipo in order to inline it */
+CCM_NINLINE_UPLEVEL, /* Function <p1> not inlined because it is a */
+ /* nested routine containing references to */
+ /* variables defined in an outer function */
+CCM_NINLINE_CMDLINE, /* Function <p1> not inlined because either */
+ /* -xinline or source code pragma prohibited it */
+CCM_NINLINE_CALL_CMPLX, /* Call to <p1> not inlined because of the */
+ /* complexity of the calling routine */
+CCM_NINLINE_LANG_MISMATCH, /* Call to <p1> not inlined because it is in */
+ /* a different language */
+CCM_NINLINE_RTN_WEAK, /* Function <p1> not inlined because it */
+ /* is marked weak */
+CCM_NINLINE_CALL_WEAKFILE, /* Call to <p1> not inlined because it is */
+ /* in a different file and it contains a */
+ /* call to a weak routine */
+CCM_NINLINE_CALL_TRYCATCH, /* Call to <p1> not inlined because it is */
+ /* in a different file and contains an */
+ /* explicit try/catch */
+CCM_NINLINE_CALL_REGP, /* Call to <p1> not inlined because it would */
+ /* cause excessive register pressure */
+CCM_NINLINE_RTN_REGP, /* Function <p1> not inlined because it would */
+ /* cause excessive register pressure */
+CCM_NINLINE_CALL_XPENSV, /* Call to <p1> not inlined because analysis */
+ /* exceeds the compilation time limit */
+CCM_NINLINE_READONLYIR, /* Function <p1> not inlined because it is in a file */
+ /* specified as read-only by -xipo_archive=readonly */
+ /* and it contains calls to static functions */
+CCM_NINLINE_CALL_THUNK, /* Call to <p1> not inlined because it is in a */
+ /* compiler-generated function that does not */
+ /* permit inlining */
+CCM_NINLINE_CALL_XTARGETS, /* Indirect callsite has too many targets; */
+ /* callsite marked do not inline */
+CCM_NINLINE_SELFTAIL_RECURSIVE, /* Function <p1> not inlined because */
+ /* of a recursive tail-call to itself */
+CCM_NINLINE_PRAGMA, /* Function <p1> not inlined because it contains */
+ /* explicit parallel or alias pragmas */
+CCM_NINLINE_CMPLX2, /* Function <p1> not inlined because it contains too */
+ /* many operations. Increase max_inst_hard in order */
+ /* to inline it: -xinline_param=max_inst_hard:n */
+CCM_NINLINE_RARE, /* Function <p1> not inlined because the call */
+ /* is rarely executed */
+CCM_NINLINE_PAR2, /* Function <p1> not inlined because it is called */
+ /* within a region guarded by an explicit */
+ /* parallel pragmas */
+CCM_NINLINE_G_LIMIT, /* Function <p1> not inlined because it would exceed */
+ /* the permitted global code size growth limit. Try */
+ /* to increase max_growth in order to inline it: */
+ /* -xinline_param=max_growth:n */
+CCM_NINLINE_L_LIMIT, /* Function <p1> not inlined because it would exceed */
+ /* the maximum function size growth limit. Increase */
+ /* max_function_inst in order to inline it: */
+ /* -xinline_param=max_function_inst:n */
+CCM_NINLINE_REC2, /* Recursive function <p1> is inlined only up to */
+ /* <i2> levels and up to <i3> size. Increase */
+ /* max_recursive_deptha or max_recursive_inst in */
+ /* order to inline it: */
+ /* -xinline_param=max_recursive_depth:n, */
+ /* -xinline_param=max_recursive_inst:n */
+CCM_NINLINE_FB2, /* Function <p1> not inlined because the */
+ /* profile-feedback execution count is too */
+ /* low. Decrease min_counter in order to inline it: */
+ /* -xinline_param:min_counter:n */
+CCM_NINLINE_CS_CMPLX, /* Function <p1> not inlined because called */
+ /* function's size is too big. Increase */
+ /* max_inst_soft in order to inline it: */
+ /* -xinline_param=max_inst_soft:n */
+CCM_NINLINE_R_EXCPT, /* Function <p1> not inlined because it contains */
+ /* an exception handler */
+CCM_NINLINE_ASM, /* Function <p1> not inlined because */
+ /* it contains asm statements */
+CCM_NINLINE_R_READONLYIR, /* Function <p1> not inlined because it is in a file */
+ /* specified as read-only by -xipo_archive=readonly */
+ /* and it is a static function */
+CCM_NINLINE_C_READONLYIR, /* Call to <p1> not inlined because the calling */
+ /* function is in a file specified as read-only */
+ /* by -xipo_archive=readonly */
+CCM_NINLINE_NEVERRETURN, /* Function <p1> not inlined because it */
+ /* never returns */
+
+ /* Group: Messages Concerning Memory Operations */
+ /* Notes: */
+ /* a. In all of these, <s1> is a string that is something like */
+ /* "A(i+5*k)" or "structure.field", giving the high-level */
+ /* construct that is being loaded or stored. */
+ /* */
+ /* b. In all of these, <x2> refers to an instruction offset, */
+ /* expressed as a 32-bit signed integer. It is assumed */
+ /* that any prefetches will be within this range of the */
+ /* load/store they are prefetching for. */
+CCM_MPREFETCH=0x08000, /* Prefetch of <s1> inserted */
+ /* [This message has a lineno for the source, */
+ /* but no instaddr for the disassembly.] */
+CCM_MPREFETCH_LD, /* Prefetch of <s1> inserted for load at <x2> */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MPREFETCH_ST, /* Prefetch of <s1> inserted for store at <x2> */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MPREFETCH_FB, /* Prefetch of <s1> inserted based on feedback data */
+ /* [This message has a lineno for the source, */
+ /* but no instaddr for the disassembly.] */
+CCM_MPREFETCH_FB_LD, /* Prefetch of <s1> inserted for load at <x2> based */
+ /* on feedback data */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MPREFETCH_FB_ST, /* Prefetch of <s1> inserted for store at <x2> based */
+ /* on feedback data */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MLOAD, /* Load below refers to <s1> */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MSTORE, /* Store below refers to <s1> */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MLOAD_P, /* Load below refers to <s1>, and was prefetched */
+ /* at <x2> */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+CCM_MSTORE_P, /* Store below refers to <s1>, and was prefetched */
+ /* at <x2> */
+ /* [This message has lineno = -1, */
+ /* and is for disassembly only] */
+
+ /* Group: Front-end messages [all compilers] */
+ /* Group: F95 Front-end Messages */
+CCM_COPYIN=0x10000, /* Parameter <i1> caused a copyin in the following */
+ /* call */
+CCM_COPYOUT, /* Parameter <i1> caused a copyout in the following */
+ /* call */
+CCM_COPYINOUT, /* Parameter <i1> caused both a copyin and copyout */
+ /* in the following call */
+CCM_PADDING, /* Padding of <i1> bytes inserted before */
+ /* array <v2> */
+CCM_PADCOMMON, /* Padding of <i1> bytes inserted before */
+ /* array <v2> in common block <v3> */
+CCM_ALIGN_EQ, /* Variable/array <v1> can not be double-aligned, */
+ /* because it is equivalenced */
+CCM_ALIGN_PERF, /* Alignment of variables in common block may cause */
+ /* performance degradation */
+CCM_ALIGN_STRUCT, /* Alignment of component <s1> in numeric sequence */
+ /* structure <s2> may cause performance degradation */
+CCM_TMP_COPY, /* Argument <v1> copied to a temporary */
+CCM_TMP_COPYM, /* Argument <v1> might be copied to a temporary; */
+ /* runtime decision made */
+CCM_PROC_MISMATCH, /* Argument <i1> to subprogram <p2> differs from */
+ /* reference on line <i3> */
+CCM_PROC_MISMATCH2, /* Scalar argument <i1> to subprogram <p2> is */
+ /* referred to as an array on line <i3> */
+CCM_PROC_MISMATCH3, /* Return type/rank from subprogram <p1> differs */
+ /* from return on line <i2> */
+CCM_DO_EXPR, /* DO statement bounds lead to no executions of the */
+ /* loop */
+CCM_AUTO_BND, /* The bounds for automatic variable <v1> are not */
+ /* available at all entry points; zero-length */
+ /* variable might be allocated */
+CCM_LIT_PAD, /* The character string literal <s1> padded */
+ /* to the length specified for the dummy argument */
+CCM_ARRAY_LOOP, /* Array statement below generated a loop */
+CCM_ARRAY_LOOPNEST, /* Array statement below generated <i1> nested loops */
+CCM_ALIGN_PERF2, /* Alignment of variable <v1> in common block <v2> */
+ /* may cause a performance degradation */
+CCM_ALIGN_PERF3, /* Alignment of variable <v1> in blank common may */
+ /* cause a performance degradation */
+CCM_IO_LOOP_ARRAY, /* I/O implied do item below generated an array */
+ /* section */
+
+ /* Group: C++ Front-end Messages */
+CCM_TMPCONST, /* Implicit invocation of class <s1> constructor for */
+ /* temporary */
+CCM_TMPDEST, /* Implicit invocation of class <s1> destructor for */
+ /* temporary */
+CCM_DBL_CONST, /* Double constant <s1> used in float expression */
+CCM_MINLINE, /* Function <p1> inlined from source file <s2> by */
+ /* front-end */
+ /* [This refers to front-end inlining, */
+ /* not the backend inlining above.] */
+CCM_MINLINE2, /* Function <p1> from source file <s2> inlined into */
+ /* inline copy of method <p3> by front-end */
+ /* [This refers to front-end inlining, */
+ /* not the backend inlining above.] */
+CCM_MINLINE3, /* Function <p1> not inlined because it uses keyword */
+ /* <s2> */
+CCM_MINLINE4, /* Function <p1> not inlined because it is too */
+ /* complex */
+CCM_TMP_COPYOUT, /* Argument <v1> copied from a temporary */
+CCM_TMP_COPYOUTM, /* Argument <v1> might be copied from a temporary; */
+ /* runtime decision made */
+CCM_TMP_COPYINOUT, /* Argument <v1> copied in and out of a temporary */
+CCM_TMP_COPYINOUTM, /* Argument <v1> might be copied in and out of */
+ /* a temporary; runtime decision made */
+
+ /* Group: C Front-end Messages */
+ /* Group: NJC Front-end Messages */
+ /* Group: Updated F95 Front-end Messages */
+CCM_ARRAY_LOOP_2, /* Array statement below generated loop <l1> */
+CCM_ARRAY_LOOPNEST_2, /* Array statement below generated <i1> nested */
+ /* loops: <l2>, <l3>, ... */
+ /* [The number of parameters will determine how many */
+ /* names appear, and the formatter will get the */
+ /* commas right.] */
+CCM_IO_LOOP_ARRAY_2, /* I/O implied do item below generated an array */
+ /* section: <l1> */
+CCM_USER_LOOP, /* Source loop below has tag <l1> */
+CCM_FOUND_LOOP, /* Discovered loop below has tag <l1> */
+CCM_MFUNCTION_LOOP, /* Copy in M-function of loop below has tag <l1> */
+
+ /* Group: Code-generator Messages */
+CCM_FSIMPLE=0x20000, /* Transformations for fsimple=<i1> applied */
+CCM_STACK, /* Function <p1> requires <i2> Mbytes of stack */
+ /* storage */
+CCM_TAILRECUR, /* Recursive tail call in <p1> optimized to jump to */
+ /* entry point */
+CCM_TAILCALL, /* Call to function <p1> was tail-call optimized */
+CCM_NI_EXIT_OR_PSEUDO, /* Template could not be early inlined because it */
+ /* contains the pseudo instruction <s1> */
+CCM_NI_BAD_UNARY_OPC, /* Template could not be early inlined because it */
+ /* contains the instruction opcode <s1> */
+CCM_NI_INT_LDD_ON_V9, /* Template could not be early inlined because it */
+ /* contains integer ldd instructions, which are */
+ /* deprecated in the v9 architecture */
+CCM_NI_LATE_INL_OPC, /* Template could not be early inlined because it */
+ /* contains the instruction opcode <s1> */
+CCM_NI_BAD_IMM_OP, /* Template could not be early inlined because the */
+ /* relocation or immediate operand <s1> is not well */
+ /* understood by the optimizer */
+CCM_NI_BAD_STATELEAF, /* Template could not be early inlined because it */
+ /* references the state register <s1> */
+CCM_NI_BAD_ASR_19, /* Template could not be early inlined because */
+ /* %asr19 is not supported in pre v8plus code */
+CCM_NI_BAD_FSR_USE, /* Template could not be early inlined because */
+ /* references to %fsr can only be optimized when the */
+ /* -iaopts flag is used */
+CCM_NI_BAD_REGISTER, /* Template could not be early inlined because it */
+ /* references the register <s1> */
+CCM_NI_NO_RET_VAL, /* Template could not be early inlined because it */
+ /* does not return the value declared */
+CCM_NI_DELAY, /* Template could not be early inlined because it */
+ /* contains a non nop delay slot */
+CCM_NI_SCALL, /* Template could not be early inlined because it */
+ /* calls a function which returns a structure */
+CCM_CASE_POSITION, /* Case block below was placed at position <i1> */
+ /* based on execution frequency */
+CCM_CALL_WITH_CODE, /* Call to <p1> replaced with inline code. <i2> */
+ /* loops created: <l3>, <l4>, ... */
+CCM_NI_BAD_SP_ADDR, /* Template could not be early inlined because it */
+ /* contains a %sp+reg address */
+CCM_NI_BAD_SP_USAGE, /* Template could not be early inlined because it */
+ /* uses/defines the stack pointer in a non-load/store instruction */
+CCM_NI_MIXED_REG_TYPES, /* Template could not be early inlined because it */
+ /* contains register <s1> used as both x-register and register pair */
+CCM_LAST
+} COMPMSG_ID;
+/*
+ * The Message Structure
+ * Each message is a fixed-length structure as follows:
+ */
+typedef struct
+{
+ int64_t instaddr; /* the PC offset, relative to the .o .text section */
+ int32_t lineno; /* the source line to which it refers */
+ COMPMSG_ID msg_type; /* the specific message index */
+ int32_t nparam; /* number of parameters to this message */
+ int32_t param_index; /* the index of the first parameter */
+} compmsg;
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+ /*
+ * Initializes the data structures, converts the source name to a string,
+ * and fills in srcname and version in the header
+ */
+ void compcom_p_open (char *srcname, int32_t version);
+
+ /*
+ * Finds or enters the string s into the string table, and returns the index
+ * of the string
+ */
+ int32_t compcom_p_string (char *s);
+
+ /*
+ * Enter the single message. Any string parameters should have been converted
+ * to int32's by calling compcom_p_string()
+ */
+ void compcom_p_putmsg (int32_t show_bits, int64_t pcoffset, int32_t lineno,
+ COMPMSG_ID m, int32_t nparams);
+
+ /*
+ * Whatever is needed to close the section and write it out to the .o
+ */
+ void compcom_p_finalize ();
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _COMP_COM_H */
diff --git a/gprofng/src/count.cc b/gprofng/src/count.cc
new file mode 100644
index 0000000..6005a49
--- /dev/null
+++ b/gprofng/src/count.cc
@@ -0,0 +1,237 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <i18n.h>
+#include <Elf.h>
+#include <collctrl.h>
+#include <StringBuilder.h>
+#include "collect.h"
+
+/* get_count_data -- format exec of bit to do the real work */
+void
+collect::get_count_data ()
+{
+ char command[8192];
+ char *s;
+ struct stat statbuf;
+
+ // reserve space for original args, plus 30 arguments to bit
+ nargs = origargc + 30;
+ char **narglist = (char **) calloc (nargs, sizeof (char *));
+ arglist = narglist;
+
+ // construct the command for bit
+ snprintf (command, sizeof (command), NTXT ("%s"), run_dir);
+ s = strstr_r (command, NTXT ("/bin"));
+ if (s != NULL)
+ {
+ // build command line for launching it
+ snprintf (s, sizeof (command) - (s - command), NTXT ("/lib/compilers/bit"));
+ if (stat (command, &statbuf) == -1)
+ {
+ // if bit command does not exist there
+ char *first_look = strdup (command);
+ snprintf (command, sizeof (command), NTXT ("%s"), run_dir);
+ s = strstr (command, NTXT ("/bin"));
+ snprintf (s, sizeof (command) - (s - command), NTXT ("/prod/bin/bit"));
+ if (stat (command, &statbuf) == -1)
+ {
+ // if bit command does not exist
+ dbe_write (2, GTXT ("bit is not installed as `%s' or `%s'\nNo experiment is possible\n"), first_look, command);
+ exit (2);
+ }
+ free (first_look);
+ }
+ *arglist++ = strdup (command);
+ }
+ else
+ {
+ dbe_write (2, GTXT ("collect can't find install bin directory\n"));
+ exit (1);
+ }
+
+ // Tell it to collect data
+ *arglist++ = NTXT ("collect");
+
+ // add the flag for real-data vs. static data
+ switch (cc->get_count ())
+ {
+ case -1:
+ *arglist++ = NTXT ("-i");
+ *arglist++ = NTXT ("static");
+ *arglist++ = NTXT ("-M");
+ break;
+ case 1:
+ *arglist++ = NTXT ("-M");
+ *arglist++ = NTXT ("-u");
+ break;
+ default:
+ abort ();
+ }
+
+ // tell bit to produce an experiment
+ *arglist++ = NTXT ("-e");
+
+ // now copy an edited list of collect options to the arglist
+ char **oargv = origargv;
+
+ // skip the "collect"
+ oargv++;
+ int argc = 1;
+ while (argc != targ_index)
+ {
+ char *p = *oargv;
+ switch (p[1])
+ {
+ // pass these arguments along, with parameter
+ case 'o':
+ case 'd':
+ case 'g':
+ case 'A':
+ case 'C':
+ case 'O':
+ case 'N':
+ *arglist++ = *oargv++;
+ *arglist++ = *oargv++;
+ argc = argc + 2;
+ break;
+ case 'I':
+ *arglist++ = *oargv++; // set the -I flag
+ *arglist++ = *oargv; // and the directory name
+ *arglist++ = NTXT ("-d"); // and the -d flag
+ *arglist++ = *oargv++; // to the same directory name
+ argc = argc + 2;
+ break;
+ case 'n':
+ case 'v':
+ // pass these arguments along as is
+ *arglist++ = *oargv++;
+ argc = argc + 1;
+ break;
+ case 'x':
+ // skip one argument
+ oargv++;
+ argc++;
+ break;
+ case 'c':
+ case 'L':
+ case 'y':
+ case 'l':
+ case 'F':
+ case 'j':
+ case 'J':
+ case 'p':
+ case 's':
+ case 'h':
+ case 'S':
+ case 'm':
+ case 'M':
+ case 'H':
+ case 'r':
+ case 'i':
+ // skip two arguments
+ oargv++;
+ oargv++;
+ argc = argc + 2;
+ break;
+ case 'R':
+ case 'Z':
+ default:
+ // these should never get this far
+ dbe_write (2, GTXT ("unexpected argument %s\n"), p);
+ abort ();
+ }
+ }
+
+ // now copy the target and its arguments
+ if (access (prog_name, X_OK) != 0) // not found
+ *arglist++ = *oargv++;
+ else
+ {
+ oargv++;
+ *arglist++ = prog_name;
+ }
+ while (*oargv != NULL)
+ *arglist++ = *oargv++;
+
+ /* now we have the full argument list composed; if verbose, print it */
+ if ((verbose == 1) || (disabled))
+ {
+ /* describe the experiment */
+ char *ccret = cc->show (0);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ }
+ ccret = cc->show_expt ();
+ if (ccret != NULL)
+ {
+ /* write this to stdout */
+ writeStr (1, ccret);
+ free (ccret);
+ }
+ /* print the arguments to bit */
+ arglist = narglist;
+ StringBuilder sb;
+ sb.append (NTXT ("Exec argv[] = "));
+ for (int ret = 0; ret < nargs; ret++)
+ {
+ if (narglist[ret] == NULL)
+ break;
+ if (ret > 0)
+ sb.append (NTXT (" "));
+ sb.append (narglist[ret]);
+ }
+ sb.append (NTXT ("\n\n"));
+ write (2, sb.toString (), sb.length ());
+ }
+
+ /* check for dry run */
+ if (disabled)
+ exit (0);
+
+ /* ensure original outputs restored for target */
+ reset_output ();
+
+ /* now exec the bit to instrument and run the target ... */
+ // (void) execve( *narglist, narglist, origenvp);
+ (void) execvp (*narglist, narglist);
+
+ /* exec failed; no experiment to delete */
+ /* restore output for collector */
+ set_output ();
+ char *em = strerror (errno);
+ if (em == NULL)
+ dbe_write (2, GTXT ("execve of %s failed: errno = %d\n"), narglist[0], errno);
+ else
+ dbe_write (2, GTXT ("execve of %s failed: %s\n"), narglist[0], em);
+ exit (1);
+}
diff --git a/gprofng/src/data_pckts.h b/gprofng/src/data_pckts.h
new file mode 100644
index 0000000..93d0307
--- /dev/null
+++ b/gprofng/src/data_pckts.h
@@ -0,0 +1,595 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DATA_PCKTS_H
+#define _DATA_PCKTS_H
+
+/*
+ * This file contains structure definitions for the binary file formats
+ * used in the experiment. It is implemented as C header file so that
+ * it can be processed by both ANSI-C and C++.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+#if WSIZE(64)
+typedef uint64_t Vaddr_type; /* process address for 64 bit apps */
+typedef uint64_t Size_type; /* size_t for 64 bit apps */
+#else
+typedef uint32_t Vaddr_type; /* process address */
+typedef uint32_t Size_type; /* size_t for 32 bit apps */
+#endif
+
+/* marker to indicate dump of O7 register on stack (support for leaf routines) */
+#define SP_LEAF_CHECK_MARKER ((uint64_t)(-1))
+
+/* marker to indicate truncated stack */
+#define SP_TRUNC_STACK_MARKER ((uint64_t)(-2))
+
+/* marker to indicate failed stack unwind */
+#define SP_FAILED_UNWIND_MARKER ((uint64_t)(-3))
+
+#define PROFILE_BUFFER_CHUNK 16384
+
+typedef enum
+{
+ MASTER_SMPL = 0,
+ PROGRAM_SMPL,
+ PERIOD_SMPL,
+ MANUAL_SMPL
+} Smpl_type;
+
+typedef enum
+{ /* values for "profpckt kind" stored in log.xml */
+ EMPTY_PCKT = 0,
+ PROF_PCKT,
+ SYNC_PCKT,
+ HW_PCKT,
+ XHWC_PCKT,
+ HEAP_PCKT,
+ MPI_PCKT,
+ MHWC_PCKT,
+ OPROF_PCKT,
+ OMP_PCKT,
+ RACE_PCKT,
+ FRAME_PCKT,
+ OMP2_PCKT,
+ DEADLOCK_PCKT,
+ OMP3_PCKT,
+ OMP4_PCKT,
+ OMP5_PCKT,
+ UID_PCKT,
+ FRAME2_PCKT,
+ IOTRACE_PCKT,
+ LAST_PCKT, /* last data packet type */
+ CLOSED_PCKT = 65535 /* -1, this packet closes a block */
+} Pckt_type;
+
+typedef enum
+{
+ EMPTY_INFO = 0,
+ STACK_INFO,
+ JAVA_INFO,
+ OMP_INFO,
+ MPI_INFO,
+ OMP2_INFO,
+ LAST_INFO /* keep this one last */
+} Info_type;
+
+#define COMPRESSED_INFO 0x80000000
+
+#define JAVA_PCKT 0x80
+#define OMPS_PCKT 0x40 /* packet contains OMP state info */
+#define PCKT_TYPE(x) ((x) & 0x1f)
+
+typedef struct CommonHead_packet
+{
+ unsigned int tsize : 16;
+ unsigned int type : 16;
+} CommonHead_packet;
+
+// All collector modules record their packets as extensions of CM_Packet
+typedef struct CM_Packet
+{
+ unsigned int tsize : 16;
+ unsigned int type : 16;
+} CM_Packet;
+
+typedef struct Common_packet
+{
+ unsigned int tsize : 16; /* packet size */
+ unsigned int type : 16;
+ pthread_t lwp_id;
+ pthread_t thr_id;
+ uint32_t cpu_id;
+ hrtime_t tstamp;
+ uint64_t frinfo;
+} Common_packet;
+
+/* Definition of values stored in the experiment PROP_MSTATE field */
+/* They include:
+ * LWP microstates (copied from msacct.h). Also see PrUsage class.
+ * Linux's CPU time
+ * er_kernel time
+ */
+/* Can be used with LMS_STATE_STRINGS (below) */
+#define LMS_USER 0 /* running in user mode */
+#define LMS_SYSTEM 1 /* running in sys call or page fault */
+#define LMS_TRAP 2 /* running in other trap */
+#define LMS_TFAULT 3 /* asleep in user text page fault */
+#define LMS_DFAULT 4 /* asleep in user data page fault */
+#define LMS_KFAULT 5 /* asleep in kernel page fault */
+#define LMS_USER_LOCK 6 /* asleep waiting for user-mode lock */
+#define LMS_SLEEP 7 /* asleep for any other reason */
+#define LMS_WAIT_CPU 8 /* waiting for CPU (latency) */
+#define LMS_STOPPED 9 /* stopped (/proc, jobcontrol, or lwp_stop) */
+#define LMS_LINUX_CPU 10 /* LINUX timer_create(CLOCK_THREAD_CPUTIME_ID) */
+#define LMS_KERNEL_CPU 11 /* LINUX timer_create(CLOCK_THREAD_CPUTIME_ID) */
+#define LMS_NUM_STATES 12 /* total number of above states */
+#define LMS_NUM_SOLARIS_MSTATES 10 /* LMS microstates thru LMS_STOPPED */
+
+// Magic value stored in experiments that identifies which LMS states are valid
+#define LMS_MAGIC_ID_SOLARIS 10 // Solaris: LMS_USER thru LMS_STOPPED
+#define LMS_MAGIC_ID_ERKERNEL_USER 2 // er_kernel user: LMS_USER, LMS_SYSTEM
+#define LMS_MAGIC_ID_ERKERNEL_KERNEL 3 // er_kernel kernel: LMS_KERNEL_CPU
+#define LMS_MAGIC_ID_LINUX 1 // Linux: LMS_LINUX_CPU
+
+#define LMS_STATE_STRINGS \
+{ \
+ NTXT("USER"), /* LMS_USER */ \
+ NTXT("SYSTEM"), /* LMS_SYSTEM */ \
+ NTXT("TRAP"), /* LMS_TRAP */ \
+ NTXT("TFAULT"), /* LMS_TFAULT */ \
+ NTXT("DFAULT"), /* LMS_DFAULT */ \
+ NTXT("KFAULT"), /* LMS_KFAULT */ \
+ NTXT("USER_LOCK"), /* LMS_USER_LOCK */ \
+ NTXT("SLEEP"), /* LMS_SLEEP */ \
+ NTXT("WAIT_CPU"), /* LMS_WAIT_CPU */ \
+ NTXT("STOPPED"), /* LMS_STOPPED */ \
+ NTXT("LINUX_CPU"), /* LMS_LINUX_CPU */ \
+ NTXT("KERNEL_CPU") /* LMS_KERNEL_CPU */ \
+}
+#define LMS_STATE_USTRINGS \
+{ \
+ GTXT("User CPU"), /* LMS_USER */ \
+ GTXT("System CPU"), /* LMS_SYSTEM */ \
+ GTXT("Trap CPU"), /* LMS_TRAP */ \
+ GTXT("Text Page Fault"), /* LMS_TFAULT */ \
+ GTXT("Data Page Fault"), /* LMS_DFAULT */ \
+ GTXT("Kernel Page Fault"), /* LMS_KFAULT */ \
+ GTXT("User Lock"), /* LMS_USER_LOCK */ \
+ GTXT("Sleep"), /* LMS_SLEEP */ \
+ GTXT("Wait CPU"), /* LMS_WAIT_CPU */ \
+ GTXT("Stopped"), /* LMS_STOPPED */ \
+ GTXT("User+System CPU"), /* LMS_LINUX_CPU */ \
+ GTXT("Kernel CPU") /* LMS_KERNEL_CPU */ \
+}
+
+typedef enum
+{
+ MALLOC_TRACE = 0,
+ FREE_TRACE,
+ REALLOC_TRACE,
+ MMAP_TRACE,
+ MUNMAP_TRACE,
+ HEAPTYPE_LAST
+} Heap_type;
+
+#define HEAPTYPE_STATE_STRINGS \
+{ \
+ NTXT("MALLOC"), \
+ NTXT("FREE"), \
+ NTXT("REALLOC"), \
+ NTXT("MMAP"), \
+ NTXT("MUNMAP") \
+}
+#define HEAPTYPE_STATE_USTRINGS \
+{ \
+ GTXT("malloc"), \
+ GTXT("free"), \
+ GTXT("realloc"), \
+ GTXT("mmap"), \
+ GTXT("munmap") \
+}
+
+typedef enum
+{
+ ZFS_TYPE = 0,
+ NFS_TYPE,
+ UFS_TYPE,
+ UDFS_TYPE,
+ LOFS_TYPE,
+ VXFS_TYPE,
+ TMPFS_TYPE,
+ PCFS_TYPE,
+ HSFS_TYPE,
+ PROCFS_TYPE,
+ FIFOFS_TYPE,
+ SWAPFS_TYPE,
+ CACHEFS_TYPE,
+ AUTOFS_TYPE,
+ SPECFS_TYPE,
+ SOCKFS_TYPE,
+ FDFS_TYPE,
+ MNTFS_TYPE,
+ NAMEFS_TYPE,
+ OBJFS_TYPE,
+ SHAREFS_TYPE,
+ EXT2FS_TYPE,
+ EXT3FS_TYPE,
+ EXT4FS_TYPE,
+ UNKNOWNFS_TYPE,
+ FSTYPE_LAST
+} FileSystem_type;
+
+typedef enum
+{
+ READ_TRACE = 0,
+ WRITE_TRACE,
+ OPEN_TRACE,
+ CLOSE_TRACE,
+ OTHERIO_TRACE,
+ READ_TRACE_ERROR,
+ WRITE_TRACE_ERROR,
+ OPEN_TRACE_ERROR,
+ CLOSE_TRACE_ERROR,
+ OTHERIO_TRACE_ERROR,
+ IOTRACETYPE_LAST
+} IOTrace_type;
+
+#define IOTRACETYPE_STATE_STRINGS \
+{ \
+ NTXT("READ"), \
+ NTXT("WRITE"), \
+ NTXT("OPEN"), \
+ NTXT("CLOSE"), \
+ NTXT("OTHERIO"), \
+ NTXT("READERROR"), \
+ NTXT("WRITEERROR"), \
+ NTXT("OPENERROR"), \
+ NTXT("CLOSEERROR"), \
+ NTXT("OTHERIOERROR") \
+}
+#define IOTRACETYPE_STATE_USTRINGS \
+{ \
+ GTXT("Read"), \
+ GTXT("Write"), \
+ GTXT("Open"), \
+ GTXT("Close"), \
+ GTXT("Other I/O"), \
+ GTXT("Read error"), \
+ GTXT("Write error"), \
+ GTXT("Open error"), \
+ GTXT("Close error"), \
+ GTXT("Other I/O error") \
+}
+
+// the type of racing memory access with redundance flag
+typedef enum
+{
+ WRITE_RACE = 0,
+ WRITE_RACE_RED,
+ READ_RACE,
+ READ_RACE_RED,
+ RACETYPE_LAST
+} Race_type;
+
+typedef struct Frame_packet
+{
+ unsigned int tsize : 16; /* packet size */
+ unsigned int type : 16;
+ uint32_t hsize; /* header size */
+ uint64_t uid; /* unique id (experiment wide) */
+} Frame_packet;
+
+typedef struct Uid_packet
+{
+ unsigned int tsize : 16; /* packet size */
+ unsigned int type : 16;
+ uint32_t flags;
+ uint64_t uid; /* unique id (experiment wide) */
+} Uid_packet;
+
+/*
+ * Components of the variable part of Frame_packet
+ */
+typedef struct Common_info
+{
+ unsigned int hsize; /* size of this info */
+ unsigned int kind;
+ uint64_t uid; /* unique id of this info if any */
+} Common_info;
+
+typedef struct Stack_info
+{ /* Native call stack */
+ unsigned int hsize;
+ unsigned int kind;
+ uint64_t uid;
+} Stack_info;
+
+typedef struct Java_info
+{ /* Java call stack */
+ unsigned int hsize;
+ unsigned int kind;
+ uint64_t uid;
+} Java_info;
+
+typedef struct OMP_info
+{ /* OMP thread state */
+ unsigned int hsize;
+ unsigned int kind;
+ uint32_t omp_state;
+ uint32_t pad;
+} OMP_info;
+
+typedef struct OMP2_info
+{ /* OpenMP user call stack */
+ unsigned int hsize;
+ unsigned int kind;
+ uint32_t omp_state;
+ uint32_t pad;
+ uint64_t uid;
+} OMP2_info;
+
+/* OMP thread states as recorded in the experiment */
+/* Definition of values stored in the experiment PROP_OMPSTATE field */
+
+/* Can be used with OMP_THR_STATE_STRINGS (below) */
+typedef enum
+{
+ OMP_NO_STATE = 0, /* Not initialized */
+ OMP_OVHD_STATE, /* Overhead */
+ OMP_WORK_STATE, /* Useful work, excluding reduction, master, single, critical */
+ OMP_IBAR_STATE, /* In an implicit barrier */
+ OMP_EBAR_STATE, /* In an explicit barrier */
+ OMP_IDLE_STATE, /* Slave waiting */
+ OMP_SERL_STATE, /* User OMPead not in any OMP parallel region */
+ OMP_RDUC_STATE, /* Reduction */
+ OMP_LKWT_STATE, /* Waiting for lock */
+ OMP_CTWT_STATE, /* Waiting to enter critical section */
+ OMP_ODWT_STATE, /* Waiting to execute an ordered section */
+ OMP_ATWT_STATE, /* Wait for atomic */
+ OMP_TSKWT_STATE, /* Task wait */
+ OMP_LAST_STATE
+} OMP_THR_STATE;
+#define OMP_THR_STATE_STRINGS \
+{ \
+ NTXT("NO"), /* OMP_NO_STATE */ \
+ NTXT("OVHD"), /* OMP_OVHD_STATE */ \
+ NTXT("WORK"), /* OMP_WORK_STATE */ \
+ NTXT("IBAR"), /* OMP_IBAR_STATE */ \
+ NTXT("EBAR"), /* OMP_EBAR_STATE */ \
+ NTXT("IDLE"), /* OMP_IDLE_STATE */ \
+ NTXT("SERL"), /* OMP_SERL_STATE */ \
+ NTXT("RDUC"), /* OMP_RDUC_STATE */ \
+ NTXT("LKWT"), /* OMP_LKWT_STATE */ \
+ NTXT("CTWT"), /* OMP_CTWT_STATE */ \
+ NTXT("ODWT"), /* OMP_ODWT_STATE */ \
+ NTXT("ATWT"), /* OMP_ATWT_STATE */ \
+ NTXT("TSKWT") /* OMP_TSKWT_STATE */ \
+}
+#define OMP_THR_STATE_USTRINGS \
+{ \
+ GTXT("None"), /* OMP_NO_STATE */ \
+ GTXT("Overhead"), /* OMP_OVHD_STATE */ \
+ GTXT("Work"), /* OMP_WORK_STATE */ \
+ GTXT("Implicit Barrier"), /* OMP_IBAR_STATE */ \
+ GTXT("Explicit Barrier"), /* OMP_EBAR_STATE */ \
+ GTXT("Idle"), /* OMP_IDLE_STATE */ \
+ GTXT("Serial"), /* OMP_SERL_STATE */ \
+ GTXT("Reduction"), /* OMP_RDUC_STATE */ \
+ GTXT("Lock Wait"), /* OMP_LKWT_STATE */ \
+ GTXT("Critical Section Wait"), /* OMP_CTWT_STATE */ \
+ GTXT("Ordered Section Wait"), /* OMP_ODWT_STATE */ \
+ GTXT("Atomic Wait"), /* OMP_ATWT_STATE */ \
+ GTXT("Task Wait") /* OMP_TSKWT_STATE */ \
+}
+
+/* sub-packet for MPI state information */
+typedef struct MPI_info
+{ /* MPI thread state */
+ unsigned int hsize;
+ unsigned int kind;
+ uint32_t mpi_state;
+ uint32_t pad;
+} MPI_info;
+
+/* MPI thread states, as recorded in the experiment */
+typedef enum
+{
+ MPI_NO_STATE = 0, /* Not initialized */
+ MPI_USER, /* Executing user code, not in MPI */
+ MPI_PROG, /* Executing in the MPI library (progressing) */
+ MPI_WAIT /* Waiting in the MPI library */
+} MPI_THR_STATE;
+
+/*
+ * Dyntext file structure
+ */
+typedef enum
+{
+ DT_HEADER = 1,
+ DT_CODE,
+ DT_LTABLE,
+ DT_SRCFILE
+} DT_type;
+
+typedef struct DT_common
+{
+ DT_type type;
+ unsigned int size;
+} DT_common;
+
+typedef struct DT_header
+{
+ DT_type type;
+ unsigned int size;
+ hrtime_t time; /* time of loading */
+ uint64_t vaddr;
+} DT_header;
+
+typedef struct DT_code
+{
+ DT_type type;
+ unsigned int size;
+} DT_code;
+
+typedef struct DT_ltable
+{
+ DT_type type;
+ unsigned int size;
+} DT_ltable;
+
+typedef struct DT_lineno
+{
+ unsigned int offset;
+ unsigned int lineno;
+} DT_lineno;
+
+typedef struct DT_srcfile
+{
+ DT_type type;
+ unsigned int size;
+} DT_srcfile;
+
+/*
+ * Archive file structure
+ */
+#define ARCH_VERSION 0x100 /* version 1.0 */
+
+/* For compatibility with older archives append new types only */
+typedef enum
+{
+ ARCH_SEGMENT_TYPE = 1,
+ ARCH_MSG_TYPE,
+ ARCH_PLT_TYPE,
+ ARCH_MODULE_TYPE,
+ ARCH_FUNCTION_TYPE,
+ ARCH_LDINSTR_TYPE,
+ ARCH_STINSTR_TYPE,
+ ARCH_PREFETCH_TYPE,
+ ARCH_BRTARGET_TYPE,
+ ARCH_JCLASS_TYPE,
+ ARCH_JMETHOD_TYPE,
+ ARCH_JUNLOAD_TYPE,
+ ARCH_INF_TYPE,
+ ARCH_JCLASS_LOCATION_TYPE
+} ARCH_type;
+
+#define ARCH_TYPE(x,y) ((ARCH_##x##_TYPE<<8)|y)
+
+typedef struct
+{
+ unsigned int type : 16;
+ unsigned int size : 16;
+} ARCH_common;
+
+/* The maximum value that fits into ARCH_common.size */
+#define ARCH_MAX_SIZE 0xffff
+
+#define ARCH_SEGMENT ARCH_TYPE(SEGMENT, 0)
+
+typedef struct
+{
+ ARCH_common common;
+ int version;
+ uint32_t inode;
+ uint32_t textsz; /* text segment size */
+ uint32_t platform; /* sparc, intel, etc. */
+} ARCH_segment;
+
+#define ARCH_MSG ARCH_TYPE(MSG, 0)
+
+typedef struct
+{
+ ARCH_common common;
+ uint32_t errcode;
+} ARCH_message;
+
+#define ARCH_INF ARCH_TYPE(INF, 0)
+
+typedef struct
+{
+ ARCH_common common;
+} ARCH_info;
+
+#define ARCH_MODULE ARCH_TYPE(MODULE, 0)
+
+typedef struct
+{
+ ARCH_common common;
+ unsigned int lang_code;
+ unsigned int fragmented;
+} ARCH_module;
+
+#define ARCH_FUNCTION ARCH_TYPE(FUNCTION, 0)
+
+typedef struct
+{
+ ARCH_common common;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t save_addr;
+} ARCH_function;
+
+#define ARCH_LDINSTR ARCH_TYPE(LDINSTR, 0)
+#define ARCH_STINSTR ARCH_TYPE(STINSTR, 0)
+#define ARCH_PREFETCH ARCH_TYPE(PREFETCH, 0)
+#define ARCH_BRTARGET ARCH_TYPE(BRTARGET, 0)
+
+typedef struct
+{
+ ARCH_common common;
+} ARCH_aninfo;
+
+#define ARCH_JCLASS_LOCATION ARCH_TYPE(JCLASS_LOCATION, 3)
+
+typedef struct
+{
+ CM_Packet comm;
+ uint32_t pad;
+ uint64_t class_id;
+} ARCH_jclass_location;
+
+#define ARCH_JCLASS ARCH_TYPE(JCLASS, 3)
+
+typedef struct
+{
+ CM_Packet comm;
+ uint32_t pad;
+ uint64_t class_id;
+ hrtime_t tstamp;
+} ARCH_jclass;
+
+#define ARCH_JMETHOD ARCH_TYPE(JMETHOD, 3)
+
+typedef struct
+{
+ CM_Packet comm;
+ uint32_t pad;
+ uint64_t class_id;
+ uint64_t method_id;
+} ARCH_jmethod;
+
+#endif /* _DATA_PCKTS_H */
diff --git a/gprofng/src/dbe_collctrl.cc b/gprofng/src/dbe_collctrl.cc
new file mode 100644
index 0000000..9219a8e
--- /dev/null
+++ b/gprofng/src/dbe_collctrl.cc
@@ -0,0 +1,28 @@
+/* Copyright (C) 2021 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 "config.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "i18n.h"
+
+#include "collctrl.cc"
diff --git a/gprofng/src/dbe_hwc.h b/gprofng/src/dbe_hwc.h
new file mode 100644
index 0000000..74b6838
--- /dev/null
+++ b/gprofng/src/dbe_hwc.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef dbe_hwc_h
+#define dbe_hwc_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "i18n.h"
+
+#define HWC_TRACELEVEL -1
+#if HWC_TRACELEVEL < 0
+#define TprintfT(x1,...)
+#define Tprintf(x1,...)
+#else
+#define TprintfT(x1,...) if( x1<=HWC_TRACELEVEL ) fprintf(stderr,__VA_ARGS__)
+#define Tprintf(x1,...) if( x1<=HWC_TRACELEVEL ) fprintf(stderr,__VA_ARGS__)
+#endif
+
+#endif
diff --git a/gprofng/src/dbe_hwcdrv.c b/gprofng/src/dbe_hwcdrv.c
new file mode 100644
index 0000000..a471c3e
--- /dev/null
+++ b/gprofng/src/dbe_hwcdrv.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 2021 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 "dbe_hwc.h"
+#include "hwcdrv.c"
diff --git a/gprofng/src/dbe_hwcfuncs.c b/gprofng/src/dbe_hwcfuncs.c
new file mode 100644
index 0000000..66d371a
--- /dev/null
+++ b/gprofng/src/dbe_hwcfuncs.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 2021 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 "dbe_hwc.h"
+#include "hwcfuncs.c"
diff --git a/gprofng/src/dbe_hwctable.c b/gprofng/src/dbe_hwctable.c
new file mode 100644
index 0000000..ce077a1
--- /dev/null
+++ b/gprofng/src/dbe_hwctable.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 2021 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 "dbe_hwc.h"
+#include "hwctable.c"
diff --git a/gprofng/src/dbe_memmgr.c b/gprofng/src/dbe_memmgr.c
new file mode 100644
index 0000000..2c2e2b4
--- /dev/null
+++ b/gprofng/src/dbe_memmgr.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2021 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 <dlfcn.h>
+#include "util.h"
+
+#define CHECK_OUT_OF_MEM(ptr, size) if (ptr == NULL) err_out_of_memory(size)
+
+/* Report Out of Memory error and exit */
+static void
+err_out_of_memory (unsigned nbytes)
+{
+ char *nm = get_prog_name (1);
+ if (nm)
+ fprintf (stderr, GTXT ("%s: Error: Memory capacity exceeded.\n"), nm);
+ else
+ fprintf (stderr, GTXT ("Error: Memory capacity exceeded.\n"));
+ fprintf (stderr, GTXT (" Requested %u bytes.\n"), nbytes);
+ exit (16);
+}
+
+#define CALL_REAL(x) (__real_##x)
+#define NULL_PTR(x) ( __real_##x == NULL )
+
+static void *(*__real_malloc)(size_t) = NULL;
+static void (*__real_free)(void *) = NULL;
+static void *(*__real_realloc)(void *, size_t) = NULL;
+static void *(*__real_calloc)(size_t, size_t) = NULL;
+static char *(*__real_strdup)(const char*) = NULL;
+static volatile int in_init = 0;
+
+static int
+init_heap_intf ()
+{
+ in_init = 1;
+ __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
+ __real_free = (void(*)(void *))dlsym (RTLD_NEXT, "free");
+ __real_realloc = (void*(*)(void *, size_t))dlsym (RTLD_NEXT, "realloc");
+ __real_calloc = (void*(*)(size_t, size_t))dlsym (RTLD_NEXT, "calloc");
+ __real_strdup = (char*(*)(const char*))dlsym (RTLD_NEXT, "strdup");
+ in_init = 0;
+ return 0;
+}
+
+/* --------------------------------------------------------------------------- */
+/* libc's memory management functions substitutions */
+
+/* Allocate memory and make sure we got some */
+void *
+malloc (size_t size)
+{
+ if (NULL_PTR (malloc))
+ init_heap_intf ();
+ void *ptr = CALL_REAL (malloc)(size);
+ CHECK_OUT_OF_MEM (ptr, size);
+ return ptr;
+}
+
+
+/* Implement a workaround for a libdl recursion problem */
+void *
+calloc (size_t nelem, size_t size)
+{
+ if (NULL_PTR (calloc))
+ {
+ /* If a program is linked with libpthread then the following
+ * calling sequence occurs:
+ * init_heap_intf -> dlsym -> calloc -> malloc -> init_heap_intf
+ * We break some performance improvement in libdl by returning
+ * NULL but preserve functionality.
+ */
+ if (in_init)
+ return NULL;
+ init_heap_intf ();
+ }
+ return CALL_REAL (calloc)(nelem, size);
+}
+
+/* Free the storage associated with data */
+void
+free (void *ptr)
+{
+ if (ptr == NULL)
+ return;
+ if (NULL_PTR (free))
+ init_heap_intf ();
+ CALL_REAL (free)(ptr);
+ return;
+}
+
+/* Reallocate buffer */
+void *
+realloc (void *ptr, size_t size)
+{
+ if (NULL_PTR (realloc))
+ init_heap_intf ();
+ ptr = CALL_REAL (realloc)(ptr, size);
+ CHECK_OUT_OF_MEM (ptr, size);
+ return ptr;
+}
diff --git a/gprofng/src/dbe_structs.h b/gprofng/src/dbe_structs.h
new file mode 100644
index 0000000..e6eaed6
--- /dev/null
+++ b/gprofng/src/dbe_structs.h
@@ -0,0 +1,219 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_STRUCTS_H
+#define _DBE_STRUCTS_H
+
+#include "dbe_types.h"
+#include "enums.h"
+
+typedef enum
+{
+ Sp_lang_unknown = 0,
+ Sp_lang_asm = 1,
+ Sp_lang_c = 2,
+ Sp_lang_ansic = 3,
+ Sp_lang_cplusplus = 4,
+ Sp_lang_fortran = 5,
+ Sp_lang_pascal = 6,
+ Sp_lang_fortran90 = 7,
+ Sp_lang_java = 8,
+ Sp_lang_c99 = 9,
+ Sp_lang_gcc = 16,
+ Sp_lang_KAI_KPTS = 32,
+ Sp_lang_KAI_KCC = 33,
+ Sp_lang_KAI_Kcc = 34
+} Sp_lang_code;
+
+struct Value
+{
+ union
+ {
+ short s;
+ int i;
+ float f;
+ double d;
+ timestruc_t t;
+ char *l; // Label
+ unsigned long long ll; // address
+ };
+};
+
+// sync enum changes with both AnMetric.java and AnVariable.java
+enum ValueTag
+{
+ VT_SHORT = 1,
+ VT_INT,
+ VT_LLONG,
+ VT_FLOAT,
+ VT_DOUBLE,
+ VT_HRTIME,
+ VT_LABEL,
+ VT_ADDRESS,
+ VT_OFFSET,
+ VT_ULLONG
+};
+
+// Tagged numeric value
+struct TValue
+{
+ ValueTag tag;
+ bool sign; // The print result will always begin with a sign (+ or -).
+ union
+ {
+ short s;
+ int i;
+ float f;
+ double d;
+ char *l;
+ void *p;
+ long long ll;
+ unsigned long long ull;
+ };
+ double to_double ();
+ int to_int ();
+ char *to_str (char *str, size_t strsz);
+ size_t get_len ();
+ void make_delta (TValue *v1, TValue *v2);
+ void make_ratio (TValue *v1, TValue *v2);
+ int compare (TValue *v);
+};
+
+// XXX MAX_HWCOUNT may need to be managed dynamically, not #defined
+#define MAX_HWCOUNT 64
+
+// Experiment collection parameters
+struct Collection_params
+{
+ int profile_mode; // if clock-profiling is on
+ long long ptimer_usec; // Clock profile timer interval (microseconds)
+ int lms_magic_id; // identifies which LMS_* states are live
+ int sync_mode; // if synctrace is on
+ int sync_threshold; // value of synctrace threshold, in microseconds
+ int sync_scope; // value of synctrace scope: Java and/or native
+
+ int heap_mode; // if heaptrace is on
+ int io_mode; // if iotrace is on
+ int race_mode; // if race-detection is on
+ int race_stack; // setting for stack data collection
+ int deadlock_mode; // if deadlock-detection is on
+ int omp_mode; // if omptrace is on
+
+ int hw_mode; // if hw-counter profiling is on
+ int xhw_mode; // if extended (true-PC) HW counter profiling for any counter
+
+ char *hw_aux_name[MAX_HWCOUNT];
+ char *hw_username[MAX_HWCOUNT];
+ int hw_interval[MAX_HWCOUNT]; // nominal interval for count
+ int hw_tpc[MAX_HWCOUNT]; // non-zero, if aggressive TPC/VA requested
+ int hw_metric_tag[MAX_HWCOUNT]; // tag as used for finding metrics
+ int hw_cpu_ver[MAX_HWCOUNT]; // Chip version number for this metric
+
+ int sample_periodic; // if periodic sampling is on
+ int sample_timer; // Sample timer (sec)
+ int limit; // experiment size limit
+ const char *pause_sig; // Pause/resume signal string
+ const char *sample_sig; // Sampling signal string
+ const char *start_delay; // Data collect start delay string
+ const char *terminate; // Data collection termination time string
+ char *linetrace;
+};
+
+const hrtime_t ZERO_TIME = (hrtime_t) 0;
+const hrtime_t MAX_TIME = (hrtime_t) 0x7fffffffffffffffLL;
+
+#define PCInvlFlag ((int) 0x8LL)
+#define PCLineFlag ((int) 0x4LL)
+#define PCTrgtFlag ((int) 0x2LL)
+#define MAKE_ADDRESS(idx, off) (((unsigned long long)(idx)<<32) | off)
+#define ADDRESS_SEG(x) ((unsigned int)(((x)>>32) & 0xffffffff))
+#define ADDRESS_OFF(x) ((unsigned int)((x) & 0xffffffff))
+
+//
+// Analyzer info
+#define AnalyzerInfoVersion 2
+
+typedef struct
+{
+ uint64_t text_labelref;
+ int32_t entries;
+ uint32_t version;
+} AnalyzerInfoHdr; // => header from .__analyzer_info
+
+typedef struct
+{
+ uint32_t offset; // offset relative to text_labelref
+ uint32_t id; // profiled instruction identifier
+ uint32_t signature; // signature of profiled instruction
+ uint32_t datatype_id; // referenced datatype identifier
+} memop_info_t; // => used for table_type=0,1,2
+
+typedef struct
+{
+ uint32_t offset; // offset relative to text_labelref
+} target_info_t; // => used for table_type=3
+
+typedef struct
+{
+ uint32_t type;
+ uint32_t offset;
+ union
+ {
+ memop_info_t *memop;
+ target_info_t *target;
+ };
+} inst_info_t;
+
+class DataObject;
+
+typedef struct
+{
+ uint32_t datatype_id; // datatype identifier (local)
+ uint32_t memop_refs; // count of referencing memops
+ uint32_t event_data; // count of event data
+ DataObject *dobj; // corresponding dataobject (unique)
+} datatype_t;
+
+typedef struct
+{
+ uint32_t offset; // entry offset in compilation unit
+ uint32_t extent; // sibling offset
+ void *parent; // container symbol
+ void *object; // resolved object
+} symbol_t;
+
+typedef struct
+{
+ char *old_prefix;
+ char *new_prefix;
+} pathmap_t;
+
+typedef struct
+{
+ char *libname;
+ enum LibExpand expand;
+} lo_expand_t;
+
+typedef struct
+{
+ int index1;
+ int index2;
+} int_pair_t;
+#endif /* _DBE_STRUCTS_H */
diff --git a/gprofng/src/dbe_types.h b/gprofng/src/dbe_types.h
new file mode 100644
index 0000000..79fd6c7
--- /dev/null
+++ b/gprofng/src/dbe_types.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _DBE_TYPES_H
+#define _DBE_TYPES_H
+
+#include <stdint.h>
+#include "gp-time.h"
+
+typedef unsigned long long Size; /* object sizes in 64 bit apps */
+typedef unsigned long long Vaddr; /* process address for 64 bit apps */
+
+typedef unsigned long long ull_t;
+typedef long long ll_t;
+typedef unsigned long ul_t;
+
+// Note: these values are stored in archive files; changing them
+// may cause old archives to become incompatible.
+enum Platform_t
+{
+ Unknown = 0,
+ Sparc,
+ Sparcv9,
+ Intel,
+ Sparcv8plus,
+ Java,
+ Amd64,
+ Aarch64
+};
+
+enum WSize_t
+{
+ Wnone,
+ W32,
+ W64
+};
+
+enum VMode
+{
+ VMODE_MACHINE = 0,
+ VMODE_USER,
+ VMODE_EXPERT
+};
+
+#endif /* _DBE_TYPES_H */
diff --git a/gprofng/src/debug.h b/gprofng/src/debug.h
new file mode 100644
index 0000000..9761f2a
--- /dev/null
+++ b/gprofng/src/debug.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PERFAN_DEBUG_H
+#define _PERFAN_DEBUG_H
+
+extern unsigned int mpmt_debug_opt;
+// To set mpmt_debug_opt use:
+// MPMT_DEBUG=4095 ; export MPMT_DEBUG
+#define DEBUG_FLAG (mpmt_debug_opt & 1)
+#define DUMP_ELF_SEC (mpmt_debug_opt & 2)
+#define DUMP_ELF_SYM (mpmt_debug_opt & 4)
+#define DUMP_RELA_SEC (mpmt_debug_opt & 8)
+#define DUMP_ELF_RELOC DUMP_RELA_SEC
+#define DUMP_DWARFLIB (mpmt_debug_opt & 16)
+#define DUMP_DWR_LINE_REGS (mpmt_debug_opt & 32)
+#define DUMP_USER_LABELS (mpmt_debug_opt & 64)
+#define DEBUG_MAPS (mpmt_debug_opt & 128)
+#define DEBUG_DBE_FILE (mpmt_debug_opt & 256)
+#define DEBUG_DATA_WINDOW (mpmt_debug_opt & 512)
+#define DEBUG_STABS (mpmt_debug_opt & 1024)
+#define DEBUG_DATAOBJ (mpmt_debug_opt & 2048)
+#define DEBUG_LOADOBJ (mpmt_debug_opt & 4096)
+#define DEBUG_SAXPARSER (mpmt_debug_opt & 8192)
+#define DUMP_JAVA_CLASS (mpmt_debug_opt & 16384)
+#define DEBUG_COMPARISON (mpmt_debug_opt & 32768)
+#define DEBUG_READ_AR (mpmt_debug_opt & 65536)
+#define DEBUG_ERR_MSG (mpmt_debug_opt & 131072)
+#define DUMP_JCLASS_READER (mpmt_debug_opt & 262144)
+#define DEBUG_DBE (mpmt_debug_opt & 524288)
+#define DEBUG_ARCHIVE (mpmt_debug_opt & 1048576)
+#define DEBUG_IO (mpmt_debug_opt & 2097152)
+#define DUMP_DYN_FILE (mpmt_debug_opt & 4194304)
+#define DUMP_JAR_FILE (mpmt_debug_opt & 8388608)
+#define DUMP_CALL_STACK (mpmt_debug_opt & 16777216)
+#define DEBUG_THREADS (mpmt_debug_opt & 33554432)
+#define DBE_USE_MMAP (mpmt_debug_opt & 67108864)
+
+#ifdef DEBUG
+
+// Turn on assertion checking whenever debugging
+#define ASSERTS 1
+
+// debug macro - provides a clean way of inserting debugging code without
+// having the distracting #ifdef DEBUG ... #else ... #endif directives
+// interspersed throughout the code. It also provides an easy way
+// to turn them off with no loss of efficiency. It is not limited
+// to printf() commands; any code may be inserted. Variables
+// needed only by the debugging code can be declared inside a
+// debug { ... } statement.
+//
+// usage:
+// debug <statement>
+// or, debug { <statements> }
+// If DEBUG is on, map "DEBUG_CODE" to nothing!
+// This results in the <statement> being executed normally
+
+#define DEBUG_CODE
+
+#else
+// If DEBUG is off, map "DEBUG_CODE" to something harmless.
+// The clever hack used here is to use a conditional with a
+// constant condition, which is optimized out by the compiler,
+// so that <statement> is not present in the compiled code!
+
+#define DEBUG_CODE if (0)
+
+#endif /*DEBUG*/
+
+#define Dprintf(x, ...) DEBUG_CODE if(x) fprintf(stderr, __VA_ARGS__)
+
+#endif /* ! _DEBUG_H */
diff --git a/gprofng/src/enums.h b/gprofng/src/enums.h
new file mode 100644
index 0000000..a2c9500
--- /dev/null
+++ b/gprofng/src/enums.h
@@ -0,0 +1,195 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PERFAN_ENUMS_H
+#define _PERFAN_ENUMS_H
+
+#include "comp_com.h"
+
+enum Cmd_status
+{
+ CMD_OK = 0,
+ CMD_BAD,
+ CMD_AMBIGUOUS,
+ CMD_BAD_ARG,
+ CMD_OUTRANGE,
+ CMD_INVALID
+};
+
+enum LibExpand
+{
+ LIBEX_SHOW = 0,
+ LIBEX_HIDE = 1,
+ LIBEX_API = 2
+};
+
+enum SrcVisible
+{
+ SRC_NA = 0,
+ SRC_CODE = 1,
+ SRC_METRIC = 2
+};
+
+enum MetricType
+{ // sync enum changes with Settings.java
+ MET_NORMAL = 0, // functions, lines, pcs; src & disasm (non-compare)
+ MET_CALL, // callers-callees
+ MET_DATA, // dataspace
+ MET_INDX, // index objects
+ MET_CALL_AGR, // call tree
+ MET_COMMON, // Analyzer uses for DSP_DISASM, DSP_SOURCE, ...
+ MET_IO, // IO activity
+ MET_SRCDIS, // src & disasm (non comparison mode)
+ MET_HEAP // Heap leaked list
+};
+
+enum ValueType
+{ // Bitmask (!) sync enum changes with AnMetric.java
+ VAL_NA = 0, // nothing specified (use this enum instead of 0)
+ VAL_TIMEVAL = 1,
+ VAL_VALUE = 2,
+ VAL_PERCENT = 4,
+ VAL_DELTA = 8,
+ VAL_RATIO = 16,
+ VAL_INTERNAL = 32,
+ VAL_HIDE_ALL = 64 // hide all, but allows settings to be remembered
+};
+
+enum CompCom
+{ // no value here can be the same as CCMV_
+ COMP_SRC = CCMV_BASIC + 1,
+ COMP_SRC_METRIC,
+ COMP_NOSRC,
+ COMP_HEX,
+ COMP_NOHEX,
+ COMP_THRESHOLD,
+ COMP_CMPLINE,
+ COMP_FUNCLINE
+};
+
+enum TLStack_align
+{
+ TLSTACK_ALIGN_ROOT = 1,
+ TLSTACK_ALIGN_LEAF
+};
+
+enum Reorder_status
+{
+ REORDER_SUCCESS,
+ REORDER_FAIL,
+ REORDER_ZERO,
+ REORDER_ONE_FUNC,
+ REORDER_FILE_OPEN,
+ REORDER_FILE_WRITE,
+ REORDER_COMP,
+ REORDER_NO_LOAD_OBJ,
+ REORDER_NO_OBJECT,
+ REORDER_INVALID
+};
+
+enum AnUtility_state
+{
+ EXP_SUCCESS = 0,
+ EXP_FAILURE = 1,
+ EXP_INCOMPLETE = 2,
+ EXP_BROKEN = 4,
+ EXP_OBSOLETE = 8
+};
+
+enum Presentation_align_type
+{
+ TEXT_LEFT = 1,
+ TEXT_CENTER = 2,
+ TEXT_RIGHT = 3
+};
+
+enum Message_type
+{
+ ERROR_MSG = 1,
+ WARNING_MSG = 2,
+ PSTAT_MSG = 3,
+ PWARN_MSG = 4
+};
+
+enum Presentation_clock_unit
+{
+ CUNIT_NULL = -1,
+ CUNIT_BYTES = -2,
+ CUNIT_TIME = -3
+};
+
+enum FuncListDisp_type
+{
+ DSP_FUNCTION = 1,
+ DSP_LINE = 2,
+ DSP_PC = 3,
+ DSP_SOURCE = 4,
+ DSP_DISASM = 5,
+ DSP_SELF = 6, // not a tab; ID for Callers-Callees fragment data
+ DSP_CALLER = 7,
+ DSP_CALLEE = 8, // not a tab; ID for Callers-Callees callees data
+ DSP_CALLTREE = 9,
+ DSP_TIMELINE = 10,
+ DSP_STATIS = 11,
+ DSP_EXP = 12,
+ DSP_LEAKLIST = 13,
+ DSP_MEMOBJ = 14, // requires a specific subtype to define a tab
+ DSP_DATAOBJ = 15,
+ DSP_DLAYOUT = 16,
+ DSP_SRC_FILE = 17, // not a tab; Details information (?)
+ DSP_IFREQ = 18,
+ DSP_RACES = 19,
+ DSP_INDXOBJ = 20, // requires a specific subtype to define a tab
+ DSP_DUALSOURCE = 21,
+ DSP_SOURCE_DISASM = 22,
+ DSP_DEADLOCKS = 23,
+ DSP_MPI_TL = 24,
+ DSP_MPI_CHART = 25,
+ //DSP_TIMELINE_CLASSIC_TBR = 26,
+ DSP_SOURCE_V2 = 27, // comparison
+ DSP_DISASM_V2 = 28, // comparison
+ //DSP_THREADS_TL = 29;
+ //DSP_THREADS_CHART = 30;
+ DSP_IOACTIVITY = 31,
+ DSP_OVERVIEW = 32,
+ DSP_IOVFD = 33,
+ DSP_IOCALLSTACK = 34,
+ DSP_MINICALLER = 37,
+ DSP_HEAPCALLSTACK = 39,
+ DSP_CALLFLAME = 40,
+ DSP_SAMPLE = 99
+};
+
+enum CmpMode
+{
+ CMP_DISABLE = 0,
+ CMP_ENABLE = 1,
+ CMP_RATIO = 2,
+ CMP_DELTA = 4
+};
+
+enum PrintMode
+{
+ PM_TEXT = 0,
+ PM_HTML = 1,
+ PM_DELIM_SEP_LIST = 2
+};
+
+#endif // _ENUMS_H
diff --git a/gprofng/src/envsets.cc b/gprofng/src/envsets.cc
new file mode 100644
index 0000000..de06fbf
--- /dev/null
+++ b/gprofng/src/envsets.cc
@@ -0,0 +1,420 @@
+/* Copyright (C) 2021 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 <assert.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "gp-defs.h"
+#include "util.h"
+#include "collctrl.h"
+#include "collect.h"
+#include "StringBuilder.h"
+#include "Settings.h"
+
+#define STDEBUFSIZE 24000
+
+#define LIBGP_COLLECTOR "libgp-collector.so"
+#define GPROFNG_PRELOAD_LIBDIRS "GPROFNG_PRELOAD_LIBDIRS"
+#define SP_COLLECTOR_EXPNAME "SP_COLLECTOR_EXPNAME"
+#define SP_COLLECTOR_FOLLOW_SPEC "SP_COLLECTOR_FOLLOW_SPEC"
+#define SP_COLLECTOR_PARAMS "SP_COLLECTOR_PARAMS"
+#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
+#define SP_COLLECTOR_ORIGIN_COLLECT "SP_COLLECTOR_ORIGIN_COLLECT"
+
+static const char *LD_AUDIT[] = {
+ // "LD_AUDIT", Do not set LD_AUDIT on Linux
+ NULL
+};
+
+static const char *LD_PRELOAD[] = {
+ "LD_PRELOAD",
+ NULL
+};
+
+static const char *SP_PRELOAD[] = {
+ "SP_COLLECTOR_PRELOAD",
+ NULL
+};
+
+static const char *LD_LIBRARY_PATH[] = {
+ "LD_LIBRARY_PATH",
+ NULL,
+};
+
+static int
+add_env (char *ev)
+{
+ int r = putenv (ev);
+ if (r != 0)
+ {
+ dbe_write (2, GTXT ("Can't putenv of %s: run aborted\n"), ev);
+ free (ev);
+ }
+ return r;
+}
+
+int
+collect::putenv_libcollector_ld_audits ()
+{
+ StringBuilder sb;
+ for (unsigned int ii = 0; ii < ARR_SIZE (LD_AUDIT) && LD_AUDIT[ii]; ++ii)
+ {
+ sb.sprintf ("%s=%s", LD_AUDIT[ii], SP_LIBAUDIT_NAME);
+ // Append the current value. Check if already set
+ char *old_val = getenv (LD_AUDIT[ii]);
+ if (old_val != NULL)
+ {
+ while (isspace (*old_val))
+ ++old_val;
+ if (*old_val != (char) 0)
+ {
+ int fromIdx = sb.length ();
+ sb.append (" ");
+ sb.append (old_val);
+ if (sb.indexOf (SP_LIBAUDIT_NAME, fromIdx) >= 0)
+ continue; // Already set. Do nothing.
+ }
+ }
+ if (add_env (sb.toString ()))
+ return 1;
+ }
+ return 0;
+}
+
+int
+collect::putenv_libcollector_ld_preloads ()
+{
+ // for those data types that get extra libs LD_PRELOAD'd, add them
+ if (cc->get_synctrace_mode () != 0)
+ add_ld_preload ("libgp-sync.so");
+ if (cc->get_heaptrace_mode () != 0)
+ add_ld_preload ("libgp-heap.so");
+ if (cc->get_iotrace_mode () != 0)
+ add_ld_preload ("libgp-iotrace.so");
+ add_ld_preload (SP_LIBCOLLECTOR_NAME);
+
+ // --- putenv SP_COLLECTOR_PRELOAD*
+ int ii;
+ for (ii = 0; SP_PRELOAD[ii]; ii++)
+ {
+ // construct the SP_PRELOAD_* environment variables
+ // and put them into the environment
+ if (add_env (dbe_sprintf ("%s=%s", SP_PRELOAD[ii], sp_preload_list[ii])))
+ return 1;
+ }
+ // --- putenv LD_PRELOADS
+ /* purge LD_PRELOAD* of values containing contents of SP_LIBCOLLECTOR_NAME */
+ if (putenv_purged_ld_preloads (SP_LIBCOLLECTOR_NAME))
+ dbe_write (2, GTXT ("Warning: %s is already defined in one or more LD_PRELOAD environment variables\n"),
+ SP_LIBCOLLECTOR_NAME);
+ if (putenv_ld_preloads ())
+ return 1;
+ return 0;
+}
+
+int
+collect::putenv_libcollector_ld_misc ()
+{
+#if 0 // XXX 1 turns on LD_DEBUG
+ putenv (strdup ("LD_DEBUG=audit,bindings,detail"));
+#endif
+ // workaround to have the dynamic linker use absolute names
+ if (add_env (dbe_strdup ("LD_ORIGIN=yes")))
+ return 1;
+
+ // On Linux we have to provide SP_COLLECTOR_LIBRARY_PATH and LD_LIBRARY_PATH
+ // so that -agentlib:gp-collector works
+ // and so that collect -F works with 32/64-bit mix of processes
+
+ // Set GPROFNG_PRELOAD_LIBDIRS
+ char *ev = getenv (GPROFNG_PRELOAD_LIBDIRS);
+ char *libpath_list = NULL;
+ if (ev == NULL && settings->preload_libdirs == NULL)
+ {
+ settings->read_rc (false);
+ ev = settings->preload_libdirs;
+ }
+ ev = dbe_strdup (ev);
+ StringBuilder sb;
+ sb.appendf ("%s=", "SP_COLLECTOR_LIBRARY_PATH");
+ int len = sb.length ();
+ int cnt = 0;
+ for (char *s = ev; s;)
+ {
+ char *s1 = strchr (s, ':');
+ if (s1)
+ *(s1++) = 0;
+ char *fname;
+ if (*s == '/')
+ {
+ fname = dbe_sprintf ("%s/%s", s, LIBGP_COLLECTOR);
+ if (access (fname, R_OK | F_OK) == 0)
+ {
+ if (++cnt != 1)
+ sb.append (':');
+ sb.appendf ("%s", s);
+ }
+ }
+ else
+ {
+ fname = dbe_sprintf ("%s/%s/%s", run_dir, s, LIBGP_COLLECTOR);
+ if (access (fname, R_OK | F_OK) == 0)
+ {
+ if (++cnt != 1)
+ sb.append (':');
+ sb.appendf ("%s/%s", run_dir, s);
+ }
+ }
+ free (fname);
+ s = s1;
+ }
+ free (ev);
+ if (cnt == 0)
+ {
+ dbe_write (2, GTXT ("configuration error: can not find %s. run aborted\n"),
+ LIBGP_COLLECTOR);
+ return 1;
+ }
+ libpath_list = sb.toString ();
+ if (add_env (libpath_list))
+ return 1;
+ libpath_list += len;
+
+ // --- set LD_LIBRARY_PATH using libpath_list
+ char *old = getenv (LD_LIBRARY_PATH[0]);
+ if (old)
+ ev = dbe_sprintf ("%s=%s:%s", LD_LIBRARY_PATH[0], libpath_list, old);
+ else
+ ev = dbe_sprintf ("%s=%s", LD_LIBRARY_PATH[0], libpath_list);
+ if (add_env (ev))
+ return 1;
+ return 0;
+}
+
+void
+collect::add_ld_preload (const char *lib)
+{
+ for (int ii = 0; SP_PRELOAD[ii]; ii++)
+ {
+ char *old_sp = sp_preload_list[ii];
+ if (old_sp == NULL)
+ sp_preload_list[ii] = strdup (lib);
+ else
+ {
+ sp_preload_list[ii] = dbe_sprintf ("%s %s", old_sp, lib);
+ free (old_sp);
+ }
+ }
+}
+
+int
+collect::putenv_memso ()
+{
+ // Set environment variable "MEM_USE_LOG" to 1, to keep it out of stderr
+ if (add_env (dbe_strdup ("MEM_USE_LOG=1")))
+ return 1;
+ // Set environment variable "MEM_ABORT_ON_ERROR", to force a core dump
+ if (add_env (dbe_strdup ("MEM_ABORT_ON_ERROR=1")))
+ return 1;
+ add_ld_preload ("mem.so");
+ return putenv_ld_preloads ();
+}
+
+// set LD_PRELOAD and friends to prepend the given library or libraries
+
+int
+collect::putenv_ld_preloads ()
+{
+ for (int ii = 0; LD_PRELOAD[ii]; ii++)
+ {
+ char *old_val = getenv (LD_PRELOAD[ii]);
+ int sp_num = ii;
+ assert (SP_PRELOAD[sp_num]);
+ char *preload_def;
+ if (old_val)
+ preload_def = dbe_sprintf ("%s=%s %s", LD_PRELOAD[ii], sp_preload_list[sp_num], old_val);
+ else
+ preload_def = dbe_sprintf ("%s=%s", LD_PRELOAD[ii], sp_preload_list[sp_num]);
+ if (add_env (preload_def))
+ return 1;
+ }
+ return 0;
+}
+
+/* copied from linetrace.c */
+/*
+ function: env_strip()
+ Finds str in env; Removes
+ all characters from previous ':' or ' '
+ up to and including any trailing ':' or ' '.
+ params:
+ env: environment variable
+ str: substring to find
+ return: count of instances removed from env
+ */
+int
+collect::env_strip (char *env, const char *str)
+{
+ int removed = 0;
+ char *p, *q;
+ if (env == NULL || str == NULL || *str == 0)
+ return 0;
+ size_t maxlen = strlen (env);
+ size_t len = strlen (str);
+ q = env;
+ while ((p = strstr (q, str)) != NULL)
+ {
+ q = p;
+ p += len;
+ if (*p)
+ {
+ while ((*p) && (*p != ':') && (*p != ' '))
+ p++; /* skip the rest of the name*/
+ while ((*p == ':') || (*p == ' '))
+ p++; /* strip trailing separator */
+ }
+ while (*q != ':' && *q != ' ' && *q != '=' && q != env)
+ q--; /* strip path */
+ if (*p)
+ { /* copy the rest of the string */
+ if (q != env)
+ q++; /* restore leading separator (if any) */
+ size_t n = (maxlen - (q - env));
+ strncpy (q, p, n);
+ }
+ else
+ *q = 0;
+ removed++;
+ }
+ return removed;
+}
+/*
+ function: putenv_purged_ld_preloads()
+ Remove selected preload strings from all LD_PRELOAD* env vars.
+ params:
+ var: executable name (leading characters don't have to match)
+ return: number of instances removed from all PRELOAD vars.
+ */
+int
+collect::putenv_purged_ld_preloads (const char *var)
+{
+ int total_removed = 0;
+ if (!var || *var == 0)
+ return 0;
+ for (int ii = 0; LD_PRELOAD[ii]; ii++)
+ {
+ char *ev = getenv (LD_PRELOAD[ii]);
+ int removed = 0;
+ if (!ev)
+ continue;
+ removed = env_strip (ev, var);
+ if (!removed)
+ continue;
+ if (putenv (ev) != 0)
+ dbe_write (2, GTXT ("Can't putenv of %s\n"), ev);
+ total_removed += removed;
+ }
+ return total_removed;
+}
+/*
+ function: putenv_append()
+ append string to current enviroment variable setting and then do a putenv()
+ params:
+ var: environment variable name
+ val: string to append
+ */
+int
+collect::putenv_append (const char *var, const char *val)
+{
+ char *ev;
+ if (!var || !val)
+ return 1;
+ const char *old_val = getenv (var);
+ if (old_val == NULL || *old_val == 0)
+ ev = dbe_sprintf ("%s=%s", var, val);
+ else
+ ev = dbe_sprintf ("%s=%s %s", var, old_val, val);
+
+ // now put the new variable into the environment
+ if (add_env (ev))
+ return 1;
+ return 0;
+}
+
+int
+collect::putenv_libcollector (void)
+{
+ char buf[MAXPATHLEN + 1];
+ // --- set SP_COLLECTOR_EXPNAME
+ // fetch the experiment name and CWD
+ char *exp = cc->get_experiment ();
+ char *cwd = getcwd (buf, MAXPATHLEN);
+ char *ev;
+
+ // format the environment variable for the experiment directory name
+ if (cwd != NULL && exp[0] != '/') // experiment is a relative path
+ ev = dbe_sprintf ("%s=%s/%s", SP_COLLECTOR_EXPNAME, cwd, exp);
+ else // getcwd failed or experiment is a fullpath
+ ev = dbe_sprintf ("%s=%s", SP_COLLECTOR_EXPNAME, exp);
+
+ // set the experiment directory name
+ if (add_env (ev))
+ return 1;
+
+ // --- set SP_COLLECTOR_PARAMS
+ // set the data descriptor
+ exp = cc->get_data_desc ();
+ if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_PARAMS, exp)))
+ return 1;
+
+ // --- set SP_COLLECTOR_FOLLOW_SPEC
+ const char *follow_spec = cc->get_follow_cmp_spec ();
+ if (follow_spec)
+ // selective following has been enabled
+ if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_FOLLOW_SPEC, follow_spec)))
+ return 1;
+
+ if (add_env (dbe_sprintf ("%s=%d", SP_COLLECTOR_FOUNDER, getpid ())))
+ return 1;
+ if (add_env (dbe_sprintf ("%s=1", SP_COLLECTOR_ORIGIN_COLLECT)))
+ return 1;
+
+ // --- set LD_*
+ if (putenv_libcollector_ld_misc ())
+ return 1;
+
+ // --- set LD_PRELOAD*
+ if (putenv_libcollector_ld_preloads () != 0)
+ return 1;
+
+ // --- set JAVA_TOOL_OPTIONS
+ if (cc->get_java_mode () == 1)
+ if (putenv_append ("JAVA_TOOL_OPTIONS", "-agentlib:gp-collector"))
+ exit (1);
+#if 0
+ // --- set LD_AUDIT*
+ if (putenv_libcollector_ld_audits () != 0)
+ return 1;
+#endif
+ return 0;
+}
diff --git a/gprofng/src/gethrtime.c b/gprofng/src/gethrtime.c
new file mode 100644
index 0000000..8ba7295
--- /dev/null
+++ b/gprofng/src/gethrtime.c
@@ -0,0 +1,166 @@
+/* Copyright (C) 2021 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 <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+/* =============================================================== */
+/*
+ * Below this are the get_clock_rate() and get_ncpus() for all architectures
+ */
+
+static int clock_rate = 0;
+static int ncpus = 0;
+static char msgbuf[1024];
+
+int
+get_clock_rate (void)
+{
+ /* Linux version -- read /proc/cpuinfo
+ * Note the parsing is different on intel-Linux and sparc-Linux
+ */
+ FILE *fp = fopen ("/proc/cpuinfo", "r");
+ if (fp != NULL)
+ {
+
+ char temp[1024];
+ while (fgets (temp, sizeof (temp), fp) != NULL)
+ {
+#if ARCH(SPARC)
+ /* cpu count for SPARC linux -- read from /proc/cpuinfo */
+ if (strncmp (temp, "ncpus active", 12) == 0)
+ {
+ char *val = strchr (temp, ':');
+ ncpus = val ? atol (val + 1) : 0;
+ }
+#endif /* ARCH(SPARC) */
+
+ if (clock_rate == 0)
+ {
+ /* pick the first line that gives a CPU clock rate */
+#if ARCH(SPARC)
+ long long clk;
+ if (strncmp (temp, "Cpu0ClkTck", 10) == 0)
+ {
+ char *val = strchr (temp, ':');
+ clk = val ? strtoll (val + 1, NULL, 16) : 0;
+ clock_rate = (int) (clk / 1000000);
+ }
+#else
+ if (strncmp (temp, "cpu MHz", 7) == 0)
+ {
+ char *val = strchr (temp, ':');
+ clock_rate = val ? atoi (val + 1) : 0;
+ }
+#endif /* ARCH() */
+ }
+
+ /* did we get a clock rate? */
+ if (clock_rate != 0)
+ {
+#if ARCH(SPARC)
+ /* since we got a cpu count, we can break from the look */
+ break;
+#endif /* ARCH(SPARC) */
+ }
+#if ARCH(Intel)
+ /* On intel-Linux, count cpus based on "cpu MHz" lines */
+ if (strncmp (temp, "cpu MHz", 7) == 0)
+ ncpus++;
+#endif /* ARCH(Intel) */
+ }
+ fclose (fp);
+ }
+
+ if (clock_rate != 0)
+ sprintf (msgbuf,
+ "Clock rate = %d MHz (from reading /proc/cpuinfo) %d CPUs\n",
+ clock_rate, ncpus);
+
+ /* did we get a clock rate? */
+ if (clock_rate == 0)
+ {
+ clock_rate = 1000;
+ sprintf (msgbuf, "Clock rate = %d MHz (set by default) %d CPUs\n",
+ clock_rate, ncpus);
+ }
+ return clock_rate;
+}
+
+int
+get_ncpus (void)
+{
+ if (clock_rate == 0)
+ get_clock_rate ();
+ return ncpus;
+}
+
+/* gethrvtime -- generic solution, getting user time from
+ * clock_gettime(CLOCK_THREAD_CPUTIME_ID,..), and reformatting.
+ * need -lrt to compile.*/
+hrtime_t
+gethrvtime ()
+{
+ struct timespec tp;
+ hrtime_t rc = 0;
+ int r = clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tp);
+ if (r == 0)
+ rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec;
+ return rc;
+}
+
+/*
+ * CLOCK_MONOTONIC
+ * Clock that cannot be set and represents monotonic time since some
+ * unspecified starting point.
+ */
+hrtime_t
+gethrtime (void)
+{
+ struct timespec tp;
+ hrtime_t rc = 0;
+
+ /*
+ * For er_kernel on Linux, we want to match how DTrace gets its timestamps.
+ * This is CLOCK_MONOTONIC_RAW. It might be changing to CLOCK_MONOTONIC.
+ * For now, we change to "RAW" and can change back if DTrace changes.
+ *
+ * The two can be different. Check the clock_gettime() man page.
+ * CLOCK_MONOTONIC_RAW is Linux-specific and introduced in 2.6.28.
+ * It is impervious to NTP or adjtime adjustments.
+ *
+ * We must match the timer used in perfan/libcollector/src/gethrtime.c.
+ *
+ * There is no issue on Solaris, where gethrtime() is provided by the kernel
+ * and used by DTrace.
+ */
+ int r = clock_gettime (CLOCK_MONOTONIC_RAW, &tp);
+ if (r == 0)
+ rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec;
+ return rc;
+}
diff --git a/gprofng/src/gp-archive.cc b/gprofng/src/gp-archive.cc
new file mode 100644
index 0000000..8d3fc23
--- /dev/null
+++ b/gprofng/src/gp-archive.cc
@@ -0,0 +1,700 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "util.h"
+#include "StringMap.h"
+#include "LoadObject.h"
+#include "DbeSession.h"
+#include "DbeFile.h"
+#include "SourceFile.h"
+#include "Elf.h"
+#include "gp-archive.h"
+#include "ArchiveExp.h"
+#include "Print.h"
+#include "Module.h"
+
+er_archive::er_archive (int argc, char *argv[]) : DbeApplication (argc, argv)
+{
+ force = 0;
+ common_archive_dir = NULL;
+ quiet = 0;
+ descendant = 1;
+ use_relative_path = 0;
+ s_option = ARCH_EXE_ONLY;
+ mask = NULL;
+}
+
+er_archive::~er_archive ()
+{
+ if (mask)
+ {
+ for (long i = 0, sz = mask->size (); i < sz; i++)
+ {
+ regex_t *regex_desc = mask->get (i);
+ regfree (regex_desc);
+ delete regex_desc;
+ }
+ delete mask;
+ }
+ delete common_archive_dir;
+}
+
+int
+er_archive::mask_is_on (const char *str)
+{
+ if (mask == NULL)
+ return 1;
+ for (long i = 0, sz = mask->size (); i < sz; i++)
+ {
+ regex_t *regex_desc = mask->get (i);
+ if (regexec (regex_desc, str, 0, NULL, 0) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+void
+er_archive::usage ()
+{
+/*
+ fprintf (stderr, GTXT ("Usage: %s [-nqFV] [-a on|ldobjects|src|usedldobjects|usedsrc|off] [-m regexp] experiment\n"), whoami);
+*/
+
+/*
+ Ruud - Isolate this line because it has an argument. Otherwise it would be at the
+ end of this long list.
+*/
+ printf ( GTXT (
+ "Usage: gprofng archive [OPTION(S)] EXPERIMENT\n"));
+
+ printf ( GTXT (
+ "\n"
+ "Archive the associated application binaries and source files in a gprofng\n"
+ "experiment to make it self contained and portable.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --version print the version number and exit.\n"
+ " --help print usage information and exit.\n"
+ " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+ "\n"
+ " -a {off|on|ldobjects|src|usedldobjects|usedsrc} specify archiving of binaries and other files;\n"
+ " in addition to disable this feature (off), or enable archiving off all\n"
+ " loadobjects and sources (on), the other options support a more\n"
+ " refined selection. All of these options enable archiving, but the\n"
+ " keyword controls what exactly is selected: all load objects (ldobjects),\n"
+ " all source files (src), the loadobjects asscoiated with a program counter\n"
+ " (usedldobjects), or the source files associated with a program counter\n"
+ " (usedsrc); the default is \"-a ldobjects\".\n"
+ "\n"
+ " -n archive the named experiment only, not any of its descendants.\n"
+ "\n"
+ " -q do not write any warnings to stderr; messages are archived and\n"
+ " can be retrieved later.\n"
+ "\n"
+ " -F force writing or rewriting of the archive; ignored with the -n\n"
+ " or -m options, or if this is a subexperiment.\n"
+ "\n"
+ " -d <path> specifies the location of a common archive; this is a directory that\n"
+ " contains archived files.\n"
+ "\n"
+ " -m <regex> archive only those source, object, and debug info files whose full\n"
+ " path name matches the given POSIX compliant regular expression.\n"
+ "\n"
+ "Limitations:\n"
+ "\n"
+ "Default archiving does not occur in case the application profiled terminates prematurely,\n"
+ "or if archiving is disabled when collecting the performance data. In such cases, this\n"
+ "tool can be used to afterwards archive the information, but it has to run on the same \n"
+ "system where the profiling data was recorded.\n"
+ "\n"
+ "Documentation:\n"
+ "\n"
+ "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+ "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+ "should give you access to this document.\n"
+ "\n"
+ "See also:\n"
+ "\n"
+ "gprofng(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
+// Ruud
+/*
+ fprintf (stderr, GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
+*/
+ exit (1);
+}
+
+Vector <LoadObject*> *
+er_archive::get_loadObjs ()
+{
+ Vector <LoadObject*> *objs = new Vector<LoadObject*>();
+ Vector <LoadObject*> *loadObjs = dbeSession->get_text_segments ();
+ if (s_option != ARCH_NOTHING)
+ {
+ for (long i = 0, sz = VecSize(loadObjs); i < sz; i++)
+ {
+ LoadObject *lo = loadObjs->get (i);
+ if ((lo->flags & SEG_FLAG_DYNAMIC) != 0)
+ continue;
+ DbeFile *df = lo->dbeFile;
+ if (df && ((df->filetype & DbeFile::F_FICTION) != 0))
+ continue;
+ if (!lo->isUsed && ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0))
+ continue;
+ objs->append (lo);
+ }
+ }
+ if (DEBUG_ARCHIVE)
+ {
+ Dprintf (DEBUG_ARCHIVE, NTXT ("get_text_segments(): %d\n"),
+ (int) (loadObjs ? loadObjs->size () : -1));
+ for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+ {
+ LoadObject *lo = loadObjs->get (i);
+ Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d [%2ld] %s\n"),
+ get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ()));
+ }
+ Dprintf (DEBUG_ARCHIVE, NTXT ("\nget_loadObjs(): %d\n"),
+ (int) (objs ? objs->size () : -1));
+ for (long i = 0, sz = VecSize(objs); i < sz; i++)
+ {
+ LoadObject *lo = objs->get (i);
+ Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d [%2ld] %s\n"),
+ get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ()));
+ }
+ }
+ delete loadObjs;
+ return objs;
+}
+
+/**
+ * Clean old archive
+ * Except the following cases:
+ * 1. Founder experiment is an MPI experiment
+ * 2. "-n" option is passed (do not archive descendants)
+ * 3. "-m" option is passed (partial archiving)
+ * 4. Experiment name is not the founder experiment (it is a sub-experiment)
+ * @param expname
+ * @param founder_exp
+ * @return 0 - success
+ */
+int
+er_archive::clean_old_archive (char *expname, ArchiveExp *founder_exp)
+{
+ if (0 == descendant)
+ { // do not archive descendants
+ fprintf (stderr, GTXT ("Warning: Option -F is ignored because -n option is specified (do not archive descendants)\n"));
+ return 1;
+ }
+ if (NULL != mask)
+ { // partial archiving
+ fprintf (stderr, GTXT ("Warning: Option -F is ignored because -m option is specified\n"));
+ return 1;
+ }
+ // Check if the experiment is the founder
+ char *s1 = dbe_strdup (expname);
+ char *s2 = dbe_strdup (founder_exp->get_expt_name ());
+ if (!s1 || !s2)
+ {
+ fprintf (stderr, GTXT ("Cannot allocate memory\n"));
+ exit (1);
+ }
+ // remove trailing slashes
+ for (int n = strlen (s1); n > 0; n--)
+ {
+ if ('/' != s1[n - 1])
+ break;
+ s1[n - 1] = 0;
+ }
+ for (int n = strlen (s2); n > 0; n--)
+ {
+ if ('/' != s2[n - 1])
+ break;
+ s2[n - 1] = 0;
+ }
+ if (strcmp (s1, s2) != 0)
+ { // not founder
+ fprintf (stderr, GTXT ("Warning: Option -F is ignored because specified experiment name %s does not match founder experiment name %s\n"), s1, s2);
+ free (s1);
+ free (s2);
+ return 1;
+ }
+ // Remove old "archives"
+ char *arch = founder_exp->get_arch_name ();
+ fprintf (stderr, GTXT ("INFO: removing existing archive: %s\n"), arch);
+ if (dbe_stat (arch, NULL) == 0)
+ {
+ char *cmd = dbe_sprintf ("/bin/rm -rf %s", arch);
+ system (cmd);
+ free (cmd);
+ if (dbe_stat (arch, NULL) != 0)
+ { // create "archives"
+ if (!founder_exp->create_dir (founder_exp->get_arch_name ()))
+ {
+ fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ());
+ exit (1);
+ }
+ }
+ }
+ free (s1);
+ free (s2);
+ return 0;
+} // clean_old_archive_if_necessary
+
+void
+er_archive::start (int argc, char *argv[])
+{
+ int last = argc - 1;
+ if (check_args (argc, argv) != last)
+ usage ();
+ check_env_var ();
+ if (s_option == ARCH_NOTHING)
+ return;
+
+ ArchiveExp *founder_exp = new ArchiveExp (argv[last]);
+ if (founder_exp->get_status () == Experiment::FAILURE)
+ {
+ if (!quiet)
+ fprintf (stderr, GTXT ("er_archive: %s: %s\n"), argv[last],
+ pr_mesgs (founder_exp->fetch_errors (), NTXT (""), NTXT ("")));
+ exit (1);
+ }
+ if (!founder_exp->create_dir (founder_exp->get_arch_name ()))
+ {
+ fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ());
+ exit (1);
+ }
+ if (!common_archive_dir)
+ common_archive_dir = dbe_strdup (getenv ("GPROFNG_ARCHIVE_COMMON_DIR"));
+ if (common_archive_dir)
+ {
+ if (!founder_exp->create_dir (common_archive_dir))
+ if (dbe_stat (common_archive_dir, NULL) != 0)
+ {
+ fprintf (stderr, GTXT ("Unable to create directory for common archive `%s'\n"), common_archive_dir);
+ exit (1);
+ }
+ }
+ // Clean old archives if necessary
+ if (force)
+ clean_old_archive (argv[last], founder_exp);
+ Vector<ArchiveExp*> *exps = new Vector<ArchiveExp*>();
+ exps->append (founder_exp);
+ if (descendant)
+ {
+ Vector<char*> *exp_names = founder_exp->get_descendants_names ();
+ if (exp_names)
+ {
+ for (long i = 0, sz = exp_names->size (); i < sz; i++)
+ {
+ char *exp_path = exp_names->get (i);
+ ArchiveExp *exp = new ArchiveExp (exp_path);
+ if (exp->get_status () == Experiment::FAILURE)
+ {
+ if (!quiet)
+ fprintf (stderr, GTXT ("er_archive: %s: %s\n"), exp_path,
+ pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT ("")));
+ delete exp;
+ continue;
+ }
+ exps->append (exp);
+ }
+ exp_names->destroy ();
+ delete exp_names;
+ }
+ }
+ for (long i = 0, sz = exps->size (); i < sz; i++)
+ {
+ ArchiveExp *exp = exps->get (i);
+ exp->read_data (s_option);
+ }
+
+ Vector <DbeFile*> *copy_files = new Vector<DbeFile*>();
+ Vector <LoadObject*> *loadObjs = get_loadObjs ();
+ for (long i = 0, sz = VecSize(loadObjs); i < sz; i++)
+ {
+ LoadObject *lo = loadObjs->get (i);
+ if (strcmp (lo->get_pathname (), "LinuxKernel") == 0)
+ continue;
+ DbeFile *df = lo->dbeFile;
+ if ((df->filetype & DbeFile::F_FICTION) != 0)
+ continue;
+ if (df->get_location () == NULL)
+ {
+ copy_files->append (df);
+ continue;
+ }
+ if ((df->filetype & DbeFile::F_JAVACLASS) != 0)
+ {
+ if (df->container)
+ { // Found in .jar file
+ copy_files->append (df->container);
+ }
+ copy_files->append (df);
+ if ((s_option & ARCH_EXE_ONLY) != 0)
+ continue;
+ }
+ lo->sync_read_stabs ();
+ Elf *elf = lo->get_elf ();
+ if (elf && (lo->checksum != 0) && (lo->checksum != elf->elf_checksum ()))
+ {
+ if (!quiet)
+ fprintf (stderr, GTXT ("er_archive: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored\n"),
+ df->get_location ());
+ continue;
+ }
+ copy_files->append (df);
+ if (elf)
+ {
+ Elf *f = elf->find_ancillary_files (lo->get_pathname ());
+ if (f)
+ copy_files->append (f->dbeFile);
+ for (long i1 = 0, sz1 = VecSize(elf->ancillary_files); i1 < sz1; i1++)
+ {
+ Elf *ancElf = elf->ancillary_files->get (i1);
+ copy_files->append (ancElf->dbeFile);
+ }
+ }
+ Vector<Module*> *modules = lo->seg_modules;
+ for (long i1 = 0, sz1 = VecSize(modules); i1 < sz1; i1++)
+ {
+ Module *mod = modules->get (i1);
+ if ((mod->flags & MOD_FLAG_UNKNOWN) != 0)
+ continue;
+ else if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0 &&
+ !mod->isUsed)
+ continue;
+ if ((s_option & ARCH_ALL) != 0)
+ mod->read_stabs (false); // Find all Sources
+ if (mod->dot_o_file && mod->dot_o_file->dbeFile)
+ copy_files->append (mod->dot_o_file->dbeFile);
+ }
+ }
+ delete loadObjs;
+
+ int bmask = DbeFile::F_LOADOBJ | DbeFile::F_JAVACLASS | DbeFile::F_JAR_FILE |
+ DbeFile::F_DOT_O | DbeFile::F_DEBUG_FILE;
+ if ((s_option & (ARCH_USED_SRC_ONLY | ARCH_ALL)) != 0)
+ {
+ bmask |= DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE;
+ Vector<SourceFile*> *sources = dbeSession->get_sources ();
+ for (long i = 0, sz = VecSize(sources); i < sz; i++)
+ {
+ SourceFile *src = sources->get (i);
+ if ((src->flags & SOURCE_FLAG_UNKNOWN) != 0)
+ continue;
+ else if ((s_option & ARCH_USED_SRC_ONLY) != 0)
+ {
+ if ((src->dbeFile->filetype & DbeFile::F_JAVA_SOURCE) != 0 &&
+ !src->isUsed)
+ continue;
+ }
+ if (src->dbeFile)
+ copy_files->append (src->dbeFile);
+ }
+ }
+
+ Vector <DbeFile*> *notfound_files = new Vector<DbeFile*>();
+ for (long i = 0, sz = VecSize(copy_files); i < sz; i++)
+ {
+ DbeFile *df = copy_files->get (i);
+ char *fnm = df->get_location ();
+ char *nm = df->get_name ();
+ Dprintf (DEBUG_ARCHIVE,
+ "%s::%d copy_files[%ld] filetype=%4d inArchive=%d '%s' --> '%s'\n",
+ get_basename (__FILE__), (int) __LINE__, i,
+ df->filetype, df->inArchive ? 1 : 0, STR (nm), STR (fnm));
+ Dprintf (DEBUG_ARCHIVE && df->container,
+ " copy_files[%ld]: Found '%s' in '%s'\n",
+ i, STR (nm), STR (df->container->get_name ()));
+ if (fnm == NULL)
+ {
+ if (!quiet)
+ notfound_files->append (df);
+ continue;
+ }
+ else if (df->inArchive)
+ {
+ Dprintf (DEBUG_ARCHIVE,
+ " NOT COPIED: copy_files[%ld]: inArchive=1 '%s'\n",
+ i, STR (nm));
+ continue;
+ }
+ else if ((df->filetype & bmask) == 0)
+ {
+ Dprintf (DEBUG_ARCHIVE,
+ " NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n",
+ i, df->container, df->filetype, bmask, STR (nm));
+ continue;
+ }
+ else if (df->container &&
+ (df->filetype & (DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE)) == 0)
+ {
+ Dprintf (DEBUG_ARCHIVE,
+ " NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n",
+ i, df->container, df->filetype, bmask, STR (nm));
+ continue;
+ }
+ else if (!mask_is_on (df->get_name ()))
+ {
+ Dprintf (DEBUG_ARCHIVE,
+ " NOT COPIED: copy_files[%ld]: mask is off for '%s'\n",
+ i, STR (nm));
+ continue;
+ }
+ char *anm = founder_exp->getNameInArchive (nm, false);
+ if (force)
+ unlink (anm);
+ int res = founder_exp->copy_file (fnm, anm, quiet, common_archive_dir, use_relative_path);
+ if (0 == res) // file successfully archived
+ df->inArchive = 1;
+ delete anm;
+ }
+ delete copy_files;
+
+ if (notfound_files->size () > 0)
+ {
+ for (long i = 0, sz = notfound_files->size (); i < sz; i++)
+ {
+ DbeFile *df = notfound_files->get (i);
+ fprintf (stderr, GTXT ("er_archive: Cannot find file: `%s'\n"), df->get_name ());
+ }
+ fprintf (stderr, GTXT ("\n If you know the correct location of the missing file(s)"
+ " you can help %s to find them by manually editing the .gprofng.rc file."
+ " See %s man pages for more details.\n"),
+ whoami, whoami);
+ }
+ delete notfound_files;
+}
+
+int
+er_archive::check_args (int argc, char *argv[])
+{
+ int opt;
+ int rseen = 0;
+ int dseen = 0;
+ // Parsing the command line
+ opterr = 0;
+ optind = 1;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"whoami", required_argument, 0, 'w'},
+ {"outfile", required_argument, 0, 'O'},
+ {NULL, 0, 0, 0}
+ };
+ while (1)
+ {
+ int option_index = 0;
+ opt = getopt_long (argc, argv, NTXT (":VFa:d:qnr:m:"),
+ long_options, &option_index);
+ if (opt == EOF)
+ break;
+ switch (opt)
+ {
+ case 'F':
+ force = 1;
+ break;
+ case 'd': // Common archive directory (absolute path)
+ if (rseen)
+ {
+ fprintf (stderr, GTXT ("Error: invalid combination of options: -r and -d are in conflict.\n"));
+ return -1;
+ }
+ if (dseen)
+ fprintf (stderr, GTXT ("Warning: option -d was specified several times. Last value is used.\n"));
+ free (common_archive_dir);
+ common_archive_dir = strdup (optarg);
+ dseen = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'n':
+ descendant = 0;
+ break;
+ case 'r': // Common archive directory (relative path)
+ if (dseen)
+ {
+ fprintf (stderr, GTXT ("Error: invalid combination of options: -d and -r are in conflict.\n"));
+ return -1;
+ }
+ if (rseen)
+ fprintf (stderr, GTXT ("Warning: option -r was specified several times. Last value is used.\n"));
+ free (common_archive_dir);
+ common_archive_dir = strdup (optarg);
+ use_relative_path = 1;
+ rseen = 1;
+ break;
+ case 'a':
+ if (strcmp (optarg, "off") == 0)
+ s_option = ARCH_NOTHING;
+ else if (strcmp (optarg, "on") == 0 ||
+ strcmp (optarg, "ldobjects") == 0)
+ s_option = ARCH_EXE_ONLY;
+ else if (strcmp (optarg, "usedldobjects") == 0)
+ s_option = ARCH_USED_EXE_ONLY;
+ else if (strcmp (optarg, "usedsrc") == 0)
+ s_option = ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY;
+ else if (strcmp (optarg, "all") == 0 || strcmp (optarg, "src") == 0)
+ s_option = ARCH_ALL;
+ else
+ {
+ fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
+ optopt, optarg);
+ return -1;
+ }
+ break;
+ case 'm':
+ {
+ regex_t *regex_desc = new regex_t ();
+ if (regcomp (regex_desc, optarg, REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
+ {
+ delete regex_desc;
+ fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
+ optopt, optarg);
+ return -1;
+ }
+ if (mask == NULL)
+ mask = new Vector<regex_t *>();
+ mask->append (regex_desc);
+ break;
+ }
+ case 'O':
+ {
+ int fd = open (optarg, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd == -1)
+ {
+ fprintf (stderr, GTXT ("er_archive: Can't open %s: %s\n"),
+ optarg, strerror (errno));
+ break;
+ }
+ if (dup2 (fd, 2) == -1)
+ {
+ close (fd);
+ fprintf (stderr, GTXT ("er_archive: Can't divert stderr: %s\n"),
+ strerror (errno));
+ break;
+ }
+ if (dup2 (fd, 1) == -1)
+ {
+ close (fd);
+ fprintf (stderr, GTXT ("er_archive: Can't divert stdout: %s\n"),
+ strerror (errno));
+ break;
+ }
+ close (fd);
+ struct timeval tp;
+ gettimeofday (&tp, NULL);
+ fprintf (stderr, "### Start %s#", ctime (&tp.tv_sec));
+ for (int i = 0; i < argc; i++)
+ fprintf (stderr, " %s", argv[i]);
+ fprintf (stderr, "\n");
+ break;
+ }
+ case 'V':
+// Ruud
+ Application::print_version_info ();
+/*
+ printf (GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
+*/
+ exit (0);
+ case 'w':
+ whoami = optarg;
+ break;
+ case 'h':
+ usage ();
+ exit (0);
+ case ':': // -s -m without operand
+ fprintf (stderr, GTXT ("Option -%c requires an operand\n"), optopt);
+ return -1;
+ case '?':
+ default:
+ fprintf (stderr, GTXT ("Unrecognized option: -%c\n"), optopt);
+ return -1;
+ }
+ }
+ return optind;
+}
+
+void
+er_archive::check_env_var ()
+{
+ char *ename = NTXT ("GPROFNG_ARCHIVE");
+ char *var = getenv (ename);
+ if (var == NULL)
+ return;
+ var = dbe_strdup (var);
+ Vector<char*> *opts = new Vector<char*>();
+ opts->append (ename);
+ for (char *s = var;;)
+ {
+ while (*s && isblank (*s))
+ s++;
+ if (*s == 0)
+ break;
+ opts->append (s);
+ while (*s && !isblank (*s))
+ s++;
+ if (*s == 0)
+ break;
+ *s = 0;
+ s++;
+ }
+ if (opts->size () > 0)
+ {
+ char **arr = (char **) malloc (sizeof (char *) *opts->size ());
+ for (long i = 0; i < opts->size (); i++)
+ arr[i] = opts->get (i);
+ if (-1 == check_args (opts->size (), arr))
+ fprintf (stderr, GTXT ("Error: Wrong SP_ER_ARCHIVE: '%s'\n"), var);
+ free (arr);
+ }
+ delete opts;
+ free (var);
+}
+
+static int
+real_main (int argc, char *argv[])
+{
+ er_archive *archive = new er_archive (argc, argv);
+ dbeSession->archive_mode = 1;
+ archive->start (argc, argv);
+ dbeSession->unlink_tmp_files ();
+ return 0;
+}
+
+/**
+ * Call catch_out_of_memory(int (*real_main)(int, char*[]), int argc, char *argv[]) which will call real_main()
+ * @param argc
+ * @param argv
+ * @return
+ */
+int
+main (int argc, char *argv[])
+{
+ return catch_out_of_memory (real_main, argc, argv);
+}
diff --git a/gprofng/src/gp-archive.h b/gprofng/src/gp-archive.h
new file mode 100644
index 0000000..1d937e0
--- /dev/null
+++ b/gprofng/src/gp-archive.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _GP_ARCHIVE_H_
+#define _GP_ARCHIVE_H_
+
+#include <regex.h>
+#include "DbeApplication.h"
+
+class ArchiveExp;
+class LoadObject;
+template <class ITEM> class Vector;
+
+enum
+{
+ ARCH_NOTHING = 0,
+ ARCH_EXE_ONLY = 1,
+ ARCH_USED_EXE_ONLY = 2,
+ ARCH_USED_SRC_ONLY = 4,
+ ARCH_ALL = 8
+};
+
+class er_archive : public DbeApplication
+{
+public:
+ er_archive (int argc, char *argv[]);
+ ~er_archive ();
+ void start (int argc, char *argv[]);
+
+private:
+ void usage ();
+ int check_args (int argc, char *argv[]);
+ int clean_old_archive (char *expname, ArchiveExp *founder_exp);
+ int mask_is_on (const char *str);
+ void check_env_var ();
+ Vector <LoadObject*> *get_loadObjs ();
+
+ Vector<regex_t *> *mask; // -m <regexp>
+ int s_option; // -s NO|ALL|USED
+ char *common_archive_dir; // -d // absolute path to common archive
+ int force; // -F
+ int quiet; // -q
+ int descendant; // -n
+ int use_relative_path; // -r
+};
+
+#endif \ No newline at end of file
diff --git a/gprofng/src/gp-collect-app.cc b/gprofng/src/gp-collect-app.cc
new file mode 100644
index 0000000..afaae70
--- /dev/null
+++ b/gprofng/src/gp-collect-app.cc
@@ -0,0 +1,1598 @@
+/* Copyright (C) 2021 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 <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+
+#include "gp-defs.h"
+#include "cpu_frequency.h"
+#include "util.h"
+#include "collctrl.h"
+#include "hwcdrv.h"
+#include "gp-experiment.h"
+#include "collect.h"
+#include "StringBuilder.h"
+
+#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
+
+extern char **environ;
+
+static volatile int interrupt = 0;
+static int saved_stdout = -1;
+static int saved_stderr = -1;
+static int no_short_usage = 0;
+static int usage_fd = 2;
+static collect *collect_obj = NULL;
+extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
+static char *outredirect = NULL;
+static int precheck;
+static int nprocesses;
+static Process **processes;
+
+int
+main (int argc, char *argv[])
+{
+ // disable any alarm that might be pending
+ int r = alarm (0);
+ if (r != 0)
+ dbe_write (2, GTXT ("collect has alarm(%d) pending\n"), r);
+ collect_obj = new collect (argc, argv, environ);
+ collect_obj->start (argc, argv);
+ delete collect_obj;
+ return 0;
+}
+
+extern "C" void
+sigint_handler (int, siginfo_t *, void *)
+{
+ interrupt = 1;
+ if (collect_obj->cc != NULL)
+ collect_obj->cc->interrupt ();
+ return;
+}
+
+extern "C" void
+sigalrm_handler (int, siginfo_t *, void *)
+{
+ dbe_write (2, GTXT ("collect: unexpected alarm clock signal received\n"));
+ return;
+}
+
+extern "C" void
+sigterm_handler (int, siginfo_t *, void *)
+{
+ for (int i = 0; i < nprocesses; i++)
+ {
+ Process *proc = processes[i];
+ if (proc != NULL)
+ kill (proc->pid, SIGTERM);
+ }
+}
+
+collect::collect (int argc, char *argv[], char **envp)
+: Application (argc, argv)
+{
+ verbose = 0;
+ disabled = 0;
+ cc = NULL;
+ collect_warnings = NULL;
+ collect_warnings_idx = 0;
+ int ii;
+ for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
+ sp_preload_list[ii] = NULL;
+ for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
+ sp_libpath_list[ii] = NULL;
+ java_path = NULL;
+ java_how = NULL;
+ jseen_global = 0;
+ nlabels = 0;
+ origargc = argc;
+ origargv = argv;
+ origenvp = envp;
+ mem_so_me = false;
+}
+
+collect::~collect ()
+{
+ delete cc;
+}
+
+struct sigaction old_sigint_handler;
+struct sigaction old_sigalrm_handler;
+
+void
+collect::start (int argc, char *argv[])
+{
+ char *ccret;
+ char *extype;
+ /* create a collector control structure, disabling aggressive warning */
+ cc = new Coll_Ctrl (0, false, false);
+ if (prog_name)
+ {
+ char *s = strrchr (prog_name, '/');
+ if (s && (s - prog_name) > 5) // Remove /bin/
+ {
+ s = dbe_sprintf (NTXT ("%.*s"), (int) (s - prog_name - 4), prog_name);
+ cc->set_project_home (s);
+ free (s);
+ }
+ }
+ char * errenable = cc->enable_expt ();
+ if (errenable)
+ {
+ writeStr (2, errenable);
+ free (errenable);
+ }
+
+ /* install a handler for SIGALRM */
+ struct sigaction act;
+ memset (&act, 0, sizeof (struct sigaction));
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = (SignalHandler) sigalrm_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGALRM, &act, &old_sigalrm_handler) == -1)
+ {
+ writeStr (2, GTXT ("Unable to install SIGALRM handler\n"));
+ exit (-1);
+ }
+
+ /* install a handler for SIGINT */
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = (SignalHandler) sigint_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGINT, &act, &old_sigint_handler) == -1)
+ {
+ writeStr (2, GTXT ("Unable to install SIGINT handler\n"));
+ exit (-1);
+ }
+
+ /* install a handler for SIGTERM */
+ sigemptyset (&act.sa_mask);
+ act.sa_sigaction = sigterm_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGTERM, &act, NULL) == -1)
+ {
+ writeStr (2, GTXT ("Unable to install SIGTERM handler\n"));
+ exit (-1);
+ }
+ if (argc > 1 && strncmp (argv[1], NTXT ("--whoami="), 9) == 0)
+ {
+ whoami = argv[1] + 9;
+ argc--;
+ argv++;
+ }
+
+ /* check for no arguments -- usage message */
+ if (argc == 1)
+ {
+ verbose = 1;
+ usage_fd = 1;
+ validate_config (0);
+ usage ();
+ exit (0);
+ }
+ else if (argc == 2 && strcmp (argv[1], NTXT ("-h")) == 0)
+ {
+ /* only one argument, -h */
+ verbose = 1;
+ validate_config (0);
+ /* now print the HWC usage message */
+ show_hwc_usage ();
+ exit (0);
+ }
+ else if (argc == 2 && (strcmp (argv[1], NTXT ("-help")) == 0 ||
+ strcmp (argv[1], NTXT ("--help")) == 0))
+ {
+ /* only one argument, -help or --help */
+ verbose = 1;
+ usage_fd = 1;
+ validate_config (0);
+ usage ();
+ exit (0);
+ }
+// Ruud
+ else if ((argc == 2) &&
+ (strcmp (argv[1], NTXT ("--version")) == 0))
+ {
+ /* only one argument, --version */
+
+ /* print the version info */
+ Application::print_version_info ();
+ exit (0);
+ }
+
+ /* precheck the arguments -- scan for -O, -M flagS */
+ precheck = 1;
+ targ_index = check_args (argc, argv);
+ if (targ_index < 0)
+ {
+ /* message has already been written */
+ usage_fd = 2;
+ short_usage ();
+ exit (1);
+ }
+ /* crack the arguments */
+ precheck = 0;
+ targ_index = check_args (argc, argv);
+ if (targ_index <= 0)
+ {
+ /* message has already been written */
+ usage_fd = 2;
+ short_usage ();
+ exit (1);
+ }
+ if (targ_index != 0)
+ check_target (argc, argv);
+ if (disabled != 0 && cc->get_count () == 0)
+ {
+ // show collection parameters; count data
+ ccret = cc->show (0);
+ writeStr (1, ccret);
+ }
+
+ // see if Java version should be checked
+ if (cc->get_java_default () == 0 && java_path != NULL)
+ validate_java (java_path, java_how, verbose);
+
+ /* if count data is requested, exec bit to do the real work */
+ /* even for a dryrun */
+ if (cc->get_count () != 0)
+ get_count_data ();
+
+ /* if a dry run, just exit */
+ if (disabled != 0)
+ {
+ writeStr (1, cc->show_expt ());
+ StringBuilder sb;
+ sb.append (GTXT ("Exec argv[] = "));
+ for (int i = 0; i < nargs; i++)
+ sb.appendf (NTXT ("%s "), arglist[i]);
+ sb.append (NTXT ("\n"));
+ char *s = sb.toString ();
+ writeStr (1, s);
+ free (s);
+ exit (0);
+ }
+
+ // If the mem_so_me flag is set, preload mem.so
+ // and launch the process
+ if (mem_so_me)
+ {
+ /* set env vars for mem.so */
+ if (putenv_memso () != 0)
+ exit (1); /* message has already been written */
+ /* ensure original outputs restored for target */
+ reset_output ();
+
+ /* now exec the target ... */
+ if (cc->get_debug_mode () == 1)
+ {
+ traceme (arglist[0], arglist);
+ extype = NTXT ("traceme");
+ }
+ else
+ {
+ execvp (arglist[0], arglist);
+ extype = NTXT ("exevcp");
+ }
+ /* oops, exec of the target failed */
+ char *em = strerror (errno);
+ set_output (); /* restore output for collector */
+ if (em == NULL)
+ dbe_write (2, GTXT ("memso %s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
+ else
+ dbe_write (2, GTXT ("memso %s of %s failed: %s\n"), extype, argv[targ_index], em);
+ exit (1);
+ }
+
+ /* normal path, setting up an experiment and launching the target */
+ /* set up the experiment */
+ ccret = cc->setup_experiment ();
+ if (ccret != NULL)
+ {
+ dbe_write (2, NTXT ("%s\n"), ccret);
+ free (ccret);
+ exit (1);
+ }
+ /* Beyond this point, the experiment is created */
+ if (collect_warnings != NULL)
+ {
+ warn_open ();
+ for (int i = 0; i < collect_warnings_idx; i++)
+ warn_comment (SP_JCMD_CWARN, COL_WARN_APP_NOT_READY, collect_warnings[i], (int) strlen (collect_warnings[i]));
+ warn_close ();
+ }
+ /* check cpu frequency variation for intel*/
+ unsigned char mode = COL_CPUFREQ_NONE;
+ int max_freq = get_cpu_frequency (&mode);
+ char freq_scaling[256];
+ char turbo_mode[256];
+ *freq_scaling = 0;
+ *turbo_mode = 0;
+ if (mode & COL_CPUFREQ_SCALING)
+ snprintf (freq_scaling, sizeof (freq_scaling), NTXT (" frequency_scaling=\"enabled\""));
+ if (mode & COL_CPUFREQ_TURBO)
+ snprintf (turbo_mode, sizeof (turbo_mode), NTXT (" turbo_mode=\"enabled\""));
+ if (mode != COL_CPUFREQ_NONE)
+ {
+ warn_open ();
+ if (warn_file != NULL)
+ {
+ warn_write ("<powerm>\n<frequency clk=\"%d\"%s%s/>\n</powerm>\n",
+ max_freq, freq_scaling, turbo_mode);
+ warn_close ();
+ }
+ }
+
+ /* check for labels to write to notes file */
+ if (nlabels != 0)
+ {
+ char *nbuf;
+ char nbuf2[MAXPATHLEN];
+ // fetch the experiment name and CWD
+ char *exp = cc->get_experiment ();
+ char *ev = getcwd (nbuf2, sizeof (nbuf2));
+
+ // format the environment variable for the experiment directory name
+ if (ev != NULL && exp[0] != '/')
+ // cwd succeeded, and experiment is a relative path
+ nbuf = dbe_sprintf (NTXT ("%s/%s/%s"), nbuf2, exp, SP_NOTES_FILE);
+ else
+ // getcwd failed or experiment is a fullpath
+ nbuf = dbe_sprintf (NTXT ("%s/%s"), exp, SP_NOTES_FILE);
+
+ FILE *f = fopen (nbuf, NTXT ("w"));
+ free (nbuf);
+ if (f != NULL)
+ {
+ for (int i = 0; i < nlabels; i++)
+ fprintf (f, NTXT ("%s\n"), label[i]);
+ fclose (f);
+ }
+ }
+ /* check for user interrupt */
+ if (interrupt == 1)
+ {
+ cc->delete_expt ();
+ writeStr (2, GTXT ("User interrupt\n"));
+ exit (0);
+ }
+
+ /* print data-collection parameters */
+ if (verbose)
+ {
+ ccret = cc->show (0);
+ if (ccret != NULL)
+ writeStr (2, ccret);
+ }
+ ccret = cc->show_expt ();
+ if (ccret != NULL)
+ writeStr (1, ccret); /* write this to stdout */
+
+ pid_t pid = (pid_t) cc->get_attach_pid ();
+ if (pid == (pid_t) 0)
+ {
+ /* No attach */
+ /* Set the environment for libcollector */
+ if (putenv_libcollector () != 0)
+ {
+ /* message has already been written */
+ cc->delete_expt ();
+ exit (1);
+ }
+ /* ensure original output fds restored for target */
+ reset_output ();
+
+ /* now exec the target ... */
+ if (cc->get_debug_mode () == 1)
+ {
+ traceme (arglist[0], arglist);
+ extype = NTXT ("traceme");
+ }
+ else
+ {
+ execvp (arglist[0], arglist);
+ extype = NTXT ("execvp");
+ }
+
+ /* we reach this point only if the target launch failed */
+ char *em = strerror (errno);
+
+ /* restore output for collector */
+ set_output ();
+
+ /* exec failed; delete experiment */
+ cc->delete_expt ();
+
+ /* print a message and exit */
+ if (em == NULL)
+ dbe_write (2, GTXT ("%s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
+ else
+ dbe_write (2, GTXT ("%s of %s failed: %s\n"), extype, argv[targ_index], em);
+ exit (1);
+ }
+ else
+ abort ();
+}
+
+/**
+ * Prepare a warning message and pass it to warn_write()
+ * @Parameters:
+ * kind Type of comment
+ * num ID
+ * s Comment sting
+ * len Length of the string
+ * @Return: none.
+ */
+void
+collect::warn_comment (const char *kind, int num, char *s, int len)
+{
+ if (len != 0)
+ warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%.*s</event>\n"),
+ kind, num, len, s);
+ else if (s == NULL)
+ warn_write (NTXT ("<event kind=\"%s\" id=\"%d\"/>\n"), kind, num);
+ else
+ warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%s</event>\n"), kind, num, s);
+}
+
+/**
+ * Open the warnings file in Append mode ("aw")
+ */
+void
+collect::warn_open ()
+{
+ // open the warnings file
+ warnfilename = dbe_sprintf (NTXT ("%s/%s"), cc->get_experiment (), SP_WARN_FILE);
+ int fd = open (warnfilename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ warn_file = fdopen (fd, NTXT ("aw"));
+}
+
+/**
+ * Close the warnings file
+ */
+void
+collect::warn_close ()
+{
+ (void) fclose (warn_file);
+}
+
+/**
+ * Format the warning message and write it to the warnings file
+ */
+void
+collect::warn_write (const char *format, ...)
+{
+ char buf[4096];
+ // format the input arguments into a string
+ va_list va;
+ va_start (va, format);
+ vsnprintf (buf, sizeof (buf), format, va);
+ va_end (va);
+ // write it to the warnings file (warnings.xml)
+ fwrite (buf, 1, strlen (buf), warn_file);
+ fflush (warn_file);
+}
+
+/* process the args, setting expt. params,
+ * and finding offset for a.out name
+ */
+int
+collect::check_args (int argc, char *argv[])
+{
+ int hseen = 0;
+ int hoffseen = 0;
+ int lseen = 0;
+ int tseen = 0;
+ int pseen = 0;
+ int sseen = 0;
+ int yseen = 0;
+ int Fseen = 0;
+ int Aseen = 0;
+ int Sseen = 0;
+ int Hseen = 0;
+ int iseen = 0;
+ int Jseen = 0;
+ int ofseen = 0;
+ char *expName = NULL;
+ bool overwriteExp = false;
+ char *ccret;
+ char *ccwarn;
+ for (targ_index = 1; targ_index < argc; targ_index++)
+ {
+ if (argv[targ_index] == NULL)
+ break;
+ if (dbe_strcmp (argv[targ_index], "--") == 0)
+ {
+ targ_index++;
+ break;
+ }
+ if (argv[targ_index][0] != '-')
+ break;
+ int param;
+ switch (argv[targ_index][1])
+ {
+ case 'y':
+ {
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ char *ptr;
+ int resume = 1;
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (yseen != 0)
+ {
+ dupflagseen ('y');
+ return -1;
+ }
+ yseen++;
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ {
+ writeStr (2, GTXT ("-y requires a signal argument\n"));
+ return -1;
+ }
+ if ((ptr = strrchr (argv[targ_index], ',')) != NULL)
+ {
+ if ((*(ptr + 1) != 'r') || (*(ptr + 2) != 0))
+ {
+ /* not the right trailer */
+ dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
+ return -1;
+ }
+ resume = 0;
+ *ptr = 0;
+ }
+ param = cc->find_sig (argv[targ_index]);
+ if (param < 0)
+ {
+ /* invalid signal */
+ dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
+ return -1;
+ }
+ ccret = cc->set_pauseresume_signal (param, resume);
+ if (ccret != NULL)
+ {
+ /* invalid signal; write message */
+ writeStr (2, ccret);
+ return -1;
+ }
+ break;
+ }
+ case 'l':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (lseen != 0)
+ {
+ dupflagseen ('l');
+ return -1;
+ }
+ lseen++;
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ {
+ writeStr (2, GTXT ("-l requires a signal argument\n"));
+ return -1;
+ }
+ param = cc->find_sig (argv[targ_index]);
+ if (param < 0)
+ {
+ /* invalid signal */
+ dbe_write (2, GTXT ("Invalid sample signal %s\n"), argv[targ_index]);
+ return -1;
+ }
+ ccret = cc->set_sample_signal (param);
+ if (ccret != NULL)
+ {
+ /* invalid signal; write message */
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ break;
+
+#ifdef GPROFNG_DOES_NOT_SUPPORT
+ case 'P':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (Pseen != 0)
+ {
+ dupflagseen ('P');
+ return -1;
+ }
+ Pseen++;
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ {
+ writeStr (2, GTXT ("-P requires a process pid argument\n"));
+ return -1;
+ }
+ ccret = cc->set_attach_pid (argv[targ_index]);
+ if (ccret != NULL)
+ {
+ /* error; write message */
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ break;
+#endif
+ case 't':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (tseen != 0)
+ {
+ dupflagseen ('t');
+ return -1;
+ }
+ tseen++;
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ {
+ writeStr (2, GTXT ("-t requires a run-duration argument\n"));
+ return -1;
+ }
+ ccret = cc->set_time_run (argv[targ_index]);
+ if (ccret != NULL)
+ {
+ /* error; write message */
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ break;
+ case 'p':
+ {
+ char *warnmsg;
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (pseen != 0)
+ {
+ dupflagseen ('p');
+ return -1;
+ }
+ pseen++;
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ {
+ writeStr (2, GTXT ("-p requires a clock-profiling argument\n"));
+ return -1;
+ }
+ ccret = cc->set_clkprof (argv[targ_index], &warnmsg);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ if (warnmsg != NULL)
+ {
+ writeStr (2, warnmsg);
+ free (warnmsg);
+ }
+ break;
+ }
+ case 's':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (sseen != 0)
+ {
+ dupflagseen ('s');
+ return -1;
+ }
+ sseen++;
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ {
+ writeStr (2, GTXT ("-s requires a synchronization-tracing argument\n"));
+ return -1;
+ }
+ ccret = cc->set_synctrace (argv[targ_index]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ break;
+ case 'h':
+ {
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ targ_index++;
+ if ((argv[targ_index] == NULL) || (strlen (argv[targ_index]) == 0))
+ {
+ writeStr (2, GTXT ("-h requires a HW-counter-profiling argument\n"));
+ return -1;
+ }
+ // Check for some special cases
+ char * string = argv[targ_index];
+ if (strcmp (argv[targ_index], NTXT ("off")) == 0)
+ {
+ if (hseen != 0)
+ {
+ no_short_usage = 1;
+ writeStr (2, GTXT ("-h off cannot be used with any other -h arguments\n"));
+ return -1;
+ }
+ hoffseen = 1;
+ hseen = 1;
+ cc->disable_hwc ();
+ break;
+ }
+ // Check to see if we can use HWC
+ unsigned hwc_maxregs = hwc_get_max_concurrent (false);
+ if (hwc_maxregs == 0)
+ {
+ char buf[1024];
+ char *pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0);
+ if (*pch)
+ dbe_write (2, GTXT ("HW counter profiling is not supported on this system: %s%s"),
+ pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
+ else
+ dbe_write (2, GTXT ("HW counter profiling is not supported on this system\n"));
+ no_short_usage = 1;
+ return -1;
+ }
+ // Make sure there's no other -h after -h off
+ if (hoffseen != 0)
+ {
+ no_short_usage = 1;
+ writeStr (2, GTXT ("No -h arguments can be used after -h off\n"));
+ return -1;
+ }
+ // set up to process HW counters (to know about default counters)
+ cc->setup_hwc ();
+ hseen++;
+ char *warnmsg;
+ if (strcmp (argv[targ_index], NTXT ("on")) == 0)
+ ccret = cc->add_default_hwcstring ("on", &warnmsg, true);
+ else if (strcmp (argv[targ_index], NTXT ("hi")) == 0 ||
+ strcmp (argv[targ_index], NTXT ("high")) == 0)
+ ccret = cc->add_default_hwcstring ("hi", &warnmsg, true);
+ else if (strcmp (argv[targ_index], NTXT ("lo")) == 0 ||
+ strcmp (argv[targ_index], NTXT ("low")) == 0)
+ ccret = cc->add_default_hwcstring ("lo", &warnmsg, true);
+ else if (strcmp (argv[targ_index], NTXT ("auto")) == 0)
+ ccret = cc->add_default_hwcstring ("auto", &warnmsg, true);
+ else
+ ccret = cc->add_hwcstring (string, &warnmsg);
+ if (ccret != NULL)
+ {
+ /* set global flag to suppress the short_usage message for any subsequent HWC errors */
+ no_short_usage = 1;
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ if (warnmsg != NULL)
+ {
+ writeStr (2, warnmsg);
+ free (warnmsg);
+ }
+ break;
+ }
+ case 'O':
+ overwriteExp = true;
+ __attribute__ ((fallthrough));
+ case 'o':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s must be followed by a file name\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (expName != NULL)
+ {
+ dbe_write (2, GTXT ("Only one -o or -O argument may be used\n"));
+ dupflagseen ('o');
+ return -1;
+ }
+ expName = argv[targ_index + 1];
+ targ_index++;
+ break;
+ case 'S':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s must be followed by a sample interval name\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (Sseen != 0)
+ {
+ dupflagseen ('S');
+ return -1;
+ }
+ Sseen++;
+ ccret = cc->set_sample_period (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ targ_index++;
+ break;
+ case 'H':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s requires a heap-tracing argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (Hseen != 0)
+ {
+ dupflagseen ('H');
+ return -1;
+ }
+ Hseen++;
+ ccret = cc->set_heaptrace (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ if (cc->get_java_default () == 1)
+ cc->set_java_mode (NTXT ("off"));
+ targ_index++;
+ break;
+ case 'i':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ fprintf (stderr, GTXT ("Argument %s requires an I/O-tracing argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (iseen != 0)
+ {
+ dupflagseen ('i');
+ return -1;
+ }
+ iseen++;
+ ccret = cc->set_iotrace (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ targ_index++;
+ break;
+ case 'j':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s requires a java-profiling argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (jseen_global != 0)
+ {
+ dupflagseen ('j');
+ return -1;
+ }
+ jseen_global++;
+ ccret = cc->set_java_mode (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ targ_index++;
+ break;
+ case 'J':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1) return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s requires a java argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (Jseen != 0)
+ {
+ dupflagseen ('J');
+ return -1;
+ }
+ Jseen++;
+ ccret = cc->set_java_args (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ targ_index++;
+ break;
+ case 'F':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s requires a descendant-following argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (Fseen != 0)
+ {
+ dupflagseen ('F');
+ return -1;
+ }
+ Fseen++;
+ ccret = cc->set_follow_mode (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ targ_index++;
+ break;
+ case 'a':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s requires a load-object archiving argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (Aseen != 0)
+ {
+ dupflagseen ('a');
+ return -1;
+ }
+ Aseen++;
+ ccret = cc->set_archive_mode (argv[targ_index + 1]);
+ if (ccret != NULL)
+ {
+ writeStr (2, ccret);
+ free (ccret);
+ return -1;
+ }
+ targ_index++;
+ break;
+ case 'C':
+ if (precheck == 1)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ if (checkflagterm (argv[targ_index]) == -1)
+ return -1;
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s must be followed by a comment\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (nlabels == MAXLABELS)
+ {
+ dbe_write (2, GTXT ("No more than %d comments may be specified\n"),
+ MAXLABELS);
+ return -1;
+ }
+ label[nlabels] = argv[targ_index + 1];
+ nlabels++;
+ targ_index++;
+ break;
+ case 'n':
+ case 'v':
+ case 'V':
+ if (precheck == 1)
+ break;
+ do_flag (&argv[targ_index][1]);
+ break;
+ case 'Z':
+ // special undocumented argument for debug builds only to allow analyzer to
+ // LD_PRELOAD mem.so for the target it spawns
+ mem_so_me = true;
+ break;
+ case '-':
+ if (strcmp (argv[targ_index], NTXT ("--verbose")) == 0)
+ do_flag ("v");
+ else if (strcmp (argv[targ_index], "--outfile") == 0)
+ {
+ if (precheck == 0)
+ {
+ targ_index++;
+ if (argv[targ_index] == NULL)
+ return 0;
+ break;
+ }
+ // process this argument now
+ if (argv[targ_index + 1] == NULL)
+ {
+ dbe_write (2, GTXT ("Argument %s requires a file argument\n"),
+ argv[targ_index]);
+ return -1;
+ }
+ if (ofseen != 0)
+ {
+ dupflagseen (argv[targ_index]);
+ return -1;
+ }
+ ofseen++;
+ if (outredirect == NULL)
+ {
+ outredirect = argv[targ_index + 1];
+ set_output ();
+ } // else already redirected; ignore with no message
+ targ_index++;
+ }
+ else
+ {
+ dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
+ return -1;
+ }
+ break;
+ default:
+ dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
+ return -1;
+ }
+ }
+ if (targ_index >= argc)
+ return -1;
+ if (argv[targ_index] == NULL)
+ {
+ if (precheck == 1)
+ return 0;
+ if (cc->get_attach_pid () != 0) /* no target is OK, if we're attaching */
+ return 0;
+ writeStr (2, GTXT ("Name of target must be specified\n"));
+ return -1;
+ }
+ if (expName)
+ {
+ ccwarn = NULL;
+ ccret = cc->set_expt (expName, &ccwarn, overwriteExp);
+ if (ccwarn)
+ {
+ writeStr (2, ccwarn);
+ free (ccwarn);
+ }
+ if (ccret)
+ {
+ writeStr (2, ccret);
+ return -1;
+ }
+ }
+ if (cc->get_attach_pid () != 0)
+ {
+ writeStr (2, GTXT ("Name of target must not be specified when -P is used\n"));
+ return -1;
+ }
+ return targ_index;
+}
+
+int
+collect::checkflagterm (const char *c)
+{
+ if (c[2] != 0)
+ {
+ dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), c);
+ return -1;
+ }
+ return 0;
+}
+
+int
+collect::do_flag (const char *flags)
+{
+ char *s;
+ for (int i = 0;; i++)
+ {
+ switch (flags[i])
+ {
+ case 0: // end of string
+ return 0;
+ case 'n':
+ disabled = 1;
+ if (verbose != 1)
+ {
+// Ruud
+ Application::print_version_info ();
+/*
+ dbe_write (2, NTXT ("GNU %s version %s\n"),
+ get_basename (prog_name), VERSION);
+*/
+ verbose = 1;
+ }
+ break;
+ case 'x':
+ s = cc->set_debug_mode (1);
+ if (s)
+ {
+ writeStr (2, s);
+ free (s);
+ }
+ break;
+ case 'v':
+ if (verbose != 1)
+ {
+// Ruud
+ Application::print_version_info ();
+/*
+ dbe_write (2, NTXT ("GNU %s version %s\n"),
+ get_basename (prog_name), VERSION);
+*/
+ verbose = 1;
+ }
+ break;
+ case 'V':
+// Ruud
+ Application::print_version_info ();
+/*
+ dbe_write (2, NTXT ("GNU %s version %s\n"),
+ get_basename (prog_name), VERSION);
+*/
+ /* no further processing.... */
+ exit (0);
+ }
+ }
+}
+
+/*
+ * traceme - cause the caller to stop at the end of the next exec()
+ * so that a debugger can attach to the new program
+ *
+ * Takes same arguments as execvp()
+ */
+int
+collect::traceme (const char *execvp_file, char *const execvp_argv[])
+{
+ int ret = -1;
+ pid_t pid = fork ();
+ if (pid == 0)
+ { // child
+ // child will set up itself to be PTRACE'd, and then exec the target executable
+ /* reset the SP_COLLECTOR_FOUNDER value to the new pid */
+ pid_t mypid = getpid ();
+ char *ev = dbe_sprintf (NTXT ("%s=%d"), SP_COLLECTOR_FOUNDER, mypid);
+ if (putenv (ev) != 0)
+ {
+ dbe_write (2, GTXT ("fork-child: Can't putenv of \"%s\": run aborted\n"), ev);
+ return 1;
+ }
+ ptrace (PTRACE_TRACEME, 0, NULL, NULL); // initiate trace
+ ret = execvp (execvp_file, execvp_argv); // execvp user command
+ return ret; // execvp failed
+ }
+ else if (pid > 0)
+ { // parent
+ int status;
+ if (waitpid (pid, &status, 0) != pid)
+ { // wait for execvp to cause signal
+ writeStr (2, GTXT ("parent waitpid() failed\n"));
+ return -2;
+ }
+ if (!WIFSTOPPED (status))
+ writeStr (2, GTXT ("WIFSTOPPED(status) failed\n"));
+
+ // originally, PTRACE_DETACH would send SIGTSTP, but now we do it here:
+ if (kill (pid, SIGTSTP) != 0)
+ writeStr (2, GTXT ("kill(pid, SIGTSTP) failed\n"));
+ if (ptrace (PTRACE_DETACH, pid, NULL, 0) != 0)
+ { // detach trace
+ writeStr (2, GTXT ("ptrace(PTRACE_DETACH) failed\n"));
+ return -4;
+ }
+ dbe_write (2, GTXT ("Waiting for attach from debugger: pid=%d\n"), (int) pid);
+
+ // wait for an external debugger to attach
+ if (waitpid (pid, &status, 0) != pid)
+ { // keep parent alive until child quits
+ writeStr (2, GTXT ("parent final waitpid() failed\n"));
+ return -5;
+ }
+ }
+ else
+ return -1; // fork failed
+ exit (0);
+}
+
+void
+collect::dupflagseen (char c)
+{
+ dbe_write (2, GTXT ("Only one -%c argument may be used\n"), c);
+}
+
+void
+collect::dupflagseen (const char *s)
+{
+ dbe_write (2, GTXT ("Only one %s argument may be used\n"), s);
+}
+
+int
+collect::set_output ()
+{
+ static int initial = 1;
+ if (outredirect)
+ {
+ int fd = open (outredirect, O_WRONLY | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd == -1)
+ {
+ dbe_write (2, GTXT ("Warning: Can't open collector output `%s': %s\n"),
+ outredirect, strerror (errno));
+ }
+ else
+ {
+ if ((saved_stdout = dup (1)) == -1 || dup2 (fd, 1) == -1)
+ dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
+ NTXT ("stdout"), strerror (errno));
+ if ((saved_stderr = dup (2)) == -1 || dup2 (fd, 2) == -1)
+ dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
+ NTXT ("stderr"), strerror (errno));
+ close (fd);
+ if ((saved_stdout != -1) && (saved_stderr != -1))
+ {
+ if (initial)
+ {
+ struct timeval tp;
+ gettimeofday (&tp, NULL);
+ writeStr (2, ctime (&tp.tv_sec));
+ initial = 0;
+ }
+ return 1; // diversion in place
+ }
+ }
+ }
+ return 0; // no diversion
+}
+
+void
+collect::reset_output ()
+{
+ if (saved_stdout != -1 &&
+ (dup2 (saved_stdout, 1) == -1 || close (saved_stdout)))
+ dbe_write (2, GTXT ("Warning: Can't restore collector stdout: %s\n"),
+ strerror (errno));
+ if (saved_stderr != -1 &&
+ (dup2 (saved_stderr, 2) == -1 || close (saved_stderr)))
+ dbe_write (2, GTXT ("Warning: Can't restore collector stderr: %s\n"),
+ strerror (errno));
+}
+
+void
+collect::usage ()
+{
+
+/*
+ Ruud - Isolate this line because it has an argument. Otherwise it would be at the
+ end of this long list.
+*/
+ printf ( GTXT (
+ "Usage: gprofng collect app [OPTION(S)] TARGET [TARGET_ARGUMENTS]\n")),
+
+/*
+-------------------------------------------------------------------------------
+ For a reason I don't understand, the continuation line(s) need to start at
+ column 26 in order for help2man to do the righ thing. Ruud
+-------------------------------------------------------------------------------
+*/
+ printf ( GTXT (
+ "\n"
+ "Collect performance data on the target program. In addition to Program\n"
+ "Counter PC) sampling, hardware event counters and various tracing options\n"
+ "are supported.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --version print the version number and exit.\n"
+ " --help print usage information and exit.\n"
+ " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+ "\n"
+ " -p {off|on|lo|hi|<value>} disable (off) or enable (on) clock-profiling using a default\n"
+ " sampling granularity, or enable clock-profiling implicitly by\n"
+ " setting the sampling granularity (lo, hi, or a specific value\n"
+ " in ms); by default clock profiling is enabled.\n"
+ "\n"
+ " -h {<ctr_def>...,<ctr_n_def>} enable hardware event counter profiling and select\n"
+ " the counter(s); to see the supported counters on this system use\n"
+ " the -h option without other arguments.\n"
+ "\n"
+ " -o <exp_name> specify the name for (and path to) the experiment directory; the\n"
+ " the default path is the current directory.\n"
+ "\n"
+ " -O <exp_name> the same as -o, but unlike the -o option, silently overwrite an\n"
+ " existing experiment directory with the same name.\n"
+ "\n"
+ " -C <label> add up to 10 comment labels to the experiment; comments appear in\n"
+ " the notes section of the header.\n"
+ "\n"
+ " -j {on|off|<path>} enable (on), or disable (off) Java profiling when the target\n"
+ " program is a JVM; optionally set the <path> to a non-default JVM;\n"
+ " the default is \"-j on\".\n"
+ "\n"
+ " -J <java-args> specify arguments to the JVM.\n"
+ "\n"
+ " -t <duration>[m|s] specify the duration over which to record data; the default unit\n"
+ " is seconds (s), but can be set to minutes (m).\n"
+ "\n"
+ " -n dry run; display several run-time settings, but do not run the\n"
+ " target, or collect performance data.\n"
+ "\n"
+ " -y <signal>[,r] specify delayed initialization and a pause/resume signal; by default\n"
+ " the target starts in paused mode; if the optional r keyword is\n"
+ " provided, start in resumed mode.\n"
+ "\n"
+ " -F {off|on|=<regex>} control to follow descendant processes; disable (off), enable (on),\n"
+ " or collect data on all descendant processes whose name matches the\n"
+ " specified regular expression; the default is \"-F on\".\n"
+ "\n"
+ " -a {off|on|ldobjects|src|usedldobjects|usedsrc} specify archiving of binaries and other files;\n"
+ " in addition to disable this feature (off), or enable archiving off all\n"
+ " loadobjects and sources (on), the other options support a more\n"
+ " refined selection. All of these options enable archiving, but the\n"
+ " keyword controls what exactly is selected: all load objects (ldobjects),\n"
+ " all source files (src), the loadobjects asscoiated with a program counter\n"
+ " (usedldobjects), or the source files associated with a program counter\n"
+ " (usedsrc); the default is \"-a ldobjects\".\n"
+ "\n"
+ " -S {off|on|<seconds>} disable (off) or enable (on) periodic sampling of process-wide resource\n"
+ " utilization; by default sampling occurs every second; use the <seconds>\n"
+ " option to change this; the default is \"-S on\".\n"
+ "\n"
+ " -l <signal> specify a signal that will trigger a sample of process-wide resource utilization.\n"
+ "\n"
+ " -s <option>[,<API>] enable synchronization wait tracing; <option> is used to define the specifics\n"
+ " of the tracing (on, off, <threshold>, or all); <API> is used to select the API:\n"
+ " \"n\" selects native/Pthreads, \"j\" selects Java, and \"nj\" selects both;\n"
+ " the default is \"-s off\".\n"
+ "\n"
+ " -H {off|on} disable (off), or enable (on) heap tracing; the default is \"-H off\".\n"
+ "\n"
+ " -i {off|on} disable (off), or enable (on) I/O tracing; the default is \"-i off\".\n"
+ "\n"
+ "Documentation:\n"
+ "\n"
+ "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+ "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+ "should give you access to this document.\n"
+ "\n"
+ "See also:\n"
+ "\n"
+ "gprofng(1), gp-archive(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
+/*
+ char *s = dbe_sprintf (GTXT ("Usage: %s <args> target <target-args>\n"),
+ whoami);
+ writeStr (usage_fd, s);
+ free (s);
+ writeStr (usage_fd, GTXT (" -p {lo|on|hi|off|<value>}\tspecify clock-profiling\n"));
+ writeStr (usage_fd, GTXT ("\t`lo' per-thread rate of ~10 samples/second\n"));
+ writeStr (usage_fd, GTXT ("\t`on' per-thread rate of ~100 samples/second (default)\n"));
+ writeStr (usage_fd, GTXT ("\t`hi' per-thread rate of ~1000 samples/second\n"));
+ writeStr (usage_fd, GTXT ("\t`off' disable clock profiling\n"));
+ writeStr (usage_fd, GTXT ("\t<value> specify profile timer period in millisec.\n"));
+ s = dbe_sprintf (GTXT ("\t\t\tRange on this system is from %.3f to %.3f millisec.\n\t\t\tResolution is %.3f millisec.\n"),
+ (double) cc->get_clk_min () / 1000.,
+ (double) cc->get_clk_max () / 1000.,
+ (double) cc->get_clk_res () / 1000.);
+ writeStr (usage_fd, s);
+ free (s);
+ writeStr (usage_fd, GTXT (" -h <ctr_def>...[,<ctr_n_def>]\tspecify HW counter profiling\n"));
+ s = dbe_sprintf (GTXT ("\tto see the supported HW counters on this machine, run \"%s -h\" with no other arguments\n"),
+ whoami);
+ writeStr (usage_fd, s);
+ free (s);
+ writeStr (usage_fd, GTXT (" -s <threshold>[,<scope>]\tspecify synchronization wait tracing\n"));
+ writeStr (usage_fd, GTXT ("\t<scope> is \"j\" for tracing Java-APIs, \"n\" for tracing native-APIs, or \"nj\" for tracing both\n"));
+ writeStr (usage_fd, GTXT (" -H {on|off}\tspecify heap tracing\n"));
+ writeStr (usage_fd, GTXT (" -i {on|off}\tspecify I/O tracing\n"));
+ writeStr (usage_fd, GTXT (" -N <lib>\tspecify library to exclude count from instrumentation (requires -c also)\n"));
+ writeStr (usage_fd, GTXT (" \tmultiple -N arguments can be provided\n"));
+ writeStr (usage_fd, GTXT (" -j {on|off|path}\tspecify Java profiling\n"));
+ writeStr (usage_fd, GTXT (" -J <java-args>\tspecify arguments to Java for Java profiling\n"));
+ writeStr (usage_fd, GTXT (" -t <duration>\tspecify time over which to record data\n"));
+ writeStr (usage_fd, GTXT (" -n\tdry run -- don't run target or collect performance data\n"));
+ writeStr (usage_fd, GTXT (" -y <signal>[,r]\tspecify delayed initialization and pause/resume signal\n"));
+ writeStr (usage_fd, GTXT ("\tWhen set, the target starts in paused mode;\n\t if the optional r is provided, it starts in resumed mode\n"));
+ writeStr (usage_fd, GTXT (" -F {on|off|=<regex>}\tspecify following descendant processes\n"));
+ writeStr (usage_fd, GTXT (" -a {on|ldobjects|src|usedldobjects|usedsrc|off}\tspecify archiving of binaries and other files;\n"));
+ writeStr (usage_fd, GTXT (" -S {on|off|<seconds>}\t Set the interval for periodic sampling of process-wide resource utilization\n"));
+ writeStr (usage_fd, GTXT (" -l <signal>\tspecify signal that will trigger a sample of process-wide resource utilization\n"));
+ writeStr (usage_fd, GTXT (" -o <expt>\tspecify experiment name\n"));
+ writeStr (usage_fd, GTXT (" --verbose\tprint expanded log of processing\n"));
+ writeStr (usage_fd, GTXT (" -C <label>\tspecify comment label (up to 10 may appear)\n"));
+ writeStr (usage_fd, GTXT (" -V|--version\tprint version number and exit\n"));
+*/
+ /* don't document this feature */
+ // writeStr (usage_fd, GTXT(" -Z\tPreload mem.so, and launch target [no experiment]\n") );
+/*
+ writeStr (usage_fd, GTXT ("\n See the gp-collect(1) man page for more information\n"));
+*/
+
+#if 0
+ /* print an extended usage message */
+ /* find a Java for Java profiling, set Java on to check Java */
+ find_java ();
+ cc->set_java_mode (NTXT ("on"));
+
+ /* check for variable-clock rate */
+ unsigned char mode = COL_CPUFREQ_NONE;
+ get_cpu_frequency (&mode);
+ if (mode != COL_CPUFREQ_NONE)
+ writeStr (usage_fd, GTXT ("NOTE: system has variable clock frequency, which may cause variable program run times.\n"));
+
+ /* show the experiment that would be run */
+ writeStr (usage_fd, GTXT ("\n Default experiment:\n"));
+ char *ccret = cc->setup_experiment ();
+ if (ccret != NULL)
+ {
+ writeStr (usage_fd, ccret);
+ free (ccret);
+ exit (1);
+ }
+ cc->delete_expt ();
+ ccret = cc->show (1);
+ if (ccret != NULL)
+ {
+ writeStr (usage_fd, ccret);
+ free (ccret);
+ }
+#endif
+}
+
+void
+collect::short_usage ()
+{
+ if (no_short_usage == 0)
+ dbe_write (usage_fd, GTXT ("Run \"%s --help\" for a usage message.\n"), whoami);
+}
+
+void
+collect::show_hwc_usage ()
+{
+ usage_fd = 1;
+ short_usage ();
+ cc->setup_hwc ();
+ hwc_usage (false, whoami, NULL);
+}
+
+void
+collect::writeStr (int f, const char *buf)
+{
+ if (buf != NULL)
+ write (f, buf, strlen (buf));
+}
diff --git a/gprofng/src/gp-display-src.cc b/gprofng/src/gp-display-src.cc
new file mode 100644
index 0000000..ca7853d
--- /dev/null
+++ b/gprofng/src/gp-display-src.cc
@@ -0,0 +1,752 @@
+/* Copyright (C) 2021 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 <unistd.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "DbeApplication.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "DbeView.h"
+#include "Print.h"
+#include "DbeFile.h"
+#include "Command.h"
+
+class er_src : public DbeApplication
+{
+public:
+ er_src (int argc, char *argv[]);
+ void start (int argc, char *argv[]);
+
+private:
+
+ // override methods in base class
+ void usage ();
+ int check_args (int argc, char *argv[]);
+ void run_args (int argc, char *argv[]);
+
+ enum Obj_Types
+ {
+ OT_EXE_ELF = 0, OT_JAVA_CLASS, OT_JAR_FILE, OT_UNKNOWN
+ };
+
+ void open (char *exe);
+ void dump_annotated (char *name, char* sel, char *src, DbeView *dbev,
+ bool is_dis, bool first);
+ void checkJavaClass (char *exe);
+ void print_header (bool first, const char* text);
+ void proc_cmd (CmdType cmd_type, bool first, char *arg1,
+ const char *arg2, const char *arg3 = NULL);
+ FILE *set_outfile (char *cmd, FILE *&set_file);
+
+ bool is_java_class () { return obj_type == OT_JAVA_CLASS; }
+
+ int dbevindex;
+ DbeView *dbev;
+ LoadObject *lo;
+ Obj_Types obj_type;
+ const char *out_fname;
+ FILE *out_file;
+ bool isDisasm;
+ bool isFuncs;
+ bool isDFuncs;
+ bool isSrc;
+ bool v_opt;
+ int multiple;
+ char *str_compcom;
+ bool hex_visible;
+ int src_visible;
+ int vis_src;
+ int vis_dis;
+ int threshold_src;
+ int threshold_dis;
+ int threshold;
+ int vis_bits;
+};
+
+static int
+real_main (int argc, char *argv[])
+{
+ er_src *src = new er_src (argc, argv);
+ src->start (argc, argv);
+ delete src;
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ return catch_out_of_memory (real_main, argc, argv);
+}
+
+er_src::er_src (int argc, char *argv[])
+: DbeApplication (argc, argv)
+{
+ obj_type = OT_UNKNOWN;
+ out_fname = "<stdout>";
+ out_file = stdout;
+ isDisasm = false;
+ isFuncs = false;
+ isDFuncs = false;
+ isSrc = false;
+ v_opt = false;
+ multiple = 0;
+ lo = NULL;
+}
+
+static int
+FuncNameCmp (const void *a, const void *b)
+{
+ Function *item1 = *((Function **) a);
+ Function *item2 = *((Function **) b);
+ return strcmp (item1->get_mangled_name (), item2->get_mangled_name ());
+}
+
+static int
+FuncAddrCmp (const void *a, const void *b)
+{
+ Function *item1 = *((Function **) a);
+ Function *item2 = *((Function **) b);
+ return (item1->img_offset == item2->img_offset) ?
+ FuncNameCmp (a, b) : item1->img_offset > item2->img_offset ? 1 : -1;
+}
+
+void
+er_src::usage ()
+{
+
+/*
+ Ruud - Isolate this line because it has an argument. Otherwise it would be at the
+ end of a long usage list.
+*/
+ printf ( GTXT (
+ "Usage: gprofng display src [OPTION(S)] TARGET-OBJECT\n"));
+
+ printf ( GTXT (
+ "\n"
+ "Display the source code listing, or source code interleaved with disassembly code,\n"
+ "as extracted from the target object (an executable, shared object, object file, or\n"
+ "a Java .class file).\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --version print the version number and exit.\n"
+ " --help print usage information and exit.\n"
+ " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+ "\n"
+ " -func list all the functions from the given object.\n"
+ "\n"
+ " -source item tag show the source code for item; the tag is used to\n"
+ " differentiate in case of multiple occurences with\n"
+ " the same name; the combination of \"all -1\" selects\n"
+ " all the functions in the object; the default is\n"
+ " \"-source all -1\".\n"
+ "\n"
+ " -disasm item tag show the source code, interleaved with the disassembled\n"
+ " instructions; the same definitions for item and tag apply.\n"
+ "\n"
+ " -outfile <filename> write results to file <filename>; a dash (-) writes to\n"
+ " stdout; this is also the default; note that this only\n"
+ " affects options included to the right of this option.\n"
+ "\n"
+ "Documentation:\n"
+ "\n"
+ "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+ "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+ "should give you access to this document.\n"
+ "\n"
+ "See also:\n"
+ "\n"
+ "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-text(1)\n"));
+/*
+ printf (GTXT ("Usage: %s [OPTION] a.out/.so/.o/.class\n\n"), whoami);
+ printf (GTXT (" -func List all the functions from the given object\n"
+ " -source, -src item tag Show the annotated source for the listed item\n"
+ " -disasm item tag Include the disassembly in the listing\n"
+ " -V Print the current release version of er_src\n"
+ " -cc, -scc, -dcc com_spec Define the compiler commentary classes to show\n"
+ " -outfile filename Open filename for output\n"));
+*/
+ exit (0);
+}
+
+void
+er_src::start (int argc, char *argv[])
+{
+ dbevindex = dbeSession->createView (0, -1);
+ dbev = dbeSession->getView (dbevindex);
+
+ // get options
+ check_args (argc, argv);
+ run_args (argc, argv);
+ if (out_file != stdout)
+ fclose (out_file);
+}
+
+FILE *
+er_src::set_outfile (char *cmd, FILE *&set_file)
+{
+ FILE *new_file;
+ if (!strcasecmp (cmd, "-"))
+ {
+ new_file = stdout;
+ out_fname = "<stdout>";
+ }
+ else
+ {
+ char *cmdpath;
+ char *fname = strstr (cmd, "~/");
+ // Handle ~ in file names
+ char *home = getenv ("HOME");
+ if (fname != NULL && home != NULL)
+ cmdpath = dbe_sprintf ("%s/%s", home, fname + 2);
+ else if ((fname = strstr (cmd, "~")) != NULL && home != NULL)
+ cmdpath = dbe_sprintf ("/home/%s", fname + 1);
+ else
+ cmdpath = strdup (cmd);
+ new_file = fopen (cmdpath, "w");
+ if (new_file == NULL)
+ {
+ fprintf (stderr, GTXT ("Unable to open file: %s"), cmdpath);
+ free (cmdpath);
+ return NULL;
+ }
+ out_fname = cmdpath;
+ }
+ if (set_file && (set_file != stdout))
+ fclose (set_file);
+
+ set_file = new_file;
+ return set_file;
+}
+
+void
+er_src::proc_cmd (CmdType cmd_type, bool first, char *arg1,
+ const char *arg2, const char *arg3)
+{
+ Cmd_status status;
+ Module *module;
+ Function *fitem;
+ int mindex, findex;
+ switch (cmd_type)
+ {
+ case SOURCE:
+ dbev->set_view_mode (VMODE_USER);
+ print_anno_file (arg1, arg2, arg3, false,
+ stdout, stdin, out_file, dbev, false);
+ break;
+ case DISASM:
+ dbev->set_view_mode (VMODE_MACHINE);
+ print_header (first, GTXT ("Annotated disassembly\n"));
+ print_anno_file (arg1, arg2, arg3, true,
+ stdout, stdin, out_file, dbev, false);
+ break;
+ case OUTFILE:
+ if (arg1)
+ set_outfile (arg1, out_file);
+ break;
+ case FUNCS:
+ print_header (false, GTXT ("Function list\n"));
+ fprintf (out_file, GTXT ("Functions sorted in lexicographic order\n"));
+ fprintf (out_file, GTXT ("\nLoad Object: %s\n\n"), lo->get_name ());
+ if (lo->wsize == W32)
+ fprintf (out_file, GTXT (" Address Size Name\n\n"));
+ else
+ fprintf (out_file, GTXT (" Address Size Name\n\n"));
+
+ Vec_loop (Module*, lo->seg_modules, mindex, module)
+ {
+ module->functions->sort (FuncNameCmp);
+ const char *fmt = (lo->wsize == W32) ?
+ GTXT (" 0x%08llx %8lld %s\n") :
+ GTXT (" 0x%016llx %16lld %s\n");
+ Vec_loop (Function*, module->functions, findex, fitem)
+ {
+ fprintf (out_file, fmt,
+ (ull_t) fitem->img_offset,
+ (ull_t) fitem->size,
+ fitem->get_name ());
+ }
+ }
+ break;
+ case DUMPFUNC:
+ lo->functions->sort (FuncAddrCmp);
+ print_header (first, GTXT ("Dump functions\n"));
+ lo->dump_functions (out_file);
+ first = false;
+ break;
+ case SCOMPCOM:
+ status = dbev->proc_compcom (arg1, true, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s"), Command::get_err_string (status));
+ break;
+ case DCOMPCOM:
+ status = dbev->proc_compcom (arg1, false, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s"), Command::get_err_string (status));
+ break;
+ case COMPCOM:
+ status = dbev->proc_compcom (arg1, true, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s"), Command::get_err_string (status), arg1);
+ status = dbev->proc_compcom (arg1, false, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s"), Command::get_err_string (status), arg1);
+ break;
+ case HELP:
+ usage ();
+ break;
+ case VERSION_cmd:
+ if (out_file != stdout)
+// Ruud
+ Application::print_version_info ();
+/*
+ fprintf (out_file, "GNU %s version %s\n", get_basename (prog_name), VERSION);
+*/
+ break;
+ default:
+ fprintf (stderr, GTXT ("Invalid option"));
+ break;
+ }
+}
+
+void
+er_src::run_args (int argc, char *argv[])
+{
+ CmdType cmd_type;
+ int arg_count, cparam;
+ char *arg;
+ char *arg1;
+ const char *arg2;
+ bool first = true;
+ bool space;
+ Module *module;
+ int mindex;
+
+ for (int i = 1; i < argc; i++)
+ {
+ if (*argv[i] != '-')
+ {
+ if (!multiple)
+ { // er_src -V exe
+ space = false;
+ dbev->set_view_mode (VMODE_USER);
+ print_header (first, GTXT ("Annotated source\n"));
+ Vec_loop (Module*, lo->seg_modules, mindex, module)
+ {
+ if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+ module->lang_code == Sp_lang_unknown)
+ continue;
+ if (space)
+ fprintf (out_file, "\n");
+ print_anno_file (module->file_name, "1", NULL, false,
+ stdout, stdin, out_file, dbev, false);
+ space = true;
+ }
+ }
+ break;
+ }
+ if (strncmp (argv[i], NTXT ("--whoami="), 9) == 0)
+ {
+ whoami = argv[i] + 9;
+ continue;
+ }
+ switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+ {
+ case SOURCE:
+ case DISASM:
+ {
+ i += arg_count;
+ multiple++;
+ if (i >= argc || argv[i] == NULL ||
+ (*(argv[i]) == '-' && atoi (argv[i]) != -1) || i + 1 == argc)
+ {
+ i--;
+ arg = argv[i];
+ arg2 = "1";
+ }
+ else
+ {
+ arg = argv[i - 1];
+ if (*(argv[i]) == '-' && atoi (argv[i]) == -1 &&
+ streq (arg, NTXT ("all")))
+ {
+ space = false;
+ if (cmd_type == SOURCE)
+ print_header (first, GTXT ("Annotated source\n"));
+ else
+ print_header (first, GTXT ("Annotated disassembly\n"));
+ Vec_loop (Module*, lo->seg_modules, mindex, module)
+ {
+ if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+ module->lang_code == Sp_lang_unknown)
+ continue;
+ if (space)
+ fprintf (out_file, "\n");
+ proc_cmd (cmd_type, first, module->file_name, "1");
+ space = true;
+ }
+ first = false;
+ break;
+ }
+ arg2 = argv[i];
+ }
+ char *fcontext = NULL;
+ arg1 = parse_fname (arg, &fcontext);
+ if (arg1 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1);
+ free (fcontext);
+ break;
+ }
+ proc_cmd (cmd_type, first, arg1, arg2, fcontext);
+ free (arg1);
+ free (fcontext);
+ first = false;
+ break;
+ }
+ case OUTFILE:
+ case FUNCS:
+ case DUMPFUNC:
+ case COMPCOM:
+ case SCOMPCOM:
+ case DCOMPCOM:
+ case VERSION_cmd:
+ case HELP:
+ proc_cmd (cmd_type, first, (arg_count > 0) ? argv[i + 1] : NULL,
+ (arg_count > 1) ? argv[i + 2] : NULL);
+ i += arg_count;
+ break;
+ default:
+ if (streq (argv[i] + 1, NTXT ("all")) || streq (argv[i] + 1, NTXT ("dall")))
+ {
+ first = false;
+ multiple++;
+ if (streq (argv[i] + 1, NTXT ("all")))
+ proc_cmd (FUNCS, first, NULL, NULL);
+ else
+ proc_cmd (DUMPFUNC, first, NULL, NULL);
+ space = false;
+ print_header (first, GTXT ("Annotated source\n"));
+ Vec_loop (Module*, lo->seg_modules, mindex, module)
+ {
+ if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+ module->lang_code == Sp_lang_unknown)
+ continue;
+ if (space)
+ fprintf (out_file, "\n");
+ proc_cmd (SOURCE, first, module->file_name, "1");
+ space = true;
+ }
+ print_header (first, GTXT ("Annotated disassembly\n"));
+ Vec_loop (Module*, lo->seg_modules, mindex, module)
+ {
+ if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+ module->lang_code == Sp_lang_unknown)
+ continue;
+ if (space)
+ fprintf (out_file, "\n");
+ proc_cmd (DISASM, first, module->file_name, "1");
+ space = true;
+ }
+ }
+ else
+ {
+ proc_cmd (cmd_type, first, (arg_count > 0) ? argv[i + 1] : NULL,
+ (arg_count > 1) ? argv[i + 2] : NULL);
+ i += arg_count;
+ break;
+ }
+ }
+ }
+}
+
+int
+er_src::check_args (int argc, char *argv[])
+{
+ CmdType cmd_type = UNKNOWN_CMD;
+ int arg_count, cparam;
+ int i;
+ char *exe;
+ bool first = true;
+ if (argc == 1)
+ usage ();
+
+ // If any comments from the .rc files, log them to stderr
+ Emsg * rcmsg = fetch_comments ();
+ while (rcmsg != NULL)
+ {
+ fprintf (stderr, "%s: %s\n", prog_name, rcmsg->get_msg ());
+ rcmsg = rcmsg->next;
+ }
+
+ // Parsing the command line
+ opterr = 0;
+ exe = NULL;
+ for (i = 1; i < argc; i++)
+ {
+ if (*argv[i] != '-')
+ {
+ exe = argv[i];
+ if (i == 1)
+ { // er_src exe ?
+ if (!exe)
+ usage ();
+ if (argc == 3) // er_src exe file
+ usage ();
+ }
+ else if (v_opt && !multiple && !exe && !str_compcom) // just er_src -V
+ exit (0);
+ if (argc < i + 1 || argc > i + 3)
+ usage ();
+ i++;
+ if (argc > i)
+ usage ();
+ open (exe);
+ return i;
+ }
+ switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+ {
+ case WHOAMI:
+ whoami = argv[i] + 1 + cparam;
+ break;
+ case HELP:
+ i += arg_count;
+ multiple++;
+ usage ();
+ break;
+ case VERSION_cmd:
+ if (first)
+ {
+// Ruud
+ Application::print_version_info ();
+/*
+ printf ("GNU %s version %s\n", get_basename (prog_name), VERSION);
+*/
+ v_opt = true;
+ first = false;
+ }
+ break;
+ case SOURCE:
+ case DISASM:
+ i += arg_count;
+ multiple++;
+ isDisasm = true;
+ if (i >= argc || argv[i] == NULL ||
+ (*(argv[i]) == '-' && atoi (argv[i]) != -1) || (i + 1 == argc))
+ i--;
+ break;
+ case DUMPFUNC:
+ i += arg_count;
+ multiple++;
+ break;
+ case FUNCS:
+ i += arg_count;
+ multiple++;
+ break;
+ case OUTFILE:
+ case COMPCOM:
+ case SCOMPCOM:
+ case DCOMPCOM:
+ i += arg_count;
+ break;
+ default:
+ if (!(streq (argv[i] + 1, NTXT ("all")) ||
+ streq (argv[i] + 1, NTXT ("dall"))))
+ {
+ fprintf (stderr, "Error: invalid option: `%s'\n", argv[i]);
+ exit (1);
+ }
+ }
+ }
+ if (!exe && !(argc == 2 && cmd_type == VERSION_cmd))
+ usage ();
+ return i;
+}
+
+void
+er_src::checkJavaClass (char* exe)
+{
+ unsigned char cf_buf[4];
+ unsigned int magic_number;
+ int fd = ::open (exe, O_RDONLY | O_LARGEFILE);
+ if (fd == -1)
+ return;
+ if (sizeof (cf_buf) == read_from_file (fd, cf_buf, sizeof (cf_buf)))
+ {
+ magic_number = cf_buf[0] << 24;
+ magic_number |= cf_buf[1] << 16;
+ magic_number |= cf_buf[2] << 8;
+ magic_number |= cf_buf[3];
+ if (magic_number == 0xcafebabe)
+ obj_type = OT_JAVA_CLASS;
+ }
+ close (fd);
+}
+
+void
+er_src::print_header (bool first, const char* text)
+{
+ if (!first)
+ fprintf (out_file, "\n");
+ if (multiple > 1)
+ {
+ fprintf (out_file, NTXT ("%s"), text);
+ fprintf (out_file, "---------------------------------------\n");
+ }
+}
+
+void
+er_src::dump_annotated (char *name, char *sel, char *src, DbeView *dbevr,
+ bool is_dis, bool first)
+{
+ Module *module;
+ bool space;
+ int mindex;
+ print_header (first, (is_dis) ? ((is_java_class ()) ?
+ GTXT ("Annotated bytecode\n") :
+ GTXT ("Annotated disassembly\n")) :
+ GTXT ("Annotated source\n"));
+ if (!name)
+ {
+ space = false;
+ Vec_loop (Module*, lo->seg_modules, mindex, module)
+ {
+ if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+ (!is_dis && module->lang_code == Sp_lang_unknown))
+ continue;
+ if (space)
+ fprintf (out_file, "\n");
+ print_anno_file (module->file_name, sel, src, is_dis,
+ stdout, stdin, out_file, dbevr, false);
+ space = true;
+ }
+ }
+ else
+ print_anno_file (name, sel, src, is_dis, stdout, stdin, out_file, dbevr, false);
+}
+
+static bool
+isFatal (bool isDisasm, LoadObject::Arch_status status)
+{
+ if (isDisasm)
+ {
+ switch (status)
+ {
+ // non-fatal errors for disassembly
+ case LoadObject::ARCHIVE_BAD_STABS:
+ case LoadObject::ARCHIVE_NO_STABS:
+ return false;
+ default:
+ return true;
+ }
+ }
+ return true;
+}
+
+void
+er_src::open (char *exe)
+{
+ LoadObject::Arch_status status;
+ char *errstr;
+ Module *module;
+ Vector<Histable*> *module_lst;
+
+ // Construct the Segment structure
+ char *path = strdup (exe);
+ lo = dbeSession->createLoadObject (path);
+ if (NULL == lo->dbeFile->find_file (lo->dbeFile->get_name ()))
+ {
+ fprintf (stderr, GTXT ("%s: Error: unable to open file %s\n"), prog_name, lo->dbeFile->get_name ());
+ exit (1);
+ }
+ checkJavaClass (exe);
+
+ if (is_java_class ())
+ {
+ lo->type = LoadObject::SEG_TEXT;
+ lo->set_platform (Java, Wnone);
+ lo->id = (uint64_t) - 1; // see AnalyzerSession::ask_which for details
+ module = dbeSession->createClassFile (dbe_strdup (exe));
+ module->loadobject = lo;
+ lo->seg_modules->append (module);
+ module->dbeFile->set_location (exe);
+ if (module->readFile () != module->AE_OK)
+ {
+ Emsg *emsg = module->get_error ();
+ if (emsg)
+ {
+ fprintf (stderr, GTXT ("%s: Error: %s\n"), prog_name, emsg->get_msg ());
+ return;
+ }
+ fprintf (stderr, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name, exe);
+ return;
+ }
+ status = lo->sync_read_stabs ();
+ if (status != LoadObject::ARCHIVE_SUCCESS)
+ {
+ if (status == LoadObject::ARCHIVE_ERR_OPEN)
+ {
+ fprintf (stderr, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name, exe);
+ return;
+ }
+ else
+ {
+ if (isDisasm)
+ if (status == LoadObject::ARCHIVE_NO_STABS)
+ {
+ fprintf (stderr, GTXT ("%s: Error: `%s' is interface; disassembly annotation not available\n"), prog_name, exe);
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ status = lo->sync_read_stabs ();
+ if (status != LoadObject::ARCHIVE_SUCCESS)
+ {
+ errstr = lo->status_str (status);
+ if (errstr)
+ {
+ fprintf (stderr, "%s: %s\n", prog_name, errstr);
+ free (errstr);
+ }
+ if (isFatal (isDisasm, status))
+ return;
+ }
+ obj_type = OT_EXE_ELF;
+
+ // if .o file, then set file as the exe name
+ if (lo->is_relocatable ())
+ {
+ // find the module, if we can
+ module_lst = new Vector<Histable*>;
+ module = dbeSession->map_NametoModule (path, module_lst, 0);
+ if (module == NULL)
+ // Create a module with the right name
+ module = dbeSession->createModule (lo, path);
+ }
+ }
+}
diff --git a/gprofng/src/gp-display-text.cc b/gprofng/src/gp-display-text.cc
new file mode 100644
index 0000000..7183553
--- /dev/null
+++ b/gprofng/src/gp-display-text.cc
@@ -0,0 +1,2834 @@
+/* Copyright (C) 2021 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 <unistd.h> // isatty
+
+#include "gp-print.h"
+#include "ipcio.h"
+#include "Command.h"
+#include "Dbe.h"
+#include "DbeApplication.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Emsg.h"
+#include "DbeView.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "PathTree.h"
+#include "LoadObject.h"
+#include "Function.h"
+#include "FilterSet.h"
+#include "Filter.h"
+#include "MetricList.h"
+#include "MemorySpace.h"
+#include "Module.h"
+#include "util.h"
+#include "i18n.h"
+#include "StringBuilder.h"
+#include "debug.h"
+#include "UserLabel.h"
+
+static char *exe_name;
+static char **new_argv;
+
+void
+reexec ()
+{
+ if (dbeSession != NULL)
+ dbeSession->unlink_tmp_files ();
+ execv (exe_name, new_argv);
+}
+
+/**
+ * Run application under enhance if the following requirements are satisfied:
+ * 1. Environment variable GPROFNG_ENHANCE is not set to "no"
+ * 2. Standard input is terminal
+ * 3. Standard output is terminal
+ * 4. /bin/enhance exists and can work on this system
+ */
+static void
+reexec_enhance (int argc, char *argv[])
+{
+ char *gp_enhance = getenv ("GPROFNG_ENHANCE");
+ if (NULL != gp_enhance && 0 == strcasecmp (gp_enhance, "no"))
+ return; // Do not enhance
+ // Verify that input and output are tty
+ if (!isatty (fileno (stdin))) // stdin is not a terminal
+ return; // Do not enhance
+ if (!isatty (fileno (stdout))) // stdout is not a terminal
+ return; // Do not enhance
+ char *enhance_name = NTXT ("/bin/enhance");
+ struct stat sbuf;
+ int res = stat (enhance_name, &sbuf); // Check if enhance exists
+ if (res == 0)
+ res = system (NTXT ("/bin/enhance /bin/true")); // Check if enhance can work
+ if (res != 0)
+ {
+ fflush (stdout);
+ printf (GTXT ("Warning: History and command editing is not supported on this system.\n"));
+ fflush (stdout);
+ return;
+ }
+ else
+ {
+ printf (GTXT ("Note: History and command editing is supported on this system.\n"));
+ fflush (stdout);
+ }
+ char **nargv = new char*[argc + 2];
+ for (int i = 0; i < argc; i++)
+ nargv[i + 1] = argv[i];
+ nargv[0] = enhance_name;
+ nargv[argc + 1] = NULL;
+ putenv (NTXT ("GPROFNG_ENHANCE=no")); // prevent recursion
+ execv (enhance_name, nargv);
+ // execv failed. Continue to run the program
+ delete[] nargv;
+}
+
+int
+main (int argc, char *argv[])
+{
+ er_print *erprint;
+ int ind = 1;
+ if (argc > ind && *argv[ind] == '-')
+ {
+ int arg_count, cparam;
+ if (Command::get_command (argv[ind] + 1, arg_count, cparam) == WHOAMI)
+ ind = ind + 1 + arg_count;
+ }
+ if (argc > ind && argv[ind] != NULL && *argv[ind] != '-')
+ reexec_enhance (argc, argv);
+
+ // Save argv for reexec())
+ exe_name = argv[0];
+ new_argv = argv;
+
+ if (argc > ind && argv[ind] != NULL && strcmp (argv[ind], "-IPC") == 0)
+ {
+ putenv (NTXT ("LC_NUMERIC=C")); // Use non-localized numeric data in IPC packets
+ erprint = new er_print (argc, argv);
+ theDbeApplication->rdtMode = false;
+ ipc_mainLoop (argc, argv);
+ }
+ else
+ {
+ erprint = new er_print (argc, argv);
+ erprint->start (argc, argv);
+ }
+
+ dbeSession->unlink_tmp_files ();
+ if (DUMP_CALL_STACK)
+ {
+ extern long total_calls_add_stack, total_stacks, total_nodes, call_stack_size[201];
+ fprintf (stderr, NTXT ("total_calls_add_stack=%lld\ntotal_stacks=%lld\ntotal_nodes=%lld\n"),
+ (long long) total_calls_add_stack, (long long) total_stacks, (long long) total_nodes);
+ for (int i = 0; i < 201; i++)
+ if (call_stack_size[i] != 0)
+ fprintf (stderr, NTXT (" call_stack_size[%d] = %6lld\n"), i,
+ (long long) call_stack_size[i]);
+ }
+#if defined(DEBUG)
+ delete erprint;
+#endif
+ return 0;
+}
+
+er_print::er_print (int argc, char *argv[])
+: DbeApplication (argc, argv)
+{
+ out_fname = GTXT ("<stdout>");
+ inp_file = stdin;
+ out_file = stdout;
+ dis_file = stdout;
+ cov_string = NULL;
+ limit = 0;
+ cstack = new Vector<Histable*>();
+ was_QQUIT = false;
+}
+
+er_print::~er_print ()
+{
+ free (cov_string);
+ delete cstack;
+ if (inp_file != stdin)
+ fclose (inp_file);
+}
+
+void
+er_print::start (int argc, char *argv[])
+{
+ Vector<String> *res = theDbeApplication->initApplication (NULL, NULL, NULL);
+ res->destroy ();
+ delete res;
+
+ // Create a view on the session
+ dbevindex = dbeSession->createView (0, -1);
+ dbev = dbeSession->getView (dbevindex);
+ limit = dbev->get_limit ();
+ (void) check_args (argc, argv);
+ int ngood = dbeSession->ngoodexps ();
+ if (ngood == 0)
+ {
+ fprintf (stderr, GTXT ("No valid experiments loaded; exiting\n"));
+ return;
+ }
+ dbeDetectLoadMachineModel (dbevindex);
+ run (argc, argv);
+}
+
+bool
+er_print::free_memory_before_exit ()
+{
+ return was_QQUIT;
+}
+
+void
+er_print::usage ()
+{
+
+/*
+ Ruud - Isolate this line because it has an argument. Otherwise it would be at the
+ end of the long option list.
+*/
+ printf ( GTXT (
+ "Usage: gprofng display text [OPTION(S)] [COMMAND(S)] [-script <script_file>] EXPERIMENT(S)\n"));
+
+ printf ( GTXT (
+ "\n"
+ "Print a plain text version of the various displays supported by gprofng.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --version print the version number and exit.\n"
+ " --help print usage information and exit.\n"
+ " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+ "\n"
+ " -script <script-file> execute the commands stored in the script file;\n"
+ " this feature may be combined with commands specified\n"
+ " at the command line.\n"
+ "\n"
+ "Commands:\n"
+ "\n"
+ "This tool supports a rich set of commands to control the display of the\n"
+ "data; instead of, or in addition to, including these commands in a script\n"
+ "file, it is also allowed to include such commands at the command line;\n"
+ "in this case, the commands need to be prepended with the \"-\" symbol; the\n"
+ "commands are processed and interpreted left from right, so the order matters;\n"
+ "The gprofng manual documents the commands that are supported.\n"
+ "\n"
+ "If this tool is invoked without options, commands, or a script file, it starts\n"
+ "in interpreter mode. The user can then issue the commands interactively; the\n"
+ "session is terminated with the \"exit\" command in the interpreter.\n"
+ "\n"
+ "Documentation:\n"
+ "\n"
+ "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+ "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+ "should give you access to this document.\n"
+ "\n"
+ "See also:\n"
+ "\n"
+ "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1)\n"));
+}
+
+int // returns count of experiments read
+er_print::check_args (int argc, char *argv[])
+{
+ CmdType cmd_type;
+ int arg_count;
+ int cparam;
+ int exp_no;
+ error_msg = NULL;
+
+ Emsg *rcmsg = fetch_comments ();
+ while (rcmsg != NULL)
+ {
+ fprintf (stderr, NTXT ("%s: %s\n"), prog_name, rcmsg->get_msg ());
+ rcmsg = rcmsg->next;
+ }
+ delete_comments ();
+
+ // Set up the list of experiments to add after checking the args
+ Vector<Vector<char*>*> *exp_list = new Vector<Vector<char*>*>();
+
+ // Prescan the command line arguments, processing only a few
+ for (int i = 1; i < argc; i++)
+ {
+ if (*argv[i] != '-')
+ {
+ // we're at the end -- get the list of experiments
+ // Build the list of experiments, and set the searchpath
+ Vector<char*> *list = dbeSession->get_group_or_expt (argv[i]);
+ if (list->size () > 0)
+ {
+ for (int j = 0, list_sz = list->size (); j < list_sz; j++)
+ {
+ char *path = list->fetch (j);
+ if (strlen (path) == 0 || strcmp (path, NTXT ("\\")) == 0)
+ continue;
+ char *p = strrchr (path, '/');
+ if (p)
+ {
+ // there's a directory in front of the name; add it to search path
+ *p = '\0';
+ dbeSession->set_search_path (path, false);
+ }
+ }
+ list->destroy ();
+ list->append (dbe_strdup (argv[i]));
+ exp_list->append (list);
+ }
+ else
+ delete list;
+ continue;
+ }
+
+ // Not at the end yet, treat the next argument as a command
+ switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+ {
+ case WHOAMI:
+ whoami = argv[i] + 1 + cparam;
+ break;
+ case HELP:
+ if (i + 1 + arg_count == argc)
+ {
+ usage();
+ exit (0);
+ }
+ break;
+ case HHELP:
+ Command::print_help (whoami, true, false, stdout);
+ fprintf (stdout, "\n");
+ indxo_list (false, stdout);
+ fprintf (stdout, "\n");
+ mo_list (false, stdout);
+ if (!getenv ("_BUILDING_MANPAGE"))
+ fprintf (stdout, GTXT ("\nSee gprofng(1) for more details\n"));
+ exit (0);
+ case ADD_EXP:
+ case DROP_EXP:
+ case OPEN_EXP:
+ printf (GTXT ("Error: command %s can not appear on the command line\n"), argv[i]);
+ exit (2);
+ case VERSION_cmd:
+ Application::print_version_info ();
+ exit (0);
+ case AMBIGUOUS_CMD:
+ fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), argv[i]);
+ exit (2);
+ case UNKNOWN_CMD:
+ fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), argv[i]);
+ exit (2);
+ // it's a plausible argument; see if we process now or later
+ case SOURCE:
+ case DISASM:
+ case CSINGLE:
+ case CPREPEND:
+ case CAPPEND:
+ case FSINGLE:
+ case SAMPLE_DETAIL:
+ case STATISTICS:
+ case HEADER:
+ //skip the arguments to that command
+ i += arg_count;
+ if (i >= argc || end_command (argv[i]))
+ i--;
+ break;
+ case PRINTMODE:
+ case INDXOBJDEF:
+ case ADDPATH:
+ case SETPATH:
+ case PATHMAP:
+ case OBJECT_SHOW:
+ case OBJECT_HIDE:
+ case OBJECT_API:
+ case OBJECTS_DEFAULT:
+ case EN_DESC:
+ // these are processed in the initial pass over the arguments
+ proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
+ (arg_count > 1) ? argv[i + 2] : NULL,
+ (arg_count > 2) ? argv[i + 3] : NULL,
+ (arg_count > 3) ? argv[i + 4] : NULL);
+ i += arg_count;
+ break;
+ default:
+ // any others, we skip for now
+ i += arg_count;
+ break;
+ }
+ }
+
+ // Make sure some experiments were specified
+ exp_no = exp_list->size ();
+ if (exp_no == 0)
+ { // no experiment name
+ fprintf (stderr, GTXT ("%s: Missing experiment directory (use the --help option to get a usage overview)\n"), whoami);
+ exit (1);
+ }
+
+ // add the experiments to the session
+ char *errstr = dbeOpenExperimentList (0, exp_list, false);
+ for (long i = 0; i < exp_list->size (); i++)
+ {
+ Vector<char*>* p = exp_list->get (i);
+ Destroy (p);
+ }
+ delete exp_list;
+ if (errstr != NULL)
+ {
+ fprintf (stderr, NTXT ("%s"), errstr);
+ free (errstr);
+ }
+
+ return exp_no;
+}
+
+int
+er_print::is_valid_seg_name (char *lo_name, int prev)
+{
+ // prev is the loadobject segment index that was last returned
+ // search starts following that loadobject
+ int index;
+ LoadObject *lo;
+ char *p_lo_name = lo_name;
+ char *name = NULL;
+
+ // strip angle brackets from all but <Unknown> and <Total>
+ if (strcmp (lo_name, "<Unknown>") && strcmp (lo_name, "<Total>"))
+ {
+ if (*lo_name == '<')
+ {
+ name = dbe_strdup (lo_name + 1);
+ p_lo_name = name;
+ char *p = strchr (name, '>');
+ if (p)
+ *p = '\0';
+ }
+ }
+
+ // get the load object list from the session
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ if (prev > 0)
+ {
+ if (lo->seg_idx == prev) // this is where we left off
+ prev = -1;
+ continue;
+ }
+
+ // does this one match?
+ if (cmp_seg_name (lo->get_pathname (), p_lo_name))
+ {
+ delete lobjs;
+ free (name);
+ size_t len = strlen (lo_name);
+ if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
+ (len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
+ {
+ fprintf (stderr, GTXT ("Error: Java class `%s' is not selectable\n"), lo_name);
+ return -1;
+ }
+ return lo->seg_idx;
+ }
+ }
+ delete lobjs;
+ free (name);
+ return -1;
+}
+
+int
+er_print::cmp_seg_name (char *full_name, char *lo_name)
+{
+ char *cmp_name;
+ if (!strchr (lo_name, '/') && (cmp_name = strrchr (full_name, '/')))
+ cmp_name++; // basename
+ else
+ cmp_name = full_name; // full path name
+ return !strcmp (lo_name, cmp_name);
+}
+
+// processing object_select
+// Note that this does not affect the strings in Settings,
+// unlike object_show, object_hide, and object_api
+int
+er_print::process_object_select (char *names)
+{
+ int index;
+ LoadObject *lo;
+ int no_lobj = 0;
+ bool got_err = false;
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ if ((names == NULL) || !strcasecmp (names, Command::ALL_CMD))
+ { // full coverage
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ dbev->set_lo_expand (lo->seg_idx, LIBEX_SHOW);
+ }
+ }
+ else
+ { // parsing coverage
+ // first, hide functions from all loadobjects
+ // except the java ones
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ char *lo_name = lo->get_name ();
+ if (lo_name != NULL)
+ {
+ size_t len = strlen (lo_name);
+ if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
+ (len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
+ continue;
+ }
+ dbev->set_lo_expand (lo->seg_idx, LIBEX_HIDE);
+ }
+
+ Vector <char *> *tokens = split_str (names, ',');
+ for (long j = 0, sz = VecSize (tokens); j < sz; j++)
+ {
+ // loop over the provided names
+ char *lo_name = tokens->get (j);
+ int seg_idx = -1;
+ seg_idx = is_valid_seg_name (lo_name, seg_idx);
+ while (seg_idx != -1)
+ {
+ dbev->set_lo_expand (seg_idx, LIBEX_SHOW);
+ no_lobj++;
+ seg_idx = is_valid_seg_name (lo_name, seg_idx);
+ }
+ if (no_lobj == 0)
+ {
+ got_err = true;
+ fprintf (stderr, GTXT ("Error: Unknown load object: `%s'\n"), lo_name);
+ }
+ free (lo_name);
+ }
+ delete tokens;
+ }
+
+ if (!got_err)
+ { // good coverage string
+ free (cov_string);
+ cov_string = strdup (names);
+ }
+ else
+ { // bad, restore original coverage
+ no_lobj = -1;
+ process_object_select (cov_string);
+ }
+ delete lobjs;
+ return no_lobj;
+}
+
+int
+er_print::set_libexpand (char *cov, enum LibExpand expand)
+{
+ bool changed = dbev->set_libexpand (cov, expand);
+ if (changed == true)
+ dbev->update_lo_expands ();
+ return 0;
+}
+
+int
+er_print::set_libdefaults ()
+{
+ dbev->set_libdefaults ();
+ return 0;
+}
+
+bool
+er_print::end_command (char *cmd)
+{
+ if (cmd == NULL || *cmd == '-')
+ return true;
+ size_t len = strlen (cmd);
+ if (cmd[len - 1] == '/')
+ len--;
+ if ((len > 3 && !strncmp (&cmd[len - 3], NTXT (".er"), 3)) ||
+ (len > 4 && !strncmp (&cmd[len - 4], NTXT (".erg"), 4)))
+ return true;
+ return false;
+}
+
+// Now actually start processing the arguments
+void
+er_print::run (int argc, char *argv[])
+{
+ CmdType cmd_type;
+ int arg_count, cparam, i;
+ bool got = false;
+ char *arg1, *arg2;
+ for (i = 1; i < argc; i++)
+ {
+ if (*argv[i] != '-') // open experiment pointer files
+ continue;
+ switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+ {
+ case WHOAMI:
+ whoami = argv[i] + 1 + cparam;
+ break;
+ case SCRIPT:
+ got = true;
+ inp_file = fopen (argv[++i], "r");
+ if (inp_file == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), argv[i]);
+ exit (3);
+ }
+ proc_script ();
+ break;
+ case STDIN:
+ got = true;
+ inp_file = stdin;
+ proc_script ();
+ break;
+ case SOURCE: // with option arg_count == 2
+ case DISASM:
+ got = true;
+ i += arg_count;
+ if ((i >= argc) || end_command (argv[i]))
+ {
+ i--;
+ arg1 = argv[i];
+ arg2 = NTXT ("");
+ }
+ else
+ {
+ arg1 = argv[i - 1];
+ arg2 = argv[i];
+ }
+ proc_cmd (cmd_type, cparam, arg1, arg2, NULL, NULL, true);
+ break;
+ case CSINGLE:
+ case CPREPEND:
+ case CAPPEND:
+ case FSINGLE:
+ got = true;
+ i += arg_count;
+ if ((i >= argc) || end_command (argv[i]))
+ {
+ i--;
+ proc_cmd (cmd_type, cparam, argv[i], NTXT ("1"));
+ }
+ else
+ proc_cmd (cmd_type, cparam, argv[i - 1], argv[i]);
+ break;
+ case SAMPLE_DETAIL: // with option arg_count == 1
+ case STATISTICS:
+ case HEADER:
+ got = true;
+ // now fall through to process the command
+ case COMPARE:
+ got = true;
+ i += arg_count;
+ if ((i >= argc) || end_command (argv[i]))
+ {
+ i--;
+ proc_cmd (cmd_type, cparam, NULL, NULL);
+ }
+ else
+ proc_cmd (cmd_type, cparam, argv[i], NULL);
+ break;
+ case PRINTMODE:
+ case INDXOBJDEF:
+ case ADDPATH:
+ case SETPATH:
+ case PATHMAP:
+ case OBJECT_SHOW:
+ case OBJECT_HIDE:
+ case OBJECT_API:
+ case OBJECTS_DEFAULT:
+ case EN_DESC:
+ got = true;
+ // these have been processed already
+ i += arg_count;
+ break;
+ case LIMIT:
+ got = true;
+ proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
+ (arg_count > 1) ? argv[i + 2] : NULL);
+ i += arg_count;
+ break;
+ default:
+ got = true;
+ proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
+ (arg_count > 1) ? argv[i + 2] : NULL);
+ i += arg_count;
+ break;
+ }
+ }
+ if (!got) // no command has been specified
+ proc_script ();
+}
+
+#define MAXARGS 20
+
+void
+er_print::proc_script ()
+{
+ CmdType cmd_type;
+ int arg_count, cparam;
+ char *cmd, *end_cmd;
+ char *script = NULL;
+ char *arglist[MAXARGS];
+ char *line = NULL;
+ int lineno = 0;
+ while (!feof (inp_file))
+ {
+ if (inp_file == stdin)
+ printf (NTXT ("(%s) "), get_basename (prog_name));
+ free (script);
+ script = read_line (inp_file);
+ if (script == NULL)
+ continue;
+ free (line);
+ line = dbe_strdup (script);
+ lineno++;
+ for (int i = 0; i < MAXARGS; i++)
+ arglist[i] = NULL;
+
+ // ensure it's terminated by a \n, and remove that character
+ strtok (script, NTXT ("\n"));
+
+ // extract the command
+ cmd = strtok (script, NTXT (" \t"));
+ if (cmd == NULL)
+ continue;
+ if (*cmd == '#')
+ {
+ fprintf (stderr, NTXT ("%s"), line);
+ continue;
+ }
+ if (*cmd == '\n')
+ continue;
+
+ char *remainder = strtok (NULL, NTXT ("\n"));
+ // now extract the arguments
+ int nargs = 0;
+ for (;;)
+ {
+ end_cmd = NULL;
+ if (nargs >= MAXARGS)
+ fprintf (stderr, GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
+ MAXARGS, cmd, lineno);
+ char *nextarg = strtok (remainder, NTXT ("\n"));
+ if ((nextarg == NULL) || (*nextarg == '#'))
+ // either the end of the line, or a comment indicator
+ break;
+ if (nargs >= MAXARGS)
+ {
+ parse_qstring (nextarg, &end_cmd);
+ nargs++;
+ }
+ else
+ arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
+ remainder = end_cmd;
+ if (remainder == NULL)
+ break;
+ // skip any blanks or tabs to get to next argument
+ while (*remainder == ' ' || *remainder == '\t')
+ remainder++;
+ }
+
+ cmd_type = Command::get_command (cmd, arg_count, cparam);
+
+ // check for extra arguments
+ if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
+ fprintf (stderr, GTXT ("Warning: extra arguments to %s command, line %d\n"),
+ cmd, lineno);
+ switch (cmd_type)
+ {
+ case SOURCE:
+ case DISASM:
+ // ignore any third parameter
+ // if there was, we have written a warning
+ proc_cmd (cmd_type, cparam, arglist[0], arglist[1], NULL, NULL,
+ (inp_file != stdin));
+ break;
+ case QUIT:
+ free (script);
+ free (line);
+ exit (0);
+ case QQUIT:
+ was_QQUIT = true;
+ free (script);
+ free (line);
+ return;
+ case STDIN:
+ break;
+ case COMMENT:
+ fprintf (dis_file, NTXT ("%s"), line);
+ break;
+ case AMBIGUOUS_CMD:
+ fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), cmd);
+ break;
+ case UNKNOWN_CMD:
+ if (*cmd != '\n')
+ fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), cmd);
+ break;
+ default:
+ proc_cmd (cmd_type, cparam, arglist[0], arglist[1]);
+ break;
+ }
+ }
+ // free up the input line
+ free (script);
+ free (line);
+}
+
+void
+er_print::proc_cmd (CmdType cmd_type, int cparam,
+ char *arg1, char *arg2, char *arg3, char *arg4, bool xdefault)
+{
+ er_print_common_display *cd;
+ FILE *ck_file, *save_file;
+ char *name;
+ int bgn_index, end_index, index;
+ Cmd_status status;
+ char *scratch, *scratch1;
+ switch (cmd_type)
+ {
+ case FUNCS:
+ print_func (Histable::FUNCTION, MODE_LIST,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
+ break;
+ case FDETAIL:
+ print_func (Histable::FUNCTION, MODE_DETAIL,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
+ break;
+ case FSINGLE:
+ print_func (Histable::FUNCTION, MODE_DETAIL,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL),
+ arg1, arg2);
+ break;
+ case HOTPCS:
+ print_func (Histable::INSTR, MODE_LIST,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
+ break;
+ case PDETAIL:
+ print_func (Histable::INSTR, MODE_DETAIL,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
+ break;
+ case HOTLINES:
+ print_func (Histable::LINE, MODE_LIST,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
+ break;
+ case LDETAIL:
+ print_func (Histable::LINE, MODE_DETAIL,
+ dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
+ break;
+ case OBJECTS:
+ print_objects ();
+ break;
+ case OVERVIEW_NEW:
+ print_overview ();
+ break;
+ case LOADOBJECT:
+ print_segments ();
+ break;
+ case GPROF:
+ print_func (Histable::FUNCTION, MODE_GPROF,
+ dbev->get_metric_list (MET_CALL), dbev->get_metric_list (MET_NORMAL));
+ break;
+ case CALLTREE:
+ if (dbev->comparingExperiments ())
+ {
+ fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
+ break;
+ }
+ print_ctree (cmd_type);
+ break;
+ case CSINGLE:
+ case CPREPEND:
+ case CAPPEND:
+ case CRMFIRST:
+ case CRMLAST:
+ print_gprof (cmd_type, arg1, arg2);
+ break;
+ case EXP_LIST:
+ exp_list ();
+ break;
+ case DESCRIBE:
+ describe ();
+ break;
+ case SCOMPCOM:
+ status = dbev->proc_compcom (arg1, true, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ break;
+ case STHRESH:
+ status = dbev->proc_thresh (arg1, true, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ break;
+ case DCOMPCOM:
+ status = dbev->proc_compcom (arg1, false, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ break;
+ case COMPCOM:
+ status = dbev->proc_compcom (arg1, true, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ status = dbev->proc_compcom (arg1, false, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ break;
+ case DTHRESH:
+ status = dbev->proc_thresh (arg1, false, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ break;
+ case SOURCE:
+ case DISASM:
+ {
+ if (arg3 != NULL)
+ abort ();
+ if (arg1 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Invalid function/file setting: \n"));
+ break;
+ }
+ char *fcontext = NULL;
+ char *arg = parse_fname (arg1, &fcontext);
+ if (arg == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1);
+ free (fcontext);
+ break;
+ }
+ if (arg2 && (strlen (arg2) == 0))
+ arg2 = NULL;
+ print_anno_file (arg, arg2, fcontext, cmd_type == DISASM,
+ dis_file, inp_file, out_file, dbev, xdefault);
+ free (arg);
+ free (fcontext);
+ break;
+ }
+ case METRIC_LIST:
+ proc_cmd (METRICS, cparam, NULL, NULL);
+ dbev->get_metric_ref (MET_NORMAL)->print_metric_list (dis_file,
+ GTXT ("Available metrics:\n"), false);
+ break;
+ case METRICS:
+ if (arg1)
+ {
+ char *ret = dbev->setMetrics (arg1, false);
+ if (ret != NULL)
+ {
+ fprintf (stderr, GTXT ("Error: %s\n"), ret);
+ proc_cmd (METRIC_LIST, cparam, NULL, NULL);
+ break;
+ }
+ }
+ scratch = dbev->get_metric_list (MET_NORMAL)->get_metrics ();
+ fprintf (dis_file, GTXT ("Current metrics: %s\n"), scratch);
+ free (scratch);
+ proc_cmd (SORT, cparam, NULL, NULL);
+ break;
+ case GMETRIC_LIST:
+ scratch = dbev->get_metric_list (MET_CALL)->get_metrics ();
+ fprintf (dis_file, GTXT ("Current caller-callee metrics: %s\n"), scratch);
+ free (scratch);
+ fprintf (dis_file, GTXT ("Current caller-callee sort Metric: %s\n"),
+ dbev->getSort (MET_DATA));
+ break;
+ case INDX_METRIC_LIST:
+ scratch = dbev->get_metric_list (MET_INDX)->get_metrics ();
+ fprintf (dis_file, GTXT ("Current index-object metrics: %s\n"), scratch);
+ free (scratch);
+ scratch = dbev->getSort (MET_INDX);
+ fprintf (dis_file, GTXT ("Current index-object sort Metric: %s\n"), scratch);
+ free (scratch);
+ break;
+ case SORT:
+ if (arg1)
+ {
+ char *ret = dbev->setSort (arg1, MET_NORMAL, false);
+ if (ret != NULL)
+ {
+ fprintf (stderr, GTXT ("Error: %s\n"), ret);
+ proc_cmd (METRICS, cparam, NULL, NULL);
+ break;
+ }
+ dbev->setSort (arg1, MET_SRCDIS, false);
+ dbev->setSort (arg1, MET_CALL, false);
+ dbev->setSort (arg1, MET_DATA, false);
+ dbev->setSort (arg1, MET_INDX, false);
+ dbev->setSort (arg1, MET_CALL_AGR, false);
+ dbev->setSort (arg1, MET_IO, false);
+ dbev->setSort (arg1, MET_HEAP, false);
+ }
+ scratch = dbev->getSort (MET_NORMAL);
+ scratch1 = dbev->getSortCmd (MET_NORMAL);
+ fprintf (dis_file,
+ GTXT ("Current Sort Metric: %s ( %s )\n"), scratch, scratch1);
+ free (scratch1);
+ free (scratch);
+ break;
+ case OBJECT_SHOW:
+ if (arg1)
+ set_libexpand (arg1, LIBEX_SHOW);
+ obj_list ();
+ break;
+ case OBJECT_HIDE:
+ if (arg1)
+ set_libexpand (arg1, LIBEX_HIDE);
+ obj_list ();
+ break;
+ case OBJECT_API:
+ if (arg1)
+ set_libexpand (arg1, LIBEX_API);
+ obj_list ();
+ break;
+ case OBJECTS_DEFAULT:
+ set_libdefaults ();
+ obj_list ();
+ break;
+ case OBJECT_LIST:
+ obj_list ();
+ break;
+ case OBJECT_SELECT:
+ if (arg1)
+ {
+ if (process_object_select (arg1) != -1)
+ proc_cmd (OBJECT_LIST, cparam, NULL, NULL);
+ else
+ fprintf (stderr, GTXT ("Error: Type \"object_list\" for a list of all load objects.\n"));
+ }
+ else
+ fprintf (stderr, GTXT ("Error: No load object has been specified.\n"));
+ break;
+ case LOADOBJECT_LIST:
+ seg_list ();
+ break;
+ case LOADOBJECT_SELECT:
+ if (arg1)
+ {
+ if (process_object_select (arg1) != -1)
+ proc_cmd (LOADOBJECT_LIST, cparam, NULL, NULL);
+ else
+ fprintf (stderr, GTXT ("Error: Type \"segment_list\" for a list of all segments.\n"));
+ }
+ else
+ fprintf (stderr, GTXT ("Error: No segment has been specified.\n"));
+ break;
+ case SAMPLE_LIST:
+ filter_list (SAMPLE_LIST);
+ break;
+ case SAMPLE_SELECT:
+ if (arg1 && !dbev->set_pattern (SAMPLE_FILTER_IDX, arg1))
+ fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+ proc_cmd (SAMPLE_LIST, cparam, NULL, NULL);
+ break;
+ case THREAD_LIST:
+ filter_list (THREAD_LIST);
+ break;
+ case THREAD_SELECT:
+ if (arg1 && !dbev->set_pattern (THREAD_FILTER_IDX, arg1))
+ fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+ proc_cmd (THREAD_LIST, cparam, NULL, NULL);
+ break;
+ case LWP_LIST:
+ filter_list (LWP_LIST);
+ break;
+ case LWP_SELECT:
+ if (arg1 && !dbev->set_pattern (LWP_FILTER_IDX, arg1))
+ fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+ proc_cmd (LWP_LIST, cparam, NULL, NULL);
+ break;
+ case CPU_LIST:
+ filter_list (CPU_LIST);
+ break;
+ case CPU_SELECT:
+ if (arg1 && !dbev->set_pattern (CPU_FILTER_IDX, arg1))
+ fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+ proc_cmd (CPU_LIST, cparam, NULL, NULL);
+ break;
+ case FILTERS:
+ if (arg1 != NULL)
+ {
+ if (strcmp (arg1, NTXT ("True")) == 0)
+ scratch = dbev->set_filter (NULL);
+ else
+ scratch = dbev->set_filter (arg1);
+ if (scratch != NULL)
+ fprintf (stderr, GTXT ("Error: %s\n"), scratch);
+ }
+ scratch = dbev->get_filter ();
+ fprintf (dis_file, GTXT ("current filter setting: \"%s\"\n"),
+ scratch == NULL ? GTXT ("<none>") : scratch);
+ break;
+ case OUTFILE:
+ if (arg1)
+ {
+ set_outfile (arg1, out_file, false);
+ if (inp_file != stdin)
+ dis_file = out_file;
+ }
+ break;
+ case APPENDFILE:
+ if (arg1)
+ {
+ set_outfile (arg1, out_file, true);
+ if (inp_file != stdin)
+ dis_file = out_file;
+ }
+ break;
+ case LIMIT:
+ if (arg1)
+ {
+ limit = (int) strtol (arg1, (char **) NULL, 10);
+ char *res = dbeSetPrintLimit (dbevindex, limit);
+ if (res != NULL)
+ fprintf (stderr, NTXT ("%s\n"), res);
+ }
+
+ limit = dbeGetPrintLimit (dbevindex);
+ fprintf (stderr, GTXT ("Print limit set to %d\n"), limit);
+ break;
+ case NAMEFMT:
+ if (arg1)
+ {
+ status = dbev->set_name_format (arg1);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ }
+ else
+ fprintf (stderr, GTXT ("Error: No format has been specified.\n"));
+ break;
+ case VIEWMODE:
+ {
+ if (arg1)
+ {
+ status = dbev->set_view_mode (arg1, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ }
+ const char *vname = "unknown";
+ int vm = dbev->get_view_mode ();
+ switch (vm)
+ {
+ case VMODE_USER:
+ vname = "user";
+ break;
+ case VMODE_EXPERT:
+ vname = "expert";
+ break;
+ case VMODE_MACHINE:
+ vname = "machine";
+ break;
+ }
+ fprintf (stderr, GTXT ("Viewmode set to %s\n"), vname);
+ }
+ break;
+
+ // EN_DESC does not make sense after experiments are read, but it does make sense on the command line,
+ // processed before the experiments are read.
+ case EN_DESC:
+ if (arg1)
+ {
+ status = dbev->set_en_desc (arg1, false);
+ if (status != CMD_OK)
+ fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+ }
+ else
+ fprintf (stderr, GTXT ("Error: No descendant processing has been specified.\n"));
+ break;
+ case SETPATH:
+ case ADDPATH:
+ if (arg1)
+ dbeSession->set_search_path (arg1, (cmd_type == SETPATH));
+ fprintf (dis_file, GTXT ("search path:\n"));
+ Vec_loop (char*, dbeSession->get_search_path (), index, name)
+ {
+ fprintf (dis_file, NTXT ("\t%s\n"), name);
+ }
+ break;
+ case PATHMAP:
+ {
+ Vector<pathmap_t*> *pathMaps = dbeSession->get_pathmaps ();
+ if (arg1 != NULL)
+ {
+ if (arg2 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No replacement path prefix has been specified.\n"));
+ break;
+ }
+ // add this mapping to the session
+ char *err = Settings::add_pathmap (pathMaps, arg1, arg2);
+ if (err != NULL)
+ {
+ fprintf (stderr, NTXT ("%s"), err);
+ free (err);
+ }
+ }
+ fprintf (dis_file, GTXT ("Path mappings: from -> to\n"));
+ for (int i = 0, sz = pathMaps->size (); i < sz; i++)
+ {
+ pathmap_t *thismap = pathMaps->get (i);
+ fprintf (dis_file, NTXT ("\t`%s' -> `%s'\n"), thismap->old_prefix, thismap->new_prefix);
+ }
+ }
+ break;
+ case SAMPLE_DETAIL:
+ if (get_exp_id (arg1, bgn_index, end_index) != -1)
+ {
+ cd = new er_print_experiment (dbev, bgn_index, end_index, false,
+ false, false, true, true);
+ print_cmd (cd);
+ delete cd;
+ }
+ break;
+ case STATISTICS:
+ if (get_exp_id (arg1, bgn_index, end_index) != -1)
+ {
+ cd = new er_print_experiment (dbev, bgn_index, end_index, false,
+ false, true, true, false);
+ print_cmd (cd);
+ delete cd;
+ }
+ break;
+ case PRINTMODE:
+ {
+ if (arg1 == NULL)
+ {
+ fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
+ break;
+ }
+ char *s = dbeSetPrintMode (dbevindex, arg1);
+ if (s != NULL)
+ {
+ fprintf (stderr, NTXT ("%s\n"), s);
+ break;
+ }
+ fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
+ }
+ break;
+ case HEADER:
+ if (get_exp_id (arg1, bgn_index, end_index) != -1)
+ {
+ cd = new er_print_experiment (dbev, bgn_index, end_index, false,
+ true, false, false, false);
+ print_cmd (cd);
+ delete cd;
+ }
+ break;
+ case COMPARE:
+ if (arg1 == NULL)
+ {
+ fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
+ break;
+ }
+ else
+ {
+ int cmp;
+ if (strcasecmp (arg1, NTXT ("OFF")) == 0 || strcmp (arg1, NTXT ("0")) == 0)
+ cmp = CMP_DISABLE;
+ else if (strcasecmp (arg1, NTXT ("ON")) == 0 || strcmp (arg1, NTXT ("1")) == 0)
+ cmp = CMP_ENABLE;
+ else if (strcasecmp (arg1, NTXT ("DELTA")) == 0)
+ cmp = CMP_DELTA;
+ else if (strcasecmp (arg1, NTXT ("RATIO")) == 0)
+ cmp = CMP_RATIO;
+ else
+ {
+ fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
+ break;
+ }
+ int oldMode = dbev->get_compare_mode ();
+ dbev->set_compare_mode (cmp);
+ if (oldMode != cmp)
+ {
+ dbev->reset_data (false);
+ dbeSession->reset_data ();
+ }
+ }
+ break;
+ case LEAKS:
+ if (!dbeSession->is_leaklist_available ())
+ {
+ fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ if (dbev->comparingExperiments ())
+ { // XXXX show warning for compare
+ fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
+ break;
+ }
+ cd = new er_print_leaklist (dbev, true, false, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case ALLOCS:
+ if (!dbeSession->is_leaklist_available ())
+ {
+ fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ cd = new er_print_leaklist (dbev, false, true, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case HEAP:
+ if (!dbeSession->is_heapdata_available ())
+ {
+ fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case HEAPSTAT:
+ if (!dbeSession->is_heapdata_available ())
+ {
+ fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, true, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case IOACTIVITY:
+ if (!dbeSession->is_iodata_available ())
+ {
+ fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ if (dbev->comparingExperiments ())
+ { // XXXX show warning for compare
+ fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
+ break;
+ }
+ cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case IOVFD:
+ if (!dbeSession->is_iodata_available ())
+ {
+ fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case IOCALLSTACK:
+ if (!dbeSession->is_iodata_available ())
+ {
+ fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case IOSTAT:
+ if (!dbeSession->is_iodata_available ())
+ {
+ fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, true, dbev->get_limit ());
+ print_cmd (cd);
+ delete cd;
+ break;
+ case HELP:
+ Command::print_help(whoami, false, true, out_file);
+ break;
+ case VERSION_cmd:
+ Application::print_version_info ();
+ break;
+ case SCRIPT:
+ if (arg1)
+ {
+ ck_file = fopen (arg1, NTXT ("r"));
+ if (ck_file == NULL)
+ fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), arg1);
+ else
+ {
+ save_file = inp_file;
+ inp_file = ck_file;
+ proc_script ();
+ inp_file = save_file;
+ }
+ }
+ else
+ fprintf (stderr, GTXT ("Error: No filename has been specified.\n"));
+ break;
+ case QUIT:
+ exit (0);
+ break;
+
+ // commands relating to index Objects
+ case INDXOBJ:
+ if ((cparam == -1) && (arg1 == NULL))
+ {
+ fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
+ break;
+ }
+ // automatically load machine model if applicable
+ dbeDetectLoadMachineModel (dbevindex);
+ indxobj (arg1, cparam);
+ break;
+ case INDXOBJLIST:
+ // automatically load machine model if applicable
+ dbeDetectLoadMachineModel (dbevindex);
+ indxo_list (false, out_file);
+ break;
+
+ // define a new IndexObject type
+ case INDXOBJDEF:
+ if (arg1 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
+ break;
+ }
+ if (arg2 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No index-expr has been specified.\n"));
+ break;
+ }
+ indxo_define (arg1, arg2, arg3, arg4);
+ break;
+
+ // the commands following this are unsupported/hidden
+ case IFREQ:
+ if (!dbeSession->is_ifreq_available ())
+ {
+ fprintf (out_file, GTXT ("\nInstruction frequency data was not requested when recording experiments\n\n"));
+ break;
+ }
+ ifreq ();
+ break;
+ case DUMPNODES:
+ dump_nodes ();
+ break;
+ case DUMPSTACKS:
+ dump_stacks ();
+ break;
+ case DUMPUNK:
+ dump_unk_pcs ();
+ break;
+ case DUMPFUNC:
+ dump_funcs (arg1);
+ break;
+ case DUMPDOBJS:
+ dump_dataobjects (arg1);
+ break;
+ case DUMPMAP:
+ dump_map ();
+ break;
+ case DUMPENTITIES:
+ dump_entities ();
+ break;
+ case DUMP_PROFILE:
+ dbev->dump_profile (out_file);
+ break;
+ case DUMP_SYNC:
+ dbev->dump_sync (out_file);
+ break;
+ case DUMP_HWC:
+ dbev->dump_hwc (out_file);
+ break;
+ case DUMP_HEAP:
+ if (!dbeSession->is_leaklist_available ())
+ {
+ fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ dbev->dump_heap (out_file);
+ break;
+ case DUMP_IOTRACE:
+ if (!dbeSession->is_iodata_available ())
+ {
+ fprintf (out_file, GTXT ("\nI/O trace information was not requested when recording experiments\n\n"));
+ break;
+ }
+ dbev->dump_iotrace (out_file);
+ break;
+ case DMEM:
+ if (arg1 == NULL)
+ fprintf (stderr, GTXT ("Error: No sample has been specified.\n"));
+ else
+ {
+ Experiment *exp = dbeSession->get_exp (0);
+ if (exp != NULL)
+ exp->DBG_memuse (arg1);
+ }
+ break;
+ case DUMP_GC:
+ if (!dbeSession->has_java ())
+ {
+ fprintf (out_file, GTXT ("\nJava garbage collection information was not requested when recording experiments\n\n"));
+ break;
+ }
+ dbev->dump_gc_events (out_file);
+ break;
+ case DKILL:
+ {
+ if (arg1 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No process has been specified.\n"));
+ break;
+ }
+ if (arg2 == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No signal has been specified.\n"));
+ break;
+ }
+ pid_t p = (pid_t) atoi (arg1);
+ int signum = atoi (arg2);
+ char *ret = dbeSendSignal (p, signum);
+ if (ret != NULL)
+ fprintf (stderr, GTXT ("Error: %s"), ret);
+ }
+ break;
+ case PROCSTATS:
+ dump_stats ();
+ break;
+ case ADD_EXP:
+ case OPEN_EXP:
+ if (arg1 == NULL)
+ fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
+ else
+ {
+ Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*>(1);
+ Vector<char*> *list = new Vector<char*>(1);
+ list->append (arg1);
+ groups->append (list);
+ char *res = dbeOpenExperimentList (dbevindex, groups, cmd_type == OPEN_EXP);
+ if (cmd_type == OPEN_EXP)
+ fprintf (stderr, GTXT ("Previously loaded experiment have been dropped.\n"));
+ if (res != NULL)
+ fprintf (stderr, NTXT ("%s"), res);
+ else
+ fprintf (stderr, GTXT ("Experiment %s has been loaded\n"), arg1);
+ free (res);
+ delete list;
+ delete groups;
+ }
+ break;
+ case DROP_EXP:
+ {
+ if (arg1 == NULL)
+ fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
+ else
+ {
+ int exp_index = dbeSession->find_experiment (arg1);
+ if (exp_index < 0)
+ fprintf (stderr, GTXT ("Error: experiment %s has not been opened.\n"), arg1);
+ else
+ {
+ Vector<int> *expid = new Vector<int> (1);
+ expid->append (exp_index);
+ char *res = dbeDropExperiment (dbevindex, expid);
+ if (res != NULL)
+ fprintf (stderr, NTXT ("%s"), res);
+ else
+ fprintf (stderr, GTXT ("Experiment %s has been dropped\n"), arg1);
+ delete expid;
+ free (res);
+ }
+ }
+ }
+ break;
+ case HHELP:
+ // automatically load machine model if applicable
+ dbeDetectLoadMachineModel (dbevindex);
+ Command::print_help (whoami, false, false, out_file);
+ fprintf (out_file, NTXT ("\n"));
+ indxo_list (false, out_file);
+ fprintf (out_file, NTXT ("\n"));
+ mo_list (false, out_file);
+ if (!getenv ("_BUILDING_MANPAGE"))
+ fprintf (out_file, GTXT ("\nSee gprofng(1) for more details\n"));
+ break;
+ case QQUIT:
+ was_QQUIT = true;
+ return;
+ default:
+ fprintf (stderr, GTXT ("Error: Invalid option\n"));
+ break;
+ }
+
+ // check for any processing error messages
+ dump_proc_warnings ();
+ fflush (out_file);
+}
+
+#define MAX_NUM_HEADER 4
+
+void
+er_print::disp_list (int num_header, int size, int align[], char *header[],
+ char **lists[])
+{
+ size_t maxlen[MAX_NUM_HEADER];
+ char fmt[MAX_NUM_HEADER][64];
+ if (num_header > MAX_NUM_HEADER)
+ abort ();
+ for (int i = 0; i < num_header; i++)
+ {
+ maxlen[i] = strlen (header[i]);
+ for (int j = 0; j < size; j++)
+ {
+ size_t len = strlen (lists[i][j]);
+ if (maxlen[i] < len)
+ maxlen[i] = len;
+ }
+
+ // get format string
+ if ((align[i] == -1) && (i == num_header - 1))
+ snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%s "));
+ else
+ snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%%ds "), (int) (align[i] * maxlen[i]));
+
+ // write header
+ fprintf (out_file, fmt[i], header[i]);
+ }
+ putc ('\n', out_file);
+
+ // write separator "==="
+ size_t np = 0;
+ for (int i = 0; (i < num_header) && (np < 132); i++)
+ {
+ size_t nc = maxlen[i];
+ if (nc + np > 132)
+ nc = 132 - np;
+ for (size_t j = 0; j < nc; j++)
+ putc ('=', out_file);
+ putc (' ', out_file);
+ np += nc + 1;
+ }
+ putc ('\n', out_file);
+
+ // write lists
+ for (int j = 0; j < size; j++)
+ {
+ for (int i = 0; i < num_header; i++)
+ fprintf (out_file, fmt[i], lists[i][j]);
+ putc ('\n', out_file);
+ }
+}
+
+void
+er_print::exp_list ()
+{
+ int size, index;
+ int align[MAX_NUM_HEADER];
+ char *header[MAX_NUM_HEADER];
+ char **lists[MAX_NUM_HEADER];
+
+ align[0] = 1; // right-justify
+ align[1] = 1; // right-justify
+ align[2] = 1; // right-justify
+ align[3] = -1; // left-justify
+ header[0] = GTXT ("ID");
+ header[1] = GTXT ("Sel");
+ header[2] = GTXT ("PID");
+ header[3] = GTXT ("Experiment");
+
+ size = dbeSession->nexps ();
+ lists[0] = new char*[size];
+ lists[1] = new char*[size];
+ lists[2] = new char*[size];
+ lists[3] = new char*[size];
+ for (index = 0; index < size; index++)
+ {
+ lists[0][index] = dbe_sprintf (NTXT ("%d"), index + 1);
+ lists[1][index] = strdup (dbev->get_exp_enable (index) ? GTXT ("yes") : GTXT ("no"));
+ lists[2][index] = dbe_sprintf (NTXT ("%d"), dbeSession->get_exp (index)->getPID ());
+ lists[3][index] = strdup (dbeSession->get_exp (index)->get_expt_name ());
+ }
+ disp_list (4, size, align, header, lists);
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < size; j++)
+ free (lists[i][j]);
+ delete[] lists[i];
+ }
+}
+
+void
+er_print::describe ()
+{
+ Vector<void*> *res = dbeGetFilterKeywords (dbev->vindex);
+ if (res == NULL)
+ return;
+ Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+ Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+ Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+ Vector <char*> *kwDescrip = (Vector<char*>*) res->fetch (5);
+ Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+ String sectionFormat = NTXT ("\n------ %s ------\n");
+ String categoryFormat = NTXT ("\n%s\n");
+ String keywordFormat = NTXT (" %-20s %s\n");
+ String empty = NTXT ("");
+ String previousCategory = empty;
+
+ for (int i = 0; i < kwKeyword->size (); i++)
+ {
+ if (kwKeyword->fetch (i) == NULL)
+ {
+ fprintf (dis_file, sectionFormat, kwCategoryI18N->fetch (i));
+ continue;
+ }
+ String cat = kwCategoryI18N->fetch (i);
+ if (dbe_strcmp (previousCategory, cat) != 0)
+ fprintf (dis_file, categoryFormat, cat);
+ previousCategory = cat;
+ Vector <String> *enumDescs = (Vector <String> *) kwEnumDescs->fetch (i);
+ String keyword = kwKeyword->fetch (i);
+ if (kwDescrip->fetch (i) != NULL)
+ {
+ fprintf (dis_file, keywordFormat, keyword, kwDescrip->fetch (i));
+ keyword = empty;
+ }
+ if (kwFormula->fetch (i) != NULL)
+ {
+ fprintf (dis_file, keywordFormat, keyword, kwFormula->fetch (i));
+ keyword = empty;
+ continue;
+ }
+ int numEnums = enumDescs != NULL ? enumDescs->size () : 0;
+ for (int jj = 0; jj < numEnums; jj++)
+ {
+ fprintf (dis_file, keywordFormat, keyword, enumDescs->fetch (jj));
+ keyword = empty;
+ }
+ }
+ destroy (res);
+}
+
+void
+er_print::obj_list ()
+{
+ LoadObject *lo;
+ int index;
+ int align[MAX_NUM_HEADER];
+ char *header[MAX_NUM_HEADER];
+ char **lists[MAX_NUM_HEADER];
+ Vector<LoadObject*> *text_segments = dbeSession->get_text_segments ();
+ if (text_segments->size () == 0)
+ {
+ fprintf (dis_file, GTXT ("There are no load objects in this experiment\n"));
+ return;
+ }
+ align[0] = -1; // left-justify
+ align[1] = -1; // left-justify
+ align[2] = -1; // left-justify
+ align[3] = -1; // left-justify
+ header[0] = GTXT ("Sel");
+ header[1] = GTXT ("Load Object");
+ header[2] = GTXT ("Index");
+ header[3] = GTXT ("Path");
+
+ int size = text_segments->size ();
+ lists[0] = new char*[size];
+ lists[1] = new char*[size];
+ lists[2] = new char*[size];
+ lists[3] = new char*[size];
+
+ char *lo_name;
+ int new_index = 0;
+ Vec_loop (LoadObject*, text_segments, index, lo)
+ {
+ lo_name = lo->get_name ();
+ if (lo_name != NULL)
+ {
+ size_t len = strlen (lo_name);
+ if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+ continue;
+ }
+ LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
+ switch (expand)
+ {
+ case LIBEX_SHOW:
+ lists[0][new_index] = dbe_strdup (GTXT ("show"));
+ break;
+ case LIBEX_HIDE:
+ lists[0][new_index] = dbe_strdup (GTXT ("hide"));
+ break;
+ case LIBEX_API:
+ lists[0][new_index] = dbe_strdup (GTXT ("API-only"));
+ break;
+ }
+ lists[1][new_index] = dbe_strdup (lo_name);
+ lists[2][new_index] = dbe_sprintf (NTXT ("%d"), lo->seg_idx);
+ lists[3][new_index] = dbe_strdup (lo->get_pathname ());
+ new_index++;
+ }
+ disp_list (4, new_index, align, header, lists);
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < new_index; j++)
+ free (lists[i][j]);
+ delete[] lists[i];
+ }
+ delete text_segments;
+}
+
+void
+er_print::seg_list ()
+{
+ LoadObject *lo;
+ int index;
+ int align[MAX_NUM_HEADER];
+ char *header[MAX_NUM_HEADER];
+ char **lists[MAX_NUM_HEADER];
+
+ // XXX seg_list only prints text segments; should extend to all
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ if (lobjs->size () == 0)
+ {
+ fprintf (dis_file, GTXT ("There are no segments in this experiment\n"));
+ return;
+ }
+ align[0] = -1; // left-justify
+ align[1] = 1; // right-justify
+ align[2] = -1; // left-justify
+ header[0] = GTXT ("Sel");
+ header[1] = GTXT ("Size");
+ header[2] = GTXT ("Segment");
+
+ int size = lobjs->size ();
+ lists[0] = new char*[size];
+ lists[1] = new char*[size];
+ lists[2] = new char*[size];
+
+ char *lo_name;
+ int new_index = 0;
+ Vec_loop (LoadObject*, lobjs, index, lo)
+ {
+ lo_name = lo->get_name ();
+ if (lo_name != NULL)
+ {
+ size_t len = strlen (lo_name);
+ if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+ continue;
+ }
+ bool expand = dbev->get_lo_expand (lo->seg_idx);
+ lists[0][new_index] = strdup (expand ? GTXT ("yes") : GTXT ("no"));
+ lists[1][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) lo->get_size ());
+ lists[2][new_index] = strdup (lo->get_pathname ());
+ new_index++;
+ }
+
+ disp_list (3, new_index, align, header, lists);
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < new_index; j++)
+ free (lists[i][j]);
+ delete[] lists[i];
+ }
+ delete lobjs;
+}
+
+void
+er_print::filter_list (CmdType cmd_type)
+{
+ FilterNumeric *select;
+ int index;
+ int align[MAX_NUM_HEADER];
+ char *header[MAX_NUM_HEADER];
+ char **lists[MAX_NUM_HEADER];
+ char *pattern;
+
+ // first ensure that the data has been read
+ MetricList *mlist = dbev->get_metric_list (MET_INDX);
+ Hist_data *data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, 0, Hist_data::ALL);
+ delete data;
+
+ align[0] = 1; // right-justify
+ align[1] = -1; // left-justify
+ align[2] = 1; // right-justify
+ align[3] = 1; // right-justify
+ header[0] = GTXT ("Exp");
+ header[1] = GTXT ("Sel");
+ header[2] = GTXT ("Total");
+ header[3] = GTXT ("Status");
+
+ int size = dbeSession->nexps ();
+ lists[0] = new char*[size];
+ lists[1] = new char*[size];
+ lists[2] = new char*[size];
+ lists[3] = new char*[size];
+ int new_index = 0;
+ for (index = 0; index < size; index++)
+ {
+ switch (cmd_type)
+ {
+ case SAMPLE_LIST:
+ select = dbev->get_FilterNumeric (index, SAMPLE_FILTER_IDX);
+ break;
+ case THREAD_LIST:
+ select = dbev->get_FilterNumeric (index, THREAD_FILTER_IDX);
+ break;
+ case LWP_LIST:
+ select = dbev->get_FilterNumeric (index, LWP_FILTER_IDX);
+ break;
+ case CPU_LIST:
+ select = dbev->get_FilterNumeric (index, CPU_FILTER_IDX);
+ break;
+ default:
+ abort (); // internal error
+ }
+ if (select == NULL)
+ continue;
+ lists[0][new_index] = dbe_sprintf (NTXT ("%d"), index + 1);
+ pattern = dbev->get_exp_enable (index) ? select->get_pattern () : NULL;
+ lists[1][new_index] = strdup (pattern && *pattern ? pattern : GTXT ("none"));
+ lists[2][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) select->nelem ());
+ lists[3][new_index] = select->get_status ();
+ new_index++;
+ }
+ disp_list (3, size, align, header, lists);
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < new_index; j++)
+ free (lists[i][j]);
+ delete[] lists[i];
+ }
+}
+
+int
+er_print::check_exp_id (int exp_id, char *sel)
+{
+ if (exp_id < 0 || exp_id >= dbeSession->nexps ())
+ {
+ fprintf (stderr, GTXT ("Error: Invalid number entered: %s\nType \"exp_list\" for a list of all experiments.\n"),
+ sel);
+ return -1;
+ }
+ return exp_id;
+}
+
+int
+er_print::get_exp_id (char *sel, int &bgn_index, int &end_index)
+{
+ int id, exp_id;
+ if (sel == NULL || strcmp (sel, NTXT ("all")) == 0)
+ {
+ // loop over all experiments
+ bgn_index = 0;
+ end_index = dbeSession->nexps () - 1;
+ }
+ else
+ {
+ id = (int) strtol (sel, (char **) NULL, 10) - 1;
+ exp_id = check_exp_id (id, sel);
+ if (exp_id == -1)
+ return -1;
+ bgn_index = end_index = exp_id;
+ }
+ return 0;
+}
+
+void
+er_print::print_objects ()
+{
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ char *msg = pr_load_objects (lobjs, NTXT (""));
+ delete lobjs;
+ fprintf (out_file, NTXT ("%s\n"), msg);
+ free (msg);
+}
+
+void
+er_print::print_overview ()
+{
+ //fprintf(out_file, NTXT("%s\n"), GTXT("Not implemented yet."));//YXXX
+ Vector<char*> *status = dbeGetOverviewText (dbevindex);
+ StringBuilder sb;
+ sb.append (GTXT ("Experiment(s):\n\n"));
+ for (int i = 0; i < status->size (); i++)
+ sb.appendf (NTXT ("%s\n"), status->fetch (i));
+ sb.append (GTXT ("Metrics:\n"));
+ sb.toFile (out_file);
+
+ Vector<void*> *data = dbeGetRefMetricTree (dbevindex, false);
+ Vector<char *> *metric_cmds = new Vector<char *>();
+ Vector<char *> *non_metric_cmds = new Vector<char *>();
+ print_overview_nodes (data, 0, metric_cmds, non_metric_cmds);
+ Vector<void*> *values = dbeGetRefMetricTreeValues (0, metric_cmds, non_metric_cmds);
+ print_overview_tree (data, 0, values, metric_cmds, non_metric_cmds);
+
+ StringBuilder sb2;
+ sb2.append (GTXT ("\nNotes: '*' indicates hot metrics, '[X]' indicates currently enabled metrics.\n"));
+ sb2.append (GTXT (" The metrics command can be used to change selections. The metric_list command lists all available metrics.\n"));
+ sb2.toFile (out_file);
+}
+
+void
+er_print::print_overview_nodes (Vector<void*> * data, int level, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
+{
+ Vector<void*> *fields = (Vector<void*> *) data->fetch (0);
+ Vector<void*> *children = (Vector<void*> *) data->fetch (1);
+ char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
+ int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
+ bool has_value = ((Vector<bool>*) fields->fetch (10))->fetch (0);
+ bool selectable = (vstyles_capable != 0) ? true : false;
+ if (selectable)
+ metric_cmds->append (name);
+ else if (has_value)
+ non_metric_cmds->append (name);
+
+ level++;
+ for (int i = 0; i < children->size (); i++)
+ print_overview_nodes ((Vector<void*> *)(children->fetch (i)), level, metric_cmds, non_metric_cmds);
+}
+
+void
+er_print::print_overview_tree (Vector<void*> * data, int level, Vector<void*> * values, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
+{
+ Vector<void*> * fields = (Vector<void*> *) data->fetch (0);
+ Vector<void*> * children = (Vector<void*> *) data->fetch (1);
+ char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
+ char *username = ((Vector<char*> *)fields->fetch (1))->fetch (0);
+ int flavors = ((Vector<int>*) fields->fetch (3))->fetch (0); //bitmask e.g. EXCLUSIVE
+ int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
+ // bool aggregation = ((Vector<bool>*) fields->fetch(9))->fetch(0);
+ // bool has_value = ((Vector<bool>*) fields->fetch(10))->fetch(0);
+ char *unit = ((Vector<char*> *) fields->fetch (11))->fetch (0);
+
+ StringBuilder sb;
+ for (int i = 0; i < level * 2; i++)
+ sb.append (NTXT (" ")); // NOI18N
+
+ bool selectable = (vstyles_capable != 0) ? true : false;
+ if (selectable)
+ {
+ bool isSelected = dbev->get_metric_list (MET_NORMAL)->find_metric_by_name (name) == NULL ? false : true;
+ if (isSelected)
+ sb.append (NTXT ("[X]"));
+ else
+ sb.append (NTXT ("[ ]"));
+ }
+ if ((unit != NULL && dbe_strcmp (unit, UNIT_SECONDS) == 0)
+ || (unit == NULL && vstyles_capable & VAL_TIMEVAL))
+ unit = GTXT ("Seconds");
+
+ bool isHiddenInOverview = ((flavors & BaseMetric::STATIC) != 0);
+ if (name != NULL && dbe_strcmp (name, L1_STATIC) == 0)
+ isHiddenInOverview = true;
+ if (!dbeSession->has_java () && name != NULL && dbe_strcmp (name, L1_GCDURATION) == 0)
+ isHiddenInOverview = true;
+ if (isHiddenInOverview)
+ return;
+
+ sb.append (username == NULL ? NTXT ("") : username); // NOI18N
+ int show = 0;
+ if (name == NULL)
+ show = 0;
+ else if (strstr (name, NTXT ("PROFDATA_TYPE_")) == NULL)
+ show = 1;
+
+ if (show)
+ {
+ sb.append (username == NULL ? NTXT ("") : NTXT (" - ")); // NOI18N
+ sb.append (name == NULL ? NTXT ("") : name); // NOI18N
+ }
+
+ // "Bugs 16624403 and 19539622" (leave this string intact for searches)
+ // add an extra condition for now
+ // once we have proper fixes, eliminate test on Bug16624402_extra_condition
+ int Bug16624402_extra_condition = 1;
+ if (username)
+ {
+ if (strcmp (username, NTXT ("Block Covered %")) == 0) Bug16624402_extra_condition = 0;
+ if (strcmp (username, NTXT ("Instr Covered %")) == 0) Bug16624402_extra_condition = 0;
+ }
+ if (Bug16624402_extra_condition > 0 && values->size () > 0)
+ {
+ Vector<void*> * valueColumns = (Vector<void*> *)values->fetch (0);
+ Vector<void*> * highlightColumns = (Vector<void*> *)values->fetch (1);
+ int jj = 0;
+ int found = 0;
+ for (jj = 0; jj < valueColumns->size (); jj++)
+ {
+ const char *value_name = "";
+ if (jj < metric_cmds->size ())
+ value_name = metric_cmds->fetch (jj);
+ else
+ value_name = non_metric_cmds->fetch (jj - metric_cmds->size ());
+ if (dbe_strcmp (value_name, name) != 0)
+ continue;
+ else
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ {
+ Vector<void*> * valueVec = (Vector<void*> *)valueColumns->fetch (jj);
+ Vector<bool> * highlights = (Vector<bool> *)highlightColumns->fetch (jj);
+ for (int kk = 0; kk < valueVec->size (); kk++)
+ {
+ char * value_str;
+ int show_value = 0;
+ switch (valueVec->type ())
+ {
+ case VEC_INTEGER:
+ value_str = dbe_sprintf (NTXT ("%ld"), (long) (((Vector<int> *)valueVec)->fetch (kk)));
+ show_value = 1;
+ break;
+ case VEC_DOUBLE:
+ value_str = dbe_sprintf (NTXT ("%.3f"), (double) (((Vector<double> *)valueVec)->fetch (kk)));
+ show_value = 1;
+ break;
+ case VEC_LLONG:
+ value_str = dbe_sprintf (NTXT ("%lld"), (long long) (((Vector<long> *)valueVec)->fetch (kk)));
+ show_value = 1;
+ break;
+ case VEC_STRING:
+ value_str = NTXT ("");
+ break;
+ default:
+ value_str = NTXT ("");
+ }
+ if (show_value)
+ {
+ if (kk == 0)
+ {
+ sb.append (unit == NULL ? NTXT ("") : NTXT (" ("));
+ sb.append (unit == NULL ? NTXT ("") : unit);
+ sb.append (unit == NULL ? NTXT ("") : NTXT (")"));
+ sb.append (NTXT (":"));
+ }
+ bool highlight = highlights->fetch (kk);
+ const char * hilite = highlight ? NTXT ("*") : NTXT ("");
+ sb.append (NTXT (" ["));
+ sb.append (hilite);
+ sb.append (value_str);
+ sb.append (NTXT ("]"));
+ }
+ }
+ }
+ }
+ sb.append (NTXT ("\n"));
+ sb.toFile (out_file);
+ level++;
+ for (int i = 0; i < children->size (); i++)
+ print_overview_tree ((Vector<void*> *)(children->fetch (i)), level, values, metric_cmds, non_metric_cmds);
+}
+
+void
+er_print::print_segments ()
+{
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ char *msg = pr_load_objects (lobjs, NTXT (""));
+ delete lobjs;
+ fprintf (dis_file, NTXT ("Not implemented yet!\n"));
+ free (msg);
+}
+
+void
+er_print::print_dobj (Print_mode mode, MetricList *mlist1,
+ char *dobj_name, char *sel)
+{
+ Hist_data *hist_data = NULL;
+ char *errstr;
+ er_print_common_display *cd;
+ int list_limit = limit;
+ Histable *sobj = NULL;
+ Dprintf (DEBUG_DATAOBJ, NTXT ("er_print::print_dobj(mode=%d,dobj=%s,sel=%s)\n"),
+ mode, (dobj_name == NULL) ? NTXT ("0") : dobj_name, (sel == NULL) ? NTXT ("0") : sel);
+ char *name = dbev->getSort (MET_DATA);
+ switch (mode)
+ {
+ case MODE_LIST:
+ hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
+ break;
+ case MODE_DETAIL:
+ // if specified, find the dataobject from the name
+ if (dobj_name && strcmp (dobj_name, NTXT ("<All>")))
+ {
+ if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
+ sel, Histable::DOBJECT, (inp_file != stdin)))
+ return;
+ if (sobj == NULL)
+ { // dataobject/segment not found
+ hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
+ if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
+ sel, Histable::DOBJECT, (inp_file != stdin)))
+ return;
+ if (sobj == NULL)
+ { // dataobject/segment not found
+ fprintf (stderr, GTXT ("Error: No dataobject with given name `%s' found.\n"),
+ dobj_name);
+ return;
+ }
+ }
+
+ list_limit = 1;
+ }
+ if (!hist_data)
+ hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
+ break;
+ case MODE_ANNOTATED:
+ hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::LAYOUT);
+ break;
+ default: // MODE_GPROF is not relevant for DataObjects
+ abort ();
+ }
+
+ if (hist_data->get_status () != Hist_data::SUCCESS)
+ {
+ // XXXX is this error message adequate?
+ errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ if (errstr)
+ {
+ fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+ free (errstr);
+ }
+ delete hist_data;
+ return;
+ }
+ cd = (er_print_common_display *) new er_print_histogram (dbev, hist_data,
+ hist_data->get_metric_list (), mode, list_limit, name, sobj, false, false);
+ free (name);
+ print_cmd (cd);
+
+ delete hist_data;
+ delete cd;
+}
+
+void
+er_print::print_func (Histable::Type type, Print_mode mode, MetricList *mlist1,
+ MetricList *mlist2, char *func_name, char *sel)
+{
+ Hist_data *hist_data;
+ Hist_data::HistItem *hitem;
+ int index;
+ char *errstr;
+ int list_limit = limit;
+ Histable *sobj = NULL;
+ MetricList *mlist;
+ StringBuilder sb;
+ char *sname = dbev->getSort (MET_NORMAL);
+ sb.append (sname);
+ free (sname);
+
+ switch (mode)
+ {
+ case MODE_DETAIL:
+ {
+ // The first metric list, mlist1, is only used to pick out the sort
+ // mlist2 is the one used to generate the data
+ char *prevsort = NULL;
+ // if specified, find the function from the function name
+ if (func_name && strcmp (func_name, NTXT ("<All>")))
+ {
+ if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+ sel, Histable::FUNCTION, (inp_file != stdin)) || (sobj == NULL)) &&
+ !dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+ sel, Histable::LOADOBJECT, (inp_file != stdin)))
+ return;
+ if (sobj == NULL)
+ { // function/segment object not found
+ fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
+ func_name);
+ return;
+ }
+ list_limit = 1;
+ }
+ else
+ {
+ // find the sort metric from the reference list
+ prevsort = mlist2->get_sort_cmd ();
+
+ // find the current sort metric from the current list
+ char *cursort = mlist1->get_sort_cmd ();
+
+ // find the corresponding metric in the reference list
+ (void) mlist2->set_sort (cursort, false);
+ free (cursort);
+ // if it fails, nothing is needed
+ }
+ hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
+
+ // restore
+ if (sobj == NULL)
+ {
+ if (prevsort == NULL)
+ abort ();
+ (void) mlist2->set_sort (prevsort, false);
+ }
+ mlist = mlist2;
+ free (prevsort);
+ break;
+ }
+ case MODE_GPROF:
+ // if specified, find the function from the function name
+ if (func_name && strcmp (func_name, NTXT ("<All>")))
+ {
+ if (!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+ sel, Histable::FUNCTION, (inp_file != stdin)))
+ return;
+ if (sobj == NULL)
+ { // function/segment object not found
+ fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
+ func_name);
+ return;
+ }
+ list_limit = 1;
+ sb.setLength (0);
+ }
+ sb.append (GTXT ("\nCallers and callees sorted by metric: "));
+ sname = dbev->getSort (MET_CALL);
+ sb.append (sname);
+ free (sname);
+
+ // Use mlist2 to generate the sort order.
+ // mlist1 is used to generate the data.
+ hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
+ mlist = mlist1;
+ break;
+ default:
+ hist_data = dbev->get_hist_data (mlist1, type, 0, Hist_data::ALL);
+ mlist = mlist1;
+ }
+
+ if (hist_data->get_status () != Hist_data::SUCCESS)
+ {
+ errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+ if (errstr)
+ {
+ fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+ free (errstr);
+ }
+ delete hist_data;
+ return;
+ }
+
+ if (type == Histable::FUNCTION)
+ {
+ for (index = 0; index < hist_data->size (); index++)
+ {
+ hitem = hist_data->fetch (index);
+ if (hitem->obj->get_type () == Histable::FUNCTION)
+ // fetch the name, since that will force a format conversion
+ ((Function *) hitem->obj)->get_name ();
+ }
+ }
+
+ char *name = sb.toString ();
+ er_print_histogram *cd = new er_print_histogram (dbev, hist_data,
+ mlist, mode, list_limit, name, sobj, false, false);
+ print_cmd (cd);
+ delete hist_data;
+ free (name);
+ delete cd;
+}
+
+void
+er_print::print_gprof (CmdType cmd_type, char *func_name, char *sel)
+{
+ Histable *sobj = NULL;
+ if (func_name != NULL)
+ {
+ if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+ sel, Histable::FUNCTION, (inp_file != stdin))
+ || sobj == NULL)
+ && !dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+ sel, Histable::LOADOBJECT, (inp_file != stdin)))
+ return;
+ if (sobj == NULL)
+ { // function/segment object not found
+ fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
+ func_name);
+ return;
+ }
+ }
+ if (cmd_type == CPREPEND)
+ {
+ if (sobj == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
+ return;
+ }
+ cstack->insert (0, sobj);
+ }
+ else if (cmd_type == CAPPEND)
+ {
+ if (sobj == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
+ return;
+ }
+ cstack->append (sobj);
+ }
+ else if (cmd_type == CSINGLE)
+ {
+ if (sobj != NULL)
+ {
+ cstack->reset ();
+ cstack->append (sobj);
+ }
+ else if (cstack->size () == 0)
+ {
+ fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
+ return;
+ }
+ }
+ else if (cmd_type == CRMFIRST)
+ {
+ if (cstack->size () <= 1)
+ {
+ fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
+ return;
+ }
+ cstack->remove (0);
+ }
+ else if (cmd_type == CRMLAST)
+ {
+ if (cstack->size () <= 1)
+ {
+ fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
+ return;
+ }
+ cstack->remove (cstack->size () - 1);
+ }
+
+ er_print_gprof *cd = new er_print_gprof (dbev, cstack);
+ print_cmd (cd);
+ delete cd;
+}
+
+/*
+ * Method print_ctree() prints Functions Call Tree.
+ */
+void
+er_print::print_ctree (CmdType cmd_type)
+{
+ if (cmd_type != CALLTREE)
+ {
+ fprintf (stderr, GTXT ("Error: Invalid command type: %d\n"), cmd_type);
+ return;
+ }
+
+ Histable *sobj = dbeSession->get_Total_Function ();
+ Vector<Histable*> *ctree_cstack = new Vector<Histable*>();
+ ctree_cstack->reset ();
+ er_print_ctree *cd = new er_print_ctree (dbev, ctree_cstack, sobj, limit);
+ print_cmd (cd);
+ delete ctree_cstack;
+ delete cd;
+}
+
+void
+er_print::memobj (char *name, int cparam)
+{
+ int type;
+ if (name != NULL)
+ {
+ // find the memory object index for the name
+ MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
+ if (mot == NULL)
+ {
+ // unknown type, report the error
+ fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
+ return;
+ }
+ type = mot->type;
+ }
+ else
+ {
+ MemObjType_t *mot = MemorySpace::findMemSpaceByIndex (cparam);
+ if (mot == NULL)
+ {
+ // unknown type, report the error
+ fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
+ return;
+ }
+ type = cparam;
+ }
+ dbePrintData (0, DSP_MEMOBJ, type, NULL, NULL, out_file);
+}
+
+void
+er_print::mo_define (char *moname, char *mo_index_exp, char *machmodel, char *short_desc, char *long_desc)
+{
+ char *ret = MemorySpace::mobj_define (moname, mo_index_exp, machmodel, short_desc, long_desc);
+ if (ret != NULL)
+ fprintf (stderr, GTXT ("mobj_define for %s failed: %s\n"), moname, ret);
+}
+
+void
+er_print::mo_list (bool showtab, FILE *outf)
+{
+ Vector<bool> *mtab = NULL;
+ Vector<void*>*res = MemorySpace::getMemObjects ();
+ if (showtab)
+ mtab = dbev->get_MemTabState ();
+ if (res == NULL)
+ // Since we checked already, this is an internal error
+ abort ();
+
+ // unpack the return
+ // Vector<char*> *index = (Vector<int> *)res->fetch(0); // not used
+ Vector<char*> *mo_names = (Vector<char*> *)res->fetch (1);
+ // Vector<char*> *mnemonic = (Vector<char> *)res->fetch(2); // not used
+ Vector<char*> *mo_expr = (Vector<char*> *)res->fetch (3);
+ Vector<char*> *mo_mach_m = (Vector<char*> *)res->fetch (4);
+ // Vector<char*> *tmpOrder = (Vector<int> *)res->fetch(5); // not used
+
+ int size = mo_names->size ();
+ if (size == 0)
+ {
+ if (!getenv ("_BUILDING_MANPAGE"))
+ fprintf (outf, GTXT (" No Memory Object Types Defined\n"));
+ }
+ else
+ {
+ if (!getenv ("_BUILDING_MANPAGE"))
+ fprintf (outf, GTXT (" Memory Object Types Available:\n"));
+ else
+ fprintf (outf, GTXT ("*Memory Object Types*\n"));
+ for (int i = 0; i < size; i++)
+ {
+ if (mtab)
+ fprintf (outf, NTXT (" %c %s\n"), mtab->fetch (i) ? 'T' : 'F',
+ mo_names->fetch (i));
+ else
+ {
+ if (mo_mach_m->fetch (i) != NULL)
+ fprintf (outf, NTXT (" %s\t\t\"%s\"\t\t(machinemodel: %s)\n"),
+ mo_names->fetch (i), mo_expr->fetch (i), mo_mach_m->fetch (i));
+ else
+ fprintf (outf, NTXT (" %s\t\t\"%s\"\n"),
+ mo_names->fetch (i), mo_expr->fetch (i));
+ }
+ }
+ }
+ delete mo_names;
+ delete mo_expr;
+ delete mo_mach_m;
+ delete res;
+}
+
+void
+er_print::indxobj (char *name, int cparam)
+{
+ int type;
+ if (name != NULL)
+ {
+ // find the index object index for the name
+ type = dbeSession->findIndexSpaceByName (name);
+ if (type < 0)
+ {
+ // unknown type, report the error
+ fprintf (stderr, GTXT ("Error: Unknown Index Object type: %s\n"), name);
+ return;
+ }
+ }
+ else
+ {
+ char *indxname = dbeSession->getIndexSpaceName (cparam);
+ if (indxname == NULL)
+ {
+ // unknown type, report the error
+ fprintf (stderr, GTXT ("Error: Unknown Index Object type: %d\n"), cparam);
+ return;
+ }
+ type = cparam;
+ }
+ dbePrintData (0, DSP_INDXOBJ, type, NULL, NULL, out_file);
+}
+
+void
+er_print::indxo_define (char *ioname, char *io_index_exp, char *sdesc, char *ldesc)
+{
+ char *ret = dbeDefineIndxObj (ioname, io_index_exp, sdesc, ldesc);
+ if (ret != NULL)
+ fprintf (stderr, GTXT ("indxobj_define for %s failed: %s\n"), ioname, ret);
+}
+
+void
+er_print::indxo_list (bool showtab, FILE *outf)
+{
+ Vector<bool> *indxtab = NULL;
+ char *name;
+ char *i18n_name;
+ if (!getenv ("_BUILDING_MANPAGE"))
+ fprintf (outf, GTXT (" Index Object Types Available:\n"));
+ else
+ fprintf (outf, GTXT ("*Index Object Types*\n"));
+ Vector<void*>*res = dbeGetIndxObjDescriptions (0);
+ if (showtab)
+ indxtab = dbev->get_IndxTabState ();
+ if (res == NULL) // If none is defined
+ return;
+ Vector<char*> *indxo_names = (Vector<char*> *)res->fetch (1);
+ Vector<char*> *indxo_i18nnames = (Vector<char*> *)res->fetch (3);
+ Vector<char*> *indxo_exprlist = (Vector<char*> *)res->fetch (5);
+ int size = indxo_names->size ();
+ for (int i = 0; i < size; i++)
+ {
+ name = indxo_names->fetch (i);
+ i18n_name = indxo_i18nnames->fetch (i);
+ if (indxtab)
+ {
+ if ((i18n_name != NULL) && (strcmp (i18n_name, name) != 0))
+ fprintf (outf, NTXT (" %c %s (%s)\n"), indxtab->fetch (i) ? 'T' : 'F',
+ i18n_name, name);
+ else
+ fprintf (outf, NTXT (" %c %s\n"), indxtab->fetch (i) ? 'T' : 'F', name);
+ }
+ else
+ {
+ if (i18n_name != NULL && strcmp (i18n_name, indxo_names->fetch (i)) != 0)
+ fprintf (outf, NTXT (" %s (%s)"), i18n_name, name);
+ else
+ fprintf (outf, NTXT (" %s"), name);
+ }
+ char *exprs = indxo_exprlist->fetch (i);
+ if (exprs != NULL)
+ fprintf (outf, NTXT (" \t%s\n"), exprs);
+ else
+ fprintf (outf, NTXT ("\n"));
+ }
+ delete indxo_names;
+ if (showtab)
+ delete res;
+}
+
+void
+er_print::ifreq ()
+{
+ dbev->ifreq (out_file);
+}
+
+void
+er_print::dump_nodes ()
+{
+ dbev->dump_nodes (out_file);
+}
+
+void
+er_print::dump_stacks ()
+{
+ dbeSession->dump_stacks (out_file);
+}
+
+void
+er_print::dump_unk_pcs ()
+{
+ // Dump the nodes associated with the <Unknown> function
+ dbev->get_path_tree ()->dumpNodes (out_file, dbeSession->get_Unknown_Function ());
+
+ // Dump the nodes associated with the <no Java callstack recorded> function
+ Vector<Function *> *matches = dbeSession->match_func_names ("<no Java callstack recorded>", dbev->get_name_format ());
+ if (matches == NULL || matches->size () == 0)
+ fprintf (out_file, GTXT ("No %s functions found\n"), "<no Java callstack recorded>");
+ else
+ {
+ Function *fitem;
+ int index;
+ Vec_loop (Function*, matches, index, fitem)
+ {
+ dbev->get_path_tree ()->dumpNodes (out_file, fitem);
+ }
+ delete matches;
+ }
+}
+
+void
+er_print::dump_funcs (char *arg1)
+{
+ if (arg1 == NULL || strlen (arg1) == 0)
+ dbeSession->dump_segments (out_file);
+ else
+ {
+ Vector<Function *> *matches = dbeSession->match_func_names (arg1, dbev->get_name_format ());
+ if (matches == NULL)
+ {
+ fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
+ return;
+ }
+ fprintf (out_file, GTXT ("%d Function's match `%s'\n"), (int) matches->size (), arg1);
+ Function *fitem;
+ int index;
+ Vec_loop (Function*, matches, index, fitem)
+ {
+ fprintf (out_file, NTXT (" %5lld -- %s (%s) [%s]\n"),
+ (ll_t) fitem->id, fitem->get_name (),
+ (fitem->module ? fitem->module->file_name : NTXT ("<unknown>")),
+ ((fitem->module && fitem->module->loadobject) ?
+ get_basename (fitem->module->loadobject->get_name ()) : NTXT ("<unknown>")));
+ }
+ delete matches;
+ }
+}
+
+void
+er_print::dump_dataobjects (char *arg1)
+{
+ // Force computation of data objects, to update master table; discard it
+ MetricList *mlist1 = dbev->get_metric_list (MET_DATA);
+ Hist_data *data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
+ delete data;
+
+ if (arg1 == NULL || strlen (arg1) == 0)
+ dbeSession->dump_dataobjects (out_file);
+ else
+ {
+ Vector<DataObject *> *matches = dbeSession->match_dobj_names (arg1);
+ if (matches == NULL)
+ {
+ fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
+ return;
+ }
+ fprintf (out_file, GTXT ("%d DataObject's match `%s'\n"), (int) matches->size (), arg1);
+ DataObject *ditem;
+ int index;
+ Vec_loop (DataObject*, matches, index, ditem)
+ {
+ fprintf (out_file, NTXT (" %5lld -- %s\n"), (ll_t) ditem->id, ditem->get_name ());
+ }
+ delete matches;
+ }
+}
+
+void
+er_print::dump_map ()
+{
+ dbeSession->dump_map (out_file);
+}
+
+void
+er_print::dump_entities ()
+{
+ int ent_prop_ids[] = {PROP_THRID, PROP_LWPID, PROP_CPUID, PROP_EXPID, -1};
+
+ // loop over experiments
+ for (int exp_id = 0; exp_id < dbeSession->nexps (); exp_id++)
+ {
+ Experiment *exp = dbeSession->get_exp (exp_id);
+ fprintf (out_file, GTXT ("Experiment %d (%s)\n"),
+ exp_id, exp->get_expt_name ());
+
+ for (int kk = 0; ent_prop_ids[kk] != -1; kk++)
+ {
+ int ent_prop_id = ent_prop_ids[kk];
+ Vector<void*> *elist = dbeGetEntities (0, exp_id, ent_prop_id);
+ if (!elist)
+ continue;
+ Vector<int> *entity_vals = (Vector<int> *) elist->fetch (0);
+ Vector<char*> *jthr_names = (Vector<char*> *)elist->fetch (1);
+ Vector<char*> *jthr_g_names = (Vector<char*> *)elist->fetch (2);
+ Vector<char*> *jthr_p_names = (Vector<char*> *)elist->fetch (3);
+ Vector<char*> *entity_name = (Vector<char*> *)elist->fetch (4);
+ int nent = entity_vals->size ();
+ char *entName = entity_name->fetch (0);
+ if (!entName)
+ entName = NTXT ("<unknown>");
+ fprintf (out_file, GTXT (" %s\n"), entName);
+ for (int i = 0; i < nent; i++)
+ fprintf (out_file, GTXT (" %s=%d: %s, %s, %s\n"),
+ entName, entity_vals->fetch (i),
+ jthr_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"),
+ jthr_g_names->fetch (i) != NULL ? jthr_g_names->fetch (i) : NTXT ("N/A"),
+ jthr_p_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"));
+ destroy (elist);
+ }
+ }
+}
+
+void
+er_print::dump_stats ()
+{
+ Emsg *m = dbev->get_path_tree ()->fetch_stats ();
+ while (m != NULL)
+ {
+ fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
+ m = m->next;
+ }
+ dbev->get_path_tree ()->delete_stats ();
+}
+
+void
+er_print::dump_proc_warnings ()
+{
+ PathTree *p = dbev->get_path_tree ();
+ if (p == NULL)
+ return;
+ Emsg *m = p->fetch_warnings ();
+ while (m != NULL)
+ {
+ fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
+ m = m->next;
+ }
+ dbev->get_path_tree ()->delete_warnings ();
+}
+
+void
+er_print::print_cmd (er_print_common_display *cd)
+{
+ cd->set_out_file (out_file);
+ cd->data_dump ();
+}
+
+FILE *
+er_print::set_outfile (char *cmd, FILE *&set_file, bool append)
+{
+ FILE *new_file;
+ char *home;
+ if (!strcasecmp (cmd, NTXT ("-")))
+ {
+ new_file = stdout;
+ out_fname = NTXT ("<stdout>");
+ }
+ else if (!strcasecmp (cmd, NTXT ("--")))
+ {
+ new_file = stderr;
+ out_fname = NTXT ("<stderr>");
+ }
+ else
+ {
+ char *fname;
+ char *path = NULL;
+ // Handle ~ in file names
+ home = getenv (NTXT ("HOME"));
+ if ((fname = strstr (cmd, NTXT ("~/"))) != NULL && home != NULL)
+ path = dbe_sprintf (NTXT ("%s/%s"), home, fname + 2);
+ else if ((fname = strstr (cmd, NTXT ("~"))) != NULL && home != NULL)
+ path = dbe_sprintf (NTXT ("/home/%s"), fname + 1);
+ else
+ path = strdup (cmd);
+ new_file = fopen (path, append ? NTXT ("a") : NTXT ("w"));
+ if (new_file == NULL)
+ {
+ fprintf (stderr, GTXT ("Error: Unable to open file: %s\n"), cmd);
+ free (path);
+ return NULL;
+ }
+ out_fname = path;
+ }
+ if (set_file && set_file != stdout)
+ fclose (set_file);
+ set_file = new_file;
+ return set_file;
+}
diff --git a/gprofng/src/gp-print.h b/gprofng/src/gp-print.h
new file mode 100644
index 0000000..80c922f
--- /dev/null
+++ b/gprofng/src/gp-print.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _GP_PRINT_H
+#define _ER_PRINT_H
+
+#include "Command.h"
+#include "DbeApplication.h"
+#include "Histable.h"
+#include "Print.h"
+
+void ipc_mainLoop (int argc, char *argv[]);
+
+class DbeView;
+template <class ITEM> class Vector;
+
+// er_print object
+class er_print : public DbeApplication
+{
+public:
+
+ er_print (int argc, char *argv[]);
+ virtual ~er_print ();
+ void start (int argc, char *argv[]);
+ bool free_memory_before_exit ();
+
+private:
+
+ char *error_msg;
+ DbeView *dbev;
+ char *out_fname;
+ FILE *inp_file;
+ FILE *dis_file;
+ FILE *out_file;
+ int dbevindex;
+ char *cov_string;
+ int limit;
+ Vector<Histable*> *cstack;
+ bool was_QQUIT;
+
+ // override methods in base class
+ int check_args (int argc, char *argv[]);
+ void usage ();
+
+ int is_valid_seg_name (char *seg_name, int prev);
+ int cmp_seg_name (char *full_name, char *seg_name);
+ int process_object_select (char *cov);
+ int set_libexpand (char *cov, enum LibExpand expand);
+ int set_libdefaults ();
+
+ bool end_command (char *cmd);
+ void run (int argc, char *argv[]);
+ void proc_script ();
+ void proc_cmd (CmdType cmd_type, int cparam, char *arg1, char *arg2,
+ char *arg3 = NULL, char *arg4 = NULL, bool xdefault = true);
+ void disp_list (int no_header, int size, int align[],
+ char *header[], char **lists[]);
+ void exp_list ();
+ void describe ();
+ void obj_list ();
+ void seg_list ();
+ void print_objects ();
+ void print_overview ();
+ void print_overview_nodes (Vector<void*> *data, int level,
+ Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds);
+ void print_overview_tree (Vector<void*> *data, int level, Vector<void*> *values,
+ Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds);
+ void print_segments ();
+ void filter_list (CmdType cmd_type);
+ int check_exp_id (int exp_id, char *sel);
+ int get_exp_id (char *sel, int &bgn_index, int &end_index);
+ void print_func (Histable::Type type, Print_mode mode,
+ MetricList *mlist1, MetricList *mlist2,
+ char *func_name = NULL, char *sel = NULL);
+ void print_gprof (CmdType cmd_type, char *func_name, char *sel);
+ void print_ctree (CmdType cmd_type);
+ void print_dobj (Print_mode type, MetricList *mlist1,
+ char *dobj_name = NULL, char *sel = NULL);
+ void memobj (char *, int);
+ void mo_list (bool showtab, FILE *outf);
+ void mo_define (char *, char *, char *, char *, char *);
+ void indxobj (char *, int);
+ void indxo_list (bool showtab, FILE *outf);
+ void indxo_define (char *, char *, char *, char *);
+ void ifreq ();
+ void dump_nodes ();
+ void dump_stacks ();
+ void dump_unk_pcs ();
+ void dump_funcs (char *);
+ void dump_dataobjects (char *);
+ void dump_map ();
+ void dump_entities ();
+ void dump_stats ();
+ void dump_proc_warnings ();
+ void send_signal ();
+ void print_cmd (er_print_common_display *);
+ FILE *set_outfile (char *cmd, FILE *&set_file, bool append);
+ void gen_mapfile (char *seg_name, char *cmd);
+};
+
+#endif /* _ER_PRINT_H */
diff --git a/gprofng/src/gprofng.cc b/gprofng/src/gprofng.cc
new file mode 100644
index 0000000..1bf5679
--- /dev/null
+++ b/gprofng/src/gprofng.cc
@@ -0,0 +1,301 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "Application.h"
+#include "i18n.h"
+#include "util.h"
+
+static int verbose = 0;
+
+class Gprofng : Application
+{
+public:
+ Gprofng (int _argc, char *_argv[]);
+ ~Gprofng ();
+ void start();
+ void usage();
+
+private:
+ void exec_cmd(char *tool_name, int argc, char **argv);
+ int argc;
+ char **argv;
+};
+
+int
+main (int argc, char *argv[])
+{
+ Gprofng *gprofng = new Gprofng (argc, argv);
+ gprofng->start();
+ delete gprofng;
+ return 0;
+}
+
+Gprofng::Gprofng (int _argc, char *_argv[]) : Application(_argc, _argv, NULL)
+{
+ argc = _argc;
+ argv = _argv;
+}
+
+Gprofng::~Gprofng () { }
+
+void
+Gprofng::usage ()
+{
+ /*
+ * Isolate the first line because it has an argument.
+ * Otherwise it would be at the end of this long list.
+ */
+ printf ( GTXT (
+ "Usage: %s [OPTION(S)] COMMAND [KEYWORD] [ARGUMENTS]\n"), whoami);
+
+ printf ( GTXT (
+ "\n"
+ "This is the driver for the GPROFNG tools suite to gather and analyze performance data.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --version print the version number and exit.\n"
+ " --help print usage information and exit.\n"
+ " --check verify if the hardware and software environment is supported.\n"
+ " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+ "\n"
+ "Commands:\n"
+ "\n"
+ "The driver supports various commands. These are listed below.\n"
+ "\n"
+ "It is also possible to invoke the lower level commands directly, but since these \n"
+ "are subject to change, in particular the options, we recommend to use the driver.\n"
+ "\n"
+ "The man pages for the commands below can be viewed using the command name with\n"
+ "\"gprofng\" replaced by \"gp\" and the spaces replaced by a dash (\"-\"). For\n"
+ "example the man page name for \"gprofng collect app\" is \"gp-collect-app\".\n"
+ "\n"
+ "The following combination of commands and keywords are supported:\n"
+ "\n"
+ "Collect performance data\n"
+ "\n"
+ " gprofng collect app collect application performance data.\n"
+ "\n"
+ "Display the performance results\n"
+ "\n"
+ " gprofng display text display the performance data in ASCII format.\n"
+ " gprofng display html generate an HTML file from one or more experiments.\n"
+/*
+ " gprofng display gui invoke the GUI to graphically analyze the results.\n"
+*/
+ " gprofng display src display source or disassembly with compiler annotations.\n"
+ "\n"
+ "Miscellaneous commands\n"
+ "\n"
+ " gprofng archive include binaries and source code in an experiment directory.\n"
+ "\n"
+ "Environment:\n"
+ "\n"
+ "The following environment variables are supported:\n"
+ "\n"
+ " GPROFNG_MAX_CALL_STACK_DEPTH set the depth of the call stack (default is 256).\n"
+ "\n"
+ " GPROFNG_USE_JAVA_OPTIONS may be set when profiling a C/C++ application\n"
+ " that uses dlopen() to execute Java code.\n"
+ "\n"
+ " GPROFNG_SSH_REMOTE_DISPLAY use this variable to define the ssh command\n"
+ " executed by the remote display tool.\n"
+ "\n"
+ " GPROFNG_SKIP_VALIDATION set this variable to disable checking hardware,\n"
+ " system, and Java versions.\n"
+ "\n"
+ " GPROFNG_ALLOW_CORE_DUMP set this variable to allow a core file to be\n"
+ " generated; otherwise an error report is created on /tmp.\n"
+ "\n"
+ " GPROFNG_ARCHIVE use this variable to define the settings for automatic\n"
+ " archiving upon experiment recording completion.\n"
+ "\n"
+ " GPROFNG_ARCHIVE_COMMON_DIR set this variable to the location of the common archive.\n"
+ "\n"
+ " GPROFNG_JAVA_MAX_CALL_STACK_DEPTH set the depth of the Java call stack; the default\n"
+ " is 256; set to 0 to disable capturing of call stacks.\n"
+ "\n"
+ " GPROFNG_JAVA_NATIVE_MAX_CALL_STACK_DEPTH set the depth of the Java native call stack;\n"
+ " the default is 256; set to 0 to disable capturing\n"
+ " of call stacks (JNI and assembly call stacks\n"
+ " are not captured).\n"
+ "\n"
+ "Documentation:\n"
+ "\n"
+ "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+ "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+ "should give you access to this document.\n"
+ "\n"
+ "See also:\n"
+ "\n"
+ "gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
+
+/*
+ printf ( GTXT (
+ "Usage: %s [--verbose] [--version] [--help] <tool-name> [<keyword>] <args>\n"
+ "\n%s\n"
+ " archive Archive binaries and sources\n"
+ " collect [app] Collect performance data\n"
+ " display [text] Print an ASCII report\n"
+ " display gui Graphical tool for analyzing an experiment\n"
+ " display html Generate an HTML file from an experiment\n"
+ " display src Print source or dissasembly\n"),
+ whoami, getenv ("_BUILDING_MANPAGE")
+ ? "*Available subcommands*"
+ : "Available Subcommands");
+*/
+}
+
+void
+Gprofng::exec_cmd (char *tool_name, int argc, char **argv)
+{
+ static const struct
+ {
+ const char *tool_name;
+ const char *keyword;
+ const char *app_name;
+ } app_names [] = {
+ { "archive", NULL, "gp-archive"},
+ { "collect", "app", "gp-collect-app"},
+ { "collect", "kernel", "gp-collect-kernel"},
+ { "display", "text", "gp-display-text"},
+ { "display", "gui", "gp-display-gui"},
+ { "display", "html", "gp-display-html"},
+ { "display", "src", "gp-display-src"},
+ { NULL, NULL}
+ };
+
+ const char *keyword = argc > 1 ? argv[1] : "";
+ int first = -1;
+ int find_tool_name = -1;
+ for (int i = 0; app_names[i].tool_name; i++)
+ if (!strcmp (tool_name, app_names[i].tool_name))
+ {
+ if (app_names[i].keyword == NULL)
+ {
+ first = i;
+ break;
+ }
+ if (!strcmp (keyword, app_names[i].keyword))
+ {
+ first = i;
+ argc--;
+ argv++;
+ break;
+ }
+ if (find_tool_name == -1)
+ find_tool_name = i;
+ }
+
+ if (first == -1)
+ {
+ if (find_tool_name == -1)
+ fprintf (stderr, GTXT ("%s: error: keyword '%s' is not supported\n"),
+ get_basename (get_name ()), tool_name);
+ else if (*keyword == 0)
+ fprintf (stderr, GTXT ("%s %s: error: no qualifier\n"),
+ get_basename (get_name ()), tool_name);
+ else
+ fprintf (stderr, GTXT ("%s %s: error: qualifier '%s' is not supported\n"),
+ get_basename (get_name ()), tool_name, keyword);
+ exit (1);
+ }
+
+ const char *aname = app_names[first].app_name;;
+
+ char **arr = (char **) malloc ((argc + 3) * sizeof (char *));
+ int n = 0;
+ char *pname = get_name ();
+ arr[n++] = dbe_sprintf ("%.*s%s", (int) (get_basename (pname) - pname),
+ pname, aname);
+ if (app_names[first].keyword)
+ arr[n++] = dbe_sprintf ("--whoami=%s %s %s", whoami, tool_name,
+ app_names[first].keyword);
+ else
+ arr[n++] = dbe_sprintf ("--whoami=%s %s", whoami, tool_name);
+ for (int i = 1; i < argc; i++)
+ arr[n++] = argv[i];
+ arr[n] = NULL;
+ if (verbose)
+ {
+ printf ("gprofng::exec\n");
+ for (int i = 0; arr[i]; i++)
+ printf ("%5d: %s\n", i, arr[i]);
+ printf("\n");
+ }
+ execv (arr[0], arr);
+
+ // If execv returns, it must have failed.
+ fprintf (stderr, GTXT ("%s failed: %s\n"), arr[0], STR (strerror (errno)));
+ exit(1);
+}
+
+void
+Gprofng::start ()
+{
+ if (argc == 1)
+ {
+ usage ();
+ exit (0);
+ }
+ for (int i = 1; i < argc; i++)
+ {
+ char *s = argv[i];
+ if (*s != '-')
+ {
+ exec_cmd(s, argc - i, argv + i);
+ return;
+ }
+ else if (!strcmp (s, "--help"))
+ {
+ usage ();
+ exit (0);
+ }
+ else if (!strcmp (s, "--version") || !strcmp (s, "-v"))
+ {
+ Application::print_version_info ();
+ exit (0);
+ }
+ else if (!strcmp (s, "--verbose"))
+ verbose = 1;
+ else if (!strcmp (s, "--check"))
+ {
+ fprintf (stderr, GTXT ("%s: error: --check is not implemented yet\n"),
+ get_basename (get_name ()));
+ exit (1);
+ }
+ else
+ {
+ fprintf (stderr, GTXT ("%s: error: unknown option %s\n"),
+ get_basename (get_name ()), s);
+ exit(1);
+ }
+ }
+ fprintf (stderr, GTXT ("%s: error: expected argument after options\n"),
+ get_basename (get_name ()));
+}
diff --git a/gprofng/src/gprofng.h2m b/gprofng/src/gprofng.h2m
new file mode 100644
index 0000000..8786768
--- /dev/null
+++ b/gprofng/src/gprofng.h2m
@@ -0,0 +1,4 @@
+[SEE ALSO]
+
+.B
+\fBgprofng-archive\fR(1), \fBgprofng-collect\fR(1), \fBgprofng-display-text\fR(1), \fBgprofng-display-src\fR(1), \fBgprofng-display-html\fR(1), \fBgprofng-display-gui\fR(1)
diff --git a/gprofng/src/gprofng.rc b/gprofng/src/gprofng.rc
new file mode 100644
index 0000000..3870220
--- /dev/null
+++ b/gprofng/src/gprofng.rc
@@ -0,0 +1,132 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Specify which classes of compiler commentary will be shown
+# with annotated source.
+scc all
+
+# Specify which classes of compiler commentary will be shown
+# with annotated disassembly
+dcc all:src
+
+# Set the default function-list metrics
+# for heap data, show inclusive leaks and bytes leaked; not allocations
+dmetrics i.heapleakbytes:e!heapleakbytes
+dmetrics i.heapleakcnt:e!heapleakcnt
+dmetrics i.heapallocbytes:e!heapallocbytes
+dmetrics i.heapalloccnt:e!heapalloccnt:
+
+# Clock profiling data
+# Note: use same display order of LMS_* in: er.rc, TimelineVariable.java,
+# Ovw_data.h, BaseMetricTreeNode.cc and Experiment.cc metric registration
+dmetrics i!total:e!.total
+# Show total cpu time
+dmetrics ei.totalcpu
+dmetrics i!.user:e!.user
+dmetrics i!system:e!.system
+dmetrics i!trap:e!.trap
+dmetrics i!lock:e!.lock
+dmetrics i!datapfault:e!.datapfault
+dmetrics i!textpfault:e!.textpfault
+dmetrics i!kernelpfault:e!.kernelpfault
+dmetrics i!stop:e!.stop
+dmetrics i!wait:e!.wait
+dmetrics i!sleep:e!.sleep
+
+# for kernel clock profiling data, show inclusive and exclusive KCPU
+dmetrics ei.kcpu
+###dmetrics ie.kcpu
+
+# for count data, show exclusive metrics only
+dmetrics i!bit:e.bit
+
+# for er_generic data, show exclusive metrics only
+dmetrics i!icount:e.icount
+
+# Hide implementation hack. Functionmark column only serves
+# to force zero-count functions to be displayed.
+dmetrics e!bit_FM
+
+# for kernel profiles, show inclusive and exclusive kucycles and kcycles
+# (kucycles and kcycles are for 12.3 and older experiments, Obsolete TBR)
+dmetrics ei.kucycles:ei.kcycles
+###dmetrics ie.kucycles:ie.kcycles
+
+# for derived HWC metrics, show exclusive only
+dmetrics i!IPC:e!.IPC
+dmetrics i!CPI:e!.CPI
+dmetrics i!K_IPC:e!.K_IPC
+dmetrics i!K_CPI:e!.K_CPI
+
+# for HWC, show exclusive only
+dmetrics i!hwc:e.hwc
+
+# for synctrace, show inclusive only
+dmetrics i.sync:e!sync
+dmetrics i.syncn:e!syncn
+
+# Set the default function-list metrics for OMP profiling
+dmetrics i.ompwork:e!ompwork
+dmetrics i.ompwait:e!ompwait
+dmetrics i!.masterthread:e!.masterthread
+
+#set the default function-list metrics for deadlock detection
+dmetrics i!deadlocks:e.deadlocks
+
+# io data
+dmetrics i.ioreadtime:e!ioreadtime
+dmetrics i.iowritetime:e!iowritetime
+dmetrics i.ioothertime:e!ioothertime
+dmetrics i.ioerrortime:e!ioerrortime
+dmetrics i!.ioreadcnt:e!ioreadcnt
+dmetrics i!.ioreadbytes:e!ioreadbytes
+dmetrics i!.iowritecnt:e!iowritecnt
+dmetrics i!.iowritebytes:e!iowritebytes
+dmetrics i!.ioothercnt:e!ioothercnt
+dmetrics i!.ioerrorcnt:e!ioerrorcnt
+
+# for any other unnamed metrics, don't show them
+dmetrics ie!.any
+
+# don't show size or address; show name
+dmetrics !size:!address:name
+
+# Select the default function-list sorting metric
+dsort ei.any:name
+###dsort ie.any:name
+
+# Set function name style
+name long
+
+# Set View mode to user
+viewmode user
+
+# Set compare mode
+compare off
+
+# Set enabling descendants to on
+en_desc on
+
+# Set path where the gprofng libraries are installed
+preload_libdirs ../lib:../lib32:../lib64
+
+# Add search path for annotated source and disasm
+addpath $expts:.
+
+# Add controls for specific load objects
+# object_hide <Unknown>
+
+# version "@(#)er.rc 1.62 11/10/31"
diff --git a/gprofng/src/i18n.cc b/gprofng/src/i18n.cc
new file mode 100644
index 0000000..32c9960
--- /dev/null
+++ b/gprofng/src/i18n.cc
@@ -0,0 +1,30 @@
+/* Copyright (C) 2021 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 "i18n.h"
+
+extern "C"
+void
+init_locale (char *Path) //set up for internationalization
+{
+ bindtextdomain (PACKAGE_NAME, LOCALEDIR);
+ textdomain (PACKAGE_NAME);
+}
diff --git a/gprofng/src/i18n.h b/gprofng/src/i18n.h
new file mode 100644
index 0000000..d02ec0e
--- /dev/null
+++ b/gprofng/src/i18n.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _I18N_H
+#define _I18N_H
+
+#include <libintl.h>
+
+#define GTXT(x) gettext(x) /* x - string literal to be i18n-ed */
+#define PTXT(x) gettext(x) /* x - expression to be i18n-ed */
+#define STXT(x) ((char *) (x)) /* x - static string literal to be i18n-ed */
+#define NTXT(x) ((char *) (x)) /* x - string literal not to be i18n-ed */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ void init_locale (char *Path);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _I18N_H */
diff --git a/gprofng/src/info.h b/gprofng/src/info.h
new file mode 100644
index 0000000..5b05833
--- /dev/null
+++ b/gprofng/src/info.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _INFO_H
+#define _INFO_H
+
+/* Header file for .info section format */
+#include <inttypes.h>
+
+/* The format of the .info section from a single object file is:
+ * Fixed-length info_header
+ * Variable length string padded to a multiple of 4 bytes, giving
+ * the name of the source file from which this contribution comes.
+ * Zero or more entries.
+ *
+ * In an executable, there will be multiple occurrences of the above.
+ * The size of the info section will be a multiple of 4 bytes.
+ */
+
+struct info_header
+{
+ char endian; /* 0 for big, 1 for little */
+ char magic[3]; /* The string "SUN" */
+ uint32_t cnt; /* number of entries for this section */
+ uint16_t len; /* The length of the header, including the string */
+ uint16_t version; /* The version number of this block */
+ uint16_t phase; /* The compiler phase that produced this info */
+ uint16_t spare;
+};
+
+#define PHASE_UNKNOWN 0
+#define PHASE_F77 1
+#define PHASE_CC 2
+#define PHASE_CPLUS 3
+#define PHASE_F95 4
+#define PHASE_IROPT 5
+#define PHASE_MAX 255
+#define F95_COPYINOUT ((PHASE_F95 << 24) | 1)
+
+/* An entry consists of a fixed-size struct entry, possibly followed by
+ * a variable length data structure whose format is determined by the
+ * type of an entry. The size of an entry is a multiple of 4 bytes.
+ */
+
+struct entry_header
+{
+ uint32_t type; /* The type of this entry. High 8 bits is the phase.
+ * Low 24 bits is the type. */
+ uint16_t len; /* length of this entry */
+ uint16_t col; /* Column number in source line */
+ uint32_t msgnum; /* Message number. High 8 bits is the phase.
+ * Low 24 bits is the type. */
+ uint32_t line; /* Line number in source file */
+};
+
+#endif
diff --git a/gprofng/src/ipc.cc b/gprofng/src/ipc.cc
new file mode 100644
index 0000000..932423c
--- /dev/null
+++ b/gprofng/src/ipc.cc
@@ -0,0 +1,2829 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <fcntl.h> // creat
+#include <unistd.h> // sleep
+#include <pthread.h> // pthread_exit
+#include <sys/wait.h> // wait
+#include <locale.h>
+
+#include "DbeApplication.h"
+#include "Histable.h"
+#include "ipcio.h"
+#include "Dbe.h"
+#include "DbeSession.h"
+#include "DbeThread.h"
+#include "DbeView.h"
+
+int ipc_flags = 0;
+IPCTraceLevel ipc_trace_level = TRACE_LVL_0;
+int ipc_single_threaded_mode = 0;
+const char *IPC_PROTOCOL_UNKNOWN = "IPC_PROTOCOL_UNKNOWN";
+const char *IPC_PROTOCOL_CURR = IPC_PROTOCOL_STR;
+char const *ipc_protocol = NULL;
+
+DbeThreadPool *ipcThreadPool;
+
+extern int currentRequestID;
+extern int currentChannelID;
+extern BufferPool *responseBufferPool;
+extern bool cancelNeeded (int);
+extern void reexec ();
+
+/* Simple implementation of support for cancel of open experiment. Since we have only one cancellable
+ operation supported at this moment, we are using just a global variable.
+ As we support more and more cancellable ops we need a more sophisticated data struture such
+ as a mt-safe array to keep track of all cancellable requests/channels and update the supporting
+ routines - setCancellableChannel, cancelNeeded (in ipcio.cc) setCancelRequestedCh */
+int cancellableChannelID = 0xFFFFFFFF;
+int cancelRequestedChannelID;
+
+static const char *table_name (int);
+
+#define VSIZE(v) ((long long) ((v) ? (v)->size() : 0))
+
+inline const char*
+bool2str (bool v)
+{
+ return v ? "true" : "false";
+}
+
+inline char*
+str2str (String v)
+{
+ return (char*) (v ? v : "NULL");
+}
+
+inline char*
+str2s (String v)
+{
+ return (char*) (v ? v : "");
+}
+
+inline DbeView *
+getView (int index)
+{
+ return dbeSession->getView (index);
+}
+
+extern "C"
+{
+ typedef void (*SignalHandler)(int);
+}
+
+/*
+ * Fatal error handlers
+ */
+extern "C" void fatalErrorHadler (int sig, siginfo_t *info, void *context);
+extern "C" void sigSEGV_handler (int sig, siginfo_t *info, void *context);
+extern "C" void sigABRT_handler (int sig, siginfo_t *info, void *context);
+static char fatalErrorBuffer1[1024 * 8];
+static char fatalErrorBuffer2[1024 * 8];
+static int fatalErrorCode = 1;
+static int fatalErrorCounter = 0;
+static void *fatalErrorContext = 0;
+static siginfo_t *fatalErrorInfo = 0;
+static char *fatalErrorDynamicMemory = NULL;
+
+extern "C" void
+fatalErrorHadler (int sig, siginfo_t *info, void *context)
+{
+ if (fatalErrorCounter > 0)
+ { // Need synchronization here
+ //sleep(10); // Wait 10 seconds to make sure previous processing is done
+ return; // exit(fatalErrorCode); // Already in processing
+ }
+ fatalErrorCounter = 1;
+ fatalErrorCode = sig;
+ fatalErrorContext = context;
+ fatalErrorInfo = info;
+ // Free reserved memory
+ if (fatalErrorDynamicMemory != NULL)
+ {
+ free (fatalErrorDynamicMemory);
+ fatalErrorDynamicMemory = NULL;
+ }
+ // Get process ID
+ pid_t pid = getpid ();
+ // Create dump file
+ snprintf (fatalErrorBuffer1, sizeof (fatalErrorBuffer1), "/tmp/analyzer.%lld",
+ (long long) pid);
+ mkdir (fatalErrorBuffer1, 0700);
+ snprintf (fatalErrorBuffer1, sizeof (fatalErrorBuffer1),
+ "/tmp/analyzer.%lld/crash.sig%d.%lld", (long long) pid, sig,
+ (long long) pid);
+ // Dump stack trace in background using pstack
+ snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+ "/usr/bin/pstack %lld > %s.pstack", (long long) pid, fatalErrorBuffer1);
+ system (fatalErrorBuffer2);
+ int fd = creat (fatalErrorBuffer1, 0600);
+ if (fd >= 0)
+ {
+ // Write error message
+ snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+ "A fatal error has been detected by er_print: Signal %lld\n",
+ (long long) sig);
+ write (fd, fatalErrorBuffer2, strlen (fatalErrorBuffer2));
+// snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+// "If you would like to submit a bug report, please use your support contract.\n"));
+// write(fd, fatalErrorBuffer2, strlen(fatalErrorBuffer2));
+ snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+ "Protocol Version: %d\n", IPC_VERSION_NUMBER);
+ write (fd, fatalErrorBuffer2, strlen (fatalErrorBuffer2));
+ close (fd);
+ // Send postmortem error message to the GUI
+ // snprintf(fatalErrorBuffer1, sizeof (fatalErrorBuffer1),
+ // "%s: %s: /tmp/analyzer.%lld",
+ // "Unexpected signal in er_print",
+ // "Crash dump",
+ // (long long) pid);
+ // res = write(2, fatalErrorBuffer2, strlen(fatalErrorBuffer1));
+ }
+ wait (0); // wait for pstack
+ //sleep(10); // Wait 10 seconds to make sure processing of fatal error is done
+ // Exit with correct status
+ exit (fatalErrorCode);
+}
+
+// SIGABRT Handler
+extern "C" void
+sigABRT_handler (int sig, siginfo_t *info, void *context)
+{
+ fatalErrorHadler (sig, info, context);
+ pthread_exit (&fatalErrorCode);
+}
+
+// SIGSEGV Handler
+extern "C" void
+sigSEGV_handler (int sig, siginfo_t *info, void *context)
+{
+ //if (fatalErrorCounter > 0) sleep(1); // Wait 1 second
+ fatalErrorHadler (sig, info, context);
+ pthread_exit (&fatalErrorCode);
+}
+
+// SIGTERM Handler
+extern "C" void sigterm_handler (int sig, siginfo_t *info, void *context);
+struct sigaction old_sigterm_handler;
+
+volatile int term_flag;
+int error_flag;
+
+extern "C" void
+sigterm_handler (int, siginfo_t *, void *)
+{
+ if (fatalErrorCounter > 0)
+ {
+ //sleep(10); // Wait 10 seconds to make sure processing of fatal error is done
+ //return; // Fatal error processing will exit it
+ pthread_exit (&fatalErrorCode);
+ }
+ term_flag = 1;
+}
+
+#define ipc_log ipc_default_log
+#define ipc_request_trace ipc_request_log
+#define ipc_response_trace ipc_response_log
+static const char *ipc_log_name = NULL;
+static const char *ipc_request_log_name = NULL;
+static const char *ipc_response_log_name = NULL;
+FILE *requestLogFileP = stderr;
+FILE *responseLogFileP = stderr;
+hrtime_t begin_time;
+long long delta_time = 0;
+int ipc_delay_microsec = 0;
+
+void
+ipc_default_log (const char *fmt, ...)
+{
+ if (!ipc_log_name || !ipc_flags)
+ return;
+ if (ipc_trace_level >= TRACE_LVL_3)
+ {
+ hrtime_t cur_time = gethrtime ();
+ unsigned long long time_stamp = (cur_time - begin_time) / 1000000 + delta_time;
+ fprintf (stderr, "%7llu: ", time_stamp);
+ }
+ va_list vp;
+ va_start (vp, fmt);
+ vfprintf (stderr, fmt, vp);
+ va_end (vp);
+ fflush (stderr);
+}
+
+extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
+struct sigaction old_sigint_handler;
+
+extern "C" void
+sigint_handler (int, siginfo_t *, void *)
+{
+ ipc_log ("SIGINT signal happens\n");
+}
+
+void
+ipc_request_log (IPCTraceLevel trace_level, const char *fmt, ...)
+{
+ if (!ipc_request_log_name || !ipc_flags || trace_level > ipc_trace_level)
+ return;
+ fprintf (responseLogFileP, "thr: %llu ", (unsigned long long) pthread_self ());
+ if (ipc_trace_level >= TRACE_LVL_3)
+ {
+ hrtime_t cur_time = gethrtime ();
+ unsigned long long time_stamp = (cur_time - begin_time) / 1000000 + delta_time;
+ fprintf (requestLogFileP, "%7llu: ", time_stamp);
+ }
+ va_list vp;
+ va_start (vp, fmt);
+ vfprintf (requestLogFileP, fmt, vp);
+ va_end (vp);
+ fflush (requestLogFileP);
+}
+
+void
+ipc_response_log (IPCTraceLevel trace_level, const char *fmt, ...)
+{
+ if (!ipc_response_log_name || !ipc_flags || trace_level > ipc_trace_level)
+ return;
+ fprintf (responseLogFileP, "thr: %llu ", (unsigned long long) pthread_self ());
+ if (ipc_trace_level >= TRACE_LVL_3)
+ {
+ hrtime_t cur_time = gethrtime ();
+ unsigned long long time_stamp = (cur_time - begin_time) / 1000000 + delta_time;
+ fprintf (responseLogFileP, "%7llu: ", time_stamp);
+ }
+ va_list vp;
+ va_start (vp, fmt);
+ vfprintf (responseLogFileP, fmt, vp);
+ va_end (vp);
+ fflush (responseLogFileP);
+}
+
+#ifdef IPC_LOG
+void
+ipc_dump (char *s, Vector<bool> *v)
+{
+ if (v == NULL)
+ {
+ ipc_log (" Vector<bool> %s is NULL\n", str2s (s));
+ return;
+ }
+ ipc_log (" Vector<bool> %s size=%lld\n", str2s (s), VSIZE (v));
+ for (int i = 0; i < v->size (); i++)
+ ipc_log (" [%d]: %s\n", i, bool2str (v->fetch (i)));
+}
+
+void
+ipc_dump (char *s, Vector<String> *v)
+{
+ if (v == NULL)
+ {
+ ipc_log (" Vector<bool> %s is NULL\n", str2s (s));
+ return;
+ }
+ ipc_log (" Vector<String> %s size=%lld\n", str2s (s), VSIZE (v));
+ for (int i = 0; i < v->size (); i++)
+ {
+ String str = v->fetch (i);
+ ipc_log (" [%d]: '%s'\n", i, str2str (str));
+ }
+}
+
+void
+ipc_dump (char *s, Vector<Obj> *v)
+{
+ if (v == NULL)
+ {
+ ipc_log (" Vector<Obj> %s is NULL\n", str2s (s));
+ return;
+ }
+ ipc_log (" Vector<void *> %s size=%lld\n", str2s (s), VSIZE (v));
+ for (int i = 0; i < v->size (); i++)
+ ipc_log (" [%d]: 0x%08llx\n", i, (long long) (v->fetch (i)));
+}
+
+#else
+#define ipc_dump(s, v)
+#endif
+
+static MetricList *
+readMetricListV2 (int dbevindex, IPCrequest* req)
+{
+ MetricType mtype = (MetricType) readInt (req);
+ Vector<int> *type = (Vector<int>*)readArray (req);
+ Vector<int> *subtype = (Vector<int>*)readArray (req);
+ Vector<bool> *sort = (Vector<bool>*)readArray (req);
+ Vector<int> *vis = (Vector<int>*)readArray (req);
+ Vector<char*> *cmd = (Vector<char*>*)readArray (req);
+ Vector<char*> *expr_spec = (Vector<char*>*)readArray (req);
+ Vector<char*> *legends = (Vector<char*>*)readArray (req);
+ MetricList *mlist = dbeGetMetricListV2 (dbevindex, mtype, type, subtype, sort,
+ vis, cmd, expr_spec, legends);
+ return mlist;
+}
+
+static void
+setCancellableChannel (int chID)
+{
+ cancellableChannelID = chID;
+}
+
+/* Add more entries here for other cancellable operations */
+static void
+checkCancellableOp (char *inp, IPCrequest* req)
+{
+ if (!strcmp (inp, "setFilterStr"))
+ setCancellableChannel (currentChannelID);
+ else if (!strcmp (inp, "openExperimentList"))
+ setCancellableChannel (currentChannelID);
+ else if (!strcmp (inp, "getFiles") || !strcmp (inp, "getFileAttributes"))
+ {
+ setCancellableChannel (currentChannelID);
+ req->setCancelImmediate ();
+ }
+}
+
+/* This is what used to be the core of ipc_mainLoop before asynch ipc.
+ Read the details of the request from the request buffer: name, args etc
+ do the work by calling the appropriate dbe routine(s) and write the
+ response to a response buffer and queue it up in the response queue */
+
+int
+ipc_doWork (void *arg)
+{
+ IPCrequest *req = (IPCrequest *) arg;
+ currentRequestID = req->getRequestID ();
+ currentChannelID = req->getChannelID ();
+ req->setStatus (IN_PROGRESS);
+ String inp = readString (req);
+ if (inp == NULL)
+ {
+ ipc_log ("NULL ipc command received, exiting\n");
+ return 0;
+ }
+ ipc_log ("ipc: %s Req %x Ch %x\n", inp, currentRequestID, currentChannelID);
+ checkCancellableOp (inp, req);
+ if (!strcmp (inp, "initApplication"))
+ {
+ bool nbm = readBoolean (req);
+ String arg1 = readString (req);
+ String arg2 = readString (req);
+ Vector<String> *arg3 = (Vector<String>*)readArray (req);
+ ipc_log (" nbm: %s, arg1: '%s', arg2: '%s'\n", bool2str (nbm), str2str (arg1), str2str (arg2));
+ ipc_dump ("arg3", arg3);
+ // set the session to be interactive
+ dbeSession->set_interactive (true);
+ if (nbm)
+ theApplication->set_name ("analyzer-NBM");
+ else
+ theApplication->set_name ("analyzer");
+
+ // XXX Why does it reset the install directory???? Or a licensing directory???
+ // Vector<String> *res = theDbeApplication->initApplication (arg1, arg2, &setProgress);
+ Vector<String> *res = theDbeApplication->initApplication (NULL, NULL, &setProgress);
+ writeArray (res, req);
+ free (arg1);
+ free (arg2);
+ destroy (arg3);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "syncTime"))
+ {
+ long long anl_time = readLong (req);
+ hrtime_t cur_time = gethrtime ();
+ long long time_stamp = (cur_time - begin_time) / 1000000;
+ delta_time = anl_time - time_stamp;
+ ipc_log (" syncTime %llu %llu \n", anl_time, delta_time);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "getInitMessages"))
+ {
+ Vector<String> *res = dbeGetInitMessages ();
+ ipc_log (" returned = %lld msgs\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "reExec"))
+ {
+ ipc_log (" started reexec()\n");
+ reexec ();
+ }
+ else if (!strcmp (inp, "dbeCreateDirectories"))
+ {
+ String arg1 = readString (req); // path
+ ipc_log (" arg = %s\n", arg1);
+ String res = dbeCreateDirectories (arg1);
+ writeString (res, req);
+ free (arg1);
+ free (res);
+ }
+ else if (!strcmp (inp, "dbeDeleteFile"))
+ {
+ String arg1 = readString (req); // path
+ ipc_log (" arg = %s\n", arg1);
+ String res = dbeDeleteFile (arg1);
+ writeString (res, req);
+ free (arg1);
+ free (res);
+ }
+ else if (!strcmp (inp, "dbeReadFile"))
+ {
+ String arg1 = readString (req);
+ ipc_log (" arg = %s\n", arg1); // path
+ Vector<String> *res = dbeReadFile (arg1);
+ writeArray (res, req);
+ free (arg1);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "dbeWriteFile"))
+ {
+ String arg1 = readString (req); // path
+ String arg2 = readString (req); // contents
+ ipc_log (" arg1 = %s arg2 = %s\n", arg1, arg2);
+ int res = dbeWriteFile (arg1, arg2);
+ writeInt (res, req);
+ free (arg1);
+ }
+ else if (!strcmp (inp, "getExpPreview"))
+ {
+ // XXX add another argument == DbeView index
+ String arg1 = readString (req);
+ ipc_log (" arg = %s\n", arg1);
+ Vector<String> *res = dbeGetExpPreview (0, arg1);
+ writeArray (res, req);
+ free (arg1);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFileAttributes"))
+ {
+ String arg1 = readString (req); // filename
+ String arg2 = readString (req); // format
+ ipc_log (" arg1 = %s arg2 = %s\n", arg1, arg2);
+ String res = dbeGetFileAttributes (arg1, arg2);
+ writeString (res, req);
+ free (arg1);
+ free (arg2);
+ free (res);
+ }
+ else if (!strcmp (inp, "getFiles"))
+ {
+ String arg1 = readString (req); // dirname
+ String arg2 = readString (req); // format
+ ipc_log (" arg1 = %s arg2 = %s\n", arg1, arg2);
+ String res = dbeGetFiles (arg1, arg2);
+ writeString (res, req);
+ free (arg1);
+ free (arg2);
+ free (res);
+ }
+ else if (!strcmp (inp, "getOSFamily"))
+ writeString ("Linux", req);
+ else if (!strcmp (inp, "getRunningProcesses"))
+ {
+ String arg1 = readString (req); // format
+ ipc_log (" arg = %s\n", arg1);
+ String res = dbeGetRunningProcesses (arg1);
+ writeString (res, req);
+ free (arg1);
+ free (res);
+ }
+ else if (!strcmp (inp, "getCurrentDirectory"))
+ {
+ char buf [2048];
+ String res = getcwd (buf, (size_t) sizeof (buf)); // Get current directory
+ writeString (res, req);
+ }
+ else if (!strcmp (inp, "getHomeDirectory"))
+ {
+ String res = getenv ("HOME"); // Get HOME directory
+ writeString (res, req);
+ }
+ else if (!strcmp (inp, "setCurrentDirectory"))
+ {
+ String arg1 = readString (req); // dirname
+ ipc_log (" arg = %s\n", arg1);
+ int res = chdir (arg1); // Change directory
+ writeInt (res, req);
+ free (arg1);
+ }
+ else if (!strcmp (inp, "getLocale"))
+ {
+ String res = setlocale (LC_ALL, ""); // Get locale
+ writeString (res, req);
+ }
+ else if (!strcmp (inp, "setLocale"))
+ {
+ String arg1 = readString (req); // locale
+ ipc_log (" arg = %s\n", arg1);
+ String res = setlocale (LC_ALL, arg1); // Set locale
+ writeString (res, req);
+ free (arg1);
+ }
+ else if (!strcmp (inp, "readRCFile"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req); // file name
+ ipc_log (" arg1=%d, arg2=%s\n", arg1, arg2);
+ String res = dbeReadRCFile (arg1, arg2); // Read RC File
+ writeString (res, req);
+ free (res);
+ }
+ else if (!strcmp (inp, "dbeGetExpParams"))
+ {
+ // XXX add another argument == DbeView index
+ String arg1 = readString (req);
+ ipc_log (" arg = %s\n", arg1);
+ String res = dbeGetExpParams (0, arg1);
+ writeString (res, req);
+ free (arg1);
+ free (res);
+ }
+ else if (!strcmp (inp, "getExperimentsGroups"))
+ {
+ Vector<Vector<char*>*> *groups = dbeGetExperimensGroups ();
+ writeArray (groups, req);
+ destroy (groups);
+ }
+ else if (!strcmp (inp, "setExperimentsGroups"))
+ {
+ Vector<Vector<char*>*> *groups = (Vector<Vector<char*>*> *)readArray (req);
+ ipc_log (" groups.size = %lld\n", VSIZE (groups));
+ char *msg_str = dbeSetExperimentsGroups (groups);
+ writeString (msg_str, req);
+ free (msg_str);
+ destroy (groups);
+ }
+ else if (!strcmp (inp, "dropExperiment"))
+ {
+ int arg1 = readInt (req);
+ Vector<int> *arg2 = (Vector<int>*)readArray (req);
+ ipc_log (" arg = %d, exps = %lld\n", arg1, VSIZE (arg2));
+ char *res = dbeDropExperiment (arg1, arg2);
+ writeString (res, req);
+ free (res);
+ delete arg2;
+ }
+ else if (!strcmp (inp, "getUserExpId"))
+ {
+ Vector<int> *arg = (Vector<int>*)readArray (req);
+ ipc_log (" expIds = %lld\n", VSIZE (arg));
+ Vector<int> *res = dbeGetUserExpId (arg);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getFounderExpId"))
+ {
+ Vector<int> *arg = (Vector<int>*)readArray (req);
+ ipc_log (" expIds = %lld\n", VSIZE (arg));
+ Vector<int> *res = dbeGetFounderExpId (arg);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getExpGroupId"))
+ {
+ Vector<int> *arg = (Vector<int>*)readArray (req);
+ ipc_log (" expIds = %lld\n", VSIZE (arg));
+ Vector<int> *res = dbeGetExpGroupId (arg);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getExpsProperty"))
+ {
+ String arg = readString (req);
+ Vector<String> *res = dbeGetExpsProperty (arg);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getExpName"))
+ {
+ // XXX add argument == DbeView index
+ Vector<String> *res = dbeGetExpName (0);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getExpState"))
+ {
+ // XXX add argument == DbeView index
+ Vector<int> *res = dbeGetExpState (0);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getExpEnable"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" arg1 = %d\n", arg1);
+ Vector<bool> *res = dbeGetExpEnable (arg1);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "setExpEnable"))
+ {
+ int arg1 = readInt (req);
+ Vector<bool> *arg2 = (Vector<bool>*)readArray (req);
+ ipc_log (" arg1=%d\n", arg1);
+ ipc_dump ("arg2", arg2);
+ bool b = dbeSetExpEnable (arg1, arg2);
+ writeBoolean (b, req);
+ ipc_log (" dbeSetExpEnable returns %s\n", bool2str (b));
+ delete arg2;
+ }
+ else if (!strcmp (inp, "getExpInfo"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<String> *res = dbeGetExpInfo (arg1);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getViewModeEnable"))
+ {
+ bool res = dbeGetViewModeEnable ();
+ writeBoolean (res, req);
+ }
+ else if (!strcmp (inp, "getJavaEnable"))
+ {
+ bool res = dbeGetJavaEnable ();
+ writeBoolean (res, req);
+ }
+ else if (!strcmp (inp, "updateNotes"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ String arg4 = readString (req);
+ bool arg5 = readBoolean (req);
+ ipc_log (" args = %d, %d\n", arg1, arg2);
+ int i = dbeUpdateNotes (arg1, arg2, arg3, arg4, arg5);
+ writeInt (i, req);
+ }
+ else if (!strcmp (inp, "getLoadObjectList"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" arg = %d\n", arg1);
+ Vector<void *> *res = dbeGetLoadObjectList (arg1);
+ if (res == NULL)
+ ipc_log (" returning = NULL for LoadObjectList\n");
+ else
+ {
+ Vector<char*> *s = (Vector<char*> *) res->fetch (0);
+ ipc_log (" returning = %lld vectors for %lld LoadObjects\n",
+ VSIZE (res), VSIZE (s));
+ }
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getLoadObjectName"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" arg = %d\n", arg1);
+ Vector<String> *res = dbeGetLoadObjectName (arg1);
+ ipc_log (" returning = %lld strings\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getTabListInfo"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" arg = %d\n", arg1);
+ Vector<void*> *res = dbeGetTabListInfo (arg1);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getSearchPath"))
+ {
+ // XXX add argument == DbeView index
+ ipc_log (" no args\n");
+ Vector<String> *res = dbeGetSearchPath (0);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setSearchPath"))
+ {
+ // XXX add another argument == DbeView index
+ Vector<String> *res = (Vector<String>*)readArray (req);
+ ipc_log (" %lld strings\n", VSIZE (res));
+ dbeSetSearchPath (0, res);
+ writeString (NULL, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getPathmaps"))
+ {
+ Vector<void*> *res = dbeGetPathmaps (0);
+ ipc_log (" returns = %lld objects, number of pathmaps = %lld\n",
+ VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setPathmaps"))
+ {
+ Vector<String> *from = (Vector<String>*)readArray (req);
+ Vector<String> *to = (Vector<String>*)readArray (req);
+ char *res = dbeSetPathmaps (from, to);
+ writeString (res, req);
+ free (res);
+ if (from)
+ {
+ from->destroy ();
+ delete from;
+ }
+ if (to)
+ {
+ to->destroy ();
+ delete to;
+ }
+ }
+ else if (!strcmp (inp, "addPathmap"))
+ {
+ // XXX add another argument == DbeView index
+ String arg1 = readString (req);
+ String arg2 = readString (req);
+ ipc_log (" args = '%s', '%s'\n", arg1 ? arg1 : "NULL", arg2 ? arg2 : "NULL");
+ char *res = dbeAddPathmap (0, arg1, arg2);
+ ipc_log (" returns = '%s'\n", (res != NULL ? res : "NULL"));
+ writeString (res, req);
+ free (arg1);
+ free (arg2);
+ }
+ else if (!strcmp (inp, "getMsg"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" args = %d, %d\n", arg1, arg2);
+ String res = dbeGetMsg (arg1, arg2);
+ ipc_log (" returns = '%s'\n", (res != NULL ? res : "<NULL>"));
+ writeString (res, req);
+ free (res);
+ }
+ else if (!strcmp (inp, "initView"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" new view = %d; clone of view %d\n", arg1, arg2);
+ dbeInitView (arg1, arg2);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "disposeWindow"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ dbeDeleteView (arg1);
+ writeString (NULL, req);
+ }
+#if 0
+ else if (!strcmp (inp, "createMapfile"))
+ {
+ int arg1 = readInt ();
+ String arg2 = readString ();
+ int arg3 = readInt ();
+ ipc_log (" args = %d, %s, %d\n", arg1, arg2, arg3);
+ String res = dbeCreateMapfile (arg1, arg2, arg3);
+ writeString (res);
+ free (arg2);
+ free (res);
+ }
+#endif
+ else if (!strcmp (inp, "setCompareModeV2"))
+ {
+ int dbevindex = readInt (req);
+ int cmp_mode = readInt (req);
+ getView (dbevindex)->set_compare_mode (cmp_mode);
+ writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+ }
+ else if (!strcmp (inp, "getCompareModeV2"))
+ {
+ int dbevindex = readInt (req);
+ int res = CMP_DISABLE;
+ if (dbeSession->expGroups && dbeSession->expGroups->size () > 1)
+ res = getView (dbevindex)->get_compare_mode ();
+ ipc_log (" %s: %d returns %d\n", inp, dbevindex, res);
+ writeInt (res, req);
+ }
+ else if (!strcmp (inp, "getRefMetricsV2"))
+ {
+ Vector<void*> *res = dbeGetRefMetricsV2 ();
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setCurMetricsV2"))
+ {
+ int dbevindex = readInt (req);
+ int cmp_mode = readInt (req);
+ MetricList *mlist = readMetricListV2 (dbevindex, req);
+ getView (dbevindex)->reset_metric_list (mlist, cmp_mode);
+ writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+ }
+ else if (!strcmp (inp, "getCurMetricsV2"))
+ {
+ int arg1 = readInt (req);
+ MetricType arg2 = (MetricType) readInt (req);
+ ipc_log (" args = %d, %d\n", arg1, arg2);
+ Vector<void*> *res = dbeGetCurMetricsV2 (arg1, arg2);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getRefMetricTree"))
+ {
+ int dbevindex = readInt (req);
+ bool include_unregistered = readBoolean (req);
+ ipc_log (" args = %d, %d\n", dbevindex, include_unregistered);
+ Vector<void*> *res = dbeGetRefMetricTree (dbevindex, include_unregistered);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getRefMetricTreeValues"))
+ {
+ int dbevindex = readInt (req);
+ Vector<String> *metcmds = (Vector<String>*)readArray (req);
+ Vector<String> *nonmetcmds = (Vector<String>*)readArray (req);
+ ipc_log (" args = %d, metcmds->size()=%lld, nonmetcmds->size()=%lld\n",
+ dbevindex, VSIZE (metcmds), VSIZE (nonmetcmds));
+ ipc_dump ("metcmds", metcmds);
+ ipc_dump ("nonmetcmds", nonmetcmds);
+ Vector<void*> *res = dbeGetRefMetricTreeValues (dbevindex, metcmds, nonmetcmds);
+#ifdef IPC_LOG
+ if (res != NULL)
+ ipc_log (" returns = %lld objects, length = %lld\n",
+ VSIZE (res), VSIZE (((Vector<int>*)res->fetch (0))));
+ else
+ ipc_log (" returns NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getOverviewText"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<char*> *res = dbeGetOverviewText (arg1);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setSort"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ MetricType arg3 = (MetricType) readInt (req);
+ bool arg4 = readBoolean (req);
+ ipc_log (" args = %d, %d, %d, %c\n", arg1, arg2, arg3, (arg4 ? 'T' : 'F'));
+ dbeSetSort (arg1, arg2, arg3, arg4);
+ writeString (NULL, req);
+ }
+
+ else if (!strcmp (inp, "getAnoValue"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<int> *res = dbeGetAnoValue (arg1);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "setAnoValue"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d, array\n", arg1);
+ Vector<int> *arg2 = (Vector<int>*)readArray (req);
+ dbeSetAnoValue (arg1, arg2);
+ writeString (NULL, req);
+ delete arg2;
+ }
+ else if (!strcmp (inp, "getNameFormat"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ int b = dbeGetNameFormat (arg1);
+ writeInt (b, req);
+ }
+ else if (!strcmp (inp, "getSoName"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ bool b = dbeGetSoName (arg1);
+ writeBoolean (b, req);
+ }
+ else if (!strcmp (inp, "setNameFormat"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ bool arg3 = readBoolean (req);
+ ipc_log (" args = %d, %d, %d\n", arg1, arg2, arg3);
+ dbeSetNameFormat (arg1, arg2, arg3);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "getViewMode"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ int i = dbeGetViewMode (arg1);
+ ipc_log (" returns = %d\n", i);
+ writeInt (i, req);
+ }
+ else if (!strcmp (inp, "setViewMode"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" args = %d, %d\n", arg1, arg2);
+ dbeSetViewMode (arg1, arg2);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "getTLValue"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetTLValue (arg1);
+ ipc_log (" returns = %lld void*'s\n", VSIZE (res));
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "setTLValue"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ String tldata_cmd = readString (req);
+ int entity_prop_id = readInt (req);
+ int align = readInt (req);
+ int depth = readInt (req);
+ dbeSetTLValue (arg1, tldata_cmd, entity_prop_id, align, depth);
+ writeString (NULL, req);
+ free (tldata_cmd);
+ }
+ else if (!strcmp (inp, "getExpFounderDescendants"))
+ {
+ Vector<void*> *res = dbeGetExpFounderDescendants ();
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getExpSelection"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetExpSelection (arg1);
+ writeArray (res, req);
+ destroy (res);
+ }
+
+ else if (!strcmp (inp, "setFilterStr"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ ipc_log (" args = %d, %s\n", arg1, arg2);
+ String res = dbeSetFilterStr (arg1, arg2);
+ ipc_log (" returns = '%s'\n", res ? res : "NULL");
+ writeString (res, req);
+ free (arg2);
+ free (res);
+ }
+
+ else if (!strcmp (inp, "getFilterStr"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ String res = dbeGetFilterStr (arg1);
+ ipc_log (" returns = '%s'\n", res ? res : "NULL");
+ writeString (res, req);
+ free (res);
+ }
+
+ else if (!strcmp (inp, "validateFilterExpression"))
+ {
+ String arg1 = readString (req);
+ int res = dbeValidateFilterExpression (arg1);
+ ipc_log (" validateFilterExpression('%s') returned %d\n", str2str (arg1), res);
+ free (arg1);
+ writeInt (res, req);
+ }
+
+ else if (!strcmp (inp, "getFilterKeywords"))
+ {
+ int dbevindex = readInt (req);
+ Vector<void*>*res = dbeGetFilterKeywords (dbevindex);
+ writeArray (res, req);
+ destroy (res);
+ }
+
+ else if (!strcmp (inp, "getFilters"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" args: view = %d, experiment = %d\n", arg1, arg2);
+ Vector<void*>*res = dbeGetFilters (arg1, arg2);
+ ipc_log (" -- returned %lld Filters\n", VSIZE (res));
+ writeArray (res, req);
+ delete res;
+ }
+
+ else if (!strcmp (inp, "updateFilters"))
+ {
+ int arg1 = readInt (req);
+ Vector<bool> *arg2 = (Vector<bool>*)readArray (req);
+ Vector<String> *arg3 = (Vector<String>*)readArray (req);
+ ipc_log ("arg1=%d arg2->size()=%lld arg3->size()=%lld\n",
+ arg1, VSIZE (arg2), VSIZE (arg3));
+ ipc_dump ("arg2", arg2);
+ ipc_dump ("arg3", arg3);
+ bool b = dbeUpdateFilters (arg1, arg2, arg3);
+ writeBoolean (b, req);
+ ipc_log (" returns %s\n", (b == true ? "true" : "false"));
+ delete arg2;
+ delete arg3;
+ }
+ else if (!strcmp (inp, "getLoadObjectState"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d \n", arg1);
+ Vector<int> *res = dbeGetLoadObjectState (arg1);
+ ipc_log (" returning = %lld int's\n", VSIZE (res));
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "setLoadObjectState"))
+ {
+ int arg1 = readInt (req);
+ Vector<int> *arg2 = (Vector<int>*)readArray (req);
+ ipc_log (" args = %d, %lld objects\n", arg1, VSIZE (arg2));
+ dbeSetLoadObjectState (arg1, arg2);
+ writeString (NULL, req);
+ delete arg2;
+ }
+ else if (!strcmp (inp, "setLoadObjectDefaults"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ dbeSetLoadObjectDefaults (arg1);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "getMemTabSelectionState"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" arg = %d\n", arg1);
+ Vector<bool> *res = dbeGetMemTabSelectionState (arg1);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setMemTabSelectionState"))
+ {
+ int arg1 = readInt (req);
+ Vector<bool> *arg2 = (Vector<bool> *)readArray (req);
+ ipc_log (" args = %d\n arg2 = %lld objects\n", arg1, VSIZE (arg2));
+ dbeSetMemTabSelectionState (arg1, arg2);
+ writeString (NULL, req);
+ destroy (arg2);
+ }
+ else if (!strcmp (inp, "getIndxTabSelectionState"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" arg = %d\n", arg1);
+ Vector<bool> *res = dbeGetIndxTabSelectionState (arg1);
+ ipc_log (" -- returned %lld-vector [bool]\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setIndxTabSelectionState"))
+ {
+ int arg1 = readInt (req);
+ Vector<bool> *arg2 = (Vector<bool> *)readArray (req);
+ ipc_log (" args = %d\n arg2 = %lld objects\n", arg1, VSIZE (arg2));
+ dbeSetIndxTabSelectionState (arg1, arg2);
+ writeString (NULL, req);
+ destroy (arg2);
+ }
+ else if (!strcmp (inp, "getTabSelectionState"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<bool> *res = dbeGetTabSelectionState (arg1);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "setTabSelectionState"))
+ {
+ int arg1 = readInt (req);
+ Vector<bool> *arg2 = (Vector<bool>*)readArray (req);
+ ipc_log (" args = %d\n arg2 = %lld objects\n", arg1, VSIZE (arg2));
+ dbeSetTabSelectionState (arg1, arg2);
+ writeString (NULL, req);
+ delete arg2;
+ }
+ else if (!strcmp (inp, "getMemObjects"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetMemObjects (arg1);
+
+#ifdef IPC_LOG
+ if (res == NULL)
+ ipc_log (" -- returned NULL\n");
+ else
+ {
+ Vector<int> *mo_types = (Vector<int> *)res->fetch (0);
+ ipc_log (" -- returned %lld-vector [ %lld-vectors]\n",
+ VSIZE (res), VSIZE (mo_types));
+ }
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "loadMachineModel"))
+ {
+ String arg1 = readString (req);
+#ifdef IPC_LOG
+ ipc_log (" arg = `%s'\n", arg1);
+#endif
+ String sts = dbeLoadMachineModel (arg1);
+#ifdef IPC_LOG
+ ipc_log (" returns '%s'\n", sts ? sts : "NULL");
+#endif
+ writeString (sts, req);
+ free (arg1);
+ }
+ else if (!strcmp (inp, "getMachineModel"))
+ {
+ String sts = dbeGetMachineModel ();
+#ifdef IPC_LOG
+ ipc_log (" returns '%s'\n", sts ? sts : "NULL");
+#endif
+ writeString (sts, req);
+ }
+ else if (!strcmp (inp, "getCPUVerMachineModel"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<char*> *res = dbeGetCPUVerMachineModel (arg1);
+ writeArray (res, req);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "listMachineModels"))
+ {
+ Vector<String> *res = dbeListMachineModels ();
+#ifdef IPC_LOG
+ if (res != NULL)
+ ipc_log (" returns = %lld strings\n", VSIZE (res));
+ else
+ ipc_log (" returns NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "defineMemObj"))
+ {
+ String arg1 = readString (req);
+ String arg2 = readString (req);
+ String arg3 = readString (req);
+ String arg4 = readString (req);
+#ifdef IPC_LOG
+ ipc_log (" args = %s, %s, %s, %s\n", arg1, arg2, arg3 == NULL ? "NULL" : arg3, arg4 == NULL ? "NULL" : arg4);
+#endif
+ String sts = dbeDefineMemObj (arg1, arg2, NULL, arg3, arg4);
+#ifdef IPC_LOG
+ ipc_log (" returns '%s'\n", sts ? sts : "NULL");
+#endif
+ writeString (sts, req);
+ free (arg1);
+ free (arg2);
+ free (arg3);
+ free (arg4);
+ }
+ else if (!strcmp (inp, "deleteMemObj"))
+ {
+ String arg1 = readString (req);
+#ifdef IPC_LOG
+ ipc_log (" args = %s\n", arg1);
+#endif
+ String sts = dbeDeleteMemObj (arg1);
+#ifdef IPC_LOG
+ ipc_log (" returns '%s'\n", sts ? sts : "NULL");
+#endif
+ writeString (sts, req);
+ free (arg1);
+ }
+ else if (!strcmp (inp, "getIndxObjDescriptions"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetIndxObjDescriptions (arg1);
+#ifdef IPC_LOG
+ if (res == NULL)
+ ipc_log (" -- returned NULL\n");
+ else
+ {
+ Vector<int> *indxo_types = (Vector<int> *)res->fetch (0);
+ ipc_log (" -- returned %lld-vector [ %lld-vectors]\n",
+ VSIZE (res), VSIZE (indxo_types));
+ }
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCustomIndxObjects"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetCustomIndxObjects (arg1);
+#ifdef IPC_LOG
+ if (res == NULL)
+ ipc_log (" -- returned NULL\n");
+ else
+ {
+ Vector<char *> *indxo_names = (Vector<char *> *)res->fetch (0);
+ ipc_log (" -- returned %lld-vector [ %lld-vectors]\n",
+ VSIZE (res), VSIZE (indxo_names));
+ }
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "defineIndxObj"))
+ {
+ String arg1 = readString (req);
+ String arg2 = readString (req);
+ String arg3 = readString (req);
+ String arg4 = readString (req);
+ ipc_log (" args = %s, %s, %s, %s\n", arg1, arg2, arg3 == NULL ? "NULL" : arg3, arg4 == NULL ? "NULL" : arg4);
+ String sts = dbeDefineIndxObj (arg1, arg2, arg3, arg4);
+ ipc_log (" returns '%s'\n", sts ? sts : "NULL");
+ writeString (sts, req);
+ free (arg1);
+ free (arg2);
+ free (arg3);
+ free (arg4);
+ }
+ else if (!strcmp (inp, "setSelObj"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ int arg3 = readInt (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, %ld, %s, %d\n", arg1, (long) arg2, table_name (arg3), arg4);
+ dbeSetSelObj (arg1, arg2, arg3, arg4);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "setSelObjV2"))
+ {
+ int arg1 = readInt (req);
+ uint64_t arg2 = readLong (req);
+ ipc_log (" args = %d, %ld\n", arg1, arg2);
+ dbeSetSelObjV2 (arg1, arg2);
+ writeString (NULL, req);
+ }
+ else if (!strcmp (inp, "getSelObj"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+ Obj i = dbeGetSelObj (arg1, arg2, arg3);
+ ipc_log (" returns = %ld (0x%08lx)\n", (long) i, (long) i);
+ writeObject (i, req);
+ }
+ else if (!strcmp (inp, "getSelObjV2"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ ipc_log (" arg1 = %d agr2 = %s\n", arg1, arg2 ? arg2 : "NULL");
+ Obj res = dbeGetSelObjV2 (arg1, arg2);
+ ipc_log (" returns = %lld\n", (long long) res);
+ writeObject (res, req);
+ free (arg2);
+ }
+ else if (!strcmp (inp, "getSelObjIO"))
+ {
+ int arg1 = readInt (req);
+ uint64_t arg2 = readLong (req);
+ int arg3 = readInt (req);
+ ipc_log (" arg1 = %d, arg2 = %lld, arg3 = %d\n", arg1, (long long) arg2, arg3);
+ Vector<uint64_t> *res = dbeGetSelObjIO (arg1, arg2, arg3);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getSelObjsIO"))
+ {
+ int arg1 = readInt (req);
+ Vector<uint64_t> *arg2 = (Vector<uint64_t>*)readArray (req);
+ int arg3 = readInt (req);
+ ipc_log (" arg1 = %d, arg2 size = %lld, arg3 = %d\n",
+ arg1, VSIZE (arg2), arg3);
+ Vector<uint64_t> *res = dbeGetSelObjsIO (arg1, arg2, arg3);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getSelObjHeapTimestamp"))
+ {
+ int arg1 = readInt (req);
+ uint64_t arg2 = readLong (req);
+ ipc_log (" arg1 = %d, arg2 = %llu\n", arg1, (unsigned long long) arg2);
+ uint64_t st = dbeGetSelObjHeapTimestamp (arg1, arg2);
+ ipc_log (" returns = %llu\n", (unsigned long long) st);
+ writeLong (st, req);
+ }
+ else if (!strcmp (inp, "getSelObjHeapUserExpId"))
+ {
+ int arg1 = readInt (req);
+ uint64_t arg2 = readLong (req);
+ ipc_log (" arg1 = %d, arg2 = %llu\n", arg1, (unsigned long long) arg2);
+ int userExpId = dbeGetSelObjHeapUserExpId (arg1, arg2);
+ ipc_log (" returns = %d\n", userExpId);
+ writeInt (userExpId, req);
+ }
+ else if (!strcmp (inp, "getSelIndex"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ int arg3 = readInt (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, 0x%08lx, %s, %d\n", arg1, (long) arg2, table_name (arg3), arg4);
+ int i = dbeGetSelIndex (arg1, arg2, arg3, arg4);
+ ipc_log (" returns = %d\n", i);
+ writeInt (i, req);
+ }
+ else if (!strcmp (inp, "printData"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ String arg4 = readString (req);
+ String arg5 = readString (req);
+ ipc_log (" args = %d, %s, %d, `%s', `%s'\n",
+ arg1, table_name (arg2), arg3,
+ (arg4 == NULL ? "NULL" : arg4),
+ (arg5 == NULL ? "NULL" : arg5));
+ String res = dbePrintData (arg1, arg2, arg3, arg4, arg5, NULL);
+ writeString (res, req);
+ free (arg4);
+ free (arg5);
+ free (res);
+ }
+ else if (!strcmp (inp, "getPrintLimit"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ int i = dbeGetPrintLimit (arg1);
+ ipc_log (" returns = %d\n", i);
+ writeInt (i, req);
+ }
+ else if (!strcmp (inp, "setPrintLimit"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" args = %d, %d\n", arg1, arg2);
+ String res = dbeSetPrintLimit (arg1, arg2);
+ writeString (res, req);
+ free (res);
+ }
+ else if (!strcmp (inp, "getPrintMode"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ int i = dbeGetPrintMode (arg1);
+ ipc_log (" returns = %d\n", i);
+ writeInt (i, req);
+ }
+ else if (!strcmp (inp, "setPrintMode"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ ipc_log (" args = %d, %s\n", arg1, arg2);
+ String res = dbeSetPrintMode (arg1, arg2);
+ writeString (res, req);
+ free (arg2);
+ free (res);
+ }
+ else if (!strcmp (inp, "getPrintDelim"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ char i = dbeGetPrintDelim (arg1);
+ ipc_log (" returns = %c\n", i);
+ writeInt ((int) i, req);
+ }
+ else if (!strcmp (inp, "getHotMarks"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" args = %d, %s (%d) \n", arg1, table_name (arg2), arg2);
+ Vector<void*> *res = dbeGetHotMarks (arg1, arg2);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getHotMarksInc"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" args = %d, %s (%d) \n", arg1, table_name (arg2), arg2);
+ Vector<void*> *res = dbeGetHotMarksInc (arg1, arg2);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getSummaryHotMarks"))
+ {
+ int arg1 = readInt (req);
+ Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, 0x%llx, %s (%d)\n", arg1, (long long) arg2, table_name (arg3), arg3);
+ Vector<void*> *res = dbeGetSummaryHotMarks (arg1, arg2, arg3);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncId"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, %s, %d, %d\n", arg1, table_name (arg2), arg3, arg4);
+ Vector<uint64_t> *res = dbeGetFuncId (arg1, arg2, arg3, arg4);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getFuncCalleeInfo"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ Vector<int> *arg3 = (Vector<int>*)readArray (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, %s, %lld, %d\n", arg1, table_name (arg2), VSIZE (arg3), arg4);
+ Vector<void*> *res = dbeGetFuncCalleeInfo (arg1, arg2, arg3, arg4);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncCallerInfo"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ Vector<int> *arg3 = (Vector<int>*)readArray (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, %s, %lld, %d\n", arg1, table_name (arg2), VSIZE (arg3), arg4);
+ Vector<void*> *res = dbeGetFuncCallerInfo (arg1, arg2, arg3, arg4);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setFuncData"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ int arg3 = readInt (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, %ld, %s, %d\n", arg1, (long) arg2, table_name (arg3), arg4);
+ int i = dbeSetFuncData (arg1, arg2, arg3, arg4);
+ ipc_log (" returns = %d\n", i);
+ writeInt (i, req);
+ }
+ else if (!strcmp (inp, "setFuncDataV2"))
+ {
+ int dbevindex = readInt (req);
+ Obj sel_obj = readObject (req);
+ int type = readInt (req);
+ int subtype = readInt (req);
+ Vector<long long> *longs = new Vector<long long>(2);
+ Vector<char *> *strings = new Vector<char *>(2);
+
+ longs->append (dbeSetFuncData (dbevindex, sel_obj, type, subtype));
+ strings->append (dbeGetMsg (dbevindex, ERROR_MSG));
+ String sf_name = NULL;
+ long long sf_id = 0;
+ switch (type)
+ {
+ case DSP_SOURCE:
+ case DSP_DISASM:
+ {
+ Histable *obj = (Histable *) sel_obj;
+ if (obj)
+ {
+ Histable *sf = obj->convertto (Histable::SOURCEFILE);
+ if (sf)
+ {
+ sf_id = sf->id;
+ sf_name = dbe_strdup (sf->get_name ());
+ }
+ }
+ break;
+ }
+ }
+ longs->append (sf_id);
+ strings->append (sf_name);
+ ipc_log (" setFuncData(%d, %ld, %s, %d) returns (%lld, %lld)\n (%s, %s)\n",
+ dbevindex, (long) sel_obj, table_name (type), subtype, longs->get (0), longs->get (1),
+ STR (strings->get (0)), STR (strings->get (1)));
+
+ Vector<void *> *res = new Vector<void *>(2);
+ res->append (longs);
+ res->append (strings);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncList"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+ Vector<void*> *res = dbeGetFuncList (arg1, arg2, arg3);
+#ifdef IPC_LOG
+ if (res != NULL)
+ ipc_log (" returns = %lld objects, length = %lld\n",
+ VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+ else
+ ipc_log (" returns NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncListV2"))
+ {
+ int dbevindex = readInt (req);
+ int mtype = readInt (req);
+ Obj sel_obj = readObject (req);
+ int type = readInt (req);
+ int subtype = readInt (req);
+ Vector<void*> *res = dbeGetFuncListV2 (dbevindex, mtype, sel_obj, type, subtype);
+ ipc_log (" args = %d 0x%x %ld, %s, %d returns = %d objects, length = %d\n",
+ dbevindex, mtype, (long) sel_obj, table_name (type), subtype,
+ (int) (res ? res->size () : 0),
+ (int) (res ? ((Vector<int>*)res->fetch (0))->size () : 0));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncListMini"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+ Vector<void*> *res = dbeGetFuncListMini (arg1, arg2, arg3);
+#ifdef IPC_LOG
+ if (res != NULL)
+ ipc_log (" returns = %lld objects, length = %lld\n",
+ VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+ else
+ ipc_log (" returns NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "dbeGetTotals"))
+ {
+ int dbevindex = readInt (req);
+ int dsptype = readInt (req);
+ int subtype = readInt (req);
+ Vector<void *> *res = dbeGetTotals (dbevindex, dsptype, subtype);
+ ipc_log (" dbeGetTotals(%d, %d, %d) returns %lld objects\n",
+ dbevindex, dsptype, subtype, VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getComparableObjsV2"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ int arg3 = readInt (req);
+ Vector<Obj> *res = dbeGetComparableObjsV2 (arg1, arg2, arg3);
+ ipc_log (" args = %d 0x%lx %d\n", arg1, (long) arg2, arg3);
+ ipc_dump ("getComparableObjsV2:res", res);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "dbeConvertSelObj"))
+ {
+ Obj obj = readObject (req);
+ int type = readInt (req);
+ Obj res = dbeConvertSelObj (obj, type);
+ ipc_log (" args = %lld %d res=%lld \n", (long long) obj, type,
+ (long long) res);
+ writeObject (res, req);
+ }
+ else if (!strcmp (inp, "getTableDataV2"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ String arg3 = readString (req);
+ String arg4 = readString (req);
+ String arg5 = readString (req);
+ Vector<uint64_t> *arg6 = (Vector<uint64_t>*)readArray (req);
+ ipc_log (" args = %d, %s, %s, %s, %s, %lld\n", arg1, STR (arg2),
+ STR (arg3), STR (arg4), STR (arg5), VSIZE (arg6));
+ Vector<void*> *res = dbeGetTableDataV2 (arg1, arg2, arg3, arg4, arg5, arg6);
+#ifdef IPC_LOG
+ if (res != NULL)
+ ipc_log (" returns = %lld objects, length = %lld\n",
+ VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+ else
+ ipc_log (" returns NULL\n");
+#endif
+ writeArray (res, req);
+ //destroy( arg6 );
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCallTreeNumLevels"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ int res = dbeGetCallTreeNumLevels (arg1);
+#ifdef IPC_LOG
+ ipc_log (" returns = %d\n", res);
+#endif
+ writeInt (res, req);
+ }
+ else if (!strcmp (inp, "getCallTreeLevel"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %s, %d\n", arg1, arg2, arg3);
+ Vector<void*> *res = dbeGetCallTreeLevel (arg1, arg2, arg3);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCallTreeChildren"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ Vector<int> *arg3 = (Vector<int> *) readArray (req); /*NodeIdx array*/
+ ipc_log (" args = %d, %s, vec_size=%lld\n", arg1, arg2, (long long) (arg3 ? arg3->size () : 0));
+ Vector<void*> *res = dbeGetCallTreeChildren (arg1, arg2, arg3);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCallTreeLevels"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ ipc_log (" args = %d, %s\n", arg1, arg2);
+ Vector<void*> *res = dbeGetCallTreeLevels (arg1, arg2);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCallTreeLevelFuncs"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %d, %d\n", arg1, arg2, arg3);
+ Vector<void*> *res = dbeGetCallTreeLevelFuncs (arg1, arg2, arg3);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCallTreeFuncs"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetCallTreeFuncs (arg1);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getGroupIds"))
+ {
+ int arg1 = readInt (req);
+ Vector<int> *res = dbeGetGroupIds (arg1);
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getNames"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ Obj arg3 = readObject (req);
+#ifdef IPC_LOG
+ ipc_log (" args = %d, %s 0x%lx\n", arg1, table_name (arg2), (long) arg3);
+#endif
+ Vector<String> *res = dbeGetNames (arg1, arg2, arg3);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getTotalMax"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+ Vector<void*> *res = dbeGetTotalMax (arg1, arg2, arg3);
+#ifdef IPC_LOG
+ if (res != NULL)
+ ipc_log (" returns = %lld vectors, length %lld\n",
+ VSIZE (res), VSIZE ((Vector<void*>*)res->fetch (0)));
+ else
+ ipc_log (" returns NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "composeFilterClause"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ Vector<int> *arg4 = (Vector<int>*)readArray (req);
+ ipc_log (" args = %d, %s, %d, %lld selections\n",
+ arg1, table_name (arg2), arg3, VSIZE (arg4));
+ String s = dbeComposeFilterClause (arg1, arg2, arg3, arg4);
+ ipc_log (" returns %s\n", (s == NULL ? "<NULL>" : s));
+ writeString (s, req);
+ }
+ else if (!strcmp (inp, "getStatisOverviewList"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<Object> *res = dbeGetStatisOverviewList (arg1);
+ ipc_log (" dbeStatisGetOverviewList returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getStatisList"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<Object> *res = dbeGetStatisList (arg1);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getSummary"))
+ {
+ int arg1 = readInt (req);
+ Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+ int arg3 = readInt (req);
+ int arg4 = readInt (req);
+ ipc_log (" args = %d, 0x%llx, %s (%d), %d\n", arg1, (long long) arg2, table_name (arg3), arg3, arg4);
+ Vector<Object> *res = dbeGetSummary (arg1, arg2, arg3, arg4);
+ ipc_log (" dbeGetSummary returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getSummaryV2"))
+ {
+ int dbevindex = readInt (req);
+ Vector<Obj> *sel_objs = (Vector<Obj>*)readArray (req);
+ int type = readInt (req);
+ int subtype = readInt (req);
+ Vector<void*> *res = dbeGetSummaryV2 (dbevindex, sel_objs, type, subtype);
+ ipc_log (" args = %d, [%lld], %s (%d), %d res=[%lld] 0x%llx \n",
+ dbevindex, VSIZE (sel_objs), table_name (type), type, subtype,
+ VSIZE (res), (unsigned long long) res);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getExpName1"))
+ {
+ // XXX add an argument = DbeView index
+ String arg1 = readString (req);
+ ipc_log (" arg = `%s'\n", arg1 ? arg1 : "NULL");
+ String res = dbeGetExpName (0, arg1);
+ writeString (res, req);
+ ipc_log (" returns `%s'\n", res ? res : "NULL");
+ free (arg1);
+ free (res);
+ }
+ else if (!strcmp (inp, "getHwcHelp"))
+ {
+ // XXX add an argument = DbeView index
+ bool forKernel = readBoolean (req);
+ Vector<String> *res = dbeGetHwcHelp (0, forKernel);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getHwcSets"))
+ {
+ // XXX add an argument = DbeView index
+ bool forKernel = readBoolean (req);
+ Vector<Vector<char*>*> *res = dbeGetHwcSets (0, forKernel);
+ writeArray (res, req);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getHwcsAll"))
+ {
+ // XXX add an argument = DbeView index
+ bool forKernel = readBoolean (req);
+ Vector<void*> *res = dbeGetHwcsAll (0, forKernel);
+ writeArray (res, req);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getHwcAttrList"))
+ {
+ // XXX add an argument = DbeView index
+ bool forKernel = readBoolean (req);
+ Vector<char*> *res = dbeGetHwcAttrList (0, forKernel);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getHwcMaxConcurrent"))
+ {
+ // XXX add an argument = DbeView index
+ bool forKernel = readBoolean (req);
+ int res = dbeGetHwcMaxConcurrent (0, forKernel);
+ writeInt (res, req);
+ }
+ else if (!strcmp (inp, "getIfreqData"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<char*> *res = dbeGetIfreqData (arg1);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getNewLeakListInfo"))
+ {
+ int arg1 = readInt (req);
+ bool arg2 = readBoolean (req);
+ ipc_log (" args = %d, %d\n", arg1, arg2);
+ Vector<void*> *res = dbeGetLeakListInfo (arg1, arg2);
+ ipc_log (" returns %lld void*'s\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getObject"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ Obj arg3 = readObject (req);
+ Obj i = dbeGetObject (arg1, arg2, arg3);
+ writeObject (i, req);
+ }
+ else if (!strcmp (inp, "getExpVerboseName"))
+ {
+ Vector<int> *arg = (Vector<int>*)readArray (req);
+ ipc_log (" expIds = %lld\n", VSIZE (arg));
+ Vector<String> *res = dbeGetExpVerboseName (arg);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getName"))
+ {
+ // XXX add an argument = DbeView index
+ int arg1 = readInt (req);
+ String res = dbeGetName (0, arg1);
+ writeString (res, req);
+ free (res);
+ }
+ else if (!strcmp (inp, "getStartTime"))
+ {
+ // XXX add an argument = DbeView index
+ int arg1 = readInt (req);
+ long long l = dbeGetStartTime (0, arg1);
+ ipc_log (" returns = %llu\n", l);
+ writeLong (l, req);
+ }
+ else if (!strcmp (inp, "getRelativeStartTime"))
+ {
+ // XXX add an argument = DbeView index
+ int arg1 = readInt (req);
+ long long l = dbeGetRelativeStartTime (0, arg1);
+ ipc_log (" returns = %llu\n", l);
+ writeLong (l, req);
+ }
+ else if (!strcmp (inp, "getEndTime"))
+ {
+ // XXX add an argument = DbeView index
+ int arg1 = readInt (req);
+ long long l = dbeGetEndTime (0, arg1);
+ ipc_log (" returns = %llu\n", l);
+ writeLong (l, req);
+ }
+ else if (!strcmp (inp, "getClock"))
+ {
+ // XXX add an argument = DbeView index
+ int arg1 = readInt (req);
+ int i = dbeGetClock (0, arg1);
+ writeInt (i, req);
+ }
+ /*
+ else if ( !strcmp( inp, "getFounderExpId" ) ) {
+ // XXX add an argument = DbeView index
+ int arg1 = readInt(req);
+ int i = dbeGetFounderExpId(0, arg1 );
+ writeInt( i, req );
+ }
+ */
+ else if (!strcmp (inp, "getEntityProps"))
+ {
+ int arg1 = readInt (req);
+ ipc_log (" args = %d\n", arg1);
+ Vector<void*> *res = dbeGetEntityProps (arg1);
+ writeArray (res, req);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getEntities"))
+ {
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %d, %d\n", arg1, arg2, arg3);
+ Vector<void*> *res = dbeGetEntities (arg1, arg2, arg3);
+ writeArray (res, req);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getEntitiesV2"))
+ {
+ int arg1 = readInt (req);
+ Vector<int> *arg2 = (Vector<int>*)readArray (req);
+ int arg3 = readInt (req);
+ ipc_log (" args = %d, %lld, %d\n", arg1, VSIZE (arg2), arg3);
+ Vector<void*> *res = dbeGetEntitiesV2 (arg1, arg2, arg3);
+ writeArray (res, req);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getTLDetails"))
+ {//TBR
+ int arg1 = readInt (req);
+ int arg2 = readInt (req);
+ int arg3 = readInt (req);
+ int arg4 = readInt (req);
+ long long arg5 = readLong (req);
+ ipc_log (" dbevindex= %d, exp_id = %d, data_id = %d, "
+ "entity_prop_id = %d, event_id = %lld\n",
+ arg1, arg2, arg3, arg4, arg5);
+ Vector<void*> *res = dbeGetTLDetails (arg1, arg2, arg3, arg4, arg5);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getStackNames"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ ipc_log (" args = %d, %ld\n", arg1, (long) arg2);
+ Vector<String> *res = dbeGetStackNames (arg1, arg2);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getStackFunctions"))
+ {
+ // XXX add an argument = DbeView index
+ Obj arg1 = readObject (req);
+ ipc_log (" args = %ld\n", (long) arg1);
+ Vector<Obj> *res = dbeGetStackFunctions (0, arg1);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getStacksFunctions"))
+ {
+ // XXX add an argument = DbeView index
+ Vector<Obj> *arg1 = (Vector<Obj>*)readArray (req);
+ ipc_log (" argc = %ld\n", (long) arg1->size ());
+ Vector<void*> *res = dbeGetStacksFunctions (0, arg1);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getStackPCs"))
+ {
+ // XXX add an argument = DbeView index
+ Obj arg1 = readObject (req);
+ ipc_log (" args = %ld\n", (long) arg1);
+ Vector<Obj> *res = dbeGetStackPCs (0, arg1);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ delete res;
+ }
+ else if (!strcmp (inp, "getIOStatistics"))
+ {
+ int dbevindex = readInt (req);
+ Vector<Vector<char*>*> *res = dbeGetIOStatistics (dbevindex);
+ writeArray (res, req);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getHeapStatistics"))
+ {
+ int dbevindex = readInt (req);
+ Vector<Vector<char*>*> *res = dbeGetHeapStatistics (dbevindex);
+ writeArray (res, req);
+ ipc_log (" returns %lld char*'s\n", VSIZE (res));
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getSamples"))
+ {
+ int dbev_id = readInt (req);
+ int exp_id = readInt (req);
+ int64_t lo = readLong (req);
+ int64_t hi = readLong (req);
+ ipc_log (" dbevindex= %d, exp_id = %d, lo_idx:%lld, hi_idx:%lld\n",
+ dbev_id, exp_id, (long long) lo, (long long) hi);
+ Vector<void*> *res = dbeGetSamples (dbev_id, exp_id, lo, hi);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getGCEvents"))
+ {
+ int dbev_id = readInt (req);
+ int exp_id = readInt (req);
+ int64_t lo = readLong (req);
+ int64_t hi = readLong (req);
+ ipc_log (" dbevindex= %d, exp_id = %d, lo_idx:%lld, hi_idx:%lld\n",
+ dbev_id, exp_id, (long long) lo, (long long) hi);
+ Vector<void*> *res = dbeGetGCEvents (dbev_id, exp_id, lo, hi);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncNames"))
+ {
+ int arg1 = readInt (req);
+ Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+ ipc_log (" arg1 = %d, arg2 absent, size = %lld\n", arg1, VSIZE (arg2));
+ Vector<String> *res = dbeGetFuncNames (arg1, arg2);
+ writeArray (res, req);
+ delete arg2;
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncIds"))
+ {
+ int arg1 = readInt (req);
+ Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+ ipc_log (" arg1 = %d, arg2 absent, size = %lld\n", arg1, VSIZE (arg2));
+ Vector<uint64_t> *res = dbeGetFuncIds (arg1, arg2);
+ writeArray (res, req);
+ delete arg2;
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getObjNamesV2"))
+ {
+ int arg1 = readInt (req);
+ Vector<uint64_t> *arg2 = (Vector<uint64_t>*)readArray (req);
+ ipc_log (" arg1 = %d, arg2 absent, size = %lld\n", arg1, VSIZE (arg2));
+ Vector<String> *res = dbeGetObjNamesV2 (arg1, arg2);
+ writeArray (res, req);
+ delete arg2;
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getFuncName"))
+ {
+ int arg1 = readInt (req);
+ Obj arg2 = readObject (req);
+ ipc_log (" arg1 = %d, arg2 = %lld\n", arg1, (long long) arg2);
+ String res = dbeGetFuncName (arg1, arg2);
+ ipc_log (" returning = %s\n", res ? res : "NULL");
+ writeString (res, req);
+ free (res);
+ }
+ else if (!strcmp (inp, "getObjNameV2"))
+ {
+ int arg1 = readInt (req);
+ uint64_t arg2 = readLong (req);
+ ipc_log (" arg1 = %d, arg2 = %llu\n", arg1, (unsigned long long) arg2);
+ String res = dbeGetObjNameV2 (arg1, arg2);
+ ipc_log (" returning = %s\n", res ? res : "NULL");
+ writeString (res, req);
+ free (res);
+ }
+ else if (!strcmp (inp, "getDataspaceTypeDesc"))
+ {
+ // XXX add an argument = DbeView index
+ Obj arg1 = readObject (req);
+ ipc_log (" arg1 absent, index = %ld\n", (long) arg1);
+ String res = dbeGetDataspaceTypeDesc (0, arg1);
+ ipc_log (" returning = %s\n", res ? res : "NULL");
+ writeString (res, req);
+ free (res);
+ }
+ /*
+ * New Interface with Timeline
+ */
+#if 0 //YXXX TBR
+ else if (!strcmp (inp, "dbeInit"))
+ dbeInit ();
+ else if (!strcmp (inp, "getDefaultExperimentName"))
+ {
+ String res = dbeGetDefaultExperimentName ();
+ ipc_log (" returning = %s\n", res);
+ writeString (res);
+ free (res);
+ }
+ else if (!strcmp (inp, "getExperimentState"))
+ {
+ String res = dbeGetExperimentState ();
+ ipc_log (" returning = %s\n", res);
+ writeString (res);
+ free (res);
+ }
+ else if (!strcmp (inp, "getExpStartTime"))
+ {
+ long long l = dbeGetExpStartTime ();
+ ipc_log (" returns = %llu\n", l);
+ writeLong (l);
+ }
+ else if (!strcmp (inp, "getExpEndTime"))
+ {
+ long long l = dbeGetExpEndTime ();
+ ipc_log (" returns = %llu\n", l);
+ writeLong (l);
+ }
+#endif
+ else if (!strcmp (inp, "getDataDescriptorsV2"))
+ {//TBR? TBD
+ int exp_id = readInt (req);
+ ipc_log (" exp_id = %d\n", exp_id);
+ Vector<void*> *res = dbeGetDataDescriptorsV2 (exp_id);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getDataPropertiesV2"))
+ {//TBR? TBD
+ int exp_id = readInt (req);
+ int arg2 = readInt (req);
+ ipc_log (" exp_id = %d, data_idx = %d\n", exp_id, arg2);
+ Vector<void*> *res = dbeGetDataPropertiesV2 (exp_id, arg2);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getExperimentTimeInfo"))
+ {
+ Vector<int> *exp_ids = (Vector<int>*)readArray (req);
+ ipc_log (" cnt = %lld\n", VSIZE (exp_ids));
+ Vector<void*> *res = dbeGetExperimentTimeInfo (exp_ids);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getExperimentDataDescriptors"))
+ {
+ Vector<int> *exp_ids = (Vector<int>*)readArray (req);
+ ipc_log (" cnt = %lld\n", VSIZE (exp_ids));
+ Vector<void*> *res = dbeGetExperimentDataDescriptors (exp_ids);
+ ipc_log (" returns = %lld objects\n", VSIZE (res));
+ writeArray (res, req);
+ destroy (res);
+ }
+#if 0 //YXXX TBR?
+ else if (!strcmp (inp, "getExprValues"))
+ {//TBR? TBD
+ int arg1 = readInt ();
+ String arg2 = readString ();
+ ipc_log (" data_idx = %d expr = %s\n", arg1, arg2 ? arg2 : "NULL");
+ Vector<long long> *res = dbeGetExprValues (arg1, arg2);
+ ipc_log (" returns = %d objects\n", res ? res->size () : 0);
+ writeArray (res);
+ delete res;
+ free (arg2);
+ }
+#endif
+ else if (!strcmp (inp, "hasTLData"))
+ {
+ int dbevindex = readInt (req);
+ Vector<int> *exp_ids = (Vector<int>*)readArray (req);
+ Vector<int> *data_ids = (Vector<int>*)readArray (req);
+ Vector<int> *eprop_ids = (Vector<int>*)readArray (req);
+ Vector<int> *eprop_vals = (Vector<int>*)readArray (req);
+ Vector<int> *auxs = (Vector<int>*)readArray (req);
+ ipc_log (" dbev_id = %d, cnt = %lld\n", dbevindex, VSIZE (exp_ids));
+ Vector<bool> *res = dbeHasTLData (dbevindex,
+ exp_ids, data_ids, eprop_ids, eprop_vals, auxs);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getTLData"))
+ {
+ int dbevindex = readInt (req);
+ int exp_id = readInt (req);
+ int tldata_type = readInt (req);
+ int entity_prop_id = readInt (req);
+ int entity_prop_val = readInt (req);
+ int aux = readInt (req);
+ long long arg5 = readLong (req);
+ long long arg6 = readLong (req);
+ int arg7 = readInt (req);
+ bool getReps = readBoolean (req);
+ Vector<String> *secondaryProps = (Vector<String>*)readArray (req);
+
+ ipc_log (" args = %d:%d; tldata_type=%d entity_prop_id=%d ent=%d aux=%d"
+ "\n tstart=%lld delta=%lld ndeltas=%d getReps=%d nProps=%lld\n",
+ dbevindex, exp_id,
+ tldata_type, entity_prop_id, entity_prop_val, aux,
+ arg5, arg6, arg7, (int) getReps, VSIZE (secondaryProps));
+ Vector<void*> *res = dbeGetTLData (dbevindex, exp_id,
+ tldata_type, entity_prop_id, entity_prop_val, aux,
+ arg5, arg6, arg7, getReps, secondaryProps);
+#ifdef IPC_LOG
+ if (res)
+ {
+ Vector<Obj> *reps = (Vector<Obj>*)res->fetch (0);
+ Vector<Obj> *props = (Vector<Obj>*)res->fetch (1);
+ if (reps)
+ {
+ Vector <long long> *fids = (Vector <long long> *)reps->fetch (2);
+ int sz = fids ? fids->size () : 0;
+ ipc_log (" returning TL reps (dDscrs); nreps=%d:", sz);
+ int i;
+ for (i = 0; i < sz && i < 7; i++)
+ ipc_log (" %lld", fids->fetch (i));
+ if (i < sz)
+ ipc_log (" ... %lld", fids->fetch (sz - 1));
+ ipc_log ("\n");
+ }
+ if (props)
+ {
+ int nprops = props->size ();
+ ipc_log (" returning values for %d properties:\n", nprops);
+ assert (secondaryProps->size () == nprops);
+ }
+ }
+ else
+ ipc_log (" returning NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ destroy (secondaryProps);
+ }
+ else if (!strcmp (inp, "getTLEventCenterTime"))
+ {
+ int dbevindex = readInt (req);
+ int exp_id = readInt (req);
+ int tldata_type = readInt (req);
+ int entity_prop_id = readInt (req);
+ int entity_prop_val = readInt (req);
+ int aux = readInt (req);
+ long long event_id = readLong (req);
+ long long move_count = readLong (req);
+ ipc_log (" args = %d:%d; tldata_type = %d entity_prop_id = %d "
+ "ent = %d aux = %d idx = %lld move=%lld\n",
+ dbevindex, exp_id,
+ tldata_type, entity_prop_id, entity_prop_val, aux, event_id, move_count);
+ Vector<long long> * res = dbeGetTLEventCenterTime (dbevindex, exp_id,
+ tldata_type, entity_prop_id, entity_prop_val, aux, event_id, move_count);
+ ipc_log (" returning idx = %lld, time = %lld\n",
+ res ? res->fetch (0) : -1, res ? res->fetch (1) : -1);
+ writeArray (res, req);
+ }
+ else if (!strcmp (inp, "getTLEventIdxNearTime"))
+ {
+ int dbevindex = readInt (req);
+ int exp_id = readInt (req);
+ int tldata_type = readInt (req);
+ int entity_prop_id = readInt (req);
+ int entity_prop_val = readInt (req);
+ int aux = readInt (req);
+ int searchDirection = readInt (req);
+ long long value = readLong (req);
+ ipc_log (" args = %d:%d; tldata_type = %d entity_prop_id = %d "
+ "ent = %d aux = %d direction = %d value = %lld(0x%llx)\n",
+ dbevindex, exp_id,
+ tldata_type, entity_prop_id, entity_prop_val, aux,
+ searchDirection, value, value);
+ long long res = dbeGetTLEventIdxNearTime (dbevindex, exp_id,
+ tldata_type, entity_prop_id, entity_prop_val, aux,
+ searchDirection, value);
+ ipc_log (" returning = %lld\n", res);
+ writeLong (res, req);
+ }
+ else if (!strcmp (inp, "getAggregatedValue"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ String arg3 = readString (req);
+ String arg4 = readString (req);
+ long long arg5 = readLong (req);
+ long long arg6 = readLong (req);
+ int arg7 = readInt (req);
+ String arg8 = readString (req);
+ String arg9 = readString (req);
+ ipc_log (" data_idx = %d lfilter = \"%s\" fexpr = \"%s\" "
+ "time = \"%s\" tstart = %lld delta = %lld "
+ "num = %d key = \"%s\" aggr = \"%s\"\n",
+ arg1, arg2 ? arg2 : "NULL", arg3 ? arg3 : "NULL",
+ arg4 ? arg4 : "NULL", arg5, arg6,
+ arg7, arg8 ? arg8 : "NULL", arg9 ? arg9 : "NULL");
+ Vector<long long> *res = dbeGetAggregatedValue (arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8, arg9);
+#ifdef IPC_LOG
+ if (res)
+ {
+ int sz = res->size ();
+ ipc_log (" returning = %d values:", sz);
+ if (sz > 10)
+ sz = 10;
+ for (int i = 0; i < sz; i++)
+ ipc_log (" %lld", res->fetch (i));
+ ipc_log ("\n");
+ }
+ else
+ ipc_log (" returning NULL\n");
+#endif
+ writeArray (res, req);
+ delete res;
+ free (arg2);
+ free (arg3);
+ free (arg4);
+ free (arg8);
+ free (arg9);
+ }
+#if 0//YXXX TBR
+ else if (!strcmp (inp, "getExprValue"))
+ {
+ int exp_id = readInt ();
+ int arg1 = readInt ();
+ int arg2 = readInt ();
+ String arg3 = readString ();
+ ipc_log (" exp_id %d, data_id = %d, event_id = %d, expr = %s\n",
+ exp_id, arg1, arg2, arg3 ? arg3 : "NULL");
+ String res = dbeGetExprValue (exp_id, arg1, arg2, arg3);
+ ipc_log (" returning = %s\n", res ? res : "");
+ writeString (res);
+ free (res);
+ free (arg3);
+ }
+ else if (!strcmp (inp, "getListValues"))
+ {
+ Obj arg1 = readObject ();
+ ipc_log (" stack = %lu\n", (long) arg1);
+ Vector<Obj> *res = dbeGetListValues (arg1);
+ ipc_log (" returns = %d objects\n", res ? res->size () : 0);
+ writeArray (res);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getListNames"))
+ {
+ Obj arg1 = readObject ();
+ ipc_log (" stack = %lu\n", (long) arg1);
+ Vector<String> *res = dbeGetListNames (arg1);
+ ipc_log (" returns = %d objects\n", res ? res->size () : 0);
+ writeArray (res);
+ destroy (res);
+ }
+#endif
+ else if (!strcmp (inp, "getLineInfo"))
+ {
+ Obj arg1 = readObject (req);
+ ipc_log (" pc = %lu\n", (long) arg1);
+ Vector<String> *res = dbeGetLineInfo (arg1);
+ ipc_log (" returning File name: '%s'\n", res ? res->fetch (0) : "");
+ ipc_log (" returning Lineno: '%s'\n", res ? res->fetch (1) : "");
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "setAlias"))
+ {
+ String arg1 = readString (req);
+ String arg2 = readString (req);
+ String arg3 = readString (req);
+ ipc_log (" name=\"%s\" uname=\"%s\" expr=\"%s\"\n",
+ arg1 ? arg1 : "", arg2 ? arg2 : "", arg3 ? arg3 : "");
+ int res = dbeSetAlias (arg1, arg2, arg3);
+ ipc_log (" returning = %d\n", res);
+ writeInt (res, req);
+ }
+ else if (!strcmp (inp, "getAlias"))
+ {
+ String arg1 = readString (req);
+ ipc_log (" name=\"%s\"\n", arg1 ? arg1 : "");
+ Vector<char*> *res = dbeGetAlias (arg1);
+ ipc_log (" returning uname: '%s'\n", res && res->fetch (0) ? res->fetch (0) : "");
+ ipc_log (" returning expr: '%s'\n", res && res->fetch (1) ? res->fetch (0) : "");
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getXYPlotData"))
+ {
+ int arg1 = readInt (req);
+ String arg2 = readString (req);
+ String arg3 = readString (req);
+ String arg4 = readString (req);
+ String arg5 = readString (req);
+ String arg6 = readString (req);
+ String arg7 = readString (req);
+ String arg8 = readString (req);
+ String arg9 = readString (req);
+ ipc_log (" data_idx = %d lfilter = \"%s\" arg = \"%s\" "
+ "func1 = \"%s\" aggr1 = \"%s\" "
+ "func2 = \"%s\" aggr2 = \"%s\" "
+ "func3 = \"%s\" aggr3 = \"%s\" \n",
+ arg1, arg2 ? arg2 : "NULL", arg3 ? arg3 : "NULL",
+ arg4 ? arg4 : "NULL", arg5 ? arg5 : "NULL", arg6 ? arg6 : "NULL",
+ arg7 ? arg7 : "NULL", arg8 ? arg8 : "NULL", arg9 ? arg9 : "NULL");
+ Vector<Vector<long long>*> *res = dbeGetXYPlotData (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+
+#ifdef IPC_LOG
+ if (res)
+ {
+ long nvals = res->size ();
+ for (long i = 0; i < nvals; ++i)
+ {
+ Vector<long long> *vals = res->fetch (i);
+ long long sz = VSIZE (vals);
+ ipc_log (" returning = %lld values:", sz);
+ if (sz > 10)
+ sz = 10;
+ for (long j = 0; j < sz; j++)
+ ipc_log (" %lld", vals->fetch (j));
+ ipc_log ("\n");
+ }
+ }
+ else
+ ipc_log (" returning NULL\n");
+#endif
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (strcmp (inp, "dbe_archive") == 0)
+ {
+ Vector<long long> *ids = (Vector<long long> *) readArray (req);
+ Vector<const char*> *locations = (Vector<const char*> *) readArray (req);
+ dbe_archive (ids, locations);
+ delete ids;
+ destroy (locations);
+ writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+ }
+ else if (strcmp (inp, "dbeSetLocations") == 0)
+ {
+ Vector<const char*> *fnames = (Vector<const char*> *) readArray (req);
+ Vector<const char*> *locations = (Vector<const char*> *) readArray (req);
+ dbeSetLocations (fnames, locations);
+ destroy (fnames);
+ destroy (locations);
+ writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+ }
+ else if (strcmp (inp, "dbeResolvedWith_setpath") == 0)
+ {
+ char *path = readString (req);
+ Vector<void *> *res = dbeResolvedWith_setpath (path);
+ free (path);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (strcmp (inp, "dbeResolvedWith_pathmap") == 0)
+ {
+ char *old_prefix = readString (req);
+ char *new_prefix = readString (req);
+ Vector<void *> *res = dbeResolvedWith_pathmap (old_prefix, new_prefix);
+ free (old_prefix);
+ free (new_prefix);
+ writeArray (res, req);
+ destroy (res);
+ }
+ else if (!strcmp (inp, "getCollectorControlValue"))
+ {
+ /* int dbevindex =*/ readInt (req);
+ char *control = readString (req);
+ ipc_log (" args = %s\n", control);
+ char *ret = dbeGetCollectorControlValue (control);
+ ipc_log (" returning %s\n", STR (ret));
+ writeString (ret, req);
+ }
+ else if (!strcmp (inp, "setCollectorControlValue"))
+ {
+ /* int dbevindex =*/ readInt (req);
+ char *control = readString (req);
+ char *value = readString (req);
+#ifdef IPC_LOG
+ ipc_log (" args = %s %s\n", control, value);
+#endif
+ char *ret = dbeSetCollectorControlValue (control, value);
+#ifdef IPC_LOG
+ if (ret)
+ ipc_log (" returning %s\n", ret);
+ else
+ ipc_log (" returning NULL\n");
+#endif
+ writeString (ret, req);
+ }
+ else if (!strcmp (inp, "unsetCollectorControlValue"))
+ {
+ /* int dbevindex =*/ readInt (req);
+ char *control = readString (req);
+ ipc_log (" args = %s\n", control);
+ char *ret = dbeUnsetCollectorControlValue (control);
+ ipc_log (" returning %s\n", STR (ret));
+ writeString (ret, req);
+ }
+ else if (!strcmp (inp, "getSignalValue"))
+ {
+ String arg1 = readString (req);
+ ipc_log (" arg1=\"%s\"\n", arg1 ? arg1 : "");
+ int res = dbeGetSignalValue (arg1);
+ ipc_log (" returning = %d\n", res);
+ writeInt (res, req);
+ }
+ else if (!strcmp (inp, "sendSignal"))
+ {
+ long long p = readLong (req);
+ int signum = readInt (req);
+ ipc_log (" args = %llu, %d\n", (long long) p, signum);
+ char * ret = dbeSendSignal ((pid_t) p, signum);
+#ifdef IPC_LOG
+ if (ret)
+ ipc_log (" returning %s\n", ret);
+ else
+ ipc_log (" returning NULL\n");
+#endif
+ writeString (ret, req);
+ }
+ else if (!strcmp (inp, "checkConnection"))
+ {
+ String arg1 = readString (req);
+ ipc_log (" arg = `%s'\n", arg1 ? arg1 : "NULL");
+ String res = dbeCheckConnection (arg1);
+ writeString (res, req);
+ ipc_log (" returns `%s'\n", res ? res : "NULL");
+ free (arg1);
+ free (res);
+ }
+ else if (!strcmp (inp, "QUIT"))
+ {
+#ifdef IPC_LOG
+ ipc_log (" %s\n", inp);
+#endif
+ exit (0);
+ }
+ else
+ {
+ ipc_log ("Unrecognized input cmd \"%s\"; Aborting.\n", inp);
+ return 1;
+ }
+ ipc_log (" processing IPC command %s complete\n", inp);
+ free (inp);
+ fflush (stdout);
+ if (req->getStatus () != CANCELLED_IMMEDIATE)
+ // wake up the main working thread, let it take care of delete
+ req->setStatus (COMPLETED);
+ delete req;
+ return 0;
+}
+
+void
+check_env_args (int argc, char *argv[])
+{
+ int indx = 2; // Skip "-IPC"
+ const char *MINUS_E = "-E";
+ const char *SP_ER_PRINT_TRACE_LEVEL = "SP_ER_PRINT_TRACE_LEVEL";
+ const char *SP_IPC_PROTOCOL = "SP_IPC_PROTOCOL";
+ const char SEPARATOR = '=';
+ char *cmd_env_var = NULL;
+ while (argc - indx >= 2)
+ {
+ char *option = argv[indx++];
+ if (!streq (option, MINUS_E))
+ continue;
+ cmd_env_var = argv[indx++];
+ char *separator = strchr (cmd_env_var, SEPARATOR);
+ if (!separator)
+ // Unrecognized option. Fatal error?
+ continue;
+ char *cmd_env_var_val = separator + 1;
+ if (!strncmp (cmd_env_var, SP_ER_PRINT_TRACE_LEVEL,
+ strlen (SP_ER_PRINT_TRACE_LEVEL)))
+ {
+ if (streq (cmd_env_var_val, "1"))
+ ipc_trace_level = TRACE_LVL_1;
+ else if (streq (cmd_env_var_val, "2"))
+ ipc_trace_level = TRACE_LVL_2;
+ else if (streq (cmd_env_var_val, "3"))
+ ipc_trace_level = TRACE_LVL_3;
+ else if (streq (cmd_env_var_val, "4"))
+ ipc_trace_level = TRACE_LVL_4;
+ continue;
+ }
+ if (!strncmp (cmd_env_var, SP_IPC_PROTOCOL, strlen (SP_IPC_PROTOCOL)))
+ {
+ if (streq (cmd_env_var_val, IPC_PROTOCOL_CURR))
+ // Only one protocol is currently supported
+ ipc_protocol = IPC_PROTOCOL_CURR;
+ else
+ ipc_protocol = IPC_PROTOCOL_UNKNOWN;
+ continue;
+ }
+ // Unrecognized option. Fatal error?
+ }
+}
+
+void
+print_ipc_protocol_confirmation ()
+{
+ if (NULL != ipc_protocol)
+ {
+ fprintf (stdout, "ER_IPC: %s\n", ipc_protocol);
+ fflush (stdout);
+ }
+}
+
+void
+ipc_mainLoop (int argc, char *argv[])
+{
+ if (getenv ("GPROFNG_DBE_DELAY"))
+ sleep (20);
+#ifdef IPC_LOG
+ ipc_flags = 1;
+#endif
+ // check_env_args(argc, argv);
+
+ char *er_print_trace_level = getenv ("SP_ER_PRINT_TRACE_LEVEL");
+ if (er_print_trace_level != NULL)
+ {
+ if (streq (er_print_trace_level, "1"))
+ ipc_trace_level = TRACE_LVL_1;
+ else if (streq (er_print_trace_level, "2"))
+ ipc_trace_level = TRACE_LVL_2;
+ else if (streq (er_print_trace_level, "3"))
+ ipc_trace_level = TRACE_LVL_3;
+ else if (streq (er_print_trace_level, "4"))
+ ipc_trace_level = TRACE_LVL_4;
+ }
+ check_env_args (argc, argv);
+ print_ipc_protocol_confirmation ();
+
+ if (ipc_flags || getenv ("SP_ER_PRINT_IPC_FLAG") || ipc_trace_level > TRACE_LVL_0)
+ {
+ ipc_flags = 1;
+ if (ipc_trace_level == TRACE_LVL_0)
+ ipc_trace_level = TRACE_LVL_1;
+ // reopen stderr as file "ipc_log"
+ ipc_log_name = getenv ("SP_ER_PRINT_IPC_LOG");
+ if (ipc_log_name == NULL)
+ ipc_log_name = "ipc_log";
+ freopen (ipc_log_name, "w", stderr);
+ if (ipc_trace_level >= TRACE_LVL_2)
+ {
+ ipc_request_log_name = "ipc_request_log";
+ ipc_response_log_name = "ipc_response_log";
+ requestLogFileP = fopen (ipc_request_log_name, "w");
+ responseLogFileP = fopen (ipc_response_log_name, "w");
+ }
+ else
+ {
+ ipc_request_log_name = "ipc_log";
+ ipc_response_log_name = "ipc_log";
+ }
+ begin_time = gethrtime ();
+ }
+ else
+ // Reopen stderr as /dev/null
+ freopen ("/dev/null", "w", stderr);
+
+ struct sigaction act;
+ memset (&act, 0, sizeof (struct sigaction));
+ term_flag = 0;
+ /* install a handler for TERM */
+ ipc_request_trace (TRACE_LVL_1, "Installing SIGTERM handler to abort on error\n");
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = (SignalHandler) sigterm_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGTERM, &act, &old_sigterm_handler) == -1)
+ {
+ ipc_request_trace (TRACE_LVL_1, "Unable to install SIGTERM handler\n");
+ abort ();
+ }
+ /* install a handler for INT */
+ ipc_request_trace (TRACE_LVL_1, "Installing SIGINT handler to send message to analyzer\n");
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = (SignalHandler) sigint_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGINT, &act, &old_sigint_handler) == -1)
+ {
+ ipc_request_trace (TRACE_LVL_1, "Unable to install SIGINT handler\n");
+ abort ();
+ }
+ ipc_log ("Installed SIGINT handler to handle Ctrl-C properly\n");
+ int er_print_catch_crash = 1; // Default: catch fatal signals
+ char *s = getenv ("GPROFNG_ALLOW_CORE_DUMP");
+ if (s && (strcasecmp (s, "no") == 0 || strcmp (s, "0") == 0))
+ er_print_catch_crash = 0;
+ if (er_print_catch_crash)
+ {
+ /* reserve memory for fatal error processing */
+ fatalErrorDynamicMemory = (char *) malloc (4 * 1024 * 1024); // reserve 4 MB
+ /* install a handler for SIGABRT */
+ ipc_request_trace (TRACE_LVL_1, "Installing SIGABRT handler to send message to analyzer\n");
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = (SignalHandler) sigABRT_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGABRT, &act, NULL) == -1)
+ {
+ ipc_request_trace (TRACE_LVL_1, "Unable to install SIGABRT handler\n");
+ // abort();
+ }
+ else
+ ipc_log ("Installed SIGABRT handler to handle crash properly\n");
+ /* install a handler for SIGSEGV */
+ ipc_request_trace (TRACE_LVL_1, "Installing SIGABRT handler to send message to analyzer\n");
+ sigemptyset (&act.sa_mask);
+ act.sa_handler = (SignalHandler) sigSEGV_handler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction (SIGSEGV, &act, NULL) == -1)
+ {
+ ipc_request_trace (TRACE_LVL_1, "Unable to install SIGSEGV handler\n");
+ // abort();
+ }
+ else
+ ipc_log ("Installed SIGSEGV handler to handle crash properly\n");
+ }
+ ipc_request_trace (TRACE_LVL_1, "Entering ipc_mainLoop; run dir `%s'\n",
+ theApplication->get_run_dir ());
+ cancelRequestedChannelID = 0xFFFFFFFF;
+ ipcThreadPool = new DbeThreadPool (0); // DbeThreadPool (-1);
+ responseBufferPool = new BufferPool ();
+ ipc_log (ipc_single_threaded_mode ?
+ "RUNNING er_print -IPC IN SINGLE THREADED MODE\n" :
+ "RUNNING er_print -IPC IN MULTITHREAD MODE\n");
+
+ /* Send "Ready" signal to the GUI */
+ setProgress (100, "Restart engine");
+
+ /* start listening for requests */
+ error_flag = 0;
+ for (;;)
+ {
+ readRequestHeader ();
+ if (term_flag == 1 || error_flag == 1)
+ {
+ ipc_request_trace (TRACE_LVL_1, "SIGTERM received, exiting\n");
+ return;
+ }
+ }
+}
+
+static const char *
+table_name (int flavor)
+{
+ static char def_name[64];
+
+ switch ((FuncListDisp_type) flavor)
+ {
+ case DSP_FUNCTION:
+ return ("FUNCTION");
+ case DSP_LINE:
+ return ("LINE");
+ case DSP_PC:
+ return ("PC");
+ case DSP_SOURCE:
+ return ("SOURCE");
+ case DSP_DISASM:
+ return ("DISASM");
+ case DSP_SELF:
+ return ("SELF");
+ case DSP_CALLER:
+ return ("CALLER");
+ case DSP_CALLEE:
+ return ("CALLEE");
+ case DSP_CALLTREE:
+ return ("CALLTREE");
+ case DSP_TIMELINE:
+ return ("TIMELINE");
+ case DSP_STATIS:
+ return ("STATIS");
+ case DSP_EXP:
+ return ("EXP");
+ case DSP_LEAKLIST:
+ return ("LEAKLIST");
+ case DSP_HEAPCALLSTACK:
+ return ("HEAP");
+ case DSP_MEMOBJ:
+ return ("MEMOBJ");
+ case DSP_DATAOBJ:
+ return ("DATAOBJ");
+ case DSP_DLAYOUT:
+ return ("DLAYOUT");
+ case DSP_SRC_FILE:
+ return ("SRC_FILE");
+ case DSP_IFREQ:
+ return ("IFREQ");
+ case DSP_RACES:
+ return ("RACES");
+ case DSP_INDXOBJ:
+ return ("INDXOBJ");
+ case DSP_DUALSOURCE:
+ return ("DUALSOURCE");
+ case DSP_SOURCE_DISASM:
+ return ("SOURCE_DISASM");
+ case DSP_DEADLOCKS:
+ return ("DEADLOCKS");
+ case DSP_SOURCE_V2:
+ return ("SOURCE_V2");
+ case DSP_DISASM_V2:
+ return ("DISASM_V2");
+ case DSP_IOACTIVITY:
+ return ("IOACTIVITY");
+ case DSP_OVERVIEW:
+ return ("OVERVIEW");
+ case DSP_SAMPLE:
+ return ("SAMPLE -- UNEXPECTED");
+ default:
+ snprintf (def_name, sizeof (def_name), "table number %d", flavor);
+ return (def_name);
+ }
+}
diff --git a/gprofng/src/ipcio.cc b/gprofng/src/ipcio.cc
new file mode 100644
index 0000000..57f2617
--- /dev/null
+++ b/gprofng/src/ipcio.cc
@@ -0,0 +1,1025 @@
+/* Copyright (C) 2021 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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <queue>
+#include "vec.h"
+#include "util.h"
+#include "ipcio.h"
+#include "DbeThread.h"
+#include "Experiment.h"
+
+#define ipc_trace if (ipc_flags) ipc_default_log
+#define ipc_request_trace if (ipc_flags) ipc_request_log
+#define ipc_response_trace if (ipc_flags) ipc_response_log
+
+using namespace std;
+
+// IPC implementation
+static const int L_PROGRESS = 0;
+static const int L_INTEGER = 1;
+static const int L_BOOLEAN = 2;
+static const int L_LONG = 3;
+static const int L_STRING = 4;
+static const int L_DOUBLE = 5;
+static const int L_ARRAY = 6;
+static const int L_OBJECT = 7;
+static const int L_CHAR = 8;
+
+int currentRequestID;
+int currentChannelID;
+static long maxSize;
+
+extern int cancellableChannelID;
+extern int error_flag;
+extern int ipc_delay_microsec;
+extern FILE *responseLogFileP;
+
+IPCresponse *IPCresponseGlobal;
+
+BufferPool *responseBufferPool;
+
+IPCrequest::IPCrequest (int sz, int reqID, int chID)
+{
+ size = sz;
+ requestID = reqID;
+ channelID = chID;
+ status = INITIALIZED;
+ idx = 0;
+ buf = (char *) malloc (size);
+ cancelImmediate = false;
+}
+
+IPCrequest::~IPCrequest ()
+{
+ free (buf);
+}
+
+void
+IPCrequest::read (void)
+{
+ for (int i = 0; i < size; i++)
+ {
+ int c = getc (stdin);
+ ipc_request_trace (TRACE_LVL_4, " IPCrequest:getc(stdin): %02x\n", c);
+ buf[i] = c;
+ }
+}
+
+IPCrequestStatus
+IPCrequest::getStatus (void)
+{
+ return status;
+}
+
+void
+IPCrequest::setStatus (IPCrequestStatus newStatus)
+{
+ status = newStatus;
+}
+
+static int
+readByte (IPCrequest* req)
+{
+ int c;
+ int val = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ if (req == NULL)
+ {
+ c = getc (stdin);
+ ipc_request_trace (TRACE_LVL_4, " readByte:getc(stdin): %02x\n", c);
+ }
+ else
+ c = req->rgetc ();
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ val = val * 16 + c - '0';
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ val = val * 16 + c - 'a' + 10;
+ break;
+ case EOF:
+ val = EOF;
+ break;
+ default:
+ fprintf (stderr, "readByte: Unknown byte: %d\n", c);
+ break;
+ }
+ }
+ return val;
+}
+
+static int
+readIVal (IPCrequest *req)
+{
+ int val = readByte (req);
+ for (int i = 0; i < 3; i++)
+ val = val * 256 + readByte (req);
+ ipc_trace (" readIVal: %d\n", val);
+ return val;
+}
+
+static String
+readSVal (IPCrequest *req)
+{
+ int len = readIVal (req);
+ if (len == -1)
+ {
+ ipc_trace (" readSVal: <NULL>\n");
+ return NULL;
+ }
+ char *str = (char *) malloc (len + 1);
+ char *s = str;
+ *s = (char) 0;
+ while (len--)
+ *s++ = req->rgetc ();
+ *s = (char) 0;
+ ipc_trace (" readSVal: '%s'\n", str);
+ return str;
+}
+
+static long long
+readLVal (IPCrequest *req)
+{
+ long long val = readByte (req);
+ for (int i = 0; i < 7; i++)
+ val = val * 256 + readByte (req);
+ ipc_trace (" readLVal: %lld\n", val);
+ return val;
+}
+
+static bool
+readBVal (IPCrequest *req)
+{
+ int val = readByte (req);
+ ipc_trace (" readBVal: %s\n", val == 0 ? "true" : "false");
+ return val != 0;
+}
+
+static char
+readCVal (IPCrequest *req)
+{
+ int val = readByte (req);
+ ipc_trace (" readCVal: %d\n", val);
+ return (char) val;
+}
+
+static double
+readDVal (IPCrequest *req)
+{
+ String s = readSVal (req);
+ double d = atof (s);
+ free (s);
+ return d;
+}
+
+static Object
+readAVal (IPCrequest *req)
+{
+ bool twoD = false;
+ int type = readByte (req);
+ if (type == L_ARRAY)
+ {
+ twoD = true;
+ type = readByte (req);
+ }
+ ipc_trace ("readAVal: twoD=%s type=%d\n", twoD ? "true" : "false", type);
+
+ int len = readIVal (req);
+ if (len == -1)
+ return NULL;
+ switch (type)
+ {
+ case L_INTEGER:
+ if (twoD)
+ {
+ Vector<Vector<int>*> *array = new Vector<Vector<int>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<int>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<int> *array = new Vector<int>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readIVal (req));
+ return array;
+ }
+ //break;
+ case L_LONG:
+ if (twoD)
+ {
+ Vector<Vector<long long>*> *array = new Vector<Vector<long long>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<long long>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<long long> *array = new Vector<long long>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readLVal (req));
+ return array;
+ }
+ //break;
+ case L_DOUBLE:
+ if (twoD)
+ {
+ Vector<Vector<double>*> *array = new Vector<Vector<double>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<double>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<double> *array = new Vector<double>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readDVal (req));
+ return array;
+ }
+ //break;
+ case L_BOOLEAN:
+ if (twoD)
+ {
+ Vector < Vector<bool>*> *array = new Vector < Vector<bool>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<bool>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<bool> *array = new Vector<bool>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readBVal (req));
+ return array;
+ }
+ //break;
+ case L_CHAR:
+ if (twoD)
+ {
+ Vector<Vector<char>*> *array = new Vector<Vector<char>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<char>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<char> *array = new Vector<char>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readCVal (req));
+ return array;
+ }
+ //break;
+ case L_STRING:
+ if (twoD)
+ {
+ Vector<Vector<String>*> *array = new Vector<Vector<String>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<String>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<String> *array = new Vector<String>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readSVal (req));
+ return array;
+ }
+ //break;
+ case L_OBJECT:
+ if (twoD)
+ {
+ Vector<Vector<Object>*> *array = new Vector<Vector<Object>*>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, (Vector<Object>*)readAVal (req));
+ return array;
+ }
+ else
+ {
+ Vector<Object> *array = new Vector<Object>(len);
+ for (int i = 0; i < len; i++)
+ array->store (i, readAVal (req));
+ return array;
+ }
+ //break;
+ default:
+ fprintf (stderr, "readAVal: Unknown code: %d\n", type);
+ break;
+ }
+ return NULL;
+}
+
+static int iVal;
+static bool bVal;
+static long long lVal;
+static String sVal;
+static double dVal;
+static Object aVal;
+
+static void
+readResult (int type, IPCrequest *req)
+{
+ int tVal = readByte (req);
+ switch (tVal)
+ {
+ case L_INTEGER:
+ iVal = readIVal (req);
+ break;
+ case L_LONG:
+ lVal = readLVal (req);
+ break;
+ case L_BOOLEAN:
+ bVal = readBVal (req);
+ break;
+ case L_DOUBLE:
+ dVal = readDVal (req);
+ break;
+ case L_STRING:
+ sVal = readSVal (req);
+ break;
+ case L_ARRAY:
+ aVal = readAVal (req);
+ break;
+ case EOF:
+ fprintf (stderr, "EOF read in readResult\n");
+ sVal = NULL;
+ return;
+ default:
+ fprintf (stderr, "Unknown code: %d\n", tVal);
+ abort ();
+ }
+ if (type != tVal)
+ {
+ fprintf (stderr, "Internal error: readResult: parameter mismatch: type=%d should be %d\n", tVal, type);
+ abort ();
+ }
+}
+
+int
+readInt (IPCrequest *req)
+{
+ readResult (L_INTEGER, req);
+ return iVal;
+}
+
+String
+readString (IPCrequest *req)
+{
+ readResult (L_STRING, req);
+ return sVal;
+}
+
+long long
+readLong (IPCrequest *req)
+{
+ readResult (L_LONG, req);
+ return lVal;
+}
+
+double
+readDouble (IPCrequest *req)
+{
+ readResult (L_DOUBLE, req);
+ return dVal;
+}
+
+bool
+readBoolean (IPCrequest *req)
+{
+ readResult (L_BOOLEAN, req);
+ return bVal;
+}
+
+DbeObj
+readObject (IPCrequest *req)
+{
+ readResult (L_LONG, req);
+ return (DbeObj) lVal;
+}
+
+Object
+readArray (IPCrequest *req)
+{
+ readResult (L_ARRAY, req);
+ return aVal;
+}
+
+// Write
+IPCresponse::IPCresponse (int sz)
+{
+ requestID = -1;
+ channelID = -1;
+ responseType = -1;
+ responseStatus = RESPONSE_STATUS_SUCCESS;
+ sb = new StringBuilder (sz);
+ next = NULL;
+}
+
+IPCresponse::~IPCresponse ()
+{
+ delete sb;
+}
+
+void
+IPCresponse::reset ()
+{
+ requestID = -1;
+ channelID = -1;
+ responseType = -1;
+ responseStatus = RESPONSE_STATUS_SUCCESS;
+ sb->setLength (0);
+}
+
+void
+IPCresponse::sendByte (int b)
+{
+ ipc_trace ("sendByte: %02x %d\n", b, b);
+ sb->appendf ("%02x", b);
+}
+
+void
+IPCresponse::sendIVal (int i)
+{
+ ipc_trace ("sendIVal: %08x %d\n", i, i);
+ sb->appendf ("%08x", i);
+}
+
+void
+IPCresponse::sendLVal (long long l)
+{
+ ipc_trace ("sendLVal: %016llx %lld\n", l, l);
+ sb->appendf ("%016llx", l);
+}
+
+void
+IPCresponse::sendSVal (const char *s)
+{
+ if (s == NULL)
+ {
+ sendIVal (-1);
+ return;
+ }
+ sendIVal ((int) strlen (s));
+ ipc_trace ("sendSVal: %s\n", s);
+ sb->appendf ("%s", s);
+}
+
+void
+IPCresponse::sendBVal (bool b)
+{
+ sendByte (b ? 1 : 0);
+}
+
+void
+IPCresponse::sendCVal (char c)
+{
+ sendByte (c);
+}
+
+void
+IPCresponse::sendDVal (double d)
+{
+ char str[32];
+ snprintf (str, sizeof (str), "%.12f", d);
+ sendSVal (str);
+}
+
+void
+IPCresponse::sendAVal (void *ptr)
+{
+ if (ptr == NULL)
+ {
+ sendByte (L_INTEGER);
+ sendIVal (-1);
+ return;
+ }
+
+ VecType type = ((Vector<void*>*)ptr)->type ();
+ switch (type)
+ {
+ case VEC_INTEGER:
+ {
+ sendByte (L_INTEGER);
+ Vector<int> *array = (Vector<int>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendIVal (array->fetch (i));
+ break;
+ }
+ case VEC_BOOL:
+ {
+ sendByte (L_BOOLEAN);
+ Vector<bool> *array = (Vector<bool>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendBVal (array->fetch (i));
+ break;
+ }
+ case VEC_CHAR:
+ {
+ sendByte (L_CHAR);
+ Vector<char> *array = (Vector<char>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendCVal (array->fetch (i));
+ break;
+ }
+ case VEC_LLONG:
+ {
+ sendByte (L_LONG);
+ Vector<long long> *array = (Vector<long long>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendLVal (array->fetch (i));
+ break;
+ }
+ case VEC_DOUBLE:
+ {
+ sendByte (L_DOUBLE);
+ Vector<double> *array = (Vector<double>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendDVal (array->fetch (i));
+ break;
+ }
+ case VEC_STRING:
+ {
+ sendByte (L_STRING);
+ Vector<String> *array = (Vector<String>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendSVal (array->fetch (i));
+ break;
+ }
+ case VEC_STRINGARR:
+ {
+ sendByte (L_ARRAY);
+ sendByte (L_STRING);
+ Vector<void*> *array = (Vector<void*>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendAVal (array->fetch (i));
+ break;
+ }
+ case VEC_INTARR:
+ {
+ sendByte (L_ARRAY);
+ sendByte (L_INTEGER);
+ Vector<void*> *array = (Vector<void*>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendAVal (array->fetch (i));
+ break;
+ }
+ case VEC_LLONGARR:
+ {
+ sendByte (L_ARRAY);
+ sendByte (L_LONG);
+ Vector<void*> *array = (Vector<void*>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendAVal (array->fetch (i));
+ break;
+ }
+ case VEC_VOIDARR:
+ {
+ sendByte (L_OBJECT);
+ Vector<void*> *array = (Vector<void*>*)ptr;
+ sendIVal (array->size ());
+ for (int i = 0; i < array->size (); i++)
+ sendAVal (array->fetch (i));
+ break;
+ }
+ default:
+ fprintf (stderr, "sendAVal: Unknown type: %d\n", type);
+ abort ();
+ }
+}
+
+static void
+writeResponseHeader (int requestID, int responseType, int responseStatus, int nBytes)
+{
+ if (responseType == RESPONSE_TYPE_HANDSHAKE)
+ nBytes = IPC_VERSION_NUMBER;
+ int use_write = 2;
+ ipc_response_trace (TRACE_LVL_1, "ResponseHeaderBegin----- %x ---- %x ----- %x -----%x -------\n", requestID, responseType, responseStatus, nBytes);
+ if (use_write)
+ {
+ char buf[23];
+ if (use_write == 1)
+ {
+ int i = 0;
+ snprintf (buf + i, 3, "%2x", HEADER_MARKER);
+ i += 2;
+ snprintf (buf + i, 9, "%8x", requestID);
+ i += 8;
+ snprintf (buf + i, 3, "%2x", responseType);
+ i += 2;
+ snprintf (buf + i, 3, "%2x", responseStatus);
+ i += 2;
+ snprintf (buf + i, 9, "%8x", nBytes);
+ }
+ else
+ snprintf (buf, 23, "%02x%08x%02x%02x%08x", HEADER_MARKER, requestID,
+ responseType, responseStatus, nBytes);
+ buf[22] = 0;
+ write (1, buf, 22);
+ }
+ else
+ {
+ cout << setfill ('0') << setw (2) << hex << HEADER_MARKER;
+ cout << setfill ('0') << setw (8) << hex << requestID;
+ cout << setfill ('0') << setw (2) << hex << responseType;
+ cout << setfill ('0') << setw (2) << hex << responseStatus;
+ cout << setfill ('0') << setw (8) << hex << nBytes;
+ cout.flush ();
+ }
+ ipc_response_trace (TRACE_LVL_1, "----------------------------ResponseHeaderEnd\n");
+ if (nBytes > maxSize)
+ {
+ maxSize = nBytes;
+ ipc_trace ("New maxsize %ld\n", maxSize);
+ }
+}
+
+bool
+cancelNeeded (int chID)
+{
+ if (chID == cancellableChannelID && chID == cancelRequestedChannelID)
+ return true;
+ else
+ return false;
+}
+
+static void
+writeResponseWithHeader (int requestID, int channelID, int responseType,
+ int responseStatus, IPCresponse* os)
+{
+ if (cancelNeeded (channelID))
+ {
+ responseStatus = RESPONSE_STATUS_CANCELLED;
+ ipc_trace ("CANCELLING %d %d\n", requestID, channelID);
+ // This is for gracefully cancelling regular ops like openExperiment - getFiles should never reach here
+ }
+ os->setRequestID (requestID);
+ os->setChannelID (channelID);
+ os->setResponseType (responseType);
+ os->setResponseStatus (responseStatus);
+ os->print ();
+ os->reset ();
+ responseBufferPool->recycle (os);
+}
+
+void
+writeAckFast (int requestID)
+{
+ writeResponseHeader (requestID, RESPONSE_TYPE_ACK, RESPONSE_STATUS_SUCCESS, 0);
+}
+
+void
+writeAck (int requestID, int channelID)
+{
+#if DEBUG
+ char *s = getenv (NTXT ("SP_NO_IPC_ACK"));
+#else /* ^DEBUG */
+ char *s = NULL;
+#endif /* ^DEBUG */
+ if (s)
+ {
+ int i = requestID;
+ int j = channelID;
+ ipc_request_trace (TRACE_LVL_4, "ACK skipped: requestID=%d channelID=%d\n", i, j);
+ }
+ else
+ {
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
+ writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_ACK,
+ RESPONSE_STATUS_SUCCESS, OUTS);
+ }
+}
+
+void
+writeHandshake (int requestID, int channelID)
+{
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
+ writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_HANDSHAKE, RESPONSE_STATUS_SUCCESS, OUTS);
+ // writeResponseHeader(requestID, RESPONSE_TYPE_HANDSHAKE, RESPONSE_STATUS_SUCCESS, IPC_VERSION_NUMBER);
+}
+
+void
+writeResponseGeneric (int responseStatus, int requestID, int channelID)
+{
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
+ writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_COMPLETE, responseStatus, OUTS);
+}
+
+BufferPool::BufferPool ()
+{
+ pthread_mutex_init (&p_mutex, NULL);
+ smallBuf = NULL;
+ largeBuf = NULL;
+}
+
+BufferPool::~BufferPool ()
+{
+ for (IPCresponse *p = smallBuf; p;)
+ {
+ IPCresponse *tmp = p;
+ p = tmp->next;
+ delete tmp;
+ }
+ for (IPCresponse *p = largeBuf; p;)
+ {
+ IPCresponse *tmp = p;
+ p = tmp->next;
+ delete tmp;
+ }
+}
+
+IPCresponse*
+BufferPool::getNewResponse (int size)
+{
+ pthread_mutex_lock (&p_mutex);
+ if (ipc_single_threaded_mode && size < BUFFER_SIZE_LARGE)
+ size = BUFFER_SIZE_LARGE;
+ IPCresponse *newResponse = NULL;
+ if (size >= BUFFER_SIZE_LARGE)
+ {
+ if (largeBuf)
+ {
+ newResponse = largeBuf;
+ largeBuf = largeBuf->next;
+ }
+ }
+ else if (smallBuf)
+ {
+ newResponse = smallBuf;
+ smallBuf = smallBuf->next;
+ }
+ if (newResponse)
+ newResponse->reset ();
+ else
+ {
+ newResponse = new IPCresponse (size);
+ ipc_trace ("GETNEWBUFFER %d\n", size);
+ }
+ pthread_mutex_unlock (&p_mutex);
+ return newResponse;
+}
+
+void
+BufferPool::recycle (IPCresponse *respB)
+{
+ pthread_mutex_lock (&p_mutex);
+ if (respB->getCurBufSize () >= BUFFER_SIZE_LARGE)
+ {
+ respB->next = largeBuf;
+ largeBuf = respB;
+ }
+ else
+ {
+ respB->next = smallBuf;
+ smallBuf = respB;
+ }
+ pthread_mutex_unlock (&p_mutex);
+}
+
+void
+writeArray (void *ptr, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE)
+ return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_LARGE);
+ OUTS->sendByte (L_ARRAY);
+ OUTS->sendAVal (ptr);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
+ RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeString (const char *s, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE)
+ return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_LARGE);
+ OUTS->sendByte (L_STRING);
+ OUTS->sendSVal (s);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
+ RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeObject (DbeObj obj, IPCrequest* req)
+{
+ writeLong ((long long) obj, req);
+}
+
+void
+writeBoolean (bool b, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE)
+ return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+ OUTS->sendByte (L_BOOLEAN);
+ OUTS->sendBVal (b);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
+ RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeInt (int i, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE)
+ return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+ OUTS->sendByte (L_INTEGER);
+ OUTS->sendIVal (i);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeChar (char c, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE)
+ return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+ OUTS->sendByte (L_CHAR);
+ OUTS->sendCVal (c);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeLong (long long l, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE)
+ return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+ OUTS->sendByte (L_LONG);
+ OUTS->sendLVal (l);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeDouble (double d, IPCrequest* req)
+{
+ if (req->getStatus () == CANCELLED_IMMEDIATE) return;
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+ OUTS->sendByte (L_DOUBLE);
+ OUTS->sendDVal (d);
+ writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+int
+setProgress (int percentage, const char *proc_str)
+{
+ if (cancelNeeded (currentChannelID))
+ {
+ // ExperimentLoadCancelException *e1 = new ExperimentLoadCancelException();
+ // throw (e1);
+ return 1;
+ }
+ if (NULL == proc_str)
+ return 1;
+ int size = strlen (proc_str) + 100; // 100 bytes for additional data
+ int bs = BUFFER_SIZE_MEDIUM;
+ if (size > BUFFER_SIZE_MEDIUM)
+ {
+ if (size > BUFFER_SIZE_LARGE) return 1; // This should never happen
+ bs = BUFFER_SIZE_LARGE;
+ }
+ IPCresponse *OUTS = responseBufferPool->getNewResponse (bs);
+ OUTS->sendByte (L_PROGRESS);
+ OUTS->sendIVal (percentage);
+ OUTS->sendSVal (proc_str);
+ writeResponseWithHeader (currentRequestID, currentChannelID, RESPONSE_TYPE_PROGRESS, RESPONSE_STATUS_SUCCESS, OUTS);
+ return 0;
+}
+
+void
+IPCresponse::print (void)
+{
+ if (ipc_delay_microsec)
+ usleep (ipc_delay_microsec);
+ int stringSize = sb->length ();
+ writeResponseHeader (requestID, responseType, responseStatus, stringSize);
+ if (stringSize > 0)
+ {
+ char *s = sb->toString ();
+ hrtime_t start_time = gethrtime ();
+ int use_write = 1;
+ if (use_write)
+ write (1, s, stringSize); // write(1, sb->toString(), stringSize);
+ else
+ {
+ cout << s;
+ cout.flush ();
+ }
+ hrtime_t end_time = gethrtime ();
+ unsigned long long time_stamp = end_time - start_time;
+ ipc_response_log (TRACE_LVL_3, "ReqID %x flush time %llu nanosec \n", requestID, time_stamp);
+ free (s);
+ }
+}
+
+void
+setCancelRequestedCh (int chID)
+{
+ cancelRequestedChannelID = chID;
+}
+
+void
+readRequestHeader ()
+{
+ int marker = readByte (NULL);
+ if (marker != HEADER_MARKER)
+ {
+ fprintf (stderr, "Internal error: received request (%d) without header marker\n", marker);
+ error_flag = 1;
+ return;
+ }
+ else
+ ipc_request_trace (TRACE_LVL_1, "RequestHeaderBegin------------------------\n");
+ int requestID = readIVal (NULL);
+ int requestType = readByte (NULL);
+ int channelID = readIVal (NULL);
+ int nBytes = readIVal (NULL);
+ if (requestType == REQUEST_TYPE_HANDSHAKE)
+ {
+ // write the ack directly to the wire, not through the response queue
+ // writeAckFast(requestID);
+ writeAck (requestID, channelID);
+ maxSize = 0;
+ writeHandshake (requestID, channelID);
+ ipc_request_trace (TRACE_LVL_1, "RQ: HANDSHAKE --- %x ----- %x ---- %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
+ }
+ else if (requestType == REQUEST_TYPE_CANCEL)
+ {
+ writeAck (requestID, channelID);
+ ipc_request_trace (TRACE_LVL_1, "RQ: CANCEL --- RQ: %x ----- %x --- CH: %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
+ if (channelID == cancellableChannelID)
+ {
+ // we have worked on at least one request belonging to this channel
+ writeResponseGeneric (RESPONSE_STATUS_SUCCESS, requestID, channelID);
+ setCancelRequestedCh (channelID);
+ ipc_trace ("CANCELLABLE %x %x\n", channelID, currentChannelID);
+ if (channelID == currentChannelID)
+ // request for this channel is currently in progress
+ ipc_request_trace (TRACE_LVL_1, "IN PROGRESS REQUEST NEEDS CANCELLATION");
+ // ssp_post_cond(waitingToFinish);
+ }
+ else
+ {
+ // FIXME:
+ // it is possible that a request for this channel is on the requestQ
+ // or has been submitted to the work group queue but is waiting for a thread to pick it up
+ writeResponseGeneric (RESPONSE_STATUS_FAILURE, requestID, channelID);
+ setCancelRequestedCh (channelID);
+ ipc_request_trace (TRACE_LVL_1, "RETURNING FAILURE TO CANCEL REQUEST channel %d\n", channelID);
+ }
+ }
+ else
+ {
+ writeAck (requestID, channelID);
+ ipc_request_trace (TRACE_LVL_1, "RQ: --- %x ----- %x ---- %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
+ IPCrequest *nreq = new IPCrequest (nBytes, requestID, channelID);
+ nreq->read ();
+ ipc_request_trace (TRACE_LVL_1, "RQ: --- %x Read from stream \n", requestID);
+ if (cancelNeeded (channelID))
+ {
+ ipc_request_trace (TRACE_LVL_1, "CANCELLABLE REQ RECVD %x %x\n", channelID, requestID);
+ writeResponseGeneric (RESPONSE_STATUS_CANCELLED, requestID, channelID);
+ delete nreq;
+ return;
+ }
+ DbeQueue *q = new DbeQueue (ipc_doWork, nreq);
+ ipcThreadPool->put_queue (q);
+ }
+}
diff --git a/gprofng/src/ipcio.h b/gprofng/src/ipcio.h
new file mode 100644
index 0000000..94a635e
--- /dev/null
+++ b/gprofng/src/ipcio.h
@@ -0,0 +1,176 @@
+/* Copyright (C) 2021 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. */
+
+/* Defines the external interface between er_ipc and the routines */
+
+#ifndef _IPCIO_H
+#define _IPCIO_H
+#include <pthread.h>
+#include "gp-defs.h"
+#include "StringBuilder.h"
+
+class DbeThreadPool;
+typedef long long DbeObj;
+typedef void *Object;
+typedef char *String;
+
+#define BUFFER_SIZE_SMALL 512
+#define BUFFER_SIZE_MEDIUM 512
+#define BUFFER_SIZE_LARGE 1024*1024
+
+#define REQUEST_HAS_NO_BODY 0xFFFFFFFF
+#define RESPONSE_STATUS_DEFAULT 0
+#define RESPONSE_STATUS_SUCCESS 1
+#define RESPONSE_STATUS_FAILURE 2
+#define RESPONSE_STATUS_CANCELLED 3
+
+#define RESPONSE_TYPE_ACK 0
+#define RESPONSE_TYPE_PROGRESS 1
+#define RESPONSE_TYPE_COMPLETE 2
+#define RESPONSE_TYPE_HANDSHAKE 3
+#define HEADER_MARKER 0xff
+
+#define REQUEST_TYPE_DEFAULT 0
+#define REQUEST_TYPE_CANCEL 1
+#define REQUEST_TYPE_HANDSHAKE 2
+
+#define IPC_PROTOCOL_STR "IPC_PROTOCOL_38"
+#define IPC_VERSION_NUMBER 38
+
+enum IPCrequestStatus
+{
+ INITIALIZED = 0,
+ IN_PROGRESS,
+ COMPLETED,
+ CANCELLED_DEFAULT,
+ CANCELLED_IMMEDIATE
+};
+
+enum IPCTraceLevel
+{
+ TRACE_LVL_0 = 0,
+ TRACE_LVL_1,
+ TRACE_LVL_2,
+ TRACE_LVL_3,
+ TRACE_LVL_4
+};
+
+class IPCrequest
+{
+ char *buf;
+ int size;
+ int idx;
+ int requestID;
+ int channelID;
+ IPCrequestStatus status;
+ bool cancelImmediate;
+public:
+ IPCrequest (int, int, int);
+ ~IPCrequest ();
+ IPCrequestStatus getStatus ();
+ void setStatus (IPCrequestStatus);
+ void read ();
+
+ int getRequestID () { return requestID; }
+ int getChannelID () { return channelID; }
+ bool isCancelImmediate () { return cancelImmediate; }
+ void setCancelImmediate () { cancelImmediate = true; }
+ char rgetc () { return buf[idx++]; }
+};
+
+class IPCresponse
+{
+public:
+ IPCresponse (int sz);
+ ~IPCresponse ();
+
+ int getRequestID () { return requestID; }
+ int getChannelID () { return channelID; }
+ void setRequestID (int r) { requestID = r; }
+ void setChannelID (int c) { channelID = c; }
+ void setResponseType (int r) { responseType = r; }
+ void setResponseStatus (int s) { responseStatus = s; }
+ int getCurBufSize () { return sb->capacity (); }
+ void sendByte (int);
+ void sendIVal (int);
+ void sendLVal (long long);
+ void sendDVal (double);
+ void sendSVal (const char *);
+ void sendBVal (bool);
+ void sendCVal (char);
+ void sendAVal (void*);
+ void print (void);
+ void reset ();
+ IPCresponse *next;
+
+private:
+ int requestID;
+ int channelID;
+ int responseType;
+ int responseStatus;
+ StringBuilder *sb;
+};
+
+class BufferPool
+{
+public:
+ BufferPool ();
+ ~BufferPool ();
+ IPCresponse* getNewResponse (int);
+ void recycle (IPCresponse *);
+private:
+ pthread_mutex_t p_mutex;
+ IPCresponse *smallBuf;
+ IPCresponse *largeBuf;
+};
+
+// Read from the wire
+int readInt (IPCrequest*);
+bool readBoolean (IPCrequest*);
+long long readLong (IPCrequest*);
+DbeObj readObject (IPCrequest*);
+Object readArray (IPCrequest*);
+String readString (IPCrequest*);
+void readRequestHeader ();
+
+// write to the wire
+void writeString (const char *, IPCrequest*);
+void writeBoolean (bool, IPCrequest*);
+void writeInt (int, IPCrequest*);
+void writeChar (char, IPCrequest*);
+void writeLong (long long, IPCrequest*);
+void writeDouble (double, IPCrequest*);
+void writeArray (void *, IPCrequest*);
+void writeObject (DbeObj, IPCrequest*);
+void writeResponseGeneric (int, int, int);
+int setProgress (int, const char *); // Update the progress bar
+int ipc_doWork (void *); // The argument is an IPCrequest
+
+extern int ipc_flags;
+extern int ipc_single_threaded_mode;
+extern DbeThreadPool *responseThreadPool;
+extern DbeThreadPool *ipcThreadPool;
+extern int cancelRequestedChannelID;
+
+void ipc_default_log (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void ipc_response_log (IPCTraceLevel, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+void ipc_request_log (IPCTraceLevel, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+#endif
diff --git a/gprofng/src/machinemodels/generic.ermm b/gprofng/src/machinemodels/generic.ermm
new file mode 100644
index 0000000..19fcc8e
--- /dev/null
+++ b/gprofng/src/machinemodels/generic.ermm
@@ -0,0 +1,32 @@
+# generic machinemodel file
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+mobj_define Memory_page_size "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_address "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp (EA_LGRP)
+
+mobj_define Physical_page "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_address "(PADDR?(PADDR):-1)"
+
+#mobj_define Vpage_4K "(((ea_pagesize==1<<12 || !ea_pagesize) && VADDR>255)?(VADDR>>12<<12):-1)"
+#mobj_define Ppage_4K "((ea_pagesize==1<<12 && PADDR)?(PADDR>>12<<12):-1)"
diff --git a/gprofng/src/machinemodels/m5.ermm b/gprofng/src/machinemodels/m5.ermm
new file mode 100644
index 0000000..83f125d
--- /dev/null
+++ b/gprofng/src/machinemodels/m5.ermm
@@ -0,0 +1,65 @@
+# Machinemodel file for M5 systems
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+indxobj_define M5_Chip ((CPUID>>3)/6)
+indxobj_define M5_Core (CPUID>>3)
+
+mobj_define Memory_page_size "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp (EA_LGRP)
+
+mobj_define Physical_page "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+# further, meminfo() tends not to give us physical addresses
+
+#mobj_define M5_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define M5_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define M5_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define M5_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+
+#mobj_define M5_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define M5_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define M5_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define M5_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+
+#mobj_define M5_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0xFFFF):-1)"
+#mobj_define M5_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>22)&0x3FFFFFF):-1)"
+#mobj_define M5_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x3):-1)"
diff --git a/gprofng/src/machinemodels/m6.ermm b/gprofng/src/machinemodels/m6.ermm
new file mode 100644
index 0000000..1071e9e
--- /dev/null
+++ b/gprofng/src/machinemodels/m6.ermm
@@ -0,0 +1,65 @@
+# Machinemodel file for M6 systems
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+indxobj_define M6_Chip ((CPUID>>3)/12)
+indxobj_define M6_Core (CPUID>>3)
+
+mobj_define Memory_page_size "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp (EA_LGRP)
+
+mobj_define Physical_page "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+# further, meminfo() tends not to give us physical addresses
+
+#mobj_define M6_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define M6_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define M6_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define M6_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+
+#mobj_define M6_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define M6_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define M6_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define M6_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+
+#mobj_define M6_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0xFFFF):-1)"
+#mobj_define M6_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>22)&0x3FFFFFF):-1)"
+#mobj_define M6_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x3):-1)"
diff --git a/gprofng/src/machinemodels/m7.ermm b/gprofng/src/machinemodels/m7.ermm
new file mode 100644
index 0000000..29e3bef
--- /dev/null
+++ b/gprofng/src/machinemodels/m7.ermm
@@ -0,0 +1,64 @@
+# Machinemodel file for M7/T7 systems
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+indxobj_define M7_Chip (CPUID>>8)
+indxobj_define M7_Core (CPUID>>3)
+
+mobj_define Memory_page_size "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp (EA_LGRP)
+
+mobj_define Physical_page "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+#mobj_define Vpage_16G "((ea_pagesize==1<<34 && VADDR>255)?(VADDR>>34<<34):-1)"
+
+#mobj_define Ppage_8K "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+#mobj_define Ppage_16G "((ea_pagesize==1<<34 && PADDR)?(PADDR>>34<<34):-1)"
+
+# we dropped the *CacheTag definitions since:
+# - they're rarely used
+# - it's unclear if they are correct for S4
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+# further, meminfo() tends not to give us physical addresses
+
+#mobj_define M7_L1ICacheSet "((PHYSPC>>6)&0x3F)"
+#mobj_define M7_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+
+#mobj_define M7_L2ICacheSet "((((PHYSPC&0xFFFFFFFFFFF00FFF)|(((PHYSPC>>24)^(PHYSPC>>16)^(PHYSPC>>8)^PHYSPC)&0xFF000))>>6)&0x1FF)"
+#mobj_define M7_L2DCacheSet "(PADDR?((((PADDR&0x2000000000000)?PADDR:((PADDR&0xFFFFFFFFFFF00FFF)|(((PADDR>>24)^(PADDR>>16)^(PADDR>>8)^PADDR)&0xFF000)))>>6)&0x01FF):-1)"
+
+#mobj_define M7_L3DCacheSet "(PADDR?((((PADDR&0x2000000000000)?PADDR:((PADDR&0xFFFFFFFFFFF00FFF)|(((PADDR>>24)^(PADDR>>16)^(PADDR>>8)^PADDR)&0xFF000)))>>6)&0x3FFF):-1)"
+#mobj_define M7_L3DBank "(PADDR?((((PADDR&0x2000000000000)?PADDR:((PADDR&0xFFFFFFFFFFF00FFF)|(((PADDR>>24)^(PADDR>>16)^(PADDR>>8)^PADDR)&0xFF000)))>>6)&0x0001):-1)"
diff --git a/gprofng/src/machinemodels/t4.ermm b/gprofng/src/machinemodels/t4.ermm
new file mode 100644
index 0000000..e27f3a4
--- /dev/null
+++ b/gprofng/src/machinemodels/t4.ermm
@@ -0,0 +1,67 @@
+# Machinemodel file for T4 systems
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+indxobj_define T4_Chip (CPUID>>6)
+indxobj_define T4_Core (CPUID>>3)
+
+mobj_define Memory_page_size "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp (EA_LGRP)
+
+mobj_define Physical_page "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_512K "((ea_pagesize==1<<19 && VADDR>255)?(VADDR>>19<<19):-1)"
+#mobj_define Vpage_4M "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_512K "((ea_pagesize==1<<19 && PADDR)?(PADDR>>19<<19):-1)"
+#mobj_define Ppage_4M "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+# further, meminfo() tends not to give us physical addresses
+
+#mobj_define T4_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define T4_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define T4_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define T4_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+#mobj_define T4_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define T4_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define T4_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define T4_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+#mobj_define T4_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0xFFF):-1)"
+#mobj_define T4_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>18)&0x1FFFFFFF):-1)"
+#mobj_define T4_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x7):-1)"
+#mobj_define T4_2_Socket "(PADDR?((PADDR>>33)&0x1):-1)"
+#mobj_define T4_4_Socket "(PADDR?((PADDR>>33)&0x3):-1)"
diff --git a/gprofng/src/machinemodels/t5.ermm b/gprofng/src/machinemodels/t5.ermm
new file mode 100644
index 0000000..6d666a9
--- /dev/null
+++ b/gprofng/src/machinemodels/t5.ermm
@@ -0,0 +1,65 @@
+# Machinemodel file for T5 systems
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+indxobj_define T5_Chip (CPUID>>7)
+indxobj_define T5_Core (CPUID>>3)
+
+mobj_define Memory_page_size "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp (EA_LGRP)
+
+mobj_define Physical_page "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+# further, meminfo() tends not to give us physical addresses
+
+#mobj_define T5_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define T5_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define T5_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define T5_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+
+#mobj_define T5_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define T5_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define T5_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define T5_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+
+#mobj_define T5_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x1FFF):-1)"
+#mobj_define T5_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>19)&0x1FFFFFFF):-1)"
+#mobj_define T5_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x7):-1)"
diff --git a/gprofng/src/parse.cc b/gprofng/src/parse.cc
new file mode 100644
index 0000000..ab22270
--- /dev/null
+++ b/gprofng/src/parse.cc
@@ -0,0 +1,927 @@
+/* Copyright (C) 2021 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 <sys/param.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "DbeFile.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Emsg.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "PRBTree.h"
+#include "Sample.h"
+#include "Elf.h"
+
+void
+Experiment::mrec_insert (MapRecord *mrec)
+{
+ int sz = mrecs->size ();
+ MapRecord *tmp = sz > 0 ? mrecs->fetch (sz - 1) : NULL;
+
+ // The following should work in most cases
+ if (tmp == NULL || tmp->ts <= mrec->ts)
+ {
+ mrecs->append (mrec);
+ return;
+ }
+
+ // If it didn't...
+ int lo = 0;
+ int hi = sz - 1;
+ while (lo <= hi)
+ {
+ int md = (lo + hi) / 2;
+ tmp = mrecs->fetch (md);
+ if (tmp->ts < mrec->ts)
+ lo = md + 1;
+ else
+ hi = md - 1;
+ }
+ mrecs->insert (lo, mrec);
+}
+
+int
+Experiment::process_arglist_cmd (char *, char *arglist)
+{
+ uarglist = arglist;
+
+ // find argv[0], and extract its basename
+ if (strcmp (uarglist, NTXT ("(fork)")) == 0)
+ return 0; // leaving target name NULL
+ char *p = uarglist;
+ char *pp = uarglist;
+ char *pl;
+ for (;;)
+ {
+ if (*p == '/')
+ pp = p + 1;
+ if (*p == ' ' || *p == 0)
+ {
+ pl = p;
+ break;
+ }
+ p++;
+ }
+ size_t len = pl - pp;
+ if (len > 0)
+ utargname = dbe_sprintf (NTXT ("%.*s"), (int) len, pp);
+ return 0;
+}
+
+int
+Experiment::process_desc_start_cmd (char *, hrtime_t ts, char *flavor,
+ char *nexp, int follow, char *txt)
+{
+ char *str;
+ Emsg *m;
+
+ if (follow == 1)
+ str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, exp %s.er, \"%s\""),
+ flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+ nexp, txt);
+ else
+ str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, no experiment, \"%s\""),
+ flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+ txt);
+ m = new Emsg (CMSG_COMMENT, str);
+ free (str);
+ runlogq->append (m);
+
+ free (flavor);
+ free (nexp);
+ free (txt);
+ return 0;
+}
+
+int
+Experiment::process_desc_started_cmd (char *, hrtime_t ts, char *flavor,
+ char *nexp, int follow, char *txt)
+{
+ char *str;
+ Emsg *m;
+
+ if (follow == 1)
+ str = dbe_sprintf (GTXT ("Started %s %ld.%09ld, exp %s.er, \"%s\""),
+ flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+ nexp, txt);
+ else
+ str = dbe_sprintf (GTXT ("Started %s %ld.%09ld, no experiment, \"%s\""),
+ flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+ txt);
+ m = new Emsg (CMSG_COMMENT, str);
+ free (str);
+ runlogq->append (m);
+ free (flavor);
+ free (nexp);
+ free (txt);
+ return 0;
+}
+
+LoadObject *
+Experiment::get_dynfunc_lo (const char *loName)
+{
+ LoadObject *lo = loadObjMap->get (loName);
+ if (lo == NULL)
+ {
+ lo = createLoadObject (loName, expIdx);// DYNFUNC_SEGMENT is always unique
+ lo->dbeFile->filetype |= DbeFile::F_FICTION;
+ lo->flags |= SEG_FLAG_DYNAMIC;
+ lo->type = LoadObject::SEG_TEXT;
+ lo->set_platform (platform, wsize);
+ append (lo);
+ }
+ return lo;
+}
+
+Function *
+Experiment::create_dynfunc (Module *mod, char *fname, int64_t vaddr,
+ int64_t fsize)
+{
+ Function *f = dbeSession->createFunction ();
+ f->set_name (fname);
+ f->flags |= FUNC_FLAG_DYNAMIC;
+ f->size = fsize;
+ f->img_offset = vaddr;
+ f->module = mod;
+ mod->functions->append (f);
+ mod->loadobject->functions->append (f);
+ return f;
+}
+
+static int
+func_cmp (const void *a, const void *b)
+{
+ Function *fp1 = *((Function **) a);
+ Function *fp2 = *((Function **) b);
+ uint64_t i1 = fp1->img_offset;
+ uint64_t i2 = fp2->img_offset;
+ return i1 < i2 ? -1 : i1 == i2 ? 0 : 1;
+}
+
+int
+Experiment::process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr,
+ int fsize, hrtime_t ts)
+{
+ Dprintf (DEBUG_MAPS,
+ "process_fn_load_cmd:%s (%s) vaddr=0x%llx msize=%lld ts=%lld\n",
+ STR (mod ? mod->get_name () : NULL), STR (fname),
+ (unsigned long long) vaddr, (long long) fsize, (long long) ts);
+ if (mod != NULL)
+ {
+ mod->functions->sort (func_cmp);
+ uint64_t lastVaddr = vaddr;
+ for (int i = 0, sz = mod->functions->size (); i < sz; i++)
+ {
+ Function *f = mod->functions->fetch (i);
+ if (lastVaddr < f->img_offset)
+ {
+ char *fnm = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"),
+ (unsigned long long) lastVaddr, fname);
+ create_dynfunc (mod, fnm, lastVaddr, f->img_offset - lastVaddr);
+ free (fnm);
+ }
+ lastVaddr = f->img_offset + f->size;
+ }
+ if (lastVaddr < vaddr + fsize)
+ {
+ char *fnm = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"),
+ (unsigned long long) lastVaddr, fname);
+ create_dynfunc (mod, fnm, lastVaddr, vaddr + fsize - lastVaddr);
+ free (fnm);
+ }
+ mod->functions->sort (func_cmp);
+ for (int i = 0, sz = mod->functions->size (); i < sz; i++)
+ {
+ Function *f = mod->functions->fetch (i);
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::LOAD;
+ mrec->obj = f;
+ mrec->base = f->img_offset;
+ mrec->size = f->size;
+ mrec->ts = ts;
+ mrec->foff = 0;
+ mrec_insert (mrec);
+ }
+ return 0;
+ }
+
+ LoadObject *ds = get_dynfunc_lo (DYNFUNC_SEGMENT);
+ Function *dfunc = create_dynfunc (ds->noname, fname, vaddr, fsize);
+
+ // check for special functions, USER, IDLE, TRUNC to disable offsets in disassembly
+ // XXX -- check based on name now
+ // Optimization: use pre-initialized localized strings
+ static const char * localized_USER_MODE = NULL;
+ static const char * localized_IDLE = NULL;
+ static const char * localized_TRUNCATED_STACK = NULL;
+ if (localized_USER_MODE == NULL)
+ {
+ localized_USER_MODE = GTXT ("<USER_MODE>");
+ localized_IDLE = GTXT ("<IDLE>");
+ localized_TRUNCATED_STACK = GTXT ("<TRUNCATED_STACK>");
+ }
+ if (strcmp (fname, localized_USER_MODE) == 0
+ || strcmp (fname, localized_IDLE) == 0
+ || strcmp (fname, localized_TRUNCATED_STACK) == 0)
+ dfunc->flags |= FUNC_FLAG_NO_OFFSET;
+
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::LOAD;
+ mrec->obj = dfunc;
+ mrec->base = vaddr;
+ mrec->size = fsize;
+ mrec->ts = ts;
+ mrec->foff = 0;
+ mrec_insert (mrec);
+ return 0;
+}
+
+int
+Experiment::process_fn_unload_cmd (char *, Vaddr vaddr, hrtime_t ts)
+{
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::UNLOAD;
+ mrec->base = vaddr;
+ mrec->ts = ts;
+ mrec_insert (mrec);
+ return 0;
+}
+
+void
+Experiment::register_metric (Metric::Type type)
+{
+ BaseMetric *mtr = dbeSession->register_metric (type);
+ metrics->append (mtr);
+}
+
+void
+Experiment::register_metric (Hwcentry *ctr, const char* aux, const char* uname)
+{
+ BaseMetric *mtr = dbeSession->register_metric (ctr, aux, uname);
+ metrics->append (mtr);
+ if (mtr->get_dependent_bm ())
+ metrics->append (mtr->get_dependent_bm ());
+}
+
+int
+Experiment::process_hwcounter_cmd (char *, int cpuver, char *counter,
+ char * int_name, int interval, int tag,
+ int i_tpc, char *modstr)
+{
+ char *str;
+ Emsg *m;
+ Hwcentry *ctr;
+ ABST_type tpc = (ABST_type) i_tpc;
+
+ // Use previously ignored tag to associate counter packets.
+ if (tag < 0 || tag >= MAX_HWCOUNT)
+ {
+ // invalid tag specified, warn user
+ str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"),
+ tag, 0, MAX_HWCOUNT - 1);
+ m = new Emsg (CMSG_ERROR, str);
+ free (str);
+ errorq->append (m);
+ free (counter);
+ return 0;
+ }
+ if (coll_params.hw_aux_name[tag])
+ {
+ // duplicate tag used, warn user
+ str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"),
+ tag);
+ m = new Emsg (CMSG_ERROR, str);
+ free (str);
+ errorq->append (m);
+ free (counter);
+ return 0;
+ }
+ hw_cpuver = cpuver;
+
+ // map it to a machinemodel string
+ if (hw_cpuver != CPUVER_UNDEFINED)
+ {
+ free (machinemodel);
+ if (hw_cpuver == 1104)
+ machinemodel = dbe_strdup (NTXT ("t4"));
+ else if (hw_cpuver == 1110)
+ machinemodel = dbe_strdup (NTXT ("t5"));
+ else if (hw_cpuver == 1204)
+ machinemodel = dbe_strdup (NTXT ("m4"));
+ else if (hw_cpuver == 1210)
+ machinemodel = dbe_strdup (NTXT ("m5"));
+ else if (hw_cpuver == 1220)
+ machinemodel = dbe_strdup (NTXT ("m6"));
+ else if (hw_cpuver == 1230)
+ machinemodel = dbe_strdup (NTXT ("m7"));
+ else
+ machinemodel = dbe_strdup (NTXT ("generic"));
+ }
+
+ // Find the entry in the machine table, and dup it
+ ctr = new Hwcentry;
+ dbeSession->append (ctr);
+ hwc_post_lookup (ctr, counter, int_name, cpuver);
+ ctr->sort_order = tag;
+ ctr->memop = tpc;
+
+ // Check if HWC name is to be modified
+ if (modstr != NULL)
+ {
+ char *s = ctr->name;
+ ctr->name = dbe_sprintf (NTXT ("%s%s"), modstr, s);
+ s = ctr->int_name;
+ ctr->int_name = dbe_sprintf (NTXT ("%s%s"), modstr, s);
+ s = ctr->metric;
+ if (s)
+ ctr->metric = dbe_sprintf (NTXT ("%s%s"), modstr, s);
+ }
+
+ char * cname = dbe_strdup (ctr->name);
+ char * uname = dbe_strdup (hwc_i18n_metric (ctr));
+ coll_params.hw_aux_name[tag] = cname;
+ coll_params.hw_username[tag] = uname;
+ coll_params.hw_interval[tag] = interval;
+ coll_params.hw_tpc[tag] = tpc;
+ coll_params.hw_cpu_ver[tag] = cpuver;
+
+ // set hw_mode and xhw_mode?
+ coll_params.hw_mode = 1;
+ if (ABST_MEMSPACE_ENABLED (tpc))
+ {
+ // yes, dataspace data available
+ coll_params.xhw_mode = 1;
+
+ // set dataspace available
+ dataspaceavail = true;
+ }
+ register_metric (ctr, cname, uname);
+ free (counter);
+ return 0;
+}
+
+// TBR:?
+
+int
+Experiment::process_hwsimctr_cmd (char *, int cpuver, char *nm, char *int_name,
+ char *metric, int reg,
+ int interval, int timecvt, int i_tpc, int tag)
+{
+ char *str;
+ Emsg *m;
+ Hwcentry *ctr;
+ ABST_type tpc = (ABST_type) i_tpc;
+
+ // Use previously ignored tag to associate counter packets.
+ if (tag < 0 || tag >= MAX_HWCOUNT)
+ {
+ // invalid tag specified, warn user
+ str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"),
+ tag, 0, MAX_HWCOUNT - 1);
+ m = new Emsg (CMSG_ERROR, str);
+ free (str);
+ errorq->append (m);
+
+ free (nm);
+ free (int_name);
+ free (metric);
+ return 0;
+ }
+ if (coll_params.hw_aux_name[tag])
+ {
+ // duplicate tag used, warn user
+ str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"),
+ tag);
+ m = new Emsg (CMSG_ERROR, str);
+ free (str);
+ errorq->append (m);
+ free (nm);
+ free (int_name);
+ free (metric);
+ return 0;
+ }
+ hw_cpuver = cpuver;
+ ctr = new Hwcentry;
+ {
+ static Hwcentry empty;
+ *ctr = empty;
+ }
+ ctr->name = nm;
+ ctr->int_name = int_name;
+ ctr->metric = metric;
+ ctr->reg_num = reg;
+ ctr->val = interval;
+ ctr->timecvt = timecvt;
+ ctr->memop = tpc;
+ ctr->sort_order = tag;
+
+ char *cname = dbe_strdup (ctr->name);
+ char *uname = dbe_strdup (hwc_i18n_metric (ctr));
+
+ coll_params.hw_aux_name[tag] = cname;
+ coll_params.hw_username[tag] = uname;
+ coll_params.hw_interval[tag] = interval;
+ coll_params.hw_tpc[tag] = tpc;
+ coll_params.hw_cpu_ver[tag] = cpuver;
+
+ // set hw_mode and xhw_mode?
+ coll_params.hw_mode = 1;
+ if (ABST_MEMSPACE_ENABLED (tpc))
+ {
+ coll_params.xhw_mode = 1;
+ // set dataspace available
+ if (getenv ("ANALYZER_DATASPACE_COUNT") != 0)
+ dataspaceavail = true;
+ }
+
+ register_metric (ctr, cname, uname);
+ return 0;
+}
+
+int
+Experiment::process_jcm_load_cmd (char *, Vaddr mid, Vaddr vaddr,
+ int msize, hrtime_t ts)
+{
+ if (jmaps == NULL)
+ return 1;
+
+ JMethod *jfunc = (JMethod*) jmaps->locate_exact_match (mid, ts);
+ if (jfunc == NULL || jfunc->get_type () != Histable::FUNCTION)
+ return 1;
+
+ LoadObject *ds = get_dynfunc_lo (JAVA_COMPILED_METHODS);
+ Module *jmodule = jfunc->module;
+ Module *dmodule = ds->noname;
+ if (jmodule)
+ {
+ dmodule = dbeSession->createModule (ds, jmodule->get_name ());
+ dmodule->lang_code = Sp_lang_java;
+ dmodule->set_file_name (dbe_strdup (jmodule->file_name));
+ }
+
+ JMethod *dfunc = dbeSession->createJMethod ();
+ dfunc->flags |= FUNC_FLAG_DYNAMIC;
+ dfunc->size = msize;
+ dfunc->module = dmodule;
+ dfunc->usrfunc = jfunc;
+ dfunc->set_addr (vaddr);
+ dfunc->set_mid (mid);
+ dfunc->set_signature (jfunc->get_signature ());
+ dfunc->set_name (jfunc->get_mangled_name ());
+ ds->functions->append (dfunc);
+ dmodule->functions->append (dfunc);
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::LOAD;
+ mrec->obj = dfunc;
+ mrec->base = vaddr;
+ mrec->size = msize;
+ mrec->ts = ts;
+ mrec->foff = 0;
+ mrec_insert (mrec);
+ return 0;
+}
+
+int
+Experiment::process_jcm_unload_cmd (char *, Vaddr /*mid*/, hrtime_t /*ts*/)
+{
+ if (jmaps == NULL)
+ return 1;
+
+ // We are ignoring this record because of the flaw in
+ // JVMPI desing that doesn't distinguish between two or more
+ // compiled instances of a method when an unload event is
+ // generated:
+ // JVMPI_COMPILED_METHOD_LOAD( mid, addr1, ... )
+ // JVMPI_COMPILED_METHOD_LOAD( mid, addr2, ... )
+ // JVMPI_COMPILED_METHOD_UNLOAD( mid ) -- which one?
+ // We rely on the ability of the PRBTree algorithms to
+ // perform mapping appropriately based on timestamps.
+ return 0;
+}
+
+int
+Experiment::process_jthr_end_cmd (char *, uint64_t tid64, Vaddr jthr,
+ Vaddr jenv, hrtime_t ts)
+{
+ int lt = 0;
+ int rt = jthreads_idx->size () - 1;
+ uint32_t ttid = mapTagValue (PROP_THRID, tid64);
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ JThread *jthread = jthreads_idx->fetch (md);
+ if (jthread->tid < ttid)
+ lt = md + 1;
+ else if (jthread->tid > ttid)
+ rt = md - 1;
+ else
+ {
+ for (; jthread; jthread = jthread->next)
+ {
+ if (jthread->jenv == jenv)
+ {
+ jthread->end = ts;
+ return 0;
+ }
+ }
+ return 0;
+ }
+ }
+ JThread *jthread = new JThread;
+ jthread->tid = mapTagValue (PROP_THRID, tid64);
+ jthread->jthr = jthr;
+ jthread->jenv = jenv;
+ jthread->jthr_id = jthreads->size ();
+ jthread->start = ZERO_TIME;
+ jthread->end = ts;
+ jthread->next = NULL;
+ jthreads->append (jthread);
+ if (lt == jthreads_idx->size ())
+ jthreads_idx->append (jthread);
+ else
+ jthreads_idx->insert (lt, jthread);
+ return 0;
+}
+
+int
+Experiment::process_jthr_start_cmd (char *, char *thread_name, char *group_name,
+ char *parent_name, uint64_t tid64,
+ Vaddr jthr, Vaddr jenv, hrtime_t ts)
+{
+ JThread *jthread = new JThread;
+ jthread->name = thread_name;
+ jthread->group_name = group_name;
+ jthread->parent_name = parent_name;
+ jthread->tid = mapTagValue (PROP_THRID, tid64);
+ jthread->jthr = jthr;
+ jthread->jenv = jenv;
+ jthread->jthr_id = jthreads->size ();
+ jthread->start = ts;
+ jthread->end = MAX_TIME;
+ jthread->next = NULL;
+
+ jthreads->append (jthread);
+
+ int lt = 0;
+ int rt = jthreads_idx->size () - 1;
+ while (lt <= rt)
+ {
+ int md = (lt + rt) / 2;
+ JThread *jtmp = jthreads_idx->fetch (md);
+ if (jtmp->tid < jthread->tid)
+ lt = md + 1;
+ else if (jtmp->tid > jthread->tid)
+ rt = md - 1;
+ else
+ {
+ jthread->next = jtmp;
+ jthreads_idx->store (md, jthread);
+ return 0;
+ }
+ }
+ if (lt == jthreads_idx->size ())
+ jthreads_idx->append (jthread);
+ else
+ jthreads_idx->insert (lt, jthread);
+ return 0;
+}
+
+int
+Experiment::process_gc_end_cmd (
+ hrtime_t ts)
+{
+ if (gcevents->size () == 0)
+ {
+ GCEvent *gcevent = new GCEvent;
+ gcevent->start = ZERO_TIME;
+ gcevent->end = ts;
+ gcevent->id = gcevents->size () + 1;
+ gcevents->append (gcevent);
+ return 0;
+ }
+ GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1);
+ if (gcevent->end == MAX_TIME)
+ gcevent->end = ts;
+ else
+ // Weird: gc_end followed by another gc_end
+ gcevent->end = ts; // extend the previous event
+ return 0;
+}
+
+int
+Experiment::process_gc_start_cmd (
+ hrtime_t ts)
+{
+ if (gcevents->size () != 0)
+ {
+ GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1);
+ // Weird: gc_start followed by another gc_start
+ if (gcevent->end == MAX_TIME)
+ return 0; // ignore nested gc_starts
+ }
+ GCEvent *gcevent = new GCEvent;
+ gcevent->start = ts;
+ gcevent->end = MAX_TIME;
+ gcevent->id = gcevents->size () + 1;
+ gcevents->append (gcevent);
+ return 0;
+}
+
+int
+Experiment::process_sample_cmd (char */*cmd*/, hrtime_t /*log_xml_time*/,
+ int sample_number, char *label)
+{
+ // sample 0 is not a sample but the starting point
+ if (sample_number == 0)
+ {
+ first_sample_label = label;
+ return 0;
+ }
+ Sample *prev_sample = samples->size () > 0 ?
+ samples->fetch (samples->size () - 1) : NULL;
+ char *start_lable = prev_sample ?
+ prev_sample->end_label : first_sample_label;
+ Sample *sample = new Sample (sample_number);
+ sample->start_label = dbe_strdup (start_lable);
+ sample->end_label = label;
+ samples->append (sample);
+ return 0;
+}
+
+int
+Experiment::process_sample_sig_cmd (char *, int sig)
+{
+ char *str;
+ Emsg *m;
+ str = dbe_sprintf (GTXT ("Sample signal %d"), sig);
+ m = new Emsg (CMSG_COMMENT, str);
+ free (str);
+ runlogq->append (m);
+ return 0;
+}
+
+int
+Experiment::process_seg_map_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr,
+ int mapsize, int /*pagesize*/, int64_t offset,
+ int64_t modeflags, int64_t chk, char *nm)
+{
+ if (nm == NULL ||
+ strncmp (nm + 1, SP_MAP_UNRESOLVABLE, strlen (SP_MAP_UNRESOLVABLE)) == 0)
+ return 0;
+
+ LoadObject *lo = loadObjMap->get (nm);
+ if (lo == NULL)
+ {
+ if (chk == 0)
+ {
+ char *archName = checkFileInArchive (nm, false);
+ if (archName)
+ {
+ Elf *elf = new Elf (archName);
+ if (elf->status == Elf::ELF_ERR_NONE)
+ {
+ chk = elf->elf_checksum ();
+ }
+ free (archName);
+ delete elf;
+ }
+ }
+ lo = dbeSession->find_lobj_by_name (nm, chk);
+ if (lo == NULL)
+ {
+ // Skip non-text segments
+ if (modeflags != (PROT_READ | PROT_EXEC))
+ return 0;
+ // A new segment
+ lo = createLoadObject (nm, chk);
+ if (strstr (nm, NTXT ("libjvm.so")))
+ {
+ lo->flags |= SEG_FLAG_JVM;
+ // Make sure <JVM-System> is created
+ (void) dbeSession->get_jvm_Function ();
+ }
+ else if (strstr (nm, NTXT ("libmtsk.so")))
+ {
+ lo->flags |= SEG_FLAG_OMP;
+ // Make sure all pseudo functions are created
+ for (int i = 0; i < OMP_LAST_STATE; i++)
+ (void) dbeSession->get_OMP_Function (i);
+ }
+ else if (dbe_strcmp (utargname, get_basename (nm)) == 0)
+ {
+ lo->flags |= SEG_FLAG_EXE;
+ (void) dbeSession->comp_lobjs->get ((char *) COMP_EXE_NAME, lo);
+ }
+ lo->checksum = chk;
+ // This is the default segment type
+ lo->type = LoadObject::SEG_TEXT;
+ lo->flags = lo->flags | SEG_FLAG_REORDER;
+ lo->set_platform (platform, wsize);
+ }
+ if (lo->dbeFile->get_location (false) == NULL)
+ {
+ char *archName = checkFileInArchive (nm, false);
+ if (archName)
+ {
+ lo->dbeFile->set_location (archName);
+ lo->dbeFile->inArchive = true;
+ lo->dbeFile->check_access (archName); // init 'sbuf'
+ lo->dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
+ free (archName);
+ }
+ else
+ {
+ archName = checkFileInArchive (nm, true);
+ if (archName)
+ {
+ lo->set_archname (archName);
+ lo->need_swap_endian = need_swap_endian;
+ }
+ }
+ if (!dbeSession->archive_mode)
+ lo->sync_read_stabs ();
+ }
+ append (lo);
+ }
+ if (lo->size == 0)
+ lo->size = mapsize;
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::LOAD;
+ mrec->obj = lo;
+ mrec->base = vaddr;
+ mrec->size = mapsize;
+ mrec->ts = ts;
+ mrec->foff = offset;
+ mrec_insert (mrec);
+ return 0;
+}
+
+int
+Experiment::process_seg_unmap_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr)
+{
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::UNLOAD;
+ mrec->base = vaddr;
+ mrec->ts = ts;
+ mrec_insert (mrec);
+ return 0;
+}
+
+int
+Experiment::process_Linux_kernel_cmd (hrtime_t ts)
+{
+ LoadObject *lo = createLoadObject ("LinuxKernel");
+ lo->flags |= SEG_FLAG_EXE;
+ lo->type = LoadObject::SEG_TEXT;
+ lo->set_platform (platform, wsize);
+ append (lo);
+ long long unsigned lo_min = (long long unsigned) (-1);
+ long long unsigned lo_max = 0;
+ Module *mod = dbeSession->createModule (lo, "LinuxKernel");
+ /*
+ * XXX need to review mod initialization
+ * A specific issue is mod->file_name. Options include:
+ * *) NULL
+ * This leads to seg faults in, e.g., Timeline view.
+ * *) "/lib/modules/$(uname -r)/kernel/kernel/ctf/ctf.ko"
+ * This leads to garbage in the Source view.
+ * *) "/boot/vmlinuz-$(uname -r)"
+ * This cannot be parsed for DWARF and is sometimes not found,
+ * but the Analyzer seems to handle such problems.
+ * *) "LinuxKernel"
+ * This is not a proper file name,
+ * but again Analyzer handles the case of not finding the file or not reading DWARF from it.
+ */
+ mod->set_file_name (dbe_strdup ("LinuxKernel"));
+ char last_mod_name[256];
+ last_mod_name[0] = '\0';
+ size_t line_n = 0;
+ char *line = NULL;
+ char kallmodsyms_copy[MAXPATHLEN];
+ snprintf (kallmodsyms_copy, sizeof (kallmodsyms_copy), "%s/kallmodsyms",
+ expt_name);
+ FILE *fd = fopen (kallmodsyms_copy, "r");
+ if (fd == NULL)
+ {
+ char *s = dbe_sprintf (GTXT ("*** Error: Cannot find kernel module symbols file %s; ignored"),
+ kallmodsyms_copy);
+ Emsg *m = new Emsg (CMSG_ERROR, s);
+ free (s);
+ errorq->append (m);
+ lo_min = 0;
+ }
+ else
+ {
+ while (getline (&line, &line_n, fd) > 0)
+ {
+ long long unsigned sym_addr;
+ long long unsigned sym_size;
+ char sym_type;
+ int sym_text;
+ char sym_name[256];
+ char mod_name[256] = "vmlinux]"; /* note trailing ] */
+ sscanf (line, "%llx %llx %c %s [%s", &sym_addr, &sym_size, &sym_type,
+ sym_name, mod_name);
+ if (line[0] == '\n' || line[0] == 0)
+ continue;
+ sym_text = (sym_type == 't' || sym_type == 'T');
+ mod_name[strlen (mod_name) - 1] = '\0'; /* chop trailing ] */
+ if (strcmp (mod_name, "ctf") == 0)
+ strcpy (mod_name, "shared_ctf");
+
+ char *mod_name_ptr;
+ int skip;
+#define strstarts(var, x) (strncmp(var, x, strlen (x)) == 0)
+ if (strcmp (sym_name, "__per_cpu_start") == 0
+ || strcmp (sym_name, "__per_cpu_end") == 0
+ || strstarts (sym_name, "__crc_")
+ || strstarts (sym_name, "__ksymtab_")
+ || strstarts (sym_name, "__kcrctab_")
+ || strstarts (sym_name, "__kstrtab_")
+ || strstarts (sym_name, "__param_")
+ || strstarts (sym_name, "__syscall_meta__")
+ || strstarts (sym_name, "__p_syscall_meta__")
+ || strstarts (sym_name, "__event_")
+ || strstarts (sym_name, "event_")
+ || strstarts (sym_name, "ftrace_event_")
+ || strstarts (sym_name, "types__")
+ || strstarts (sym_name, "args__")
+ || strstarts (sym_name, "__tracepoint_")
+ || strstarts (sym_name, "__tpstrtab_")
+ || strstarts (sym_name, "__tpstrtab__")
+ || strstarts (sym_name, "__initcall_")
+ || strstarts (sym_name, "__setup_")
+ || strstarts (sym_name, "__pci_fixup_")
+ || strstarts (sym_name, "__dta_")
+ || strstarts (sym_name, "__dtrace_probe_")
+ || (strstr (sym_name, ".") != NULL
+ && strstr (sym_name, ".clone.") == NULL))
+ {
+ mod_name_ptr = last_mod_name;
+ skip = 1;
+ }
+ else
+ {
+ mod_name_ptr = mod_name;
+ skip = 0;
+ }
+#undef strstarts
+
+ if (sym_text && skip == 0)
+ {
+ char fname[128];
+ snprintf (fname, sizeof (fname), "%s`%s", mod_name_ptr, sym_name);
+ Function *func = dbeSession->createFunction ();
+ func->set_name (fname);
+ // func->flags |= FUNC_FLAG_???; // XXX
+ func->size = sym_size;
+ func->img_offset = sym_addr;
+ func->module = mod;
+ lo->functions->append (func);
+ mod->functions->append (func);
+ if (lo_min > sym_addr)
+ lo_min = sym_addr;
+ if (lo_max < sym_addr + sym_size)
+ lo_max = sym_addr + sym_size;
+ }
+ sprintf (last_mod_name, mod_name_ptr);
+ }
+ fclose (fd);
+ }
+ free (line);
+ lo->size = lo_max;
+ lo->functions->sort (func_cmp);
+ mod->functions->sort (func_cmp);
+
+ MapRecord *mrec = new MapRecord;
+ mrec->kind = MapRecord::LOAD;
+ mrec->obj = lo;
+ mrec->base = lo_min;
+ mrec->size = lo_max - lo_min;
+ mrec->ts = ts;
+ mrec->foff = lo_min;
+ mrec_insert (mrec);
+ return 0;
+}
diff --git a/gprofng/src/stab.h b/gprofng/src/stab.h
new file mode 100644
index 0000000..4610105
--- /dev/null
+++ b/gprofng/src/stab.h
@@ -0,0 +1,205 @@
+/* Copyright (C) 2021 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. */
+
+/*
+ * This file gives definitions supplementing <a.out.h>
+ * for debugging symbol table entries.
+ * These entries must have one of the N_STAB bits on,
+ * and are subject to relocation according to the masks in <a.out.h>
+ * on 4.x (stabs not relocated on SVR4).
+ */
+
+#ifndef _STAB_H
+#define _STAB_H
+
+/* this file also contains fragments of a.out.h relevant to
+ * support of stab processing within ELF files
+ * (when a.out.h is not available)
+ */
+struct stab
+{
+ unsigned n_strx; /* index into file string table */
+ unsigned char n_type; /* type flag (N_TEXT,..) */
+ char n_other; /* used by N_SLINE stab */
+ short n_desc; /* see stabs documentation */
+ unsigned n_value; /* value of symbol (or sdb offset) */
+};
+
+/* patchtypes for N_PATCH stab (n_desc field) */
+#define P_BITFIELD 0x1
+#define P_SPILL 0x2
+#define P_SCOPY 0x3
+
+/* markers for N_CODETAG stab (n_other field) */
+#define CODETAG_BITFIELD 0x1 /* load/store of a bit field */
+#define CODETAG_SPILL 0x2 /* spill of registers */
+#define CODETAG_SCOPY 0x3 /* structure copy load/store */
+#define CODETAG_FSTART 0x4 /* points to first inst of new frame (0==leaf)*/
+#define CODETAG_END_CTORS 0x5 /* end of calls to super-class constructors */
+/* UNUSED 0x6 DW_ATCF_SUN_branch_target in dwarf, not used in stabs */
+#define CODETAG_STACK_PROBE 0x7 /* marks insns which probe the stack memory */
+
+/*
+ * Simple values for n_type.
+ */
+#define N_UNDF 0x0 /* undefined */
+#define N_ABS 0x2 /* absolute */
+#define N_TEXT 0x4 /* text */
+#define N_DATA 0x6 /* data */
+#define N_BSS 0x8 /* bss */
+#define N_COMM 0x12 /* common (internal to ld) */
+#define N_FN 0x1f /* file name symbol */
+#define N_EXT 01 /* external bit, or'ed in */
+#define N_TYPE 0x1e /* mask for all the type bits */
+
+/*
+ * maximum length of stab string before using continuation stab.
+ * (this is just a suggested limit), assembler has no limit.
+ */
+#define MAX_STAB_STR_LEN 250
+
+/*
+ * for symbolic debuggers:
+ */
+#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */
+#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */
+#define N_FUN 0x24 /* procedure: name,,0,linenumber,0 */
+#define N_OUTL 0x25 /* outlined func: name,,0,linenumber,0 */
+#define N_STSYM 0x26 /* static symbol: name,,0,type,0 or section relative */
+#define N_TSTSYM 0x27 /* thread static symbol: Ttdata.data */
+#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,0 or section relative */
+#define N_TLCSYM 0x29 /* thread local symbol: Ttbss.bss */
+#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */
+#define N_ROSYM 0x2c /* ro_data: name,,0,type,0 or section relative */
+#define N_FLSYM 0x2e /* fragmented data: name,,0,type,0 */
+#define N_TFLSYM 0x2f /* thread fragmented data: name,,0,type,0 */
+#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */
+#define N_CMDLINE 0x34 /* command line info */
+#define N_OBJ 0x38 /* object file path or name */
+#define N_OPT 0x3c /* compiler options */
+#define N_RSYM 0x40 /* register sym: name,,0,type,register */
+#define N_SLINE 0x44 /* src line: 0,,0,linenumber,function relative */
+#define N_XLINE 0x45 /* h.o. src line: 0,,0,linenumber>>16,0 */
+#define N_ILDPAD 0x4c /* now used as ild pad stab value=strtab delta
+ * was designed for "function start.end" */
+#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */
+#define N_ENDM 0x62 /* last stab emitted for object module */
+#define N_SO 0x64 /* source file name: name,,0,0,0 */
+#define N_MOD 0x66 /* f90 module: name,,0,0,0 */
+#define N_EMOD 0x68 /* end of f90 module: name,,0,0,0 */
+#define N_READ_MOD 0x6a /* use of f90 module: name;locallist,,0,0,0 */
+#define N_ALIAS 0x6c /* alias name: name,,0,0,0 */
+#define N_LSYM 0x80 /* local sym: name,,0,type,offset */
+#define N_BINCL 0x82 /* header file: name,,0,0,0 */
+#define N_SOL 0x84 /* #included file name: name,,0,0,0 */
+#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */
+#define N_EINCL 0xa2 /* end of include file */
+#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,0 */
+#define N_SINCL 0xa6 /* shared include file */
+#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,function relative */
+#define N_EXCL 0xc2 /* excluded include file */
+#define N_USING 0xc4 /* C++ using command */
+#define N_ISYM 0xc6 /* position independent type symbol, internal */
+#define N_ESYM 0xc8 /* position independent type symbol, external */
+#define N_PATCH 0xd0 /* Instruction to be ignored by run-time checking. */
+#define N_CONSTRUCT 0xd2 /* C++ constructor call. */
+#define N_DESTRUCT 0xd4 /* C++ destructor call. */
+#define N_CODETAG 0xd8 /* Generic code tag */
+#define N_FUN_CHILD 0xd9 /* Identifies a child function */
+#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,function relative */
+#define N_BCOMM 0xe2 /* begin common: name,, */
+#define N_TCOMM 0xe3 /* begin task common: name,, */
+#define N_ECOMM 0xe4 /* end task_common/common: name,, */
+#define N_XCOMM 0xe6 /* excluded common block */
+#define N_ECOML 0xe8 /* end common (local name): ,,address */
+#define N_WITH 0xea /* pascal with statement: type,,0,0,offset */
+#define N_LENG 0xfe /* second stab entry with length information */
+
+/*
+ * for analyzer (cache profile feedback support)
+ */
+#define N_CPROF 0xf0 /* annotation for cache profile feedback */
+
+/*
+ * n_descr values used in N_CPROF stabs. The n_descr field of
+ * an N_CPROF stab identifies the type of table whose location
+ * is defined by the N_CPROF stab.
+ */
+typedef enum n_cprof_instr_type_t
+{
+ N_CPROF_INSTR_TYPE_LOAD = 0, /* profiled load ops */
+ N_CPROF_INSTR_TYPE_STORE, /* profiled store ops */
+ N_CPROF_INSTR_TYPE_PREFETCH, /* profiled prefetch ops */
+ N_CPROF_INSTR_TYPE_BRTARGET, /* branch target locations */
+ N_CPROF_INSTR_TYPE_NTYPES /* number of types */
+} n_cprof_instr_type_t;
+
+/*
+ * for code browser only
+ */
+#define N_BROWS 0x48 /* path to associated .cb file */
+
+/*
+ * for functions -- n_other bits for N_FUN stab
+ */
+#define N_FUN_PURE (1 << 0)
+#define N_FUN_ELEMENTAL (1 << 1)
+#define N_FUN_RECURSIVE (1 << 2)
+#define N_FUN_AMD64_PARMDUMP (1 << 3)
+
+/*
+ * for variables -- n_other bits for N_LSYM, N_GSYM, N_LCSYM, N_STSYM, ...
+ */
+#define N_SYM_OMP_TLS (1 << 3)
+
+/*
+ * Optional language designations for N_SO (n_desc field)
+ */
+#define N_SO_AS 1 /* Assembler */
+#define N_SO_C 2 /* C */
+#define N_SO_ANSI_C 3 /* ANSI C */
+#define N_SO_CC 4 /* C++ */
+#define N_SO_FORTRAN 5 /* Fortran 77 */
+#define N_SO_FORTRAN77 5 /* Fortran 77 */
+#define N_SO_PASCAL 6 /* Pascal */
+#define N_SO_FORTRAN90 7 /* Fortran 90 */
+#define N_SO_JAVA 8 /* Java */
+#define N_SO_C99 9 /* C99 */
+
+/*
+ * Floating point type values (encoded in "R" type specification string)
+ */
+#define NF_NONE 0 /* Undefined type */
+#define NF_SINGLE 1 /* Float IEEE 32 bit floating point */
+#define NF_DOUBLE 2 /* Double IEEE 64 bit floating point */
+#define NF_COMPLEX 3 /* Complex (2 32bit floats) */
+#define NF_COMPLEX16 4 /* Complex (2 64bit doubles) */
+#define NF_COMPLEX32 5 /* Complex (2 128bit long doubles) */
+#define NF_LDOUBLE 6 /* Long double 128 bit floating point */
+#define NF_INTERARITH 7 /* Interval (2 32bit floats) */
+#define NF_DINTERARITH 8 /* Interval (2 64bit doubles) */
+#define NF_QINTERARITH 9 /* Interval (2 128bit long doubles) */
+#define NF_IMAGINARY 10 /* Imaginary (1 32bit floats) */
+#define NF_DIMAGINARY 11 /* Imaginary (1 64bit doubles) */
+#define NF_QIMAGINARY 12 /* Imaginary (1 128bit long doubles) */
+
+#endif
+
+
diff --git a/gprofng/src/util.cc b/gprofng/src/util.cc
new file mode 100644
index 0000000..b93deaf
--- /dev/null
+++ b/gprofng/src/util.cc
@@ -0,0 +1,1582 @@
+/* Copyright (C) 2021 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 <sys/param.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dirent.h> // readdir()
+#include <sys/param.h> // MAXPATHLEN
+#include <pthread.h> // mutex
+#include <libgen.h> // dirname
+#include <sys/types.h> // open
+#include <sys/stat.h> // open
+#include <errno.h> // errno
+#include <fcntl.h> // open
+
+#include "util.h"
+#include "dbe_structs.h"
+#include "StringBuilder.h"
+#include "StringMap.h" // For directory names
+#include "Application.h" // Only for get_prog_name
+#include "vec.h"
+
+void
+tsadd (timestruc_t *result, timestruc_t *time)
+{
+ // This routine will add "time" to "result".
+ result->tv_sec += time->tv_sec;
+ result->tv_nsec += time->tv_nsec;
+ if (result->tv_nsec >= NANOSEC)
+ {
+ result->tv_nsec -= NANOSEC;
+ result->tv_sec++;
+ }
+}
+
+void
+tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
+{
+ // This routine will store "time1" - "time2" in "result".
+
+ if (time1->tv_nsec >= time2->tv_nsec)
+ {
+ result->tv_nsec = time1->tv_nsec - time2->tv_nsec;
+ if (time1->tv_sec >= time2->tv_sec)
+ result->tv_sec = time1->tv_sec - time2->tv_sec;
+ else
+ {
+ result->tv_sec = -1;
+ result->tv_nsec = 0;
+ }
+ }
+ else
+ {
+ result->tv_nsec = time1->tv_nsec + NANOSEC - time2->tv_nsec;
+ if (time1->tv_sec - 1 >= time2->tv_sec)
+ result->tv_sec = time1->tv_sec - 1 - time2->tv_sec;
+ else
+ {
+ result->tv_sec = -1;
+ result->tv_nsec = 0;
+ }
+ }
+}
+
+int
+tscmp (timestruc_t *time1, timestruc_t *time2)
+{
+ // This routine will return 1 if "time1" is greater than "time2"
+ // and 0 if "time1" is equal to "time2" and -1 otherwise.
+ if (time1->tv_sec == time2->tv_sec)
+ return time1->tv_nsec > time2->tv_nsec ? 1 :
+ time1->tv_nsec == time2->tv_nsec ? 0 : -1;
+ else
+ return time1->tv_sec > time2->tv_sec ? 1 : -1;
+}
+
+void
+int_max (int *maximum, int count)
+{
+ if (count > *maximum)
+ *maximum = count;
+}
+
+double
+TValue::to_double ()
+{
+ switch (tag)
+ {
+ case VT_DOUBLE:
+ return (double) d;
+ case VT_INT:
+ return (double) i;
+ case VT_ULLONG:
+ return (double) ull;
+ case VT_LLONG:
+ case VT_ADDRESS:
+ return (double) ll;
+ case VT_FLOAT:
+ return (double) f;
+ case VT_SHORT:
+ return (double) s;
+ default:
+ return 0.0;
+ }
+}
+
+int
+TValue::to_int ()
+{
+ switch (tag)
+ {
+ case VT_DOUBLE:
+ return (int) d;
+ case VT_INT:
+ return (int) i;
+ case VT_ULLONG:
+ return (int) ull;
+ case VT_LLONG:
+ case VT_ADDRESS:
+ return (int) ll;
+ case VT_FLOAT:
+ return (int) f;
+ case VT_SHORT:
+ return (int) s;
+ default:
+ return 0;
+ }
+}
+
+size_t
+TValue::get_len ()
+{
+ char buf[256];
+ return strlen (to_str (buf, sizeof (buf)));
+}
+
+char *
+TValue::to_str (char *str, size_t strsz)
+{
+ switch (tag)
+ {
+ case VT_DOUBLE:
+ if (d == 0.)
+ {
+ if (sign)
+ snprintf (str, strsz, NTXT ("+0. "));
+ else
+ snprintf (str, strsz, NTXT ("0. "));
+ }
+ else if (sign)
+ snprintf (str, strsz, NTXT ("%+.3lf"), d);
+ else
+ snprintf (str, strsz, NTXT ("%.3lf"), d);
+ break;
+ case VT_INT:
+ snprintf (str, strsz, NTXT ("%u"), i);
+ break;
+ case VT_LLONG:
+ if (sign)
+ snprintf (str, strsz, NTXT ("%+lld"), ll);
+ else
+ snprintf (str, strsz, NTXT ("%lld"), ll);
+ break;
+ case VT_ULLONG:
+ snprintf (str, strsz, NTXT ("%llu"), ll);
+ break;
+ case VT_ADDRESS:
+ snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
+ break;
+ case VT_FLOAT:
+ snprintf (str, strsz, NTXT ("%.3f"), f);
+ break;
+ case VT_SHORT:
+ snprintf (str, strsz, NTXT ("%hu"), s);
+ break;
+ case VT_LABEL:
+ return l; // 'str' is not used !!!
+ default:
+ *str = '\0';
+ break;
+ }
+
+ return str;
+}
+
+void
+TValue::make_delta (TValue *v1, TValue *v2)
+{
+ assert (v1->tag == v2->tag);
+ tag = v1->tag;
+ sign = true;
+ switch (v1->tag)
+ {
+ case VT_INT:
+ i = v1->i - v2->i;
+ break;
+ case VT_LLONG:
+ ll = v1->ll - v2->ll;
+ break;
+ case VT_ULLONG:
+ case VT_ADDRESS:
+ tag = VT_LLONG;
+ ll = (long long) (v1->ull - v2->ull);
+ break;
+ case VT_FLOAT:
+ f = v1->f - v2->f;
+ break;
+ case VT_DOUBLE:
+ d = v1->d - v2->d;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+}
+
+void
+TValue::make_ratio (TValue *v1, TValue *v2)
+{
+ assert (v1->tag == v2->tag);
+ double x1 = v1->to_double ();
+ double x2 = v2->to_double ();
+ sign = false;
+ if (x1 == 0.)
+ {
+ // if the numerator is 0, the ratio is 1. or 0. only
+ d = (x2 == 0.) ? 1. : 0.;
+ tag = VT_DOUBLE;
+ }
+ else
+ {
+ // EUGENE replace 99.999 with a variable that is known by both DBE and GUI
+ if (x1 > 99.999 * x2)
+ {
+ l = dbe_strdup (">99.999");
+ tag = VT_LABEL;
+ }
+ else if (x1 < -99.999 * x2)
+ {
+ l = dbe_strdup ("<-99.999");
+ tag = VT_LABEL;
+ }
+ else
+ {
+ d = x1 / x2;
+ tag = VT_DOUBLE;
+ }
+ }
+}
+
+int
+TValue::compare (TValue *v)
+{
+ if (tag != v->tag)
+ { // Only for comparison (Ratio)
+ if (tag == VT_LABEL)
+ {
+ if (v->tag == VT_LABEL)
+ return strcoll (l, v->l);
+ return 1;
+ }
+ if (v->tag == VT_LABEL)
+ return -1;
+ return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
+ }
+ switch (tag)
+ {
+ case VT_SHORT:
+ return s < v->s ? -1 : (s == v->s ? 0 : 1);
+ case VT_INT:
+ return i < v->i ? -1 : (i == v->i ? 0 : 1);
+ case VT_FLOAT:
+ return f < v->f ? -1 : (f == v->f ? 0 : 1);
+ case VT_DOUBLE:
+ return d < v->d ? -1 : (d == v->d ? 0 : 1);
+ case VT_LABEL:
+ return strcoll (l, v->l);
+ case VT_LLONG:
+ case VT_ULLONG:
+ case VT_ADDRESS:
+ case VT_HRTIME:
+ default:
+ return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
+ }
+}
+
+char *
+strstr_r (char *s1, const char *s2)
+{
+ char *str = NULL;
+ for (char *s = s1; s;)
+ {
+ s = strstr (s, s2);
+ if (s)
+ {
+ str = s;
+ s++;
+ }
+ }
+ return str;
+}
+
+// reversal order of strpbrk
+
+char *
+strrpbrk (const char *string, const char *brkset)
+{
+ const char *p;
+ const char *s;
+ for (s = string + strlen (string) - 1; s >= string; s--)
+ {
+ for (p = brkset; *p != '\0' && *p != *s; ++p)
+ ;
+ if (*p != '\0')
+ return ((char *) s);
+ }
+ return NULL;
+}
+
+char *
+read_line (FILE *fptr)
+{
+ // get an input line, no size limit
+ int line_sz = 128; // starting size
+ char *line = (char *) malloc (line_sz);
+
+ // read as much of the line as will fit in memory
+ line[0] = 0;
+ int len = 0;
+ for (;;)
+ {
+ while (fgets (line + len, line_sz - len, fptr) != NULL)
+ {
+ len = (int) strlen (line);
+ if (len == 0 || line[len - 1] == '\n')
+ break;
+ // increase the buffer
+ char *lineNew = (char *) malloc (2 * line_sz);
+ strncpy (lineNew, line, line_sz);
+ lineNew[line_sz] = '\0';
+ free (line);
+ line = lineNew;
+ line_sz *= 2;
+ if (line == NULL)
+ {
+ fprintf (stderr, GTXT (" Line too long -- out of memory; exiting\n"));
+ exit (1);
+ }
+ }
+ if (len == 0)
+ {
+ free (line);
+ return NULL;
+ }
+ // see if there's a continuation line
+ if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
+ {
+ // remove the trailing \ and the \n, and keep going
+ line[len - 2] = 0;
+ len -= 2;
+ }
+ else
+ break;
+ }
+ return line; // expecting the caller to free it
+}
+
+Vector<char *> *
+split_str (char *str, char delimiter)
+{
+ Vector<char *> *v = new Vector<char *>;
+ for (char *s = str; s;)
+ {
+ if (*s == '"')
+ {
+ char *next_s = NULL;
+ char *tok = parse_qstring (s, &next_s);
+ if (tok && *tok != '\0')
+ v->append (tok);
+ if (*next_s)
+ s = next_s + 1;
+ else
+ s = NULL;
+ }
+ else
+ {
+ char *next_s = strchr (s, delimiter);
+ if (next_s)
+ {
+ if (next_s != s)
+ v->append (dbe_strndup (s, next_s - s));
+ s = next_s + 1;
+ }
+ else
+ {
+ if (*s != '\0')
+ v->append (dbe_strdup (s));
+ s = NULL;
+ }
+ }
+ }
+ return v;
+}
+
+// get quoted string
+char *
+parse_qstring (char *in_str, char **endptr)
+{
+ int i;
+ char c, c2;
+ char term;
+ char csnum[2 * MAXPATHLEN];
+
+ // Skip any leading blanks or tabs
+ while (*in_str == '\t' || *in_str == ' ')
+ in_str++;
+
+ int gtxt = 0;
+ if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
+ && *(in_str + 3) == 'T' && *(in_str + 4) == '(')
+ {
+ gtxt = 1;
+ in_str += 5;
+ }
+ // non-quoted string
+ if (*in_str == '"')
+ term = '"';
+ else if (*in_str == '\'')
+ term = '\'';
+ else
+ return strtok_r (in_str, NTXT (" "), endptr);
+
+ StringBuilder sb;
+ while ((c = *(++in_str)) != '\0')
+ {
+ if (c == term) // the closing quote
+ break;
+ if (c == '\\')
+ { // handle any escaped characters
+ c2 = *(++in_str);
+ switch (c2)
+ {
+ case '\"':
+ sb.append ('\"');
+ break;
+ case '\'':
+ sb.append ('\'');
+ break;
+ case '\\':
+ sb.append ('\\');
+ break;
+ case 't':
+ sb.append ('\t');
+ break;
+ case 'r':
+ sb.append ('\r');
+ break;
+ case 'b':
+ sb.append ('\b');
+ break;
+ case 'f':
+ sb.append ('\f');
+ break;
+ case 'n':
+ sb.append ('\n');
+ break;
+ default:
+ if ((c2 >= '0') && (c2 <= '9'))
+ {
+ for (i = 0; i < MAXPATHLEN; i++)
+ {
+ if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
+ ((c2 < 'a') || (c2 > 'f')) &&
+ ((c2 < 'A') || (c2 > 'F')))
+ {
+ csnum[i] = '\0';
+ --in_str;
+ break;
+ }
+ else
+ {
+ csnum[i] = c2;
+ c2 = *(++in_str);
+ }
+ }
+ sb.append ((char) strtoul (csnum, endptr, 0));
+ }
+ else
+ sb.append (c2);
+ break;
+ }
+ }
+ else
+ sb.append (c);
+ }
+ if (c == term && gtxt && *in_str == ')')
+ in_str++;
+ if (*in_str == '\0')
+ *endptr = in_str;
+ else
+ *endptr = in_str + 1;
+ return sb.toString ();
+}
+
+// parse a file name of the form name`name2`
+// returns name
+// stores the pointer to named in fcontext
+// returns NULL if the string is not properly formatted
+char *
+parse_fname (char *in_str, char **fcontext)
+{
+ *fcontext = NULL;
+ int ch = '`';
+ if (in_str == NULL)
+ return NULL;
+ char *copy = strdup (in_str);
+ char *p = strchr (copy, ch);
+ if (p != NULL)
+ {
+ // yes, there's an embedded file name
+ *p = '\0';
+ p++;
+ // now find the terminating single quote
+ char *p1 = strchr (p, ch);
+ if (p1 == NULL)
+ {
+ // if we don't have the closing `, the format is incorrect
+ free (copy);
+ return NULL;
+ }
+ //remove the closing quote
+ *p1 = '\0';
+ // see if there's anything following it
+ if (*(p1 + 1) != 0)
+ {
+ // error in format
+ free (copy);
+ return NULL;
+ }
+ free (*fcontext);
+ *fcontext = strdup (p);
+ }
+ return copy;
+}
+
+int
+get_paren (const char *name)
+{
+ char buf[8192];
+ char *ptr;
+ int temp_level1, temp_level2;
+
+ temp_level1 = temp_level2 = 0;
+ snprintf (buf, sizeof (buf), NTXT ("%s"), name);
+ while ((ptr = strrpbrk (buf, "><)(")) != NULL)
+ {
+ if (*ptr == '>')
+ temp_level1++;
+ else if (*ptr == '<')
+ temp_level1--;
+ else if (*ptr == ')')
+ temp_level2++;
+ else
+ {
+ temp_level2--;
+ if (temp_level1 <= 0 && temp_level2 <= 0)
+ return (int) (ptr - buf);
+ }
+ *ptr = '\0';
+ }
+ return -1;
+}
+
+// CRC-64 based on x^64 + x^11 + x^2 + x + 1 polynomial.
+// This algorithm doesn't perform well but is short and
+// readable. We currently use it for a small amount of
+// short strings. Should this change, another algorithm
+// with better performance is to be used instead.
+static uint64_t masks[256] = {
+ /* 0 */ 0x000000, 0x000807, 0x00100e, 0x001809, 0x00201c, 0x00281b,
+ /* 6 */ 0x003012, 0x003815, 0x004038, 0x00483f, 0x005036, 0x005831,
+ /* 12 */ 0x006024, 0x006823, 0x00702a, 0x00782d, 0x008070, 0x008877,
+ /* 18 */ 0x00907e, 0x009879, 0x00a06c, 0x00a86b, 0x00b062, 0x00b865,
+ /* 24 */ 0x00c048, 0x00c84f, 0x00d046, 0x00d841, 0x00e054, 0x00e853,
+ /* 30 */ 0x00f05a, 0x00f85d, 0x0100e0, 0x0108e7, 0x0110ee, 0x0118e9,
+ /* 36 */ 0x0120fc, 0x0128fb, 0x0130f2, 0x0138f5, 0x0140d8, 0x0148df,
+ /* 42 */ 0x0150d6, 0x0158d1, 0x0160c4, 0x0168c3, 0x0170ca, 0x0178cd,
+ /* 48 */ 0x018090, 0x018897, 0x01909e, 0x019899, 0x01a08c, 0x01a88b,
+ /* 54 */ 0x01b082, 0x01b885, 0x01c0a8, 0x01c8af, 0x01d0a6, 0x01d8a1,
+ /* 60 */ 0x01e0b4, 0x01e8b3, 0x01f0ba, 0x01f8bd, 0x0201c0, 0x0209c7,
+ /* 66 */ 0x0211ce, 0x0219c9, 0x0221dc, 0x0229db, 0x0231d2, 0x0239d5,
+ /* 72 */ 0x0241f8, 0x0249ff, 0x0251f6, 0x0259f1, 0x0261e4, 0x0269e3,
+ /* 78 */ 0x0271ea, 0x0279ed, 0x0281b0, 0x0289b7, 0x0291be, 0x0299b9,
+ /* 84 */ 0x02a1ac, 0x02a9ab, 0x02b1a2, 0x02b9a5, 0x02c188, 0x02c98f,
+ /* 90 */ 0x02d186, 0x02d981, 0x02e194, 0x02e993, 0x02f19a, 0x02f99d,
+ /* 96 */ 0x030120, 0x030927, 0x03112e, 0x031929, 0x03213c, 0x03293b,
+ /* 102 */ 0x033132, 0x033935, 0x034118, 0x03491f, 0x035116, 0x035911,
+ /* 108 */ 0x036104, 0x036903, 0x03710a, 0x03790d, 0x038150, 0x038957,
+ /* 114 */ 0x03915e, 0x039959, 0x03a14c, 0x03a94b, 0x03b142, 0x03b945,
+ /* 120 */ 0x03c168, 0x03c96f, 0x03d166, 0x03d961, 0x03e174, 0x03e973,
+ /* 126 */ 0x03f17a, 0x03f97d, 0x040380, 0x040b87, 0x04138e, 0x041b89,
+ /* 132 */ 0x04239c, 0x042b9b, 0x043392, 0x043b95, 0x0443b8, 0x044bbf,
+ /* 138 */ 0x0453b6, 0x045bb1, 0x0463a4, 0x046ba3, 0x0473aa, 0x047bad,
+ /* 144 */ 0x0483f0, 0x048bf7, 0x0493fe, 0x049bf9, 0x04a3ec, 0x04abeb,
+ /* 150 */ 0x04b3e2, 0x04bbe5, 0x04c3c8, 0x04cbcf, 0x04d3c6, 0x04dbc1,
+ /* 156 */ 0x04e3d4, 0x04ebd3, 0x04f3da, 0x04fbdd, 0x050360, 0x050b67,
+ /* 162 */ 0x05136e, 0x051b69, 0x05237c, 0x052b7b, 0x053372, 0x053b75,
+ /* 168 */ 0x054358, 0x054b5f, 0x055356, 0x055b51, 0x056344, 0x056b43,
+ /* 174 */ 0x05734a, 0x057b4d, 0x058310, 0x058b17, 0x05931e, 0x059b19,
+ /* 180 */ 0x05a30c, 0x05ab0b, 0x05b302, 0x05bb05, 0x05c328, 0x05cb2f,
+ /* 186 */ 0x05d326, 0x05db21, 0x05e334, 0x05eb33, 0x05f33a, 0x05fb3d,
+ /* 192 */ 0x060240, 0x060a47, 0x06124e, 0x061a49, 0x06225c, 0x062a5b,
+ /* 198 */ 0x063252, 0x063a55, 0x064278, 0x064a7f, 0x065276, 0x065a71,
+ /* 204 */ 0x066264, 0x066a63, 0x06726a, 0x067a6d, 0x068230, 0x068a37,
+ /* 210 */ 0x06923e, 0x069a39, 0x06a22c, 0x06aa2b, 0x06b222, 0x06ba25,
+ /* 216 */ 0x06c208, 0x06ca0f, 0x06d206, 0x06da01, 0x06e214, 0x06ea13,
+ /* 222 */ 0x06f21a, 0x06fa1d, 0x0702a0, 0x070aa7, 0x0712ae, 0x071aa9,
+ /* 228 */ 0x0722bc, 0x072abb, 0x0732b2, 0x073ab5, 0x074298, 0x074a9f,
+ /* 234 */ 0x075296, 0x075a91, 0x076284, 0x076a83, 0x07728a, 0x077a8d,
+ /* 240 */ 0x0782d0, 0x078ad7, 0x0792de, 0x079ad9, 0x07a2cc, 0x07aacb,
+ /* 246 */ 0x07b2c2, 0x07bac5, 0x07c2e8, 0x07caef, 0x07d2e6, 0x07dae1,
+ /* 252 */ 0x07e2f4, 0x07eaf3, 0x07f2fa, 0x07fafd
+};
+
+uint64_t
+crc64 (const char *str, size_t len)
+{
+ uint64_t res = 0LL;
+ for (size_t i = 0; i < len; i++)
+ {
+ unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
+ res = res << 8;
+ res ^= masks [b];
+ }
+ return res;
+}
+
+/**
+ * Canonize path inside the string provided by the argument
+ * @param path
+ * @return path
+ */
+char *
+canonical_path (char *path)
+{
+ char *s1, *s2;
+ if (!path)
+ return path;
+ s1 = path;
+ s2 = path;
+ while (*s1)
+ {
+ if (*s1 == '.' && s1[1] == '/')
+ { // remove .///
+ for (s1++; *s1; s1++)
+ if (*s1 != '/')
+ break;
+ }
+ else if (*s1 == '/')
+ { // replace /// with /
+ *(s2++) = *s1;
+ for (s1++; *s1; s1++)
+ if (*s1 != '/')
+ break;
+ }
+ else
+ {
+ while (*s1)
+ { // copy file or directory name
+ if (*s1 == '/')
+ break;
+ *(s2++) = *(s1++);
+ }
+ }
+ }
+ *s2 = 0;
+ if (s2 != path && (s2 - 1) != path && s2[-1] == '/') // remove last /
+ *(s2 - 1) = 0;
+ return path;
+}
+
+char *
+get_relative_path (char *name)
+{
+ if (*name == '/' && theApplication)
+ {
+ char *cwd = theApplication->get_cur_dir ();
+ if (cwd)
+ {
+ size_t len = strlen (cwd);
+ if (len > 0 && len < strlen (name) && name[len] == '/'
+ && strncmp (cwd, name, len) == 0)
+ {
+ for (name += len + 1; *name == '/'; name++)
+ ;
+ return name;
+ }
+ }
+ }
+ return name;
+}
+
+/**
+ * Generate a relative link name from path_from to path_to
+ * Example:
+ * path_from=a/b/c/d
+ * path_to=a/b/e/f/g
+ * lname=../../e/f/g
+ * @param path_to
+ * @param path_from
+ * @return lname - relative link
+ */
+char *
+get_relative_link (const char *path_from, const char *path_to)
+{
+ if (!path_to)
+ path_to = ".";
+ if (!path_from)
+ path_from = ".";
+ char *s1 = dbe_strdup (path_to);
+ s1 = canonical_path (s1);
+ char *s2 = dbe_strdup (path_from);
+ s2 = canonical_path (s2);
+ long l = dbe_sstrlen (s1);
+ // try to find common directories
+ int common_slashes = 0;
+ int last_common_slash = -1;
+ for (int i = 0; i < l; i++)
+ {
+ if (s1[i] != s2[i]) break;
+ if (s1[i] == 0) break;
+ if (s1[i] == '/')
+ {
+ common_slashes++;
+ last_common_slash = i;
+ }
+ }
+ // find slashes in remaining path_to
+ int slashes = 0;
+ for (int i = last_common_slash + 1; i < l; i++)
+ {
+ if (s1[i] == '/')
+ {
+ // Exclude "/./" case
+ if (i > last_common_slash + 2)
+ {
+ if (s1[i - 1] == '.' && s1[i - 2] == '/')
+ continue;
+ }
+ else if (i > 0 && s1[i - 1] == '.')
+ continue;
+ slashes++;
+ }
+ }
+ // generate relative path
+ StringBuilder sb;
+ for (int i = 0; i < slashes; i++)
+ sb.append ("../");
+ sb.append (s2 + last_common_slash + 1);
+ char *lname = sb.toString ();
+ free (s1);
+ free (s2);
+ return lname;
+}
+
+char *
+get_prog_name (int basename)
+{
+ char *nm = NULL;
+ if (theApplication)
+ {
+ nm = theApplication->get_name ();
+ if (nm && basename)
+ nm = get_basename (nm);
+ }
+ return nm;
+}
+
+char *
+dbe_strndup (const char *str, size_t len)
+{
+ if (str == NULL)
+ return NULL;
+ char *s = (char *) malloc (len + 1);
+ strncpy (s, str, len);
+ s[len] = '\0';
+ return s;
+}
+
+char *
+dbe_sprintf (const char *fmt, ...)
+{
+ char buffer[256];
+ int buf_size;
+ va_list vp;
+
+ va_start (vp, fmt);
+ buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
+ va_end (vp);
+ if (buf_size < (int) sizeof (buffer))
+ {
+ if (buf_size <= 1)
+ buffer[0] = 0;
+ return strdup (buffer);
+ }
+
+ va_start (vp, fmt);
+ char *buf = (char *) malloc (buf_size);
+ vsnprintf (buf, buf_size, fmt, vp);
+ va_end (vp);
+ return buf;
+}
+
+ssize_t
+dbe_write (int f, const char *fmt, ...)
+{
+ char buffer[256];
+ int buf_size;
+ va_list vp;
+
+ va_start (vp, fmt);
+ buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
+ va_end (vp);
+ if (buf_size < (int) sizeof (buffer))
+ {
+ if (buf_size <= 1)
+ buffer[0] = 0;
+ return write (f, buffer, strlen (buffer));
+ }
+
+ va_start (vp, fmt);
+ char *buf = (char *) malloc (buf_size);
+ vsnprintf (buf, buf_size, fmt, vp);
+ va_end (vp);
+ ssize_t val = write (f, buf, strlen (buf));
+ free (buf);
+ return val;
+}
+
+/* Worker Threads to avoid hanging on file servers */
+
+/*
+ * Thread states
+ */
+enum
+{
+ THREAD_START,
+ THREAD_STARTED,
+ THREAD_CANCEL,
+ THREAD_CANCELED,
+ THREAD_CREATE,
+ THREAD_NOT_CREATED,
+ THREAD_FINISHED
+};
+
+/*
+ * Communication structure
+ */
+struct worker_thread_info
+{
+ pthread_t thread_id; /* ID returned by pthread_create() */
+ int thread_num; /* Application-defined thread # */
+ volatile int control; /* Thread state */
+ volatile int result; /* Return status */
+ struct stat64 statbuf; /* File info from stat64() */
+ const char *path; /* File */
+};
+
+static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+static int worker_thread_number = 0;
+/**
+ * Call stat64() on current worker thread
+ * Check if control is not THREAD_CANCEL
+ * If control is THREAD_CANCEL return (exit thread)
+ * @param *wt_info
+ */
+static void *
+dbe_stat_on_thread (void *arg)
+{
+ struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
+ pthread_mutex_lock (&worker_thread_lock);
+ {
+ if (wt_info->control != THREAD_START)
+ {
+ // Already too late
+ pthread_mutex_unlock (&worker_thread_lock);
+ return 0;
+ }
+ wt_info->control = THREAD_STARTED;
+ }
+ pthread_mutex_unlock (&worker_thread_lock);
+ const char * path = wt_info->path;
+ int st = stat64 (path, &(wt_info->statbuf));
+ pthread_mutex_lock (&worker_thread_lock);
+ {
+ if (wt_info->control == THREAD_CANCEL)
+ {
+ // Too late.
+ pthread_mutex_unlock (&worker_thread_lock);
+ free (wt_info);
+ return 0;
+ }
+ wt_info->result = st;
+ wt_info->control = THREAD_FINISHED;
+ }
+ pthread_mutex_unlock (&worker_thread_lock);
+ return 0;
+}
+
+/**
+ * Create a worker thread to call specified function
+ * Wait for its result, but not longer than 5 seconds
+ * If the timeout happens, tell the thread to cancel
+ * @param path
+ * @param wt_info
+ * @return thread state
+ */
+static int
+dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
+{
+ wt_info->result = 0;
+ wt_info->control = THREAD_START;
+ pthread_attr_t attr;
+ /* Initialize thread creation attributes */
+ int res = pthread_attr_init (&attr);
+ if (res != 0)
+ {
+ wt_info->control = THREAD_NOT_CREATED;
+ return THREAD_NOT_CREATED;
+ }
+ wt_info->thread_id = 0;
+ wt_info->path = path;
+ // Lock
+ pthread_mutex_lock (&worker_thread_lock);
+ worker_thread_number++;
+ wt_info->thread_num = worker_thread_number;
+ // Unlock
+ pthread_mutex_unlock (&worker_thread_lock);
+ // Create thread
+ res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
+ if (res != 0)
+ {
+ wt_info->control = THREAD_NOT_CREATED;
+ pthread_attr_destroy (&attr);
+ return THREAD_NOT_CREATED;
+ }
+ // Wait for the thread to finish
+ res = 0;
+ useconds_t maxusec = 5000000; // 5 seconds
+ useconds_t deltausec = 1000; // 1 millisecond
+ int max = maxusec / deltausec;
+ for (int i = 0; i < max; i++)
+ {
+ if (THREAD_FINISHED == wt_info->control)
+ break; // We are done
+ usleep (deltausec);
+ }
+ // Lock
+ pthread_mutex_lock (&worker_thread_lock);
+ if (THREAD_FINISHED != wt_info->control)
+ {
+ // Cancel thread
+ wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
+ res = THREAD_CANCEL;
+ }
+ // Unlock
+ pthread_mutex_unlock (&worker_thread_lock);
+ // Destroy the thread attributes object, since it is no longer needed
+ pthread_attr_destroy (&attr);
+ // Report that thread was canceled
+ if (THREAD_CANCEL == res)
+ return res; /* Cannot free memory allocated by thread */
+ // Free all thread resources
+ void *resources = 0;
+ res = pthread_join (wt_info->thread_id, &resources);
+ free (resources); /* Free memory allocated by thread */
+ return THREAD_FINISHED;
+}
+
+static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
+static Map<const char*, int> *dirnamesMap = NULL;
+
+#define DIR_STATUS_EXISTS 0
+#define DIR_STATUS_UNKNOWN 2
+
+/**
+ * Check if this directory name is known
+ * Return:
+ * @param path
+ * 0 - known, exists
+ * 1 - known, does not exist
+ * 2 - not known
+ */
+static int
+check_dirname (const char *path)
+{
+ pthread_mutex_lock (&dirnames_lock);
+ if (NULL == dirnamesMap)
+ dirnamesMap = new StringMap<int>(128, 128);
+ pthread_mutex_unlock (&dirnames_lock);
+ int res = DIR_STATUS_UNKNOWN;
+ if (path && *path)
+ {
+ char *fn = dbe_strdup (path);
+ char *dn = dirname (fn);
+ if (dn && *dn)
+ res = dirnamesMap->get (dn);
+ free (fn);
+ }
+ return res;
+}
+
+/**
+ * Save directory name and its status
+ * @param path
+ * @param status
+ * @return
+ */
+static void
+extract_and_save_dirname (const char *path, int status)
+{
+ pthread_mutex_lock (&dirnames_lock);
+ if (NULL == dirnamesMap)
+ dirnamesMap = new StringMap<int>(128, 128);
+ pthread_mutex_unlock (&dirnames_lock);
+ char *fn = dbe_strdup (path);
+ if (fn && *fn != 0)
+ {
+ char *dn = dirname (fn);
+ if (dn && (*dn != 0))
+ {
+ int st = 0; // exists
+ if (0 != status)
+ st = 1; // does not exist
+ dirnamesMap->put (dn, st);
+ }
+ }
+ free (fn);
+}
+
+// get status for specified file
+static int
+dbe_stat_internal (const char *path, struct stat64 *sbuf, bool file_only)
+{
+ struct stat64 statbuf;
+ int dir_status = check_dirname (path);
+ if (dir_status == DIR_STATUS_UNKNOWN)
+ {
+ // Try to use a worker thread
+ if (theApplication->get_number_of_worker_threads () > 0)
+ {
+ struct worker_thread_info *wt_info;
+ wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
+ if (wt_info != NULL)
+ {
+ int res = dbe_dispatch_on_thread (path, wt_info);
+ if (THREAD_FINISHED == res)
+ {
+ int st = wt_info->result;
+ extract_and_save_dirname (path, st);
+ if (st == 0 && file_only)
+ if (S_ISREG ((wt_info->statbuf).st_mode) == 0)
+ st = -1; // It is not a regular file
+ if (sbuf != NULL)
+ *sbuf = wt_info->statbuf;
+ free (wt_info);
+ return st;
+ }
+ else
+ {
+ if (THREAD_CANCEL == res)
+ {
+ // Worker thread hung. Cannot free wt_info.
+ // Allocated memory will be freed by worker thread.
+ // save directory
+ extract_and_save_dirname (path, 1);
+ return 1; // stat64 failed
+ }
+ else // THREAD_NOT_CREATED - continue on current thread
+ free (wt_info);
+ }
+ }
+ }
+ }
+ else if (dir_status != DIR_STATUS_EXISTS)
+ return -1; // does not exist
+ if (sbuf == NULL)
+ sbuf = &statbuf;
+ int st = stat64 (path, sbuf);
+ Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
+ if (st == -1)
+ return -1;
+ else if (file_only && S_ISREG (sbuf->st_mode) == 0)
+ return -1; // It is not ordinary file
+ return st;
+}
+
+// get status for the regular file
+
+int
+dbe_stat_file (const char *path, struct stat64 *sbuf)
+{
+ int res = dbe_stat_internal (path, sbuf, true);
+ return res;
+}
+
+// get status for specified file
+
+int
+dbe_stat (const char *path, struct stat64 *sbuf)
+{
+ int res = dbe_stat_internal (path, sbuf, false);
+ return res;
+}
+
+/**
+ * Reads directory and prepares list of files according to the specified format
+ * Supported formats:
+ * "/bin/ls -a" - see 'man ls' for details
+ * "/bin/ls -aF" - see 'man ls' for details
+ * @param path
+ * @param format
+ * @return char * files
+ */
+char *
+dbe_read_dir (const char *path, const char *format)
+{
+ StringBuilder sb;
+ DIR *dir = opendir (path);
+ if (dir == NULL)
+ return sb.toString ();
+ int format_aF = 0;
+ if (!strcmp (format, NTXT ("/bin/ls -aF")))
+ format_aF = 1;
+ struct dirent *entry = NULL;
+ if (format != NULL)
+ {
+ while ((entry = readdir (dir)) != NULL)
+ {
+ sb.append (entry->d_name);
+ if (format_aF)
+ {
+ const char *attr = NTXT ("@"); // Link
+ struct stat64 sbuf;
+ sbuf.st_mode = 0;
+ char filename[MAXPATHLEN + 1];
+ snprintf (filename, sizeof (filename), NTXT ("%s/%s"), path, entry->d_name);
+ dbe_stat (filename, &sbuf);
+ if (S_IREAD & sbuf.st_mode)
+ { // Readable
+ if (S_ISDIR (sbuf.st_mode) != 0) // Directory
+ attr = NTXT ("/");
+ else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
+ attr = NTXT ("");
+ }
+ sb.append (attr);
+ }
+ sb.append (NTXT ("\n"));
+ }
+ }
+ closedir (dir);
+ return sb.toString ();
+}
+
+/**
+ * Gets list of processes according to the specified format
+ * Supported formats:
+ * "/bin/ps -ef" - see 'man ps' for details
+ * @param format
+ * @return char * processes
+ */
+char *
+dbe_get_processes (const char *format)
+{
+ StringBuilder sb;
+ if (!strcmp (format, NTXT ("/bin/ps -ef")))
+ {
+ char buf[BUFSIZ];
+ FILE *ptr = popen (format, "r");
+ if (ptr != NULL)
+ {
+ while (fgets (buf, BUFSIZ, ptr) != NULL)
+ sb.append (buf);
+ pclose (ptr);
+ }
+ }
+ return sb.toString ();
+}
+
+/**
+ * Creates the directory named by the specified path name, including any
+ * necessary but nonexistent parent directories.
+ * Uses system utility "/bin/mkdir -p"
+ * Temporary limitation: path name should not contain spaces.
+ * Returns message from "/bin/mkdir -p"
+ * @param pathname
+ * @return result
+ */
+char *
+dbe_create_directories (const char *pathname)
+{
+ StringBuilder sb;
+ char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
+ char out[BUFSIZ];
+ FILE *ptr = popen (makedir, "r");
+ if (ptr != NULL)
+ {
+ while (fgets (out, BUFSIZ, ptr) != NULL)
+ sb.append (out);
+ pclose (ptr);
+ }
+ free (makedir);
+ DIR *dir = opendir (pathname);
+ if (dir != NULL)
+ {
+ closedir (dir);
+ return NULL; // success
+ }
+ else
+ sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
+ return sb.toString (); // error
+}
+
+/**
+ * Deletes the file or the directory named by the specified path name.
+ * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
+ * Uses system utility "/bin/rm" or "/bin/rmdir"
+ * Temporary limitation: path name should not contain spaces.
+ * Returns error message from system utility
+ * @param pathname
+ * @return result
+ */
+char *
+dbe_delete_file (const char *pathname)
+{
+ StringBuilder sb;
+ char *cmd = NULL;
+ struct stat64 sbuf;
+ sbuf.st_mode = 0;
+ int st = dbe_stat (pathname, &sbuf);
+ if (st == 0)
+ { // Exists
+ if (S_ISDIR (sbuf.st_mode) != 0) // Directory
+ cmd = dbe_sprintf (NTXT ("/bin/rmdir %s 2>&1"), pathname);
+ else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
+ cmd = dbe_sprintf (NTXT ("/bin/rm %s 2>&1"), pathname);
+ }
+ else
+ return NULL; // Nothing to remove
+ if (cmd != NULL)
+ {
+ char out[BUFSIZ];
+ FILE *ptr = popen (cmd, "r");
+ if (ptr != NULL)
+ {
+ while (fgets (out, BUFSIZ, ptr) != NULL)
+ sb.append (out);
+ pclose (ptr);
+ }
+ free (cmd);
+ }
+ else
+ sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
+ return sb.toString ();
+}
+
+char *
+dbe_xml2str (const char *s)
+{
+ if (s == NULL)
+ return NULL;
+ StringBuilder sb;
+ while (*s)
+ {
+ if (*s == '&')
+ {
+ if (strncmp (s, NTXT ("&nbsp;"), 6) == 0)
+ {
+ sb.append (' ');
+ s += 6;
+ continue;
+ }
+ else if (strncmp (s, NTXT ("&quot;"), 6) == 0)
+ {
+ sb.append ('"');
+ s += 6;
+ continue;
+ }
+ else if (strncmp (s, NTXT ("&amp;"), 5) == 0)
+ {
+ sb.append ('&');
+ s += 5;
+ continue;
+ }
+ else if (strncmp (s, NTXT ("&lt;"), 4) == 0)
+ {
+ sb.append ('<');
+ s += 4;
+ continue;
+ }
+ else if (strncmp (s, NTXT ("&gt;"), 4) == 0)
+ {
+ sb.append ('>');
+ s += 4;
+ continue;
+ }
+ }
+ sb.append (*s);
+ s++;
+ }
+ return sb.toString ();
+}
+
+void
+swapByteOrder (void *p, size_t sz)
+{
+ if (sz == 8)
+ {
+ uint64_t *pv = (uint64_t *) p;
+ uint64_t v = *pv;
+ v = ((v & 0x00000000FF000000) << 8) | ((v >> 8) & 0x00000000FF000000) |
+ ((v & 0x0000000000FF0000) << 24) | ((v >> 24) & 0x0000000000FF0000) |
+ ((v & 0x000000000000FF00) << 40) | ((v >> 40) & 0x000000000000FF00) |
+ (v >> 56) | (v << 56);
+ *pv = v;
+ }
+ else if (sz == 4)
+ {
+ uint32_t *pv = (uint32_t *) p;
+ uint32_t v = *pv;
+ v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
+ *pv = v;
+ }
+ else if (sz == 2)
+ {
+ uint16_t *pv = (uint16_t *) p;
+ uint16_t v = *pv;
+ v = (v >> 8) | (v << 8);
+ *pv = v;
+ }
+}
+
+void
+destroy (void *vec)
+{
+ if (vec == NULL)
+ return;
+ Vector<void*> *array = (Vector<void*>*)vec;
+ switch (array->type ())
+ {
+ case VEC_STRING:
+ ((Vector<char *>*)array)->destroy ();
+ break;
+ case VEC_VOIDARR:
+ case VEC_STRINGARR:
+ case VEC_INTARR:
+ case VEC_BOOLARR:
+ case VEC_LLONGARR:
+ case VEC_DOUBLEARR:
+ for (long i = 0; i < array->size (); i++)
+ destroy (array->fetch (i));
+ break;
+ case VEC_INTEGER:
+ case VEC_CHAR:
+ case VEC_BOOL:
+ case VEC_DOUBLE:
+ case VEC_LLONG:
+ default:
+ break;
+ }
+ delete array;
+}
+
+int64_t
+read_from_file (int fd, void *buffer, int64_t nbyte)
+{
+ int64_t cnt = 0;
+ char *buf = (char *) buffer;
+ while (nbyte > 0)
+ { // Sometimes system cannot read 'nbyte'
+ ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
+ if (n <= 0)
+ break;
+ nbyte -= n;
+ cnt += n;
+ }
+ return cnt;
+}
+
+/**
+ * Create symbolic link to the path
+ * @param path - path with spaces
+ * @param dir - directory where the link should be created
+ * @return symbolic link
+ */
+char *
+dbe_create_symlink_to_path (const char *path, const char *dir)
+{
+ char *symbolic_link = NULL;
+ if (NULL == path || NULL == dir)
+ return NULL;
+ int res = mkdir (dir, 0777);
+ if (res != 0 && dbe_stat (dir, NULL) != 0)
+ return NULL; // Cannot create directory
+ long len = dbe_sstrlen (path);
+ if (len <= 4)
+ return NULL; // Unknown situation
+ if (strcmp ((path + len - 4), "/bin") != 0) // Unknown situation
+ return NULL;
+ int max = 99; // Just an arbitrary number
+ for (int i = 1; i <= max; i++)
+ {
+ // Try to create symbolic link
+ char *d = dbe_sprintf ("%s/%d", dir, i);
+ if (NULL == d)
+ return NULL;
+ res = mkdir (d, 0777);
+ symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
+ free (d);
+ if (NULL == symbolic_link) // Not enough memory
+ return NULL;
+ res = symlink (path, symbolic_link);
+ if (res == 0) // Link is created - use it.
+ break;
+ // Check if such link already exists
+ int e = errno;
+ char buf[MAXPATHLEN + 1];
+ memset (buf, 0, MAXPATHLEN + 1);
+ ssize_t n = readlink (symbolic_link, buf, MAXPATHLEN);
+ if (n == len && strcmp (path, buf) == 0) // Link is correct - use it.
+ break;
+ if (i == max)
+ { // report the error
+ fprintf (stderr, GTXT ("Error: symlink(%s, %s) returned error: %d\n"), path, symbolic_link, res);
+ fprintf (stderr, GTXT ("Error: errno=%d (%s)\n"), e, strerror (e));
+ fflush (stderr);
+ }
+ free (symbolic_link);
+ symbolic_link = NULL;
+ }
+ return symbolic_link;
+}
+
+// Compute checksum for specified file.
+// This code is from usr/src/cmd/cksum.c, adapted for us
+// crcposix -- compute posix.2 compatable 32 bit CRC
+//
+// The POSIX.2 (draft 10) CRC algorithm.
+// This is a 32 bit CRC with polynomial
+// x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
+// x**8 + x**7 + x**5 + x**4 + x**2 + x**1 + x**0
+//
+// layout is from the POSIX.2 Rationale
+
+static uint32_t crctab_posix[256] = {
+ 0x00000000L,
+ 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL,
+ 0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L,
+ 0x2B4BCB61L, 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
+ 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, 0x5F15ADACL,
+ 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, 0x6A1936C8L, 0x6ED82B7FL,
+ 0x639B0DA6L, 0x675A1011L, 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL,
+ 0x745E66CDL, 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
+ 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, 0xBE2B5B58L,
+ 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, 0xAD2F2D84L, 0xA9EE3033L,
+ 0xA4AD16EAL, 0xA06C0B5DL, 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL,
+ 0xD9714B49L, 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
+ 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, 0xE13EF6F4L,
+ 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, 0x34867077L, 0x30476DC0L,
+ 0x3D044B19L, 0x39C556AEL, 0x278206ABL, 0x23431B1CL, 0x2E003DC5L,
+ 0x2AC12072L, 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
+ 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, 0x7897AB07L,
+ 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, 0x6B93DDDBL, 0x6F52C06CL,
+ 0x6211E6B5L, 0x66D0FB02L, 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L,
+ 0x53DC6066L, 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
+ 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, 0xBFA1B04BL,
+ 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, 0x8AAD2B2FL, 0x8E6C3698L,
+ 0x832F1041L, 0x87EE0DF6L, 0x99A95DF3L, 0x9D684044L, 0x902B669DL,
+ 0x94EA7B2AL, 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
+ 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, 0xC6BCF05FL,
+ 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, 0xD5B88683L, 0xD1799B34L,
+ 0xDC3ABDEDL, 0xD8FBA05AL, 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L,
+ 0x644FC637L, 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
+ 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, 0x5C007B8AL,
+ 0x58C1663DL, 0x558240E4L, 0x51435D53L, 0x251D3B9EL, 0x21DC2629L,
+ 0x2C9F00F0L, 0x285E1D47L, 0x36194D42L, 0x32D850F5L, 0x3F9B762CL,
+ 0x3B5A6B9BL, 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
+ 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, 0xF12F560EL,
+ 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, 0xE22B20D2L, 0xE6EA3D65L,
+ 0xEBA91BBCL, 0xEF68060BL, 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L,
+ 0xDA649D6FL, 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
+ 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, 0xAE3AFBA2L,
+ 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, 0x9B3660C6L, 0x9FF77D71L,
+ 0x92B45BA8L, 0x9675461FL, 0x8832161AL, 0x8CF30BADL, 0x81B02D74L,
+ 0x857130C3L, 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
+ 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, 0x7B827D21L,
+ 0x7F436096L, 0x7200464FL, 0x76C15BF8L, 0x68860BFDL, 0x6C47164AL,
+ 0x61043093L, 0x65C52D24L, 0x119B4BE9L, 0x155A565EL, 0x18197087L,
+ 0x1CD86D30L, 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
+ 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, 0x2497D08DL,
+ 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, 0xC5A92679L, 0xC1683BCEL,
+ 0xCC2B1D17L, 0xC8EA00A0L, 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL,
+ 0xDBEE767CL, 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
+ 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, 0x89B8FD09L,
+ 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, 0x9ABC8BD5L, 0x9E7D9662L,
+ 0x933EB0BBL, 0x97FFAD0CL, 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL,
+ 0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
+};
+
+static void
+m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
+{
+ while (n-- > 0)
+ *crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
+}
+
+// Do CRC-POSIX function by calling a library entry point that has a
+// slightly different calling sequence.
+static uint32_t
+docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
+{
+ m_crcposix (&crcval, bp, n);
+ return (crcval);
+}
+
+// Sum algorithms require various kinds of post-processing.
+// The 'S' and 'R' variables are from the POSIX.2 (Draft 8?) description
+// of the "sum" utility.
+static uint32_t
+postprocess (uint32_t S, long long n)
+{
+ // POSIX tacks on significant bytes of the length so that
+ // different length sequences of '\0' have different sums;
+ // then it complements sum.
+ unsigned char char_n[sizeof (n)];
+ uint32_t i;
+ for (i = 0; n != 0; n >>= 8, ++i)
+ char_n[i] = (unsigned char) (n & 0xFF);
+ return (~docrcposix (S, char_n, i));
+}
+
+uint32_t
+get_cksum (const char * pathname, char ** errmsg)
+{
+ int fd = open (pathname, O_RDONLY);
+ if (fd < 0)
+ {
+ if (errmsg)
+ *errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
+ return 0; // error
+ }
+ uint32_t crcval = 0;
+ long long bytes = 0;
+ int64_t n;
+ unsigned char buf[4096];
+ while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
+ {
+ bytes += n;
+ crcval = docrcposix (crcval, buf, n);
+ }
+ close (fd);
+ crcval = postprocess (crcval, bytes);
+ return crcval;
+}
diff --git a/gprofng/src/util.h b/gprofng/src/util.h
new file mode 100644
index 0000000..0d1b8bc
--- /dev/null
+++ b/gprofng/src/util.h
@@ -0,0 +1,185 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PERFAN_UTIL_H
+#define _PERFAN_UTIL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stdint.h>
+
+#include "gp-defs.h"
+#include "gp-time.h"
+#include "i18n.h"
+#include "debug.h"
+
+#define SWAP_ENDIAN(x) swapByteOrder((void *) (&(x)), sizeof(x))
+#define AppendString(len, arr, ...) len += snprintf(arr + len, sizeof(arr) - len, __VA_ARGS__)
+#define ARR_SIZE(x) (sizeof (x) / sizeof (*(x)))
+
+// Utility routines.
+
+//
+// Inline functions
+//
+// max(a, b) - Return the maximum of two values
+inline int
+max (int a, int b)
+{
+ return (a >= b) ? a : b;
+}
+
+// min(a, b) - Return the minimum of two values
+inline int
+min (int a, int b)
+{
+ return (a <= b) ? a : b;
+}
+
+// streq(s1, s2) - Returns 1 if strings are the same, 0 otherwise
+inline int
+streq (const char *s1, const char *s2)
+{
+ return strcmp (s1, s2) == 0;
+}
+
+// StrChr(str, ch) - Rerurn 'str' if 'ch' does not occur in 'str' or
+// a pointer to the next symbol after the first occurrence of 'ch' in 'str'
+inline char *
+StrChr (char *str, char ch)
+{
+ char *s = strchr (str, ch);
+ return s ? (s + 1) : str;
+}
+
+// StrRchr(str, ch) - Rerurn 'str' if 'ch' does not occur in 'str' or
+// a pointer to the next symbol after the last occurrence of 'ch' in 'str'
+inline char *
+StrRchr (char *str, char ch)
+{
+ char *s = strrchr (str, ch);
+ return s ? (s + 1) : str;
+}
+
+inline char*
+STR (const char *s)
+{
+ return s ? (char*) s : (char*) NTXT ("NULL");
+}
+
+inline char*
+get_str (const char *s, const char *s1)
+{
+ return s ? (char*) s : (char*) s1;
+}
+
+inline char *
+get_basename (const char* name)
+{
+ return StrRchr ((char*) name, '/');
+}
+
+inline char *
+dbe_strdup (const char *str)
+{
+ return str ? strdup (str) : NULL;
+}
+
+inline long
+dbe_sstrlen (const char *str)
+{
+ return str ? (long) strlen (str) : 0;
+}
+
+inline int
+dbe_strcmp (const char *s1, const char *s2)
+{
+ return s1 ? (s2 ? strcmp (s1, s2) : 1) : (s2 ? -1 : 0);
+}
+
+// tstodouble(t) - Return timestruc_t in (double) seconds
+inline double
+tstodouble (timestruc_t t)
+{
+ return (double) t.tv_sec + (double) (t.tv_nsec / 1000000000.0);
+}
+
+inline void
+hr2timestruc (timestruc_t *d, hrtime_t s)
+{
+ d->tv_sec = (long) (s / NANOSEC);
+ d->tv_nsec = (long) (s % NANOSEC);
+}
+
+inline hrtime_t
+timestruc2hr (timestruc_t *s)
+{
+ return (hrtime_t) s->tv_sec * NANOSEC + (hrtime_t) s->tv_nsec;
+}
+
+struct stat64;
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+ //
+ // Declaration of utility functions
+ //
+ void tsadd (timestruc_t *result, timestruc_t *time);
+ void tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2);
+ int tscmp (timestruc_t *time1, timestruc_t *time2);
+ void int_max (int *maximum, int count);
+ char *strstr_r (char *s1, const char *s2);
+ char *strrpbrk (const char *string, const char *brkset);
+ char *read_line (FILE *);
+ char *parse_qstring (char *in_str, char **endptr);
+ char *parse_fname (char *in_str, char **fcontext);
+ int get_paren (const char *name);
+
+ uint64_t crc64 (const char *str, size_t len);
+ char *canonical_path (char *path);
+ char *get_relative_path (char *name);
+ char *get_relative_link (const char *path_to, const char *path_from);
+ char *get_prog_name (int basename);
+ char *dbe_strndup (const char *str, size_t len);
+ int dbe_stat (const char *path, struct stat64 *sbuf);
+ int dbe_stat_file (const char *path, struct stat64 *sbuf);
+ char *dbe_read_dir (const char *path, const char *format);
+ char *dbe_get_processes (const char *format);
+ char *dbe_create_directories (const char *pathname);
+ char *dbe_delete_file (const char *pathname);
+ char *dbe_xml2str (const char *s);
+ void swapByteOrder (void *p, size_t sz);
+ char *dbe_sprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+ ssize_t dbe_write (int f, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ char *dbe_create_symlink_to_path (const char *path, const char *dir);
+ int64_t read_from_file (int fd, void *buffer, int64_t nbyte);
+ uint32_t get_cksum (const char * pathname, char ** errmsg);
+
+#ifdef __cplusplus
+}
+int catch_out_of_memory (int (*real_main)(int, char*[]), int argc, char *argv[]);
+#endif
+
+
+#endif /* _UTIL_H */
diff --git a/gprofng/src/vec.h b/gprofng/src/vec.h
new file mode 100644
index 0000000..28b1800c
--- /dev/null
+++ b/gprofng/src/vec.h
@@ -0,0 +1,524 @@
+/* Copyright (C) 2021 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. */
+
+#ifndef _PERFAN_VEC_H
+#define _PERFAN_VEC_H
+
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+
+// This package implements a vector of items.
+
+#define Destroy(x) if (x) { (x)->destroy(); delete (x); (x) = NULL; }
+#define VecSize(x) ((x) ? (x)->size() : 0)
+
+void destroy (void *vec); // Free up the "two-dimension" Vectors
+
+typedef int (*CompareFunc)(const void*, const void*);
+typedef int (*ExtCompareFunc)(const void*, const void*, const void*);
+typedef int (*SearchFunc)(char*, char*);
+
+extern "C"
+{
+ typedef int (*StdCompareFunc)(const void*, const void*);
+}
+
+enum Search_type
+{
+ LINEAR,
+ BINARY,
+ HASH
+};
+
+enum Direction
+{
+ FORWARD,
+ REVERSE
+};
+
+enum VecType
+{
+ VEC_VOID = 0,
+ VEC_INTEGER,
+ VEC_CHAR,
+ VEC_BOOL,
+ VEC_DOUBLE,
+ VEC_LLONG,
+ VEC_VOIDARR,
+ VEC_STRING,
+ VEC_INTARR,
+ VEC_BOOLARR,
+ VEC_LLONGARR,
+ VEC_STRINGARR,
+ VEC_DOUBLEARR
+};
+
+template <class ITEM> void
+qsort (ITEM *, size_t, ExtCompareFunc, void *);
+
+template <typename ITEM> class Vector
+{
+public:
+
+ Vector ()
+ {
+ count = 0;
+ data = NULL;
+ limit = 0;
+ sorted = false;
+ };
+
+ Vector (long sz);
+
+ virtual
+ ~Vector ()
+ {
+ free (data);
+ }
+
+ void append (const ITEM item);
+ void addAll (Vector<ITEM> *vec);
+ Vector<ITEM> *copy (); // Return a copy of "this".
+
+ ITEM
+ fetch (long index)
+ {
+ return data[index];
+ }
+
+ ITEM
+ get (long index)
+ {
+ return data[index];
+ }
+
+ // Return the first index in "this" that equals "item".
+ // Return -1 if "item" is not found.
+ long find (const ITEM item);
+ long find_r (const ITEM item);
+
+ // Insert "item" into "index"'th slot of "this",
+ // moving everything over by 1.
+ void insert (long index, const ITEM item);
+
+ // Insert "item" after locating its appropriate index
+ void incorporate (const ITEM item, CompareFunc func);
+
+ // Remove and return the "index"'th item from "this",
+ // moving everything over by 1.
+ ITEM remove (long index);
+
+ // Swap two items in "this",
+ void swap (long index1, long index2);
+
+ long
+ size ()
+ {
+ return count;
+ }
+
+ // Store "item" into the "index"'th slot of "this".
+ void store (long index, const ITEM item);
+
+ void
+ put (long index, const ITEM item)
+ {
+ store (index, item);
+ }
+
+ // Sort the vector according to compare
+ void
+ sort (CompareFunc compare, void *arg = NULL)
+ {
+ qsort (data, count, (ExtCompareFunc) compare, arg);
+ sorted = true;
+ }
+
+ // Binary search, vector must be sorted
+ long bisearch (long start, long end, void *key, CompareFunc func);
+ void destroy (); // delete all vector elements (must be pointers!)
+
+ void
+ reset ()
+ {
+ count = 0;
+ sorted = false;
+ }
+
+ bool
+ is_sorted ()
+ {
+ return sorted;
+ }
+
+ virtual VecType
+ type ()
+ {
+ return VEC_VOID;
+ }
+
+ virtual void
+ dump (const char * /* msg */)
+ {
+ return;
+ }
+
+private:
+
+ void resize (long index);
+
+ ITEM *data; // Pointer to data vector
+ long count; // Number of items
+ long limit; // Vector length (power of 2)
+ bool sorted;
+};
+
+template<> VecType Vector<int>::type ();
+template<> VecType Vector<unsigned>::type ();
+template<> VecType Vector<char>::type ();
+template<> VecType Vector<bool>::type ();
+template<> VecType Vector<double>::type ();
+template<> VecType Vector<long long>::type ();
+template<> VecType Vector<uint64_t>::type ();
+template<> VecType Vector<void*>::type ();
+template<> VecType Vector<char*>::type ();
+template<> VecType Vector<Vector<int>*>::type ();
+template<> VecType Vector<Vector<char*>*>::type ();
+template<> VecType Vector<Vector<long long>*>::type ();
+template<> void Vector<char *>::destroy ();
+
+#define KILOCHUNK 1024
+#define MEGACHUNK 1024*1024
+#define GIGACHUNK 1024*1024*1024
+
+// A standard looping construct:
+#define Vec_loop(ITEM, vec, index, item) \
+if (vec != NULL) \
+ for (index = 0, item = ((vec)->size() > 0) ? (vec)->fetch(0) : (ITEM)0; \
+ index < (vec)->size(); \
+ item = (++index < (vec)->size()) ? (vec)->fetch(index) : (ITEM)0)
+
+template <typename ITEM>
+Vector<ITEM>::Vector (long sz)
+{
+ count = 0;
+ limit = sz > 0 ? sz : KILOCHUNK; // was 0;
+ data = limit ? (ITEM *) malloc (sizeof (ITEM) * limit) : NULL;
+ sorted = false;
+}
+
+template <typename ITEM> void
+Vector<ITEM>
+::resize (long index)
+{
+ if (index < limit)
+ return;
+ if (limit < 16)
+ limit = 16;
+ while (index >= limit)
+ {
+ if (limit > GIGACHUNK)
+ limit += GIGACHUNK; // Deoptimization for large experiments
+ else
+ limit = limit * 2;
+ }
+ data = (ITEM *) realloc (data, limit * sizeof (ITEM));
+}
+
+template <typename ITEM> void
+Vector<ITEM>::append (const ITEM item)
+{
+ // This routine will append "item" to the end of "this".
+ if (count >= limit)
+ resize (count);
+ data[count++] = item;
+}
+
+template <typename ITEM> void
+Vector<ITEM>::addAll (Vector<ITEM> *vec)
+{
+ if (vec)
+ for (int i = 0, sz = vec->size (); i < sz; i++)
+ append (vec->fetch (i));
+}
+
+template <typename ITEM> Vector<ITEM> *
+Vector<ITEM>::copy ()
+{
+ // This routine will return a copy of "this".
+ Vector<ITEM> *vector;
+ vector = new Vector<ITEM>;
+ vector->count = count;
+ vector->limit = limit;
+ vector->data = (ITEM *) malloc (sizeof (ITEM) * limit);
+ (void) memcpy ((char *) vector->data, (char *) data, sizeof (ITEM) * count);
+ return vector;
+}
+
+template <typename ITEM> long
+Vector<ITEM>::find (const ITEM match_item)
+{
+ for (long i = 0; i < size (); i++)
+ if (match_item == get (i))
+ return i;
+ return -1;
+}
+
+template <typename ITEM> long
+Vector<ITEM>::find_r (const ITEM match_item)
+{
+ for (long i = size () - 1; i >= 0; i--)
+ if (match_item == get (i))
+ return i;
+ return -1;
+}
+
+template <typename ITEM> void
+Vector<ITEM>::insert (long index, const ITEM item)
+{
+ // This routine will insert "item" into the "index"'th slot of "this".
+ // An error occurs if "index" > size().
+ // "index" is allowed to be equal to "count" in the case that
+ // you are inserting past the last element of the vector.
+ // In that case, the bcopy below becomes a no-op.
+ assert (index >= 0);
+ assert (index <= count);
+ append (item);
+ (void) memmove (((char *) (&data[index + 1])), (char *) (&data[index]),
+ (count - index - 1) * sizeof (ITEM));
+ data[index] = item;
+}
+
+template <typename ITEM> ITEM
+Vector<ITEM>::remove (long index)
+{
+ // This routine will remove the "index"'th item from "this" and
+ // return it. An error occurs if "index" >= size();.
+ assert (index >= 0);
+ assert (index < count);
+ ITEM item = data[index];
+ for (long i = index + 1; i < count; i++)
+ data[i - 1] = data[i];
+ count--;
+ // Bad code that works good when ITEM is a pointer type
+ data[count] = item;
+ return data[count];
+}
+
+template <typename ITEM> void
+Vector<ITEM>::swap (long index1, long index2)
+{
+ ITEM item;
+ item = data[index1];
+ data[index1] = data[index2];
+ data[index2] = item;
+}
+
+template <typename ITEM> void
+Vector<ITEM>::store (long index, const ITEM item)
+{
+ if (index >= count)
+ {
+ resize (index);
+ memset (&data[count], 0, (index - count) * sizeof (ITEM));
+ count = index + 1;
+ }
+ data[index] = item;
+}
+
+// This routine performs a binary search across
+// the entire vector, with "start" being the low boundary.
+// It is assumed that the vector is SORTED in
+// ASCENDING ORDER by the same criteria as the
+// compare function.
+// If no match is found, -1 is returned.
+template <typename ITEM> long
+Vector<ITEM>::bisearch (long start, long end, void *key, CompareFunc compare)
+{
+ ITEM *itemp;
+ if (end == -1)
+ end = count;
+ if (start >= end)
+ return -1; // start exceeds limit
+ itemp = (ITEM *) bsearch ((char *) key, (char *) &data[start],
+ end - start, sizeof (ITEM), (StdCompareFunc) compare);
+ if (itemp == (ITEM *) 0)
+ return -1; // not found
+ return (long) (itemp - data);
+}
+
+template <typename ITEM> void
+Vector<ITEM>::incorporate (const ITEM item, CompareFunc compare)
+{
+ long lt = 0;
+ long rt = count - 1;
+ while (lt <= rt)
+ {
+ long md = (lt + rt) / 2;
+ if (compare (data[md], item) < 0)
+ lt = md + 1;
+ else
+ rt = md - 1;
+ }
+ if (lt == count)
+ append (item);
+ else
+ insert (lt, item);
+}
+
+#define QSTHRESH 6
+
+template <typename ITEM> void
+qsort (ITEM *base, size_t nelem, ExtCompareFunc qcmp, void *arg)
+{
+ for (;;)
+ {
+ // For small arrays use insertion sort
+ if (nelem < QSTHRESH)
+ {
+ for (size_t i = 1; i < nelem; i++)
+ {
+ ITEM *p = base + i;
+ ITEM *q = p - 1;
+ if (qcmp (q, p, arg) > 0)
+ {
+ ITEM t = *p;
+ *p = *q;
+ while (q > base && qcmp (q - 1, &t, arg) > 0)
+ {
+ *q = *(q - 1);
+ --q;
+ }
+ *q = t;
+ }
+ }
+ return;
+ }
+
+ ITEM *last = base + nelem - 1;
+ ITEM *mid = base + nelem / 2;
+ // Sort the first, middle, and last elements
+ ITEM *a1 = base, *a2, *a3;
+ if (qcmp (base, mid, arg) > 0)
+ {
+ if (qcmp (mid, last, arg) > 0)
+ { // l-m-b
+ a2 = last;
+ a3 = last;
+ }
+ else if (qcmp (base, last, arg) > 0)
+ { // l-b-m
+ a2 = mid;
+ a3 = last;
+ }
+ else
+ { // m-b-l
+ a2 = mid;
+ a3 = mid;
+ }
+ }
+ else if (qcmp (mid, last, arg) > 0)
+ {
+ a1 = mid;
+ a3 = last;
+ if (qcmp (base, last, arg) > 0) // m-l-b
+ a2 = base;
+ else // b-l-m
+ a2 = a3;
+ }
+ else // b-m-l
+ a3 = a2 = a1;
+ if (a1 != a2)
+ {
+ ITEM t = *a1;
+ *a1 = *a2;
+ if (a2 != a3)
+ *a2 = *a3;
+ *a3 = t;
+ }
+
+ // Partition
+ ITEM *i = base + 1;
+ ITEM *j = last - 1;
+ for (;;)
+ {
+ while (i < mid && qcmp (i, mid, arg) <= 0)
+ i++;
+ while (j > mid && qcmp (mid, j, arg) <= 0)
+ j--;
+ if (i == j)
+ break;
+ ITEM t = *i;
+ *i = *j;
+ *j = t;
+ if (i == mid)
+ {
+ mid = j;
+ i++;
+ }
+ else if (j == mid)
+ {
+ mid = i;
+ j--;
+ }
+ else
+ {
+ i++;
+ j--;
+ }
+ }
+
+ // Compare two partitions. Do the smaller one by recursion
+ // and loop over the larger one.
+ size_t nleft = mid - base;
+ size_t nright = nelem - nleft - 1;
+ if (nleft <= nright)
+ {
+ qsort (base, nleft, qcmp, arg);
+ base = mid + 1;
+ nelem = nright;
+ }
+ else
+ {
+ qsort (mid + 1, nright, qcmp, arg);
+ nelem = nleft;
+ }
+ }
+}
+
+template<> inline void
+Vector<char*>::destroy ()
+{
+ for (long i = 0; i < count; i++)
+ free (data[i]);
+ count = 0;
+}
+
+template <typename ITEM> inline void
+Vector<ITEM>::destroy ()
+{
+ for (long i = 0; i < count; i++)
+ delete data[i];
+ count = 0;
+}
+
+#endif /* _VEC_H */