This is an archive of the discontinued LLVM Phabricator instance.

Add llvm_gcov_flush to be called outside a shared library
ClosedPublic

Authored by chh on Apr 9 2018, 1:45 PM.

Diff Detail

Event Timeline

chh created this revision.Apr 9 2018, 1:45 PM
sylvestre.ledru edited reviewers, added: marco-c; removed: sylvestre.ledru.Apr 9 2018, 11:55 PM

With this change, gcov_flush will resolve to the copy in the main executable for each shared library -- this is not the desired the behavior.

chh added a comment.Apr 10 2018, 3:21 PM

If we use the unit test case, call __gcov_flush from the main function,
and dump static variables in GCDAProfiling.c, we can see that __gcov_flush
is resolved to the same copy for func.shared, func2.shared, and main.
However, when __gcov_flush is called from main and from f1_flush and f2_flush,
they use different copies of static variables defined in GCDAProfiling.c.
The "flush_fn_head" and its flush functions are different, so 3 calls of
__gcov_flush will flush to 3 different output files:

instrprof-dlopen-func.gcda
instrprof-dlopen-func2.gcda
instrprof-dlopen-dlclose-main.gcda

This keeps current Android use cases working as before __gcov_flush is hidden.
Is there other use case that could be broken by this change?

The behavior will change if the shared libraries are not 'dlopen'ed but loaded at program startup time.

chh added a comment.Apr 11 2018, 11:29 AM

Yes, calling __gcov_flush within .so files are different,
but it's a revert of https://reviews.llvm.org/D38124.
I think https://bugs.llvm.org/show_bug.cgi?id=27224
can be fixed by hiding only llvm_gcda_* functions,
without any change to __gcov_flush.

(1) Before https://reviews.llvm.org/D38124:

  • Calling __gcov_flush within .so or main function dumps to main gcda file.
  • Android's dlsym() lookup/call of __gcov_flush dumps to .so file specific gcda files.

(2) After https://reviews.llvm.org/D38124:

  • Android's dlsym() cannot find/call __gcov_flush.
  • Calling __gcov_flush from main works as in (1).
  • Calling __gcov_flush from .so works differently; it will dump to .so specific gcda file, not the main one.

(3) With this change, we revert __gcov_flush behavior back to (1).

Is there any application that needs to call __gcov_flush within .so
and expects the output to .so specific gcda file like in (2)?
I think the behavior of (1) is more desirable.
If a main program wants to dump to .so specific gcda file, like Android,
it can use dlsym() to look up .so specific __gcov_flush.

void removed a reviewer: void.Apr 17 2018, 2:34 PM
belleyb added a comment.EditedApr 18 2018, 6:29 AM

@chh I had a chance to try out your proposed changes. It's not causing us any trouble. In fact, __gcov_flush() is not even used at all (at least in LLVM 5.0.1).. I can recompile llvm, compiler_rt and clang and re-run all the tests with __gcov_flush commented out! No problem.

I would suggest adding a bit more documentation to __gcov_flush(), thus describing what those "special cases" are...

@chh I had a chance to try out your proposed changes. It's not causing us any trouble. In fact, __gcov_flush() is not even used at all (at least in LLVM 5.0.1).. I can recompile llvm, compiler_rt and clang and re-run all the tests with __gcov_flush commented out! No problem.

I would suggest adding a bit more documentation to __gcov_flush(), thus describing what those "special cases" are...

__gcov_flush is only used if you actually call it (it's needed for example if you want to profile only part of your program).

In GCC, gcov_flush is not hidden, so perhaps we should do the same to keep the same behavior? I've also submitted https://reviews.llvm.org/D48538, which is making gcov_flush flush counters for all shared libraries (like GCC does, with the same caveat: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83879).

chh added a comment.Jun 25 2018, 10:12 AM

@chh I had a chance to try out your proposed changes. It's not causing us any trouble. In fact, __gcov_flush() is not even used at all (at least in LLVM 5.0.1).. I can recompile llvm, compiler_rt and clang and re-run all the tests with __gcov_flush commented out! No problem.

I would suggest adding a bit more documentation to __gcov_flush(), thus describing what those "special cases" are...

__gcov_flush is only used if you actually call it (it's needed for example if you want to profile only part of your program).

In GCC, gcov_flush is not hidden, so perhaps we should do the same to keep the same behavior? I've also submitted https://reviews.llvm.org/D48538, which is making gcov_flush flush counters for all shared libraries (like GCC does, with the same caveat: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83879).

I have no problem keeping these functions compatible with GCC.
My earlier proposal and David's comment in the mailing list seemed to be lost and not showing here.
So, let me summarize the case here. This change should make __gcov_flush not hidden as before in GCC,
but earlier change made it hidden as well as other llvm_gov_* functions.
Could we have both __gov_flush and llvm_gov_flush functions, one unhidden and one hidden?

chh updated this revision to Diff 152957.Jun 26 2018, 2:03 PM
chh edited the summary of this revision. (Show Details)

Wouldn't it be better to keep compatibility with GCC and make
__gcov_flush have default visibility?

  • Marco.

Il 26/06/2018 00:21, Xinliang David Li ha scritto:

I don't have an objection having another interface which is just a
simple wrapper to __gcov_flush but with default visibility. Also
clearly document its usage and behavior.

David

GCC's behavior is not documented and it also has changed over the years.

Unless there is a bug, changing LLVM's gcov_flush visibility can potentially break clients that depend on this behavior.

GCC's behavior is not documented and it also has changed over the years.

Unless there is a bug, changing LLVM's gcov_flush visibility can potentially break clients that depend on this behavior.

I think that's the issue though. LLVM changed visibility of this function recently too. We had Android code depending on this function being visible, and that broke.

Yes, the behavior changed very recently, I would be surprised if
somebody came to depend on it. It's more likely that some clients are
depending on the old behavior.

  • Marco.

Il 26/06/2018 22:43, Stephen Hines via Phabricator ha scritto:

srhines added a comment.

In https://reviews.llvm.org/D45454#1144099, @davidxl wrote:

GCC's behavior is not documented and it also has changed over the years.

Unless there is a bug, changing LLVM's gcov_flush visibility can potentially break clients that depend on this behavior.

I think that's the issue though. LLVM changed visibility of this function recently too. We had Android code depending on this function being visible, and that broke.

https://reviews.llvm.org/D45454

chh updated this revision to Diff 153532.Jun 29 2018, 10:48 AM
chh retitled this revision from Make __gcov_flush visible outside a shared library to Add llvm_gcov_flush to be called outside a shared library.
chh edited the summary of this revision. (Show Details)

Now keep __gcov_flush hidden as libgcov; add llvm_gcov_flush to call from outside of .so files.

Thanks for picking this up again and updating the change to add llvm_gcov_flush().

test/profile/Inputs/instrprof-dlopen-dlclose-main.c
21

Should also clear dlerror() before this call and check that dlerror() returned a non-NULL pointer indicating that this search failed.

Why keeping a gcov_flush which is incompatible with GCC and previous versions of LLVM and adding a llvm_gcov_flush which is compatible? I feel the other way around (or even just having an unhidden "gcov_flush" and not introducing "llvm_gcov_flush") would be more sensible.

With the current gcov_flush implementation in LLVM, making gcov_flush's visibility to be default will simply lead to wrong behavior. GCC libgcov's implementation is more elaborate -- it allows gcov_flush to dump gcda data for all dynamic objects while making sure gcov_exit only dumps the gcda files from the same dynamic module (otherwise, there will be wrong profile merging). This is done via two levels of linked list.

The patch https://reviews.llvm.org/D48538 is in the right direction, but not complete yet.

chh added a comment.Jun 29 2018, 11:37 AM

Marco, latest patch does not change gcov_flush, which is also hidden in libgcov.
Android coverage test programs have depended on an earlier compiler-rt that did not hide
gcov_flush.
If that's the only use case broken by recent change of compiler-rt, which hide gcov_flush,
I think it is okay to keep compiler-rt the same as it is now.
Adding a visible llvm_gcov_flush will allow Android coverage test program to use it and dump system .so profiling data,
from the main test program.
Keeping an hidden
gcov_flush has the purpose that David mentioned earlier, to let each .so file dump its own profiling data.

OK! Sounds good to me to keep it hidden until
https://reviews.llvm.org/D48538 is done (I'm going to try to finish it
soon).

Il 29/06/2018 19:34, David Li via Phabricator ha scritto:

davidxl added a comment.

With the current gcov_flush implementation in LLVM, making gcov_flush's visibility to be default will simply lead to wrong behavior. GCC libgcov's implementation is more elaborate -- it allows gcov_flush to dump gcda data for all dynamic objects while making sure gcov_exit only dumps the gcda files from the same dynamic module (otherwise, there will be wrong profile merging). This is done via two levels of linked list.

The patch https://reviews.llvm.org/D48538 is in the right direction, but not complete yet.

https://reviews.llvm.org/D45454

chh updated this revision to Diff 153569.Jun 29 2018, 2:16 PM
chh marked an inline comment as done.

Added calls to dlerror() before other dl* functions.

davidxl added inline comments.Jun 29 2018, 2:25 PM
lib/profile/GCDAProfiling.c
546

Just document this interface has non-hidden visibility and will resolve to a unified copy. The right underlying behavior is for it to dump profiles from all dynamic modules, but it is not there until Marco's patch is in.

In other words, do not need to document the current behavior for now.

chh updated this revision to Diff 153573.Jun 29 2018, 2:26 PM

check dlerror() where it shouldn't be NULL

test/profile/Inputs/instrprof-dlopen-dlclose-main.c
21

Look up of __gcov_flush is expected to fail because it's hidden.
Other places checks for returned value and report dlerror() messages.

LGTM. Thanks for making the checking more clear. This should help bridge the gap for now, so that we can resume getting per-library profile data in Android.

chh updated this revision to Diff 153576.Jun 29 2018, 2:32 PM
chh marked an inline comment as done.
davidxl accepted this revision.Jun 29 2018, 2:33 PM

lgtm

This revision is now accepted and ready to land.Jun 29 2018, 2:33 PM
This revision was automatically updated to reflect the committed changes.
Herald added a subscriber: Restricted Project. · View Herald TranscriptJun 29 2018, 2:50 PM