Re: [PATCH v17 06/18] trace-cmd: Add new library API for reading ftrace buffers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue,  3 Dec 2019 12:35:10 +0200
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@xxxxxxxxx> wrote:

> 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.

Hmm, would be good to know what this would be used for.

> 
> Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@xxxxxxxxx>
> ---
>  include/trace-cmd/trace-cmd.h |   8 +++
>  lib/trace-cmd/trace-util.c    | 114 ++++++++++++++++++++++++++++++++++
>  2 files changed, 122 insertions(+)
> 
> diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
> index 5d4292e..831bb1a 100644
> --- a/include/trace-cmd/trace-cmd.h
> +++ b/include/trace-cmd/trace-cmd.h
> @@ -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[];
> diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c
> index e019dce..a54a905 100644
> --- a/lib/trace-cmd/trace-util.c
> +++ b/lib/trace-cmd/trace-util.c
> @@ -1185,3 +1185,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))

Hmm, need to be documented that breaking out of the loop will likely
call future reads to lose events. The records on the page after the
record that causes the break will be lost from future reads.

-- Steve



> +				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;
> +}




[Index of Archives]     [Linux USB Development]     [Linux USB Development]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux