| /* Copyright (C) 2021-2024 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 <errno.h> |
| |
| #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 (); |
| execvp (exe_name, new_argv); |
| fprintf (stderr, GTXT ("Error: reexec() failed (%d: %s)\n"), errno, |
| STR(strerror (errno))); |
| fflush (stderr); |
| exit (1); |
| } |
| |
| /** |
| * 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>"); |
| |