1 /* Performance monitoring unit (PMU) profiler. If available, use an
2 external tool to collect hardware performance counter data and
3 write it in the .gcda files.
5 Copyright (C) 2011. Free Software Foundation, Inc.
6 Contributed by Sharad Singhai <singhai@google.com>.
8 This file is part of GCC.
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 3, or (at your option) any later
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
31 #include "coretypes.h"
33 #if (defined (__x86_64__) || defined (__i386__))
37 #if defined(inhibit_libc)
38 #define IN_LIBGCOV (-1)
44 #define GCOV_LINKAGE /* nothing */
48 #ifdef TARGET_POSIX_IO
52 #include <sys/types.h>
55 #if defined(inhibit_libc)
62 #include <sys/types.h>
65 #define XNEWVEC(type,ne) (type *)calloc((ne),sizeof(type))
66 #define XNEW(type) (type *)malloc(sizeof(type))
67 #define XDELETEVEC(p) free(p)
68 #define XDELETE(p) free(p)
70 #define PFMON_CMD "/usr/bin/pfmon"
71 #define ADDR2LINE_CMD "/usr/bin/addr2line"
72 #define PMU_TOOL_MAX_ARGS (20)
73 static char default_addr2line
[] = "??:0";
74 static const char pfmon_ll_header
[] = "# counts %self %cum "
75 "<10 <32 <64 <256 <1024 >=1024 %wself "
77 static const char pfmon_bm_header
[] =
78 "# counts %self %cum code addr symbol\n";
80 const char *pfmon_intel_ll_args
[PMU_TOOL_MAX_ARGS
] = {
82 "--aggregate-results",
85 "--smpl-module=pebs-ll",
86 "--ld-lat-threshold=4",
87 "--pebs-ll-dcmiss-code",
88 "--resolve-addresses",
89 "-emem_inst_retired:LATENCY_ABOVE_THRESHOLD",
90 "--long-smpl-periods=10000",
91 0 /* terminating NULL must be present */
94 const char *pfmon_amd_ll_args
[PMU_TOOL_MAX_ARGS
] = {
96 "--aggregate-results",
101 "--resolve-addresses",
102 "-eibsop_event:uops",
104 "--long-smpl-periods=0xffff0",
105 0 /* terminating NULL must be present */
108 const char *pfmon_intel_brm_args
[PMU_TOOL_MAX_ARGS
] = {
110 "--aggregate-results",
113 "--resolve-addresses",
114 "-eMISPREDICTED_BRANCH_RETIRED",
115 "--long-smpl-periods=10000",
116 0 /* terminating NULL must be present */
119 const char *pfmon_amd_brm_args
[PMU_TOOL_MAX_ARGS
] = {
121 "--aggregate-results",
124 "--resolve-addresses",
125 "-eRETIRED_MISPREDICTED_BRANCH_INSTRUCTIONS",
126 "--long-smpl-periods=10000",
127 0 /* terminating NULL must be present */
130 const char *addr2line_args
[PMU_TOOL_MAX_ARGS
] = {
133 0 /* terminating NULL must be present */
145 PET_INTEL_LOAD_LATENCY
,
146 PET_AMD_LOAD_LATENCY
,
147 PET_INTEL_BRANCH_MISPREDICT
,
148 PET_AMD_BRANCH_MISPREDICT
,
152 typedef struct pmu_tool_fns
{
153 const char *name
; /* name of the pmu tool */
154 /* pmu tool commandline argument. */
155 const char **arg_array
;
156 /* Initialize pmu module. */
157 void *(*init_pmu_module
) (void);
158 /* Start profililing. */
159 void (*start_pmu_module
) (pid_t ppid
, char *tmpfile
, const char **args
);
160 /* Stop profililing. */
161 void (*stop_pmu_module
) (void);
162 /* How to parse the output generated by the PMU tool. */
163 int (*parse_pmu_output
) (char *filename
, void *pmu_data
);
164 /* How to write parsed pmu data into gcda file. */
165 void (*gcov_write_pmu_data
) (void *data
);
166 /* How to cleanup any data structure created during parsing. */
167 void (*cleanup_pmu_data
) (void *data
);
168 /* How to initialize symbolizer for the PPID. */
169 int (*start_symbolizer
) (pid_t ppid
);
170 void (*end_symbolizer
) (void);
171 char *(*symbolize
) (void *addr
);
176 PMU_NONE
, /* Not configurated at all. */
177 PMU_INITIALIZED
, /* Configured and initialized. */
178 PMU_ERROR
, /* Configuration error. Cannot recover. */
179 PMU_ON
, /* Currently profiling. */
180 PMU_OFF
/* Currently stopped, but can be restarted. */
183 enum cpu_vendor_signature
185 CPU_VENDOR_UKNOWN
= 0,
186 CPU_VENDOR_INTEL
= 0x756e6547, /* Genu */
187 CPU_VENDOR_AMD
= 0x68747541 /* Auth */
190 /* Info about pmu tool during the run time. */
193 /* Current pmu tool. */
194 enum pmu_tool_type tool
;
196 enum pmu_event_type event
;
197 /* filename for storing the pmu profile. */
198 char *pmu_profile_filename
;
199 /* Intermediate file where the tool stores the PMU data. */
200 char *raw_pmu_profile_filename
;
201 /* Where PMU tool's stderr should be stored. */
202 char *tool_stderr_filename
;
203 enum pmu_state pmu_profiling_state
;
204 enum cpu_vendor_signature cpu_vendor
; /* as discovered by cpuid */
205 pid_t pmu_tool_pid
; /* process id of the pmu tool */
206 pid_t symbolizer_pid
; /* process id of the symbolizer */
207 int symbolizer_to_pipefd
[2]; /* pipe for writing to the symbolizer */
208 int symbolizer_from_pipefd
[2]; /* pipe for reading from the symbolizer */
209 void *pmu_data
; /* an opaque pointer for the tool to store pmu data */
210 int verbose
; /* turn on additional debugging */
211 unsigned top_n_address
; /* how many addresses to symbolize */
212 pmu_tool_fns
*tool_details
; /* list of functions how to start/stop/parse */
215 /* Global struct for recordkeeping. */
216 static struct pmu_tool_info
*the_pmu_tool_info
;
218 /* Additional info is printed if these are non-zero. */
219 static int tool_debug
= 0;
220 static int sym_debug
= 0;
222 static int parse_load_latency_line (char *line
, gcov_pmu_ll_info_t
*ll_info
);
223 static int parse_branch_mispredict_line (char *line
,
224 gcov_pmu_brm_info_t
*brm_info
);
225 static unsigned convert_pct_to_unsigned (float pct
);
226 static void start_pfmon_module (pid_t ppid
, char *tmpfile
, const char **pfmon_args
);
227 static void *init_pmu_load_latency (void);
228 static void *init_pmu_branch_mispredict (void);
229 static void destroy_load_latency_infos (void *info
);
230 static void destroy_branch_mispredict_infos (void *info
);
231 static int parse_pfmon_load_latency (char *filename
, void *pmu_data
);
232 static int parse_pfmon_branch_mispredicts (char *filename
, void *pmu_data
);
233 static gcov_unsigned_t
gcov_tag_pmu_tool_header_length (gcov_pmu_tool_header_t
235 static void gcov_write_tool_header (gcov_pmu_tool_header_t
*header
);
236 static void gcov_write_load_latency_infos (void *info
);
237 static void gcov_write_branch_mispredict_infos (void *info
);
238 static void gcov_write_ll_line (const gcov_pmu_ll_info_t
*ll_info
);
239 static void gcov_write_branch_mispredict_line (const gcov_pmu_brm_info_t
241 static int start_addr2line_symbolizer (pid_t pid
);
242 static void end_addr2line_symbolizer (void);
243 static char *symbolize_addr2line (void *p
);
244 static void reset_symbolizer_parent_pipes (void);
245 static void reset_symbolizer_child_pipes (void);
246 /* parse and cache relevant tool info. */
247 static int parse_pmu_profile_options (const char *options
);
248 static gcov_pmu_tool_header_t
*parse_pfmon_tool_header (FILE *fp
,
249 const char *end_header
);
252 /* How to access the necessary functions for the PMU tools. */
253 pmu_tool_fns all_pmu_tool_fns
[PTT_LAST
][PET_LAST
] = {
256 "intel-load-latency", /* name */
257 pfmon_intel_ll_args
, /* tool args */
258 init_pmu_load_latency
, /* initialization */
259 start_pfmon_module
, /* start */
261 parse_pfmon_load_latency
, /* parse */
262 gcov_write_load_latency_infos
, /* write */
263 destroy_load_latency_infos
, /* cleanup */
264 start_addr2line_symbolizer
, /* start symbolizer */
265 end_addr2line_symbolizer
, /* end symbolizer */
266 symbolize_addr2line
, /* symbolize */
269 "amd-load-latency", /* name */
270 pfmon_amd_ll_args
, /* tool args */
271 init_pmu_load_latency
, /* initialization */
272 start_pfmon_module
, /* start */
274 parse_pfmon_load_latency
, /* parse */
275 gcov_write_load_latency_infos
, /* write */
276 destroy_load_latency_infos
, /* cleanup */
277 start_addr2line_symbolizer
, /* start symbolizer */
278 end_addr2line_symbolizer
, /* end symbolizer */
279 symbolize_addr2line
, /* symbolize */
282 "intel-branch-mispredict", /* name */
283 pfmon_intel_brm_args
, /* tool args */
284 init_pmu_branch_mispredict
, /* initialization */
285 start_pfmon_module
, /* start */
287 parse_pfmon_branch_mispredicts
, /* parse */
288 gcov_write_branch_mispredict_infos
,/* write */
289 destroy_branch_mispredict_infos
, /* cleanup */
290 start_addr2line_symbolizer
, /* start symbolizer */
291 end_addr2line_symbolizer
, /* end symbolizer */
292 symbolize_addr2line
, /* symbolize */
295 "amd-branch-mispredict", /* name */
296 pfmon_amd_brm_args
, /* tool args */
297 init_pmu_branch_mispredict
, /* initialization */
298 start_pfmon_module
, /* start */
300 parse_pfmon_branch_mispredicts
, /* parse */
301 gcov_write_branch_mispredict_infos
,/* write */
302 destroy_branch_mispredict_infos
, /* cleanup */
303 start_addr2line_symbolizer
, /* start symbolizer */
304 end_addr2line_symbolizer
, /* end symbolizer */
305 symbolize_addr2line
, /* symbolize */
310 /* Determine the CPU vendor. Currently only distinguishes x86 based
311 cpus where the vendor is either Intel or AMD. Returns one of the
312 enum cpu_vendor_signatures. */
315 get_x86cpu_vendor (void)
317 unsigned int vendor
= CPU_VENDOR_UKNOWN
;
319 #if (defined (__x86_64__) || defined (__i386__))
320 if (__get_cpuid_max (0, &vendor
) < 1)
321 return CPU_VENDOR_UKNOWN
; /* Cannot determine cpu type. */
324 if (vendor
== CPU_VENDOR_INTEL
|| vendor
== CPU_VENDOR_AMD
)
327 return CPU_VENDOR_UKNOWN
;
331 /* Parse PMU tool option string provided on the command line and store
332 information in global structure. Return 0 on success, otherwise
333 return 1. Any changes to this should be synced with
334 check_pmu_profile_options() which does compile time check. */
337 parse_pmu_profile_options (const char *options
)
339 enum pmu_tool_type ptt
= the_pmu_tool_info
->tool
;
340 enum pmu_event_type pet
= PET_LAST
;
341 const char *pmutool_path
;
342 the_pmu_tool_info
->cpu_vendor
= get_x86cpu_vendor ();
343 /* Determine the platform we are running on. */
344 if (the_pmu_tool_info
->cpu_vendor
== CPU_VENDOR_UKNOWN
)
346 /* Cpuid failed or uknown vendor. */
347 the_pmu_tool_info
->pmu_profiling_state
= PMU_ERROR
;
351 /* Validate the options. */
352 if (strcmp(options
, "load-latency") &&
353 strcmp(options
, "load-latency-verbose") &&
354 strcmp(options
, "branch-mispredict") &&
355 strcmp(options
, "branch-mispredict-verbose"))
358 /* Check if are aksed to collect load latency PMU data. */
359 if (!strcmp(options
, "load-latency") ||
360 !strcmp(options
, "load-latency-verbose"))
362 if (the_pmu_tool_info
->cpu_vendor
== CPU_VENDOR_INTEL
)
363 pet
= PET_INTEL_LOAD_LATENCY
;
365 pet
= PET_AMD_LOAD_LATENCY
;
366 if (!strcmp(options
, "load-latency-verbose"))
367 the_pmu_tool_info
->verbose
= 1;
370 /* Check if are aksed to collect branch mispredict PMU data. */
371 if (!strcmp(options
, "branch-mispredict") ||
372 !strcmp(options
, "branch-mispredict-verbose"))
374 if (the_pmu_tool_info
->cpu_vendor
== CPU_VENDOR_INTEL
)
375 pet
= PET_INTEL_BRANCH_MISPREDICT
;
377 pet
= PET_AMD_BRANCH_MISPREDICT
;
378 if (!strcmp(options
, "branch-mispredict-verbose"))
379 the_pmu_tool_info
->verbose
= 1;
382 the_pmu_tool_info
->tool_details
= &all_pmu_tool_fns
[ptt
][pet
];
383 the_pmu_tool_info
->event
= pet
;
385 /* Allow users to override the default tool path. */
386 pmutool_path
= getenv ("GCOV_PMUTOOL_PATH");
387 if (pmutool_path
&& strlen (pmutool_path
))
388 the_pmu_tool_info
->tool_details
->arg_array
[0] = pmutool_path
;
393 /* Do the initialization of addr2line symbolizer for the process id
394 given by TASK_PID. It forks an addr2line process and creates two
395 pipes where addresses can be written and source_filename:line_num
396 entries can be read. Returns 0 on success, non-zero otherwise. */
399 start_addr2line_symbolizer (pid_t task_pid
)
402 char *addr2line_path
;
404 /* Allow users to override the default addr2line path. */
405 addr2line_path
= getenv ("GCOV_ADDR2LINE_PATH");
406 if (addr2line_path
&& strlen (addr2line_path
))
407 addr2line_args
[0] = addr2line_path
;
409 if (pipe (the_pmu_tool_info
->symbolizer_from_pipefd
) == -1)
411 fprintf (stderr
, "Cannot create symbolizer write pipe.\n");
414 if (pipe (the_pmu_tool_info
->symbolizer_to_pipefd
) == -1)
416 fprintf (stderr
, "Cannot create symbolizer read pipe.\n");
423 /* error condition */
424 fprintf (stderr
, "Cannot create symbolizer process.\n");
425 reset_symbolizer_parent_pipes ();
426 reset_symbolizer_child_pipes ();
432 /* child does an exec and then connects to/from the pipe */
434 char proc_exe_buf
[128];
435 int new_write_fd
, new_read_fd
;
438 /* Go over the current addr2line args. */
439 for (i
= 0; i
< PMU_TOOL_MAX_ARGS
&& addr2line_args
[i
]; ++i
)
442 /* We are going to add one more arg for the /proc/pid/exe */
443 if (n_args
>= (PMU_TOOL_MAX_ARGS
- 1))
445 fprintf (stderr
, "too many addr2line args: %d\n", n_args
);
448 snprintf (proc_exe_buf
, sizeof (proc_exe_buf
), "/proc/%d/exe",
451 /* Add the extra arg for the process id. */
452 addr2line_args
[n_args
] = proc_exe_buf
;
455 addr2line_args
[n_args
] = (const char *)NULL
; /* terminating NULL */
459 fprintf (stderr
, "addr2line args:");
460 for (i
= 0; i
< PMU_TOOL_MAX_ARGS
&& addr2line_args
[i
]; ++i
)
461 fprintf (stderr
, " %s", addr2line_args
[i
]);
462 fprintf (stderr
, "\n");
465 /* Close unused ends of the two pipes. */
466 reset_symbolizer_child_pipes ();
468 /* Connect the pipes to stdin/stdout of the child process. */
469 new_read_fd
= dup2 (the_pmu_tool_info
->symbolizer_to_pipefd
[0], 0);
470 new_write_fd
= dup2 (the_pmu_tool_info
->symbolizer_from_pipefd
[1], 1);
471 if (new_read_fd
== -1 || new_write_fd
== -1)
473 fprintf (stderr
, "could not dup symbolizer fds\n");
474 reset_symbolizer_parent_pipes ();
475 reset_symbolizer_child_pipes ();
478 the_pmu_tool_info
->symbolizer_to_pipefd
[0] = new_read_fd
;
479 the_pmu_tool_info
->symbolizer_from_pipefd
[1] = new_write_fd
;
481 /* Do execve with NULL env. */
482 execve (addr2line_args
[0], (char * const*)addr2line_args
,
483 (char * const*)NULL
);
484 /* exec returned, an error condition. */
485 fprintf (stderr
, "could not create symbolizer process: %s\n",
487 reset_symbolizer_parent_pipes ();
488 reset_symbolizer_child_pipes ();
494 the_pmu_tool_info
->symbolizer_pid
= pid
;
495 /* Close unused ends of the two pipes. */
496 reset_symbolizer_parent_pipes ();
502 /* Close unused write end of the from-pipe and read end of the
506 reset_symbolizer_parent_pipes (void)
508 if (the_pmu_tool_info
->symbolizer_from_pipefd
[1] != -1)
510 close (the_pmu_tool_info
->symbolizer_from_pipefd
[1]);
511 the_pmu_tool_info
->symbolizer_from_pipefd
[1] = -1;
513 if (the_pmu_tool_info
->symbolizer_to_pipefd
[0] != -1)
515 close (the_pmu_tool_info
->symbolizer_to_pipefd
[0]);
516 the_pmu_tool_info
->symbolizer_to_pipefd
[0] = -1;
520 /* Close unused write end of the to-pipe and read end of the
524 reset_symbolizer_child_pipes (void)
526 if (the_pmu_tool_info
->symbolizer_to_pipefd
[1] != -1)
528 close (the_pmu_tool_info
->symbolizer_to_pipefd
[1]);
529 the_pmu_tool_info
->symbolizer_to_pipefd
[1] = -1;
531 if (the_pmu_tool_info
->symbolizer_from_pipefd
[0] != -1)
533 close (the_pmu_tool_info
->symbolizer_from_pipefd
[0]);
534 the_pmu_tool_info
->symbolizer_from_pipefd
[0] = -1;
539 /* Perform cleanup for the symbolizer process. */
542 end_addr2line_symbolizer (void)
546 pid_t pid
= the_pmu_tool_info
->symbolizer_pid
;
548 /* Symbolizer was not running. */
552 reset_symbolizer_parent_pipes ();
553 reset_symbolizer_child_pipes ();
555 wait_status
= waitpid (pid
, &pid_status
, 0);
558 if (wait_status
== pid
)
559 fprintf (stderr
, "Normal exit. symbolizer terminated.\n");
561 fprintf (stderr
, "Abnormal exit. symbolizer status, %d.\n", pid_status
);
563 the_pmu_tool_info
->symbolizer_pid
= 0; /* Symoblizer no longer running. */
567 /* Given an address ADDR, return a string containing
568 source_filename:line_num entries. */
571 symbolize_addr2line (void *addr
)
573 char buf
[32]; /* holds the ascii version of address */
576 char *srcfile_linenum
;
577 size_t max_length
= 1024;
579 if (!the_pmu_tool_info
->symbolizer_pid
)
580 return default_addr2line
; /* symbolizer is not running */
582 write_count
= snprintf (buf
, sizeof (buf
), "%p\n", addr
);
584 /* Write the address into the pipe. */
585 if (write (the_pmu_tool_info
->symbolizer_to_pipefd
[1], buf
, write_count
)
589 fprintf (stderr
, "Cannot write symbolizer pipe.\n");
590 return default_addr2line
;
593 srcfile_linenum
= XNEWVEC (char, max_length
);
594 read_count
= read (the_pmu_tool_info
->symbolizer_from_pipefd
[0],
595 srcfile_linenum
, max_length
);
596 if (read_count
== -1)
599 fprintf (stderr
, "Cannot read symbolizer pipe.\n");
600 XDELETEVEC (srcfile_linenum
);
601 return default_addr2line
;
604 srcfile_linenum
[read_count
] = 0;
606 fprintf (stderr
, "symbolizer: for address %p, read_count %d, got %s\n",
607 addr
, read_count
, srcfile_linenum
);
608 return srcfile_linenum
;
611 /* Start monitoring PPID process via pfmon tool using TMPFILE as a
612 file to store the raw data and using PFMON_ARGS as the command line
616 start_pfmon_module (pid_t ppid
, char *tmpfile
, const char **pfmon_args
)
619 unsigned int n_args
= 0;
622 char filename_buf
[1024];
626 /* Go over the current pfmon args */
627 for (i
= 0; i
< PMU_TOOL_MAX_ARGS
&& pfmon_args
[i
]; ++i
)
630 if (the_pmu_tool_info
->verbose
)
631 extra_args
= 4; /* account for additional --verbose */
635 /* We are going to add args. */
636 if (n_args
>= (PMU_TOOL_MAX_ARGS
- extra_args
))
638 fprintf (stderr
, "too many pfmon args: %d\n", n_args
);
642 n_chars
= snprintf (pid_buf
, sizeof (pid_buf
), "--attach-task=%ld",
644 if (n_chars
>= sizeof (pid_buf
))
646 fprintf (stderr
, "pfmon task id too long: %s\n", pid_buf
);
649 pfmon_args
[n_args
] = pid_buf
;
652 n_chars
= snprintf (filename_buf
, sizeof (filename_buf
), "--smpl-outfile=%s",
654 if (n_chars
>= sizeof (filename_buf
))
656 fprintf (stderr
, "pfmon filename too long: %s\n", filename_buf
);
659 pfmon_args
[n_args
] = filename_buf
;
662 n_chars
= snprintf (top_n_buf
, sizeof (top_n_buf
), "--smpl-show-top=%d",
663 the_pmu_tool_info
->top_n_address
);
664 if (n_chars
>= sizeof (top_n_buf
))
666 fprintf (stderr
, "pfmon option too long: %s\n", top_n_buf
);
669 pfmon_args
[n_args
] = top_n_buf
;
672 if (the_pmu_tool_info
->verbose
) {
673 /* Add --verbose as well. */
674 pfmon_args
[n_args
] = "--verbose";
677 pfmon_args
[n_args
] = (char *)NULL
;
681 fprintf (stderr
, "pfmon args:");
682 for (i
= 0; i
< PMU_TOOL_MAX_ARGS
&& pfmon_args
[i
]; ++i
)
683 fprintf (stderr
, " %s", pfmon_args
[i
]);
684 fprintf (stderr
, "\n");
686 /* Do execve with NULL env. */
687 execve (pfmon_args
[0], (char *const *)pfmon_args
, (char * const*)NULL
);
688 /* does not return */
691 /* Convert a fractional PCT to an unsigned integer after
692 muliplying by 100. */
695 convert_pct_to_unsigned (float pct
)
697 return (unsigned)(pct
* 100.0f
);
700 /* Parse the load latency info pointed by LINE and save it into
701 LL_INFO. Returns 0 if the line was parsed successfully, non-zero
704 An example header+line look like these:
705 "counts %self %cum <10 <32 <64 <256 <1024 >=1024
706 %wself code addr symbol"
707 "218 24.06% 24.06% 100.00% 0.00% 0.00% 0.00% 0.00% 0.00% 22.70%
708 0x0000000000413e75 CalcSSIM(...)+965</tmp/psnr>"
712 parse_load_latency_line (char *line
, gcov_pmu_ll_info_t
*ll_info
)
715 /* These are percentages parsed as floats, but then converted to
716 integers after multiplying by 100. */
717 float self
, cum
, lt_10
, lt_32
, lt_64
, lt_256
, lt_1024
, gt_1024
, wself
;
720 pmu_tool_fns
*tool_details
= the_pmu_tool_info
->tool_details
;
722 n_values
= sscanf (line
, "%u%f%%%f%%%f%%%f%%%f%%%f%%%f%%%f%%%f%%%lx",
723 &counts
, &self
, &cum
, <_10
, <_32
, <_64
, <_256
,
724 <_1024
, >_1024
, &wself
, &p
);
728 /* Values read successfully. Do the assignment after converting
729 * percentages into ints. */
730 ll_info
->counts
= counts
;
731 ll_info
->self
= convert_pct_to_unsigned (self
);
732 ll_info
->cum
= convert_pct_to_unsigned (cum
);
733 ll_info
->lt_10
= convert_pct_to_unsigned (lt_10
);
734 ll_info
->lt_32
= convert_pct_to_unsigned (lt_32
);
735 ll_info
->lt_64
= convert_pct_to_unsigned (lt_64
);
736 ll_info
->lt_256
= convert_pct_to_unsigned (lt_256
);
737 ll_info
->lt_1024
= convert_pct_to_unsigned (lt_1024
);
738 ll_info
->gt_1024
= convert_pct_to_unsigned (gt_1024
);
739 ll_info
->wself
= convert_pct_to_unsigned (wself
);
740 ll_info
->code_addr
= p
;
742 /* Run the raw address through the symbolizer. */
743 if (tool_details
->symbolize
)
745 char *sym_info
= tool_details
->symbolize ((void *)p
);
746 /* sym_info is of the form src_filename:linenum. Descriminator is
747 currently not supported by addr2line. */
748 char *sep
= strchr (sym_info
, ':');
751 /* Assume entire string is srcfile. */
752 ll_info
->filename
= (char *)sym_info
;
757 /* Terminate the filename string at the separator. */
759 ll_info
->filename
= (char *)sym_info
;
760 /* Convert rest of the sym info to a line number. */
761 ll_info
->line
= atol (sep
+1);
763 ll_info
->discriminator
= 0;
767 /* No symbolizer available. */
768 ll_info
->filename
= NULL
;
770 ll_info
->discriminator
= 0;
775 /* Parse the branch mispredict info pointed by LINE and save it into
776 BRM_INFO. Returns 0 if the line was parsed successfully, non-zero
779 An example header+line look like these:
780 "counts %self %cum code addr symbol"
781 "6869 37.67% 37.67% 0x00000000004007e5 sum(std::vector<int*,
782 std::allocator<int*> > const&)+51</root/tmp/array>"
786 parse_branch_mispredict_line (char *line
, gcov_pmu_brm_info_t
*brm_info
)
789 /* These are percentages parsed as floats, but then converted to
790 ints after multiplying by 100. */
794 pmu_tool_fns
*tool_details
= the_pmu_tool_info
->tool_details
;
796 n_values
= sscanf (line
, "%u%f%%%f%%%lx",
797 &counts
, &self
, &cum
, &p
);
801 /* Values read successfully. Do the assignment after converting
802 * percentages into ints. */
803 brm_info
->counts
= counts
;
804 brm_info
->self
= convert_pct_to_unsigned (self
);
805 brm_info
->cum
= convert_pct_to_unsigned (cum
);
806 brm_info
->code_addr
= p
;
808 /* Run the raw address through the symbolizer. */
809 if (tool_details
->symbolize
)
811 char *sym_info
= tool_details
->symbolize ((void *)p
);
812 /* sym_info is of the form src_filename:linenum. Descriminator is
813 currently not supported by addr2line. */
814 char *sep
= strchr (sym_info
, ':');
817 /* Assume entire string is srcfile. */
818 brm_info
->filename
= sym_info
;
823 /* Terminate the filename string at the separator. */
825 brm_info
->filename
= sym_info
;
826 /* Convert rest of the sym info to a line number. */
827 brm_info
->line
= atol (sep
+1);
829 brm_info
->discriminator
= 0;
833 /* No symbolizer available. */
834 brm_info
->filename
= NULL
;
836 brm_info
->discriminator
= 0;
841 /* Delete load latency info structures INFO. */
844 destroy_load_latency_infos (void *info
)
847 ll_infos_t
* ll_infos
= (ll_infos_t
*)info
;
849 /* delete each element */
850 for (i
= 0; i
< ll_infos
->ll_count
; ++i
)
851 XDELETE (ll_infos
->ll_array
[i
]);
852 /* delete the array itself */
853 XDELETE (ll_infos
->ll_array
);
854 __destroy_pmu_tool_header (ll_infos
->pmu_tool_header
);
855 free (ll_infos
->pmu_tool_header
);
856 ll_infos
->ll_array
= 0;
857 ll_infos
->ll_count
= 0;
860 /* Delete branch mispredict structure INFO. */
863 destroy_branch_mispredict_infos (void *info
)
866 brm_infos_t
* brm_infos
= (brm_infos_t
*)info
;
868 /* delete each element */
869 for (i
= 0; i
< brm_infos
->brm_count
; ++i
)
870 XDELETE (brm_infos
->brm_array
[i
]);
871 /* delete the array itself */
872 XDELETE (brm_infos
->brm_array
);
873 __destroy_pmu_tool_header (brm_infos
->pmu_tool_header
);
874 free (brm_infos
->pmu_tool_header
);
875 brm_infos
->brm_array
= 0;
876 brm_infos
->brm_count
= 0;
879 /* Parse FILENAME for load latency lines into a structure
880 PMU_DATA. Returns 0 on on success. Returns non-zero on
884 parse_pfmon_load_latency (char *filename
, void *pmu_data
)
887 size_t buflen
= 2*1024;
889 ll_infos_t
*load_latency_infos
= (ll_infos_t
*)pmu_data
;
890 gcov_pmu_tool_header_t
*tool_header
= 0;
892 if ((fp
= fopen (filename
, "r")) == NULL
)
894 fprintf (stderr
, "cannot open pmu data file: %s\n", filename
);
898 if (!(tool_header
= parse_pfmon_tool_header (fp
, pfmon_ll_header
)))
900 fprintf (stderr
, "cannot parse pmu data file header: %s\n", filename
);
904 buf
= XNEWVEC (char, buflen
);
905 while (fgets (buf
, buflen
, fp
))
907 gcov_pmu_ll_info_t
*ll_info
= XNEW (gcov_pmu_ll_info_t
);
908 if (!parse_load_latency_line (buf
, ll_info
))
910 /* valid line, add to the array */
911 load_latency_infos
->ll_count
++;
912 if (load_latency_infos
->ll_count
>=
913 load_latency_infos
->alloc_ll_count
)
915 /* need to realloc */
916 load_latency_infos
->ll_array
=
917 realloc (load_latency_infos
->ll_array
,
918 2 * load_latency_infos
->alloc_ll_count
);
919 if (load_latency_infos
->ll_array
== NULL
)
921 fprintf (stderr
, "Cannot allocate load latency memory.\n");
922 __destroy_pmu_tool_header (tool_header
);
928 load_latency_infos
->ll_array
[load_latency_infos
->ll_count
- 1] =
932 /* Delete invalid line. */
937 load_latency_infos
->pmu_tool_header
= tool_header
;
941 /* Parse open file FP until END_HEADER is seen. The data matching
942 gcov_pmu_tool_header_t fields is saved and returned in a new
943 struct. In case of failure, it returns NULL. */
945 static gcov_pmu_tool_header_t
*
946 parse_pfmon_tool_header (FILE *fp
, const char *end_header
)
948 static const char tag_hostname
[] = "# hostname: ";
949 static const char tag_kversion
[] = "# kernel version: ";
950 static const char tag_hostcpu
[] = "# host CPUs: ";
951 static const char tag_column_desc_start
[] = "# description of columns:";
952 static const char tag_column_desc_end
[] =
953 "# other columns are self-explanatory";
954 size_t buflen
= 4*1024;
955 char *buf
, *buf_start
, *buf_end
;
956 gcov_pmu_tool_header_t
*tool_header
= XNEWVEC (gcov_pmu_tool_header_t
, 1);
960 char *column_description
= 0;
961 char *column_desc_start
= 0;
962 char *column_desc_end
= 0;
963 const char *column_header
= 0;
964 int got_hostname
= 0;
965 int got_kversion
= 0 ;
967 int got_end_header
= 0;
968 int got_column_description
= 0;
970 buf
= XNEWVEC (char, buflen
);
972 buf_end
= buf
+ buflen
;
973 while (buf
< (buf_end
- 1) && fgets (buf
, buf_end
- buf
, fp
))
975 if (strncmp (end_header
, buf
, buf_end
- buf
) == 0)
981 strncmp (buf
, tag_hostname
, strlen (tag_hostname
)) == 0)
983 size_t len
= strlen (buf
) - strlen (tag_hostname
);
984 hostname
= XNEWVEC (char, len
);
985 memcpy (hostname
, buf
+ strlen (tag_hostname
), len
);
986 hostname
[len
- 1] = 0;
987 tool_header
->hostname
= hostname
;
992 strncmp (buf
, tag_kversion
, strlen (tag_kversion
)) == 0)
994 size_t len
= strlen (buf
) - strlen (tag_kversion
);
995 kversion
= XNEWVEC (char, len
);
996 memcpy (kversion
, buf
+ strlen (tag_kversion
), len
);
997 kversion
[len
- 1] = 0;
998 tool_header
->kernel_version
= kversion
;
1003 strncmp (buf
, tag_hostcpu
, strlen (tag_hostcpu
)) == 0)
1005 size_t len
= strlen (buf
) - strlen (tag_hostcpu
);
1006 hostcpu
= XNEWVEC (char, len
);
1007 memcpy (hostcpu
, buf
+ strlen (tag_hostcpu
), len
);
1008 hostcpu
[len
- 1] = 0;
1009 tool_header
->host_cpu
= hostcpu
;
1012 if (!got_column_description
&&
1013 strncmp (buf
, tag_column_desc_start
, strlen (tag_column_desc_start
))
1016 column_desc_start
= buf
;
1017 column_desc_end
= 0;
1018 /* Continue reading until end of the column descriptor. */
1019 while (buf
< (buf_end
- 1) && fgets (buf
, buf_end
- buf
, fp
))
1021 if (strncmp (buf
, tag_column_desc_end
,
1022 strlen (tag_column_desc_end
)) == 0)
1024 column_desc_end
= buf
+ strlen (tag_column_desc_end
);
1027 buf
+= strlen (buf
);
1029 if (column_desc_end
)
1031 /* Found the end, copy it into a new string. */
1032 column_description
= XNEWVEC (char, column_desc_end
-
1033 column_desc_start
+ 1);
1034 got_column_description
= 1;
1035 strcpy (column_description
, column_desc_start
);
1036 tool_header
->column_description
= column_description
;
1039 buf
+= strlen (buf
);
1042 /* If we are missing any of the fields, return NULL. */
1043 if (!got_end_header
|| !got_hostname
|| !got_kversion
|| !got_hostcpu
1044 || !got_column_description
)
1049 free (column_description
);
1055 switch (the_pmu_tool_info
->event
)
1057 case PET_INTEL_LOAD_LATENCY
:
1058 case PET_AMD_LOAD_LATENCY
:
1059 column_header
= pfmon_ll_header
;
1061 case PET_INTEL_BRANCH_MISPREDICT
:
1062 case PET_AMD_BRANCH_MISPREDICT
:
1063 column_header
= pfmon_bm_header
;
1068 tool_header
->column_header
= strdup (column_header
);
1069 tool_header
->full_header
= buf_start
;
1074 /* Parse FILENAME for branch mispredict lines into a structure
1075 PMU_DATA. Returns 0 on on success. Returns non-zero on
1079 parse_pfmon_branch_mispredicts (char *filename
, void *pmu_data
)
1082 size_t buflen
= 2*1024;
1084 brm_infos_t
*brm_infos
= (brm_infos_t
*)pmu_data
;
1085 gcov_pmu_tool_header_t
*tool_header
= 0;
1087 if ((fp
= fopen (filename
, "r")) == NULL
)
1089 fprintf (stderr
, "cannot open pmu data file: %s\n", filename
);
1093 if (!(tool_header
= parse_pfmon_tool_header (fp
, pfmon_bm_header
)))
1095 fprintf (stderr
, "cannot parse pmu data file header: %s\n", filename
);
1099 buf
= XNEWVEC (char, buflen
);
1100 while (fgets (buf
, buflen
, fp
))
1102 gcov_pmu_brm_info_t
*brm
= XNEW (gcov_pmu_brm_info_t
);
1103 if (!parse_branch_mispredict_line (buf
, brm
))
1105 /* Valid line, add to the array. */
1106 brm_infos
->brm_count
++;
1107 if (brm_infos
->brm_count
>= brm_infos
->alloc_brm_count
)
1109 /* Do we need to realloc? */
1110 brm_infos
->brm_array
=
1111 realloc (brm_infos
->brm_array
,
1112 2 * brm_infos
->alloc_brm_count
);
1113 if (brm_infos
->brm_array
== NULL
) {
1115 "Cannot allocate memory for br mispredicts.\n");
1116 __destroy_pmu_tool_header (tool_header
);
1122 brm_infos
->brm_array
[brm_infos
->brm_count
- 1] = brm
;
1125 /* Delete invalid line. */
1130 brm_infos
->pmu_tool_header
= tool_header
;
1134 /* Start the monitoring process using pmu tool. Return 0 on success,
1135 non-zero otherwise. */
1142 /* no start function */
1143 if (!the_pmu_tool_info
->tool_details
->start_pmu_module
)
1149 /* error condition */
1150 fprintf (stderr
, "Cannot create PMU profiling process, exiting.\n");
1156 pid_t ppid
= getppid();
1157 char *tmpfile
= the_pmu_tool_info
->raw_pmu_profile_filename
;
1158 const char **pfmon_args
= the_pmu_tool_info
->tool_details
->arg_array
;
1161 /* Redirect stderr from the child process into a separate file. */
1162 new_stderr_fd
= creat (the_pmu_tool_info
->tool_stderr_filename
,
1163 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
);
1164 if (new_stderr_fd
!= -1)
1165 dup2 (new_stderr_fd
, 2);
1166 /* The following does an exec and thus is not expected to return. */
1167 the_pmu_tool_info
->tool_details
->start_pmu_module(ppid
, tmpfile
,
1169 /* exec returned, an error condition. */
1170 fprintf (stderr
, "could not create profiling process: %s\n",
1171 the_pmu_tool_info
->tool_details
->arg_array
[0]);
1177 the_pmu_tool_info
->pmu_tool_pid
= pid
;
1182 /* Allocate and initialize pmu load latency structure. */
1185 init_pmu_load_latency (void)
1187 ll_infos_t
*load_latency
= XNEWVEC (ll_infos_t
, 1);
1188 load_latency
->ll_count
= 0;
1189 load_latency
->alloc_ll_count
= 64;
1190 load_latency
->ll_array
= XNEWVEC (gcov_pmu_ll_info_t
*,
1191 load_latency
->alloc_ll_count
);
1192 return (void *)load_latency
;
1195 /* Allocate and initialize pmu branch mispredict structure. */
1198 init_pmu_branch_mispredict (void)
1200 brm_infos_t
*brm_info
= XNEWVEC (brm_infos_t
, 1);
1201 brm_info
->brm_count
= 0;
1202 brm_info
->alloc_brm_count
= 64;
1203 brm_info
->brm_array
= XNEWVEC (gcov_pmu_brm_info_t
*,
1204 brm_info
->alloc_brm_count
);
1205 return (void *)brm_info
;
1208 /* Initialize pmu tool based upon PMU_INFO. Sets the appropriate tool
1209 type in the global the_pmu_tool_info. */
1212 init_pmu_tool (struct gcov_pmu_info
*pmu_info
)
1214 the_pmu_tool_info
->pmu_profiling_state
= PMU_NONE
;
1215 the_pmu_tool_info
->verbose
= 0;
1216 the_pmu_tool_info
->tool
= PTT_PFMON
; /* we support only pfmon */
1217 the_pmu_tool_info
->pmu_tool_pid
= 0;
1218 the_pmu_tool_info
->top_n_address
= pmu_info
->pmu_top_n_address
;
1219 the_pmu_tool_info
->symbolizer_pid
= 0;
1220 the_pmu_tool_info
->symbolizer_to_pipefd
[0] = -1;
1221 the_pmu_tool_info
->symbolizer_to_pipefd
[1] = -1;
1222 the_pmu_tool_info
->symbolizer_from_pipefd
[0] = -1;
1223 the_pmu_tool_info
->symbolizer_from_pipefd
[1] = -1;
1225 if (parse_pmu_profile_options (pmu_info
->pmu_tool
))
1228 if (the_pmu_tool_info
->pmu_profiling_state
== PMU_ERROR
)
1230 fprintf (stderr
, "Unsupported PMU module: %s, disabling PMU profiling.\n",
1231 pmu_info
->pmu_tool
);
1235 if (the_pmu_tool_info
->tool_details
->init_pmu_module
)
1236 /* initialize module */
1237 the_pmu_tool_info
->pmu_data
=
1238 the_pmu_tool_info
->tool_details
->init_pmu_module();
1242 /* Initialize PMU profiling based upon the information passed in
1243 PMU_INFO and use pmu_profile_filename as the file to store the PMU
1244 profile. This is called multiple times from libgcov, once per
1245 object file. We need to make sure to do the necessary
1246 initialization only the first time. For subsequent invocations it
1247 behaves as a NOOP. */
1250 __gcov_init_pmu_profiler (struct gcov_pmu_info
*pmu_info
)
1252 char *raw_pmu_profile_filename
;
1253 char *tool_stderr_filename
;
1254 if (!pmu_info
|| !pmu_info
->pmu_profile_filename
|| !pmu_info
->pmu_tool
)
1257 /* Allocate the global structure on first invocation. */
1258 if (!the_pmu_tool_info
)
1260 the_pmu_tool_info
= XNEWVEC (struct pmu_tool_info
, 1);
1261 if (!the_pmu_tool_info
)
1263 fprintf (stderr
, "Error allocating memory for PMU tool\n");
1266 if (init_pmu_tool (pmu_info
))
1268 /* Initialization error. */
1269 XDELETE (the_pmu_tool_info
);
1270 the_pmu_tool_info
= 0;
1275 switch (the_pmu_tool_info
->pmu_profiling_state
)
1278 the_pmu_tool_info
->pmu_profile_filename
=
1279 strdup (pmu_info
->pmu_profile_filename
);
1280 /* Construct an intermediate filename by substituting trailing
1281 '.gcda' with '.pmud'. */
1282 raw_pmu_profile_filename
= strdup (pmu_info
->pmu_profile_filename
);
1283 if (raw_pmu_profile_filename
== NULL
)
1285 fprintf (stderr
, "Cannot allocate memory\n");
1288 strcpy (raw_pmu_profile_filename
+ strlen (raw_pmu_profile_filename
) - 4,
1291 /* Construct a filename for collecting PMU tool's stderr by
1292 substituting trailing '.gcda' with '.stderr'. */
1293 tool_stderr_filename
=
1294 XNEWVEC (char, strlen (pmu_info
->pmu_profile_filename
) + 1 + 2);
1295 strcpy (tool_stderr_filename
, pmu_info
->pmu_profile_filename
);
1296 strcpy (tool_stderr_filename
+ strlen (tool_stderr_filename
) - 4,
1298 the_pmu_tool_info
->raw_pmu_profile_filename
= raw_pmu_profile_filename
;
1299 the_pmu_tool_info
->tool_stderr_filename
= tool_stderr_filename
;
1300 the_pmu_tool_info
->pmu_profiling_state
= PMU_INITIALIZED
;
1303 case PMU_INITIALIZED
:
1313 /* Start PMU profiling. It updates the current state. */
1316 __gcov_start_pmu_profiler (void)
1318 if (!the_pmu_tool_info
)
1321 switch (the_pmu_tool_info
->pmu_profiling_state
)
1323 case PMU_INITIALIZED
:
1325 the_pmu_tool_info
->pmu_profiling_state
= PMU_ON
;
1327 the_pmu_tool_info
->pmu_profiling_state
= PMU_ERROR
;
1331 /* PMU was not properly initialized, don't attempt start it. */
1332 the_pmu_tool_info
->pmu_profiling_state
= PMU_ERROR
;
1336 /* Restarting PMU is not yet supported. */
1347 /* Stop PMU profiling. Currently it doesn't do anything except
1351 __gcov_stop_pmu_profiler (void)
1353 if (!the_pmu_tool_info
)
1356 if (the_pmu_tool_info
->tool_details
->stop_pmu_module
)
1357 the_pmu_tool_info
->tool_details
->stop_pmu_module();
1358 if (the_pmu_tool_info
->pmu_profiling_state
== PMU_ON
)
1359 the_pmu_tool_info
->pmu_profiling_state
= PMU_OFF
;
1362 /* Write the load latency information LL_INFO into the gcda file. */
1365 gcov_write_ll_line (const gcov_pmu_ll_info_t
*ll_info
)
1367 gcov_unsigned_t len
= GCOV_TAG_PMU_LOAD_LATENCY_LENGTH (ll_info
->filename
);
1368 gcov_write_tag_length (GCOV_TAG_PMU_LOAD_LATENCY_INFO
, len
);
1369 gcov_write_unsigned (ll_info
->counts
);
1370 gcov_write_unsigned (ll_info
->self
);
1371 gcov_write_unsigned (ll_info
->cum
);
1372 gcov_write_unsigned (ll_info
->lt_10
);
1373 gcov_write_unsigned (ll_info
->lt_32
);
1374 gcov_write_unsigned (ll_info
->lt_64
);
1375 gcov_write_unsigned (ll_info
->lt_256
);
1376 gcov_write_unsigned (ll_info
->lt_1024
);
1377 gcov_write_unsigned (ll_info
->gt_1024
);
1378 gcov_write_unsigned (ll_info
->wself
);
1379 gcov_write_counter (ll_info
->code_addr
);
1380 gcov_write_unsigned (ll_info
->line
);
1381 gcov_write_unsigned (ll_info
->discriminator
);
1382 gcov_write_string (ll_info
->filename
);
1386 /* Write the branch mispredict information BRM_INFO into the gcda file. */
1389 gcov_write_branch_mispredict_line (const gcov_pmu_brm_info_t
*brm_info
)
1391 gcov_unsigned_t len
= GCOV_TAG_PMU_BRANCH_MISPREDICT_LENGTH (
1392 brm_info
->filename
);
1393 gcov_write_tag_length (GCOV_TAG_PMU_BRANCH_MISPREDICT_INFO
, len
);
1394 gcov_write_unsigned (brm_info
->counts
);
1395 gcov_write_unsigned (brm_info
->self
);
1396 gcov_write_unsigned (brm_info
->cum
);
1397 gcov_write_counter (brm_info
->code_addr
);
1398 gcov_write_unsigned (brm_info
->line
);
1399 gcov_write_unsigned (brm_info
->discriminator
);
1400 gcov_write_string (brm_info
->filename
);
1403 /* Write load latency information INFO into the gcda file. The gcda
1404 file has already been opened and is available for writing. */
1407 gcov_write_load_latency_infos (void *info
)
1410 const ll_infos_t
*ll_infos
= (const ll_infos_t
*)info
;
1411 gcov_unsigned_t stamp
= 0; /* Don't use stamp as we don't support merge. */
1412 /* We don't support merge, and instead always rewrite the file. But
1413 to rewrite a gcov file we must first read it, however the read
1414 value is ignored. */
1415 gcov_read_unsigned ();
1417 gcov_write_tag_length (GCOV_DATA_MAGIC
, GCOV_VERSION
);
1418 gcov_write_unsigned (stamp
);
1419 if (ll_infos
->pmu_tool_header
)
1420 gcov_write_tool_header (ll_infos
->pmu_tool_header
);
1421 for (i
= 0; i
< ll_infos
->ll_count
; ++i
)
1423 /* Write each line. */
1424 gcov_write_ll_line (ll_infos
->ll_array
[i
]);
1429 /* Write branch mispredict information INFO into the gcda file. The
1430 gcda file has already been opened and is available for writing. */
1433 gcov_write_branch_mispredict_infos (void *info
)
1436 const brm_infos_t
*brm_infos
= (const brm_infos_t
*)info
;
1437 gcov_unsigned_t stamp
= 0; /* Don't use stamp as we don't support merge. */
1438 /* We don't support merge, and instead always rewrite the file. */
1440 gcov_write_tag_length (GCOV_DATA_MAGIC
, GCOV_VERSION
);
1441 gcov_write_unsigned (stamp
);
1442 if (brm_infos
->pmu_tool_header
)
1443 gcov_write_tool_header (brm_infos
->pmu_tool_header
);
1444 for (i
= 0; i
< brm_infos
->brm_count
; ++i
)
1446 /* Write each line. */
1447 gcov_write_branch_mispredict_line (brm_infos
->brm_array
[i
]);
1452 /* Compute TOOL_HEADER length for writing into the gcov file. */
1454 static gcov_unsigned_t
1455 gcov_tag_pmu_tool_header_length (gcov_pmu_tool_header_t
*header
)
1457 gcov_unsigned_t len
= 0;
1460 len
+= gcov_string_length (header
->host_cpu
);
1461 len
+= gcov_string_length (header
->hostname
);
1462 len
+= gcov_string_length (header
->kernel_version
);
1463 len
+= gcov_string_length (header
->column_header
);
1464 len
+= gcov_string_length (header
->column_description
);
1465 len
+= gcov_string_length (header
->full_header
);
1470 /* Write tool header into the gcda file. It assumes that the gcda file
1471 has already been opened and is available for writing. */
1474 gcov_write_tool_header (gcov_pmu_tool_header_t
*header
)
1476 gcov_unsigned_t len
= gcov_tag_pmu_tool_header_length (header
);
1477 gcov_write_tag_length (GCOV_TAG_PMU_TOOL_HEADER
, len
);
1478 gcov_write_string (header
->host_cpu
);
1479 gcov_write_string (header
->hostname
);
1480 gcov_write_string (header
->kernel_version
);
1481 gcov_write_string (header
->column_header
);
1482 gcov_write_string (header
->column_description
);
1483 gcov_write_string (header
->full_header
);
1487 /* End PMU profiling. If GCDA_ERROR is non-zero then write profiling data into
1488 already open gcda file */
1491 __gcov_end_pmu_profiler (int gcda_error
)
1496 pmu_tool_fns
*tool_details
;
1498 if (!the_pmu_tool_info
)
1501 tool_details
= the_pmu_tool_info
->tool_details
;
1502 pid
= the_pmu_tool_info
->pmu_tool_pid
;
1506 fprintf (stderr
, "terminating PMU profiling process %ld\n", (long)pid
);
1507 kill (pid
, SIGTERM
);
1509 fprintf (stderr
, "parent: waiting for pmu process to end\n");
1510 wait_status
= waitpid (pid
, &pid_status
, 0);
1512 if (wait_status
== pid
)
1513 fprintf (stderr
, "Normal exit. Child terminated.\n");
1515 fprintf (stderr
, "Abnormal exit. child status, %d.\n", pid_status
);
1519 if (the_pmu_tool_info
->pmu_profiling_state
!= PMU_OFF
)
1523 "__gcov_dump_pmu_profile: incorrect pmu state: %d, pid: %ld\n",
1524 the_pmu_tool_info
->pmu_profiling_state
,
1525 (unsigned long)pid
);
1529 if (!tool_details
->parse_pmu_output
)
1532 /* Since we are going to parse the output, we also need symbolizer. */
1533 if (tool_details
->start_symbolizer
)
1534 tool_details
->start_symbolizer (getpid ());
1536 if (!tool_details
->parse_pmu_output
1537 (the_pmu_tool_info
->raw_pmu_profile_filename
,
1538 the_pmu_tool_info
->pmu_data
))
1540 if (!gcda_error
&& tool_details
->gcov_write_pmu_data
)
1541 /* Write tool output into the gcda file. */
1542 tool_details
->gcov_write_pmu_data (the_pmu_tool_info
->pmu_data
);
1545 if (tool_details
->end_symbolizer
)
1546 tool_details
->end_symbolizer ();
1548 if (tool_details
->cleanup_pmu_data
)
1549 tool_details
->cleanup_pmu_data (the_pmu_tool_info
->pmu_data
);