-
Notifications
You must be signed in to change notification settings - Fork 37.7k
tracing: macOS USDT support #25541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tracing: macOS USDT support #25541
Conversation
Concept ACK. It would be great to support tracing on MacOS assuming the maintenance burden is satisfactory. (The linter checks are failing currently.) |
Concept ACK |
05f7baf
to
1aacde1
Compare
Concept ACK. Thank you for working on this 🚀 I plan to review this. I want to see e.g. what additional things we would need to consider when adding new tracepoints. A few first impressions, notes, and questions:
cc @jb55 |
// since the dtrace macros are automatically generated in uppercase, additional | ||
// macros are needed to translate the lowercase context & event names into the | ||
// required uppercase CONTEXT_EVENT macros |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could change that, if this makes it a lot easier for macOS. This would probably be an API break, but I think the tracepoints are still experimental enough to be able to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing to uppercase was part of my initial implementation but I changed my mind.
Even if we need those uppercase macros for macOS, the actual tracepoints for macOS would still be of the format net:inbound_message
. But my understanding is that if we change TRACEx
to TRACE6(NET, INBOUND_MESSSAGE, ..args)
the Linux tracepoints would be NET:INBOUND_MESSSAGE
thus not having a unified format across systems.
Thank you for the review @0xB10C! I am not happy with that custom patch either, but this being my first interaction with the build system, I was not sure what is consider acceptable. In retrospect, it is not and it adds unnecessary maintenance burden.
If what you mentioned at #25541 (comment) is acceptable and we find a way to not use
Looking into the probes_sdt branch in that article, it seems that generating it during build time might be possible. This would possibly result to a probes.d file that works for both Linux and macOS. I initially avoided going that route because of the currently required changes (patch) after the file generation.
I think being different makes sense as the resulting file has a different target os? My
Yes, I plan to enhance the docs as soon as this works well. I'll convert this to a draft PR until I find a way to get rid of the patch and in the meantime fix the failing checks. |
8edd380
to
64d0862
Compare
@@ -4275,7 +4275,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt | |||
pfrom->ConnectionTypeAsString().c_str(), | |||
msg.m_type.c_str(), | |||
msg.m_recv.size(), | |||
msg.m_recv.data() | |||
(unsigned char*)(msg.m_recv.data()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: I want to check if this causes a difference in the number of instructions for this tracepoint. I think a reinterpret_cast
could also work here as an alternative:
Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions [..]
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
f3734d8
to
c6ce901
Compare
4a23882
to
8498bcf
Compare
This deduplicates the TRACEx macros by using systemtaps [STAP_PROBEV] variadic macro instead of the [DTrace compability DTRACE_PROBE] macros. Bitcoin Core never had DTrace tracepoints, so we don't need to use the drop-in replacement for it. As noted in bitcoin#25541[1], these macros aren't compatibile with DTrace on macOS anyway. The (currently unused) TRACE() macro is renamed to TRACEPOINT0(). The deduplication is helpful for the next commit too. This also renames the TRACEx macro to TRACEPOINT to clarify what the macro does: inserting a tracepoint vs tracing (logging) something. [STAP_PROBEV]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l407 [DTrace compability DTRACE_PROBE]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l490 [1]: https://github.com/bitcoin/bitcoin/pull/25541/files#diff-553886c5f808e01e3452c7b21e879cc355da388ef7680bf310f6acb926d43266R30-R31
Before this commit, we would always prepare tracepoint arguments regardless of the tracepoint being used or not. While we already made sure not to include expensive arguments in our tracepoints, this commit introduces gating to make sure the arguments are only prepared if the tracepoints are actually used. This is a win-win improvement to our tracing framework. For users not interested in tracing, the overhead is reduced to a cheap 'greater than 0' compare. As the semaphore-gating technique used here is available in bpftrace, bcc, and libbpf, users interested in tracing don't have to change their tracing scripts while profiting from potential future tracepoints passing slightly more expensive arguments. In the context of bitcoin#26531's mempool tracepoints, one example could be passing serialized transactions for RBF replacements. Under the hood, the semaphore-gating works by placing a 2-byte semaphore in the '.probes' ELF section. The address of the semaphore is contained in the ELF note providing the tracepoint information (`readelf -n ./src/bitcoind | grep NT_STAPSDT`). Tracing toolkits like bpftrace, bcc, and libbpf increase the semaphore at the address upon attaching to the tracepoint. We only prepare the arguments and reach the tracepoint if the semaphore is greater than zero. The semaphore is decreased when detaching from the tracepoint. The implementation of the TRACEPOINT_ACTIVE macro is flexible enough that it can be adapted for macOS dtrace tracing (bitcoin#25541). With dtrace, [CONTEXT]_[EVENT]_ENABLED() can be used to gate the tracepoints. While the TRACEPOINT0(context, event) macro without arguments doesn't need a check if it's active or not (no arguments can be prepared and passed), it does require a TRACEPOINT_SEMAPHORE() due to _SDT_HAS_SEMAPHORES requiring all tracepoints to have a semaphore. As the check is cheap, a check is added to not cause problems with the semaphore being unused. This also extends the "Adding a new tracepoint" documentation to include information about the semaphores and updated step-by-step instructions on how to add a new tracepoint.
Before this commit, we would always prepare tracepoint arguments regardless of the tracepoint being used or not. While we already made sure not to include expensive arguments in our tracepoints, this commit introduces gating to make sure the arguments are only prepared if the tracepoints are actually used. This is a win-win improvement to our tracing framework. For users not interested in tracing, the overhead is reduced to a cheap 'greater than 0' compare. As the semaphore-gating technique used here is available in bpftrace, bcc, and libbpf, users interested in tracing don't have to change their tracing scripts while profiting from potential future tracepoints passing slightly more expensive arguments. In the context of bitcoin#26531's mempool tracepoints, one example could be passing serialized transactions for RBF replacements. Under the hood, the semaphore-gating works by placing a 2-byte semaphore in the '.probes' ELF section. The address of the semaphore is contained in the ELF note providing the tracepoint information (`readelf -n ./src/bitcoind | grep NT_STAPSDT`). Tracing toolkits like bpftrace, bcc, and libbpf increase the semaphore at the address upon attaching to the tracepoint. We only prepare the arguments and reach the tracepoint if the semaphore is greater than zero. The semaphore is decreased when detaching from the tracepoint. The implementation of the TRACEPOINT_ACTIVE macro is flexible enough that it can be adapted for macOS dtrace tracing (bitcoin#25541). With dtrace, [CONTEXT]_[EVENT]_ENABLED() can be used to gate the tracepoints. While the TRACEPOINT0(context, event) macro without arguments doesn't need a check if it's active or not (no arguments can be prepared and passed), it does require a TRACEPOINT_SEMAPHORE() due to _SDT_HAS_SEMAPHORES requiring all tracepoints to have a semaphore. As the check is cheap, a check is added to not cause problems with the semaphore being unused. This also extends the "Adding a new tracepoint" documentation to include information about the semaphores and updated step-by-step instructions on how to add a new tracepoint.
This deduplicates the TRACEx macros by using systemtaps [STAP_PROBEV] variadic macro instead of the [DTrace compability DTRACE_PROBE] macros. Bitcoin Core never had DTrace tracepoints, so we don't need to use the drop-in replacement for it. As noted in bitcoin#25541[1], these macros aren't compatibile with DTrace on macOS anyway. The (currently unused) TRACE() macro is renamed to TRACEPOINT0(). The deduplication is helpful for the next commit too. This also renames the TRACEx macro to TRACEPOINT to clarify what the macro does: inserting a tracepoint vs tracing (logging) something. [STAP_PROBEV]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l407 [DTrace compability DTRACE_PROBE]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l490 [1]: https://github.com/bitcoin/bitcoin/pull/25541/files#diff-553886c5f808e01e3452c7b21e879cc355da388ef7680bf310f6acb926d43266R30-R31
Before this commit, we would always prepare tracepoint arguments regardless of the tracepoint being used or not. While we already made sure not to include expensive arguments in our tracepoints, this commit introduces gating to make sure the arguments are only prepared if the tracepoints are actually used. This is a win-win improvement to our tracing framework. For users not interested in tracing, the overhead is reduced to a cheap 'greater than 0' compare. As the semaphore-gating technique used here is available in bpftrace, bcc, and libbpf, users interested in tracing don't have to change their tracing scripts while profiting from potential future tracepoints passing slightly more expensive arguments. In the context of bitcoin#26531's mempool tracepoints, one example could be passing serialized transactions for RBF replacements. Under the hood, the semaphore-gating works by placing a 2-byte semaphore in the '.probes' ELF section. The address of the semaphore is contained in the ELF note providing the tracepoint information (`readelf -n ./src/bitcoind | grep NT_STAPSDT`). Tracing toolkits like bpftrace, bcc, and libbpf increase the semaphore at the address upon attaching to the tracepoint. We only prepare the arguments and reach the tracepoint if the semaphore is greater than zero. The semaphore is decreased when detaching from the tracepoint. The implementation of the TRACEPOINT_ACTIVE macro is flexible enough that it can be adapted for macOS dtrace tracing (bitcoin#25541). With dtrace, [CONTEXT]_[EVENT]_ENABLED() can be used to gate the tracepoints. While the TRACEPOINT0(context, event) macro without arguments doesn't need a check if it's active or not (no arguments can be prepared and passed), it does require a TRACEPOINT_SEMAPHORE() due to _SDT_HAS_SEMAPHORES requiring all tracepoints to have a semaphore. As the check is cheap, a check is added to not cause problems with the semaphore being unused. This also extends the "Adding a new tracepoint" documentation to include information about the semaphores and updated step-by-step instructions on how to add a new tracepoint.
This deduplicates the TRACEx macros by using systemtaps [STAP_PROBEV] variadic macro instead of the [DTrace compability DTRACE_PROBE] macros. Bitcoin Core never had DTrace tracepoints, so we don't need to use the drop-in replacement for it. As noted in bitcoin#25541[1], these macros aren't compatibile with DTrace on macOS anyway. The (currently unused) TRACE() macro is renamed to TRACEPOINT0(). The deduplication is helpful for the next commit too. This also renames the TRACEx macro to TRACEPOINT to clarify what the macro does: inserting a tracepoint vs tracing (logging) something. [STAP_PROBEV]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l407 [DTrace compability DTRACE_PROBE]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l490 [1]: https://github.com/bitcoin/bitcoin/pull/25541/files#diff-553886c5f808e01e3452c7b21e879cc355da388ef7680bf310f6acb926d43266R30-R31
Before this commit, we would always prepare tracepoint arguments regardless of the tracepoint being used or not. While we already made sure not to include expensive arguments in our tracepoints, this commit introduces gating to make sure the arguments are only prepared if the tracepoints are actually used. This is a win-win improvement to our tracing framework. For users not interested in tracing, the overhead is reduced to a cheap 'greater than 0' compare. As the semaphore-gating technique used here is available in bpftrace, bcc, and libbpf, users interested in tracing don't have to change their tracing scripts while profiting from potential future tracepoints passing slightly more expensive arguments. In the context of bitcoin#26531's mempool tracepoints, one example could be passing serialized transactions for RBF replacements. Under the hood, the semaphore-gating works by placing a 2-byte semaphore in the '.probes' ELF section. The address of the semaphore is contained in the ELF note providing the tracepoint information (`readelf -n ./src/bitcoind | grep NT_STAPSDT`). Tracing toolkits like bpftrace, bcc, and libbpf increase the semaphore at the address upon attaching to the tracepoint. We only prepare the arguments and reach the tracepoint if the semaphore is greater than zero. The semaphore is decreased when detaching from the tracepoint. The implementation of the TRACEPOINT_ACTIVE macro is flexible enough that it can be adapted for macOS dtrace tracing (bitcoin#25541). With dtrace, [CONTEXT]_[EVENT]_ENABLED() can be used to gate the tracepoints. While the TRACEPOINT0(context, event) macro without arguments doesn't need a check if it's active or not (no arguments can be prepared and passed), it does require a TRACEPOINT_SEMAPHORE() due to _SDT_HAS_SEMAPHORES requiring all tracepoints to have a semaphore. As the check is cheap, a check is added to not cause problems with the semaphore being unused. This also extends the "Adding a new tracepoint" documentation to include information about the semaphores and updated step-by-step instructions on how to add a new tracepoint.
This deduplicates the TRACEx macros by using systemtaps [STAP_PROBEV] variadic macro instead of the [DTrace compability DTRACE_PROBE] macros. Bitcoin Core never had DTrace tracepoints, so we don't need to use the drop-in replacement for it. As noted in bitcoin#25541[1], these macros aren't compatibile with DTrace on macOS anyway. The (currently unused) TRACE() macro is renamed to TRACEPOINT0(). The deduplication is helpful for the next commit too. This also renames the TRACEx macro to TRACEPOINT to clarify what the macro does: inserting a tracepoint vs tracing (logging) something. [STAP_PROBEV]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l407 [DTrace compability DTRACE_PROBE]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l490 [1]: https://github.com/bitcoin/bitcoin/pull/25541/files#diff-553886c5f808e01e3452c7b21e879cc355da388ef7680bf310f6acb926d43266R30-R31
Before this commit, we would always prepare tracepoint arguments regardless of the tracepoint being used or not. While we already made sure not to include expensive arguments in our tracepoints, this commit introduces gating to make sure the arguments are only prepared if the tracepoints are actually used. This is a win-win improvement to our tracing framework. For users not interested in tracing, the overhead is reduced to a cheap 'greater than 0' compare. As the semaphore-gating technique used here is available in bpftrace, bcc, and libbpf, users interested in tracing don't have to change their tracing scripts while profiting from potential future tracepoints passing slightly more expensive arguments. In the context of bitcoin#26531's mempool tracepoints, one example could be passing serialized transactions for RBF replacements. Under the hood, the semaphore-gating works by placing a 2-byte semaphore in the '.probes' ELF section. The address of the semaphore is contained in the ELF note providing the tracepoint information (`readelf -n ./src/bitcoind | grep NT_STAPSDT`). Tracing toolkits like bpftrace, bcc, and libbpf increase the semaphore at the address upon attaching to the tracepoint. We only prepare the arguments and reach the tracepoint if the semaphore is greater than zero. The semaphore is decreased when detaching from the tracepoint. The implementation of the TRACEPOINT_ACTIVE macro is flexible enough that it can be adapted for macOS dtrace tracing (bitcoin#25541). With dtrace, [CONTEXT]_[EVENT]_ENABLED() can be used to gate the tracepoints. While the TRACEPOINT0(context, event) macro without arguments doesn't need a check if it's active or not (no arguments can be prepared and passed), it does require a TRACEPOINT_SEMAPHORE() due to _SDT_HAS_SEMAPHORES requiring all tracepoints to have a semaphore. As the check is cheap, a check is added to not cause problems with the semaphore being unused. This also extends the "Adding a new tracepoint" documentation to include information about the semaphores and updated step-by-step instructions on how to add a new tracepoint.
What's the status of this? |
It seems that there isn't enough interest for this change. But anyway. with the current status of #26593, it doesn't make sense for this PR to be dealt with before that one is merged. Additionally, there is a chance that #26593 will make it easier to reason for macOS USDT support if what I proposed gets into the final PR. |
Ok, going to close this for now, until these is sort of outcome out of #26593. Can be reopened if/when required. |
This PR adds macOS support for User-Space, Statically Defined Tracing (USDT) as well as dtrace example scripts based on the existing bpftrace scripts for Linux. This is tested on macOS 10.15.
Overview
The current implementation of USDT only supports Linux as the
DTRACE_PROBE*(context, event, ...args)
macros are not supported on macOS. As initially referenced in #22238, the process of using USDT probes on macOS is slightly different and it's described in the BUILDING CODE CONTAINING USDT PROBES section in the dtrace(1) manpage.This more involved process includes
util/probes.d
which defines the providers and specifies their probes.util/probes.d
to generate the header fileutil/probes.h
with the neccesary tracepoints macros which are of the formatCONTEXT_EVENT(...args)
.util/trace.h
.Notes
Part of the macOS process is to create the providers description in a.d
file. Therefore, types not supported by the D language (specificallybool
andstd::byte
) cannot be used as part of the probe's signature. On those occasions, in lack of a better solution, only supported types are used and then a patch is applied at the generatedutil/probes.h
file to replace the temporary D-supported types with those that we actually need.You can reproduce the initial header file by runningdtrace -h -s src/util/probes.d -o src/util/probes.h
(compiling with that results to errors because of not matching types) and then apply theprobes-fix.diff
patch withgit apply probes-fix.diff
.Edit:
util/probes.h
is now generated during build time after changes (see #25541 (comment) and #25541 (comment)) that removed the need for the non supported types.Having the
bitcoind
binary compiled with USDT support, you can then use the dtrace example scriptsconnectblock_benchmark.d
,log_p2p_traffic.d
,log_utxos.d
(root privileges needed) to test the macOS support. Extra documentation for those can be found at contrib/tracing as they are functionally the same as the existing bpftrace scripts.Adding tracepoints to Bitcoin Core (extra steps after this PR)
After this PR when a new tracepoint is added, we will need to
util/probes.d
together with a new provider if needed.#define context_event CONTEXT_EVENT
macro atutil/trace.h
. This might not be final as discussed at tracing: macOS USDT support #25541 (comment).