@@ -380,6 +380,14 @@ char *tracecmd_read_instance_file(struct tracecmd_instance *instance,
void tracecmd_set_clock(struct tracecmd_instance *instance, char **old_clock);
+int tracecmd_iterate_raw_events(struct tep_handle *tep,
+ struct tracecmd_instance *instance,
+ int (*callback)(struct tep_event *,
+ struct tep_record *,
+ int, void *context),
+ void *callback_context);
+
+
/* --- Plugin handling --- */
extern struct tep_plugin_option trace_ftrace_options[];
@@ -1182,3 +1182,117 @@ int tracecmd_write_file(const char *file, const char *str, const char *type)
}
return ret;
}
+
+static int
+get_events_in_page(struct tep_handle *tep, void *page,
+ int size, int cpu,
+ int (*callback)(struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_context)
+{
+ struct tep_record *last_record = NULL;
+ struct tep_event *event = NULL;
+ struct tep_record *record;
+ int id, cnt = 0;
+
+ if (size <= 0)
+ return 0;
+
+ while (true) {
+ event = NULL;
+ record = tracecmd_read_page_record(tep, page, size,
+ last_record);
+ if (!record)
+ break;
+ free_record(last_record);
+ id = tep_data_type(tep, record);
+ event = tep_find_event(tep, id);
+ if (event && callback) {
+ if (callback(event, record, cpu, callback_context))
+ break;
+ }
+ last_record = record;
+ }
+ free_record(last_record);
+
+ return cnt;
+}
+
+/*
+ * tracecmd_iterate_raw_events - Iterate through events in trace_pipe_raw
+ * per CPU trace files
+ * @tep: a handle to the trace event parser context
+ * @instance: ftrace instance, can be NULL for the top instance
+ * @callback: A user function, called for each record from the file.
+ * @callback_context: A custom context, passed to the user callback function
+ *
+ * If the @callback returns non-zero, the iteration stops.
+ *
+ * Returns -1 in case of an error, or 0 otherwise.
+ */
+int tracecmd_iterate_raw_events(struct tep_handle *tep,
+ struct tracecmd_instance *instance,
+ int (*callback)(struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_context)
+{
+ unsigned int p_size;
+ struct dirent *dent;
+ char file[PATH_MAX];
+ void *page = NULL;
+ struct stat st;
+ char *path;
+ DIR *dir;
+ int ret;
+ int cpu;
+ int fd;
+ int r;
+
+ p_size = getpagesize();
+ path = tracecmd_get_instance_file(instance, "per_cpu");
+ if (!path)
+ return -1;
+ dir = opendir(path);
+ if (!dir) {
+ ret = -1;
+ goto error;
+ }
+ page = malloc(p_size);
+ if (!page) {
+ ret = -1;
+ goto error;
+ }
+ while ((dent = readdir(dir))) {
+ const char *name = dent->d_name;
+
+ if (strlen(name) < 4 || strncmp(name, "cpu", 3) != 0)
+ continue;
+ cpu = atoi(name + 3);
+ sprintf(file, "%s/%s", path, name);
+ ret = stat(file, &st);
+ if (ret < 0 || !S_ISDIR(st.st_mode))
+ continue;
+
+ sprintf(file, "%s/%s/trace_pipe_raw", path, name);
+ fd = open(file, O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ continue;
+ do {
+ r = read(fd, page, p_size);
+ if (r > 0)
+ get_events_in_page(tep, page, r, cpu,
+ callback, callback_context);
+ } while (r > 0);
+ close(fd);
+ }
+ ret = 0;
+
+error:
+ if (dir)
+ closedir(dir);
+ free(page);
+ tracecmd_put_tracing_file(path);
+ return ret;
+}
A new libtracecmd API is introduced: int tracecmd_iterate_raw_events(struct tep_handle *tep, struct tracecmd_instance *instance, int (*callback)(struct tep_event *, struct tep_record *, int, void *context), void *callback_context); It reads events from trace_pipe_raw, per cpu ftrace buffer, and calls a user callback for each of them. The API is instance aware. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- include/trace-cmd/trace-cmd.h | 8 +++ lib/trace-cmd/trace-util.c | 114 ++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+)