xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/collctrl.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 <unistd.h>
23 #include <strings.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/statvfs.h>
28 #include <sys/param.h>
29 #include <signal.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <ctype.h>
33 #include <dirent.h>
34 #include <libgen.h>
35 #include <assert.h>
36 #include <regex.h>  /* regcomp() */
37 
38 #include "util.h"
39 #include "libiberty.h"
40 #include "collctrl.h"
41 #include "hwcdrv.h"
42 #include "StringBuilder.h"
43 
44 #define SP_GROUP_HEADER     "#analyzer experiment group"
45 #define DD_MAXPATHLEN       (MAXPATHLEN * 4) /* large, to build up data descriptor */
46 
47 /* If the system doesn't provide strsignal, we get it defined in
48    libiberty but no declaration is supplied.   */
49 #if !defined (HAVE_STRSIGNAL) && !defined (strsignal)
50 extern const char *strsignal (int);
51 #endif
52 
53 // _SC_CPUID_MAX is not available on 2.6/2.7
54 #ifndef _SC_CPUID_MAX
55 #define _SC_CPUID_MAX       517
56 #endif
57 
58 static const char *get_fstype (char *);
59 static cpu_info_t cpu_info;
60 
61 static void
read_str(char * from,char ** to)62 read_str (char *from, char **to)
63 {
64   if (*to != NULL)
65     return;
66   for (char *s = from; *s; s++)
67     if (*s != ':' && *s != '\t' && *s != ' ')
68       {
69 	for (int i = ((int) strlen (s)) - 1; i >= 0; i--)
70 	  {
71 	    if (s[i] != '\n' && s[i] != ' ' && s[i] != '\t')
72 	      {
73 		*to = strndup(s, i + 1);
74 		return;
75 	      }
76 	  }
77 	return; // string is empty
78       }
79 }
80 
81 static int
read_int(char * from)82 read_int (char *from)
83 {
84   char *val = strchr (from, ':');
85   if (val)
86     return atoi (val + 1);
87   return 0;
88 }
89 
90 cpu_info_t *
read_cpuinfo()91 read_cpuinfo()
92 {
93   static int inited = 0;
94   if (inited)
95     return &cpu_info;
96   inited = 1;
97 
98 #if defined(__aarch64__)
99   asm volatile("mrs %0, cntfrq_el0" : "=r" (cpu_info.cpu_clk_freq));
100 #endif
101 
102   // Read /proc/cpuinfo to get CPU info and clock rate
103   FILE *procf = fopen ("/proc/cpuinfo", "r");
104   if (procf != NULL)
105     {
106       char temp[1024];
107       while (fgets (temp, (int) sizeof (temp), procf) != NULL)
108 	{
109 	  if (strncmp (temp, "processor", 9) == 0)
110 	    cpu_info.cpu_cnt++;
111 	  else if (strncmp (temp, "cpu MHz", 7) == 0)
112 	    cpu_info.cpu_clk_freq = read_int (temp + 9);
113 	  else if (strncmp (temp, "cpu family", 10) == 0)
114 	    cpu_info.cpu_family = read_int (temp + 10);
115 	  else if (strncmp (temp, "vendor_id", 9) == 0)
116 	    {
117 	      if (cpu_info.cpu_vendorstr == NULL)
118 		read_str (temp + 9, &cpu_info.cpu_vendorstr);
119 	    }
120 	  else if (strncmp (temp, "model name", 10) == 0)
121 	    {
122 	      if (cpu_info.cpu_modelstr == NULL)
123 		read_str (temp + 10, &cpu_info.cpu_modelstr);
124 	    }
125 	  else if (strncmp (temp, "model", 5) == 0)
126 	    cpu_info.cpu_model = read_int (temp + 5);
127 	  else if (strncmp (temp, "CPU implementer", 15) == 0)
128 	    cpu_info.cpu_family = read_int (temp + 15);
129 	  else if (strncmp (temp, "CPU architecture", 16) == 0)
130 	    cpu_info.cpu_model = read_int (temp + 16);
131 	}
132       fclose (procf);
133     }
134   return &cpu_info;
135 }
136 
Coll_Ctrl(int _interactive,bool _defHWC,bool _kernelHWC)137 Coll_Ctrl::Coll_Ctrl (int _interactive, bool _defHWC, bool _kernelHWC)
138 {
139   char hostname[MAXPATHLEN];
140   long ncpumax;
141   interactive = _interactive;
142   defHWC = _defHWC;
143   kernelHWC = _kernelHWC;
144 
145   /* set this host's parameters */
146   gethostname (hostname, 1023);
147   node_name = strdup (hostname);
148   char *p = strchr (node_name, (int) '.');
149   if (p != NULL)
150     *p = 0;
151   default_stem = strdup ("test");
152 
153   /* get CPU count and processor clock rate */
154   ncpumax = sysconf (_SC_CPUID_MAX);
155   if (ncpumax == -1)
156     {
157       ncpus = sysconf (_SC_NPROCESSORS_CONF);
158       /* add 2048 to count, since on some systems CPUID does not start at zero */
159       ncpumax = ncpus + 2048;
160     }
161   cpu_info_t *cpu_p = read_cpuinfo();
162   ncpus = cpu_p->cpu_cnt;
163   cpu_clk_freq = cpu_p->cpu_clk_freq;
164 
165   /* check resolution of system clock */
166   sys_resolution = sysconf (_SC_CLK_TCK);
167   if (sys_resolution == 0)
168     sys_period = 10000;
169   else
170     sys_period = MICROSEC / (int) sys_resolution;
171 
172   /* determine memory page size and number of pages */
173   npages = sysconf (_SC_PHYS_PAGES);
174   page_size = sysconf (_SC_PAGE_SIZE);
175 
176   /* set default clock parameters */
177   hwcprof_enabled_cnt = 0; // must be set before calling determine_profile_params();
178   determine_profile_params (); // inits clk_params which is used by clock profiling AND HWCs
179   cpc_cpuver = CPUVER_UNDEFINED;
180 
181   /* set default control values */
182   debug_mode = 0;
183 #if defined(GPROFNG_JAVA_PROFILING)
184   java_mode = 1;
185 #else
186   java_mode = 0;
187 #endif
188   java_default = 1;
189   java_path = NULL;
190   java_args = NULL;
191   njava_args = 0;
192   follow_mode = FOLLOW_ON;
193   follow_default = 1;
194   follow_spec_usr = NULL;
195   follow_spec_cmp = NULL;
196   prof_idle = 1;
197   archive_mode = strdup ("on");
198   pauseresume_sig = 0;
199   sample_sig = 0;
200   uinterrupt = 0;
201   attach_pid = 0;
202   time_run = 0;
203   start_delay = 0;
204 
205   /* clear the string pointers */
206   uexpt_name = NULL;
207   expt_name = NULL;
208   expt_dir = NULL;
209   base_name = NULL;
210   udir_name = NULL;
211   store_dir = NULL;
212   prev_store_dir = strdup ("");
213   store_ptr = NULL;
214   expt_group = NULL;
215   target_name = NULL;
216   data_desc = NULL;
217   lockname = NULL;
218   hwc_string = NULL;
219   project_home = NULL;
220   lockfd = -1;
221 
222   /* set default data collection values */
223   enabled = 0;
224   opened = 0;
225   clkprof_enabled = 1;
226   clkprof_default = 1;
227   for (unsigned ii = 0; ii < MAX_PICS; ii++)
228     {
229       memset (&hwctr[ii], 0, sizeof (Hwcentry));
230       hwctr[ii].reg_num = -1;
231     }
232   hwcprof_default = 0;
233   if (defHWC == true)
234     {
235       setup_hwc ();
236       hwcprof_default = 1;
237     }
238   else  // disable the default, and reset the counters
239     hwcprof_enabled_cnt = 0;
240   synctrace_enabled = 0;
241   synctrace_thresh = -1;
242   synctrace_scope = 0;
243   heaptrace_enabled = 0;
244   heaptrace_checkenabled = 0;
245   iotrace_enabled = 0;
246   count_enabled = 0;
247   Iflag = 0;
248   Nflag = 0;
249   sample_period = 1;
250   sample_default = 1;
251   size_limit = 0;
252   nofswarn = 0;
253   expno = 1;
254 
255   // ensure that the default name is updated
256   // but don't print any message
257   (void) preprocess_names ();
258   (void) update_expt_name (false, false);
259 }
260 
261 /* Copy constructor */
Coll_Ctrl(Coll_Ctrl * cc)262 Coll_Ctrl::Coll_Ctrl (Coll_Ctrl * cc)
263 {
264   uinterrupt = 0;
265   interactive = cc->interactive;
266   defHWC = cc->defHWC;
267   kernelHWC = cc->kernelHWC;
268   node_name = strdup (cc->node_name);
269   default_stem = strdup (cc->default_stem);
270   ncpus = cc->ncpus;
271   cpu_clk_freq = cc->cpu_clk_freq;
272   npages = cc->npages;
273   page_size = cc->page_size;
274   cpc_cpuver = cc->cpc_cpuver;
275   debug_mode = cc->debug_mode;
276   java_mode = cc->java_mode;
277   java_default = cc->java_default;
278   java_path = NULL;
279   java_args = NULL;
280   njava_args = 0;
281   follow_mode = cc->follow_mode;
282   follow_default = cc->follow_default;
283   if (cc->follow_spec_usr)
284     {
285       follow_spec_usr = strdup (cc->follow_spec_usr);
286       follow_spec_cmp = strdup (cc->follow_spec_cmp);
287     }
288   else
289     {
290       follow_spec_usr = NULL;
291       follow_spec_cmp = NULL;
292     }
293   archive_mode = strdup (cc->archive_mode);
294   pauseresume_sig = cc->pauseresume_sig;
295   sample_sig = cc->sample_sig;
296   time_run = cc->time_run;
297   start_delay = cc->start_delay;
298   clk_params = cc->clk_params;
299   clkprof_enabled = cc->clkprof_enabled;
300   clkprof_default = cc->clkprof_default;
301   clkprof_timer = cc->clkprof_timer;
302   clkprof_timer_target = cc->clkprof_timer_target;
303 
304   // copy HW counter information
305   hwcprof_default = cc->hwcprof_default;
306   hwcprof_enabled_cnt = cc->hwcprof_enabled_cnt;
307   if (cc->hwc_string != NULL)
308     hwc_string = strdup (cc->hwc_string);
309   else
310     hwc_string = NULL;
311   for (int i = 0; i < hwcprof_enabled_cnt; i++)
312     hwcentry_dup (&hwctr[i], &(cc->hwctr[i]));
313   project_home = cc->project_home ? strdup (cc->project_home) : NULL;
314   synctrace_enabled = cc->synctrace_enabled;
315   synctrace_thresh = cc->synctrace_thresh;
316   synctrace_scope = cc->synctrace_scope;
317   heaptrace_enabled = cc->heaptrace_enabled;
318   heaptrace_checkenabled = cc->heaptrace_checkenabled;
319   iotrace_enabled = cc->iotrace_enabled;
320   count_enabled = cc->count_enabled;
321   Iflag = cc->Iflag;
322   Nflag = cc->Nflag;
323   sample_period = cc->sample_period;
324   sample_default = cc->sample_default;
325   size_limit = cc->size_limit;
326   nofswarn = cc->nofswarn;
327 
328   // these will get reset during preprocess_names()
329   expt_name = NULL;
330   expt_dir = NULL;
331   store_dir = NULL;
332   base_name = NULL;
333   expno = 1;
334 
335   // these represent user settings
336   expt_group = NULL;
337   if (cc->expt_group != NULL)
338     expt_group = strdup (cc->expt_group);
339   uexpt_name = NULL;
340   if (cc->uexpt_name != NULL)
341     uexpt_name = strdup (cc->uexpt_name);
342   udir_name = NULL;
343   if (cc->udir_name != NULL)
344     udir_name = strdup (cc->udir_name);
345 
346   /* clear the string pointers */
347   prev_store_dir = strdup ("");
348   store_ptr = NULL;
349   target_name = NULL;
350   data_desc = NULL;
351   lockname = NULL;
352   lockfd = -1;
353 
354   /* set default data collection values */
355   enabled = cc->enabled;
356   opened = 0;
357   nofswarn = cc->nofswarn;
358   sys_resolution = cc->sys_resolution;
359   sys_period = cc->sys_period;
360 
361   // ensure that the default name is updated
362   (void) preprocess_names ();
363   (void) update_expt_name (false, false);
364   build_data_desc ();
365 }
366 
~Coll_Ctrl()367 Coll_Ctrl::~Coll_Ctrl ()
368 {
369   free (node_name);
370   free (expt_name);
371   free (expt_dir);
372   free (base_name);
373   free (udir_name);
374   free (store_dir);
375   free (store_ptr);
376   free (expt_group);
377   free (target_name);
378   free (data_desc);
379   free (lockname);
380   free (hwc_string);
381   free (project_home);
382   free (java_path);
383   hwcprof_enabled_cnt = 0;
384 }
385 
386 /* set up the experiment */
387 char *
setup_experiment()388 Coll_Ctrl::setup_experiment ()
389 {
390   char *ret;
391   if (enabled == 0)
392     return NULL;
393   build_data_desc ();
394 
395   /* create the experiment directory */
396   ret = create_exp_dir ();
397   if (ret != NULL)
398     return ret;
399 
400   /* if an experiment-group, join it */
401   ret = join_group ();
402   if (ret != NULL)
403     {
404       remove_exp_dir ();
405       return ret;
406     }
407   /* all is OK, return 0 */
408   opened = 1;
409   return NULL;
410 }
411 
412 void
interrupt()413 Coll_Ctrl::interrupt ()
414 {
415   uinterrupt = 1;
416 }
417 
418 char *
enable_expt()419 Coll_Ctrl::enable_expt ()
420 {
421   if (opened == 1)
422     return strdup (GTXT ("Experiment is active; command ignored.\n"));
423   if (cpu_clk_freq == 0)
424     return strdup (GTXT ("Can not determine CPU clock frequency.\n"));
425   if (sys_resolution == 0)
426     return strdup (GTXT ("System clock profile resolution can not be determined.\n"));
427   enabled = 1;
428   return NULL;
429 }
430 
431 /* close the experiment */
432 void
close_expt()433 Coll_Ctrl::close_expt ()
434 {
435   opened = 0;
436   (void) update_expt_name (false, false);
437 }
438 
439 /* close and delete the experiment */
440 void
delete_expt()441 Coll_Ctrl::delete_expt ()
442 {
443   if (opened == 0)
444     return;
445   remove_exp_dir ();
446 
447   /* The order of removing the directory and closing
448    * the experiment may seem unnatural, but it's not.
449    * We do need to update names when we close the experiment
450    * (actually Coll_Ctrl object) and we can't remove anything
451    * after that.
452    */
453   close_expt ();
454 }
455 
456 // Check the experiment settings for consistency.  Returns NULL if OK,
457 //	or an error message if there are invalid combinations of settings
458 char *
check_consistency()459 Coll_Ctrl::check_consistency ()
460 {
461   /* check for Java arguments, but not Java profiling */
462   if (java_args != NULL && java_mode == 0)
463     return strdup (GTXT ("Java arguments can not be set if Java profiling is not enabled.\n"));
464 
465   /* if count data, no other data is allowed */
466   if (count_enabled != 0
467       && ((clkprof_default != 1 && clkprof_enabled != 0)
468 	  || hwcprof_enabled_cnt != 0 || synctrace_enabled != 0
469 	  || heaptrace_enabled != 0 || iotrace_enabled != 0))
470     return strdup (GTXT ("Count data cannot be collected along with any other data.\n"));
471 
472   /* if count data, various other options are not allowed */
473   if (count_enabled != 0
474       && ((java_mode != 0 && java_default != 1)
475 	  || java_args != NULL || debug_mode != 0
476 	  || (follow_mode != 0 && follow_default != 1)
477 	  || pauseresume_sig != 0 || sample_sig != 0
478 	  || (sample_default != 1 && sample_period != 0) || time_run != 0))
479     return strdup (GTXT ("Count data cannot be collected with any of -F -S -y -l -j -J -x -t .\n"));
480   /* if not count data, I and N options are not allowed */
481   if (count_enabled == 0 && (Iflag != 0 || Nflag != 0))
482     return strdup (GTXT ("-I or -N can only be specified with count data.\n"));
483   return NULL;
484 }
485 
486 char *
check_expt(char ** warn)487 Coll_Ctrl::check_expt (char **warn)
488 {
489   char *ret;
490   *warn = NULL;
491   ret = check_consistency ();
492   if (ret != NULL)      /* something is wrong, return the error */
493     return ret;
494   /* check for heaptrace and java -- warn that it covers native allocations only */
495   if (heaptrace_enabled == 1 && java_mode == 1 && java_default == 0)
496     *warn = strdup (GTXT ("Note: Heap profiling will only trace native allocations, not Java allocations.\n"));
497 
498   /* if no profiling data selected, warn the user */
499   if (clkprof_enabled == 0 && hwcprof_enabled_cnt == 0 && synctrace_enabled == 0
500       && heaptrace_enabled == 0 && iotrace_enabled == 0 && count_enabled == 0)
501     *warn = strdup (GTXT ("Warning: No function level data requested; only statistics will be collected.\n\n"));
502   build_data_desc ();
503 
504   /* verify that the directory exists */
505   struct stat statbuf;
506   if (stat (store_dir, &statbuf) != 0)
507     return dbe_sprintf (GTXT ("Store directory %s is not accessible: %s\n"),
508 			store_dir, strerror (errno));
509   if (access (store_dir, W_OK) != 0)
510     return dbe_sprintf (GTXT ("Store directory %s is not writeable: %s\n"),
511 		store_dir, strerror (errno));
512 
513   /* if an experiment-group, verify that it can be written */
514   ret = check_group ();
515   if (ret != NULL)
516     return ret;
517   return NULL;
518 }
519 
520 char *
show(int i)521 Coll_Ctrl::show (int i)
522 {
523   char UEbuf[4096];
524   UEbuf[0] = 0;
525   if (i == 0)
526     {
527       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
528 		GTXT ("Collection parameters:\n"));
529       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
530 		GTXT ("    experiment enabled\n"));
531     }
532   if (target_name != NULL)
533     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
534 	      GTXT ("\ttarget = %s\n"), target_name);
535   if (uexpt_name != NULL)
536     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
537 	      GTXT ("\tuser_expt_name = %s\n"), uexpt_name);
538   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
539 	    GTXT ("\texpt_name = %s\n"),
540 	    ((expt_name != NULL) ? expt_name : NTXT ("<NULL>")));
541   if (udir_name != NULL)
542     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
543 	      GTXT ("\tdir_name = %s\n"), udir_name);
544   if (expt_group != NULL)
545     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
546 	      GTXT ("\texpt_group = %s\n"), expt_group);
547   if (debug_mode == 1)
548     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
549 	      GTXT ("\tdebug_mode enabled\n"));
550   if (clkprof_enabled != 0)
551     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
552 	      GTXT ("\tclock profiling enabled, %.3f millisec.\n"),
553 	      (double) (clkprof_timer) / 1000.);
554   if (synctrace_enabled != 0)
555     {
556       if (synctrace_thresh < 0)
557 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
558 		  GTXT ("\tsynchronization tracing enabled, threshold: calibrate; "));
559       else if (synctrace_thresh == 0)
560 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
561 		  GTXT ("\tsynchronization tracing enabled, threshold: all; "));
562       else
563 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
564 		  GTXT ("\tsynchronization tracing enabled, threshold: %d micros.; "), synctrace_thresh);
565       switch (synctrace_scope)
566 	{
567 	case SYNCSCOPE_NATIVE:
568 	  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
569 		    GTXT ("Native-APIs\n"));
570 	  break;
571 	case SYNCSCOPE_JAVA:
572 	  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
573 		    GTXT ("Java-APIs\n"));
574 	  break;
575 	case SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA:
576 	  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
577 		    GTXT ("Native- and Java-APIs\n"));
578 	  break;
579 	default:
580 	  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
581 		    GTXT ("ERR -- unexpected synctrace_scope %d\n"), synctrace_scope);
582 	  break;
583 	}
584     }
585   if (hwcprof_enabled_cnt != 0)
586     {
587       char ctrbuf[MAXPATHLEN];
588       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
589 		GTXT ("\thardware counter profiling%s enabled:\n"),
590 		(hwcprof_default == 1 ? GTXT (" (default)") : ""));
591       for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
592 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
593 		  GTXT ("\t  %u. %s\n"), ii + 1,
594 		  hwc_hwcentry_specd_string (ctrbuf, MAXPATHLEN, &hwctr[ii]));
595     }
596   if (heaptrace_enabled != 0)
597     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
598 	      GTXT ("\theap tracing enabled, %s\n"),
599 	      (heaptrace_checkenabled == 0 ? GTXT ("no checking") :
600 	       (heaptrace_checkenabled == 1 ? GTXT ("over/underrun checking") :
601 		GTXT ("over/underrun checking and pattern storing"))));
602   if (iotrace_enabled != 0)
603     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
604 	      GTXT ("\tI/O tracing enabled\n"));
605   switch (count_enabled)
606     {
607     case 0:
608       break;
609     case 1:
610       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
611 		GTXT ("\tcount data enabled\n"));
612       break;
613     case -1:
614       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
615 		GTXT ("\tstatic count data will be generated (for a.out only)\n"));
616       break;
617     }
618   switch (follow_mode)
619     {
620     case FOLLOW_ON:
621       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
622 		GTXT ("\tdescendant processes will be followed\n"));
623       break;
624     case FOLLOW_ALL:
625       if (follow_spec_usr && follow_spec_cmp)
626 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
627 		  GTXT ("\texperiments will be recorded for descendant processes that match pattern '%s'\n"),
628 		  follow_spec_usr);
629       else
630 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
631 		  GTXT ("\tdescendant processes will all be followed\n"));
632       break;
633     case FOLLOW_NONE:
634       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
635 		GTXT ("\tdescendant processes will not be followed\n"));
636       break;
637     default:
638       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
639 		GTXT ("\tfollowing descendant processes: <UNKNOWN>\n"));
640       break;
641     }
642   if (java_mode == 0)
643     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
644 	      GTXT ("\tjava profiling disabled\n"));
645   if (pauseresume_sig != 0)
646     {
647       const char *buf = strsignal (pauseresume_sig);
648       if (buf != NULL)
649 	{
650 	  if (pauseresume_pause == 1)
651 	    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
652 		      GTXT ("\tpause-resume (delayed initialization) signal %s (%d) -- paused\n"), buf, pauseresume_sig);
653 	  else
654 	    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
655 		      GTXT ("\tpause-resume (delayed initialization) signal %s (%d)\n"), buf, pauseresume_sig);
656 	}
657       else
658 	{
659 	  if (pauseresume_pause == 1)
660 	    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
661 		      GTXT ("\tpause-resume (delayed initialization) signal %d -- paused\n"), pauseresume_sig);
662 	  else
663 	    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
664 		      GTXT ("\tpause-resume (delayed initialization) signal %d\n"), pauseresume_sig);
665 	}
666     }
667   if (sample_sig != 0)
668     {
669       const char *buf = strsignal (sample_sig);
670       if (buf != NULL)
671 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
672 		  GTXT ("\tsample signal %s (%d)\n"), buf, sample_sig);
673       else
674 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
675 		  GTXT ("\tsample signal %d\n"), sample_sig);
676     }
677   if (time_run != 0 || start_delay != 0)
678     {
679       if (start_delay != 0)
680 	{
681 	  if (time_run != 0)
682 	    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
683 		      GTXT ("\tdata-collection duration, %d-%d secs.\n"), start_delay, time_run);
684 	  else
685 	    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
686 		      GTXT ("\tdata-collection duration, %d- secs.\n"), start_delay);
687 	}
688       else
689 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
690 		  GTXT ("\tdata-collection duration, %d secs.\n"), time_run);
691     }
692   if (sample_period != 0)
693     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
694 	      GTXT ("\tperiodic sampling, %d secs.\n"), sample_period);
695   else
696     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
697 	      GTXT ("\tno periodic sampling\n"));
698   if (size_limit != 0)
699     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
700 	      GTXT ("\texperiment size limit %d MB.\n"), size_limit);
701   else
702     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
703 	      GTXT ("\tno experiment size limit set\n"));
704   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
705 	    GTXT ("\texperiment archiving: -a %s\n"), archive_mode);
706   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
707 	    GTXT ("\tdata descriptor: \"%s\"\n"),
708 	    ((data_desc != NULL) ? data_desc : NTXT ("<NULL>")));
709 #if 0
710   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
711 	    GTXT ("\t expt_dir: %s\n"),
712 	    ((expt_dir != NULL) ? expt_dir : NTXT ("<NULL>")));
713   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
714 	    GTXT ("\t base_name: %s\n"),
715 	    ((base_name != NULL) ? base_name : NTXT ("<NULL>")));
716   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
717 	    GTXT ("\t store_dir: %s\n"),
718 	    ((store_dir != NULL) ? store_dir : NTXT ("<NULL>")));
719   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
720 	    GTXT ("\t store_ptr: %s\n"),
721 	    ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")));
722 #endif
723   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
724 	    GTXT ("\t\thost: `%s', ncpus = %d, clock frequency %d MHz.\n"),
725 	    ((node_name != NULL) ? node_name : NTXT ("<NULL>")),
726 	    (int) ncpus, (int) cpu_clk_freq);
727   if (npages > 0)
728     {
729       long long memsize = ((long long) npages * (long long) page_size) / (1024 * 1024);
730       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
731 		GTXT ("\t\tmemory:  %ld pages @ %ld bytes = %lld MB.\n"),
732 		npages, page_size, memsize);
733     }
734   return strdup (UEbuf);
735 }
736 
737 #define MAX_COLLECT_ARGS    100
738 
739 char **
get_collect_args()740 Coll_Ctrl::get_collect_args ()
741 {
742   char buf[DD_MAXPATHLEN];
743   char **p;
744   char **argv = (char **) calloc (MAX_COLLECT_ARGS, sizeof (char *));
745   if (argv == NULL)     // poor way of dealing with calloc failure
746     abort ();
747   p = argv;
748   *p++ = strdup ("collect");
749   if (debug_mode == 1)
750     *p++ = strdup ("-x");
751   if (clkprof_enabled != 0)
752     {
753       *p++ = strdup ("-p");
754       snprintf (buf, sizeof (buf), "%du", clkprof_timer);
755       *p++ = strdup (buf);
756     }
757   if (hwcprof_enabled_cnt > 0)
758     {
759       *buf = 0;
760       *p++ = strdup ("-h");
761       for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
762 	{
763 	  char*rateString = hwc_rate_string (&hwctr[ii], 1); //"1" is for temporary goldfile compatibility. TBR YXXX!!
764 	  snprintf (buf + strlen (buf), sizeof (buf) - strlen (buf),
765 		    "%s%s,%s%s", ii ? "," : "", hwctr[ii].name,
766 		    rateString ? rateString : "",
767 		    (ii + 1 < hwcprof_enabled_cnt) ? "," : "");
768 	  free (rateString);
769 	}
770       if (strlen (buf) + 1 >= sizeof (buf))
771 	abort ();
772       *p++ = strdup (buf);
773     }
774   if (heaptrace_enabled != 0)
775     {
776       *p++ = strdup ("-H");
777       *p++ = strdup ("on");
778     }
779   if (iotrace_enabled != 0)
780     {
781       *p++ = strdup ("-i");
782       *p++ = strdup ("on");
783     }
784   if (synctrace_enabled != 0)
785     {
786       *p++ = strdup ("-s");
787       if (synctrace_thresh < 0)
788 	*p++ = strdup ("calibrate");
789       else if (synctrace_thresh == 0)
790 	*p++ = strdup ("all");
791       else
792 	*p++ = dbe_sprintf ("%d", synctrace_thresh);
793       *p++ = dbe_sprintf (",%d", synctrace_scope);
794     }
795   if (follow_mode != 0)
796     {
797       *p++ = strdup ("-F");
798       char * fs = get_follow_usr_spec ();
799       if (fs)
800 	*p++ = strdup (fs);
801       else
802 	{
803 	  switch (get_follow_mode ())
804 	    {
805 	    case FOLLOW_ON:
806 	      *p++ = strdup ("on");
807 	      break;
808 	    case FOLLOW_ALL:
809 	      *p++ = strdup ("all");
810 	      break;
811 	    case FOLLOW_NONE:
812 	    default:
813 	      *p++ = strdup ("off");
814 	      break;
815 	    }
816 	}
817     }
818   *p++ = strdup ("-a");
819   *p++ = strdup (get_archive_mode ());
820   if (java_mode != 0)
821     {
822       *p++ = strdup ("-j");
823       *p++ = strdup ("on");
824     }
825   if (pauseresume_sig != 0)
826     {
827       *p++ = strdup ("-y");
828       *p++ = dbe_sprintf ("%d%s", pauseresume_sig,
829 			  (pauseresume_pause == 0 ? ",r" : ""));
830     }
831   if (sample_sig != 0)
832     {
833       *p++ = strdup ("-l");
834       *p++ = dbe_sprintf ("%d", sample_sig);
835     }
836   if (sample_period != 0)
837     {
838       *p++ = strdup ("-S");
839       *p++ = dbe_sprintf ("%d", sample_period);
840     }
841   if (size_limit != 0)
842     {
843       *p++ = strdup ("-L");
844       *p++ = dbe_sprintf ("%d", size_limit);
845     }
846   if (expt_group != NULL)
847     {
848       *p++ = strdup ("-g");
849       *p++ = strdup (expt_group);
850     }
851   if (udir_name != 0)
852     {
853       *p++ = strdup ("-d");
854       *p++ = strdup (udir_name);
855     }
856   if (expt_name != 0)
857     {
858       *p++ = strdup ("-o");
859       *p++ = strdup (expt_name);
860     }
861   if (p - argv >= MAX_COLLECT_ARGS) // argument list too small -- fatal error
862     abort ();
863   return argv;
864 }
865 
866 char *
show_expt()867 Coll_Ctrl::show_expt ()
868 {
869   if (enabled == 0)
870     return NULL;
871   char UEbuf[4096];
872   UEbuf[0] = 0;
873   snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
874 	    GTXT ("Creating experiment directory %s (Process ID: %ld) ...\n"),
875 	    ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")), (long) getpid ());
876   char *caller = getenv ("SP_COLLECTOR_FROM_GUI"); // Collector from GUI
877   if (caller != NULL)   // Print non-localized message
878     snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
879 	      NTXT ("\nCreating experiment directory %s (Process ID: %ld) ...\n"),
880 	      ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")), (long) getpid ());
881 #if 0
882   char *fstype = get_fstype (store_dir);
883   if ((fstype != NULL) && (nofswarn == 0))
884     {
885       // only warn if clock or hwc profiling is turned on
886       if (clkprof_enabled || hwcprof_enabled_cnt != 0)
887 	snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
888 		  GTXT ("this experiment is being recorded to a file system \nof type \"%s\", which may distort the measured performance."),
889 		  fstype);
890     }
891 #endif
892   return strdup (UEbuf);
893 }
894 
895 void
set_clk_params(int min,int res,int max,int hi,int norm,int lo)896 Coll_Ctrl::set_clk_params (int min, int res, int max, int hi, int norm, int lo)
897 {
898   clk_params.min = min;
899   clk_params.res = res;
900   clk_params.max = max;
901   clk_params.hival = hi;
902   clk_params.normval = norm;
903   clk_params.lowval = lo;
904   set_clkprof_timer_target (clk_params.normval); // note: requires clk_params to be initialized!
905 }
906 
907 char *
reset_clkprof(int val)908 Coll_Ctrl::reset_clkprof (int val)
909 {
910   if (val != clkprof_timer)
911     {
912       // profiler has had to reset to a different value; warn user
913       char *msg = dbe_sprintf (
914 	      GTXT ("Warning: Clock profiling timer reset from %.3f millisec. to %.3f millisec. as required by profiling driver\n\n"),
915 	      (double) (clkprof_timer) / 1000., (double) (val) / 1000.);
916       adjust_clkprof_timer (val);
917       return msg;
918     }
919   return NULL;
920 }
921 
922 char *
set_clkprof(const char * string,char ** warn)923 Coll_Ctrl::set_clkprof (const char *string, char** warn)
924 {
925   int ticks;
926   int nclkprof_timer;
927   int prevclkprof_enabled;
928   int prevclkprof_default;
929   *warn = NULL;
930   if (opened == 1)
931     return strdup (GTXT ("Experiment is active; command ignored.\n"));
932   /* if the first character is a +, warn user that it is no longer supported */
933   if (string[0] == '+')
934     return strdup (GTXT ("Warning: clock-based memoryspace and dataspace profiling is no longer supported\n"));
935   if (strcmp (string, "off") == 0)
936     {
937       clkprof_enabled = 0;
938       clkprof_default = 0;
939       return NULL;
940     }
941   else if (string == NULL || strcmp (string, "on") == 0)
942     nclkprof_timer = clk_params.normval;
943   else if (strcmp (string, "lo") == 0 || strcmp (string, "low") == 0)
944     nclkprof_timer = clk_params.lowval;
945   else if (strcmp (string, "hi") == 0 || strcmp (string, "high") == 0
946 	   || strcmp (string, "h") == 0)
947     nclkprof_timer = clk_params.hival;
948   else
949     {
950       /* the remaining string should be a number > 0 */
951       char *endchar = NULL;
952       double dval = strtod (string, &endchar);
953       if (*endchar == 'm' || *endchar == 0) /* user specified milliseconds */
954 	dval = dval * 1000.;
955       else if (*endchar == 'u')     /* user specified microseconds */
956 	dval = dval;
957       else
958 	return dbe_sprintf (GTXT ("Unrecognized clock-profiling interval `%s'\n"), string);
959       nclkprof_timer = (int) (dval + 0.5);
960     }
961   // we now have the proposed value; ensure it's within limits
962   if (nclkprof_timer <= 0)
963     return dbe_sprintf (GTXT ("Unrecognized clock-profiling interval `%s'\n"), string);
964 
965   // Check consistency with experiment
966   prevclkprof_enabled = clkprof_enabled;
967   prevclkprof_default = clkprof_default;
968   clkprof_enabled = 1;
969   clkprof_default = 0;
970   char *ret = check_consistency ();
971   if (ret != NULL)
972     {
973       clkprof_default = prevclkprof_default;
974       clkprof_enabled = prevclkprof_enabled;
975       return ret;
976     }
977   int ref_nclkprof_timer = nclkprof_timer;
978 
979   // check for minimum value
980   if (nclkprof_timer < clk_params.min)
981     {
982       /* value too small, use minimum value, with warning */
983       *warn = dbe_sprintf (
984 		GTXT ("Warning: Clock profiling at %.3f millisec. interval is not supported on this system; minimum %.3f millisec. used\n"),
985 		(double) (nclkprof_timer) / 1000., (double) (clk_params.min) / 1000.);
986       nclkprof_timer = clk_params.min;
987     }
988 
989   // check for maximum value
990   if (nclkprof_timer > clk_params.max)
991     {
992       *warn = dbe_sprintf (
993 		GTXT ("Clock profiling at %.3f millisec. interval is not supported on this system; maximum %.3f millisec. used\n"),
994 		(double) (nclkprof_timer) / 1000., (double) (clk_params.max) / 1000.);
995       nclkprof_timer = clk_params.max;
996     }
997 
998   /* see if setting is a multiple of the period */
999   if (nclkprof_timer > clk_params.res)
1000     {
1001       ticks = ((nclkprof_timer / clk_params.res) * clk_params.res);
1002       if (ticks != nclkprof_timer)
1003 	{
1004 	  /* no, we need to reset to a multiple */
1005 	  *warn = dbe_sprintf (
1006 		    GTXT ("Clock profile interval rounded from %.3f to %.3f (system resolution = %.3f) millisec."),
1007 		    (double) (nclkprof_timer) / 1000., (double) (ticks) / 1000.,
1008 		    (double) (clk_params.res) / 1000.);
1009 	  nclkprof_timer = ticks;
1010 	}
1011     }
1012 
1013   // limit reference "target" rate.  Target rate is also used for HWCS.
1014   if (ref_nclkprof_timer > PROFINT_MAX)
1015     ref_nclkprof_timer = PROFINT_MAX;
1016   if (ref_nclkprof_timer < PROFINT_MIN)
1017     ref_nclkprof_timer = PROFINT_MIN;
1018   set_clkprof_timer_target (ref_nclkprof_timer);
1019   adjust_clkprof_timer (nclkprof_timer);
1020   return NULL;
1021 }
1022 
1023 char *
set_synctrace(const char * string)1024 Coll_Ctrl::set_synctrace (const char *string)
1025 {
1026   if (opened == 1)
1027     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1028   char *comma_p = NULL;
1029   if (string == NULL)
1030     {
1031       /* no argument provided,  use default: calibrate and native */
1032       synctrace_enabled = 1;
1033       synctrace_thresh = -1;
1034       synctrace_scope = SYNCSCOPE_NATIVE;
1035       char *ret = check_consistency ();
1036       if (ret != NULL)
1037 	{
1038 	  synctrace_enabled = 0;
1039 	  return ret;
1040 	}
1041       return NULL;
1042     }
1043   char *val = strdup (string);
1044   /* see if there's a comma in the string */
1045   char *next = strchr (val, (int) ',');
1046   if (next != NULL)
1047     {
1048       /* remember where the comma was */
1049       comma_p = next;
1050 
1051       /* set the scope based on the characters following the comma */
1052       synctrace_scope = 0;
1053       next++;
1054       while (*next != 0)
1055 	{
1056 	  if (*next == 'n')
1057 	    synctrace_scope |= SYNCSCOPE_NATIVE;
1058 	  else if (*next == 'j')
1059 	    synctrace_scope |= SYNCSCOPE_JAVA;
1060 	  else
1061 	    return dbe_sprintf (GTXT ("Unrecognized synchronization tracing threshold `%s'\n"), string);
1062 	  next++;
1063 	}
1064       if (synctrace_scope == 0)
1065 	synctrace_scope = SYNCSCOPE_NATIVE;
1066       /* clear the comma for the threshold determination */
1067       *comma_p = 0;
1068     }
1069   else      /* no ",<scope>" -- default to native and Java */
1070     synctrace_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA;
1071   if (!strlen (val) || !strcmp (val, "calibrate") || !strcmp (val, "on"))
1072     {
1073       /* use default: calibrate and native */
1074       synctrace_enabled = 1;
1075       synctrace_thresh = -1;
1076       free (val);
1077       char *ret = check_consistency ();
1078       if (ret != NULL)
1079 	{
1080 	  synctrace_enabled = 0;
1081 	  return ret;
1082 	}
1083       return NULL;
1084     }
1085   if (strcmp (val, "off") == 0)
1086     {
1087       synctrace_enabled = 0;
1088       free (val);
1089       return NULL;
1090     }
1091   if (strcmp (val, "all") == 0)
1092     {
1093       /* set to record all events */
1094       synctrace_thresh = 0;
1095       synctrace_enabled = 1;
1096       char *ret = check_consistency ();
1097       free (val);
1098       if (ret != NULL)
1099 	{
1100 	  synctrace_enabled = 0;
1101 	  return ret;
1102 	}
1103       return NULL;
1104     }
1105   /* the remaining string should be a number >= 0 */
1106   char *endchar = NULL;
1107   int tval = (int) strtol (val, &endchar, 0);
1108   if (*endchar != 0 || tval < 0)
1109     {
1110       free (val);
1111       return dbe_sprintf (GTXT ("Unrecognized synchronization tracing threshold `%s'\n"), string);
1112     }
1113   free (val);
1114   synctrace_thresh = tval;
1115   synctrace_enabled = 1;
1116   return NULL;
1117 }
1118 
1119 char *
set_heaptrace(const char * string)1120 Coll_Ctrl::set_heaptrace (const char *string)
1121 {
1122   if (opened == 1)
1123     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1124   if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
1125     {
1126       heaptrace_enabled = 1;
1127       char *ret = check_consistency ();
1128       if (ret != NULL)
1129 	{
1130 	  heaptrace_enabled = 0;
1131 	  return ret;
1132 	}
1133       return NULL;
1134     }
1135   if (strcmp (string, "off") == 0)
1136     {
1137       heaptrace_enabled = 0;
1138       return NULL;
1139     }
1140 #if 0
1141   if (strcmp (string, "check") == 0)
1142     {
1143       /* set to check for over/underruns */
1144       heaptrace_checkenabled = 1;
1145       heaptrace_enabled = 1;
1146       return NULL;
1147     }
1148   if (strcmp (string, "clear") == 0)
1149     {
1150       /* set to check for over/underruns, and store patterns */
1151       heaptrace_checkenabled = 2;
1152       heaptrace_enabled = 1;
1153       return NULL;
1154     }
1155 #endif
1156   return dbe_sprintf (GTXT ("Unrecognized heap tracing parameter `%s'\n"), string);
1157 }
1158 
1159 char *
set_iotrace(const char * string)1160 Coll_Ctrl::set_iotrace (const char *string)
1161 {
1162   if (opened == 1)
1163     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1164   if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
1165     {
1166       iotrace_enabled = 1;
1167       char *ret = check_consistency ();
1168       if (ret != NULL)
1169 	{
1170 	  iotrace_enabled = 0;
1171 	  return ret;
1172 	}
1173       return NULL;
1174     }
1175   if (strcmp (string, "off") == 0)
1176     {
1177       iotrace_enabled = 0;
1178       return NULL;
1179     }
1180   return dbe_sprintf (GTXT ("Unrecognized I/O tracing parameter `%s'\n"), string);
1181 }
1182 
1183 char *
set_count(const char * string)1184 Coll_Ctrl::set_count (const char *string)
1185 {
1186   int ret = -1;
1187   if (opened == 1)
1188     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1189   if (string == NULL || strlen (string) == 0 || strcmp (string, "off") == 0)
1190     {
1191       count_enabled = 0;
1192       ret = 0;
1193     }
1194   if (strcmp (string, "on") == 0)
1195     {
1196       count_enabled = 1;
1197       char *cret = check_consistency ();
1198       if (cret != NULL)
1199 	{
1200 	  count_enabled = 0;
1201 	  return cret;
1202 	}
1203       ret = 0;
1204     }
1205   if (strcmp (string, "static") == 0)
1206     {
1207       count_enabled = -1;
1208       char *cret = check_consistency ();
1209       if (cret != NULL)
1210 	{
1211 	  count_enabled = 0;
1212 	  return cret;
1213 	}
1214       ret = 0;
1215     }
1216   if (ret == 0)
1217     {
1218       if (count_enabled != 0)
1219 	{
1220 	  /* ensure that sample period is 0, if set by default */
1221 	  if (sample_default == 1)
1222 	    sample_period = 0;
1223 	  /* ensure that clock profiling is off, if set by default */
1224 	  if (clkprof_default == 1)
1225 	    {
1226 	      clkprof_default = 0;
1227 	      clkprof_enabled = 0;
1228 	    }
1229 	  if (hwcprof_default == 1)
1230 	    hwcprof_default = 0;
1231 	}
1232       return NULL;
1233     }
1234   return dbe_sprintf (GTXT ("Unrecognized count parameter `%s'\n"), string);
1235 }
1236 
1237 char *
set_time_run(const char * valarg)1238 Coll_Ctrl::set_time_run (const char *valarg)
1239 {
1240   if (opened == 1)
1241     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1242   if (valarg == NULL)   /* invalid setting */
1243     return strdup (GTXT ("time parameter can not be NULL\n"));
1244   /* the string should be a number >= 0 */
1245   int prev_start_delay = start_delay;
1246   int prev_time_run = time_run;
1247   const char *endchar = valarg;
1248   char *newchar = NULL;
1249   int val = 0;
1250   if (*endchar != '-')
1251     {
1252       val = (int) strtol (endchar, &newchar, 0);
1253       endchar = newchar;
1254       if (val < 0)
1255 	return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
1256       if (*endchar == 'm')
1257 	{
1258 	  val = val * 60; /* convert to seconds */
1259 	  endchar++;
1260 	}
1261       else if (*endchar == 's')     /* no conversion needed */
1262 	endchar++;
1263       if (*endchar == 0)
1264 	{
1265 	  time_run = val;
1266 	  return NULL;
1267 	}
1268       else if (*endchar != '-')
1269 	return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
1270     }
1271   /* a second number is provided */
1272   start_delay = val;
1273   endchar++;
1274   val = (int) strtol (endchar, &newchar, 0);
1275   endchar = newchar;
1276   if (val < 0)
1277     {
1278       start_delay = prev_start_delay;
1279       return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
1280     }
1281   if (*endchar == 'm')
1282     {
1283       val = val * 60; /* convert to seconds */
1284       endchar++;
1285     }
1286   else if (*endchar == 's')     /* no conversion needed */
1287     endchar++;
1288   if (*endchar != 0)
1289     {
1290       start_delay = prev_start_delay;
1291       return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
1292     }
1293   time_run = val;
1294   if (time_run != 0 && start_delay >= time_run)
1295     {
1296       start_delay = prev_start_delay;
1297       return dbe_sprintf (GTXT ("Invalid time parameter `%s': start time must be earlier than end time\n"), valarg);
1298     }
1299   char *ret = check_consistency ();
1300   if (ret != NULL)
1301     {
1302       start_delay = prev_start_delay;
1303       time_run = prev_time_run;
1304       return ret;
1305     }
1306   return NULL;
1307 }
1308 
1309 char *
set_attach_pid(char * valarg)1310 Coll_Ctrl::set_attach_pid (char *valarg)
1311 {
1312   if (opened == 1)
1313     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1314   if (valarg == NULL)
1315     return strdup (GTXT ("Specified PID can not be NULL\n"));
1316 
1317   /* the string should be a number corresponding to an active process' pid */
1318   char *endchar = NULL;
1319   int val = (int) strtol (valarg, &endchar, 0);
1320   if (*endchar != 0 || val < 0)
1321     return dbe_sprintf (GTXT ("Invalid process pid `%s'\n"), valarg);
1322   int prev_attach_pid = attach_pid;
1323   attach_pid = val;
1324   char *ret = check_consistency ();
1325   if (ret != NULL)
1326     {
1327       attach_pid = prev_attach_pid;
1328       return ret;
1329     }
1330   return NULL;
1331 }
1332 
1333 void
free_hwc_fields(Hwcentry * tmpctr)1334 Coll_Ctrl::free_hwc_fields (Hwcentry * tmpctr)
1335 {
1336   if (tmpctr->name != NULL)
1337     free (tmpctr->name);
1338   if (tmpctr->int_name != NULL)
1339     free (tmpctr->int_name);
1340   memset (tmpctr, 0, sizeof (Hwcentry));
1341   tmpctr->reg_num = -1;
1342 }
1343 
1344 void
hwcentry_dup(Hwcentry * hnew,Hwcentry * _hwc)1345 Coll_Ctrl::hwcentry_dup (Hwcentry *hnew, Hwcentry *_hwc)
1346 {
1347   *hnew = *_hwc;
1348   if (_hwc->name != NULL)
1349     hnew->name = strdup (_hwc->name);
1350   else
1351     hnew->name = NULL;
1352   if (_hwc->int_name != NULL)
1353     hnew->int_name = strdup (_hwc->int_name);
1354   else
1355     hnew->int_name = NULL;
1356   if (_hwc->metric != NULL)
1357     hnew->metric = strdup (_hwc->metric);
1358   else
1359     hnew->metric = NULL;
1360   if (_hwc->short_desc != NULL)
1361     hnew->short_desc = strdup (_hwc->short_desc);
1362   else
1363     hnew->short_desc = NULL;
1364   if (_hwc->reg_list != NULL)
1365     {
1366       hnew->reg_list = (regno_t*) malloc (sizeof (regno_t*) * MAX_PICS);
1367       // poor way of dealing with malloc failure
1368       if (hnew->reg_list)
1369 	{
1370 	  for (int i = 0; i < MAX_PICS; i++)
1371 	    {
1372 	      hnew->reg_list[i] = _hwc->reg_list[i];
1373 	      if (hnew->reg_list[i] == REGNO_ANY)
1374 		break;
1375 	    }
1376 	}
1377     }
1378 }
1379 
1380 // Routine to initialize the HWC tables, set up the default experiment, etc.
1381 void
setup_hwc()1382 Coll_Ctrl::setup_hwc ()
1383 {
1384   static bool is_hwc_setup = false;
1385   if (is_hwc_setup == true)
1386     return;
1387   // try to set the default counters
1388   is_hwc_setup = true;
1389   set_hwcdefault ();
1390 }
1391 
1392 hrtime_t
clkprof_timer_2_hwcentry_min_time(int target_clkprof_usec)1393 Coll_Ctrl::clkprof_timer_2_hwcentry_min_time (int target_clkprof_usec)
1394 {
1395   hrtime_t hwc_nanosec;
1396   if (target_clkprof_usec == clk_params.normval)
1397     hwc_nanosec = HWCTIME_ON;
1398   else if (target_clkprof_usec == clk_params.lowval)
1399     hwc_nanosec = HWCTIME_LO;
1400   else if (target_clkprof_usec == clk_params.hival)
1401     hwc_nanosec = HWCTIME_HI;
1402   else
1403     hwc_nanosec = 1000LL * target_clkprof_usec; // nanoseconds
1404   return hwc_nanosec;
1405 }
1406 
1407 void
set_clkprof_timer_target(int microseconds)1408 Coll_Ctrl::set_clkprof_timer_target (int microseconds)
1409 {
1410   clkprof_timer = microseconds;
1411   clkprof_timer_target = microseconds;
1412   hrtime_t hwc_min_time_nanosec = clkprof_timer_2_hwcentry_min_time (microseconds);
1413   for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
1414     {
1415       hwctr[ii].min_time_default = hwc_min_time_nanosec;
1416       hwc_update_val (&hwctr[ii]);
1417     }
1418 }
1419 
1420 void
adjust_clkprof_timer(int use)1421 Coll_Ctrl::adjust_clkprof_timer (int use)
1422 {
1423   clkprof_timer = use;
1424 }
1425 
1426 /* set HWC counter set from a string */
1427 char * /* return an error string */
set_hwcstring(const char * string,char ** warnmsg)1428 Coll_Ctrl::set_hwcstring (const char *string, char **warnmsg)
1429 {
1430   *warnmsg = NULL;
1431   if (string == NULL || strcmp (string, "off") == 0)
1432     {
1433       hwcprof_enabled_cnt = 0;
1434       return NULL;
1435     }
1436   setup_hwc ();
1437   int old_cnt = hwcprof_enabled_cnt;
1438   int old_hwcprof_default = hwcprof_default;
1439 
1440   /* reset any previous count to zero */
1441   hwcprof_enabled_cnt = 0;
1442   char *ret = add_hwcstring (string, warnmsg);
1443   if (ret != NULL)
1444     {
1445       // restore previous setting
1446       hwcprof_enabled_cnt = old_cnt;
1447       hwcprof_default = old_hwcprof_default;
1448     }
1449   return ret;
1450 }
1451 
1452 /* add additional HWC counters to counter set from string */
1453 char * /* return an error string */
add_hwcstring(const char * string,char ** warnmsg)1454 Coll_Ctrl::add_hwcstring (const char *string, char **warnmsg)
1455 {
1456   *warnmsg = NULL;
1457   if (string == NULL || strcmp (string, "off") == 0)
1458     {
1459       hwcprof_enabled_cnt = 0;
1460       return NULL;
1461     }
1462   setup_hwc ();
1463   int rc = 0;
1464   int old_cnt = hwcprof_enabled_cnt;
1465   int prev_cnt = hwcprof_enabled_cnt;
1466   // int old_hwcprof_default = hwcprof_default;
1467   char UEbuf[MAXPATHLEN * 5];
1468   int UEsz;
1469   Hwcentry tmpctr[MAX_PICS];
1470   Hwcentry * ctrtable[MAX_PICS];
1471   char *emsg;
1472   char *wmsg;
1473   UEbuf[0] = 0;
1474   UEsz = sizeof (UEbuf);
1475   if (opened == 1)
1476     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1477   if (hwcprof_default == 0)
1478     {
1479       /* Copy the counters already defined */
1480       for (int ii = 0; ii < prev_cnt; ii++)
1481 	tmpctr[ii] = hwctr[ii];
1482     }
1483   else  /* the previously-defined counters were defaulted; don't copy them */
1484     prev_cnt = 0;
1485 
1486   /* look up the CPU version */
1487   cpc_cpuver = hwc_get_cpc_cpuver ();
1488   if (string && *string)
1489     {
1490       /* lookup counters */
1491       /* set up a pointer array */
1492       for (unsigned ii = 0; ii < MAX_PICS; ii++)
1493 	ctrtable[ii] = &tmpctr[ii];
1494       hrtime_t global_min_time = clkprof_timer_2_hwcentry_min_time (clkprof_timer_target);
1495       rc = hwc_lookup (kernelHWC, global_min_time, string, &ctrtable[prev_cnt], MAX_PICS - prev_cnt, &emsg, &wmsg);
1496       if (wmsg != NULL)
1497 	*warnmsg = wmsg;
1498       if (rc < 0)
1499 	return emsg;
1500       /* set count for sum of old and new counters */
1501       rc = rc + prev_cnt;
1502     }
1503 
1504   /* even though the actual hwctr[] array is not updated, we can check consistency */
1505   char *ret = check_consistency ();
1506   if (ret != NULL)
1507     {
1508       hwcprof_enabled_cnt = old_cnt;
1509       return ret;
1510     }
1511 
1512   /* finally, validate the full counter set */
1513   emsg = hwc_validate_ctrs (kernelHWC, ctrtable, rc);
1514   if (emsg != NULL)
1515     {
1516       hwcprof_enabled_cnt = old_cnt;
1517       return emsg;
1518     }
1519 
1520   /* success, update real counters and the string for them */
1521   /* turn off the default */
1522   hwcprof_default = 0;
1523   hwcprof_enabled_cnt = rc;
1524   free (hwc_string);
1525   for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
1526     {
1527       /* shallow copy of new counters */
1528       hwctr[ii] = tmpctr[ii];
1529       char *rateString = hwc_rate_string (&hwctr[ii], 0);
1530       snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
1531 		NTXT (",%s,%s"), hwctr[ii].name,
1532 		rateString ? rateString : "");
1533       free (rateString);
1534     }
1535   /* now duplicate that string, skipping the leading comma */
1536   hwc_string = strdup (&UEbuf[1]);
1537   return NULL;
1538 }
1539 
1540 /* add default HWC counters to counter set with resolution (on, hi, or lo) */
1541 /* Note that the resultion will also be used to set the clock-profiling default */
1542 char * /* return an error string */
add_default_hwcstring(const char * resolution,char ** warnmsg,bool add,bool forKernel)1543 Coll_Ctrl::add_default_hwcstring (const char *resolution, char **warnmsg, bool add, bool forKernel)
1544 {
1545   setup_hwc ();
1546   *warnmsg = NULL;
1547   char *def_string = hwc_get_default_cntrs2 (forKernel, 1);
1548   if (def_string == NULL)
1549     {
1550       /* no string defined, format and return an error message */
1551       char cpuname[128];
1552       hwc_get_cpuname (cpuname, sizeof (cpuname));
1553       return dbe_sprintf (GTXT ("No default HW counter set is defined for %s\n"), cpuname);
1554     }
1555   int len = strlen (def_string);
1556   if (len == 0)
1557     {
1558       /* string zero-length, meaning default counters can't be used */
1559       char cpuname[128];
1560       hwc_get_cpuname (cpuname, sizeof (cpuname));
1561       return dbe_sprintf (GTXT ("HW counter set for %s cannot be loaded on this system\n"), cpuname);
1562     }
1563   /* allocate return string */
1564   int retsize = 2 * len + 10;
1565   char *ret = (char *) malloc (retsize);
1566   if (ret == NULL)
1567     return strdup (GTXT ("internal error formating HW counter set; malloc failed\n"));
1568   *ret = 0;
1569   char *retp = ret;
1570   char *stringp = def_string;
1571   int first = 1;
1572   char *hwc_defaultx = strdup (def_string);
1573 
1574   /* now massage the string in order to insert resolution for each counter */
1575   for (;;)
1576     {
1577       /* find the next comma */
1578       char * next;
1579       char *nextp;
1580       if (first == 1)
1581 	nextp = stringp;
1582       else
1583 	nextp = stringp + 1;
1584       first = 0;
1585       if ((next = strchr (nextp, (int) ',')) != NULL)
1586 	{
1587 	  if (next == nextp)
1588 	    {
1589 	      /* next counter is zero-length -- invalid string */
1590 	      char cpuname[128];
1591 	      hwc_get_cpuname (cpuname, sizeof (cpuname));
1592 	      free (ret);
1593 	      ret = dbe_sprintf (GTXT ("HW counter set for %s, \"%s\", format error\n"), cpuname, hwc_defaultx);
1594 	      free (hwc_defaultx);
1595 	      return ret;
1596 	    }
1597 	  /* another field found */
1598 	  *next = 0;
1599 	  char nextc = *(next + 1);
1600 	  if ((nextc == 0) || (nextc == ','))
1601 	    {
1602 	      /* either ,, between fields, or string ends in comma */
1603 	      /* append the string */
1604 	      strncat (retp, stringp, (retsize - strlen (retp) - 1));
1605 	      strncat (retp, ",", (retsize - strlen (retp) - 1));
1606 	      strncat (retp, resolution, (retsize - strlen (retp) - 1));
1607 	      if (nextc == 0)       /* string ended in comma; we're done */
1608 		break;
1609 	    }
1610 	  else
1611 	    {
1612 	      /* string had only one comma between counter names; that's not valid */
1613 	      char cpuname[128];
1614 	      hwc_get_cpuname (cpuname, sizeof (cpuname));
1615 	      free (ret);
1616 	      ret = dbe_sprintf (GTXT ("HW counter set for %s, \"%s\", format error\n"), cpuname, hwc_defaultx);
1617 	      free (hwc_defaultx);
1618 	      return ret;
1619 	    }
1620 	  /* string had ,, between fields; move to next field */
1621 	  stringp = next + 1;
1622 	  if (* (stringp + 1) == 0)     /* name ended in ,, -- we're done */
1623 	    break;
1624 	  continue;
1625 	}
1626       else
1627 	{
1628 	  /* no comma found, add the last counter and the comma and resolution */
1629 	  strncat (retp, stringp, (retsize - strlen (retp) - 1));
1630 	  strncat (retp, ",", (retsize - strlen (retp) - 1));
1631 	  strncat (retp, resolution, (retsize - strlen (retp) - 1));
1632 	  break;
1633 	}
1634     }
1635 
1636   /* we have now formatted the new string, with resolution inserted */
1637   char *ccret;
1638   if (add == true)
1639     ccret = add_hwcstring (ret, warnmsg);
1640   else
1641     ccret = set_hwcstring (ret, warnmsg);
1642   free (hwc_defaultx);
1643   free (ret);
1644 
1645   /* now set the clock-profiling timer, if on by default */
1646   if (clkprof_default == 1)
1647     {
1648       if (strcmp (resolution, NTXT ("on")) == 0)
1649 	set_clkprof_timer_target (clk_params.normval);
1650       else if (strcmp (resolution, NTXT ("lo")) == 0)
1651 	set_clkprof_timer_target (clk_params.lowval);
1652       else if (strcmp (resolution, NTXT ("hi")) == 0)
1653 	set_clkprof_timer_target (clk_params.hival);
1654     }
1655   return ccret;
1656 }
1657 
1658 void
set_hwcdefault()1659 Coll_Ctrl::set_hwcdefault ()
1660 {
1661   char *string = hwc_get_default_cntrs2 (kernelHWC, 1);
1662   if (string != NULL)
1663     {
1664       if (strlen (string) == 0)
1665 	hwcprof_default = 0;
1666       else
1667 	{
1668 	  char * warnmsg = NULL;
1669 	  char *ccret = add_hwcstring (string, &warnmsg);
1670 	  if (ccret != NULL)
1671 	    {
1672 #if 0
1673 	      /* set string to zero-length so that it won't be used again */
1674 	      hwc_set_default_cntrs (kernelHWC, NTXT (""));
1675 #endif
1676 	      hwcprof_default = 0;
1677 	    }
1678 	  else
1679 	    hwcprof_default = 1;
1680 	}
1681       free (string);
1682     }
1683   else
1684     hwcprof_default = 0;
1685 }
1686 
1687 void
disable_hwc()1688 Coll_Ctrl::disable_hwc ()
1689 {
1690   hwcprof_enabled_cnt = 0;
1691   hwcprof_default = 0;
1692   free (hwc_string);
1693   hwc_string = NULL;
1694 }
1695 
1696 char *
set_sample_period(const char * string)1697 Coll_Ctrl::set_sample_period (const char *string)
1698 {
1699   int val;
1700   if (opened == 1)
1701     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1702   if (string == NULL || strcmp (string, "on") == 0)
1703     val = 1;
1704   else if (strcmp (string, "off") == 0)
1705     val = 0;
1706   else
1707     {
1708       /* string should be a number > 0 */
1709       char *endchar = NULL;
1710       val = (int) strtol (string, &endchar, 0);
1711       if (*endchar != 0 || val <= 0)
1712 	return dbe_sprintf (GTXT ("Unrecognized sample period `%s'\n"), string);
1713     }
1714   /* set that value */
1715   int prev_sample_period = sample_period;
1716   sample_period = val;
1717   char *ret = check_consistency ();
1718   if (ret != NULL)
1719     {
1720       sample_period = prev_sample_period;
1721       return ret;
1722     }
1723   sample_default = 0;
1724   return NULL;
1725 }
1726 
1727 char *
set_size_limit(const char * string)1728 Coll_Ctrl::set_size_limit (const char *string)
1729 {
1730   if (opened == 1)
1731     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1732   if (string == NULL || strlen (string) == 0
1733       || strcmp (string, "unlimited") == 0 || strcmp (string, "none") == 0)
1734     {
1735       size_limit = 0;
1736       return NULL;
1737     }
1738   /* string should be a number >0; 0 is an error */
1739   char *endchar = NULL;
1740   int val = (int) strtol (string, &endchar, 0);
1741   if (*endchar != 0 || val <= 0)
1742     return dbe_sprintf (GTXT ("Unrecognized size limit `%s'\n"), string);
1743   size_limit = val;
1744   return 0;
1745 }
1746 
1747 void
build_data_desc()1748 Coll_Ctrl::build_data_desc ()
1749 {
1750   StringBuilder sb;
1751 
1752   // Put sample sig before clock profiling. Dbx uses PROF
1753   // for that purpose and we want it to be processed first.
1754   if (project_home)
1755     sb.appendf ("P:%s;", project_home);
1756   if (sample_sig != 0)
1757     sb.appendf ("g:%d;", sample_sig);
1758   if (pauseresume_sig != 0)
1759     sb.appendf ("d:%d%s;", pauseresume_sig, pauseresume_pause == 1 ? "p" : "");
1760   if (clkprof_enabled == 1)
1761     sb.appendf ("p:%d;", clkprof_timer);
1762   if (synctrace_enabled == 1)
1763     sb.appendf ("s:%d,%d;", synctrace_thresh, synctrace_scope);
1764   if (heaptrace_enabled == 1)
1765     sb.appendf ("H:%d;", heaptrace_checkenabled);
1766   if (iotrace_enabled == 1)
1767     sb.append ("i:;");
1768   if (hwcprof_enabled_cnt > 0)
1769     {
1770       sb.appendf ("h:%s", (hwcprof_default == true) ? "*" : "");
1771       for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
1772 	{
1773 	  Hwcentry *h = hwctr + ii;
1774 	  hrtime_t min_time = h->min_time;
1775 	  if (min_time == HWCTIME_TBD)
1776 	    // user did not specify any value for overflow rate
1777 	    min_time = h->min_time_default;
1778 	  if (ii > 0)
1779 	    sb.append (',');
1780 	  sb.appendf ("%d:%d:%lld:%s:%s:%lld:%d:m%lld:%d:%d:0x%x",
1781 		    h->use_perf_event_type, h->type, (long long) h->config,
1782 		    strcmp (h->name, h->int_name) ? h->name : "",
1783 		    h->int_name, (long long) h->reg_num, h->val,
1784 		    (long long) min_time, ii, /*tag*/ h->timecvt, h->memop);
1785 	}
1786       sb.append (";");
1787     }
1788   if (time_run != 0 || start_delay != 0)
1789     {
1790       if (start_delay != 0)
1791 	sb.appendf ("t:%d:%d;", start_delay, time_run);
1792       else
1793 	sb.appendf ("t:%d;", time_run);
1794     }
1795   if (sample_period != 0)
1796     sb.appendf ("S:%d;", sample_period);
1797   if (size_limit != 0)
1798     sb.appendf ("L:%d;", size_limit);
1799   if (java_mode != 0)
1800     sb.appendf ("j:%d;", (int) java_mode);
1801   if (follow_mode != FOLLOW_NONE)
1802     sb.appendf ("F:%d;", (int) follow_mode);
1803   sb.appendf ("a:%s;", archive_mode);
1804   free (data_desc);
1805   data_desc = sb.toString ();
1806 }
1807 
1808 char *
check_group()1809 Coll_Ctrl::check_group ()
1810 {
1811   char group_file[MAXPATHLEN];
1812   if (expt_group == NULL)
1813     return NULL;
1814   // Is the group an relative path, with a store directory set?
1815   if ((expt_group[0] == '/') || ((udir_name == NULL) || (udir_name[0] == '0')))
1816     snprintf (group_file, sizeof (group_file), "%s", expt_group);
1817   else  // relative path, store directory; make group_file in that directory
1818     snprintf (group_file, sizeof (group_file), "%s/%s", udir_name, expt_group);
1819   // See if we can write the group file
1820   int ret = access (group_file, W_OK);
1821   if (ret != 0)
1822     {
1823       if (errno == ENOENT)
1824 	{
1825 	  char *stmp = group_file;
1826 	  char *dir = dirname (stmp);
1827 	  ret = access (dir, W_OK);
1828 	  if (ret != 0) // group file does not exist;
1829 	    return dbe_sprintf (GTXT ("Directory (%s) for group file %s is not writeable: %s\n"),
1830 				dir, group_file, strerror (errno));
1831 	}
1832       else
1833 	return dbe_sprintf (GTXT ("Group file %s is not writeable: %s\n"),
1834 			    group_file, strerror (errno));
1835     }
1836   return NULL;
1837 }
1838 
1839 char *
join_group()1840 Coll_Ctrl::join_group ()
1841 {
1842   int tries = 0;
1843   int groupfd;
1844   FILE *file;
1845   char group_file[MAXPATHLEN];
1846   struct stat statbuf;
1847   struct flock flockbuf;
1848   flockbuf.l_type = F_WRLCK;
1849   flockbuf.l_whence = SEEK_SET;
1850   flockbuf.l_start = 0;
1851   flockbuf.l_len = 0;
1852   if (expt_group == NULL)
1853     return NULL;
1854   // Is the group an relative path, with a store directory set?
1855   if (expt_group[0] == '/' || udir_name == NULL || udir_name[0] == '0')
1856     snprintf (group_file, sizeof (group_file), "%s", expt_group);
1857   else  // relative path, store directory; make group_file in that directory
1858       snprintf (group_file, sizeof (group_file), "%s/%s", udir_name, expt_group);
1859   for (;;)
1860     {
1861       tries++;
1862       // try to open the group file
1863       while ((groupfd = open (group_file, O_RDWR)) >= 0)
1864 	{
1865 	  if (uinterrupt == 1)
1866 	    {
1867 	      close (groupfd);
1868 	      return strdup (GTXT ("user interrupt\n"));
1869 	    }
1870 	  // it's opened, now lock it
1871 	  if (fcntl (groupfd, F_SETLK, &flockbuf) != -1)
1872 	    {
1873 	      // we got the lock; check the file size
1874 	      if (fstat (groupfd, &statbuf) != 0)
1875 		{
1876 		  // can't stat the file -- give up
1877 		  close (groupfd);
1878 		  return dbe_sprintf (GTXT ("Can't fstat group file %s\n"), group_file);
1879 		}
1880 	      if (statbuf.st_size == 0)
1881 		{
1882 		  // size is zero: we got the lock just as someone
1883 		  //   else created the group file
1884 		  //   close the file and release the lock; try again
1885 		  close (groupfd);
1886 		  continue;
1887 		}
1888 	      else
1889 		{
1890 		  // size is non-zero, add our record
1891 		  file = fdopen (groupfd, "a");
1892 		  if (file == NULL)
1893 		    {
1894 		      close (groupfd);
1895 		      return dbe_sprintf (GTXT ("Can't access group file %s\n"), group_file);
1896 		    }
1897 		  if (fprintf (file, "%s\n", store_ptr) <= 0)
1898 		    {
1899 		      fclose (file);
1900 		      return dbe_sprintf (GTXT ("Can't update group file %s\n"), group_file);
1901 		    }
1902 		  // close the file, releasing our lock
1903 		  fclose (file);
1904 		  return NULL;
1905 		}
1906 	    }
1907 	  else
1908 	    {
1909 	      // can't get the lock, close the file and try again
1910 	      close (groupfd);
1911 	      if (uinterrupt == 1)
1912 		return strdup (GTXT ("user interrupt\n"));
1913 	      if (tries == 11900)
1914 		return dbe_sprintf (GTXT ("Timed out: waiting for group file %s\n"), group_file);
1915 #if 0
1916 	      if (tries % 500 == 0)
1917 		USR_WARN (GTXT ("Waiting for group file %s . . ."), group_file);
1918 #endif
1919 	      usleep (10000U);
1920 	      continue;
1921 	    }
1922 	}
1923       // If the error was not that the file did not exist, report it
1924       if (errno != ENOENT)
1925 	return dbe_sprintf (GTXT ("Can't open group file %s: %s\n"),
1926 			    group_file, strerror (errno));
1927       // the file did not exist, try to create it
1928       groupfd = open (group_file, O_CREAT | O_EXCL | O_RDWR, 0666);
1929       if (groupfd < 0)
1930 	{
1931 	  // we could not create the file
1932 	  if (errno == EEXIST)
1933 	    continue;
1934 	  return dbe_sprintf (GTXT ("Can't create group file %s: %s\n"),
1935 			      group_file, strerror (errno));
1936 	}
1937       // we created the group file, now lock it, waiting for the lock
1938       while (fcntl (groupfd, F_SETLKW, &flockbuf) == -1)
1939 	{
1940 	  // we created the file, but couldn't lock it
1941 	  if (errno != EINTR)
1942 	    return dbe_sprintf (GTXT ("Unable to lock group file %s\n"), group_file);
1943 	}
1944       // we created and locked the file, write to it
1945       file = fdopen (groupfd, "a");
1946       if (file == NULL)
1947 	{
1948 	  close (groupfd);
1949 	  return dbe_sprintf (GTXT ("Can't access group file %s\n"), group_file);
1950 	}
1951       // write the header line
1952       if (fprintf (file, "%s\n", SP_GROUP_HEADER) <= 0)
1953 	{
1954 	  fclose (file);
1955 	  return dbe_sprintf (GTXT ("Can't initialize group file %s\n"), group_file);
1956 	}
1957       if (fprintf (file, "%s\n", store_ptr) <= 0)
1958 	{
1959 	  fclose (file);
1960 	  return dbe_sprintf (GTXT ("Can't update group file %s\n"), group_file);
1961 	}
1962       // finally, close the file, releasing the lock
1963       fclose (file);
1964       return NULL;
1965     }
1966   // never reached
1967 }
1968 
1969 char *
set_directory(char * dir,char ** warn)1970 Coll_Ctrl::set_directory (char *dir, char **warn)
1971 {
1972   struct stat statbuf;
1973   *warn = NULL;
1974   if (opened == 1)
1975     return strdup (GTXT ("Experiment is active; command ignored.\n"));
1976   if (stat (dir, &statbuf) != 0)
1977     return dbe_sprintf (GTXT ("Can't set directory `%s': %s\n"),
1978 			dir, strerror (errno));
1979   if (!S_ISDIR (statbuf.st_mode))
1980     return dbe_sprintf (GTXT ("Can't set directory `%s': %s\n"),
1981 			dir, strerror (ENOTDIR));
1982   free (udir_name);
1983   udir_name = strdup (dir);
1984 
1985   // Process new setting
1986   *warn = preprocess_names ();
1987   if ((uexpt_name != NULL) || (interactive != 0))
1988     {
1989       char *ret = update_expt_name (true, true);
1990       if (ret != NULL)
1991 	{
1992 	  if (*warn != NULL)
1993 	    {
1994 	      char *msg = dbe_sprintf ("%s%s", *warn, ret);
1995 	      free (*warn);
1996 	      free (ret);
1997 	      *warn = msg;
1998 	    }
1999 	  else
2000 	    *warn = ret;
2001 	}
2002     }
2003   else
2004     (void) update_expt_name (false, false);
2005   return NULL;      // All is OK
2006 }
2007 
2008 int
set_target(char * targetname)2009 Coll_Ctrl::set_target (char* targetname)
2010 {
2011   free (target_name);
2012   target_name = NULL;
2013   if (targetname != NULL)
2014     target_name = strdup (targetname);
2015   return 0;
2016 }
2017 
2018 void
set_default_stem(const char * stem)2019 Coll_Ctrl::set_default_stem (const char* stem)
2020 {
2021   default_stem = strdup (stem);
2022   preprocess_names ();
2023   (void) update_expt_name (false, false); // no warnings
2024 }
2025 
2026 char *
set_expt(const char * ename,char ** warn,bool overwriteExp)2027 Coll_Ctrl::set_expt (const char *ename, char **warn, bool overwriteExp)
2028 {
2029   *warn = NULL;
2030   if (ename == NULL)
2031     {
2032       free (uexpt_name);
2033       uexpt_name = NULL;
2034       return NULL;
2035     }
2036   char *exptname = canonical_path(strdup(ename));
2037   size_t i = strlen (exptname);
2038   if (i < 4 || strcmp (&exptname[i - 3], ".er") != 0)
2039     {
2040       free (exptname);
2041       return dbe_sprintf (GTXT ("Experiment name `%s' must end in `.er'\n"),
2042 			  ename);
2043     }
2044   // Name is OK
2045   free (uexpt_name);
2046   uexpt_name = exptname;
2047   preprocess_names ();
2048   char *err = update_expt_name (true, true, overwriteExp);
2049   if (err != NULL)
2050     return err;
2051   if (overwriteExp)
2052     {
2053       char *nm = dbe_sprintf ("%s/%s", store_dir, base_name);
2054       struct stat statbuf;
2055       char *cmd = dbe_sprintf ("/bin/rm -rf %s >/dev/null 2>&1", nm);
2056       system (cmd);
2057       free (cmd);
2058       if (stat (nm, &statbuf) == 0)
2059 	return dbe_sprintf (GTXT ("Cannot remove experiment `%s'\n"), nm);
2060       if (errno != ENOENT)
2061 	return dbe_sprintf (GTXT ("Cannot remove experiment `%s'\n"), nm);
2062       free (nm);
2063     }
2064   *warn = update_expt_name (true, false);
2065   return NULL;
2066 }
2067 
2068 char *
set_group(char * groupname)2069 Coll_Ctrl::set_group (char *groupname)
2070 {
2071   if (opened == 1)
2072     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2073   if (expt_group != NULL)
2074     {
2075       free (expt_group);
2076       expt_group = NULL;
2077     }
2078   if (groupname == NULL)
2079     {
2080       // reset the name
2081       preprocess_names ();
2082       (void) update_expt_name (true, false);
2083       return NULL;
2084     }
2085   int i = (int) strlen (groupname);
2086   if (i < 5 || strcmp (&groupname[i - 4], ".erg") != 0)
2087     return dbe_sprintf (GTXT ("Experiment group name `%s'must end in `.erg'\n"), groupname);
2088   expt_group = strdup (groupname);
2089   preprocess_names ();
2090   (void) update_expt_name (true, false);
2091   return NULL;
2092 }
2093 
2094 char *
set_java_mode(const char * string)2095 Coll_Ctrl::set_java_mode (const char *string)
2096 {
2097   struct stat statbuf;
2098   if (opened == 1)
2099     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2100   if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
2101     {
2102 #if defined(GPROFNG_JAVA_PROFILING)
2103       int prev_java_mode = java_mode;
2104       int prev_java_default = java_default;
2105       java_mode = 1;
2106       java_default = 0;
2107       char *ret = check_consistency ();
2108       if (ret != NULL)
2109 	{
2110 	  java_mode = prev_java_mode;
2111 	  java_default = prev_java_default;
2112 	  return ret;
2113 	}
2114       return NULL;
2115 #else
2116       return strdup (GTXT ("gprofng was built without support for profiling Java applications\n"));
2117 #endif
2118     }
2119   if (strcmp (string, "off") == 0)
2120     {
2121       int prev_java_mode = java_mode;
2122       int prev_java_default = java_default;
2123       java_mode = 0;
2124       java_default = 0;
2125       char *ret = check_consistency ();
2126       if (ret != NULL)
2127 	{
2128 	  java_mode = prev_java_mode;
2129 	  java_default = prev_java_default;
2130 	  return ret;
2131 	}
2132 	free (java_path);
2133       java_path = NULL;
2134       return NULL;
2135     }
2136   /* any other value should be a path to Java installation directory */
2137   if (stat (string, &statbuf) == 0)
2138     {
2139       if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
2140 	{
2141 	  // it's a directory -- set the Java path to it
2142 	  int prev_java_mode = java_mode;
2143 	  int prev_java_default = java_default;
2144 	  java_mode = 1;
2145 	  java_default = 0;
2146 	  char *ret = check_consistency ();
2147 	  if (ret != NULL)
2148 	    {
2149 	      java_mode = prev_java_mode;
2150 	      java_default = prev_java_default;
2151 	      return ret;
2152 	    }
2153 	  return set_java_path (string);
2154 	}
2155     }
2156   return dbe_sprintf (GTXT ("Java-profiling parameter is neither \"on\", nor \"off\", nor is it a directory: `%s'\n"), string);
2157 }
2158 
2159 char *
set_java_path(const char * string)2160 Coll_Ctrl::set_java_path (const char *string)
2161 {
2162   if (opened == 1)
2163     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2164   free (java_path);
2165   java_path = strdup (string);
2166   return NULL;
2167 }
2168 
2169 char *
set_java_args(char * string)2170 Coll_Ctrl::set_java_args (char *string)
2171 {
2172   char *next;
2173   if (opened == 1)
2174     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2175   char *prev_java_args = java_args;
2176   if (string == NULL || strlen (string) == 0)
2177     java_args = strdup ("");
2178   else
2179     java_args = strdup (string);
2180   // now count the number of Java arguments
2181   for (next = java_args; *next; next++)
2182     {
2183       if (*next == ' ' || *next == '\t')
2184 	continue;
2185       njava_args++;
2186       for (++next; *next; next++)
2187 	if (*next == ' ' || *next == '\t')
2188 	  break;
2189       if (!*next)
2190 	break;
2191     }
2192   if (njava_args == 0)
2193     java_args = NULL;
2194   char *ret = check_consistency ();
2195   if (ret != NULL)
2196     {
2197       java_args = prev_java_args;
2198       return ret;
2199     }
2200   free (prev_java_args);
2201   return NULL;
2202 }
2203 
2204 char *
set_follow_mode(const char * string)2205 Coll_Ctrl::set_follow_mode (const char *string)
2206 {
2207   if (opened == 1)
2208     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2209   free (follow_spec_usr);
2210   free (follow_spec_cmp);
2211   follow_spec_usr = NULL;
2212   follow_spec_cmp = NULL;
2213   if (string == NULL || strlen (string) == 0 || strcmp (string, "all") == 0
2214       || strcmp (string, "on") == 0)
2215     {
2216       follow_mode = FOLLOW_ON;
2217       follow_default = 0;
2218       return NULL;
2219     }
2220   if (strcmp (string, "off") == 0)
2221     {
2222       follow_mode = FOLLOW_NONE;
2223       follow_default = 0;
2224       return NULL;
2225     }
2226 
2227   /* compile regular expression if string starts with "=" */
2228   if (string[0] == '=' && string[1] != 0)
2229     {
2230       // user has specified a string matching specification
2231       regex_t regex_desc;
2232       int ercode;
2233       const char *userspec = &string[1];
2234       size_t newstrlen = strlen (userspec) + 3;
2235       char * str = (char *) malloc (newstrlen);
2236       if (str)
2237 	{
2238 	  snprintf (str, newstrlen, "^%s$", userspec);
2239 	  assert (strlen (str) == newstrlen - 1);
2240 	  ercode = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
2241 	}
2242       else
2243 	ercode = 1;
2244       if (!ercode)
2245 	{
2246 	  follow_spec_usr = strdup (string);
2247 	  /* Ideally, follow_spec_cmp = [serialized regex_desc], */
2248 	  /* so that libcollector wouldn't have to recompile it. */
2249 	  /* For now, just copy the regular expression into follow_spec_cmp */
2250 	  follow_spec_cmp = str;
2251 	  follow_mode = FOLLOW_ALL;
2252 	  follow_default = 0;
2253 	  return NULL;
2254 	}
2255       // syntax error in parsing string
2256 #if 0
2257       char errbuf[256];
2258       regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
2259       fprintf (stderr, "Coll_Ctrl::set_follow_mode: regerror()=%s\n", errbuf);
2260 #endif
2261       free (str);
2262     }
2263   return dbe_sprintf (GTXT ("Unrecognized follow-mode parameter `%s'\n"), string);
2264 }
2265 
2266 char *
set_prof_idle(const char * string)2267 Coll_Ctrl::set_prof_idle (const char *string)
2268 {
2269   if (opened == 1)
2270     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2271   if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
2272     {
2273       prof_idle = 1;
2274       return NULL;
2275     }
2276   if (strcmp (string, "off") == 0)
2277     {
2278       prof_idle = 0;
2279       return NULL;
2280     }
2281   return dbe_sprintf (GTXT ("Unrecognized profiling idle cpus parameter `%s'\n"), string);
2282 }
2283 
2284 char *
set_archive_mode(const char * string)2285 Coll_Ctrl::set_archive_mode (const char *string)
2286 {
2287   if (opened == 1)
2288     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2289   if (string == NULL || strlen (string) == 0)
2290     string = "on";
2291   if (strcasecmp (string, "on") == 0 || strcasecmp (string, "off") == 0
2292       || strcasecmp (string, "ldobjects") == 0
2293       || strcasecmp (string, "usedldobjects") == 0
2294       || strcasecmp (string, "src") == 0 || strcasecmp (string, "usedsrc") == 0
2295       || strcasecmp (string, "all") == 0)
2296     {
2297       free (archive_mode);
2298       archive_mode = strdup (string);
2299       return NULL;
2300     }
2301   return dbe_sprintf (GTXT ("Unrecognized archive-mode parameter `%s'\n"), string);
2302 }
2303 
2304 char *
set_sample_signal(int value)2305 Coll_Ctrl::set_sample_signal (int value)
2306 {
2307   const char *buf;
2308   if (opened == 1)
2309     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2310   if (value == 0)
2311     {
2312       sample_sig = 0;
2313       return NULL;
2314     }
2315   if (value == pauseresume_sig)
2316     return report_signal_conflict (value);
2317   if ((buf = strsignal (value)) != NULL)
2318     sample_sig = value;
2319   else
2320     return dbe_sprintf (GTXT ("Invalid sample signal %d\n"), value);
2321   return NULL;
2322 }
2323 
2324 /* find a signal by name */
2325 int
find_sig(const char * string)2326 Coll_Ctrl::find_sig (const char *string)
2327 {
2328   int val;
2329   char *signame_alloc = NULL;
2330   const char *signame;
2331   val = -1;
2332   if (strcmp (string, "off") == 0)
2333     return 0;
2334   // see if the name begins with SIG
2335   if (strncmp (string, "SIG", 3) != 0)
2336     {
2337       // no: add it
2338       signame_alloc = (char *) malloc (strlen (string) + 3 + 1);
2339       if (signame_alloc == NULL)
2340 	return -1;
2341       strcpy (signame_alloc, "SIG");
2342       strcpy (&signame_alloc[3], string);
2343       signame = signame_alloc;
2344     }
2345   else
2346     signame = string;
2347 
2348   /* see if the string is a number */
2349   char *endchar = NULL;
2350   val = (int) strtol (signame, &endchar, 0);
2351   if (*endchar != 0)
2352     val = strtosigno (signame);
2353   free (signame_alloc);
2354   if (val == SIGKILL)
2355     return -1;
2356   return val;
2357 }
2358 
2359 char *
set_pauseresume_signal(int value,int resume)2360 Coll_Ctrl::set_pauseresume_signal (int value, int resume)
2361 {
2362   if (opened == 1)
2363     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2364   if (value == 0)
2365     {
2366       pauseresume_sig = 0;
2367       return NULL;
2368     }
2369   if (value == sample_sig)
2370     return report_signal_conflict (value);
2371   if (strsignal (value) != NULL)
2372     {
2373       pauseresume_sig = value;
2374       pauseresume_pause = resume;
2375     }
2376   else
2377     return dbe_sprintf (GTXT ("Invalid pause-resume (delayed initialization) signal %d\n"), value);
2378   return NULL;
2379 }
2380 
2381 char *
report_signal_conflict(int value)2382 Coll_Ctrl::report_signal_conflict (int value)
2383 {
2384   const char *xbuf = strsignal (value);
2385   if (xbuf != NULL)
2386     return dbe_sprintf (GTXT ("Signal %s (%d) can not be used for both sample and pause-resume (delayed initialization)\n"),
2387 			xbuf, value);
2388   return dbe_sprintf (GTXT ("Signal %d can not be used for both sample and pause-resume (delayed initialization)\n"),
2389 		      value);
2390 }
2391 
2392 char *
set_debug_mode(int value)2393 Coll_Ctrl::set_debug_mode (int value)
2394 {
2395   if (opened == 1)
2396     return strdup (GTXT ("Experiment is active; command ignored.\n"));
2397   debug_mode = value;
2398   return NULL;
2399 }
2400 
2401 char *
create_exp_dir()2402 Coll_Ctrl::create_exp_dir ()
2403 {
2404   int max = 4095; // 0xFFF - can be increased if it seems too low
2405   for (int i = 0; i < max; i++)
2406     {
2407       if (mkdir (store_ptr,
2408 		 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0)
2409 	{
2410 	  int err = errno;
2411 	  if (err == EACCES)
2412 	    return dbe_sprintf (GTXT ("Store directory %s is not writeable: %s\n"),
2413 				store_dir, strerror (err));
2414 	  if (i + 1 >= max) // no more attempts
2415 	    return dbe_sprintf (GTXT ("Unable to create directory `%s' -- %s\n%s: %d\n"),
2416 				store_ptr, strerror (err),
2417 				GTXT ("collect: Internal error: loop count achieved"),
2418 				max);
2419 	  char *ermsg = update_expt_name (false, false, true);
2420 	  if (ermsg != NULL)
2421 	    {
2422 	      char *msg = dbe_sprintf (GTXT ("Unable to create directory `%s' -- %s\n"),
2423 				       store_ptr, ermsg);
2424 	      free (ermsg);
2425 	      return msg;
2426 	    }
2427 	  continue;
2428 	}
2429       return NULL;  // All is OK
2430     }
2431   return dbe_sprintf (GTXT ("Unable to create directory `%s'\n"), store_ptr);
2432 }
2433 
2434 char *
get_exp_name(const char * stembase)2435 Coll_Ctrl::get_exp_name (const char *stembase)
2436 {
2437   expno = 1;
2438   return dbe_sprintf ("%s.%d.er", stembase, expno);
2439 }
2440 
2441 char *
preprocess_names()2442 Coll_Ctrl::preprocess_names ()
2443 {
2444   char buf[MAXPATHLEN];
2445   char msgbuf[MAXPATHLEN];
2446   char *ret = NULL;
2447 
2448   /* convert the experiment name and directory into store name/dir */
2449   /* free the old strings */
2450   if (store_dir != NULL)
2451     {
2452       free (store_dir);
2453       store_dir = NULL;
2454     }
2455   if (expt_dir != NULL)
2456     {
2457       free (expt_dir);
2458       expt_dir = NULL;
2459     }
2460   if (base_name != NULL)
2461     {
2462       free (base_name);
2463       base_name = NULL;
2464     }
2465   if (expt_name != NULL)
2466     {
2467       free (expt_name);
2468       expt_name = NULL;
2469     }
2470   expno = 1;
2471   if (uexpt_name != NULL)
2472     expt_name = strdup (uexpt_name);
2473   else
2474     {
2475       // no user name -- pick a default
2476       char *c;
2477       char *stem;
2478       char *stembase;
2479       if (expt_group == NULL)
2480 	{
2481 	  stem = strdup (default_stem);
2482 	  stembase = stem;
2483 	}
2484       else
2485 	{
2486 	  stem = strdup (expt_group);
2487 	  stem[strlen (stem) - 4] = 0;
2488 	  stembase = stem;
2489 	  // now remove any leading directory
2490 	  for (int i = 0;; i++)
2491 	    {
2492 	      if (stem[i] == 0)
2493 		break;
2494 	      if (stem[i] == '/')
2495 		stembase = &stem[i + 1];
2496 	    }
2497 	  if (strlen (stembase) == 0)
2498 	    {
2499 	      free (stem);
2500 	      stem = strdup (default_stem);
2501 	      stembase = stem;
2502 	    }
2503 	}
2504       c = get_exp_name (stembase);
2505       expt_name = c;
2506       free (stem);
2507     }
2508   snprintf (buf, sizeof (buf), NTXT ("%s"), expt_name);
2509   if (buf[0] == '/')
2510     {
2511       // it's a full path name
2512       if (udir_name != NULL)
2513 	{
2514 	  snprintf (msgbuf, sizeof (msgbuf),
2515 		    GTXT ("Warning: Experiment name is an absolute path; directory name %s ignored.\n"),
2516 		    udir_name);
2517 	  ret = strdup (msgbuf);
2518 	}
2519     }
2520 
2521   // now extract the directory and basename
2522   int lastslash = 0;
2523   for (int i = 0;; i++)
2524     {
2525       if (buf[i] == 0)
2526 	break;
2527       if (buf[i] == '/')
2528 	lastslash = i;
2529     }
2530   expt_dir = strdup (buf);
2531   if (lastslash != 0)
2532     base_name = strdup (&buf[lastslash + 1]);
2533   else
2534     base_name = strdup (buf);
2535   expt_dir[lastslash] = 0;
2536   if (expt_dir[0] == '/')
2537     store_dir = strdup (expt_dir);
2538   else if ((udir_name == NULL) || (udir_name[0] == 0))
2539     {
2540       if (expt_dir[0] == 0)
2541 	store_dir = strdup (".");
2542       else
2543 	store_dir = strdup (expt_dir);
2544     }
2545   else
2546     {
2547       /* udir_name is a non-empty string */
2548       if (expt_dir[0] == 0)
2549 	store_dir = strdup (udir_name);
2550       else
2551 	{
2552 	  snprintf (buf, sizeof (buf), "%s/%s", udir_name, expt_dir);
2553 	  store_dir = strdup (buf);
2554 	}
2555     }
2556   free (store_ptr);
2557   if (strcmp (store_dir, ".") == 0)
2558     store_ptr = strdup (base_name);
2559   else
2560     {
2561       snprintf (buf, sizeof (buf), "%s/%s", store_dir, base_name);
2562       store_ptr = strdup (buf);
2563     }
2564 
2565   // determine the file system type
2566   if (strcmp (store_dir, prev_store_dir) != 0)
2567     {
2568       free (prev_store_dir);
2569       prev_store_dir = strdup (store_dir);
2570       const char *fstype = get_fstype (store_dir);
2571       if (interactive && enabled && (fstype != NULL) && (nofswarn == 0))
2572 	{
2573 	  snprintf (msgbuf, sizeof (msgbuf),
2574 		    GTXT ("%sExperiment directory is set to a file system of type \"%s\",\n  which may distort the measured performance;\n  it is preferable to record to a local disk.\n"),
2575 		    (ret == NULL ? "" : ret), fstype);
2576 	  free (ret);
2577 	  ret = strdup (msgbuf);
2578 	}
2579     }
2580   return ret;
2581 }
2582 
2583 char *
update_expt_name(bool chgmsg,bool chkonly,bool newname)2584 Coll_Ctrl::update_expt_name (bool chgmsg, bool chkonly, bool newname)
2585 {
2586   char *ret = NULL;
2587   struct stat statbuf;
2588   // make sure the name ends in .er
2589   // set count to the length of the name
2590   int count = (int) strlen (base_name);
2591 
2592   // this should have been checked already, so we can abort
2593   if (count < 4 || strcmp (&base_name[count - 3], ".er") != 0)
2594     abort ();
2595   int pcount = count - 4;
2596   if (!newname)
2597     { // check if old name can be used
2598       char fullname[MAXPATHLEN];
2599       snprintf (fullname, sizeof (fullname), "%s/%s", store_dir, base_name);
2600       if (stat (fullname, &statbuf) != 0)
2601 	if (errno == ENOENT) // name does not exist, we can use it
2602 	  return NULL;
2603     }
2604   else if (chkonly)
2605     return NULL;
2606 
2607   // current name will not work, update the name
2608   DIR *dir;
2609   struct dirent *dir_entry;
2610 
2611   // see if there's a numeric field in front of the .er of the name
2612   int digits = 0;
2613   while (isdigit ((int) (base_name[pcount])) != 0)
2614     {
2615       pcount--;
2616       if (pcount == 0)  // name is of the form 12345.er; don't update it
2617 	return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
2618 			    base_name);
2619       digits++;
2620     }
2621   if (digits == 0)  // name is of form xyz.er (or xyz..er); don't update it
2622     return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
2623 			base_name);
2624   if (base_name[pcount] != '.')   // name is of form xyz123.er; don't update it
2625     return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
2626 			base_name);
2627   if (chkonly)
2628     return NULL;
2629 
2630   // save the name for a changed message
2631   char *oldbase = strdup (base_name);
2632 
2633   // the name is of the from prefix.nnn.er; extract the value of nnn
2634   int version = atoi (&base_name[pcount + 1]);
2635   if (newname)  // do not try to use old name
2636     version++;
2637   int max_version = version - 1;
2638 
2639   // terminate the base_name string after that . yielding "prefix."
2640   base_name[pcount + 1] = 0;
2641   if ((dir = opendir (store_dir)) == NULL)
2642     {
2643       // ignore error -- we'll hit it again later
2644       free (oldbase);
2645       return NULL;
2646     }
2647 
2648   // find the maximum version in the directory
2649   // count is the number of characters before the number
2650   //
2651   while ((dir_entry = readdir (dir)) != NULL)
2652     {
2653       count = (int) strlen (dir_entry->d_name);
2654       if ((count < 4) || (strcmp (&dir_entry->d_name[count - 3], ".er") != 0))
2655 	continue;
2656       // check that the name is of the form prefix.nnn.er; if not, skip it
2657       if (strncmp (base_name, dir_entry->d_name, pcount + 1) == 0)
2658 	{
2659 	  // the "prefix." part matches, terminate the entry name before the .er
2660 	  dir_entry->d_name[count - 3] = 0;
2661 	  char *lastchar;
2662 	  int dversion = (int) strtol (&dir_entry->d_name[pcount + 1], &lastchar, 10);
2663 
2664 	  // if it did not end where the .er was, skip it
2665 	  if (*lastchar != 0)
2666 	    continue;
2667 	  if (dversion > max_version)
2668 	    max_version = dversion;
2669 	}
2670     }
2671 
2672   // we now have the maximum version determined
2673   char newbase[MAXPATHLEN];
2674   base_name[pcount + 1] = 0;
2675   version = max_version + 1;
2676   snprintf (newbase, sizeof (newbase), "%s%d.er", base_name, version);
2677   if ((strcmp (oldbase, newbase) != 0) && chgmsg)
2678     {
2679       ret = dbe_sprintf (GTXT ("name %s is in use; changed to %s\n"),
2680 		oldbase, newbase);
2681       free (oldbase);
2682     }
2683   else
2684     free (oldbase);
2685   free (base_name);
2686   base_name = strdup (newbase);
2687 
2688   // now, reset expt_name to reflect new setting
2689   free (expt_name);
2690   if (expt_dir[0] == 0)
2691     expt_name = strdup (base_name);
2692   else
2693     expt_name = dbe_sprintf ("%s/%s", expt_dir, base_name);
2694   free (store_ptr);
2695   if (strcmp (store_dir, ".") == 0)
2696     store_ptr = strdup (base_name);
2697   else
2698     store_ptr = dbe_sprintf ("%s/%s", store_dir, base_name);
2699   closedir (dir);
2700   return ret;
2701 }
2702 
2703 void
remove_exp_dir()2704 Coll_Ctrl::remove_exp_dir ()
2705 {
2706   if (store_ptr == NULL)
2707     return;
2708   rmdir (store_ptr);
2709   free (store_ptr);
2710   store_ptr = NULL;
2711   return;
2712 }
2713 
2714 void
determine_profile_params()2715 Coll_Ctrl::determine_profile_params ()
2716 {
2717   struct itimerval itimer;
2718   struct itimerval otimer;
2719   int period;
2720   long nperiod;
2721   struct sigaction act;
2722   struct sigaction old_handler;
2723   memset (&act, 0, sizeof (struct sigaction));
2724   period = 997;
2725 
2726   // set SIGPROF handler to SIG_IGN
2727   sigemptyset (&act.sa_mask);
2728   act.sa_handler = SIG_IGN;
2729   act.sa_flags = SA_RESTART | SA_SIGINFO;
2730   if (sigaction (SIGPROF, &act, &old_handler) == -1)
2731     {
2732       /* couldn't set signal */
2733       fprintf (stderr, GTXT ("Can't set SIGPROF: %s\n"), strerror (errno));
2734       exit (1);
2735     }
2736 
2737   // set the timer to arbitrary resolution
2738   itimer.it_interval.tv_sec = period / MICROSEC;
2739   itimer.it_interval.tv_usec = period % MICROSEC;
2740   itimer.it_value = itimer.it_interval;
2741   setitimer (ITIMER_REALPROF, &itimer, &otimer);
2742 
2743   // now reset the timer to turn it off
2744   itimer.it_value.tv_sec = 0;
2745   itimer.it_value.tv_usec = 0;
2746   if (setitimer (ITIMER_REALPROF, &itimer, &otimer) == -1)  // call failed
2747     nperiod = -1;
2748   else
2749     nperiod = otimer.it_interval.tv_sec * MICROSEC + otimer.it_interval.tv_usec;
2750 
2751   // check the returned value: is the what we asked for?
2752   if (period == nperiod)    // arbitrary precision is OK
2753     set_clk_params (PROFINT_MIN, 1, PROFINT_MAX, PROFINT_HIGH, PROFINT_NORM, PROFINT_LOW);
2754   else if (nperiod < 10000) // hi resolution allowed, but not arbitrary precision
2755     set_clk_params ((int) nperiod, 1000, PROFINT_MAX, 1000, 10000, 100000);
2756   else      // low resolution only allowed
2757     set_clk_params (10000, 10000, PROFINT_MAX, 1000, 10000, 100000);
2758 
2759   // If old handler was default, ignore it; otherwise restore it
2760   if (old_handler.sa_handler != SIG_DFL)
2761     {
2762       act.sa_handler = old_handler.sa_handler;
2763       if (sigaction (SIGPROF, &act, &old_handler) == -1)
2764 	{
2765 	  /* couldn't reset signal */
2766 	  fprintf (stderr, GTXT ("Can't reset SIGPROF: %s\n"), strerror (errno));
2767 	  exit (1);
2768 	}
2769     }
2770 }
2771 
2772 const char *
get_fstype(char *)2773 get_fstype (char *)
2774 {
2775   /* On Linux, statvfs() doesn't return any information that seems to indicate
2776      the filetype. The structure statvfs does not have any field/flag that
2777      gives this information. Comparing the fields from
2778      /usr/include/bits/statvfs.h:
2779 	      unsigned long int f_fsid;
2780 	      int __f_unused;
2781 	      ^^^^ On Solaris, this is where f_basetype is
2782 	      unsigned long int f_flag;
2783 	      unsigned long int f_namemax;
2784 	      XXX Need to revisit this XXX
2785    */
2786   return NULL; // no NFS warning on Linux for now
2787 }
2788 
2789 //========== Special functions to communicate with the Collector GUI ==========//
2790 
2791 /* Interface strings GUI <-> CLI */
2792 const char *ipc_str_exp_limit = "exp_limit";
2793 const char *ipc_str_time_limit = "time_limit";
2794 const char *ipc_str_arch_exp = "arch_exp";
2795 const char *ipc_str_descendant = "descendant";
2796 const char *ipc_str_clkprof = "clkprof";
2797 const char *ipc_str_hwcprof = "hwcprof";
2798 const char *ipc_str_hwc2_prof = "hwc2_prof";
2799 const char *ipc_str_javaprof = "javaprof";
2800 const char *ipc_str_sample = "sample";
2801 const char *ipc_str_sample_sig = "sample_sig";
2802 const char *ipc_str_pause_resume_sig = "pause_resume_sig";
2803 const char *ipc_str_synctrace = "synctrace";
2804 const char *ipc_str_heaptrace = "heaptrace";
2805 const char *ipc_str_iotrace = "iotrace";
2806 const char *ipc_str_count = "count";
2807 const char *ipc_str_prof_idle = "prof_idle";    // -x option
2808 // Standard answers
2809 const char *ipc_str_empty = "";
2810 const char *ipc_str_on = "on";
2811 const char *ipc_str_off = "off";
2812 const char *ipc_str_src = "src";
2813 const char *ipc_str_usedsrc = "usedsrc";
2814 const char *ipc_str_usedldobjects = "usedldobjects";
2815 const char *ipc_str_unlimited = "unlimited";
2816 const char *ipc_str_unknown_control = "Unknown control";
2817 const char *ipc_str_internal_error = "Internal error";
2818 
2819 /**
2820  * Finds signal name
2821  * @param signal
2822  * @return NULL or signal name (pointer to allocated memory)
2823  */
2824 char *
find_signal_name(int signal)2825 Coll_Ctrl::find_signal_name (int signal)
2826 {
2827   char *str_signal = NULL;
2828   const char *buf = strsignal (signal);
2829   if (buf != NULL)
2830     str_signal = strdup (buf);
2831   return str_signal;
2832 }
2833 
2834 /**
2835  * Gets control's value
2836  * @param control
2837  * @return value
2838  */
2839 char *
get(char * control)2840 Coll_Ctrl::get (char * control)
2841 {
2842   int len = strlen (control);
2843   if (!strncmp (control, ipc_str_exp_limit, len))
2844     {
2845       if ((size_limit > 0))
2846 	return dbe_sprintf ("%d", size_limit);
2847       return strdup (ipc_str_unlimited);
2848     }
2849   if (!strncmp (control, ipc_str_time_limit, len))
2850     {
2851       if ((time_run != 0) || (start_delay != 0))
2852 	{
2853 	  if (start_delay != 0)
2854 	    {
2855 	      if (time_run != 0)
2856 		return dbe_sprintf ("%ds-%ds", start_delay, start_delay + time_run);
2857 	      return dbe_sprintf ("%ds-0s", start_delay);
2858 	    }
2859 	  return dbe_sprintf ("0s-%ds", time_run);
2860 	}
2861       return strdup (ipc_str_unlimited);
2862     }
2863   if (strncmp (control, ipc_str_arch_exp, len) == 0)
2864     return strdup (get_archive_mode ());
2865   if (!strncmp (control, ipc_str_descendant, len))
2866     {
2867       switch (get_follow_mode ())
2868 	{
2869 	case FOLLOW_ON:
2870 	  return strdup (ipc_str_on);
2871 	case FOLLOW_ALL:
2872 	  return strdup (ipc_str_on);
2873 	case FOLLOW_NONE:
2874 	default:
2875 	  return strdup (ipc_str_off);
2876 	}
2877     }
2878   if (!strncmp (control, ipc_str_prof_idle, len))
2879     {
2880       if (prof_idle == 0)
2881 	return strdup (ipc_str_off);
2882       return strdup (ipc_str_on);
2883     }
2884   if (!strncmp (control, ipc_str_clkprof, len))
2885     {
2886       if (clkprof_default == 1 && clkprof_enabled == 1)     // Default value
2887 	return strdup (ipc_str_empty);
2888       if (clkprof_enabled == 0)
2889 	return strdup (ipc_str_off);
2890       if ((clkprof_timer > 0))
2891 	return dbe_sprintf ("%d", clkprof_timer / 1000);
2892       return strdup (ipc_str_internal_error);
2893     }
2894   if (!strncmp (control, ipc_str_hwcprof, len))
2895     {
2896       if (hwcprof_enabled_cnt == 0)
2897 	return strdup (ipc_str_off);
2898       if (hwc_string != NULL)
2899 	return dbe_sprintf ("on\n%s", hwc_string);
2900       return strdup (ipc_str_on); // XXX need more details?
2901     }
2902   if (!strncmp (control, ipc_str_javaprof, len))
2903     {
2904       if ((java_mode == 0))
2905 	return strdup (ipc_str_off);
2906       return strdup (ipc_str_on);
2907     }
2908   if (!strncmp (control, ipc_str_sample, len))
2909     {
2910       if (sample_default == 1 && sample_period == 1)    // Default value
2911 	return strdup (ipc_str_empty);
2912       if (sample_period == 0)
2913 	return strdup (ipc_str_off);
2914       if (sample_period > 0)
2915 	return dbe_sprintf ("%d", sample_period);
2916       return strdup (ipc_str_internal_error);
2917     }
2918   if (!strncmp (control, ipc_str_sample_sig, len))
2919     {
2920       if ((sample_sig == 0))
2921 	return strdup (ipc_str_off);
2922       char *str_signal = find_signal_name (sample_sig);
2923       if (str_signal != NULL)
2924 	return str_signal;
2925       return dbe_sprintf (GTXT ("Invalid sample signal %d\n"), sample_sig);
2926     }
2927   if (!strncmp (control, ipc_str_pause_resume_sig, len))
2928     {
2929       if (pauseresume_sig == 0)
2930 	return strdup (ipc_str_off);
2931       char *str_signal = find_signal_name (pauseresume_sig);
2932       if (str_signal != NULL)
2933 	return str_signal;
2934       return dbe_sprintf (GTXT ("Invalid pause/resume signal %d\n"), pauseresume_sig);
2935     }
2936   if (!strncmp (control, ipc_str_synctrace, len))
2937     {
2938       if (synctrace_enabled == 0)
2939 	return strdup (ipc_str_off);
2940       if (synctrace_thresh < 0)
2941 	return strdup ("on\nthreshold: calibrate");
2942       if (synctrace_thresh == 0)
2943 	return strdup ("on\nthreshold: all");
2944       return dbe_sprintf ("on\nthreshold: %d", synctrace_thresh);
2945     }
2946   if (!strncmp (control, ipc_str_heaptrace, len))
2947     {
2948       if ((heaptrace_enabled == 0))
2949 	return strdup (ipc_str_off);
2950       return strdup (ipc_str_on);
2951     }
2952   if (!strncmp (control, ipc_str_iotrace, len))
2953     {
2954       if ((iotrace_enabled == 0))
2955 	return strdup (ipc_str_off);
2956       return strdup (ipc_str_on);
2957     }
2958   if (!strncmp (control, ipc_str_count, len))
2959     {
2960       if ((count_enabled == 0))
2961 	return strdup (ipc_str_off);
2962       if ((count_enabled < 0))
2963 	return strdup ("on\nstatic");
2964       return strdup (ipc_str_on);
2965     }
2966   return strdup (ipc_str_unknown_control);
2967 }
2968 
2969 /**
2970  * Resets control's value (restores the default value)
2971  * @param control
2972  * @param value
2973  * @return error or warning or NULL (done)
2974  */
2975 char *
set(char * control,const char * value)2976 Coll_Ctrl::set (char * control, const char * value)
2977 {
2978   char * ret;
2979   char * warn = NULL;
2980   int len = strlen (control);
2981   if (!strncmp (control, ipc_str_exp_limit, len))
2982     return set_size_limit (value);
2983   if (!strncmp (control, ipc_str_time_limit, len))
2984     return set_time_run (value);
2985   if (!strncmp (control, ipc_str_arch_exp, len))
2986     return set_archive_mode (value);
2987   if (!strncmp (control, ipc_str_descendant, len))
2988     return set_follow_mode (value);
2989   if (!strncmp (control, ipc_str_prof_idle, len))
2990     return set_prof_idle (value);
2991   if (!strncmp (control, ipc_str_clkprof, len))
2992     {
2993       ret = set_clkprof (value, &warn);
2994       if (ret == NULL)
2995 	{
2996 	  if (warn != NULL)
2997 	    return warn; // Warning
2998 	  return NULL; // Done
2999 	}
3000       return ret; // Error
3001     }
3002   if (!strncmp (control, ipc_str_hwcprof, len))
3003     {
3004       ret = set_hwcstring (value, &warn);
3005       if (ret == NULL)
3006 	{
3007 	  if (warn != NULL)
3008 	    return warn; // Warning
3009 	  return NULL; // Done
3010 	}
3011       return ret; // Error
3012     }
3013   if (!strncmp (control, ipc_str_hwc2_prof, len))
3014     {
3015       ret = set_hwcstring (value, &warn);
3016       if (ret == NULL)
3017 	{
3018 	  if (warn != NULL)
3019 	    return warn; // Warning
3020 	  return NULL; // Done
3021 	}
3022       return ret; // Error
3023     }
3024   if (!strncmp (control, ipc_str_javaprof, len))
3025     return set_java_mode (value);
3026   if (!strncmp (control, ipc_str_sample, len))
3027     return set_sample_period (value);
3028   if (!strncmp (control, ipc_str_sample_sig, len))
3029     return set_sample_signal (find_sig (value));
3030   if (!strncmp (control, ipc_str_pause_resume_sig, len))
3031     {
3032       char *str_signal = strdup (value);
3033       char *str_state = strchr (str_signal, (int) '\n');
3034       if (str_state != NULL)
3035 	{
3036 	  *str_state = 0;
3037 	  str_state++;
3038 	}
3039       int signal = atoi (str_signal);
3040       int state = 0;
3041       if (str_state != NULL)
3042 	state = atoi (str_state);
3043       free (str_signal);
3044       return set_pauseresume_signal (signal, state);
3045     }
3046   if (!strncmp (control, ipc_str_synctrace, len))
3047     return set_synctrace (value);
3048   if (!strncmp (control, ipc_str_heaptrace, len))
3049     return set_heaptrace (value);
3050   if (!strncmp (control, ipc_str_iotrace, len))
3051     return set_iotrace (value);
3052   if (!strncmp (control, ipc_str_count, len))
3053     return set_count (value);
3054   return strdup (ipc_str_unknown_control);
3055 }
3056 
3057 /**
3058  * Resets control's value (restores the default value)
3059  * @param control
3060  * @return error or NULL (done)
3061  */
3062 char *
unset(char * control)3063 Coll_Ctrl::unset (char * control)
3064 {
3065   int len = strlen (control);
3066   if (!strncmp (control, ipc_str_exp_limit, len))
3067     size_limit = 0;
3068   if (!strncmp (control, ipc_str_time_limit, len))
3069     {
3070       time_run = 0;
3071       start_delay = 0;
3072     }
3073   if (!strncmp (control, ipc_str_arch_exp, len))
3074     {
3075       archive_mode = strdup ("on");
3076       return NULL;
3077     }
3078   if (!strncmp (control, ipc_str_descendant, len))
3079     {
3080       follow_mode = FOLLOW_NONE;
3081       return NULL;
3082     }
3083   if (!strncmp (control, ipc_str_prof_idle, len))
3084     {
3085       prof_idle = 1;
3086       return NULL;
3087     }
3088   if (!strncmp (control, ipc_str_clkprof, len))
3089     {
3090       clkprof_default = 1;
3091       clkprof_enabled = 1;
3092       return NULL;
3093     }
3094   if (!strncmp (control, ipc_str_hwcprof, len))
3095     {
3096       setup_hwc ();
3097       set_hwcdefault ();
3098       return NULL;
3099     }
3100   if (!strncmp (control, ipc_str_javaprof, len))
3101     {
3102       java_mode = 0;
3103       java_default = 0;
3104       free (java_path);
3105       java_path = NULL;
3106       free (java_args);
3107       java_args = NULL;
3108     }
3109   if (!strncmp (control, ipc_str_sample, len))
3110     {
3111       sample_period = 1;
3112       sample_default = 1;
3113       return NULL;
3114     }
3115   if (!strncmp (control, ipc_str_sample_sig, len))
3116     {
3117       sample_sig = 0;
3118       return NULL;
3119     }
3120   if (!strncmp (control, ipc_str_pause_resume_sig, len))
3121     {
3122       pauseresume_sig = 0;
3123       return NULL;
3124     }
3125   if (!strncmp (control, ipc_str_synctrace, len))
3126     {
3127       synctrace_enabled = 0;
3128       synctrace_thresh = -1;
3129       return NULL;
3130     }
3131   if (!strncmp (control, ipc_str_heaptrace, len))
3132     {
3133       heaptrace_enabled = 0;
3134       return NULL;
3135     }
3136   if (!strncmp (control, ipc_str_iotrace, len))
3137     {
3138       iotrace_enabled = 0;
3139       return NULL;
3140     }
3141   if (!strncmp (control, ipc_str_count, len))
3142     {
3143       count_enabled = 0;
3144       Iflag = 0;
3145       Nflag = 0;
3146       return NULL;
3147     }
3148   return strdup (ipc_str_unknown_control);
3149 }
3150 
3151 void
set_project_home(char * s)3152 Coll_Ctrl::set_project_home (char *s)
3153 {
3154   if (s)
3155     project_home = strdup (s);
3156 }
3157