mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-06 02:33:28 +01:00
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.
55 lines
2.3 KiB
C
55 lines
2.3 KiB
C
// Copyright (c) 2020-2021 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_UTIL_TRACE_H
|
|
#define BITCOIN_UTIL_TRACE_H
|
|
|
|
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
|
|
|
#ifdef ENABLE_TRACING
|
|
|
|
// Setting SDT_USE_VARIADIC lets systemtap (sys/sdt.h) know that we want to use
|
|
// the optional variadic macros to define tracepoints.
|
|
#define SDT_USE_VARIADIC 1
|
|
|
|
// Setting _SDT_HAS_SEMAPHORES let's systemtap (sys/sdt.h) know that we want to
|
|
// use the optional semaphore feature for our tracepoints. This feature allows
|
|
// us to check if something is attached to a tracepoint. We only want to prepare
|
|
// some potentially expensive tracepoint arguments, if the tracepoint is being
|
|
// used. Here, an expensive argument preparation could, for example, be
|
|
// calculating a hash or serialization of a data structure.
|
|
#define _SDT_HAS_SEMAPHORES 1
|
|
|
|
// Used to define a counting semaphore for a tracepoint. This semaphore is
|
|
// automatically incremented by tracing frameworks (bpftrace, bcc, libbpf, ...)
|
|
// upon attaching to the tracepoint and decremented when detaching. This needs
|
|
// to be a global variable. It's placed in the '.probes' ELF section.
|
|
#define TRACEPOINT_SEMAPHORE(context, event) \
|
|
unsigned short context##_##event##_semaphore __attribute__((section(".probes")))
|
|
|
|
#include <sys/sdt.h>
|
|
|
|
// Returns true if something is attached to the tracepoint.
|
|
#define TRACEPOINT_ACTIVE(context, event) (context##_##event##_semaphore > 0)
|
|
|
|
// A USDT tracepoint with one to twelve arguments. It's checked that the
|
|
// tracepoint is active before preparing its arguments.
|
|
#define TRACEPOINT(context, event, ...) \
|
|
do { \
|
|
if (TRACEPOINT_ACTIVE(context, event)) { \
|
|
STAP_PROBEV(context, event __VA_OPT__(, ) __VA_ARGS__); \
|
|
} \
|
|
} while(0)
|
|
|
|
#else
|
|
|
|
#define TRACEPOINT_SEMAPHORE(context, event)
|
|
#define TRACEPOINT_ACTIVE(context, event) false
|
|
#define TRACEPOINT(context, ...)
|
|
|
|
#endif // ENABLE_TRACING
|
|
|
|
|
|
#endif // BITCOIN_UTIL_TRACE_H
|