On Wed, Aug 29, 2018 at 12:44 PM Martin Liška <mli...@suse.cz> wrote: > > On 08/29/2018 11:17 AM, Richard Biener wrote: > > On Wed, Aug 29, 2018 at 10:31 AM Martin Liška <mli...@suse.cz> wrote: > >> > >> Hello. > >> > >> Moving the thread from gcc ML into gcc-patches. That's first implementation > >> of shared libgcov library. Currently inclusion of t-libgcov is added only > >> to *-linux targets. Is it fine to add to all configurations that already > >> include 't-slibgcc t-slibgcc-elf-ver'? > >> > >> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests. > > > > I understand this is to make profiling work with multiple DSOs (all > > instrumented). > > Yes. > > > But does this also make the case work when those DSOs are dlopened/dlclosed > > multiple times? > > That works fine even now, when a DSO is loaded, __gcov_init is called and > it registers gcov_info into __gcov_root. > > Following sample: > > #include <dlfcn.h> > #include <assert.h> > #include <unistd.h> > > int main() > { > for (int i = 0; i < 10; i++) > { > void *handle = dlopen ("libfoo.so", RTLD_NOW); > assert (handle); > > void (*fn) (void) = dlsym (handle, "foo"); > assert (fn); > > fn (); > sleep (1); > } > > return 0; > }
That doesn't dlclose ;) > has: > > $ gcov-dump -l foo.gcda > foo.gcda:data:magic `gcda':version `A82*' > foo.gcda:stamp 2235622999 > foo.gcda: a3000000: 22:PROGRAM_SUMMARY checksum=0x02bfe640 > foo.gcda: counts=2, runs=1, sum_all=20, run_max=10, sum_max=10 > foo.gcda: counter histogram: > foo.gcda: 9: num counts=2, min counter=10, cum_counter=20 > foo.gcda: 01000000: 3:FUNCTION ident=1636255671, > lineno_checksum=0x2172766e, cfg_checksum=0xc0bbb23e > foo.gcda: 01a10000: 4:COUNTERS arcs 2 counts > foo.gcda: 0: 10 10 > foo.gcda: 01af0000: 2:COUNTERS time_profiler 1 counts > foo.gcda: 0: 1 > > which is fine, runs == 1 and arcs counter executed 10x. > > > I understand that with the shared libgcov implementation this > > library must be finalized last? > > If you do profiling, then you depend on libgcov, thus it's loaded before a > DSO (or executable) > is loaded. > > Wouldn't it be better to have some additional > > object that lives in an executable only? Or do we want profiled DSOs > > without > > profiling the executable using it? > > That should be rare, but it will be possible as __gcov_exit will be > eventually called. I'm not too familiar but I guess each DSO _fini will call __gcov_exit? > Does that case work with the shared libgcov > > (with dlopen/dlclose)? > > Yes, I've just tested that. > > Does it work when DSO1 is compiled with GCC N > > and DSO2 is compiled with GCC N+1 where the libgcov ABI changed? > > For such case we have: > > /* Exactly one of these will be live in the process image. */ > struct gcov_master __gcov_master = > {GCOV_VERSION, 0}; > ... > and it's check in __gcov_init. So it doesn't work. Too bad, in the past we shipped a profiling (-pg) glibc build but that would then only work for the same compiler. I guess using a shared libgcov makes profiling the dynamic loader DSO impossible? So we'd likely want a -static-libgcov option as well? > > > > I think we need a better understanding of the situation before jumping to > > the conclusion that a shared libgcov is the solution. Maybe better > > isolating > > the individual instances is better? > > It's undesired as seen in the PR. When doing profiling of indirect jumps > we need have exactly one __gcov_indirect_call_callee. That's because one can > do indirect calls that cross DSO boundaries. But usually you don't inline across DSO boundaries and after devirtualizing you still need to go through the PLT... Btw, when you dlopen/dlcose a DSO multiple times the same function can end up at different addresses, does gcov somehow deal with this? It seems that the profile functions get the callee address. Can you shortly tell why the testcase in the PR segfaults? Does the issue only affect indirect call profiling? Richard. > Martin > > > > > Richard. > > > >> Martin > >> > >> libgcc/ChangeLog: > >> > >> 2018-08-28 Martin Liska <mli...@suse.cz> > >> > >> PR gcov-profile/84107 > >> * Makefile.in: Build libgcov.so objects separately, > >> add rule for libgcov.map and how the library > >> is linked. > >> * config.host: Add t-libgcov and t-libgcov-elf-ver > >> to *-linux targets. > >> * config/t-libgcov: New file. > >> * config/t-libgcov-elf-ver: New file. > >> * libgcov-driver.c: Declare function if new L_gcov_shared > >> is defined. > >> * libgcov-interface.c: Likewise. > >> * libgcov-merge.c: Likewise. > >> * libgcov-profiler.c: Likewise. > >> * libgcov-std.ver.in: New file. > >> * libgcov.h (__gcov_init): Remove ATTRIBUTE_HIDDEN. > >> (__gcov_exit): Likewise. > >> (__gcov_merge_add): Likewise. > >> (__gcov_merge_time_profile): Likewise. > >> (__gcov_merge_single): Likewise. > >> (__gcov_merge_ior): Likewise. > >> (__gcov_merge_icall_topn): Likewise. > >> (gcov_sort_n_vals): Likewise. > >> (__gcov_fork): Likewise. > >> (__gcov_execl): Likewise. > >> (__gcov_execlp): Likewise. > >> (__gcov_execle): Likewise. > >> (__gcov_execv): Likewise. > >> (__gcov_execvp): Likewise. > >> (__gcov_execve): Likewise. > >> --- > >> libgcc/Makefile.in | 56 ++++++++++++++++++++++++++++++--- > >> libgcc/config.host | 2 +- > >> libgcc/config/t-libgcov | 46 +++++++++++++++++++++++++++ > >> libgcc/config/t-libgcov-elf-ver | 3 ++ > >> libgcc/libgcov-driver.c | 4 +-- > >> libgcc/libgcov-interface.c | 28 ++++++++--------- > >> libgcc/libgcov-merge.c | 14 ++++----- > >> libgcc/libgcov-profiler.c | 34 ++++++++++---------- > >> libgcc/libgcov-std.ver.in | 53 +++++++++++++++++++++++++++++++ > >> libgcc/libgcov.h | 31 +++++++++--------- > >> 10 files changed, 209 insertions(+), 62 deletions(-) > >> create mode 100644 libgcc/config/t-libgcov > >> create mode 100644 libgcc/config/t-libgcov-elf-ver > >> create mode 100644 libgcc/libgcov-std.ver.in > >> > >> >