There is no need to write out gcdas when forking because we can just reset the counters in the parent process.
Let say a counter is N before the fork, then fork and this counter is set to 0 in the child process.
In the parent process, the counter is incremented by P and in the child process it's incremented by C.
When dump is ran at exit, parent process will dump N+P for the given counter and the child process will dump 0+C, so when the gcdas are merged the resulting counter will be N+P+C.
About exec** functions, since the current process is replaced by an another one there is no need to reset the counters but just write out the gcdas since the counters are definitely lost.
To avoid to have lists in a bad state, we just lock them during the fork and the flush (if called explicitely) and lock them when an element is added.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
- Build Status
Buildable 46995 Build 49727: arc lint + arc unit
Event Timeline
Also, as we discussed, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93623#c5 regarding exec.
compiler-rt/lib/profile/GCDAProfiling.c | ||
---|---|---|
677 | Could you expand the comment explaining a situation where this could fail if we didn't lock? | |
683 | Nit: do we need this check or can we just use the earlier one on pid == 0? | |
687 | What if we have a thread in another process making modifications to the list? | |
llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp | ||
635 | Since we are now mostly doing different things on forks and execs, we could remove this vector and just do the operations directly instead of adding to the vec. | |
671 | Isn't this bug fixed by splitting the block? |
If exec** fails we need to reset the counters since they've have dumped just before to avoid to count them twice.
Add more comments to explain why we need to lock around the fork
compiler-rt/lib/profile/GCDAProfiling.c | ||
---|---|---|
683 | I added this check to be sure we had a true fork in case of someone wrote its own fork function. | |
687 | When forking, only the thread in the parent process is copied so in the child process we've only one thread. | |
llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp | ||
635 | If we make the insertions of new code in the second for loop, we'll invalidate the iterator used in this loop. | |
671 | With the example shew here, the split is in foo but not in bar, blah() should be in another block |
Could you test the last iteration of the patch on Mozilla's CI (with the workaround for the mismatch in LLVM version used by Rust)?
llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp | ||
---|---|---|
635 | M->getOrInsertFunction is what would invalidate the iterator? You could clean things up a bit by having two vectors then, one for forks and one for execs. | |
686 | Replace with // No need to reset the counters since they'll be lost after the exec** |
llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp | ||
---|---|---|
635 | Builder.Create** will invalidate the iterator |
Could you expand the comment explaining a situation where this could fail if we didn't lock?