Skip to content

Commit eba321a

Browse files
glemcorostedt
authored andcommitted
tools/rv: Add support for nested monitors
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 <idle>-0 [004] event state1 x event -> state2 <idle>-0 [004] error event not expected in state2 # rv mon sched -t <idle>-0 [004] event_nested1 state1 x event -> state2 <idle>-0 [004] error_nested1 event not expected in state2 Cc: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Juri Lelli <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Gabriele Monaco <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent fbe6c09 commit eba321a

File tree

2 files changed

+179
-48
lines changed

2 files changed

+179
-48
lines changed

tools/verification/rv/include/rv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct monitor {
77
char name[MAX_DA_NAME_LEN];
88
char desc[MAX_DESCRIPTION];
99
int enabled;
10+
int nested;
1011
};
1112

1213
int should_stop(void);

tools/verification/rv/src/in_kernel.c

Lines changed: 178 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
*/
77
#include <getopt.h>
88
#include <stdlib.h>
9+
#include <stdio.h>
910
#include <string.h>
1011
#include <errno.h>
1112
#include <unistd.h>
13+
#include <dirent.h>
1214

1315
#include <trace.h>
1416
#include <utils.h>
1517
#include <rv.h>
1618

1719
static int config_has_id;
20+
static int config_is_container;
1821
static int config_my_pid;
1922
static int config_trace;
2023

@@ -44,6 +47,51 @@ static int __ikm_read_enable(char *monitor_name)
4447
return enabled;
4548
}
4649

50+
/*
51+
* __ikm_find_monitor - find the full name of a possibly nested module
52+
*
53+
* __does not log errors.
54+
*
55+
* Returns 1 if we found the monitor, -1 on error and 0 if it does not exist.
56+
* The string out_name is populated with the full name, which can be
57+
* equal to monitor_name or container/monitor_name if nested
58+
*/
59+
static int __ikm_find_monitor_name(char *monitor_name, char *out_name)
60+
{
61+
char *available_monitors, container[MAX_DA_NAME_LEN+1], *cursor, *end;
62+
int retval = 1;
63+
64+
available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL);
65+
if (!available_monitors)
66+
return -1;
67+
68+
cursor = strstr(available_monitors, monitor_name);
69+
if (!cursor) {
70+
retval = 0;
71+
goto out_free;
72+
}
73+
74+
for (; cursor > available_monitors; cursor--)
75+
if (*(cursor-1) == '\n')
76+
break;
77+
end = strstr(cursor, "\n");
78+
memcpy(out_name, cursor, end-cursor);
79+
out_name[end-cursor] = '\0';
80+
81+
cursor = strstr(out_name, ":");
82+
if (cursor)
83+
*cursor = '/';
84+
else {
85+
sprintf(container, "%s:", monitor_name);
86+
if (strstr(available_monitors, container))
87+
config_is_container = 1;
88+
}
89+
90+
out_free:
91+
free(available_monitors);
92+
return retval;
93+
}
94+
4795
/*
4896
* ikm_read_enable - reads monitor's enable status
4997
*
@@ -137,7 +185,17 @@ static char *ikm_read_desc(char *monitor_name)
137185
static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
138186
{
139187
int enabled;
140-
char *desc;
188+
char *desc, *nested_name;
189+
190+
nested_name = strstr(name, ":");
191+
if (nested_name) {
192+
*nested_name = '/';
193+
++nested_name;
194+
ikm->nested = 1;
195+
} else {
196+
nested_name = name;
197+
ikm->nested = 0;
198+
}
141199

142200
enabled = ikm_read_enable(name);
143201
if (enabled < 0) {
@@ -151,7 +209,7 @@ static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
151209
return -1;
152210
}
153211

154-
strncpy(ikm->name, name, MAX_DA_NAME_LEN);
212+
strncpy(ikm->name, nested_name, MAX_DA_NAME_LEN);
155213
ikm->enabled = enabled;
156214
strncpy(ikm->desc, desc, MAX_DESCRIPTION);
157215

@@ -273,7 +331,7 @@ static int ikm_has_id(char *monitor_name)
273331
int ikm_list_monitors(void)
274332
{
275333
char *available_monitors;
276-
struct monitor ikm;
334+
struct monitor ikm = {0};
277335
char *curr, *next;
278336
int retval;
279337

@@ -293,7 +351,9 @@ int ikm_list_monitors(void)
293351
if (retval)
294352
err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr);
295353

296-
printf("%-24s %s %s\n", ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
354+
printf("%s%-*s %s %s\n", ikm.nested ? " - " : "",
355+
ikm.nested ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN,
356+
ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
297357
curr = ++next;
298358

299359
} while (strlen(curr));
@@ -343,11 +403,11 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
343403
unsigned long long final_state;
344404
unsigned long long pid;
345405
unsigned long long id;
346-
int cpu = record->cpu;
347406
int val;
407+
bool missing_id;
348408

349409
if (config_has_id)
350-
tep_get_field_val(s, trace_event, "id", record, &id, 1);
410+
missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1);
351411

352412
tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
353413

@@ -356,12 +416,21 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
356416
else if (config_my_pid && (config_my_pid == pid))
357417
return 0;
358418

359-
tep_print_event(trace_event->tep, s, record, "%16s-%-8d ", TEP_PRINT_COMM, TEP_PRINT_PID);
419+
tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ",
420+
TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU);
360421

361-
trace_seq_printf(s, "[%.3d] event ", cpu);
422+
if (config_is_container)
423+
tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME);
424+
else
425+
trace_seq_printf(s, "event ");
362426

363-
if (config_has_id)
364-
trace_seq_printf(s, "%8llu ", id);
427+
if (config_has_id) {
428+
if (missing_id)
429+
/* placeholder if we are dealing with a mixed-type container*/
430+
trace_seq_printf(s, " ");
431+
else
432+
trace_seq_printf(s, "%8llu ", id);
433+
}
365434

366435
state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
367436
event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
@@ -394,9 +463,10 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
394463
int cpu = record->cpu;
395464
char *state, *event;
396465
int val;
466+
bool missing_id;
397467

398468
if (config_has_id)
399-
tep_get_field_val(s, trace_event, "id", record, &id, 1);
469+
missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1);
400470

401471
tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
402472

@@ -405,10 +475,20 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
405475
else if (config_my_pid == pid)
406476
return 0;
407477

408-
trace_seq_printf(s, "%8lld [%03d] error ", pid, cpu);
478+
trace_seq_printf(s, "%8lld [%03d] ", pid, cpu);
409479

410-
if (config_has_id)
411-
trace_seq_printf(s, "%8llu ", id);
480+
if (config_is_container)
481+
tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME);
482+
else
483+
trace_seq_printf(s, "error ");
484+
485+
if (config_has_id) {
486+
if (missing_id)
487+
/* placeholder if we are dealing with a mixed-type container*/
488+
trace_seq_printf(s, " ");
489+
else
490+
trace_seq_printf(s, "%8llu ", id);
491+
}
412492

413493
state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
414494
event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
@@ -421,6 +501,64 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
421501
return 0;
422502
}
423503

504+
static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst)
505+
{
506+
char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
507+
int retval;
508+
509+
snprintf(event, sizeof(event), "event_%s", monitor_name);
510+
retval = tracefs_event_enable(inst->inst, "rv", event);
511+
if (retval)
512+
return -1;
513+
514+
tep_register_event_handler(inst->tep, -1, "rv", event,
515+
ikm_event_handler, NULL);
516+
517+
snprintf(event, sizeof(event), "error_%s", monitor_name);
518+
retval = tracefs_event_enable(inst->inst, "rv", event);
519+
if (retval)
520+
return -1;
521+
522+
tep_register_event_handler(inst->tep, -1, "rv", event,
523+
ikm_error_handler, NULL);
524+
525+
/* set if at least 1 monitor has id in case of a container */
526+
config_has_id = ikm_has_id(monitor_name);
527+
if (config_has_id < 0)
528+
return -1;
529+
530+
531+
return 0;
532+
}
533+
534+
static int ikm_enable_trace_container(char *monitor_name,
535+
struct trace_instance *inst)
536+
{
537+
DIR *dp;
538+
char *abs_path, rv_path[MAX_PATH];
539+
struct dirent *ep;
540+
int retval = 0;
541+
542+
snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name);
543+
abs_path = tracefs_instance_get_file(NULL, rv_path);
544+
if (!abs_path)
545+
return -1;
546+
dp = opendir(abs_path);
547+
if (!dp)
548+
goto out_free;
549+
550+
while (!retval && (ep = readdir(dp))) {
551+
if (ep->d_type != DT_DIR || ep->d_name[0] == '.')
552+
continue;
553+
retval = ikm_enable_trace_events(ep->d_name, inst);
554+
}
555+
556+
closedir(dp);
557+
out_free:
558+
free(abs_path);
559+
return retval;
560+
}
561+
424562
/*
425563
* ikm_setup_trace_instance - set up a tracing instance to collect data
426564
*
@@ -430,19 +568,12 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
430568
*/
431569
static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
432570
{
433-
char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
434571
struct trace_instance *inst;
435572
int retval;
436573

437574
if (!config_trace)
438575
return NULL;
439576

440-
config_has_id = ikm_has_id(monitor_name);
441-
if (config_has_id < 0) {
442-
err_msg("ikm: failed to read monitor %s event format\n", monitor_name);
443-
goto out_err;
444-
}
445-
446577
/* alloc data */
447578
inst = calloc(1, sizeof(*inst));
448579
if (!inst) {
@@ -454,23 +585,13 @@ static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
454585
if (retval)
455586
goto out_free;
456587

457-
/* enable events */
458-
snprintf(event, sizeof(event), "event_%s", monitor_name);
459-
retval = tracefs_event_enable(inst->inst, "rv", event);
460-
if (retval)
461-
goto out_inst;
462-
463-
tep_register_event_handler(inst->tep, -1, "rv", event,
464-
ikm_event_handler, NULL);
465-
466-
snprintf(event, sizeof(event), "error_%s", monitor_name);
467-
retval = tracefs_event_enable(inst->inst, "rv", event);
588+
if (config_is_container)
589+
retval = ikm_enable_trace_container(monitor_name, inst);
590+
else
591+
retval = ikm_enable_trace_events(monitor_name, inst);
468592
if (retval)
469593
goto out_inst;
470594

471-
tep_register_event_handler(inst->tep, -1, "rv", event,
472-
ikm_error_handler, NULL);
473-
474595
/* ready to enable */
475596
tracefs_trace_on(inst->inst);
476597

@@ -633,32 +754,41 @@ static int parse_arguments(char *monitor_name, int argc, char **argv)
633754
int ikm_run_monitor(char *monitor_name, int argc, char **argv)
634755
{
635756
struct trace_instance *inst = NULL;
757+
char *nested_name, full_name[2*MAX_DA_NAME_LEN];
636758
int retval;
637759

638-
/*
639-
* Check if monitor exists by seeing it is enabled.
640-
*/
641-
retval = __ikm_read_enable(monitor_name);
642-
if (retval < 0)
760+
nested_name = strstr(monitor_name, ":");
761+
if (nested_name)
762+
++nested_name;
763+
else
764+
nested_name = monitor_name;
765+
766+
retval = __ikm_find_monitor_name(monitor_name, full_name);
767+
if (!retval)
643768
return 0;
769+
if (retval < 0) {
770+
err_msg("ikm: error finding monitor %s\n", nested_name);
771+
return -1;
772+
}
644773

774+
retval = __ikm_read_enable(full_name);
645775
if (retval) {
646-
err_msg("ikm: monitor %s (in-kernel) is already enabled\n", monitor_name);
776+
err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name);
647777
return -1;
648778
}
649779

650780
/* we should be good to go */
651-
retval = parse_arguments(monitor_name, argc, argv);
781+
retval = parse_arguments(full_name, argc, argv);
652782
if (retval)
653-
ikm_usage(1, monitor_name, "ikm: failed parsing arguments");
783+
ikm_usage(1, nested_name, "ikm: failed parsing arguments");
654784

655785
if (config_trace) {
656-
inst = ikm_setup_trace_instance(monitor_name);
786+
inst = ikm_setup_trace_instance(nested_name);
657787
if (!inst)
658788
return -1;
659789
}
660790

661-
retval = ikm_enable(monitor_name);
791+
retval = ikm_enable(full_name);
662792
if (retval < 0)
663793
goto out_free_instance;
664794

@@ -682,17 +812,17 @@ int ikm_run_monitor(char *monitor_name, int argc, char **argv)
682812
sleep(1);
683813
}
684814

685-
ikm_disable(monitor_name);
815+
ikm_disable(full_name);
686816
ikm_destroy_trace_instance(inst);
687817

688818
if (config_reactor && config_initial_reactor)
689-
ikm_write_reactor(monitor_name, config_initial_reactor);
819+
ikm_write_reactor(full_name, config_initial_reactor);
690820

691821
return 1;
692822

693823
out_free_instance:
694824
ikm_destroy_trace_instance(inst);
695825
if (config_reactor && config_initial_reactor)
696-
ikm_write_reactor(monitor_name, config_initial_reactor);
826+
ikm_write_reactor(full_name, config_initial_reactor);
697827
return -1;
698828
}

0 commit comments

Comments
 (0)