LIBTRACEFS(3) libtracefs Manual LIBTRACEFS(3)

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

#include <tracefs.h>
int tracefs_cpu_read_size(struct tracefs_cpu *tcpu);
int tracefs_cpu_read(struct tracefs_cpu *tcpu, void *buffer, bool nonblock);
int tracefs_cpu_buffered_read(struct tracefs_cpu *tcpu, void *buffer, bool nonblock);
int tracefs_cpu_write(struct tracefs_cpu *tcpu, int wfd, bool nonblock);
int tracefs_cpu_stop(struct tracefs_cpu *tcpu);
int tracefs_cpu_flush(struct tracefs_cpu *tcpu, void *buffer);
int tracefs_cpu_flush_write(struct tracefs_cpu *tcpu, int wfd);
int tracefs_cpu_pipe(struct tracefs_cpu *tcpu, int wfd, bool nonblock);

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.

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.

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

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.

tracefs_cpu_open(3) tracefs_cpu_close(3) tracefs_cpu_read_buf(3) tracefs_cpu_buffered_read_buf(3) tracefs_cpu_flush_buf(3) libtracefs(3), libtraceevent(3), trace-cmd(1)

Steven Rostedt <rostedt@goodmis.org[1]>

Report bugs to <linux-trace-devel@vger.kernel.org[2]>

libtracefs is Free Software licensed under the GNU LGPL 2.1

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

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

1.
rostedt@goodmis.org
mailto:rostedt@goodmis.org
2.
linux-trace-devel@vger.kernel.org
mailto:linux-trace-devel@vger.kernel.org
01/13/2024 libtracefs 1.8.0