@@ -501,4 +501,7 @@ void *tracecmd_record_page(struct tracecmd_input *handle,
void *tracecmd_record_offset(struct tracecmd_input *handle,
struct tep_record *record);
+/* --- Containers --- */
+int tracecmd_get_container_pids(char *cont_id, int **pids, int *pids_count);
+
#endif /* _TRACE_CMD_H */
@@ -17,6 +17,7 @@ OBJS += trace-filter-hash.o
OBJS += trace-msg.o
OBJS += trace-plugin.o
OBJS += trace-timesync.o
+OBJS += trace-containers.o
# Additional util objects
OBJS += trace-blk-hack.o
new file mode 100644
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * Updates:
+ * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include "trace-cmd-local.h"
+
+#define CGROUPV1_CPUSET_DOCKER "/sys/fs/cgroup/cpuset/docker/"
+#define CGROUPV1_PID_FILE "cgroup.procs"
+
+static char *read_text_file(char *file)
+{
+ char stbuf[BUFSIZ];
+ char *buf = NULL;
+ int size = 0;
+ int fd = -1;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ size = read(fd, stbuf, BUFSIZ);
+ if (size <= 0)
+ goto out;
+ buf = malloc(size + 1);
+ if (!buf)
+ goto out;
+ memcpy(buf, stbuf, size);
+ buf[size] = '\0';
+
+out:
+ if (fd >= 0)
+ close(fd);
+
+ return buf;
+}
+
+static char *match_in_dir(char *path, char *match)
+{
+ char *match_path = NULL;
+ struct dirent *dent;
+ char *name = NULL;
+ DIR *dir;
+
+ dir = opendir(path);
+ if (!dir)
+ return NULL;
+
+ while ((dent = readdir(dir))) {
+ name = dent->d_name;
+
+ if (!strncmp(name, match, strlen(match)))
+ break;
+ name = NULL;
+ }
+
+ closedir(dir);
+ if (name)
+ asprintf(&match_path, "%s/%s", path, name);
+
+ return match_path;
+}
+
+static int get_v1_docker_pids(char *cont_id, int **pids, int *pids_count)
+{
+ char *cont_dir = NULL;
+ char *pid_file = NULL;
+ char *pid_buf = NULL;
+ int *pid_array = NULL;
+ char *savestr;
+ char *pid_str;
+ int pcount = 0;
+ int ret = -1;
+
+ cont_dir = match_in_dir(CGROUPV1_CPUSET_DOCKER, cont_id);
+ if (!cont_dir)
+ goto out;
+ if (asprintf(&pid_file, "%s/%s", cont_dir, CGROUPV1_PID_FILE) < 0)
+ goto out;
+ pid_buf = read_text_file(pid_file);
+ if (!pid_buf)
+ goto out;
+
+ *pids = NULL;
+ *pids_count = 0;
+ pid_str = strtok_r(pid_buf, " \t\r\n\v\f", &savestr);
+ while (pid_str) {
+ pid_array = realloc(pid_array, (pcount + 1) * sizeof(int));
+ if (!pid_array)
+ break;
+ pid_array[pcount++] = atoi(pid_str);
+ pid_str = strtok_r(NULL, " \t\r\n\v\f", &savestr);
+ }
+
+ if (!pid_str) {
+ *pids = pid_array;
+ *pids_count = pcount;
+ ret = 0;
+ } else
+ free(pid_array);
+
+out:
+ free(cont_dir);
+ free(pid_file);
+ free(pid_buf);
+
+ return ret;
+}
+
+/*
+ * tracecmd_get_container_pids - Get PIDs associated with a given container
+ *
+ *@cont_id - container identifier
+ *@pids - returns allocated array of size @pids_count with PIDs
+ *@pids_count - size of returned array @pids
+ *
+ * Returns -1 in case of an error, 0 otherwise
+ * In case of success, returned array @pids must be freed by free()
+ */
+int tracecmd_get_container_pids(char *cont_id, int **pids, int *pids_count)
+{
+ int ret;
+
+ ret = get_v1_docker_pids(cont_id, pids, pids_count);
+ if (!ret)
+ return ret;
+
+ return -1;
+}
@@ -168,6 +168,7 @@ enum buffer_instance_flags {
BUFFER_FL_GUEST = 1 << 2,
BUFFER_FL_AGENT = 1 << 3,
BUFFER_FL_HAS_CLOCK = 1 << 4,
+ BUFFER_FL_CONTAINER = 1 << 5,
};
struct func_list {
@@ -5442,6 +5442,7 @@ void init_top_instance(void)
}
enum {
+ OPT_container = 241,
OPT_tsyncinterval = 242,
OPT_user = 243,
OPT_procmap = 244,
@@ -5705,6 +5706,46 @@ static void add_arg(struct buffer_instance *instance,
/* Not found? */
}
+static void set_trace_child(struct buffer_instance *instance)
+{
+ test_set_event_pid(instance);
+ if (!instance->have_event_fork) {
+#ifdef NO_PTRACE
+ die("trace child: ptrace not supported");
+#endif
+ instance->ptrace_child = 1;
+ do_ptrace = 1;
+ } else {
+ save_option(instance, "event-fork");
+ }
+ if (instance->have_func_fork)
+ save_option(instance, "function-fork");
+}
+
+static struct buffer_instance *parse_container(char *container)
+{
+ struct buffer_instance *instance;
+ int pids_count = 0;
+ int *pids = NULL;
+ int ret;
+
+ ret = tracecmd_get_container_pids(container, &pids, &pids_count);
+ if (ret < 0 || !pids_count)
+ die("Failed to get container %s PIDs", container);
+
+ instance = create_instance(container);
+ if (!instance)
+ die("Failed to create instance %s", container);
+ add_instance(instance, local_cpu_count);
+ instance->flags |= BUFFER_FL_CONTAINER;
+ set_trace_child(instance);
+ for (int i = 0; i < pids_count; i++)
+ add_filter_pid(instance, pids[i], 0);
+
+ free(pids);
+ return instance;
+}
+
static void parse_record_options(int argc,
char **argv,
enum trace_cmd curr_cmd,
@@ -5750,6 +5791,7 @@ static void parse_record_options(int argc,
{"user", required_argument, NULL, OPT_user},
{"module", required_argument, NULL, OPT_module},
{"tsync-interval", required_argument, NULL, OPT_tsyncinterval},
+ {"container", required_argument, NULL, OPT_container},
{NULL, 0, NULL, 0}
};
@@ -5870,20 +5912,8 @@ static void parse_record_options(int argc,
free(pids);
break;
case 'c':
- test_set_event_pid(ctx->instance);
+ set_trace_child(ctx->instance);
do_children = 1;
- if (!ctx->instance->have_event_fork) {
-#ifdef NO_PTRACE
- die("-c invalid: ptrace not supported");
-#endif
- do_ptrace = 1;
- ctx->instance->ptrace_child = 1;
-
- } else {
- save_option(ctx->instance, "event-fork");
- }
- if (ctx->instance->have_func_fork)
- save_option(ctx->instance, "function-fork");
break;
case 'C':
ctx->instance->clock = optarg;
@@ -6100,6 +6130,9 @@ static void parse_record_options(int argc,
top_instance.tsync.loop_interval = atoi(optarg);
guest_sync_set = true;
break;
+ case OPT_container:
+ ctx->instance = parse_container(optarg);
+ break;
case OPT_quiet:
case 'q':
quiet = true;
A new command "--container <container-id>" is added to "trace-cmd record" sub command. It creates a ftrace instance and runs the tracing of container's PIDs into it. Multiple "--container" options can be specified, to trace multiple containers at the same time. The new option behaves as "-B": all trace-cmd options specified after "--container" affect only the tracing related to this container. The patch is a POC, it introduces the infrastructure and helper functions for container tracing. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- include/trace-cmd/trace-cmd.h | 3 + lib/trace-cmd/Makefile | 1 + lib/trace-cmd/trace-containers.c | 141 +++++++++++++++++++++++++++++++ tracecmd/include/trace-local.h | 1 + tracecmd/trace-record.c | 59 ++++++++++--- 5 files changed, 192 insertions(+), 13 deletions(-) create mode 100644 lib/trace-cmd/trace-containers.c