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