bug fix to VISIthreadchooseMetRes to check for 'Cancel' case. removed warnings
[dyninst.git] / paradyn / src / VISIthread / VISIthreadmain.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 /////////////////////////////////////////////////////////////////////
43 // * VISIthread main loop
44 // * Callback routines for UI Upcalls:  VISIthreadchooseMetRes
45 //              VISIthreadshowMsgREPLY, VISIthreadshowErrorREPLY
46 // * Callback routines for DataManager Upcalls:  VISIthreadDataCallback  
47 //              VISIthreadnewMetricCallback, VISIthreadFoldCallback 
48 //              VISIthreadnewResourceCallback VISIthreadPhaseCallback
49 /////////////////////////////////////////////////////////////////////
50 #include <signal.h>
51 #include <math.h>
52 #include <stdlib.h>
53 #include "util/h/rpcUtil.h"
54 #include "util/h/sys.h"
55 #include "paradyn/src/VMthread/VMtypes.h"
56 #include "VISIthread.thread.SRVR.h"
57 #include "VISIthreadTypes.h"
58 #include "paradyn/src/pdMain/paradyn.h"
59 #include "dyninstRPC.xdr.CLNT.h"
60 #include "paradyn/src/DMthread/DMinclude.h"
61 #include "paradyn/src/DMthread/DVbufferpool.h"
62 #include "paradyn/src/TCthread/tunableConst.h"
63
64 #define  ERROR_MSG(s1, s2) \
65          uiMgr->showError(s1,s2); 
66 #define  min(a,b) ((a)<(b) ? (a):(b))
67
68 char *AbbreviatedFocus(const char *);
69
70 void flush_buffer_if_full(VISIGlobalsStruct *ptr) {
71    assert(ptr->buffer_next_insert_index <= ptr->buffer.size());
72    if (ptr->buffer_next_insert_index != ptr->buffer.size())
73       return;
74
75    ptr->visip->Data(ptr->buffer);
76
77    if (ptr->visip->did_error_occur()) {
78       PARADYN_DEBUG(("igen: after visip->Data() in VISIthreadDataHandler"));
79       ptr->quit = 1;
80       return;
81    }
82    ptr->buffer_next_insert_index = 0;
83 }
84
85 void flush_buffer_if_nonempty(VISIGlobalsStruct *ptr) {
86    const unsigned num_to_send = ptr->buffer_next_insert_index;
87    assert(num_to_send <= ptr->buffer.size());
88
89    if (num_to_send == 0){
90       ptr->buffer_next_insert_index = 0;
91       return;
92    }
93
94    if (num_to_send < ptr->buffer.size()) {
95       // send less than the full buffer --> need to make a temporary buffer
96       // Make sure this doesn't happen on the critical path!
97       vector<T_visi::dataValue> temp(num_to_send);
98       for (unsigned i = 0; i < num_to_send; i++)
99          temp[i] = ptr->buffer[i];
100       ptr->visip->Data(temp);
101    }
102    else
103       ptr->visip->Data(ptr->buffer);
104
105    if (ptr->visip->did_error_occur()) {
106       PARADYN_DEBUG(("igen: after visip->Data() in VISIthreadDataHandler"));
107       ptr->buffer_next_insert_index = 0;
108       ptr->quit = 1;
109       return;
110     }
111     ptr->buffer_next_insert_index = 0;
112 }
113
114 // trace data streams
115 void flush_traceBuffer_if_full(VISIGlobalsStruct *ptr) {
116    assert(ptr->buffer_next_insert_index <= ptr->traceBuffer.size());
117    if (ptr->buffer_next_insert_index != ptr->traceBuffer.size())
118       return;
119
120    ptr->visip->TraceData(ptr->traceBuffer);
121
122    if (ptr->visip->did_error_occur()) {
123       PARADYN_DEBUG(("igen: after visip->TraceData() in VISIthreadTraceDataHandler"));
124       ptr->quit = 1;
125       return;
126    }
127    ptr->buffer_next_insert_index = 0;
128 }
129
130 // trace data streams
131 void flush_traceBuffer_if_nonempty(VISIGlobalsStruct *ptr) {
132    const unsigned num_to_send = ptr->buffer_next_insert_index;
133    assert(num_to_send <= ptr->traceBuffer.size());
134
135    if (num_to_send == 0){
136       ptr->buffer_next_insert_index = 0;
137       return;
138    }
139
140    if (num_to_send < ptr->traceBuffer.size()) {
141       // send less than the full buffer --> need to make a temporary buffer
142       // Make sure this doesn't happen on the critical path!
143       vector<T_visi::traceDataValue> temp(num_to_send);
144       for (unsigned i = 0; i < num_to_send; i++)
145          temp[i] = ptr->traceBuffer[i];
146       ptr->visip->TraceData(temp);
147    }
148    else
149       ptr->visip->TraceData(ptr->traceBuffer);
150
151    if (ptr->visip->did_error_occur()) {
152       PARADYN_DEBUG(("igen: after visip->TraceData() in VISIthreadTracceDataHandler"));
153       ptr->buffer_next_insert_index = 0;
154       ptr->quit = 1;
155       return;
156     }
157     ptr->buffer_next_insert_index = 0;
158 }
159
160 /////////////////////////////////////////////////////////////
161 //  VISIthreadDataHandler: routine to handle data values from 
162 //    the datamanger to the visualization  
163 //
164 //  adds the data value to it's local buffer and if the buffer
165 //  is full sends it to the visualization process
166 /////////////////////////////////////////////////////////////
167 void VISIthreadDataHandler(metricInstanceHandle mi,
168                            int bucketNum,
169                            sampleValue value,
170                            phaseType){
171
172   VISIthreadGlobals *ptr;
173   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
174       PARADYN_DEBUG(("thr_getspecific in VISIthreadDataCallback"));
175       ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadDataCallback");
176       return;
177   }
178
179   if(ptr->start_up || ptr->quit) // process has not been started or has exited 
180       return;
181
182   // if visi has not allocated buffer space yet
183   if(!(ptr->buffer.size())){  
184       return;               
185   }
186
187   if(ptr->buffer_next_insert_index >= ptr->buffer.size()) {
188       PARADYN_DEBUG(("buffer_next_insert_index out of range: VISIthreadDataCallback")); 
189       ERROR_MSG(16,"buffer_next_insert_index out of range: VISIthreadDataCallback");
190       ptr->quit = 1;
191       return; 
192   }
193
194   // find metricInstInfo for this metricInstanceHandle
195   metricInstInfo *info = NULL;
196   for(unsigned i=0; i < ptr->mrlist.size(); i++){
197       if(ptr->mrlist[i].mi_id == mi){
198           info = &(ptr->mrlist[i]);
199       }
200   }
201   if(!info) return;  // just ignore values 
202
203   // add data value to buffer
204   T_visi::dataValue &bufferEntry = ptr->buffer[ptr->buffer_next_insert_index++];
205   bufferEntry.data = value;
206   bufferEntry.metricId = info->m_id;
207   bufferEntry.resourceId = info->r_id; 
208   bufferEntry.bucketNum = bucketNum;
209
210   // if buffer is full, send buffer to visualization
211   flush_buffer_if_full(ptr);
212   info = 0;
213 }
214
215 /////////////////////////////////////////////////////////////
216 //  VISIthreadDataCallback: Callback routine for DataManager 
217 //    newPerfData Upcall
218 //
219 /////////////////////////////////////////////////////////////
220 void VISIthreadDataCallback(vector<dataValueType> *values,
221                             u_int num_values){
222
223   
224   VISIthreadGlobals *ptr;
225   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
226       PARADYN_DEBUG(("thr_getspecific in VISIthreadDataCallback"));
227       ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadDataCallback");
228       return;
229   }
230
231   if(!ptr) return;
232
233   // if visi process has not been started yet or if visi process has exited 
234   if(ptr->start_up || ptr->quit)  return;
235
236   if (values->size() < num_values) num_values = values->size();
237   for(unsigned i=0; i < num_values;i++){
238       VISIthreadDataHandler((*values)[i].mi,
239                             (*values)[i].bucketNum,
240                             (*values)[i].value,
241                             (*values)[i].type);
242   }
243   // dealloc buffer space
244   datavalues_bufferpool.dealloc(values);
245
246 }
247
248 /////////////////////////////////////////////////////////////
249 //  VISIthreadTraceDataHandler: routine to handle trace data values from
250 //    the datamanger to the visualization
251 //
252 //  adds the data value to it's local buffer and if the buffer
253 //  is full sends it to the visualization process
254 /////////////////////////////////////////////////////////////
255 void VISIthreadTraceDataHandler(metricInstanceHandle mi,
256                             byteArray value){
257
258   VISIthreadGlobals *ptr;
259   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
260       PARADYN_DEBUG(("thr_getspecific in VISIthreadDataCallback"));
261       ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadDataCallback");
262       return;
263   }
264
265   if(ptr->start_up || ptr->quit) // process has not been started or has exited
266       return;
267
268   // if visi has not allocated buffer space yet
269   if(!(ptr->traceBuffer.size())){
270       return;
271   }
272
273   if(ptr->buffer_next_insert_index >= ptr->traceBuffer.size()) {
274       PARADYN_DEBUG(("buffer_next_insert_index out of range: VISIthreadTraceDataCallback"));
275       ERROR_MSG(16,"buffer_next_insert_index out of range: VISIthreadTraceDataCallback");
276       ptr->quit = 1;
277       return;
278   }
279
280   // find metricInstInfo for this metricInstanceHandle
281   metricInstInfo *info = NULL;
282   for(unsigned i=0; i < ptr->mrlist.size(); i++){
283       if(ptr->mrlist[i].mi_id == mi){
284           info = &(ptr->mrlist[i]);
285       }
286   }
287   if(!info) return;  // just ignore values
288
289   // add data value to buffer
290 T_visi::traceDataValue &traceBufferEntry = ptr->traceBuffer[ptr->buffer_next_insert_index++];
291   traceBufferEntry.metricId = info->m_id;
292   traceBufferEntry.resourceId = info->r_id;
293   traceBufferEntry.traceDataRecord = value;
294
295   //flush_buffer_if_full(ptr);
296   flush_traceBuffer_if_full(ptr);
297   if (!value.length())
298     flush_traceBuffer_if_nonempty(ptr);
299
300   info = 0;
301 }
302
303
304 /////////////////////////////////////////////////////////////
305 //  VISIthreadTraceDataCallback: Callback routine for DataManager
306 //    newTracePerfData Upcall
307 //
308 /////////////////////////////////////////////////////////////
309 void VISIthreadTraceDataCallback(perfStreamHandle ,
310                             metricInstanceHandle ,
311                             timeStamp ,
312                             int num_values,
313                             void *values){
314
315
316   VISIthreadGlobals *ptr;
317   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
318       PARADYN_DEBUG(("thr_getspecific in VISIthreadTraceDataCallback"));
319       ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadTraceDataCallback");
320       return;
321   }
322
323   if(!ptr) return;
324
325   // if visi process has not been started yet or if visi process has exited
326   if(ptr->start_up || ptr->quit)  return;
327
328     vector<traceDataValueType> *traceValues =
329       (vector<traceDataValueType> *)values;
330   if (traceValues->size() < (u_int)num_values) num_values = traceValues->size();
331   for(int i=0; i < num_values;i++){
332       VISIthreadTraceDataHandler((*traceValues)[i].mi,
333                             (*traceValues)[i].traceRecord);
334   }
335   tracedatavalues_bufferpool.dealloc(traceValues);
336
337 }
338
339 /////////////////////////////////////////////////////////
340 //  VISIthreadnewMetricCallback: callback for dataManager
341 //    newMetricDefined Upcall
342 //    (not currently implemented)  
343 /////////////////////////////////////////////////////////
344 void VISIthreadnewMetricCallback(perfStreamHandle,
345                                  const char *,
346                                  int,
347                                  int,
348                                  const char *,
349                                  metricHandle,
350                                  dm_MetUnitsType){
351  VISIthreadGlobals *ptr;
352
353   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
354     PARADYN_DEBUG(("thr_getspecific in VISIthreadnewMetricCallback"));
355     ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadnewMetricCallback");
356     return;
357   }
358   if(ptr->start_up || ptr->quit)  // visi process has not started or exiting 
359     return;
360 }
361
362 ///////////////////////////////////////////////////////////
363 //  VISIthreadnewResourceCallback: callback for dataManager
364 //    newResourceDefined Upcall 
365 //    (not currently implemented)  
366 //////////////////////////////////////////////////////////
367 void VISIthreadnewResourceCallback(perfStreamHandle,
368                                    resourceHandle,
369                                    resourceHandle, 
370                                    const char *,
371                                    const char *){
372
373   VISIthreadGlobals *ptr;
374   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
375    PARADYN_DEBUG(("thr_getspecific in VISIthreadnewResourceCallback"));
376    ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadnewResourceCallback");
377    return;
378   }
379
380   if(ptr->start_up || ptr->quit)  // process not started or exiting 
381     return;
382
383 }
384
385 ///////////////////////////////////////////////////////
386 //  VISIthreadFoldCallback: callback for dataManager
387 //     histFold upcall
388 //
389 //  if thread's local data buffer is not empty send
390 //  the data buffer to the visualization process
391 //  before sending Fold msg to visi process  
392 ///////////////////////////////////////////////////////
393 // TODO: do something with this phase_type info
394 void VISIthreadFoldCallback(perfStreamHandle,
395                         timeStamp width, phaseType phase_type){
396
397
398  VISIthreadGlobals *ptr;
399
400   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
401      PARADYN_DEBUG(("thr_getspecific in VISIthreadFoldCallback"));
402      ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadFoldCallback");
403      return;
404   }
405
406   if(ptr->start_up || ptr->quit) // process has not been started or has exited 
407      return;
408
409   
410   if ((ptr->buffer_next_insert_index >= ptr->buffer.size()) && 
411         ptr->buffer.size()){   
412      PARADYN_DEBUG(("buffer_next_insert_index out of range: VISIthreadFoldCallback")); 
413      ERROR_MSG(16,"buffer_next_insert_index out of range: VISIthreadFoldCallback");
414      ptr->quit = 1;
415      return;  
416   }
417
418   // ignore folds for other phase types 
419   if(ptr->args->phase_type != phase_type) return;
420   // ignore folds for other phase data...this is an old phase visi
421   if(ptr->currPhaseHandle != -1) {
422       if((phase_type != GlobalPhase) && 
423          (ptr->args->my_phaseId != ((u_int)ptr->currPhaseHandle))) return;
424   }
425
426   // if new Width is same as old width ignore Fold 
427   if(ptr->bucketWidth != width){
428      // if buffer is not empty send visualization buffer of data values
429      flush_buffer_if_nonempty(ptr);
430
431      ptr->bucketWidth = width;
432      // call visualization::Fold routine
433      ptr->visip->Fold((double)width);
434      if(ptr->visip->did_error_occur()){
435         PARADYN_DEBUG(("igen: after visip->Fold() in VISIthreadFoldCallback"));
436         ptr->quit = 1;
437         return;
438      }
439   }
440
441 }
442 ///////////////////////////////////////////////////////
443 //  VISIthreadPhaseCallback: callback for dataManager
444 //     new phase definition upcall 
445 //
446 ///////////////////////////////////////////////////////
447 void VISIthreadPhaseCallback(perfStreamHandle, 
448                              const char *name,
449                              phaseHandle handle,
450                              timeStamp begin,
451                              timeStamp end,
452                              float bucketWidth,
453                              bool, bool){
454
455    VISIthreadGlobals *ptr;
456    if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
457       PARADYN_DEBUG(("thr_getspecific in VISIthreadPhaseCallback"));
458       ERROR_MSG(13,"thr_getspecific in VISIthread::VISIthreadPhaseCallback");
459       return;
460    }
461
462    if(ptr->start_up || ptr->quit)  // process not been started yet or exiting 
463      return;
464
465    // send visi phase end call for current phase
466    // if(ptr->currPhaseHandle != -1)
467        ptr->visip->PhaseEnd((double)begin,ptr->currPhaseHandle);
468
469    ptr->currPhaseHandle = handle;
470
471    // send visi phase start call for new phase
472    ptr->visip->PhaseStart((double)begin,(double)end,bucketWidth,name,handle);
473 }
474
475
476 /////////////////////////////////////////////////////////////
477 // Start the visualization process:  this is called when the
478 // first set of valid metrics and resources is enabled
479 ///////////////////////////////////////////////////////////
480 int VISIthreadStartProcess(){
481
482   VISIthreadGlobals *ptr;
483
484   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
485     PARADYN_DEBUG(("thr_getspecific in VISIthreadStartProcess"));
486     ERROR_MSG(13,"Error in VISIthreadStartProcess: thr_getspecific");
487     return(0);
488   }
489
490   // start the visualization process
491   if(ptr->start_up){
492     PARADYN_DEBUG(("start_up in VISIthreadStartProcess"));
493     vector<string> av;
494     // start at 1 since RPCprocessCreate will add 0th arg to list
495     unsigned index=1;
496     while(ptr->args->argv[index]) {
497       av += ptr->args->argv[index];
498       index++;
499     }
500     ptr->fd = RPCprocessCreate("localhost","",ptr->args->argv[0], av);
501
502     if (ptr->fd < 0) {
503       PARADYN_DEBUG(("Error in process Create: RPCprocessCreate"));
504       ERROR_MSG(14,"");
505       ptr->quit = 1;
506       return(0);
507     }
508
509     ptr->visip = new visiUser(ptr->fd); 
510     if (ptr->visip->errorConditionFound) {
511       ERROR_MSG(14,"");
512       ptr->quit = 1;
513       return(0);
514     }
515
516     if(msg_bind_buffered(ptr->fd,0,
517         (int(*)(void*)) xdrrec_eof,ptr->visip->net_obj()) != THR_OKAY) {
518       PARADYN_DEBUG(("Error in msg_bind(ptr->fd)"));
519       ERROR_MSG(14,"");
520       ptr->quit = 1;
521       return(0);
522     }
523
524   }
525   ptr->start_up = 0;  // indicates that process has been started
526   return(1);
527 }
528
529 ///////////////////////////////////////////////////////////////////
530 // make an enable request to the DM if the enable limit hasn't been
531 // reached and if there are still things to enable
532 ///////////////////////////////////////////////////////////////////
533 bool VISIMakeEnableRequest(){
534
535   VISIthreadGlobals *ptr;
536
537   if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
538     PARADYN_DEBUG(("thr_getspecific in MakeEnableRequest"));
539     ERROR_MSG(13,"Error in VISIMakeEnableRequest: thr_getspecific");
540     return(0);
541   }
542   
543   if(!(ptr->request)) return false;
544   if(ptr->next_to_enable >= ptr->request->size()) return false;
545
546   // check to see if the limit has been reached
547   if(ptr->args->mi_limit > 0){
548       if(ptr->args->mi_limit <= (int)ptr->mrlist.size()){
549           string msg("A visi has enabled the maximum number of metric/focus ");
550           msg += string("pairs that it can enable. limit = ");
551           msg += string(ptr->args->mi_limit); 
552           msg += string("\n");
553           uiMgr->showError(97,P_strdup(msg.string_of()));
554           // clean up state
555           if(ptr->request) delete ptr->request;
556           if(ptr->retryList) delete ptr->retryList;
557           ptr->request = 0;
558           ptr->retryList = 0;
559           ptr->next_to_enable = 0;
560           ptr->first_in_curr_request = 0;
561           return false;
562       }
563   }
564
565   // get the TC value for the maximum packet size for an enable
566   // request to the DM
567   tunableFloatConstant packetSizeTC =
568   tunableConstantRegistry::findFloatTunableConstant("EnableRequestPacketSize");
569   u_int request_size = (u_int)packetSizeTC.getValue();
570   if(request_size == 0) request_size = 2;
571
572   // there is an enable limit for this visi: adjust the request_size 
573   if(ptr->args->mi_limit > 0) {
574       if((ptr->args->mi_limit - ptr->mrlist.size()) < request_size){ 
575           request_size = (ptr->args->mi_limit - ptr->mrlist.size()); 
576       }
577   }
578
579   if(request_size > (ptr->request->size() - ptr->next_to_enable)){
580       request_size = (ptr->request->size() - ptr->next_to_enable); 
581   }
582
583   // create the request vector of pairs and make enable request to DM
584   vector<metric_focus_pair> *metResParts = 
585                              new vector<metric_focus_pair>(request_size);
586   assert(request_size == metResParts->size());
587
588   for(u_int i=0; i < request_size; i++){
589       (*metResParts)[i] = (*(ptr->request))[ptr->next_to_enable+i]; 
590
591   }
592   ptr->first_in_curr_request = ptr->next_to_enable;
593   ptr->next_to_enable += request_size;
594   ptr->dmp->enableDataRequest(ptr->ps_handle, ptr->pt_handle, metResParts,0,
595                               ptr->args->phase_type,
596                               ptr->args->my_phaseId,0,0,0);
597   return true;
598 }
599
600
601 ///////////////////////////////////////////////////////////////////
602 //  VISIthreadchooseMetRes: callback for User Interface Manager 
603 //    chooseMetricsandResources upcall
604 //    input: list of metric/focus matrices 
605 //
606 //  If there is not an enable request already in progress for this
607 //  visi, then update request info. and call VISIMakeEnableRequest
608 //  Otherwise, just update request info. (a call to VISIMakeEnableRequest
609 //  will occur when the response to the request in progress is received)
610 ///////////////////////////////////////////////////////////////////
611 int VISIthreadchooseMetRes(vector<metric_focus_pair> *newMetRes){
612
613     if(newMetRes)
614        PARADYN_DEBUG(("In VISIthreadchooseMetRes size = %d",newMetRes->size()));
615
616     VISIthreadGlobals *ptr;
617     if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
618         PARADYN_DEBUG(("thr_getspecific in VISIthreadchooseMetRes"));
619         ERROR_MSG(13,"thr_getspecific VISIthread::VISIthreadchooseMetRes");
620         return 1;
621     }
622
623     // for Blizzard, get the memory bounds
624     ptr->dmp->getMemoryBounds(ptr->ps_handle, newMetRes) ;
625
626     // there is not an enable currently in progress
627     if(!(ptr->request)){ 
628         // check for invalid reply ==> user picked "Cancel" menu option
629         if(newMetRes == 0){
630            if(ptr->start_up){
631                ptr->quit = 1;
632            }
633            return 1;
634         }
635         else {
636             ptr->request = newMetRes;
637             newMetRes = 0;
638             ptr->next_to_enable = 0;
639             ptr->first_in_curr_request = 0;
640         }
641         if(!VISIMakeEnableRequest()){ 
642             assert(!(ptr->request));
643             assert(!(ptr->retryList));
644             assert(!(ptr->next_to_enable));
645             assert(!(ptr->first_in_curr_request));
646         }
647     }
648     else { // add new elements to request list
649         // check for invalid reply ==> user picked "Cancel" menu option
650         if(newMetRes == 0){ return 1; }
651         *(ptr->request) += *newMetRes;
652         newMetRes = 0;
653     }
654     return 1;
655 }
656
657 ///////////////////////////////////////////////////////////////////
658 // send new set of metric/foci to visi along with old data buckets for
659 // each pair
660 ///////////////////////////////////////////////////////////////////
661 bool VISISendResultsToVisi(VISIthreadGlobals *ptr,u_int numEnabled){
662
663       // create a visi_matrix_Array to send to visualization
664       vector<T_visi::visi_matrix> pairList;
665       // the newly enabled pairs are the last numEnabled in the list
666       u_int start = ptr->mrlist.size() - numEnabled; 
667       assert((start+numEnabled) == ptr->mrlist.size());
668
669       for(unsigned i=start; i < ptr->mrlist.size(); i++){
670           T_visi::visi_matrix matrix;
671           matrix.met.Id = ptr->mrlist[i].m_id;
672           matrix.met.name = ptr->mrlist[i].metric_name; 
673           matrix.met.units = ptr->mrlist[i].metric_units;
674           if(ptr->mrlist[i].units_type == UnNormalized){
675               matrix.met.unitstype = 0;
676           }
677           else if (ptr->mrlist[i].units_type == Normalized){
678               matrix.met.unitstype = 1;
679           }
680           else{
681               matrix.met.unitstype = 2;
682           }
683           matrix.met.aggregate = AVE;
684           matrix.res.Id = ptr->mrlist[i].r_id;
685           if((matrix.res.name = 
686               AbbreviatedFocus(ptr->mrlist[i].focus_name.string_of()))
687               ==0){
688               ERROR_MSG(12,"in VISIthreadchooseMetRes");
689               ptr->quit = 1;
690               return false;
691           }
692           pairList += matrix;
693       }
694
695
696       PARADYN_DEBUG(("before call to AddMetricsResources\n"));
697       if(ptr->args->phase_type == GlobalPhase){
698           ptr->visip->AddMetricsResources(pairList,
699                                           ptr->dmp->getGlobalBucketWidth(),
700                                           ptr->dmp->getMaxBins(),
701                                           ptr->args->start_time,
702                                           -1);
703       }
704       else {
705       ptr->visip->AddMetricsResources(pairList,
706                                       ptr->dmp->getCurrentBucketWidth(),
707                                       ptr->dmp->getMaxBins(),
708                                       ptr->args->start_time,
709                                       ptr->args->my_phaseId);
710       }
711       if(ptr->visip->did_error_occur()){
712           PARADYN_DEBUG(("igen: visip->AddMetsRess(): VISIthreadchooseMetRes"));
713           ptr->quit = 1;
714           return false;
715       }
716
717       // get old data bucket values for new metric/resources and
718       // send them to visualization
719       sampleValue *buckets = new sampleValue[1001];
720       for(unsigned q = start; q < ptr->mrlist.size(); q++){
721           int howmany = ptr->dmp->getSampleValues(ptr->mrlist[q].mi_id,
722                                             buckets,1000,0,
723                                             ptr->args->phase_type);
724           // send visi all old data bucket values
725           if(howmany > 0){
726               vector<sampleValue> bulk_data;
727               for (u_int ve=0; ve< ((u_int)howmany); ve++){
728                   bulk_data += buckets[ve];
729               }
730               ptr->visip->BulkDataTransfer(bulk_data, (int)ptr->mrlist[q].m_id,
731                                         (int)ptr->mrlist[q].r_id);
732               if(ptr->visip->did_error_occur()){
733               PARADYN_DEBUG(("igen:vp->BulkDataTransfer():VISIthreadchoose"));
734                   ptr->quit = 1;
735                   return false;
736               }
737               bulk_data.resize(0);
738           }
739       }
740       return true;
741 }
742
743 ///////////////////////////////////////////////////////////////////
744 // Callback routine for enable data calls to the DM
745 //     response: the response vector from the DM corr. to the request
746 //     
747 // Checks to see if something new has been enabled, if so it sends new
748 // pairs to visi process (starting visi process first if it has not already
749 // done so).  If there are more things to enable, then a call to 
750 // VISIMakeEnableRequest is made, otherwise a remenuing call could be made
751 // to the UI with all pairs that were requested, but not enabled
752 ///////////////////////////////////////////////////////////////////
753 void VISIthreadEnableCallback(vector<metricInstInfo> *response, u_int){
754
755     VISIthreadGlobals *ptr;
756     if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
757         PARADYN_DEBUG(("thr_getspecific in VISIthreadEnableCallback"));
758         ERROR_MSG(13,"thr_getspecific VISIthread::VISIthreadEnableCallback");
759         return;
760     }
761
762     // for each successfully enabled pair, check to see if it is newly enabled
763     // if it is not successfully enabled add it to the retry list
764     u_int numEnabled = 0; // number enalbed
765     for(u_int i=0; i < response->size(); i++){
766         if ((*response)[i].successfully_enabled) {
767             bool found = false;
768             for(u_int j=0; j < ptr->mrlist.size(); j++){
769                 if((*response)[i].mi_id == ptr->mrlist[j].mi_id){
770                     found = true;
771                     break;
772             } }
773             if(!found){ // this is a new metric/focus pair
774                 ptr->mrlist += (*response)[i];
775                 numEnabled++;
776             }
777         }
778         else { // add it to retry list
779             if(ptr->retryList){
780                 *(ptr->retryList) += 
781                      (*ptr->request)[i+ptr->first_in_curr_request];
782             }
783             else {
784                 ptr->retryList = new vector<metric_focus_pair>;
785                 *(ptr->retryList) += 
786                      (*ptr->request)[i+ptr->first_in_curr_request];
787             }
788         }
789     }
790
791     // if something was enabled and if process is not started, then start it
792     if(numEnabled > 0){
793         // increase the buffer size
794         flush_buffer_if_nonempty(ptr);
795
796         // trace data streams
797         flush_traceBuffer_if_nonempty(ptr);
798
799         unsigned newMaxBufferSize = min(ptr->buffer.size()+numEnabled,
800                                         DM_DATABUF_LIMIT);
801         ptr->buffer.resize(newMaxBufferSize); // new
802
803         // trace data streams
804         ptr->traceBuffer.resize(10); // new
805
806         // if this is the first set of enabled values, start visi process
807         if(ptr->start_up){
808             if(!VISIthreadStartProcess()){
809                 ptr->quit = 1;
810                 return;
811             }
812         }
813         assert(!ptr->start_up);
814
815         // send new set of metric/focus pairs to visi
816         if(!VISISendResultsToVisi(ptr,numEnabled)){
817             cout << "error after call to VISISendResultsToVisi\n";
818         }
819     }
820
821     // if we have reached the limit display limit msg and clean-up state
822     // else if there are more things to enable get the next set
823     // else clean up state and if the retryList is non-empty send msgs
824     if(ptr->next_to_enable < ptr->request->size()){ // more to enable
825        if((ptr->args->mi_limit > 0) &&  // this visi has a limit 
826           ((int)(ptr->mrlist.size()) >= ptr->args->mi_limit)){ // limit reached 
827             string msg("A visi has enabled the maximum number of metric/");
828             msg += string("focus pairs that it can enable. Some pairs may ");
829             msg += string("not have been enabled.  limit =  ");
830             msg += string(ptr->args->mi_limit); 
831             msg += string("\n");
832             uiMgr->showError(97,P_strdup(msg.string_of()));
833             // clean up state
834             if (ptr->request) delete ptr->request;
835             if (ptr->retryList) delete ptr->retryList;
836             ptr->next_to_enable = 0;
837             ptr->first_in_curr_request = 0;
838             ptr->request = 0;
839             ptr->retryList = 0;
840         }
841         else { // try to enable more
842             if(!VISIMakeEnableRequest()) 
843                 cout << "error after call to VISIMakeEnableRequest\n";
844         }
845
846     }
847     else {  // enable request is complete, send retry list and cleanup
848         // if remenuFlag is set and retry list is not empty: remenu
849         if((ptr->args->remenuFlag)&&ptr->retryList&&(ptr->retryList->size())){
850             // don't free retryList since it is passed to UI
851             string msg("Cannot enable the following metric/focus pair(s):\n");
852             for (u_int ii=0; ii < ptr->retryList->size(); ii++) {
853                 string *focusName=NULL;
854                 focusName = new 
855                    string(dataMgr->getFocusName(&((*ptr->retryList)[ii].res)));
856                 msg +=  
857                    string(dataMgr->getMetricName((*ptr->retryList)[ii].met));
858                 if (focusName) {
859                     msg += string("(");
860                     msg += string(AbbreviatedFocus((*focusName).string_of()));
861                     msg += string(")");
862                 }
863                 msg += string(" ");
864             }
865             ptr->ump->chooseMetricsandResources(VISIthreadchooseMetRes,
866                                                 ptr->retryList);
867             ptr->ump->showError(86,P_strdup(msg.string_of()));
868         }
869         else if (ptr->start_up && (!ptr->mrlist.size())) { 
870             // if nothing was ever enabled, and remenuflag is not set quit
871             ptr->quit = 1;
872             if(ptr->retryList) delete ptr->retryList;
873         }
874         // clean up state
875         if(ptr->request) delete ptr->request;
876         ptr->next_to_enable = 0;
877         ptr->first_in_curr_request = 0;
878         ptr->request = 0;
879         ptr->retryList = 0;
880     }
881 }
882
883 ////////////////////////////////////////////////////////
884 //  VISIthreadshowMsgREPLY: callback for User Interface 
885 //    Manager showMsgREPLY upcall (not currently implemented) 
886 ///////////////////////////////////////////////////////
887 void VISIthreadshowMsgREPLY(int){
888 }
889
890 ////////////////////////////////////////////////////////
891 //  VISIthreadshowErrorREPLY: callback for User Interface 
892 //    Manager showErrorREPLY upcall (not currently implemented)
893 ///////////////////////////////////////////////////////
894 void VISIthreadshowErrorREPLY(int){
895 }
896
897 ///////////////////////////////////////////////////////////////////
898 //  VISIthread main routine
899 //  input: parent thread tid, visualization command line arguments
900 //
901 //  initializes thread local variables, starts visualization process
902 //  and enters main loop
903 ///////////////////////////////////////////////////////////////////
904 void *VISIthreadmain(void *vargs){ 
905  
906   //initialize global variables
907   VISIthreadGlobals *globals;
908   globals = new VISIthreadGlobals;
909
910   VISIthread *vtp = new VISIthread(VMtid);
911   globals->ump = uiMgr;
912   globals->vmp = vmMgr;
913   globals->dmp = dataMgr;
914   globals->args = (visi_thread_args *) vargs;
915   globals->visip = NULL;     // assigned value in VISIthreadStartProcess 
916   globals->currPhaseHandle = -1;
917
918   globals->start_up = 1;
919   globals->fd_first = 0;
920
921   // globals->buffer is left a 0-sized array
922   globals->buffer_next_insert_index = 0;
923
924   globals->fd = -1;
925   globals->quit = 0;
926   globals->bucketWidth = globals->args->bucketWidth;
927
928   globals->request = 0;
929   globals->retryList = 0;
930   globals->num_Enabled = 0;
931   globals->next_to_enable = 0;
932   globals->first_in_curr_request = 0;
933
934   // set control callback routines 
935   controlCallback callbacks;
936   callbacks.mFunc = VISIthreadnewMetricCallback;
937   callbacks.rFunc = VISIthreadnewResourceCallback; 
938   callbacks.fFunc = VISIthreadFoldCallback;
939   callbacks.pFunc = VISIthreadPhaseCallback;
940   callbacks.sFunc = 0;
941   callbacks.bFunc = 0;
942   callbacks.cFunc = 0;
943   callbacks.eFunc = VISIthreadEnableCallback;
944
945   PARADYN_DEBUG(("before create performance stream in visithread"));
946
947   // create performance stream
948   union dataCallback dataHandlers;
949   dataHandlers.sample = VISIthreadDataCallback;
950   if((globals->ps_handle = globals->dmp->createPerformanceStream(
951                    Sample,dataHandlers,callbacks)) == 0){
952       PARADYN_DEBUG(("Error in createPerformanceStream"));
953       ERROR_MSG(15,"Error in VISIthreadchooseMetRes: createPerformanceStream");
954       globals->quit = 1;
955   }
956
957   PARADYN_DEBUG(("perf. stream = %d in visithread",(int)globals->ps_handle));
958
959   // trace data streams
960   // set control tracecallback routines
961   controlCallback tracecallbacks;
962   tracecallbacks.mFunc = VISIthreadnewMetricCallback;
963   tracecallbacks.rFunc = VISIthreadnewResourceCallback;
964   tracecallbacks.fFunc = 0;
965   tracecallbacks.pFunc = 0;
966   tracecallbacks.sFunc = 0;
967   tracecallbacks.bFunc = 0;
968   tracecallbacks.cFunc = 0;
969   tracecallbacks.eFunc = VISIthreadEnableCallback;
970
971   PARADYN_DEBUG(("before create performance stream in visithread"));
972
973   // create trace performance stream
974   union dataCallback traceDataHandlers;
975   traceDataHandlers.trace = VISIthreadTraceDataCallback;
976   if((globals->pt_handle = globals->dmp->createPerformanceStream(
977                    Trace,traceDataHandlers,tracecallbacks)) == 0){
978       PARADYN_DEBUG(("Error in createPerformanceStream"));
979       ERROR_MSG(15,"Error in VISIthreadchooseMetRes: createPerformanceStream");
980       globals->quit = 1;
981   }
982
983   PARADYN_DEBUG(("perf. stream = %d in visithread",(int)globals->pt_handle));
984
985
986   if (thr_setspecific(visiThrd_key, globals) != THR_OKAY) {
987       PARADYN_DEBUG(("Error in thr_setspecific"));
988       ERROR_MSG(14,"Error in VISIthreadmain: thr_setspecific");
989       globals->quit = 1;
990   }
991
992   // if forceProcessStart is set, start visi process and skip menuing
993   // and parsing of initial set of metrics and resources
994   if( globals->args->forceProcessStart){
995
996      // start visi process
997      if(!VISIthreadStartProcess()){
998           globals->quit = 1;
999      }
1000   }
1001   // parse globals->args->matrix
1002   // to determine if menuing needs to be done.  If so, call UIM rouitine
1003   // chooseMetricsandResources before entering main loop, if not, call
1004   // AddMetricsResources routine with metric and focus pointers (these
1005   // need to be created from the metricList and resourceList) 
1006   // until parsing routine is in place call chooseMetricsandResources
1007   // with NULL metric and resource pointers
1008   else{
1009
1010     // TODO: add parsing code 
1011
1012     // call get metrics and resources with first set
1013     globals->ump->chooseMetricsandResources(VISIthreadchooseMetRes, NULL);
1014   }
1015
1016  
1017   PARADYN_DEBUG(("before enter main loop"));
1018   while(!(globals->quit)){
1019       if (globals->visip) {
1020         // visip may not have been set yet
1021         // see if any async upcalls have been buffered
1022         while (globals->visip->buffered_requests()) {
1023           if (globals->visip->process_buffered() == T_visi::error) {
1024             cout << "error on visi\n";
1025             assert(0);
1026           }
1027         }
1028       }
1029       thread_t tag = MSG_TAG_ANY;
1030       // int from = msg_poll(&tag, 1);
1031       int from  = msg_poll_preference(&tag, 1,globals->fd_first);
1032       globals->fd_first = !globals->fd_first;
1033
1034       if (globals->ump->isValidTag((T_UI::message_tags)tag)) {
1035         if (globals->ump->waitLoop(true, (T_UI::message_tags)tag) ==
1036             T_UI::error) {
1037           // TODO
1038           cerr << "Error in VISIthreadmain.C\n";
1039           assert(0);
1040         }
1041       } else if (globals->vmp->isValidTag((T_VM::message_tags)tag)) {
1042         if (globals->vmp->waitLoop(true, (T_VM::message_tags)tag) ==
1043             T_VM::error) {
1044           // TODO
1045           cerr << "Error in VISIthreadmain.C\n";
1046           assert(0);
1047         }
1048       } else if (globals->dmp->isValidTag((T_dataManager::message_tags)tag)) {
1049         if (globals->dmp->waitLoop(true, (T_dataManager::message_tags)tag) ==
1050             T_dataManager::error) {
1051           // TODO
1052           cerr << "Error in VISIthreadmain.C\n";
1053           assert(0);
1054         }
1055       } else if (tag == MSG_TAG_FILE){
1056         assert(globals->visip);
1057         assert(from == globals->visip->get_fd());
1058         if (globals->visip->waitLoop() == T_visi::error) {
1059           PARADYN_DEBUG(("igen: visip->awaitResponce() in VISIthreadmain"));
1060           globals->quit = 1;
1061         }
1062         // see if any async upcalls have been buffered
1063         while (globals->visip->buffered_requests()) {
1064           if (globals->visip->process_buffered() == T_visi::error) {
1065             cout << "error on visi\n";
1066             assert(0);
1067           }
1068         }
1069       } else if (vtp->isValidTag((T_VISIthread::message_tags)tag)) {
1070         if (vtp->waitLoop(true, (T_VISIthread::message_tags)tag) ==
1071             T_VISIthread::error) {
1072           // TODO
1073           cerr << "Error in VISIthreadmain.C\n";
1074           assert(0);
1075         }
1076       } else {
1077         cerr << "Unrecognized message in VISIthreadmain.C\n";
1078         assert(0);
1079       }
1080   }
1081   PARADYN_DEBUG(("leaving main loop"));
1082
1083   // disable all metricInstance data collection
1084   for(unsigned i =0; i < globals->mrlist.size(); i++){
1085         metricInstanceHandle handle = globals->mrlist[i].mi_id;
1086         globals->dmp->disableDataCollection(globals->ps_handle,handle,
1087                                             globals->args->phase_type);
1088         // trace data streams
1089         globals->dmp->disableDataCollection(globals->pt_handle,handle,
1090                                             globals->args->phase_type);
1091
1092   }
1093
1094   PARADYN_DEBUG(("before destroy perfomancestream"));
1095   if(!(globals->dmp->destroyPerformanceStream(globals->ps_handle))){
1096       ERROR_MSG(16,"remove() in VISIthreadmain");
1097   }
1098
1099   // trace data streams
1100   if(!(globals->dmp->destroyPerformanceStream(globals->pt_handle))){
1101       ERROR_MSG(16,"remove() in VISIthreadmain");
1102   }
1103
1104
1105   // notify UIM that VISIthread is dying 
1106   globals->ump->threadExiting();
1107
1108   // notify VM 
1109   PARADYN_DEBUG(("before notify VM of thread died"));
1110   globals->vmp->VMVisiDied(thr_self());
1111   PARADYN_DEBUG(("after notify VM of thread died"));
1112
1113   // unbind file descriptor associated with visualization
1114   if(!globals->start_up){
1115       if(msg_unbind(globals->fd) == THR_ERR){
1116           PARADYN_DEBUG(("Error in msg_unbind(globals->fd)"));
1117           ERROR_MSG(14,"Error in VISIthreadmain: msg_unbind");
1118       }
1119       delete globals->visip;
1120   }
1121
1122   PARADYN_DEBUG(("leaving visithread main"));
1123   thr_exit((void *)0);
1124
1125   return((void *)0);
1126 }
1127
1128
1129
1130 // TODO: change the printf stmts to error no.s and calls to UIM 
1131 // error reporting routine
1132 ///////////////////////////////////////////////////////////////////
1133 //  error handler for igen errors.  For all igen error types, the 
1134 //  visithread kills the visualization process, cleans up its state
1135 //  and dies.  Igen errors between a visualization process and its
1136 //  visithread will not result in the paradyn process dying. 
1137 ///////////////////////////////////////////////////////////////////
1138 void visiUser::handle_error()
1139 {
1140   VISIthreadGlobals *ptr;
1141
1142    if (thr_getspecific(visiThrd_key, (void **) &ptr) != THR_OKAY) {
1143       PARADYN_DEBUG(("thr_getspecific in handle_error"));
1144       ERROR_MSG(13,"thr_getspecific in visiUser::handle_error");
1145    }
1146
1147   // err_state is set by the event that caused the error
1148   switch (get_err_state()) {
1149       case igen_no_err:
1150          fprintf(stderr,"Handle error called for igen_no_err tid = %d\n",
1151                  thr_self());
1152          break;
1153       case igen_encode_err:
1154       case igen_decode_err:
1155       case igen_call_err:
1156       case igen_request_err:
1157       case igen_send_err:
1158       case igen_read_err:
1159       default:
1160          ptr->quit = 1;
1161          break;
1162   }
1163 }
1164
1165 char *AbbreviatedFocus(const char *longName){
1166
1167 int i,size,num = 0;
1168 int flag  = 0;
1169 char *newword;
1170 int nextFocus = 0;
1171 int numChars = 0;
1172 int first = 0;
1173
1174   if(longName == NULL)
1175      return(NULL);
1176
1177   size = strlen(longName); 
1178   newword = (char *)malloc((size)+2);
1179   memset(newword,'\0',size+2);
1180
1181   for(i = 0; i < size; i++){
1182       if(longName[i] == '/'){
1183           if(!nextFocus){
1184              nextFocus = 1;
1185              first = 1;
1186              numChars = 0;
1187           }
1188           else if (first){
1189             first = 0;
1190           }
1191           else { 
1192              flag = 1;
1193           }
1194       }
1195       else if(longName[i] == ','){
1196           nextFocus = 0;
1197           flag = 0;
1198           if(first){
1199             num -=numChars;
1200             numChars = 0;
1201           }
1202           else {
1203             newword[num] = ',';
1204             num++;
1205           }
1206       }
1207       if (flag){
1208           newword[num] = longName[i]; 
1209           num++;
1210       }
1211       else if (nextFocus) {
1212            newword[num] = longName[i];
1213            num++;
1214            numChars++;
1215       }
1216   }
1217   if(first){
1218       num -=numChars;
1219   }
1220
1221   if(num <= 0) {
1222      free(newword);
1223      newword = (char *) malloc(strlen(VISI_DEFAULT_FOCUS)+1);
1224      strcpy(newword,VISI_DEFAULT_FOCUS);
1225   } else {
1226      if(newword[num-1] == ','){
1227         newword[num-1] = '\0';
1228      }
1229      newword[num] = '\0';
1230   }
1231   PARADYN_DEBUG(("abbreviated focus = %s size = %d\n",newword,size));
1232   PARADYN_DEBUG(("abbreviated focus num = %d",num));
1233   return(newword);
1234 }
1235