Updates to Real Time Linux Analysis tool for 5.19:

Various clean ups and fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCYpOnTBQccm9zdGVkdEBn
 b29kbWlzLm9yZwAKCRAp5XQQmuv6qmJSAP9f6esP4RxZjNefiu6bLD43FMml9V2T
 OLA+EZ9SIn21PgD+JGZ8kXNojDR8ZDa7j3j+7y5nzAj1x6jh8sdDUslryQI=
 =vG72
 -----END PGP SIGNATURE-----

Merge tag 'trace-tools-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing tool updates from Steven Rostedt:

 - Various clean ups and fixes to rtla (Real Time Linux Analysis)

* tag 'trace-tools-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  rtla: Remove procps-ng dependency
  rtla: Fix __set_sched_attr error message
  rtla: Minor grammar fix for rtla README
  rtla: Don't overwrite existing directory mode
  rtla: Avoid record NULL pointer dereference
  rtla/Makefile: Properly handle dependencies
This commit is contained in:
Linus Torvalds 2022-05-29 10:48:58 -07:00
commit c3a9a3c5f5
9 changed files with 165 additions and 51 deletions

View File

@ -17,9 +17,21 @@ DOC_MAN1 = $(addprefix $(OUTPUT),$(_DOC_MAN1))
RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null)
RST2MAN_OPTS += --verbose
TEST_RST2MAN = $(shell sh -c "rst2man --version > /dev/null 2>&1 || echo n")
$(OUTPUT)%.1: %.rst
ifndef RST2MAN_DEP
$(error "rst2man not found, but required to generate man pages")
$(info ********************************************)
$(info ** NOTICE: rst2man not found)
$(info **)
$(info ** Consider installing the latest rst2man from your)
$(info ** distribution, e.g., 'dnf install python3-docutils' on Fedora,)
$(info ** or from source:)
$(info **)
$(info ** https://docutils.sourceforge.io/docs/dev/repository.html )
$(info **)
$(info ********************************************)
$(error NOTICE: rst2man required to generate man pages)
endif
rst2man $(RST2MAN_OPTS) $< > $@

View File

@ -23,6 +23,7 @@ $(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
$(call allow-override,LDCONFIG,ldconfig)
INSTALL = install
MKDIR = mkdir
FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
-fasynchronous-unwind-tables -fstack-clash-protection
WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
@ -31,7 +32,7 @@ TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs)
CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS)
LDFLAGS := -ggdb
LIBS := $$($(PKG_CONFIG) --libs libtracefs) -lprocps
LIBS := $$($(PKG_CONFIG) --libs libtracefs)
SRC := $(wildcard src/*.c)
HDR := $(wildcard src/*.h)
@ -57,6 +58,41 @@ else
DOCSRC = $(SRCTREE)/../../../Documentation/tools/rtla/
endif
LIBTRACEEVENT_MIN_VERSION = 1.5
LIBTRACEFS_MIN_VERSION = 1.3
TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n")
ifeq ("$(TEST_LIBTRACEEVENT)", "n")
.PHONY: warning_traceevent
warning_traceevent:
@echo "********************************************"
@echo "** NOTICE: libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher not found"
@echo "**"
@echo "** Consider installing the latest libtraceevent from your"
@echo "** distribution, e.g., 'dnf install libtraceevent' on Fedora,"
@echo "** or from source:"
@echo "**"
@echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ "
@echo "**"
@echo "********************************************"
endif
TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n")
ifeq ("$(TEST_LIBTRACEFS)", "n")
.PHONY: warning_tracefs
warning_tracefs:
@echo "********************************************"
@echo "** NOTICE: libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher not found"
@echo "**"
@echo "** Consider installing the latest libtracefs from your"
@echo "** distribution, e.g., 'dnf install libtracefs' on Fedora,"
@echo "** or from source:"
@echo "**"
@echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ "
@echo "**"
@echo "********************************************"
endif
.PHONY: all
all: rtla
@ -68,7 +104,7 @@ static: $(OBJ)
.PHONY: install
install: doc_install
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
$(MKDIR) -p $(DESTDIR)$(BINDIR)
$(INSTALL) rtla -m 755 $(DESTDIR)$(BINDIR)
$(STRIP) $(DESTDIR)$(BINDIR)/rtla
@test ! -f $(DESTDIR)$(BINDIR)/osnoise || rm $(DESTDIR)$(BINDIR)/osnoise

View File

@ -1,19 +1,16 @@
RTLA: Real-Time Linux Analysis tools
The rtla is a meta-tool that includes a set of commands that
aims to analyze the real-time properties of Linux. But, instead of
testing Linux as a black box, rtla leverages kernel tracing
capabilities to provide precise information about the properties
and root causes of unexpected results.
The rtla meta-tool includes a set of commands that aims to analyze
the real-time properties of Linux. Instead of testing Linux as a black box,
rtla leverages kernel tracing capabilities to provide precise information
about the properties and root causes of unexpected results.
Installing RTLA
RTLA depends on some libraries and tools. More precisely, it depends on the
following libraries:
RTLA depends on the following libraries and tools:
- libtracefs
- libtraceevent
- procps
It also depends on python3-docutils to compile man pages.

View File

@ -809,7 +809,7 @@ int osnoise_hist_main(int argc, char *argv[])
retval = set_comm_sched_attr("osnoise/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
goto out_hist;
goto out_free;
}
}
@ -819,7 +819,7 @@ int osnoise_hist_main(int argc, char *argv[])
record = osnoise_init_trace_tool("osnoise");
if (!record) {
err_msg("Failed to enable the trace instance\n");
goto out_hist;
goto out_free;
}
if (params->events) {
@ -869,6 +869,7 @@ int osnoise_hist_main(int argc, char *argv[])
out_hist:
trace_events_destroy(&record->trace, params->events);
params->events = NULL;
out_free:
osnoise_free_histogram(tool->data);
out_destroy:
osnoise_destroy_tool(record);

View File

@ -572,7 +572,7 @@ int osnoise_top_main(int argc, char **argv)
retval = osnoise_top_apply_config(tool, params);
if (retval) {
err_msg("Could not apply config\n");
goto out_top;
goto out_free;
}
trace = &tool->trace;
@ -580,14 +580,14 @@ int osnoise_top_main(int argc, char **argv)
retval = enable_osnoise(trace);
if (retval) {
err_msg("Failed to enable osnoise tracer\n");
goto out_top;
goto out_free;
}
if (params->set_sched) {
retval = set_comm_sched_attr("osnoise/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
goto out_top;
goto out_free;
}
}
@ -597,7 +597,7 @@ int osnoise_top_main(int argc, char **argv)
record = osnoise_init_trace_tool("osnoise");
if (!record) {
err_msg("Failed to enable the trace instance\n");
goto out_top;
goto out_free;
}
if (params->events) {
@ -649,6 +649,7 @@ int osnoise_top_main(int argc, char **argv)
out_top:
trace_events_destroy(&record->trace, params->events);
params->events = NULL;
out_free:
osnoise_free_top(tool->data);
osnoise_destroy_tool(record);
osnoise_destroy_tool(tool);

View File

@ -821,7 +821,7 @@ int timerlat_hist_main(int argc, char *argv[])
retval = timerlat_hist_apply_config(tool, params);
if (retval) {
err_msg("Could not apply config\n");
goto out_hist;
goto out_free;
}
trace = &tool->trace;
@ -829,14 +829,14 @@ int timerlat_hist_main(int argc, char *argv[])
retval = enable_timerlat(trace);
if (retval) {
err_msg("Failed to enable timerlat tracer\n");
goto out_hist;
goto out_free;
}
if (params->set_sched) {
retval = set_comm_sched_attr("timerlat/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
goto out_hist;
goto out_free;
}
}
@ -844,7 +844,7 @@ int timerlat_hist_main(int argc, char *argv[])
dma_latency_fd = set_cpu_dma_latency(params->dma_latency);
if (dma_latency_fd < 0) {
err_msg("Could not set /dev/cpu_dma_latency.\n");
goto out_hist;
goto out_free;
}
}
@ -854,7 +854,7 @@ int timerlat_hist_main(int argc, char *argv[])
record = osnoise_init_trace_tool("timerlat");
if (!record) {
err_msg("Failed to enable the trace instance\n");
goto out_hist;
goto out_free;
}
if (params->events) {
@ -904,6 +904,7 @@ int timerlat_hist_main(int argc, char *argv[])
close(dma_latency_fd);
trace_events_destroy(&record->trace, params->events);
params->events = NULL;
out_free:
timerlat_free_histogram(tool->data);
osnoise_destroy_tool(record);
osnoise_destroy_tool(tool);

View File

@ -612,7 +612,7 @@ int timerlat_top_main(int argc, char *argv[])
retval = timerlat_top_apply_config(top, params);
if (retval) {
err_msg("Could not apply config\n");
goto out_top;
goto out_free;
}
trace = &top->trace;
@ -620,14 +620,14 @@ int timerlat_top_main(int argc, char *argv[])
retval = enable_timerlat(trace);
if (retval) {
err_msg("Failed to enable timerlat tracer\n");
goto out_top;
goto out_free;
}
if (params->set_sched) {
retval = set_comm_sched_attr("timerlat/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
goto out_top;
goto out_free;
}
}
@ -635,7 +635,7 @@ int timerlat_top_main(int argc, char *argv[])
dma_latency_fd = set_cpu_dma_latency(params->dma_latency);
if (dma_latency_fd < 0) {
err_msg("Could not set /dev/cpu_dma_latency.\n");
goto out_top;
goto out_free;
}
}
@ -645,7 +645,7 @@ int timerlat_top_main(int argc, char *argv[])
record = osnoise_init_trace_tool("timerlat");
if (!record) {
err_msg("Failed to enable the trace instance\n");
goto out_top;
goto out_free;
}
if (params->events) {
@ -699,6 +699,7 @@ int timerlat_top_main(int argc, char *argv[])
close(dma_latency_fd);
trace_events_destroy(&record->trace, params->events);
params->events = NULL;
out_free:
timerlat_free_top(top->data);
osnoise_destroy_tool(record);
osnoise_destroy_tool(top);

View File

@ -3,7 +3,7 @@
* Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
*/
#include <proc/readproc.h>
#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@ -255,50 +255,114 @@ int __set_sched_attr(int pid, struct sched_attr *attr)
retval = sched_setattr(pid, attr, flags);
if (retval < 0) {
err_msg("boost_with_deadline failed to boost pid %d: %s\n",
err_msg("Failed to set sched attributes to the pid %d: %s\n",
pid, strerror(errno));
return 1;
}
return 0;
}
/*
* set_comm_sched_attr - set sched params to threads starting with char *comm
* procfs_is_workload_pid - check if a procfs entry contains a comm_prefix* comm
*
* This function uses procps to list the currently running threads and then
* set the sched_attr *attr to the threads that start with char *comm. It is
* Check if the procfs entry is a directory of a process, and then check if the
* process has a comm with the prefix set in char *comm_prefix. As the
* current users of this function only check for kernel threads, there is no
* need to check for the threads for the process.
*
* Return: True if the proc_entry contains a comm file with comm_prefix*.
* Otherwise returns false.
*/
static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_entry)
{
char buffer[MAX_PATH];
int comm_fd, retval;
char *t_name;
if (proc_entry->d_type != DT_DIR)
return 0;
if (*proc_entry->d_name == '.')
return 0;
/* check if the string is a pid */
for (t_name = proc_entry->d_name; t_name; t_name++) {
if (!isdigit(*t_name))
break;
}
if (*t_name != '\0')
return 0;
snprintf(buffer, MAX_PATH, "/proc/%s/comm", proc_entry->d_name);
comm_fd = open(buffer, O_RDONLY);
if (comm_fd < 0)
return 0;
memset(buffer, 0, MAX_PATH);
retval = read(comm_fd, buffer, MAX_PATH);
close(comm_fd);
if (retval <= 0)
return 0;
retval = strncmp(comm_prefix, buffer, strlen(comm_prefix));
if (retval)
return 0;
/* comm already have \n */
debug_msg("Found workload pid:%s comm:%s", proc_entry->d_name, buffer);
return 1;
}
/*
* set_comm_sched_attr - set sched params to threads starting with char *comm_prefix
*
* This function uses procfs to list the currently running threads and then set the
* sched_attr *attr to the threads that start with char *comm_prefix. It is
* mainly used to set the priority to the kernel threads created by the
* tracers.
*/
int set_comm_sched_attr(const char *comm, struct sched_attr *attr)
int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr)
{
int flags = PROC_FILLCOM | PROC_FILLSTAT;
PROCTAB *ptp;
proc_t task;
struct dirent *proc_entry;
DIR *procfs;
int retval;
ptp = openproc(flags);
if (!ptp) {
err_msg("error openproc()\n");
return -ENOENT;
if (strlen(comm_prefix) >= MAX_PATH) {
err_msg("Command prefix is too long: %d < strlen(%s)\n",
MAX_PATH, comm_prefix);
return 1;
}
memset(&task, 0, sizeof(task));
procfs = opendir("/proc");
if (!procfs) {
err_msg("Could not open procfs\n");
return 1;
}
while (readproc(ptp, &task)) {
retval = strncmp(comm, task.cmd, strlen(comm));
if (retval)
while ((proc_entry = readdir(procfs))) {
retval = procfs_is_workload_pid(comm_prefix, proc_entry);
if (!retval)
continue;
retval = __set_sched_attr(task.tid, attr);
if (retval)
goto out_err;
}
closeproc(ptp);
/* procfs_is_workload_pid confirmed it is a pid */
retval = __set_sched_attr(atoi(proc_entry->d_name), attr);
if (retval) {
err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name);
goto out_err;
}
debug_msg("Set sched attributes for pid:%s\n", proc_entry->d_name);
}
return 0;
out_err:
closeproc(ptp);
closedir(procfs);
return 1;
}

View File

@ -6,6 +6,7 @@
* '18446744073709551615\0'
*/
#define BUFF_U64_STR_SIZE 24
#define MAX_PATH 1024
#define container_of(ptr, type, member)({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
@ -53,5 +54,5 @@ struct sched_attr {
};
int parse_prio(char *arg, struct sched_attr *sched_param);
int set_comm_sched_attr(const char *comm, struct sched_attr *attr);
int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
int set_cpu_dma_latency(int32_t latency);