* [PATCH 0/3] Introduce new API to reset ftrace instance
@ 2023-03-28 15:03 Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 1/3] libtracefs: New " Tzvetomir Stoyanov (VMware)
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2023-03-28 15:03 UTC (permalink / raw)
To: rostedt; +Cc: linux-trace-devel
A new API tracefs_instance_reset() for resetting instance to its default
state, based on the logic from "trace-cmd reset" command.
Tzvetomir Stoyanov (VMware) (3):
libtracefs: New API to reset ftrace instance
libtracefs: Documentation for tracefs_instance_reset()
libtracefs: Unit test for tracefs_instance_reset()
Documentation/libtracefs-instances-manage.txt | 7 +-
Documentation/libtracefs.txt | 1 +
include/tracefs-local.h | 1 +
include/tracefs.h | 1 +
src/tracefs-instance.c | 196 ++++++++++++++++++
src/tracefs-utils.c | 20 ++
utest/tracefs-utest.c | 183 ++++++++++++++++
7 files changed, 407 insertions(+), 2 deletions(-)
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/3] libtracefs: New API to reset ftrace instance
2023-03-28 15:03 [PATCH 0/3] Introduce new API to reset ftrace instance Tzvetomir Stoyanov (VMware)
@ 2023-03-28 15:03 ` Tzvetomir Stoyanov (VMware)
2023-04-24 19:42 ` Steven Rostedt
2023-03-28 15:03 ` [PATCH 2/3] libtracefs: Documentation for tracefs_instance_reset() Tzvetomir Stoyanov (VMware)
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2023-03-28 15:03 UTC (permalink / raw)
To: rostedt; +Cc: linux-trace-devel
Resetting a ftrace instance to its default state is not a trivial task.
A lot of trace files have to be modified, with different syntaxes and
in strict order. Although there is such functionality in "trace-cmd
reset" command, it will be good to have it in the tracefs library as
well.
A new API tracefs_instance_reset() is introduced, which resets given
ftrace instance to its default state. The logic and most of the helper
functions from "trace-cmd reset" command are copied in the tracefs
library.
Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
include/tracefs-local.h | 1 +
include/tracefs.h | 1 +
src/tracefs-instance.c | 196 ++++++++++++++++++++++++++++++++++++++++
src/tracefs-utils.c | 20 ++++
4 files changed, 218 insertions(+)
diff --git a/include/tracefs-local.h b/include/tracefs-local.h
index 2007d26..da99a30 100644
--- a/include/tracefs-local.h
+++ b/include/tracefs-local.h
@@ -64,6 +64,7 @@ int trace_get_instance(struct tracefs_instance *instance);
/* Can be overridden */
void tracefs_warning(const char *fmt, ...);
+char *strstrip(char *str);
int str_read_file(const char *file, char **buffer, bool warn);
char *trace_append_file(const char *dir, const char *name);
char *trace_find_tracing_dir(bool debugfs);
diff --git a/include/tracefs.h b/include/tracefs.h
index 3547b5a..5e9d84b 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -23,6 +23,7 @@ int tracefs_tracing_dir_is_mounted(bool mount, const char **path);
struct tracefs_instance;
void tracefs_instance_free(struct tracefs_instance *instance);
+void tracefs_instance_reset(struct tracefs_instance *instance);
struct tracefs_instance *tracefs_instance_create(const char *name);
struct tracefs_instance *tracefs_instance_alloc(const char *tracing_dir,
const char *name);
diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c
index 57f5c7f..d3c6581 100644
--- a/src/tracefs-instance.c
+++ b/src/tracefs-instance.c
@@ -1239,3 +1239,199 @@ char *tracefs_instance_get_affinity(struct tracefs_instance *instance)
return set;
}
+
+static int clear_trigger(const char *file)
+{
+ char trigger[BUFSIZ];
+ char *save = NULL;
+ char *line;
+ char *buf;
+ int size;
+ int len;
+ int ret;
+
+ size = str_read_file(file, &buf, true);
+ if (size < 1)
+ return 0;
+
+ trigger[0] = '!';
+
+ for (line = strtok_r(buf, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) {
+ if (line[0] == '#')
+ continue;
+ len = strlen(line);
+ if (len > BUFSIZ - 2)
+ len = BUFSIZ - 2;
+ strncpy(trigger + 1, line, len);
+ trigger[len + 1] = '\0';
+ /* We don't want any filters or extra on the line */
+ strtok(trigger, " ");
+ write_file(file, trigger, O_WRONLY);
+ }
+
+ free(buf);
+
+ /*
+ * Some triggers have an order in removing them.
+ * They will not be removed if done in the wrong order.
+ */
+ size = str_read_file(file, &buf, true);
+ if (size < 1)
+ return 0;
+
+ ret = 0;
+ for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
+ if (line[0] == '#')
+ continue;
+ ret = 1;
+ break;
+ }
+ free(buf);
+ return ret;
+}
+
+static void disable_func_stack_trace_instance(struct tracefs_instance *instance)
+{
+ char *content;
+ char *cond;
+ int size;
+
+ content = tracefs_instance_file_read(instance, "current_tracer", &size);
+ if (!content)
+ return;
+ cond = strstrip(content);
+ if (memcmp(cond, "function", size - (cond - content)) != 0)
+ goto out;
+
+ tracefs_option_disable(instance, TRACEFS_OPTION_FUNC_STACKTRACE);
+ out:
+ free(content);
+}
+
+static void reset_cpu_mask(struct tracefs_instance *instance)
+{
+ int cpus = sysconf(_SC_NPROCESSORS_CONF);
+ int fullwords = (cpus - 1) / 32;
+ int bits = (cpus - 1) % 32 + 1;
+ int len = (fullwords + 1) * 9;
+ char buf[len + 1];
+
+ buf[0] = '\0';
+ sprintf(buf, "%x", (unsigned int)((1ULL << bits) - 1));
+ while (fullwords-- > 0)
+ strcat(buf, ",ffffffff");
+
+ tracefs_instance_file_write(instance, "tracing_cpumask", buf);
+}
+
+static void clear_func_filter(struct tracefs_instance *instance, const char *file)
+{
+ char filter[BUFSIZ];
+ char *line;
+ char *buf;
+ char *p;
+ int len;
+
+ buf = tracefs_instance_file_read(instance, file, NULL);
+ if (!buf)
+ return;
+
+ /* Now remove filters */
+ filter[0] = '!';
+
+ /*
+ * To delete a filter, we need to write a '!filter'
+ * to the file for each filter.
+ */
+ for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
+ if (line[0] == '#')
+ continue;
+ len = strlen(line);
+ if (len > BUFSIZ - 2)
+ len = BUFSIZ - 2;
+
+ strncpy(filter + 1, line, len);
+ filter[len + 1] = '\0';
+ /*
+ * To remove "unlimited" filters, we must remove
+ * the ":unlimited" from what we write.
+ */
+ p = strstr(filter, ":unlimited");
+ if (p) {
+ *p = '\0';
+ len = p - filter;
+ }
+ /*
+ * The write to this file expects white space
+ * at the end :-p
+ */
+ filter[len] = '\n';
+ filter[len+1] = '\0';
+ tracefs_instance_file_append(instance, file, filter);
+ }
+}
+
+static void clear_func_filters(struct tracefs_instance *instance)
+{
+ int i;
+ const char * const files[] = { "set_ftrace_filter",
+ "set_ftrace_notrace",
+ "set_graph_function",
+ "set_graph_notrace",
+ NULL };
+
+ for (i = 0; files[i]; i++)
+ clear_func_filter(instance, files[i]);
+}
+
+/**
+ * tracefs_instance_reset - Reset a ftrace instance to its default state
+ * @instance - a ftrace instance to be reseted
+ *
+ * The main logic and the helper functions are copied from
+ * trace-cmd/tracecmd/trace-record.c, trace_reset()
+ */
+void tracefs_instance_reset(struct tracefs_instance *instance)
+{
+ char **systems;
+ char **events;
+ char *file;
+ int i, j;
+
+ tracefs_trace_off(instance);
+ disable_func_stack_trace_instance(instance);
+ tracefs_tracer_clear(instance);
+ tracefs_instance_file_write(instance, "events/enable", "0");
+ tracefs_instance_file_write(instance, "set_ftrace_pid", "");
+ tracefs_instance_file_clear(instance, "trace");
+
+ systems = tracefs_event_systems(NULL);
+ if (systems) {
+ for (i = 0; systems[i]; i++) {
+ events = tracefs_system_events(NULL, systems[i]);
+ if (!events)
+ continue;
+ for (j = 0; events[j]; j++) {
+ file = tracefs_event_get_file(instance, systems[i],
+ events[j], "filter");
+ write_file(file, "0", O_WRONLY | O_TRUNC);
+ tracefs_put_tracing_file(file);
+
+ file = tracefs_event_get_file(instance, systems[i],
+ events[j], "trigger");
+ clear_trigger(file);
+ tracefs_put_tracing_file(file);
+ }
+ tracefs_list_free(events);
+ }
+ tracefs_list_free(systems);
+ }
+
+ tracefs_instance_file_write(instance, "error_log", " ");
+ tracefs_instance_file_write(instance, "trace_clock", "local");
+ tracefs_instance_file_write(instance, "set_event_pid", "");
+ reset_cpu_mask(instance);
+ clear_func_filters(instance);
+ tracefs_instance_file_write(instance, "tracing_max_latency", "0");
+ tracefs_trace_on(instance);
+}
diff --git a/src/tracefs-utils.c b/src/tracefs-utils.c
index 9acf2ad..ef90677 100644
--- a/src/tracefs-utils.c
+++ b/src/tracefs-utils.c
@@ -319,6 +319,26 @@ void tracefs_put_tracing_file(char *name)
free(name);
}
+/* The function is copied from trace-cmd */
+__hidden char *strstrip(char *str)
+{
+ char *s;
+
+ if (!str)
+ return NULL;
+
+ s = str + strlen(str) - 1;
+ while (s >= str && isspace(*s))
+ s--;
+ s++;
+ *s = '\0';
+
+ for (s = str; *s && isspace(*s); s++)
+ ;
+
+ return s;
+}
+
__hidden int str_read_file(const char *file, char **buffer, bool warn)
{
char stbuf[BUFSIZ];
--
2.39.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/3] libtracefs: Documentation for tracefs_instance_reset()
2023-03-28 15:03 [PATCH 0/3] Introduce new API to reset ftrace instance Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 1/3] libtracefs: New " Tzvetomir Stoyanov (VMware)
@ 2023-03-28 15:03 ` Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 3/3] libtracefs: Unit test " Tzvetomir Stoyanov (VMware)
2023-03-28 15:13 ` [PATCH 0/3] Introduce new API to reset ftrace instance Steven Rostedt
3 siblings, 0 replies; 9+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2023-03-28 15:03 UTC (permalink / raw)
To: rostedt; +Cc: linux-trace-devel
The newly introduced API tracefs_instance_reset() should be described in
the tracefs man pages.
Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
Documentation/libtracefs-instances-manage.txt | 7 +++++--
Documentation/libtracefs.txt | 1 +
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Documentation/libtracefs-instances-manage.txt b/Documentation/libtracefs-instances-manage.txt
index c03a272..1e0735e 100644
--- a/Documentation/libtracefs-instances-manage.txt
+++ b/Documentation/libtracefs-instances-manage.txt
@@ -4,7 +4,7 @@ libtracefs(3)
NAME
----
tracefs_instance_create, tracefs_instance_destroy, tracefs_instance_alloc, tracefs_instance_free,
-tracefs_instance_is_new, tracefs_instances - Manage trace instances.
+tracefs_instance_is_new, tracefs_instances, tracefs_instance_reset - Manage trace instances.
SYNOPSIS
--------
@@ -18,6 +18,7 @@ struct tracefs_instance pass:[*]*tracefs_instance_alloc*(const char pass:[*]_tra
void *tracefs_instance_free*(struct tracefs_instance pass:[*]_instance_);
bool *tracefs_instance_is_new*(struct tracefs_instance pass:[*]_instance_);
char pass:[**]*tracefs_instances*(const char pass:[*]_regex_);
+void *tracefs_instance_reset*(struct tracefs_instance pass:[*]_instance_);
--
@@ -60,6 +61,8 @@ it will match all instances that exist. The returned list must be freed with
*tracefs_list_free*(3). Note, if no instances are found an empty list is returned
and that too needs to be free with *tracefs_list_free*(3).
+The *tracefs_instance_reset*() function resets the given _instance_ to its default state.
+
RETURN VALUE
------------
The *tracefs_instance_create()* and *tracefs_instance_alloc()* functions return a pointer to
@@ -106,7 +109,7 @@ struct tracefs_instance *inst = tracefs_instance_alloc(NULL, "bar");
}
...
-
+ tracefs_instance_reset(inst);
tracefs_instance_free(inst);
--
FILES
diff --git a/Documentation/libtracefs.txt b/Documentation/libtracefs.txt
index c3f448d..052e1c9 100644
--- a/Documentation/libtracefs.txt
+++ b/Documentation/libtracefs.txt
@@ -25,6 +25,7 @@ Trace instances:
struct tracefs_instance pass:[*]*tracefs_instance_alloc*(const char pass:[*]_tracing_dir_, const char pass:[*]_name_);
void *tracefs_instance_free*(struct tracefs_instance pass:[*]_instance_);
char pass:[**]*tracefs_instances*(const char pass:[*]_regex_);
+ void *tracefs_instance_reset*(struct tracefs_instance pass:[*]_instance_);
bool *tracefs_instance_is_new*(struct tracefs_instance pass:[*]_instance_);
bool *tracefs_file_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_);
bool *tracefs_dir_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_);
--
2.39.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/3] libtracefs: Unit test for tracefs_instance_reset()
2023-03-28 15:03 [PATCH 0/3] Introduce new API to reset ftrace instance Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 1/3] libtracefs: New " Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 2/3] libtracefs: Documentation for tracefs_instance_reset() Tzvetomir Stoyanov (VMware)
@ 2023-03-28 15:03 ` Tzvetomir Stoyanov (VMware)
2023-04-24 19:45 ` Steven Rostedt
2023-03-28 15:13 ` [PATCH 0/3] Introduce new API to reset ftrace instance Steven Rostedt
3 siblings, 1 reply; 9+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2023-03-28 15:03 UTC (permalink / raw)
To: rostedt; +Cc: linux-trace-devel
The logic of the tracefs_instance_reset() is complex and should be
covered by the unit tests of the tracefs library.
Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
utest/tracefs-utest.c | 183 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 183 insertions(+)
diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
index e0e3c07..5866339 100644
--- a/utest/tracefs-utest.c
+++ b/utest/tracefs-utest.c
@@ -1618,6 +1618,187 @@ static void test_instance_file(void)
free(inst_dir);
}
+static bool test_check_file_contetnt(struct tracefs_instance *instance, char *file,
+ char *content, bool full_match, bool ignore_comments)
+{
+ char *save = NULL;
+ char *buf, *line;
+ bool ret = false;
+ int len;
+
+ if (!tracefs_file_exists(instance, file))
+ return false;
+
+ buf = tracefs_instance_file_read(instance, file, NULL);
+ if (strlen(content) == 0) {
+ /* check for empty file */
+ if (!buf)
+ return true;
+ if (!ignore_comments) {
+ if (strlen(buf) > 0)
+ goto out;
+ } else {
+ line = strtok_r(buf, "\n", &save);
+ while (line) {
+ if (line[0] != '#')
+ goto out;
+ line = strtok_r(NULL, "\n", &save);
+ }
+ }
+ } else {
+ if (!buf || strlen(buf) < 1)
+ return false;
+ if (full_match) {
+ /* strip the newline */
+ len = strlen(buf)-1;
+ while (buf[len] == '\n' || buf[len] == '\r') {
+ buf[len] = '\0';
+ len = strlen(buf)-1;
+ if (len < 0)
+ goto out;
+ }
+ if (strcmp(buf, content))
+ goto out;
+ } else {
+ if (!strstr(buf, content))
+ goto out;
+ }
+ }
+
+ ret = true;
+out:
+ free(buf);
+ return ret;
+}
+
+static bool test_check_event_file_contetnt(struct tracefs_instance *instance,
+ char *system, char *event, char *file,
+ char *content, bool full_match, bool ignore_comments)
+{
+ char *efile;
+ int ret;
+
+ ret = asprintf(&efile, "events/%s/%s/%s", system, event, file);
+ if (ret <= 0)
+ return false;
+ ret = test_check_file_contetnt(instance, efile, content, full_match, ignore_comments);
+ free(efile);
+ return ret;
+}
+
+static bool check_cpu_mask(struct tracefs_instance *instance)
+{
+ int cpus = sysconf(_SC_NPROCESSORS_CONF);
+ int fullwords = (cpus - 1) / 32;
+ int bits = (cpus - 1) % 32 + 1;
+ int len = (fullwords + 1) * 9;
+ char buf[len + 1];
+
+ buf[0] = '\0';
+ sprintf(buf, "%x", (unsigned int)((1ULL << bits) - 1));
+ while (fullwords-- > 0)
+ strcat(buf, ",ffffffff");
+
+ return test_check_file_contetnt(instance, "tracing_cpumask", buf, true, false);
+}
+
+static bool test_instance_check_default_state(struct tracefs_instance *instance)
+{
+ char **systems;
+ char **events;
+ int i, j;
+ int ok;
+
+ if (tracefs_trace_is_on(instance) != 1)
+ return false;
+ if (!test_check_file_contetnt(instance, "current_tracer", "nop", true, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "events/enable", "0", true, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "set_ftrace_pid", "no pid", true, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "trace", "", true, true))
+ return false;
+ if (!test_check_file_contetnt(instance, "error_log", "", true, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "trace_clock", "[local]", false, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "set_event_pid", "", true, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "tracing_max_latency", "0", true, false))
+ return false;
+ if (!test_check_file_contetnt(instance, "set_ftrace_filter", "", true, true))
+ return false;
+ if (!test_check_file_contetnt(instance, "set_ftrace_notrace", "", true, true))
+ return false;
+ if (!check_cpu_mask(instance))
+ return false;
+
+ ok = 1;
+ systems = tracefs_event_systems(NULL);
+ if (systems) {
+ for (i = 0; systems[i]; i++) {
+ events = tracefs_system_events(NULL, systems[i]);
+ if (!events)
+ continue;
+ for (j = 0; events[j]; j++) {
+ if (!test_check_event_file_contetnt(instance, systems[i], events[j],
+ "enable", "0", true, false))
+ break;
+ if (!test_check_event_file_contetnt(instance, systems[i], events[j],
+ "filter", "none", true, false))
+ break;
+ if (!test_check_event_file_contetnt(instance, systems[i], events[j],
+ "trigger", "", true, true))
+ break;
+ }
+ if (events[j])
+ ok = 0;
+ tracefs_list_free(events);
+ if (!ok)
+ return false;
+ }
+ tracefs_list_free(systems);
+ }
+
+ return true;
+}
+
+static void test_instance_reset(void)
+{
+ struct tracefs_instance *instance = NULL;
+ const char *name = get_rand_str();
+
+ CU_TEST(tracefs_instance_exists(name) == false);
+ instance = tracefs_instance_create(name);
+ CU_TEST(instance != NULL);
+
+ CU_TEST(test_instance_check_default_state(instance) == true);
+
+ CU_TEST(tracefs_tracer_set(instance, TRACEFS_TRACER_HWLAT) == 0);
+ CU_TEST(tracefs_event_enable(instance, "bridge", "fdb_delete") == 0);
+ CU_TEST(tracefs_instance_file_write(instance, "set_ftrace_pid", "5") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "trace_clock", "global") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "set_event_pid", "5") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "set_ftrace_filter",
+ "schedule:stacktrace") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "set_ftrace_notrace",
+ "schedule:stacktrace") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "tracing_cpumask", "0f") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "events/syscalls/sys_exit_read/trigger",
+ "enable_event:kmem:kmalloc:1") > 0);
+ CU_TEST(tracefs_instance_file_write(instance, "events/bridge/fdb_delete/filter",
+ "common_pid == 5") > 0);
+
+ CU_TEST(test_instance_check_default_state(instance) == false);
+
+ tracefs_instance_reset(instance);
+ CU_TEST(test_instance_check_default_state(instance) == true);
+
+ CU_TEST(tracefs_instance_destroy(instance) == 0);
+ tracefs_instance_free(instance);
+}
+
static bool check_fd_name(int fd, const char *dir, const char *name)
{
char link[PATH_MAX + 1];
@@ -2354,6 +2535,8 @@ void test_tracefs_lib(void)
test_file_fd);
CU_add_test(suite, "instance file descriptor",
test_instance_file);
+ CU_add_test(suite, "instance reset",
+ test_instance_reset);
CU_add_test(suite, "systems and events APIs",
test_system_event);
CU_add_test(suite, "tracefs_iterate_raw_events API",
--
2.39.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] Introduce new API to reset ftrace instance
2023-03-28 15:03 [PATCH 0/3] Introduce new API to reset ftrace instance Tzvetomir Stoyanov (VMware)
` (2 preceding siblings ...)
2023-03-28 15:03 ` [PATCH 3/3] libtracefs: Unit test " Tzvetomir Stoyanov (VMware)
@ 2023-03-28 15:13 ` Steven Rostedt
2023-04-13 12:17 ` Tzvetomir Stoyanov
3 siblings, 1 reply; 9+ messages in thread
From: Steven Rostedt @ 2023-03-28 15:13 UTC (permalink / raw)
To: Tzvetomir Stoyanov (VMware); +Cc: linux-trace-devel
On Tue, 28 Mar 2023 18:03:05 +0300
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:
> A new API tracefs_instance_reset() for resetting instance to its default
> state, based on the logic from "trace-cmd reset" command.
HAH!!!
I was just thinking that I needed to implement this earlier today.
I'm so happy when someone else does my work for me :-D
Thanks Tzvetomir, I'll hopefully get a chance to review this sometime this
week.
-- Steve
>
> Tzvetomir Stoyanov (VMware) (3):
> libtracefs: New API to reset ftrace instance
> libtracefs: Documentation for tracefs_instance_reset()
> libtracefs: Unit test for tracefs_instance_reset()
>
> Documentation/libtracefs-instances-manage.txt | 7 +-
> Documentation/libtracefs.txt | 1 +
> include/tracefs-local.h | 1 +
> include/tracefs.h | 1 +
> src/tracefs-instance.c | 196 ++++++++++++++++++
> src/tracefs-utils.c | 20 ++
> utest/tracefs-utest.c | 183 ++++++++++++++++
> 7 files changed, 407 insertions(+), 2 deletions(-)
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] Introduce new API to reset ftrace instance
2023-03-28 15:13 ` [PATCH 0/3] Introduce new API to reset ftrace instance Steven Rostedt
@ 2023-04-13 12:17 ` Tzvetomir Stoyanov
2023-04-13 12:20 ` Steven Rostedt
0 siblings, 1 reply; 9+ messages in thread
From: Tzvetomir Stoyanov @ 2023-04-13 12:17 UTC (permalink / raw)
To: Steven Rostedt; +Cc: linux-trace-devel
On Tue, Mar 28, 2023 at 6:13 PM Steven Rostedt <rostedt@goodmis.org> wrote:
>
> On Tue, 28 Mar 2023 18:03:05 +0300
> "Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:
>
> > A new API tracefs_instance_reset() for resetting instance to its default
> > state, based on the logic from "trace-cmd reset" command.
>
> HAH!!!
>
> I was just thinking that I needed to implement this earlier today.
>
> I'm so happy when someone else does my work for me :-D
>
> Thanks Tzvetomir, I'll hopefully get a chance to review this sometime this
> week.
ping
Did you have time to take a look at these patches? I'm planing to use
the library in a new project and need this new functionality.
>
> -- Steve
>
> >
> > Tzvetomir Stoyanov (VMware) (3):
> > libtracefs: New API to reset ftrace instance
> > libtracefs: Documentation for tracefs_instance_reset()
> > libtracefs: Unit test for tracefs_instance_reset()
> >
> > Documentation/libtracefs-instances-manage.txt | 7 +-
> > Documentation/libtracefs.txt | 1 +
> > include/tracefs-local.h | 1 +
> > include/tracefs.h | 1 +
> > src/tracefs-instance.c | 196 ++++++++++++++++++
> > src/tracefs-utils.c | 20 ++
> > utest/tracefs-utest.c | 183 ++++++++++++++++
> > 7 files changed, 407 insertions(+), 2 deletions(-)
> >
>
--
Tzvetomir (Ceco) Stoyanov
VMware Open Source Technology Center
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] Introduce new API to reset ftrace instance
2023-04-13 12:17 ` Tzvetomir Stoyanov
@ 2023-04-13 12:20 ` Steven Rostedt
0 siblings, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2023-04-13 12:20 UTC (permalink / raw)
To: Tzvetomir Stoyanov; +Cc: linux-trace-devel
On Thu, 13 Apr 2023 15:17:11 +0300
Tzvetomir Stoyanov <tz.stoyanov@gmail.com> wrote:
> ping
> Did you have time to take a look at these patches? I'm planing to use
> the library in a new project and need this new functionality.
No, I haven't had a chance. I've been focusing on kernel scheduler changes.
But I'll try to carve out time for this as well, as I will need this
functionality too.
-- Steve
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] libtracefs: New API to reset ftrace instance
2023-03-28 15:03 ` [PATCH 1/3] libtracefs: New " Tzvetomir Stoyanov (VMware)
@ 2023-04-24 19:42 ` Steven Rostedt
0 siblings, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2023-04-24 19:42 UTC (permalink / raw)
To: Tzvetomir Stoyanov (VMware); +Cc: linux-trace-devel
On Tue, 28 Mar 2023 18:03:06 +0300
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:
> Resetting a ftrace instance to its default state is not a trivial task.
> A lot of trace files have to be modified, with different syntaxes and
> in strict order. Although there is such functionality in "trace-cmd
> reset" command, it will be good to have it in the tracefs library as
> well.
> A new API tracefs_instance_reset() is introduced, which resets given
> ftrace instance to its default state. The logic and most of the helper
> functions from "trace-cmd reset" command are copied in the tracefs
> library.
>
> Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
> ---
> include/tracefs-local.h | 1 +
> include/tracefs.h | 1 +
> src/tracefs-instance.c | 196 ++++++++++++++++++++++++++++++++++++++++
> src/tracefs-utils.c | 20 ++++
> 4 files changed, 218 insertions(+)
>
> diff --git a/include/tracefs-local.h b/include/tracefs-local.h
> index 2007d26..da99a30 100644
> --- a/include/tracefs-local.h
> +++ b/include/tracefs-local.h
> @@ -64,6 +64,7 @@ int trace_get_instance(struct tracefs_instance *instance);
> /* Can be overridden */
> void tracefs_warning(const char *fmt, ...);
>
> +char *strstrip(char *str);
> int str_read_file(const char *file, char **buffer, bool warn);
> char *trace_append_file(const char *dir, const char *name);
> char *trace_find_tracing_dir(bool debugfs);
> diff --git a/include/tracefs.h b/include/tracefs.h
> index 3547b5a..5e9d84b 100644
> --- a/include/tracefs.h
> +++ b/include/tracefs.h
> @@ -23,6 +23,7 @@ int tracefs_tracing_dir_is_mounted(bool mount, const char **path);
> struct tracefs_instance;
>
> void tracefs_instance_free(struct tracefs_instance *instance);
> +void tracefs_instance_reset(struct tracefs_instance *instance);
> struct tracefs_instance *tracefs_instance_create(const char *name);
> struct tracefs_instance *tracefs_instance_alloc(const char *tracing_dir,
> const char *name);
> diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c
> index 57f5c7f..d3c6581 100644
> --- a/src/tracefs-instance.c
> +++ b/src/tracefs-instance.c
> @@ -1239,3 +1239,199 @@ char *tracefs_instance_get_affinity(struct tracefs_instance *instance)
>
> return set;
> }
> +
> +static int clear_trigger(const char *file)
> +{
> + char trigger[BUFSIZ];
> + char *save = NULL;
> + char *line;
> + char *buf;
> + int size;
> + int len;
> + int ret;
> +
> + size = str_read_file(file, &buf, true);
So this will warn if the file doesn't exist?
Note, this should still work without warning if the kernel is not
configured with triggers enabled. This should only warn if we
established that the trigger file existed before calling this function.
> + if (size < 1)
> + return 0;
> +
> + trigger[0] = '!';
> +
> + for (line = strtok_r(buf, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) {
> + if (line[0] == '#')
> + continue;
> + len = strlen(line);
> + if (len > BUFSIZ - 2)
> + len = BUFSIZ - 2;
> + strncpy(trigger + 1, line, len);
> + trigger[len + 1] = '\0';
> + /* We don't want any filters or extra on the line */
> + strtok(trigger, " ");
> + write_file(file, trigger, O_WRONLY);
> + }
> +
> + free(buf);
> +
> + /*
> + * Some triggers have an order in removing them.
> + * They will not be removed if done in the wrong order.
> + */
> + size = str_read_file(file, &buf, true);
> + if (size < 1)
> + return 0;
> +
> + ret = 0;
> + for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
> + if (line[0] == '#')
> + continue;
> + ret = 1;
> + break;
> + }
> + free(buf);
> + return ret;
> +}
> +
> +static void disable_func_stack_trace_instance(struct tracefs_instance *instance)
> +{
> + char *content;
> + char *cond;
> + int size;
> +
> + content = tracefs_instance_file_read(instance, "current_tracer", &size);
> + if (!content)
> + return;
> + cond = strstrip(content);
> + if (memcmp(cond, "function", size - (cond - content)) != 0)
> + goto out;
> +
> + tracefs_option_disable(instance, TRACEFS_OPTION_FUNC_STACKTRACE);
> + out:
> + free(content);
> +}
> +
> +static void reset_cpu_mask(struct tracefs_instance *instance)
> +{
> + int cpus = sysconf(_SC_NPROCESSORS_CONF);
> + int fullwords = (cpus - 1) / 32;
> + int bits = (cpus - 1) % 32 + 1;
> + int len = (fullwords + 1) * 9;
> + char buf[len + 1];
> +
> + buf[0] = '\0';
> + sprintf(buf, "%x", (unsigned int)((1ULL << bits) - 1));
> + while (fullwords-- > 0)
> + strcat(buf, ",ffffffff");
> +
> + tracefs_instance_file_write(instance, "tracing_cpumask", buf);
> +}
> +
> +static void clear_func_filter(struct tracefs_instance *instance, const char *file)
> +{
> + char filter[BUFSIZ];
> + char *line;
> + char *buf;
> + char *p;
> + int len;
> +
> + buf = tracefs_instance_file_read(instance, file, NULL);
> + if (!buf)
> + return;
> +
> + /* Now remove filters */
> + filter[0] = '!';
> +
> + /*
> + * To delete a filter, we need to write a '!filter'
> + * to the file for each filter.
> + */
> + for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
> + if (line[0] == '#')
> + continue;
> + len = strlen(line);
> + if (len > BUFSIZ - 2)
> + len = BUFSIZ - 2;
> +
> + strncpy(filter + 1, line, len);
> + filter[len + 1] = '\0';
> + /*
> + * To remove "unlimited" filters, we must remove
> + * the ":unlimited" from what we write.
> + */
> + p = strstr(filter, ":unlimited");
> + if (p) {
> + *p = '\0';
> + len = p - filter;
> + }
> + /*
> + * The write to this file expects white space
> + * at the end :-p
> + */
> + filter[len] = '\n';
> + filter[len+1] = '\0';
> + tracefs_instance_file_append(instance, file, filter);
> + }
> +}
> +
> +static void clear_func_filters(struct tracefs_instance *instance)
> +{
> + int i;
> + const char * const files[] = { "set_ftrace_filter",
> + "set_ftrace_notrace",
> + "set_graph_function",
> + "set_graph_notrace",
Should also add "stack_trace_filter".
> + NULL };
> +
> + for (i = 0; files[i]; i++)
> + clear_func_filter(instance, files[i]);
> +}
> +
> +/**
> + * tracefs_instance_reset - Reset a ftrace instance to its default state
> + * @instance - a ftrace instance to be reseted
> + *
> + * The main logic and the helper functions are copied from
> + * trace-cmd/tracecmd/trace-record.c, trace_reset()
> + */
> +void tracefs_instance_reset(struct tracefs_instance *instance)
> +{
> + char **systems;
> + char **events;
> + char *file;
> + int i, j;
> +
> + tracefs_trace_off(instance);
> + disable_func_stack_trace_instance(instance);
> + tracefs_tracer_clear(instance);
> + tracefs_instance_file_write(instance, "events/enable", "0");
> + tracefs_instance_file_write(instance, "set_ftrace_pid", "");
> + tracefs_instance_file_clear(instance, "trace");
> +
> + systems = tracefs_event_systems(NULL);
> + if (systems) {
> + for (i = 0; systems[i]; i++) {
> + events = tracefs_system_events(NULL, systems[i]);
> + if (!events)
> + continue;
> + for (j = 0; events[j]; j++) {
> + file = tracefs_event_get_file(instance, systems[i],
> + events[j], "filter");
> + write_file(file, "0", O_WRONLY | O_TRUNC);
> + tracefs_put_tracing_file(file);
> +
> + file = tracefs_event_get_file(instance, systems[i],
> + events[j], "trigger");
Here we can test if the file exists before calling clear_trigger().
-- Steve
> + clear_trigger(file);
> + tracefs_put_tracing_file(file);
> + }
> + tracefs_list_free(events);
> + }
> + tracefs_list_free(systems);
> + }
> +
> + tracefs_instance_file_write(instance, "error_log", " ");
> + tracefs_instance_file_write(instance, "trace_clock", "local");
> + tracefs_instance_file_write(instance, "set_event_pid", "");
> + reset_cpu_mask(instance);
> + clear_func_filters(instance);
> + tracefs_instance_file_write(instance, "tracing_max_latency", "0");
> + tracefs_trace_on(instance);
> +}
> diff --git a/src/tracefs-utils.c b/src/tracefs-utils.c
> index 9acf2ad..ef90677 100644
> --- a/src/tracefs-utils.c
> +++ b/src/tracefs-utils.c
> @@ -319,6 +319,26 @@ void tracefs_put_tracing_file(char *name)
> free(name);
> }
>
> +/* The function is copied from trace-cmd */
> +__hidden char *strstrip(char *str)
> +{
> + char *s;
> +
> + if (!str)
> + return NULL;
> +
> + s = str + strlen(str) - 1;
> + while (s >= str && isspace(*s))
> + s--;
> + s++;
> + *s = '\0';
> +
> + for (s = str; *s && isspace(*s); s++)
> + ;
> +
> + return s;
> +}
> +
> __hidden int str_read_file(const char *file, char **buffer, bool warn)
> {
> char stbuf[BUFSIZ];
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] libtracefs: Unit test for tracefs_instance_reset()
2023-03-28 15:03 ` [PATCH 3/3] libtracefs: Unit test " Tzvetomir Stoyanov (VMware)
@ 2023-04-24 19:45 ` Steven Rostedt
0 siblings, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2023-04-24 19:45 UTC (permalink / raw)
To: Tzvetomir Stoyanov (VMware); +Cc: linux-trace-devel
On Tue, 28 Mar 2023 18:03:08 +0300
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:
> The logic of the tracefs_instance_reset() is complex and should be
> covered by the unit tests of the tracefs library.
>
> Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
> ---
> utest/tracefs-utest.c | 183 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 183 insertions(+)
>
> diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
> index e0e3c07..5866339 100644
> --- a/utest/tracefs-utest.c
> +++ b/utest/tracefs-utest.c
> @@ -1618,6 +1618,187 @@ static void test_instance_file(void)
> free(inst_dir);
> }
>
> +static bool test_check_file_contetnt(struct tracefs_instance *instance, char *file,
Misspelling of "content"
> + char *content, bool full_match, bool ignore_comments)
> +{
> + char *save = NULL;
> + char *buf, *line;
> + bool ret = false;
> + int len;
> +
> + if (!tracefs_file_exists(instance, file))
> + return false;
> +
> + buf = tracefs_instance_file_read(instance, file, NULL);
> + if (strlen(content) == 0) {
> + /* check for empty file */
> + if (!buf)
> + return true;
> + if (!ignore_comments) {
> + if (strlen(buf) > 0)
> + goto out;
> + } else {
> + line = strtok_r(buf, "\n", &save);
> + while (line) {
> + if (line[0] != '#')
> + goto out;
> + line = strtok_r(NULL, "\n", &save);
> + }
> + }
> + } else {
> + if (!buf || strlen(buf) < 1)
> + return false;
> + if (full_match) {
> + /* strip the newline */
> + len = strlen(buf)-1;
Let's keep with the linux style of spaces between operands:
strlen(buf) - 1;
> + while (buf[len] == '\n' || buf[len] == '\r') {
> + buf[len] = '\0';
> + len = strlen(buf)-1;
Here too.
> + if (len < 0)
> + goto out;
> + }
> + if (strcmp(buf, content))
> + goto out;
> + } else {
> + if (!strstr(buf, content))
> + goto out;
> + }
> + }
> +
> + ret = true;
> +out:
> + free(buf);
> + return ret;
> +}
> +
> +static bool test_check_event_file_contetnt(struct tracefs_instance *instance,
Misspelled "content".
-- Steve
> + char *system, char *event, char *file,
> + char *content, bool full_match, bool ignore_comments)
> +{
> + char *efile;
> + int ret;
> +
> + ret = asprintf(&efile, "events/%s/%s/%s", system, event, file);
> + if (ret <= 0)
> + return false;
> + ret = test_check_file_contetnt(instance, efile, content, full_match, ignore_comments);
> + free(efile);
> + return ret;
> +}
> +
> +static bool check_cpu_mask(struct tracefs_instance *instance)
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2023-04-24 19:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-28 15:03 [PATCH 0/3] Introduce new API to reset ftrace instance Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 1/3] libtracefs: New " Tzvetomir Stoyanov (VMware)
2023-04-24 19:42 ` Steven Rostedt
2023-03-28 15:03 ` [PATCH 2/3] libtracefs: Documentation for tracefs_instance_reset() Tzvetomir Stoyanov (VMware)
2023-03-28 15:03 ` [PATCH 3/3] libtracefs: Unit test " Tzvetomir Stoyanov (VMware)
2023-04-24 19:45 ` Steven Rostedt
2023-03-28 15:13 ` [PATCH 0/3] Introduce new API to reset ftrace instance Steven Rostedt
2023-04-13 12:17 ` Tzvetomir Stoyanov
2023-04-13 12:20 ` Steven Rostedt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).