]> Git Repo - binutils.git/blob - gprofng/src/collctrl.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / collctrl.cc
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)
50 extern const char *strsignal (int);
51 #endif
52
53 // _SC_CPUID_MAX is not available on 2.6/2.7
54 #ifndef _SC_CPUID_MAX
55 #define _SC_CPUID_MAX       517
56 #endif
57
58 const char *get_fstype (char *);
59
60 Coll_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 */
236 Coll_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
341 Coll_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 */
361 char *
362 Coll_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
386 void
387 Coll_Ctrl::interrupt ()
388 {
389   uinterrupt = 1;
390 }
391
392 char *
393 Coll_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 */
406 void
407 Coll_Ctrl::close_expt ()
408 {
409   opened = 0;
410   (void) update_expt_name (false, false);
411 }
412
413 /* close and delete the experiment */
414 void
415 Coll_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
432 char *
433 Coll_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
460 char *
461 Coll_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
494 char *
495 Coll_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
713 char **
714 Coll_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
840 char *
841 Coll_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
869 void
870 Coll_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
881 char *
882 Coll_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
896 char *
897 Coll_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
997 char *
998 Coll_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
1096 char *
1097 Coll_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
1136 char *
1137 Coll_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
1160 char *
1161 Coll_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
1214 char *
1215 Coll_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
1286 char *
1287 Coll_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
1310 void
1311 Coll_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
1321 void
1322 Coll_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.
1358 void
1359 Coll_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
1369 hrtime_t
1370 Coll_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
1384 void
1385 Coll_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
1397 void
1398 Coll_Ctrl::adjust_clkprof_timer (int use)
1399 {
1400   clkprof_timer = use;
1401 }
1402
1403 /* set HWC counter set from a string */
1404 char * /* return an error string */
1405 Coll_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 */
1430 char * /* return an error string */
1431 Coll_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 */
1519 char * /* return an error string */
1520 Coll_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
1635 void
1636 Coll_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
1664 void
1665 Coll_Ctrl::disable_hwc ()
1666 {
1667   hwcprof_enabled_cnt = 0;
1668   hwcprof_default = 0;
1669   free (hwc_string);
1670   hwc_string = NULL;
1671 }
1672
1673 char *
1674 Coll_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
1704 char *
1705 Coll_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
1724 void
1725 Coll_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
1801 char *
1802 Coll_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
1832 char *
1833 Coll_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
1962 char *
1963 Coll_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
2001 int
2002 Coll_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
2011 void
2012 Coll_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
2019 char *
2020 Coll_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
2061 char *
2062 Coll_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
2087 char *
2088 Coll_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
2152 char *
2153 Coll_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
2162 char *
2163 Coll_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
2197 char *
2198 Coll_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
2259 char *
2260 Coll_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
2277 char *
2278 Coll_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
2297 char *
2298 Coll_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 */
2318 int
2319 Coll_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
2352 char *
2353 Coll_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
2374 char *
2375 Coll_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
2385 char *
2386 Coll_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
2394 char *
2395 Coll_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
2427 char *
2428 Coll_Ctrl::get_exp_name (const char *stembase)
2429 {
2430   expno = 1;
2431   return dbe_sprintf ("%s.%d.er", stembase, expno);
2432 }
2433
2434 char *
2435 Coll_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
2576 char *
2577 Coll_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
2696 void
2697 Coll_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
2707 void
2708 Coll_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
2765 const char *
2766 get_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 */
2785 const char *ipc_str_exp_limit = "exp_limit";
2786 const char *ipc_str_time_limit = "time_limit";
2787 const char *ipc_str_arch_exp = "arch_exp";
2788 const char *ipc_str_descendant = "descendant";
2789 const char *ipc_str_clkprof = "clkprof";
2790 const char *ipc_str_hwcprof = "hwcprof";
2791 const char *ipc_str_hwc2_prof = "hwc2_prof";
2792 const char *ipc_str_javaprof = "javaprof";
2793 const char *ipc_str_sample = "sample";
2794 const char *ipc_str_sample_sig = "sample_sig";
2795 const char *ipc_str_pause_resume_sig = "pause_resume_sig";
2796 const char *ipc_str_synctrace = "synctrace";
2797 const char *ipc_str_heaptrace = "heaptrace";
2798 const char *ipc_str_iotrace = "iotrace";
2799 const char *ipc_str_count = "count";
2800 const char *ipc_str_prof_idle = "prof_idle";    // -x option
2801 // Standard answers
2802 const char *ipc_str_empty = "";
2803 const char *ipc_str_on = "on";
2804 const char *ipc_str_off = "off";
2805 const char *ipc_str_src = "src";
2806 const char *ipc_str_usedsrc = "usedsrc";
2807 const char *ipc_str_usedldobjects = "usedldobjects";
2808 const char *ipc_str_unlimited = "unlimited";
2809 const char *ipc_str_unknown_control = "Unknown control";
2810 const 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  */
2817 char *
2818 Coll_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  */
2832 char *
2833 Coll_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  */
2968 char *
2969 Coll_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  */
3055 char *
3056 Coll_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
3144 void
3145 Coll_Ctrl::set_project_home (char *s)
3146 {
3147   if (s)
3148     project_home = strdup (s);
3149 }
This page took 0.19954 seconds and 4 git commands to generate.