CURDIR=$(dirname $0)/
TESTDIR=$CURDIR/../../../
-# This is needed since the testpoint creates a pipe with the consumerd domain
-# suffixed
-TESTPOINT_BASE_PATH=$(readlink -f "$CURDIR/lttng.t_p_n")
-TESTPOINT_PIPE_PATH=$(mktemp -u "${TESTPOINT_BASE_PATH}.XXXXXX")
-TESTPOIT_ARGS="CONSUMER_PAUSE_PIPE_PATH=${TESTPOINT_PIPE_PATH} LTTNG_TESTPOINT_ENABLE=1"
TESTPOINT=$(readlink -f ${CURDIR}/.libs/libpause_consumer.so)
TESTAPP_PATH="$TESTDIR/utils/testapp"
TESTAPP_NAME="gen-ust-events"
TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
+TESTAPP_STATE_FILE="$(mktemp -u)"
-NR_ITER=-1
+NR_ITER=1000
NR_USEC_WAIT=5
SESSION_NAME="my_session"
-UST_CHANNEL_NAME="my_ust_channel"
-EVENT_NAME="tp:tptest"
+CHANNEL_NAME="my_channel"
-NR_NOTIFICATION_EXPECTED=5
-NR_CLIENT_APP=50
-
-TRACE_PATH=$(mktemp -d)
DIR=$(readlink -f $TESTDIR)
PAGE_SIZE=$(getconf PAGE_SIZE)
-NUM_TESTS=46
+NUM_TEST_UST=50
+NUM_TEST_KERNEL=50
+NUM_TESTS=$(($NUM_TEST_UST + $NUM_TEST_KERNEL))
source $TESTDIR/utils/utils.sh
print_test_banner "$TEST_DESC"
app_pids=()
+
+function kernel_event_generator_toogle_state
+{
+ kernel_event_generator_suspended=$((kernel_event_generator_suspended==0))
+
+}
+function kernel_event_generator
+{
+ state_file=$1
+ kernel_event_generator_suspended=0
+ trap kernel_event_generator_toogle_state SIGUSR1
+ trap "exit" SIGTERM SIGINT
+ while (true); do
+ if [[ $kernel_event_generator_suspended -eq "1" ]]; then
+ touch $state_file
+ sleep 0.5
+ else
+ if [[ -f $state_file ]]; then
+ rm $state_file 2> /dev/null
+ fi
+ echo -n "1000" > /proc/lttng-test-filter-event
+ fi
+ done
+}
+
+function ust_event_generator_toogle_state
+{
+ ust_event_generator_suspended=$((ust_event_generator_suspended==0))
+
+}
+function ust_event_generator
+{
+ state_file=$1
+ ust_event_generator_suspended=0
+ trap ust_event_generator_toogle_state SIGUSR1
+ trap "exit" SIGTERM SIGINT
+ while (true); do
+ if [[ $ust_event_generator_suspended -eq "1" ]]; then
+ touch $state_file
+ sleep 0.5
+ else
+ if [[ -f $state_file ]]; then
+ rm $state_file 2> /dev/null
+ fi
+ taskset -c 0 $TESTAPP_BIN $NR_ITER $NR_USEC_WAIT > /dev/null 2>&1
+ fi
+ done
+}
+
function start_client {
local pid=-1
local output_file=$1
function wait_for_message ()
{
- local file_pattern=$1
- local message=$2
+ local directory=$1
+ local file_pattern=$2
+ local message=$3
- for file in $CURDIR/${file_pattern}*; do
+ for file in $directory/${file_pattern}*; do
while(true); do
# Check for "error" message
grep -q "error:" ${file}
function print_errors ()
{
- local file_pattern=$1
+ local directory=$1
+ local file_pattern=$2
- for file in $CURDIR/${file_pattern}*; do
+ for file in $directory/${file_pattern}*; do
# Check for "error" message
error_message=$(grep "error:" ${file})
- if [[ "${error_message}" -ne "" ]]; then
+ if [[ "${error_message}x" != "x" ]]; then
diag "Errors for application ${file}:"
diag "${error_message}"
fi
local message=$1
local pipe=$2
echo -ne "${message}" > "${pipe}"
- return $?
}
function stop_consumerd ()
{
local pipe=$1
comm_consumerd "1" "$pipe"
- ok $? "Stopping consumption consumerd"
}
function resume_consumerd ()
{
local pipe=$1
comm_consumerd "\0" "$pipe"
- ok $? "Resuming consumerd"
}
function test_multi_app ()
{
+ local domain_type=$1
+ local event_generator_pid=$2
+
local app_pids=()
local low_output_file_pattern="low_app_output_file_"
local high_output_file_pattern="high_app_output_file_"
-
- # Cleanup
- rm ${CURDIR}/${low_output_file_pattern}* 2> /dev/null
- rm ${CURDIR}/${high_output_file_pattern}* 2> /dev/null
+ local output_dir=$(mktemp -d)
+
+ local testpoint_base_path=$(readlink -f "$output_dir/lttng.t_p_n_multi_app")
+ local testpoint_pipe_path=$(mktemp -u "${testpoint_base_path}.XXXXXX")
+
+ local nr_notification_expected=5
+ local nr_client_app=50
+ local domain_string=""
+ local event_name=""
+
+ case $domain_type in
+ ust)
+ domain_string=LTTNG_DOMAIN_UST
+ event_name="tp:tptest"
+ ;;
+ kernel)
+ domain_string=LTTNG_DOMAIN_KERNEL
+ event_name="lttng_test_filter_event"
+ ;;
+ *)
+ fail "Invalid domain type"
+ exit 1
+ ;;
+ esac
# Setup
- LTTNG_SESSIOND_ENV_VARS="LTTNG_TESTPOINT_ENABLE=1 CONSUMER_PAUSE_PIPE_PATH=${TESTPOINT_PIPE_PATH} LD_PRELOAD=${TESTPOINT}"
+ LTTNG_SESSIOND_ENV_VARS="LTTNG_TESTPOINT_ENABLE=1 CONSUMER_PAUSE_PIPE_PATH=${testpoint_pipe_path} LD_PRELOAD=${TESTPOINT}"
start_lttng_sessiond
- # Start app in infinite loop
- $TESTAPP_BIN $NR_ITER $NR_USEC_WAIT $file_sync_after_first_event &
- app_pid=$!
- # Pin to CPU zero to force specific sub buffer usage
- taskset -p -c 0 $app_pid > /dev/null 2>&1
-
- # Wait for sync with app
- while [ ! -f "${file_sync_after_first_event}" ]; do
- sleep 0.5
- done
- rm ${file_sync_after_first_event}
-
create_lttng_session_ok $SESSION_NAME $TRACE_PATH
- enable_ust_lttng_channel_ok $SESSION_NAME $UST_CHANNEL_NAME --subbuf-size=$PAGE_SIZE
- enable_ust_lttng_event_ok $SESSION_NAME $EVENT_NAME $UST_CHANNEL_NAME
+ enable_${domain_type}_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME --subbuf-size=$PAGE_SIZE
+ enable_${domain_type}_lttng_event_ok $SESSION_NAME $event_name $CHANNEL_NAME
# Fetch consumerd testpoint pipe information
# This is needed since the testpoint create a pipe with the consumer type suffixed
- for f in "$TESTPOINT_BASE_PATH"*; do
+ consumerd_pipe=()
+ for f in "$testpoint_pipe_path"*; do
consumerd_pipe+=("$f")
done
- for (( i = 0; i < $NR_CLIENT_APP; i++ )); do
- low_app_output_file=$CURDIR/${low_output_file_pattern}${i}
- high_app_output_file=$CURDIR/${high_output_file_pattern}${i}
- start_client $low_app_output_file $SESSION_NAME $UST_CHANNEL_NAME LTTNG_DOMAIN_UST LOW RATIO 0.0 $NR_NOTIFICATION_EXPECTED
- start_client $high_app_output_file $SESSION_NAME $UST_CHANNEL_NAME LTTNG_DOMAIN_UST HIGH RATIO 0.420 $NR_NOTIFICATION_EXPECTED
+ for (( i = 0; i < $nr_client_app; i++ )); do
+ low_app_output_file=$output_dir/${low_output_file_pattern}${i}
+ high_app_output_file=$output_dir/${high_output_file_pattern}${i}
+ start_client $low_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string LOW RATIO 0.0 $nr_notification_expected
+ start_client $high_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 $nr_notification_expected
done
- wait_for_message "${low_output_file_pattern}" "sync: ready"
- wait_for_message "${high_output_file_pattern}" "sync: ready"
+ wait_for_message $output_dir "${low_output_file_pattern}" "sync: ready"
+ wait_for_message $output_dir "${high_output_file_pattern}" "sync: ready"
# Test notification reception
- for (( i = 0; i < $NR_NOTIFICATION_EXPECTED; i++ )); do
+ for (( i = 0; i < $nr_notification_expected; i++ )); do
# Stop consumerd consumption to force high notification
start_lttng_tracing_ok $SESSION_NAME
stop_consumerd "${pipe}"
done
- wait_for_message "${high_output_file_pattern}" "notification: high $i"
+ wait_for_message $output_dir "${high_output_file_pattern}" "notification: high $i"
+
+ # Put application in suspend mode to prevent double low
+ # notification and synchronize on state file.
+ kill -s SIGUSR1 $event_generator_pid
+ while [ ! -f "${TESTAPP_STATE_FILE}" ]; do
+ sleep 0.5
+ done
# Resume consumerd
for pipe in "${consumerd_pipe[@]}"; do
stop_lttng_tracing $SESSION_NAME
# Check for notifications reception
- wait_for_message "${low_output_file_pattern}" "notification: low $i"
+ wait_for_message $output_dir "${low_output_file_pattern}" "notification: low $i"
ret=$?
ok $ret "Notifications $i received"
if [[ $ret -ne "0" ]]; then
# Error occurred bail out
break;
fi
+
+ # Put application in active mode and synchronize on state file.
+ kill -s SIGUSR1 $event_generator_pid
+ while [ -f "${TESTAPP_STATE_FILE}" ]; do
+ sleep 0.5
+ done
done
- wait_for_message "${low_output_file_pattern}" "exit: 0"
+ wait_for_message $output_dir "${low_output_file_pattern}" "exit: 0"
ret=$?
ok $ret "Application for low notification terminated normally"
- if [[ $ret -eq "0" ]]; then
- rm ${CURDIR}/${low_output_file_pattern}* 2> /dev/null
- else
- # Keep the file
- print_errors "${low_output_file_pattern}"
+ if [[ $ret -ne "0" ]]; then
+ print_errors $output_dir "${low_output_file_pattern}"
fi
- wait_for_message "${high_output_file_pattern}" "exit: 0"
+ wait_for_message $output_dir "${high_output_file_pattern}" "exit: 0"
ret=$?
ok $ret "Application for high notification terminated normally"
- if [[ $ret -eq "0" ]]; then
- rm ${CURDIR}/${high_output_file_pattern}* 2> /dev/null
- else
+ if [[ $ret -ne "0" ]]; then
+ print_errors $output_dir "${high_output_file_pattern}"
+ fi
+
+ rm -rf $output_dir
+
+ destroy_lttng_session_ok $SESSION_NAME
+ stop_lttng_sessiond
+
+ for pipe in "${consumerd_pipe[@]}"; do
+ rm -rf "${pipe}"
+ done
+}
+
+function test_multi_app_ust ()
+{
+ diag "Multi client app UST notification"
+ ust_event_generator $TESTAPP_STATE_FILE &
+ local generator_pid=$!
+
+ test_multi_app ust $generator_pid
+
+ kill -9 $generator_pid 2> /dev/null
+ wait $generator_pid 2> /dev/null
+ rm -rf ${TESTAPP_STATE_FILE} 2> /dev/null
+}
+
+function test_multi_app_kernel ()
+{
+ diag "Multi client app kernel notification"
+ modprobe lttng-test
+
+ kernel_event_generator $TESTAPP_STATE_FILE &
+ local generator_pid=$!
+
+ test_multi_app kernel $generator_pid
+
+
+ kill -9 $generator_pid 2>/dev/null
+ wait $generator_pid 2> /dev/null
+ rm -rf ${TESTAPP_STATE_FILE} 2> /dev/null
+
+ rmmod lttng-test
+}
+
+function test_on_register_evaluation_ust ()
+{
+ diag "On register notification UST"
+
+ # Start app in infinite loop
+ ust_event_generator $TESTAPP_STATE_FILE &
+ local generator_pid=$!
+
+ test_on_register_evaluation ust $generator_pid
+
+ kill -9 $generator_pid 2> /dev/null
+ wait $generator_pid 2> /dev/null
+ rm -rf ${TESTAPP_STATE_FILE} 2> /dev/null
+
+}
+
+function test_on_register_evaluation_kernel()
+{
+ diag "On register notification kernel"
+
+ modprobe lttng-test
+
+ kernel_event_generator $TESTAPP_STATE_FILE &
+ local generator_pid=$!
+
+ test_on_register_evaluation kernel $generator_pid
+
+
+ kill -9 $generator_pid 2> /dev/null
+ wait $generator_pid 2> /dev/null
+ rm -rf ${TESTAPP_STATE_FILE} 2> /dev/null
+
+ rmmod lttng-test
+}
+
+function test_on_register_evaluation ()
+{
+ local domain_type=$1
+ local event_generator_pid=$2
+
+ local app_pids=()
+ local high_output_file_pattern="high_app_output_file_on_register_evaluation"
+
+ local output_dir=$(mktemp -d)
+ local testpoint_base_path=$(readlink -f "$output_dir/lttng.t_p_n_register_evaluation")
+ local testpoint_pipe_path=$(mktemp -u "${testpoint_base_path}.XXXXXX")
+ local domain_string=""
+ local event_name=""
+
+ case $domain_type in
+ ust)
+ domain_string=LTTNG_DOMAIN_UST
+ event_name="tp:tptest"
+ ;;
+ kernel)
+ domain_string=LTTNG_DOMAIN_KERNEL
+ event_name="lttng_test_filter_event"
+ ;;
+ *)
+ fail "Invalid domain type"
+ exit 1
+ ;;
+ esac
+
+ # Setup
+ LTTNG_SESSIOND_ENV_VARS="LTTNG_TESTPOINT_ENABLE=1 CONSUMER_PAUSE_PIPE_PATH=${testpoint_pipe_path} LD_PRELOAD=${TESTPOINT}"
+ start_lttng_sessiond
+
+ create_lttng_session_ok $SESSION_NAME $TRACE_PATH
+ enable_${domain_type}_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME --subbuf-size=$PAGE_SIZE
+ enable_${domain_type}_lttng_event_ok $SESSION_NAME $event_name $CHANNEL_NAME
+
+ # Fetch consumerd testpoint pipe information
+ # This is needed since the testpoint create a pipe with the consumer type suffixed
+ consumerd_pipe=()
+ for f in "$testpoint_pipe_path"*; do
+ consumerd_pipe+=("$f")
+ done
+
+ high_app_output_file=${high_output_file_pattern}.first_receiver
+ high_app_output_path=$output_dir/${high_app_output_file}
+ start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1
+
+ wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
+
+ # Stop consumerd consumption to force high notification
+ start_lttng_tracing_ok $SESSION_NAME
+
+ for pipe in "${consumerd_pipe[@]}"; do
+ stop_consumerd "${pipe}"
+ done
+
+ wait_for_message $output_dir "${high_app_output_file}" "notification: high 0"
+
+ # Start a second receiver, the receiver should receive a high
+ # notification on subscription
+ high_app_output_file=${high_output_file_pattern}.second_receiver
+ high_app_output_path=$output_dir/${high_app_output_file}
+ start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1
+ wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
+ wait_for_message $output_dir "${high_app_output_file}" "notification: high 0"
+
+ # Resume consumerd
+ for pipe in "${consumerd_pipe[@]}"; do
+ resume_consumerd "${pipe}"
+ done
+
+ wait_for_message $output_dir "${high_output_file_pattern}" "exit: 0"
+ ret=$?
+ ok $ret "Application for high notification terminated normally"
+ if [[ $ret -ne "0" ]]; then
# Keep the file
print_errors "${high_output_file_pattern}"
fi
- kill -9 $app_pid
- wait $app_pid 2> /dev/null
+ rm -rf $output_dir
+ destroy_lttng_session_ok $SESSION_NAME
stop_lttng_sessiond
+
+ kill -9 $generator_pid
+ wait $generator_pid 2> /dev/null
+
+ for pipe in "${consumerd_pipe[@]}"; do
+ rm -rf "${pipe}"
+ done
+
}
TESTS=(
- test_multi_app
+ test_multi_app_ust
+ test_on_register_evaluation_ust
+)
+
+if [ "$(id -u)" == "0" ]; then
+ TESTS+=(
+ test_multi_app_kernel
+ test_on_register_evaluation_kernel
)
+else
+ skip 0 "Root access is needed. Skipping all kernel multi-app notification tests." $NUM_TEST_KERNEL
+fi
+
for fct_test in ${TESTS[@]};
do
# Only delete if successful
rm -rf $TRACE_PATH
done
-