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