diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml index d3b0d433a..d898cfdff 100644 --- a/.github/workflows/presubmit.yml +++ b/.github/workflows/presubmit.yml @@ -132,7 +132,7 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} - name: Integration test run: | - THAPI_BIN_DIR=./build/ici/bin bats integration_tests/ + THAPI_INSTALL_DIR=./build/ici bats integration_tests/ build-in-tree-and-check: needs: efficios_dep diff --git a/configure.ac b/configure.ac index ee8c71aba..464ccbb6b 100644 --- a/configure.ac +++ b/configure.ac @@ -102,7 +102,10 @@ AC_SUBST([ENABLE_CLANG_PARSER]) PKG_CHECK_MODULES([LIBFFI], [libffi >= 3.2]) PKG_CHECK_MODULES([BABELTRACE2], [babeltrace2 >= 2.0]) -PKG_CHECK_MODULES([LTTNG_UST], [lttng-ust >= 2.10]) +# Use of __attribute__((constructor)) requires `lttng-ust >= 2.12.8` to work properly. +# Specifically, the following fix: +# https://github.com/lttng/lttng-ust/commit/a8fafb675a9f580f6a889223e26664ea11cb0c99. +PKG_CHECK_MODULES([LTTNG_UST], [lttng-ust >= 2.12.8]) PKG_CHECK_MODULES([PROTOBUF], [protobuf >= 3.0]) AX_RUBY_EXTENSION([cast-to-yaml], [yes]) @@ -137,6 +140,8 @@ AC_FUNC_MMAP AC_FUNC_REALLOC AC_CHECK_FUNCS([clock_gettime ftruncate memmove memset strdup strstr strtoull strlen strchr]) +AX_GCC_FUNC_ATTRIBUTE(constructor) + AC_CONFIG_FILES([ Makefile xprof/Makefile diff --git a/integration_tests/setup_suite.bash b/integration_tests/setup_suite.bash index e01a9c4c0..5e9d26d61 100644 --- a/integration_tests/setup_suite.bash +++ b/integration_tests/setup_suite.bash @@ -2,7 +2,10 @@ setup_suite() { export THAPI_HOME=${THAPI_HOME:-${PWD}} - export THAPI_BIN_DIR=${THAPI_BIN_DIR:-${THAPI_HOME}/install/bin} + export THAPI_INSTALL_DIR=${THAPI_INSTALL_DIR:-${THAPI_HOME}/install} + export THAPI_BIN_DIR=${THAPI_BIN_DIR:-${THAPI_INSTALL_DIR}/bin} + export THAPI_INC_DIR=${THAPI_INC_DIR:-${THAPI_INSTALL_DIR}/include} + export THAPI_LIB_DIR=${THAPI_LIB_DIR:-${THAPI_INSTALL_DIR}/lib} export THAPI_TEST_BIN=${THAPI_TEST_BIN:-clinfo} export IPROF=${IPROF:-${THAPI_BIN_DIR}/iprof} diff --git a/integration_tests/toggle.bats b/integration_tests/toggle.bats new file mode 100644 index 000000000..0b7060776 --- /dev/null +++ b/integration_tests/toggle.bats @@ -0,0 +1,71 @@ +#!/usr/bin/env bats + +teardown_file() { + rm -rf $THAPI_HOME/thapi-traces +} + +get_unique_jobid() { + echo ${BATS_TEST_NAME}.${RANDOM} +} + +@test "toggle_api" { + rm -rf toggle_traces 2> /dev/null + + cc -I${THAPI_INC_DIR} ./integration_tests/toggle.c -o toggle \ + -Wl,-rpath,${THAPI_LIB_DIR} -L${THAPI_LIB_DIR} -lThapi + + $IPROF --trace-output toggle_traces --no-analysis -- ./toggle + dir=$(ls -d -1 ./toggle_traces/*/) + + start_count=`$BBT -c $dir | grep lttng_ust_toggle:start | wc -l` + [ "$start_count" -eq 1 ] + + stop_count=`$BBT -c $dir | grep lttng_ust_toggle:stop | wc -l` + [ "$stop_count" -eq 2 ] +} + +toggle_count_base() { + rm -rf toggle_traces 2> /dev/null + + THAPI_SYNC_DAEMON=fs THAPI_JOBID=$(get_unique_jobid) timeout 40s $MPIRUN -n $1 \ + $IPROF --trace-output toggle_traces --no-analysis -- ./toggle_mpi $2 + + traces=$($BBT ./toggle_traces) + + echo $traces +} + +toggle_count_traces() { + traces=$(toggle_count_base $1 $2) + echo $traces | sed -e "s/ \[/\n[/g" | grep . | wc -l +} + +@test "toggle_plugin_mpi_np_1" { + mpicc -I${THAPI_INC_DIR} ./integration_tests/toggle_mpi.c -o toggle_mpi \ + -Wl,-rpath,${THAPI_LIB_DIR} -L${THAPI_LIB_DIR} -lThapi + + count_0=$(toggle_count_traces 1 0) + count_1=$(toggle_count_traces 1 1) + count_2=$(toggle_count_traces 1 2) + + [ "$count_2" -eq 0 ] + [ "$count_0" -gt "$count_1" ] +} + +toggle_count_vpids() { + traces=$(toggle_count_base $1 $2) + echo $traces | sed -e "s/ - /, /g" | sed -e "s/,/\n/g" | grep vpid | sort | uniq | wc -l +} + +@test "toggle_plugin_mpi_np_2" { + mpicc -I${THAPI_INC_DIR} ./integration_tests/toggle_mpi.c -o toggle_mpi \ + -Wl,-rpath,${THAPI_LIB_DIR} -L${THAPI_LIB_DIR} -lThapi + + count_0=$(toggle_count_vpids 2 0) + count_1=$(toggle_count_vpids 2 1) + count_2=$(toggle_count_vpids 2 2) + + [ "$count_0" -eq 2 ] + [ "$count_1" -eq 1 ] + [ "$count_2" -eq 0 ] +} diff --git a/integration_tests/toggle.c b/integration_tests/toggle.c new file mode 100644 index 000000000..bc1e1e900 --- /dev/null +++ b/integration_tests/toggle.c @@ -0,0 +1,6 @@ +#include + +int main(int argc, char *argv[]) { + thapi_start(); + thapi_stop(); +} diff --git a/integration_tests/toggle_mpi.c b/integration_tests/toggle_mpi.c new file mode 100644 index 000000000..d98fc77cf --- /dev/null +++ b/integration_tests/toggle_mpi.c @@ -0,0 +1,30 @@ +#include +#include + +#include + +int main(int argc, char *argv[]) { + int variant = (argc > 1) ? atoi(argv[1]) : 0; + + MPI_Init(&argc, &argv); + + int rank, size; + + switch (variant) { + case 0: + thapi_start(); + case 1: + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) thapi_start(); + MPI_Comm_size(MPI_COMM_WORLD, &size); + break; + default: + break; + } + + thapi_stop(); + + MPI_Finalize(); + + return 0; +} diff --git a/m4/ax_gcc_func_attribute.m4 b/m4/ax_gcc_func_attribute.m4 new file mode 100644 index 000000000..fa4e089d6 --- /dev/null +++ b/m4/ax_gcc_func_attribute.m4 @@ -0,0 +1,242 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's function +# attributes; many other compilers also provide function attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_. +# +# The macro caches its result in the ax_cv_have_func_attribute_ +# variable. +# +# The macro currently supports the following function attributes: +# +# alias +# aligned +# alloc_size +# always_inline +# artificial +# cold +# const +# constructor +# constructor_priority for constructor attribute with priority +# deprecated +# destructor +# dllexport +# dllimport +# error +# externally_visible +# fallthrough +# flatten +# format +# format_arg +# gnu_format +# gnu_inline +# hot +# ifunc +# leaf +# malloc +# noclone +# noinline +# nonnull +# noreturn +# nothrow +# optimize +# pure +# sentinel +# sentinel_position +# unused +# used +# visibility +# warning +# warn_unused_result +# weak +# weakref +# +# Unsupported function attributes will be tested with a prototype +# returning an int and not accepting any arguments and the result of the +# check might be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [alias], [ + int foo( void ) { return 0; } + int bar( void ) __attribute__(($1("foo"))); + ], + [aligned], [ + int foo( void ) __attribute__(($1(32))); + ], + [alloc_size], [ + void *foo(int a) __attribute__(($1(1))); + ], + [always_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [artificial], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [cold], [ + int foo( void ) __attribute__(($1)); + ], + [const], [ + int foo( void ) __attribute__(($1)); + ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], + [constructor], [ + int foo( void ) __attribute__(($1)); + ], + [deprecated], [ + int foo( void ) __attribute__(($1(""))); + ], + [destructor], [ + int foo( void ) __attribute__(($1)); + ], + [dllexport], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [dllimport], [ + int foo( void ) __attribute__(($1)); + ], + [error], [ + int foo( void ) __attribute__(($1(""))); + ], + [externally_visible], [ + int foo( void ) __attribute__(($1)); + ], + [fallthrough], [ + void foo( int x ) {switch (x) { case 1: __attribute__(($1)); case 2: break ; }}; + ], + [flatten], [ + int foo( void ) __attribute__(($1)); + ], + [format], [ + int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); + ], + [gnu_format], [ + int foo(const char *p, ...) __attribute__((format(gnu_printf, 1, 2))); + ], + [format_arg], [ + char *foo(const char *p) __attribute__(($1(1))); + ], + [gnu_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [hot], [ + int foo( void ) __attribute__(($1)); + ], + [ifunc], [ + int my_foo( void ) { return 0; } + static int (*resolve_foo(void))(void) { return my_foo; } + int foo( void ) __attribute__(($1("resolve_foo"))); + ], + [leaf], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [malloc], [ + void *foo( void ) __attribute__(($1)); + ], + [noclone], [ + int foo( void ) __attribute__(($1)); + ], + [noinline], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [nonnull], [ + int foo(char *p) __attribute__(($1(1))); + ], + [noreturn], [ + void foo( void ) __attribute__(($1)); + ], + [nothrow], [ + int foo( void ) __attribute__(($1)); + ], + [optimize], [ + __attribute__(($1(3))) int foo( void ) { return 0; } + ], + [pure], [ + int foo( void ) __attribute__(($1)); + ], + [sentinel], [ + int foo(void *p, ...) __attribute__(($1)); + ], + [sentinel_position], [ + int foo(void *p, ...) __attribute__(($1(1))); + ], + [returns_nonnull], [ + void *foo( void ) __attribute__(($1)); + ], + [unused], [ + int foo( void ) __attribute__(($1)); + ], + [used], [ + int foo( void ) __attribute__(($1)); + ], + [visibility], [ + int foo_def( void ) __attribute__(($1("default"))); + int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); + ], + [warning], [ + int foo( void ) __attribute__(($1(""))); + ], + [warn_unused_result], [ + int foo( void ) __attribute__(($1)); + ], + [weak], [ + int foo( void ) __attribute__(($1)); + ], + [weakref], [ + static int foo( void ) { return 0; } + static int bar( void ) __attribute__(($1("foo"))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo( void ) __attribute__(($1)); + ] + )], []) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([grep -- -Wattributes conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' function attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/utils/Makefile.am b/utils/Makefile.am index 8e27fa9c3..b6a6e9f29 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -43,6 +43,47 @@ dlinfo_wrapper_CFLAGS = -Wall -Wextra bin_PROGRAMS += thapi_metadata +include_HEADERS = thapi.h + +lib_LTLIBRARIES = libThapi.la +nodist_libThapi_la_SOURCES = \ + thapi_toggle_tracepoints.h \ + thapi_toggle_tracepoints.c +libThapi_la_SOURCES = thapi_toggle.c +libThapi_la_CFLAGS = $(LTTNG_FLAGS) $(LTTNG_UST_CFLAGS) +libThapi_la_LDFLAGS = $(LTTNG_UST_LIBS) + +BTX_THAPI_TOGGLE_GENERATED = \ + btx_thapi_toggle/metababel/metababel.h \ + btx_thapi_toggle/metababel/btx_component.h \ + btx_thapi_toggle/metababel/btx_component.c \ + btx_thapi_toggle/metababel/btx_upstream.h \ + btx_thapi_toggle/metababel/btx_upstream.c \ + btx_thapi_toggle/metababel/btx_downstream.h \ + btx_thapi_toggle/metababel/btx_downstream.c \ + btx_thapi_toggle/btx_main.c + +$(BTX_THAPI_TOGGLE_GENERATED) &: $(srcdir)/btx_thapi_toggle.yaml + $(METABABEL) --enable-callbacks on_downstream -t FILTER -p toggle -c toggle \ + --upstream $(srcdir)/btx_thapi_toggle.yaml --downstream $(srcdir)/btx_thapi_toggle.yaml \ + -o btx_thapi_toggle + +bt2dir = $(pkglibdir)/bt2 +bt2_LTLIBRARIES = libThapiToggle.la + +nodist_libThapiToggle_la_SOURCES = $(BTX_THAPI_TOGGLE_GENERATED) +libThapiToggle_la_SOURCES = thapi_toggle_callbacks.cpp +libThapiToggle_la_CFLAGS = -fPIC -shared -Wall -Wextra -Wno-unused-parameter $(BABELTRACE2_CFLAGS) \ + -I./btx_thapi_toggle -I$(top_srcdir)/utils/include +libThapiToggle_la_CXXFLAGS = -fPIC -shared -Wall -Wextra -Wno-unused-parameter $(BABELTRACE2_CFLAGS) \ + -I./btx_thapi_toggle -I$(top_srcdir)/utils/include +libThapiToggle_la_LDFLAGS = $(BABELTRACE2_LIBS) -avoid-version -module + +BUILT_SOURCES += \ + thapi_toggle_tracepoints.h \ + thapi_toggle_tracepoints.c \ + $(BTX_THAPI_TOGGLE_GENERATED) + bin_SCRIPTS = \ babeltrace_thapi @@ -62,6 +103,7 @@ CLEANFILES = \ version \ optparse_thapi.rb \ lttng/tracepoint_gen.h \ + $(BTX_THAPI_TOGGLE_GENERATED) \ $(BUILT_SOURCES) EXTRA_DIST = \ @@ -74,6 +116,8 @@ EXTRA_DIST = \ gen_library_base.rb \ dump_trace_format.rb \ thapi_metadata_tracepoints.tp \ + thapi_toggle_tracepoints.tp \ + btx_thapi_toggle.yaml \ command.rb \ meta_parameters.rb \ optparse_thapi.rb \ diff --git a/utils/babeltrace_thapi.in b/utils/babeltrace_thapi.in index 8a7b9a9db..915e66dbd 100755 --- a/utils/babeltrace_thapi.in +++ b/utils/babeltrace_thapi.in @@ -322,7 +322,7 @@ def bt_graphs(inputs) 'filter.btx_aggreg.aggreg', 'sink.btx_tally.tally'], 'timeline' => ['filter.intervals.interval', 'sink.btx_timeline.timeline'], - 'trace' => ['sink.text.rubypretty'], + 'trace' => ['filter.toggle.toggle', 'sink.text.rubypretty'], 'to_interval' => ['filter.intervals.interval', 'filter.btx_stripper.stripper', 'sink.ctf.fs'], 'to_aggreg' => ['filter.intervals.interval', 'filter.btx_aggreg.aggreg', diff --git a/utils/btx_thapi_toggle.yaml b/utils/btx_thapi_toggle.yaml new file mode 100644 index 000000000..53266a1c0 --- /dev/null +++ b/utils/btx_thapi_toggle.yaml @@ -0,0 +1,28 @@ +:environment: + :entries: + - :name: hostname + :type: string +:stream_classes: +- :name: thapi_toggle + :default_clock_class: {} + :packet_context_field_class: + :type: structure + :members: + - :name: cpu_id + :field_class: + :type: integer_signed + :cast_type: int64_t + :event_common_context_field_class: + :type: structure + :members: + - :name: vpid + :field_class: + :type: integer_signed + :cast_type: int64_t + - :name: vtid + :field_class: + :type: integer_signed + :cast_type: int64_t + :event_classes: + - :name: lttng_ust_toggle:start + - :name: lttng_ust_toggle:stop diff --git a/utils/thapi.h b/utils/thapi.h new file mode 100644 index 000000000..b94918a4c --- /dev/null +++ b/utils/thapi.h @@ -0,0 +1,15 @@ +#if !defined(THAPI) +#define THAPI + +#ifdef __cplusplus +extern "C" { +#endif + +void thapi_start(void); +void thapi_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif // THAPI diff --git a/utils/thapi_toggle.c b/utils/thapi_toggle.c new file mode 100644 index 000000000..0fedca261 --- /dev/null +++ b/utils/thapi_toggle.c @@ -0,0 +1,13 @@ +#include "thapi.h" +#include "thapi_toggle_tracepoints.h" + +#ifndef LTTNG_UST_CONSTRUCTOR_PRIO +#error "LTTNG_UST_CONSTRUCTOR_PRIO is not defined." +#endif + +void thapi_start(void) { tracepoint(lttng_ust_toggle, start); } + +void __attribute__((constructor(LTTNG_UST_CONSTRUCTOR_PRIO + 1))) +thapi_stop(void) { + tracepoint(lttng_ust_toggle, stop); +} diff --git a/utils/thapi_toggle_callbacks.cpp b/utils/thapi_toggle_callbacks.cpp new file mode 100644 index 000000000..00e6c183d --- /dev/null +++ b/utils/thapi_toggle_callbacks.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#include +#include + +#include + +using ToggleKey = std::tuple; +using ToggleMap = std::map; + +static char hostname_s[HOST_NAME_MAX + 1]; + +static void init(void **data) { *data = new ToggleMap; } + +static void finalize(void *data) { delete static_cast(data); } + +static void thapi_start_callback(void *btx_handle, void *tmap, int64_t cpuid, const char *hostname, + int64_t vpid, int64_t vtid) { + auto map = static_cast(tmap); + auto key = ToggleKey{std::string(hostname), vpid}; + (*map)[key] = true; + strncpy(hostname_s, hostname, HOST_NAME_MAX); +} + +static void thapi_stop_callback(void *btx_handle, void *tmap, int64_t cpuid, const char *hostname, + int64_t vpid, int64_t vtid) { + auto map = static_cast(tmap); + auto key = ToggleKey{std::string(hostname), vpid}; + (*map)[key] = false; +} + +static void push_downstream(void *btx_handle, void *tmap, const bt_message *msg) { + bool push_msg = true; + + if (bt_message_get_type(msg) == BT_MESSAGE_TYPE_EVENT) { + const bt_event *event = bt_message_event_borrow_event_const(msg); + const bt_field *ccf = bt_event_borrow_common_context_field_const(event); + const bt_field *vpid = bt_field_structure_borrow_member_field_by_name_const(ccf, "vpid"); + uint64_t vpid_v = bt_field_integer_signed_get_value(vpid); + + auto map = static_cast(tmap); + auto key = ToggleKey{std::string(hostname_s), vpid_v}; + push_msg = (*map)[key]; + } + + if (push_msg) { + btx_push_message(btx_handle, msg); + } else { + bt_message_put_ref(msg); + } +} + +void btx_register_usr_callbacks(void *btx_handle) { + btx_register_callbacks_initialize_component(btx_handle, &init); + btx_register_callbacks_lttng_ust_toggle_start(btx_handle, + &thapi_start_callback); + btx_register_callbacks_lttng_ust_toggle_stop(btx_handle, + &thapi_stop_callback); + btx_register_callbacks_finalize_component(btx_handle, &finalize); + + btx_register_on_downstream_message_callback(btx_handle, &push_downstream); +} diff --git a/utils/thapi_toggle_tracepoints.tp b/utils/thapi_toggle_tracepoints.tp new file mode 100644 index 000000000..83fc7fac0 --- /dev/null +++ b/utils/thapi_toggle_tracepoints.tp @@ -0,0 +1,13 @@ +TRACEPOINT_EVENT( + lttng_ust_toggle, + start, + TP_ARGS(), + TP_FIELDS() +) + +TRACEPOINT_EVENT( + lttng_ust_toggle, + stop, + TP_ARGS(), + TP_FIELDS() +)