The liblttngkconsumerd can now be used to dump snapshots to tracefiles for one or all buffers configured for mmap output.
Signed-off-by: Julien Desfossez <[email protected]> --- include/lttng/lttng-kconsumerd.h | 29 +++++ liblttngkconsumerd/lttngkconsumerd.c | 224 ++++++++++++++++++++++++---------- 2 files changed, 191 insertions(+), 62 deletions(-) diff --git a/include/lttng/lttng-kconsumerd.h b/include/lttng/lttng-kconsumerd.h index 8d16d56..454af6e 100644 --- a/include/lttng/lttng-kconsumerd.h +++ b/include/lttng/lttng-kconsumerd.h @@ -70,6 +70,7 @@ struct lttng_kconsumerd_fd { unsigned long max_sb_size; /* the subbuffer size for this channel */ void *mmap_base; size_t mmap_len; + unsigned long snapshot_start; enum lttng_event_output output; /* splice or mmap */ }; @@ -132,6 +133,34 @@ extern int lttng_kconsumerd_on_read_subbuffer_splice( struct lttng_kconsumerd_fd *kconsumerd_fd, unsigned long len); /* + * Capture a snapshot for all mmap buffers + * + * Returns 0 on success, < 0 on error + */ +extern int lttng_kconsumerd_get_all_snapshots( + struct lttng_kconsumerd_local_data *ctx); + +/* + * Capture a snapshot for a specific fd + * this function is responsible for reserving the subbuffer + * reading its content and releasing it. + * + * Returns 0 on success, < 0 on error + */ +extern int lttng_kconsumerd_get_snapshot( + struct lttng_kconsumerd_local_data *ctx, + struct lttng_kconsumerd_fd *kconsumerd_fd); + +/* + * Dump a snapshot to a tracefile + * + * Returns 0 on success, < 0 on error + */ +extern int lttng_kconsumerd_on_read_subbuffer_mmap_snapshot( + struct lttng_kconsumerd_local_data *ctx, + struct lttng_kconsumerd_fd *kconsumerd_fd, unsigned long end); + +/* * Send return code to session daemon. * * Returns the return code of sendmsg : the number of bytes transmitted or -1 diff --git a/liblttngkconsumerd/lttngkconsumerd.c b/liblttngkconsumerd/lttngkconsumerd.c index ba26026..81749be 100644 --- a/liblttngkconsumerd/lttngkconsumerd.c +++ b/liblttngkconsumerd/lttngkconsumerd.c @@ -150,6 +150,7 @@ static int kconsumerd_add_fd(struct lttcomm_kconsumerd_msg *buf, tmp_fd->mmap_len = 0; tmp_fd->mmap_base = NULL; tmp_fd->output = buf->output; + tmp_fd->snapshot_start = 0; strncpy(tmp_fd->path_name, buf->path_name, PATH_MAX); tmp_fd->path_name[PATH_MAX - 1] = '\0'; @@ -361,6 +362,42 @@ void lttng_kconsumerd_set_command_sock_path( ctx->kconsumerd_command_sock_path = sock; } +static void lttng_kconsumerd_sync_trace_file( + struct lttng_kconsumerd_fd *kconsumerd_fd, off_t orig_offset) +{ + int outfd = kconsumerd_fd->out_fd; + /* + * This does a blocking write-and-wait on any page that belongs to the + * subbuffer prior to the one we just wrote. + * Don't care about error values, as these are just hints and ways to + * limit the amount of page cache used. + */ + if (orig_offset >= kconsumerd_fd->max_sb_size) { + sync_file_range(outfd, orig_offset - kconsumerd_fd->max_sb_size, + kconsumerd_fd->max_sb_size, + SYNC_FILE_RANGE_WAIT_BEFORE + | SYNC_FILE_RANGE_WRITE + | SYNC_FILE_RANGE_WAIT_AFTER); + /* + * Give hints to the kernel about how we access the file: + * POSIX_FADV_DONTNEED : we won't re-access data in a near future after + * we write it. + * + * We need to call fadvise again after the file grows because the + * kernel does not seem to apply fadvise to non-existing parts of the + * file. + * + * Call fadvise _after_ having waited for the page writeback to + * complete because the dirty page writeback semantic is not well + * defined. So it can be expected to lead to lower throughput in + * streaming. + */ + posix_fadvise(outfd, orig_offset - kconsumerd_fd->max_sb_size, + kconsumerd_fd->max_sb_size, POSIX_FADV_DONTNEED); + } +} + + /* * Mmap the ring buffer, read it and write the data to the tracefile. * @@ -371,7 +408,6 @@ int lttng_kconsumerd_on_read_subbuffer_mmap( struct lttng_kconsumerd_fd *kconsumerd_fd, unsigned long len) { unsigned long mmap_offset; - char *padding = NULL; long ret = 0; off_t orig_offset = kconsumerd_fd->out_fd_offset; int fd = kconsumerd_fd->consumerd_fd; @@ -400,42 +436,11 @@ int lttng_kconsumerd_on_read_subbuffer_mmap( kconsumerd_fd->out_fd_offset += ret; } - /* - * This does a blocking write-and-wait on any page that belongs to the - * subbuffer prior to the one we just wrote. - * Don't care about error values, as these are just hints and ways to - * limit the amount of page cache used. - */ - if (orig_offset >= kconsumerd_fd->max_sb_size) { - sync_file_range(outfd, orig_offset - kconsumerd_fd->max_sb_size, - kconsumerd_fd->max_sb_size, - SYNC_FILE_RANGE_WAIT_BEFORE - | SYNC_FILE_RANGE_WRITE - | SYNC_FILE_RANGE_WAIT_AFTER); + lttng_kconsumerd_sync_trace_file(kconsumerd_fd, orig_offset); - /* - * Give hints to the kernel about how we access the file: - * POSIX_FADV_DONTNEED : we won't re-access data in a near future after - * we write it. - * - * We need to call fadvise again after the file grows because the - * kernel does not seem to apply fadvise to non-existing parts of the - * file. - * - * Call fadvise _after_ having waited for the page writeback to - * complete because the dirty page writeback semantic is not well - * defined. So it can be expected to lead to lower throughput in - * streaming. - */ - posix_fadvise(outfd, orig_offset - kconsumerd_fd->max_sb_size, - kconsumerd_fd->max_sb_size, POSIX_FADV_DONTNEED); - } goto end; end: - if (padding != NULL) { - free(padding); - } return ret; } @@ -482,36 +487,8 @@ int lttng_kconsumerd_on_read_subbuffer_splice( SYNC_FILE_RANGE_WRITE); kconsumerd_fd->out_fd_offset += ret; } + lttng_kconsumerd_sync_trace_file(kconsumerd_fd, orig_offset); - /* - * This does a blocking write-and-wait on any page that belongs to the - * subbuffer prior to the one we just wrote. - * Don't care about error values, as these are just hints and ways to - * limit the amount of page cache used. - */ - if (orig_offset >= kconsumerd_fd->max_sb_size) { - sync_file_range(outfd, orig_offset - kconsumerd_fd->max_sb_size, - kconsumerd_fd->max_sb_size, - SYNC_FILE_RANGE_WAIT_BEFORE - | SYNC_FILE_RANGE_WRITE - | SYNC_FILE_RANGE_WAIT_AFTER); - /* - * Give hints to the kernel about how we access the file: - * POSIX_FADV_DONTNEED : we won't re-access data in a near future after - * we write it. - * - * We need to call fadvise again after the file grows because the - * kernel does not seem to apply fadvise to non-existing parts of the - * file. - * - * Call fadvise _after_ having waited for the page writeback to - * complete because the dirty page writeback semantic is not well - * defined. So it can be expected to lead to lower throughput in - * streaming. - */ - posix_fadvise(outfd, orig_offset - kconsumerd_fd->max_sb_size, - kconsumerd_fd->max_sb_size, POSIX_FADV_DONTNEED); - } goto end; splice_error: @@ -536,6 +513,129 @@ end: } /* + * Capture a snapshot for all mmap buffers + * + * Returns 0 on success, < 0 on error + */ +int lttng_kconsumerd_get_all_snapshots(struct lttng_kconsumerd_local_data *ctx) +{ + struct lttng_kconsumerd_fd *iter, *tmp; + int ret = 0; + + pthread_mutex_lock(&kconsumerd_data.lock); + cds_list_for_each_entry_safe(iter, tmp, &kconsumerd_data.fd_list.head, list) { + if (iter->output == LTTNG_EVENT_MMAP) { + ret = lttng_kconsumerd_get_snapshot(ctx, iter); + if (ret < 0) { + goto end; + } + } + } + pthread_mutex_unlock(&kconsumerd_data.lock); + +end: + return ret; +} + +/* + * Capture a snapshot for a specific fd + * this function is responsible for reserving the subbuffer + * reading its content and releasing it. + * + * Returns 0 on success, < 0 on error + */ +int lttng_kconsumerd_get_snapshot(struct lttng_kconsumerd_local_data *ctx, + struct lttng_kconsumerd_fd *kconsumerd_fd) +{ + unsigned long len; + int err; + long ret = 0; + int infd = kconsumerd_fd->consumerd_fd; + + err = kernctl_snapshot(infd); + if (err != 0) { + ret = errno; + perror("Getting sub-buffer snapshot."); + goto end; + } + err = kernctl_snapshot_get_produced(infd, &len); + if (err != 0) { + ret = errno; + perror("kernctl_snapshot_get_produced"); + goto end; + } + /* write the subbuffer to the tracefile */ + ret = lttng_kconsumerd_on_read_subbuffer_mmap_snapshot(ctx, + kconsumerd_fd, len); + if (ret < 0) { + ERR("Error writing to tracefile"); + } + +end: + return ret; +} + +/* + * Dump a snapshot to a tracefile + * + * Returns 0 on success, < 0 on error + */ +int lttng_kconsumerd_on_read_subbuffer_mmap_snapshot( + struct lttng_kconsumerd_local_data *ctx, + struct lttng_kconsumerd_fd *kconsumerd_fd, unsigned long end) +{ + unsigned long len; + long ret = 0; + off_t orig_offset = kconsumerd_fd->out_fd_offset; + int fd = kconsumerd_fd->consumerd_fd; + int outfd = kconsumerd_fd->out_fd; + unsigned long start = kconsumerd_fd->snapshot_start; + unsigned long max_subbuf_size = kconsumerd_fd->max_sb_size; + + len = end - start; + DBG("snapshot len = %lu, need to read %lu subbuff\n", len, + len/max_subbuf_size); + while (len > 0) { + DBG("reading snapshot at pos %lu on fd %d\n", start, fd); + ret = kernctl_get_subbuf(fd, &start); + if (ret != 0) { + ret = errno; + perror("kernctl_get_subbuf"); + goto end; + } + + ret = write(outfd, kconsumerd_fd->mmap_base + start, max_subbuf_size); + if (ret >= max_subbuf_size) { + len -= max_subbuf_size; + } else if (ret < 0) { + ret = errno; + perror("Error in file write"); + goto end; + } + ret = kernctl_put_next_subbuf(fd); + if (ret != 0) { + ret = errno; + perror("kernctl_put_subbuf"); + goto end; + } + + start += max_subbuf_size; + kconsumerd_fd->snapshot_start += max_subbuf_size; + if (outfd != 0) { + /* This won't block, but will start writeout asynchronously */ + sync_file_range(outfd, kconsumerd_fd->out_fd_offset, ret, + SYNC_FILE_RANGE_WRITE); + kconsumerd_fd->out_fd_offset += ret; + } + } + + lttng_kconsumerd_sync_trace_file(kconsumerd_fd, orig_offset); + +end: + return ret; +} + +/* * Poll on the should_quit pipe and the command socket return -1 on error and * should exit, 0 if data is available on the command socket */ -- 1.7.4.1 _______________________________________________ ltt-dev mailing list [email protected] http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
