Added code to change sampling rate as bucket width changes (this is not
[dyninst.git] / paradyn / src / DMthread / DMmain.C
1 /*
2  * DMmain.C: main loop of the Data Manager thread.
3  *
4  * $Log: DMmain.C,v $
5  * Revision 1.76  1995/10/13 22:06:38  newhall
6  * Added code to change sampling rate as bucket width changes (this is not
7  * completely implemented in daemon code yet, so now it has no effect).
8  * Purify fixes.  Added phaseType parameter to sampleDataCallbackFunc
9  * Added 2 new DM interface routines: getResourceName, getResourceLabelName
10  *
11  * Revision 1.75  1995/09/26  20:22:11  naim
12  * New function defintion: showErrorCallback. This function allows error msgs
13  * from paradynd
14  *
15  * Revision 1.74  1995/08/24  17:23:53  newhall
16  * fixed compile error
17  *
18  * Revision 1.73  1995/08/24  15:02:26  hollings
19  * AIX/SP-2 port (including option for split instruction/data heaps)
20  * Tracing of rexec (correctly spawns a paradynd if needed)
21  * Added rtinst function to read getrusage stats (can now be used in metrics)
22  * Critical Path
23  * Improved Error reporting in MDL sematic checks
24  * Fixed MDL Function call statement
25  * Fixed bugs in TK usage (strings passed where UID expected)
26  *
27  * Revision 1.72  1995/08/20  03:51:27  newhall
28  * *** empty log message ***
29  *
30  * Revision 1.71  1995/08/20 03:37:07  newhall
31  * changed parameters to DM_sequential_init
32  * added persistent data and persistent collection flags
33  *
34  * Revision 1.70  1995/08/18  21:47:46  mjrg
35  * uncommented defineDaemon
36  *
37  * Removed calls to metDoTunable, metDoDaemon, and metDoProcess from
38  * DM_post_thread_create_init.
39  * Fixed dataManager::defineDaemon.
40  *
41  * Revision 1.69  1995/08/12  22:28:22  newhall
42  * Added DM_post_thread_create_init, DM_sequential_init. Changes to DMmain
43  *
44  * Revision 1.68  1995/08/11  21:50:31  newhall
45  * Removed DM kludge method function.  Added calls to metDoDaemon,
46  * metDoProcess and metDoTunable that were moved out of metMain
47  *
48  * Revision 1.67  1995/08/01  02:11:08  newhall
49  * complete implementation of phase interface:
50  *   - additions and changes to DM interface functions
51  *   - changes to DM classes to support data collection at current or
52  *     global phase granularity
53  * added alphabetical ordering to foci name creation
54  *
55  * Revision 1.66  1995/07/06  01:52:49  newhall
56  * update for new version of Histogram library, removed compiler warnings
57  *
58  * Revision 1.65  1995/06/02  20:48:19  newhall
59  * * removed all pointers to datamanager class objects from datamanager
60  *    interface functions and from client threads, objects are now
61  *    refered to by handles or by passing copies of DM internal data
62  * * removed applicationContext class from datamanager
63  * * replaced List and HTable container classes with STL containers
64  * * removed global variables from datamanager
65  * * remove redundant lists of class objects from datamanager
66  * * some reorginization and clean-up of data manager classes
67  * * removed all stringPools and stringHandles
68  * * KLUDGE: there are PC friend members of DM classes that should be
69  *    removed when the PC is re-written
70  *
71  * Revision 1.63  1995/03/02  04:23:19  krisna
72  * warning and bug fixes.
73  *
74  * Revision 1.62  1995/03/01  00:12:27  newhall
75  * added static members to phaseInfo class
76  *
77  * Revision 1.61  1995/02/27  18:43:03  tamches
78  * Changes to reflect the new TCthread; syntax for creating/declaring
79  * tunable constants, as well as syntax for obtaining current
80  * value of tunable constants has changed.
81  *
82  * Revision 1.60  1995/02/26  02:14:03  newhall
83  * added some of the phase interface support
84  *
85  * Revision 1.59  1995/02/16  19:10:41  markc
86  * Removed start slash from comments
87  *
88  * Revision 1.58  1995/02/16  08:15:53  markc
89  * Changed Boolean to bool
90  * Changed interfaces for igen-xdr to use string/vectors rather than char igen-arrays
91  * Check for buffered igen calls.
92  *
93  * Revision 1.57  1995/01/26  17:58:18  jcargill
94  * Changed igen-generated include files to new naming convention; fixed
95  * some bugs compiling with gcc-2.6.3.
96  *
97  * Revision 1.56  1994/12/21  00:36:43  tamches
98  * Minor change to tunable constant declaration to reflect new tc constructors.
99  * Fewer compiler warnings.
100  *
101  * Revision 1.55  1994/12/15  07:38:22  markc
102  * Initialized count used to track resourceBatch requests.
103  *
104  * Revision 1.54  1994/11/11  23:06:49  markc
105  * Check to see if status is non-null
106  *
107  * Revision 1.53  1994/11/11  07:08:51  markc
108  * Added extra arg to RPC_make_arg_list to tell paradyndPVM that it should
109  * start other paradyndPVMs
110  *
111  * Revision 1.52  1994/11/09  18:39:34  rbi
112  * the "Don't Blame Me" commit
113  *
114  * Revision 1.51  1994/11/03  21:58:49  karavan
115  * Allow blank string for parent resource name so paradyndSIM will work
116  *
117  * Revision 1.50  1994/11/03  20:54:13  karavan
118  * Changed error printfs to calls to UIM::showError
119  *
120  * Revision 1.49  1994/11/02  11:45:58  markc
121  * Pass NULL rather than "" in resourceInfoCallback
122  *
123  * Revision 1.48  1994/09/30  19:17:45  rbi
124  * Abstraction interface change.
125  *
126  * Revision 1.47  1994/09/22  00:55:37  markc
127  * Changed "String" to "char*"
128  * Changed arg types for DMsetupSocket
129  * Made createResource() take a const char* rather than char*
130  *
131  * Revision 1.46  1994/09/05  20:03:07  jcargill
132  * Better control of PC output through tunable constants.
133  *
134  * Revision 1.45  1994/08/22  15:58:36  markc
135  * Add code for class daemonEntry
136  *
137  * Revision 1.44  1994/08/17  17:56:24  markc
138  * Added flavor paramater to paradyn daemon data structure.
139  * Added flavor parameter to reportSelf function call.
140  *
141  * Revision 1.43  1994/08/05  16:03:57  hollings
142  * more consistant use of stringHandle vs. char *.
143  *
144  * Revision 1.42  1994/08/03  19:06:24  hollings
145  * Added tunableConstant to print enable/disable pairs.
146  *
147  * Fixed fold to report fold info to all perfStreams even if they have
148  * not active data being displayed.
149  *
150  * Revision 1.41  1994/07/28  22:31:08  krisna
151  * include <rpc/types.h>
152  * stringCompare to match qsort prototype
153  * proper prorotypes for starting DMmain
154  *
155  * Revision 1.40  1994/07/26  20:03:05  hollings
156  * added suppressSearch.
157  *
158  * Revision 1.39  1994/07/25  14:55:36  hollings
159  * added suppress resource option.
160  *
161  * Revision 1.38  1994/07/20  18:59:24  hollings
162  * added resource batch mode.
163  *
164  * Revision 1.37  1994/07/07  03:30:16  markc
165  * Changed expected return types for appContext functions from integer to Boolean
166  *
167  * Revision 1.36  1994/07/05  03:27:17  hollings
168  * added observed cost model.
169  *
170  * Revision 1.35  1994/07/02  01:43:11  markc
171  * Removed all uses of type aggregation from enableDataCollection.
172  * The metricInfo structure now contains the aggregation operator.
173  *
174  * Revision 1.34  1994/06/29  02:55:59  hollings
175  * fixed code to remove instrumenation when done with it.
176  *
177  * Revision 1.33  1994/06/27  21:23:25  rbi
178  * Abstraction-specific resources and mapping info
179  *
180  * Revision 1.32  1994/06/27  18:54:48  hollings
181  * changed stdio printf for paradynd.
182  *
183  * Revision 1.31  1994/06/17  22:07:59  hollings
184  * Added code to provide upcall for resource batch mode when a large number
185  * of resources is about to be added.
186  *
187  * Revision 1.30  1994/06/14  15:22:46  markc
188  * Added arg to enableDataCollection call to support aggregation.
189  *
190  * Revision 1.29  1994/06/02  23:25:19  markc
191  * Added virtual function 'handle_error' to pardynDaemon class which uses the
192  * error handling features that igen provides.
193  *
194  * Revision 1.28  1994/05/31  18:26:15  markc
195  * strdup'd a string passed into createResource, since igen will free the memory
196  * for the string on return from the function.
197  *
198  * Revision 1.27  1994/05/18  02:51:04  hollings
199  * fixed cast one return of malloc.
200  *
201  * Revision 1.26  1994/05/18  00:43:28  hollings
202  * added routine to print output of stdout.
203  *
204  * Revision 1.25  1994/05/17  00:16:38  hollings
205  * Changed process id speperator from [] to {} to get around braindead tcl.
206  *
207  * Revision 1.24  1994/05/16  22:31:38  hollings
208  * added way to request unique resource name.
209  *
210  * Revision 1.23  1994/05/12  23:34:00  hollings
211  * made path to paradyn.h relative.
212  *
213  * Revision 1.22  1994/05/10  03:57:37  hollings
214  * Changed data upcall to return array of buckets.
215  *
216  * Revision 1.21  1994/05/09  20:56:20  hollings
217  * added changeState callback.
218  *
219  * Revision 1.20  1994/05/02  20:37:45  hollings
220  * Fixed compiler warning.
221  *
222  * Revision 1.19  1994/04/21  23:24:26  hollings
223  * removed process name from calls to RPC_make_arg_list.
224  *
225  * Revision 1.18  1994/04/20  15:30:10  hollings
226  * Added error numbers.
227  * Added data manager function to get histogram buckets.
228  *
229  * Revision 1.17  1994/04/18  22:28:31  hollings
230  * Changes to create a canonical form of a resource list.
231  *
232  * Revision 1.16  1994/04/12  22:33:34  hollings
233  * Fixed casts back to time64 which were dropping off the fraction of seconds
234  * in the timestamps of samples.
235  *
236  * Revision 1.15  1994/04/12  15:32:00  hollings
237  * added tunable constant samplingRate to control the frequency of sampling.
238  *
239  * Revision 1.14  1994/04/11  23:18:49  hollings
240  * added checks to make sure time moves forward.
241  *
242  * Revision 1.13  1994/04/04  21:36:12  newhall
243  * added synchronization code to DM thread startup
244  *
245  * Revision 1.12  1994/04/01  20:17:22  hollings
246  * Added init of well known socket fd global.
247  *
248  * Revision 1.11  1994/03/25  22:59:33  hollings
249  * Made the data manager tolerate paraynd's dying.
250  *
251  * Revision 1.10  1994/03/24  16:41:20  hollings
252  * Added support for multiple paradynd's at once.
253  *
254  * Revision 1.9  1994/03/21  20:32:48  hollings
255  * Changed the mid to mi mapping to be per paradyn daemon.  This is required
256  * because mids are asigned by the paradynd's, and are not globally unique.
257  *
258  * Revision 1.8  1994/03/20  01:49:48  markc
259  * Gave process structure a buffer to allow multiple writers.  Added support
260  * to register name of paradyn daemon.  Changed addProcess to return type int.
261  *
262  * Revision 1.7  1994/03/08  17:39:33  hollings
263  * Added foldCallback and getResourceListName.
264  *
265  * Revision 1.6  1994/02/25  20:58:11  markc
266  * Added support for storing paradynd's pids.
267  *
268  * Revision 1.5  1994/02/24  04:36:31  markc
269  * Added an upcall to dyninstRPC.I to allow paradynd's to report information at
270  * startup.  Added a data member to the class that igen generates.
271  * Make depend differences due to new header files that igen produces.
272  * Added support to allow asynchronous starts of paradynd's.  The dataManager has
273  * an advertised port that new paradynd's can connect to.
274  *
275  * Revision 1.4  1994/02/08  21:05:55  hollings
276  * Found a few pointer problems.
277  *
278  * Revision 1.3  1994/02/03  23:26:58  hollings
279  * Changes to work with g++ version 2.5.2.
280  *
281  * Revision 1.2  1994/02/02  00:42:33  hollings
282  * Changes to the Data manager to reflect the file naming convention and
283  * to support the integration of the Performance Consultant.
284  *
285  * Revision 1.1  1994/01/28  01:34:17  hollings
286  * The initial version of the Data Management thread.
287  *
288  *
289  */
290 #include <assert.h>
291 extern "C" {
292 double   quiet_nan();
293 #include <malloc.h>
294 #include <stdio.h>
295 }
296
297 #include "thread/h/thread.h"
298 #include "paradyn/src/TCthread/tunableConst.h"
299 #include "dataManager.thread.SRVR.h"
300 #include "dyninstRPC.xdr.CLNT.h"
301 #include "DMdaemon.h"
302 #include "DMmetric.h"
303 #include "DMperfstream.h"
304 #include "DMabstractions.h"
305 #include "paradyn/src/pdMain/paradyn.h"
306 #include "paradyn/src/UIthread/Status.h"
307
308 #include "util/h/Vector.h"
309 #include "util/h/Dictionary.h"
310 #include "util/h/String.h"
311 #include "DMphase.h"
312
313 // bool parse_metrics(string metric_file);
314 bool metMain(string &userFile);
315
316 // this has to be declared before baseAbstr, cmfAbstr, and rootResource 
317 int dataManager::sock_fd;  
318 int dataManager::socket;  
319 dataManager *dataManager::dm = NULL;  
320
321 dictionary_hash<string,abstraction*> abstraction::allAbstractions(string::hash);
322 abstraction *baseAbstr = new abstraction("BASE");
323 abstraction *cmfAbstr = new abstraction("CMF");
324
325 dictionary_hash<string,metric*> metric::allMetrics(string::hash);
326 dictionary_hash<metricInstanceHandle,metricInstance *> 
327                 metricInstance::allMetricInstances(metricInstance::mhash);
328 dictionary_hash<perfStreamHandle,performanceStream*>  
329                 performanceStream::allStreams(performanceStream::pshash);
330 dictionary_hash<string, resource*> resource::allResources(string::hash);
331 dictionary_hash<string,resourceList *> resourceList::allFoci(string::hash);
332
333 vector<resource*> resource::resources;
334 vector<metric*> metric::metrics;
335 vector<paradynDaemon*> paradynDaemon::allDaemons;
336 vector<daemonEntry*> paradynDaemon::allEntries;
337 vector<executable*> paradynDaemon::programs;
338 vector<resourceList *> resourceList::foci;
339 vector<phaseInfo *> phaseInfo::dm_phases;
340 vector<bool> metricInstance::nextId;
341 vector<bool> performanceStream::nextId;
342
343 resource *resource::rootResource = new resource();
344 timeStamp metricInstance::curr_bucket_width;
345 timeStamp metricInstance::global_bucket_width;
346 phaseHandle metricInstance::curr_phase_id;
347 u_int metricInstance::num_curr_hists = 0;
348 u_int metricInstance::num_global_hists = 0;
349
350 double paradynDaemon::earliestFirstTime = 0;
351
352 void DMchangeSampleRate(float rate); //callback routine for TC "samplingRate"
353 void newSampleRate(float rate);
354
355 //
356 // IO from application processes.
357 //
358 void dynRPCUser::applicationIO(int pid, int len, string data)
359 {
360
361     // NOTE: this fixes a purify error with the commented out code (a memory
362     // segment error occurs occasionally with the line "cout << rest << endl") 
363     // this is problably not the best fix,  but I can't figure out why 
364     // the error is occuring (rest is always '\0' terminated when this
365     // error occurs)---tn 
366     fprintf(stdout,data.string_of());
367
368 #ifdef n_def
369     char *ptr;
370     char *rest;
371     // extra should really be per process.
372     static string extra;
373
374     rest = P_strdup(data.string_of());
375
376     char *tp = rest;
377     ptr = P_strchr(rest, '\n');
378     while (ptr) {
379         *ptr = '\0';
380         if (pid) {
381             printf("pid %d:", pid);
382         } else {
383             printf("paradynd: ");
384         }
385         if (extra.length()) {
386             cout << extra;
387             extra = (char*) NULL;
388         }
389         cout << rest << endl;
390         rest = ptr+1;
391         if(rest)
392             ptr = P_strchr(rest, '\n');
393         else
394             ptr = 0;
395     }
396     extra += rest;
397     delete tp;
398     rest = 0;
399 #endif
400
401 }
402
403 extern status_line *DMstatus;
404
405 void dynRPCUser::resourceBatchMode(bool onNow)
406 {
407     static int count=0;
408
409     int prev = count;
410     if (onNow) {
411         count++;
412     } else {
413         count--;
414     }
415
416     if (count == 0) {
417         performanceStream::ResourceBatchMode(batchEnd);
418     } else if (!prev) {
419         performanceStream::ResourceBatchMode(batchStart);
420     }
421 }
422
423 //
424 // upcalls from remote process.
425 //
426 void dynRPCUser::resourceInfoCallback(int program,
427                                       vector<string> resource_name,
428                                       string abstr) {
429     resourceHandle r = createResource(resource_name, abstr);
430     resourceInfoResponse(resource_name, r);
431 }
432
433 void dynRPCUser::mappingInfoCallback(int program,
434                                      string abstraction, 
435                                      string type, 
436                                      string key,
437                                      string value)
438 {
439   AMnewMapping(abstraction.string_of(),type.string_of(),key.string_of(),
440                value.string_of());    
441 }
442
443 class uniqueName {
444   public:
445     uniqueName(stringHandle base) { name = base; nextId = 0; }
446     int nextId;
447     stringHandle name;
448 };
449
450 // commented out since igen no longer supports sync upcalls
451 #ifdef notdef
452 char *dynRPCUser::getUniqueResource(int program, 
453                                     string parentString, 
454                                     string newResource)
455 {
456     uniqueName *ret;
457     char newName[80];
458     stringHandle ptr;
459     static List<uniqueName*> allUniqueNames;
460
461     sprintf(newName, "%s/%s", parentString.string_of(), newResource.string_of());
462     ptr = dataManager::names.findAndAdd(newName);
463
464     ret = allUniqueNames.find(ptr);
465
466     if (!ret) {
467         ret = new uniqueName(ptr);
468         allUniqueNames.add(ret, ptr);
469     }
470     // changed from [] to {} due to TCL braindeadness.
471     sprintf(newName, "%s{%d}", newResource.string_of(), ret->nextId++);
472     ptr = dataManager::names.findAndAdd(newName);
473
474     return((char*)ptr);
475 }
476 #endif
477
478 //
479 // Display errors using showError function from the UIM class
480 // This function allows to display error messages from paradynd
481 // using the "upcall" or "call back" mechanism.
482 // Parameters:  errCode = Error code
483 //              errString = Error message
484 //              hostName = Host name where the error occur
485 // Call: there is a macro defined in "showerror.h". This macro must be
486 //       used when calling this function. A typical call is:
487 //       showErrorCallback(99, "Erro message test"). This macro will
488 //       automatically insert the additional host info required.
489 //
490 void dynRPCUser::showErrorCallback(int errCode, 
491                                    string errString,
492                                    string hostName)
493 {
494     string msg;
495
496     if (errString.length() > 0) {
497         if (hostName.length() > 0) {
498             msg = string("<Msg from daemon on host ") + hostName + 
499                   string("> ") + errString;
500         }
501         else { 
502             msg = string("<Msg from daemon on host ?> ") + errString; 
503         }
504         uiMgr->showError(errCode, P_strdup(msg.string_of()));
505     }
506     else {
507         uiMgr->showError(errCode, ""); 
508     }
509
510     //
511     // hostName.length() should always be > 0, otherwise
512     // hostName is not defined (i.e. "?" will be used instead).
513     // if errString.length()==0, (i.e. errString.string_of()==""),
514     // then we will use the default error message in errorList.tcl
515     // This message, however, will not include any info about the current
516     // host name.
517     //
518 }
519
520 //
521 // used when a new program gets forked.
522 //
523 void dynRPCUser::newProgramCallbackFunc(int pid,
524                                         vector<string> argvString,
525                                         string machine_name)
526 {
527     // there better be a paradynd running on this machine!
528     paradynDaemon *pd, *daemon = NULL;
529     for(unsigned i = 0; i < paradynDaemon::allDaemons.size(); i++){
530         pd = paradynDaemon::allDaemons[i];
531         if(pd->machine.length() && (pd->machine == machine_name)){
532             daemon = pd;
533         }
534     }
535     // for now, abort if there is no paradynd, this should not happen
536     if (!daemon) {
537         printf("process started on %s, can't find paradynd there\n",
538                 machine_name.string_of());
539         printf("paradyn error #1 encountered\n");
540         exit(-1);
541     }
542       
543    assert (paradynDaemon::addRunningProgram(pid, argvString, daemon));
544 }
545
546 void dynRPCUser::newMetricCallback(T_dyninstRPC::metricInfo info)
547 {
548     addMetric(info);
549 }
550
551 void dynRPCUser::firstSampleCallback (int program,
552                                       double firstTime) {
553
554   assert(0 && "Invalid virtual function");
555 }
556
557 void dynRPCUser::cpDataCallbackFunc(int program,
558                                          double timeStamp,
559                                          int context,
560                                          double total,
561                                          double share)
562 {
563     assert(0 && "Invalid virtual function");
564 }
565
566 void dynRPCUser::sampleDataCallbackFunc(int program,
567                                            int mid,
568                                            double startTimeStamp,
569                                            double endTimeStamp,
570                                            double value)
571 {
572     assert(0 && "Invalid virtual function");
573 }
574
575
576 //
577 // When a paradynd is started remotely, ie not by paradyn, this upcall
578 // reports the information for that paradynd to paradyn
579 //
580 void 
581 dynRPCUser::reportSelf (string m, string p, int pd, string flavor)
582 {
583   assert(0);
584   return;
585 }
586
587 void 
588 dynRPCUser::reportStatus (string line)
589 {
590     assert(0 && "Invalid virtual function");
591 }
592
593 // 
594 // establish socket that will be advertised to paradynd's
595 // this socket will allow paradynd's to connect to paradyn for pvm
596 //
597 static void
598 DMsetupSocket (int &sockfd)
599 {
600   // setup "well known" socket for pvm paradynd's to connect to
601   assert ((dataManager::dm->socket =
602        RPC_setup_socket (sockfd, AF_INET, SOCK_STREAM)) >= 0);
603
604   // bind fd for this thread
605   msg_bind (sockfd, true);
606 }
607
608 static void
609 DMnewParadynd ()
610 {
611   // accept the connection
612   int new_fd = RPC_getConnect(dataManager::dm->sock_fd);
613   if (new_fd < 0) {
614     uiMgr->showError(4, "unable to connect to new paradynd");
615   }
616   // add new daemon to dictionary of all deamons
617   paradynDaemon::addDaemon(new_fd); 
618 }
619
620 void DM_eFunction(int errno, char *message)
621 {
622     printf("error: %s\b", message);
623     abort();
624 }
625
626
627 int dataManager::DM_sequential_init(const char* met_file){
628    string mfile = met_file;
629    return(metMain(mfile)); 
630 }
631
632 int dataManager::DM_post_thread_create_init(int tid) {
633
634
635     thr_name("Data Manager");
636     dataManager::dm = new dataManager(tid);
637
638     // supports argv passed to paradynDaemon
639     // new paradynd's may try to connect to well known port
640     DMsetupSocket (dataManager::dm->sock_fd);
641
642     assert(RPC_make_arg_list(paradynDaemon::args, AF_INET, SOCK_STREAM,
643                              dataManager::dm->socket, 1, 1, "", false));
644
645     // start initial phase
646     string dm_phase0 = "phase_0";
647     phaseInfo::startPhase(0.0,dm_phase0);
648
649     char DMbuff[64];
650     unsigned int msgSize = 64;
651     msg_send (MAINtid, MSG_TAG_DM_READY, (char *) NULL, 0);
652     unsigned int tag = MSG_TAG_ALL_CHILDREN_READY;
653     msg_recv (&tag, DMbuff, &msgSize);
654     return 1;
655 }
656
657 //
658 // Main loop for the dataManager thread.
659 //
660 void *DMmain(void* varg)
661 {
662     // We declare the "printChangeCollection" tunable constant here; it will
663     // last for the lifetime of this function, which is pretty much forever.
664     // (used to be declared as global in DMappContext.C.  Globally declared
665     //  tunables are now a no-no).  Note that the variable name (printCC) is
666     // unimportant.   -AT
667     tunableBooleanConstantDeclarator printCC("printChangeCollection", 
668               "Print the name of metric/focus when enabled or disabled",
669               false, // initial value
670               NULL, // callback
671               developerConstant);
672
673     // Now the same for "printSampleArrival"
674     tunableBooleanConstantDeclarator printSA("printSampleArrival", 
675               "Print out status lines to show the arrival of samples",
676               false, // initial value
677               NULL, // callback
678               developerConstant);
679
680     // Now for the float TC "samplingRate"
681     tunableFloatConstantDeclarator sampR ("samplingRate",
682               "how often to sample intermediate performance data (in seconds)",
683               0.5, // initial value
684               0.0, // min
685               1000.0, // max
686               DMchangeSampleRate, // callback
687               userConstant);
688
689
690     int tid; memcpy((void*)&tid,varg, sizeof(int));
691     dataManager::DM_post_thread_create_init(tid);
692
693     int ret;
694     unsigned int tag;
695     paradynDaemon *pd = NULL;
696     while (1) {
697         for(unsigned i = 0; i < paradynDaemon::allDaemons.size(); i++){
698             pd = paradynDaemon::allDaemons[i]; 
699             // handle up to max async requests that may have been buffered
700             // while blocking on a sync request
701             while (pd->buffered_requests()){
702                 if(pd->process_buffered() == T_dyninstRPC::error) {
703                     cout << "error on paradyn daemon\n";
704                     paradynDaemon::removeDaemon(pd, true);
705         } } }
706
707         tag = MSG_TAG_ANY;
708         ret = msg_poll(&tag, true);
709         assert(ret != THR_ERR);
710
711         if (tag == MSG_TAG_FILE) {
712             // must be an upcall on something speaking the dynRPC protocol.
713             if (ret == dataManager::dm->sock_fd){
714                 DMnewParadynd(); // set up a new daemon
715             }
716             else {
717                 for(unsigned i = 0; i < paradynDaemon::allDaemons.size(); i++){
718                     pd = paradynDaemon::allDaemons[i]; 
719                     if(pd->get_fd() == ret){
720                         if(pd->waitLoop() == T_dyninstRPC::error) {
721                             cout << "error on paradyn daemon\n";
722                             paradynDaemon::removeDaemon(pd, true);
723                     }}
724
725                     // handle async requests that may have been buffered
726                     // while blocking on a sync request
727                     while(pd->buffered_requests()){
728                         if(pd->process_buffered() == T_dyninstRPC::error) {
729                             cout << "error on paradyn daemon\n";
730                             paradynDaemon::removeDaemon(pd, true);
731                     }}
732                 }
733             }
734         } else if (dataManager::dm->isValidTag
735                   ((T_dataManager::message_tags)tag)) {
736             if (dataManager::dm->waitLoop(true, 
737                (T_dataManager::message_tags)tag) == T_dataManager::error) {
738                 // handle error
739                 assert(0);
740             }
741         } else {
742             cerr << "Unrecognized message in DMmain.C\n";
743             assert(0);
744         }
745    }
746 }
747
748
749 void addMetric(T_dyninstRPC::metricInfo &info)
750 {
751     // if metric already exists return
752     if(metric::allMetrics.defines(info.name)){
753         return;
754     }
755     metric *met = new metric(info);
756     // now tell all perfStreams
757     dictionary_hash_iter<perfStreamHandle,performanceStream*> 
758                 allS(performanceStream::allStreams);
759     perfStreamHandle h;
760     performanceStream *ps;
761     while(allS.next(h,ps)){
762         if(ps->controlFunc.mFunc){
763             // set the correct destination thread.
764             dataManager::dm->setTid(ps->threadId);
765             dataManager::dm->newMetricDefined(ps->controlFunc.mFunc, 
766                                               ps->Handle(),
767                                               met->getName(),
768                                               met->getStyle(),
769                                               met->getAggregate(),
770                                               met->getUnits(),
771                                               met->getHandle());
772         }
773     }
774 }
775
776
777 #ifdef n_def
778 resourceHandle createResource(resourceHandle parent, vector<string>& res_name,
779                          string& res_string,string& abstr)
780 {
781     /* first check to see if the resource has already been defined */
782     resource *p = resource::resources[parent];
783     resourceHandle *child = p->findChild(res_string.string_of());
784     if (child){
785         return(*child); 
786         delete child;
787     }
788
789     // if abstr is not defined then use default abstraction 
790     if(!abstr.string_of()){
791         abstr = string("BASE");
792     }
793
794     /* then create it */
795     resource *ret =  new resource(parent,res_name,res_string,abstr);
796
797     /* inform others about it if they need to know */
798     dictionary_hash_iter<perfStreamHandle,performanceStream*> 
799                         allS(performanceStream::allStreams);
800     perfStreamHandle h;
801     performanceStream *ps;
802     resourceHandle r_handle = ret->getHandle();
803     string name = ret->getFullName(); 
804     while(allS.next(h,ps)){
805         ps->callResourceFunc(parent,r_handle,name,abstr);
806     }
807     return(r_handle);
808 }
809 #endif
810
811 // I don't want to parse for '/' more than once, thus the use of a string vector
812 resourceHandle createResource(vector<string>& resource_name, string& abstr) {
813   resource *parent = NULL;
814   unsigned r_size = resource_name.size();
815   string p_name;
816
817
818   switch (r_size) {
819     case 0:
820         // Should this case ever occur ?
821         assert(0); break;
822     case 1:
823         parent = resource::rootResource; break;
824     default:
825         for (unsigned ri=0; ri<(r_size-1); ri++) 
826             p_name += string("/") + resource_name[ri];
827         parent = resource::string_to_resource(p_name);
828         assert(parent);
829         break;
830     }
831     if (!parent) assert(0);
832
833     /* first check to see if the resource has already been defined */
834     resource *p = resource::resources[parent->getHandle()];
835     string myName = p_name;
836     myName += "/";
837     myName += resource_name[r_size - 1];
838     resourceHandle *child = p->findChild(myName.string_of());
839     if (child){
840         return(*child); 
841         delete child;
842     }
843
844     // if abstr is not defined then use default abstraction 
845     if(!abstr.string_of()){
846         abstr = string("BASE");
847     }
848
849     /* then create it */
850     resource *ret =  new resource(parent->getHandle(),resource_name,
851                                   myName,abstr);
852
853     /* inform others about it if they need to know */
854     dictionary_hash_iter<perfStreamHandle,performanceStream*> 
855                         allS(performanceStream::allStreams);
856     perfStreamHandle h;
857     performanceStream *ps;
858     resourceHandle r_handle = ret->getHandle();
859     string name = ret->getFullName(); 
860     while(allS.next(h,ps)){
861         ps->callResourceFunc(parent->getHandle(),r_handle,ret->getFullName(),
862         ret->getAbstractionName());
863     }
864     return(r_handle);
865 }
866
867 void newSampleRate(float rate)
868 {
869     paradynDaemon *pd = NULL;
870     for(unsigned i = 0; i < paradynDaemon::allDaemons.size(); i++){
871         pd = paradynDaemon::allDaemons[i]; 
872         // cout << " in newSampleRate: before call to daemons rate = " 
873         //      << rate << endl; 
874         // TODO: uncomment this to change sampling rate
875         // pd->setSampleRate(rate);
876     }
877 }
878
879 // sampling rate should not be a tunable constant, so changing the tunable 
880 // constant does nothing. ha!
881 void DMchangeSampleRate(float rate){
882     
883 }
884
885 #ifdef ndef
886 // Note - the metric parser has been moved into the dataManager
887 bool parse_metrics(string metric_file) {
888      bool parseResult = metMain(metric_file);
889     return parseResult;
890 }
891 #endif
892
893