]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/callgrind/command.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / callgrind / command.c
1 /*
2    This file is part of Callgrind, a Valgrind tool for call graph
3    profiling programs.
4
5    Copyright (C) 2002-2010, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
6
7    This tool is derived from and contains lot of code from Cachegrind
8    Copyright (C) 2002 Nicholas Nethercote (njn@valgrind.org)
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of the
13    License, or (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23    02111-1307, USA.
24
25    The GNU General Public License is contained in the file COPYING.
26 */
27
28 /*
29  * Functions related to interactive commands via "callgrind.cmd"
30  */
31
32 #include "config.h"
33 #include "global.h"
34
35 #include "pub_tool_threadstate.h" // VG_N_THREADS
36
37 // Version for the syntax in command/result files for interactive control
38 #define COMMAND_VERSION "1.0"
39
40 static Char outbuf[FILENAME_LEN + FN_NAME_LEN + OBJ_NAME_LEN];
41
42 static Char* command_file = 0;
43 static Char* command_file2 = 0;
44 static Char* current_command_file = 0;
45 static Char* result_file = 0;
46 static Char* result_file2 = 0;
47 static Char* current_result_file = 0;
48 static Char* info_file = 0;
49 static Char* out_file = 0;
50
51 static Int thisPID = 0;
52
53 /**
54  * Setup for interactive control of a callgrind run
55  */
56 static void setup_control(void)
57 {
58   Int fd, size;
59   SysRes res;
60   Char* dir;
61
62   CLG_ASSERT(thisPID != 0);
63
64   fd = -1;
65   dir = CLG_(get_out_directory)();
66   out_file = CLG_(get_out_file)();
67
68   /* name of command file */
69   size = VG_(strlen)(dir) + VG_(strlen)(DEFAULT_COMMANDNAME) +10;
70   command_file = (char*) CLG_MALLOC("cl.command.sc.1", size);
71   CLG_ASSERT(command_file != 0);
72   VG_(sprintf)(command_file, "%s/%s.%d",
73                dir, DEFAULT_COMMANDNAME, thisPID);
74
75   /* This is for compatibility with the "Force Now" Button of current
76    * KCachegrind releases, as it doesn't use ".pid" to distinguish
77    * different callgrind instances from same base directory.
78    */
79   command_file2 = (char*) CLG_MALLOC("cl.command.sc.2", size);
80   CLG_ASSERT(command_file2 != 0);
81   VG_(sprintf)(command_file2, "%s/%s",
82                dir, DEFAULT_COMMANDNAME);
83
84   size = VG_(strlen)(dir) + VG_(strlen)(DEFAULT_RESULTNAME) +10;
85   result_file = (char*) CLG_MALLOC("cl.command.sc.3", size);
86   CLG_ASSERT(result_file != 0);
87   VG_(sprintf)(result_file, "%s/%s.%d",
88                dir, DEFAULT_RESULTNAME, thisPID);
89
90   /* If we get a command from a command file without .pid, use
91    * a result file without .pid suffix
92    */
93   result_file2 = (char*) CLG_MALLOC("cl.command.sc.4", size);
94   CLG_ASSERT(result_file2 != 0);
95   VG_(sprintf)(result_file2, "%s/%s",
96                dir, DEFAULT_RESULTNAME);
97
98   info_file = (char*) CLG_MALLOC("cl.command.sc.5",
99                                  VG_(strlen)(DEFAULT_INFONAME) + 10);
100   CLG_ASSERT(info_file != 0);
101   VG_(sprintf)(info_file, "%s.%d", DEFAULT_INFONAME, thisPID);
102
103   CLG_DEBUG(1, "Setup for interactive control (PID: %d):\n", thisPID);
104   CLG_DEBUG(1, "  output file:    '%s'\n", out_file);
105   CLG_DEBUG(1, "  command file:   '%s'\n", command_file);
106   CLG_DEBUG(1, "  result file:    '%s'\n", result_file);
107   CLG_DEBUG(1, "  info file:      '%s'\n", info_file);
108
109   /* create info file to indicate that we are running */ 
110   res = VG_(open)(info_file, VKI_O_WRONLY|VKI_O_TRUNC, 0);
111   if (sr_isError(res)) { 
112     res = VG_(open)(info_file, VKI_O_CREAT|VKI_O_WRONLY,
113                    VKI_S_IRUSR|VKI_S_IWUSR);
114     if (sr_isError(res)) {
115       VG_(message)(Vg_DebugMsg, 
116                    "warning: can't write info file '%s'\n", info_file);
117       info_file = 0;
118       fd = -1;
119     }
120   }
121   if (!sr_isError(res))
122       fd = (Int) sr_Res(res);
123   if (fd>=0) {
124     Char buf[512];
125     Int i;
126
127     WRITE_STR3(fd,
128                "# This file is generated by Callgrind-" VERSION ".\n"
129                "# It is used to enable controlling the supervision of\n"
130                "#  '", VG_(args_the_exename), "'\n"
131                "# by external tools.\n\n");
132     
133     VG_(sprintf)(buf, "version: " COMMAND_VERSION "\n");
134     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
135     
136     WRITE_STR3(fd, "base: ", dir, "\n");
137     WRITE_STR3(fd, "dumps: ", out_file, "\n");
138     WRITE_STR3(fd, "control: ", command_file, "\n");
139     WRITE_STR3(fd, "result: ", result_file, "\n");
140
141     WRITE_STR2(fd, "cmd: ", VG_(args_the_exename));    
142     for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
143         HChar* arg = * (HChar**)VG_(indexXA)( VG_(args_for_client), i );
144         if (!arg) continue;
145         WRITE_STR2(fd, " ", arg);
146     }
147     VG_(write)(fd, "\n", 1);
148     VG_(close)(fd);
149   }
150 }
151
152 void CLG_(init_command)()
153 {
154   thisPID = VG_(getpid)();
155   setup_control();
156 }
157
158 void CLG_(finish_command)()
159 {
160   /* unlink info file */
161   if (info_file) VG_(unlink)(info_file);
162 }
163
164
165 static Int createRes(Int fd)
166 {
167     SysRes res;
168
169     if (fd > -2) return fd;
170
171     /* fd == -2: No error, but we need to create the file */
172     CLG_ASSERT(current_result_file != 0);
173     res = VG_(open)(current_result_file,
174                    VKI_O_CREAT|VKI_O_WRONLY|VKI_O_TRUNC,
175                    VKI_S_IRUSR|VKI_S_IWUSR);
176
177     /* VG_(open) can return any negative number on error. Remap errors to -1,
178      * to not confuse it with our special value -2
179      */
180     if (sr_isError(res)) fd = -1;
181     else fd = (Int) sr_Res(res);
182
183     return fd;
184 }
185
186 /* Run Info: Persistant information of the callgrind run */
187 static Int dump_info(Int fd)
188 {
189     Char* buf = outbuf;
190     int i;
191     
192     if ( (fd = createRes(fd)) <0) return fd;
193
194     /* creator */
195     VG_(sprintf)(buf, "creator: callgrind-" VERSION "\n");
196     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
197
198     /* version */
199     VG_(sprintf)(buf, "version: " COMMAND_VERSION "\n");
200     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
201     
202     /* "pid:" line */
203     VG_(sprintf)(buf, "pid: %d\n", VG_(getpid)());
204     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
205     
206     /* "base:" line */
207     WRITE_STR3(fd, "base: ", out_file, "\n");
208     
209     /* "cmd:" line */
210     WRITE_STR2(fd, "cmd: ", VG_(args_the_exename));
211     for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
212         HChar* arg = * (HChar**)VG_(indexXA)( VG_(args_for_client), i );
213         if (!arg) continue;
214         WRITE_STR2(fd, " ", arg);
215     }
216     VG_(write)(fd, "\n", 1);
217
218     return fd;
219 }
220
221
222 /* Helper for dump_state */
223
224 Int dump_fd;
225
226 void static dump_state_of_thread(thread_info* ti)
227 {
228     Char* buf = outbuf;
229     int t = CLG_(current_tid);
230     Int p, i;
231     static FullCost sum = 0, tmp = 0;
232     BBCC *from, *to;
233     call_entry* ce;
234
235     p = VG_(sprintf)(buf, "events-%d: ", t);
236     CLG_(init_cost_lz)( CLG_(sets).full, &sum );
237     CLG_(copy_cost_lz)( CLG_(sets).full, &tmp, ti->lastdump_cost );
238     CLG_(add_diff_cost)( CLG_(sets).full, sum,
239                         ti->lastdump_cost,
240                         ti->states.entry[0]->cost);
241     CLG_(copy_cost)( CLG_(sets).full, ti->lastdump_cost, tmp );
242     p += CLG_(sprint_mappingcost)(buf + p, CLG_(dumpmap), sum);
243     p += VG_(sprintf)(buf+p, "\n");
244     VG_(write)(dump_fd, (void*)buf, p);
245
246     p = VG_(sprintf)(buf, "frames-%d: %d\n", t,
247                      CLG_(current_call_stack).sp);
248     VG_(write)(dump_fd, (void*)buf, p);
249     ce = 0;
250     for(i = 0; i < CLG_(current_call_stack).sp; i++) {
251       ce = CLG_(get_call_entry)(i);
252       /* if this frame is skipped, we don't have counters */
253       if (!ce->jcc) continue;
254       
255       from = ce->jcc->from;
256       p = VG_(sprintf)(buf, "function-%d-%d: %s\n",t, i, 
257                        from->cxt->fn[0]->name);     
258       VG_(write)(dump_fd, (void*)buf, p);
259       
260       p = VG_(sprintf)(buf, "calls-%d-%d: ",t, i);
261       p+= VG_(sprintf)(buf+p, "%llu\n", ce->jcc->call_counter);
262       VG_(write)(dump_fd, (void*)buf, p);
263       
264       /* FIXME: EventSets! */
265       CLG_(copy_cost)( CLG_(sets).full, sum, ce->jcc->cost );
266       CLG_(copy_cost)( CLG_(sets).full, tmp, ce->enter_cost );
267       CLG_(add_diff_cost)( CLG_(sets).full, sum,
268                           ce->enter_cost, CLG_(current_state).cost );
269       CLG_(copy_cost)( CLG_(sets).full, ce->enter_cost, tmp );
270       
271       p = VG_(sprintf)(buf, "events-%d-%d: ",t, i);
272       p += CLG_(sprint_mappingcost)(buf + p, CLG_(dumpmap), sum );
273       p += VG_(sprintf)(buf+p, "\n");
274       VG_(write)(dump_fd, (void*)buf, p);
275     }
276     if (ce && ce->jcc) {
277       to = ce->jcc->to;
278       p = VG_(sprintf)(buf, "function-%d-%d: %s\n",t, i, 
279                        to->cxt->fn[0]->name );      
280       VG_(write)(dump_fd, (void*)buf, p);
281     }
282 }
283
284 /* Dump info on current callgrind state */
285 static Int dump_state(Int fd)
286 {
287     Char* buf = outbuf;
288     thread_info** th;
289     int t, p;
290     Int orig_tid = CLG_(current_tid);
291
292     if ( (fd = createRes(fd)) <0) return fd;
293
294     VG_(sprintf)(buf, "instrumentation: %s\n",
295                  CLG_(instrument_state) ? "on":"off");
296     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
297
298     if (!CLG_(instrument_state)) return fd;
299
300     VG_(sprintf)(buf, "executed-bbs: %llu\n", CLG_(stat).bb_executions);
301     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
302
303     VG_(sprintf)(buf, "executed-calls: %llu\n", CLG_(stat).call_counter);
304     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
305
306     VG_(sprintf)(buf, "distinct-bbs: %d\n", CLG_(stat).distinct_bbs);
307     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
308
309     VG_(sprintf)(buf, "distinct-calls: %d\n", CLG_(stat).distinct_jccs);
310     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
311
312     VG_(sprintf)(buf, "distinct-functions: %d\n", CLG_(stat).distinct_fns);
313     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
314
315     VG_(sprintf)(buf, "distinct-contexts: %d\n", CLG_(stat).distinct_contexts);
316     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
317
318     /* "events:" line. Given here because it will be dynamic in the future */
319     p = VG_(sprintf)(buf, "events: ");
320     CLG_(sprint_eventmapping)(buf+p, CLG_(dumpmap));
321     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
322     VG_(write)(fd, "\n", 1);
323                 
324     /* "part:" line (number of last part. Is 0 at start */
325     VG_(sprintf)(buf, "\npart: %d\n", CLG_(get_dump_counter)());
326     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
327                 
328     /* threads */
329     th = CLG_(get_threads)();
330     p = VG_(sprintf)(buf, "threads:");
331     for(t=1;t<VG_N_THREADS;t++) {
332         if (!th[t]) continue;
333         p += VG_(sprintf)(buf+p, " %d", t);
334     }
335     p += VG_(sprintf)(buf+p, "\n");
336     VG_(write)(fd, (void*)buf, p);
337
338     VG_(sprintf)(buf, "current-tid: %d\n", orig_tid);
339     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
340
341     /* current event counters */
342     dump_fd = fd;
343     CLG_(forall_threads)(dump_state_of_thread);
344
345     return fd;
346 }
347
348 void CLG_(check_command)()
349 {
350     /* check for dumps needed */
351     static Char buf[512];
352     static Char cmdBuffer[512];
353     Char *cmdPos = 0, *cmdNextLine = 0;
354     Int fd, bytesRead = 0, do_kill = 0;
355     SysRes res;
356     Int currentPID;
357     static Int check_counter = 0;
358
359     /* Check for PID change, i.e. whether we run as child after a fork.
360      * If yes, we setup interactive control for the new process
361      */
362     currentPID = VG_(getpid)();
363     if (thisPID != currentPID) {
364         thisPID = currentPID;
365         setup_control();
366     }
367
368     /* Toggle between 2 command files, with/without ".pid" postfix
369      * (needed for compatibility with KCachegrind, which wants to trigger
370      *  a dump by writing into a command file without the ".pid" postfix)
371      */
372     check_counter++;
373     if (check_counter % 2) {
374         current_command_file = command_file;
375         current_result_file  = result_file;
376     }
377     else {
378         current_command_file = command_file2;
379         current_result_file  = result_file2;
380     }
381     
382     res = VG_(open)(current_command_file, VKI_O_RDONLY,0);
383     if (!sr_isError(res)) {
384         fd = (Int) sr_Res(res);
385         bytesRead = VG_(read)(fd,cmdBuffer,500);
386         cmdBuffer[500] = 0; /* no command overrun please */
387         VG_(close)(fd);
388         /* don't delete command file on read error (e.g. EAGAIN) */
389         if (bytesRead>0) {
390             cmdPos = cmdBuffer;
391         }
392     }
393
394     /* force creation of result file if needed */
395     fd = -2;
396
397     while((bytesRead>0) && *cmdPos) {
398       
399         /* Calculate pointer for next line */
400         cmdNextLine = cmdPos+1;
401         while((bytesRead>0) && *cmdNextLine && (*cmdNextLine != '\n')) {
402           cmdNextLine++;
403           bytesRead--;
404         }
405         if ((bytesRead>0) && (*cmdNextLine == '\n')) {
406           *cmdNextLine = 0;
407           cmdNextLine++;
408           bytesRead--;
409         } 
410
411         /* Command with integer option */
412         if ((*cmdPos >= '0') && (*cmdPos <='9')) {
413           int value = *cmdPos-'0';
414           cmdPos++;
415           while((*cmdPos >= '0') && (*cmdPos <='9')) {
416             value = 10*value + (*cmdPos-'0');
417             cmdPos++;
418           }
419           while((*cmdPos == ' ') || (*cmdPos == '\t')) cmdPos++;
420           
421           switch(*cmdPos) {
422 #if CLG_ENABLE_DEBUG
423             /* verbosity */
424           case 'V':
425           case 'v':
426             CLG_(clo).verbose = value;
427             break;
428 #endif
429           default:
430             break;            
431           }
432
433           cmdPos = cmdNextLine;
434           continue;
435         }  
436
437         /* Command with boolean/switch option */
438         if ((*cmdPos=='+') || 
439             (*cmdPos=='-')) {
440           int value = (cmdPos[0] == '+');
441           cmdPos++;
442           while((*cmdPos == ' ') || (*cmdPos == '\t')) cmdPos++;
443           
444           switch(*cmdPos) {
445           case 'I':
446           case 'i':
447             CLG_(set_instrument_state)("Command", value);
448             break;
449
450           default:
451             break;
452           }
453
454           cmdPos = cmdNextLine;
455           continue;
456         }
457
458         /* regular command */
459         switch(*cmdPos) {
460         case 'D':
461         case 'd':
462           /* DUMP */
463
464           /* skip command */
465           while(*cmdPos && (*cmdPos != ' ')) cmdPos++;
466           if (*cmdPos)
467             VG_(sprintf)(buf, "Dump Command:%s", cmdPos);
468           else
469             VG_(sprintf)(buf, "Dump Command");
470           CLG_(dump_profile)(buf, False);
471           break;
472             
473         case 'Z':
474         case 'z':
475             CLG_(zero_all_cost)(False);
476             break;
477
478         case 'K':
479         case 'k':
480             /* Kill: Delay to be able to remove command file before. */
481             do_kill = 1;
482             break;
483
484         case 'I':
485         case 'i':
486             fd = dump_info(fd);
487             break;
488
489         case 's':
490         case 'S':
491             fd = dump_state(fd);
492             break;
493
494         case 'O':
495         case 'o':
496             /* Options Info */
497             if ( (fd = createRes(fd)) <0) break;
498
499             VG_(sprintf)(buf, "\ndesc: Option: --skip-plt=%s\n",
500                          CLG_(clo).skip_plt ? "yes" : "no");
501             VG_(write)(fd, (void*)buf, VG_(strlen)(buf));           
502             VG_(sprintf)(buf, "desc: Option: --collect-jumps=%s\n",
503                          CLG_(clo).collect_jumps ? "yes" : "no");
504             VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
505             VG_(sprintf)(buf, "desc: Option: --separate-recs=%d\n",
506                          CLG_(clo).separate_recursions);
507             VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
508             VG_(sprintf)(buf, "desc: Option: --separate-callers=%d\n",
509                          CLG_(clo).separate_callers);
510             VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
511
512             break;
513
514         default:
515           break;
516         }
517
518         cmdPos = cmdNextLine;
519     }
520
521     /* If command executed, delete command file */
522     if (cmdPos) VG_(unlink)(current_command_file);
523     if (fd>=0) VG_(close)(fd);      
524
525     if (do_kill) {
526       VG_(message)(Vg_UserMsg,
527                    "Killed because of command from %s\n",
528                    current_command_file);
529       CLG_(fini)(0);
530       VG_(exit)(1);
531     }
532 }