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