added new call registerValidVisis. This single call from Visi Manager to
[dyninst.git] / paradyn / src / VMthread / VMmain.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /* $Log: VMmain.C,v $
43 /* Revision 1.43  1997/06/02 19:41:54  karavan
44 /* added new call registerValidVisis.  This single call from Visi Manager to
45 /* UI thread at startup registers all valid visis as specified in a config
46 /* file, and replaces use of synchronous VM->VMAvailableVisis().
47 /*
48  * Revision 1.42  1996/11/26 16:07:14  naim
49  * Fixing asserts - naim
50  *
51  * Revision 1.41  1996/08/16 21:09:24  tamches
52  * updated copyright for release 1.1
53  *
54  * Revision 1.40  1996/04/04 21:50:13  newhall
55  * added mi_limit to VMAddNewVisualization
56  *
57  * Revision 1.39  1996/01/05 20:01:12  newhall
58  * removed warnings
59  *
60  * Revision 1.38  1995/10/30  23:07:36  naim
61  * Eliminating warning message - naim
62  *
63  * Revision 1.37  1995/09/26  20:27:46  naim
64  * Minor changes in error messages
65  *
66  * Revision 1.36  1995/09/18  18:22:41  newhall
67  * changes to avoid for-scope problem
68  *
69  */
70
71 #include "thread/h/thread.h"
72 #include "VM.thread.SRVR.h"
73 #include "UI.thread.CLNT.h"
74 #include "performanceConsultant.thread.CLNT.h"
75 #include "VISIthread.thread.CLNT.h"
76 #include "VMtypes.h"
77 #include "paradyn/src/pdMain/paradyn.h"
78 #include "paradyn/src/met/metParse.h"
79
80 /*
81 #include "../UIthread/Status.h"
82 */
83
84 #define ERROR_MSG(s1, s2) \
85    uiMgr->showError(s1,s2); 
86
87 static int      currNumActiveVisis = 0;
88 thread_key_t visiThrd_key;
89 vector<VMactiveVisi *> activeVisis; 
90 vector<VMvisis *> visiList;
91 extern void* VISIthreadmain(void *args);
92 VM *VM::vmp = NULL;
93
94
95 /////////////////////////////////////////////////////////////
96 //  VMActiveVisis: VM server routine, returns a list of all 
97 //        visualization processes that are currently active
98 /////////////////////////////////////////////////////////////
99 vector<VM_activeVisiInfo> *VM::VMActiveVisis(){
100
101   vector<VM_activeVisiInfo> *temp;
102   if (!(temp = new vector<VM_activeVisiInfo>)) {
103       ERROR_MSG(18,"malloc failure in VMActiveVisis");
104       return NULL;
105   }
106
107   for(unsigned i=0; i < activeVisis.size(); i++) {
108       VM_activeVisiInfo newElm;
109       newElm.visiNum = (activeVisis[i])->visiThreadId;
110       newElm.visiTypeId = (activeVisis[i])->visiTypeId;
111       newElm.name = activeVisis[i]->name;
112       *temp += newElm;
113   }
114   return(temp);
115 }
116
117
118 /////////////////////////////////////////////////////////////
119 // VMAvailableVisis: VM server routine, returns a list of all
120 //                   available visualizations 
121 /////////////////////////////////////////////////////////////
122 vector<VM_visiInfo> *VM::VMAvailableVisis(){
123
124   PARADYN_DEBUG(("in VMAvailableVisis"));
125   vector<VM_visiInfo> *temp;
126   if (!(temp = new vector<VM_visiInfo>)) {
127       ERROR_MSG(18,"malloc in VMAvailableVisis");
128       return NULL;
129   }
130
131   for(unsigned i=0; i < visiList.size(); i++) {
132      VM_visiInfo newVal;
133      newVal.name = visiList[i]->name; 
134      newVal.visiTypeId = visiList[i]->Id; 
135      *temp += newVal;
136   }
137   return(temp);
138 }
139
140 /////////////////////////////////////////////////////////////
141 //  VMAddNewVisualization:  VM server routine
142 //  name: visualization's name (used in menuing)  
143 //  args: the command line arguments for the visualization
144 //        argv[0] is the name of the executable
145 // Note - this may add the visi to the list, or update an entry
146 //        in the list
147 /////////////////////////////////////////////////////////////
148 int VM_AddNewVisualization(const char *name,
149                               vector<string> *arg_str,
150                               int  forceProcessStart,
151                               int  mi_limit,
152                               char *matrix,
153                               int numMatrices){
154
155    if (!arg_str || !name) {
156        // TODO -- is this error number correct
157        ERROR_MSG(20,"parameters in VM::VMAddNewVisualization");
158        return(VMERROR);
159    }
160
161   // walk the list to determine if a visi with  this name is on the list
162   string temp_name = name;
163   VMvisis *temp = NULL;
164   for(unsigned i=0; i < visiList.size(); i++){
165       if(visiList[i]->name == temp_name){
166           temp = visiList[i]; 
167           break;
168       }
169   }
170   if(!temp){
171       // create new VMvisis list element and add to visiList
172       if (!(temp = new VMvisis)) {
173           perror("malloc in VM::VMAddNewVisualization");
174           ERROR_MSG(18,"malloc in VM::VMAddNewVisualization");
175           return(VMERROR);
176       }
177       temp->Id = visiList.size();
178       visiList += temp; 
179       PARADYN_DEBUG(("visi added %s forcestart %d",name,forceProcessStart));
180   }
181   else { // redefine an existing entry
182       if(temp->argv){
183           unsigned i = 0;
184           while(temp->argv[i]){
185               delete (temp->argv[i++]);
186           }
187       }
188       delete (temp->argv);
189   }
190
191   unsigned size = arg_str->size();
192   // update info. for new entry 
193   if((temp->argv = new (char*)[size+1]) == NULL){
194       ERROR_MSG(18,"malloc in VM::VMAddNewVisualization");
195       return(VMERROR);
196   }
197
198   // argv must be null terminated
199   temp->argv[size] = (char *) 0;
200   unsigned a_size = arg_str->size();
201   for(unsigned i1=0; i1<a_size; i1++){
202       if((temp->argv[i1] = strdup((*arg_str)[i1].string_of())) == NULL){
203           ERROR_MSG(19,"strdup in VM::VMAddNewVisualization");
204           return(VMERROR);
205       }
206   }
207   temp->name = name;
208
209   if (matrix){
210       if((temp->matrix = strdup(matrix)) == NULL){
211           ERROR_MSG(19,"strdup in VM::VMAddNewVisualization");
212           return(VMERROR);
213       }
214   }
215   else {
216       temp->matrix = NULL;
217   }
218   temp->numMatrices = numMatrices;
219   delete matrix;
220   temp->argc = size;
221   temp->forceProcessStart = forceProcessStart;
222   if(mi_limit > 0)
223       temp->mi_limit = mi_limit;
224   else 
225       temp->mi_limit = 0;
226   return(VMOK); 
227 }
228
229 /////////////////////////////////////////////////////////////
230 //  VMAddNewVisualization:  VM server routine
231 //  name: visualization's name (used in menuing)  
232 //  args: the command line arguments for the visualization
233 //        argv[0] is the name of the executable
234 // Note - this may add the visi to the list, or update an entry
235 //        in the list
236 /////////////////////////////////////////////////////////////
237 int VM::VMAddNewVisualization(const char *name,
238                               vector<string> *arg_str,
239                               int  forceProcessStart,
240                               int  mi_limit,
241                               char *matrix,
242                               int numMatrices){
243
244     return(VM_AddNewVisualization(name, arg_str, forceProcessStart,
245                                  mi_limit, matrix, numMatrices));
246 }
247
248 /////////////////////////////////////////////////////////////
249 //  VMStringToMetResPair: VM server routine, converts a string
250 //      representation of a metric/focus pair list to the 
251 //      internal representation
252 //  return value NULL indicates an error in parsing the string
253 /////////////////////////////////////////////////////////////
254  vector<metric_focus_pair> *VM::VMStringToMetResPair(const char *){
255
256    return(NULL);
257 }
258
259 /////////////////////////////////////////////////////////////
260 // VMCreateVisi: VM server routine, starts a visualization process
261 //
262 // remenuFlag: if set, remenuing request made by visithread when
263 //             a set of metrics and resource choices can't be enabled
264 // forceProcessStart: if 1, the first menuing request is skiped
265 //                     (visi process is started w/o menuing first)
266 //                    if 0, menuing is done before starting the visi
267 //                    if -1, the force value is obtained from the visi table
268 // visiTypeId: identifier indicating wch visi to start
269 // matrix: a string representation of an initail set 
270 //         of metrics and/or resources for the visi 
271 //         (this has to be a string because it can be 
272 //          invoked due to a create visi command from the
273 //          config. file with a list of mets and res ) 
274 /////////////////////////////////////////////////////////////
275 int  VM::VMCreateVisi(int remenuFlag,
276                       int forceProcessStart,
277                       int visiTypeId,
278                       phaseType phase_type,
279                       vector<metric_focus_pair> *matrix){
280
281   // get visi process command line to pass to visithread thr_create 
282   if(visiTypeId >= (int)visiList.size()){
283       PARADYN_DEBUG(("in VM::VMCreateVisi"));
284       ERROR_MSG(20,"visi Id out of range in VM::VMCreateVisi");
285       return(VMERROR);
286   }
287   VMvisis *visitemp = visiList[visiTypeId];
288   visi_thread_args *temp =  new visi_thread_args;
289   temp->argc = visitemp->argc;
290   temp->argv = (char **)visitemp->argv;
291   temp->parent_tid = thr_self();
292   temp->phase_type = phase_type;
293   if(phase_type == GlobalPhase){
294       temp->bucketWidth = dataMgr->getGlobalBucketWidth();
295       temp->start_time = 0.0;
296       temp->my_phaseId = 0;
297   }
298   else {
299       temp->bucketWidth = dataMgr->getCurrentBucketWidth();
300       temp->start_time = dataMgr->getCurrentStartTime();
301       temp->my_phaseId = dataMgr->getCurrentPhaseId();
302    }
303   // make sure bucket width is positive 
304   if(temp->bucketWidth <= 0.0) {
305       PARADYN_DEBUG(("bucketWidth is <= 0.0\n"));
306       temp->bucketWidth = 0.1; 
307   }
308       
309
310   if(matrix != NULL){
311       temp->matrix = matrix;
312   }
313   else {
314       // TODO: check active visi list to see if visi has
315       // pre-defined set of metric/focus pairs, if so
316       // parse the string representation into metrespair rep.
317       temp->matrix = NULL;
318   }
319   temp->remenuFlag = remenuFlag;
320   if(forceProcessStart == -1)
321       temp->forceProcessStart = visitemp->forceProcessStart;
322   else
323       temp->forceProcessStart = forceProcessStart;
324
325   temp->mi_limit = visitemp->mi_limit;
326   PARADYN_DEBUG(("forceProcessStart = %d\n",temp->forceProcessStart));
327   // create a visi thread  
328   thread_t tid;
329   thr_create(0,0,&VISIthreadmain,temp,0,&tid);
330
331   // create a new visipointer
332   VMactiveVisi *temp2 = new VMactiveVisi;
333   if(temp2 == NULL){
334       ERROR_MSG(18,"new in VM::VMCreateVisi");
335       return(VMERROR);
336   }
337
338   temp2->visip = new VISIthreadUser(tid);
339
340   // add  entry to active visi table 
341    temp2->name = visitemp->name;
342    temp2->visiThreadId = tid;
343    activeVisis += temp2;
344  
345   PARADYN_DEBUG(("in VM::VMCreateVisi: tid = %d added to list",tid));
346   currNumActiveVisis++;
347   return(VMOK);
348 }
349
350 /////////////////////////////////////////////////////////////
351 // VMDestroyVisi: VM server routine, kills a visualization 
352 // visiThreadId: thread identifier associated with the visi to kill
353 /////////////////////////////////////////////////////////////
354 void VM::VMDestroyVisi(thread_t visiThreadId){
355
356   PARADYN_DEBUG(("VM::VMDestroyVisi: visiThreadId = %d",visiThreadId));
357   PARADYN_DEBUG(("currNumActiveVisis = %d",currNumActiveVisis));
358
359   // kill visiThread associated with visi
360   for(unsigned i = 0; i < activeVisis.size(); i++){
361       if(activeVisis[i]->visiThreadId == visiThreadId){
362           // remove entry from active visi table
363           VMactiveVisi *temp = activeVisis[i];
364           temp->visip->VISIKillVisi();  
365           activeVisis[i] = activeVisis[activeVisis.size() - 1];
366           activeVisis.resize(activeVisis.size() - 1);
367           delete(temp->visip);
368           delete(temp);
369           currNumActiveVisis--;
370           PARADYN_DEBUG(("in VM::VMDestroyVisi: tid = %d removed",getTid()));
371           break;
372   } }
373   PARADYN_DEBUG(("VM::VMDestroyVisi: after temp->visip->VISIKillVisi"));
374 }
375
376
377 /////////////////////////////////////////////////////////////
378 //  VMVisiDied: VM server routine, notification of dead visi 
379 //  visiThreadId: thread identifier of visithread that has died
380 /////////////////////////////////////////////////////////////
381 void VM::VMVisiDied(thread_t visiThreadId){
382
383   for(unsigned i=0; i < activeVisis.size(); i++){
384       if(activeVisis[i]->visiThreadId == visiThreadId){
385           VMactiveVisi *temp = activeVisis[i];
386           // remove element from activeVisis list
387           activeVisis[i] = activeVisis[activeVisis.size() - 1];
388           activeVisis.resize(activeVisis.size() - 1);
389           delete(temp->visip);
390           delete(temp);
391           currNumActiveVisis--;
392   } }
393 }
394
395 int VM::VM_sequential_init(){
396   return 1;
397 }
398
399
400 void myfree(void* ptr) {
401     (void) free(ptr);
402 }
403 extern unsigned metVisiSize();
404 extern visiMet *metgetVisi(unsigned);
405
406 int VM::VM_post_thread_create_init(){
407
408   thr_name("Visualization Manager");
409   VMtid = thr_self();
410
411   // create key for VISIthread local storage
412   if (thr_keycreate(&visiThrd_key, myfree) != THR_OKAY) {
413      PARADYN_DEBUG(("visiThrd_key in VM::VMmain"));
414      ERROR_MSG(20,"visiThrd_key in VM::VMmain");
415      return 0;
416   }
417
418   // visis are defined in the configuration language and
419   // reported using VMAddNewVisualization
420
421   VM::vmp = new VM(MAINtid);
422
423   // Get PDL visi entries
424   for(unsigned u=0; u < metVisiSize(); u++){
425       visiMet *next_visi = metgetVisi(u);
426       if(next_visi){
427           vector<string> argv;
428           bool aflag;
429           aflag=(RPCgetArg(argv, next_visi->command().string_of()));
430           assert(aflag);
431           VM_AddNewVisualization(next_visi->name().string_of(), &argv, 
432                                 next_visi->force(),next_visi->limit(),NULL, 0);
433       }
434
435   }
436
437   char  VMbuff[32];
438   // global synchronization
439   int retVal = msg_send (MAINtid, MSG_TAG_VM_READY,(char *)NULL,0);
440   tag_t mtag   = MSG_TAG_ALL_CHILDREN_READY;
441   unsigned msgSize = 0;
442   retVal = msg_recv (&mtag, VMbuff, &msgSize);
443
444   // register valid visis with the UI
445   vector<VM_visiInfo> *temp = new vector<VM_visiInfo>;
446   for(unsigned i=0; i < visiList.size(); i++) {
447      VM_visiInfo newVal;
448      newVal.name = visiList[i]->name; 
449      newVal.visiTypeId = visiList[i]->Id; 
450      *temp += newVal;
451   }
452   uiMgr->registerValidVisis(temp);
453
454   return 1;
455 }
456
457
458 // main loop for visualization manager thread
459 void *VMmain(void* varg) {
460
461   int arg; memcpy((void *) &arg, varg, sizeof arg);
462
463   VM::VM_post_thread_create_init();
464
465
466   while(1){
467       unsigned tag = MSG_TAG_ANY;
468       int from = msg_poll(&tag, 1);
469       assert(from != THR_ERR);
470       if (uiMgr->isValidTag((T_UI::message_tags)tag)) {
471         if (uiMgr->waitLoop(true, (T_UI::message_tags)tag) == T_UI::error) {
472           // TODO
473           cerr << "Error in VMmain.C, needs to be handled\n";
474           assert(0);
475         }
476       } else if (perfConsult->isValidTag(
477                  (T_performanceConsultant::message_tags)tag)) {
478         if (perfConsult->waitLoop(true, 
479            (T_performanceConsultant::message_tags)tag) ==
480            T_performanceConsultant::error) {
481           // TODO
482           cerr << "Error in VMmain.C, needs to be handled\n";
483           assert(0);
484         }
485       } else if (VM::vmp->isValidTag((T_VM::message_tags) tag)) {
486         // check for incoming client calls
487         if (VM::vmp->waitLoop(true, (T_VM::message_tags)tag) == T_VM::error) {
488           // TODO
489           cerr << "Error in VMmain.C, needs to be handled\n";
490           assert(0);
491         }
492       } else {
493         // TODO
494         cerr << "Message sent that is not recognized in PCmain.C\n";
495         assert(0);
496       }
497   }
498   for(unsigned i=0; i < visiList.size(); i++){
499       for(int j=0; j < (*visiList[i]).argc; j++){
500           free((*visiList[i]).argv[j]);
501       }
502   }
503   return((void *)0);
504 }