Linux-Trace-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/5] New libtracefs APIs for trace options and trace dir
@ 2021-01-15  5:04 Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 1/5] libtracefs: New APIs for trace options Tzvetomir Stoyanov (VMware)
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-01-15  5:04 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

A new set of tracefs library APIs for:
 - Working with trace options.
 - Working with non default tracing directory.
 
Tzvetomir Stoyanov (VMware) (5):
  libtracefs: New APIs for trace options
  libtracefs: Unit tests for tracing options APIs
  libtracefs: Add information about top tracing directory in instance
    structure
  libtracefs: New APIs for getting existing trace instance
  libtracefs: Unit tests for working with non default tracing dir

 include/tracefs.h      |  57 ++++++
 src/tracefs-instance.c | 137 +++++++++++---
 src/tracefs-tools.c    | 251 +++++++++++++++++++++++++
 utest/tracefs-utest.c  | 416 +++++++++++++++++++++++++++++++++++------
 4 files changed, 771 insertions(+), 90 deletions(-)

-- 
2.29.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/5] libtracefs: New APIs for trace options
  2021-01-15  5:04 [PATCH 0/5] New libtracefs APIs for trace options and trace dir Tzvetomir Stoyanov (VMware)
@ 2021-01-15  5:04 ` Tzvetomir Stoyanov (VMware)
  2021-01-19 21:12   ` Steven Rostedt
  2021-01-15  5:04 ` [PATCH 2/5] libtracefs: Unit tests for tracing options APIs Tzvetomir Stoyanov (VMware)
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-01-15  5:04 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

These new APIs can be used to check and set various trace options

tracefs_options_get_supported();
tracefs_option_is_supported();
tracefs_options_get_enabled();
tracefs_option_is_enabled();
tracefs_options_set();
tracefs_options_clear();
tracefs_option_string();

Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
 include/tracefs.h   |  54 ++++++++++
 src/tracefs-tools.c | 251 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 305 insertions(+)

diff --git a/include/tracefs.h b/include/tracefs.h
index 85a776e..1f10a00 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -80,4 +80,58 @@ int tracefs_fill_local_events(const char *tracing_dir,
 
 char *tracefs_get_clock(struct tracefs_instance *instance);
 
+#define		TRACEFS_OPTION_ANNOTATE		((unsigned long long)1 << 0)
+#define		TRACEFS_OPTION_BIN		((unsigned long long)1 << 1)
+#define		TRACEFS_OPTION_BLK_CGNAME	((unsigned long long)1 << 2)
+#define		TRACEFS_OPTION_BLK_CGROUP	((unsigned long long)1 << 3)
+#define		TRACEFS_OPTION_BLK_CLASSIC	((unsigned long long)1 << 4)
+#define		TRACEFS_OPTION_BLOCK		((unsigned long long)1 << 5)
+#define		TRACEFS_OPTION_CONTEXT_INFO	((unsigned long long)1 << 6)
+#define		TRACEFS_OPTION_DISABLE_ON_FREE	((unsigned long long)1 << 7)
+#define		TRACEFS_OPTION_DISPLAY_GRAPH	((unsigned long long)1 << 8)
+#define		TRACEFS_OPTION_EVENT_FORK	((unsigned long long)1 << 9)
+#define		TRACEFS_OPTION_FGRAPH_ABSTIME	((unsigned long long)1 << 10)
+#define		TRACEFS_OPTION_FGRAPH_CPU	((unsigned long long)1 << 11)
+#define		TRACEFS_OPTION_FGRAPH_DURATION	((unsigned long long)1 << 12)
+#define		TRACEFS_OPTION_FGRAPH_IRQS	((unsigned long long)1 << 13)
+#define		TRACEFS_OPTION_FGRAPH_OVERHEAD	((unsigned long long)1 << 14)
+#define		TRACEFS_OPTION_FGRAPH_OVERRUN	((unsigned long long)1 << 15)
+#define		TRACEFS_OPTION_FGRAPH_PROC	((unsigned long long)1 << 16)
+#define		TRACEFS_OPTION_FGRAPH_TAIL	((unsigned long long)1 << 17)
+#define		TRACEFS_OPTION_FUNC_STACKTRACE	((unsigned long long)1 << 18)
+#define		TRACEFS_OPTION_FUNCTION_FORK	((unsigned long long)1 << 19)
+#define		TRACEFS_OPTION_FUNCTION_TRACE	((unsigned long long)1 << 20)
+#define		TRACEFS_OPTION_GRAPH_TIME	((unsigned long long)1 << 21)
+#define		TRACEFS_OPTION_HEX		((unsigned long long)1 << 22)
+#define		TRACEFS_OPTION_IRQ_INFO		((unsigned long long)1 << 23)
+#define		TRACEFS_OPTION_LATENCY_FORMAT	((unsigned long long)1 << 24)
+#define		TRACEFS_OPTION_MARKERS		((unsigned long long)1 << 25)
+#define		TRACEFS_OPTION_OVERWRITE	((unsigned long long)1 << 26)
+#define		TRACEFS_OPTION_PAUSE_ON_TRACE	((unsigned long long)1 << 27)
+#define		TRACEFS_OPTION_PRINTK_MSG_ONLY	((unsigned long long)1 << 28)
+#define		TRACEFS_OPTION_PRINT_PARENT	((unsigned long long)1 << 29)
+#define		TRACEFS_OPTION_RAW		((unsigned long long)1 << 30)
+#define		TRACEFS_OPTION_RECORD_CMD	((unsigned long long)1 << 31)
+#define		TRACEFS_OPTION_RECORD_TGID	((unsigned long long)1 << 32)
+#define		TRACEFS_OPTION_SLEEP_TIME	((unsigned long long)1 << 33)
+#define		TRACEFS_OPTION_STACKTRACE	((unsigned long long)1 << 34)
+#define		TRACEFS_OPTION_SYM_ADDR		((unsigned long long)1 << 35)
+#define		TRACEFS_OPTION_SYM_OFFSET	((unsigned long long)1 << 36)
+#define		TRACEFS_OPTION_SYM_USEROBJ	((unsigned long long)1 << 37)
+#define		TRACEFS_OPTION_TEST_NOP_ACCEPT	((unsigned long long)1 << 38)
+#define		TRACEFS_OPTION_TEST_NOP_REFUSE	((unsigned long long)1 << 39)
+#define		TRACEFS_OPTION_TRACE_PRINTK	((unsigned long long)1 << 40)
+#define		TRACEFS_OPTION_USERSTACKTRACE	((unsigned long long)1 << 41)
+#define		TRACEFS_OPTION_VERBOSE		((unsigned long long)1 << 42)
+
+#define		TRACEFS_OPTION_INVALID		((unsigned long long)1 << 43)
+
+unsigned long long tracefs_options_get_supported(struct tracefs_instance *instance);
+bool tracefs_option_is_supported(struct tracefs_instance *instance, unsigned long long id);
+unsigned long long tracefs_options_get_enabled(struct tracefs_instance *instance);
+bool tracefs_option_is_enabled(struct tracefs_instance *instance, unsigned long long id);
+int tracefs_options_set(struct tracefs_instance *instance, unsigned long long options);
+int tracefs_options_clear(struct tracefs_instance *instance, unsigned long long options);
+const char *tracefs_option_string(unsigned long long id);
+
 #endif /* _TRACE_FS_H */
diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c
index 101f389..0505552 100644
--- a/src/tracefs-tools.c
+++ b/src/tracefs-tools.c
@@ -9,12 +9,66 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
 
 #include "tracefs.h"
 #include "tracefs-local.h"
 
 #define TRACE_CTRL	"tracing_on"
 
+struct options_map {
+	unsigned long long id;
+	char *name;
+} options_map[] = {
+	{ TRACEFS_OPTION_ANNOTATE,		"annotate" },
+	{ TRACEFS_OPTION_BIN,			"bin" },
+	{ TRACEFS_OPTION_BLK_CGNAME,		"blk_cgname" },
+	{ TRACEFS_OPTION_BLK_CGROUP,		"blk_cgroup" },
+	{ TRACEFS_OPTION_BLK_CLASSIC,		"blk_classic" },
+	{ TRACEFS_OPTION_BLOCK,			"block" },
+	{ TRACEFS_OPTION_CONTEXT_INFO,		"context-info" },
+	{ TRACEFS_OPTION_DISABLE_ON_FREE,	"disable_on_free" },
+	{ TRACEFS_OPTION_DISPLAY_GRAPH,		"display-graph" },
+	{ TRACEFS_OPTION_EVENT_FORK,		"event-fork" },
+	{ TRACEFS_OPTION_FGRAPH_ABSTIME,	"funcgraph-abstime" },
+	{ TRACEFS_OPTION_FGRAPH_CPU,		"funcgraph-cpu" },
+	{ TRACEFS_OPTION_FGRAPH_DURATION,	"funcgraph-duration" },
+	{ TRACEFS_OPTION_FGRAPH_IRQS,		"funcgraph-irqs" },
+	{ TRACEFS_OPTION_FGRAPH_OVERHEAD,	"funcgraph-overhead" },
+	{ TRACEFS_OPTION_FGRAPH_OVERRUN,	"funcgraph-overrun" },
+	{ TRACEFS_OPTION_FGRAPH_PROC,		"funcgraph-proc" },
+	{ TRACEFS_OPTION_FGRAPH_TAIL,		"funcgraph-tail" },
+	{ TRACEFS_OPTION_FUNC_STACKTRACE,	"func_stack_trace" },
+	{ TRACEFS_OPTION_FUNCTION_FORK,		"function-fork" },
+	{ TRACEFS_OPTION_FUNCTION_TRACE,	"function-trace" },
+	{ TRACEFS_OPTION_GRAPH_TIME,		"graph-time" },
+	{ TRACEFS_OPTION_HEX,			"hex" },
+	{ TRACEFS_OPTION_IRQ_INFO,		"irq-info" },
+	{ TRACEFS_OPTION_LATENCY_FORMAT,	"latency-format" },
+	{ TRACEFS_OPTION_MARKERS,		"markers" },
+	{ TRACEFS_OPTION_OVERWRITE,		"overwrite" },
+	{ TRACEFS_OPTION_PAUSE_ON_TRACE,	"pause-on-trace" },
+	{ TRACEFS_OPTION_PRINTK_MSG_ONLY,	"printk-msg-only" },
+	{ TRACEFS_OPTION_PRINT_PARENT,		"print-parent" },
+	{ TRACEFS_OPTION_RAW,			"raw" },
+	{ TRACEFS_OPTION_RECORD_CMD,		"record-cmd" },
+	{ TRACEFS_OPTION_RECORD_TGID,		"record-tgid" },
+	{ TRACEFS_OPTION_SLEEP_TIME,		"sleep-time" },
+	{ TRACEFS_OPTION_STACKTRACE,		"stacktrace" },
+	{ TRACEFS_OPTION_SYM_ADDR,		"sym-addr" },
+	{ TRACEFS_OPTION_SYM_OFFSET,		"sym-offset" },
+	{ TRACEFS_OPTION_SYM_USEROBJ,		"sym-userobj" },
+	{ TRACEFS_OPTION_TEST_NOP_ACCEPT,	"test_nop_accept" },
+	{ TRACEFS_OPTION_TEST_NOP_REFUSE,	"test_nop_refuse" },
+	{ TRACEFS_OPTION_TRACE_PRINTK,		"trace_printk" },
+	{ TRACEFS_OPTION_USERSTACKTRACE,	"userstacktrace" },
+	{ TRACEFS_OPTION_VERBOSE,		"verbose" },
+	{ TRACEFS_OPTION_INVALID,		"unknown" },
+};
+
 static int trace_on_off(int fd, bool on)
 {
 	const char *val = on ? "1" : "0";
@@ -107,3 +161,200 @@ int tracefs_trace_off_fd(int fd)
 		return -1;
 	return trace_on_off(fd, false);
 }
+
+/**
+ * tracefs_option_string - Get trace option name from ID
+ * @id: trace option ID
+ *
+ * Returns string with option name, or "unknown" in case of not known option ID
+ */
+const char *tracefs_option_string(unsigned long long id)
+{
+	int size = sizeof(options_map) / sizeof(struct options_map);
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (options_map[i].id == id)
+			return options_map[i].name;
+	}
+
+	return options_map[size - 1].name;
+}
+
+/**
+ * tracefs_option_id - Get trace option ID from name
+ * @name: trace option name
+ *
+ * Returns trace option ID or TRACEFS_OPTION_INVALID in case of an error or
+ * unknown option name.
+ */
+unsigned long long tracefs_option_id(char *name)
+{
+	int size = sizeof(options_map) / sizeof(struct options_map);
+	int i;
+
+	if (!name)
+		return TRACEFS_OPTION_INVALID;
+
+	for (i = 0; i < size; i++) {
+		if (strlen(name) == strlen(options_map[i].name) &&
+		    !strcmp(options_map[i].name, name))
+			return options_map[i].id;
+	}
+
+	return TRACEFS_OPTION_INVALID;
+}
+
+static unsigned long long trace_get_options(struct tracefs_instance *instance,
+					    bool enabled)
+{
+	unsigned long long options = 0;
+	unsigned long long id;
+	char file[PATH_MAX];
+	struct dirent *dent;
+	char *dname = NULL;
+	DIR *dir = NULL;
+	long long val;
+
+	dname = tracefs_instance_get_file(instance, "options");
+	if (!dname)
+		goto error;
+	dir = opendir(dname);
+	if (!dir)
+		goto error;
+
+	while ((dent = readdir(dir))) {
+		if (*dent->d_name == '.')
+			continue;
+		if (enabled) {
+			snprintf(file, PATH_MAX, "options/%s", dent->d_name);
+			if (tracefs_instance_file_read_number(instance, file, &val) != 0 ||
+			    val != 1)
+				continue;
+		}
+		id = tracefs_option_id(dent->d_name);
+		if (id != TRACEFS_OPTION_INVALID)
+			options |= id;
+	}
+	closedir(dir);
+	tracefs_put_tracing_file(dname);
+
+	return options;
+
+error:
+	if (dir)
+		closedir(dir);
+	tracefs_put_tracing_file(dname);
+	return 0;
+}
+
+/**
+ * tracefs_options_get_supported - Get all supported trace options in given instance
+ * @instance: ftrace instance, can be NULL for the top instance
+ *
+ * Returns bitmask of all trace options, supported in given instance
+ */
+unsigned long long tracefs_options_get_supported(struct tracefs_instance *instance)
+{
+	return trace_get_options(instance, false);
+}
+
+/**
+ * tracefs_options_get_enabled - Get all currently enabled trace options in given instance
+ * @instance: ftrace instance, can be NULL for the top instance
+ *
+ * Returns bitmask of all trace options, that are currently set in given instance
+ */
+unsigned long long tracefs_options_get_enabled(struct tracefs_instance *instance)
+{
+	return trace_get_options(instance, true);
+}
+
+static int trace_config_options(struct tracefs_instance *instance,
+				unsigned long long options, bool set)
+{
+	int size = sizeof(options_map) / sizeof(struct options_map);
+	char *set_str = set ? "1" : "0";
+	int str_size = strlen(set_str);
+	char file[PATH_MAX];
+	long long i;
+
+	for (i = 0; i < size && options; i++) {
+		if (!(options & options_map[i].id))
+			continue;
+		options &= ~options_map[i].id;
+		snprintf(file, PATH_MAX, "options/%s", options_map[i].name);
+		if (str_size != tracefs_instance_file_write(instance, file, set_str))
+			break;
+	}
+
+	if (options)
+		return -1;
+	return 0;
+}
+
+/**
+ * tracefs_options_set - Enable trace options
+ * @instance: ftrace instance, can be NULL for the top instance
+ * @options: bitmask of trace options that will be enabled
+ *
+ * Returns -1 in case of an error or 0 otherwise
+ */
+int tracefs_options_set(struct tracefs_instance *instance, unsigned long long options)
+{
+	return trace_config_options(instance, options, true);
+}
+
+/**
+ * tracefs_options_clear - Disable trace options
+ * @instance: ftrace instance, can be NULL for the top instance
+ * @options: bitmask of trace options that will be disabled
+ *
+ * Returns -1 in case of an error or 0 otherwise
+ */
+int tracefs_options_clear(struct tracefs_instance *instance, unsigned long long options)
+{
+	return trace_config_options(instance, options, false);
+}
+
+/**
+ * tracefs_option_is_supported - Check if an option is supported
+ * @instance: ftrace instance, can be NULL for the top instance
+ * @id: option id
+ *
+ * Returns true if an option with given id is supported by the system, false if
+ * it is not supported.
+ */
+bool tracefs_option_is_supported(struct tracefs_instance *instance, unsigned long long id)
+{
+	char file[PATH_MAX];
+	const char *oname = tracefs_option_string(id);
+
+	if (!oname)
+		return false;
+	snprintf(file, PATH_MAX, "options/%s", oname);
+	return tracefs_file_exists(instance, (char *)file);
+}
+
+/**
+ * tracefs_option_is_enabled - Check if an option is enabled in given instance
+ * @instance: ftrace instance, can be NULL for the top instance
+ * @id: option id
+ *
+ * Returns true if an option with given id is enabled in the given instance,
+ * false if it is not enabled.
+ */
+bool tracefs_option_is_enabled(struct tracefs_instance *instance, unsigned long long id)
+{
+	const char *oname = tracefs_option_string(id);
+	char file[PATH_MAX];
+	long long res;
+
+	if (!oname)
+		return false;
+	snprintf(file, PATH_MAX, "options/%s", oname);
+	if (!tracefs_instance_file_read_number(instance, file, &res) && res)
+		return true;
+
+	return false;
+}
-- 
2.29.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/5] libtracefs: Unit tests for tracing options APIs
  2021-01-15  5:04 [PATCH 0/5] New libtracefs APIs for trace options and trace dir Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 1/5] libtracefs: New APIs for trace options Tzvetomir Stoyanov (VMware)
@ 2021-01-15  5:04 ` Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 3/5] libtracefs: Add information about top tracing directory in instance structure Tzvetomir Stoyanov (VMware)
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-01-15  5:04 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

Unit tests for these new APIs:

tracefs_options_get_supported();
tracefs_option_is_supported();
tracefs_options_get_enabled();
tracefs_option_is_enabled();
tracefs_options_set();
tracefs_options_clear();
tracefs_option_string();

Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
 utest/tracefs-utest.c | 125 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
index 0520f49..1ade5dd 100644
--- a/utest/tracefs-utest.c
+++ b/utest/tracefs-utest.c
@@ -452,6 +452,129 @@ static void test_tracing_onoff(void)
 		close(fd);
 }
 
+static bool check_option(long long id, bool exist, int enabled)
+{
+	const char *name = tracefs_option_string(id);
+	char file[PATH_MAX];
+	char *path = NULL;
+	bool ret = false;
+	bool supported;
+	struct stat st;
+	char buf[10];
+	int fd;
+	int r;
+	int rstat;
+
+	CU_TEST(name != NULL);
+	supported = tracefs_option_is_supported(test_instance, id);
+	CU_TEST(supported == exist);
+	if (supported != exist)
+		goto out;
+	snprintf(file, PATH_MAX, "options/%s", name);
+	path = tracefs_instance_get_file(test_instance, file);
+	CU_TEST(path != NULL);
+	rstat = stat(path, &st);
+	if (exist) {
+		CU_TEST(rstat == 0);
+		if (rstat != 0)
+			goto out;
+	} else {
+		CU_TEST(stat(path, &st) == -1);
+		if (rstat != -1)
+			goto out;
+	}
+
+	fd = open(path, O_RDONLY);
+	if (exist) {
+		CU_TEST(fd >= 0);
+		if (fd < 0)
+			goto out;
+	} else {
+		CU_TEST(fd < 0);
+		if (fd >= 0)
+			goto out;
+	}
+
+	if (exist && enabled >= 0) {
+		int val = enabled ? '1' : '0';
+
+		r = read(fd, buf, 10);
+		CU_TEST(r == 2);
+		CU_TEST(buf[0] == val);
+		if (buf[0] != val)
+			goto out;
+	}
+
+	ret = true;
+out:
+	tracefs_put_tracing_file(path);
+	if (fd >= 0)
+		close(fd);
+	return ret;
+}
+
+static void test_tracing_options(void)
+{
+	unsigned long long options_enabled = 0;
+	unsigned long long options_all = 0;
+	unsigned long long i = 1;
+	char file[PATH_MAX];
+	const char *name;
+
+	options_all = tracefs_options_get_supported(test_instance);
+	options_enabled = tracefs_options_get_enabled(test_instance);
+	CU_TEST(options_all > 0);
+
+	/* Invalid parameters test */
+	CU_TEST(!tracefs_option_is_supported(test_instance, TRACEFS_OPTION_INVALID << 1));
+	CU_TEST(!tracefs_option_is_enabled(test_instance, TRACEFS_OPTION_INVALID << 1));
+	CU_TEST(tracefs_options_set(test_instance, TRACEFS_OPTION_INVALID << 1) == -1);
+	CU_TEST(tracefs_options_clear(test_instance, TRACEFS_OPTION_INVALID << 1) == -1);
+	name = tracefs_option_string(TRACEFS_OPTION_INVALID << 1);
+	CU_TEST(!strcmp(name, "unknown"));
+
+	/* Test all valid options */
+	do {
+		name = tracefs_option_string(i);
+		CU_TEST(name != NULL);
+		CU_TEST(strcmp(name, "unknown"));
+		snprintf(file, PATH_MAX, "options/%s", name);
+
+		if (options_all & i) {
+			options_all &= ~i;
+			CU_TEST(check_option(i, true, -1));
+			CU_TEST(tracefs_option_is_supported(test_instance, i));
+		} else {
+			CU_TEST(check_option(i, false, -1));
+			CU_TEST(!tracefs_option_is_supported(test_instance, i));
+		}
+
+		if (options_enabled & i) {
+			options_enabled &= ~i;
+			CU_TEST(check_option(i, true, 1));
+			CU_TEST(tracefs_option_is_supported(test_instance, i));
+			CU_TEST(tracefs_option_is_enabled(test_instance, i));
+			CU_TEST(tracefs_options_clear(test_instance, i) == 0);
+			CU_TEST(check_option(i, true, 0));
+			CU_TEST(tracefs_options_set(test_instance, i) == 0);
+			CU_TEST(check_option(i, true, 1));
+		} else if (options_all & i) {
+			CU_TEST(check_option(i, true, 0));
+			CU_TEST(tracefs_option_is_supported(test_instance, i));
+			CU_TEST(!tracefs_option_is_enabled(test_instance, i));
+			CU_TEST(tracefs_options_set(test_instance, i) == 0);
+			CU_TEST(check_option(i, true, 1));
+			CU_TEST(tracefs_options_clear(test_instance, i) == 0);
+			CU_TEST(check_option(i, true, 0));
+		}
+		i <<= 1;
+	} while (i < TRACEFS_OPTION_INVALID);
+
+	CU_TEST(options_all == 0);
+	CU_TEST(options_enabled == 0);
+
+}
+
 static void exclude_string(char **strings, char *name)
 {
 	int i;
@@ -761,5 +884,7 @@ void test_tracefs_lib(void)
 		    test_get_clock);
 	CU_add_test(suite, "tracing on / off",
 		    test_tracing_onoff);
+	CU_add_test(suite, "tracing options",
+		    test_tracing_options);
 
 }
-- 
2.29.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/5] libtracefs: Add information about top tracing directory in instance structure
  2021-01-15  5:04 [PATCH 0/5] New libtracefs APIs for trace options and trace dir Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 1/5] libtracefs: New APIs for trace options Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 2/5] libtracefs: Unit tests for tracing options APIs Tzvetomir Stoyanov (VMware)
@ 2021-01-15  5:04 ` Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 4/5] libtracefs: New APIs for getting existing trace instance Tzvetomir Stoyanov (VMware)
  2021-01-15  5:04 ` [PATCH 5/5] libtracefs: Unit tests for working with non default tracing dir Tzvetomir Stoyanov (VMware)
  4 siblings, 0 replies; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-01-15  5:04 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

There are use cases, where the library could be used with non default
system trace directory - for example a partial copy of a system trace
directory from another machine. More flexibility is added to the tracefs
library, to handle these use cases. The full path to the system trace
directory is added in the instance structure and is used to get trace
files from that instance.

Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
 src/tracefs-instance.c | 80 ++++++++++++++++++++++++++----------------
 1 file changed, 49 insertions(+), 31 deletions(-)

diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c
index b5f8298..468da1b 100644
--- a/src/tracefs-instance.c
+++ b/src/tracefs-instance.c
@@ -20,30 +20,43 @@
 
 #define FLAG_INSTANCE_NEWLY_CREATED	(1 << 0)
 struct tracefs_instance {
+	char	*trace_dir;
 	char	*name;
 	int	flags;
 };
 
 /**
  * instance_alloc - allocate a new ftrace instance
+ * @trace_dir - Full path to the tracing directory, where the instance is
  * @name: The name of the instance (instance will point to this)
  *
  * Returns a newly allocated instance, or NULL in case of an error.
  */
-static struct tracefs_instance *instance_alloc(const char *name)
+static struct tracefs_instance *instance_alloc(const char *trace_dir, const char *name)
 {
 	struct tracefs_instance *instance;
 
 	instance = calloc(1, sizeof(*instance));
-	if (instance && name) {
+	if (!instance)
+		goto error;
+	instance->trace_dir = strdup(trace_dir);
+	if (!instance->trace_dir)
+		goto error;
+	if (name) {
 		instance->name = strdup(name);
-		if (!instance->name) {
-			free(instance);
-			instance = NULL;
-		}
+		if (!instance->name)
+			goto error;
 	}
 
 	return instance;
+
+error:
+	if (instance) {
+		free(instance->name);
+		free(instance->trace_dir);
+		free(instance);
+	}
+	return NULL;
 }
 
 /**
@@ -56,6 +69,7 @@ void tracefs_instance_free(struct tracefs_instance *instance)
 {
 	if (!instance)
 		return;
+	free(instance->trace_dir);
 	free(instance->name);
 	free(instance);
 }
@@ -105,12 +119,16 @@ bool tracefs_instance_is_new(struct tracefs_instance *instance)
 struct tracefs_instance *tracefs_instance_create(const char *name)
 {
 	struct tracefs_instance *inst = NULL;
+	char *path = NULL;
+	const char *tdir;
 	struct stat st;
 	mode_t mode;
-	char *path;
 	int ret;
 
-	inst = instance_alloc(name);
+	tdir = tracefs_tracing_dir();
+	if (!tdir)
+		return NULL;
+	inst = instance_alloc(tdir, name);
 	if (!inst)
 		return NULL;
 
@@ -170,18 +188,18 @@ int tracefs_instance_destroy(struct tracefs_instance *instance)
 char *
 tracefs_instance_get_file(struct tracefs_instance *instance, const char *file)
 {
-	char *path;
-	char *buf;
+	char *path = NULL;
 	int ret;
 
-	if (instance && instance->name) {
-		ret = asprintf(&buf, "instances/%s/%s", instance->name, file);
-		if (ret < 0)
-			return NULL;
-		path = tracefs_get_tracing_file(buf);
-		free(buf);
-	} else
-		path = tracefs_get_tracing_file(file);
+	if (!instance)
+		return tracefs_get_tracing_file(file);
+	if (!instance->name)
+		ret = asprintf(&path, "%s/%s", instance->trace_dir, file);
+	else
+		ret = asprintf(&path, "%s/instances/%s/%s",
+			       instance->trace_dir, instance->name, file);
+	if (ret < 0)
+		return NULL;
 
 	return path;
 }
@@ -196,21 +214,21 @@ tracefs_instance_get_file(struct tracefs_instance *instance, const char *file)
  */
 char *tracefs_instance_get_dir(struct tracefs_instance *instance)
 {
-	char *buf;
-	char *path;
+	char *path = NULL;
 	int ret;
 
-	if (instance && instance->name) {
-		ret = asprintf(&buf, "instances/%s", instance->name);
-		if (ret < 0) {
-			warning("Failed to allocate path for instance %s",
-				 instance->name);
-			return NULL;
-		}
-		path = tracefs_get_tracing_file(buf);
-		free(buf);
-	} else
-		path = trace_find_tracing_dir();
+	if (!instance) /* Top instance of default system trace directory */
+		return trace_find_tracing_dir();
+
+	if (!instance->name)
+		return strdup(instance->trace_dir);
+
+	ret = asprintf(&path, "%s/instances/%s", instance->trace_dir, instance->name);
+	if (ret < 0) {
+		warning("Failed to allocate path for instance %s",
+			 instance->name);
+		return NULL;
+	}
 
 	return path;
 }
-- 
2.29.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 4/5] libtracefs: New APIs for getting existing trace instance
  2021-01-15  5:04 [PATCH 0/5] New libtracefs APIs for trace options and trace dir Tzvetomir Stoyanov (VMware)
                   ` (2 preceding siblings ...)
  2021-01-15  5:04 ` [PATCH 3/5] libtracefs: Add information about top tracing directory in instance structure Tzvetomir Stoyanov (VMware)
@ 2021-01-15  5:04 ` Tzvetomir Stoyanov (VMware)
  2021-01-19 22:18   ` Steven Rostedt
  2021-01-15  5:04 ` [PATCH 5/5] libtracefs: Unit tests for working with non default tracing dir Tzvetomir Stoyanov (VMware)
  4 siblings, 1 reply; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-01-15  5:04 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

The new API allocates an instance structure for existing trace instance.
It has an optional tracing_dir parameter, which allows to get instances
from non default trace directory. If the instance with the given name does
not exist, the API fails. If no name is given, the structure for the top
instance in the given trace directory is allocated and returned.

struct tracefs_instance *tracefs_instance_get(const char *tracing_dir,
					      const char *name);

This helper API is added also, to get the tracing directory where the
instance is configured. In most cases this should be the default system
trace directroy mount point.

const char *tracefs_instance_get_trace_dir(struct tracefs_instance *instance);

Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
 include/tracefs.h      |  3 +++
 src/tracefs-instance.c | 57 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+)

diff --git a/include/tracefs.h b/include/tracefs.h
index 1f10a00..20aa995 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -20,9 +20,12 @@ struct tracefs_instance;
 
 void tracefs_instance_free(struct tracefs_instance *instance);
 struct tracefs_instance *tracefs_instance_create(const char *name);
+struct tracefs_instance *tracefs_instance_get(const char *tracing_dir,
+					      const char *name);
 int tracefs_instance_destroy(struct tracefs_instance *instance);
 bool tracefs_instance_is_new(struct tracefs_instance *instance);
 const char *tracefs_instance_get_name(struct tracefs_instance *instance);
+const char *tracefs_instance_get_trace_dir(struct tracefs_instance *instance);
 char *
 tracefs_instance_get_file(struct tracefs_instance *instance, const char *file);
 char *tracefs_instance_get_dir(struct tracefs_instance *instance);
diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c
index 468da1b..112e237 100644
--- a/src/tracefs-instance.c
+++ b/src/tracefs-instance.c
@@ -151,6 +151,49 @@ error:
 	return NULL;
 }
 
+/**
+ * tracefs_instance_get - Allocate an instance structure for existing trace instance
+ * @tracing_dir: full path to the system trace directory, where the new instance is
+ *		 if NULL, the default top tracing directory is used.
+ * @name: Name of the instance.
+ *
+ * Allocates and initializes a new instance structure. If the instance does not
+ * exist, do not create it and exit with error.
+ * Returns a pointer to a newly allocated instance, or NULL in case of an error
+ * or the requested instance does not exists.
+ * The returned instance must be freed by tracefs_instance_free().
+ */
+struct tracefs_instance *tracefs_instance_get(const char *tracing_dir,
+					      const char *name)
+{
+	struct tracefs_instance *inst = NULL;
+	char file[PATH_MAX];
+	const char *tdir;
+	struct stat st;
+	int ret;
+
+	if (tracing_dir) {
+		ret = stat(tracing_dir, &st);
+		if (ret < 0 || !S_ISDIR(st.st_mode))
+			return NULL;
+		tdir = tracing_dir;
+
+	} else
+		tdir = tracefs_tracing_dir();
+	if (!tdir)
+		return NULL;
+
+	if (name) {
+		sprintf(file, "%s/instances/%s", tdir, name);
+		ret = stat(file, &st);
+		if (ret < 0 || !S_ISDIR(st.st_mode))
+			return NULL;
+	}
+	inst = instance_alloc(tdir, name);
+
+	return inst;
+}
+
 /**
  * tracefs_instance_destroy - Remove a ftrace instance
  * @instance: Pointer to the instance to be removed
@@ -247,6 +290,20 @@ const char *tracefs_instance_get_name(struct tracefs_instance *instance)
 	return NULL;
 }
 
+/**
+ * tracefs_instance_get_trace_dir - return the top trace directory, where the instance is confuigred
+ * @instance: ftrace instance
+ *
+ * Returns the top trace directory where the given @instance is configured.
+ * The returned string must *not* be freed.
+ */
+const char *tracefs_instance_get_trace_dir(struct tracefs_instance *instance)
+{
+	if (instance)
+		return instance->trace_dir;
+	return NULL;
+}
+
 static int write_file(const char *file, const char *str)
 {
 	int ret;
-- 
2.29.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 5/5] libtracefs: Unit tests for working with non default tracing dir
  2021-01-15  5:04 [PATCH 0/5] New libtracefs APIs for trace options and trace dir Tzvetomir Stoyanov (VMware)
                   ` (3 preceding siblings ...)
  2021-01-15  5:04 ` [PATCH 4/5] libtracefs: New APIs for getting existing trace instance Tzvetomir Stoyanov (VMware)
@ 2021-01-15  5:04 ` Tzvetomir Stoyanov (VMware)
  4 siblings, 0 replies; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-01-15  5:04 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

All unit tests are modified to work with custom defined trace directory,
instead of default system one. A new tests are added which duplicate
part of the system trace directory and test various library APIs on
that copy.

Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
 utest/tracefs-utest.c | 349 +++++++++++++++++++++++++++++++-----------
 1 file changed, 261 insertions(+), 88 deletions(-)

diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
index 1ade5dd..a45a19a 100644
--- a/utest/tracefs-utest.c
+++ b/utest/tracefs-utest.c
@@ -10,6 +10,7 @@
 #include <unistd.h>
 #include <time.h>
 #include <dirent.h>
+#include <ftw.h>
 
 #include <CUnit/CUnit.h>
 #include <CUnit/Basic.h>
@@ -18,8 +19,15 @@
 
 #define TRACEFS_SUITE		"trasefs library"
 #define TEST_INSTANCE_NAME	"cunit_test_iter"
+#define TEST_TRACE_DIR		"/tmp/trace_utest.XXXXXX"
 #define TEST_ARRAY_SIZE		500
 
+#define ALL_TRACERS	"available_tracers"
+#define CUR_TRACER	"current_tracer"
+#define PER_CPU		"per_cpu"
+#define TRACE_ON	"tracing_on"
+#define TRACE_CLOCK	"trace_clock"
+
 static struct tracefs_instance *test_instance;
 static struct tep_handle *test_tep;
 struct test_sample {
@@ -55,7 +63,7 @@ static int test_callback(struct tep_event *event, struct tep_record *record,
 	return 0;
 }
 
-static void test_iter_write(void)
+static void test_iter_write(struct tracefs_instance *instance)
 {
 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
 	cpu_set_t *cpuset, *cpusave;
@@ -70,7 +78,7 @@ static void test_iter_write(void)
 
 	sched_getaffinity(0, cpu_size, cpusave);
 
-	path = tracefs_instance_get_file(test_instance, "trace_marker");
+	path = tracefs_instance_get_file(instance, "trace_marker");
 	CU_TEST(path != NULL);
 	fd = open(path, O_WRONLY);
 	tracefs_put_tracing_file(path);
@@ -94,15 +102,15 @@ static void test_iter_write(void)
 }
 
 
-static void iter_raw_events_on_cpu(int cpu)
+static void iter_raw_events_on_cpu(struct tracefs_instance *instance, int cpu)
 {
 	int check = 0;
 	int ret;
 	int i;
 
 	test_found = 0;
-	test_iter_write();
-	ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, 0,
+	test_iter_write(instance);
+	ret = tracefs_iterate_raw_events(test_tep, instance, NULL, 0,
 					 test_callback, &cpu);
 	CU_TEST(ret == 0);
 	if (cpu < 0) {
@@ -120,22 +128,27 @@ static void iter_raw_events_on_cpu(int cpu)
 	}
 }
 
-static void test_iter_raw_events(void)
+static void test_instance_iter_raw_events(struct tracefs_instance *instance)
 {
 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
 	int ret;
 	int i;
 
-	ret = tracefs_iterate_raw_events(NULL, test_instance, NULL, 0, test_callback, NULL);
+	ret = tracefs_iterate_raw_events(NULL, instance, NULL, 0, test_callback, NULL);
 	CU_TEST(ret < 0);
 	ret = tracefs_iterate_raw_events(test_tep, NULL, NULL, 0, test_callback, NULL);
 	CU_TEST(ret == 0);
-	ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, 0, NULL, NULL);
+	ret = tracefs_iterate_raw_events(test_tep, instance, NULL, 0, NULL, NULL);
 	CU_TEST(ret < 0);
 
-	iter_raw_events_on_cpu(-1);
+	iter_raw_events_on_cpu(instance, -1);
 	for (i = 0; i < cpus; i++)
-		iter_raw_events_on_cpu(i);
+		iter_raw_events_on_cpu(instance, i);
+}
+
+static void test_iter_raw_events(void)
+{
+	test_instance_iter_raw_events(test_instance);
 }
 
 #define RAND_STR_SIZE 20
@@ -215,10 +228,6 @@ static void test_instance_file_read(struct tracefs_instance *inst, const char *f
 	free(file);
 }
 
-#define ALL_TRACERS	"available_tracers"
-#define CUR_TRACER	"current_tracer"
-#define PER_CPU		"per_cpu"
-#define TRACE_ON	"tracing_on"
 static void test_instance_file(void)
 {
 	struct tracefs_instance *instance = NULL;
@@ -323,7 +332,7 @@ static void test_instance_file(void)
 	free(inst_dir);
 }
 
-static bool check_fd_name(int fd, char *name)
+static bool check_fd_name(int fd, const char *dir, const char *name)
 {
 	char link[PATH_MAX + 1];
 	char path[PATH_MAX + 1];
@@ -344,6 +353,10 @@ static bool check_fd_name(int fd, char *name)
 	if (ret > PATH_MAX || ret < 0)
 		return false;
 	path[ret] = 0;
+	ret = strncmp(dir, path, strlen(dir));
+	CU_TEST(ret == 0);
+	if (ret)
+		return false;
 	file = basename(path);
 	CU_TEST(file != NULL);
 	if (!file)
@@ -389,23 +402,26 @@ static bool check_fd_mode(int fd, int mode)
 	return true;
 }
 
-static void test_instance_file_fd(void)
+static void test_instance_file_fd(struct tracefs_instance *instance)
 {
 	const char *name = get_rand_str();
+	const char *tdir = tracefs_instance_get_trace_dir(instance);
 	long long res = -1;
 	char rd[2];
 	int fd;
 
-	fd = tracefs_instance_file_open(test_instance, name, -1);
+	CU_TEST(tdir != NULL);
+	fd = tracefs_instance_file_open(instance, name, -1);
 	CU_TEST(fd == -1);
-	fd = tracefs_instance_file_open(test_instance, TRACE_ON, O_RDONLY);
+	fd = tracefs_instance_file_open(instance, TRACE_ON, O_RDONLY);
 	CU_TEST(fd >= 0);
-	CU_TEST(check_fd_name(fd, TRACE_ON));
+
+	CU_TEST(check_fd_name(fd, tdir, TRACE_ON));
 	CU_TEST(check_fd_mode(fd, O_RDONLY));
 
-	CU_TEST(tracefs_instance_file_read_number(test_instance, "available_tracer", &res) != 0);
-	CU_TEST(tracefs_instance_file_read_number(test_instance, name, &res) != 0);
-	CU_TEST(tracefs_instance_file_read_number(test_instance, TRACE_ON, &res) == 0);
+	CU_TEST(tracefs_instance_file_read_number(instance, ALL_TRACERS, &res) != 0);
+	CU_TEST(tracefs_instance_file_read_number(instance, name, &res) != 0);
+	CU_TEST(tracefs_instance_file_read_number(instance, TRACE_ON, &res) == 0);
 	CU_TEST((res == 0 || res == 1));
 	CU_TEST(read(fd, &rd, 1) == 1);
 	rd[1] = 0;
@@ -414,45 +430,57 @@ static void test_instance_file_fd(void)
 	close(fd);
 }
 
-static void test_tracing_onoff(void)
+static void test_file_fd(void)
 {
+	test_instance_file_fd(test_instance);
+}
+
+static void test_instance_tracing_onoff(struct tracefs_instance *instance)
+{
+	const char *tdir = tracefs_instance_get_trace_dir(instance);
 	long long res = -1;
 	int fd;
 
-	fd = tracefs_trace_on_get_fd(test_instance);
+	CU_TEST(tdir != NULL);
+	fd = tracefs_trace_on_get_fd(instance);
 	CU_TEST(fd >= 0);
-	CU_TEST(check_fd_name(fd, TRACE_ON));
+	CU_TEST(check_fd_name(fd, tdir, TRACE_ON));
 	CU_TEST(check_fd_mode(fd, O_RDWR));
-	CU_TEST(tracefs_instance_file_read_number(test_instance, TRACE_ON, &res) == 0);
+	CU_TEST(tracefs_instance_file_read_number(instance, TRACE_ON, &res) == 0);
 	if (res == 1) {
-		CU_TEST(tracefs_trace_is_on(test_instance) == 1);
-		CU_TEST(tracefs_trace_off(test_instance) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 0);
-		CU_TEST(tracefs_trace_on(test_instance) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 1);
+		CU_TEST(tracefs_trace_is_on(instance) == 1);
+		CU_TEST(tracefs_trace_off(instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 0);
+		CU_TEST(tracefs_trace_on(instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 1);
 
 		CU_TEST(tracefs_trace_off_fd(fd) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 0);
 		CU_TEST(tracefs_trace_on_fd(fd) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 1);
+		CU_TEST(tracefs_trace_is_on(instance) == 1);
 	} else {
-		CU_TEST(tracefs_trace_is_on(test_instance) == 0);
-		CU_TEST(tracefs_trace_on(test_instance) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 1);
-		CU_TEST(tracefs_trace_off(test_instance) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 0);
+		CU_TEST(tracefs_trace_on(instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 1);
+		CU_TEST(tracefs_trace_off(instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 0);
 
 		CU_TEST(tracefs_trace_on_fd(fd) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 1);
+		CU_TEST(tracefs_trace_is_on(instance) == 1);
 		CU_TEST(tracefs_trace_off_fd(fd) == 0);
-		CU_TEST(tracefs_trace_is_on(test_instance) == 0);
+		CU_TEST(tracefs_trace_is_on(instance) == 0);
 	}
 
 	if (fd >= 0)
 		close(fd);
 }
 
-static bool check_option(long long id, bool exist, int enabled)
+static void test_tracing_onoff(void)
+{
+	test_instance_tracing_onoff(test_instance);
+}
+
+static bool check_option(struct tracefs_instance *instance, long long id, bool exist, int enabled)
 {
 	const char *name = tracefs_option_string(id);
 	char file[PATH_MAX];
@@ -466,12 +494,12 @@ static bool check_option(long long id, bool exist, int enabled)
 	int rstat;
 
 	CU_TEST(name != NULL);
-	supported = tracefs_option_is_supported(test_instance, id);
+	supported = tracefs_option_is_supported(instance, id);
 	CU_TEST(supported == exist);
 	if (supported != exist)
 		goto out;
 	snprintf(file, PATH_MAX, "options/%s", name);
-	path = tracefs_instance_get_file(test_instance, file);
+	path = tracefs_instance_get_file(instance, file);
 	CU_TEST(path != NULL);
 	rstat = stat(path, &st);
 	if (exist) {
@@ -499,7 +527,7 @@ static bool check_option(long long id, bool exist, int enabled)
 		int val = enabled ? '1' : '0';
 
 		r = read(fd, buf, 10);
-		CU_TEST(r == 2);
+		CU_TEST(r >= 1);
 		CU_TEST(buf[0] == val);
 		if (buf[0] != val)
 			goto out;
@@ -513,7 +541,7 @@ out:
 	return ret;
 }
 
-static void test_tracing_options(void)
+static void test_instance_tracing_options(struct tracefs_instance *instance)
 {
 	unsigned long long options_enabled = 0;
 	unsigned long long options_all = 0;
@@ -521,15 +549,15 @@ static void test_tracing_options(void)
 	char file[PATH_MAX];
 	const char *name;
 
-	options_all = tracefs_options_get_supported(test_instance);
-	options_enabled = tracefs_options_get_enabled(test_instance);
+	options_all = tracefs_options_get_supported(instance);
+	options_enabled = tracefs_options_get_enabled(instance);
 	CU_TEST(options_all > 0);
 
 	/* Invalid parameters test */
-	CU_TEST(!tracefs_option_is_supported(test_instance, TRACEFS_OPTION_INVALID << 1));
-	CU_TEST(!tracefs_option_is_enabled(test_instance, TRACEFS_OPTION_INVALID << 1));
-	CU_TEST(tracefs_options_set(test_instance, TRACEFS_OPTION_INVALID << 1) == -1);
-	CU_TEST(tracefs_options_clear(test_instance, TRACEFS_OPTION_INVALID << 1) == -1);
+	CU_TEST(!tracefs_option_is_supported(instance, TRACEFS_OPTION_INVALID << 1));
+	CU_TEST(!tracefs_option_is_enabled(instance, TRACEFS_OPTION_INVALID << 1));
+	CU_TEST(tracefs_options_set(instance, TRACEFS_OPTION_INVALID << 1) == -1);
+	CU_TEST(tracefs_options_clear(instance, TRACEFS_OPTION_INVALID << 1) == -1);
 	name = tracefs_option_string(TRACEFS_OPTION_INVALID << 1);
 	CU_TEST(!strcmp(name, "unknown"));
 
@@ -542,37 +570,41 @@ static void test_tracing_options(void)
 
 		if (options_all & i) {
 			options_all &= ~i;
-			CU_TEST(check_option(i, true, -1));
-			CU_TEST(tracefs_option_is_supported(test_instance, i));
+			CU_TEST(check_option(instance, i, true, -1));
+			CU_TEST(tracefs_option_is_supported(instance, i));
 		} else {
-			CU_TEST(check_option(i, false, -1));
-			CU_TEST(!tracefs_option_is_supported(test_instance, i));
+			CU_TEST(check_option(instance, i, false, -1));
+			CU_TEST(!tracefs_option_is_supported(instance, i));
 		}
 
 		if (options_enabled & i) {
 			options_enabled &= ~i;
-			CU_TEST(check_option(i, true, 1));
-			CU_TEST(tracefs_option_is_supported(test_instance, i));
-			CU_TEST(tracefs_option_is_enabled(test_instance, i));
-			CU_TEST(tracefs_options_clear(test_instance, i) == 0);
-			CU_TEST(check_option(i, true, 0));
-			CU_TEST(tracefs_options_set(test_instance, i) == 0);
-			CU_TEST(check_option(i, true, 1));
+			CU_TEST(check_option(instance, i, true, 1));
+			CU_TEST(tracefs_option_is_supported(instance, i));
+			CU_TEST(tracefs_option_is_enabled(instance, i));
+			CU_TEST(tracefs_options_clear(instance, i) == 0);
+			CU_TEST(check_option(instance, i, true, 0));
+			CU_TEST(tracefs_options_set(instance, i) == 0);
+			CU_TEST(check_option(instance, i, true, 1));
 		} else if (options_all & i) {
-			CU_TEST(check_option(i, true, 0));
-			CU_TEST(tracefs_option_is_supported(test_instance, i));
-			CU_TEST(!tracefs_option_is_enabled(test_instance, i));
-			CU_TEST(tracefs_options_set(test_instance, i) == 0);
-			CU_TEST(check_option(i, true, 1));
-			CU_TEST(tracefs_options_clear(test_instance, i) == 0);
-			CU_TEST(check_option(i, true, 0));
+			CU_TEST(check_option(instance, i, true, 0));
+			CU_TEST(tracefs_option_is_supported(instance, i));
+			CU_TEST(!tracefs_option_is_enabled(instance, i));
+			CU_TEST(tracefs_options_set(instance, i) == 0);
+			CU_TEST(check_option(instance, i, true, 1));
+			CU_TEST(tracefs_options_clear(instance, i) == 0);
+			CU_TEST(check_option(instance, i, true, 0));
 		}
 		i <<= 1;
 	} while (i < TRACEFS_OPTION_INVALID);
 
 	CU_TEST(options_all == 0);
 	CU_TEST(options_enabled == 0);
+}
 
+static void test_tracing_options(void)
+{
+	test_instance_tracing_options(test_instance);
 }
 
 static void exclude_string(char **strings, char *name)
@@ -606,16 +638,13 @@ static void test_check_files(const char *fdir, char **files)
 		CU_TEST(files[i][0] == '/');
 }
 
-static void test_system_event(void)
+static void system_event(const char *tdir)
 {
-	const char *tdir;
+
 	char **systems;
 	char **events;
 	char *sdir = NULL;
 
-	tdir  = tracefs_tracing_dir();
-	CU_TEST(tdir != NULL);
-
 	systems = tracefs_event_systems(tdir);
 	CU_TEST(systems != NULL);
 
@@ -638,7 +667,16 @@ static void test_system_event(void)
 	free(sdir);
 }
 
-static void test_tracers(void)
+static void test_system_event(void)
+{
+	const char *tdir;
+
+	tdir  = tracefs_tracing_dir();
+	CU_TEST(tdir != NULL);
+	system_event(tdir);
+}
+
+static void test_instance_tracers(struct tracefs_instance *instance)
 {
 	const char *tdir;
 	char **tracers;
@@ -646,7 +684,7 @@ static void test_tracers(void)
 	char *tracer;
 	int i;
 
-	tdir  = tracefs_tracing_dir();
+	tdir  = tracefs_instance_get_trace_dir(instance);
 	CU_TEST(tdir != NULL);
 
 	tracers = tracefs_tracers(tdir);
@@ -667,6 +705,11 @@ static void test_tracers(void)
 	free(tfile);
 }
 
+static void test_tracers(void)
+{
+	test_instance_tracers(test_instance);
+}
+
 static void test_check_events(struct tep_handle *tep, char *system, bool exist)
 {
 	struct dirent *dent;
@@ -706,17 +749,13 @@ static void test_check_events(struct tep_handle *tep, char *system, bool exist)
 
 }
 
-static void test_local_events(void)
+static void local_events(const char *tdir)
 {
 	struct tep_handle *tep;
-	const char *tdir;
 	char **systems;
 	char *lsystems[3];
 	int i;
 
-	tdir  = tracefs_tracing_dir();
-	CU_TEST(tdir != NULL);
-
 	tep = tracefs_local_events(tdir);
 	CU_TEST(tep != NULL);
 
@@ -757,6 +796,15 @@ static void test_local_events(void)
 	tracefs_list_free(systems);
 }
 
+static void test_local_events(void)
+{
+	const char *tdir;
+
+	tdir  = tracefs_tracing_dir();
+	CU_TEST(tdir != NULL);
+	local_events(tdir);
+}
+
 struct test_walk_instance {
 	struct tracefs_instance *instance;
 	bool found;
@@ -806,13 +854,13 @@ static void test_instances_walk(void)
 	}
 }
 
-static void current_clock_check(const char *clock)
+static void current_clock_check(struct tracefs_instance *instance, const char *clock)
 {
 	int size = 0;
 	char *clocks;
 	char *str;
 
-	clocks = tracefs_instance_file_read(test_instance, "trace_clock", &size);
+	clocks = tracefs_instance_file_read(instance, TRACE_CLOCK, &size);
 	CU_TEST(clocks != NULL);
 	CU_TEST(size > strlen(clock));
 	str = strstr(clocks, clock);
@@ -823,16 +871,140 @@ static void current_clock_check(const char *clock)
 	free(clocks);
 }
 
-static void test_get_clock(void)
+static void test_instance_get_clock(struct tracefs_instance *instance)
 {
 	const char *clock;
 
-	clock = tracefs_get_clock(test_instance);
+	clock = tracefs_get_clock(instance);
 	CU_TEST(clock != NULL);
-	current_clock_check(clock);
+	current_clock_check(instance, clock);
 	free((char *)clock);
 }
 
+static void test_get_clock(void)
+{
+	test_instance_get_clock(test_instance);
+}
+
+static void copy_trace_file(const char *from, char *to)
+{
+	int fd_from = -1;
+	int fd_to = -1;
+	char buf[512];
+	int ret;
+
+	fd_from = open(from, O_RDONLY);
+	if (fd_from < 0)
+		goto out;
+	fd_to = open(to, O_WRONLY | O_TRUNC | O_CREAT);
+	if (fd_to < 0)
+		goto out;
+
+	while ((ret = read(fd_from, buf, 512)) > 0) {
+		if (write(fd_to, buf, ret) == -1)
+			break;
+	}
+
+out:
+	if (fd_to >= 0)
+		close(fd_to);
+	if (fd_from >= 0)
+		close(fd_from);
+}
+
+static int trace_dir_base;
+static char *trace_tmp_dir;
+static int copy_trace_walk(const char *fpath, const struct stat *sb,
+			   int typeflag, struct FTW *ftwbuf)
+{
+	char path[PATH_MAX];
+
+	sprintf(path, "%s%s", trace_tmp_dir, fpath + trace_dir_base);
+
+	switch (typeflag) {
+	case FTW_D:
+		mkdir(path, 0750);
+		break;
+	case FTW_F:
+		copy_trace_file(fpath, path);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static void dup_trace_dir(char *to, char *dir)
+{
+	const char *trace_dir = tracefs_tracing_dir();
+	char file_from[PATH_MAX];
+	char file_to[PATH_MAX];
+
+	sprintf(file_from, "%s/%s", trace_dir, dir);
+	sprintf(file_to, "%s/%s", to, dir);
+	trace_tmp_dir = file_to;
+	trace_dir_base = strlen(file_from);
+	nftw(file_from, copy_trace_walk, 20, 0);
+}
+
+static void dup_trace_file(char *to, char *file)
+{
+	const char *trace_dir = tracefs_tracing_dir();
+	char file_from[PATH_MAX];
+	char file_to[PATH_MAX];
+
+	sprintf(file_from, "%s/%s", trace_dir, file);
+	sprintf(file_to, "%s/%s", to, file);
+	copy_trace_file(file_from, file_to);
+}
+
+static char *copy_trace_dir(void)
+{
+	char template[] = TEST_TRACE_DIR;
+	char *dname = mkdtemp(template);
+
+	dup_trace_dir(dname, "events");
+	dup_trace_dir(dname, "options");
+	dup_trace_file(dname, TRACE_ON);
+	dup_trace_file(dname, CUR_TRACER);
+	dup_trace_file(dname, TRACE_CLOCK);
+	dup_trace_file(dname, ALL_TRACERS);
+
+	return strdup(dname);
+}
+
+static int del_trace_walk(const char *fpath, const struct stat *sb,
+			  int typeflag, struct FTW *ftwbuf)
+{
+	remove(fpath);
+	return 0;
+}
+
+void del_trace_dir(char *dir)
+{
+	nftw(dir, del_trace_walk, 20, FTW_DEPTH);
+}
+
+static void test_custom_trace_dir(void)
+{
+	struct tracefs_instance *instance;
+	char *dname = copy_trace_dir();
+
+	instance = tracefs_instance_get(dname, NULL);
+	CU_TEST(instance != NULL);
+
+	system_event(dname);
+	local_events(dname);
+	test_instance_tracing_options(instance);
+	test_instance_get_clock(instance);
+	test_instance_file_fd(instance);
+	test_instance_tracers(instance);
+
+	tracefs_instance_free(instance);
+	del_trace_dir(dname);
+	free(dname);
+}
+
 static int test_suite_destroy(void)
 {
 	tracefs_instance_destroy(test_instance);
@@ -867,7 +1039,7 @@ void test_tracefs_lib(void)
 	CU_add_test(suite, "tracing file / directory APIs",
 		    test_trace_file);
 	CU_add_test(suite, "instance file / directory APIs",
-		    test_instance_file_fd);
+		    test_file_fd);
 	CU_add_test(suite, "instance file descriptor",
 		    test_instance_file);
 	CU_add_test(suite, "systems and events APIs",
@@ -886,5 +1058,6 @@ void test_tracefs_lib(void)
 		    test_tracing_onoff);
 	CU_add_test(suite, "tracing options",
 		    test_tracing_options);
-
+	CU_add_test(suite, "custom system directory",
+		    test_custom_trace_dir);
 }
-- 
2.29.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/5] libtracefs: New APIs for trace options
  2021-01-15  5:04 ` [PATCH 1/5] libtracefs: New APIs for trace options Tzvetomir Stoyanov (VMware)
@ 2021-01-19 21:12   ` Steven Rostedt
  0 siblings, 0 replies; 8+ messages in thread
From: Steven Rostedt @ 2021-01-19 21:12 UTC (permalink / raw)
  To: Tzvetomir Stoyanov (VMware); +Cc: linux-trace-devel

On Fri, 15 Jan 2021 07:04:06 +0200
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:

> These new APIs can be used to check and set various trace options
> 
> tracefs_options_get_supported();
> tracefs_option_is_supported();
> tracefs_options_get_enabled();
> tracefs_option_is_enabled();
> tracefs_options_set();
> tracefs_options_clear();
> tracefs_option_string();
> 
> Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
> ---
>  include/tracefs.h   |  54 ++++++++++
>  src/tracefs-tools.c | 251 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 305 insertions(+)
> 
> diff --git a/include/tracefs.h b/include/tracefs.h
> index 85a776e..1f10a00 100644
> --- a/include/tracefs.h
> +++ b/include/tracefs.h
> @@ -80,4 +80,58 @@ int tracefs_fill_local_events(const char *tracing_dir,
>  
>  char *tracefs_get_clock(struct tracefs_instance *instance);
>  
> +#define		TRACEFS_OPTION_ANNOTATE		((unsigned long long)1 << 0)
> +#define		TRACEFS_OPTION_BIN		((unsigned long long)1 << 1)
> +#define		TRACEFS_OPTION_BLK_CGNAME	((unsigned long long)1 << 2)
> +#define		TRACEFS_OPTION_BLK_CGROUP	((unsigned long long)1 << 3)
> +#define		TRACEFS_OPTION_BLK_CLASSIC	((unsigned long long)1 << 4)
> +#define		TRACEFS_OPTION_BLOCK		((unsigned long long)1 << 5)
> +#define		TRACEFS_OPTION_CONTEXT_INFO	((unsigned long long)1 << 6)
> +#define		TRACEFS_OPTION_DISABLE_ON_FREE	((unsigned long long)1 << 7)
> +#define		TRACEFS_OPTION_DISPLAY_GRAPH	((unsigned long long)1 << 8)
> +#define		TRACEFS_OPTION_EVENT_FORK	((unsigned long long)1 << 9)
> +#define		TRACEFS_OPTION_FGRAPH_ABSTIME	((unsigned long long)1 << 10)
> +#define		TRACEFS_OPTION_FGRAPH_CPU	((unsigned long long)1 << 11)
> +#define		TRACEFS_OPTION_FGRAPH_DURATION	((unsigned long long)1 << 12)
> +#define		TRACEFS_OPTION_FGRAPH_IRQS	((unsigned long long)1 << 13)
> +#define		TRACEFS_OPTION_FGRAPH_OVERHEAD	((unsigned long long)1 << 14)
> +#define		TRACEFS_OPTION_FGRAPH_OVERRUN	((unsigned long long)1 << 15)
> +#define		TRACEFS_OPTION_FGRAPH_PROC	((unsigned long long)1 << 16)
> +#define		TRACEFS_OPTION_FGRAPH_TAIL	((unsigned long long)1 << 17)
> +#define		TRACEFS_OPTION_FUNC_STACKTRACE	((unsigned long long)1 << 18)
> +#define		TRACEFS_OPTION_FUNCTION_FORK	((unsigned long long)1 << 19)
> +#define		TRACEFS_OPTION_FUNCTION_TRACE	((unsigned long long)1 << 20)
> +#define		TRACEFS_OPTION_GRAPH_TIME	((unsigned long long)1 << 21)
> +#define		TRACEFS_OPTION_HEX		((unsigned long long)1 << 22)
> +#define		TRACEFS_OPTION_IRQ_INFO		((unsigned long long)1 << 23)
> +#define		TRACEFS_OPTION_LATENCY_FORMAT	((unsigned long long)1 << 24)
> +#define		TRACEFS_OPTION_MARKERS		((unsigned long long)1 << 25)
> +#define		TRACEFS_OPTION_OVERWRITE	((unsigned long long)1 << 26)
> +#define		TRACEFS_OPTION_PAUSE_ON_TRACE	((unsigned long long)1 << 27)
> +#define		TRACEFS_OPTION_PRINTK_MSG_ONLY	((unsigned long long)1 << 28)
> +#define		TRACEFS_OPTION_PRINT_PARENT	((unsigned long long)1 << 29)
> +#define		TRACEFS_OPTION_RAW		((unsigned long long)1 << 30)
> +#define		TRACEFS_OPTION_RECORD_CMD	((unsigned long long)1 << 31)
> +#define		TRACEFS_OPTION_RECORD_TGID	((unsigned long long)1 << 32)
> +#define		TRACEFS_OPTION_SLEEP_TIME	((unsigned long long)1 << 33)
> +#define		TRACEFS_OPTION_STACKTRACE	((unsigned long long)1 << 34)
> +#define		TRACEFS_OPTION_SYM_ADDR		((unsigned long long)1 << 35)
> +#define		TRACEFS_OPTION_SYM_OFFSET	((unsigned long long)1 << 36)
> +#define		TRACEFS_OPTION_SYM_USEROBJ	((unsigned long long)1 << 37)
> +#define		TRACEFS_OPTION_TEST_NOP_ACCEPT	((unsigned long long)1 << 38)
> +#define		TRACEFS_OPTION_TEST_NOP_REFUSE	((unsigned long long)1 << 39)
> +#define		TRACEFS_OPTION_TRACE_PRINTK	((unsigned long long)1 << 40)
> +#define		TRACEFS_OPTION_USERSTACKTRACE	((unsigned long long)1 << 41)
> +#define		TRACEFS_OPTION_VERBOSE		((unsigned long long)1 << 42)
> +
> +#define		TRACEFS_OPTION_INVALID		((unsigned long long)1 << 43)

I really think that we should define "TRACEFS_OPTION_INVALID" as zero.

Especially since we may grow this list, and we don't want INVALID to be in
the middle of valid options. And it should be treated as special. As the
above is a bit mask, a NULL bitmask is "invalid" or "unkown".

Anyway, I would redo the above as bit numbers instead of a bit mask. And we
could abstract out the bitmask in case these options grow beyond 64.

enum tracefs_option_bits {
 TRACEFS_OPTION_ANNOTATE,
 TRACEFS_OPTION_BIN,
 TRACEFS_OPTION_CGNAME,
 [..]
 TRACEFS_OPTION_VERBOSE,
};

#define TRACEFS_OPTION_CURRENT_MAX TRACEFS_OPTION_VERBOSE
#define TRACEFS_OPTION_UNKNOWN		0

struct tracefs_option {
	unsigned long long	mask;
};

typedef struct tracefs_option tracefs_option_t

And encourage people to use accessor functions to use it.

static inline bool tracefs_option_is_set(tracefs_option_t option, int bit)
{
	return option.mask & (1 << bit);
}

static inline void tracefs_option_set(tracefs_option_t *option, int bit)
{
	option->mask |= 1ULL << bit;
}

static inline void tracefs_option_clear(tracefs_option_t *option, int bit)
{
	option->mask &= ~(1ULL << bit);
}

Then replace all the "unsigned long long" with tracefs_option_t.

> +
> +unsigned long long tracefs_options_get_supported(struct tracefs_instance *instance);
> +bool tracefs_option_is_supported(struct tracefs_instance *instance, unsigned long long id);
> +unsigned long long tracefs_options_get_enabled(struct tracefs_instance *instance);
> +bool tracefs_option_is_enabled(struct tracefs_instance *instance, unsigned long long id);
> +int tracefs_options_set(struct tracefs_instance *instance, unsigned long long options);
> +int tracefs_options_clear(struct tracefs_instance *instance, unsigned long long options);
> +const char *tracefs_option_string(unsigned long long id);
> +
>  #endif /* _TRACE_FS_H */
> diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c
> index 101f389..0505552 100644
> --- a/src/tracefs-tools.c
> +++ b/src/tracefs-tools.c
> @@ -9,12 +9,66 @@
>  #include <stdlib.h>
>  #include <unistd.h>
>  #include <fcntl.h>
> +#include <sys/types.h>
> +#include <dirent.h>
> +#include <limits.h>
> +#include <errno.h>
>  
>  #include "tracefs.h"
>  #include "tracefs-local.h"
>  
>  #define TRACE_CTRL	"tracing_on"
>  
> +struct options_map {
> +	unsigned long long id;
> +	char *name;
> +} options_map[] = {

By using bits instead of the mask, we could make "id" == the index of the
array, and make this map just a array of strings. That is:

const char * const *options_map[] =
  { "annotate", "bin", ... };

Then, options_map[TRACEFS_OPTION_ANNOTATE] would be "annotate".


> +	{ TRACEFS_OPTION_ANNOTATE,		"annotate" },
> +	{ TRACEFS_OPTION_BIN,			"bin" },
> +	{ TRACEFS_OPTION_BLK_CGNAME,		"blk_cgname" },
> +	{ TRACEFS_OPTION_BLK_CGROUP,		"blk_cgroup" },
> +	{ TRACEFS_OPTION_BLK_CLASSIC,		"blk_classic" },
> +	{ TRACEFS_OPTION_BLOCK,			"block" },
> +	{ TRACEFS_OPTION_CONTEXT_INFO,		"context-info" },
> +	{ TRACEFS_OPTION_DISABLE_ON_FREE,	"disable_on_free" },
> +	{ TRACEFS_OPTION_DISPLAY_GRAPH,		"display-graph" },
> +	{ TRACEFS_OPTION_EVENT_FORK,		"event-fork" },
> +	{ TRACEFS_OPTION_FGRAPH_ABSTIME,	"funcgraph-abstime" },
> +	{ TRACEFS_OPTION_FGRAPH_CPU,		"funcgraph-cpu" },
> +	{ TRACEFS_OPTION_FGRAPH_DURATION,	"funcgraph-duration" },
> +	{ TRACEFS_OPTION_FGRAPH_IRQS,		"funcgraph-irqs" },
> +	{ TRACEFS_OPTION_FGRAPH_OVERHEAD,	"funcgraph-overhead" },
> +	{ TRACEFS_OPTION_FGRAPH_OVERRUN,	"funcgraph-overrun" },
> +	{ TRACEFS_OPTION_FGRAPH_PROC,		"funcgraph-proc" },
> +	{ TRACEFS_OPTION_FGRAPH_TAIL,		"funcgraph-tail" },
> +	{ TRACEFS_OPTION_FUNC_STACKTRACE,	"func_stack_trace" },
> +	{ TRACEFS_OPTION_FUNCTION_FORK,		"function-fork" },
> +	{ TRACEFS_OPTION_FUNCTION_TRACE,	"function-trace" },
> +	{ TRACEFS_OPTION_GRAPH_TIME,		"graph-time" },
> +	{ TRACEFS_OPTION_HEX,			"hex" },
> +	{ TRACEFS_OPTION_IRQ_INFO,		"irq-info" },
> +	{ TRACEFS_OPTION_LATENCY_FORMAT,	"latency-format" },
> +	{ TRACEFS_OPTION_MARKERS,		"markers" },
> +	{ TRACEFS_OPTION_OVERWRITE,		"overwrite" },
> +	{ TRACEFS_OPTION_PAUSE_ON_TRACE,	"pause-on-trace" },
> +	{ TRACEFS_OPTION_PRINTK_MSG_ONLY,	"printk-msg-only" },
> +	{ TRACEFS_OPTION_PRINT_PARENT,		"print-parent" },
> +	{ TRACEFS_OPTION_RAW,			"raw" },
> +	{ TRACEFS_OPTION_RECORD_CMD,		"record-cmd" },
> +	{ TRACEFS_OPTION_RECORD_TGID,		"record-tgid" },
> +	{ TRACEFS_OPTION_SLEEP_TIME,		"sleep-time" },
> +	{ TRACEFS_OPTION_STACKTRACE,		"stacktrace" },
> +	{ TRACEFS_OPTION_SYM_ADDR,		"sym-addr" },
> +	{ TRACEFS_OPTION_SYM_OFFSET,		"sym-offset" },
> +	{ TRACEFS_OPTION_SYM_USEROBJ,		"sym-userobj" },
> +	{ TRACEFS_OPTION_TEST_NOP_ACCEPT,	"test_nop_accept" },
> +	{ TRACEFS_OPTION_TEST_NOP_REFUSE,	"test_nop_refuse" },
> +	{ TRACEFS_OPTION_TRACE_PRINTK,		"trace_printk" },
> +	{ TRACEFS_OPTION_USERSTACKTRACE,	"userstacktrace" },
> +	{ TRACEFS_OPTION_VERBOSE,		"verbose" },
> +	{ TRACEFS_OPTION_INVALID,		"unknown" },
> +};
> +
>  static int trace_on_off(int fd, bool on)
>  {
>  	const char *val = on ? "1" : "0";
> @@ -107,3 +161,200 @@ int tracefs_trace_off_fd(int fd)
>  		return -1;
>  	return trace_on_off(fd, false);
>  }
> +
> +/**
> + * tracefs_option_string - Get trace option name from ID
> + * @id: trace option ID
> + *
> + * Returns string with option name, or "unknown" in case of not known option ID
> + */
> +const char *tracefs_option_string(unsigned long long id)
> +{
> +	int size = sizeof(options_map) / sizeof(struct options_map);
> +	int i;

If we just had the options as a bit number and not a mask, this would
simply be:

	if (id < size)
		return options_map[id].name;
	return "unknown";

> +
> +	for (i = 0; i < size; i++) {
> +		if (options_map[i].id == id)
> +			return options_map[i].name;
> +	}
> +
> +	return options_map[size - 1].name;
> +}
> +
> +/**
> + * tracefs_option_id - Get trace option ID from name
> + * @name: trace option name
> + *
> + * Returns trace option ID or TRACEFS_OPTION_INVALID in case of an error or
> + * unknown option name.
> + */
> +unsigned long long tracefs_option_id(char *name)
> +{
> +	int size = sizeof(options_map) / sizeof(struct options_map);
> +	int i;
> +
> +	if (!name)
> +		return TRACEFS_OPTION_INVALID;
> +
> +	for (i = 0; i < size; i++) {
> +		if (strlen(name) == strlen(options_map[i].name) &&
> +		    !strcmp(options_map[i].name, name))

This would just be:
			return i;

> +			return options_map[i].id;
> +	}
> +
> +	return TRACEFS_OPTION_INVALID;
> +}
> +
> +static unsigned long long trace_get_options(struct tracefs_instance *instance,
> +					    bool enabled)
> +{
> +	unsigned long long options = 0;
> +	unsigned long long id;
> +	char file[PATH_MAX];
> +	struct dirent *dent;
> +	char *dname = NULL;
> +	DIR *dir = NULL;
> +	long long val;
> +
> +	dname = tracefs_instance_get_file(instance, "options");
> +	if (!dname)
> +		goto error;
> +	dir = opendir(dname);
> +	if (!dir)
> +		goto error;
> +
> +	while ((dent = readdir(dir))) {
> +		if (*dent->d_name == '.')
> +			continue;
> +		if (enabled) {
> +			snprintf(file, PATH_MAX, "options/%s", dent->d_name);
> +			if (tracefs_instance_file_read_number(instance, file, &val) != 0 ||
> +			    val != 1)
> +				continue;
> +		}
> +		id = tracefs_option_id(dent->d_name);
> +		if (id != TRACEFS_OPTION_INVALID)
> +			options |= id;

Here we would have options be of type tracefs_options_t, and it would be:

			options.mask |= 1 << id;

> +	}
> +	closedir(dir);
> +	tracefs_put_tracing_file(dname);
> +
> +	return options;
> +
> +error:
> +	if (dir)
> +		closedir(dir);
> +	tracefs_put_tracing_file(dname);
> +	return 0;
> +}
> +
> +/**
> + * tracefs_options_get_supported - Get all supported trace options in given instance
> + * @instance: ftrace instance, can be NULL for the top instance
> + *
> + * Returns bitmask of all trace options, supported in given instance
> + */
> +unsigned long long tracefs_options_get_supported(struct tracefs_instance *instance)
> +{
> +	return trace_get_options(instance, false);
> +}
> +
> +/**
> + * tracefs_options_get_enabled - Get all currently enabled trace options in given instance
> + * @instance: ftrace instance, can be NULL for the top instance
> + *
> + * Returns bitmask of all trace options, that are currently set in given instance
> + */
> +unsigned long long tracefs_options_get_enabled(struct tracefs_instance *instance)
> +{
> +	return trace_get_options(instance, true);
> +}
> +
> +static int trace_config_options(struct tracefs_instance *instance,
> +				unsigned long long options, bool set)

options should be of type tracefs_options_t, and the user could set them
with the helper functions above.

> +{
> +	int size = sizeof(options_map) / sizeof(struct options_map);
> +	char *set_str = set ? "1" : "0";
> +	int str_size = strlen(set_str);

Hmm, since set_str can only be "1" or "0" why the strlen? It will always be
1.

Yeah, I think we really need to abstract out the options mask, as it would
break once we have more than 64 different options. Which is a real
possibility. When we do get there, we can make tracefs_options_t, be a
structure of two words, or create an extended version.

-- Steve

> +	char file[PATH_MAX];
> +	long long i;
> +
> +	for (i = 0; i < size && options; i++) {
> +		if (!(options & options_map[i].id))
> +			continue;
> +		options &= ~options_map[i].id;
> +		snprintf(file, PATH_MAX, "options/%s", options_map[i].name);
> +		if (str_size != tracefs_instance_file_write(instance, file, set_str))
> +			break;
> +	}
> +
> +	if (options)
> +		return -1;
> +	return 0;
> +}
> +
> +/**
> + * tracefs_options_set - Enable trace options
> + * @instance: ftrace instance, can be NULL for the top instance
> + * @options: bitmask of trace options that will be enabled
> + *
> + * Returns -1 in case of an error or 0 otherwise
> + */
> +int tracefs_options_set(struct tracefs_instance *instance, unsigned long long options)
> +{
> +	return trace_config_options(instance, options, true);
> +}
> +
> +/**
> + * tracefs_options_clear - Disable trace options
> + * @instance: ftrace instance, can be NULL for the top instance
> + * @options: bitmask of trace options that will be disabled
> + *
> + * Returns -1 in case of an error or 0 otherwise
> + */
> +int tracefs_options_clear(struct tracefs_instance *instance, unsigned long long options)
> +{
> +	return trace_config_options(instance, options, false);
> +}
> +
> +/**
> + * tracefs_option_is_supported - Check if an option is supported
> + * @instance: ftrace instance, can be NULL for the top instance
> + * @id: option id
> + *
> + * Returns true if an option with given id is supported by the system, false if
> + * it is not supported.
> + */
> +bool tracefs_option_is_supported(struct tracefs_instance *instance, unsigned long long id)
> +{
> +	char file[PATH_MAX];
> +	const char *oname = tracefs_option_string(id);
> +
> +	if (!oname)
> +		return false;
> +	snprintf(file, PATH_MAX, "options/%s", oname);
> +	return tracefs_file_exists(instance, (char *)file);
> +}
> +
> +/**
> + * tracefs_option_is_enabled - Check if an option is enabled in given instance
> + * @instance: ftrace instance, can be NULL for the top instance
> + * @id: option id
> + *
> + * Returns true if an option with given id is enabled in the given instance,
> + * false if it is not enabled.
> + */
> +bool tracefs_option_is_enabled(struct tracefs_instance *instance, unsigned long long id)
> +{
> +	const char *oname = tracefs_option_string(id);
> +	char file[PATH_MAX];
> +	long long res;
> +
> +	if (!oname)
> +		return false;
> +	snprintf(file, PATH_MAX, "options/%s", oname);
> +	if (!tracefs_instance_file_read_number(instance, file, &res) && res)
> +		return true;
> +
> +	return false;
> +}


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/5] libtracefs: New APIs for getting existing trace instance
  2021-01-15  5:04 ` [PATCH 4/5] libtracefs: New APIs for getting existing trace instance Tzvetomir Stoyanov (VMware)
@ 2021-01-19 22:18   ` Steven Rostedt
  0 siblings, 0 replies; 8+ messages in thread
From: Steven Rostedt @ 2021-01-19 22:18 UTC (permalink / raw)
  To: Tzvetomir Stoyanov (VMware); +Cc: linux-trace-devel

On Fri, 15 Jan 2021 07:04:09 +0200
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:

> +++ b/include/tracefs.h
> @@ -20,9 +20,12 @@ struct tracefs_instance;
>  
>  void tracefs_instance_free(struct tracefs_instance *instance);
>  struct tracefs_instance *tracefs_instance_create(const char *name);
> +struct tracefs_instance *tracefs_instance_get(const char *tracing_dir,
> +					      const char *name);

I don't think I care for the "_get" name here because it doesn't get
anything, it allocates it. As below, we have functions with "_get" that
return something that already exists (and why it returns a "const" value).

I think the above should be called:

  tracefs_instance_alloc()

?

-- Steve


>  int tracefs_instance_destroy(struct tracefs_instance *instance);
>  bool tracefs_instance_is_new(struct tracefs_instance *instance);
>  const char *tracefs_instance_get_name(struct tracefs_instance *instance);
> +const char *tracefs_instance_get_trace_dir(struct tracefs_instance *instance);
>  char *
>  tracefs_instance_get_file(struct tracefs_instance *instance, const char *file);
>  char *tracefs_instance_get_dir(struct tracefs_instance *instance);
> diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, back to index

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-15  5:04 [PATCH 0/5] New libtracefs APIs for trace options and trace dir Tzvetomir Stoyanov (VMware)
2021-01-15  5:04 ` [PATCH 1/5] libtracefs: New APIs for trace options Tzvetomir Stoyanov (VMware)
2021-01-19 21:12   ` Steven Rostedt
2021-01-15  5:04 ` [PATCH 2/5] libtracefs: Unit tests for tracing options APIs Tzvetomir Stoyanov (VMware)
2021-01-15  5:04 ` [PATCH 3/5] libtracefs: Add information about top tracing directory in instance structure Tzvetomir Stoyanov (VMware)
2021-01-15  5:04 ` [PATCH 4/5] libtracefs: New APIs for getting existing trace instance Tzvetomir Stoyanov (VMware)
2021-01-19 22:18   ` Steven Rostedt
2021-01-15  5:04 ` [PATCH 5/5] libtracefs: Unit tests for working with non default tracing dir Tzvetomir Stoyanov (VMware)

Linux-Trace-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-trace-devel/0 linux-trace-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-trace-devel linux-trace-devel/ https://lore.kernel.org/linux-trace-devel \
		linux-trace-devel@vger.kernel.org
	public-inbox-index linux-trace-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-trace-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git