xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/gp-collect-app.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "config.h"
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <strings.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/wait.h>
31 #include <sys/utsname.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include <time.h>
35 #include <errno.h>
36 #include <sys/ptrace.h>
37 
38 #include "gp-defs.h"
39 #include "cpu_frequency.h"
40 #include "util.h"
41 #include "collctrl.h"
42 #include "hwcdrv.h"
43 #include "gp-experiment.h"
44 #include "collect.h"
45 #include "StringBuilder.h"
46 
47 #define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
48 
49 extern char **environ;
50 
51 static volatile int interrupt = 0;
52 static int saved_stdout = -1;
53 static int  saved_stderr = -1;
54 static int no_short_usage = 0;
55 static int usage_fd = 2;
56 static collect *collect_obj = NULL;
57 extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
58 static char *outredirect = NULL;
59 static int precheck;
60 static int nprocesses;
61 static Process **processes;
62 
63 int
main(int argc,char * argv[])64 main (int argc, char *argv[])
65 {
66   // disable any alarm that might be pending
67   int r = alarm (0);
68   if (r != 0)
69     dbe_write (2, GTXT ("collect has alarm(%d) pending\n"), r);
70   collect_obj = new collect (argc, argv, environ);
71   collect_obj->start (argc, argv);
72   delete collect_obj;
73   return 0;
74 }
75 
76 extern "C" void
sigint_handler(int,siginfo_t *,void *)77 sigint_handler (int, siginfo_t *, void *)
78 {
79   interrupt = 1;
80   if (collect_obj->cc != NULL)
81     collect_obj->cc->interrupt ();
82   return;
83 }
84 
85 extern "C" void
sigalrm_handler(int,siginfo_t *,void *)86 sigalrm_handler (int, siginfo_t *, void *)
87 {
88   dbe_write (2, GTXT ("collect: unexpected alarm clock signal received\n"));
89   return;
90 }
91 
92 extern "C" void
sigterm_handler(int,siginfo_t *,void *)93 sigterm_handler (int, siginfo_t *, void *)
94 {
95   for (int i = 0; i < nprocesses; i++)
96     {
97       Process *proc = processes[i];
98       if (proc != NULL)
99 	kill (proc->pid, SIGTERM);
100     }
101 }
102 
collect(int argc,char * argv[],char ** envp)103 collect::collect (int argc, char *argv[], char **envp)
104 : Application (argc, argv)
105 {
106   verbose = 0;
107   disabled = 0;
108   cc = NULL;
109   collect_warnings = NULL;
110   collect_warnings_idx = 0;
111   int ii;
112   for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
113     sp_preload_list[ii] = NULL;
114   for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
115     sp_libpath_list[ii] = NULL;
116   java_path = NULL;
117   java_how = NULL;
118   jseen_global = 0;
119   nlabels = 0;
120   origargc = argc;
121   origargv = argv;
122   origenvp = envp;
123   mem_so_me = false;
124 }
125 
~collect()126 collect::~collect ()
127 {
128   delete cc;
129 }
130 
131 struct sigaction old_sigint_handler;
132 struct sigaction old_sigalrm_handler;
133 
134 void
start(int argc,char * argv[])135 collect::start (int argc, char *argv[])
136 {
137   char *ccret;
138   char *extype;
139   /* create a collector control structure, disabling aggressive warning */
140   cc = new Coll_Ctrl (0, false, false);
141   if (prog_name)
142     {
143       char *s = strrchr (prog_name, '/');
144       if (s && (s - prog_name) > 5) // Remove /bin/
145 	{
146 	  s = dbe_sprintf (NTXT ("%.*s"), (int) (s - prog_name - 4), prog_name);
147 	  cc->set_project_home (s);
148 	  free (s);
149 	}
150     }
151   char * errenable = cc->enable_expt ();
152   if (errenable)
153     {
154       writeStr (2, errenable);
155       free (errenable);
156     }
157 
158   /* install a handler for SIGALRM */
159   struct sigaction act;
160   memset (&act, 0, sizeof (struct sigaction));
161   sigemptyset (&act.sa_mask);
162   act.sa_handler = (SignalHandler) sigalrm_handler;
163   act.sa_flags = SA_RESTART | SA_SIGINFO;
164   if (sigaction (SIGALRM, &act, &old_sigalrm_handler) == -1)
165     {
166       writeStr (2, GTXT ("Unable to install SIGALRM handler\n"));
167       exit (-1);
168     }
169 
170   /* install a handler for SIGINT */
171   sigemptyset (&act.sa_mask);
172   act.sa_handler = (SignalHandler) sigint_handler;
173   act.sa_flags = SA_RESTART | SA_SIGINFO;
174   if (sigaction (SIGINT, &act, &old_sigint_handler) == -1)
175     {
176       writeStr (2, GTXT ("Unable to install SIGINT handler\n"));
177       exit (-1);
178     }
179 
180   /* install a handler for SIGTERM */
181   sigemptyset (&act.sa_mask);
182   act.sa_sigaction = sigterm_handler;
183   act.sa_flags = SA_RESTART | SA_SIGINFO;
184   if (sigaction (SIGTERM, &act, NULL) == -1)
185     {
186       writeStr (2, GTXT ("Unable to install SIGTERM handler\n"));
187       exit (-1);
188     }
189   if (argc > 1 && strncmp (argv[1], NTXT ("--whoami="), 9) == 0)
190     {
191       whoami = argv[1] + 9;
192       argc--;
193       argv++;
194     }
195 
196   /* check for no arguments -- usage message */
197   if (argc == 1)
198     {
199       verbose = 1;
200       usage_fd = 1;
201       validate_config (0);
202       usage ();
203       exit (0);
204     }
205   else if (argc == 2 && strcmp (argv[1], NTXT ("-h")) == 0)
206     {
207       /* only one argument, -h */
208       verbose = 1;
209       validate_config (0);
210       /* now print the HWC usage message */
211       show_hwc_usage ();
212       exit (0);
213     }
214   else if (argc == 2 && (strcmp (argv[1], NTXT ("-help")) == 0 ||
215 			 strcmp (argv[1], NTXT ("--help")) == 0))
216     {
217       /* only one argument, -help or --help */
218       verbose = 1;
219       usage_fd = 1;
220       validate_config (0);
221       usage ();
222       exit (0);
223     }
224 // Ruud
225   else if ((argc == 2) &&
226 	   (strcmp (argv[1], NTXT ("--version")) == 0))
227     {
228       /* only one argument, --version */
229 
230       /* print the version info */
231       Application::print_version_info ();
232       exit (0);
233     }
234 
235   /* precheck the arguments -- scan for -O, -M flagS */
236   precheck = 1;
237   targ_index = check_args (argc, argv);
238   if (targ_index < 0)
239     {
240       /* message has already been written */
241       usage_fd = 2;
242       short_usage ();
243       exit (1);
244     }
245   /* crack the arguments */
246   precheck = 0;
247   targ_index = check_args (argc, argv);
248   if (targ_index <= 0)
249     {
250       /* message has already been written */
251       usage_fd = 2;
252       short_usage ();
253       exit (1);
254     }
255   if (targ_index != 0)
256     check_target (argc, argv);
257   if (disabled != 0 && cc->get_count () == 0)
258     {
259       // show collection parameters; count data
260       ccret = cc->show (0);
261       writeStr (1, ccret);
262     }
263 
264   // see if Java version should be checked
265   if (cc->get_java_default () == 0 && java_path != NULL)
266     validate_java (java_path, java_how, verbose);
267 
268   /* if count data is requested, exec bit to do the real work */
269   /* even for a dryrun */
270   if (cc->get_count () != 0)
271     get_count_data ();
272 
273   /* if a dry run, just exit */
274   if (disabled != 0)
275     {
276       writeStr (1, cc->show_expt ());
277       StringBuilder sb;
278       sb.append (GTXT ("Exec argv[] = "));
279       for (int i = 0; i < nargs; i++)
280 	sb.appendf (NTXT ("%s "), arglist[i]);
281       sb.append (NTXT ("\n"));
282       char *s = sb.toString ();
283       writeStr (1, s);
284       free (s);
285       exit (0);
286     }
287 
288   // If the mem_so_me flag is set, preload mem.so
289   //	and launch the process
290   if (mem_so_me)
291     {
292       /* set env vars for mem.so */
293       if (putenv_memso () != 0)
294 	exit (1); /* message has already been written */
295       /* ensure original outputs restored for target */
296       reset_output ();
297 
298       /* now exec the target ... */
299       if (cc->get_debug_mode () == 1)
300 	{
301 	  traceme (arglist[0], arglist);
302 	  extype = NTXT ("traceme");
303 	}
304       else
305 	{
306 	  execvp (arglist[0], arglist);
307 	  extype = NTXT ("exevcp");
308 	}
309       /* oops, exec of the target failed */
310       char *em = strerror (errno);
311       set_output ();    /* restore output for collector */
312       if (em == NULL)
313 	dbe_write (2, GTXT ("memso %s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
314       else
315 	dbe_write (2, GTXT ("memso %s of %s failed: %s\n"), extype, argv[targ_index], em);
316       exit (1);
317     }
318 
319   /* normal path, setting up an experiment and launching the target */
320   /* set up the experiment */
321   ccret = cc->setup_experiment ();
322   if (ccret != NULL)
323     {
324       dbe_write (2, NTXT ("%s\n"), ccret);
325       free (ccret);
326       exit (1);
327     }
328   /* Beyond this point, the experiment is created */
329   if (collect_warnings != NULL)
330     {
331       warn_open ();
332       for (int i = 0; i < collect_warnings_idx; i++)
333 	warn_comment (SP_JCMD_CWARN, COL_WARN_APP_NOT_READY, collect_warnings[i], (int) strlen (collect_warnings[i]));
334       warn_close ();
335     }
336   /* check cpu frequency variation for intel*/
337   unsigned char mode = COL_CPUFREQ_NONE;
338   int max_freq = get_cpu_frequency (&mode);
339   char freq_scaling[256];
340   char turbo_mode[256];
341   *freq_scaling = 0;
342   *turbo_mode = 0;
343   if (mode & COL_CPUFREQ_SCALING)
344     snprintf (freq_scaling, sizeof (freq_scaling), NTXT (" frequency_scaling=\"enabled\""));
345   if (mode & COL_CPUFREQ_TURBO)
346     snprintf (turbo_mode, sizeof (turbo_mode), NTXT (" turbo_mode=\"enabled\""));
347   if (mode != COL_CPUFREQ_NONE)
348     {
349       warn_open ();
350       if (warn_file != NULL)
351 	{
352 	  warn_write ("<powerm>\n<frequency clk=\"%d\"%s%s/>\n</powerm>\n",
353 		      max_freq, freq_scaling, turbo_mode);
354 	  warn_close ();
355 	}
356     }
357 
358   /* check for labels to write to notes file */
359   if (nlabels != 0)
360     {
361       char *nbuf;
362       char nbuf2[MAXPATHLEN];
363       // fetch the experiment name and CWD
364       char *exp = cc->get_experiment ();
365       char *ev = getcwd (nbuf2, sizeof (nbuf2));
366 
367       // format the environment variable for the experiment directory name
368       if (ev != NULL && exp[0] != '/')
369 	// cwd succeeded, and experiment is a relative path
370 	nbuf = dbe_sprintf (NTXT ("%s/%s/%s"), nbuf2, exp, SP_NOTES_FILE);
371       else
372 	// getcwd failed or experiment is a fullpath
373 	nbuf = dbe_sprintf (NTXT ("%s/%s"), exp, SP_NOTES_FILE);
374 
375       FILE *f = fopen (nbuf, NTXT ("w"));
376       free (nbuf);
377       if (f != NULL)
378 	{
379 	  for (int i = 0; i < nlabels; i++)
380 	    fprintf (f, NTXT ("%s\n"), label[i]);
381 	  fclose (f);
382 	}
383     }
384   /* check for user interrupt */
385   if (interrupt == 1)
386     {
387       cc->delete_expt ();
388       writeStr (2, GTXT ("User interrupt\n"));
389       exit (0);
390     }
391 
392   /* print data-collection parameters */
393   if (verbose)
394     {
395       ccret = cc->show (0);
396       if (ccret != NULL)
397 	writeStr (2, ccret);
398     }
399   ccret = cc->show_expt ();
400   if (ccret != NULL)
401     writeStr (1, ccret);    /* write this to stdout */
402 
403   pid_t pid = (pid_t) cc->get_attach_pid ();
404   if (pid == (pid_t) 0)
405     {
406       /* No attach */
407       /* Set the environment for libcollector */
408       if (putenv_libcollector () != 0)
409 	{
410 	  /* message has already been written */
411 	  cc->delete_expt ();
412 	  exit (1);
413 	}
414       /* ensure original output fds restored for target */
415       reset_output ();
416 
417       /* now exec the target ... */
418       if (cc->get_debug_mode () == 1)
419 	{
420 	  traceme (arglist[0], arglist);
421 	  extype = NTXT ("traceme");
422 	}
423       else
424 	{
425 	  execvp (arglist[0], arglist);
426 	  extype = NTXT ("execvp");
427 	}
428 
429       /* we reach this point only if the target launch failed */
430       char *em = strerror (errno);
431 
432       /* restore output for collector */
433       set_output ();
434 
435       /* exec failed; delete experiment */
436       cc->delete_expt ();
437 
438       /* print a message and exit */
439       if (em == NULL)
440 	dbe_write (2, GTXT ("%s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
441       else
442 	dbe_write (2, GTXT ("%s of %s failed: %s\n"), extype, argv[targ_index], em);
443       exit (1);
444     }
445   else
446     abort ();
447 }
448 
449 /**
450  * Prepare a warning message and pass it to warn_write()
451  * @Parameters:
452  * kind Type of comment
453  * num ID
454  * s Comment sting
455  * len Length of the string
456  * @Return: none.
457  */
458 void
warn_comment(const char * kind,int num,char * s,int len)459 collect::warn_comment (const char *kind, int num, char *s, int len)
460 {
461   if (len != 0)
462     warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%.*s</event>\n"),
463 		kind, num, len, s);
464   else if (s == NULL)
465     warn_write (NTXT ("<event kind=\"%s\" id=\"%d\"/>\n"), kind, num);
466   else
467     warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%s</event>\n"), kind, num, s);
468 }
469 
470 /**
471  * Open the warnings file in Append mode ("aw")
472  */
473 void
warn_open()474 collect::warn_open ()
475 {
476   // open the warnings file
477   warnfilename = dbe_sprintf (NTXT ("%s/%s"), cc->get_experiment (), SP_WARN_FILE);
478   int fd = open (warnfilename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
479   warn_file = fdopen (fd, NTXT ("aw"));
480 }
481 
482 /**
483  * Close the warnings file
484  */
485 void
warn_close()486 collect::warn_close ()
487 {
488   (void) fclose (warn_file);
489 }
490 
491 /**
492  * Format the warning message and write it to the warnings file
493  */
494 void
warn_write(const char * format,...)495 collect::warn_write (const char *format, ...)
496 {
497   char buf[4096];
498   // format the input arguments into a string
499   va_list va;
500   va_start (va, format);
501   vsnprintf (buf, sizeof (buf), format, va);
502   va_end (va);
503   // write it to the warnings file (warnings.xml)
504   fwrite (buf, 1, strlen (buf), warn_file);
505   fflush (warn_file);
506 }
507 
508 /* process the args, setting expt. params,
509  *	and finding offset for a.out name
510  */
511 int
check_args(int argc,char * argv[])512 collect::check_args (int argc, char *argv[])
513 {
514   int hseen = 0;
515   int hoffseen = 0;
516   int lseen = 0;
517   int tseen = 0;
518   int pseen = 0;
519   int sseen = 0;
520   int yseen = 0;
521   int Fseen = 0;
522   int Aseen = 0;
523   int Sseen = 0;
524   int Hseen = 0;
525   int iseen = 0;
526   int Jseen = 0;
527   int ofseen = 0;
528   char *expName = NULL;
529   bool overwriteExp = false;
530   char *ccret;
531   char *ccwarn;
532   for (targ_index = 1; targ_index < argc; targ_index++)
533     {
534       if (argv[targ_index] == NULL)
535 	break;
536       if (dbe_strcmp (argv[targ_index], "--") == 0)
537 	{
538 	  targ_index++;
539 	  break;
540 	}
541       if (argv[targ_index][0] != '-')
542 	break;
543       int param;
544       switch (argv[targ_index][1])
545 	{
546 	case 'y':
547 	  {
548 	    if (precheck == 1)
549 	      {
550 		targ_index++;
551 		if (argv[targ_index] == NULL)
552 		  return 0;
553 		break;
554 	      }
555 	    char *ptr;
556 	    int resume = 1;
557 	    if (checkflagterm (argv[targ_index]) == -1) return -1;
558 	    if (yseen != 0)
559 	      {
560 		dupflagseen ('y');
561 		return -1;
562 	      }
563 	    yseen++;
564 	    targ_index++;
565 	    if (argv[targ_index] == NULL)
566 	      {
567 		writeStr (2, GTXT ("-y requires a signal argument\n"));
568 		return -1;
569 	      }
570 	    if ((ptr = strrchr (argv[targ_index], ',')) != NULL)
571 	      {
572 		if ((*(ptr + 1) != 'r') || (*(ptr + 2) != 0))
573 		  {
574 		    /* not the right trailer */
575 		    dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
576 		    return -1;
577 		  }
578 		resume = 0;
579 		*ptr = 0;
580 	      }
581 	    param = cc->find_sig (argv[targ_index]);
582 	    if (param < 0)
583 	      {
584 		/* invalid signal */
585 		dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
586 		return -1;
587 	      }
588 	    ccret = cc->set_pauseresume_signal (param, resume);
589 	    if (ccret != NULL)
590 	      {
591 		/* invalid signal; write message */
592 		writeStr (2, ccret);
593 		return -1;
594 	      }
595 	    break;
596 	  }
597 	case 'l':
598 	  if (precheck == 1)
599 	    {
600 	      targ_index++;
601 	      if (argv[targ_index] == NULL)
602 		return 0;
603 	      break;
604 	    }
605 	  if (checkflagterm (argv[targ_index]) == -1) return -1;
606 	  if (lseen != 0)
607 	    {
608 	      dupflagseen ('l');
609 	      return -1;
610 	    }
611 	  lseen++;
612 	  targ_index++;
613 	  if (argv[targ_index] == NULL)
614 	    {
615 	      writeStr (2, GTXT ("-l requires a signal argument\n"));
616 	      return -1;
617 	    }
618 	  param = cc->find_sig (argv[targ_index]);
619 	  if (param < 0)
620 	    {
621 	      /* invalid signal */
622 	      dbe_write (2, GTXT ("Invalid sample signal %s\n"), argv[targ_index]);
623 	      return -1;
624 	    }
625 	  ccret = cc->set_sample_signal (param);
626 	  if (ccret != NULL)
627 	    {
628 	      /* invalid signal; write message */
629 	      writeStr (2, ccret);
630 	      free (ccret);
631 	      return -1;
632 	    }
633 	  break;
634 
635 #ifdef GPROFNG_DOES_NOT_SUPPORT
636 	case 'P':
637 	  if (precheck == 1)
638 	    {
639 	      targ_index++;
640 	      if (argv[targ_index] == NULL)
641 		return 0;
642 	      break;
643 	    }
644 	  if (checkflagterm (argv[targ_index]) == -1)
645 	    return -1;
646 	  if (Pseen != 0)
647 	    {
648 	      dupflagseen ('P');
649 	      return -1;
650 	    }
651 	  Pseen++;
652 	  targ_index++;
653 	  if (argv[targ_index] == NULL)
654 	    {
655 	      writeStr (2, GTXT ("-P requires a process pid argument\n"));
656 	      return -1;
657 	    }
658 	  ccret = cc->set_attach_pid (argv[targ_index]);
659 	  if (ccret != NULL)
660 	    {
661 	      /* error; write message */
662 	      writeStr (2, ccret);
663 	      free (ccret);
664 	      return -1;
665 	    }
666 	  break;
667 #endif
668 	case 't':
669 	  if (precheck == 1)
670 	    {
671 	      targ_index++;
672 	      if (argv[targ_index] == NULL)
673 		return 0;
674 	      break;
675 	    }
676 
677 	  if (checkflagterm (argv[targ_index]) == -1) return -1;
678 	  if (tseen != 0)
679 	    {
680 	      dupflagseen ('t');
681 	      return -1;
682 	    }
683 	  tseen++;
684 	  targ_index++;
685 	  if (argv[targ_index] == NULL)
686 	    {
687 	      writeStr (2, GTXT ("-t requires a run-duration argument\n"));
688 	      return -1;
689 	    }
690 	  ccret = cc->set_time_run (argv[targ_index]);
691 	  if (ccret != NULL)
692 	    {
693 	      /* error; write message */
694 	      writeStr (2, ccret);
695 	      free (ccret);
696 	      return -1;
697 	    }
698 	  break;
699 	case 'p':
700 	  {
701 	    char *warnmsg;
702 	    if (precheck == 1)
703 	      {
704 		targ_index++;
705 		if (argv[targ_index] == NULL)
706 		  return 0;
707 		break;
708 	      }
709 	    if (checkflagterm (argv[targ_index]) == -1) return -1;
710 	    if (pseen != 0)
711 	      {
712 		dupflagseen ('p');
713 		return -1;
714 	      }
715 	    pseen++;
716 	    targ_index++;
717 	    if (argv[targ_index] == NULL)
718 	      {
719 		writeStr (2, GTXT ("-p requires a clock-profiling argument\n"));
720 		return -1;
721 	      }
722 	    ccret = cc->set_clkprof (argv[targ_index], &warnmsg);
723 	    if (ccret != NULL)
724 	      {
725 		writeStr (2, ccret);
726 		free (ccret);
727 		return -1;
728 	      }
729 	    if (warnmsg != NULL)
730 	      {
731 		writeStr (2, warnmsg);
732 		free (warnmsg);
733 	      }
734 	    break;
735 	  }
736 	case 's':
737 	  if (precheck == 1)
738 	    {
739 	      targ_index++;
740 	      if (argv[targ_index] == NULL)
741 		return 0;
742 	      break;
743 	    }
744 	  if (checkflagterm (argv[targ_index]) == -1) return -1;
745 	  if (sseen != 0)
746 	    {
747 	      dupflagseen ('s');
748 	      return -1;
749 	    }
750 	  sseen++;
751 	  targ_index++;
752 	  if (argv[targ_index] == NULL)
753 	    {
754 	      writeStr (2, GTXT ("-s requires a synchronization-tracing argument\n"));
755 	      return -1;
756 	    }
757 	  ccret = cc->set_synctrace (argv[targ_index]);
758 	  if (ccret != NULL)
759 	    {
760 	      writeStr (2, ccret);
761 	      free (ccret);
762 	      return -1;
763 	    }
764 	  break;
765 	case 'h':
766 	  {
767 	    if (precheck == 1)
768 	      {
769 		targ_index++;
770 		if (argv[targ_index] == NULL)
771 		  return 0;
772 		break;
773 	      }
774 	    if (checkflagterm (argv[targ_index]) == -1)
775 	      return -1;
776 	    targ_index++;
777 	    if ((argv[targ_index] == NULL) || (strlen (argv[targ_index]) == 0))
778 	      {
779 		writeStr (2, GTXT ("-h requires a HW-counter-profiling argument\n"));
780 		return -1;
781 	      }
782 	    // Check for some special cases
783 	    char * string = argv[targ_index];
784 	    if (strcmp (argv[targ_index], NTXT ("off")) == 0)
785 	      {
786 		if (hseen != 0)
787 		  {
788 		    no_short_usage = 1;
789 		    writeStr (2, GTXT ("-h off cannot be used with any other -h arguments\n"));
790 		    return -1;
791 		  }
792 		hoffseen = 1;
793 		hseen = 1;
794 		cc->disable_hwc ();
795 		break;
796 	      }
797 	    // Check to see if we can use HWC
798 	    unsigned hwc_maxregs = hwc_get_max_concurrent (false);
799 	    if (hwc_maxregs == 0)
800 	      {
801 		char buf[1024];
802 		char *pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0);
803 		if (*pch)
804 		  dbe_write (2, GTXT ("HW counter profiling is not supported on this system: %s%s"),
805 			     pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
806 		else
807 		  dbe_write (2, GTXT ("HW counter profiling is not supported on this system\n"));
808 		no_short_usage = 1;
809 		return -1;
810 	      }
811 	    // Make sure there's no other -h after -h off
812 	    if (hoffseen != 0)
813 	      {
814 		no_short_usage = 1;
815 		writeStr (2, GTXT ("No -h arguments can be used after -h off\n"));
816 		return -1;
817 	      }
818 	    // set up to process HW counters (to know about default counters)
819 	    cc->setup_hwc ();
820 	    hseen++;
821 	    char *warnmsg;
822 	    if (strcmp (argv[targ_index], NTXT ("on")) == 0)
823 	      ccret = cc->add_default_hwcstring ("on", &warnmsg, true);
824 	    else if (strcmp (argv[targ_index], NTXT ("hi")) == 0 ||
825 		     strcmp (argv[targ_index], NTXT ("high")) == 0)
826 	      ccret = cc->add_default_hwcstring ("hi", &warnmsg, true);
827 	    else if (strcmp (argv[targ_index], NTXT ("lo")) == 0 ||
828 		     strcmp (argv[targ_index], NTXT ("low")) == 0)
829 	      ccret = cc->add_default_hwcstring ("lo", &warnmsg, true);
830 	    else if (strcmp (argv[targ_index], NTXT ("auto")) == 0)
831 	      ccret = cc->add_default_hwcstring ("auto", &warnmsg, true);
832 	    else
833 	      ccret = cc->add_hwcstring (string, &warnmsg);
834 	    if (ccret != NULL)
835 	      {
836 		/* set global flag to suppress the short_usage message for any subsequent HWC errors */
837 		no_short_usage = 1;
838 		writeStr (2, ccret);
839 		free (ccret);
840 		return -1;
841 	      }
842 	    if (warnmsg != NULL)
843 	      {
844 		writeStr (2, warnmsg);
845 		free (warnmsg);
846 	      }
847 	    break;
848 	  }
849 	case 'O':
850 	  overwriteExp = true;
851 	  ATTRIBUTE_FALLTHROUGH
852 	case 'o':
853 	  if (precheck == 1)
854 	    {
855 	      targ_index++;
856 	      if (argv[targ_index] == NULL)
857 		return 0;
858 	      break;
859 	    }
860 	  if (checkflagterm (argv[targ_index]) == -1)
861 	    return -1;
862 	  if (argv[targ_index + 1] == NULL)
863 	    {
864 	      dbe_write (2, GTXT ("Argument %s must be followed by a file name\n"),
865 			 argv[targ_index]);
866 	      return -1;
867 	    }
868 	  if (expName != NULL)
869 	    {
870 	      dbe_write (2, GTXT ("Only one -o or -O argument may be used\n"));
871 	      dupflagseen ('o');
872 	      return -1;
873 	    }
874 	  expName = argv[targ_index + 1];
875 	  targ_index++;
876 	  break;
877 	case 'S':
878 	  if (precheck == 1)
879 	    {
880 	      targ_index++;
881 	      if (argv[targ_index] == NULL)
882 		return 0;
883 	      break;
884 	    }
885 	  if (checkflagterm (argv[targ_index]) == -1) return -1;
886 	  if (argv[targ_index + 1] == NULL)
887 	    {
888 	      dbe_write (2, GTXT ("Argument %s must be followed by a sample interval name\n"),
889 			 argv[targ_index]);
890 	      return -1;
891 	    }
892 	  if (Sseen != 0)
893 	    {
894 	      dupflagseen ('S');
895 	      return -1;
896 	    }
897 	  Sseen++;
898 	  ccret = cc->set_sample_period (argv[targ_index + 1]);
899 	  if (ccret != NULL)
900 	    {
901 	      writeStr (2, ccret);
902 	      free (ccret);
903 	      return -1;
904 	    }
905 	  targ_index++;
906 	  break;
907 	case 'H':
908 	  if (precheck == 1)
909 	    {
910 	      targ_index++;
911 	      if (argv[targ_index] == NULL)
912 		return 0;
913 	      break;
914 	    }
915 	  if (checkflagterm (argv[targ_index]) == -1)
916 	    return -1;
917 	  if (argv[targ_index + 1] == NULL)
918 	    {
919 	      dbe_write (2, GTXT ("Argument %s requires a heap-tracing argument\n"),
920 			 argv[targ_index]);
921 	      return -1;
922 	    }
923 	  if (Hseen != 0)
924 	    {
925 	      dupflagseen ('H');
926 	      return -1;
927 	    }
928 	  Hseen++;
929 	  ccret = cc->set_heaptrace (argv[targ_index + 1]);
930 	  if (ccret != NULL)
931 	    {
932 	      writeStr (2, ccret);
933 	      free (ccret);
934 	      return -1;
935 	    }
936 	  if (cc->get_java_default () == 1)
937 	    cc->set_java_mode (NTXT ("off"));
938 	  targ_index++;
939 	  break;
940 	case 'i':
941 	  if (precheck == 1)
942 	    {
943 	      targ_index++;
944 	      if (argv[targ_index] == NULL)
945 		return 0;
946 	      break;
947 	    }
948 	  if (checkflagterm (argv[targ_index]) == -1)
949 	    return -1;
950 	  if (argv[targ_index + 1] == NULL)
951 	    {
952 	      fprintf (stderr, GTXT ("Argument %s requires an I/O-tracing argument\n"),
953 		       argv[targ_index]);
954 	      return -1;
955 	    }
956 	  if (iseen != 0)
957 	    {
958 	      dupflagseen ('i');
959 	      return -1;
960 	    }
961 	  iseen++;
962 	  ccret = cc->set_iotrace (argv[targ_index + 1]);
963 	  if (ccret != NULL)
964 	    {
965 	      writeStr (2, ccret);
966 	      free (ccret);
967 	      return -1;
968 	    }
969 	  targ_index++;
970 	  break;
971 	case 'j':
972 	  if (precheck == 1)
973 	    {
974 	      targ_index++;
975 	      if (argv[targ_index] == NULL)
976 		return 0;
977 	      break;
978 	    }
979 	  if (checkflagterm (argv[targ_index]) == -1) return -1;
980 	  if (argv[targ_index + 1] == NULL)
981 	    {
982 	      dbe_write (2, GTXT ("Argument %s requires a java-profiling argument\n"),
983 			 argv[targ_index]);
984 	      return -1;
985 	    }
986 	  if (jseen_global != 0)
987 	    {
988 	      dupflagseen ('j');
989 	      return -1;
990 	    }
991 	  jseen_global++;
992 	  ccret = cc->set_java_mode (argv[targ_index + 1]);
993 	  if (ccret != NULL)
994 	    {
995 	      writeStr (2, ccret);
996 	      free (ccret);
997 	      return -1;
998 	    }
999 	  targ_index++;
1000 	  break;
1001 	case 'J':
1002 	  if (precheck == 1)
1003 	    {
1004 	      targ_index++;
1005 	      if (argv[targ_index] == NULL)
1006 		return 0;
1007 	      break;
1008 	    }
1009 	  if (checkflagterm (argv[targ_index]) == -1) return -1;
1010 	  if (argv[targ_index + 1] == NULL)
1011 	    {
1012 	      dbe_write (2, GTXT ("Argument %s requires a java argument\n"),
1013 			 argv[targ_index]);
1014 	      return -1;
1015 	    }
1016 	  if (Jseen != 0)
1017 	    {
1018 	      dupflagseen ('J');
1019 	      return -1;
1020 	    }
1021 	  Jseen++;
1022 	  ccret = cc->set_java_args (argv[targ_index + 1]);
1023 	  if (ccret != NULL)
1024 	    {
1025 	      writeStr (2, ccret);
1026 	      free (ccret);
1027 	      return -1;
1028 	    }
1029 	  targ_index++;
1030 	  break;
1031 	case 'F':
1032 	  if (precheck == 1)
1033 	    {
1034 	      targ_index++;
1035 	      if (argv[targ_index] == NULL)
1036 		return 0;
1037 	      break;
1038 	    }
1039 	  if (checkflagterm (argv[targ_index]) == -1)
1040 	    return -1;
1041 	  if (argv[targ_index + 1] == NULL)
1042 	    {
1043 	      dbe_write (2, GTXT ("Argument %s requires a descendant-following argument\n"),
1044 			 argv[targ_index]);
1045 	      return -1;
1046 	    }
1047 	  if (Fseen != 0)
1048 	    {
1049 	      dupflagseen ('F');
1050 	      return -1;
1051 	    }
1052 	  Fseen++;
1053 	  ccret = cc->set_follow_mode (argv[targ_index + 1]);
1054 	  if (ccret != NULL)
1055 	    {
1056 	      writeStr (2, ccret);
1057 	      free (ccret);
1058 	      return -1;
1059 	    }
1060 	  targ_index++;
1061 	  break;
1062 	case 'a':
1063 	  if (precheck == 1)
1064 	    {
1065 	      targ_index++;
1066 	      if (argv[targ_index] == NULL)
1067 		return 0;
1068 	      break;
1069 	    }
1070 	  if (checkflagterm (argv[targ_index]) == -1)
1071 	    return -1;
1072 	  if (argv[targ_index + 1] == NULL)
1073 	    {
1074 	      dbe_write (2, GTXT ("Argument %s requires a load-object archiving argument\n"),
1075 			 argv[targ_index]);
1076 	      return -1;
1077 	    }
1078 	  if (Aseen != 0)
1079 	    {
1080 	      dupflagseen ('a');
1081 	      return -1;
1082 	    }
1083 	  Aseen++;
1084 	  ccret = cc->set_archive_mode (argv[targ_index + 1]);
1085 	  if (ccret != NULL)
1086 	    {
1087 	      writeStr (2, ccret);
1088 	      free (ccret);
1089 	      return -1;
1090 	    }
1091 	  targ_index++;
1092 	  break;
1093 	case 'C':
1094 	  if (precheck == 1)
1095 	    {
1096 	      targ_index++;
1097 	      if (argv[targ_index] == NULL)
1098 		return 0;
1099 	      break;
1100 	    }
1101 	  if (checkflagterm (argv[targ_index]) == -1)
1102 	    return -1;
1103 	  if (argv[targ_index + 1] == NULL)
1104 	    {
1105 	      dbe_write (2, GTXT ("Argument %s must be followed by a comment\n"),
1106 			 argv[targ_index]);
1107 	      return -1;
1108 	    }
1109 	  if (nlabels == MAXLABELS)
1110 	    {
1111 	      dbe_write (2, GTXT ("No more than %d comments may be specified\n"),
1112 			 MAXLABELS);
1113 	      return -1;
1114 	    }
1115 	  label[nlabels] = argv[targ_index + 1];
1116 	  nlabels++;
1117 	  targ_index++;
1118 	  break;
1119 	case 'n':
1120 	case 'v':
1121 	case 'V':
1122 	  if (precheck == 1)
1123 	    break;
1124 	  do_flag (&argv[targ_index][1]);
1125 	  break;
1126 	case 'Z':
1127 	  // special undocumented argument for debug builds only to allow analyzer to
1128 	  // LD_PRELOAD mem.so for the target it spawns
1129 	  mem_so_me = true;
1130 	  break;
1131 	case '-':
1132 	  if (strcmp (argv[targ_index], NTXT ("--verbose")) == 0)
1133 	    do_flag ("v");
1134 	  else if (strcmp (argv[targ_index], "--outfile") == 0)
1135 	    {
1136 	      if (precheck == 0)
1137 		{
1138 		  targ_index++;
1139 		  if (argv[targ_index] == NULL)
1140 		    return 0;
1141 		  break;
1142 		}
1143 	      // process this argument now
1144 	      if (argv[targ_index + 1] == NULL)
1145 		{
1146 		  dbe_write (2, GTXT ("Argument %s requires a file argument\n"),
1147 			     argv[targ_index]);
1148 		  return -1;
1149 		}
1150 	      if (ofseen != 0)
1151 		{
1152 		  dupflagseen (argv[targ_index]);
1153 		  return -1;
1154 		}
1155 	      ofseen++;
1156 	      if (outredirect == NULL)
1157 		{
1158 		  outredirect = argv[targ_index + 1];
1159 		  set_output ();
1160 		} // else already redirected; ignore with no message
1161 	      targ_index++;
1162 	    }
1163 	  else
1164 	    {
1165 	      dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
1166 	      return -1;
1167 	    }
1168 	  break;
1169 	default:
1170 	  dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
1171 	  return -1;
1172 	}
1173     }
1174   if (targ_index >= argc)
1175     return -1;
1176   if (argv[targ_index] == NULL)
1177     {
1178       if (precheck == 1)
1179 	return 0;
1180       if (cc->get_attach_pid () != 0)  /* no target is OK, if we're attaching */
1181 	return 0;
1182       writeStr (2, GTXT ("Name of target must be specified\n"));
1183       return -1;
1184     }
1185   if (expName)
1186     {
1187       ccwarn = NULL;
1188       ccret = cc->set_expt (expName, &ccwarn, overwriteExp);
1189       if (ccwarn)
1190 	{
1191 	  writeStr (2, ccwarn);
1192 	  free (ccwarn);
1193 	}
1194       if (ccret)
1195 	{
1196 	  writeStr (2, ccret);
1197 	  return -1;
1198 	}
1199     }
1200   if (cc->get_attach_pid () != 0)
1201     {
1202       writeStr (2, GTXT ("Name of target must not be specified when -P is used\n"));
1203       return -1;
1204     }
1205   return targ_index;
1206 }
1207 
1208 int
checkflagterm(const char * c)1209 collect::checkflagterm (const char *c)
1210 {
1211   if (c[2] != 0)
1212     {
1213       dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), c);
1214       return -1;
1215     }
1216   return 0;
1217 }
1218 
1219 int
do_flag(const char * flags)1220 collect::do_flag (const char *flags)
1221 {
1222   char *s;
1223   for (int i = 0;; i++)
1224     {
1225       switch (flags[i])
1226 	{
1227 	case 0: // end of string
1228 	  return 0;
1229 	case 'n':
1230 	  disabled = 1;
1231 	  if (verbose != 1)
1232 	    {
1233 // Ruud
1234 	      Application::print_version_info ();
1235 /*
1236 	      dbe_write (2, NTXT ("GNU %s version %s\n"),
1237 			 get_basename (prog_name), VERSION);
1238 */
1239 	      verbose = 1;
1240 	    }
1241 	  break;
1242 	case 'x':
1243 	  s = cc->set_debug_mode (1);
1244 	  if (s)
1245 	    {
1246 	      writeStr (2, s);
1247 	      free (s);
1248 	    }
1249 	  break;
1250 	case 'v':
1251 	  if (verbose != 1)
1252 	    {
1253 // Ruud
1254 	      Application::print_version_info ();
1255 /*
1256 	      dbe_write (2, NTXT ("GNU %s version %s\n"),
1257 			 get_basename (prog_name), VERSION);
1258 */
1259 	      verbose = 1;
1260 	    }
1261 	  break;
1262 	case 'V':
1263 // Ruud
1264 	  Application::print_version_info ();
1265 /*
1266 	  dbe_write (2, NTXT ("GNU %s version %s\n"),
1267 		     get_basename (prog_name), VERSION);
1268 */
1269 	  /* no further processing.... */
1270 	  exit (0);
1271 	}
1272     }
1273 }
1274 
1275 /*
1276  * traceme - cause the caller to stop at the end of the next exec()
1277  *	 so that a debugger can attach to the new program
1278  *
1279  * Takes same arguments as execvp()
1280  */
1281 int
traceme(const char * execvp_file,char * const execvp_argv[])1282 collect::traceme (const char *execvp_file, char *const execvp_argv[])
1283 {
1284   int ret = -1;
1285   pid_t pid = fork ();
1286   if (pid == 0)
1287     { // child
1288       // child will set up itself to be PTRACE'd, and then exec the target executable
1289       /* reset the SP_COLLECTOR_FOUNDER value to the new pid */
1290       pid_t mypid = getpid ();
1291       char *ev = dbe_sprintf (NTXT ("%s=%d"), SP_COLLECTOR_FOUNDER, mypid);
1292       if (putenv (ev) != 0)
1293 	{
1294 	  dbe_write (2, GTXT ("fork-child: Can't putenv of \"%s\": run aborted\n"), ev);
1295 	  return 1;
1296 	}
1297       ptrace (PTRACE_TRACEME, 0, NULL, NULL); // initiate trace
1298       ret = execvp (execvp_file, execvp_argv); // execvp user command
1299       return ret; // execvp failed
1300     }
1301   else if (pid > 0)
1302     { // parent
1303       int status;
1304       if (waitpid (pid, &status, 0) != pid)
1305 	{ // wait for execvp to cause signal
1306 	  writeStr (2, GTXT ("parent waitpid() failed\n"));
1307 	  return -2;
1308 	}
1309       if (!WIFSTOPPED (status))
1310 	writeStr (2, GTXT ("WIFSTOPPED(status) failed\n"));
1311 
1312       // originally, PTRACE_DETACH would send SIGTSTP, but now we do it here:
1313       if (kill (pid, SIGTSTP) != 0)
1314 	writeStr (2, GTXT ("kill(pid, SIGTSTP) failed\n"));
1315       if (ptrace (PTRACE_DETACH, pid, NULL, 0) != 0)
1316 	{ // detach trace
1317 	  writeStr (2, GTXT ("ptrace(PTRACE_DETACH) failed\n"));
1318 	  return -4;
1319 	}
1320       dbe_write (2, GTXT ("Waiting for attach from debugger: pid=%d\n"), (int) pid);
1321 
1322       // wait for an external debugger to attach
1323       if (waitpid (pid, &status, 0) != pid)
1324 	{ // keep parent alive until child quits
1325 	  writeStr (2, GTXT ("parent final waitpid() failed\n"));
1326 	  return -5;
1327 	}
1328     }
1329   else
1330     return -1; // fork failed
1331   exit (0);
1332 }
1333 
1334 void
dupflagseen(char c)1335 collect::dupflagseen (char c)
1336 {
1337   dbe_write (2, GTXT ("Only one -%c argument may be used\n"), c);
1338 }
1339 
1340 void
dupflagseen(const char * s)1341 collect::dupflagseen (const char *s)
1342 {
1343   dbe_write (2, GTXT ("Only one %s argument may be used\n"), s);
1344 }
1345 
1346 int
set_output()1347 collect::set_output ()
1348 {
1349   static int initial = 1;
1350   if (outredirect)
1351     {
1352       int fd = open (outredirect, O_WRONLY | O_CREAT | O_APPEND,
1353 		     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1354       if (fd == -1)
1355 	{
1356 	  dbe_write (2, GTXT ("Warning: Can't open collector output `%s': %s\n"),
1357 		     outredirect, strerror (errno));
1358 	}
1359       else
1360 	{
1361 	  if ((saved_stdout = dup (1)) == -1 || dup2 (fd, 1) == -1)
1362 	    dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
1363 		       NTXT ("stdout"), strerror (errno));
1364 	  if ((saved_stderr = dup (2)) == -1 || dup2 (fd, 2) == -1)
1365 	    dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
1366 		       NTXT ("stderr"), strerror (errno));
1367 	  close (fd);
1368 	  if ((saved_stdout != -1) && (saved_stderr != -1))
1369 	    {
1370 	      if (initial)
1371 		{
1372 		  struct timeval tp;
1373 		  gettimeofday (&tp, NULL);
1374 		  writeStr (2, ctime (&tp.tv_sec));
1375 		  initial = 0;
1376 		}
1377 	      return 1; // diversion in place
1378 	    }
1379 	}
1380     }
1381   return 0; // no diversion
1382 }
1383 
1384 void
reset_output()1385 collect::reset_output ()
1386 {
1387   if (saved_stdout != -1 &&
1388       (dup2 (saved_stdout, 1) == -1 || close (saved_stdout)))
1389     dbe_write (2, GTXT ("Warning: Can't restore collector stdout: %s\n"),
1390 	       strerror (errno));
1391   if (saved_stderr != -1 &&
1392       (dup2 (saved_stderr, 2) == -1 || close (saved_stderr)))
1393     dbe_write (2, GTXT ("Warning: Can't restore collector stderr: %s\n"),
1394 	       strerror (errno));
1395 }
1396 
1397 void
usage()1398 collect::usage ()
1399 {
1400 
1401 /*
1402   Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
1403   end of this long list.
1404 */
1405   printf ( GTXT (
1406     "Usage: gprofng collect app [OPTION(S)] TARGET [TARGET_ARGUMENTS]\n")),
1407 
1408 /*
1409 -------------------------------------------------------------------------------
1410   For a reason I don't understand, the continuation line(s) need to start at
1411   column 26 in order for help2man to do the righ thing. Ruud
1412 -------------------------------------------------------------------------------
1413 */
1414   printf ( GTXT (
1415     "\n"
1416     "Collect performance data on the target program. In addition to Program\n"
1417     "Counter PC) sampling, hardware event counters and various tracing options\n"
1418     "are supported.\n"
1419     "\n"
1420     "Options:\n"
1421     "\n"
1422     " --version           print the version number and exit.\n"
1423     " --help              print usage information and exit.\n"
1424     " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
1425     "\n"
1426     " -p {off|on|lo|hi|<value>}  disable (off) or enable (on) clock-profiling using a default\n"
1427     "                    sampling granularity, or enable clock-profiling implicitly by\n"
1428     "                    setting the sampling granularity (lo, hi, or a specific value\n"
1429     "                    in ms); by default clock profiling is enabled.\n"
1430     "\n"
1431     " -h {<ctr_def>...,<ctr_n_def>}  enable hardware event counter profiling and select\n"
1432     "                    the counter(s); to see the supported counters on this system use\n"
1433     "                    the -h option without other arguments.\n"
1434     "\n"
1435     " -o <exp_name>     specify the name for (and path to) the experiment directory; the\n"
1436     "                    the default path is the current directory.\n"
1437     "\n"
1438     " -O <exp_name>     the same as -o, but unlike the -o option, silently overwrite an\n"
1439     "                    existing experiment directory with the same name.\n"
1440     "\n"
1441     " -C <label>        add up to 10 comment labels to the experiment; comments appear in\n"
1442     "                    the notes section of the header.\n"
1443     "\n"
1444     " -j {on|off|<path>} enable (on), or disable (off) Java profiling when the target\n"
1445     "                     program is a JVM; optionally set the <path> to a non-default JVM;\n"
1446     "                     the default is \"-j on\".\n"
1447     "\n"
1448     " -J <java-args>    specify arguments to the JVM.\n"
1449     "\n"
1450     " -t <duration>[m|s]  specify the duration over which to record data; the default unit\n"
1451     "                      is seconds (s), but can be set to minutes (m).\n"
1452     "\n"
1453     " -n                  dry run; display several run-time settings, but do not run the\n"
1454     "                      target, or collect performance data.\n"
1455     "\n"
1456     " -y <signal>[,r]     specify delayed initialization and a pause/resume signal; by default\n"
1457     "                      the target starts in paused mode; if the optional r keyword is\n"
1458     "                      provided, start in resumed mode.\n"
1459     "\n"
1460     " -F {off|on|=<regex>}  control to follow descendant processes; disable (off), enable (on),\n"
1461     "                        or collect data on all descendant processes whose name matches the\n"
1462     "                        specified regular expression; the default is \"-F on\".\n"
1463     "\n"
1464     " -a {off|on|ldobjects|src|usedldobjects|usedsrc}  specify archiving of binaries and other files;\n"
1465     "                    in addition to disable this feature (off), or enable archiving off all\n"
1466     "                    loadobjects and sources (on), the other options support a more\n"
1467     "                    refined selection. All of these options enable archiving, but the\n"
1468     "                    keyword controls what exactly is selected: all load objects (ldobjects),\n"
1469     "                    all source files (src), the loadobjects asscoiated with a program counter\n"
1470     "                    (usedldobjects), or the source files associated with a program counter\n"
1471     "                    (usedsrc); the default is \"-a ldobjects\".\n"
1472     "\n"
1473     " -S {off|on|<seconds>}  disable (off) or enable (on) periodic sampling of process-wide resource\n"
1474     "                         utilization; by default sampling occurs every second; use the <seconds>\n"
1475     "                         option to change this; the default is \"-S on\".\n"
1476     "\n"
1477     " -l <signal>       specify a signal that will trigger a sample of process-wide resource utilization.\n"
1478     "\n"
1479     " -s <option>[,<API>]  enable synchronization wait tracing; <option> is used to define the specifics\n"
1480     "                       of the tracing (on, off, <threshold>, or all); <API> is used to select the API:\n"
1481     "                       \"n\" selects native/Pthreads, \"j\" selects Java, and \"nj\" selects both;\n"
1482     "                       the default is \"-s off\".\n"
1483     "\n"
1484     " -H {off|on}        disable (off), or enable (on) heap tracing; the default is \"-H off\".\n"
1485     "\n"
1486     " -i {off|on}        disable (off), or enable (on) I/O tracing; the default is \"-i off\".\n"
1487     "\n"
1488     "Documentation:\n"
1489     "\n"
1490     "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
1491     "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
1492     "should give you access to this document.\n"
1493     "\n"
1494     "See also:\n"
1495     "\n"
1496     "gprofng(1), gp-archive(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
1497 /*
1498   char *s = dbe_sprintf (GTXT ("Usage:  %s <args> target <target-args>\n"),
1499 			 whoami);
1500   writeStr (usage_fd, s);
1501   free (s);
1502   writeStr (usage_fd, GTXT ("  -p {lo|on|hi|off|<value>}\tspecify clock-profiling\n"));
1503   writeStr (usage_fd, GTXT ("\t`lo'    per-thread rate of ~10 samples/second\n"));
1504   writeStr (usage_fd, GTXT ("\t`on'    per-thread rate of ~100 samples/second (default)\n"));
1505   writeStr (usage_fd, GTXT ("\t`hi'    per-thread rate of ~1000 samples/second\n"));
1506   writeStr (usage_fd, GTXT ("\t`off'   disable clock profiling\n"));
1507   writeStr (usage_fd, GTXT ("\t<value> specify profile timer period in millisec.\n"));
1508   s = dbe_sprintf (GTXT ("\t\t\tRange on this system is from %.3f to %.3f millisec.\n\t\t\tResolution is %.3f millisec.\n"),
1509 		   (double) cc->get_clk_min () / 1000.,
1510 		   (double) cc->get_clk_max () / 1000.,
1511 		   (double) cc->get_clk_res () / 1000.);
1512   writeStr (usage_fd, s);
1513   free (s);
1514   writeStr (usage_fd, GTXT ("  -h <ctr_def>...[,<ctr_n_def>]\tspecify HW counter profiling\n"));
1515   s = dbe_sprintf (GTXT ("\tto see the supported HW counters on this machine, run \"%s -h\" with no other arguments\n"),
1516 		   whoami);
1517   writeStr (usage_fd, s);
1518   free (s);
1519   writeStr (usage_fd, GTXT ("  -s <threshold>[,<scope>]\tspecify synchronization wait tracing\n"));
1520   writeStr (usage_fd, GTXT ("\t<scope> is \"j\" for tracing Java-APIs, \"n\" for tracing native-APIs, or \"nj\" for tracing both\n"));
1521   writeStr (usage_fd, GTXT ("  -H {on|off}\tspecify heap tracing\n"));
1522   writeStr (usage_fd, GTXT ("  -i {on|off}\tspecify I/O tracing\n"));
1523   writeStr (usage_fd, GTXT ("  -N <lib>\tspecify library to exclude count from instrumentation (requires -c also)\n"));
1524   writeStr (usage_fd, GTXT ("          \tmultiple -N arguments can be provided\n"));
1525   writeStr (usage_fd, GTXT ("  -j {on|off|path}\tspecify Java profiling\n"));
1526   writeStr (usage_fd, GTXT ("  -J <java-args>\tspecify arguments to Java for Java profiling\n"));
1527   writeStr (usage_fd, GTXT ("  -t <duration>\tspecify time over which to record data\n"));
1528   writeStr (usage_fd, GTXT ("  -n\tdry run -- don't run target or collect performance data\n"));
1529   writeStr (usage_fd, GTXT ("  -y <signal>[,r]\tspecify delayed initialization and pause/resume signal\n"));
1530   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"));
1531   writeStr (usage_fd, GTXT ("  -F {on|off|=<regex>}\tspecify following descendant processes\n"));
1532   writeStr (usage_fd, GTXT ("  -a {on|ldobjects|src|usedldobjects|usedsrc|off}\tspecify archiving of binaries and other files;\n"));
1533   writeStr (usage_fd, GTXT ("  -S {on|off|<seconds>}\t Set the interval for periodic sampling of process-wide resource utilization\n"));
1534   writeStr (usage_fd, GTXT ("  -l <signal>\tspecify signal that will trigger a sample of process-wide resource utilization\n"));
1535   writeStr (usage_fd, GTXT ("  -o <expt>\tspecify experiment name\n"));
1536   writeStr (usage_fd, GTXT ("  --verbose\tprint expanded log of processing\n"));
1537   writeStr (usage_fd, GTXT ("  -C <label>\tspecify comment label (up to 10 may appear)\n"));
1538   writeStr (usage_fd, GTXT ("  -V|--version\tprint version number and exit\n"));
1539 */
1540   /* don't document this feature */
1541   //	writeStr (usage_fd, GTXT("  -Z\tPreload mem.so, and launch target [no experiment]\n") );
1542 /*
1543   writeStr (usage_fd, GTXT ("\n See the gp-collect(1) man page for more information\n"));
1544 */
1545 
1546 #if 0
1547   /* print an extended usage message */
1548   /* find a Java for Java profiling, set Java on to check Java */
1549   find_java ();
1550   cc->set_java_mode (NTXT ("on"));
1551 
1552   /* check for variable-clock rate */
1553   unsigned char mode = COL_CPUFREQ_NONE;
1554   get_cpu_frequency (&mode);
1555   if (mode != COL_CPUFREQ_NONE)
1556     writeStr (usage_fd, GTXT ("NOTE: system has variable clock frequency, which may cause variable program run times.\n"));
1557 
1558   /* show the experiment that would be run */
1559   writeStr (usage_fd, GTXT ("\n Default experiment:\n"));
1560   char *ccret = cc->setup_experiment ();
1561   if (ccret != NULL)
1562     {
1563       writeStr (usage_fd, ccret);
1564       free (ccret);
1565       exit (1);
1566     }
1567   cc->delete_expt ();
1568   ccret = cc->show (1);
1569   if (ccret != NULL)
1570     {
1571       writeStr (usage_fd, ccret);
1572       free (ccret);
1573     }
1574 #endif
1575 }
1576 
1577 void
short_usage()1578 collect::short_usage ()
1579 {
1580   if (no_short_usage == 0)
1581     dbe_write (usage_fd, GTXT ("Run \"%s --help\" for a usage message.\n"), whoami);
1582 }
1583 
1584 void
show_hwc_usage()1585 collect::show_hwc_usage ()
1586 {
1587   usage_fd = 1;
1588   short_usage ();
1589   cc->setup_hwc ();
1590   hwc_usage (false, whoami, NULL);
1591 }
1592 
1593 void
writeStr(int f,const char * buf)1594 collect::writeStr (int f, const char *buf)
1595 {
1596   if (buf != NULL)
1597     write (f, buf, strlen (buf));
1598 }
1599