fixed some resizing bugs
[dyninst.git] / visiClients / barchart / dg2.C
1 // dg2.C
2 // customized (for barchart) version of DGclient.C in tclVisi directory
3
4 /* $Log: dg2.C,v $
5 /* Revision 1.3  1994/10/10 14:36:18  tamches
6 /* fixed some resizing bugs
7 /*
8  * Revision 1.2  1994/09/29  20:05:39  tamches
9  * minor cvs fixes
10  *
11  * Revision 1.1  1994/09/29  19:52:25  tamches
12  * initial implementation.
13  * This is a modified version of DGclient.C (tclVisi/src), specially
14  * tuned for the barchart program.
15  *
16 */
17
18 // An updated version of DGClient.C for barchart2.C
19 // Contains several **deletions** to remove blt_barchart influences
20
21 #include <stdlib.h> // exit()
22 #include <iostream.h>
23 #include <tcl.h>
24 #include <tk.h>
25 #include "dg2.h"
26 #include "visi/h/visualization.h"
27 #include "barChartTcl.h"
28 #include "barChart.h"
29
30 void my_visi_callback(void* arg0, int* arg1, long unsigned int* arg2) {
31     if (visi_callback() == -1)
32        exit(0);
33 }
34
35 int Dg2AddMetricsCallback(int dummy) {
36   int retval = Tcl_Eval(MainInterp, "DgConfigCallback");
37   if (retval == TCL_ERROR)
38      fprintf(stderr, "%s\n", MainInterp->result);
39
40   // if necessary, the tcl program will call xAxisHasChanged and/or yAxisHasChanged, which
41   // are commands we implement in barChart.C.
42   // We take action then.
43
44   return(retval);
45 }
46
47 //int Dg2NewDataCallbackGeneral(int dummy) {
48 //   // A fairly general new-data handler; is smart enough to
49 //   // know when and if a **range** of values needs to be redrawn
50 //   // (perhaps because we've fallen behind?) as opposed to just
51 //   // the latest value --- the histogram would need this, for
52 //   // example (to avoid gaps), but the barchart can always just use
53 //   // the most recent value and not care if it's fallen behind...
54 //
55 //   // A more specific one is actually in use at the moment; it
56 //   // is Dg2NewDataCallback().  I haven't deleted the source code for
57 //   // this guy since it's potentially useful for visis other than
58 //   // the barchart.
59 //
60 //   // I have, however, removed the "DgValidCallback" from the original
61 //   // DGclient.C
62 //
63 //   static LastBucket = 0; // this very important STATIC variable keeps
64 //                          // track of the last bucket number we've processed.
65 //                          // We'll be sending a data-callback on range
66 //                          // LastBucket+1 thru what we see as the latest bucket
67 //                          // which has been filled with data.  Presumably, if
68 //                          // we keep up, this'll always be the range
69 //                          // (LastBucket+1, LastBucket+1).
70 //
71 //   // set "thislast" to dataGrid[m][r].LastBucketFilled() for the first
72 //   // datagrid element we find with the Valid bit set to true...
73 //   int thislast = findMostRecentBucket();
74 //
75 //   // There are no more "DgValidCallback" calls, since barchart never
76 //   // seemed to use them in the first place...
77 //
78 //   if (thislast < LastBucket)
79 //      LastBucket = thislast-1; // will rarely if ever happen; just to avoid sending
80 //                               // an empty range...
81 //
82 //   if (thislast >= 0) {
83 //      // send a data-callback on range (LastBucket+1, thislast)
84 //      // This is where the previous version of Dg would invoke
85 //      // the tcl script DgDataCallback.  Now that we're C++, we don't
86 //      // do that.
87 //
88 //      UsersNewDataCallbackRoutine(LastBucket+1, thislast);
89 //
90 //      LastBucket = thislast;
91 //   }
92 //
93 //   return TCL_OK;
94 //}
95
96 int Dg2Fold(int dummy) {
97   int retval = Tcl_Eval(MainInterp, "DgFoldCallback");
98   if (retval == TCL_ERROR)
99     fprintf(stderr, "%s\n", MainInterp->result);
100
101   return(retval);
102 }
103
104 int Dg2InvalidMetricsOrResources(int dummy) {
105   int retval = Tcl_Eval(MainInterp, "DgInvalidCallback");
106   if (retval == TCL_ERROR)
107     fprintf(stderr, "%s\n", MainInterp->result);
108
109   return(retval);
110 }
111
112 int Dg2PhaseNameCallback(int dummy) {
113   int retval = Tcl_Eval(MainInterp, "DgPhaseCallback");
114   if (retval == TCL_ERROR)
115     fprintf(stderr, "%s\n", MainInterp->result);
116
117   return(retval);
118 }
119
120 #define   AGGREGATE        0
121 #define   BINWIDTH         1
122 #define   FOLDMETHOD       2
123 #define   METRICNAME       3
124 #define   METRICUNITS      4
125 #define   NUMBINS          5
126 #define   NUMMETRICS       6
127 #define   NUMRESOURCES     7
128 #define   DEFINEPHASE      8
129 #define   RESOURCENAME     9
130 #define   STARTSTREAM      10
131 #define   STOPSTREAM       11
132 #define   DGSUM            12
133 #define   DGVALID          13
134 #define   VALUE            14
135 #define   CMDERROR         15
136 #define   LASTBUCKET       16
137 #define   FIRSTBUCKET      18
138
139 struct cmdTabEntry 
140 {
141   char *cmdname;
142   int index;
143   int numargs;
144 };
145
146 static struct cmdTabEntry Dg_Cmds[] = {
147   {"aggregate",    AGGREGATE,       2},
148   {"binwidth",     BINWIDTH,        0},
149   {"firstbucket",  FIRSTBUCKET,      2},
150   {"foldmethod",   FOLDMETHOD,      2},
151   {"lastbucket",   LASTBUCKET,      2},
152   {"metricname",   METRICNAME,      1},
153   {"metricunits",  METRICUNITS,     1},
154   {"numbins",      NUMBINS,         0},
155   {"nummetrics",   NUMMETRICS,      0},
156   {"numresources", NUMRESOURCES,    0},
157   {"phase",        DEFINEPHASE,     3},
158   {"resourcename", RESOURCENAME,    1},
159   {"start",        STARTSTREAM,     2},
160   {"stop",         STOPSTREAM,      2},
161   {"sum",          DGSUM,           2},
162   {"valid",        DGVALID,         2},
163   {"value",        VALUE,           3},
164   {NULL,           CMDERROR,        0}
165 };
166
167 int findCommand(Tcl_Interp *interp, 
168                        int argc, 
169                        char *argv[]) {
170
171   if (argc == 0) {
172      sprintf(interp->result, "USAGE: Dg <option> [args...]\n");
173      return CMDERROR;
174   }
175
176   for (cmdTabEntry *C = Dg_Cmds; C->cmdname!=NULL; C++) {
177      if (strcmp(argv[0], C->cmdname) == 0) {
178         if (argc-1 == C->numargs) 
179            return C->index; // successful parsing
180
181         sprintf(interp->result, 
182               "%s: wrong number of args (%d). Should be %d\n",
183               argv[0], argc-1, C->numargs);
184         return CMDERROR;
185      }
186   }
187
188   sprintf(interp->result, "unknown option (%s)\n", argv[0]);
189   return CMDERROR;
190 }
191
192 int Dg_TclCommand(ClientData clientData,
193                Tcl_Interp *interp, 
194                int argc, 
195                char *argv[]) {
196   // entrypoint to the tcl "Dg" command we've installed
197   // all the sprintf()'s are rather slow...
198
199   // parse the arguments, using the global variable Dg_Cmds[] to tell what's what.
200   int cmdDex = findCommand(interp, argc-1, argv+1);
201   if (cmdDex == CMDERROR)
202     return TCL_ERROR;
203
204   int m, r, buck; // metric number, resource number, bucket number
205
206   switch(cmdDex) {
207   case AGGREGATE:   
208     m = atoi(argv[2]);
209     r = atoi(argv[3]);
210     sprintf(interp->result,"%g", dataGrid.AggregateValue(m,r));
211     return TCL_OK;
212
213   case BINWIDTH:     
214     sprintf(interp->result, "%g", dataGrid.BinWidth());
215     return TCL_OK;
216
217   case FIRSTBUCKET:
218     m = atoi(argv[2]);
219     r = atoi(argv[3]);
220     sprintf(interp->result,"%d", dataGrid[m][r].FirstValidBucket()); 
221     return TCL_OK;
222
223   case FOLDMETHOD:
224     m = atoi(argv[2]);
225     sprintf(interp->result,"%d", dataGrid.FoldMethod(m));
226     return TCL_OK;
227
228   case LASTBUCKET:
229     m = atoi(argv[2]);
230     r = atoi(argv[3]);
231     sprintf(interp->result,"%d", dataGrid[m][r].LastBucketFilled());
232     return TCL_OK;
233
234   case METRICNAME:  
235     m = atoi(argv[2]);
236     sprintf(interp->result, "%s", dataGrid.MetricName(m));
237     return TCL_OK;
238
239   case METRICUNITS:  
240     m = atoi(argv[2]);
241     sprintf(interp->result, "%s", dataGrid.MetricUnits(m));
242     return TCL_OK;
243
244   case NUMBINS:     
245     sprintf(interp->result, "%d", dataGrid.NumBins());
246     return TCL_OK;
247
248   case NUMMETRICS:  
249     sprintf(interp->result, "%d", dataGrid.NumMetrics());
250     return TCL_OK;
251
252   case NUMRESOURCES:
253     sprintf(interp->result, "%d", dataGrid.NumResources());
254     return TCL_OK;
255
256   case DEFINEPHASE:       
257     NamePhase(atof(argv[2]), atof(argv[3]), argv[4]);
258     return TCL_OK;
259
260   case RESOURCENAME:
261     r = atoi(argv[2]);
262     sprintf(interp->result, "%s", dataGrid.ResourceName(r));
263     return TCL_OK;
264
265   case STARTSTREAM:       
266     GetMetsRes(argv[2], atoi(argv[3]), 0); // 0-->histogram (1-->scalar)
267                                            // argv[3] is num
268     return TCL_OK;
269
270   case STOPSTREAM:
271     m = atoi(argv[2]);
272     r = atoi(argv[3]);
273     StopMetRes(m, r);
274     return TCL_OK;
275
276   case DGSUM:         
277     m = atoi(argv[2]);
278     r = atoi(argv[3]);
279     sprintf(interp->result,"%g", dataGrid.SumValue(m,r));
280     return TCL_OK;
281
282   case DGVALID:
283     m = atoi(argv[2]);
284     r = atoi(argv[3]);
285     sprintf(interp->result, "%d", dataGrid.Valid(m,r));
286     return TCL_OK;
287
288   case VALUE:       
289     m = atoi(argv[2]);
290     r = atoi(argv[3]);
291     buck = atoi(argv[4]);
292     sprintf(interp->result,"%g", dataGrid[m][r].Value(buck));
293     return TCL_OK;
294   }
295
296   sprintf(interp->result, "Internal error (func findCommand)\n");
297   return TCL_ERROR;
298 }
299
300 void (*UsersNewDataCallbackRoutine)(int firstBucket, int lastBucket);
301    // we will call this routine for you when we get a new-data callback
302    // from the visi lib (first, we do a bit of processing for you, such
303    // as determining what the range is buckets you haven't seen yet is).
304
305 //int Dg2_Init(Tcl_Interp *interp, void (*userDataCallbackRoutine)(int, int)) {
306 int Dg2_Init(Tcl_Interp *interp) {
307    // initialize with the visi lib
308    int fd = VisiInit();
309    if (fd < 0) {
310       cerr << "Dg2_Init() -- could not initialize with the visi lib" << endl;
311       exit(5);
312    }
313
314    // Arrange for my_visi_callback() to be called whenever there is data waiting
315    // to be read off of descriptor "fd".  Extremely important! [tcl book page 357]
316    Tk_CreateFileHandler(fd, TK_READABLE, (Tk_FileProc *) my_visi_callback, 0);
317
318    // Register C++ Callback routines with the visi lib when
319    // certain events happen.  The most important (performance-wise)
320    // is the DATAVALUES callback, which signals the arrival of
321    // new barchart data.  We must process this callback very quickly,
322    // in order to perturb the system as little as possible.
323
324    if (RegistrationCallback(ADDMETRICSRESOURCES, Dg2AddMetricsCallback) != 0) {
325       cerr << "Dg2_Init() -- couldn't install ADDMETRICSRESOURCES callback with visilib" << endl;
326       exit(5);
327    }
328
329    if (RegistrationCallback(FOLD, Dg2Fold) != 0) {
330       cerr << "Dg2_Init() -- couldn't install FOLD callback with visilib" << endl;
331       exit(5);
332    }
333
334    if (RegistrationCallback(INVALIDMETRICSRESOURCES, Dg2InvalidMetricsOrResources) != 0) {
335       cerr << "Dg2_Init() -- couldn't install INVALID callback with visilib" << endl;
336       exit(5);
337    }
338
339    if (RegistrationCallback(PHASENAME, Dg2PhaseNameCallback) != 0) {
340       cerr << "Dg2_Init() -- couldn't install PHASENAME callback with visilib" << endl;
341       exit(5);
342    }
343
344    if (RegistrationCallback(DATAVALUES, Dg2NewDataCallback) != 0) {
345       cerr << "Dg2_Init() -- couldn't install DATAVALUES callback with visilib" << endl;
346       exit(5);
347    }
348
349    (void) StartVisi(0, NULL); // presently, the return value is undefined
350
351    // install "Dg" as a new tcl command; Dg_TclCommand() will be invoked when a script
352    // calls Dg.
353    Tcl_CreateCommand(interp, "Dg", Dg_TclCommand, 
354                     (ClientData *) NULL,(Tcl_CmdDeleteProc *) NULL);
355  
356    return TCL_OK;
357 }