1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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)
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.
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. */
28 #include <sys/types.h>
29 #include <sys/param.h>
31 #include <sys/utsname.h>
36 #include <sys/ptrace.h>
39 #include "cpu_frequency.h"
43 #include "gp-experiment.h"
45 #include "StringBuilder.h"
47 #define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
49 extern char **environ
;
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
;
60 static int nprocesses
;
61 static Process
**processes
;
64 main (int argc
, char *argv
[])
66 // disable any alarm that might be pending
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
);
77 sigint_handler (int, siginfo_t
*, void *)
80 if (collect_obj
->cc
!= NULL
)
81 collect_obj
->cc
->interrupt ();
86 sigalrm_handler (int, siginfo_t
*, void *)
88 dbe_write (2, GTXT ("collect: unexpected alarm clock signal received\n"));
93 sigterm_handler (int, siginfo_t
*, void *)
95 for (int i
= 0; i
< nprocesses
; i
++)
97 Process
*proc
= processes
[i
];
99 kill (proc
->pid
, SIGTERM
);
103 collect::collect (int argc
, char *argv
[], char **envp
)
104 : Application (argc
, argv
)
109 collect_warnings
= NULL
;
110 collect_warnings_idx
= 0;
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
;
131 struct sigaction old_sigint_handler
;
132 struct sigaction old_sigalrm_handler
;
135 collect::start (int argc
, char *argv
[])
139 /* create a collector control structure, disabling aggressive warning */
140 cc
= new Coll_Ctrl (0, false, false);
143 char *s
= strrchr (prog_name
, '/');
144 if (s
&& (s
- prog_name
) > 5) // Remove /bin/
146 s
= dbe_sprintf (NTXT ("%.*s"), (int) (s
- prog_name
- 4), prog_name
);
147 cc
->set_project_home (s
);
151 char * errenable
= cc
->enable_expt ();
154 writeStr (2, errenable
);
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)
166 writeStr (2, GTXT ("Unable to install SIGALRM handler\n"));
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)
176 writeStr (2, GTXT ("Unable to install SIGINT handler\n"));
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)
186 writeStr (2, GTXT ("Unable to install SIGTERM handler\n"));
189 if (argc
> 1 && strncmp (argv
[1], NTXT ("--whoami="), 9) == 0)
191 whoami
= argv
[1] + 9;
196 /* check for no arguments -- usage message */
205 else if (argc
== 2 && strcmp (argv
[1], NTXT ("-h")) == 0)
207 /* only one argument, -h */
210 /* now print the HWC usage message */
214 else if (argc
== 2 && (strcmp (argv
[1], NTXT ("-help")) == 0 ||
215 strcmp (argv
[1], NTXT ("--help")) == 0))
217 /* only one argument, -help or --help */
225 else if ((argc
== 2) &&
226 (strcmp (argv
[1], NTXT ("--version")) == 0))
228 /* only one argument, --version */
230 /* print the version info */
231 Application::print_version_info ();
235 /* precheck the arguments -- scan for -O, -M flagS */
237 targ_index
= check_args (argc
, argv
);
240 /* message has already been written */
245 /* crack the arguments */
247 targ_index
= check_args (argc
, argv
);
250 /* message has already been written */
256 check_target (argc
, argv
);
257 if (disabled
!= 0 && cc
->get_count () == 0)
259 // show collection parameters; count data
260 ccret
= cc
->show (0);
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
);
268 /* if count data is requested, exec bit to do the real work */
269 /* even for a dryrun */
270 if (cc
->get_count () != 0)
273 /* if a dry run, just exit */
276 writeStr (1, cc
->show_expt ());
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 ();
288 // If the mem_so_me flag is set, preload mem.so
289 // and launch the process
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 */
298 /* now exec the target ... */
299 if (cc
->get_debug_mode () == 1)
301 traceme (arglist
[0], arglist
);
302 extype
= NTXT ("traceme");
306 execvp (arglist
[0], arglist
);
307 extype
= NTXT ("exevcp");
309 /* oops, exec of the target failed */
310 char *em
= strerror (errno
);
311 set_output (); /* restore output for collector */
313 dbe_write (2, GTXT ("memso %s of %s failed: errno = %d\n"), extype
, argv
[targ_index
], errno
);
315 dbe_write (2, GTXT ("memso %s of %s failed: %s\n"), extype
, argv
[targ_index
], em
);
319 /* normal path, setting up an experiment and launching the target */
320 /* set up the experiment */
321 ccret
= cc
->setup_experiment ();
324 dbe_write (2, NTXT ("%s\n"), ccret
);
328 /* Beyond this point, the experiment is created */
329 if (collect_warnings
!= NULL
)
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
]));
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];
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
)
350 if (warn_file
!= NULL
)
352 warn_write ("<powerm>\n<frequency clk=\"%d\"%s%s/>\n</powerm>\n",
353 max_freq
, freq_scaling
, turbo_mode
);
358 /* check for labels to write to notes file */
362 char nbuf2
[MAXPATHLEN
];
363 // fetch the experiment name and CWD
364 char *exp
= cc
->get_experiment ();
365 char *ev
= getcwd (nbuf2
, sizeof (nbuf2
));
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
);
372 // getcwd failed or experiment is a fullpath
373 nbuf
= dbe_sprintf (NTXT ("%s/%s"), exp
, SP_NOTES_FILE
);
375 FILE *f
= fopen (nbuf
, NTXT ("w"));
379 for (int i
= 0; i
< nlabels
; i
++)
380 fprintf (f
, NTXT ("%s\n"), label
[i
]);
384 /* check for user interrupt */
388 writeStr (2, GTXT ("User interrupt\n"));
392 /* print data-collection parameters */
395 ccret
= cc
->show (0);
399 ccret
= cc
->show_expt ();
401 writeStr (1, ccret
); /* write this to stdout */
403 pid_t pid
= (pid_t
) cc
->get_attach_pid ();
404 if (pid
== (pid_t
) 0)
407 /* Set the environment for libcollector */
408 if (putenv_libcollector () != 0)
410 /* message has already been written */
414 /* ensure original output fds restored for target */
417 /* now exec the target ... */
418 if (cc
->get_debug_mode () == 1)
420 traceme (arglist
[0], arglist
);
421 extype
= NTXT ("traceme");
425 execvp (arglist
[0], arglist
);
426 extype
= NTXT ("execvp");
429 /* we reach this point only if the target launch failed */
430 char *em
= strerror (errno
);
432 /* restore output for collector */
435 /* exec failed; delete experiment */
438 /* print a message and exit */
440 dbe_write (2, GTXT ("%s of %s failed: errno = %d\n"), extype
, argv
[targ_index
], errno
);
442 dbe_write (2, GTXT ("%s of %s failed: %s\n"), extype
, argv
[targ_index
], em
);
450 * Prepare a warning message and pass it to warn_write()
452 * kind Type of comment
455 * len Length of the string
459 collect::warn_comment (const char *kind
, int num
, char *s
, int len
)
462 warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%.*s</event>\n"),
465 warn_write (NTXT ("<event kind=\"%s\" id=\"%d\"/>\n"), kind
, num
);
467 warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%s</event>\n"), kind
, num
, s
);
471 * Open the warnings file in Append mode ("aw")
474 collect::warn_open ()
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"));
483 * Close the warnings file
486 collect::warn_close ()
488 (void) fclose (warn_file
);
492 * Format the warning message and write it to the warnings file
495 collect::warn_write (const char *format
, ...)
498 // format the input arguments into a string
500 va_start (va
, format
);
501 vsnprintf (buf
, sizeof (buf
), format
, va
);
503 // write it to the warnings file (warnings.xml)
504 fwrite (buf
, 1, strlen (buf
), warn_file
);
508 /* process the args, setting expt. params,
509 * and finding offset for a.out name
512 collect::check_args (int argc
, char *argv
[])
528 char *expName
= NULL
;
529 bool overwriteExp
= false;
532 for (targ_index
= 1; targ_index
< argc
; targ_index
++)
534 if (argv
[targ_index
] == NULL
)
536 if (dbe_strcmp (argv
[targ_index
], "--") == 0)
541 if (argv
[targ_index
][0] != '-')
544 switch (argv
[targ_index
][1])
551 if (argv
[targ_index
] == NULL
)
557 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
565 if (argv
[targ_index
] == NULL
)
567 writeStr (2, GTXT ("-y requires a signal argument\n"));
570 if ((ptr
= strrchr (argv
[targ_index
], ',')) != NULL
)
572 if ((*(ptr
+ 1) != 'r') || (*(ptr
+ 2) != 0))
574 /* not the right trailer */
575 dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv
[targ_index
]);
581 param
= cc
->find_sig (argv
[targ_index
]);
585 dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv
[targ_index
]);
588 ccret
= cc
->set_pauseresume_signal (param
, resume
);
591 /* invalid signal; write message */
601 if (argv
[targ_index
] == NULL
)
605 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
613 if (argv
[targ_index
] == NULL
)
615 writeStr (2, GTXT ("-l requires a signal argument\n"));
618 param
= cc
->find_sig (argv
[targ_index
]);
622 dbe_write (2, GTXT ("Invalid sample signal %s\n"), argv
[targ_index
]);
625 ccret
= cc
->set_sample_signal (param
);
628 /* invalid signal; write message */
635 #ifdef GPROFNG_DOES_NOT_SUPPORT
640 if (argv
[targ_index
] == NULL
)
644 if (checkflagterm (argv
[targ_index
]) == -1)
653 if (argv
[targ_index
] == NULL
)
655 writeStr (2, GTXT ("-P requires a process pid argument\n"));
658 ccret
= cc
->set_attach_pid (argv
[targ_index
]);
661 /* error; write message */
672 if (argv
[targ_index
] == NULL
)
677 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
685 if (argv
[targ_index
] == NULL
)
687 writeStr (2, GTXT ("-t requires a run-duration argument\n"));
690 ccret
= cc
->set_time_run (argv
[targ_index
]);
693 /* error; write message */
705 if (argv
[targ_index
] == NULL
)
709 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
717 if (argv
[targ_index
] == NULL
)
719 writeStr (2, GTXT ("-p requires a clock-profiling argument\n"));
722 ccret
= cc
->set_clkprof (argv
[targ_index
], &warnmsg
);
731 writeStr (2, warnmsg
);
740 if (argv
[targ_index
] == NULL
)
744 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
752 if (argv
[targ_index
] == NULL
)
754 writeStr (2, GTXT ("-s requires a synchronization-tracing argument\n"));
757 ccret
= cc
->set_synctrace (argv
[targ_index
]);
770 if (argv
[targ_index
] == NULL
)
774 if (checkflagterm (argv
[targ_index
]) == -1)
777 if ((argv
[targ_index
] == NULL
) || (strlen (argv
[targ_index
]) == 0))
779 writeStr (2, GTXT ("-h requires a HW-counter-profiling argument\n"));
782 // Check for some special cases
783 char * string
= argv
[targ_index
];
784 if (strcmp (argv
[targ_index
], NTXT ("off")) == 0)
789 writeStr (2, GTXT ("-h off cannot be used with any other -h arguments\n"));
797 // Check to see if we can use HWC
798 unsigned hwc_maxregs
= hwc_get_max_concurrent (false);
799 if (hwc_maxregs
== 0)
802 char *pch
= hwcfuncs_errmsg_get (buf
, sizeof (buf
), 0);
804 dbe_write (2, GTXT ("HW counter profiling is not supported on this system: %s%s"),
805 pch
, pch
[strlen (pch
) - 1] == '\n' ? "" : "\n");
807 dbe_write (2, GTXT ("HW counter profiling is not supported on this system\n"));
811 // Make sure there's no other -h after -h off
815 writeStr (2, GTXT ("No -h arguments can be used after -h off\n"));
818 // set up to process HW counters (to know about default counters)
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);
833 ccret
= cc
->add_hwcstring (string
, &warnmsg
);
836 /* set global flag to suppress the short_usage message for any subsequent HWC errors */
844 writeStr (2, warnmsg
);
851 ATTRIBUTE_FALLTHROUGH
856 if (argv
[targ_index
] == NULL
)
860 if (checkflagterm (argv
[targ_index
]) == -1)
862 if (argv
[targ_index
+ 1] == NULL
)
864 dbe_write (2, GTXT ("Argument %s must be followed by a file name\n"),
870 dbe_write (2, GTXT ("Only one -o or -O argument may be used\n"));
874 expName
= argv
[targ_index
+ 1];
881 if (argv
[targ_index
] == NULL
)
885 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
886 if (argv
[targ_index
+ 1] == NULL
)
888 dbe_write (2, GTXT ("Argument %s must be followed by a sample interval name\n"),
898 ccret
= cc
->set_sample_period (argv
[targ_index
+ 1]);
911 if (argv
[targ_index
] == NULL
)
915 if (checkflagterm (argv
[targ_index
]) == -1)
917 if (argv
[targ_index
+ 1] == NULL
)
919 dbe_write (2, GTXT ("Argument %s requires a heap-tracing argument\n"),
929 ccret
= cc
->set_heaptrace (argv
[targ_index
+ 1]);
936 if (cc
->get_java_default () == 1)
937 cc
->set_java_mode (NTXT ("off"));
944 if (argv
[targ_index
] == NULL
)
948 if (checkflagterm (argv
[targ_index
]) == -1)
950 if (argv
[targ_index
+ 1] == NULL
)
952 fprintf (stderr
, GTXT ("Argument %s requires an I/O-tracing argument\n"),
962 ccret
= cc
->set_iotrace (argv
[targ_index
+ 1]);
975 if (argv
[targ_index
] == NULL
)
979 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
980 if (argv
[targ_index
+ 1] == NULL
)
982 dbe_write (2, GTXT ("Argument %s requires a java-profiling argument\n"),
986 if (jseen_global
!= 0)
992 ccret
= cc
->set_java_mode (argv
[targ_index
+ 1]);
1005 if (argv
[targ_index
] == NULL
)
1009 if (checkflagterm (argv
[targ_index
]) == -1) return -1;
1010 if (argv
[targ_index
+ 1] == NULL
)
1012 dbe_write (2, GTXT ("Argument %s requires a java argument\n"),
1022 ccret
= cc
->set_java_args (argv
[targ_index
+ 1]);
1025 writeStr (2, ccret
);
1035 if (argv
[targ_index
] == NULL
)
1039 if (checkflagterm (argv
[targ_index
]) == -1)
1041 if (argv
[targ_index
+ 1] == NULL
)
1043 dbe_write (2, GTXT ("Argument %s requires a descendant-following argument\n"),
1053 ccret
= cc
->set_follow_mode (argv
[targ_index
+ 1]);
1056 writeStr (2, ccret
);
1066 if (argv
[targ_index
] == NULL
)
1070 if (checkflagterm (argv
[targ_index
]) == -1)
1072 if (argv
[targ_index
+ 1] == NULL
)
1074 dbe_write (2, GTXT ("Argument %s requires a load-object archiving argument\n"),
1084 ccret
= cc
->set_archive_mode (argv
[targ_index
+ 1]);
1087 writeStr (2, ccret
);
1097 if (argv
[targ_index
] == NULL
)
1101 if (checkflagterm (argv
[targ_index
]) == -1)
1103 if (argv
[targ_index
+ 1] == NULL
)
1105 dbe_write (2, GTXT ("Argument %s must be followed by a comment\n"),
1109 if (nlabels
== MAXLABELS
)
1111 dbe_write (2, GTXT ("No more than %d comments may be specified\n"),
1115 label
[nlabels
] = argv
[targ_index
+ 1];
1124 do_flag (&argv
[targ_index
][1]);
1127 // special undocumented argument for debug builds only to allow analyzer to
1128 // LD_PRELOAD mem.so for the target it spawns
1132 if (strcmp (argv
[targ_index
], NTXT ("--verbose")) == 0)
1134 else if (strcmp (argv
[targ_index
], "--outfile") == 0)
1139 if (argv
[targ_index
] == NULL
)
1143 // process this argument now
1144 if (argv
[targ_index
+ 1] == NULL
)
1146 dbe_write (2, GTXT ("Argument %s requires a file argument\n"),
1152 dupflagseen (argv
[targ_index
]);
1156 if (outredirect
== NULL
)
1158 outredirect
= argv
[targ_index
+ 1];
1160 } // else already redirected; ignore with no message
1165 dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv
[targ_index
]);
1170 dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv
[targ_index
]);
1174 if (targ_index
>= argc
)
1176 if (argv
[targ_index
] == NULL
)
1180 if (cc
->get_attach_pid () != 0) /* no target is OK, if we're attaching */
1182 writeStr (2, GTXT ("Name of target must be specified\n"));
1188 ccret
= cc
->set_expt (expName
, &ccwarn
, overwriteExp
);
1191 writeStr (2, ccwarn
);
1196 writeStr (2, ccret
);
1200 if (cc
->get_attach_pid () != 0)
1202 writeStr (2, GTXT ("Name of target must not be specified when -P is used\n"));
1209 collect::checkflagterm (const char *c
)
1213 dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), c
);
1220 collect::do_flag (const char *flags
)
1223 for (int i
= 0;; i
++)
1227 case 0: // end of string
1234 Application::print_version_info ();
1236 dbe_write (2, NTXT ("GNU %s version %s\n"),
1237 get_basename (prog_name), VERSION);
1243 s
= cc
->set_debug_mode (1);
1254 Application::print_version_info ();
1256 dbe_write (2, NTXT ("GNU %s version %s\n"),
1257 get_basename (prog_name), VERSION);
1264 Application::print_version_info ();
1266 dbe_write (2, NTXT ("GNU %s version %s\n"),
1267 get_basename (prog_name), VERSION);
1269 /* no further processing.... */
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
1279 * Takes same arguments as execvp()
1282 collect::traceme (const char *execvp_file
, char *const execvp_argv
[])
1285 pid_t pid
= fork ();
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)
1294 dbe_write (2, GTXT ("fork-child: Can't putenv of \"%s\": run aborted\n"), ev
);
1297 ptrace (PTRACE_TRACEME
, 0, NULL
, NULL
); // initiate trace
1298 ret
= execvp (execvp_file
, execvp_argv
); // execvp user command
1299 return ret
; // execvp failed
1304 if (waitpid (pid
, &status
, 0) != pid
)
1305 { // wait for execvp to cause signal
1306 writeStr (2, GTXT ("parent waitpid() failed\n"));
1309 if (!WIFSTOPPED (status
))
1310 writeStr (2, GTXT ("WIFSTOPPED(status) failed\n"));
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)
1317 writeStr (2, GTXT ("ptrace(PTRACE_DETACH) failed\n"));
1320 dbe_write (2, GTXT ("Waiting for attach from debugger: pid=%d\n"), (int) pid
);
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"));
1330 return -1; // fork failed
1335 collect::dupflagseen (char c
)
1337 dbe_write (2, GTXT ("Only one -%c argument may be used\n"), c
);
1341 collect::dupflagseen (const char *s
)
1343 dbe_write (2, GTXT ("Only one %s argument may be used\n"), s
);
1347 collect::set_output ()
1349 static int initial
= 1;
1352 int fd
= open (outredirect
, O_WRONLY
| O_CREAT
| O_APPEND
,
1353 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
1356 dbe_write (2, GTXT ("Warning: Can't open collector output `%s': %s\n"),
1357 outredirect
, strerror (errno
));
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
));
1368 if ((saved_stdout
!= -1) && (saved_stderr
!= -1))
1373 gettimeofday (&tp
, NULL
);
1374 writeStr (2, ctime (&tp
.tv_sec
));
1377 return 1; // diversion in place
1381 return 0; // no diversion
1385 collect::reset_output ()
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"),
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"),
1402 Ruud - Isolate this line because it has an argument. Otherwise it would be at the
1403 end of this long list.
1406 "Usage: gprofng collect app [OPTION(S)] TARGET [TARGET_ARGUMENTS]\n")),
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 -------------------------------------------------------------------------------
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"
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"
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"
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"
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"
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"
1441 " -C <label> add up to 10 comment labels to the experiment; comments appear in\n"
1442 " the notes section of the header.\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"
1448 " -J <java-args> specify arguments to the JVM.\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"
1453 " -n dry run; display several run-time settings, but do not run the\n"
1454 " target, or collect performance data.\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"
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"
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"
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"
1477 " -l <signal> specify a signal that will trigger a sample of process-wide resource utilization.\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"
1484 " -H {off|on} disable (off), or enable (on) heap tracing; the default is \"-H off\".\n"
1486 " -i {off|on} disable (off), or enable (on) I/O tracing; the default is \"-i off\".\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"
1496 "gprofng(1), gp-archive(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
1498 char *s = dbe_sprintf (GTXT ("Usage: %s <args> target <target-args>\n"),
1500 writeStr (usage_fd, 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);
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"),
1517 writeStr (usage_fd, 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"));
1540 /* don't document this feature */
1541 // writeStr (usage_fd, GTXT(" -Z\tPreload mem.so, and launch target [no experiment]\n") );
1543 writeStr (usage_fd, GTXT ("\n See the gp-collect(1) man page for more information\n"));
1547 /* print an extended usage message */
1548 /* find a Java for Java profiling, set Java on to check Java */
1550 cc
->set_java_mode (NTXT ("on"));
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"));
1558 /* show the experiment that would be run */
1559 writeStr (usage_fd
, GTXT ("\n Default experiment:\n"));
1560 char *ccret
= cc
->setup_experiment ();
1563 writeStr (usage_fd
, ccret
);
1568 ccret
= cc
->show (1);
1571 writeStr (usage_fd
, ccret
);
1578 collect::short_usage ()
1580 if (no_short_usage
== 0)
1581 dbe_write (usage_fd
, GTXT ("Run \"%s --help\" for a usage message.\n"), whoami
);
1585 collect::show_hwc_usage ()
1590 hwc_usage (false, whoami
, NULL
);
1594 collect::writeStr (int f
, const char *buf
)
1597 write (f
, buf
, strlen (buf
));