aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-07-22 15:32:45 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-07-22 15:32:45 -0400
commit3ed62b0c016ba90d7e5c1d33d40e894a6b584b05 (patch)
tree70782fd831ac4c478e42642a62cc17cb29bfa25e
parentfe4d69ff08af09af62b6021ddba1fa0340756cf7 (diff)
downloadtrace-cmd-trace-devel.tar.gz
trace-cmd: Add -m option to record to limit size of data filetrace-devel
As long runs of recording traces can cause the disk to fill up, adding an option that lets the user limit the size of the data file can be really useful. Now with the '-m' option to trace-cmd record, this will limit the max size of the per cpu data files to this number in kilobytes (rounded to pages). Suggested-by: David Sommerseth <davids@redhat.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Documentation/trace-cmd-record.1.txt9
-rw-r--r--trace-cmd.h2
-rw-r--r--trace-record.c17
-rw-r--r--trace-recorder.c181
-rw-r--r--trace-usage.c2
5 files changed, 202 insertions, 9 deletions
diff --git a/Documentation/trace-cmd-record.1.txt b/Documentation/trace-cmd-record.1.txt
index b95e1b4f..832a2571 100644
--- a/Documentation/trace-cmd-record.1.txt
+++ b/Documentation/trace-cmd-record.1.txt
@@ -194,6 +194,15 @@ OPTIONS
that buffer. A 'time' buffer instance is created and all timer events
will be enabled for that event.
+*-m* 'size'::
+ The max size in kilobytes that a per cpu buffer should be. Note, due
+ to rounding to page size, the number may not be totally correct.
+ Also, this is performed by switching between two buffers that are half
+ the given size thus the output may not be of the given size even if
+ much more was written.
+
+ Use this to prevent running out of diskspace for long runs.
+
*-k*::
By default, when trace-cmd is finished tracing, it will reset the buffers
and disable all the tracing that it enabled. This option keeps trace-cmd
diff --git a/trace-cmd.h b/trace-cmd.h
index bae4cc14..cbbc6ed8 100644
--- a/trace-cmd.h
+++ b/trace-cmd.h
@@ -238,8 +238,10 @@ enum {
void tracecmd_free_recorder(struct tracecmd_recorder *recorder);
struct tracecmd_recorder *tracecmd_create_recorder(const char *file, int cpu, unsigned flags);
struct tracecmd_recorder *tracecmd_create_recorder_fd(int fd, int cpu, unsigned flags);
+struct tracecmd_recorder *tracecmd_create_recorder_maxkb(const char *file, int cpu, unsigned flags, int maxkb);
struct tracecmd_recorder *tracecmd_create_buffer_recorder_fd(int fd, int cpu, unsigned flags, const char *buffer);
struct tracecmd_recorder *tracecmd_create_buffer_recorder(const char *file, int cpu, unsigned flags, const char *buffer);
+struct tracecmd_recorder *tracecmd_create_buffer_recorder_maxkb(const char *file, int cpu, unsigned flags, const char *buffer, int maxkb);
int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep);
void tracecmd_stop_recording(struct tracecmd_recorder *recorder);
diff --git a/trace-record.c b/trace-record.c
index 407576f7..ac9f70a5 100644
--- a/trace-record.c
+++ b/trace-record.c
@@ -84,6 +84,9 @@ static char *host;
static int *client_ports;
static int sfd;
+/* Max size to let a per cpu file get */
+static int max_kb;
+
static int do_ptrace;
static int filter_task;
@@ -1532,14 +1535,15 @@ create_recorder_instance(struct buffer_instance *instance, const char *file, int
char *path;
if (!name)
- return tracecmd_create_recorder(file, cpu, recorder_flags);
+ return tracecmd_create_recorder_maxkb(file, cpu, recorder_flags, max_kb);
tmp = malloc_or_die(strlen(name) + strlen("instances/") + 1);
sprintf(tmp, "instances/%s", name);
path = tracecmd_get_tracing_file(tmp);
free(tmp);
- record = tracecmd_create_buffer_recorder(file, cpu, recorder_flags, path);
+ record = tracecmd_create_buffer_recorder_maxkb(file, cpu, recorder_flags,
+ path, max_kb);
tracecmd_put_tracing_file(path);
return record;
@@ -2343,7 +2347,7 @@ void trace_record (int argc, char **argv)
if (extract)
opts = "+haf:Fp:co:O:sr:g:l:n:P:N:tb:ksiT";
else
- opts = "+hae:f:Fp:cdDo:O:s:r:vg:l:n:P:N:tb:B:ksiT";
+ opts = "+hae:f:Fp:cdDo:O:s:r:vg:l:n:P:N:tb:B:ksiTm:";
c = getopt_long (argc-1, argv+1, opts, long_options, &option_index);
if (c == -1)
break;
@@ -2482,6 +2486,13 @@ void trace_record (int argc, char **argv)
die("-N incompatible with -o");
host = optarg;
break;
+ case 'm':
+ if (max_kb)
+ die("-m can only be specified once");
+ if (!record)
+ die("only record take 'm' option");
+ max_kb = atoi(optarg);
+ break;
case 't':
use_tcp = 1;
break;
diff --git a/trace-recorder.c b/trace-recorder.c
index dd23e93f..7db5f3ed 100644
--- a/trace-recorder.c
+++ b/trace-recorder.c
@@ -37,30 +37,79 @@
struct tracecmd_recorder {
int fd;
+ int fd1;
+ int fd2;
int trace_fd;
int brass[2];
int page_size;
int cpu;
int stop;
+ int max;
+ int pages;
+ int count;
unsigned flags;
};
+static int append_file(int size, int dst, int src)
+{
+ char buf[size];
+ int r;
+
+ lseek64(src, 0, SEEK_SET);
+
+ /* If there's an error, then we are pretty much screwed :-p */
+ do {
+ r = read(src, buf, size);
+ if (r < 0)
+ return r;
+ r = write(dst, buf, r);
+ if (r < 0)
+ return r;
+ } while (r);
+ return 0;
+}
+
void tracecmd_free_recorder(struct tracecmd_recorder *recorder)
{
if (!recorder)
return;
+ if (recorder->max) {
+ /* Need to put everything into fd1 */
+ if (recorder->fd == recorder->fd1) {
+ int ret;
+ /*
+ * Crap, the older data is in fd2, and we need
+ * to append fd1 onto it, and then copy over to fd1
+ */
+ ret = append_file(recorder->page_size,
+ recorder->fd2, recorder->fd1);
+ /* Error on copying, then just keep fd1 */
+ if (ret) {
+ lseek64(recorder->fd1, 0, SEEK_END);
+ goto close;
+ }
+ lseek64(recorder->fd1, 0, SEEK_SET);
+ ftruncate(recorder->fd1, 0);
+ }
+ append_file(recorder->page_size, recorder->fd1, recorder->fd2);
+ }
+ close:
if (recorder->trace_fd >= 0)
close(recorder->trace_fd);
- if (recorder->fd >= 0)
- close(recorder->fd);
+ if (recorder->fd1 >= 0)
+ close(recorder->fd1);
+
+ if (recorder->fd2 >= 0)
+ close(recorder->fd2);
free(recorder);
}
struct tracecmd_recorder *
-tracecmd_create_buffer_recorder_fd(int fd, int cpu, unsigned flags, const char *buffer)
+tracecmd_create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
+ const char *buffer, int maxkb)
{
struct tracecmd_recorder *recorder;
char *path = NULL;
@@ -79,8 +128,26 @@ tracecmd_create_buffer_recorder_fd(int fd, int cpu, unsigned flags, const char *
recorder->brass[1] = -1;
recorder->page_size = getpagesize();
-
+ if (maxkb) {
+ int kb_per_page = recorder->page_size >> 10;
+
+ if (!kb_per_page)
+ kb_per_page = 1;
+ recorder->max = maxkb / kb_per_page;
+ /* keep max half */
+ recorder->max >>= 1;
+ if (!recorder->max)
+ recorder->max = 1;
+ } else
+ recorder->max = 0;
+
+ recorder->count = 0;
+ recorder->pages = 0;
+
+ /* fd always points to what to write to */
recorder->fd = fd;
+ recorder->fd1 = fd;
+ recorder->fd2 = fd2;
path = malloc_or_die(strlen(buffer) + 40);
if (!path)
@@ -112,6 +179,12 @@ tracecmd_create_buffer_recorder_fd(int fd, int cpu, unsigned flags, const char *
}
struct tracecmd_recorder *
+tracecmd_create_buffer_recorder_fd(int fd, int cpu, unsigned flags, const char *buffer)
+{
+ return tracecmd_create_buffer_recorder_fd2(fd, -1, cpu, flags, buffer, 0);
+}
+
+struct tracecmd_recorder *
tracecmd_create_buffer_recorder(const char *file, int cpu, unsigned flags, const char *buffer)
{
struct tracecmd_recorder *recorder;
@@ -130,6 +203,51 @@ tracecmd_create_buffer_recorder(const char *file, int cpu, unsigned flags, const
return recorder;
}
+struct tracecmd_recorder *
+tracecmd_create_buffer_recorder_maxkb(const char *file, int cpu, unsigned flags,
+ const char *buffer, int maxkb)
+{
+ struct tracecmd_recorder *recorder = NULL;
+ char *file2;
+ int len;
+ int fd;
+ int fd2;
+
+ if (!maxkb)
+ return tracecmd_create_buffer_recorder(file, cpu, flags, buffer);
+
+ len = strlen(file);
+ file2 = malloc(len + 3);
+ if (!file2)
+ return NULL;
+
+ sprintf(file2, "%s.1", file);
+
+ fd = open(file, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
+ if (fd < 0)
+ goto out;
+
+ fd2 = open(file2, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
+ if (fd < 0)
+ goto err;
+
+ recorder = tracecmd_create_buffer_recorder_fd2(fd, fd2, cpu, flags, buffer, maxkb);
+ if (!recorder)
+ goto err2;
+ out:
+ /* Unlink file2, we need to add everything to file at the end */
+ unlink(file2);
+ free(file2);
+
+ return recorder;
+ err2:
+ close(fd2);
+ err:
+ close(fd);
+ unlink(file);
+ goto out;
+}
+
struct tracecmd_recorder *tracecmd_create_recorder_fd(int fd, int cpu, unsigned flags)
{
char *tracing;
@@ -156,6 +274,54 @@ struct tracecmd_recorder *tracecmd_create_recorder(const char *file, int cpu, un
return tracecmd_create_buffer_recorder(file, cpu, flags, tracing);
}
+struct tracecmd_recorder *
+tracecmd_create_recorder_maxkb(const char *file, int cpu, unsigned flags, int maxkb)
+{
+ char *tracing;
+
+ tracing = tracecmd_find_tracing_dir();
+ if (!tracing) {
+ errno = ENODEV;
+ return NULL;
+ }
+
+ return tracecmd_create_buffer_recorder_maxkb(file, cpu, flags, tracing, maxkb);
+}
+
+static inline void update_fd(struct tracecmd_recorder *recorder, int size)
+{
+ int fd;
+
+ if (!recorder->max)
+ return;
+
+ recorder->count += size;
+
+ if (recorder->count >= recorder->page_size) {
+ recorder->count = 0;
+ recorder->pages++;
+ }
+
+ if (recorder->pages < recorder->max)
+ return;
+
+ recorder->pages = 0;
+
+ fd = recorder->fd;
+
+ /* Swap fd to next file. */
+ if (fd == recorder->fd1)
+ fd = recorder->fd2;
+ else
+ fd = recorder->fd1;
+
+ /* Zero out the new file we are writing to */
+ lseek64(fd, 0, SEEK_SET);
+ ftruncate(fd, 0);
+
+ recorder->fd = fd;
+}
+
/*
* Returns -1 on error.
* or bytes of data read.
@@ -181,7 +347,8 @@ static long splice_data(struct tracecmd_recorder *recorder)
return -1;
}
ret = 0;
- }
+ } else
+ update_fd(recorder, ret);
return ret;
}
@@ -203,8 +370,10 @@ static long read_data(struct tracecmd_recorder *recorder)
}
ret = 0;
}
- if (ret > 0)
+ if (ret > 0) {
write(recorder->fd, buf, ret);
+ update_fd(recorder, ret);
+ }
return ret;
}
diff --git a/trace-usage.c b/trace-usage.c
index 159da824..b8f26e64 100644
--- a/trace-usage.c
+++ b/trace-usage.c
@@ -19,6 +19,7 @@ static struct usage_help usage_help[] = {
" %s record [-v][-e event [-f filter]][-p plugin][-F][-d][-D][-o file] \\\n"
" [-s usecs][-O option ][-l func][-g func][-n func] \\\n"
" [-P pid][-N host:port][-t][-r prio][-b size][-B buf][command ...]\n"
+ " [-m max]\n"
" -e run command with event enabled\n"
" -f filter for previous -e event\n"
" -p run command with plugin enabled\n"
@@ -29,6 +30,7 @@ static struct usage_help usage_help[] = {
" -l filter function name\n"
" -g set graph function\n"
" -n do not trace function\n"
+ " -m max size per CPU in kilobytes\n"
" -v will negate all -e after it (disable those events)\n"
" -d disable function tracer when running\n"
" -D Full disable of function tracing (for all users)\n"