@@ -270,8 +270,9 @@ struct tracecmd_output *tracecmd_get_output_handle_fd(int fd);
enum {
TRACECMD_RECORD_NOSPLICE = (1 << 0), /* Use read instead of splice */
- TRACECMD_RECORD_SNAPSHOT = (1 << 1), /* extract from snapshot */
+ TRACECMD_RECORD_SNAPSHOT = (1 << 1), /* Extract from snapshot */
TRACECMD_RECORD_BLOCK = (1 << 2), /* Block on splice write */
+ TRACECMD_RECORD_NOBRASS = (1 << 3), /* Splice directly without a brass pipe */
};
void tracecmd_free_recorder(struct tracecmd_recorder *recorder);
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
+#include <poll.h>
#include <unistd.h>
#include <errno.h>
@@ -26,6 +27,8 @@
# define SPLICE_F_GIFT 8
#endif
+#define POLL_TIMEOUT_MS 1000
+
struct tracecmd_recorder {
int fd;
int fd1;
@@ -40,6 +43,7 @@ struct tracecmd_recorder {
int pages;
int count;
unsigned fd_flags;
+ unsigned trace_fd_flags;
unsigned flags;
};
@@ -127,6 +131,8 @@ tracecmd_create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
if (!(recorder->flags & TRACECMD_RECORD_BLOCK))
recorder->fd_flags |= SPLICE_F_NONBLOCK;
+ recorder->trace_fd_flags = SPLICE_F_MOVE;
+
/* Init to know what to free and release */
recorder->trace_fd = -1;
recorder->brass[0] = -1;
@@ -171,7 +177,8 @@ tracecmd_create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
goto out_free;
}
- if ((recorder->flags & TRACECMD_RECORD_NOSPLICE) == 0) {
+ if (!(recorder->flags & (TRACECMD_RECORD_NOSPLICE |
+ TRACECMD_RECORD_NOBRASS))) {
ret = pipe(recorder->brass);
if (ret < 0)
goto out_free;
@@ -372,7 +379,7 @@ static long splice_data(struct tracecmd_recorder *recorder)
long ret;
read = splice(recorder->trace_fd, NULL, recorder->brass[1], NULL,
- recorder->pipe_size, SPLICE_F_MOVE);
+ recorder->pipe_size, recorder->trace_fd_flags);
if (read < 0) {
if (errno != EAGAIN && errno != EINTR) {
warning("recorder error in splice input");
@@ -399,6 +406,39 @@ static long splice_data(struct tracecmd_recorder *recorder)
return total_read;
}
+/*
+ * Returns -1 on error.
+ * or bytes of data read.
+ */
+static long direct_splice_data(struct tracecmd_recorder *recorder)
+{
+ struct pollfd pfd = {
+ .fd = recorder->trace_fd,
+ .events = POLLIN,
+ };
+ long read;
+ int ret;
+
+ ret = poll(&pfd, 1, POLL_TIMEOUT_MS);
+ if (ret < 0)
+ return -1;
+
+ if (!(pfd.revents | POLLIN))
+ return 0;
+
+ read = splice(recorder->trace_fd, NULL, recorder->fd, NULL,
+ recorder->pipe_size, recorder->trace_fd_flags);
+ if (read < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ warning("recorder error in splice input");
+ return -1;
+ }
+
+ return read;
+}
+
/*
* Returns -1 on error.
* or bytes of data read.
@@ -433,6 +473,17 @@ static long read_data(struct tracecmd_recorder *recorder)
return r;
}
+static long move_data(struct tracecmd_recorder *recorder)
+{
+ if (recorder->flags & TRACECMD_RECORD_NOSPLICE)
+ return read_data(recorder);
+
+ if (recorder->flags & TRACECMD_RECORD_NOBRASS)
+ return direct_splice_data(recorder);
+
+ return splice_data(recorder);
+}
+
static void set_nonblock(struct tracecmd_recorder *recorder)
{
long flags;
@@ -440,8 +491,11 @@ static void set_nonblock(struct tracecmd_recorder *recorder)
/* Do not block on reads for flushing */
flags = fcntl(recorder->trace_fd, F_GETFL);
fcntl(recorder->trace_fd, F_SETFL, flags | O_NONBLOCK);
+ recorder->trace_fd_flags |= SPLICE_F_NONBLOCK;
- /* Do not block on streams for write */
+ /* Do not block on pipes for write */
+ flags = fcntl(recorder->fd, F_GETFL);
+ fcntl(recorder->fd, F_SETFL, flags | O_NONBLOCK);
recorder->fd_flags |= SPLICE_F_NONBLOCK;
}
@@ -455,10 +509,7 @@ long tracecmd_flush_recording(struct tracecmd_recorder *recorder)
set_nonblock(recorder);
do {
- if (recorder->flags & TRACECMD_RECORD_NOSPLICE)
- ret = read_data(recorder);
- else
- ret = splice_data(recorder);
+ ret = move_data(recorder);
if (ret < 0)
return ret;
total += ret;
@@ -487,7 +538,10 @@ long tracecmd_flush_recording(struct tracecmd_recorder *recorder)
int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep)
{
- struct timespec req;
+ struct timespec req = {
+ .tv_sec = sleep / 1000000,
+ .tv_nsec = (sleep % 1000000) * 1000,
+ };
long read = 1;
long ret;
@@ -495,17 +549,12 @@ int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long s
do {
/* Only sleep if we did not read anything last time */
- if (!read && sleep) {
- req.tv_sec = sleep / 1000000;
- req.tv_nsec = (sleep % 1000000) * 1000;
+ if (!read && sleep)
nanosleep(&req, NULL);
- }
+
read = 0;
do {
- if (recorder->flags & TRACECMD_RECORD_NOSPLICE)
- ret = read_data(recorder);
- else
- ret = splice_data(recorder);
+ ret = move_data(recorder);
if (ret < 0)
return ret;
read += ret;
When `trace-cmd record` is reading tracing data over FIFO we can do a direct splice from the FIFO to the output file descriptor instead of doing two through an additional pipe buffer. This patch implements specialized tracecmd_recorder data transfer version for this case. Signed-off-by: Slavomir Kaslev <kaslevs@vmware.com> --- include/trace-cmd/trace-cmd.h | 3 +- lib/trace-cmd/trace-recorder.c | 81 +++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 17 deletions(-)