updating the feature formerly known as SAVE.
[dyninst.git] / paradyn / src / UIthread / paradyn.tcl.C
1 /*
2  * Copyright (c) 1996-1999 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 /* paradyn.tcl.C
43    $Id: paradyn.tcl.C,v 1.86 1999/05/19 21:16:39 karavan Exp $
44    This code implements the tcl "paradyn" command.  See the README file for 
45    command descriptions.
46 */
47
48 #include <assert.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #include "util/h/headers.h"
53 #include "UIglobals.h"
54 #include "paradyn/src/DMthread/DMinclude.h"
55 #include "../TCthread/tunableConst.h"
56 #include "VM.thread.CLNT.h"
57 #include "thread/h/thread.h"
58 #include "../pdMain/paradyn.h"
59 #include "abstractions.h"
60 #include "whereAxisTcl.h"
61 #include "shgPhases.h"
62
63 #include "util/h/pathName.h" // expand_tilde_pathname
64
65 #include "Status.h"
66
67 extern bool detachApplication(bool);
68
69 extern appState PDapplicState;
70
71 status_line *app_name=NULL;
72 extern status_line *app_status;
73
74 void disablePAUSEandRUN() {
75   if (Tcl_VarEval(interp,"changeApplicState 2",0)==TCL_ERROR) {
76     string msg = string("Tcl interpreter failed in routine changeApplicState: ");
77     msg += string((const char *) interp->result);
78     uiMgr->showError(83, P_strdup(msg.string_of()));
79   }
80 }
81
82 void enablePAUSEorRUN()
83 {
84   string msg = string("Tcl interpreter failed in routine changeApplicState: ");
85   if (PDapplicState==appRunning) {
86     if (Tcl_VarEval(interp,"changeApplicState 1",0)==TCL_ERROR) {
87       msg += string((const char *) interp->result);
88       uiMgr->showError(83, P_strdup(msg.string_of()));
89     }   
90   }
91   else {
92     if (Tcl_VarEval(interp,"changeApplicState 0",0)==TCL_ERROR) {
93       msg += string((const char *) interp->result);
94       uiMgr->showError(83, P_strdup(msg.string_of()));
95     }
96   }
97 }
98
99 int ParadynPauseCmd(ClientData,
100                     Tcl_Interp *interp,
101                     int, char **) {
102   // Called by mainMenu.tcl when the PAUSE button is clicked on.
103   
104   // First, disable the PAUSE button, so we can't click on it twice.
105   // Note that we won't enable the RUN button just yet...we wait until
106   // the pause has been processed.
107   myTclEval(interp, ".parent.buttons.2 configure -state disabled");
108
109   //sleep(1);
110   dataMgr->pauseApplication();
111
112   myTclEval(interp, ".parent.buttons.1 configure -state normal");
113   
114   return TCL_OK;
115 }
116
117 int ParadynContCmd(ClientData,
118                    Tcl_Interp *interp,
119                    int, char **) {
120   // Called by mainMenu.tcl when the RUN button is clicked on.
121
122   // First, we disable the RUN button so it can't be clicked on again.
123
124   myTclEval(interp, ".parent.buttons.1 configure -state disabled");
125
126   // NOTE: we don't enable the PAUSE button just yet...we wait until
127   // the (synchronous) igen call has completed, to avoid a race condition.
128
129   if (!dataMgr->continueApplication())
130      cerr << "warning: dataMgr->continueApplication() failed" << endl;
131
132   // Okay, now it's safe to enable the PAUSE button.
133   myTclEval(interp, ".parent.buttons.2 configure -state normal");
134
135   return TCL_OK;
136 }
137
138 int ParadynStatusCmd(ClientData,
139                 Tcl_Interp *,
140                 int,
141                 char **)
142 {
143   dataMgr->printStatus();
144   return TCL_OK;
145 }
146
147 int ParadynMetricsCmd(ClientData,
148                         Tcl_Interp *,
149                         int,
150                         char **)
151 {
152   vector<string> *ml = dataMgr->getAvailableMetrics(false);
153   for (unsigned i=0; i < ml->size(); i++)
154     Tcl_AppendElement(interp, (char*)(*ml)[i].string_of());
155   delete ml;
156   return TCL_OK;
157 }
158
159
160 int ParadynDaemonsCmd(ClientData,
161                       Tcl_Interp *interp, 
162                       int,
163                       char **)
164 {
165   vector<string> *dl = dataMgr->getAvailableDaemons();
166   for (unsigned i=0; i < dl->size(); i++)
167     Tcl_AppendElement(interp, (char*)(*dl)[i].string_of());
168   delete dl;
169   return TCL_OK;
170 }
171
172
173 int ParadynResourcesCmd(ClientData,
174                         Tcl_Interp *,
175                         int,
176                         char **)
177 {
178   dataMgr->printResources();
179   return TCL_OK;
180 }
181
182 int ParadynListCmd(ClientData,
183                 Tcl_Interp *,
184                 int,
185                 char **)
186 {
187   dataMgr->printResources();
188
189   vector<string> *ml = dataMgr->getAvailableMetrics(false);
190   for (unsigned i=0; i < ml->size(); i++) {
191     cout << ((*ml)[i]).string_of() << endl;
192   }
193
194   cout << "CONSTANTS" << endl;
195
196   vector<tunableBooleanConstant> allBoolConstants = tunableConstantRegistry::getAllBoolTunableConstants();
197   for (unsigned boollcv = 0; boollcv < allBoolConstants.size(); boollcv++) {
198      tunableBooleanConstant &tbc = allBoolConstants[boollcv];
199      cout << tbc.getName() << " = ";
200      if (tbc.getValue())
201         cout << "true" << endl;
202      else
203         cout << "false" << endl;
204   }
205
206   vector<tunableFloatConstant> allFloatConstants = tunableConstantRegistry::getAllFloatTunableConstants();
207   for (unsigned floatlcv = 0; floatlcv < allFloatConstants.size(); floatlcv++) {
208      tunableFloatConstant &tfc = allFloatConstants[floatlcv];
209
210      cout << tfc.getName() << " = " << tfc.getValue() << endl;
211   }
212
213   cout << "bucketWidth " << dataMgr->getCurrentBucketWidth() << endl;
214   cout << "number of buckets = " << dataMgr->getMaxBins() << endl;
215   dataMgr->printDaemons();
216   return TCL_OK;
217 }
218
219 int ParadynDetachCmd (ClientData,
220                       Tcl_Interp *,
221                       int,
222                       char **)
223 {
224   dataMgr->detachApplication(true);
225   return TCL_OK;
226 }
227
228 metricHandle *
229 StrToMetHandle (char *mstr)
230 {
231   metricHandle *mh = new metricHandle;
232   if (sscanf (mstr, "%u", mh) <= 0) {
233     delete mh;
234     return (metricHandle *) NULL;
235   }
236   else return mh;
237 }
238
239 char *
240 MetHandleToStr (metricHandle mh)
241 {
242   char *result = new char[12];
243   sprintf (result, "%u", mh);
244   return result;
245 }
246
247 int ParadynGetTotalCmd (ClientData,
248                      Tcl_Interp *,
249                      int argc,
250                      char *argv[])
251 {
252   metricHandle *met;
253   metricInstInfo *mi;
254   float val;
255
256   if (argc < 2) {
257     sprintf(interp->result, "USAGE: gettotal <metid>");
258     return TCL_ERROR;
259   }
260
261   if (!(met = dataMgr->findMetric (argv[1]))) {
262     Tcl_AppendElement (interp, "invalid metric identifier");
263     return TCL_ERROR;
264   }
265   
266   mi = uim_enabled.find((void *) *met);
267   if (!mi) {
268     Tcl_AppendResult (interp, "unable to find metric ", MetHandleToStr(*met),
269                       (char *)NULL);
270     delete met;
271     return TCL_ERROR;
272   }
273   else {
274     val = dataMgr->getTotValue(mi->mi_id);
275     sprintf(interp->result, "%g", val);
276     delete met;
277   }  
278   return TCL_OK;
279 }
280
281 int ParadynPrintCmd (ClientData,
282                      Tcl_Interp *,
283                      int,
284                      char *argv[])
285 {
286   if (argv[1][0] == 'm') {   // print metric
287     float val;
288     metricInstInfo *mi;
289     metricHandle *met;
290
291     if (! (met = dataMgr->findMetric (argv[2]))) {
292       Tcl_AppendElement (interp, "Invalid metric");
293       return TCL_ERROR;
294     }
295     mi = uim_enabled.find((void *) *met);
296
297     if (!mi) {
298       sprintf (interp->result, "unable to find metric %s\n", 
299                argv[2]);
300       delete met;
301       return TCL_ERROR;
302      } else {
303       val = dataMgr->getMetricValue(mi->mi_id);
304       printf ("metric %s, val = %f\n", 
305                dataMgr->getMetricName(*met), val);
306     }
307   } else {
308     sprintf (interp->result, "Unknown option: paradyn print %s\n", argv[1]);
309     return TCL_ERROR;
310   }
311   return TCL_OK;
312 }
313
314 void processUsage()
315 {
316   printf("USAGE: process <-user user> <-machine machine> <-daemon> daemon> <-dir> directory \"command\"\n");
317 }
318
319 /****
320  * Process
321  * Calls data manager service "addExecutable".  
322  * Returns TCL_OK or TCL_ERROR
323  *
324  * Note: when there is an error, we should store specific error codes
325  *       someplace (presumably, interp->result).  Why?  Because, right now,
326  *       any time there's an error in starting up, tcl code puts up an error dialog
327  *       box that is so generic as to be nearly useless to the user.
328  */
329 int ParadynAttachCmd(ClientData, Tcl_Interp *interp,
330                      int argc, char **argv) {
331    char *user = NULL;
332    char *machine = NULL;
333    char *paradynd = NULL;
334    int afterattach = 0; // 0 --> as is, 1 --> pause, 2 --> run
335
336    // cmd gives the path to the executable...used only to read the symbol table.
337    char *cmd = NULL; // program name
338
339    char *pidstr = NULL;
340
341    for (int i=1; i < argc-1; i++) {
342       if (0==strcmp("-user", argv[i]) && i+1 < argc) {
343          user = argv[++i];
344       }
345       else if (0==strcmp("-machine", argv[i]) && i+1 < argc) {
346          machine = argv[++i];
347       }
348       else if (0==strcmp("-daemon", argv[i]) && i+1 < argc) {
349          paradynd = argv[++i];
350       }
351       else if (0==strcmp("-command", argv[i]) && i+1 < argc) {
352          cmd = argv[++i];
353       }
354       else if (0==strcmp("-pid", argv[i]) && i+1 < argc) {
355          pidstr = argv[++i];
356       }
357       else if (0==strcmp("-afterattach", argv[i]) && i+1 < argc) {
358          const char *afterattachstr = argv[++i];
359          afterattach = atoi(afterattachstr);
360          if (afterattach < 0 || afterattach > 2) {
361             Tcl_SetResult(interp, "paradyn attach: bad -afterattach value: ", TCL_STATIC);
362             Tcl_AppendResult(interp, afterattachstr, NULL);
363             cerr << interp->result << endl;
364             return TCL_ERROR;
365          }
366       }
367       else {
368          Tcl_SetResult(interp, "paradyn attach: unrecognized option, or option missing required argument: ", TCL_STATIC);
369          Tcl_AppendResult(interp, argv[i], NULL);
370          cerr << interp->result << endl;
371          return TCL_ERROR;
372       }
373    }
374
375    if (pidstr == NULL && cmd == NULL) {
376       Tcl_SetResult(interp, "paradyn attach: at least one of the -pid and -command options are required", TCL_STATIC);
377       cerr << interp->result << endl;
378       return TCL_ERROR;
379    }
380
381    if (!app_name)
382       app_name = new status_line("Application name");
383
384    string theMessage;
385    if (cmd)
386       theMessage += string("program: ") + cmd + " ";
387
388    if (machine)
389       theMessage += string("machine: ") + machine + " ";
390    
391    if (user)
392       theMessage += string("user: ") + user + " ";
393
394    if (paradynd)
395       theMessage += string("daemon: ") + paradynd + " ";
396
397    app_name->message(theMessage.string_of());
398
399    if (!app_status) {
400       app_status = new status_line("Application status");
401    }
402   
403    // Disabling PAUSE and RUN during attach can help avoid deadlocks.
404    disablePAUSEandRUN();
405
406    // Note: the following is not an igen call to paradynd...just to the DM thread
407    if (!dataMgr->attach(machine, user, cmd, pidstr, paradynd, afterattach)) {
408       Tcl_SetResult(interp, "", TCL_STATIC);
409       return TCL_ERROR;
410    }
411
412    return TCL_OK;
413 }
414
415 int ParadynProcessCmd(ClientData,
416                       Tcl_Interp *interp,
417                       int argc,
418                       char *argv[])
419 {
420   char *user = NULL;
421   char *machine = NULL;
422   char *paradynd = NULL;
423   string idir;
424   int i;
425   
426   for (i=1; i < argc-1; i++) {
427     if (!strcmp("-user", argv[i])) {
428       if (i+1 == argc) {
429         processUsage();
430         return TCL_ERROR;
431       }
432       user = argv[++i];
433     } else if (!strcmp("-machine", argv[i])) {
434       if (i+1 == argc) {
435         processUsage();
436         return TCL_ERROR;
437       }
438       machine = argv[++i];
439     } else if (!strcmp("-daemon", argv[i])) {
440       if (i+1 == argc) {
441         processUsage();
442         return TCL_ERROR;
443       }
444       paradynd = argv[++i];
445     } else if (!strcmp("-dir", argv[i])) {
446       if (i+1 == argc) {
447         processUsage();
448         return TCL_ERROR;
449       }
450       idir = argv[++i];
451     } else if (argv[i][0] != '-') {
452       break;
453     } else {
454       processUsage();
455       return TCL_ERROR;
456     }
457   }
458
459   if (!app_name) {
460     app_name = new status_line("Application name");
461   }
462
463   static char tmp_buf[1024];
464   sprintf(tmp_buf, "program: %s, machine: %s, user: %s, daemon: %s",
465           argv[i], machine?machine:"(local)", user?user:"(self)",
466           paradynd?paradynd:"(defd)");
467   app_name->message(tmp_buf);
468
469   if (!app_status) {
470     app_status = new status_line("Application status");
471   }
472  
473   vector<string> av;
474   unsigned ve=i;
475   while (argv[ve]) {
476     av += argv[ve];
477     ve++;
478   }
479
480   // We disabled PAUSE and RUN buttons to avoid problems. If any of these
481   // keys is pressed while defining a process, we end in a deadlock - naim
482   disablePAUSEandRUN();
483
484   // At this point, we take a look at "idir"; if it starts with ~some_user_name,
485   // then we alter "idir".  In the spirit of Tcl_TildeSubst (tclGlob.c).
486   // The only reason we don't use Tcl_TildeSubst is because it uses Tcl_DStringFree,
487   // etc., where we much prefer to use the string class.
488
489   string dir = expand_tilde_pathname(idir); // idir --> "initial dir"
490
491   // Note: the following is not an igen call to paradynd...just to the DM thread.
492   if (dataMgr->addExecutable(machine, user, paradynd, dir.string_of(),
493                              &av) == false)
494   {
495     // NOTE: dataMgr->addExecutable isn't returning detailed-enough error
496     // code as a result, so we can't provide the user with good diagnostics
497     // when dataMgr->addExecutable() fails.  FIX THIS SITUATION BY MAKING THE RETURN VAL
498     // OF dataMgr->addExecutable() SOMETHING OTHER THAN JUST A BOOL.
499     // (Actually, this may not be such a huge problem because dataMgr->addExecutable
500     // or something it calls seems to be putting up the error dialog box window as soon
501     // as it encounters an error.)
502     Tcl_SetResult(interp, "", TCL_STATIC);
503
504     return TCL_ERROR;
505   }
506   else {
507     // We used to enable the RUN button here, but now the implementation has
508     // changed (we wait for DYNINSTinit to run).
509
510     return TCL_OK;
511   }
512 }
513
514 //
515 //  disable  <metid>
516 //
517 int ParadynDisableCmd (ClientData,
518                       Tcl_Interp *interp,
519                       int argc,
520                       char *argv[])
521 {
522   metricHandle *met;
523   metricInstInfo *mi;
524
525   // Hold Everything!
526   dataMgr->pauseApplication ();
527
528   if (argc < 2) {
529     sprintf(interp->result, "USAGE: disable <metid>");
530     return TCL_ERROR;
531   }
532
533   if (! (met = dataMgr->findMetric(argv[1]))) {
534     sprintf(interp->result, "Invalid metric %s", argv[1]);
535     return TCL_ERROR;
536   }
537
538   mi = uim_enabled.find((void *) *met);
539
540   if (!mi) {
541     sprintf (interp->result, "unable to find metric %s\n", 
542              MetHandleToStr(*met)); 
543     delete met;
544     return TCL_ERROR;
545   }
546   else {
547     // TODO: phase type should be entered as a command arg 
548     dataMgr->disableDataCollection (uim_ps_handle, 0, mi->mi_id,GlobalPhase);
549     delete met;
550   }
551   return TCL_OK;
552 }
553
554 //
555 //  enable <metric> ?<resource>? ...
556 //    returns metric id
557 //
558 int ParadynEnableCmd (ClientData,
559                       Tcl_Interp *interp,
560                       int argc,
561                       char *argv[])
562 {
563   metricHandle *met;
564   metricInstInfo *mi;
565   vector<resourceHandle> *resList;
566
567   // Hold Everything!
568   dataMgr->pauseApplication ();
569
570   // Build a resource list from the tcl list
571   if (argc == 2)
572     resList = dataMgr->getRootResources();
573   else {
574     char **argsv;
575     int argsc;
576     resourceHandle *res;
577
578     if (Tcl_SplitList(interp, argv[2], &argsc, &argsv) != TCL_OK) {
579       printf("Error parsing resource list '%s'", argv[2]);
580       return TCL_ERROR;
581     }
582
583     resList = new vector<resourceHandle>;
584     cout << "enable request for ";
585     for (int i = 0; i < argsc; i++) {
586       res = dataMgr->findResource(argsv[i]);
587       cout << argsv[i] << " ";
588       resList += *res;
589     }
590     cout << endl;
591     Tcl_Free((char*)argsv);
592   }
593
594   // Now check the metric
595   met = dataMgr->findMetric (argv[1]);
596   if (!met) {
597     sprintf (interp->result, "metric %s is not defined\n", argv[1]);
598     delete resList;
599     return TCL_ERROR;
600   }
601   else {
602
603     // Finally enable the data collection
604     // TODO: phaseType, and persistent flags should be command args
605     
606     vector<metric_focus_pair> *request = new vector<metric_focus_pair>;
607     metric_focus_pair new_request_entry(*met,*resList);
608     *request += new_request_entry;
609     assert(request->size() == 1);
610     // 0 is used as the second parameter for non-trace use 
611     dataMgr->enableDataRequest(uim_ps_handle,0,request,0,GlobalPhase,0,0,0,0);
612
613     // KLUDGE: wait for async response from DM
614     bool ready=false;
615     vector<metricInstInfo> *response;
616     // wait for response from DM
617     while(!ready){
618           T_dataManager::msg_buf buffer;
619           T_dataManager::message_tags waitTag;
620           tag_t tag = T_dataManager::enableDataCallback_REQ;
621           thread_t from;
622           int err = msg_poll(&from, &tag, true);
623           assert(err != THR_ERR);
624           if (dataMgr->isValidTag((T_dataManager::message_tags)tag)) {
625               waitTag = dataMgr->waitLoop(true,
626                         (T_dataManager::message_tags)tag,&buffer);
627               if(waitTag == T_dataManager::enableDataCallback_REQ){
628                   ready = true;
629                   response = buffer.enableDataCallback_call.response;
630                   buffer.enableDataCallback_call.response = 0;
631               }
632               else {
633                   cout << "error UI wait data enable resp:tag invalid" << endl;
634                   assert(0);
635               }
636           }
637           else{
638               cout << "error UI wait data enable resp:tag invalid" << endl;
639               assert(0);
640           }
641     } // while(!ready)
642     mi = 0;
643     // if this MI was successfully enabled
644     if(response && (*response)[0].successfully_enabled) {
645           mi = new metricInstInfo;
646           mi->successfully_enabled = (*response)[0].successfully_enabled;
647           mi->mi_id = (*response)[0].mi_id;
648           mi->m_id = (*response)[0].m_id;
649           mi->r_id = (*response)[0].r_id;
650           mi->metric_name = (*response)[0].metric_name;
651           mi->metric_units = (*response)[0].metric_units;
652           mi->focus_name = (*response)[0].focus_name;
653           mi->units_type = (*response)[0].units_type;
654     }
655
656     if (mi) {
657       uim_enabled.add(mi, (void *)mi->mi_id);
658       sprintf(interp->result, MetHandleToStr (mi->mi_id));
659       printf ("metric %s, id = %s\n", argv[1], MetHandleToStr(mi->mi_id));
660     } else {
661       sprintf (interp->result, "can't enable metric %s for focus \n", argv[1]);
662       return TCL_ERROR;
663     }
664   }
665   return TCL_OK;
666 }
667
668 int ParadynCoreCmd (ClientData,
669                     Tcl_Interp *,
670                     int argc,
671                     char *argv[])
672 {
673   int pid;
674
675   if (argc != 2) {
676     printf("usage: paradyn core <pid>\n");
677     return TCL_ERROR;
678   }
679   if (sscanf(argv[1],"%d",&pid) != 1) {
680     printf("usage: paradyn core <pid>\n");
681     return TCL_ERROR;
682   }
683
684   dataMgr->coreProcess(pid);
685   return TCL_OK;
686 }
687
688 int ParadynSetCmd (ClientData,
689                     Tcl_Interp *interp,
690                     int argc,
691                     char *argv[])
692 {
693   // args: <tunable-name> <new-val>
694   if (argc != 3) {
695     sprintf(interp->result,"USAGE: %s <variable> <value>", argv[0]);
696     return TCL_ERROR;
697   }
698
699   if (!tunableConstantRegistry::existsTunableConstant(argv[1])) {
700      cout << "Tunable constant " << argv[1] << " does not exist; cannot set its value to " << argv[2] << endl;
701      return TCL_ERROR;
702   }
703   
704   if (tunableConstantRegistry::getTunableConstantType(argv[1]) == tunableBoolean) {
705      int boolVal;
706      if (TCL_ERROR == Tcl_GetBoolean(interp, argv[2], &boolVal))
707         return TCL_ERROR;
708      else {
709         tunableConstantRegistry::setBoolTunableConstant(argv[1], (bool)boolVal);
710 //        cout << "tunable boolean constant " << argv[1] << " set to " << boolVal << endl;
711      }
712   }
713   else {
714      double doubleVal;
715      if (TCL_ERROR == Tcl_GetDouble(interp, argv[2], &doubleVal))
716         return TCL_ERROR;
717      else {
718         tunableConstantRegistry::setFloatTunableConstant(argv[1], (float)doubleVal);
719 //        cout << "tunable float constant " << argv[1] << " set to " << doubleVal << endl;
720      }
721   }
722
723   return TCL_OK;
724 }
725
726 extern abstractions *theAbstractions;
727 int ParadynWaSetAbstraction(ClientData, Tcl_Interp *interp,
728                             int argc, char **argv) {
729    if (argc != 2) {
730       cerr << "ParadynWaSetAbstraction: wrong # args" << endl;
731       return TCL_ERROR;
732    }
733    
734    assert(0==strcmp(argv[0], "waSetAbstraction"));
735    string absName = string(argv[1]);
736
737    int menuIndex = theAbstractions->name2index(absName);
738       // -1 if not found
739
740    if (menuIndex == -1) {
741       cout << "paradyn waSetAbstraction: could not change the abstraction to \"" << absName << "\" because it does not (yet?) exist" << endl;
742       return TCL_ERROR;
743    }
744
745    menuIndex++; // tcl menus are base 1 (0 is reserved for tearoff)
746
747    string commandStr = theAbstractions->getAbsMenuName() + " invoke " +
748                        string(menuIndex);
749    cout << "invoking menu item " << menuIndex << endl;
750
751    if (TCL_OK != Tcl_Eval(interp, (char*)commandStr.string_of())) {
752       cerr << interp->result << endl;
753       exit(5);
754    }
755
756    return TCL_OK;
757 }
758
759 int ParadynWaSelectUnselect(Tcl_Interp *interp,
760                             const char *name,
761                             bool selectFlag) {
762    if (!theAbstractions->existsCurrent())
763       return TCL_ERROR;
764
765    const bool found = theAbstractions->
766                       selectUnSelectFromFullPathName(name, selectFlag);
767    if (!found) {
768       if (selectFlag)
769          cout << "paradyn waSelect: ";
770       else
771          cout << "paradyn waUnselect: ";
772       cout << "could not find the item: " << name << endl;
773    }
774    else
775       initiateWhereAxisRedraw(interp, true); // whereAxisTcl.C
776
777    return TCL_OK;
778 }
779
780 int ParadynWaSelect(ClientData, Tcl_Interp *interp,
781                     int argc, char **argv) {
782    if (argc != 2) {
783       cerr << "ParadynWaSelect: too many arguments" << endl;
784       return TCL_ERROR;
785    }
786
787    assert(0==strcmp(argv[0], "waSelect"));
788    return ParadynWaSelectUnselect(interp, argv[1], true);
789 }
790
791 int ParadynWaUnSelect(ClientData, Tcl_Interp *interp,
792                     int argc, char **argv) {
793    if (argc != 2) {
794       cerr << "ParadynWaUnselect: too many arguments" << endl;
795       return TCL_ERROR;
796    }
797
798    assert(0==strcmp(argv[0], "waUnselect"));
799    return ParadynWaSelectUnselect(interp, argv[1], false);
800 }
801
802 int ParadynApplicationDefinedCmd(ClientData, Tcl_Interp *interp,
803                                  int, char **) {
804    // returns true iff an application has been defined
805    setResultBool(interp, dataMgr->applicationDefined());
806    return TCL_OK;
807 }
808                                 
809 int ParadynSuppressCmd (ClientData,
810                        Tcl_Interp *interp,
811                        int argc,
812                        char *argv[])
813 {
814   bool suppressInst, suppressChildren = false;
815
816   if (argc != 3) {
817     printf("Usage: paradyn suppress <search|inst|searchChildren> <resource list>\n");
818     return TCL_ERROR;
819   }
820   if (!strcmp(argv[1], "search")) {
821     suppressInst = false;
822     suppressChildren = false;
823   } else if (!strcmp(argv[1], "inst")) {
824     suppressInst = true;
825   } else if (!strcmp(argv[1], "searchChildren")) {
826     suppressInst = false;
827     suppressChildren = true;
828   } else {
829     printf("Usage: paradyn suppress <search|inst|searchChildren> <resource list>\n");
830     return TCL_ERROR;
831   }
832
833   {
834     char **argsv;
835     int argsc;
836     resourceHandle *res;
837     
838     if (Tcl_SplitList(interp, argv[2], &argsc, &argsv) != TCL_OK) {
839       printf("Error parsing resource list '%s'", argv[2]);
840       return TCL_ERROR;
841     }
842     
843     cout << "suppress request for ";
844     for (int i = 0; i < argsc; i++) {
845       res = dataMgr->findResource (argsv[i]);
846       cout << argsv[i];
847
848       if (res == NULL) {
849          cerr << "sorry, data manager could not findResource" << endl;
850          return TCL_ERROR;
851       }
852
853       if (suppressInst) {
854         dataMgr->setResourceInstSuppress(*res, true);
855       } else {
856         if (suppressChildren)
857           dataMgr->setResourceSearchChildrenSuppress(*res, true);
858         else
859           dataMgr->setResourceSearchSuppress(*res, true);
860       }
861       delete res;
862     }
863     cout << endl;
864     Tcl_Free((char*)argsv);
865     return TCL_OK;
866   }
867 }
868
869 int ParadynVisiCmd (ClientData,
870                     Tcl_Interp *interp,
871                     int argc,
872                     char *argv[])
873 {
874 //
875 //  @begin(barf)
876 //    This should be automated with a visi command 
877 //    dictionary or at least a switch statement.  --rbi
878 //  @end(barf)
879 //
880   if (argc < 2) {
881     sprintf(interp->result,
882             "USAGE: visi [kill <ivalue>|create <ivalue>|info|active<cmd>]");
883     return TCL_ERROR;
884   }
885   if (argv[1][0] == 'a') {
886     vector<VM_activeVisiInfo> *temp;
887
888     temp = vmMgr->VMActiveVisis();
889     for (unsigned i=0; i < temp->size(); i++) {
890       printf("active_info %d: name %s TypeId %d visiNum = %d\n",i,
891              ((*temp)[i]).name.string_of(),
892              ((*temp)[i]).visiTypeId,((*temp)[i]).visiNum);
893     }
894     delete temp;
895   }
896   else if (argv[1][0] == 'i') {
897       vector<VM_visiInfo> *visi_info;
898
899       visi_info = vmMgr->VMAvailableVisis();
900       for (unsigned i=0; i < visi_info->size();i++) {
901         printf("visi %d: name %s visiTypeId %d\n",i,
902                ((*visi_info)[i]).name.string_of(), 
903                ((*visi_info)[i]).visiTypeId);
904       }
905       delete visi_info;
906     } 
907   else if (argv[1][0] == 'c') {
908     int ok, i;
909     int j;
910     if (Tcl_GetInt (interp, argv[2], &i) != TCL_OK) 
911       return TCL_ERROR;
912     if (Tcl_GetInt (interp, argv[3], &j) != TCL_OK) 
913       return TCL_ERROR;
914     if(j == 1){
915         ok = vmMgr->VMCreateVisi(1,-1,i,CurrentPhase,NULL); 
916     }
917     else {
918         ok = vmMgr->VMCreateVisi(1,-1,i,GlobalPhase,NULL); 
919     }
920   } 
921   else if (argv[1][0] == 'k') {
922     int i;
923     if (Tcl_GetInt (interp, argv[2], &i) != TCL_OK) 
924       return TCL_ERROR;
925     vmMgr->VMDestroyVisi(i);
926   } 
927   else {
928     sprintf(interp->result,
929             "USAGE: visi [kill <ivalue>|create <ivalue>|info|active<cmd>]");
930     return TCL_ERROR;
931   }
932   return TCL_OK;
933 }
934
935 int ParadynSaveCmd (ClientData,
936                     Tcl_Interp *interp,
937                     int argc,
938                     char *argv[])
939 {
940   
941   if (argc == 4) {
942     if (!strcmp(argv[1], "data")) {
943       // "save data [global|phase|all] <dirname>" 
944       char *dirname = new char [strlen(argv[3])+1];
945       strcpy (dirname, argv[3]);
946       cout << "paradyn save " << dirname << " data all" << endl;
947       switch (argv[2][0]) {
948       case 'a':
949         dataMgr->saveAllData(dirname, All);
950         break;
951       case 'g':
952         dataMgr->saveAllData(dirname, Global);
953         break;
954       case 'p':
955         dataMgr->saveAllData(dirname, Phase);
956         break;
957       default:
958         sprintf(interp->result, 
959                 "USAGE: save data [global|phase|all] <dirname>\n");
960         return TCL_ERROR;
961       }
962       return TCL_OK;
963     } else if (!strcmp(argv[1], "resources")) {
964       // "save resources all <filename>"
965       char *fname = new char [strlen(argv[3])+1];
966       strcpy (fname, argv[3]);
967       dataMgr->saveAllResources(fname);
968       return TCL_OK;
969     } else if (!strcmp(argv[1], "shg")) {
970       // "save shg [global|phase]"
971       char *fname = new char [strlen(argv[3])+1];
972       strcpy (fname, argv[3]);
973       cout << "paradyn save " << argv[2] << fname << " shg" << endl;
974       if (!strcmp(argv[2], "phase"))
975         perfConsult->saveSHG(fname, 0);   // save phase shg(s)
976       else
977         perfConsult->saveSHG(fname, 1);   // save global shg
978       return TCL_OK;
979     }
980   }
981   sprintf(interp->result, 
982           "USAGE: save data [global|phase|all] <dirname>\n save resources all <file>\n save shg [global|phase|all] <dirname>\n");
983   return TCL_ERROR;
984 }
985
986 int ParadynDaemonStartInfoCmd(ClientData, Tcl_Interp *, int, char **) {
987   dataMgr->displayDaemonStartInfo();
988   return TCL_OK;
989 }
990
991 int ParadynGeneralInfoCmd(ClientData, Tcl_Interp *, int, char **) {
992   dataMgr->displayParadynGeneralInfo();
993   return TCL_OK;
994 }
995
996 int ParadynLicenseInfoCmd(ClientData, Tcl_Interp *, int, char **) {
997   dataMgr->displayParadynLicenseInfo();
998   return TCL_OK;
999 }
1000
1001 int ParadynReleaseInfoCmd(ClientData, Tcl_Interp *, int, char **) {
1002   dataMgr->displayParadynReleaseInfo();
1003   return TCL_OK;
1004 }
1005
1006 int ParadynVersionInfoCmd(ClientData, Tcl_Interp *, int, char **) {
1007   dataMgr->displayParadynVersionInfo();
1008   return TCL_OK;
1009 }
1010
1011 static struct cmdTabEntry Pd_Cmds[] = {
1012   {"applicationDefined", ParadynApplicationDefinedCmd},
1013   {"attach", ParadynAttachCmd},
1014   {"pause", ParadynPauseCmd},
1015   {"cont", ParadynContCmd},
1016   {"status", ParadynStatusCmd},
1017   {"list", ParadynListCmd},
1018   {"daemons", ParadynDaemonsCmd},
1019   {"detach", ParadynDetachCmd},
1020   {"disable", ParadynDisableCmd},
1021   {"enable", ParadynEnableCmd},
1022   {"gettotal", ParadynGetTotalCmd},
1023   {"metrics", ParadynMetricsCmd},
1024   {"print", ParadynPrintCmd},
1025   {"process", ParadynProcessCmd},
1026   {"resources", ParadynResourcesCmd},
1027   {"set", ParadynSetCmd},
1028   {"save", ParadynSaveCmd},
1029   {"core", ParadynCoreCmd},
1030   {"suppress", ParadynSuppressCmd},
1031   {"visi", ParadynVisiCmd},
1032   {"waSetAbstraction", ParadynWaSetAbstraction},
1033   {"waSelect", ParadynWaSelect},
1034   {"waUnselect", ParadynWaUnSelect},
1035   {"daemonStartInfo", ParadynDaemonStartInfoCmd},
1036   {"generalInfo", ParadynGeneralInfoCmd},
1037   {"licenseInfo", ParadynLicenseInfoCmd},
1038   {"releaseInfo", ParadynReleaseInfoCmd},
1039   {"versionInfo", ParadynVersionInfoCmd},
1040   {NULL, NULL}
1041 };
1042
1043 int ParadynCmd(ClientData clientData, 
1044                 Tcl_Interp *interp, 
1045                 int argc, 
1046                 char *argv[])
1047 {
1048   int i;
1049
1050   if (argc < 2) {
1051     sprintf(interp->result,"USAGE: %s <cmd>", argv[0]);
1052     return TCL_ERROR;
1053   }
1054
1055   for (i = 0; Pd_Cmds[i].cmdname; i++) {
1056     if (strcmp(Pd_Cmds[i].cmdname,argv[1]) == 0) {
1057       return ((Pd_Cmds[i].func)(clientData,interp,argc-1,argv+1));      
1058       }
1059   }
1060
1061   sprintf(interp->result,"unknown paradyn cmd '%s'",argv[1]);
1062   return TCL_ERROR;  
1063 }