libgcov.c is the main file to generate libgcov.a. This single source generates
21 object files and then archives to a library. These objects are of
very different purposes but they are in the same file guarded by various macros.
The source file becomes quite large and its readability becomes very
low. In its current state:
1) The code is very hard to understand by new developers;
2) It makes regressions more likely when making simple changes;
More importantly,
3) it makes code reuse/sharing very difficult. For instance, Using
libgcov to implement an offline profile tool (see below); kernel FDO
support etc.
We came to this issue when working on an offline tool to handle
profile counters.
Our plan is to have a profile-tool can merge, diff, collect statistics, and
better dump raw profile counters. This is one of the most requested features
from out internal users. This tool can also be very useful for any FDO/coverage
users. In the first part of tool, we want to have the weight
merge. Again, to reuse the code, we have to change libgcov.c. But we don't want
to further diverge libgcov.a in our google branches from the trunk.
Another issue in libgcov.c is function gcov_exit(). It is a huge function
with about 467 lines of code. This function traverses gcov_list and dumps all
the gcda files. The code for merging the gcda files also sits in the same
function. The structure makes the code-reuse and extension really difficult
(like in kernel FDO, we have to break this function to reuse some of the code).
We propose to break gcov_exit into smaller functions and split libgcov.c into
several files. Our plan for profile-tool is listed in (3).
1. break gcov_exit() into the following structure:
gcov_exit()
--> gcov_exit_compute_summary()
--> allocate_filename_struct()
for gi_ptr in gcov_list
--> gcov_exit_dump_gcov()
--> gcov_exit_open_gcda_file()
--> gcov_exit_merge_gcda ()
--> gcov_exit_write_gcda ()
2. split libgcov.c into the following files:
libgcov-profiler.c
libgcov-merge.c
libgcov-interface.c
libgcov-driver.c
libgcov-driver-system.c (source included into libgcov-driver.c)
The details of the splitting:
libgcov-interface.c
/* This file contains API functions to other programs and the supporting
functions. */
__gcov_dump()
__gcov_execl()
__gcov_execle()
__gcov_execlp()
__gcov_execv()
__gcov_execve()
__gcov_execvp()
__gcov_flush()
__gcov_fork()
__gcov_reset()
init_mx()
init_mx_once()
libgcov-profiler.c
/* This file contains runtime profile handlers. */
variables:
__gcov_indirect_call_callee
__gcov_indirect_call_counters
functions:
__gcov_average_profiler()
__gcov_indirect_call_profiler()
__gcov_indirect_call_profiler_v2()
__gcov_interval_profiler()
__gcov_ior_profiler()
__gcov_one_value_profiler()
__gcov_one_value_profiler_body()
__gcov_pow2_profiler()
libgcov-merge.c
/* This file contains the merge functions for various counters. */
functions:
__gcov_merge_add()
__gcov_merge_delta()
__gcov_merge_ior()
__gcov_merge_single()
libcov-driver.c
/* This file contains the gcov dumping functions. We separate the
system dependent part to libgcov-driver-system.c. */
variables:
gcov_list
gcov_max_filename
gcov_dump_complete
------ newly added file static variables --
this_prg
all_prg
crc32
gi_filename
fn_buffer
fn_tail
sum_buffer
next_sum_buffer
sum_tail
----- end -----
functions:
free_fn_data()
buffer_fn_data()
crc32_unsigned()
gcov_version()
gcov_histogram_insert()
gcov_compute_histogram()
gcov_clear()
__gcov_init()
gcov_exit()
------- newly added static functions --
gcov_exit_compute_summary ()
gcov_exit_merge_gcda()
gcov_exit_write_gcda()
gcov_exit_dump_gcov()
----- end -----
libgcov-driver-system.c
/* system dependent part of ligcov-driver.c. */
functions:
create_file_directory()
------- newly added static functions --
gcov_error() /* This replaces all fprintf(stderr, ...) */
allocate_filename_struct()
gcov_exit_open_gcda_file()
3. add offline profile-tool support.
We will change the interface of merge functions to make it
take in-memory gcov_info list, and a weight as the arguments.
We will add libgcov-tool.c. It has two APIs:
(1) read_profile_dir(): read a profile directory and reconstruct the
gcov_info link list in-memory.
(2) merge_profiles(): merge two in-memory gcov_info link list.
We also add profile-tool.c in gcc directory. It will source-include
libgcov-tool.c and build a host binary. (We don't do library style
because that will need a hard dependence from gcc to libgcc).
profile-tool.c will mainly handle user options and the write-out of
gcov-info link list. Some changes in gcov-io.[ch] will be also needed.
Thanks,
-Rong