[ltt-dev] [LTTNG-TOOLS PATCH 1/3] Snapshot handling in liblttngkconsumerd
Julien Desfossez
julien.desfossez at polymtl.ca
Sun Aug 14 23:13:34 EDT 2011
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 <julien.desfossez at polymtl.ca>
---
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
More information about the lttng-dev
mailing list