From 176b56b261a711822f35e36ec5e2d5e0758770de Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 4 Mar 2009 12:51:29 -0600 Subject: Start of new ring_buffer transport. 2009-03-04 David Smith * runtime.h: Added _stp_exit() prototype. * transport/ring_buffer.c: New file. * transport/transport.c: Removed unneeded utt_trace lines. Includes transport/ring_buffer.c. (_stp_transport_fs_init): Calls _stp_transport_data_fs_init(). (_stp_transport_fs_close): Calls _stp_transport_data_fs_close(). * transport/transport.h: Added prototypes. --- runtime/transport/ring_buffer.c | 338 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 runtime/transport/ring_buffer.c (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c new file mode 100644 index 00000000..53149fcd --- /dev/null +++ b/runtime/transport/ring_buffer.c @@ -0,0 +1,338 @@ +#include +#include + +static struct ring_buffer *__stp_ring_buffer = NULL; +//DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); + +static void __stp_free_ring_buffer(void) +{ + if (__stp_ring_buffer) + ring_buffer_free(__stp_ring_buffer); + __stp_ring_buffer = NULL; +} + +static int __stp_alloc_ring_buffer(void) +{ + int i; + unsigned long buffer_size = _stp_bufsize; + + dbug_trans(1, "%lu\n", buffer_size); + __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); + if (!__stp_ring_buffer) + goto fail; + +// DRS: do we need this? +#if 0 + for_each_possible_cpu(i) { + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); + + b->last_task = NULL; + b->last_is_kernel = -1; + b->tracing = 0; + b->buffer_size = buffer_size; + b->sample_received = 0; + b->sample_lost_overflow = 0; + b->backtrace_aborted = 0; + b->sample_invalid_eip = 0; + b->cpu = i; + INIT_DELAYED_WORK(&b->work, wq_sync_buffer); + } +#endif + return 0; + +fail: + __stp_free_ring_buffer(); + return -ENOMEM; +} + + +static atomic_t _stp_trace_attached = ATOMIC_INIT(0); +static struct trace_iterator _stp_trace_iter; + +static int _stp_data_open_trace(struct inode *inode, struct file *file) +{ + /* We only allow for one reader */ + dbug_trans(1, "trace attach\n"); + if (atomic_inc_return(&_stp_trace_attached) != 1) { + atomic_dec(&_stp_trace_attached); + dbug_trans(1, "returning EBUSY\n"); + return -EBUSY; + } + + file->private_data = &_stp_trace_iter; + return 0; +} + +static int _stp_data_release_trace(struct inode *inode, struct file *file) +{ + dbug_trans(1, "trace detach\n"); + atomic_dec(&_stp_trace_attached); + return 0; +} + +struct trace_seq { + unsigned char buffer[PAGE_SIZE]; + unsigned int len; + unsigned int readpos; +}; + +ssize_t +_stp_trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) +{ + int len; + int ret; + + dbug_trans(1, "s: %p\n", s); + if (s == NULL) + return -EFAULT; + + dbug_trans(1, "len: %d, readpos: %d, buffer: %p\n", s->len, + s->readpos, s->buffer); + if (s->len <= s->readpos) + return -EBUSY; + + len = s->len - s->readpos; + if (cnt > len) + cnt = len; + ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); + if (ret) + return -EFAULT; + + s->readpos += len; + return cnt; +} + +static void +trace_seq_reset(struct trace_seq *s) +{ + s->len = 0; + s->readpos = 0; +} + +/* + * Trace iterator - used by printout routines who present trace + * results to users and which routines might sleep, etc: + */ +struct trace_iterator { +#if 0 + struct trace_array *tr; + struct tracer *trace; + void *private; +#endif + struct ring_buffer_iter *buffer_iter[NR_CPUS]; + + /* The below is zeroed out in pipe_read */ + struct trace_seq seq; +#if 0 + struct trace_entry *ent; + int cpu; + u64 ts; + + unsigned long iter_flags; +#endif + loff_t pos; +#if 0 + long idx; + + cpumask_var_t started; +#endif +}; + +static int trace_empty(struct trace_iterator *iter) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (iter->buffer_iter[cpu]) { + if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) + return 0; +#if 0 + } else { + if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) + return 0; +#endif + } + } + + return 1; +} + +/* Must be called with trace_types_lock mutex held. */ +static int tracing_wait_pipe(struct file *filp) +{ + struct trace_iterator *iter = filp->private_data; + + while (trace_empty(iter)) { + + if ((filp->f_flags & O_NONBLOCK)) { + return -EAGAIN; + } + + /* + * This is a make-shift waitqueue. The reason we don't use + * an actual wait queue is because: + * 1) we only ever have one waiter + * 2) the tracing, traces all functions, we don't want + * the overhead of calling wake_up and friends + * (and tracing them too) + * Anyway, this is really very primitive wakeup. + */ + set_current_state(TASK_INTERRUPTIBLE); + //iter->tr->waiter = current; + + /* sleep for 100 msecs, and try again. */ + schedule_timeout(HZ/10); + + //iter->tr->waiter = NULL; + + if (signal_pending(current)) { + return -EINTR; + } + +#if 0 + if (iter->trace != current_trace) + return 0; + + /* + * We block until we read something and tracing is disabled. + * We still block if tracing is disabled, but we have never + * read anything. This allows a user to cat this file, and + * then enable tracing. But after we have read something, + * we give an EOF when tracing is again disabled. + * + * iter->pos will be 0 if we haven't read anything. + */ + if (!tracer_enabled && iter->pos) + break; +#else + if (iter->pos) + break; +#endif + + continue; + } + + return 1; +} + +/* + * Consumer reader. + */ +static ssize_t +_stp_data_read_trace(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct trace_iterator *iter = filp->private_data; + ssize_t sret; + + /* return any leftover data */ + dbug_trans(1, "%lu\n", (unsigned long)cnt); + sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); + if (sret != -EBUSY) + return sret; + + trace_seq_reset(&iter->seq); + +waitagain: + sret = tracing_wait_pipe(filp); + if (sret <= 0) + goto out; + + /* stop when tracing is finished */ + if (trace_empty(iter)) { + sret = 0; + goto out; + } + + if (cnt >= PAGE_SIZE) + cnt = PAGE_SIZE - 1; + + /* reset all but tr, trace, and overruns */ + memset(&iter->seq, 0, + sizeof(struct trace_iterator) - + offsetof(struct trace_iterator, seq)); + iter->pos = -1; + +#if 0 + while (find_next_entry_inc(iter) != NULL) { + enum print_line_t ret; + int len = iter->seq.len; + + ret = print_trace_line(iter); + if (ret == TRACE_TYPE_PARTIAL_LINE) { + /* don't print partial lines */ + iter->seq.len = len; + break; + } + if (ret != TRACE_TYPE_NO_CONSUME) + trace_consume(iter); + + if (iter->seq.len >= cnt) + break; + } +#endif + + /* Now copy what we have to the user */ + sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); + if (iter->seq.readpos >= iter->seq.len) + trace_seq_reset(&iter->seq); + + /* + * If there was nothing to send to user, inspite of consuming trace + * entries, go back to wait for more entries. + */ + if (sret == -EBUSY) + goto waitagain; + +out: + return sret; +} + +static struct file_operations __stp_data_fops = { + .owner = THIS_MODULE, + .open = _stp_data_open_trace, + .release = _stp_data_release_trace, +#if 0 + .poll = tracing_poll_pipe, +#endif + .read = _stp_data_read_trace, +#if 0 + .splice_read = tracing_splice_read_pipe, +#endif +}; + +static struct dentry *__stp_entry; + +static int _stp_transport_data_fs_init(void) +{ + int rc; + + // allocate buffer + dbug_trans(1, "entry...\n"); + rc = __stp_alloc_ring_buffer(); + if (rc != 0) + return rc; + + // create file(s) + __stp_entry = debugfs_create_file("trace", 0600, _stp_get_module_dir(), + NULL, &__stp_data_fops); + if (!__stp_entry) + pr_warning("Could not create debugfs 'trace' entry\n"); + else { + __stp_entry->d_inode->i_uid = _stp_uid; + __stp_entry->d_inode->i_gid = _stp_gid; + } + + dbug_trans(1, "returning 0...\n"); + return 0; +} + +static void _stp_transport_data_fs_close(void) +{ + if (__stp_entry) + debugfs_remove(__stp_entry); + __stp_entry = NULL; + + __stp_free_ring_buffer(); +} + -- cgit From eb3101a40fe446cffab677a7d117f028bae9afba Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 9 Mar 2009 10:06:20 -0500 Subject: First working version that actually produces output. 2009-03-09 David Smith * print_new.c (stp_print_flush): Calls _stp_data_write_reserve() and _stp_data_write_commit(). * transport/ring_buffer.c (__stp_alloc_ring_buffer): Sets up a default buffer size of STP_BUFFER_SIZE; (trace_seq_reset): New function. (peek_next_entry): New function. (__find_next_entry): New function. (find_next_entry_inc): New function. (_stp_data_read_trace): Uses find_next_entry_inc() to get the next entry, then calls _stp_entry_to_user() to copy it to the user's buffer, then calls ring_buffer_consume() to consume it. (_stp_data_write_reserve): New function. (_stp_data_write_commit): New function. * transport/transport.c (_stp_transport_close): Calls functions that were ifdef'ed out. * transport/transport.h (struct _stp_entry): Added _stp_entry definition and _stp_data_write_reserve()/_stp_data_write_commit() prototypes. --- runtime/transport/ring_buffer.c | 302 ++++++++++++++++++++++++++++++++-------- 1 file changed, 244 insertions(+), 58 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 53149fcd..8b176ae3 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,8 +4,58 @@ static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); +#if 1 +/* + * Trace iterator - used by printout routines who present trace + * results to users and which routines might sleep, etc: + */ +struct _stp_ring_buffer_iterator { +#if 0 + struct trace_array *tr; + struct tracer *trace; + void *private; + struct ring_buffer_iter *buffer_iter[NR_CPUS]; + + /* The below is zeroed out in pipe_read */ + struct trace_seq seq; + struct trace_entry *ent; +#endif + int cpu; + u64 ts; + +#if 0 + unsigned long iter_flags; + loff_t pos; + long idx; + + cpumask_var_t started; +#endif +}; +static struct _stp_ring_buffer_iterator _stp_iter; +#else +static struct ring_buffer_iter *__stp_ring_buffer_iter[NR_CPUS]; +#endif + static void __stp_free_ring_buffer(void) { + int i; + +#if 0 + if (__stp_ring_buffer) { + ring_buffer_record_disable(__stp_ring_buffer); + for_each_possible_cpu(i) { + ring_buffer_record_disable_cpu(__stp_ring_buffer, i); + } + } +#endif + +#if 0 + for_each_possible_cpu(i) { + if (__stp_ring_buffer_iter[i]) + ring_buffer_read_finish(__stp_ring_buffer_iter[i]); + } +#endif + if (__stp_ring_buffer) ring_buffer_free(__stp_ring_buffer); __stp_ring_buffer = NULL; @@ -16,11 +66,22 @@ static int __stp_alloc_ring_buffer(void) int i; unsigned long buffer_size = _stp_bufsize; + if (buffer_size == 0) + buffer_size = STP_BUFFER_SIZE; dbug_trans(1, "%lu\n", buffer_size); __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); if (!__stp_ring_buffer) goto fail; +#if 0 + dbug_trans(1, "enabling recording...\n"); + ring_buffer_record_enable(__stp_ring_buffer); + for_each_possible_cpu(i) { + ring_buffer_record_enable_cpu(__stp_ring_buffer, i); + } +#endif + + // DRS: do we need this? #if 0 for_each_possible_cpu(i) { @@ -37,7 +98,24 @@ static int __stp_alloc_ring_buffer(void) b->cpu = i; INIT_DELAYED_WORK(&b->work, wq_sync_buffer); } + + /* Allocate the first page for all buffers */ + for_each_possible_cpu(i) { + data = global_trace.data[i] = &per_cpu(global_trace_cpu, i); + max_tr.data[i] = &per_cpu(max_data, i); + } #endif + +#if 0 + for_each_possible_cpu(i) { + __stp_ring_buffer_iter[i] = + ring_buffer_read_start(__stp_ring_buffer, i); + + if (!__stp_ring_buffer_iter[i]) + goto fail; + } +#endif + return 0; fail: @@ -47,7 +125,6 @@ fail: static atomic_t _stp_trace_attached = ATOMIC_INIT(0); -static struct trace_iterator _stp_trace_iter; static int _stp_data_open_trace(struct inode *inode, struct file *file) { @@ -59,7 +136,7 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) return -EBUSY; } - file->private_data = &_stp_trace_iter; +// file->private_data = &_stp_trace_iter; return 0; } @@ -102,6 +179,28 @@ _stp_trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) return cnt; } +size_t +_stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) +{ + int ret; + + dbug_trans(1, "entry(%p), ubuf(%p), cnt(%lu)\n", entry, ubuf, cnt); + if (entry == NULL || ubuf == NULL) + return -EFAULT; + + /* We don't do partial entries - just fail. */ + if (entry->len > cnt) + return -EBUSY; + + if (cnt > entry->len) + cnt = entry->len; + ret = copy_to_user(ubuf, entry->buf, cnt); + if (ret) + return -EFAULT; + + return cnt; +} + static void trace_seq_reset(struct trace_seq *s) { @@ -109,6 +208,7 @@ trace_seq_reset(struct trace_seq *s) s->readpos = 0; } +#if 0 /* * Trace iterator - used by printout routines who present trace * results to users and which routines might sleep, etc: @@ -137,34 +237,37 @@ struct trace_iterator { cpumask_var_t started; #endif }; +#endif -static int trace_empty(struct trace_iterator *iter) +#if 0 +static int _stp_data_empty(void) { int cpu; for_each_possible_cpu(cpu) { - if (iter->buffer_iter[cpu]) { - if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) - return 0; #if 0 - } else { - if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) + if (__stp_ring_buffer_iter[cpu]) { + if (!ring_buffer_iter_empty(__stp_ring_buffer_iter[cpu])) return 0; -#endif } +#else + if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) + return 0; +#endif } return 1; } +#endif /* Must be called with trace_types_lock mutex held. */ -static int tracing_wait_pipe(struct file *filp) +static ssize_t tracing_wait_pipe(struct file *filp) { - struct trace_iterator *iter = filp->private_data; - - while (trace_empty(iter)) { +// while (_stp_data_empty()) { + while (ring_buffer_empty(__stp_ring_buffer)) { if ((filp->f_flags & O_NONBLOCK)) { + dbug_trans(1, "returning -EAGAIN\n"); return -EAGAIN; } @@ -186,6 +289,7 @@ static int tracing_wait_pipe(struct file *filp) //iter->tr->waiter = NULL; if (signal_pending(current)) { + dbug_trans(1, "returning -EINTR\n"); return -EINTR; } @@ -204,17 +308,71 @@ static int tracing_wait_pipe(struct file *filp) */ if (!tracer_enabled && iter->pos) break; -#else - if (iter->pos) - break; #endif continue; } + dbug_trans(1, "returning 1\n"); return 1; } +static struct _stp_entry * +peek_next_entry(int cpu, u64 *ts) +{ + struct ring_buffer_event *event; + + event = ring_buffer_peek(__stp_ring_buffer, cpu, ts); + + return event ? ring_buffer_event_data(event) : NULL; +} + +static struct _stp_entry * +__find_next_entry(int *ent_cpu, u64 *ent_ts) +{ + struct _stp_entry *ent, *next = NULL; + u64 next_ts = 0, ts; + int next_cpu = -1; + int cpu; + + for_each_possible_cpu(cpu) { + + if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) + continue; + + ent = peek_next_entry(cpu, &ts); + + /* + * Pick the entry with the smallest timestamp: + */ + if (ent && (!next || ts < next_ts)) { + next = ent; + next_cpu = cpu; + next_ts = ts; + } + } + + if (ent_cpu) + *ent_cpu = next_cpu; + + if (ent_ts) + *ent_ts = next_ts; + + return next; +} + +/* Find the next real entry, and increment the iterator to the next entry */ +static struct _stp_entry *find_next_entry_inc(void) +{ + return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); + +// if (iter->ent) +// trace_iterator_increment(iter); + +// return iter->ent ? iter : NULL; +} + + /* * Consumer reader. */ @@ -222,24 +380,18 @@ static ssize_t _stp_data_read_trace(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct trace_iterator *iter = filp->private_data; ssize_t sret; + struct _stp_entry *entry; - /* return any leftover data */ dbug_trans(1, "%lu\n", (unsigned long)cnt); - sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); - if (sret != -EBUSY) - return sret; - - trace_seq_reset(&iter->seq); -waitagain: sret = tracing_wait_pipe(filp); + dbug_trans(1, "tracing_wait_pipe returned %ld\n", sret); if (sret <= 0) goto out; /* stop when tracing is finished */ - if (trace_empty(iter)) { + if (ring_buffer_empty(__stp_ring_buffer)) { sret = 0; goto out; } @@ -247,43 +399,23 @@ waitagain: if (cnt >= PAGE_SIZE) cnt = PAGE_SIZE - 1; - /* reset all but tr, trace, and overruns */ - memset(&iter->seq, 0, - sizeof(struct trace_iterator) - - offsetof(struct trace_iterator, seq)); - iter->pos = -1; + dbug_trans(1, "sret = %lu\n", (unsigned long)sret); + sret = 0; + while ((entry = find_next_entry_inc()) != NULL) { + ssize_t len; -#if 0 - while (find_next_entry_inc(iter) != NULL) { - enum print_line_t ret; - int len = iter->seq.len; - - ret = print_trace_line(iter); - if (ret == TRACE_TYPE_PARTIAL_LINE) { - /* don't print partial lines */ - iter->seq.len = len; + len = _stp_entry_to_user(entry, ubuf, cnt); + if (len <= 0) break; - } - if (ret != TRACE_TYPE_NO_CONSUME) - trace_consume(iter); - if (iter->seq.len >= cnt) + ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, + &_stp_iter.ts); + ubuf += len; + cnt -= len; + sret += len; + if (cnt <= 0) break; } -#endif - - /* Now copy what we have to the user */ - sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); - if (iter->seq.readpos >= iter->seq.len) - trace_seq_reset(&iter->seq); - - /* - * If there was nothing to send to user, inspite of consuming trace - * entries, go back to wait for more entries. - */ - if (sret == -EBUSY) - goto waitagain; - out: return sret; } @@ -301,6 +433,59 @@ static struct file_operations __stp_data_fops = { #endif }; +/* + * This function prepares the cpu buffer to write a sample. + * + * Struct op_entry is used during operations on the ring buffer while + * struct op_sample contains the data that is stored in the ring + * buffer. Struct entry can be uninitialized. The function reserves a + * data array that is specified by size. Use + * op_cpu_buffer_write_commit() after preparing the sample. In case of + * errors a null pointer is returned, otherwise the pointer to the + * sample. + * + */ +static struct _stp_entry * +_stp_data_write_reserve(size_t size) +{ + struct ring_buffer_event *event; + struct _stp_entry *entry; + + event = ring_buffer_lock_reserve(__stp_ring_buffer, + (sizeof(struct _stp_entry) + size), + 0); + if (unlikely(! event)) { + dbug_trans(1, "event = NULL (%p)?\n", event); + return NULL; + } + + entry = ring_buffer_event_data(event); + entry->event = event; + entry->len = size; + return entry; +} + +static int _stp_data_write_commit(struct _stp_entry *entry) +{ + if (unlikely(! entry)) { + dbug_trans(1, "entry = NULL, returning -EINVAL\n"); + return -EINVAL; + } + +#if 0 + return ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); +#else + { + int ret; + ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); + dbug_trans(1, "after commit, empty returns %d\n", + ring_buffer_empty(__stp_ring_buffer)); + return ret; + } +#endif +} + + static struct dentry *__stp_entry; static int _stp_transport_data_fs_init(void) @@ -314,7 +499,8 @@ static int _stp_transport_data_fs_init(void) return rc; // create file(s) - __stp_entry = debugfs_create_file("trace", 0600, _stp_get_module_dir(), + __stp_entry = debugfs_create_file("trace0", 0600, + _stp_get_module_dir(), NULL, &__stp_data_fops); if (!__stp_entry) pr_warning("Could not create debugfs 'trace' entry\n"); -- cgit From ef20115ab2d3d5d1a2e9fca84eff53c7430a24c6 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 9 Mar 2009 14:25:10 -0500 Subject: Cleanup. --- runtime/transport/ring_buffer.c | 177 ++++------------------------------------ 1 file changed, 15 insertions(+), 162 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 8b176ae3..af171d04 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -32,30 +32,10 @@ struct _stp_ring_buffer_iterator { #endif }; static struct _stp_ring_buffer_iterator _stp_iter; -#else -static struct ring_buffer_iter *__stp_ring_buffer_iter[NR_CPUS]; #endif static void __stp_free_ring_buffer(void) { - int i; - -#if 0 - if (__stp_ring_buffer) { - ring_buffer_record_disable(__stp_ring_buffer); - for_each_possible_cpu(i) { - ring_buffer_record_disable_cpu(__stp_ring_buffer, i); - } - } -#endif - -#if 0 - for_each_possible_cpu(i) { - if (__stp_ring_buffer_iter[i]) - ring_buffer_read_finish(__stp_ring_buffer_iter[i]); - } -#endif - if (__stp_ring_buffer) ring_buffer_free(__stp_ring_buffer); __stp_ring_buffer = NULL; @@ -73,49 +53,6 @@ static int __stp_alloc_ring_buffer(void) if (!__stp_ring_buffer) goto fail; -#if 0 - dbug_trans(1, "enabling recording...\n"); - ring_buffer_record_enable(__stp_ring_buffer); - for_each_possible_cpu(i) { - ring_buffer_record_enable_cpu(__stp_ring_buffer, i); - } -#endif - - -// DRS: do we need this? -#if 0 - for_each_possible_cpu(i) { - struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); - - b->last_task = NULL; - b->last_is_kernel = -1; - b->tracing = 0; - b->buffer_size = buffer_size; - b->sample_received = 0; - b->sample_lost_overflow = 0; - b->backtrace_aborted = 0; - b->sample_invalid_eip = 0; - b->cpu = i; - INIT_DELAYED_WORK(&b->work, wq_sync_buffer); - } - - /* Allocate the first page for all buffers */ - for_each_possible_cpu(i) { - data = global_trace.data[i] = &per_cpu(global_trace_cpu, i); - max_tr.data[i] = &per_cpu(max_data, i); - } -#endif - -#if 0 - for_each_possible_cpu(i) { - __stp_ring_buffer_iter[i] = - ring_buffer_read_start(__stp_ring_buffer, i); - - if (!__stp_ring_buffer_iter[i]) - goto fail; - } -#endif - return 0; fail: @@ -123,7 +60,6 @@ fail: return -ENOMEM; } - static atomic_t _stp_trace_attached = ATOMIC_INIT(0); static int _stp_data_open_trace(struct inode *inode, struct file *file) @@ -136,7 +72,6 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) return -EBUSY; } -// file->private_data = &_stp_trace_iter; return 0; } @@ -208,62 +143,8 @@ trace_seq_reset(struct trace_seq *s) s->readpos = 0; } -#if 0 -/* - * Trace iterator - used by printout routines who present trace - * results to users and which routines might sleep, etc: - */ -struct trace_iterator { -#if 0 - struct trace_array *tr; - struct tracer *trace; - void *private; -#endif - struct ring_buffer_iter *buffer_iter[NR_CPUS]; - - /* The below is zeroed out in pipe_read */ - struct trace_seq seq; -#if 0 - struct trace_entry *ent; - int cpu; - u64 ts; - - unsigned long iter_flags; -#endif - loff_t pos; -#if 0 - long idx; - - cpumask_var_t started; -#endif -}; -#endif - -#if 0 -static int _stp_data_empty(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { -#if 0 - if (__stp_ring_buffer_iter[cpu]) { - if (!ring_buffer_iter_empty(__stp_ring_buffer_iter[cpu])) - return 0; - } -#else - if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) - return 0; -#endif - } - - return 1; -} -#endif - -/* Must be called with trace_types_lock mutex held. */ static ssize_t tracing_wait_pipe(struct file *filp) { -// while (_stp_data_empty()) { while (ring_buffer_empty(__stp_ring_buffer)) { if ((filp->f_flags & O_NONBLOCK)) { @@ -292,25 +173,6 @@ static ssize_t tracing_wait_pipe(struct file *filp) dbug_trans(1, "returning -EINTR\n"); return -EINTR; } - -#if 0 - if (iter->trace != current_trace) - return 0; - - /* - * We block until we read something and tracing is disabled. - * We still block if tracing is disabled, but we have never - * read anything. This allows a user to cat this file, and - * then enable tracing. But after we have read something, - * we give an EOF when tracing is again disabled. - * - * iter->pos will be 0 if we haven't read anything. - */ - if (!tracer_enabled && iter->pos) - break; -#endif - - continue; } dbug_trans(1, "returning 1\n"); @@ -362,14 +224,9 @@ __find_next_entry(int *ent_cpu, u64 *ent_ts) } /* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *find_next_entry_inc(void) +static struct _stp_entry *find_next_entry(void) { return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); - -// if (iter->ent) -// trace_iterator_increment(iter); - -// return iter->ent ? iter : NULL; } @@ -401,7 +258,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = find_next_entry_inc()) != NULL) { + while ((entry = find_next_entry) != NULL) { ssize_t len; len = _stp_entry_to_user(entry, ubuf, cnt); @@ -421,9 +278,9 @@ out: } static struct file_operations __stp_data_fops = { - .owner = THIS_MODULE, - .open = _stp_data_open_trace, - .release = _stp_data_release_trace, + .owner = THIS_MODULE, + .open = _stp_data_open_trace, + .release = _stp_data_release_trace, #if 0 .poll = tracing_poll_pipe, #endif @@ -467,22 +324,18 @@ _stp_data_write_reserve(size_t size) static int _stp_data_write_commit(struct _stp_entry *entry) { - if (unlikely(! entry)) { - dbug_trans(1, "entry = NULL, returning -EINVAL\n"); - return -EINVAL; - } + int ret; -#if 0 - return ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); -#else - { - int ret; - ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); - dbug_trans(1, "after commit, empty returns %d\n", - ring_buffer_empty(__stp_ring_buffer)); - return ret; + if (unlikely(! entry)) { + dbug_trans(1, "entry = NULL, returning -EINVAL\n"); + return -EINVAL; } -#endif + + ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); + dbug_trans(1, "after commit, empty returns %d\n", + ring_buffer_empty(__stp_ring_buffer)); + + return ret; } -- cgit From 49f34ab20c2afd95b6a34a904563d456d6deb1d1 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 11 Mar 2009 12:54:19 -0500 Subject: Handles polling and breaks down large buffers. 2009-03-11 David Smith * print_new.c (stp_print_flush): Breaks up the buffer into smaller pieces (since the ring_buffer likes lots of small events, not one large one). * transport/ring_buffer.c (__stp_alloc_ring_buffer): Reserves space for struct _stp_entry. (_stp_data_poll_trace): New function. (_stp_data_write_commit): Wakes up any tasks waiting on data. --- runtime/transport/ring_buffer.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index af171d04..cab8c2fa 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -1,9 +1,15 @@ #include #include +#include +#include static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); +/* _stp_poll_wait is a waitqueue for tasks blocked on + * _stp_data_poll_trace() */ +static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); + #if 1 /* * Trace iterator - used by printout routines who present trace @@ -46,13 +52,17 @@ static int __stp_alloc_ring_buffer(void) int i; unsigned long buffer_size = _stp_bufsize; - if (buffer_size == 0) - buffer_size = STP_BUFFER_SIZE; + if (buffer_size == 0) { + dbug_trans(1, "using default buffer size...\n"); + buffer_size = STP_BUFFER_SIZE + + (4000 * sizeof(struct _stp_entry)); + } dbug_trans(1, "%lu\n", buffer_size); __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); if (!__stp_ring_buffer) goto fail; + dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); return 0; fail: @@ -224,7 +234,7 @@ __find_next_entry(int *ent_cpu, u64 *ent_ts) } /* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *find_next_entry(void) +static struct _stp_entry *_stp_find_next_entry(void) { return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); } @@ -258,7 +268,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = find_next_entry) != NULL) { + while ((entry = _stp_find_next_entry()) != NULL) { ssize_t len; len = _stp_entry_to_user(entry, ubuf, cnt); @@ -277,13 +287,26 @@ out: return sret; } + +static unsigned int +_stp_data_poll_trace(struct file *filp, poll_table *poll_table) +{ + dbug_trans(1, "entry\n"); + if (! ring_buffer_empty(__stp_ring_buffer)) + return POLLIN | POLLRDNORM; + poll_wait(filp, &_stp_poll_wait, poll_table); + if (! ring_buffer_empty(__stp_ring_buffer)) + return POLLIN | POLLRDNORM; + + dbug_trans(1, "exit\n"); + return 0; +} + static struct file_operations __stp_data_fops = { .owner = THIS_MODULE, .open = _stp_data_open_trace, .release = _stp_data_release_trace, -#if 0 - .poll = tracing_poll_pipe, -#endif + .poll = _stp_data_poll_trace, .read = _stp_data_read_trace, #if 0 .splice_read = tracing_splice_read_pipe, @@ -335,6 +358,7 @@ static int _stp_data_write_commit(struct _stp_entry *entry) dbug_trans(1, "after commit, empty returns %d\n", ring_buffer_empty(__stp_ring_buffer)); + wake_up_interruptible(&_stp_poll_wait); return ret; } -- cgit From 12659e2d5eea60a6c1021effa7776bc8e58bb508 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 11 Mar 2009 16:10:14 -0500 Subject: Small update. 2009-03-11 David Smith * print_new.c (stp_print_flush): Updated MAX_RESERVE_SIZE. * transport/ring_buffer.c (__stp_alloc_ring_buffer): Reserves more space. --- runtime/transport/ring_buffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index cab8c2fa..4295a37b 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -54,8 +54,7 @@ static int __stp_alloc_ring_buffer(void) if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); - buffer_size = STP_BUFFER_SIZE - + (4000 * sizeof(struct _stp_entry)); + buffer_size = STP_BUFFER_SIZE * 30; } dbug_trans(1, "%lu\n", buffer_size); __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); -- cgit From 976f6b6a6fae081d1d72d06457d64af87db789ef Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 12 Mar 2009 12:57:31 -0500 Subject: Updated buffer size. 2009-03-12 David Smith * transport/ring_buffer.c (__stp_alloc_ring_buffer): Updated buffer size. --- runtime/transport/ring_buffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 4295a37b..51e9efa2 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -54,8 +54,12 @@ static int __stp_alloc_ring_buffer(void) if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); - buffer_size = STP_BUFFER_SIZE * 30; + buffer_size = _stp_nsubbufs * _stp_subbuf_size; } + /* The number passed to ring_buffer_alloc() is per cpu. Our + * 'buffer_size' is a total number of bytes to allocate. So, + * we need to divide buffer_size by the number of cpus. */ + buffer_size /= num_online_cpus(); dbug_trans(1, "%lu\n", buffer_size); __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); if (!__stp_ring_buffer) -- cgit From c24cd76e91647ebdf98445439083c1b0e0a65dd4 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 12 Mar 2009 16:16:16 -0500 Subject: Start of STP_BULKMODE support. 2009-03-12 David Smith * transport/ring_buffer.c (_stp_transport_data_fs_init): Start of STP_BULKMODE support - creates one trace file per cpu. (_stp_transport_data_fs_close): Cleans up one trace file per cpu. --- runtime/transport/ring_buffer.c | 50 +++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 12 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 51e9efa2..22e62cdf 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -3,6 +3,10 @@ #include #include +#ifdef STP_BULKMODE +#error "bulkmode support unfinished..." +#endif + static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); @@ -366,11 +370,12 @@ static int _stp_data_write_commit(struct _stp_entry *entry) } -static struct dentry *__stp_entry; +static struct dentry *__stp_entry[NR_CPUS] = { NULL }; static int _stp_transport_data_fs_init(void) { int rc; + long cpu; // allocate buffer dbug_trans(1, "entry...\n"); @@ -379,14 +384,31 @@ static int _stp_transport_data_fs_init(void) return rc; // create file(s) - __stp_entry = debugfs_create_file("trace0", 0600, - _stp_get_module_dir(), - NULL, &__stp_data_fops); - if (!__stp_entry) - pr_warning("Could not create debugfs 'trace' entry\n"); - else { - __stp_entry->d_inode->i_uid = _stp_uid; - __stp_entry->d_inode->i_gid = _stp_gid; + for_each_possible_cpu(cpu) { + char cpu_file[9]; /* 5(trace) + 3(XXX) + 1(\0) = 9 */ + + if (cpu > 999 || cpu < 0) { + _stp_transport_data_fs_close(); + return -EINVAL; + } + sprintf(cpu_file, "trace%ld", cpu); + __stp_entry[cpu] = debugfs_create_file(cpu_file, 0600, + _stp_get_module_dir(), + (void *)cpu, + &__stp_data_fops); + + if (!__stp_entry[cpu]) { + pr_warning("Could not create debugfs 'trace' entry\n"); + __stp_free_ring_buffer(); + return -ENOENT; + } + __stp_entry[cpu]->d_inode->i_uid = _stp_uid; + __stp_entry[cpu]->d_inode->i_gid = _stp_gid; + +#ifndef STP_BULKMODE + if (cpu != 0) + break; +#endif } dbug_trans(1, "returning 0...\n"); @@ -395,9 +417,13 @@ static int _stp_transport_data_fs_init(void) static void _stp_transport_data_fs_close(void) { - if (__stp_entry) - debugfs_remove(__stp_entry); - __stp_entry = NULL; + int cpu; + + for_each_possible_cpu(cpu) { + if (__stp_entry[cpu]) + debugfs_remove(__stp_entry[cpu]); + __stp_entry[cpu] = NULL; + } __stp_free_ring_buffer(); } -- cgit From 8d1dd679bdbe3f4c40305fdbca0c1b4002913e87 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 13 Mar 2009 13:22:10 -0500 Subject: More bulkmode support. Only allows for one reader of all trace files. 2009-03-13 David Smith * transport/ring_buffer.c (__stp_free_ring_buffer): Frees _stp_trace_reader_cpumask. (__stp_alloc_ring_buffer): Allocates and clears _stp_trace_reader_cpumask. (_stp_data_open_trace): Instead of using an atomic variable, uses a cpumask variable to allow for only one reader of trace files. (_stp_data_release_trace): Clears cpumask when trace files are closed. --- runtime/transport/ring_buffer.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 22e62cdf..a933ff9a 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef STP_BULKMODE #error "bulkmode support unfinished..." @@ -44,8 +45,11 @@ struct _stp_ring_buffer_iterator { static struct _stp_ring_buffer_iterator _stp_iter; #endif +static cpumask_var_t _stp_trace_reader_cpumask; + static void __stp_free_ring_buffer(void) { + free_cpumask_var(_stp_trace_reader_cpumask); if (__stp_ring_buffer) ring_buffer_free(__stp_ring_buffer); __stp_ring_buffer = NULL; @@ -56,6 +60,10 @@ static int __stp_alloc_ring_buffer(void) int i; unsigned long buffer_size = _stp_bufsize; + if (!alloc_cpumask_var(&_stp_trace_reader_cpumask, GFP_KERNEL)) + goto fail; + cpumask_clear(_stp_trace_reader_cpumask); + if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); buffer_size = _stp_nsubbufs * _stp_subbuf_size; @@ -77,25 +85,39 @@ fail: return -ENOMEM; } -static atomic_t _stp_trace_attached = ATOMIC_INIT(0); - static int _stp_data_open_trace(struct inode *inode, struct file *file) { - /* We only allow for one reader */ + long cpu_file = (long) inode->i_private; + + /* We only allow for one reader per cpu */ dbug_trans(1, "trace attach\n"); - if (atomic_inc_return(&_stp_trace_attached) != 1) { - atomic_dec(&_stp_trace_attached); +#ifdef STP_BULKMODE + if (!cpumask_test_cpu(cpu_file, _stp_trace_reader_cpumask)) + cpumask_set_cpu(cpu_file, _stp_trace_reader_cpumask); + else { dbug_trans(1, "returning EBUSY\n"); return -EBUSY; } - +#else + if (!cpumask_empty(_stp_trace_reader_cpumask)) { + dbug_trans(1, "returning EBUSY\n"); + return -EBUSY; + } + cpumask_setall(_stp_trace_reader_cpumask); +#endif return 0; } static int _stp_data_release_trace(struct inode *inode, struct file *file) { + long cpu_file = (long) inode->i_private; dbug_trans(1, "trace detach\n"); - atomic_dec(&_stp_trace_attached); +#ifdef STP_BULKMODE + cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); +#else + cpumask_clear(_stp_trace_reader_cpumask); +#endif + return 0; } -- cgit From 325d52059ed170a698dd4d13e2b418e8e9ab0862 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 13 Mar 2009 14:22:56 -0500 Subject: More bulkmode support. 2009-03-13 David Smith * transport/ring_buffer.c (_stp_data_open_trace): Passes the inode's private data into the file's private data. (_stp_trace_seq_to_user): Deleted unused function. (trace_seq_reset): Ditto. (__stp_find_next_entry): Renamed and added bulkmode support. (_stp_find_next_entry): Updated call. (_stp_data_read_trace): Updated call. --- runtime/transport/ring_buffer.c | 67 ++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index a933ff9a..3ea29f95 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -105,6 +105,7 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) } cpumask_setall(_stp_trace_reader_cpumask); #endif + file->private_data = inode->i_private; return 0; } @@ -121,38 +122,6 @@ static int _stp_data_release_trace(struct inode *inode, struct file *file) return 0; } -struct trace_seq { - unsigned char buffer[PAGE_SIZE]; - unsigned int len; - unsigned int readpos; -}; - -ssize_t -_stp_trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) -{ - int len; - int ret; - - dbug_trans(1, "s: %p\n", s); - if (s == NULL) - return -EFAULT; - - dbug_trans(1, "len: %d, readpos: %d, buffer: %p\n", s->len, - s->readpos, s->buffer); - if (s->len <= s->readpos) - return -EBUSY; - - len = s->len - s->readpos; - if (cnt > len) - cnt = len; - ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); - if (ret) - return -EFAULT; - - s->readpos += len; - return cnt; -} - size_t _stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) { @@ -175,13 +144,6 @@ _stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) return cnt; } -static void -trace_seq_reset(struct trace_seq *s) -{ - s->len = 0; - s->readpos = 0; -} - static ssize_t tracing_wait_pipe(struct file *filp) { while (ring_buffer_empty(__stp_ring_buffer)) { @@ -229,9 +191,24 @@ peek_next_entry(int cpu, u64 *ts) } static struct _stp_entry * -__find_next_entry(int *ent_cpu, u64 *ent_ts) +__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) { - struct _stp_entry *ent, *next = NULL; + struct _stp_entry *ent; + +#ifdef STP_BULKMODE + /* + * If we are in a per_cpu trace file, don't bother by iterating over + * all cpus and peek directly. + */ + if (ring_buffer_empty_cpu(buffer, (int)cpu_file)) + return NULL; + ent = peek_next_entry(cpu_file, ent_ts); + if (ent_cpu) + *ent_cpu = cpu_file; + + return ent; +#else + struct _stp_entry *next = NULL; u64 next_ts = 0, ts; int next_cpu = -1; int cpu; @@ -260,12 +237,13 @@ __find_next_entry(int *ent_cpu, u64 *ent_ts) *ent_ts = next_ts; return next; +#endif } /* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *_stp_find_next_entry(void) +static struct _stp_entry *_stp_find_next_entry(long cpu_file) { - return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); + return __stp_find_next_entry(cpu_file, &_stp_iter.cpu, &_stp_iter.ts); } @@ -278,6 +256,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, { ssize_t sret; struct _stp_entry *entry; + long cpu_file = (long) filp->private_data; dbug_trans(1, "%lu\n", (unsigned long)cnt); @@ -297,7 +276,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = _stp_find_next_entry()) != NULL) { + while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { ssize_t len; len = _stp_entry_to_user(entry, ubuf, cnt); -- cgit From 7d573b8d318836ef75d1f2888a50da230b7d83cc Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 13 Mar 2009 16:48:58 -0500 Subject: Working bulkmode support. 2009-03-13 David Smith * print_new.c (stp_print_flush): Added bulkmode support for new transport. * transport/ring_buffer.c (__stp_find_next_entry): Fixed syntax error in bulkmode code. (_stp_transport_data_fs_init): Changed 'for_each_possible_cpu()' to 'for_each_online_cpu()' so that non-online cpu's won't have a trace file created. --- runtime/transport/ring_buffer.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 3ea29f95..1d46c378 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,10 +4,6 @@ #include #include -#ifdef STP_BULKMODE -#error "bulkmode support unfinished..." -#endif - static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); @@ -200,7 +196,7 @@ __stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) * If we are in a per_cpu trace file, don't bother by iterating over * all cpus and peek directly. */ - if (ring_buffer_empty_cpu(buffer, (int)cpu_file)) + if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) return NULL; ent = peek_next_entry(cpu_file, ent_ts); if (ent_cpu) @@ -385,7 +381,7 @@ static int _stp_transport_data_fs_init(void) return rc; // create file(s) - for_each_possible_cpu(cpu) { + for_each_online_cpu(cpu) { char cpu_file[9]; /* 5(trace) + 3(XXX) + 1(\0) = 9 */ if (cpu > 999 || cpu < 0) { -- cgit From 2e07d704dc5d7304d6a9e666553a1a8ac4382730 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 31 Mar 2009 12:02:25 -0500 Subject: 2009-03-31 David Smith * print_new.c (stp_print_flush): Pushed MAX_RESERVE logic down to _stp_data_write_reserve(). Now just keeps calling _stp_data_write_reserve() until it has written the entire print buffer. * transport/ring_buffer.c (_stp_data_write_reserve): Breaks large reserve requests down into smaller ones for better buffer use. Returns the number of bytes reserved. * transport/transport.h: Updated _stp_data_write_reserve() prototype. --- runtime/transport/ring_buffer.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 1d46c378..abe9c360 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -317,6 +317,15 @@ static struct file_operations __stp_data_fops = { #endif }; +/* Here's how __STP_MAX_RESERVE_SIZE is figured. The value of + * BUF_PAGE_SIZE was gotten from the kernel's ring_buffer code. It + * is divided by 4, so we waste a maximum of 1/4 of the buffer (in + * the case of a small reservation). We then subtract the sizes of + * structures needed for every reservation. */ +#define __STP_MAX_RESERVE_SIZE ((/*BUF_PAGE_SIZE*/ 4080 / 4) \ + - sizeof(struct _stp_entry) \ + - sizeof(struct ring_buffer_event)) + /* * This function prepares the cpu buffer to write a sample. * @@ -329,24 +338,31 @@ static struct file_operations __stp_data_fops = { * sample. * */ -static struct _stp_entry * -_stp_data_write_reserve(size_t size) +static size_t +_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) { struct ring_buffer_event *event; - struct _stp_entry *entry; + + if (entry == NULL) + return -EINVAL; + + if (size_request > __STP_MAX_RESERVE_SIZE) { + size_request = __STP_MAX_RESERVE_SIZE; + } event = ring_buffer_lock_reserve(__stp_ring_buffer, - (sizeof(struct _stp_entry) + size), + (sizeof(struct _stp_entry) + size_request), 0); if (unlikely(! event)) { dbug_trans(1, "event = NULL (%p)?\n", event); - return NULL; + entry = NULL; + return 0; } - entry = ring_buffer_event_data(event); - entry->event = event; - entry->len = size; - return entry; + *entry = ring_buffer_event_data(event); + (*entry)->event = event; + (*entry)->len = size_request; + return size_request; } static int _stp_data_write_commit(struct _stp_entry *entry) -- cgit From 4a8c28f93fa29e47c604e80e383c826070d6c383 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 6 May 2009 12:25:02 -0500 Subject: Start of support for older transport and cleanup. * runtime/transport/control.c: Added inclusion of linux/delay.h to get declaration of msleep(). * runtime/transport/relay_v2.c: New skeleton file for transport version 2. * runtime/transport/ring_buffer.c: Cleanup. * runtime/transport/transport.c: Ditto. --- runtime/transport/ring_buffer.c | 51 ++++++++--------------------------------- 1 file changed, 9 insertions(+), 42 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index abe9c360..99ce2031 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -5,41 +5,20 @@ #include static struct ring_buffer *__stp_ring_buffer = NULL; -//DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); /* _stp_poll_wait is a waitqueue for tasks blocked on * _stp_data_poll_trace() */ static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); -#if 1 /* * Trace iterator - used by printout routines who present trace * results to users and which routines might sleep, etc: */ -struct _stp_ring_buffer_iterator { -#if 0 - struct trace_array *tr; - struct tracer *trace; - void *private; - struct ring_buffer_iter *buffer_iter[NR_CPUS]; - - /* The below is zeroed out in pipe_read */ - struct trace_seq seq; - struct trace_entry *ent; -#endif +struct _stp_ring_buffer_data { int cpu; u64 ts; - -#if 0 - unsigned long iter_flags; - loff_t pos; - long idx; - - cpumask_var_t started; -#endif }; -static struct _stp_ring_buffer_iterator _stp_iter; -#endif +static struct _stp_ring_buffer_data _stp_rb_data; static cpumask_var_t _stp_trace_reader_cpumask; @@ -159,13 +138,10 @@ static ssize_t tracing_wait_pipe(struct file *filp) * Anyway, this is really very primitive wakeup. */ set_current_state(TASK_INTERRUPTIBLE); - //iter->tr->waiter = current; /* sleep for 100 msecs, and try again. */ schedule_timeout(HZ/10); - //iter->tr->waiter = NULL; - if (signal_pending(current)) { dbug_trans(1, "returning -EINTR\n"); return -EINTR; @@ -186,8 +162,9 @@ peek_next_entry(int cpu, u64 *ts) return event ? ring_buffer_event_data(event) : NULL; } +/* Find the next real entry */ static struct _stp_entry * -__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) +_stp_find_next_entry(long cpu_file) { struct _stp_entry *ent; @@ -199,8 +176,7 @@ __stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) return NULL; ent = peek_next_entry(cpu_file, ent_ts); - if (ent_cpu) - *ent_cpu = cpu_file; + _stp_rb_data.cpu = cpu_file; return ent; #else @@ -226,22 +202,13 @@ __stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) } } - if (ent_cpu) - *ent_cpu = next_cpu; - - if (ent_ts) - *ent_ts = next_ts; + _stp_rb_data.cpu = next_cpu; + _stp_rb_data.ts = next_ts; return next; #endif } -/* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *_stp_find_next_entry(long cpu_file) -{ - return __stp_find_next_entry(cpu_file, &_stp_iter.cpu, &_stp_iter.ts); -} - /* * Consumer reader. @@ -279,8 +246,8 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, if (len <= 0) break; - ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, - &_stp_iter.ts); + ring_buffer_consume(__stp_ring_buffer, _stp_rb_data.cpu, + &_stp_rb_data.ts); ubuf += len; cnt -= len; sret += len; -- cgit From 6edf848ad0053423dd3b06851ab8d62a260a56e8 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 7 May 2009 15:02:05 -0500 Subject: Hid details of internal ring_buffer.c structure. * runtime/print_new.c (stp_print_flush): Calls _stp_data_entry_data() to get data pointer. * runtime/transport/transport.h: Removed _stp_entry definition. Added _stp_data_entry_data() declaration. * runtime/transport/ring_buffer.c: Uses new _stp_data_entry structure. (_stp_data_entry_data): Added. --- runtime/transport/ring_buffer.c | 95 +++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 36 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 99ce2031..0385e7d3 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,6 +4,11 @@ #include #include +struct _stp_data_entry { + size_t len; + unsigned char buf[]; +}; + static struct ring_buffer *__stp_ring_buffer = NULL; /* _stp_poll_wait is a waitqueue for tasks blocked on @@ -98,12 +103,18 @@ static int _stp_data_release_trace(struct inode *inode, struct file *file) } size_t -_stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) +_stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf, + size_t cnt) { int ret; + struct _stp_data_entry *entry; - dbug_trans(1, "entry(%p), ubuf(%p), cnt(%lu)\n", entry, ubuf, cnt); - if (entry == NULL || ubuf == NULL) + dbug_trans(1, "event(%p), ubuf(%p), cnt(%lu)\n", event, ubuf, cnt); + if (event == NULL || ubuf == NULL) + return -EFAULT; + + entry = (struct _stp_data_entry *)ring_buffer_event_data(event); + if (entry == NULL) return -EFAULT; /* We don't do partial entries - just fail. */ @@ -152,21 +163,17 @@ static ssize_t tracing_wait_pipe(struct file *filp) return 1; } -static struct _stp_entry * -peek_next_entry(int cpu, u64 *ts) +static struct ring_buffer_event * +peek_next_event(int cpu, u64 *ts) { - struct ring_buffer_event *event; - - event = ring_buffer_peek(__stp_ring_buffer, cpu, ts); - - return event ? ring_buffer_event_data(event) : NULL; + return ring_buffer_peek(__stp_ring_buffer, cpu, ts); } -/* Find the next real entry */ -static struct _stp_entry * -_stp_find_next_entry(long cpu_file) +/* Find the next real event */ +static struct ring_buffer_event * +_stp_find_next_event(long cpu_file) { - struct _stp_entry *ent; + struct ring_buffer_event *event; #ifdef STP_BULKMODE /* @@ -175,12 +182,12 @@ _stp_find_next_entry(long cpu_file) */ if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) return NULL; - ent = peek_next_entry(cpu_file, ent_ts); + event = peek_next_event(cpu_file, &_stp_rb_data.ts); _stp_rb_data.cpu = cpu_file; - return ent; + return event; #else - struct _stp_entry *next = NULL; + struct ring_buffer_event *next = NULL; u64 next_ts = 0, ts; int next_cpu = -1; int cpu; @@ -190,13 +197,13 @@ _stp_find_next_entry(long cpu_file) if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) continue; - ent = peek_next_entry(cpu, &ts); + event = peek_next_event(cpu, &ts); /* - * Pick the entry with the smallest timestamp: + * Pick the event with the smallest timestamp: */ - if (ent && (!next || ts < next_ts)) { - next = ent; + if (event && (!next || ts < next_ts)) { + next = event; next_cpu = cpu; next_ts = ts; } @@ -218,7 +225,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { ssize_t sret; - struct _stp_entry *entry; + struct ring_buffer_event *event; long cpu_file = (long) filp->private_data; dbug_trans(1, "%lu\n", (unsigned long)cnt); @@ -239,10 +246,10 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { + while ((event = _stp_find_next_event(cpu_file)) != NULL) { ssize_t len; - len = _stp_entry_to_user(entry, ubuf, cnt); + len = _stp_event_to_user(event, ubuf, cnt); if (len <= 0) break; @@ -284,13 +291,14 @@ static struct file_operations __stp_data_fops = { #endif }; -/* Here's how __STP_MAX_RESERVE_SIZE is figured. The value of +/* + * Here's how __STP_MAX_RESERVE_SIZE is figured. The value of * BUF_PAGE_SIZE was gotten from the kernel's ring_buffer code. It * is divided by 4, so we waste a maximum of 1/4 of the buffer (in - * the case of a small reservation). We then subtract the sizes of - * structures needed for every reservation. */ -#define __STP_MAX_RESERVE_SIZE ((/*BUF_PAGE_SIZE*/ 4080 / 4) \ - - sizeof(struct _stp_entry) \ + * the case of a small reservation). + */ +#define __STP_MAX_RESERVE_SIZE ((/*BUF_PAGE_SIZE*/ 4080 / 4) \ + - sizeof(struct _stp_data_entry) \ - sizeof(struct ring_buffer_event)) /* @@ -306,9 +314,10 @@ static struct file_operations __stp_data_fops = { * */ static size_t -_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +_stp_data_write_reserve(size_t size_request, void **entry) { struct ring_buffer_event *event; + struct _stp_data_entry *sde; if (entry == NULL) return -EINVAL; @@ -318,7 +327,7 @@ _stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) } event = ring_buffer_lock_reserve(__stp_ring_buffer, - (sizeof(struct _stp_entry) + size_request), + sizeof(struct _stp_data_entry) + size_request, 0); if (unlikely(! event)) { dbug_trans(1, "event = NULL (%p)?\n", event); @@ -326,22 +335,36 @@ _stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) return 0; } - *entry = ring_buffer_event_data(event); - (*entry)->event = event; - (*entry)->len = size_request; + sde = (struct _stp_data_entry *)ring_buffer_event_data(event); + sde->len = size_request; + + *entry = event; return size_request; } -static int _stp_data_write_commit(struct _stp_entry *entry) +static unsigned char *_stp_data_entry_data(void *entry) +{ + struct ring_buffer_event *event = entry; + struct _stp_data_entry *sde; + + if (event == NULL) + return NULL; + + sde = (struct _stp_data_entry *)ring_buffer_event_data(event); + return sde->buf; +} + +static int _stp_data_write_commit(void *entry) { int ret; + struct ring_buffer_event *event = (struct ring_buffer_event *)entry; if (unlikely(! entry)) { dbug_trans(1, "entry = NULL, returning -EINVAL\n"); return -EINVAL; } - ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); + ret = ring_buffer_unlock_commit(__stp_ring_buffer, event, 0); dbug_trans(1, "after commit, empty returns %d\n", ring_buffer_empty(__stp_ring_buffer)); -- cgit From e57421f400d17786c1fdbead5fbca27a1fbe4ec5 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 22 May 2009 10:50:30 -0500 Subject: Added error checking and other updates. * runtime/vsprintf.c: Added transport.h inclusion for STP_BUFFER_SIZE definition. * runtime/transport/debugfs.c (_stp_register_ctl_channel_fs): Added error checking. * runtime/transport/transport.c (_stp_get_root_dir): Ditto. (_stp_transport_fs_init): Added original transport support and error checking. * runtime/transport/relay_v2.c (__stp_relay_create_buf_file_callback): Added error checking. (_stp_transport_data_fs_init): Ditto. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_init): Ditto. * runtime/transport/utt.c: Removed unused file. * runtime/transport/utt.h: Ditto. --- runtime/transport/ring_buffer.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 0385e7d3..217d0735 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -405,6 +405,13 @@ static int _stp_transport_data_fs_init(void) __stp_free_ring_buffer(); return -ENOENT; } + else if (IS_ERR(__stp_entry[cpu])) { + rc = PTR_ERR(__stp_entry[cpu]); + pr_warning("Could not create debugfs 'trace' entry\n"); + __stp_free_ring_buffer(); + return rc; + } + __stp_entry[cpu]->d_inode->i_uid = _stp_uid; __stp_entry[cpu]->d_inode->i_gid = _stp_gid; -- cgit From 01adca5bca8d61e3fdf09017496deec8859fe12d Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 3 Jun 2009 13:04:54 -0500 Subject: Fixed STP_TRANSPORT_VERSION 1 behavior. * runtime/transport/control.c (_stp_ctl_write_dbug): Added support for more messages. * runtime/transport/relay_v2.c (_stp_transport_data_fs_start): New function. (_stp_transport_data_fs_stop): Ditto. (_stp_transport_data_fs_close): Moved some functionality into _stp_transport_data_fs_stop() and calls _stp_transport_data_fs_stop() also. (_stp_transport_data_fs_init): Moved some functionality into _stp_transport_data_fs_start() and calls _stp_transport_data_fs_start() also. * runtime/transport/relayfs.c (_stp_transport_data_fs_start): New function. (_stp_transport_data_fs_stop): Ditto. (_stp_transport_data_fs_close): Moved some functionality into _stp_transport_data_fs_stop() and calls _stp_transport_data_fs_stop() also. (_stp_transport_data_fs_init): Moved some functionality into _stp_transport_data_fs_start() and calls _stp_transport_data_fs_start() also. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_start): New empty function. (_stp_transport_data_fs_stop): Ditto. * runtime/transport/transport.h: Added _stp_transport_data_fs_start() and _stp_transport_data_fs_stop() prototypes. * runtime/transport/transport.c (_stp_cleanup_and_exit): Calls _stp_transport_data_fs_stop(). (_stp_transport_close): Calls _stp_transport_fs_close() earlier. (_stp_transport_init): Calls _stp_transport_data_fs_start(). --- runtime/transport/ring_buffer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 217d0735..bed441e5 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -425,6 +425,16 @@ static int _stp_transport_data_fs_init(void) return 0; } +static void _stp_transport_data_fs_start(void) +{ + /* Do nothing. */ +} + +static void _stp_transport_data_fs_stop(void) +{ + /* Do nothing. */ +} + static void _stp_transport_data_fs_close(void) { int cpu; -- cgit From 24a5e9a6a87b2f7c8b7264ceb94c65a3a9550d47 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 13:09:31 -0500 Subject: Enabled overwrite processing on original transports. * runtime/transport/relay_v2.c (_stp_transport_data_fs_overwrite): Renamed from stp_relay_set_overwrite(). * runtime/transport/relayfs.c (stp_relay_set_overwrite): Ditto. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_overwrite): New place holder function. * runtime/transport/transport.c (_stp_detach): Calls _stp_transport_data_fs_overwrite(). (_stp_attach): Calls _stp_transport_data_fs_overwrite(). * runtime/transport/transport.h: Added prototype for _stp_transport_data_fs_overwrite(). --- runtime/transport/ring_buffer.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index bed441e5..45ad8e2b 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -448,3 +448,7 @@ static void _stp_transport_data_fs_close(void) __stp_free_ring_buffer(); } +static void _stp_transport_data_fs_overwrite(int overwrite) +{ + /* FIXME: Just a place holder for now. */ +} -- cgit From f530a9fec01f287d42072632d5607d5fa275479d Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 16:11:17 -0500 Subject: Moved global data into a single structure. --- runtime/transport/ring_buffer.c | 84 ++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 39 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 45ad8e2b..418465c2 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -9,12 +9,6 @@ struct _stp_data_entry { unsigned char buf[]; }; -static struct ring_buffer *__stp_ring_buffer = NULL; - -/* _stp_poll_wait is a waitqueue for tasks blocked on - * _stp_data_poll_trace() */ -static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); - /* * Trace iterator - used by printout routines who present trace * results to users and which routines might sleep, etc: @@ -23,16 +17,24 @@ struct _stp_ring_buffer_data { int cpu; u64 ts; }; -static struct _stp_ring_buffer_data _stp_rb_data; -static cpumask_var_t _stp_trace_reader_cpumask; +struct _stp_relay_data_type { + struct ring_buffer *rb; + struct _stp_ring_buffer_data rb_data; + cpumask_var_t trace_reader_cpumask; +}; +static struct _stp_relay_data_type _stp_relay_data; + +/* _stp_poll_wait is a waitqueue for tasks blocked on + * _stp_data_poll_trace() */ +static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); static void __stp_free_ring_buffer(void) { - free_cpumask_var(_stp_trace_reader_cpumask); - if (__stp_ring_buffer) - ring_buffer_free(__stp_ring_buffer); - __stp_ring_buffer = NULL; + free_cpumask_var(_stp_relay_data.trace_reader_cpumask); + if (_stp_relay_data.rb) + ring_buffer_free(_stp_relay_data.rb); + _stp_relay_data.rb = NULL; } static int __stp_alloc_ring_buffer(void) @@ -40,9 +42,10 @@ static int __stp_alloc_ring_buffer(void) int i; unsigned long buffer_size = _stp_bufsize; - if (!alloc_cpumask_var(&_stp_trace_reader_cpumask, GFP_KERNEL)) + if (!alloc_cpumask_var(&_stp_relay_data.trace_reader_cpumask, + GFP_KERNEL)) goto fail; - cpumask_clear(_stp_trace_reader_cpumask); + cpumask_clear(_stp_relay_data.trace_reader_cpumask); if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); @@ -53,11 +56,11 @@ static int __stp_alloc_ring_buffer(void) * we need to divide buffer_size by the number of cpus. */ buffer_size /= num_online_cpus(); dbug_trans(1, "%lu\n", buffer_size); - __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); - if (!__stp_ring_buffer) + _stp_relay_data.rb = ring_buffer_alloc(buffer_size, 0); + if (!_stp_relay_data.rb) goto fail; - dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); + dbug_trans(1, "size = %lu\n", ring_buffer_size(_stp_relay_data.rb)); return 0; fail: @@ -72,18 +75,18 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) /* We only allow for one reader per cpu */ dbug_trans(1, "trace attach\n"); #ifdef STP_BULKMODE - if (!cpumask_test_cpu(cpu_file, _stp_trace_reader_cpumask)) - cpumask_set_cpu(cpu_file, _stp_trace_reader_cpumask); + if (!cpumask_test_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask)) + cpumask_set_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask); else { dbug_trans(1, "returning EBUSY\n"); return -EBUSY; } #else - if (!cpumask_empty(_stp_trace_reader_cpumask)) { + if (!cpumask_empty(_stp_relay_data.trace_reader_cpumask)) { dbug_trans(1, "returning EBUSY\n"); return -EBUSY; } - cpumask_setall(_stp_trace_reader_cpumask); + cpumask_setall(_stp_relay_data.trace_reader_cpumask); #endif file->private_data = inode->i_private; return 0; @@ -94,9 +97,9 @@ static int _stp_data_release_trace(struct inode *inode, struct file *file) long cpu_file = (long) inode->i_private; dbug_trans(1, "trace detach\n"); #ifdef STP_BULKMODE - cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); + cpumask_clear_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask); #else - cpumask_clear(_stp_trace_reader_cpumask); + cpumask_clear(_stp_relay_data.trace_reader_cpumask); #endif return 0; @@ -132,7 +135,7 @@ _stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf, static ssize_t tracing_wait_pipe(struct file *filp) { - while (ring_buffer_empty(__stp_ring_buffer)) { + while (ring_buffer_empty(_stp_relay_data.rb)) { if ((filp->f_flags & O_NONBLOCK)) { dbug_trans(1, "returning -EAGAIN\n"); @@ -166,7 +169,7 @@ static ssize_t tracing_wait_pipe(struct file *filp) static struct ring_buffer_event * peek_next_event(int cpu, u64 *ts) { - return ring_buffer_peek(__stp_ring_buffer, cpu, ts); + return ring_buffer_peek(_stp_relay_data.rb, cpu, ts); } /* Find the next real event */ @@ -180,10 +183,10 @@ _stp_find_next_event(long cpu_file) * If we are in a per_cpu trace file, don't bother by iterating over * all cpus and peek directly. */ - if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) + if (ring_buffer_empty_cpu(_stp_relay_data.rb, (int)cpu_file)) return NULL; - event = peek_next_event(cpu_file, &_stp_rb_data.ts); - _stp_rb_data.cpu = cpu_file; + event = peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts); + _stp_relay_data.rb_data.cpu = cpu_file; return event; #else @@ -194,7 +197,7 @@ _stp_find_next_event(long cpu_file) for_each_possible_cpu(cpu) { - if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) + if (ring_buffer_empty_cpu(_stp_relay_data.rb, cpu)) continue; event = peek_next_event(cpu, &ts); @@ -209,8 +212,8 @@ _stp_find_next_event(long cpu_file) } } - _stp_rb_data.cpu = next_cpu; - _stp_rb_data.ts = next_ts; + _stp_relay_data.rb_data.cpu = next_cpu; + _stp_relay_data.rb_data.ts = next_ts; return next; #endif @@ -236,7 +239,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, goto out; /* stop when tracing is finished */ - if (ring_buffer_empty(__stp_ring_buffer)) { + if (ring_buffer_empty(_stp_relay_data.rb)) { sret = 0; goto out; } @@ -253,8 +256,9 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, if (len <= 0) break; - ring_buffer_consume(__stp_ring_buffer, _stp_rb_data.cpu, - &_stp_rb_data.ts); + ring_buffer_consume(_stp_relay_data.rb, + _stp_relay_data.rb_data.cpu, + &_stp_relay_data.rb_data.ts); ubuf += len; cnt -= len; sret += len; @@ -270,10 +274,10 @@ static unsigned int _stp_data_poll_trace(struct file *filp, poll_table *poll_table) { dbug_trans(1, "entry\n"); - if (! ring_buffer_empty(__stp_ring_buffer)) + if (! ring_buffer_empty(_stp_relay_data.rb)) return POLLIN | POLLRDNORM; poll_wait(filp, &_stp_poll_wait, poll_table); - if (! ring_buffer_empty(__stp_ring_buffer)) + if (! ring_buffer_empty(_stp_relay_data.rb)) return POLLIN | POLLRDNORM; dbug_trans(1, "exit\n"); @@ -326,7 +330,7 @@ _stp_data_write_reserve(size_t size_request, void **entry) size_request = __STP_MAX_RESERVE_SIZE; } - event = ring_buffer_lock_reserve(__stp_ring_buffer, + event = ring_buffer_lock_reserve(_stp_relay_data.rb, sizeof(struct _stp_data_entry) + size_request, 0); if (unlikely(! event)) { @@ -364,9 +368,9 @@ static int _stp_data_write_commit(void *entry) return -EINVAL; } - ret = ring_buffer_unlock_commit(__stp_ring_buffer, event, 0); + ret = ring_buffer_unlock_commit(_stp_relay_data.rb, event, 0); dbug_trans(1, "after commit, empty returns %d\n", - ring_buffer_empty(__stp_ring_buffer)); + ring_buffer_empty(_stp_relay_data.rb)); wake_up_interruptible(&_stp_poll_wait); return ret; @@ -380,6 +384,8 @@ static int _stp_transport_data_fs_init(void) int rc; long cpu; + _stp_relay_data.rb = NULL; + // allocate buffer dbug_trans(1, "entry...\n"); rc = __stp_alloc_ring_buffer(); -- cgit From 7b1be319b40ec791c4fdbe77065204a4c3ed439b Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 16:42:35 -0500 Subject: Transports now export their state. * runtime/transport/transport.h: Added prototype for _stp_transport_get_state(). * runtime/transport/relay_v2.c (_stp_transport_get_state): New function. * runtime/transport/relayfs.c (_stp_transport_get_state): Ditto. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_init): Sets state. (_stp_transport_data_fs_start): Ditto. (_stp_transport_data_fs_stop): Ditto. (_stp_transport_get_state): Returns state. * runtime/print_new.c (stp_print_flush): Checks transport state before trying to flush. --- runtime/transport/ring_buffer.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'runtime/transport/ring_buffer.c') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 418465c2..0b73d4b4 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -19,6 +19,7 @@ struct _stp_ring_buffer_data { }; struct _stp_relay_data_type { + enum _stp_transport_state transport_state; struct ring_buffer *rb; struct _stp_ring_buffer_data rb_data; cpumask_var_t trace_reader_cpumask; @@ -384,6 +385,7 @@ static int _stp_transport_data_fs_init(void) int rc; long cpu; + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; _stp_relay_data.rb = NULL; // allocate buffer @@ -428,17 +430,22 @@ static int _stp_transport_data_fs_init(void) } dbug_trans(1, "returning 0...\n"); + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; return 0; } static void _stp_transport_data_fs_start(void) { - /* Do nothing. */ + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) { + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + } } static void _stp_transport_data_fs_stop(void) { - /* Do nothing. */ + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + } } static void _stp_transport_data_fs_close(void) @@ -454,6 +461,11 @@ static void _stp_transport_data_fs_close(void) __stp_free_ring_buffer(); } +static enum _stp_transport_state _stp_transport_get_state(void) +{ + return _stp_relay_data.transport_state; +} + static void _stp_transport_data_fs_overwrite(int overwrite) { /* FIXME: Just a place holder for now. */ -- cgit