From nobody Thu Dec 18 08:37:39 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A83F425A352 for ; Tue, 25 Mar 2025 14:34:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742913258; cv=none; b=M/Zv1+NZSKOJjJZkhfVPK1VJzGnfKyCPHcn0oAaDOd1tDz2RBNdgJn/l7UdhiTKbmGKHAJ3Myuf74fxWa6xiefaZtoM4NiTnhlxWuQu9NlUpv6NCBx/ln+/TAyhc3JQWdZDfFCzf6pUD9zoI9IXaawLjYwlfTsTuXaM+WdMW49I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742913258; c=relaxed/simple; bh=op4bZHNgFkTMeMbsYcAkob/xeuuEeaMPRJ0DS4GK3Ac=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=kObcY9ITxywpYBc5J5QNhytAWKlxO2JAz9DpoNwg34KWqxWDpLVVkxVqaZ+pKgfzJjfSOHpVzG/YH6YWLS0uJkGHOPl6aW6x39oVErSor9G9a1TRne2I/1pWuZvgW06I3kLprGwCXm0KwrLmnly4krbvcyt3otaemBwba+fsQq4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 837CAC4AF09; Tue, 25 Mar 2025 14:34:18 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.98) (envelope-from ) id 1tx5Ms-00000002P1L-4066; Tue, 25 Mar 2025 10:35:02 -0400 Message-ID: <20250325143502.803979565@goodmis.org> User-Agent: quilt/0.68 Date: Tue, 25 Mar 2025 10:34:42 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org Cc: Tomas Glozar , John Kacur , Ingo Molnar , Peter Zijlstra , Juri Lelli , Gabriele Monaco Subject: [for-next][PATCH 6/9] tools/rv: Add support for nested monitors References: <20250325143436.168114339@goodmis.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gabriele Monaco RV now supports nested monitors, this functionality requires a container monitor, which has virtually no functionality besides holding other monitors, and nested monitors, that have a container as parent. Nested monitors' sysfs folders are physically nested in the container's folder, and they are listed in the available_monitors file with the notation container:monitor. These changes go against the assumption that each line in the available_monitors file correspond to a folder in the rv directory, breaking the functionality of the rv tool. Add support for nested containers in the rv userspace tool, indenting nested monitors while listed and allowing both the notation with and without container name, which are equivalent: # rv list mon1 mon2 container: - nested1 - nested2 ## notation with container name # rv mon container:nested1 ## notation without container name # rv mon nested1 Either way, enabling a nested monitor is the same as enabling any other non-nested monitor. Selecting the container with rv mon enables all the nested monitors, if -t is passed, the trace also includes the monitor name next to the event: # rv mon nested1 -t -0 [004] event state1 x event -> state2 -0 [004] error event not expected in state2 # rv mon sched -t -0 [004] event_nested1 state1 x event -> state2 -0 [004] error_nested1 event not expected in state2 Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Juri Lelli Link: https://lore.kernel.org/20250305140406.350227-7-gmonaco@redhat.com Signed-off-by: Gabriele Monaco Signed-off-by: Steven Rostedt (Google) --- tools/verification/rv/include/rv.h | 1 + tools/verification/rv/src/in_kernel.c | 226 ++++++++++++++++++++------ 2 files changed, 179 insertions(+), 48 deletions(-) diff --git a/tools/verification/rv/include/rv.h b/tools/verification/rv/inc= lude/rv.h index 0cab1037a98f..6f668eb266cb 100644 --- a/tools/verification/rv/include/rv.h +++ b/tools/verification/rv/include/rv.h @@ -7,6 +7,7 @@ struct monitor { char name[MAX_DA_NAME_LEN]; char desc[MAX_DESCRIPTION]; int enabled; + int nested; }; =20 int should_stop(void); diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/= src/in_kernel.c index f2bbc75a76f4..032b85101929 100644 --- a/tools/verification/rv/src/in_kernel.c +++ b/tools/verification/rv/src/in_kernel.c @@ -6,15 +6,18 @@ */ #include #include +#include #include #include #include +#include =20 #include #include #include =20 static int config_has_id; +static int config_is_container; static int config_my_pid; static int config_trace; =20 @@ -44,6 +47,51 @@ static int __ikm_read_enable(char *monitor_name) return enabled; } =20 +/* + * __ikm_find_monitor - find the full name of a possibly nested module + * + * __does not log errors. + * + * Returns 1 if we found the monitor, -1 on error and 0 if it does not exi= st. + * The string out_name is populated with the full name, which can be + * equal to monitor_name or container/monitor_name if nested + */ +static int __ikm_find_monitor_name(char *monitor_name, char *out_name) +{ + char *available_monitors, container[MAX_DA_NAME_LEN+1], *cursor, *end; + int retval =3D 1; + + available_monitors =3D tracefs_instance_file_read(NULL, "rv/available_mon= itors", NULL); + if (!available_monitors) + return -1; + + cursor =3D strstr(available_monitors, monitor_name); + if (!cursor) { + retval =3D 0; + goto out_free; + } + + for (; cursor > available_monitors; cursor--) + if (*(cursor-1) =3D=3D '\n') + break; + end =3D strstr(cursor, "\n"); + memcpy(out_name, cursor, end-cursor); + out_name[end-cursor] =3D '\0'; + + cursor =3D strstr(out_name, ":"); + if (cursor) + *cursor =3D '/'; + else { + sprintf(container, "%s:", monitor_name); + if (strstr(available_monitors, container)) + config_is_container =3D 1; + } + +out_free: + free(available_monitors); + return retval; +} + /* * ikm_read_enable - reads monitor's enable status * @@ -137,7 +185,17 @@ static char *ikm_read_desc(char *monitor_name) static int ikm_fill_monitor_definition(char *name, struct monitor *ikm) { int enabled; - char *desc; + char *desc, *nested_name; + + nested_name =3D strstr(name, ":"); + if (nested_name) { + *nested_name =3D '/'; + ++nested_name; + ikm->nested =3D 1; + } else { + nested_name =3D name; + ikm->nested =3D 0; + } =20 enabled =3D ikm_read_enable(name); if (enabled < 0) { @@ -151,7 +209,7 @@ static int ikm_fill_monitor_definition(char *name, stru= ct monitor *ikm) return -1; } =20 - strncpy(ikm->name, name, MAX_DA_NAME_LEN); + strncpy(ikm->name, nested_name, MAX_DA_NAME_LEN); ikm->enabled =3D enabled; strncpy(ikm->desc, desc, MAX_DESCRIPTION); =20 @@ -273,7 +331,7 @@ static int ikm_has_id(char *monitor_name) int ikm_list_monitors(void) { char *available_monitors; - struct monitor ikm; + struct monitor ikm =3D {0}; char *curr, *next; int retval; =20 @@ -293,7 +351,9 @@ int ikm_list_monitors(void) if (retval) err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr); =20 - printf("%-24s %s %s\n", ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF= ]"); + printf("%s%-*s %s %s\n", ikm.nested ? " - " : "", + ikm.nested ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN, + ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]"); curr =3D ++next; =20 } while (strlen(curr)); @@ -343,11 +403,11 @@ ikm_event_handler(struct trace_seq *s, struct tep_rec= ord *record, unsigned long long final_state; unsigned long long pid; unsigned long long id; - int cpu =3D record->cpu; int val; + bool missing_id; =20 if (config_has_id) - tep_get_field_val(s, trace_event, "id", record, &id, 1); + missing_id =3D tep_get_field_val(s, trace_event, "id", record, &id, 1); =20 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); =20 @@ -356,12 +416,21 @@ ikm_event_handler(struct trace_seq *s, struct tep_rec= ord *record, else if (config_my_pid && (config_my_pid =3D=3D pid)) return 0; =20 - tep_print_event(trace_event->tep, s, record, "%16s-%-8d ", TEP_PRINT_COMM= , TEP_PRINT_PID); + tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ", + TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU); =20 - trace_seq_printf(s, "[%.3d] event ", cpu); + if (config_is_container) + tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); + else + trace_seq_printf(s, "event "); =20 - if (config_has_id) - trace_seq_printf(s, "%8llu ", id); + if (config_has_id) { + if (missing_id) + /* placeholder if we are dealing with a mixed-type container*/ + trace_seq_printf(s, " "); + else + trace_seq_printf(s, "%8llu ", id); + } =20 state =3D tep_get_field_raw(s, trace_event, "state", record, &val, 0); event =3D tep_get_field_raw(s, trace_event, "event", record, &val, 0); @@ -394,9 +463,10 @@ ikm_error_handler(struct trace_seq *s, struct tep_reco= rd *record, int cpu =3D record->cpu; char *state, *event; int val; + bool missing_id; =20 if (config_has_id) - tep_get_field_val(s, trace_event, "id", record, &id, 1); + missing_id =3D tep_get_field_val(s, trace_event, "id", record, &id, 1); =20 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); =20 @@ -405,10 +475,20 @@ ikm_error_handler(struct trace_seq *s, struct tep_rec= ord *record, else if (config_my_pid =3D=3D pid) return 0; =20 - trace_seq_printf(s, "%8lld [%03d] error ", pid, cpu); + trace_seq_printf(s, "%8lld [%03d] ", pid, cpu); =20 - if (config_has_id) - trace_seq_printf(s, "%8llu ", id); + if (config_is_container) + tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); + else + trace_seq_printf(s, "error "); + + if (config_has_id) { + if (missing_id) + /* placeholder if we are dealing with a mixed-type container*/ + trace_seq_printf(s, " "); + else + trace_seq_printf(s, "%8llu ", id); + } =20 state =3D tep_get_field_raw(s, trace_event, "state", record, &val, 0); event =3D tep_get_field_raw(s, trace_event, "event", record, &val, 0); @@ -421,6 +501,64 @@ ikm_error_handler(struct trace_seq *s, struct tep_reco= rd *record, return 0; } =20 +static int ikm_enable_trace_events(char *monitor_name, struct trace_instan= ce *inst) +{ + char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' =3D 7 */ + int retval; + + snprintf(event, sizeof(event), "event_%s", monitor_name); + retval =3D tracefs_event_enable(inst->inst, "rv", event); + if (retval) + return -1; + + tep_register_event_handler(inst->tep, -1, "rv", event, + ikm_event_handler, NULL); + + snprintf(event, sizeof(event), "error_%s", monitor_name); + retval =3D tracefs_event_enable(inst->inst, "rv", event); + if (retval) + return -1; + + tep_register_event_handler(inst->tep, -1, "rv", event, + ikm_error_handler, NULL); + + /* set if at least 1 monitor has id in case of a container */ + config_has_id =3D ikm_has_id(monitor_name); + if (config_has_id < 0) + return -1; + + + return 0; +} + +static int ikm_enable_trace_container(char *monitor_name, + struct trace_instance *inst) +{ + DIR *dp; + char *abs_path, rv_path[MAX_PATH]; + struct dirent *ep; + int retval =3D 0; + + snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name); + abs_path =3D tracefs_instance_get_file(NULL, rv_path); + if (!abs_path) + return -1; + dp =3D opendir(abs_path); + if (!dp) + goto out_free; + + while (!retval && (ep =3D readdir(dp))) { + if (ep->d_type !=3D DT_DIR || ep->d_name[0] =3D=3D '.') + continue; + retval =3D ikm_enable_trace_events(ep->d_name, inst); + } + + closedir(dp); +out_free: + free(abs_path); + return retval; +} + /* * ikm_setup_trace_instance - set up a tracing instance to collect data * @@ -430,19 +568,12 @@ ikm_error_handler(struct trace_seq *s, struct tep_rec= ord *record, */ static struct trace_instance *ikm_setup_trace_instance(char *monitor_name) { - char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' =3D 7 */ struct trace_instance *inst; int retval; =20 if (!config_trace) return NULL; =20 - config_has_id =3D ikm_has_id(monitor_name); - if (config_has_id < 0) { - err_msg("ikm: failed to read monitor %s event format\n", monitor_name); - goto out_err; - } - /* alloc data */ inst =3D calloc(1, sizeof(*inst)); if (!inst) { @@ -454,23 +585,13 @@ static struct trace_instance *ikm_setup_trace_instanc= e(char *monitor_name) if (retval) goto out_free; =20 - /* enable events */ - snprintf(event, sizeof(event), "event_%s", monitor_name); - retval =3D tracefs_event_enable(inst->inst, "rv", event); - if (retval) - goto out_inst; - - tep_register_event_handler(inst->tep, -1, "rv", event, - ikm_event_handler, NULL); - - snprintf(event, sizeof(event), "error_%s", monitor_name); - retval =3D tracefs_event_enable(inst->inst, "rv", event); + if (config_is_container) + retval =3D ikm_enable_trace_container(monitor_name, inst); + else + retval =3D ikm_enable_trace_events(monitor_name, inst); if (retval) goto out_inst; =20 - tep_register_event_handler(inst->tep, -1, "rv", event, - ikm_error_handler, NULL); - /* ready to enable */ tracefs_trace_on(inst->inst); =20 @@ -633,32 +754,41 @@ static int parse_arguments(char *monitor_name, int ar= gc, char **argv) int ikm_run_monitor(char *monitor_name, int argc, char **argv) { struct trace_instance *inst =3D NULL; + char *nested_name, full_name[2*MAX_DA_NAME_LEN]; int retval; =20 - /* - * Check if monitor exists by seeing it is enabled. - */ - retval =3D __ikm_read_enable(monitor_name); - if (retval < 0) + nested_name =3D strstr(monitor_name, ":"); + if (nested_name) + ++nested_name; + else + nested_name =3D monitor_name; + + retval =3D __ikm_find_monitor_name(monitor_name, full_name); + if (!retval) return 0; + if (retval < 0) { + err_msg("ikm: error finding monitor %s\n", nested_name); + return -1; + } =20 + retval =3D __ikm_read_enable(full_name); if (retval) { - err_msg("ikm: monitor %s (in-kernel) is already enabled\n", monitor_name= ); + err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name); return -1; } =20 /* we should be good to go */ - retval =3D parse_arguments(monitor_name, argc, argv); + retval =3D parse_arguments(full_name, argc, argv); if (retval) - ikm_usage(1, monitor_name, "ikm: failed parsing arguments"); + ikm_usage(1, nested_name, "ikm: failed parsing arguments"); =20 if (config_trace) { - inst =3D ikm_setup_trace_instance(monitor_name); + inst =3D ikm_setup_trace_instance(nested_name); if (!inst) return -1; } =20 - retval =3D ikm_enable(monitor_name); + retval =3D ikm_enable(full_name); if (retval < 0) goto out_free_instance; =20 @@ -682,17 +812,17 @@ int ikm_run_monitor(char *monitor_name, int argc, cha= r **argv) sleep(1); } =20 - ikm_disable(monitor_name); + ikm_disable(full_name); ikm_destroy_trace_instance(inst); =20 if (config_reactor && config_initial_reactor) - ikm_write_reactor(monitor_name, config_initial_reactor); + ikm_write_reactor(full_name, config_initial_reactor); =20 return 1; =20 out_free_instance: ikm_destroy_trace_instance(inst); if (config_reactor && config_initial_reactor) - ikm_write_reactor(monitor_name, config_initial_reactor); + ikm_write_reactor(full_name, config_initial_reactor); return -1; } --=20 2.47.2