]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gprofng/src/gp-collect-app.cc
Update year range in gprofng copyright notices
[thirdparty/binutils-gdb.git] / gprofng / src / gp-collect-app.cc
CommitLineData
76bdc726 1/* Copyright (C) 2021-2023 Free Software Foundation, Inc.
bb368aad
VM
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
49extern char **environ;
50
51static volatile int interrupt = 0;
52static int saved_stdout = -1;
53static int saved_stderr = -1;
54static int no_short_usage = 0;
55static int usage_fd = 2;
56static collect *collect_obj = NULL;
57extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
58static char *outredirect = NULL;
59static int precheck;
60static int nprocesses;
61static Process **processes;
62
63int
64main (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
76extern "C" void
77sigint_handler (int, siginfo_t *, void *)
78{
79 interrupt = 1;
80 if (collect_obj->cc != NULL)
81 collect_obj->cc->interrupt ();
82 return;
83}
84
85extern "C" void
86sigalrm_handler (int, siginfo_t *, void *)
87{
88 dbe_write (2, GTXT ("collect: unexpected alarm clock signal received\n"));
89 return;
90}
91
92extern "C" void
93sigterm_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
103collect::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
126collect::~collect ()
127{
128 delete cc;
129}
130
131struct sigaction old_sigint_handler;
132struct sigaction old_sigalrm_handler;
133
134void
135collect::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 */
458void
459collect::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 */
473void
474collect::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 */
485void
486collect::warn_close ()
487{
488 (void) fclose (warn_file);
489}
490
491/**
492 * Format the warning message and write it to the warnings file
493 */
494void
495collect::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 */
511int
512collect::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;
c5edd3b8 851 ATTRIBUTE_FALLTHROUGH
bb368aad
VM
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
1208int
1209collect::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
1219int
1220collect::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 */
1281int
1282collect::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
1334void
1335collect::dupflagseen (char c)
1336{
1337 dbe_write (2, GTXT ("Only one -%c argument may be used\n"), c);
1338}
1339
1340void
1341collect::dupflagseen (const char *s)
1342{
1343 dbe_write (2, GTXT ("Only one %s argument may be used\n"), s);
1344}
1345
1346int
1347collect::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
1384void
1385collect::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
1397void
1398collect::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
1577void
1578collect::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
1584void
1585collect::show_hwc_usage ()
1586{
1587 usage_fd = 1;
1588 short_usage ();
1589 cc->setup_hwc ();
1590 hwc_usage (false, whoami, NULL);
1591}
1592
1593void
1594collect::writeStr (int f, const char *buf)
1595{
1596 if (buf != NULL)
1597 write (f, buf, strlen (buf));
1598}