667a27030b0369b048422647e3ffa8e2e156d308
[ghc-hetmet.git] / ghc / utils / prof / cgprof / daVinci.c
1 /* ------------------------------------------------------------------------
2  * $Id: daVinci.c,v 1.1 2000/04/05 10:06:36 simonmar Exp $
3  *                                                                      
4  *      Copyright (C) 1995-2000 University of Oxford
5  *                                                                      
6  * Permission to use, copy, modify, and distribute this software,
7  * and to incorporate it, in whole or in part, into other software,
8  * is hereby granted without fee, provided that
9  *   (1) the above copyright notice and this permission notice appear in
10  *       all copies of the source code, and the above copyright notice
11  *       appear in clearly visible form on all supporting documentation
12  *       and distribution media;
13  *   (2) modified versions of this software be accompanied by a complete
14  *       change history describing author, date, and modifications made;
15  *       and
16  *   (3) any redistribution of the software, in original or modified
17  *       form, be without fee and subject to these same conditions.
18  * --------------------------------------------------------------------- */
19
20 #include "daVinci.h"
21 #include <stdarg.h>
22 #include <string.h>
23
24 static char* extra_space(int);
25 static void recur_graphToDaVinci(int,Matrix *, Matrix *,char*,int);
26 static char *parse_word(char**);
27 static char *parse_quoted(char**);
28 static char *dup_str(char*);
29 double this_total_time,
30        this_total_comp_max, this_total_comp_avg,
31        this_total_comm_max, this_total_comm_avg, 
32        this_total_comp_idle_max, this_total_comp_idle_avg;
33 long int this_hrel_max, this_hrel_avg;
34 int  this_syncs;
35
36 char *lastDavinciCmd;
37
38 /* -----------------------------------------------------------------------------
39  * Send a command with ok return value daVinci
40  * -------------------------------------------------------------------------- */
41
42 void cmdDaVinci(char* format,...) {
43   static char xs[MAX_PROFILE_LINE_LENGTH];
44   va_list args;
45
46   va_start(args, format);
47   vfprintf(stdout, format, args);
48   fprintf(stdout, "\n");
49   va_end(args);
50   fflush(stdout); 
51   lastDavinciCmd = format;
52 }
53
54 /* -----------------------------------------------------------------------------
55  * Initialise daVinci
56  * -------------------------------------------------------------------------- */
57
58 void initDaVinci() {
59   cmdDaVinci("window(title(\"GHC profiler: cost-centre-stack view\"))\n");
60   cmdDaVinci("set(font_size(8))");  
61   cmdDaVinci("set(animation_speed(0))");
62   cmdDaVinci("set(scrolling_on_selection(false))");
63   /* SAJ */
64   /* cmdDaVinci("set(no_cache(true)))"); */
65   cmdDaVinci("app_menu(create_icons(["
66                   "icon_entry(\"delete\","
67                              "\"delete.xbm\","
68                              "\"Delete node and its children\"),"
69                   "icon_entry(\"undo\","
70                              "\"undo.xbm\","
71                              "\"Undo delete\"),"
72                   "blank,"
73                   "icon_entry(\"time\","
74                              "\"time.xbm\","
75                              "\"Cost metric view\"),"
76                   "icon_entry(\"percent\","
77                              "\"percent.xbm\","
78                              "\"Percentage view\"),"
79                   "blank,"
80                   "icon_entry(\"compress\","
81                              "\"compress.xbm\","
82                              "\"Compressed node view\"),"
83                   "icon_entry(\"uncompress\","
84                              "\"uncompress.xbm\","
85                              "\"Uncompressed node view\"),"
86                   "blank,"
87                   "icon_entry(\"absolute\","
88                              "\"absolute.xbm\","
89                              "\"Display inherited profile results\"),"
90                   "icon_entry(\"absdelta\","
91                              "\"absdelta.xbm\","
92                              "\"Display flat profile results\"),"
93                   "icon_entry(\"reldelta\","
94                              "\"reldelta.xbm\","
95                              "\"Trim zero-cost sub-trees\"),"
96                   "icon_entry(\"weightdelta\","
97                              "\"weightdelta.xbm\","
98                              "\"Trim zero-cost nodes\"),"
99                   "blank,"
100                   "icon_entry(\"sync\","
101                              "\"sync.xbm\","
102                              "\"Graph view\"),"
103                   "icon_entry(\"comp\","
104                              "\"comp.xbm\","
105                              "\"SCCs critical path\"),"
106                   "icon_entry(\"comm\","
107                              "\"comm.xbm\","
108                              "\"Computation time critical path\"),"
109                   "icon_entry(\"wait\","
110                              "\"wait.xbm\","
111                              "\"Heap usage critical path\"),"
112                   "icon_entry(\"hrel\","
113                              "\"hrel.xbm\","
114                              "\"Node spy\"),"
115                   "blank,"
116                   "icon_entry(\"help\","
117                              "\"help.xbm\","
118                              "\"Help\"),"
119               "]))");
120
121   activateDaVinciMenu("default");     
122   cmdDaVinci("app_menu(create_menus([menu_entry_mne(\"jump\",\"Goto a node\",\"G\",control,\"G\")]))\n");
123   /* SAJ */
124   // cmdDaVinci("app_menu(activate_menus([\"jump\"]))"); 
125 }
126
127 /* -----------------------------------------------------------------------------
128  * Menu FSM
129  * -------------------------------------------------------------------------- */
130
131 void activateDaVinciMenu(char *pressed) {
132   static int compress=1,time=1,critical_type=0,critical=0,undo=1,delete=0;
133
134   if (strcmp(pressed,"absolute")==0)    critical_type=0;
135   if (strcmp(pressed,"absdelta")==0)    critical_type=1;
136   if (strcmp(pressed,"reldelta")==0)    critical_type=2;
137   if (strcmp(pressed,"weightdelta")==0) critical_type=3;
138
139   if (strcmp(pressed,"sync")==0)  critical=0;
140   if (strcmp(pressed,"comp")==0)  critical=1;
141   if (strcmp(pressed,"comm")==0)  critical=2;
142   if (strcmp(pressed,"wait")==0)  critical=3;
143   if (strcmp(pressed,"hrel")==0)  critical=4;
144
145   if (strcmp(pressed,"compress")==0 || strcmp(pressed,"uncompress")==0) 
146     compress=!compress;
147
148   if (strcmp(pressed,"time")==0 || strcmp(pressed,"percent")==0)
149     time=!time;
150
151   if (strcmp(pressed,"undo")==0)   {undo=!undo;}
152   if (strcmp(pressed,"delete")==0) {delete=!delete;}
153
154   printf("app_menu(activate_icons([");
155   if (critical_type!=0) printf("\"absolute\",");
156   if (critical_type!=1) printf("\"absdelta\",");
157   if (critical_type!=2) printf("\"reldelta\",");
158   if (critical_type!=3) printf("\"weightdelta\",");
159
160   if (critical!=0) printf("\"sync\",");
161   if (critical!=1) printf("\"comp\",");
162   if (critical!=2) printf("\"comm\",");
163   if (critical!=3) printf("\"wait\",");
164   if (critical!=4) printf("\"hrel\",");
165
166   if (!compress)   printf("\"compress\",");
167   if (compress)    printf("\"uncompress\",");
168   if (!time)       printf("\"time\",");
169   if (time)        printf("\"percent\",");
170   if (!delete)     printf("\"delete\",");
171   if (!undo)       printf("\"undo\",");
172   
173   cmdDaVinci("\"help\"]))");  
174 }
175
176 /* -----------------------------------------------------------------------------
177  * Graph to daVinci
178  * -------------------------------------------------------------------------- */
179
180 void graphToDaVinci(int root,Matrix *graph, Matrix *costs, int removezerocosts) {
181   int i,j;
182   object_cost *ptr;
183   char zeronodes[MAX_PROFILE_LINE_LENGTH*2];     // is this a sen. MAX
184   char TEMPzeronodes[MAX_PROFILE_LINE_LENGTH*2];
185   char* p_zeronodes = zeronodes;
186   char* TEMPp_zeronodes = TEMPzeronodes;
187  
188   printf("graph(new([");
189   if (PrintLogo) {
190     /* I have implemented some name changes here. They are purely for output and */
191     /* following the relation (comp = scc, comm = ticks, wait = bytes            */
192     printf("l(\"info\",n(\"\",["
193            "a(\"COLOR\",\"gold\"),"
194            "a(\"FONTFAMILY\",\"courier\"),"
195            //"a(\"_GO\",\"icon\"),"
196            //"a(\"ICONFILE\",\"oxpara.xbm\"),"
197            "a(\"OBJECT\",\""
198            "Program statistics\\n\\n"
199            "Time elapsed     =  %6.2f ticks\\n"
200            "Heap usage       =  %6.2f bytes\\n"
201            "Total scc count  =  %6.2f (scc)\\n"
202            "\")],[])),",
203            TotalComm,TotalCompIdle,
204            TotalComp
205            );
206   } 
207
208   if (root==-1) {
209     printf("]))\n");
210   } else {
211     ptr = &Mat(object_cost,*costs,root,0);
212     this_total_comp_max     = ptr->comp_max;
213     this_total_comp_avg     = ptr->comp_avg;
214     this_total_comm_max     = ptr->comm_max;
215     this_total_comm_avg     = ptr->comm_avg;
216     this_total_comp_idle_max= ptr->comp_idle_max;
217     this_total_comp_idle_avg= ptr->comp_idle_avg;
218     this_total_time         = 0.00001 + 
219                               this_total_comp_max+ this_total_comm_max;
220     this_hrel_max       = ptr->hrel_max;
221     this_hrel_avg       = ptr->hrel_avg;
222     this_syncs          = ptr->syncs;
223     recur_graphToDaVinci(root,graph,costs,p_zeronodes,removezerocosts);
224
225     printf("]))\n");
226     fflush(stdout);
227     cmdDaVinci("special(focus_node(\"%d\"))\n",root);
228
229     /* graph will have been altered so that visted elements are marked
230        by a negative value. These are reset */
231     for(i=0;i<graph->rows;i++) {
232       for(j=0;j<graph->cols;j++) {
233         if (Mat_dense(*graph,i,j))
234           if (Mat(int,*graph,i,j)<0) Mat(int,*graph,i,j)=1;
235       }
236     }
237
238     if (removezerocosts==1)
239     {
240       if (strlen(p_zeronodes)>0) 
241          { strncpy(TEMPp_zeronodes,p_zeronodes,strlen(p_zeronodes)-1);
242            printf("select_nodes_labels([%s])\n",TEMPp_zeronodes);
243          }
244       strcpy(TEMPp_zeronodes,"");
245       strcpy(p_zeronodes,"");
246     }
247   }
248 }
249
250 static char *printCompressNode(int node, object_cost *ptr) {
251   char name[MAX_FUNNAME+20];
252   char comp[MAX_FUNNAME+20];
253   char comm[MAX_FUNNAME+20];
254   static char res[(MAX_FUNNAME+20)*4];
255   char tempstring[MAX_FUNNAME+20];
256   char *padding;
257   int width=0,x;
258   char delimiter[] = "&";
259
260   if (symbol_table[node].type==CG_SSTEP) 
261     sprintf(name,"%d %s",
262             symbol_table[node].lineno,symbol_table[node].filename);
263   else
264   { 
265     strcpy(tempstring,symbol_table[node].filename);
266     sprintf(name,"%s",strtok(tempstring,delimiter));
267   }  
268
269   if (NodeviewTime) {
270     /* changed this for GHC stats */
271     sprintf(comp,"\\nTime  %6.2fticks\\n",ptr->comm_max);
272     sprintf(comm,"Bytes %6.2funits",ptr->comp_idle_max);
273   } else {
274     sprintf(comp,"\\nTime  %6.2f%%\\n",(ptr->comm_max/TotalComm)*100.0);
275     sprintf(comm,"Bytes %6.2f%%",(ptr->comp_idle_max/TotalCompIdle)*100.0);
276   }
277   /* Slightly arbitrary choice for max display length of CC string */
278   /* If it is larger than this the display nodes look bad */
279   if (strlen(name)>20) name[20]='\0';
280   x=strlen(name);
281   if (((20-(strlen(name)+3))/2)>19)
282      padding = extra_space(0);
283   else
284      padding = extra_space((20-(strlen(name)+3))/2); /* includes \\n */
285   strcpy(res,padding);
286   strcat(res,name);
287   strcat(res,comp);
288   strcat(res,comm);
289   return res;
290 }
291
292 static char *printUncompressNode(int node, object_cost *ptr) {
293   char name   [MAX_FUNNAME+40];
294   char module [MAX_FUNNAME+40];
295   char group  [MAX_FUNNAME+40];
296   char syncs[MAX_FUNNAME+40];
297   char head [MAX_FUNNAME+40];
298   char comp [MAX_FUNNAME+40];
299   char comm [MAX_FUNNAME+40];
300   char wait [MAX_FUNNAME+40];
301   char hrel [MAX_FUNNAME+40];
302   char tempstring[MAX_FUNNAME+20];
303   char tempstring2[MAX_FUNNAME+20];
304   char *tempstring3;
305   char *tempstring5;
306   char tempstring4[MAX_FUNNAME+20];
307   char delimiter[] = "&";
308
309
310   static char res[(MAX_FUNNAME+40)*7];
311   char *padding;
312   int width=0,x;
313
314   if (symbol_table[node].type==CG_SSTEP) 
315     sprintf(name,"%s line %d\\n",
316             symbol_table[node].filename,symbol_table[node].lineno);
317   else
318   {
319     strcpy(tempstring,symbol_table[node].filename);
320     strcpy(tempstring2,symbol_table[node].filename);
321     sprintf(name,"%s",strtok(tempstring,delimiter));
322     strcpy(tempstring4,tempstring2);
323     tempstring5 = strpbrk(tempstring4,delimiter);
324     sprintf(module,"%s",strtok(tempstring5+1,delimiter));
325     tempstring3 = strrchr(tempstring2,'&');
326     sprintf(group,"%s",tempstring3+1);
327   }
328
329   sprintf(syncs,"");
330   if (NodeviewTime) {
331
332     sprintf(head, "Metric   Total  \\n");
333     sprintf(comp, " Time    %6.2ft \\n",ptr->comm_max);
334     sprintf(comm, " Bytes   %6.2fu \\n",ptr->comp_idle_max);
335     sprintf(wait, " SCC     %6.2fc \\n",ptr->comp_max);
336
337
338   } else {
339
340     sprintf(head, "Metric   Total  \\n");
341     sprintf(comp, " Time    %5.1f%% \\n",100.0*SAFEDIV(ptr->comm_max,TotalComm));
342     sprintf(comm, " Bytes   %5.1f%% \\n",100.0*SAFEDIV(ptr->comp_idle_max,TotalCompIdle));
343     sprintf(wait, " SCC     %5.1f%% \\n",100.0*SAFEDIV(ptr->comp_max,TotalComp));
344
345   }
346           
347   if ((x=strlen(name))>width)  width=x;
348   if ((x=strlen(hrel))>width)  width=x;
349   padding = extra_space((width-strlen(name)+3)/2); /* includes \\n */
350   /* strcpy(res,padding); */
351   strcpy(res,"Cost centre: ");
352   strcat(res,name);
353   strcat(res,"\\n");
354   strcat(res,"Module     : ");
355   strcat(res,module);
356   strcat(res,"\\n");
357   strcat(res,"Group      : ");
358   strcat(res,group);
359   strcat(res,"\\n\\n");
360  
361   /* padding = extra_space((width-strlen(syncs)+3)/2); */
362   //strcat(res,padding);
363   strcat(res,syncs);
364   strcat(res,head);
365   strcat(res,comp);
366   strcat(res,comm);
367   strcat(res,wait);
368   /* strcat(res,hrel); */
369   return res;
370 }
371
372
373 double nodeColour(object_cost *cost) {
374
375   switch (CriticalPath + CriticalType) {
376   case CRITTYPE_ABSOLUTE+CRITICAL_SYNCS:      
377   case CRITTYPE_ABSDELTA+CRITICAL_SYNCS:      
378   case CRITTYPE_RELDELTA+CRITICAL_SYNCS:      
379   case CRITTYPE_WEIGHTDELTA+CRITICAL_SYNCS:
380     return SAFEDIV(((double)cost->syncs),((double)this_syncs));
381
382   case CRITTYPE_ABSOLUTE+CRITICAL_COMP:       
383     return SAFEDIV(cost->comp_max,this_total_comp_max);
384
385   case CRITTYPE_ABSOLUTE+CRITICAL_COMM:       
386     return SAFEDIV(cost->comm_max,this_total_comm_max);
387
388   case CRITTYPE_ABSOLUTE+CRITICAL_WAIT:       
389     return SAFEDIV(cost->comp_idle_max,this_total_comp_idle_max);
390
391   case CRITTYPE_ABSOLUTE+CRITICAL_HREL:       
392     return SAFEDIV(((double) cost->hrel_max),((double)this_hrel_max));
393
394   case CRITTYPE_ABSDELTA+CRITICAL_COMP:
395     return SAFEDIV(cost->comp_max,TotalComp);
396
397   case CRITTYPE_ABSDELTA+CRITICAL_COMM:
398     return SAFEDIV(cost->comm_max,TotalComm);
399
400   case CRITTYPE_ABSDELTA+CRITICAL_WAIT:
401     return SAFEDIV(cost->comp_idle_max,TotalCompIdle);
402
403   case CRITTYPE_ABSDELTA+CRITICAL_HREL:
404     return SAFEDIV(((double) (cost->hrel_max - cost->hrel_avg)),
405                    ((double) (this_hrel_max-this_hrel_avg)));
406
407   case CRITTYPE_RELDELTA+CRITICAL_COMP:
408    return SAFEDIV((cost->comp_max-cost->comp_avg),
409                   (cost->comp_avg*DeltaNormalise));
410
411   case CRITTYPE_RELDELTA+CRITICAL_COMM:
412    return SAFEDIV((cost->comm_max-cost->comm_avg),
413            (cost->comm_avg*DeltaNormalise));
414
415   case CRITTYPE_RELDELTA+CRITICAL_WAIT:
416    return SAFEDIV((cost->comp_idle_max-cost->comp_idle_avg),
417                   (cost->comp_idle_avg*DeltaNormalise));
418
419   case CRITTYPE_RELDELTA+CRITICAL_HREL:
420     return SAFEDIV(((double) (cost->hrel_max - cost->hrel_avg)),
421                    ((double) (cost->hrel_avg*DeltaNormalise)));
422
423   case CRITTYPE_WEIGHTDELTA+CRITICAL_COMP:
424    return (SAFEDIV((cost->comp_max-cost->comp_avg),
425                    (cost->comp_avg*DeltaNormalise))*
426            SAFEDIV(cost->comp_max,this_total_comp_max));
427
428   case CRITTYPE_WEIGHTDELTA+CRITICAL_COMM:
429    return (SAFEDIV((cost->comm_max-cost->comm_avg),
430                    (cost->comm_avg*DeltaNormalise))*
431            SAFEDIV(cost->comm_max,this_total_comm_max));
432
433   case CRITTYPE_WEIGHTDELTA+CRITICAL_WAIT:
434    return (SAFEDIV((cost->comp_idle_max-cost->comp_idle_avg),
435                    (cost->comp_idle_avg*DeltaNormalise))*
436            SAFEDIV(cost->comp_idle_max,this_total_comp_idle_max));
437
438   case CRITTYPE_WEIGHTDELTA+CRITICAL_HREL:
439     return (SAFEDIV(((double) (cost->hrel_max - cost->hrel_avg)),
440                     ((double) (cost->hrel_avg*DeltaNormalise)))*
441             SAFEDIV(((double) cost->hrel_max),((double)this_hrel_max)));
442
443   }
444   return 0.0;
445 }
446
447 int percentToColour(double colour) {
448   int range=255,base=0;
449
450   if (!Colour) {
451     base =100;
452     range=155;
453   }
454   if      (colour>1.0) return (base+range);
455   else if (colour<0.0) return base;
456   else return (((int) (((double)range)*colour))+base);
457 }
458
459 /* -----------------------------------------------------------------------------
460  * Recursively draw the graph
461  * -------------------------------------------------------------------------- */
462
463 static void recur_graphToDaVinci(int node,Matrix *graph,Matrix *costs,char* p_zeronodes, int mode){
464   object_cost *ptr;
465   int i,j,no_children=0,*children,colour,small;
466   char line[MAX_FUNNAME], *node_str;
467   char tempnode[MAX_FUNNAME];
468   if (Mat(int,*graph,node,node)<0) {
469     printf("r(\"%d\") ",node);
470   } else {
471     for(i=0;i<graph->cols;i++) 
472       if (node!=i && Mat_dense(*graph,node,i)) no_children++;
473   
474     if (no_children>0) {
475       children = calloc(no_children,sizeof(int));
476       if (children==NULL) {
477         fprintf(stderr,"{printDaVinci} unable to allocate %d ",no_children);
478         exit(1);
479       }
480       for((i=0,j=0);i<graph->cols;i++)
481         if (node!=i && Mat_dense(*graph,node,i)) children[j++]=i;
482
483       qsort(children,no_children,sizeof(int),
484             (int (*)(const void *,const void *)) cmp_symbol_entry);
485     }
486     ptr = &Mat(object_cost,*costs,node,0);
487     node_str=(NodeviewCompress)?
488                 printCompressNode(node,ptr):
489                 printUncompressNode(node,ptr);
490     printf("l(\"%d\",n(\"\",[a(\"OBJECT\",\"%s\"),",node,node_str);
491     printf("a(\"FONTFAMILY\",\"courier\"),");
492       
493
494       // hide the CAF:REPOSITORY as default
495       if (!strncmp(node_str,"Cost centre: CAF:REPOSITORY",26))
496          printf("a(\"HIDDEN\",\"true\"),"); // when uncompressed
497       if (!strncmp(node_str," CAF:REPOSITORY",12)) 
498          printf("a(\"HIDDEN\",\"true\"),"); // when compressed
499
500
501       if (mode==2)
502       {
503         if ((ptr->comm_max+ptr->comp_idle_max+ptr->comp_max) <= 0.0)
504             printf("a(\"HIDDEN\",\"true\"),");
505       }  
506       //for pruning all zero-cost nodes
507       if (mode==1)
508       {
509       if ((ptr->comm_max+ptr->comp_idle_max+ptr->comp_max) <= 0.0)
510           { fprintf(log,"Node %d %s is a candidate for deletion\n",node, node_str);
511             sprintf(tempnode,"\"%d\",",node);
512             strcat(p_zeronodes,tempnode);
513           }
514       } 
515
516     colour=percentToColour(1.0-nodeColour(ptr));
517        printf("a(\"COLOR\",\"#ff%.2x%.2x\")",colour,colour);
518     printf("],[");
519     Mat(int,*graph,node,node)=-1;
520     for(i=0;i<no_children;i++) {
521
522       printf("e(\"%d->%d\",[],",node,children[i]);
523  
524       recur_graphToDaVinci(children[i],graph,costs,p_zeronodes,mode);
525       printf(")");
526       if (i<(no_children-1)) {printf(",");}
527     } 
528     printf("]))");
529   } 
530 }
531
532
533
534 static void recur_graphToDaVinci_old(int node,Matrix *graph, Matrix *costs) {
535   object_cost *ptr;
536   int i,j,no_children=0,*children,colour,small;
537   char line[MAX_FUNNAME], *node_str;
538   if (Mat(int,*graph,node,node)<0) {
539     fprintf(log,"r(\"%d\") ",node);
540     printf("r(\"%d\") ",node);
541   } else {
542     for(i=0;i<graph->cols;i++) 
543       if (node!=i && Mat_dense(*graph,node,i)) no_children++;
544   
545     if (no_children>0) {
546       children = calloc(no_children,sizeof(int));
547       if (children==NULL) {
548         fprintf(stderr,"{printDaVinci} unable to allocate %d ",no_children);
549         exit(1);
550       }
551       for((i=0,j=0);i<graph->cols;i++)
552         if (node!=i && Mat_dense(*graph,node,i)) children[j++]=i;
553
554       qsort(children,no_children,sizeof(int),
555             (int (*)(const void *,const void *)) cmp_symbol_entry);
556     }
557     ptr = &Mat(object_cost,*costs,node,0);
558     node_str=(NodeviewCompress)?
559                 printCompressNode(node,ptr):
560                 printUncompressNode(node,ptr);
561     fprintf(log,"l(\"%d\",n(\"\",[a(\"OBJECT\",\"%s\"),",node,node_str);
562     printf("l(\"%d\",n(\"\",[a(\"OBJECT\",\"%s\"),",node,node_str);
563     fprintf(log,"a(\"FONTFAMILY\",\"courier\"),");
564     printf("a(\"FONTFAMILY\",\"courier\"),");
565     if (symbol_table[node].type==CG_SSTEP)
566       printf("a(\"BORDER\",\"double\"),");
567     else 
568       //if (prune subgraphs of zero cost node)
569                                                             // minNodeSize hardwired
570       if ((ptr->comm_max+ptr->comp_idle_max+ptr->comp_max) < minNodeSize)
571           printf("a(\"HIDDEN\",\"true\"),");
572         
573       //if ((ptr->comm_max+ptr->comp_idle_max+ptr->comp_max) < 0.01) 
574       //    small=1; 
575       //else small=0;
576  
577
578     colour=percentToColour(1.0-nodeColour(ptr));
579     //if (!small) 
580        fprintf(log,"a(\"COLOR\",\"#ff%.2x%.2x\")",colour,colour);
581        printf("a(\"COLOR\",\"#ff%.2x%.2x\")",colour,colour);
582     //else 
583     //   printf("a(\"COLOR\",\"yellow\"),"); 
584     fprintf(log,"],[");
585     printf("],[");
586     Mat(int,*graph,node,node)=-1;
587     for(i=0;i<no_children;i++) {
588
589       //if (!small) 
590            fprintf(log,"e(\"%d->%d\",[],",node,children[i]);
591            printf("e(\"%d->%d\",[],",node,children[i]);
592       //else 
593       //     printf("e(\"%d->%d\",[a(\"EDGECOLOR\",\"yellow\")],",node,children[i]);
594  
595       recur_graphToDaVinci_old(children[i],graph,costs);
596       fprintf(log,")");
597       printf(")");
598       if (i<(no_children-1)) {fprintf(log,","); printf(",");}
599     } 
600     fprintf(log,"]))");
601     printf("]))");
602   } 
603 }
604
605
606 /* -----------------------------------------------------------------------------
607  * Update colour
608  * -------------------------------------------------------------------------- */
609
610 void updateColours(int root, Matrix *graph, Matrix *costs) {
611   int i,colour,last;
612   object_cost *ptr;
613
614   printf("graph(change_attr([");
615   for(last=costs->rows-1;last>=0;last--)
616     if (Mat_dense(*graph,last,last)) break;
617
618   for(i=0;i<costs->rows;i++) {
619     if (Mat_dense(*graph,i,i)) {
620       colour = percentToColour(1.0-nodeColour(&Mat(object_cost,*costs,i,0)));
621       printf("node(\"%d\",[a(\"COLOR\",\"#ff%.2x%.2x\")])",
622              i,colour,colour);
623       if (i<last) printf(",");    
624     }
625   }
626   printf("]))\n");
627 }
628
629 /* -----------------------------------------------------------------------------
630  * Parse answer from daVinci
631  * -------------------------------------------------------------------------- */
632
633 davinciCmd parseDaVinciCmd(char *input) {
634   davinciCmd result;
635   char *crp;
636   char *word,*label;
637   int i;
638   
639   result.size=1;
640   for(crp=input;*crp;crp++)
641     if (*crp==',') result.size++;
642
643   crp=input;
644   word = parse_word(&crp);
645   if (Verbose) fprintf(log,"{parseDaVinciCmd}=%s size=%d\n",word,result.size);
646   if        (strcmp(word,"node_selections_labels")==0) {
647     result.type=DAVINCI_NODE;
648     result.list =calloc(result.size,sizeof(char*));
649     if (result.list==NULL) {
650       fprintf(stderr,"{parseDaVinciCmd} failed to allocate storage");
651       exit(1);
652     }
653     crp+=2;
654     i=0;
655     word = parse_quoted(&crp);
656     result.list[i++] = dup_str(word);
657     while (*crp++==',') {
658       word = parse_quoted(&crp);
659       result.list[i++] = dup_str(word);
660     }
661   } else if (strcmp(word,"icon_selection")==0) {
662     result.type=DAVINCI_ICON;
663     result.list =calloc(result.size,sizeof(char*));
664     if (result.list==NULL) {
665       fprintf(stderr,"{parseDaVinciCmd} failed to allocate storage");
666       exit(1);
667     }
668     crp++;
669     i=0;
670     word = parse_quoted(&crp);
671     result.list[i++] = dup_str(word);
672   } else if (strcmp(word,"tcl_answer")==0) {
673     result.type=DAVINCI_TCL;
674     result.list =calloc(result.size,sizeof(char*));
675     if (result.list==NULL) {
676       fprintf(stderr,"{parseDaVinciCmd} failed to allocate storage");
677       exit(1);
678     }
679     crp++;
680     i=0;
681     word = parse_quoted(&crp);
682     result.list[i++] = dup_str(word);
683   } else if (strcmp(word,"menu_selection")==0) {
684     result.type=DAVINCI_MENU;
685     result.list =calloc(result.size,sizeof(char*));
686     if (result.list==NULL) {
687       fprintf(stderr,"{parseDaVinciCmd} failed to allocate storage");
688       exit(1);
689     }
690     crp++;
691     i=0;
692     word = parse_quoted(&crp);
693     result.list[i++] = dup_str(word);
694   }else if (strcmp(word,"node_double_click")==0) {
695     result.type=DAVINCI_OK;
696   } else if (strcmp(word,"edge_selection_labels")==0)  {
697     result.type=DAVINCI_OK;
698   } else if (strcmp(word,"ok")==0)  {
699     result.type=DAVINCI_OK;
700   } else if (strcmp(word,"quit")==0)  {
701     result.type=DAVINCI_QUIT;
702   } else {
703     result.type=DAVINCI_ERROR;
704   }
705   return result;  
706 }
707
708 /* -----------------------------------------------------------------------------
709  * Misc.
710  * -------------------------------------------------------------------------- */
711
712
713 /* Function that returns a string containing \texttt{x} spaces. */
714 static char* extra_space(int x) {
715   static char space[MAX_FUNNAME+1];
716   int i;
717
718   if (Verbose) fprintf(log,"Padding is %d\n",x);
719   for(i=0;(i<x)&&(i<MAX_FUNNAME);i++) space[i]=' ';
720   space[i]='\0';
721   return space;
722 }
723
724
725 static char *parse_word(char **crp) {
726   static char result[MAX_FUNNAME];
727   int i=0;
728
729   while(islower(**crp) || **crp=='_') {
730     result[i++]=**crp;
731     (*crp)++;
732   }
733   result[i]='\0';
734   return result;
735 }
736
737 static char *parse_quoted(char **crp) {
738   static char result[MAX_FUNNAME];
739   int i=0;
740   if (**crp=='\"') {
741     (*crp)++;
742     while (**crp != '\"') {
743       result[i++]=**crp;
744       (*crp)++;
745     }
746     (*crp)++;
747   }
748   result[i]='\0';
749   return result;
750 }
751
752 static char *dup_str(char *xs) {
753   char *result;
754
755   if (xs==NULL) return NULL;
756   else {
757     result = malloc(strlen(xs)+1);
758     if (result==NULL) {
759       fprintf(stderr,"{dup_str}: unable to allocate bytes");
760       exit(1);
761     }
762     strcpy(result,xs);
763     return result;
764   }
765 }