libtracefs(3)
=============

NAME
----
tracefs_cpu_read_size, tracefs_cpu_read, tracefs_cpu_buffered_read, tracefs_cpu_write,
tracefs_cpu_stop, tracefs_cpu_flush, tracefs_cpu_flush_write, tracefs_cpu_pipe
- Reading trace_pipe_raw data

SYNOPSIS
--------
[verse]
--
*#include <tracefs.h>*

int *tracefs_cpu_read_size*(struct tracefs_cpu pass:[*]_tcpu_);
int *tracefs_cpu_read*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_, bool _nonblock_);
int *tracefs_cpu_buffered_read*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_, bool _nonblock_);
int *tracefs_cpu_write*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_, bool _nonblock_);
int *tracefs_cpu_stop*(struct tracefs_cpu pass:[*]_tcpu_);
int *tracefs_cpu_flush*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_);
int *tracefs_cpu_flush_write*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_);
int *tracefs_cpu_pipe*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_, bool _nonblock_);
--

DESCRIPTION
-----------
This set of APIs can be used to read the raw data from the trace_pipe_raw
files in the tracefs file system.

The *tracefs_cpu_read_size()* returns the subbuffer size of the trace_pipe_raw. This
returns the minimum size of the buffer that is passed to the below functions.

The *tracefs_cpu_read()* reads the trace_pipe_raw files associated to _tcpu_ into _buffer_.
_buffer_ must be at least the size of the sub buffer of the ring buffer,
which is returned by *tracefs_cpu_read_size()*. If _nonblock_ is set, and
there's no data available, it will return immediately. Otherwise depending
on how _tcpu_ was opened, it will block. If _tcpu_ was opened with nonblock
set, then this _nonblock_ will make no difference.

The *tracefs_cpu_buffered_read()* is basically the same as *tracefs_cpu_read()*
except that it uses a pipe through splice to buffer reads. This will batch
reads keeping the reading from the ring buffer less intrusive to the system,
as just reading all the time can cause quite a disturbance. Note, one
difference between this and *tracefs_cpu_read()* is that it will read only in
sub buffer pages. If the ring buffer has not filled a page, then it will not
return anything, even with _nonblock_ set.  Calls to *tracefs_cpu_flush()*
should be done to read the rest of the file at the end of the trace.

The *tracefs_cpu_write()* will pipe the data from the trace_pipe_raw
file associated with _tcpu_ into the _wfd_ file descriptor. If _nonblock_ is set,
then it will not block on if there's nothing to write. Note, it will only write
sub buffer size data to _wfd_. Calls to tracefs_cpu_flush_write() are needed to
write out the rest.

The *tracefs_cpu_stop()* will attempt to unblock a task blocked on _tcpu_ reading it.
On older kernels, it may not do anything for the pipe reads, as older kernels do not
wake up tasks waiting on the ring buffer. Returns 0 if it definitely woke up any possible
waiters, but returns 1 if it is not sure it worked and waiters may need to have a signal
sent to them.

The *tracefs_cpu_flush()* reads the trace_pipe_raw file associated by the _tcpu_ and puts it
into _buffer_, which must be the size of the sub buffer which is retrieved.
by *tracefs_cpu_read_size()*. This should be called at the end of tracing
to get the rest of the data. This call will convert the file descriptor of
trace_pipe_raw into non-blocking mode.

The *tracefs_cpu_flush_write()* same as *trace_cpu_flush()* except it takes a file
descriptor _wfd_ to flush the data into.

The *tracefs_cpu_pipe()* is similar to *tracefs_cpu_write()* but the _wfd_ file descriptor
must be a pipe. This call is an optimization of *tracefs_cpu_write()* that uses two calls
to *splice*(2) in order to connect the trace_pipe_raw file descriptor with the write file
descriptor. *splice*(2) requires that one of the passed in file descriptors is a pipe.
If the application wants to pass the data to an existing pipe, there's no reason for
there to be two *splice*(2) system calls and *tracefs_cpu_pipe()* can simply use a single
call to _wfd_.

RETURN VALUE
------------
The *tracefs_cpu_open()* returns a struct tracefs_cpu descriptor that can be
used by the other functions or NULL on error.

The *tracefs_cpu_read_size()* returns the minimum size of the buffers to be
used with *tracefs_cpu_read()*, *tracefs_cpu_buffered_read()* and *tracefs_cpu_flush()*.
Returns negative on error.

The *tracefs_cpu_read()* returns the number of bytes read, or negative on error.

The *tracefs_cpu_buffered_read()* returns the number of bytes read or negative on error.

The *tracefs_cpu_write()* returns the number of bytes written to the file
or negative on error.

The *tracefs_cpu_stop()* returns zero if any waiters were guaranteed to be
woken up from waiting on input, or returns one if this is an older kernel
that does not supply that guarantee, and a signal may need to be sent to
any waiters. Returns negative on error.

The *tracefs_cpu_flush()* returns the number of bytes read or negative on error.

The *tracefs_cpu_flush_write()* returns the number of bytes written to the
file  or negative on error.

EXAMPLE
-------
[source,c]
--
#define _LARGEFILE64_SOURCE
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
#include <unistd.h>
#include <tracefs.h>

struct thread_data {
	struct tracefs_cpu	*tcpu;
	int			done;
	int			fd;
};

static void *thread_run(void *arg)
{
	struct thread_data *data = arg;
	struct tracefs_cpu *tcpu = data->tcpu;
	int fd = data->fd;
	int ret;

	while (!data->done) {
		ret = tracefs_cpu_write(tcpu, fd, false);
		printf("wrote %d\n", ret);
	}
	return NULL;
}

int main (int argc, char **argv)
{
	struct tracefs_instance *instance;
	struct thread_data data;
	pthread_t thread;
	char *file;
	int secs = 10;
	int cpu;
	int ret;

	if (argc < 3 || !isdigit(argv[1][0])) {
		printf("usage: %s cpu file_destination [sleep secs]\n\n", argv[0]);
		exit(-1);
	}

	cpu = atoi(argv[1]);
	file = argv[2];

	if (argc > 3)
		secs = atoi(argv[3]);

	instance = tracefs_instance_create("cpu_write");
	if (!instance) {
		perror("create instance");
		exit(-1);
	}

	memset(&data, 0, sizeof(data));

	data.tcpu = tracefs_cpu_open(instance, cpu, 0);
	if (!data.tcpu) {
		perror("Open instance");
		exit(-1);
	}

	data.fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
	if (data.fd < 0) {
		perror(file);
		exit(-1);
	}

	pthread_create(&thread, NULL, thread_run, &data);

	sleep(secs);

	data.done = 1;
	printf("stopping\n");
	ret = tracefs_cpu_stop(data.tcpu);

	printf("joining %d\n", ret);
	pthread_join(thread, NULL);

	tracefs_trace_off(instance);
	do {
		ret = tracefs_cpu_flush_write(data.tcpu, data.fd);
		printf("flushed %d\n", ret);
	} while (ret > 0);
	tracefs_trace_on(instance);

	tracefs_cpu_close(data.tcpu);
	close(data.fd);

	return 0;
}
--
FILES
-----
[verse]
--
*tracefs.h*
	Header file to include in order to have access to the library APIs.
*-ltracefs*
	Linker switch to add when building a program that uses the library.
--

SEE ALSO
--------
*tracefs_cpu_open*(3)
*tracefs_cpu_close*(3)
*libtracefs*(3),
*libtraceevent*(3),
*trace-cmd*(1)

AUTHOR
------
[verse]
--
*Steven Rostedt* <rostedt@goodmis.org>
--
REPORTING BUGS
--------------
Report bugs to  <linux-trace-devel@vger.kernel.org>

LICENSE
-------
libtracefs is Free Software licensed under the GNU LGPL 2.1

RESOURCES
---------
https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/

COPYING
-------
Copyright \(C) 2022 Google, Inc. Free use of this software is granted under
the terms of the GNU Public License (GPL).
