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 * 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 #include #include #include #include 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* -- REPORTING BUGS -------------- Report bugs to 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).