Removed start slash from comments
[dyninst.git] / paradyn / src / DMthread / DMappContext.C
1 /*
2  * DMappConext.C: application context class for the data manager thread.
3  *
4  * $Log: DMappContext.C,v $
5  * Revision 1.50  1995/02/16 19:10:39  markc
6  * Removed start slash from comments
7  *
8  * Revision 1.49  1995/02/16  08:11:16  markc
9  * Changed Boolean to bool
10  * Changed interfaces that call igen-xdr calls to use strings and vectors rather
11  *    than char*'s and igen-arrays
12  *
13  * Revision 1.48  1995/01/26  17:58:11  jcargill
14  * Changed igen-generated include files to new naming convention; fixed
15  * some bugs compiling with gcc-2.6.3.
16  *
17  * Revision 1.47  1994/12/21  00:36:41  tamches
18  * Minor change to tunable constant declaration to reflect new tc constructors.
19  * Fewer compiler warnings.
20  *
21  * Revision 1.46  1994/11/09  18:39:30  rbi
22  * the "Don't Blame Me" commit
23  *
24  * Revision 1.45  1994/11/04  20:13:32  karavan
25  * added a status line.
26  *
27  * Revision 1.44  1994/11/04  16:30:38  rbi
28  * added getAvailableDaemons()
29  *
30  * Revision 1.43  1994/11/03  20:54:01  karavan
31  * Changed error printfs to calls to UIM::showError
32  *
33  * Revision 1.42  1994/11/03  16:10:11  rbi
34  * Updated addExecutable
35  *
36  * Revision 1.41  1994/11/02  11:45:12  markc
37  * Put a hack into addExecutable to handle incorrect parameters passed in.
38  *
39  * Revision 1.40  1994/09/22  00:52:29  markc
40  * Changed "String" to "char*"
41  * Used access methods for private member functions from igen classes
42  * Removed purify error (new char[len] --> char[len+1] on line 303
43  * Typecast args passed to msg_bind_buffered
44  * Added "const" to applicationContext::defineDaemon(), ::findEntry() args
45  *
46  * Revision 1.39  1994/09/05  20:02:59  jcargill
47  * Better control of PC output through tunable constants.
48  *
49  * Revision 1.38  1994/08/22  15:57:26  markc
50  * Added support for config language version 2.
51  * Check for "" parms and convert them to NULL since NULL signifies undefined,
52  * not "".
53  * Support daemon dictionary.
54  *
55  * Revision 1.37  1994/08/08  20:15:17  hollings
56  * added suppress instrumentation command.
57  *
58  * Revision 1.36  1994/08/05  16:03:55  hollings
59  * more consistant use of stringHandle vs. char *.
60  *
61  * Revision 1.35  1994/08/03  19:06:23  hollings
62  * Added tunableConstant to print enable/disable pairs.
63  *
64  * Fixed fold to report fold info to all perfStreams even if they have
65  * not active data being displayed.
66  *
67  * Revision 1.34  1994/07/28  22:31:06  krisna
68  * include <rpc/types.h>
69  * stringCompare to match qsort prototype
70  * proper prorotypes for starting DMmain
71  *
72  * Revision 1.33  1994/07/25  14:55:34  hollings
73  * added suppress resource option.
74  *
75  * Revision 1.32  1994/07/14  23:46:23  hollings
76  * added getCurrentHybridCost, and fixed max for predicted cost.
77  *
78  * Revision 1.31  1994/07/08  21:56:25  jcargill
79  * Changed XDR connection to paradynd to a buffered bind
80  *
81  * Revision 1.30  1994/07/07  03:28:59  markc
82  * Added routine to start a paradyn daemon.
83  * Changed int returns to type Boolean to agree with expected return values from
84  * interface functions.
85  *
86  * Revision 1.29  1994/07/05  03:27:15  hollings
87  * added observed cost model.
88  *
89  * Revision 1.28  1994/07/02  01:43:08  markc
90  * Removed all uses of type aggregation from enableDataCollection.
91  * The metricInfo structure now contains the aggregation operator.
92  *
93  * Revision 1.27  1994/06/29  02:55:55  hollings
94  * fixed code to remove instrumenation when done with it.
95  *
96  * Revision 1.26  1994/06/23  19:26:20  karavan
97  * added option for core dump of all processes with pid=-1 in coreProcess
98  * command.
99  *
100  * Revision 1.25  1994/06/17  22:07:57  hollings
101  * Added code to provide upcall for resource batch mode when a large number
102  * of resources is about to be added.
103  *
104  * Revision 1.24  1994/06/14  15:21:34  markc
105  * Set the aggOp field in metricInstance so the metric can choose from one of
106  * four types of aggregation (max, min, sum, avg).  The aggregation is done in
107  * aggregateSample.C
108  *
109  * Revision 1.23  1994/06/02  23:25:17  markc
110  * Added virtual function 'handle_error' to pardynDaemon class which uses the
111  * error handling features that igen provides.
112  *
113  * Revision 1.22  1994/05/30  19:23:58  hollings
114  * Corrected call to change state for continue to be appRunning not appPaused.
115  *
116  * Revision 1.21  1994/05/23  20:28:04  karavan
117  * fixed return values for addExecutable
118  *
119  * Revision 1.20  1994/05/17  00:17:06  hollings
120  * Made sure we did the correct thing on a callErrr.
121  *
122  * Revision 1.19  1994/05/11  18:45:37  markc
123  * Put code in addExecutable to assign the machine name for paradynDaemons
124  * that are started on the local host.
125  *
126  * Revision 1.18  1994/05/10  03:57:35  hollings
127  * Changed data upcall to return array of buckets.
128  *
129  * Revision 1.17  1994/05/09  20:56:18  hollings
130  * added changeState callback.
131  *
132  * Revision 1.16  1994/04/20  15:30:09  hollings
133  * Added error numbers.
134  * Added data manager function to get histogram buckets.
135  *
136  * Revision 1.15  1994/04/18  22:28:30  hollings
137  * Changes to create a canonical form of a resource list.
138  *
139  * Revision 1.14  1994/03/31  01:42:19  markc
140  * Added pauseProcess, continueProcess member functions.
141  *
142  * Revision 1.13  1994/03/25  22:59:28  hollings
143  * Made the data manager tolerate paraynd's dying.
144  *
145  * Revision 1.12  1994/03/24  16:41:18  hollings
146  * Added support for multiple paradynd's at once.
147  *
148  * Revision 1.11  1994/03/22  21:02:53  hollings
149  * Made it possible to add new processes (& paradynd's) via addExecutable.
150  *
151  * Revision 1.10  1994/03/20  01:49:46  markc
152  * Gave process structure a buffer to allow multiple writers.  Added support
153  * to register name of paradyn daemon.  Changed addProcess to return type int.
154  *
155  * Revision 1.9  1994/03/08  17:39:31  hollings
156  * Added foldCallback and getResourceListName.
157  *
158  * Revision 1.8  1994/03/01  21:24:50  hollings
159  * removed call to print all metrics.
160  *
161  * Revision 1.7  1994/02/25  20:58:10  markc
162  * Added support for storing paradynd's pids.
163  *
164  * Revision 1.6  1994/02/24  04:36:29  markc
165  * Added an upcall to dyninstRPC.I to allow paradynd's to report information at
166  * startup.  Added a data member to the class that igen generates.
167  * Make depend differences due to new header files that igen produces.
168  * Added support to allow asynchronous starts of paradynd's.  The dataManager has
169  * an advertised port that new paradynd's can connect to.
170  *
171  * Revision 1.5  1994/02/09  22:35:29  hollings
172  * added debugging code to print Hash table.
173  *
174  * Revision 1.4  1994/02/08  21:05:54  hollings
175  * Found a few pointer problems.
176  *
177  * Revision 1.3  1994/02/05  23:14:00  hollings
178  * Made sure we didn't return an mi when the enable failed.
179  *
180  * Revision 1.2  1994/02/02  00:42:31  hollings
181  * Changes to the Data manager to reflect the file naming convention and
182  * to support the integration of the Performance Consultant.
183  *
184  * Revision 1.1  1994/01/28  01:34:15  hollings
185  * The initial version of the Data Management thread.
186  *
187  *
188  */
189 #include <assert.h>
190 extern "C" {
191 double   quiet_nan(int unused);
192 #include <malloc.h>
193 #include <rpc/types.h>
194 #include <rpc/xdr.h>
195 #include <stdio.h>
196 }
197
198 #include "thread/h/thread.h"
199 #include "../pdMain/paradyn.h"
200 #include "dataManager.thread.h"
201 #include "dyninstRPC.xdr.CLNT.h"
202 #include "DMinternals.h"
203 #include "util/h/tunableConst.h"
204 #include "../UIthread/Status.h"
205
206 tunableBooleanConstant printChangeCollection(false, NULL, developerConstant,
207     "printChangeCollection", 
208     "Print the name of metric/focus when enabled or disabled");
209
210 List<performanceStream*> applicationContext::streams;
211
212 status_line *DMstatus;
213
214 void paradynDdebug(int pid)
215 {
216 }
217
218 // change a char* that points to "" to point to NULL
219 // NULL is used to signify "NO ARGUMENT"
220 // NULL is easier to detect than "" (which needs a strlen to detect)
221 static void fixArg(char *&argToFix)
222 {
223   if (argToFix && !strlen(argToFix))
224     argToFix = (char*) 0;
225 }
226
227 String_Array convertResourceList(resourceList *rl)
228 {
229     String_Array ret;
230
231     ret.count = rl->getCount();
232     ret.data = (char **) rl->convertToStringList();
233     return(ret);
234 }
235
236 // called when a program is started external to paradyn and
237 // must inform paradyn that it exists
238 bool applicationContext::addRunningProgram (int pid,
239                                             const vector<string> &argv,
240                                             paradynDaemon *daemon)
241 {
242         executable *exec = new executable (pid, argv, daemon);
243         programs.add(exec);
244         return true;
245 }
246
247
248 //
249 // add a new paradyn daemon
250 // called when a new paradynd contacts the advertised socket
251 //
252 bool applicationContext::addDaemon (int new_fd)
253 {
254   paradynDaemon *new_daemon;
255
256   new_daemon = new paradynDaemon (new_fd);
257
258   msg_bind_buffered (new_daemon->get_fd(), true, (int(*)(void*)) xdrrec_eof,
259                      (void*)new_daemon->net_obj());
260
261   // TODO - do I need the pid for this ?
262   // The pid is reported later in an upcall
263   // paradynDdebug (new_daemon->pid);
264
265   daemons.add(new_daemon);
266
267   return (true);
268 }
269
270 //
271 // Dispose of daemon state.
272 //    This is called because someone wants to kill a daemon, or the daemon
273 //       died and we need to cleanup after it.
274 //
275 void applicationContext::removeDaemon(paradynDaemon *d, bool informUser)
276 {
277 #ifdef notdef
278     executable *e;
279     List<executable*> progs;
280 #endif
281
282     if (informUser) {
283         //printf("paradynd (pid %d) had died\n", d->getPid());
284         //printf("paradyn Error #5\n");
285       uiMgr->showError (5, "paradynd has died");
286     }
287
288     d->dead = true;
289 #ifdef notdef
290     daemons.remove(d);
291
292     //
293     // Delete executables running on the dead paradyn daemon.
294     //
295     for (progs = programs; e = *progs; progs++) {
296        if (e->controlPath == d) {
297            programs.remove(e);
298            delete(e);
299        }
300     }
301
302 #endif
303
304     // tell the thread package to ignore the fd to the daemon.
305     msg_unbind(d->get_fd());
306 }
307
308 //
309 // add a new daemon
310 // check to see if a daemon that matches the function args exists
311 // if it does exist, return a pointer to it
312 // otherwise, create a new daemon
313 //
314 paradynDaemon *applicationContext::getDaemonHelper (char *machine, 
315                                                     char *login,
316                                                     char *name)
317 {
318   paradynDaemon *daemon;
319   List<paradynDaemon*> curr;
320   daemonEntry *def;
321   char statusLine[256];
322
323   // if name is null, use the default daemon name
324   if (!name) 
325     if (!setDefaultArgs(name))
326       return NULL;
327   
328   // find out if we have a paradynd on this machine+login+paradynd
329   for (curr=daemons, daemon = NULL; *curr; curr++) {
330     if ((!machine || ((*curr)->machine == machine)) &&
331         (!login || ((*curr)->login == login)) &&
332         (name && ((*curr)->name == name))) {
333       return (*curr);
334     }
335   }
336
337   // find a matching entry in the dicitionary, and start it
338   def = findEntry(machine, name);
339   if (!def)
340     return ((paradynDaemon*) 0);
341
342   // fill in machine name if emtpy
343   if (!machine) {
344     struct utsname un;
345     P_uname(&un);
346     machine = P_strdup(un.nodename);
347   }
348
349   sprintf(statusLine, "Starting daemon on %s",machine);
350   (*DMstatus) << statusLine;
351
352   daemon = new paradynDaemon(machine, login, def->getCommand(), def->getName(),
353                              def->getFlavor());
354
355   (*DMstatus) << "ready";
356
357   if (daemon->get_fd() < 0) {
358     //printf("unable to start paradynd: %s\n", def->getCommand());
359     //printf("paradyn Error #6\n");
360     uiMgr->showError (6, "unable to start paradynd");
361     return((paradynDaemon*) NULL);
362   }
363   daemons.add(daemon);
364   msg_bind_buffered (daemon->get_fd(), true, (int(*)(void*))xdrrec_eof,
365                      (void*) daemon->net_obj());
366
367   paradynDdebug(daemon->getPid());
368   return daemon;
369 }
370
371 // 
372 // add a new daemon, unless a daemon is already running on that machine
373 // with the same machine, login, and program
374 //
375 bool applicationContext::getDaemon (char *machine,
376                                        char *login,
377                                        char *name)
378 {
379   // change all "" to NULL
380   fixArg(machine); fixArg(login); fixArg(name);
381
382   if (!getDaemonHelper(machine, login, name))
383     return false;
384   else
385     return true;
386 }
387
388 bool applicationContext::defineDaemon (const char *command,
389                                           const char *dir,
390                                           const char *login,
391                                           const char *name,
392                                           const char *machine,
393                                           int flavor)
394 {
395   List<daemonEntry*> walk;
396   daemonEntry *newE;
397
398   if (!name || !command)
399     return false;
400
401   for (walk=allEntries; *walk; walk++)
402     if ((*walk)->getName() == name) {
403       if ((*walk)->setAll(machine, command, name, login, dir, flavor))
404         return true;
405       else
406         return false;
407     }
408   newE = new daemonEntry(machine, command, name, login, dir, flavor);
409   if (!newE)
410     return false;
411   allEntries.add(newE);
412   return true;
413 }
414
415 daemonEntry *applicationContext::findEntry(const char *m, const char *n)
416 {
417   List<daemonEntry*> walk;
418
419   if (!n)
420     return ((daemonEntry*) 0);
421   // TODO -- casting
422   for (walk=allEntries; *walk; walk++) {
423     if ((*walk)->getName() == n)
424       return (*walk);
425   }
426   return ((daemonEntry*) 0);
427 }
428
429 void applicationContext::printDaemons()
430 {
431   List<daemonEntry*> walk;
432   for (walk=allEntries; *walk; walk++) {
433     (*walk)->print();
434   }
435 }
436
437 //
438 // Return list of names of defined daemons.  
439 //
440 String_Array applicationContext::getAvailableDaemons()
441 {
442     int i;
443     String_Array names;
444     List<daemonEntry*> walk;
445
446     walk=allEntries;
447     names.count = walk.count();
448     names.data = (char **) malloc(sizeof(char*) * names.count);
449     // TODO -- casting stringHandle to char*
450     // TODO -- memory leak ?
451     for (i=0; *walk; walk++,i++) {
452        names.data[i] = P_strdup((*walk)->getName().string_of());
453        assert(names.data[i]);
454     }
455     assert(i==names.count);
456     return(names);
457 }
458
459 //
460 // add a new executable (binary) to a program.
461 //
462 bool applicationContext::addExecutable(char  *machine,
463                                           char *login,
464                                           char *name,
465                                           char *dir,
466                                           const vector<string> &argv)
467 {
468   int pid;
469   executable *exec;
470   paradynDaemon *daemon;
471   static status_line pidnum("Processes");
472   static char tmp_buf[256];
473
474   if (! DMstatus) {
475     DMstatus = new status_line("Data Manager");
476   }
477
478   if ((daemon = getDaemonHelper(machine, login, name)) ==
479       (paradynDaemon*) NULL)
480     return false;
481
482   startResourceBatchMode();
483   pid = daemon->addExecutable(argv);
484   endResourceBatchMode();
485
486   // did the application get started ok?
487   if (pid > 0 && !daemon->did_error_occur()) {
488     // TODO
489
490     sprintf (tmp_buf, "%sPID=%d ", tmp_buf, pid);
491     pidnum.message(tmp_buf);
492
493     exec = new executable(pid, argv, daemon);
494     programs.add(exec);
495     return (true);
496   } else {
497     return(false);
498   }
499 }
500
501 //
502 // Indicate if at least one application has been defined.
503 //
504 bool applicationContext::applicationDefined() {
505     return(programs.count() != 0);
506 }
507
508 //
509 // start the programs running.
510 //
511 bool applicationContext::startApplication()
512 {
513     executable *exec;
514     List<executable*> curr;
515
516     for (curr = programs; exec = *curr; curr++) {
517         exec->controlPath->startProgram(exec->pid);
518     }
519     return(true);
520 }
521
522 //
523 // pause all processes.
524 //
525 bool applicationContext::pauseApplication()
526 {
527     paradynDaemon *dm;
528     performanceStream* s;
529     List<paradynDaemon*> curr;
530     List<performanceStream*> currStreams;
531
532     for (curr = daemons; dm = *curr; curr++) {
533         dm->pauseApplication();
534     }
535
536     // tell perf streams about change.
537     for (currStreams = streams; s = *currStreams; currStreams++) {
538         s->callStateFunc(appPaused);
539     }
540
541     return(true);
542 }
543
544 //
545 // pause one processes.
546 //
547 bool applicationContext::pauseProcess(int pid)
548 {
549     executable *exec;
550     List<executable*> curr;
551
552     for (curr = programs; exec = *curr; curr++) {
553         if (exec->pid == pid) break; 
554     }
555     if (exec) {
556         exec->controlPath->pauseProgram(exec->pid);
557         return(true); 
558     } else
559         return (false);
560 }
561
562 //
563 // continue all processes.
564 //
565 bool applicationContext::continueApplication()
566 {
567     paradynDaemon *dm;
568     performanceStream* s;
569     List<paradynDaemon*> curr;
570     List<performanceStream*> currStreams;
571
572     for (curr = daemons; dm = *curr; curr++) {
573         dm->continueApplication();
574     }
575
576     // tell perf streams about change.
577     for (currStreams = streams; s = *currStreams; currStreams++) {
578         s->callStateFunc(appRunning);
579     }
580
581     return(true);
582 }
583
584 //
585 // continue one processes.
586 //
587 bool applicationContext::continueProcess(int pid)
588 {
589     executable *exec;
590     List<executable*> curr;
591
592     for (curr = programs; exec = *curr; curr++) {
593         if (exec->pid == pid) break;
594     }
595     if (exec) {
596         exec->controlPath->continueProgram(exec->pid);
597         return(true); 
598     } else
599         return (false);
600 }
601
602 //
603 // detach the paradyn tool from a running program.  This should clean all
604 //   of the dynamic instrumentation that has been inserted.
605 //
606 bool applicationContext::detachApplication(bool pause)
607 {
608     executable *exec;
609     List<executable*> curr;
610
611     for (curr = programs; exec = *curr; curr++) {
612         exec->controlPath->detachProgram(exec->pid, pause);
613     }
614     return(true);
615 }
616
617 //
618 // print the status of each process.  This is used mostly for debugging.
619 //
620 void applicationContext::printStatus()
621 {
622     executable *exec;
623     List<executable*> curr;
624
625     for (curr = programs; exec = *curr; curr++) {
626       string status = exec->controlPath->getStatus(exec->pid);
627         if (!exec->controlPath->did_error_occur()) {
628           cout << status << endl;
629         }
630     }
631 }
632
633 //
634 // Cause the passed process id to dump a core file.  This is also used for
635 //    debugging.
636 // If pid = -1, all processes will dump core files.
637 //
638 void applicationContext::coreProcess(int pid)
639 {
640     executable *exec;
641     List<executable*> curr;
642
643     for (curr = programs; exec = *curr; curr++) {
644         if ((exec->pid == pid) || (pid == -1)) {
645             exec->controlPath->coreProcess(exec->pid);
646             printf("found process and coreing it\n");
647         }
648     }
649   }
650
651 //
652 // Find out what metrics are available.  This just returns their names.
653 //
654 String_Array applicationContext::getAvailableMetrics()
655 {
656     int i;
657     String_Array names;
658     HTable<metric*> cm;
659
660     names.count = metric::allMetrics.count();
661     names.data = (char **) malloc(sizeof(char*) * names.count);
662     // TODO -- storing stringHandles into char* ?
663     for (cm=metric::allMetrics,i=0; *cm; cm++,i++) {
664        names.data[i] = (char*) (*cm)->getName();
665        assert(names.data[i]);
666     }
667     assert(i==names.count);
668     return(names);
669 }
670
671 //
672 // look up the metric info about the passed metric.
673 //
674 metric *applicationContext::findMetric(char *name)
675 {
676     stringHandle iName;
677
678     iName = metric::names.findAndAdd(name);
679     return(metric::allMetrics.find(iName));
680 }
681
682 bool applicationContext::setInstSuppress(resource *res, bool newValue)
683 {
684     bool ret;
685     paradynDaemon *daemon;
686     List<paradynDaemon*> curr;
687
688     ret = false;
689     for (curr = daemons; daemon = *curr; curr++) {
690         ret |= daemon->setTracking((char*)res->getFullName(), newValue);
691     }
692     return(ret);
693 }
694
695 //
696 // Get the expected delay (as a fraction of the running program) for the passed
697 //   resource list (focus) and metric.
698 //
699 float applicationContext::getPredictedDataCost(resourceList *rl, metric *m)
700 {
701     char *metName;
702     double val, max;
703     paradynDaemon *daemon;
704     List<paradynDaemon*> curr;
705
706     if (!rl || !m) return(0.0);
707
708     vector<string> vs;
709     assert(rl->convertToStringList(vs));
710
711     max = 0.0;
712
713     // TODO -- stringHandle or char*
714     metName = (char*) m->getName();
715     assert(metName);
716     for (curr = daemons; *curr; curr++) {
717         daemon = *curr;
718         val = daemon->getPredictedDataCost(vs, metName);
719         if (val > max) max = val;
720     }
721     return(max);
722 }
723
724 float applicationContext::getCurrentHybridCost()
725 {
726     double val, max;
727     paradynDaemon *daemon;
728     List<paradynDaemon*> curr;
729
730     max = 0.0;
731     for (curr = daemons; *curr; curr++) {
732         daemon = *curr;
733         val = daemon->getCurrentHybridCost();
734         if (val > max) max = val;
735     }
736     return(max);
737 }
738
739 void histDataCallBack(sampleValue *buckets,
740                       int count,
741                       int first,
742                       void *arg)
743 {
744     metricInstance *mi;
745     performanceStream *ps;
746     List<performanceStream*> curr;
747
748     mi = (metricInstance *) arg;
749     for (curr = mi->users; ps = *curr; curr++) {
750         ps->callSampleFunc(mi, buckets, count, first);
751     }
752 }
753
754 void histFoldCallBack(timeStamp width, void *arg)
755 {
756     performanceStream *ps;
757     static timeStamp oldWidth;
758     List<performanceStream*> curr;
759
760     if (oldWidth == width) return;
761     oldWidth = width;
762
763     for (curr = applicationContext::streams; ps = *curr; curr++) {
764         ps->callFoldFunc(width);
765     }
766 }
767
768 //
769 // Start collecting data about the passed resource list (focus) and metric.
770 //    The returned metricInstance is used to provide a unique handle for this
771 //    metric/focus pair.
772 //
773 metricInstance *applicationContext::enableDataCollection(resourceList *rl, 
774                                                          metric *m)
775 {
776     int id;
777     component *comp;
778     bool foundOne;
779     stringHandle name;
780     metricInstance *mi;
781     paradynDaemon *daemon;
782     List<paradynDaemon*> curr;
783
784     vector<string> vs;
785     assert(rl->convertToStringList(vs));
786
787     // 
788     // for each daemon request the data to be enabled.
789     //
790     mi = new metricInstance(rl, m);
791     foundOne = false;
792     for (curr = daemons; daemon = *curr; curr++) {
793         id = daemon->enableDataCollection(vs, (const char*) m->getName());
794         if (printChangeCollection.getValue()) {
795           cout << "EDC:  " << (char*)m->getName()
796             << (char *) rl->getCanonicalName() << " " << id <<"\n";
797         }
798         if (id > 0 && !daemon->did_error_occur()) {
799             comp = new component(*curr, id, mi);
800             mi->components.add(comp, (void *) *curr);
801             mi->parts.add(&comp->sample, (void *) *curr);
802             foundOne = true;
803         }
804     }
805     if (foundOne) {
806         mi->data = new Histogram(m->getStyle(), 
807                                  histDataCallBack, 
808                                  histFoldCallBack, 
809                                  (void *) mi);
810         name = rl->getCanonicalName();
811         m->enabledCombos.add(mi, name);
812         mi->count = 1;
813
814         if (printChangeCollection.getValue()) {
815           cout << "EN: " << m->getName() 
816             << ((char *)rl->getCanonicalName()) << "\n";
817         }
818         return(mi);
819     } else {
820         delete(mi);
821         return(NULL);
822     }
823 }
824
825 //
826 // This actuals stops the data from being collected.
827 //
828 void applicationContext::disableDataCollection(metricInstance *mi)
829 {
830     metric *m;
831     component *c;
832     stringHandle name;
833     List<component*> curr;
834
835     m = mi->met;
836     name = mi->focus->getCanonicalName();
837
838     if (printChangeCollection.getValue()) {
839         cout << "DI: " << m->getName() << ((char *) name) << "\n";
840     }
841
842     m->enabledCombos.remove(name);
843     for (curr = mi->components; c = *curr; curr++) {
844         delete(c);
845     }
846     // TODO -- is this safe, what if data is reported for this ?
847     delete(mi);
848 }
849
850 void applicationContext::startResourceBatchMode() 
851 {
852     List<performanceStream*> curr;
853     for (curr = streams; *curr; curr++) {
854         (*curr)->callResourceBatchFunc(batchStart);
855     }
856 }
857
858 void applicationContext::endResourceBatchMode() 
859 {
860     List<performanceStream*> curr;
861     for (curr = streams; *curr; curr++) {
862         (*curr)->callResourceBatchFunc(batchEnd);
863     }
864 }
865
866 bool applicationContext::setDefaultArgs(char *&name)
867 {
868   if (!name)
869     name = strdup("defd");
870   if (name)
871     return true;
872   else 
873     return false;
874 }