tracing: Only prepare tracepoint arguments when actually tracing #26593

pull 0xB10C wants to merge 3 commits into bitcoin:master from 0xB10C:2022-11-only-prepare-tracepoint-arguments-when-tracing changing 16 files +221 −120
  1. 0xB10C commented at 8:50 pm on November 28, 2022: contributor

    Currently, if the tracepoints are compiled (e.g. in depends and release builds), we always prepare the tracepoint arguments regardless of the tracepoints being used or not. We made sure that the argument preparation is as cheap as possible, but we can almost completely eliminate any overhead for users not interested in the tracepoints (the vast majority), by gating the tracepoint argument preparation with an if(something is attached to this tracepoint). To achieve this, we use the optional semaphore feature provided by SystemTap.

    The first commit simplifies and deduplicates our tracepoint macros from 13 TRACEx macros to a single TRACEPOINT macro. This makes them easier to use and also avoids more duplicate macro definitions in the second commit.

    The Linux tracing tools I’m aware of (bcc, bpftrace, libbpf, and systemtap) all support the semaphore gating feature. Thus, all existing tracepoints and their argument preparation is gated in the second commit. For details, please refer to the commit messages and the updated documentation in doc/tracing.md.

    Also adding unit tests that include all tracepoint macros to make sure there are no compiler problems with them (e.g. some varadiac extension not supported).

    Reviewers might want to check:

    • Do the tracepoints still work for you? Do the examples in contrib/tracing/ run on your system (as bpftrace frequently breaks on every new version, please test master too if it should’t work for you)? Do the CI interface tests still pass?
    • Is the new documentation clear?
    • The TRACEPOINT_SEMAPHORE(event, context) macros places global variables in our global namespace. Is this something we strictly want to avoid or maybe move to all TRACEPOINT_SEMAPHOREs to a separate .cpp file or even namespace? I like having the TRACEPOINT_SEMAPHORE() in same file as the TRACEPOINT(), but open for suggestion on alternative approaches.
    • Are newly added tracepoints in the unit tests visible when using readelf -n /src/test/test_bitcoin? You can run the new unit tests with ./src/test/test_bitcoin --run_test=util_trace_tests* --log_level=all.

    fail_tests.bt:

    0#!/usr/bin/env bpftrace
    1
    2usdt:./src/test/test_bitcoin:test:check_if_attached {
    3  printf("the 'check_if_attached' test should have failed\n");
    4}
    5
    6usdt:./src/test/test_bitcoin:test:expensive_section {
    7  printf("the 'expensive_section' test should have failed\n");
    8}
    

    Run the unit tests with ./src/test/test_bitcoin and start bpftrace fail_tests.bt -p $(pidof test_bitcoin) in a separate terminal. The unit tests should fail with:

    0Running 594 test cases...
    1test/util_trace_tests.cpp(31): error: in "util_trace_tests/test_tracepoint_check_if_attached": check false has failed
    2test/util_trace_tests.cpp(51): error: in "util_trace_tests/test_tracepoint_manual_tracepoint_active_check": check false has failed
    3
    4*** 2 failures are detected in the test module "Bitcoin Core Test Suite"
    

    These links might provide more contextual information for reviewers:

  2. DrahtBot commented at 8:50 pm on November 28, 2022: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage

    For detailed information about the code coverage, see the test coverage report.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK vasild
    Concept ACK jb55, kouloumos
    Approach ACK virtu
    Stale ACK laanwj, willcl-ark

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #29071 (refactor: Remove Span operator==, Use std::ranges::equal by maflcko)

    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.

  3. 0xB10C force-pushed on Nov 28, 2022
  4. in src/util/trace.h:52 in 94331ba3cc outdated
    60+//  if (TRACEPOINT_ACTIVE(context, event)) {
    61+//      result = slightly_expensive_calulation();
    62+//      TRACEPOINT_UNCHECKED(context, event, result);
    63+//  }
    64+//
    65+#define TRACEPOINT_UNCHECKED(context, event, args...) \
    


    luke-jr commented at 11:39 pm on November 28, 2022:
    Aren’t variadic macros (at least in this form) an extension, not standard C++?

    0xB10C commented at 8:11 am on November 29, 2022:
    TIL, could change to ... and __VA_ARGS__ if needed

    fanquake commented at 10:22 am on November 29, 2022:
  5. in src/util/trace.h:52 in 94331ba3cc outdated
    49+//  if (TRACEPOINT_ACTIVE(context, event)) {
    50+//      result = slightly_expensive_calulation();
    51+//      TRACEPOINT_UNCHECKED(context, event, result);
    52+//  }
    53+//
    54+#define TRACEPOINT_UNCHECKED(context, event, args...) \
    


    0xB10C commented at 10:08 am on November 29, 2022:

    Thinking about it: We might not need an extra TRACEPOINT_UNCHECKED macro. We can also use the TRACEPOINT in all places where we’d use the unchecked one. This would mean would do two TRACEPOINT_ACTIVE checks, but these are extremely cheap and might even be optimized to one by the compiler.

    Dropping the unchecked version results in is a smaller, better internal tracepoint API and removes the possibility that someone uses the unchecked version but doesn’t gate it.

  6. 0xB10C force-pushed on Nov 29, 2022
  7. 0xB10C commented at 4:28 pm on November 29, 2022: contributor
    • Addressed #26593 (review) by using __VA_ARGS__. Also using a separate TRACEPOINT0 macro for tracepoints without arguments, as using the TRACEPOINT macro without arguments is only be possible with GCC (clang warns that we are using gcc extensions). Tested with both clang and gcc.
    • Adressed #26593 (review) by dropping the TRACEPOINT_UNCHECKED macro.
    • Added unit tests for the TRACEPOINT macros. The tracepoints in the unit tests don’t do anything in particular, but the tests show that the macros work. Through the CI we cover ENABLE_TRACING being defined and undefined. The test case test_tracepoint_check_if_attached also shows that the TRACEPOINT_ACTIVE macro is not broken (it’s tested that it’s working in the functional tests).
  8. 0xB10C force-pushed on Nov 29, 2022
  9. jb55 commented at 5:25 pm on November 29, 2022: contributor
    genius. Concept ACK
  10. vasild commented at 7:30 am on December 2, 2022: contributor
    Concept ACK
  11. virtu commented at 9:52 am on December 12, 2022: contributor

    Approach ACK

    Super cool stuff. This effectively removes any runtime overhead of tracepoints on modern processors with branch prediction and speculative execution when no probes are attached .

    Some feedback on testing with 61ca0f9:

    • functional tests executed successfully on x86_64 and arm64

    • demo scripts in contrib/tracing: right now, bpftrace scripts work, bcc scripts don’t

    • generated assembly looks as expected:

      • tracing code is semaphore-gated using compare and branch instructions:

        0# x86_64
        1cmp    WORD PTR [rip+0x8f816b],0x0        # 0x55d32c25d6c0 <net_outbound_message_semaphore>
        2jne    0x55d32b965800 <_ZN8CConnman11PushMessageEP5CNodeO17CSerializedNetMsg+1488>
        3
        4# arm64
        5ldrh    w1, [x0, [#1776](/bitcoin-bitcoin/1776/)]
        6cbnz    w1, 0xaaaab2413fa4 <_ZN8CConnman11PushMessageEP5CNodeO17CSerializedNetMsg+1228>
        
      • tracing code uses nop when no probe is attached vs. int3 (x86_64) / brk (arm64) to trap when probe is attached

    • used gdb to inspect semaphores: they are correctly initialized to zero and set to one if one or more(!) probes are attached. The documentation I read stated semaphores act as probe reference counters, so I was expecting semaphore values to reflect the number of probes. However, it looks like semaphores and counters were separated. This does not impact correct behavior though:

       0(gdb) # no probe attached
       1(gdb) x/hx &net_outbound_message_semaphore
       20xaaaacc8506f0 <net_outbound_message_semaphore>:        0x0000
       3(gdb) # started one instance of contrib/tracing/log_p2p_traffic.bt
       4(gdb) x/hx &net_outbound_message_semaphore
       50xaaaacc8506f0 <net_outbound_message_semaphore>:        0x0001
       6(gdb) # started another instance of contrib/tracing/log_p2p_traffic.bt
       7(gdb) x/hx &net_outbound_message_semaphore
       80xaaaacc8506f0 <net_outbound_message_semaphore>:        0x0001
       9(gdb) # stopped first instance
      10(gdb) x/hx &net_outbound_message_semaphore
      110xaaaacc8506f0 <net_outbound_message_semaphore>:        0x0001
      12(gdb) # stopped second instance
      13(gdb) x/hx &net_outbound_message_semaphore
      140xaaaacc8506f0 <net_outbound_message_semaphore>:        0x0000
      
  12. 0xB10C commented at 8:34 am on December 13, 2022: contributor
    Thanks for the detailed review and testing. I’ve too noticed that the current example bcc scripts have a problem with the semaphores. The functional tests, also using bcc, work as intended as they use the PID to attach to the bitcoind process. Will add a commit to allow running the example scripts by specifying a PID.
  13. kouloumos commented at 6:37 pm on December 15, 2022: contributor
    Concept ACK! I’ve though about something similar while working on #25541 and even more when you mentioned performance impact on #25832.
  14. 0xB10C force-pushed on Dec 20, 2022
  15. 0xB10C force-pushed on Dec 20, 2022
  16. 0xB10C commented at 12:41 pm on December 20, 2022: contributor

    demo scripts in contrib/tracing: right now, bpftrace scripts work, bcc scripts don’t – (https://github.com/bitcoin/bitcoin/pull/26593#issuecomment-1346186050)

    Rebased and added a commit that fixes the bcc example scripts by using the PID of bitcoind instead of the file path. We already do this in the tests (https://github.com/bitcoin/bitcoin/commit/220a5a2841172a07d6d7849596316f0e0933e272).

  17. 0xB10C force-pushed on Dec 20, 2022
  18. DrahtBot added the label Needs rebase on Jan 4, 2023
  19. 0xB10C force-pushed on Jan 4, 2023
  20. DrahtBot removed the label Needs rebase on Jan 4, 2023
  21. DrahtBot added the label Needs rebase on Mar 8, 2023
  22. 0xB10C force-pushed on Mar 9, 2023
  23. DrahtBot removed the label Needs rebase on Mar 9, 2023
  24. in src/test/util_trace_tests.cpp:54 in 38df8dd065 outdated
    24+BOOST_AUTO_TEST_CASE(test_tracepoint_n_args)
    25+{
    26+  TRACEPOINT(test, one_arg, 1);
    27+  TRACEPOINT(test, six_args, 1, 2, 3, 4, 5, 6);
    28+  TRACEPOINT(test, twelve_args, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
    29+  BOOST_CHECK(true);
    


    willcl-ark commented at 1:40 pm on March 17, 2023:
    Is this test just checking that there is no error thrown when using the macro in this way?

    0xB10C commented at 6:06 pm on March 17, 2023:

    Yes, from the OP: “Also adding unit tests that include all tracepoint macros to make sure there are no compiler problems with them (e.g. some varadiac extension not supported).” I added them after addressing #26593 (review)

    But I think it makes sense to document this in the unit tests with a comment too. Will add on next push.

  25. willcl-ark approved
  26. willcl-ark commented at 4:31 pm on March 17, 2023: member

    Lightly tested ACK.

    1. I didn’t manage to get bpftrace itself running on my Ubuntu system yet, but I was able to get the python scripts log_raw_p2p_msgs.py, log_utxocache_flush.py and p2p_monitor.py (using bcc) to run successfully under sudo.
      (I do wonder about the viability of the bpftrace scripts in this project, seeing as they seem to be so brittle/difficult to use.)
    2. The usdt tests all passed successfully:
    0interface_usdt_coinselection.py                        | ✓ Passed  | 5 s
    1interface_usdt_net.py                                  | ✓ Passed  | 4 s
    2interface_usdt_utxocache.py                            | ✓ Passed  | 11 s
    3interface_usdt_validation.py                           | ✓ Passed  | 3 s
    
    1. The new variadic macro is much simpler to reason about and I agree seems like a nice win all round.
    2. I was also able to see the semaphores being loaded from memory, compared to zero, and conditionally jumped to, as detailed in the PR description, e.g. for CCoinsViewCache::AddCoin()
    0   ...
    1   0x0000000000b60927 <+615>:   movzwl 0xa64bea(%rip),%eax        # 0x15c5518 <utxocache_add_semaphore>
    2   0x0000000000b6092e <+622>:   cmp    $0x0,%eax
    3   0x0000000000b60931 <+625>:   jle    0xb609d6 <_ZN15CCoinsViewCache7AddCoinERK9COutPointO4Coinb+790>
    4   ...
    
    1. I don’t think having these semaphores in the global namespace should be a big issue for debugging or namespacing. So really it comes down to organisational priorities, where I’d agree with you that having them in the same file as the tracepoint feels cleaner.
  27. in src/util/trace.h:17 in 38df8dd065 outdated
    25-#define TRACE9(context, event, a, b, c, d, e, f, g, h, i) DTRACE_PROBE9(context, event, a, b, c, d, e, f, g, h, i)
    26-#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j) DTRACE_PROBE10(context, event, a, b, c, d, e, f, g, h, i, j)
    27-#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k) DTRACE_PROBE11(context, event, a, b, c, d, e, f, g, h, i, j, k)
    28-#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l) DTRACE_PROBE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l)
    29+// A USDT tracepoint with no arguments.
    30+#define TRACEPOINT0(context, event) \
    


    willcl-ark commented at 11:18 am on March 20, 2023:

    Why do we need this special-cased 0 arg tracepoint? ISTM that the systemtap variadic supports 0 arg calls:

    https://github.com/jav/systemtap/blob/2da355dd02a18bf4f67e2ceeb504b351b4bd5b83/includes/sys/sdt.h#L291-L303


    0xB10C commented at 3:58 pm on March 20, 2023:

    fwiw: This is the “source”, I think the repo you linked to is an outdated fork: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=4075a5ff1c3f09c3913615e62840595efe003c6d;hb=HEAD#l404

    But yes, reading that comment I’d agree that it should work. I’ve added the following to try it but it doesn’t compile. IIRC that’s the reason why I added the TRACEPOINT0().

     0diff --git a/src/test/util_trace_tests.cpp b/src/test/util_trace_tests.cpp
     1index 6e3e846b4..488d7b669 100644
     2--- a/src/test/util_trace_tests.cpp
     3+++ b/src/test/util_trace_tests.cpp
     4@@ -9,6 +9,7 @@
     5 #include <util/trace.h>
     6
     7 TRACEPOINT_SEMAPHORE(test, zero_args);
     8+TRACEPOINT_SEMAPHORE(test, zero_args2);
     9 TRACEPOINT_SEMAPHORE(test, one_arg);
    10 TRACEPOINT_SEMAPHORE(test, six_args);
    11 TRACEPOINT_SEMAPHORE(test, twelve_args);
    12@@ -19,6 +20,7 @@ BOOST_FIXTURE_TEST_SUITE(util_trace_tests, BasicTestingSetup)
    13 BOOST_AUTO_TEST_CASE(test_tracepoint_zero_args)
    14 {
    15   TRACEPOINT0(test, zero_args);
    16+  TRACEPOINT(test, zero_args2);
    17   BOOST_CHECK(true);
    18 }
    
     0In file included from ./util/trace.h:22,
     1                 from test/util_trace_tests.cpp:9:
     2test/util_trace_tests.cpp: In member function ‘void util_trace_tests::test_tracepoint_zero_args::test_method()’:
     3./util/trace.h:43:9: error: expected primary-expression before ‘)’ token
     4   43 |         STAP_PROBEV(context, event, __VA_ARGS__)
     5      |         ^~~~~~~~~~~
     6test/util_trace_tests.cpp:23:3: note: in expansion of macro ‘TRACEPOINT’
     7   23 |   TRACEPOINT(test, zero_args2);
     8      |   ^~~~~~~~~~
     9./util/trace.h:43:9: error: template argument 1 is invalid
    10   43 |         STAP_PROBEV(context, event, __VA_ARGS__)
    11      |         ^~~~~~~~~~~
    12test/util_trace_tests.cpp:23:3: note: in expansion of macro ‘TRACEPOINT’
    13   23 |   TRACEPOINT(test, zero_args2);
    14      |   ^~~~~~~~~~
    15./util/trace.h:43:9: error: expected primary-expression before ‘)’ token
    16   43 |         STAP_PROBEV(context, event, __VA_ARGS__)
    17      |         ^~~~~~~~~~~
    18test/util_trace_tests.cpp:23:3: note: in expansion of macro ‘TRACEPOINT’
    19   23 |   TRACEPOINT(test, zero_args2);
    20      |   ^~~~~~~~~~
    21./util/trace.h:43:9: error: expected primary-expression before ‘)’ token
    22   43 |         STAP_PROBEV(context, event, __VA_ARGS__)
    23      |         ^~~~~~~~~~~
    24test/util_trace_tests.cpp:23:3: note: in expansion of macro ‘TRACEPOINT’
    25   23 |   TRACEPOINT(test, zero_args2);
    26      |   ^~~~~~~~~~
    27make[2]: *** [Makefile:18883: test/test_bitcoin-util_trace_tests.o] Error 1
    28make[2]: *** Waiting for unfinished jobs....
    29make[2]: Leaving directory '..'
    30make[1]: *** [Makefile:19418: all-recursive] Error 1
    31make[1]: Leaving directory '..'
    32make: *** [Makefile:816: all-recursive] Error 1
    

    0xB10C commented at 3:59 pm on March 20, 2023:
    Plan to revisit this once I have the time to experiment

    martinus commented at 5:52 pm on April 2, 2023:

    Macro magic to the rescue! This works for me:

     0diff --git a/src/test/util_trace_tests.cpp b/src/test/util_trace_tests.cpp
     1index 6e3e846b4f..952b9cc6e4 100644
     2--- a/src/test/util_trace_tests.cpp
     3+++ b/src/test/util_trace_tests.cpp
     4@@ -18,7 +18,7 @@ BOOST_FIXTURE_TEST_SUITE(util_trace_tests, BasicTestingSetup)
     5 
     6 BOOST_AUTO_TEST_CASE(test_tracepoint_zero_args)
     7 {
     8-  TRACEPOINT0(test, zero_args);
     9+  TRACEPOINT(test, zero_args);
    10   BOOST_CHECK(true);
    11 }
    12 
    13diff --git a/src/util/trace.h b/src/util/trace.h
    14index 816d8c295d..3a0aed391b 100644
    15--- a/src/util/trace.h
    16+++ b/src/util/trace.h
    17@@ -29,25 +29,19 @@
    18     unsigned short context##_##event##_semaphore __attribute__((section (".probes")))
    19 
    20 // Returns true if something is attached to the tracepoint.
    21-#define TRACEPOINT_ACTIVE(context, event) context##_##event##_semaphore > 0
    22-
    23-// A USDT tracepoint with no arguments.
    24-#define TRACEPOINT0(context, event) \
    25-    if (TRACEPOINT_ACTIVE(context, event)) \
    26-        STAP_PROBE(context, event)
    27+#define TRACEPOINT_ACTIVE(context, event, ...) context##_##event##_semaphore > 0
    28 
    29 // A USDT tracepoint with one to twelve arguments. It's checked that the
    30 // tracepoint is active before preparing its arguments.
    31-#define TRACEPOINT(context, event, ...) \
    32-    if (TRACEPOINT_ACTIVE(context, event)) \
    33-        STAP_PROBEV(context, event, __VA_ARGS__)
    34+#define TRACEPOINT(context, ...) \
    35+    if (TRACEPOINT_ACTIVE(context, __VA_ARGS__)) \
    36+        STAP_PROBEV(context, __VA_ARGS__)
    37 
    38 #else
    39 
    40 #define TRACEPOINT_SEMAPHORE(context, event)
    41 #define TRACEPOINT_ACTIVE(context, event) false
    42-#define TRACEPOINT0(context, event)
    43-#define TRACEPOINT(context, event, ...)
    44+#define TRACEPOINT(context, ...)
    45 
    46 #endif // ENABLE_TRACING
    

    The trick is to make event part of the variadic macro, so that there’s always at least 1 argument in the variadic


    martinus commented at 5:15 am on April 3, 2023:

    Based on @willcl-ark’s comment #26916 (comment) here is a version that works without any warnings in clang and gcc:

     0diff --git a/src/test/util_trace_tests.cpp b/src/test/util_trace_tests.cpp
     1index 6e3e846b4f..952b9cc6e4 100644
     2--- a/src/test/util_trace_tests.cpp
     3+++ b/src/test/util_trace_tests.cpp
     4@@ -18,7 +18,7 @@ BOOST_FIXTURE_TEST_SUITE(util_trace_tests, BasicTestingSetup)
     5 
     6 BOOST_AUTO_TEST_CASE(test_tracepoint_zero_args)
     7 {
     8-  TRACEPOINT0(test, zero_args);
     9+  TRACEPOINT(test, zero_args);
    10   BOOST_CHECK(true);
    11 }
    12 
    13diff --git a/src/util/trace.h b/src/util/trace.h
    14index 816d8c295d..aa88771b1e 100644
    15--- a/src/util/trace.h
    16+++ b/src/util/trace.h
    17@@ -26,28 +26,41 @@
    18 // upon attaching to the tracepoint and decremented when detaching. This needs
    19 // to be a global variable. It's placed in the '.probes' ELF section.
    20 #define TRACEPOINT_SEMAPHORE(context, event) \
    21-    unsigned short context##_##event##_semaphore __attribute__((section (".probes")))
    22+    unsigned short context##_##event##_semaphore __attribute__((section(".probes")))
    23+
    24+// Extract the first argument of a variable number of arguments, even without warning
    25+// when only 1 argument is provided
    26+#define TRACEPOINT_FIRST_ARG(...) TRACEPOINT_FIRST_ARG_HELPER(__VA_ARGS__, dummy)
    27+#define TRACEPOINT_FIRST_ARG_HELPER(arg1, ...) arg1
    28 
    29 // Returns true if something is attached to the tracepoint.
    30-#define TRACEPOINT_ACTIVE(context, event) context##_##event##_semaphore > 0
    31+#define TRACEPOINT_ACTIVE(context, event) TRACEPOINT_ACTIVE_HELPER(context, event)
    32+#define TRACEPOINT_ACTIVE_HELPER(context, event) context##_##event##_semaphore > 0
    33 
    34-// A USDT tracepoint with no arguments.
    35-#define TRACEPOINT0(context, event) \
    36-    if (TRACEPOINT_ACTIVE(context, event)) \
    37-        STAP_PROBE(context, event)
    38+#if defined(__clang__)
    39+#define TRACEPOINT_DISABLE_WARN_ZERO_VARIADIC_PUSH _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"")
    40+#define TRACEPOINT_DISABLE_WARN_ZERO_VARIADIC_POP _Pragma("clang diagnostic pop")
    41+#else
    42+#define TRACEPOINT_DISABLE_WARN_ZERO_VARIADIC_PUSH
    43+#define TRACEPOINT_DISABLE_WARN_ZERO_VARIADIC_POP
    44+#endif
    45 
    46 // A USDT tracepoint with one to twelve arguments. It's checked that the
    47 // tracepoint is active before preparing its arguments.
    48-#define TRACEPOINT(context, event, ...) \
    49-    if (TRACEPOINT_ACTIVE(context, event)) \
    50-        STAP_PROBEV(context, event, __VA_ARGS__)
    51+#define TRACEPOINT(context, ...)                                             \
    52+    do {                                                                     \
    53+        if (TRACEPOINT_ACTIVE(context, TRACEPOINT_FIRST_ARG(__VA_ARGS__))) { \
    54+            TRACEPOINT_DISABLE_WARN_ZERO_VARIADIC_PUSH                       \
    55+            STAP_PROBEV(context, __VA_ARGS__);                               \
    56+            TRACEPOINT_DISABLE_WARN_ZERO_VARIADIC_POP                        \
    57+        }                                                                    \
    58+    } while (0)
    59 
    60 #else
    61 
    62 #define TRACEPOINT_SEMAPHORE(context, event)
    63 #define TRACEPOINT_ACTIVE(context, event) false
    64-#define TRACEPOINT0(context, event)
    65-#define TRACEPOINT(context, event, ...)
    66+#define TRACEPOINT(context, ...)
    67 
    68 #endif // ENABLE_TRACING
    

    0xB10C commented at 2:48 pm on November 23, 2023:

    Do you remember why you added a do { ... } while (0) to the TRACEPOINT macro?

    edit: It’s a common thing to do in macros. See https://stackoverflow.com/q/154136/8896600. I’m keeping it.

  28. in doc/tracing.md:390 in bfd97effdf outdated
    386@@ -336,7 +387,7 @@ Displaying notes found in: .note.stapsdt
    387   stapsdt              0x0000005d	NT_STAPSDT (SystemTap probe descriptors)
    388     Provider: net
    389     Name: outbound_message
    390-    Location: 0x0000000000107c05, Base: 0x0000000000579c90, Semaphore: 0x0000000000000000
    391+    Location: 0x0000000000107c05, Base: 0x0000000000579c90, Semaphore: 0x0000000000a69780
    


    kouloumos commented at 8:44 pm on April 8, 2023:

    Regarding listing available tracepoints, there is another addition when using info probes in gdb, which now also shows semaphores. A snippet from my binary:

    0(gdb) info probes
    1Type Provider   Name             Where              Semaphore          Object
    2stap net        inbound_message  0x00005625b02d4106 0x0000000000ab1724 /src/bitcoind
    3stap net        outbound_message 0x00005625b029f395 0x0000000000ab1722  /src/bitcoind
    4stap validation block_connected  0x00005625b04b914d 0x0000000000ab1720 /src/bitcoind
    
  29. in src/util/trace.h:36 in bfd97effdf outdated
    40+// to be a global variable. It's placed in the '.probes' ELF section.
    41+#define TRACEPOINT_SEMAPHORE(context, event) \
    42+    unsigned short context##_##event##_semaphore __attribute__((section (".probes")))
    43+
    44+// Returns true if something is attached to the tracepoint.
    45+#define TRACEPOINT_ACTIVE(context, event) context##_##event##_semaphore > 0
    


    kouloumos commented at 9:06 pm on April 8, 2023:
    I see that there is a PASTE macro that can be used instead of directly using the token-pasting operator (##), but I can’t figure out why it exists and if it offers any advantage. https://github.com/bitcoin/bitcoin/blob/db720b5a703c90625fa7a4773bd2db5672427cbe/src/util/macros.h#L8

    martinus commented at 8:06 pm on April 10, 2023:

    I see that there is a PASTE macro that can be used instead of directly using the token-pasting operator (##), but I can’t figure out why it exists and if it offers any advantage. https://github.com/bitcoin/bitcoin/blob/db720b5a703c90625fa7a4773bd2db5672427cbe/src/util/macros.h#L8

    The macro is a bit badly named, the main one here is PASTE2. The advantage is that due to the indirection you can use macros as arguments in the macro and they will be expanded before concatenation. See e.g. https://stackoverflow.com/questions/24708006/c-macro-indirection

  30. kouloumos commented at 9:41 pm on April 8, 2023: contributor

    master (49b87bfe7e2799d25ce709123ecafa872b36e87a)

    Tracepoint Disabled Enabled (not hooked) Enabled (hooked)
    mempool:added 1 24 24
    mempool:removed 1 136 136
    mempool:replaced 4 60 60
    mempool:rejected 2 250 250
    net:inbound_message 1 50 50
    net:outbound_message 3 43 43
    validation:block_connected 1 8 8
    utxocache:flush 2 95 95
    utxocache:add 1 6 6
    utxocache:spent 1 6 6
    utxocache:uncache 1 6 6
    coin_selection:selected_coins 4 107 107
    coin_selection:normal_create_tx_internal 1 10 10
    coin_selection:attempting_aps_create_tx 1 2 2
    coin_selection:aps_create_tx_internal - 11 11

    PR (rebased as part of 26593-additions)

    Tracepoint Disabled Enabled (not hooked) Enabled (hooked)
    mempool:added 1 2 29
    mempool:removed 1 7 146
    mempool:replaced 4 3 60
    mempool:rejected 2 3 254
    net:inbound_message 1 2 54
    net:outbound_message 3 3 52
    validation:block_connected 1 3 10
    utxocache:flush 2 2 98
    utxocache:add 1 3 8
    utxocache:spent 1 3 8
    utxocache:uncache 1 3 9
    coin_selection:selected_coins 4 3 109
    coin_selection:normal_create_tx_internal 1 3 12
    coin_selection:attempting_aps_create_tx 1 4 6
    coin_selection:aps_create_tx_internal - 3 12

    The data are from my python gdb script that automatically measures executed instructions for all scenarios. You can find it in my 26593-additions branch alongside usage details in order to reproduce the results.

     0# extend_gdb.py
     1To make this file available to your gdb process:
     21. Make sure that this file and `tracepoint_helper.py` are in the same dir
     32. (gdb) source extend_gdb.py
     4
     5You can now run the custom commands of this file.
     6The main command is:
     7(gdb) scenario run <scenario> <tracepoint> (--no-build)
     8
     9Running it with no arguments will run all scenarios:
    10- tracepoints disabled
    11- tracepoints enabled
    12- tracepoints enabled (hooked)
    13
    14The records are then saved in "output_<commit-hash>.txt"
    

    Notes for the preliminary work on that branch:

    • it’s a rebased vesion of this PR in order to include the newly added mempool tracepoints.
    • includes “missing” bpftrace scripts because these are what I’m using in my script to enable probes/hook on tracepoints.

    Regarding the TRACEPOINT_SEMAPHORE(event, context) macros: I don’t see any advantage on having them in the same file. I consider them as part of tracepoints’ inner workings which are already abstracted in another file. But still not opposing the current implementation as (based on my attempts) having them in trace.h is not possible and the inclusion of an extra file probably adds unnecessary complexity at this point. However, with my alternative approach (explained below) those are not needed.

    macos support compatibility

    I’ve rebased #25541 on top of this PR in macos-usdt-support-26593 and it works; there is only an issue with the new unit test. Because the macos implementation doesn’t support arbitrary tracepoints, the TRACEPOINT macro expands to “undeclared identifier” error. To solve it, I made a change to conditionally include that test file to the build process. As this test case is only conditionally applicable (empty if not linux), maybe this can also apply to this PR.

    Another approach(?)

    This PR’s gated approach reminded me of the auto-generated header file from probes.d in #25541. In #25541 (comment) you mentioned how that file could also be generated on Linux with dtrace supplied by Systemtap, so I replicated this sempahor-gated functionality using the semaphores of the linux auto-generated probes.h file. The main advantage of this alternative approach is the unified build process for linux and macos as the current (pending) implementation for macos already uses the probes.d file. It then becomes trivial to also support tracepoints on macos. What do you think of this approach? This is essentially a mashup of your work, the macos support branch and eklitzke’s probes_sdt branch. You can find my changes at the 26593-another-approach branch (diff) , feel free to pick whatever you like.

  31. 0xB10C commented at 7:58 am on April 11, 2023: contributor

    Thanks for the helpful comments @willcl-ark, @martinus and @kouloumos! I plan to address these and update this PR with your suggestions. Currently, I’m prioritizing other projects during the feature freeze, so it might take a few more weeks.

    Marking this as in draft until I address the feedback.

  32. 0xB10C marked this as a draft on Apr 25, 2023
  33. DrahtBot added the label Needs rebase on May 19, 2023
  34. fanquake referenced this in commit 97ba72117c on Aug 7, 2023
  35. sidhujag referenced this in commit 36f919d626 on Aug 9, 2023
  36. maflcko commented at 4:52 pm on September 20, 2023: member
    Are you still working on this?
  37. 0xB10C commented at 9:59 am on October 1, 2023: contributor
    I plan to revisit this in the next two months. Feel free to close if I don’t do it before the end of 2023.
  38. 0xB10C force-pushed on Nov 24, 2023
  39. 0xB10C force-pushed on Nov 24, 2023
  40. DrahtBot added the label CI failed on Nov 24, 2023
  41. DrahtBot removed the label CI failed on Nov 24, 2023
  42. DrahtBot removed the label Needs rebase on Nov 24, 2023
  43. 0xB10C commented at 11:48 am on November 24, 2023: contributor

    Rebased and addressed comments

    • #26593 (review): @martinus I took parts from your suggestion and added you as a co-author for the first commit. Thanks for the macro-magic. There’s now only the TRACEPOINT() macro that works for tracepoints with 0 to 12 args.
    • #26593 (review): I clarified unit tests and added a new test for a manual TRACEPOINT_ACTIVE() macro.
    • #26593 (review): updated the GDB info probes output in the docs

    I also thought a bit about @kouloumos alternative approach that would allow us to use the tracepoints on Linux, macOS and potentially *BSD (not tested). This would require dtrace during build-time. I’m not sure this is something we want. If we explore in this direction, then it’s probably better to do it in a separate PR.

    As the first commit is an overall simplification and cleanup, it might make also sense to split it off into a separate PR while we are exploring alternatives.

    While this is rebased and ready for review again, I’d prefer progress on #25832 while we’re exploring alternatives to #26593. I’ll leave this as work-in-progress until we’re clearer on alternatives.

  44. DrahtBot added the label Needs rebase on Dec 8, 2023
  45. 0xB10C force-pushed on Dec 8, 2023
  46. 0xB10C commented at 2:08 pm on December 8, 2023: contributor

    Rebased with #28349 merged.

    While this is rebased and ready for review again, I’d prefer progress on #25832 while we’re exploring alternatives to #26593. I’ll leave this as work-in-progress until we’re clearer on alternatives.

    I’ve also been working on a branch that adds tracepoint support for macOS and FreeBSD based on this branch. Doesn’t need dtrace and doesn’t need any header file like sys/sdt.h. Once it’s in a usable state I’ll un-draft this PR here.

  47. DrahtBot removed the label Needs rebase on Dec 8, 2023
  48. DrahtBot added the label Needs rebase on Dec 11, 2023
  49. 0xB10C force-pushed on Dec 13, 2023
  50. 0xB10C commented at 4:36 pm on December 13, 2023: contributor
    Rebased. Now includes the tracepoint changes from #25273.
  51. DrahtBot removed the label Needs rebase on Dec 13, 2023
  52. 0xB10C force-pushed on Jan 10, 2024
  53. 0xB10C force-pushed on Jan 10, 2024
  54. DrahtBot added the label CI failed on Jan 10, 2024
  55. DrahtBot removed the label CI failed on Jan 10, 2024
  56. DrahtBot added the label CI failed on Jan 13, 2024
  57. DrahtBot added the label Needs rebase on Jan 23, 2024
  58. 0xB10C force-pushed on Jan 24, 2024
  59. 0xB10C force-pushed on Jan 24, 2024
  60. 0xB10C commented at 12:40 pm on January 24, 2024: contributor
  61. DrahtBot removed the label CI failed on Jan 24, 2024
  62. DrahtBot removed the label Needs rebase on Jan 24, 2024
  63. willcl-ark added the label Utils/log/libs on Jan 24, 2024
  64. fanquake commented at 2:06 pm on March 6, 2024: member
    @0xB10C can you give a summary of the current state of these changes? It’s draft, and from the looks of the most recent comment, that’s because it’s waiting on support for macOS and FreeBSD based on this branch.. Is that still correct/being worked on?
  65. 0xB10C commented at 10:48 am on March 7, 2024: contributor

    Thanks for the poke. Undrafting.

    I have a branch building on top of this PR adding support for no-dependency no-overhead-if-not-used macOS tracing in a working state and a concept for FreeBSD to do the same. Still some work to do before I can open a PR. This PR was a draft as I wanted to make sure it’s compatible with both the macOS and FreeBSD changes. I think it’s mostly compatible with the changes here.

    Nonetheless, I would prefer review on #25832 first from reviewers interested in tracepoints.

  66. 0xB10C marked this as ready for review on Mar 7, 2024
  67. in contrib/tracing/log_raw_p2p_msgs.py:135 in 3933bdd6cf outdated
    131@@ -132,8 +132,9 @@ def print_message(event, inbound):
    132           )
    133 
    134 
    135-def main(bitcoind_path):
    136-    bitcoind_with_usdts = USDT(path=str(bitcoind_path))
    137+def main(pid):
    


    laanwj commented at 12:28 pm on April 8, 2024:
    Attaching by pid is a good idea, even aside from semaphores, as it attaches a specific instance instead of all processes sharing the binary, which i think it does if you provide the path.
  68. laanwj commented at 1:19 pm on April 8, 2024: member

    For some reason, after building with this, I dont get any output from:

    0$ gdb src/bitcoind
    1...
    2(gdb) info tracepoints
    3No tracepoints.
    

    Tested with gdb 15.0.50.20240219-git and 13.1.

    I checked that the tracepoints are included:

    0$ readelf -n ./src/bitcoind | grep NT_STAPSDT -A 4 -B 2
    1  stapsdt              0x00000062       NT_STAPSDT (SystemTap probe descriptors)
    2    Provider: net
    3    Name: outbound_message
    4    Location: 0x00000000001809bc, Base: 0x0000000000a2cb60, Semaphore: 0x0000000000b73248
    5    Arguments: -8@%r14 8@%r15 8@-560(%rbp) 8@24(%rcx) 8@%rax 8@%rdx
    6...
    

    I don’t know if this is an actual problem as we don’t rely on gdb for tracing, but if so it’s a documentation issue.

    Edit: something is broken here, it also doesn’t show them for the master branch.

  69. laanwj commented at 1:56 pm on April 8, 2024: member

    Oh, it’s info probes not info tracepoints. Whoops. It checks out now.

    Code review and lightly tested ACK 3933bdd6cfc9accab9e0ed47e83a5cc27ada6b68

  70. DrahtBot requested review from kouloumos on Apr 8, 2024
  71. DrahtBot requested review from vasild on Apr 8, 2024
  72. DrahtBot requested review from willcl-ark on Apr 8, 2024
  73. in src/util/trace.h:49 in 3933bdd6cf outdated
    57+// A USDT tracepoint with one to twelve arguments. It's checked that the
    58+// tracepoint is active before preparing its arguments.
    59+#define TRACEPOINT(context, ...)                                                \
    60+    do {                                                                        \
    61+        if (TRACEPOINT_ACTIVE(context, TRACEPOINT_FIRST_ARG(__VA_ARGS__))) {    \
    62+            STAP_PROBEV(context, __VA_ARGS__);                                  \
    


    maflcko commented at 2:21 pm on April 8, 2024:
    0#define TRACEPOINT(context, event, ...)                                                \
    1    do {                                                                        \
    2        if (TRACEPOINT_ACTIVE(context, event)) {    \
    3            STAP_PROBEV(context, event, __VA_ARGS__);                                  \
    

    question: Does the following not work in C++20?


    0xB10C commented at 9:32 pm on April 9, 2024:
    Tried this, but didn’t work for zero arguments tracepoint (the newly introduced tests catched this). However, we can use __VA_OPT__ from C++ 20.
  74. maflcko commented at 8:07 am on April 9, 2024: member
    left a nit/question
  75. 0xB10C force-pushed on Apr 9, 2024
  76. DrahtBot added the label CI failed on Apr 9, 2024
  77. DrahtBot commented at 8:39 pm on April 9, 2024: contributor

    🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the documentation.

    Possibly this is due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    Leave a comment here, if you need help tracking down a confusing failure.

    Debug: https://github.com/bitcoin/bitcoin/runs/23620364225

  78. 0xB10C force-pushed on Apr 9, 2024
  79. DrahtBot removed the label CI failed on Apr 9, 2024
  80. 0xB10C commented at 8:53 am on April 10, 2024: contributor
    As mentioned in #26593 (review), with C++20, we can use __VA_OPT__ and drop the changes from #26593 (review). Done that and rebased.
  81. in src/util/trace.h:29 in 38e24dfc5f outdated
    26+// Used to define a counting semaphore for a tracepoint. This semaphore is
    27+// automatically incremented by tracing frameworks (bpftrace, bcc, libbpf, ...)
    28+// upon attaching to the tracepoint and decremented when detaching. This needs
    29+// to be a global variable. It's placed in the '.probes' ELF section.
    30+#define TRACEPOINT_SEMAPHORE(context, event) \
    31+    unsigned short context##_##event##_semaphore __attribute__((section(".probes")))
    


    maflcko commented at 9:06 am on April 10, 2024:

    question, feel free to ignore:

    Does it need to be in a separate macro, to be put in the global namespace, or would it work to use static inside the function scope?

    If so, it could be combined into the TRACEPOINT macro, and using TRACEPOINT without it would not be possible.


    0xB10C commented at 10:39 am on April 10, 2024:

    I remember trying a few combinations of this and in all cases the compiler/liker failed to find the semaphore. I just retried with the following patch which I think is similar to what you describe.

     0diff --git a/src/util/trace.h b/src/util/trace.h
     1index a4f0ea1ca4..8d7f6bdb74 100644
     2--- a/src/util/trace.h
     3+++ b/src/util/trace.h
     4@@ -27,8 +27,8 @@
     5 // automatically incremented by tracing frameworks (bpftrace, bcc, libbpf, ...)
     6 // upon attaching to the tracepoint and decremented when detaching. This needs
     7 // to be a global variable. It's placed in the '.probes' ELF section.
     8-#define TRACEPOINT_SEMAPHORE(context, event) \
     9-    unsigned short context##_##event##_semaphore __attribute__((section(".probes")))
    10+#define TRACEPOINT_SEMAPHORE(context, event)
    11+//    unsigned short context##_##event##_semaphore __attribute__((section(".probes")))
    12
    13 #include <sys/sdt.h>
    14
    15@@ -39,6 +39,7 @@
    16 // tracepoint is active before preparing its arguments.
    17 #define TRACEPOINT(context, event, ...)                                         \
    18     do {                                                                        \
    19+        static unsigned short context##_##event##_semaphore __attribute__((section(".probes"))); \
    20         if (TRACEPOINT_ACTIVE(context, event)) {                                \
    21             STAP_PROBEV(context, event __VA_OPT__(, ) __VA_ARGS__);                           \
    22         }                                                                       \
    

    This (1) breaks the extra if(TRACEPOINT_ACTIVE(context, event)) and (2) the linker complains it can’t find the semaphores (e.g. undefined reference to utxocache_spent_semaphore').

    Otherwise, if we find a way to do it, I’d be happy to do it as I’m not too excited about having the semaphores as globals..


    maflcko commented at 11:42 am on April 10, 2024:
    Thanks for the explanation. I don’t see another solution right now.
  82. in contrib/tracing/log_raw_p2p_msgs.py:179 in 38e24dfc5f outdated
    176@@ -176,8 +177,8 @@ def handle_outbound(_, data, size):
    177 
    178 
    179 if __name__ == "__main__":
    180-    if len(sys.argv) < 2:
    


    willcl-ark commented at 11:04 am on April 29, 2024:

    In: 38e24dfc5f1c54723018bf9d973b7d9cf9a2b824 If you re-touch these, it might be nice (user-friendly) to add a simple check that we are running as root. Currently without root you see:

     0Hooking into bitcoind with pid 4039799
     1Traceback (most recent call last):
     2  File "/home/will/src/bitcoin/contrib/tracing/p2p_monitor.py", line 258, in <module>
     3    main(pid)
     4  File "/home/will/src/bitcoin/contrib/tracing/p2p_monitor.py", line 124, in main
     5    bitcoind_with_usdts.enable_probe(
     6  File "/usr/lib/python3/dist-packages/bcc-0.30.0+679166bd-py3.11.egg/bcc/usdt.py", line 161, in enable_probe
     7bcc.usdt.USDTException: Failed to enable USDT probe 'inbound_message':
     8the specified pid might not contain the given language's runtime,
     9or the runtime was not built with the required USDT probes. Look
    10for a configure flag similar to --with-dtrace or --enable-dtrace.
    11To check which probes are present in the process, use the tplist tool.
    

    Could improve easily with a root check, e.g.:

     0diff --git a/contrib/tracing/p2p_monitor.py b/contrib/tracing/p2p_monitor.py
     1index 6d8ae43c71..d107c5f994 100755
     2--- a/contrib/tracing/p2p_monitor.py
     3+++ b/contrib/tracing/p2p_monitor.py
     4@@ -244,8 +244,13 @@ def render(screen, peers, cur_list_pos, scroll, ROWS_AVALIABLE_FOR_LIST, info_pa
     5                         i + 3, 1, " %s (%d byte) --->" %
     6                         (msg.msg_type, msg.size), curses.A_NORMAL)
     7 
     8+import os
     9+def running_as_root() -> bool:
    10+    return os.getuid() == 0
    11 
    12 if __name__ == "__main__":
    13+    if not running_as_root():
    14+        print("Detected that we are not running as root, this is likely not what you want")
    15     if len(sys.argv) != 2:
    16         print("USAGE:", sys.argv[0], "<pid of bitcoind>")
    17         exit()
    

    There’s of course a counter-argument that anyone hooking into tracepoints will likely understand they need root access to the kernel 😃


    0xB10C commented at 12:35 pm on April 29, 2024:
    I agree that adding this makes sense as the bcc error message isn’t clear. If I retouch, I’ll add it.

    0xB10C commented at 8:56 am on May 25, 2024:

    ~I decided against this. You don’t strictly need to be root (https://hackmd.io/@willcl-ark/r19LVO2_6 or #24358 (comment)). Checking for getuid == 0 would require you to run as root.~

    Nvm, I thought there was an exit in there. Since this is only a print, seems fine and helpful.

  83. in doc/tracing.md:300 in 9343ee83ec outdated
    307+  );
    308+  …
    309+}
    310+```
    311+
    312+If needed, an extra `if(TRACEPOINT_ACTIVE(context, event) {..}` check can be
    


    willcl-ark commented at 11:56 am on April 29, 2024:

    In: 9343ee83ec9ca1ac32d9686f6aea6d755c623562

    It’s not clear to me how this differs from the semaphore gating being introduced. ISTM that the caller will need the semaphore in either case, so what difference does preparing the argument inside this if make? The TRACEPOINT macro appears to expand to an if(TRACEPOINT_ACTIVE( ...


    0xB10C commented at 12:34 pm on April 29, 2024:

    In some cases, tracepoint argument preparation can require more than a single readable line in the TRACEPOINT macro. An example is the transaction serialization here. For context, see #26531 (comment). I don’t currently plan on PRing something like this, but had this running for more than a year to collect data on full-rbf RBF replacements.

     0    if(TRACEPOINT_ACTIVE(mempool, added)) {
     1        CDataStream added_tx(SER_NETWORK, PROTOCOL_VERSION);
     2        added_tx << entry.GetTx();
     3        TRACEPOINT(mempool, added,
     4            entry.GetTx().GetHash().data(),
     5            entry.GetTxSize(),
     6            entry.GetFee(),
     7            added_tx.size(),
     8            added_tx.data()
     9        );
    10    }
    

    willcl-ark commented at 12:36 pm on April 29, 2024:
    Ah I see, that makes sense now then, thanks.
  84. willcl-ark approved
  85. willcl-ark commented at 12:13 pm on April 29, 2024: member

    ACK 38e24dfc5f1c54723018bf9d973b7d9cf9a2b824

    I think the macro simplification included in this change is a nice win for simplicity. Ran all the updated examples in contrib/tracing, and played around with adding/removing various tracepoint arguments to check everything works as expected.

    Left one q and one suggestion inline, but neither a blocker for this.

  86. DrahtBot requested review from laanwj on Apr 29, 2024
  87. in doc/tracing.md:269 in 38e24dfc5f outdated
    287-#define TRACE9(context, event, a, b, c, d, e, f, g, h, i)
    288-#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j)
    289-#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k)
    290-#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l)
    291+Use the `TRACEPOINT` macro to add a new tracepoint. If not yet included, include
    292+the `util/trace.h` (defines the tracepoint macros) with `#include <util/trace.h>`.
    


    vasild commented at 12:03 pm on May 10, 2024:
    nit: replace “include the trace.h” with either “include trace.h” or “include the trace.h header”
  88. in src/util/trace.h:14 in 38e24dfc5f outdated
    10@@ -11,39 +11,46 @@
    11 
    12 #ifdef ENABLE_TRACING
    13 
    14+// Setting SDT_USE_VARIADIC let's systemtap (sys/sdt.h) know that we want to use
    


    vasild commented at 12:05 pm on May 10, 2024:

    nit:

    0// Setting SDT_USE_VARIADIC lets systemtap (sys/sdt.h) know that we want to use
    
  89. in doc/tracing.md:300 in 38e24dfc5f outdated
    319+  …
    320+}
    321 ```
    322 
    323-For example:
    324+If needed, an extra `if(TRACEPOINT_ACTIVE(context, event) {..}` check can be
    


    vasild commented at 12:11 pm on May 10, 2024:

    3 nits:

    0If needed, an extra `if (TRACEPOINT_ACTIVE(context, event)) {...}` check can be
    
  90. in doc/tracing.md:311 in 38e24dfc5f outdated
    338-);
    339+// An example tracepoint with an expensive argument.
    340+
    341+TRACEPOINT_SEMAPHORE(example, gated_expensive_argument);
    342+…
    343+if(TRACEPOINT_ACTIVE(example, gated_expensive_argument) {
    


    vasild commented at 12:19 pm on May 10, 2024:

    nit:

    0if (TRACEPOINT_ACTIVE(example, gated_expensive_argument)) {
    
  91. in src/test/util_trace_tests.cpp:23 in 38e24dfc5f outdated
    18+BOOST_FIXTURE_TEST_SUITE(util_trace_tests, BasicTestingSetup)
    19+
    20+// Tests the TRACEPOINT macro and that we can compile tracepoints with 0 to 12 args.
    21+BOOST_AUTO_TEST_CASE(test_tracepoints)
    22+{
    23+  TRACEPOINT(test, zero_args);
    


    vasild commented at 12:21 pm on May 10, 2024:
    Indentation in Bitcoin Core is 4 spaces. This file uses 2 spaces (also some of the examples in doc/tracing.md).
  92. in src/util/trace.h:36 in 38e24dfc5f outdated
    44-#define TRACE9(context, event, a, b, c, d, e, f, g, h, i) DTRACE_PROBE9(context, event, a, b, c, d, e, f, g, h, i)
    45-#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j) DTRACE_PROBE10(context, event, a, b, c, d, e, f, g, h, i, j)
    46-#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k) DTRACE_PROBE11(context, event, a, b, c, d, e, f, g, h, i, j, k)
    47-#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l) DTRACE_PROBE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l)
    48+// Returns true if something is attached to the tracepoint.
    49+#define TRACEPOINT_ACTIVE(context, event) context##_##event##_semaphore > 0
    


    vasild commented at 12:48 pm on May 10, 2024:

    I know it would be weird usage if somebody does something like TRACEPOINT_ACTIVE(...) + 1 but in general it is better to define macros in such a way to avoid unexpected outcomes. In that case it would translate to context##_##event##_semaphore > (0 + 1) whereas the expectation would be (context##_##event##_semaphore > 0) + 1.

    0#define TRACEPOINT_ACTIVE(context, event) (context##_##event##_semaphore > 0)
    
  93. in src/util/trace.h:42 in 38e24dfc5f outdated
    52+// tracepoint is active before preparing its arguments.
    53+#define TRACEPOINT(context, event, ...)                                         \
    54+    do {                                                                        \
    55+        if (TRACEPOINT_ACTIVE(context, event)) {                                \
    56+            STAP_PROBEV(context, event __VA_OPT__(, ) __VA_ARGS__);                           \
    57+        }                                                                       \
    


    vasild commented at 12:51 pm on May 10, 2024:

    whitespace:

    0        if (TRACEPOINT_ACTIVE(context, event)) {                                \
    1            STAP_PROBEV(context, event __VA_OPT__(, ) __VA_ARGS__);             \
    2        }                                                                       \
    
  94. in contrib/tracing/mempool_monitor.py:119 in 38e24dfc5f outdated
    113@@ -114,8 +114,9 @@
    114 """
    115 
    116 
    117-def main(bitcoind_path):
    118-    bitcoind_with_usdts = USDT(path=str(bitcoind_path))
    119+def main(bitcoind_pid):
    120+    print(f"Hooking into bitcoind with pid {pid}")
    121+    bitcoind_with_usdts = USDT(pid=int(bitcoind_pid))
    


    vasild commented at 1:00 pm on May 10, 2024:

    The argument is called bitcoind_pid, but the print uses {pid}. The neighboring py files use just pid:

    0def main(pid):
    1    print(f"Hooking into bitcoind with pid {pid}")
    2    bitcoind_with_usdts = USDT(pid=int(pid))
    
  95. vasild commented at 1:02 pm on May 10, 2024: contributor

    Approach ACK 38e24dfc5f1c54723018bf9d973b7d9cf9a2b824

    Mostly nits that would be nice to address + one blocker about the bitcoind_pid vs pid mismatch.

  96. DrahtBot added the label Needs rebase on May 24, 2024
  97. 0xB10C force-pushed on May 25, 2024
  98. 0xB10C commented at 8:49 am on May 25, 2024: contributor
    Addressed @vasild comments and #26593 (review) (thanks!) and rebased.
  99. 0xB10C force-pushed on May 25, 2024
  100. DrahtBot removed the label Needs rebase on May 25, 2024
  101. DrahtBot added the label Needs rebase on Jun 17, 2024
  102. tracing: dedup TRACE macros & rename to TRACEPOINT
    This deduplicates the TRACEx macros by using systemtaps STAP_PROBEV[0]
    variadic macro instead of the DTrace compability DTRACE_PROBE[1] macros.
    Bitcoin Core never had DTrace tracepoints, so we don't need to use the
    drop-in replacement for it. As noted in pr25541[2], these macros aren't
    compatibile with DTrace on macOS anyway.
    
    This also renames the TRACEx macro to TRACEPOINT to clarify what the
    macro does: inserting a tracepoint vs tracing (logging) something.
    
    [0]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l407
    [1]: https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h;h=24d5e01c37805e55c36f7202e5d4e821b85167a1;hb=ecab2afea46099b4e7dfd551462689224afdbe3a#l490
    [2]: https://github.com/bitcoin/bitcoin/pull/25541/files#diff-553886c5f808e01e3452c7b21e879cc355da388ef7680bf310f6acb926d43266R30-R31
    
    Co-authored-by: Martin Leitner-Ankerl <martin.ankerl@gmail.com>
    3991ae0bf7
  103. tracing: only prepare tracepoint args if attached
    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. An example are mempool
    tracepoints that pass serialized transactions. We've avoided the
    serialization in the past as it was too expensive.
    
    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.
    
    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.
    1842583f6b
  104. tracing: use bitcoind pid in bcc tracing examples
    BCC needs the PID of a bitcoind process to attach to the tracepoints
    (instead of the binary path used before) when the tracepoints have a
    semaphore.
    
    For reference, we already use the PID in our tracepoint interface
    tests. See 220a5a2841172a07d6d7849596316f0e0933e272.
    1949b64afe
  105. 0xB10C force-pushed on Jun 18, 2024
  106. DrahtBot removed the label Needs rebase on Jun 18, 2024
  107. vasild approved
  108. vasild commented at 11:16 am on June 21, 2024: contributor

    ACK 1949b64afe7ecf91091f58623e75341a75996da0

    Thank you!

  109. DrahtBot requested review from willcl-ark on Jun 21, 2024

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-05 16:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me